pcb 4.1.1
An interactive printed circuit board layout editor.

polygon.c

Go to the documentation of this file.
00001 
00079 #ifdef HAVE_CONFIG_H
00080 #include "config.h"
00081 #endif
00082 
00083 #include <assert.h>
00084 #include <math.h>
00085 #include <memory.h>
00086 #include <setjmp.h>
00087 
00088 #include "global.h"
00089 #include "box.h"
00090 #include "create.h"
00091 #include "crosshair.h"
00092 #include "data.h"
00093 #include "draw.h"
00094 #include "error.h"
00095 #include "find.h"
00096 #include "misc.h"
00097 #include "move.h"
00098 #include "pcb-printf.h"
00099 #include "polygon.h"
00100 #include "remove.h"
00101 #include "rtree.h"
00102 #include "search.h"
00103 #include "set.h"
00104 #include "thermal.h"
00105 #include "undo.h"
00106 
00107 #ifdef HAVE_LIBDMALLOC
00108 #include <dmalloc.h>
00109 #endif
00110 
00111 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5  : (x) - 0.5)))
00112 
00113 #define UNSUBTRACT_BLOAT 10
00114 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100
00115 #define SUBTRACT_LINE_BATCH_SIZE 20
00116 
00117 static double rotate_circle_seg[4];
00118 
00119 void
00120 polygon_init (void)
00121 {
00122   double cos_ang = cos (2.0 * M_PI / POLY_CIRC_SEGS_F);
00123   double sin_ang = sin (2.0 * M_PI / POLY_CIRC_SEGS_F);
00124 
00125   rotate_circle_seg[0] = cos_ang;  rotate_circle_seg[1] = -sin_ang;
00126   rotate_circle_seg[2] = sin_ang;  rotate_circle_seg[3] =  cos_ang;
00127 }
00128 
00129 Cardinal
00130 polygon_point_idx (PolygonType *polygon, PointType *point)
00131 {
00132   assert (point >= polygon->Points);
00133   assert (point <= polygon->Points + polygon->PointN);
00134   return ((char *)point - (char *)polygon->Points) / sizeof (PointType);
00135 }
00136 
00144 Cardinal
00145 polygon_point_contour (PolygonType *polygon, Cardinal point)
00146 {
00147   Cardinal i;
00148   Cardinal contour = 0;
00149 
00150   for (i = 0; i < polygon->HoleIndexN; i++)
00151     if (point >= polygon->HoleIndex[i])
00152       contour = i + 1;
00153   return contour;
00154 }
00155 
00156 Cardinal
00157 next_contour_point (PolygonType *polygon, Cardinal point)
00158 {
00159   Cardinal contour;
00160   Cardinal this_contour_start;
00161   Cardinal next_contour_start;
00162 
00163   contour = polygon_point_contour (polygon, point);
00164 
00165   this_contour_start = (contour == 0) ? 0 :
00166                                         polygon->HoleIndex[contour - 1];
00167   next_contour_start =
00168     (contour == polygon->HoleIndexN) ? polygon->PointN :
00169                                        polygon->HoleIndex[contour];
00170 
00171   /* Wrap back to the start of the contour we're in if we pass the end */
00172   if (++point == next_contour_start)
00173     point = this_contour_start;
00174 
00175   return point;
00176 }
00177 
00178 Cardinal
00179 prev_contour_point (PolygonType *polygon, Cardinal point)
00180 {
00181   Cardinal contour;
00182   Cardinal prev_contour_end;
00183   Cardinal this_contour_end;
00184 
00185   contour = polygon_point_contour (polygon, point);
00186 
00187   prev_contour_end = (contour == 0) ? 0 :
00188                                       polygon->HoleIndex[contour - 1];
00189   this_contour_end =
00190     (contour == polygon->HoleIndexN) ? polygon->PointN - 1:
00191                                        polygon->HoleIndex[contour] - 1;
00192 
00193   /* Wrap back to the start of the contour we're in if we pass the end */
00194   if (point == prev_contour_end)
00195     point = this_contour_end;
00196   else
00197     point--;
00198 
00199   return point;
00200 }
00201 
00202 static void
00203 add_noholes_polyarea (PLINE *pline, void *user_data)
00204 {
00205   PolygonType *poly = (PolygonType *)user_data;
00206 
00207   /* Prepend the pline into the NoHoles linked list */
00208   pline->next = poly->NoHoles;
00209   poly->NoHoles = pline;
00210 }
00211 
00212 void
00213 ComputeNoHoles (PolygonType *poly)
00214 {
00215   poly_FreeContours (&poly->NoHoles);
00216   if (poly->Clipped)
00217     NoHolesPolygonDicer (poly, NULL, add_noholes_polyarea, poly);
00218   else
00219     printf ("Compute_noholes caught poly->Clipped = NULL\n");
00220   poly->NoHolesValid = 1;
00221 }
00222 
00223 static POLYAREA *
00224 biggest (POLYAREA * p)
00225 {
00226   POLYAREA *n, *top = NULL;
00227   PLINE *pl;
00228   rtree_t *tree;
00229   double big = -1;
00230   if (!p)
00231     return NULL;
00232   n = p;
00233   do
00234     {
00235 #if 0
00236       if (n->contours->area < PCB->IsleArea)
00237         {
00238           n->b->f = n->f;
00239           n->f->b = n->b;
00240           poly_DelContour (&n->contours);
00241           if (n == p)
00242             p = n->f;
00243           n = n->f;
00244           if (!n->contours)
00245             {
00246               free (n);
00247               return NULL;
00248             }
00249         }
00250 #endif
00251       if (n->contours->area > big)
00252         {
00253           top = n;
00254           big = n->contours->area;
00255         }
00256     }
00257   while ((n = n->f) != p);
00258   assert (top);
00259   if (top == p)
00260     return p;
00261   pl = top->contours;
00262   tree = top->contour_tree;
00263   top->contours = p->contours;
00264   top->contour_tree = p->contour_tree;
00265   p->contours = pl;
00266   p->contour_tree = tree;
00267   assert (pl);
00268   assert (p->f);
00269   assert (p->b);
00270   return p;
00271 }
00272 
00273 POLYAREA *
00274 ContourToPoly (PLINE * contour)
00275 {
00276   POLYAREA *p;
00277   poly_PreContour (contour, TRUE);
00278   assert (contour->Flags.orient == PLF_DIR);
00279   if (!(p = poly_Create ()))
00280     return NULL;
00281   poly_InclContour (p, contour);
00282   assert (poly_Valid (p));
00283   return p;
00284 }
00285 
00286 static POLYAREA *
00287 original_poly (PolygonType * p)
00288 {
00289   PLINE *contour = NULL;
00290   POLYAREA *np = NULL;
00291   Cardinal n;
00292   Vector v;
00293   int hole = 0;
00294 
00295   if ((np = poly_Create ()) == NULL)
00296     return NULL;
00297 
00298   /* first make initial polygon contour */
00299   for (n = 0; n < p->PointN; n++)
00300     {
00301       /* No current contour? Make a new one starting at point */
00302       /*   (or) Add point to existing contour */
00303 
00304       v[0] = p->Points[n].X;
00305       v[1] = p->Points[n].Y;
00306       if (contour == NULL)
00307         {
00308           if ((contour = poly_NewContour (v)) == NULL)
00309             return NULL;
00310         }
00311       else
00312         {
00313           poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00314         }
00315 
00316       /* Is current point last in contour? If so process it. */
00317       if (n == p->PointN - 1 ||
00318           (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
00319         {
00320           poly_PreContour (contour, TRUE);
00321 
00322           /* make sure it is a positive contour (outer) or negative (hole) */
00323           if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR))
00324             poly_InvContour (contour);
00325           assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR));
00326 
00327           poly_InclContour (np, contour);
00328           contour = NULL;
00329           assert (poly_Valid (np));
00330 
00331           hole++;
00332         }
00333   }
00334   return biggest (np);
00335 }
00336 
00337 POLYAREA *
00338 PolygonToPoly (PolygonType *p)
00339 {
00340   return original_poly (p);
00341 }
00342 
00343 POLYAREA *
00344 RectPoly (Coord x1, Coord x2, Coord y1, Coord y2)
00345 {
00346   PLINE *contour = NULL;
00347   Vector v;
00348 
00349   /* Return NULL for zero or negatively sized rectangles */
00350   if (x2 <= x1 || y2 <= y1)
00351     return NULL;
00352 
00353   v[0] = x1;
00354   v[1] = y1;
00355   if ((contour = poly_NewContour (v)) == NULL)
00356     return NULL;
00357   v[0] = x2;
00358   v[1] = y1;
00359   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00360   v[0] = x2;
00361   v[1] = y2;
00362   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00363   v[0] = x1;
00364   v[1] = y2;
00365   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00366   return ContourToPoly (contour);
00367 }
00368 
00369 POLYAREA *
00370 OctagonPoly (Coord x, Coord y, Coord radius)
00371 {
00372   PLINE *contour = NULL;
00373   Vector v;
00374 
00375   v[0] = x + ROUND (radius * 0.5);
00376   v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2);
00377   if ((contour = poly_NewContour (v)) == NULL)
00378     return NULL;
00379   v[0] = x + ROUND (radius * TAN_22_5_DEGREE_2);
00380   v[1] = y + ROUND (radius * 0.5);
00381   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00382   v[0] = x - (v[0] - x);
00383   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00384   v[0] = x - ROUND (radius * 0.5);
00385   v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2);
00386   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00387   v[1] = y - (v[1] - y);
00388   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00389   v[0] = x - ROUND (radius * TAN_22_5_DEGREE_2);
00390   v[1] = y - ROUND (radius * 0.5);
00391   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00392   v[0] = x - (v[0] - x);
00393   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00394   v[0] = x + ROUND (radius * 0.5);
00395   v[1] = y - ROUND (radius * TAN_22_5_DEGREE_2);
00396   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00397   return ContourToPoly (contour);
00398 }
00399 
00409 void
00410 frac_circle (PLINE * c, Coord X, Coord Y, Vector v, int fraction)
00411 {
00412   double e1, e2, t1;
00413   int i, range;
00414 
00415   poly_InclVertex (c->head.prev, poly_CreateNode (v));
00416   /* move vector to origin */
00417   e1 = (v[0] - X) * POLY_CIRC_RADIUS_ADJ;
00418   e2 = (v[1] - Y) * POLY_CIRC_RADIUS_ADJ;
00419 
00420   /* NB: the caller adds the last vertex, hence the -1 */
00421   range = POLY_CIRC_SEGS / fraction - 1;
00422   for (i = 0; i < range; i++)
00423     {
00424       /* rotate the vector */
00425       t1 = rotate_circle_seg[0] * e1 + rotate_circle_seg[1] * e2;
00426       e2 = rotate_circle_seg[2] * e1 + rotate_circle_seg[3] * e2;
00427       e1 = t1;
00428       v[0] = X + ROUND (e1);
00429       v[1] = Y + ROUND (e2);
00430       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00431     }
00432 }
00433 
00437 POLYAREA *
00438 CirclePoly (Coord x, Coord y, Coord radius)
00439 {
00440   PLINE *contour;
00441   Vector v;
00442 
00443   if (radius <= 0)
00444     return NULL;
00445   v[0] = x + radius;
00446   v[1] = y;
00447   if ((contour = poly_NewContour (v)) == NULL)
00448     return NULL;
00449   frac_circle (contour, x, y, v, 1);
00450   contour->is_round = TRUE;
00451   contour->cx = x;
00452   contour->cy = y;
00453   contour->radius = radius;
00454   return ContourToPoly (contour);
00455 }
00456 
00461 POLYAREA *
00462 RoundRect (Coord x1, Coord x2, Coord y1, Coord y2, Coord t)
00463 {
00464   PLINE *contour = NULL;
00465   Vector v;
00466 
00467   assert (x2 > x1);
00468   assert (y2 > y1);
00469   v[0] = x1 - t;
00470   v[1] = y1;
00471   if ((contour = poly_NewContour (v)) == NULL)
00472     return NULL;
00473   frac_circle (contour, x1, y1, v, 4);
00474   v[0] = x2;
00475   v[1] = y1 - t;
00476   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00477   frac_circle (contour, x2, y1, v, 4);
00478   v[0] = x2 + t;
00479   v[1] = y2;
00480   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00481   frac_circle (contour, x2, y2, v, 4);
00482   v[0] = x1;
00483   v[1] = y2 + t;
00484   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00485   frac_circle (contour, x1, y2, v, 4);
00486   return ContourToPoly (contour);
00487 }
00488 
00489 #define ARC_ANGLE 5
00490 static POLYAREA *
00491 ArcPolyNoIntersect (ArcType * a, Coord thick)
00492 {
00493   PLINE *contour = NULL;
00494   POLYAREA *np = NULL;
00495   Vector v;
00496   BoxType *ends;
00497   int i, segs;
00498   double ang, da, rx, ry;
00499   long half;
00500   double radius_adj;
00501 
00502   if (thick <= 0)
00503     return NULL;
00504   if (a->Delta < 0)
00505     {
00506       a->StartAngle += a->Delta;
00507       a->Delta = -a->Delta;
00508     }
00509   half = (thick + 1) / 2;
00510   ends = GetArcEnds (a);
00511   /* start with inner radius */
00512   rx = MAX (a->Width - half, 0);
00513   ry = MAX (a->Height - half, 0);
00514   segs = 1;
00515   if(thick > 0)
00516     segs = MAX (segs, a->Delta * M_PI / 360 *
00517                       sqrt (hypot (rx, ry) /
00518                             POLY_ARC_MAX_DEVIATION / 2 / thick));
00519   segs = MAX(segs, a->Delta / ARC_ANGLE);
00520 
00521   ang = a->StartAngle;
00522   da = (1.0 * a->Delta) / segs;
00523   radius_adj = (M_PI*da/360)*(M_PI*da/360)/2;
00524   v[0] = a->X - rx * cos (ang * M180);
00525   v[1] = a->Y + ry * sin (ang * M180);
00526   if ((contour = poly_NewContour (v)) == NULL)
00527     return 0;
00528   for (i = 0; i < segs - 1; i++)
00529     {
00530       ang += da;
00531       v[0] = a->X - rx * cos (ang * M180);
00532       v[1] = a->Y + ry * sin (ang * M180);
00533       poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00534     }
00535   /* find last point */
00536   ang = a->StartAngle + a->Delta;
00537   v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj);
00538   v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj);
00539   /* add the round cap at the end */
00540   frac_circle (contour, ends->X2, ends->Y2, v, 2);
00541   /* and now do the outer arc (going backwards) */
00542   rx = (a->Width + half) * (1+radius_adj);
00543   ry = (a->Width + half) * (1+radius_adj);
00544   da = -da;
00545   for (i = 0; i < segs; i++)
00546     {
00547       v[0] = a->X - rx * cos (ang * M180);
00548       v[1] = a->Y + ry * sin (ang * M180);
00549       poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00550       ang += da;
00551     }
00552   /* now add other round cap */
00553   ang = a->StartAngle;
00554   v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj);
00555   v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj);
00556   frac_circle (contour, ends->X1, ends->Y1, v, 2);
00557   /* now we have the whole contour */
00558   if (!(np = ContourToPoly (contour)))
00559     return NULL;
00560   return np;
00561 }
00562 
00563 #define MIN_CLEARANCE_BEFORE_BISECT 10.
00564 POLYAREA *
00565 ArcPoly (ArcType * a, Coord thick)
00566 {
00567   double delta;
00568   ArcType seg1, seg2;
00569   POLYAREA *tmp1, *tmp2, *res;
00570 
00571   delta = (a->Delta < 0) ? -a->Delta : a->Delta;
00572 
00573   /* If the arc segment would self-intersect, we need to construct it as the union of
00574      two non-intersecting segments */
00575 
00576   if (2 * M_PI * a->Width * (1. - (double)delta / 360.) - thick < MIN_CLEARANCE_BEFORE_BISECT)
00577     {
00578       int half_delta = a->Delta / 2;
00579 
00580       seg1 = seg2 = *a;
00581       seg1.Delta = half_delta;
00582       seg2.Delta -= half_delta;
00583       seg2.StartAngle += half_delta;
00584 
00585       tmp1 = ArcPolyNoIntersect (&seg1, thick);
00586       tmp2 = ArcPolyNoIntersect (&seg2, thick);
00587       poly_Boolean_free (tmp1, tmp2, &res, PBO_UNITE);
00588       return res;
00589     }
00590 
00591   return ArcPolyNoIntersect (a, thick);
00592 }
00593 
00594 POLYAREA *
00595 LinePoly (LineType * L, Coord thick)
00596 {
00597   PLINE *contour = NULL;
00598   POLYAREA *np = NULL;
00599   Vector v;
00600   double d, dx, dy;
00601   long half;LineType _l=*L,*l=&_l;
00602 
00603   if (thick <= 0)
00604     return NULL;
00605   half = (thick + 1) / 2;
00606   d = hypot (l->Point1.X - l->Point2.X, l->Point1.Y - l->Point2.Y);
00607   if (!TEST_FLAG (SQUAREFLAG,l))
00608     if (d == 0)                   /* line is a point */
00609       return CirclePoly (l->Point1.X, l->Point1.Y, half);
00610   if (d != 0)
00611     {
00612       d = half / d;
00613       dx = (l->Point1.Y - l->Point2.Y) * d;
00614       dy = (l->Point2.X - l->Point1.X) * d;
00615     }
00616   else
00617     {
00618       dx = half;
00619       dy = 0;
00620     }
00621   if (TEST_FLAG (SQUAREFLAG,l))/* take into account the ends */
00622     {
00623       l->Point1.X -= dy;
00624       l->Point1.Y += dx;
00625       l->Point2.X += dy;
00626       l->Point2.Y -= dx;
00627     }
00628   v[0] = l->Point1.X - dx;
00629   v[1] = l->Point1.Y - dy;
00630   if ((contour = poly_NewContour (v)) == NULL)
00631     return 0;
00632   v[0] = l->Point2.X - dx;
00633   v[1] = l->Point2.Y - dy;
00634   if (TEST_FLAG (SQUAREFLAG,l))
00635     poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00636   else
00637     frac_circle (contour, l->Point2.X, l->Point2.Y, v, 2);
00638   v[0] = l->Point2.X + dx;
00639   v[1] = l->Point2.Y + dy;
00640   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00641   v[0] = l->Point1.X + dx;
00642   v[1] = l->Point1.Y + dy;
00643   if (TEST_FLAG (SQUAREFLAG,l))
00644     poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00645   else
00646     frac_circle (contour, l->Point1.X, l->Point1.Y, v, 2);
00647   /* now we have the line contour */
00648   if (!(np = ContourToPoly (contour)))
00649     return NULL;
00650   return np;
00651 }
00652 
00656 POLYAREA *
00657 SquarePadPoly (PadType * pad, Coord clear)
00658 {
00659   PLINE *contour = NULL;
00660   POLYAREA *np = NULL;
00661   Vector v;
00662   double d;
00663   double tx, ty;
00664   double cx, cy;
00665   PadType _t=*pad,*t=&_t;
00666   PadType _c=*pad,*c=&_c;
00667   int halfthick = (pad->Thickness + 1) / 2;
00668   int halfclear = (clear + 1) / 2;
00669 
00670   d = hypot (pad->Point1.X - pad->Point2.X, pad->Point1.Y - pad->Point2.Y);
00671   if (d != 0)
00672     {
00673       double a = halfthick / d;
00674       tx = (t->Point1.Y - t->Point2.Y) * a;
00675       ty = (t->Point2.X - t->Point1.X) * a;
00676       a = halfclear / d;
00677       cx = (c->Point1.Y - c->Point2.Y) * a;
00678       cy = (c->Point2.X - c->Point1.X) * a;
00679 
00680       t->Point1.X -= ty;
00681       t->Point1.Y += tx;
00682       t->Point2.X += ty;
00683       t->Point2.Y -= tx;
00684       c->Point1.X -= cy;
00685       c->Point1.Y += cx;
00686       c->Point2.X += cy;
00687       c->Point2.Y -= cx;
00688     }
00689   else
00690     {
00691       tx = halfthick;
00692       ty = 0;
00693       cx = halfclear;
00694       cy = 0;
00695 
00696       t->Point1.Y += tx;
00697       t->Point2.Y -= tx;
00698       c->Point1.Y += cx;
00699       c->Point2.Y -= cx;
00700     }
00701 
00702   v[0] = c->Point1.X - tx;
00703   v[1] = c->Point1.Y - ty;
00704   if ((contour = poly_NewContour (v)) == NULL)
00705     return 0;
00706   frac_circle (contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4);
00707 
00708   v[0] = t->Point2.X - cx;
00709   v[1] = t->Point2.Y - cy;
00710   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00711   frac_circle (contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4);
00712 
00713   v[0] = c->Point2.X + tx;
00714   v[1] = c->Point2.Y + ty;
00715   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00716   frac_circle (contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4);
00717 
00718   v[0] = t->Point1.X + cx;
00719   v[1] = t->Point1.Y + cy;
00720   poly_InclVertex (contour->head.prev, poly_CreateNode (v));
00721   frac_circle (contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4);
00722 
00723   /* now we have the line contour */
00724   if (!(np = ContourToPoly (contour)))
00725     return NULL;
00726   return np;
00727 }
00728 
00732 static int
00733 Subtract (POLYAREA * np1, PolygonType * p, bool fnp)
00734 {
00735   POLYAREA *merged = NULL, *np = np1;
00736   int x;
00737   assert (np);
00738   assert (p);
00739   if (!p->Clipped)
00740     {
00741       if (fnp)
00742         poly_Free (&np);
00743       return 1;
00744     }
00745   assert (poly_Valid (p->Clipped));
00746   assert (poly_Valid (np));
00747   if (fnp)
00748     x = poly_Boolean_free (p->Clipped, np, &merged, PBO_SUB);
00749   else
00750     {
00751       x = poly_Boolean (p->Clipped, np, &merged, PBO_SUB);
00752       poly_Free (&p->Clipped);
00753     }
00754   assert (!merged || poly_Valid (merged));
00755   if (x != err_ok)
00756     {
00757       fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x);
00758       poly_Free (&merged);
00759       p->Clipped = NULL;
00760       if (p->NoHoles) printf ("Just leaked in Subtract\n");
00761       p->NoHoles = NULL;
00762       return -1;
00763     }
00764   p->Clipped = biggest (merged);
00765   assert (!p->Clipped || poly_Valid (p->Clipped));
00766   if (!p->Clipped)
00767     Message ("Polygon cleared out of existence near (%d, %d)\n",
00768              (p->BoundingBox.X1 + p->BoundingBox.X2) / 2,
00769              (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2);
00770   return 1;
00771 }
00772 
00776 POLYAREA *
00777 PinPoly (PinType * pin, Coord thick, Coord clear)
00778 {
00779   int size;
00780 
00781   if (TEST_FLAG (SQUAREFLAG, pin))
00782     {
00783       size = (thick + 1) / 2;
00784       return RoundRect (pin->X - size, pin->X + size, pin->Y - size,
00785                         pin->Y + size, (clear + 1) / 2);
00786     }
00787   else
00788     {
00789       size = (thick + clear + 1) / 2;
00790       if (TEST_FLAG (OCTAGONFLAG, pin))
00791         {
00792           return OctagonPoly (pin->X, pin->Y, size + size);
00793         }
00794     }
00795   return CirclePoly (pin->X, pin->Y, size);
00796 }
00797 
00798 POLYAREA *
00799 BoxPolyBloated (BoxType *box, Coord bloat)
00800 {
00801   return RectPoly (box->X1 - bloat, box->X2 + bloat,
00802                    box->Y1 - bloat, box->Y2 + bloat);
00803 }
00804 
00808 static int
00809 SubtractPin (DataType * d, PinType * pin, LayerType * l, PolygonType * p)
00810 {
00811   POLYAREA *np;
00812   Cardinal i;
00813 
00814   if (pin->Clearance == 0)
00815     return 0;
00816   i = GetLayerNumber (d, l);
00817   if (TEST_THERM (i, pin))
00818     {
00819       np = ThermPoly ((PCBType *) (d->pcb), pin, i);
00820       if (!np)
00821         return 0;
00822     }
00823   else
00824     {
00825       np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance);
00826       if (!np)
00827         return -1;
00828     }
00829   return Subtract (np, p, TRUE);
00830 }
00831 
00832 static int
00833 SubtractLine (LineType * line, PolygonType * p)
00834 {
00835   POLYAREA *np;
00836 
00837   if (!TEST_FLAG (CLEARLINEFLAG, line))
00838     return 0;
00839   if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
00840     return -1;
00841   return Subtract (np, p, true);
00842 }
00843 
00844 static int
00845 SubtractArc (ArcType * arc, PolygonType * p)
00846 {
00847   POLYAREA *np;
00848 
00849   if (!TEST_FLAG (CLEARLINEFLAG, arc))
00850     return 0;
00851   if (!(np = ArcPoly (arc, arc->Thickness + arc->Clearance)))
00852     return -1;
00853   return Subtract (np, p, true);
00854 }
00855 
00856 static int
00857 SubtractText (TextType * text, PolygonType * p)
00858 {
00859   POLYAREA *np;
00860   const BoxType *b = &text->BoundingBox;
00861 
00862   if (!TEST_FLAG (CLEARLINEFLAG, text))
00863     return 0;
00864   if (!(np = RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat,
00865                         b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat)))
00866     return -1;
00867   return Subtract (np, p, true);
00868 }
00869 
00870 static int
00871 SubtractPad (PadType * pad, PolygonType * p)
00872 {
00873   POLYAREA *np = NULL;
00874 
00875   if (pad->Clearance == 0)
00876     return 0;
00877   if (TEST_FLAG (SQUAREFLAG, pad))
00878     {
00879       if (!
00880           (np = SquarePadPoly (pad, pad->Thickness + pad->Clearance)))
00881         return -1;
00882     }
00883   else
00884     {
00885       if (!
00886           (np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance)))
00887         return -1;
00888     }
00889   return Subtract (np, p, true);
00890 }
00891 
00892 struct cpInfo
00893 {
00894   const BoxType *other;
00895   DataType *data;
00896   LayerType *layer;
00897   PolygonType *polygon;
00898   bool bottom;
00899   POLYAREA *accumulate;
00900   int batch_size;
00901   jmp_buf env;
00902 };
00903 
00904 static void
00905 subtract_accumulated (struct cpInfo *info, PolygonType *polygon)
00906 {
00907   if (info->accumulate == NULL)
00908     return;
00909   Subtract (info->accumulate, polygon, true);
00910   info->accumulate = NULL;
00911   info->batch_size = 0;
00912 }
00913 
00914 static int
00915 pin_sub_callback (const BoxType * b, void *cl)
00916 {
00917   PinType *pin = (PinType *) b;
00918   struct cpInfo *info = (struct cpInfo *) cl;
00919   PolygonType *polygon;
00920   POLYAREA *np;
00921   POLYAREA *merged;
00922   Cardinal i;
00923 
00924   /* don't subtract the object that was put back! */
00925   if (b == info->other)
00926     return 0;
00927   polygon = info->polygon;
00928 
00929   i = GetLayerNumber (info->data, info->layer);
00930 
00931   if (VIA_IS_BURIED (pin) && (!VIA_ON_LAYER (pin, i)))
00932     return 0;
00933 
00934   if (pin->Clearance == 0)
00935     return 0;
00936   if (TEST_THERM (i, pin))
00937     {
00938       np = ThermPoly ((PCBType *) (info->data->pcb), pin, i);
00939       if (!np)
00940         return 1;
00941     }
00942   else
00943     {
00944       np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance);
00945       if (!np)
00946         longjmp (info->env, 1);
00947     }
00948 
00949   poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
00950   info->accumulate = merged;
00951 
00952   info->batch_size ++;
00953 
00954   if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE)
00955     subtract_accumulated (info, polygon);
00956 
00957   return 1;
00958 }
00959 
00960 static int
00961 arc_sub_callback (const BoxType * b, void *cl)
00962 {
00963   ArcType *arc = (ArcType *) b;
00964   struct cpInfo *info = (struct cpInfo *) cl;
00965   PolygonType *polygon;
00966 
00967   /* don't subtract the object that was put back! */
00968   if (b == info->other)
00969     return 0;
00970   if (!TEST_FLAG (CLEARLINEFLAG, arc))
00971     return 0;
00972   polygon = info->polygon;
00973   if (SubtractArc (arc, polygon) < 0)
00974     longjmp (info->env, 1);
00975   return 1;
00976 }
00977 
00978 static int
00979 pad_sub_callback (const BoxType * b, void *cl)
00980 {
00981   PadType *pad = (PadType *) b;
00982   struct cpInfo *info = (struct cpInfo *) cl;
00983   PolygonType *polygon;
00984 
00985   /* don't subtract the object that was put back! */
00986   if (b == info->other)
00987     return 0;
00988   if (pad->Clearance == 0)
00989     return 0;
00990   polygon = info->polygon;
00991   if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), !info->bottom))
00992     {
00993       if (SubtractPad (pad, polygon) < 0)
00994         longjmp (info->env, 1);
00995       return 1;
00996     }
00997   return 0;
00998 }
00999 
01000 static int
01001 line_sub_callback (const BoxType * b, void *cl)
01002 {
01003   LineType *line = (LineType *) b;
01004   struct cpInfo *info = (struct cpInfo *) cl;
01005   PolygonType *polygon;
01006   POLYAREA *np;
01007   POLYAREA *merged;
01008 
01009   /* don't subtract the object that was put back! */
01010   if (b == info->other)
01011     return 0;
01012   if (!TEST_FLAG (CLEARLINEFLAG, line))
01013     return 0;
01014   polygon = info->polygon;
01015 
01016   if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
01017     longjmp (info->env, 1);
01018 
01019   poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
01020   info->accumulate = merged;
01021   info->batch_size ++;
01022 
01023   if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE)
01024     subtract_accumulated (info, polygon);
01025 
01026   return 1;
01027 }
01028 
01029 static int
01030 text_sub_callback (const BoxType * b, void *cl)
01031 {
01032   TextType *text = (TextType *) b;
01033   struct cpInfo *info = (struct cpInfo *) cl;
01034   PolygonType *polygon;
01035 
01036   /* don't subtract the object that was put back! */
01037   if (b == info->other)
01038     return 0;
01039   if (!TEST_FLAG (CLEARLINEFLAG, text))
01040     return 0;
01041   polygon = info->polygon;
01042   if (SubtractText (text, polygon) < 0)
01043     longjmp (info->env, 1);
01044   return 1;
01045 }
01046 
01047 static int
01048 Group (DataType *Data, Cardinal layer)
01049 {
01050   Cardinal i, j;
01051   for (i = 0; i < max_group; i++)
01052     for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++)
01053       if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j])
01054         return i;
01055   return i;
01056 }
01057 
01058 static int
01059 clearPoly (DataType *Data, LayerType *Layer, PolygonType * polygon,
01060            const BoxType * here, Coord expand)
01061 {
01062   int r = 0;
01063   BoxType region;
01064   struct cpInfo info;
01065   Cardinal group;
01066 
01067   if (!TEST_FLAG (CLEARPOLYFLAG, polygon)
01068       || GetLayerNumber (Data, Layer) >= max_copper_layer)
01069     return 0;
01070   group = Group (Data, GetLayerNumber (Data, Layer));
01071   info.bottom = (group == Group (Data, bottom_silk_layer));
01072   info.data = Data;
01073   info.other = here;
01074   info.layer = Layer;
01075   info.polygon = polygon;
01076   if (here)
01077     region = clip_box (here, &polygon->BoundingBox);
01078   else
01079     region = polygon->BoundingBox;
01080   region = bloat_box (&region, expand);
01081 
01082   if (setjmp (info.env) == 0)
01083     {
01084       r = 0;
01085       info.accumulate = NULL;
01086       info.batch_size = 0;
01087       if (info.bottom || group == Group (Data, top_silk_layer))
01088         r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
01089       GROUP_LOOP (Data, group);
01090       {
01091         r +=
01092           r_search (layer->line_tree, &region, NULL, line_sub_callback,
01093                     &info);
01094         subtract_accumulated (&info, polygon);
01095         r +=
01096           r_search (layer->arc_tree, &region, NULL, arc_sub_callback, &info);
01097         r +=
01098           r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
01099       }
01100       END_LOOP;
01101       r += r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
01102       r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
01103       subtract_accumulated (&info, polygon);
01104     }
01105   polygon->NoHolesValid = 0;
01106   return r;
01107 }
01108 
01109 static int
01110 Unsubtract (POLYAREA * np1, PolygonType * p)
01111 {
01112   POLYAREA *merged = NULL, *np = np1;
01113   POLYAREA *orig_poly, *clipped_np;
01114   int x;
01115   assert (np);
01116   assert (p && p->Clipped);
01117 
01118   orig_poly = original_poly (p);
01119 
01120   x = poly_Boolean_free (np, orig_poly, &clipped_np, PBO_ISECT);
01121   if (x != err_ok)
01122     {
01123       fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x);
01124       poly_Free (&clipped_np);
01125       goto fail;
01126     }
01127 
01128   x = poly_Boolean_free (p->Clipped, clipped_np, &merged, PBO_UNITE);
01129   if (x != err_ok)
01130     {
01131       fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x);
01132       poly_Free (&merged);
01133       goto fail;
01134     }
01135   p->Clipped = biggest (merged);
01136   assert (!p->Clipped || poly_Valid (p->Clipped));
01137   return 1;
01138 
01139 fail:
01140   p->Clipped = NULL;
01141   if (p->NoHoles) printf ("Just leaked in Unsubtract\n");
01142   p->NoHoles = NULL;
01143   return 0;
01144 }
01145 
01146 static int
01147 UnsubtractPin (PinType * pin, LayerType * l, PolygonType * p)
01148 {
01149   POLYAREA *np;
01150 
01151   /* overlap a bit to prevent gaps from rounding errors */
01152   np = BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT);
01153 
01154   if (!np)
01155     return 0;
01156   if (!Unsubtract (np, p))
01157     return 0;
01158   clearPoly (PCB->Data, l, p, (const BoxType *) pin, 2 * UNSUBTRACT_BLOAT);
01159   return 1;
01160 }
01161 
01162 static int
01163 UnsubtractArc (ArcType * arc, LayerType * l, PolygonType * p)
01164 {
01165   POLYAREA *np;
01166 
01167   if (!TEST_FLAG (CLEARLINEFLAG, arc))
01168     return 0;
01169 
01170   /* overlap a bit to prevent gaps from rounding errors */
01171   np = BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT);
01172 
01173   if (!np)
01174     return 0;
01175   if (!Unsubtract (np, p))
01176     return 0;
01177   clearPoly (PCB->Data, l, p, (const BoxType *) arc, 2 * UNSUBTRACT_BLOAT);
01178   return 1;
01179 }
01180 
01181 static int
01182 UnsubtractLine (LineType * line, LayerType * l, PolygonType * p)
01183 {
01184   POLYAREA *np;
01185 
01186   if (!TEST_FLAG (CLEARLINEFLAG, line))
01187     return 0;
01188 
01189   /* overlap a bit to prevent notches from rounding errors */
01190   np = BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT);
01191 
01192   if (!np)
01193     return 0;
01194   if (!Unsubtract (np, p))
01195     return 0;
01196   clearPoly (PCB->Data, l, p, (const BoxType *) line, 2 * UNSUBTRACT_BLOAT);
01197   return 1;
01198 }
01199 
01200 static int
01201 UnsubtractText (TextType * text, LayerType * l, PolygonType * p)
01202 {
01203   POLYAREA *np;
01204 
01205   if (!TEST_FLAG (CLEARLINEFLAG, text))
01206     return 0;
01207 
01208   /* overlap a bit to prevent notches from rounding errors */
01209   np = BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT);
01210 
01211   if (!np)
01212     return -1;
01213   if (!Unsubtract (np, p))
01214     return 0;
01215   clearPoly (PCB->Data, l, p, (const BoxType *) text, 2 * UNSUBTRACT_BLOAT);
01216   return 1;
01217 }
01218 
01219 static int
01220 UnsubtractPad (PadType * pad, LayerType * l, PolygonType * p)
01221 {
01222   POLYAREA *np;
01223 
01224   /* overlap a bit to prevent notches from rounding errors */
01225   np = BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT);
01226 
01227   if (!np)
01228     return 0;
01229   if (!Unsubtract (np, p))
01230     return 0;
01231   clearPoly (PCB->Data, l, p, (const BoxType *) pad, 2 * UNSUBTRACT_BLOAT);
01232   return 1;
01233 }
01234 
01235 static bool inhibit = false;
01236 
01237 int
01238 InitClip (DataType *Data, LayerType *layer, PolygonType * p)
01239 {
01240   if (inhibit)
01241     return 0;
01242   if (p->Clipped)
01243     poly_Free (&p->Clipped);
01244   p->Clipped = original_poly (p);
01245   poly_FreeContours (&p->NoHoles);
01246   if (!p->Clipped)
01247     return 0;
01248   assert (poly_Valid (p->Clipped));
01249   if (TEST_FLAG (CLEARPOLYFLAG, p))
01250     clearPoly (Data, layer, p, NULL, 0);
01251   else
01252     p->NoHolesValid = 0;
01253   return 1;
01254 }
01255 
01264 bool
01265 RemoveExcessPolygonPoints (LayerType *Layer, PolygonType *Polygon)
01266 {
01267   PointType *p;
01268   Cardinal n, prev, next;
01269   LineType line;
01270   bool changed = false;
01271 
01272   if (Undoing ())
01273     return (false);
01274 
01275   for (n = 0; n < Polygon->PointN; n++)
01276     {
01277       prev = prev_contour_point (Polygon, n);
01278       next = next_contour_point (Polygon, n);
01279       p = &Polygon->Points[n];
01280 
01281       line.Point1 = Polygon->Points[prev];
01282       line.Point2 = Polygon->Points[next];
01283       line.Thickness = 0;
01284       if (IsPointOnLine (p->X, p->Y, 0.0, &line))
01285         {
01286           RemoveObject (POLYGONPOINT_TYPE, Layer, Polygon, p);
01287           changed = true;
01288         }
01289     }
01290   return (changed);
01291 }
01292 
01299 Cardinal
01300 GetLowestDistancePolygonPoint (PolygonType *Polygon, Coord X, Coord Y)
01301 {
01302   double mindistance = (double) MAX_COORD * MAX_COORD;
01303   PointType *ptr1, *ptr2;
01304   Cardinal n, result = 0;
01305 
01306   /* we calculate the distance to each segment and choose the
01307    * shortest distance. If the closest approach between the
01308    * given point and the projected line (i.e. the segment extended)
01309    * is not on the segment, then the distance is the distance
01310    * to the segment end point.
01311    */
01312 
01313   for (n = 0; n < Polygon->PointN; n++)
01314     {
01315       double u, dx, dy;
01316       ptr1 = &Polygon->Points[prev_contour_point (Polygon, n)];
01317       ptr2 = &Polygon->Points[n];
01318 
01319       dx = ptr2->X - ptr1->X;
01320       dy = ptr2->Y - ptr1->Y;
01321       if (dx != 0.0 || dy != 0.0)
01322         {
01323           /* projected intersection is at P1 + u(P2 - P1) */
01324           u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy);
01325 
01326           if (u < 0.0)
01327             {                   /* ptr1 is closest point */
01328               u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y);
01329             }
01330           else if (u > 1.0)
01331             {                   /* ptr2 is closest point */
01332               u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y);
01333             }
01334           else
01335             {                   /* projected intersection is closest point */
01336               u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) +
01337                 SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y);
01338             }
01339           if (u < mindistance)
01340             {
01341               mindistance = u;
01342               result = n;
01343             }
01344         }
01345     }
01346   return (result);
01347 }
01348 
01352 void
01353 GoToPreviousPoint (void)
01354 {
01355   switch (Crosshair.AttachedPolygon.PointN)
01356     {
01357       /* do nothing if mode has just been entered */
01358     case 0:
01359       break;
01360 
01361       /* reset number of points and 'LINE_MODE' state */
01362     case 1:
01363       Crosshair.AttachedPolygon.PointN = 0;
01364       Crosshair.AttachedLine.State = STATE_FIRST;
01365       addedLines = 0;
01366       break;
01367 
01368       /* back-up one point */
01369     default:
01370       {
01371         PointType *points = Crosshair.AttachedPolygon.Points;
01372         Cardinal n = Crosshair.AttachedPolygon.PointN - 2;
01373 
01374         Crosshair.AttachedPolygon.PointN--;
01375         Crosshair.AttachedLine.Point1.X = points[n].X;
01376         Crosshair.AttachedLine.Point1.Y = points[n].Y;
01377         break;
01378       }
01379     }
01380 }
01381 
01385 void
01386 ClosePolygon (void)
01387 {
01388   Cardinal n = Crosshair.AttachedPolygon.PointN;
01389 
01390   /* check number of points */
01391   if (n >= 3)
01392     {
01393       /* if 45 degree lines are what we want do a quick check
01394        * if closing the polygon makes sense
01395        */
01396       if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB))
01397         {
01398           Coord dx, dy;
01399 
01400           dx = abs (Crosshair.AttachedPolygon.Points[n - 1].X -
01401                     Crosshair.AttachedPolygon.Points[0].X);
01402           dy = abs (Crosshair.AttachedPolygon.Points[n - 1].Y -
01403                     Crosshair.AttachedPolygon.Points[0].Y);
01404           if (!(dx == 0 || dy == 0 || dx == dy))
01405             {
01406               Message
01407                 (_
01408                  ("Cannot close polygon because 45 degree lines are requested.\n"));
01409               return;
01410             }
01411         }
01412       CopyAttachedPolygonToLayer ();
01413       Draw ();
01414     }
01415   else
01416     Message (_("A polygon has to have at least 3 points\n"));
01417 }
01418 
01423 void
01424 CopyAttachedPolygonToLayer (void)
01425 {
01426   PolygonType *polygon;
01427   int saveID;
01428 
01429   /* move data to layer and clear attached struct */
01430   polygon = CreateNewPolygon (CURRENT, NoFlags ());
01431   saveID = polygon->ID;
01432   *polygon = Crosshair.AttachedPolygon;
01433   polygon->ID = saveID;
01434   SET_FLAG (CLEARPOLYFLAG, polygon);
01435   if (TEST_FLAG (NEWFULLPOLYFLAG, PCB))
01436     SET_FLAG (FULLPOLYFLAG, polygon);
01437   memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType));
01438   SetPolygonBoundingBox (polygon);
01439   if (!CURRENT->polygon_tree)
01440     CURRENT->polygon_tree = r_create_tree (NULL, 0, 0);
01441   r_insert_entry (CURRENT->polygon_tree, (BoxType *) polygon, 0);
01442   InitClip (PCB->Data, CURRENT, polygon);
01443   DrawPolygon (CURRENT, polygon);
01444   SetChangedFlag (true);
01445 
01446   /* reset state of attached line */
01447   Crosshair.AttachedLine.State = STATE_FIRST;
01448   addedLines = 0;
01449 
01450   /* add to undo list */
01451   AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon);
01452   IncrementUndoSerialNumber ();
01453 }
01454 
01461 int
01462 PolygonHoles (PolygonType *polygon, const BoxType *range,
01463               int (*callback) (PLINE *contour, void *user_data),
01464               void *user_data)
01465 {
01466   POLYAREA *pa = polygon->Clipped;
01467   PLINE *pl;
01468   /* If this hole is so big the polygon doesn't exist, then it's not
01469    * really a hole.
01470    */
01471   if (!pa)
01472     return 0;
01473   for (pl = pa->contours->next; pl; pl = pl->next)
01474     {
01475       if (range != NULL &&
01476           (pl->xmin > range->X2 || pl->xmax < range->X1 ||
01477            pl->ymin > range->Y2 || pl->ymax < range->Y1))
01478         continue;
01479       if (callback (pl, user_data))
01480         {
01481           return 1;
01482         }
01483     }
01484   return 0;
01485 }
01486 
01487 struct plow_info
01488 {
01489   int type;
01490   void *ptr1, *ptr2;
01491   LayerType *layer;
01492   DataType *data;
01493   int (*callback) (DataType *, LayerType *, PolygonType *, int, void *,
01494                    void *, void *);
01495   void *userdata;
01496 };
01497 
01498 static int
01499 subtract_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon,
01500                int type, void *ptr1, void *ptr2, void *userdata)
01501 {
01502   PinType *via;
01503   int layer_n = GetLayerNumber (Data, Layer);
01504 
01505   if (!Polygon->Clipped)
01506     return 0;
01507   switch (type)
01508     {
01509     case PIN_TYPE:
01510       SubtractPin (Data, (PinType *) ptr2, Layer, Polygon);
01511       Polygon->NoHolesValid = 0;
01512       return 1;
01513     case VIA_TYPE:
01514       via = (PinType *) ptr2;
01515       if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n))
01516         {
01517           SubtractPin (Data, via, Layer, Polygon);
01518           Polygon->NoHolesValid = 0;
01519           return 1;
01520         }
01521       break;
01522     case LINE_TYPE:
01523       SubtractLine ((LineType *) ptr2, Polygon);
01524       Polygon->NoHolesValid = 0;
01525       return 1;
01526     case ARC_TYPE:
01527       SubtractArc ((ArcType *) ptr2, Polygon);
01528       Polygon->NoHolesValid = 0;
01529       return 1;
01530     case PAD_TYPE:
01531       SubtractPad ((PadType *) ptr2, Polygon);
01532       Polygon->NoHolesValid = 0;
01533       return 1;
01534     case TEXT_TYPE:
01535       SubtractText ((TextType *) ptr2, Polygon);
01536       Polygon->NoHolesValid = 0;
01537       return 1;
01538     }
01539   return 0;
01540 }
01541 
01542 static int
01543 add_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon,
01544           int type, void *ptr1, void *ptr2, void *userdata)
01545 {
01546   PinType *via;
01547   int layer_n = GetLayerNumber (Data, Layer);
01548 
01549   switch (type)
01550     {
01551     case PIN_TYPE:
01552       UnsubtractPin ((PinType *) ptr2, Layer, Polygon);
01553       return 1;
01554     case VIA_TYPE:
01555       via = (PinType *) ptr2;
01556       if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n))
01557         {
01558           UnsubtractPin ((PinType *) ptr2, Layer, Polygon);
01559           return 1;
01560         }
01561         break;
01562     case LINE_TYPE:
01563       UnsubtractLine ((LineType *) ptr2, Layer, Polygon);
01564       return 1;
01565     case ARC_TYPE:
01566       UnsubtractArc ((ArcType *) ptr2, Layer, Polygon);
01567       return 1;
01568     case PAD_TYPE:
01569       UnsubtractPad ((PadType *) ptr2, Layer, Polygon);
01570       return 1;
01571     case TEXT_TYPE:
01572       UnsubtractText ((TextType *) ptr2, Layer, Polygon);
01573       return 1;
01574     }
01575   return 0;
01576 }
01577 
01578 static int
01579 plow_callback (const BoxType * b, void *cl)
01580 {
01581   struct plow_info *plow = (struct plow_info *) cl;
01582   PolygonType *polygon = (PolygonType *) b;
01583 
01584   if (TEST_FLAG (CLEARPOLYFLAG, polygon))
01585     return plow->callback (plow->data, plow->layer, polygon, plow->type,
01586                            plow->ptr1, plow->ptr2, plow->userdata);
01587   return 0;
01588 }
01589 
01590 int
01591 PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
01592               int (*call_back) (DataType *data, LayerType *lay,
01593                                 PolygonType *poly, int type, void *ptr1,
01594                                 void *ptr2, void *userdata),
01595               void *userdata)
01596 {
01597   BoxType sb = ((PinType *) ptr2)->BoundingBox;
01598   int r = 0;
01599   struct plow_info info;
01600 
01601   info.type = type;
01602   info.ptr1 = ptr1;
01603   info.ptr2 = ptr2;
01604   info.data = Data;
01605   info.callback = call_back;
01606   info.userdata = userdata;
01607   switch (type)
01608     {
01609     case PIN_TYPE:
01610     case VIA_TYPE:
01611       if (type == PIN_TYPE || ptr1 == ptr2 || ptr1 == NULL)
01612         {
01613           LAYER_LOOP (Data, max_copper_layer);
01614           {
01615             info.layer = layer;
01616             r +=
01617               r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
01618           }
01619           END_LOOP;
01620         }
01621       else
01622         {
01623           GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data,
01624                                                                          ((LayerType *) ptr1))));
01625           {
01626             info.layer = layer;
01627             r +=
01628               r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
01629           }
01630           END_LOOP;
01631         }
01632       break;
01633     case LINE_TYPE:
01634     case ARC_TYPE:
01635     case TEXT_TYPE:
01636       /* the cast works equally well for lines and arcs */
01637       if (!TEST_FLAG (CLEARLINEFLAG, (LineType *) ptr2))
01638         return 0;
01639       /* silk doesn't plow */
01640       if (GetLayerNumber (Data, (LayerType *)ptr1) >= max_copper_layer)
01641         return 0;
01642       GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data,
01643                                                                      ((LayerType *) ptr1))));
01644       {
01645         info.layer = layer;
01646         r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
01647       }
01648       END_LOOP;
01649       break;
01650     case PAD_TYPE:
01651       {
01652         Cardinal group = GetLayerGroupNumberByNumber (
01653                             TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ?
01654                               bottom_silk_layer : top_silk_layer);
01655         GROUP_LOOP (Data, group);
01656         {
01657           info.layer = layer;
01658           r +=
01659             r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
01660         }
01661         END_LOOP;
01662       }
01663       break;
01664 
01665     case ELEMENT_TYPE:
01666       {
01667         PIN_LOOP ((ElementType *) ptr1);
01668         {
01669           PlowsPolygon (Data, PIN_TYPE, ptr1, pin, call_back, userdata);
01670         }
01671         END_LOOP;
01672         PAD_LOOP ((ElementType *) ptr1);
01673         {
01674           PlowsPolygon (Data, PAD_TYPE, ptr1, pad, call_back, userdata);
01675         }
01676         END_LOOP;
01677       }
01678       break;
01679     }
01680   return r;
01681 }
01682 
01683 void
01684 RestoreToPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
01685 {
01686   if (!Data->polyClip)
01687     return;
01688 
01689   if (type == POLYGON_TYPE)
01690     InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2);
01691   else
01692     PlowsPolygon (Data, type, ptr1, ptr2, add_plow, NULL);
01693 }
01694 
01695 void
01696 ClearFromPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
01697 {
01698   if (!Data->polyClip)
01699     return;
01700 
01701   if (type == POLYGON_TYPE)
01702     InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2);
01703   else
01704     PlowsPolygon (Data, type, ptr1, ptr2, subtract_plow, NULL);
01705 }
01706 
01707 bool
01708 isects (POLYAREA * a, PolygonType *p, bool fr)
01709 {
01710   POLYAREA *x;
01711   bool ans;
01712   ans = Touching (a, p->Clipped);
01713   /* argument may be register, so we must copy it */
01714   x = a;
01715   if (fr)
01716     poly_Free (&x);
01717   return ans;
01718 }
01719 
01720 
01721 bool
01722 IsPointInPolygon (Coord X, Coord Y, Coord r, PolygonType *p)
01723 {
01724   POLYAREA *c;
01725   Vector v;
01726   v[0] = X;
01727   v[1] = Y;
01728   if (poly_CheckInside (p->Clipped, v))
01729     return true;
01730   if (r < 1)
01731     return false;
01732   if (!(c = CirclePoly (X, Y, r)))
01733     return false;
01734   return isects (c, p, true);
01735 }
01736 
01737 
01738 bool
01739 IsPointInPolygonIgnoreHoles (Coord X, Coord Y, PolygonType *p)
01740 {
01741   Vector v;
01742   v[0] = X;
01743   v[1] = Y;
01744   return poly_InsideContour (p->Clipped->contours, v);
01745 }
01746 
01747 bool
01748 IsRectangleInPolygon (Coord X1, Coord Y1, Coord X2, Coord Y2, PolygonType *p)
01749 {
01750   POLYAREA *s;
01751   if (!
01752       (s = RectPoly (min (X1, X2), max (X1, X2), min (Y1, Y2), max (Y1, Y2))))
01753     return false;
01754   return isects (s, p, true);
01755 }
01756 
01763 static void
01764 r_NoHolesPolygonDicer (POLYAREA * pa,
01765                        void (*emit) (PLINE *, void *), void *user_data)
01766 {
01767   PLINE *p = pa->contours;
01768 
01769   if (!pa->contours->next)                 /* no holes */
01770     {
01771       pa->contours = NULL; /* The callback now owns the contour */
01772       /* Don't bother removing it from the POLYAREA's rtree
01773          since we're going to free the POLYAREA below anyway */
01774       emit (p, user_data);
01775       poly_Free (&pa);
01776       return;
01777     }
01778   else
01779     {
01780       POLYAREA *poly2, *left, *right;
01781 
01782       /* make a rectangle of the left region slicing through the middle of the first hole */
01783       poly2 = RectPoly (p->xmin, (p->next->xmin + p->next->xmax) / 2,
01784                         p->ymin, p->ymax);
01785       poly_AndSubtract_free (pa, poly2, &left, &right);
01786       if (left)
01787         {
01788           POLYAREA *cur, *next;
01789           cur = left;
01790           do
01791             {
01792               next = cur->f;
01793               cur->f = cur->b = cur; /* Detach this polygon piece */
01794               r_NoHolesPolygonDicer (cur, emit, user_data);
01795               /* NB: The POLYAREA was freed by its use in the recursive dicer */
01796             }
01797           while ((cur = next) != left);
01798         }
01799       if (right)
01800         {
01801           POLYAREA *cur, *next;
01802           cur = right;
01803           do
01804             {
01805               next = cur->f;
01806               cur->f = cur->b = cur; /* Detach this polygon piece */
01807               r_NoHolesPolygonDicer (cur, emit, user_data);
01808               /* NB: The POLYAREA was freed by its use in the recursive dicer */
01809             }
01810           while ((cur = next) != right);
01811         }
01812     }
01813 }
01814 
01815 void
01816 NoHolesPolygonDicer (PolygonType *p, const BoxType * clip,
01817                      void (*emit) (PLINE *, void *), void *user_data)
01818 {
01819   POLYAREA *main_contour, *cur, *next;
01820 
01821   main_contour = poly_Create ();
01822   /* copy the main poly only */
01823   poly_Copy1 (main_contour, p->Clipped);
01824   /* clip to the bounding box */
01825   if (clip)
01826     {
01827       POLYAREA *cbox = RectPoly (clip->X1, clip->X2, clip->Y1, clip->Y2);
01828       poly_Boolean_free (main_contour, cbox, &main_contour, PBO_ISECT);
01829     }
01830   if (main_contour == NULL)
01831     return;
01832   /* Now dice it up.
01833    * NB: Could be more than one piece (because of the clip above)
01834    */
01835   cur = main_contour;
01836   do
01837     {
01838       next = cur->f;
01839       cur->f = cur->b = cur; /* Detach this polygon piece */
01840       r_NoHolesPolygonDicer (cur, emit, user_data);
01841       /* NB: The POLYAREA was freed by its use in the recursive dicer */
01842     }
01843   while ((cur = next) != main_contour);
01844 }
01845 
01850 bool
01851 MorphPolygon (LayerType *layer, PolygonType *poly)
01852 {
01853   POLYAREA *p, *start;
01854   bool many = false;
01855   FlagType flags;
01856 
01857   if (!poly->Clipped || TEST_FLAG (LOCKFLAG, poly))
01858     return false;
01859   if (poly->Clipped->f == poly->Clipped)
01860     return false;
01861   ErasePolygon (poly);
01862   start = p = poly->Clipped;
01863   /* This is ugly. The creation of the new polygons can cause
01864    * all of the polygon pointers (including the one we're called
01865    * with to change if there is a realloc in GetPolygonMemory().
01866    * That will invalidate our original "poly" argument, potentially
01867    * inside the loop. We need to steal the Clipped pointer and
01868    * hide it from the Remove call so that it still exists while
01869    * we do this dirty work.
01870    */
01871   poly->Clipped = NULL;
01872   if (poly->NoHoles) printf ("Just leaked in MorpyPolygon\n");
01873   poly->NoHoles = NULL;
01874   flags = poly->Flags;
01875   RemovePolygon (layer, poly);
01876   inhibit = true;
01877   do
01878     {
01879       VNODE *v;
01880       PolygonType *newone;
01881 
01882       if (p->contours->area > PCB->IsleArea)
01883         {
01884           newone = CreateNewPolygon (layer, flags);
01885           if (!newone)
01886             return false;
01887           many = true;
01888           v = &p->contours->head;
01889           CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
01890           for (v = v->next; v != &p->contours->head; v = v->next)
01891             CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
01892           newone->BoundingBox.X1 = p->contours->xmin;
01893           newone->BoundingBox.X2 = p->contours->xmax + 1;
01894           newone->BoundingBox.Y1 = p->contours->ymin;
01895           newone->BoundingBox.Y2 = p->contours->ymax + 1;
01896           AddObjectToCreateUndoList (POLYGON_TYPE, layer, newone, newone);
01897           newone->Clipped = p;
01898           p = p->f;             /* go to next pline */
01899           newone->Clipped->b = newone->Clipped->f = newone->Clipped;     /* unlink from others */
01900           r_insert_entry (layer->polygon_tree, (BoxType *) newone, 0);
01901           DrawPolygon (layer, newone);
01902         }
01903       else
01904         {
01905           POLYAREA *t = p;
01906 
01907           p = p->f;
01908           poly_DelContour (&t->contours);
01909           free (t);
01910         }
01911     }
01912   while (p != start);
01913   inhibit = false;
01914   IncrementUndoSerialNumber ();
01915   return many;
01916 }
01917 
01918 void debug_pline (PLINE *pl)
01919 {
01920   VNODE *v;
01921   pcb_fprintf (stderr, "\txmin %#mS xmax %#mS ymin %#mS ymax %#mS\n",
01922            pl->xmin, pl->xmax, pl->ymin, pl->ymax);
01923   v = &pl->head;
01924   while (v)
01925     {
01926       pcb_fprintf(stderr, "\t\tvnode: %#mD\n", v->point[0], v->point[1]);
01927       v = v->next;
01928       if (v == &pl->head)
01929         break;
01930     }
01931 }
01932 
01933 void
01934 debug_polyarea (POLYAREA *p)
01935 {
01936   PLINE *pl;
01937 
01938   fprintf (stderr, "POLYAREA %p\n", p);
01939   for (pl=p->contours; pl; pl=pl->next)
01940     debug_pline (pl);
01941 }
01942 
01943 void
01944 debug_polygon (PolygonType *p)
01945 {
01946   Cardinal i;
01947   POLYAREA *pa;
01948   fprintf (stderr, "POLYGON %p  %d pts\n", p, p->PointN);
01949   for (i=0; i<p->PointN; i++)
01950     pcb_fprintf(stderr, "\t%d: %#mD\n", i, p->Points[i].X, p->Points[i].Y);
01951   if (p->HoleIndexN)
01952     {
01953       fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN);
01954       for (i=0; i<p->HoleIndexN; i++)
01955         fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]);
01956     }
01957   else
01958     fprintf (stderr, "it has no holes\n");
01959   pa = p->Clipped;
01960   while (pa)
01961     {
01962       debug_polyarea (pa);
01963       pa = pa->f;
01964       if (pa == p->Clipped)
01965         break;
01966     }
01967 }
01968 
01973 void
01974 PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer,
01975                        POLYAREA *Input, FlagType Flags)
01976 {
01977   PolygonType *Polygon;
01978   POLYAREA *pa;
01979   PLINE *pline;
01980   VNODE *node;
01981   bool outer;
01982 
01983   if (Input == NULL)
01984     return;
01985 
01986   pa = Input;
01987   do
01988     {
01989       Polygon = CreateNewPolygon (Layer, Flags);
01990 
01991       pline = pa->contours;
01992       outer = true;
01993 
01994       do
01995         {
01996           if (!outer)
01997             CreateNewHoleInPolygon (Polygon);
01998           outer = false;
01999 
02000           node = &pline->head;
02001           do
02002             {
02003               CreateNewPointInPolygon (Polygon, node->point[0],
02004                                                 node->point[1]);
02005             }
02006           while ((node = node->next) != &pline->head);
02007 
02008         }
02009       while ((pline = pline->next) != NULL);
02010 
02011       InitClip (Destination, Layer, Polygon);
02012       SetPolygonBoundingBox (Polygon);
02013       if (!Layer->polygon_tree)
02014         Layer->polygon_tree = r_create_tree (NULL, 0, 0);
02015       r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
02016 
02017       DrawPolygon (Layer, Polygon);
02018       /* add to undo list */
02019       AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
02020     }
02021   while ((pa = pa->f) != Input);
02022 
02023   SetChangedFlag (true);
02024 }