4 * \brief Special polygon editing routines.
6 * Here's a brief tour of the data and life of a polygon, courtesy of
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
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
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
47 * The dicer output is used for HIDs which cannot render things with
48 * holes (which would require erasure).
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
91 #include "crosshair.h"
98 #include "pcb-printf.h"
107 #ifdef HAVE_LIBDMALLOC
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];
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
;
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.
142 * 1 for first hole etc..
145 polygon_point_contour (PolygonType
*polygon
, Cardinal point
)
148 Cardinal contour
= 0;
150 for (i
= 0; i
< polygon
->HoleIndexN
; i
++)
151 if (point
>= polygon
->HoleIndex
[i
])
157 next_contour_point (PolygonType
*polygon
, Cardinal point
)
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];
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
;
179 prev_contour_point (PolygonType
*polygon
, Cardinal point
)
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];
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
;
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
;
213 ComputeNoHoles (PolygonType
*poly
)
215 poly_FreeContours (&poly
->NoHoles
);
217 NoHolesPolygonDicer (poly
, NULL
, add_noholes_polyarea
, poly
);
219 printf ("Compute_noholes caught poly->Clipped = NULL\n");
220 poly
->NoHolesValid
= 1;
224 biggest (POLYAREA
* p
)
226 POLYAREA
*n
, *top
= NULL
;
236 if (n
->contours
->area
< PCB
->IsleArea
)
240 poly_DelContour (&n
->contours
);
251 if (n
->contours
->area
> big
)
254 big
= n
->contours
->area
;
257 while ((n
= n
->f
) != p
);
262 tree
= top
->contour_tree
;
263 top
->contours
= p
->contours
;
264 top
->contour_tree
= p
->contour_tree
;
266 p
->contour_tree
= tree
;
274 ContourToPoly (PLINE
* contour
)
277 poly_PreContour (contour
, TRUE
);
278 assert (contour
->Flags
.orient
== PLF_DIR
);
279 if (!(p
= poly_Create ()))
281 poly_InclContour (p
, contour
);
282 assert (poly_Valid (p
));
287 original_poly (PolygonType
* p
)
289 PLINE
*contour
= NULL
;
295 if ((np
= poly_Create ()) == 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
;
308 if ((contour
= poly_NewContour (v
)) == NULL
)
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
);
329 assert (poly_Valid (np
));
338 PolygonToPoly (PolygonType
*p
)
340 return original_poly (p
);
344 RectPoly (Coord x1
, Coord x2
, Coord y1
, Coord y2
)
346 PLINE
*contour
= NULL
;
349 /* Return NULL for zero or negatively sized rectangles */
350 if (x2
<= x1
|| y2
<= y1
)
355 if ((contour
= poly_NewContour (v
)) == NULL
)
359 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
362 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
365 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
366 return ContourToPoly (contour
);
370 OctagonPoly (Coord x
, Coord y
, Coord radius
)
372 PLINE
*contour
= NULL
;
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
)
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.
410 frac_circle (PLINE
* c
, Coord X
, Coord Y
, Vector v
, int fraction
)
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
;
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.
438 CirclePoly (Coord x
, Coord y
, Coord radius
)
447 if ((contour
= poly_NewContour (v
)) == NULL
)
449 frac_circle (contour
, x
, y
, v
, 1);
450 contour
->is_round
= TRUE
;
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.
462 RoundRect (Coord x1
, Coord x2
, Coord y1
, Coord y2
, Coord t
)
464 PLINE
*contour
= NULL
;
471 if ((contour
= poly_NewContour (v
)) == NULL
)
473 frac_circle (contour
, x1
, y1
, v
, 4);
476 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
477 frac_circle (contour
, x2
, y1
, v
, 4);
480 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
481 frac_circle (contour
, x2
, y2
, v
, 4);
484 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
485 frac_circle (contour
, x1
, y2
, v
, 4);
486 return ContourToPoly (contour
);
491 ArcPolyNoIntersect (ArcType
* a
, Coord thick
)
493 PLINE
*contour
= NULL
;
498 double ang
, da
, rx
, ry
;
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);
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
);
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
)
528 for (i
= 0; i
< segs
- 1; i
++)
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
);
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
));
552 /* now add other round cap */
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
)))
563 #define MIN_CLEARANCE_BEFORE_BISECT 10.
565 ArcPoly (ArcType
* a
, Coord thick
)
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;
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
);
591 return ArcPolyNoIntersect (a
, thick
);
595 LinePoly (LineType
* L
, Coord thick
)
597 PLINE
*contour
= NULL
;
601 long half
;LineType _l
=*L
,*l
=&_l
;
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
);
613 dx
= (l
->Point1
.Y
- l
->Point2
.Y
) * d
;
614 dy
= (l
->Point2
.X
- l
->Point1
.X
) * d
;
621 if (TEST_FLAG (SQUAREFLAG
,l
))/* take into account the ends */
628 v
[0] = l
->Point1
.X
- dx
;
629 v
[1] = l
->Point1
.Y
- dy
;
630 if ((contour
= poly_NewContour (v
)) == NULL
)
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
));
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
));
646 frac_circle (contour
, l
->Point1
.X
, l
->Point1
.Y
, v
, 2);
647 /* now we have the line contour */
648 if (!(np
= ContourToPoly (contour
)))
654 * \brief Make a rounded-corner rectangle.
657 SquarePadPoly (PadType
* pad
, Coord clear
)
659 PLINE
*contour
= NULL
;
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
);
673 double a
= halfthick
/ d
;
674 tx
= (t
->Point1
.Y
- t
->Point2
.Y
) * a
;
675 ty
= (t
->Point2
.X
- t
->Point1
.X
) * a
;
677 cx
= (c
->Point1
.Y
- c
->Point2
.Y
) * a
;
678 cy
= (c
->Point2
.X
- c
->Point1
.X
) * a
;
702 v
[0] = c
->Point1
.X
- tx
;
703 v
[1] = c
->Point1
.Y
- ty
;
704 if ((contour
= poly_NewContour (v
)) == NULL
)
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
)))
730 * \brief Clear np1 from the polygon.
733 Subtract (POLYAREA
* np1
, PolygonType
* p
, bool fnp
)
735 POLYAREA
*merged
= NULL
, *np
= np1
;
745 assert (poly_Valid (p
->Clipped
));
746 assert (poly_Valid (np
));
748 x
= poly_Boolean_free (p
->Clipped
, np
, &merged
, PBO_SUB
);
751 x
= poly_Boolean (p
->Clipped
, np
, &merged
, PBO_SUB
);
752 poly_Free (&p
->Clipped
);
754 assert (!merged
|| poly_Valid (merged
));
757 fprintf (stderr
, "Error while clipping PBO_SUB: %d\n", x
);
760 if (p
->NoHoles
) printf ("Just leaked in Subtract\n");
764 p
->Clipped
= biggest (merged
);
765 assert (!p
->Clipped
|| poly_Valid (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);
774 * \brief Create a polygon of the pin clearance.
777 PinPoly (PinType
* pin
, Coord thick
, Coord clear
)
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);
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
);
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.
809 SubtractPin (DataType
* d
, PinType
* pin
, LayerType
* l
, PolygonType
* p
)
814 if (pin
->Clearance
== 0)
816 i
= GetLayerNumber (d
, l
);
817 if (TEST_THERM (i
, pin
))
819 np
= ThermPoly ((PCBType
*) (d
->pcb
), pin
, i
);
825 np
= PinPoly (pin
, PIN_SIZE (pin
), pin
->Clearance
);
829 return Subtract (np
, p
, TRUE
);
833 SubtractLine (LineType
* line
, PolygonType
* p
)
837 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
839 if (!(np
= LinePoly (line
, line
->Thickness
+ line
->Clearance
)))
841 return Subtract (np
, p
, true);
845 SubtractArc (ArcType
* arc
, PolygonType
* p
)
849 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
851 if (!(np
= ArcPoly (arc
, arc
->Thickness
+ arc
->Clearance
)))
853 return Subtract (np
, p
, true);
857 SubtractText (TextType
* text
, PolygonType
* p
)
860 const BoxType
*b
= &text
->BoundingBox
;
862 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
864 if (!(np
= RoundRect (b
->X1
+ PCB
->Bloat
, b
->X2
- PCB
->Bloat
,
865 b
->Y1
+ PCB
->Bloat
, b
->Y2
- PCB
->Bloat
, PCB
->Bloat
)))
867 return Subtract (np
, p
, true);
871 SubtractPad (PadType
* pad
, PolygonType
* p
)
875 if (pad
->Clearance
== 0)
877 if (TEST_FLAG (SQUAREFLAG
, pad
))
880 (np
= SquarePadPoly (pad
, pad
->Thickness
+ pad
->Clearance
)))
886 (np
= LinePoly ((LineType
*) pad
, pad
->Thickness
+ pad
->Clearance
)))
889 return Subtract (np
, p
, true);
894 const BoxType
*other
;
897 PolygonType
*polygon
;
899 POLYAREA
*accumulate
;
905 subtract_accumulated (struct cpInfo
*info
, PolygonType
*polygon
)
907 if (info
->accumulate
== NULL
)
909 Subtract (info
->accumulate
, polygon
, true);
910 info
->accumulate
= NULL
;
911 info
->batch_size
= 0;
915 pin_sub_callback (const BoxType
* b
, void *cl
)
917 PinType
*pin
= (PinType
*) b
;
918 struct cpInfo
*info
= (struct cpInfo
*) cl
;
919 PolygonType
*polygon
;
924 /* don't subtract the object that was put back! */
925 if (b
== info
->other
)
927 polygon
= info
->polygon
;
929 if (pin
->Clearance
== 0)
931 i
= GetLayerNumber (info
->data
, info
->layer
);
932 if (TEST_THERM (i
, pin
))
934 np
= ThermPoly ((PCBType
*) (info
->data
->pcb
), pin
, i
);
940 np
= PinPoly (pin
, PIN_SIZE (pin
), pin
->Clearance
);
942 longjmp (info
->env
, 1);
945 poly_Boolean_free (info
->accumulate
, np
, &merged
, PBO_UNITE
);
946 info
->accumulate
= merged
;
950 if (info
->batch_size
== SUBTRACT_PIN_VIA_BATCH_SIZE
)
951 subtract_accumulated (info
, polygon
);
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
)
966 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
968 polygon
= info
->polygon
;
969 if (SubtractArc (arc
, polygon
) < 0)
970 longjmp (info
->env
, 1);
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
)
984 if (pad
->Clearance
== 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);
997 line_sub_callback (const BoxType
* b
, void *cl
)
999 LineType
*line
= (LineType
*) b
;
1000 struct cpInfo
*info
= (struct cpInfo
*) cl
;
1001 PolygonType
*polygon
;
1005 /* don't subtract the object that was put back! */
1006 if (b
== info
->other
)
1008 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
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
);
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
)
1035 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
1037 polygon
= info
->polygon
;
1038 if (SubtractText (text
, polygon
) < 0)
1039 longjmp (info
->env
, 1);
1044 Group (DataType
*Data
, Cardinal layer
)
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
])
1055 clearPoly (DataType
*Data
, LayerType
*Layer
, PolygonType
* polygon
,
1056 const BoxType
* here
, Coord expand
)
1063 if (!TEST_FLAG (CLEARPOLYFLAG
, polygon
)
1064 || GetLayerNumber (Data
, Layer
) >= max_copper_layer
)
1066 group
= Group (Data
, GetLayerNumber (Data
, Layer
));
1067 info
.bottom
= (group
== Group (Data
, bottom_silk_layer
));
1071 info
.polygon
= polygon
;
1073 region
= clip_box (here
, &polygon
->BoundingBox
);
1075 region
= polygon
->BoundingBox
;
1076 region
= bloat_box (®ion
, expand
);
1078 if (setjmp (info
.env
) == 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
, ®ion
, NULL
, pad_sub_callback
, &info
);
1085 GROUP_LOOP (Data
, group
);
1088 r_search (layer
->line_tree
, ®ion
, NULL
, line_sub_callback
,
1090 subtract_accumulated (&info
, polygon
);
1092 r_search (layer
->arc_tree
, ®ion
, NULL
, arc_sub_callback
, &info
);
1094 r_search (layer
->text_tree
, ®ion
, NULL
, text_sub_callback
, &info
);
1097 r
+= r_search (Data
->via_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
1098 r
+= r_search (Data
->pin_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
1099 subtract_accumulated (&info
, polygon
);
1101 polygon
->NoHolesValid
= 0;
1106 Unsubtract (POLYAREA
* np1
, PolygonType
* p
)
1108 POLYAREA
*merged
= NULL
, *np
= np1
;
1109 POLYAREA
*orig_poly
, *clipped_np
;
1112 assert (p
&& p
->Clipped
);
1114 orig_poly
= original_poly (p
);
1116 x
= poly_Boolean_free (np
, orig_poly
, &clipped_np
, PBO_ISECT
);
1119 fprintf (stderr
, "Error while clipping PBO_ISECT: %d\n", x
);
1120 poly_Free (&clipped_np
);
1124 x
= poly_Boolean_free (p
->Clipped
, clipped_np
, &merged
, PBO_UNITE
);
1127 fprintf (stderr
, "Error while clipping PBO_UNITE: %d\n", x
);
1128 poly_Free (&merged
);
1131 p
->Clipped
= biggest (merged
);
1132 assert (!p
->Clipped
|| poly_Valid (p
->Clipped
));
1137 if (p
->NoHoles
) printf ("Just leaked in Unsubtract\n");
1143 UnsubtractPin (PinType
* pin
, LayerType
* l
, PolygonType
* p
)
1147 /* overlap a bit to prevent gaps from rounding errors */
1148 np
= BoxPolyBloated (&pin
->BoundingBox
, UNSUBTRACT_BLOAT
);
1152 if (!Unsubtract (np
, p
))
1154 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pin
, 2 * UNSUBTRACT_BLOAT
);
1159 UnsubtractArc (ArcType
* arc
, LayerType
* l
, PolygonType
* p
)
1163 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
1166 /* overlap a bit to prevent gaps from rounding errors */
1167 np
= BoxPolyBloated (&arc
->BoundingBox
, UNSUBTRACT_BLOAT
);
1171 if (!Unsubtract (np
, p
))
1173 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) arc
, 2 * UNSUBTRACT_BLOAT
);
1178 UnsubtractLine (LineType
* line
, LayerType
* l
, PolygonType
* p
)
1182 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
1185 /* overlap a bit to prevent notches from rounding errors */
1186 np
= BoxPolyBloated (&line
->BoundingBox
, UNSUBTRACT_BLOAT
);
1190 if (!Unsubtract (np
, p
))
1192 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) line
, 2 * UNSUBTRACT_BLOAT
);
1197 UnsubtractText (TextType
* text
, LayerType
* l
, PolygonType
* p
)
1201 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
1204 /* overlap a bit to prevent notches from rounding errors */
1205 np
= BoxPolyBloated (&text
->BoundingBox
, UNSUBTRACT_BLOAT
);
1209 if (!Unsubtract (np
, p
))
1211 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) text
, 2 * UNSUBTRACT_BLOAT
);
1216 UnsubtractPad (PadType
* pad
, LayerType
* l
, PolygonType
* p
)
1220 /* overlap a bit to prevent notches from rounding errors */
1221 np
= BoxPolyBloated (&pad
->BoundingBox
, UNSUBTRACT_BLOAT
);
1225 if (!Unsubtract (np
, p
))
1227 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pad
, 2 * UNSUBTRACT_BLOAT
);
1231 static bool inhibit
= false;
1234 InitClip (DataType
*Data
, LayerType
*layer
, PolygonType
* p
)
1239 poly_Free (&p
->Clipped
);
1240 p
->Clipped
= original_poly (p
);
1241 poly_FreeContours (&p
->NoHoles
);
1244 assert (poly_Valid (p
->Clipped
));
1245 if (TEST_FLAG (CLEARPOLYFLAG
, p
))
1246 clearPoly (Data
, layer
, p
, NULL
, 0);
1248 p
->NoHolesValid
= 0;
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.
1261 RemoveExcessPolygonPoints (LayerType
*Layer
, PolygonType
*Polygon
)
1264 Cardinal n
, prev
, next
;
1266 bool changed
= 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
];
1280 if (IsPointOnLine (p
->X
, p
->Y
, 0.0, &line
))
1282 RemoveObject (POLYGONPOINT_TYPE
, Layer
, Polygon
, p
);
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.
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
++)
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
);
1323 { /* ptr1 is closest point */
1324 u
= SQUARE (X
- ptr1
->X
) + SQUARE (Y
- ptr1
->Y
);
1327 { /* ptr2 is closest point */
1328 u
= SQUARE (X
- ptr2
->X
) + SQUARE (Y
- ptr2
->Y
);
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
)
1346 * \brief Go back to the previous point of the polygon.
1349 GoToPreviousPoint (void)
1351 switch (Crosshair
.AttachedPolygon
.PointN
)
1353 /* do nothing if mode has just been entered */
1357 /* reset number of points and 'LINE_MODE' state */
1359 Crosshair
.AttachedPolygon
.PointN
= 0;
1360 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1364 /* back-up one point */
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
;
1379 * \brief Close polygon if possible.
1384 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1386 /* check number of points */
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
))
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
))
1404 ("Cannot close polygon because 45 degree lines are requested.\n"));
1408 CopyAttachedPolygonToLayer ();
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
1420 CopyAttachedPolygonToLayer (void)
1422 PolygonType
*polygon
;
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
;
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
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
),
1462 POLYAREA
*pa
= polygon
->Clipped
;
1464 /* If this hole is so big the polygon doesn't exist, then it's not
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
))
1475 if (callback (pl
, user_data
))
1489 int (*callback
) (DataType
*, LayerType
*, PolygonType
*, int, void *,
1495 subtract_plow (DataType
*Data
, LayerType
*Layer
, PolygonType
*Polygon
,
1496 int type
, void *ptr1
, void *ptr2
, void *userdata
)
1498 if (!Polygon
->Clipped
)
1504 SubtractPin (Data
, (PinType
*) ptr2
, Layer
, Polygon
);
1505 Polygon
->NoHolesValid
= 0;
1508 SubtractLine ((LineType
*) ptr2
, Polygon
);
1509 Polygon
->NoHolesValid
= 0;
1512 SubtractArc ((ArcType
*) ptr2
, Polygon
);
1513 Polygon
->NoHolesValid
= 0;
1516 SubtractPad ((PadType
*) ptr2
, Polygon
);
1517 Polygon
->NoHolesValid
= 0;
1520 SubtractText ((TextType
*) ptr2
, Polygon
);
1521 Polygon
->NoHolesValid
= 0;
1528 add_plow (DataType
*Data
, LayerType
*Layer
, PolygonType
*Polygon
,
1529 int type
, void *ptr1
, void *ptr2
, void *userdata
)
1535 UnsubtractPin ((PinType
*) ptr2
, Layer
, Polygon
);
1538 UnsubtractLine ((LineType
*) ptr2
, Layer
, Polygon
);
1541 UnsubtractArc ((ArcType
*) ptr2
, Layer
, Polygon
);
1544 UnsubtractPad ((PadType
*) ptr2
, Layer
, Polygon
);
1547 UnsubtractText ((TextType
*) ptr2
, Layer
, Polygon
);
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
);
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
),
1572 BoxType sb
= ((PinType
*) ptr2
)->BoundingBox
;
1574 struct plow_info info
;
1580 info
.callback
= call_back
;
1581 info
.userdata
= userdata
;
1586 if (type
== PIN_TYPE
|| ptr1
== ptr2
|| ptr1
== NULL
)
1588 LAYER_LOOP (Data
, max_copper_layer
);
1592 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1598 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1599 ((LayerType
*) ptr1
))));
1603 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1611 /* the cast works equally well for lines and arcs */
1612 if (!TEST_FLAG (CLEARLINEFLAG
, (LineType
*) ptr2
))
1614 /* silk doesn't plow */
1615 if (GetLayerNumber (Data
, (LayerType
*)ptr1
) >= max_copper_layer
)
1617 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1618 ((LayerType
*) ptr1
))));
1621 r
+= r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1627 Cardinal group
= GetLayerGroupNumberByNumber (
1628 TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ?
1629 bottom_silk_layer
: top_silk_layer
);
1630 GROUP_LOOP (Data
, group
);
1634 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1642 PIN_LOOP ((ElementType
*) ptr1
);
1644 PlowsPolygon (Data
, PIN_TYPE
, ptr1
, pin
, call_back
, userdata
);
1647 PAD_LOOP ((ElementType
*) ptr1
);
1649 PlowsPolygon (Data
, PAD_TYPE
, ptr1
, pad
, call_back
, userdata
);
1659 RestoreToPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1661 if (!Data
->polyClip
)
1664 if (type
== POLYGON_TYPE
)
1665 InitClip (PCB
->Data
, (LayerType
*) ptr1
, (PolygonType
*) ptr2
);
1667 PlowsPolygon (Data
, type
, ptr1
, ptr2
, add_plow
, NULL
);
1671 ClearFromPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1673 if (!Data
->polyClip
)
1676 if (type
== POLYGON_TYPE
)
1677 InitClip (PCB
->Data
, (LayerType
*) ptr1
, (PolygonType
*) ptr2
);
1679 PlowsPolygon (Data
, type
, ptr1
, ptr2
, subtract_plow
, NULL
);
1683 isects (POLYAREA
* a
, PolygonType
*p
, bool fr
)
1687 ans
= Touching (a
, p
->Clipped
);
1688 /* argument may be register, so we must copy it */
1697 IsPointInPolygon (Coord X
, Coord Y
, Coord r
, PolygonType
*p
)
1703 if (poly_CheckInside (p
->Clipped
, v
))
1707 if (!(c
= CirclePoly (X
, Y
, r
)))
1709 return isects (c
, p
, true);
1714 IsPointInPolygonIgnoreHoles (Coord X
, Coord Y
, PolygonType
*p
)
1719 return poly_InsideContour (p
->Clipped
->contours
, v
);
1723 IsRectangleInPolygon (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, PolygonType
*p
)
1727 (s
= RectPoly (min (X1
, X2
), max (X1
, X2
), min (Y1
, Y2
), max (Y1
, Y2
))))
1729 return isects (s
, p
, true);
1735 * \note This function will free the passed POLYAREA.
1736 * It must only be passed a single POLYAREA (pa->f == pa->b == pa).
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
);
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,
1760 poly_AndSubtract_free (pa
, poly2
, &left
, &right
);
1763 POLYAREA
*cur
, *next
;
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
);
1776 POLYAREA
*cur
, *next
;
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
);
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 */
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
)
1808 * NB: Could be more than one piece (because of the clip above)
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
1826 MorphPolygon (LayerType
*layer
, PolygonType
*poly
)
1828 POLYAREA
*p
, *start
;
1832 if (!poly
->Clipped
|| TEST_FLAG (LOCKFLAG
, poly
))
1834 if (poly
->Clipped
->f
== poly
->Clipped
)
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
);
1855 PolygonType
*newone
;
1857 if (p
->contours
->area
> PCB
->IsleArea
)
1859 newone
= CreateNewPolygon (layer
, flags
);
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
);
1883 poly_DelContour (&t
->contours
);
1889 IncrementUndoSerialNumber ();
1893 void debug_pline (PLINE
*pl
)
1896 pcb_fprintf (stderr
, "\txmin %#mS xmax %#mS ymin %#mS ymax %#mS\n",
1897 pl
->xmin
, pl
->xmax
, pl
->ymin
, pl
->ymax
);
1901 pcb_fprintf(stderr
, "\t\tvnode: %#mD\n", v
->point
[0], v
->point
[1]);
1909 debug_polyarea (POLYAREA
*p
)
1913 fprintf (stderr
, "POLYAREA %p\n", p
);
1914 for (pl
=p
->contours
; pl
; pl
=pl
->next
)
1919 debug_polygon (PolygonType
*p
)
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
);
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
]);
1933 fprintf (stderr
, "it has no holes\n");
1937 debug_polyarea (pa
);
1939 if (pa
== p
->Clipped
)
1945 * \brief Convert a POLYAREA (and all linked POLYAREA) to raw PCB
1946 * polygons on the given layer.
1949 PolyToPolygonsOnLayer (DataType
*Destination
, LayerType
*Layer
,
1950 POLYAREA
*Input
, FlagType Flags
)
1952 PolygonType
*Polygon
;
1964 Polygon
= CreateNewPolygon (Layer
, Flags
);
1966 pline
= pa
->contours
;
1972 CreateNewHoleInPolygon (Polygon
);
1975 node
= &pline
->head
;
1978 CreateNewPointInPolygon (Polygon
, node
->point
[0],
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);