/* * 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 . */ /* * Uses libharu by Takeshi Kanno to generate pdf documents. */ #include #include #include #include "pdf.h" #include 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 */