summaryrefslogtreecommitdiff
path: root/hyp2mat/lib/pcb.cc
diff options
context:
space:
mode:
Diffstat (limited to 'hyp2mat/lib/pcb.cc')
-rw-r--r--hyp2mat/lib/pcb.cc333
1 files changed, 333 insertions, 0 deletions
diff --git a/hyp2mat/lib/pcb.cc b/hyp2mat/lib/pcb.cc
new file mode 100644
index 0000000..86bc657
--- /dev/null
+++ b/hyp2mat/lib/pcb.cc
@@ -0,0 +1,333 @@
+/*
+ * 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/>.
+ */
+
+#include <iostream>
+#include <iomanip>
+
+#include "config.h"
+#include "hyp2mat.h"
+
+#include "hyperlynx.h"
+#include "pdf.h"
+#include "csxcad.h"
+
+using namespace Hyp2Mat;
+
+PCB::PCB()
+{
+ debug = 0;
+ raw = false;
+ via_plating_thickness = 0;
+ _arc_precision = 0;
+ _clearance = -1.0;
+ _epsilon_r = -1.0;
+ _epsilon_r_override = false;
+ _bulk_resistivity = -1.0;
+ _bulk_resistivity_override = false;
+ _loss_tangent = -1.0;
+ _loss_tangent_override = false;
+}
+
+/*
+ * Read a pcb in hyperlynx format.
+ * "filename" is the Hyperlynx file to import.
+ * "layers" is the names of the layers to import. Default is importing all layers.
+ * "nets" is the names of the nets to import. Default is importing all nets.
+ */
+
+void PCB::ReadHyperLynx (std::string filename, std::vector<std::string> layers, std::vector<std::string> nets)
+{
+
+ /* set accuracy with which circle arcs are converted to polygons */
+ Polygon::SetArcPrecision(_arc_precision);
+
+ /* read hyperlynx file */
+ HyperLynx hyperlynx;
+
+ hyperlynx.layers = layers;
+ hyperlynx.nets = nets;
+ hyperlynx.raw = raw;
+ hyperlynx.arc_precision = _arc_precision;
+ hyperlynx.clearance = _clearance;
+ hyperlynx.flood_layers = flood_layers;
+ hyperlynx.bounds = _bounds;
+
+ hyperlynx.Read(filename, *this);
+
+ /* Check for empty board outline; add default board outline if outline empty */
+ _CheckBoardOutline();
+
+ /* Epsilon_r, bulk resistivity and loss tangent overrides */
+ _UserOverrides();
+
+ return;
+}
+
+/*
+ * Write a pcb in pdf format
+ */
+
+void PCB::WritePDF (std::string filename, double hue, double saturation, double brightness)
+{
+ PDF pdf;
+ pdf.SetPalette(hue, saturation, brightness);
+ pdf.Write(filename, *this);
+}
+
+/*
+ * Write a pcb in csxcad format
+ */
+
+void PCB::WriteCSXCAD (std::string filename, bool pcb_outline, bool lossy_copper, bool metal_3d)
+{
+ CSXCAD csxcad;
+ csxcad.Write(filename, *this, pcb_outline, lossy_copper, metal_3d);
+}
+
+/*
+ * Set dielectric epsilon r. Overrides value in Hyperlynx file.
+ */
+
+void PCB::SetEpsilonR(double new_epsilon_r)
+{
+ /* save the new value of epsilon r. run before loading hyperlynx file. */
+ _epsilon_r = new_epsilon_r;
+ _epsilon_r_override = true;
+
+ return;
+}
+
+void PCB::SetLossTangent(double new_loss_tangent)
+{
+ /* save the new value of loss_tangent. run before loading hyperlynx file. */
+ _loss_tangent = new_loss_tangent;
+ _loss_tangent_override = true;
+ return;
+}
+
+void PCB::SetBulkResistance(double new_bulk_resistivity)
+{
+ /* save the new value of bulk_resistivity. run before loading hyperlynx file. */
+ _bulk_resistivity = new_bulk_resistivity;
+ _bulk_resistivity_override = true;
+ return;
+}
+
+/*
+ * Modify the value of epsilon r. Run after loading hyperlynx file.
+ */
+
+void PCB::_UserOverrides()
+{
+
+ /* set all layers to epsilon_r, except outer copper layers, which we assume are in air (er = 1) */
+
+ /* iterate over all layers, setting epsilon */
+ for (LayerList::iterator i = stackup.begin(); i != stackup.end(); ++i) {
+
+ /* override epsilon and loss tangent of dielectric layers */
+ if (_epsilon_r_override && (i->layer_type == LAYER_DIELECTRIC)) i->epsilon_r = _epsilon_r;
+ if (_loss_tangent_override && (i->layer_type == LAYER_DIELECTRIC)) i->loss_tangent = _loss_tangent;
+
+ /* override resistivity of metal layers */
+ if (_bulk_resistivity_override && (i->layer_type != LAYER_DIELECTRIC)) i->bulk_resistivity = _bulk_resistivity;
+
+ /* check for outer copper layer */
+ if (i->layer_type == LAYER_DIELECTRIC)
+ continue;
+
+ /* find dielectric layer above current metal layer */
+ bool upper_layer_found = false;
+ for (LayerList::iterator j = stackup.begin(); j != i; ++j)
+ if (j->layer_type == LAYER_DIELECTRIC) upper_layer_found = true;
+
+ /* find dielectric layer below current metal layer */
+ bool lower_layer_found = false;
+ for (LayerList::iterator j = i; j != stackup.end(); ++j)
+ if (j->layer_type == LAYER_DIELECTRIC) lower_layer_found = true;
+
+ /* assume outer copper layers are in air */
+ if (!upper_layer_found || !lower_layer_found) {
+ i->epsilon_r = 1.0;
+ i->loss_tangent = 0.0;
+ }
+ }
+ return;
+}
+
+/*
+ * set resolution of x and y coordinates
+ */
+
+void PCB::SetGrid(double new_grid)
+{
+ if (new_grid > 0.0) Polygon::SetGrid(new_grid);
+ return;
+}
+
+/*
+ * set maximum difference between perfect circle arc and polygonal approximation
+ */
+
+void PCB::SetArcPrecision(double new_arc_precision)
+{
+ if (new_arc_precision >= 0.0) _arc_precision = new_arc_precision;
+ return;
+}
+
+/*
+ * set track to plane clearance
+ */
+
+void PCB::SetClearance(double new_clearance)
+{
+ if (new_clearance >= 0.0) _clearance = new_clearance;
+ return;
+}
+
+/*
+ * Calculate the bounding rectangle of a pcb.
+ */
+
+Bounds PCB::GetBounds() {
+ Bounds bounds;
+ bounds.x_min = 0;
+ bounds.x_max = 0;
+ bounds.y_min = 0;
+ bounds.y_max = 0;
+ bounds.z_min = 0;
+ bounds.z_max = 0;
+
+ /* iterate over layers; find z_max and z_min */
+ if (!stackup.empty()) {
+ bounds.z_min = stackup.back().z0;
+ bounds.z_max = stackup.front().z1;
+ for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) {
+ if (l->z0 < bounds.z_min) bounds.z_min = l->z0;
+ if (l->z1 > bounds.z_max) bounds.z_max = l->z1;
+ }
+ }
+
+ /* iterate over board edge; find x_min, x_max, y_min, y_max */
+ bool first_point = true;
+
+ for (FloatPolygons::iterator i = board.begin(); i != board.end(); ++i)
+ for (FloatPolygon::iterator j = i->poly.begin(); j != i->poly.end(); ++j) {
+ if ((j->x > bounds.x_max) || first_point) bounds.x_max = j->x;
+ if ((j->y > bounds.y_max) || first_point) bounds.y_max = j->y;
+ if ((j->x < bounds.x_min) || first_point) bounds.x_min = j->x;
+ if ((j->y < bounds.y_min) || first_point) bounds.y_min = j->y;
+ first_point = false;
+ }
+
+ /* iterate over layers */
+ for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l)
+ for (FloatPolygons::iterator i = l->metal.begin(); i != l->metal.end(); ++i)
+ for (FloatPolygon::iterator j = i->poly.begin(); j != i->poly.end(); ++j) {
+ if ((j->x > bounds.x_max) || first_point) bounds.x_max = j->x;
+ if ((j->y > bounds.y_max) || first_point) bounds.y_max = j->y;
+ if ((j->x < bounds.x_min) || first_point) bounds.x_min = j->x;
+ if ((j->y < bounds.y_min) || first_point) bounds.y_min = j->y;
+ first_point = false;
+ }
+
+ /* iterate over vias */
+ for (ViaList::iterator i = via.begin(); i != via.end(); ++i) {
+ if ((i->x + i->radius > bounds.x_max) || first_point) bounds.x_max = i->x + i->radius;
+ if ((i->y + i->radius > bounds.y_max) || first_point) bounds.y_max = i->y + i->radius;
+ if ((i->x - i->radius < bounds.x_min) || first_point) bounds.x_min = i->x - i->radius;
+ if ((i->y - i->radius < bounds.y_min) || first_point) bounds.y_min = i->y - i->radius;
+ first_point = false;
+ }
+
+ return bounds;
+ }
+
+/*
+ * Set the bounding rectangle of a pcb.
+ */
+
+void PCB::SetBounds(Bounds new_bounds)
+{
+ _bounds = new_bounds;
+}
+
+void PCB::_CheckBoardOutline()
+{
+ if (!board.empty()) return;
+
+ if (debug) std::cerr << "board outline empty" << std::endl;
+
+ Bounds bounds = GetBounds();
+
+ if ((bounds.x_min != bounds.x_max) && (bounds.y_min != bounds.y_max)) {
+
+ if (debug) std::cerr << "adding default board outline" << std::endl;
+
+ /* add rectangular outline to pcb */
+
+ Hyp2Mat::FloatPoly outline;
+ outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_min, bounds.y_min));
+ outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_min, bounds.y_max));
+ outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_max, bounds.y_max));
+ outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_max, bounds.y_min));
+ outline.is_hole = false;
+ outline.nesting_level = 0;
+
+ board.push_back(outline);
+ }
+}
+
+void PCB::PrintSummary() {
+ Bounds bounds = GetBounds();
+
+ /* save stream flags and precision */
+ std::ios::fmtflags saved_flgs = std::cerr.flags();
+ std::streamsize saved_prec = std::cerr.precision();
+ std::cerr.flags(std::ios::fixed);
+ std::cerr.precision(2);
+
+ double m_to_mm = 1000;
+ std::cerr << "board size:" << std::endl;
+ std::cerr << " x = " << std::setw(8) << bounds.x_min*m_to_mm << " : " << std::setw(8) << bounds.x_max*m_to_mm << " mm" << std::endl;
+ std::cerr << " y = " << std::setw(8) << bounds.y_min*m_to_mm << " : " << std::setw(8) << bounds.y_max*m_to_mm << " mm" << std::endl;
+ std::cerr << " z = " << std::setw(8) << bounds.z_min*m_to_mm << " : " << std::setw(8) << bounds.z_max*m_to_mm << " mm" << std::endl;
+
+ std::cerr << "layers:" << std::endl;
+ if (stackup.empty()) std::cerr << "(none)";
+ for (LayerList::iterator it = stackup.begin(); it != stackup.end(); ++it) {
+ std::cerr << " ";
+ switch (it->layer_type) {
+ case LAYER_SIGNAL: std::cerr << "signal " << std::setw(8) << it->thickness * 1E6 << " um" ; break;
+ case LAYER_DIELECTRIC: std::cerr << "dielectric " << std::setw(8) << it->thickness * 1E3 << " mm" ; break;
+ case LAYER_PLANE: std::cerr << "plane " << std::setw(8) << it->thickness * 1E6 << " um" ; break;
+ default: std::cerr << "*** " << std::setw(8) << it->thickness * 1E3 << " mm" ; break;
+ }
+ std::cerr << " eps_r " << it->epsilon_r << " '" << it->layer_name << "'" << std::endl;
+ }
+
+ /* reset flags and precision */
+ std::cerr.flags(saved_flgs);
+ std::cerr.precision(saved_prec);
+
+ return;
+}
+
+/* not truncated */