delorie.com/archives/browse.cgi   search  
Mail Archives: geda-user/2014/06/12/23:30:26

X-Authentication-Warning: delorie.com: mail set sender to geda-user-bounces using -f
X-Recipient: geda-user AT delorie DOT com
X-Cam-AntiVirus: no malware found
X-Cam-ScannerInfo: http://www.cam.ac.uk/cs/email/scanner/
Message-ID: <1402630167.26608.5.camel@pcjc2lap>
Subject: [geda-user] First cut at file-format (and rendering) support for arc-segments
in polygon contours
From: Peter Clifton <peter DOT clifton AT clifton-electronics DOT co DOT uk>
To: geda-user AT delorie DOT com
Date: Fri, 13 Jun 2014 04:29:27 +0100
Organization: Clifton Electronics
X-Mailer: Evolution 3.10.4-0ubuntu1
Mime-Version: 1.0
Sender: "Peter C.J. Clifton" <pcjc2 AT hermes DOT cam DOT ac DOT uk>
Reply-To: geda-user AT delorie DOT com

--=-JNhRtckRCiqUODnUc5lN
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

Very first cut test... missing the following:

Save support
File format version bump
Sanity checking of new file syntax - somewhat different to our usual
Correct bounds update of the polygon, taking into account possible protrusion of arc-segments
Rendering the arc segments when dragging the polygon
Ability to edit / create these radiused features within PCB
Semantic tagging of the contours to allow STEP / gerber / IDF to use the true contour
Sane encapsulation of the data (right now, it adds to the PointType structure, because I was being lazy)
No checks for production of self-intersecting contours (these would go in the edit tool though).



-- 
Peter Clifton <peter DOT clifton AT clifton-electronics DOT co DOT uk>

Clifton Electronics

--=-JNhRtckRCiqUODnUc5lN
Content-Disposition: attachment;
	filename*0=0001-Add-support-for-arc-segments-in-polygon-object-outli.pat;
	filename*1=ch
Content-Type: text/x-patch;
	name="0001-Add-support-for-arc-segments-in-polygon-object-outli.patch";
	charset="UTF-8"
Content-Transfer-Encoding: 7bit

From 10f361d8421698208c3e877924b1f92faf477278 Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter AT clifton-electronics DOT co DOT uk>
Date: Fri, 13 Jun 2014 01:22:11 +0100
Subject: [PATCH] Add support for arc segments in polygon object outline
 definitions

Test with a polygon like this:

  Polygon("clearpoly")
  (
    [5.0000mm 7.0000mm included_angle: 90] [7.0000mm 5.0000mm]
    [28.000mm 5.0000mm included_angle: 90] [30.000mm 7.0000mm]
    [30.000mm 28.000mm included_angle: 90] [28.000mm 30.000mm]
    [7.0000mm 30.000mm included_angle: 90] [5.0000mm 28.000mm]
  )


NOTE THAT THE ARC BOUNDS ARE NOT YET INCLUDED IN THE BOUNDING BOX CALCULATION,
SO THIS WILL BREAK VARIOUS THINGS PRETTY HORRIBLY IF AN ARC PROTRUDES AS AN
EXTREME FEATURE IN EITHER THE +/-X or +/-Y DIRECTIONS.
---
 src/action.c           |   6 ++-
 src/copy.c             |   2 +-
 src/create.c           |  11 +++--
 src/create.h           |   2 +-
 src/global.h           |   2 +
 src/hid/common/hidgl.c |   2 +
 src/insert.c           |   2 +-
 src/parse_l.l          |   1 +
 src/parse_y.y          |  10 ++--
 src/polygon.c          | 131 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/polygon.h          |  17 +++++++
 11 files changed, 168 insertions(+), 18 deletions(-)

diff --git a/src/action.c b/src/action.c
index 5d2b4df..184cefa 100644
--- a/src/action.c
+++ b/src/action.c
@@ -1428,7 +1428,8 @@ NotifyMode (void)
 	  {
 	    CreateNewPointInPolygon (&Crosshair.AttachedPolygon,
 				     Crosshair.AttachedLine.Point2.X,
-				     Crosshair.AttachedLine.Point2.Y);
+				     Crosshair.AttachedLine.Point2.Y,
+				     0);
 
 	    /* copy the coordinates */
 	    Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X;
@@ -1519,7 +1520,8 @@ NotifyMode (void)
 		{
 		  CreateNewPointInPolygon (&Crosshair.AttachedPolygon,
 					   Crosshair.AttachedLine.Point2.X,
-					   Crosshair.AttachedLine.Point2.Y);
+					   Crosshair.AttachedLine.Point2.Y,
+					   0);
 
 		  /* copy the coordinates */
 		  Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X;
diff --git a/src/copy.c b/src/copy.c
index b0cd9c8..a580e8e 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -101,7 +101,7 @@ CopyPolygonLowLevel (PolygonType *Dest, PolygonType *Src)
           CreateNewHoleInPolygon (Dest);
           hole++;
         }
-      CreateNewPointInPolygon (Dest, Src->Points[n].X, Src->Points[n].Y);
+      CreateNewPointInPolygon (Dest, Src->Points[n].X, Src->Points[n].Y, Src->Points[n].included_angle);
     }
   SetPolygonBoundingBox (Dest);
   Dest->Flags = Src->Flags;
diff --git a/src/create.c b/src/create.c
index a1c8867..64a22ec 100644
--- a/src/create.c
+++ b/src/create.c
@@ -576,10 +576,10 @@ CreateNewPolygonFromRectangle (LayerType *Layer,
   if (!polygon)
     return (polygon);
 
-  CreateNewPointInPolygon (polygon, X1, Y1);
-  CreateNewPointInPolygon (polygon, X2, Y1);
-  CreateNewPointInPolygon (polygon, X2, Y2);
-  CreateNewPointInPolygon (polygon, X1, Y2);
+  CreateNewPointInPolygon (polygon, X1, Y1, 0);
+  CreateNewPointInPolygon (polygon, X2, Y1, 0);
+  CreateNewPointInPolygon (polygon, X2, Y2, 0);
+  CreateNewPointInPolygon (polygon, X1, Y2, 0);
   SetPolygonBoundingBox (polygon);
   if (!Layer->polygon_tree)
     Layer->polygon_tree = r_create_tree (NULL, 0, 0);
@@ -644,13 +644,14 @@ CreateNewPolygon (LayerType *Layer, FlagType Flags)
  * creates a new point in a polygon
  */
 PointType *
-CreateNewPointInPolygon (PolygonType *Polygon, Coord X, Coord Y)
+CreateNewPointInPolygon (PolygonType *Polygon, Coord X, Coord Y, Angle included_angle)
 {
   PointType *point = GetPointMemoryInPolygon (Polygon);
 
   /* copy values */
   point->X = X;
   point->Y = Y;
+  point->included_angle = included_angle;
   point->ID = ID++;
   return (point);
 }
diff --git a/src/create.h b/src/create.h
index fa49a1b..5b6cfdd 100644
--- a/src/create.h
+++ b/src/create.h
@@ -51,7 +51,7 @@ ArcType * CreateNewArcOnLayer (LayerType *, Coord, Coord, Coord, Coord, Angle, A
 PolygonType * CreateNewPolygonFromRectangle (LayerType *, Coord, Coord, Coord, Coord, FlagType);
 TextType * CreateNewText (LayerType *, FontType *, Coord, Coord, unsigned, int, char *, FlagType);
 PolygonType * CreateNewPolygon (LayerType *, FlagType);
-PointType * CreateNewPointInPolygon (PolygonType *, Coord, Coord);
+PointType * CreateNewPointInPolygon (PolygonType *, Coord, Coord, Angle included_angle);
 PolygonType * CreateNewHoleInPolygon (PolygonType *polygon);
 void RefdesMapInit (void);
 ElementType * CreateNewElement (DataType *, FontType *, FlagType, char *, char *, char *, Coord, Coord, BYTE, int, FlagType, bool);
diff --git a/src/global.h b/src/global.h
index 8a0d6ee..6e4bd9c 100644
--- a/src/global.h
+++ b/src/global.h
@@ -236,8 +236,10 @@ typedef struct			/* a line/polygon point */
 {
   Coord X, Y, X2, Y2;	/* so Point type can be cast as BoxType */
   long int ID;
+  Angle included_angle;
 } PointType;
 
+
 /* Lines, rats, pads, etc.  */
 typedef struct {
   ANYLINEFIELDS;
diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
index 0c4ac20..559365c 100644
--- a/src/hid/common/hidgl.c
+++ b/src/hid/common/hidgl.c
@@ -749,10 +749,12 @@ fill_contour (PLINE *contour)
   borast_traps_t traps;
 
   /* If the contour is round, then call hidgl_fill_circle to draw it. */
+#if 0
   if (contour->is_round) {
     hidgl_fill_circle (contour->cx, contour->cy, contour->radius);
     return;
   }
+#endif
 
   /* If we don't have a cached set of tri-strips, compute them */
   if (contour->tristrip_vertices == NULL) {
diff --git a/src/insert.c b/src/insert.c
index a254998..8868d8b 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -180,7 +180,7 @@ InsertPointIntoPolygon (LayerType *Layer, PolygonType *Polygon)
    */
   ErasePolygon (Polygon);
   r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
-  save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
+  save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY, 0);
   for (n = Polygon->PointN - 1; n > InsertAt; n--)
     Polygon->Points[n] = Polygon->Points[n - 1];
 
diff --git a/src/parse_l.l b/src/parse_l.l
index 4f64880..a4e0a05 100644
--- a/src/parse_l.l
+++ b/src/parse_l.l
@@ -123,6 +123,7 @@ Groups		{ return(T_GROUPS); }
 Styles		{ return(T_STYLES); }
 Polygon		{ return(T_POLYGON); }
 Hole		{ return(T_POLYGON_HOLE); }
+included_angle: { return(T_INCLUDED_ANGLE); }
 Arc		{ return(T_ARC); }
 NetList		{ return(T_NETLIST); }
 Net		{ return(T_NET); }
diff --git a/src/parse_y.y b/src/parse_y.y
index 6cd4c7b..8e2225c 100644
--- a/src/parse_y.y
+++ b/src/parse_y.y
@@ -119,7 +119,7 @@ static Coord new_units (PLMeasure m);
 
 %token	T_FILEVERSION T_PCB T_LAYER T_VIA T_RAT T_LINE T_ARC T_RECTANGLE T_TEXT T_ELEMENTLINE
 %token	T_ELEMENT T_PIN T_PAD T_GRID T_FLAGS T_SYMBOL T_SYMBOLLINE T_CURSOR
-%token	T_ELEMENTARC T_MARK T_GROUPS T_STYLES T_POLYGON T_POLYGON_HOLE T_NETLIST T_NET T_CONN
+%token	T_ELEMENTARC T_MARK T_GROUPS T_STYLES T_POLYGON T_POLYGON_HOLE T_INCLUDED_ANGLE T_NETLIST T_NET T_CONN
 %token	T_AREA T_THERMAL T_DRC T_ATTRIBUTE
 %token	T_UMIL T_CMIL T_MIL T_IN T_NM T_UM T_MM T_M T_KM T_PX
 %type	<integer>	symbolid
@@ -1184,11 +1184,15 @@ polygonpoint
 			/* xcoord ycoord */
 		: '(' measure measure ')'
 			{
-				CreateNewPointInPolygon(Polygon, OU ($2), OU ($3));
+				CreateNewPointInPolygon(Polygon, OU ($2), OU ($3), 0);
 			}
 		| '[' measure measure ']'
 			{
-				CreateNewPointInPolygon(Polygon, NU ($2), NU ($3));
+				CreateNewPointInPolygon(Polygon, NU ($2), NU ($3), 0);
+			}
+		| '[' measure measure T_INCLUDED_ANGLE number ']'
+			{
+				CreateNewPointInPolygon(Polygon, NU ($2), NU ($3), $5);
 			}
 		;
 
diff --git a/src/polygon.c b/src/polygon.c
index 4623b52..13aac8e 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -111,6 +111,7 @@ dicer output is used for HIDs which cannot render things with holes
 #define SUBTRACT_LINE_BATCH_SIZE 20
 
 static double rotate_circle_seg[4];
+static double bw_rotate_circle_seg[4];
 
 void
 polygon_init (void)
@@ -120,6 +121,9 @@ polygon_init (void)
 
   rotate_circle_seg[0] = cos_ang;  rotate_circle_seg[1] = -sin_ang;
   rotate_circle_seg[2] = sin_ang;  rotate_circle_seg[3] =  cos_ang;
+
+  bw_rotate_circle_seg[0] =  cos_ang;  bw_rotate_circle_seg[1] =  sin_ang;
+  bw_rotate_circle_seg[2] = -sin_ang;  bw_rotate_circle_seg[3] =  cos_ang;
 }
 
 Cardinal
@@ -273,6 +277,51 @@ ContourToPoly (PLINE * contour)
   return p;
 }
 
+static void
+degree_circle (PLINE * c, Coord X, Coord Y /* <- Center */, Vector v /* First point, already laid by caller */, Angle sweep)
+{
+  /* We don't re-add a point at v, nor do we add the last point, sweep degrees around from (X,Y)-v */
+  double e1, e2, t1;
+  int i, range;
+
+//  poly_InclVertex (c->head.prev, poly_CreateNode (v));
+
+  /* move vector to origin */
+  e1 = (v[0] - X) * POLY_CIRC_RADIUS_ADJ;
+  e2 = (v[1] - Y) * POLY_CIRC_RADIUS_ADJ;
+
+  if (sweep > 0)
+    {
+      /* NB: the caller added the first vertex, and will add the last vertex, hence the -1 */
+      range = POLY_CIRC_SEGS * sweep / 360 - 1;
+      for (i = 0; i < range; i++)
+        {
+          /* rotate the vector */
+          t1 = rotate_circle_seg[0] * e1 + rotate_circle_seg[1] * e2;
+          e2 = rotate_circle_seg[2] * e1 + rotate_circle_seg[3] * e2;
+          e1 = t1;
+          v[0] = X + ROUND (e1);
+          v[1] = Y + ROUND (e2);
+          poly_InclVertex (c->head.prev, poly_CreateNode (v));
+        }
+    }
+  else
+    {
+      /* NB: the caller added the first vertex, and will add the last vertex, hence the -1 */
+      range = POLY_CIRC_SEGS * -sweep / 360 - 1;
+      for (i = 0; i < range; i++)
+        {
+          /* rotate the vector */
+          t1 = bw_rotate_circle_seg[0] * e1 + bw_rotate_circle_seg[1] * e2;
+          e2 = bw_rotate_circle_seg[2] * e1 + bw_rotate_circle_seg[3] * e2;
+          e1 = t1;
+          v[0] = X + ROUND (e1);
+          v[1] = Y + ROUND (e2);
+          poly_InclVertex (c->head.prev, poly_CreateNode (v));
+        }
+    }
+}
+
 static POLYAREA *
 original_poly (PolygonType * p)
 {
@@ -291,8 +340,7 @@ original_poly (PolygonType * p)
       /* No current contour? Make a new one starting at point */
       /*   (or) Add point to existing contour */
 
-      v[0] = p->Points[n].X;
-      v[1] = p->Points[n].Y;
+      v[0] = p->Points[n].X, v[1] = p->Points[n].Y;
       if (contour == NULL)
         {
           if ((contour = poly_NewContour (v)) == NULL)
@@ -303,6 +351,77 @@ original_poly (PolygonType * p)
           poly_InclVertex (contour->head.prev, poly_CreateNode (v));
         }
 
+      if (p->Points[n].included_angle != 0)
+        {
+          Cardinal next_n;
+          Coord px, py;
+          Coord nx, ny;
+          Coord hx, hy;
+          Coord cx, cy;
+          double p_to_h_dist;
+          double c_to_h_dist;
+          double unit_hcx, unit_hcy;
+
+          next_n = n + 1;
+          if (next_n == p->PointN ||
+              (hole < p->HoleIndexN && next_n == p->HoleIndex[hole]))
+            next_n = (hole == 0) ? 0 : p->HoleIndex[hole - 1];
+
+          /* XXX: Compute center of arc */
+
+          px = p->Points[     n].X, py = p->Points[     n].Y;
+          nx = p->Points[next_n].X, ny = p->Points[next_n].Y;
+
+          /* Find the point halfway between the to points the arc spans */
+          hx = px + (nx - px) / 2;
+          hy = py + (ny - py) / 2;
+
+          /* The arc center lies on a line passing through hx, hy, perpendicular
+           * to the direction between our two end-points.
+           *
+           *              n
+           *            / |
+           *          /   |h
+           *    -----c----|-------------- line passing (hx, hy), perpendicular to p[n]-p[next_n]
+           *          \   |
+           *            \ |
+           *              p
+           *
+           *  Find cx, cy.
+           *
+           *  We know that c-p[n] = radius. (But we don't know that radius).
+           *  We have the included angle, /_ p[n].c.p[next_n]
+           *  |(hx,hy)-p[n]| = sin(angle/2) * radius
+           *
+           * tan(ang/2) = |(hx,hy)-p[n]| / |(hx,hy)-(cx,cy)|
+           *
+           * |(hx,hy)-(cx,cy)| = |(hx,hy)-p[n]| / tan(ang/2)
+           *
+           */
+
+          p_to_h_dist = sqrt (pow(nx - py, 2) + pow (ny - py, 2)) / 2.;
+          c_to_h_dist = p_to_h_dist / tan (TO_RADIANS (p->Points[n].included_angle) / 2.);
+
+          unit_hcx = (float)-(hy - py) / p_to_h_dist;
+          unit_hcy = (float)(hx - px) / p_to_h_dist;
+
+          cx = hx + unit_hcx * c_to_h_dist;
+          cy = hy + unit_hcy * c_to_h_dist;
+
+#if 0 /* DEBUG TO SHOW THE CENTER OF THE ARC */
+          v[0] = cx, v[1] = cy;
+          poly_InclVertex (contour->head.prev, poly_CreateNode (v));
+          v[0] = p->Points[n].X, v[1] = p->Points[n].Y;
+#endif
+
+          degree_circle (contour, cx, cy, v, p->Points[n].included_angle);
+
+#if 0 /* DEBUG TO SHOW THE CENTER OF THE ARC */
+          v[0] = cx, v[1] = cy;  /* DEBUG TO SHOW THE CENTER OF THE ARC */
+          poly_InclVertex (contour->head.prev, poly_CreateNode (v));
+#endif
+        }
+
       /* Is current point last in contour? If so process it. */
       if (n == p->PointN - 1 ||
           (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
@@ -419,6 +538,7 @@ frac_circle (PLINE * c, Coord X, Coord Y, Vector v, int fraction)
     }
 }
 
+
 /* create a circle approximation from lines */
 POLYAREA *
 CirclePoly (Coord x, Coord y, Coord radius)
@@ -1837,9 +1957,9 @@ MorphPolygon (LayerType *layer, PolygonType *poly)
             return false;
           many = true;
           v = &p->contours->head;
-          CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
+          CreateNewPointInPolygon (newone, v->point[0], v->point[1], 0);
           for (v = v->next; v != &p->contours->head; v = v->next)
-            CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
+            CreateNewPointInPolygon (newone, v->point[0], v->point[1], 0);
           newone->BoundingBox.X1 = p->contours->xmin;
           newone->BoundingBox.X2 = p->contours->xmax + 1;
           newone->BoundingBox.Y1 = p->contours->ymin;
@@ -1951,7 +2071,8 @@ PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer,
           do
             {
               CreateNewPointInPolygon (Polygon, node->point[0],
-                                                node->point[1]);
+                                                node->point[1],
+                                                0);
             }
           while ((node = node->next) != &pline->head);
 
diff --git a/src/polygon.h b/src/polygon.h
index a02fd99..369efea 100644
--- a/src/polygon.h
+++ b/src/polygon.h
@@ -37,11 +37,28 @@
 #define POLY_CIRC_SEGS 40
 #define POLY_CIRC_SEGS_F ((float)POLY_CIRC_SEGS)
 
+#if 0
+/* THIS IS BROKEN:
+ *
+ * IT BREAKS THE CIRCULARITY OF CIRULAR CONTORS, AS THE FIRST
+ * FIRST VERTEX ADDED BY CirclePoly IS NOT RADIUS ADJUSTED.
+ *
+ * IT BREAKS CIRCULARITY OF ALIGMENT BETWEEN A LINE AND ITS END-CAPS,
+ * LEADING TO MORE COMPLEX CONTOURS FOR COMMON LINE-LINE INTERSECTIONS,
+ * SUCH AS 90 AND 45 DEGREE ANGLES
+ *
+ * IT WAS INTENDED TO AVOID DRC ERRORS WITH "TOO-CLOSE" FEATURES,
+ * BUT COULD OTHERWISE CAUSE THEM FOR "TOO THIN" FEATURES - INSIDE/OUTSIDE
+ * CONTOUR APPROXIMATION NEEDS TO BE CONTROLED DEPENDING ON THE REQUIREMENT
+ */
 /* adjustment to make the segments outline the circle rather than connect
  * points on the circle: 1 - cos (\alpha / 2) < (\alpha / 2) ^ 2 / 2
  */
 #define POLY_CIRC_RADIUS_ADJ (1.0 + M_PI / POLY_CIRC_SEGS_F * \
                                     M_PI / POLY_CIRC_SEGS_F / 2.0)
+#else
+#define POLY_CIRC_RADIUS_ADJ 1.0
+#endif
 
 /* polygon diverges from modelled arc no more than MAX_ARC_DEVIATION * thick */
 #define POLY_ARC_MAX_DEVIATION 0.02
-- 
1.9.1


--=-JNhRtckRCiqUODnUc5lN--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019