Cleanup r_string when leaving make_route_string().
[geda-pcb/pcjc2.git] / src / polygon.c
blob82ebe61c44bed825cba02acef653f557c45075a4
1 /*!
2 * \file src/polygon.c
4 * \brief Special polygon editing routines.
6 * Here's a brief tour of the data and life of a polygon, courtesy of
7 * Ben Jackson:
9 * A PCB PolygonType contains an array of points outlining the polygon.
10 * This is what is manipulated by the UI and stored in the saved PCB.
12 * A PolygonType also contains a POLYAREA called 'Clipped' which is
13 * computed dynamically by InitClip every time a board is loaded.
14 * The point array is coverted to a POLYAREA by original_poly and then
15 * holes are cut in it by clearPoly.
16 * After that it is maintained dynamically as parts are added, moved or
17 * removed (this is why sometimes bugs can be fixed by just re-loading
18 * the board).
20 * A POLYAREA consists of a linked list of PLINE structures.
21 * The head of that list is POLYAREA.contours.
22 * The first contour is an outline of a filled region.
23 * All of the subsequent PLINEs are holes cut out of that first contour.
24 * POLYAREAs are in a doubly-linked list and each member of the list is
25 * an independent (non-overlapping) area with its own outline and holes.
26 * The function biggest() finds the largest POLYAREA so that
27 * PolygonType.Clipped points to that shape.
28 * The rest of the polygon still exists, it's just ignored when turning
29 * the polygon into copper.
31 * The first POLYAREA in PolygonType.Clipped is what is used for the
32 * vast majority of Polygon related tests.
33 * The basic logic for an intersection is "is the target shape inside
34 * POLYAREA.contours and NOT fully enclosed in any of
35 * POLYAREA.contours.next... (the holes)".
37 * The polygon dicer (NoHolesPolygonDicer and r_NoHolesPolygonDicer)
38 * emits a series of "simple" PLINE shapes.
39 * That is, the PLINE isn't linked to any other "holes" oulines.
40 * That's the meaning of the first test in r_NoHolesPolygonDicer.
41 * It is testing to see if the PLINE contour (the first, making it a
42 * solid outline) has a valid next pointer (which would point to one or
43 * more holes).
44 * The dicer works by recursively chopping the polygon in half through
45 * the first hole it sees (which is guaranteed to eliminate at least
46 * that one hole).
47 * The dicer output is used for HIDs which cannot render things with
48 * holes (which would require erasure).
50 * <hr>
52 * <h1><b>Copyright.</b></h1>\n
54 * PCB, interactive printed circuit board design
56 * Copyright (C) 1994,1995,1996,2010 Thomas Nau
58 * This program is free software; you can redistribute it and/or modify
59 * it under the terms of the GNU General Public License as published by
60 * the Free Software Foundation; either version 2 of the License, or
61 * (at your option) any later version.
63 * This program is distributed in the hope that it will be useful,
64 * but WITHOUT ANY WARRANTY; without even the implied warranty of
65 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66 * GNU General Public License for more details.
68 * You should have received a copy of the GNU General Public License
69 * along with this program; if not, write to the Free Software
70 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
72 * Contact addresses for paper mail and Email:
74 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
76 * Thomas.Nau@rz.uni-ulm.de
79 #ifdef HAVE_CONFIG_H
80 #include "config.h"
81 #endif
83 #include <assert.h>
84 #include <math.h>
85 #include <memory.h>
86 #include <setjmp.h>
88 #include "global.h"
89 #include "box.h"
90 #include "create.h"
91 #include "crosshair.h"
92 #include "data.h"
93 #include "draw.h"
94 #include "error.h"
95 #include "find.h"
96 #include "misc.h"
97 #include "move.h"
98 #include "pcb-printf.h"
99 #include "polygon.h"
100 #include "remove.h"
101 #include "rtree.h"
102 #include "search.h"
103 #include "set.h"
104 #include "thermal.h"
105 #include "undo.h"
107 #ifdef HAVE_LIBDMALLOC
108 #include <dmalloc.h>
109 #endif
111 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5 : (x) - 0.5)))
113 #define UNSUBTRACT_BLOAT 10
114 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100
115 #define SUBTRACT_LINE_BATCH_SIZE 20
117 static double rotate_circle_seg[4];
119 void
120 polygon_init (void)
122 double cos_ang = cos (2.0 * M_PI / POLY_CIRC_SEGS_F);
123 double sin_ang = sin (2.0 * M_PI / POLY_CIRC_SEGS_F);
125 rotate_circle_seg[0] = cos_ang; rotate_circle_seg[1] = -sin_ang;
126 rotate_circle_seg[2] = sin_ang; rotate_circle_seg[3] = cos_ang;
129 Cardinal
130 polygon_point_idx (PolygonType *polygon, PointType *point)
132 assert (point >= polygon->Points);
133 assert (point <= polygon->Points + polygon->PointN);
134 return ((char *)point - (char *)polygon->Points) / sizeof (PointType);
138 * \brief Find contour number.
140 * 0 for outer,
142 * 1 for first hole etc..
144 Cardinal
145 polygon_point_contour (PolygonType *polygon, Cardinal point)
147 Cardinal i;
148 Cardinal contour = 0;
150 for (i = 0; i < polygon->HoleIndexN; i++)
151 if (point >= polygon->HoleIndex[i])
152 contour = i + 1;
153 return contour;
156 Cardinal
157 next_contour_point (PolygonType *polygon, Cardinal point)
159 Cardinal contour;
160 Cardinal this_contour_start;
161 Cardinal next_contour_start;
163 contour = polygon_point_contour (polygon, point);
165 this_contour_start = (contour == 0) ? 0 :
166 polygon->HoleIndex[contour - 1];
167 next_contour_start =
168 (contour == polygon->HoleIndexN) ? polygon->PointN :
169 polygon->HoleIndex[contour];
171 /* Wrap back to the start of the contour we're in if we pass the end */
172 if (++point == next_contour_start)
173 point = this_contour_start;
175 return point;
178 Cardinal
179 prev_contour_point (PolygonType *polygon, Cardinal point)
181 Cardinal contour;
182 Cardinal prev_contour_end;
183 Cardinal this_contour_end;
185 contour = polygon_point_contour (polygon, point);
187 prev_contour_end = (contour == 0) ? 0 :
188 polygon->HoleIndex[contour - 1];
189 this_contour_end =
190 (contour == polygon->HoleIndexN) ? polygon->PointN - 1:
191 polygon->HoleIndex[contour] - 1;
193 /* Wrap back to the start of the contour we're in if we pass the end */
194 if (point == prev_contour_end)
195 point = this_contour_end;
196 else
197 point--;
199 return point;
202 static void
203 add_noholes_polyarea (PLINE *pline, void *user_data)
205 PolygonType *poly = (PolygonType *)user_data;
207 /* Prepend the pline into the NoHoles linked list */
208 pline->next = poly->NoHoles;
209 poly->NoHoles = pline;
212 void
213 ComputeNoHoles (PolygonType *poly)
215 poly_FreeContours (&poly->NoHoles);
216 if (poly->Clipped)
217 NoHolesPolygonDicer (poly, NULL, add_noholes_polyarea, poly);
218 else
219 printf ("Compute_noholes caught poly->Clipped = NULL\n");
220 poly->NoHolesValid = 1;
223 static POLYAREA *
224 biggest (POLYAREA * p)
226 POLYAREA *n, *top = NULL;
227 PLINE *pl;
228 rtree_t *tree;
229 double big = -1;
230 if (!p)
231 return NULL;
232 n = p;
235 #if 0
236 if (n->contours->area < PCB->IsleArea)
238 n->b->f = n->f;
239 n->f->b = n->b;
240 poly_DelContour (&n->contours);
241 if (n == p)
242 p = n->f;
243 n = n->f;
244 if (!n->contours)
246 free (n);
247 return NULL;
250 #endif
251 if (n->contours->area > big)
253 top = n;
254 big = n->contours->area;
257 while ((n = n->f) != p);
258 assert (top);
259 if (top == p)
260 return p;
261 pl = top->contours;
262 tree = top->contour_tree;
263 top->contours = p->contours;
264 top->contour_tree = p->contour_tree;
265 p->contours = pl;
266 p->contour_tree = tree;
267 assert (pl);
268 assert (p->f);
269 assert (p->b);
270 return p;
273 POLYAREA *
274 ContourToPoly (PLINE * contour)
276 POLYAREA *p;
277 poly_PreContour (contour, TRUE);
278 assert (contour->Flags.orient == PLF_DIR);
279 if (!(p = poly_Create ()))
280 return NULL;
281 poly_InclContour (p, contour);
282 assert (poly_Valid (p));
283 return p;
286 static POLYAREA *
287 original_poly (PolygonType * p)
289 PLINE *contour = NULL;
290 POLYAREA *np = NULL;
291 Cardinal n;
292 Vector v;
293 int hole = 0;
295 if ((np = poly_Create ()) == NULL)
296 return NULL;
298 /* first make initial polygon contour */
299 for (n = 0; n < p->PointN; n++)
301 /* No current contour? Make a new one starting at point */
302 /* (or) Add point to existing contour */
304 v[0] = p->Points[n].X;
305 v[1] = p->Points[n].Y;
306 if (contour == NULL)
308 if ((contour = poly_NewContour (v)) == NULL)
309 return NULL;
311 else
313 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
316 /* Is current point last in contour? If so process it. */
317 if (n == p->PointN - 1 ||
318 (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
320 poly_PreContour (contour, TRUE);
322 /* make sure it is a positive contour (outer) or negative (hole) */
323 if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR))
324 poly_InvContour (contour);
325 assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR));
327 poly_InclContour (np, contour);
328 contour = NULL;
329 assert (poly_Valid (np));
331 hole++;
334 return biggest (np);
337 POLYAREA *
338 PolygonToPoly (PolygonType *p)
340 return original_poly (p);
343 POLYAREA *
344 RectPoly (Coord x1, Coord x2, Coord y1, Coord y2)
346 PLINE *contour = NULL;
347 Vector v;
349 /* Return NULL for zero or negatively sized rectangles */
350 if (x2 <= x1 || y2 <= y1)
351 return NULL;
353 v[0] = x1;
354 v[1] = y1;
355 if ((contour = poly_NewContour (v)) == NULL)
356 return NULL;
357 v[0] = x2;
358 v[1] = y1;
359 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
360 v[0] = x2;
361 v[1] = y2;
362 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
363 v[0] = x1;
364 v[1] = y2;
365 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
366 return ContourToPoly (contour);
369 POLYAREA *
370 OctagonPoly (Coord x, Coord y, Coord radius)
372 PLINE *contour = NULL;
373 Vector v;
375 v[0] = x + ROUND (radius * 0.5);
376 v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2);
377 if ((contour = poly_NewContour (v)) == NULL)
378 return NULL;
379 v[0] = x + ROUND (radius * TAN_22_5_DEGREE_2);
380 v[1] = y + ROUND (radius * 0.5);
381 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
382 v[0] = x - (v[0] - x);
383 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
384 v[0] = x - ROUND (radius * 0.5);
385 v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2);
386 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
387 v[1] = y - (v[1] - y);
388 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
389 v[0] = x - ROUND (radius * TAN_22_5_DEGREE_2);
390 v[1] = y - ROUND (radius * 0.5);
391 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
392 v[0] = x - (v[0] - x);
393 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
394 v[0] = x + ROUND (radius * 0.5);
395 v[1] = y - ROUND (radius * TAN_22_5_DEGREE_2);
396 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
397 return ContourToPoly (contour);
401 * \brief Add vertices in a fractional-circle starting from v
402 * centered at X, Y and going counter-clockwise.
404 * Does not include the first point.
405 * last argument is 1 for a full circle.
406 * 2 for a half circle.
407 * or 4 for a quarter circle.
409 void
410 frac_circle (PLINE * c, Coord X, Coord Y, Vector v, int fraction)
412 double e1, e2, t1;
413 int i, range;
415 poly_InclVertex (c->head.prev, poly_CreateNode (v));
416 /* move vector to origin */
417 e1 = (v[0] - X) * POLY_CIRC_RADIUS_ADJ;
418 e2 = (v[1] - Y) * POLY_CIRC_RADIUS_ADJ;
420 /* NB: the caller adds the last vertex, hence the -1 */
421 range = POLY_CIRC_SEGS / fraction - 1;
422 for (i = 0; i < range; i++)
424 /* rotate the vector */
425 t1 = rotate_circle_seg[0] * e1 + rotate_circle_seg[1] * e2;
426 e2 = rotate_circle_seg[2] * e1 + rotate_circle_seg[3] * e2;
427 e1 = t1;
428 v[0] = X + ROUND (e1);
429 v[1] = Y + ROUND (e2);
430 poly_InclVertex (c->head.prev, poly_CreateNode (v));
435 * \brief Create a circle approximation from lines.
437 POLYAREA *
438 CirclePoly (Coord x, Coord y, Coord radius)
440 PLINE *contour;
441 Vector v;
443 if (radius <= 0)
444 return NULL;
445 v[0] = x + radius;
446 v[1] = y;
447 if ((contour = poly_NewContour (v)) == NULL)
448 return NULL;
449 frac_circle (contour, x, y, v, 1);
450 contour->is_round = TRUE;
451 contour->cx = x;
452 contour->cy = y;
453 contour->radius = radius;
454 return ContourToPoly (contour);
458 * \brief Make a rounded-corner rectangle with radius t beyond
459 * x1,x2,y1,y2 rectangle.
461 POLYAREA *
462 RoundRect (Coord x1, Coord x2, Coord y1, Coord y2, Coord t)
464 PLINE *contour = NULL;
465 Vector v;
467 assert (x2 > x1);
468 assert (y2 > y1);
469 v[0] = x1 - t;
470 v[1] = y1;
471 if ((contour = poly_NewContour (v)) == NULL)
472 return NULL;
473 frac_circle (contour, x1, y1, v, 4);
474 v[0] = x2;
475 v[1] = y1 - t;
476 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
477 frac_circle (contour, x2, y1, v, 4);
478 v[0] = x2 + t;
479 v[1] = y2;
480 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
481 frac_circle (contour, x2, y2, v, 4);
482 v[0] = x1;
483 v[1] = y2 + t;
484 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
485 frac_circle (contour, x1, y2, v, 4);
486 return ContourToPoly (contour);
489 #define ARC_ANGLE 5
490 static POLYAREA *
491 ArcPolyNoIntersect (ArcType * a, Coord thick)
493 PLINE *contour = NULL;
494 POLYAREA *np = NULL;
495 Vector v;
496 BoxType *ends;
497 int i, segs;
498 double ang, da, rx, ry;
499 long half;
500 double radius_adj;
502 if (thick <= 0)
503 return NULL;
504 if (a->Delta < 0)
506 a->StartAngle += a->Delta;
507 a->Delta = -a->Delta;
509 half = (thick + 1) / 2;
510 ends = GetArcEnds (a);
511 /* start with inner radius */
512 rx = MAX (a->Width - half, 0);
513 ry = MAX (a->Height - half, 0);
514 segs = 1;
515 if(thick > 0)
516 segs = MAX (segs, a->Delta * M_PI / 360 *
517 sqrt (hypot (rx, ry) /
518 POLY_ARC_MAX_DEVIATION / 2 / thick));
519 segs = MAX(segs, a->Delta / ARC_ANGLE);
521 ang = a->StartAngle;
522 da = (1.0 * a->Delta) / segs;
523 radius_adj = (M_PI*da/360)*(M_PI*da/360)/2;
524 v[0] = a->X - rx * cos (ang * M180);
525 v[1] = a->Y + ry * sin (ang * M180);
526 if ((contour = poly_NewContour (v)) == NULL)
527 return 0;
528 for (i = 0; i < segs - 1; i++)
530 ang += da;
531 v[0] = a->X - rx * cos (ang * M180);
532 v[1] = a->Y + ry * sin (ang * M180);
533 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
535 /* find last point */
536 ang = a->StartAngle + a->Delta;
537 v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj);
538 v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj);
539 /* add the round cap at the end */
540 frac_circle (contour, ends->X2, ends->Y2, v, 2);
541 /* and now do the outer arc (going backwards) */
542 rx = (a->Width + half) * (1+radius_adj);
543 ry = (a->Width + half) * (1+radius_adj);
544 da = -da;
545 for (i = 0; i < segs; i++)
547 v[0] = a->X - rx * cos (ang * M180);
548 v[1] = a->Y + ry * sin (ang * M180);
549 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
550 ang += da;
552 /* now add other round cap */
553 ang = a->StartAngle;
554 v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj);
555 v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj);
556 frac_circle (contour, ends->X1, ends->Y1, v, 2);
557 /* now we have the whole contour */
558 if (!(np = ContourToPoly (contour)))
559 return NULL;
560 return np;
563 #define MIN_CLEARANCE_BEFORE_BISECT 10.
564 POLYAREA *
565 ArcPoly (ArcType * a, Coord thick)
567 double delta;
568 ArcType seg1, seg2;
569 POLYAREA *tmp1, *tmp2, *res;
571 delta = (a->Delta < 0) ? -a->Delta : a->Delta;
573 /* If the arc segment would self-intersect, we need to construct it as the union of
574 two non-intersecting segments */
576 if (2 * M_PI * a->Width * (1. - (double)delta / 360.) - thick < MIN_CLEARANCE_BEFORE_BISECT)
578 int half_delta = a->Delta / 2;
580 seg1 = seg2 = *a;
581 seg1.Delta = half_delta;
582 seg2.Delta -= half_delta;
583 seg2.StartAngle += half_delta;
585 tmp1 = ArcPolyNoIntersect (&seg1, thick);
586 tmp2 = ArcPolyNoIntersect (&seg2, thick);
587 poly_Boolean_free (tmp1, tmp2, &res, PBO_UNITE);
588 return res;
591 return ArcPolyNoIntersect (a, thick);
594 POLYAREA *
595 LinePoly (LineType * L, Coord thick)
597 PLINE *contour = NULL;
598 POLYAREA *np = NULL;
599 Vector v;
600 double d, dx, dy;
601 long half;LineType _l=*L,*l=&_l;
603 if (thick <= 0)
604 return NULL;
605 half = (thick + 1) / 2;
606 d = hypot (l->Point1.X - l->Point2.X, l->Point1.Y - l->Point2.Y);
607 if (!TEST_FLAG (SQUAREFLAG,l))
608 if (d == 0) /* line is a point */
609 return CirclePoly (l->Point1.X, l->Point1.Y, half);
610 if (d != 0)
612 d = half / d;
613 dx = (l->Point1.Y - l->Point2.Y) * d;
614 dy = (l->Point2.X - l->Point1.X) * d;
616 else
618 dx = half;
619 dy = 0;
621 if (TEST_FLAG (SQUAREFLAG,l))/* take into account the ends */
623 l->Point1.X -= dy;
624 l->Point1.Y += dx;
625 l->Point2.X += dy;
626 l->Point2.Y -= dx;
628 v[0] = l->Point1.X - dx;
629 v[1] = l->Point1.Y - dy;
630 if ((contour = poly_NewContour (v)) == NULL)
631 return 0;
632 v[0] = l->Point2.X - dx;
633 v[1] = l->Point2.Y - dy;
634 if (TEST_FLAG (SQUAREFLAG,l))
635 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
636 else
637 frac_circle (contour, l->Point2.X, l->Point2.Y, v, 2);
638 v[0] = l->Point2.X + dx;
639 v[1] = l->Point2.Y + dy;
640 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
641 v[0] = l->Point1.X + dx;
642 v[1] = l->Point1.Y + dy;
643 if (TEST_FLAG (SQUAREFLAG,l))
644 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
645 else
646 frac_circle (contour, l->Point1.X, l->Point1.Y, v, 2);
647 /* now we have the line contour */
648 if (!(np = ContourToPoly (contour)))
649 return NULL;
650 return np;
654 * \brief Make a rounded-corner rectangle.
656 POLYAREA *
657 SquarePadPoly (PadType * pad, Coord clear)
659 PLINE *contour = NULL;
660 POLYAREA *np = NULL;
661 Vector v;
662 double d;
663 double tx, ty;
664 double cx, cy;
665 PadType _t=*pad,*t=&_t;
666 PadType _c=*pad,*c=&_c;
667 int halfthick = (pad->Thickness + 1) / 2;
668 int halfclear = (clear + 1) / 2;
670 d = hypot (pad->Point1.X - pad->Point2.X, pad->Point1.Y - pad->Point2.Y);
671 if (d != 0)
673 double a = halfthick / d;
674 tx = (t->Point1.Y - t->Point2.Y) * a;
675 ty = (t->Point2.X - t->Point1.X) * a;
676 a = halfclear / d;
677 cx = (c->Point1.Y - c->Point2.Y) * a;
678 cy = (c->Point2.X - c->Point1.X) * a;
680 t->Point1.X -= ty;
681 t->Point1.Y += tx;
682 t->Point2.X += ty;
683 t->Point2.Y -= tx;
684 c->Point1.X -= cy;
685 c->Point1.Y += cx;
686 c->Point2.X += cy;
687 c->Point2.Y -= cx;
689 else
691 tx = halfthick;
692 ty = 0;
693 cx = halfclear;
694 cy = 0;
696 t->Point1.Y += tx;
697 t->Point2.Y -= tx;
698 c->Point1.Y += cx;
699 c->Point2.Y -= cx;
702 v[0] = c->Point1.X - tx;
703 v[1] = c->Point1.Y - ty;
704 if ((contour = poly_NewContour (v)) == NULL)
705 return 0;
706 frac_circle (contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4);
708 v[0] = t->Point2.X - cx;
709 v[1] = t->Point2.Y - cy;
710 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
711 frac_circle (contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4);
713 v[0] = c->Point2.X + tx;
714 v[1] = c->Point2.Y + ty;
715 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
716 frac_circle (contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4);
718 v[0] = t->Point1.X + cx;
719 v[1] = t->Point1.Y + cy;
720 poly_InclVertex (contour->head.prev, poly_CreateNode (v));
721 frac_circle (contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4);
723 /* now we have the line contour */
724 if (!(np = ContourToPoly (contour)))
725 return NULL;
726 return np;
730 * \brief Clear np1 from the polygon.
732 static int
733 Subtract (POLYAREA * np1, PolygonType * p, bool fnp)
735 POLYAREA *merged = NULL, *np = np1;
736 int x;
737 assert (np);
738 assert (p);
739 if (!p->Clipped)
741 if (fnp)
742 poly_Free (&np);
743 return 1;
745 assert (poly_Valid (p->Clipped));
746 assert (poly_Valid (np));
747 if (fnp)
748 x = poly_Boolean_free (p->Clipped, np, &merged, PBO_SUB);
749 else
751 x = poly_Boolean (p->Clipped, np, &merged, PBO_SUB);
752 poly_Free (&p->Clipped);
754 assert (!merged || poly_Valid (merged));
755 if (x != err_ok)
757 fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x);
758 poly_Free (&merged);
759 p->Clipped = NULL;
760 if (p->NoHoles) printf ("Just leaked in Subtract\n");
761 p->NoHoles = NULL;
762 return -1;
764 p->Clipped = biggest (merged);
765 assert (!p->Clipped || poly_Valid (p->Clipped));
766 if (!p->Clipped)
767 Message ("Polygon cleared out of existence near (%d, %d)\n",
768 (p->BoundingBox.X1 + p->BoundingBox.X2) / 2,
769 (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2);
770 return 1;
774 * \brief Create a polygon of the pin clearance.
776 POLYAREA *
777 PinPoly (PinType * pin, Coord thick, Coord clear)
779 int size;
781 if (TEST_FLAG (SQUAREFLAG, pin))
783 size = (thick + 1) / 2;
784 return RoundRect (pin->X - size, pin->X + size, pin->Y - size,
785 pin->Y + size, (clear + 1) / 2);
787 else
789 size = (thick + clear + 1) / 2;
790 if (TEST_FLAG (OCTAGONFLAG, pin))
792 return OctagonPoly (pin->X, pin->Y, size + size);
795 return CirclePoly (pin->X, pin->Y, size);
798 POLYAREA *
799 BoxPolyBloated (BoxType *box, Coord bloat)
801 return RectPoly (box->X1 - bloat, box->X2 + bloat,
802 box->Y1 - bloat, box->Y2 + bloat);
806 * \brief Remove the pin clearance from the polygon.
808 static int
809 SubtractPin (DataType * d, PinType * pin, LayerType * l, PolygonType * p)
811 POLYAREA *np;
812 Cardinal i;
814 if (pin->Clearance == 0)
815 return 0;
816 i = GetLayerNumber (d, l);
817 if (TEST_THERM (i, pin))
819 np = ThermPoly ((PCBType *) (d->pcb), pin, i);
820 if (!np)
821 return 0;
823 else
825 np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance);
826 if (!np)
827 return -1;
829 return Subtract (np, p, TRUE);
832 static int
833 SubtractLine (LineType * line, PolygonType * p)
835 POLYAREA *np;
837 if (!TEST_FLAG (CLEARLINEFLAG, line))
838 return 0;
839 if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
840 return -1;
841 return Subtract (np, p, true);
844 static int
845 SubtractArc (ArcType * arc, PolygonType * p)
847 POLYAREA *np;
849 if (!TEST_FLAG (CLEARLINEFLAG, arc))
850 return 0;
851 if (!(np = ArcPoly (arc, arc->Thickness + arc->Clearance)))
852 return -1;
853 return Subtract (np, p, true);
856 static int
857 SubtractText (TextType * text, PolygonType * p)
859 POLYAREA *np;
860 const BoxType *b = &text->BoundingBox;
862 if (!TEST_FLAG (CLEARLINEFLAG, text))
863 return 0;
864 if (!(np = RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat,
865 b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat)))
866 return -1;
867 return Subtract (np, p, true);
870 static int
871 SubtractPad (PadType * pad, PolygonType * p)
873 POLYAREA *np = NULL;
875 if (pad->Clearance == 0)
876 return 0;
877 if (TEST_FLAG (SQUAREFLAG, pad))
879 if (!
880 (np = SquarePadPoly (pad, pad->Thickness + pad->Clearance)))
881 return -1;
883 else
885 if (!
886 (np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance)))
887 return -1;
889 return Subtract (np, p, true);
892 struct cpInfo
894 const BoxType *other;
895 DataType *data;
896 LayerType *layer;
897 PolygonType *polygon;
898 bool bottom;
899 POLYAREA *accumulate;
900 int batch_size;
901 jmp_buf env;
904 static void
905 subtract_accumulated (struct cpInfo *info, PolygonType *polygon)
907 if (info->accumulate == NULL)
908 return;
909 Subtract (info->accumulate, polygon, true);
910 info->accumulate = NULL;
911 info->batch_size = 0;
914 static int
915 pin_sub_callback (const BoxType * b, void *cl)
917 PinType *pin = (PinType *) b;
918 struct cpInfo *info = (struct cpInfo *) cl;
919 PolygonType *polygon;
920 POLYAREA *np;
921 POLYAREA *merged;
922 Cardinal i;
924 /* don't subtract the object that was put back! */
925 if (b == info->other)
926 return 0;
927 polygon = info->polygon;
929 if (pin->Clearance == 0)
930 return 0;
931 i = GetLayerNumber (info->data, info->layer);
932 if (TEST_THERM (i, pin))
934 np = ThermPoly ((PCBType *) (info->data->pcb), pin, i);
935 if (!np)
936 return 1;
938 else
940 np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance);
941 if (!np)
942 longjmp (info->env, 1);
945 poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
946 info->accumulate = merged;
948 info->batch_size ++;
950 if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE)
951 subtract_accumulated (info, polygon);
953 return 1;
956 static int
957 arc_sub_callback (const BoxType * b, void *cl)
959 ArcType *arc = (ArcType *) b;
960 struct cpInfo *info = (struct cpInfo *) cl;
961 PolygonType *polygon;
963 /* don't subtract the object that was put back! */
964 if (b == info->other)
965 return 0;
966 if (!TEST_FLAG (CLEARLINEFLAG, arc))
967 return 0;
968 polygon = info->polygon;
969 if (SubtractArc (arc, polygon) < 0)
970 longjmp (info->env, 1);
971 return 1;
974 static int
975 pad_sub_callback (const BoxType * b, void *cl)
977 PadType *pad = (PadType *) b;
978 struct cpInfo *info = (struct cpInfo *) cl;
979 PolygonType *polygon;
981 /* don't subtract the object that was put back! */
982 if (b == info->other)
983 return 0;
984 if (pad->Clearance == 0)
985 return 0;
986 polygon = info->polygon;
987 if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), !info->bottom))
989 if (SubtractPad (pad, polygon) < 0)
990 longjmp (info->env, 1);
991 return 1;
993 return 0;
996 static int
997 line_sub_callback (const BoxType * b, void *cl)
999 LineType *line = (LineType *) b;
1000 struct cpInfo *info = (struct cpInfo *) cl;
1001 PolygonType *polygon;
1002 POLYAREA *np;
1003 POLYAREA *merged;
1005 /* don't subtract the object that was put back! */
1006 if (b == info->other)
1007 return 0;
1008 if (!TEST_FLAG (CLEARLINEFLAG, line))
1009 return 0;
1010 polygon = info->polygon;
1012 if (!(np = LinePoly (line, line->Thickness + line->Clearance)))
1013 longjmp (info->env, 1);
1015 poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE);
1016 info->accumulate = merged;
1017 info->batch_size ++;
1019 if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE)
1020 subtract_accumulated (info, polygon);
1022 return 1;
1025 static int
1026 text_sub_callback (const BoxType * b, void *cl)
1028 TextType *text = (TextType *) b;
1029 struct cpInfo *info = (struct cpInfo *) cl;
1030 PolygonType *polygon;
1032 /* don't subtract the object that was put back! */
1033 if (b == info->other)
1034 return 0;
1035 if (!TEST_FLAG (CLEARLINEFLAG, text))
1036 return 0;
1037 polygon = info->polygon;
1038 if (SubtractText (text, polygon) < 0)
1039 longjmp (info->env, 1);
1040 return 1;
1043 static int
1044 Group (DataType *Data, Cardinal layer)
1046 Cardinal i, j;
1047 for (i = 0; i < max_group; i++)
1048 for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++)
1049 if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j])
1050 return i;
1051 return i;
1054 static int
1055 clearPoly (DataType *Data, LayerType *Layer, PolygonType * polygon,
1056 const BoxType * here, Coord expand)
1058 int r = 0;
1059 BoxType region;
1060 struct cpInfo info;
1061 Cardinal group;
1063 if (!TEST_FLAG (CLEARPOLYFLAG, polygon)
1064 || GetLayerNumber (Data, Layer) >= max_copper_layer)
1065 return 0;
1066 group = Group (Data, GetLayerNumber (Data, Layer));
1067 info.bottom = (group == Group (Data, bottom_silk_layer));
1068 info.data = Data;
1069 info.other = here;
1070 info.layer = Layer;
1071 info.polygon = polygon;
1072 if (here)
1073 region = clip_box (here, &polygon->BoundingBox);
1074 else
1075 region = polygon->BoundingBox;
1076 region = bloat_box (&region, expand);
1078 if (setjmp (info.env) == 0)
1080 r = 0;
1081 info.accumulate = NULL;
1082 info.batch_size = 0;
1083 if (info.bottom || group == Group (Data, top_silk_layer))
1084 r += r_search (Data->pad_tree, &region, NULL, pad_sub_callback, &info);
1085 GROUP_LOOP (Data, group);
1087 r +=
1088 r_search (layer->line_tree, &region, NULL, line_sub_callback,
1089 &info);
1090 subtract_accumulated (&info, polygon);
1091 r +=
1092 r_search (layer->arc_tree, &region, NULL, arc_sub_callback, &info);
1093 r +=
1094 r_search (layer->text_tree, &region, NULL, text_sub_callback, &info);
1096 END_LOOP;
1097 r += r_search (Data->via_tree, &region, NULL, pin_sub_callback, &info);
1098 r += r_search (Data->pin_tree, &region, NULL, pin_sub_callback, &info);
1099 subtract_accumulated (&info, polygon);
1101 polygon->NoHolesValid = 0;
1102 return r;
1105 static int
1106 Unsubtract (POLYAREA * np1, PolygonType * p)
1108 POLYAREA *merged = NULL, *np = np1;
1109 POLYAREA *orig_poly, *clipped_np;
1110 int x;
1111 assert (np);
1112 assert (p && p->Clipped);
1114 orig_poly = original_poly (p);
1116 x = poly_Boolean_free (np, orig_poly, &clipped_np, PBO_ISECT);
1117 if (x != err_ok)
1119 fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x);
1120 poly_Free (&clipped_np);
1121 goto fail;
1124 x = poly_Boolean_free (p->Clipped, clipped_np, &merged, PBO_UNITE);
1125 if (x != err_ok)
1127 fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x);
1128 poly_Free (&merged);
1129 goto fail;
1131 p->Clipped = biggest (merged);
1132 assert (!p->Clipped || poly_Valid (p->Clipped));
1133 return 1;
1135 fail:
1136 p->Clipped = NULL;
1137 if (p->NoHoles) printf ("Just leaked in Unsubtract\n");
1138 p->NoHoles = NULL;
1139 return 0;
1142 static int
1143 UnsubtractPin (PinType * pin, LayerType * l, PolygonType * p)
1145 POLYAREA *np;
1147 /* overlap a bit to prevent gaps from rounding errors */
1148 np = BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT);
1150 if (!np)
1151 return 0;
1152 if (!Unsubtract (np, p))
1153 return 0;
1154 clearPoly (PCB->Data, l, p, (const BoxType *) pin, 2 * UNSUBTRACT_BLOAT);
1155 return 1;
1158 static int
1159 UnsubtractArc (ArcType * arc, LayerType * l, PolygonType * p)
1161 POLYAREA *np;
1163 if (!TEST_FLAG (CLEARLINEFLAG, arc))
1164 return 0;
1166 /* overlap a bit to prevent gaps from rounding errors */
1167 np = BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT);
1169 if (!np)
1170 return 0;
1171 if (!Unsubtract (np, p))
1172 return 0;
1173 clearPoly (PCB->Data, l, p, (const BoxType *) arc, 2 * UNSUBTRACT_BLOAT);
1174 return 1;
1177 static int
1178 UnsubtractLine (LineType * line, LayerType * l, PolygonType * p)
1180 POLYAREA *np;
1182 if (!TEST_FLAG (CLEARLINEFLAG, line))
1183 return 0;
1185 /* overlap a bit to prevent notches from rounding errors */
1186 np = BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT);
1188 if (!np)
1189 return 0;
1190 if (!Unsubtract (np, p))
1191 return 0;
1192 clearPoly (PCB->Data, l, p, (const BoxType *) line, 2 * UNSUBTRACT_BLOAT);
1193 return 1;
1196 static int
1197 UnsubtractText (TextType * text, LayerType * l, PolygonType * p)
1199 POLYAREA *np;
1201 if (!TEST_FLAG (CLEARLINEFLAG, text))
1202 return 0;
1204 /* overlap a bit to prevent notches from rounding errors */
1205 np = BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT);
1207 if (!np)
1208 return -1;
1209 if (!Unsubtract (np, p))
1210 return 0;
1211 clearPoly (PCB->Data, l, p, (const BoxType *) text, 2 * UNSUBTRACT_BLOAT);
1212 return 1;
1215 static int
1216 UnsubtractPad (PadType * pad, LayerType * l, PolygonType * p)
1218 POLYAREA *np;
1220 /* overlap a bit to prevent notches from rounding errors */
1221 np = BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT);
1223 if (!np)
1224 return 0;
1225 if (!Unsubtract (np, p))
1226 return 0;
1227 clearPoly (PCB->Data, l, p, (const BoxType *) pad, 2 * UNSUBTRACT_BLOAT);
1228 return 1;
1231 static bool inhibit = false;
1234 InitClip (DataType *Data, LayerType *layer, PolygonType * p)
1236 if (inhibit)
1237 return 0;
1238 if (p->Clipped)
1239 poly_Free (&p->Clipped);
1240 p->Clipped = original_poly (p);
1241 poly_FreeContours (&p->NoHoles);
1242 if (!p->Clipped)
1243 return 0;
1244 assert (poly_Valid (p->Clipped));
1245 if (TEST_FLAG (CLEARPOLYFLAG, p))
1246 clearPoly (Data, layer, p, NULL, 0);
1247 else
1248 p->NoHolesValid = 0;
1249 return 1;
1253 * \brief Remove redundant polygon points.
1255 * Any point that lies on the straight line between the points on either
1256 * side of it is redundant.
1258 * \return True if any points are removed.
1260 bool
1261 RemoveExcessPolygonPoints (LayerType *Layer, PolygonType *Polygon)
1263 PointType *p;
1264 Cardinal n, prev, next;
1265 LineType line;
1266 bool changed = false;
1268 if (Undoing ())
1269 return (false);
1271 for (n = 0; n < Polygon->PointN; n++)
1273 prev = prev_contour_point (Polygon, n);
1274 next = next_contour_point (Polygon, n);
1275 p = &Polygon->Points[n];
1277 line.Point1 = Polygon->Points[prev];
1278 line.Point2 = Polygon->Points[next];
1279 line.Thickness = 0;
1280 if (IsPointOnLine (p->X, p->Y, 0.0, &line))
1282 RemoveObject (POLYGONPOINT_TYPE, Layer, Polygon, p);
1283 changed = true;
1286 return (changed);
1290 * \brief .
1292 * \return The index of the polygon point which is the end point of the
1293 * segment with the lowest distance to the passed coordinates.
1295 Cardinal
1296 GetLowestDistancePolygonPoint (PolygonType *Polygon, Coord X, Coord Y)
1298 double mindistance = (double) MAX_COORD * MAX_COORD;
1299 PointType *ptr1, *ptr2;
1300 Cardinal n, result = 0;
1302 /* we calculate the distance to each segment and choose the
1303 * shortest distance. If the closest approach between the
1304 * given point and the projected line (i.e. the segment extended)
1305 * is not on the segment, then the distance is the distance
1306 * to the segment end point.
1309 for (n = 0; n < Polygon->PointN; n++)
1311 double u, dx, dy;
1312 ptr1 = &Polygon->Points[prev_contour_point (Polygon, n)];
1313 ptr2 = &Polygon->Points[n];
1315 dx = ptr2->X - ptr1->X;
1316 dy = ptr2->Y - ptr1->Y;
1317 if (dx != 0.0 || dy != 0.0)
1319 /* projected intersection is at P1 + u(P2 - P1) */
1320 u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy);
1322 if (u < 0.0)
1323 { /* ptr1 is closest point */
1324 u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y);
1326 else if (u > 1.0)
1327 { /* ptr2 is closest point */
1328 u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y);
1330 else
1331 { /* projected intersection is closest point */
1332 u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) +
1333 SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y);
1335 if (u < mindistance)
1337 mindistance = u;
1338 result = n;
1342 return (result);
1346 * \brief Go back to the previous point of the polygon.
1348 void
1349 GoToPreviousPoint (void)
1351 switch (Crosshair.AttachedPolygon.PointN)
1353 /* do nothing if mode has just been entered */
1354 case 0:
1355 break;
1357 /* reset number of points and 'LINE_MODE' state */
1358 case 1:
1359 Crosshair.AttachedPolygon.PointN = 0;
1360 Crosshair.AttachedLine.State = STATE_FIRST;
1361 addedLines = 0;
1362 break;
1364 /* back-up one point */
1365 default:
1367 PointType *points = Crosshair.AttachedPolygon.Points;
1368 Cardinal n = Crosshair.AttachedPolygon.PointN - 2;
1370 Crosshair.AttachedPolygon.PointN--;
1371 Crosshair.AttachedLine.Point1.X = points[n].X;
1372 Crosshair.AttachedLine.Point1.Y = points[n].Y;
1373 break;
1379 * \brief Close polygon if possible.
1381 void
1382 ClosePolygon (void)
1384 Cardinal n = Crosshair.AttachedPolygon.PointN;
1386 /* check number of points */
1387 if (n >= 3)
1389 /* if 45 degree lines are what we want do a quick check
1390 * if closing the polygon makes sense
1392 if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB))
1394 Coord dx, dy;
1396 dx = abs (Crosshair.AttachedPolygon.Points[n - 1].X -
1397 Crosshair.AttachedPolygon.Points[0].X);
1398 dy = abs (Crosshair.AttachedPolygon.Points[n - 1].Y -
1399 Crosshair.AttachedPolygon.Points[0].Y);
1400 if (!(dx == 0 || dy == 0 || dx == dy))
1402 Message
1404 ("Cannot close polygon because 45 degree lines are requested.\n"));
1405 return;
1408 CopyAttachedPolygonToLayer ();
1409 Draw ();
1411 else
1412 Message (_("A polygon has to have at least 3 points\n"));
1416 * \brief Moves the data of the attached (new) polygon to the current
1417 * layer.
1419 void
1420 CopyAttachedPolygonToLayer (void)
1422 PolygonType *polygon;
1423 int saveID;
1425 /* move data to layer and clear attached struct */
1426 polygon = CreateNewPolygon (CURRENT, NoFlags ());
1427 saveID = polygon->ID;
1428 *polygon = Crosshair.AttachedPolygon;
1429 polygon->ID = saveID;
1430 SET_FLAG (CLEARPOLYFLAG, polygon);
1431 if (TEST_FLAG (NEWFULLPOLYFLAG, PCB))
1432 SET_FLAG (FULLPOLYFLAG, polygon);
1433 memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType));
1434 SetPolygonBoundingBox (polygon);
1435 if (!CURRENT->polygon_tree)
1436 CURRENT->polygon_tree = r_create_tree (NULL, 0, 0);
1437 r_insert_entry (CURRENT->polygon_tree, (BoxType *) polygon, 0);
1438 InitClip (PCB->Data, CURRENT, polygon);
1439 DrawPolygon (CURRENT, polygon);
1440 SetChangedFlag (true);
1442 /* reset state of attached line */
1443 Crosshair.AttachedLine.State = STATE_FIRST;
1444 addedLines = 0;
1446 /* add to undo list */
1447 AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon);
1448 IncrementUndoSerialNumber ();
1452 * \brief Find polygon holes in range, then call the callback function
1453 * for each hole.
1455 * If the callback returns non-zero, stop the search.
1458 PolygonHoles (PolygonType *polygon, const BoxType *range,
1459 int (*callback) (PLINE *contour, void *user_data),
1460 void *user_data)
1462 POLYAREA *pa = polygon->Clipped;
1463 PLINE *pl;
1464 /* If this hole is so big the polygon doesn't exist, then it's not
1465 * really a hole.
1467 if (!pa)
1468 return 0;
1469 for (pl = pa->contours->next; pl; pl = pl->next)
1471 if (range != NULL &&
1472 (pl->xmin > range->X2 || pl->xmax < range->X1 ||
1473 pl->ymin > range->Y2 || pl->ymax < range->Y1))
1474 continue;
1475 if (callback (pl, user_data))
1477 return 1;
1480 return 0;
1483 struct plow_info
1485 int type;
1486 void *ptr1, *ptr2;
1487 LayerType *layer;
1488 DataType *data;
1489 int (*callback) (DataType *, LayerType *, PolygonType *, int, void *,
1490 void *, void *);
1491 void *userdata;
1494 static int
1495 subtract_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon,
1496 int type, void *ptr1, void *ptr2, void *userdata)
1498 if (!Polygon->Clipped)
1499 return 0;
1500 switch (type)
1502 case PIN_TYPE:
1503 case VIA_TYPE:
1504 SubtractPin (Data, (PinType *) ptr2, Layer, Polygon);
1505 Polygon->NoHolesValid = 0;
1506 return 1;
1507 case LINE_TYPE:
1508 SubtractLine ((LineType *) ptr2, Polygon);
1509 Polygon->NoHolesValid = 0;
1510 return 1;
1511 case ARC_TYPE:
1512 SubtractArc ((ArcType *) ptr2, Polygon);
1513 Polygon->NoHolesValid = 0;
1514 return 1;
1515 case PAD_TYPE:
1516 SubtractPad ((PadType *) ptr2, Polygon);
1517 Polygon->NoHolesValid = 0;
1518 return 1;
1519 case TEXT_TYPE:
1520 SubtractText ((TextType *) ptr2, Polygon);
1521 Polygon->NoHolesValid = 0;
1522 return 1;
1524 return 0;
1527 static int
1528 add_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon,
1529 int type, void *ptr1, void *ptr2, void *userdata)
1531 switch (type)
1533 case PIN_TYPE:
1534 case VIA_TYPE:
1535 UnsubtractPin ((PinType *) ptr2, Layer, Polygon);
1536 return 1;
1537 case LINE_TYPE:
1538 UnsubtractLine ((LineType *) ptr2, Layer, Polygon);
1539 return 1;
1540 case ARC_TYPE:
1541 UnsubtractArc ((ArcType *) ptr2, Layer, Polygon);
1542 return 1;
1543 case PAD_TYPE:
1544 UnsubtractPad ((PadType *) ptr2, Layer, Polygon);
1545 return 1;
1546 case TEXT_TYPE:
1547 UnsubtractText ((TextType *) ptr2, Layer, Polygon);
1548 return 1;
1550 return 0;
1553 static int
1554 plow_callback (const BoxType * b, void *cl)
1556 struct plow_info *plow = (struct plow_info *) cl;
1557 PolygonType *polygon = (PolygonType *) b;
1559 if (TEST_FLAG (CLEARPOLYFLAG, polygon))
1560 return plow->callback (plow->data, plow->layer, polygon, plow->type,
1561 plow->ptr1, plow->ptr2, plow->userdata);
1562 return 0;
1566 PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2,
1567 int (*call_back) (DataType *data, LayerType *lay,
1568 PolygonType *poly, int type, void *ptr1,
1569 void *ptr2, void *userdata),
1570 void *userdata)
1572 BoxType sb = ((PinType *) ptr2)->BoundingBox;
1573 int r = 0;
1574 struct plow_info info;
1576 info.type = type;
1577 info.ptr1 = ptr1;
1578 info.ptr2 = ptr2;
1579 info.data = Data;
1580 info.callback = call_back;
1581 info.userdata = userdata;
1582 switch (type)
1584 case PIN_TYPE:
1585 case VIA_TYPE:
1586 if (type == PIN_TYPE || ptr1 == ptr2 || ptr1 == NULL)
1588 LAYER_LOOP (Data, max_copper_layer);
1590 info.layer = layer;
1591 r +=
1592 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
1594 END_LOOP;
1596 else
1598 GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data,
1599 ((LayerType *) ptr1))));
1601 info.layer = layer;
1602 r +=
1603 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
1605 END_LOOP;
1607 break;
1608 case LINE_TYPE:
1609 case ARC_TYPE:
1610 case TEXT_TYPE:
1611 /* the cast works equally well for lines and arcs */
1612 if (!TEST_FLAG (CLEARLINEFLAG, (LineType *) ptr2))
1613 return 0;
1614 /* silk doesn't plow */
1615 if (GetLayerNumber (Data, (LayerType *)ptr1) >= max_copper_layer)
1616 return 0;
1617 GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data,
1618 ((LayerType *) ptr1))));
1620 info.layer = layer;
1621 r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
1623 END_LOOP;
1624 break;
1625 case PAD_TYPE:
1627 Cardinal group = GetLayerGroupNumberByNumber (
1628 TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ?
1629 bottom_silk_layer : top_silk_layer);
1630 GROUP_LOOP (Data, group);
1632 info.layer = layer;
1633 r +=
1634 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info);
1636 END_LOOP;
1638 break;
1640 case ELEMENT_TYPE:
1642 PIN_LOOP ((ElementType *) ptr1);
1644 PlowsPolygon (Data, PIN_TYPE, ptr1, pin, call_back, userdata);
1646 END_LOOP;
1647 PAD_LOOP ((ElementType *) ptr1);
1649 PlowsPolygon (Data, PAD_TYPE, ptr1, pad, call_back, userdata);
1651 END_LOOP;
1653 break;
1655 return r;
1658 void
1659 RestoreToPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
1661 if (!Data->polyClip)
1662 return;
1664 if (type == POLYGON_TYPE)
1665 InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2);
1666 else
1667 PlowsPolygon (Data, type, ptr1, ptr2, add_plow, NULL);
1670 void
1671 ClearFromPolygon (DataType * Data, int type, void *ptr1, void *ptr2)
1673 if (!Data->polyClip)
1674 return;
1676 if (type == POLYGON_TYPE)
1677 InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2);
1678 else
1679 PlowsPolygon (Data, type, ptr1, ptr2, subtract_plow, NULL);
1682 bool
1683 isects (POLYAREA * a, PolygonType *p, bool fr)
1685 POLYAREA *x;
1686 bool ans;
1687 ans = Touching (a, p->Clipped);
1688 /* argument may be register, so we must copy it */
1689 x = a;
1690 if (fr)
1691 poly_Free (&x);
1692 return ans;
1696 bool
1697 IsPointInPolygon (Coord X, Coord Y, Coord r, PolygonType *p)
1699 POLYAREA *c;
1700 Vector v;
1701 v[0] = X;
1702 v[1] = Y;
1703 if (poly_CheckInside (p->Clipped, v))
1704 return true;
1705 if (r < 1)
1706 return false;
1707 if (!(c = CirclePoly (X, Y, r)))
1708 return false;
1709 return isects (c, p, true);
1713 bool
1714 IsPointInPolygonIgnoreHoles (Coord X, Coord Y, PolygonType *p)
1716 Vector v;
1717 v[0] = X;
1718 v[1] = Y;
1719 return poly_InsideContour (p->Clipped->contours, v);
1722 bool
1723 IsRectangleInPolygon (Coord X1, Coord Y1, Coord X2, Coord Y2, PolygonType *p)
1725 POLYAREA *s;
1726 if (!
1727 (s = RectPoly (min (X1, X2), max (X1, X2), min (Y1, Y2), max (Y1, Y2))))
1728 return false;
1729 return isects (s, p, true);
1733 * \brief .
1735 * \note This function will free the passed POLYAREA.
1736 * It must only be passed a single POLYAREA (pa->f == pa->b == pa).
1738 static void
1739 r_NoHolesPolygonDicer (POLYAREA * pa,
1740 void (*emit) (PLINE *, void *), void *user_data)
1742 PLINE *p = pa->contours;
1744 if (!pa->contours->next) /* no holes */
1746 pa->contours = NULL; /* The callback now owns the contour */
1747 /* Don't bother removing it from the POLYAREA's rtree
1748 since we're going to free the POLYAREA below anyway */
1749 emit (p, user_data);
1750 poly_Free (&pa);
1751 return;
1753 else
1755 POLYAREA *poly2, *left, *right;
1757 /* make a rectangle of the left region slicing through the middle of the first hole */
1758 poly2 = RectPoly (p->xmin, (p->next->xmin + p->next->xmax) / 2,
1759 p->ymin, p->ymax);
1760 poly_AndSubtract_free (pa, poly2, &left, &right);
1761 if (left)
1763 POLYAREA *cur, *next;
1764 cur = left;
1767 next = cur->f;
1768 cur->f = cur->b = cur; /* Detach this polygon piece */
1769 r_NoHolesPolygonDicer (cur, emit, user_data);
1770 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1772 while ((cur = next) != left);
1774 if (right)
1776 POLYAREA *cur, *next;
1777 cur = right;
1780 next = cur->f;
1781 cur->f = cur->b = cur; /* Detach this polygon piece */
1782 r_NoHolesPolygonDicer (cur, emit, user_data);
1783 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1785 while ((cur = next) != right);
1790 void
1791 NoHolesPolygonDicer (PolygonType *p, const BoxType * clip,
1792 void (*emit) (PLINE *, void *), void *user_data)
1794 POLYAREA *main_contour, *cur, *next;
1796 main_contour = poly_Create ();
1797 /* copy the main poly only */
1798 poly_Copy1 (main_contour, p->Clipped);
1799 /* clip to the bounding box */
1800 if (clip)
1802 POLYAREA *cbox = RectPoly (clip->X1, clip->X2, clip->Y1, clip->Y2);
1803 poly_Boolean_free (main_contour, cbox, &main_contour, PBO_ISECT);
1805 if (main_contour == NULL)
1806 return;
1807 /* Now dice it up.
1808 * NB: Could be more than one piece (because of the clip above)
1810 cur = main_contour;
1813 next = cur->f;
1814 cur->f = cur->b = cur; /* Detach this polygon piece */
1815 r_NoHolesPolygonDicer (cur, emit, user_data);
1816 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1818 while ((cur = next) != main_contour);
1822 * \brief Make a polygon split into multiple parts into multiple
1823 * polygons.
1825 bool
1826 MorphPolygon (LayerType *layer, PolygonType *poly)
1828 POLYAREA *p, *start;
1829 bool many = false;
1830 FlagType flags;
1832 if (!poly->Clipped || TEST_FLAG (LOCKFLAG, poly))
1833 return false;
1834 if (poly->Clipped->f == poly->Clipped)
1835 return false;
1836 ErasePolygon (poly);
1837 start = p = poly->Clipped;
1838 /* This is ugly. The creation of the new polygons can cause
1839 * all of the polygon pointers (including the one we're called
1840 * with to change if there is a realloc in GetPolygonMemory().
1841 * That will invalidate our original "poly" argument, potentially
1842 * inside the loop. We need to steal the Clipped pointer and
1843 * hide it from the Remove call so that it still exists while
1844 * we do this dirty work.
1846 poly->Clipped = NULL;
1847 if (poly->NoHoles) printf ("Just leaked in MorpyPolygon\n");
1848 poly->NoHoles = NULL;
1849 flags = poly->Flags;
1850 RemovePolygon (layer, poly);
1851 inhibit = true;
1854 VNODE *v;
1855 PolygonType *newone;
1857 if (p->contours->area > PCB->IsleArea)
1859 newone = CreateNewPolygon (layer, flags);
1860 if (!newone)
1861 return false;
1862 many = true;
1863 v = &p->contours->head;
1864 CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
1865 for (v = v->next; v != &p->contours->head; v = v->next)
1866 CreateNewPointInPolygon (newone, v->point[0], v->point[1]);
1867 newone->BoundingBox.X1 = p->contours->xmin;
1868 newone->BoundingBox.X2 = p->contours->xmax + 1;
1869 newone->BoundingBox.Y1 = p->contours->ymin;
1870 newone->BoundingBox.Y2 = p->contours->ymax + 1;
1871 AddObjectToCreateUndoList (POLYGON_TYPE, layer, newone, newone);
1872 newone->Clipped = p;
1873 p = p->f; /* go to next pline */
1874 newone->Clipped->b = newone->Clipped->f = newone->Clipped; /* unlink from others */
1875 r_insert_entry (layer->polygon_tree, (BoxType *) newone, 0);
1876 DrawPolygon (layer, newone);
1878 else
1880 POLYAREA *t = p;
1882 p = p->f;
1883 poly_DelContour (&t->contours);
1884 free (t);
1887 while (p != start);
1888 inhibit = false;
1889 IncrementUndoSerialNumber ();
1890 return many;
1893 void debug_pline (PLINE *pl)
1895 VNODE *v;
1896 pcb_fprintf (stderr, "\txmin %#mS xmax %#mS ymin %#mS ymax %#mS\n",
1897 pl->xmin, pl->xmax, pl->ymin, pl->ymax);
1898 v = &pl->head;
1899 while (v)
1901 pcb_fprintf(stderr, "\t\tvnode: %#mD\n", v->point[0], v->point[1]);
1902 v = v->next;
1903 if (v == &pl->head)
1904 break;
1908 void
1909 debug_polyarea (POLYAREA *p)
1911 PLINE *pl;
1913 fprintf (stderr, "POLYAREA %p\n", p);
1914 for (pl=p->contours; pl; pl=pl->next)
1915 debug_pline (pl);
1918 void
1919 debug_polygon (PolygonType *p)
1921 Cardinal i;
1922 POLYAREA *pa;
1923 fprintf (stderr, "POLYGON %p %d pts\n", p, p->PointN);
1924 for (i=0; i<p->PointN; i++)
1925 pcb_fprintf(stderr, "\t%d: %#mD\n", i, p->Points[i].X, p->Points[i].Y);
1926 if (p->HoleIndexN)
1928 fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN);
1929 for (i=0; i<p->HoleIndexN; i++)
1930 fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]);
1932 else
1933 fprintf (stderr, "it has no holes\n");
1934 pa = p->Clipped;
1935 while (pa)
1937 debug_polyarea (pa);
1938 pa = pa->f;
1939 if (pa == p->Clipped)
1940 break;
1945 * \brief Convert a POLYAREA (and all linked POLYAREA) to raw PCB
1946 * polygons on the given layer.
1948 void
1949 PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer,
1950 POLYAREA *Input, FlagType Flags)
1952 PolygonType *Polygon;
1953 POLYAREA *pa;
1954 PLINE *pline;
1955 VNODE *node;
1956 bool outer;
1958 if (Input == NULL)
1959 return;
1961 pa = Input;
1964 Polygon = CreateNewPolygon (Layer, Flags);
1966 pline = pa->contours;
1967 outer = true;
1971 if (!outer)
1972 CreateNewHoleInPolygon (Polygon);
1973 outer = false;
1975 node = &pline->head;
1978 CreateNewPointInPolygon (Polygon, node->point[0],
1979 node->point[1]);
1981 while ((node = node->next) != &pline->head);
1984 while ((pline = pline->next) != NULL);
1986 InitClip (Destination, Layer, Polygon);
1987 SetPolygonBoundingBox (Polygon);
1988 if (!Layer->polygon_tree)
1989 Layer->polygon_tree = r_create_tree (NULL, 0, 0);
1990 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
1992 DrawPolygon (Layer, Polygon);
1993 /* add to undo list */
1994 AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
1996 while ((pa = pa->f) != Input);
1998 SetChangedFlag (true);