summaryrefslogtreecommitdiff
path: root/hyp2mat/lib/draw.cc
diff options
context:
space:
mode:
Diffstat (limited to 'hyp2mat/lib/draw.cc')
-rw-r--r--hyp2mat/lib/draw.cc296
1 files changed, 296 insertions, 0 deletions
diff --git a/hyp2mat/lib/draw.cc b/hyp2mat/lib/draw.cc
new file mode 100644
index 0000000..0de9634
--- /dev/null
+++ b/hyp2mat/lib/draw.cc
@@ -0,0 +1,296 @@
+/*
+ * 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 the Clipper library from Angus Johnson to do polygon arithmetic
+ */
+
+#include <iostream>
+#include <cstdio>
+#include <cmath>
+#include "hypfile.h"
+
+using namespace std;
+using namespace HypFile;
+
+/*
+ * Polygon constructor
+ */
+
+Polygon::Polygon()
+{
+ vertex.clear();
+ polygon_type = POLYGON_TYPE_COPPER;
+ id = -1;
+ positive = true; /* is a polygon, not a hole */
+ width = 0.0;
+ plane_separation = -1.0; /* negative if not set */
+ left_plane_separation = -1.0; /* negative if not set */
+ net_name.clear();
+ layer_name.clear();
+}
+
+/*
+ * Draw an arc from (x1, y1) to (x2, y2) with center (xc, yc) and radius r using a polygonal approximation.
+ * Arc may be clockwise or counterclockwise.
+ */
+
+Polygon HypFile::Hyp::arc2poly(double x1, double y1, double x2, double y2, double xc, double yc, double r, bool clockwise)
+{
+
+ Polygon arc_segment;
+ arc_segment.width = 0;
+ arc_segment.positive = true;
+ arc_segment.layer_name = "";
+
+ int poly_points = 0;
+
+ double alpha = atan2(y1-yc, x1-xc);
+ double beta = atan2(y2-yc, x2-xc);
+
+
+ if (clockwise) {
+ // draw arc clockwise from (x1,y1) to (x2,y2)
+ if (alpha < beta)
+ alpha = alpha + 2 * pi;
+ }
+ else {
+ // draw arc counterclockwise from (x1,y1) to (x2,y2)
+ if (beta < alpha)
+ beta = beta + 2 * pi;
+ // draw a circle if starting and end points are the same
+ if ((x1 == x2) && (y1 == y2))
+ beta = alpha + 2 * pi;
+ }
+
+ // Calculate number of segments needed for a full circle.
+ int segments = min_circle_segments;
+
+ if (arc_precision > 0) {
+ // Increase number of segments until difference between circular arc
+ // and polygonal approximation is less than max_arc_error
+
+ double arc_error;
+ do {
+ arc_error = r * (1 - cos(pi/segments));
+ if (arc_error > arc_precision) segments += 4;
+ }
+ while (arc_error > arc_precision);
+
+ }
+ else if (arc_precision < 0)
+ error("error: negative arc precision");
+
+ // A full circle is drawn using 'segments' segments; a 90 degree arc using segments/4.
+ poly_points = round(segments*abs(beta-alpha)/(2*pi));
+
+ // Sanity checks
+ if (poly_points < 1) poly_points = 1;
+
+ // first point
+ arc_segment.vertex.push_back(Point(x1, y1));
+
+ // intermediate points
+ for (int i = 1; i < poly_points ; i++) {
+ double angle = alpha + (beta - alpha) * i / poly_points;
+ double x = xc + r * cos(angle);
+ double y = yc + r * sin(angle);
+ arc_segment.vertex.push_back(Point(x, y));
+ }
+
+ // last point
+ arc_segment.vertex.push_back(Point(x2, y2));
+
+ return arc_segment;
+}
+
+/*
+ * Draws straight metal trace segment as a polygon.
+ */
+
+Polygon HypFile::Hyp::segment2poly(double x1, double y1, double x2, double y2, double width)
+{
+/*
+ * Note a hyperlynx line segment is drawn, ending in two half-circles:
+ * ------------------------------- ^
+ * / \ |
+ * | | width
+ * \ / |
+ * ------------------------------- V
+ *
+ * <----------- length ---------->
+ */
+
+ Polygon line_segment;
+ line_segment.width = 0;
+ line_segment.positive = true;
+ line_segment.layer_name = "";
+
+ /* Sanity check */
+ double dx;
+ double dy;
+ if (( x1 == x2) && (y2 == y1)) {
+ dx = width/2;
+ dy = 0;
+ }
+ else {
+ double length = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
+ dx = width / 2 * (y2 - y1) / length;
+ dy = width / 2 * (x2 - x1) / length;
+ }
+
+ Polygon arc2 = arc2poly(x2 + dx, y2 - dy, x2 - dx, y2 + dy, x2, y2, width/2, false);
+ Polygon arc1 = arc2poly(x1 - dx, y1 + dy, x1 + dx, y1 - dy, x1, y1, width/2, false);
+
+ line_segment.vertex = arc2.vertex;
+ line_segment.vertex.insert(line_segment.vertex.end(), arc1.vertex.begin(), arc1.vertex.end());
+
+ return line_segment;
+}
+
+/*
+ * Convert a pad to a polygon
+ */
+
+Polygon HypFile::Hyp::pad2poly(double pad_x, double pad_y, Pad pad)
+{
+ Polygon pad_poly;
+ pad_poly.width = 0;
+ pad_poly.layer_name = pad.layer_name;
+ pad_poly.positive = true;
+ if (pad.pad_type == PAD_TYPE_ANTIPAD) pad_poly.polygon_type = POLYGON_TYPE_ANTIPAD;
+ else pad_poly.polygon_type = POLYGON_TYPE_PAD;
+
+ double sx = pad.pad_sx;
+ double sy = pad.pad_sy;
+ double angle = pad.pad_angle;
+
+ if (fmod(angle, 180) == 0) angle = 0;
+ else if (fmod(angle, 90) == 0) {
+ double t;
+ t = sx;
+ sx = sy;
+ sy = t;
+ angle = 0;
+ }
+
+ /*
+ * Circular and oval pads
+ */
+
+ if (pad.pad_shape == PAD_SHAPE_OVAL) {
+ /* calculate number of segments needed */
+ int segments = min_circle_segments;
+ if (arc_precision > 0) {
+ /* Increase number of segments until difference between oval
+ and polygonal approximation is less than max_arc_error */
+ double arc_error_x;
+ double arc_error_y;
+ do {
+ arc_error_x = sx / 2 * (1 - cos(pi/segments));
+ arc_error_y = sy / 2 * (1 - cos(pi/segments));
+ if ((arc_error_x > arc_precision) || (arc_error_y > arc_precision)) segments += 4;
+ }
+ while ((arc_error_x > arc_precision) || (arc_error_y > arc_precision));
+ }
+ /* calculate points */
+ for (int i = 0; i < segments; i++) {
+ double alpha = 2 * pi * i / segments;
+ double x = sx / 2 / cos(pi / segments) * cos(alpha);
+ double y = sy / 2 / cos(pi / segments) * sin(alpha);
+ pad_poly.vertex.push_back(Point(x, y));
+ }
+ }
+
+ /*
+ * Square and rectangular pads
+ */
+
+ else if (pad.pad_shape == PAD_SHAPE_RECTANGULAR) {
+ pad_poly.vertex.push_back(Point( sx/2, sy/2));
+ pad_poly.vertex.push_back(Point( sx/2, -sy/2));
+ pad_poly.vertex.push_back(Point(-sx/2, -sy/2));
+ pad_poly.vertex.push_back(Point(-sx/2, sy/2));
+ }
+
+ /*
+ * Oblong pads
+ */
+
+ else if (pad.pad_shape == PAD_SHAPE_OBLONG) {
+ if (sx > sy) {
+ /* horizontal oblong pad */
+ double x1 = (sx - sy)/2;
+ double y1 = -sy/2;
+ double x2 = x1;
+ double y2 = -y1;
+ double xc = (sx - sy)/2;
+ double yc = 0;
+ double r = sy/2;
+ Polygon arc_right = arc2poly(x1, y1, x2, y2, xc, yc, r, false);
+ Polygon arc_left = arc2poly(-x1, -y1, -x2, -y2, -xc, -yc, r, false);
+ pad_poly.vertex = arc_right.vertex;
+ pad_poly.vertex.insert(pad_poly.vertex.end(), arc_left.vertex.begin(), arc_left.vertex.end());
+ }
+ else {
+ /* vertical oblong pad */
+ double x1 = sx/2;
+ double y1 = (sy - sx)/2;
+ double x2 = -x1;
+ double y2 = y1;
+ double xc = 0;
+ double yc = (sy-sx)/2;
+ double r = sx/2;
+ Polygon arc_top = arc2poly(x1, y1, x2, y2, xc, yc, r, false);
+ Polygon arc_bottom = arc2poly(-x1, -y1, -x2, -y2, -xc, -yc, r, false);
+ pad_poly.vertex = arc_top.vertex;
+ pad_poly.vertex.insert(pad_poly.vertex.end(), arc_bottom.vertex.begin(), arc_bottom.vertex.end());
+ }
+ }
+
+ /*
+ * Unknown pad shape
+ */
+
+ else error("unknown pad shape");
+
+ /* Rotate polygon over pad rotation angle */
+ if (angle != 0) {
+ double cosa = cos(angle * pi / 180);
+ double sina = sin(angle * pi / 180);
+ for (PointList::iterator i = pad_poly.vertex.begin(); i != pad_poly.vertex.end(); ++i) {
+ double x_rot = cosa * i->x - sina * i->y ;
+ double y_rot = sina * i->x + cosa * i->y ;
+ i->x = x_rot;
+ i->y = y_rot;
+ }
+ }
+
+ /* Translate polygon to pad center */
+ for (PointList::iterator i = pad_poly.vertex.begin(); i != pad_poly.vertex.end(); ++i) {
+ i->x += pad_x;
+ i->y += pad_y;
+ }
+
+ /* return pad converted to polygon */
+ return pad_poly;
+}
+
+/* not truncated */