diff options
Diffstat (limited to 'hyp2mat/lib/pdf.cc')
-rw-r--r-- | hyp2mat/lib/pdf.cc | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/hyp2mat/lib/pdf.cc b/hyp2mat/lib/pdf.cc new file mode 100644 index 0000000..a233f29 --- /dev/null +++ b/hyp2mat/lib/pdf.cc @@ -0,0 +1,292 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Uses libharu by Takeshi Kanno to generate pdf documents. + */ + +#include <iostream> +#include <cstdio> +#include <algorithm> +#include "pdf.h" +#include <hpdf_types.h> + +using namespace Hyp2Mat; + +PDF::PDF() +{ + text_height = 10; /* caption size in points */ + margin = text_height; /* page margin */ + m_to_points = 1 / (2.54 / 100 / 72); /* convert m to points (1/72 of an inch) */ + x_max = x_min = y_max = y_min = 0; +} + +/* + * PDF error handler + */ + +void error_handler (HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data) +{ + printf ("ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no); + throw std::exception (); /* throw exception on error */ +} + +/* + * set page size to size of pcb board + */ + +void PDF::set_page_size(HPDF_Page page) +{ + double width = x_max - x_min + 2 * margin; + double height = y_max - y_min + 2 * margin + text_height; /* add margin for caption */ + + if (width < 3) width = 3; + if (height < 3) height = 3; + + HPDF_Page_SetWidth(page, width); + HPDF_Page_SetHeight(page, height); +} + +/* + * Generate color palette given hue, saturation and value (brightness). + * After Martin Ankerl * "How to Generate Random Colors Programmatically" + */ + +void PDF::set_color(HPDF_Page page, int color_idx) +{ + PaletteColor rgb = Color(color_idx); + + HPDF_Page_SetRGBStroke(page, rgb.red, rgb.green, rgb.blue); + HPDF_Page_SetRGBFill(page, rgb.red, rgb.green, rgb.blue); +} + +/* + * Set stroke and fill color to black + */ + +void PDF::set_color_black(HPDF_Page page) +{ + HPDF_Page_SetRGBStroke(page, 0, 0, 0); + HPDF_Page_SetRGBFill(page, 0, 0, 0); +} + +/* + * fill all polygons + */ + +void PDF::page_fill(HPDF_Page page) +{ + if (HPDF_Page_GetGMode(page) == HPDF_GMODE_PATH_OBJECT) HPDF_Page_Fill (page); + return; +} + +/* + * draw all polygon outlines + */ + +void PDF::page_stroke(HPDF_Page page) +{ + if (HPDF_Page_GetGMode(page) == HPDF_GMODE_PATH_OBJECT) HPDF_Page_Stroke (page); + return; +} + +/* + * Write layer name on top of page + */ + +void PDF::draw_caption(HPDF_Page page, HPDF_Font font, std::string txt) +{ + HPDF_Page_SetFontAndSize(page, font, text_height); + HPDF_Page_BeginText(page); + HPDF_Page_MoveTextPos(page, margin, y_max - y_min + margin + text_height); /* page top left */ + HPDF_Page_ShowText(page, txt.c_str()); + HPDF_Page_EndText(page); +} + +/* + * Export copper polygon as pdf + */ + +void PDF::draw(HPDF_Page page, FloatPolygon& poly) +{ + double old_px, old_py; + + /* pdf requires outer edge of polygon to be clockwise; holes to be counterclockwise */ + + bool firstpoint = true; + for (FloatPolygon::iterator i = poly.begin(); i != poly.end(); ++i) { + + double px = i->x * m_to_points - x_min + margin; + double py = i->y * m_to_points - y_min + margin; + if (firstpoint) { + HPDF_Page_MoveTo(page, px, py); + firstpoint = false; + } + else { + if ((px != old_px) || (py != old_py)) + HPDF_Page_LineTo(page, px, py); + } + old_px = px; old_py = py; + } + HPDF_Page_ClosePath (page); + return; +} + +/* + * Export all polygons of a copper layer as pdf. May contain holes. + */ + +void PDF::draw(HPDF_Page page, FloatPolygons& polygons) +{ + for (FloatPolygons::iterator i = polygons.begin(); i != polygons.end(); ++i) + draw(page, i->poly); +} + +/* + * Draws a via as a circle. + */ + +void PDF::draw(HPDF_Page page, Hyp2Mat::Via& via) +{ + double x = via.x * m_to_points - x_min + margin; + double y = via.y * m_to_points - y_min + margin; + double r = via.radius * m_to_points; + HPDF_Page_Circle(page, x, y, r); +} + +void PDF::draw_composite_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb) +{ + /* new page */ + HPDF_Page page = HPDF_AddPage(pdf); + set_page_size(page); + HPDF_Page_SetLineWidth(page, 0); + draw_caption(page, font, "Composite"); + + /* draw board */ + set_color_black(page); + draw(page, pcb.board); + page_stroke (page); + + /* draw layers */ + int current_color = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) { + if (l->layer_type == LAYER_DIELECTRIC) continue; + set_color(page, current_color++); + draw(page, l->metal); + page_stroke (page); + } + + /* draw vias */ + set_color_black(page); + for (ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) + PDF::draw(page, *i); + page_fill (page); + + return; +} + +void PDF::draw_layer_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb) +{ + + int current_color = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) { + if (l->layer_type == LAYER_DIELECTRIC) continue; + + HPDF_Page page = HPDF_AddPage(pdf); + set_page_size(page); + HPDF_Page_SetLineWidth(page, 0); + + /* draw caption */ + draw_caption(page, font, l->layer_name); + + /* draw board */ + set_color_black(page); + draw(page, pcb.board); + page_stroke (page); + + /* draw layer */ + set_color(page, current_color++); + draw(page, l->metal); + page_fill (page); + + /* draw vias */ + set_color_black(page); + for (ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) { + /* blind vias: only draw via if via goes through current layer */ + if ((i->z0 <= l->z0) && (i->z1 >= l->z1)) { + draw(page, *i); + } + } + page_fill (page); + } +} + +/* + * Save current board as pdf. + * First page is the composite view of all signal layers, + * subsequent pages are one layer each. + */ + +void PDF::Write(const std::string& filename, Hyp2Mat::PCB& pcb) +{ + /* choose a color palette. Change HSV values to what suits your taste */ + int number_of_colors = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) + if (l->layer_type != LAYER_DIELECTRIC) number_of_colors++; /* count layers to determine number of colors needed */ + + SetNumberOfColors(number_of_colors); + + HPDF_Doc pdf = HPDF_New (error_handler, NULL); /* set error-handler */ + if (!pdf) { + std::cerr << "cannot create pdf object" << std::endl; + return; + } + + try { + /* get pcb size */ + Bounds bounds = pcb.GetBounds(); + x_max = bounds.x_max * m_to_points; + y_max = bounds.y_max * m_to_points; + x_min = bounds.x_min * m_to_points; + y_min = bounds.y_min * m_to_points; + + /* Document settings */ + HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL); + HPDF_SetInfoAttr(pdf, HPDF_INFO_CREATOR, "hyp2mat"); + HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL); + + /* Draw composite page */ + draw_composite_view(pdf, font, pcb); + + /* Draw individual layers' pages */ + draw_layer_view(pdf, font, pcb); + + HPDF_SaveToFile (pdf, filename.c_str()); + } + catch (...) { + HPDF_Free (pdf); + return; + } + + HPDF_Free (pdf); + + return; +} +/* not truncated */ |