4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996,2010 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
30 Here's a brief tour of the data and life of a polygon, courtesy of Ben
33 A PCB PolygonType contains an array of points outlining the polygon.
34 This is what is manipulated by the UI and stored in the saved PCB.
36 A PolygonType also contains a POLYAREA called 'Clipped' which is
37 computed dynamically by InitClip every time a board is loaded. The
38 point array is coverted to a POLYAREA by original_poly and then holes
39 are cut in it by clearPoly. After that it is maintained dynamically
40 as parts are added, moved or removed (this is why sometimes bugs can
41 be fixed by just re-loading the board).
43 A POLYAREA consists of a linked list of PLINE structures. The head of
44 that list is POLYAREA.contours. The first contour is an outline of a
45 filled region. All of the subsequent PLINEs are holes cut out of that
46 first contour. POLYAREAs are in a doubly-linked list and each member
47 of the list is an independent (non-overlapping) area with its own
48 outline and holes. The function biggest() finds the largest POLYAREA
49 so that PolygonType.Clipped points to that shape. The rest of the
50 polygon still exists, it's just ignored when turning the polygon into
53 The first POLYAREA in PolygonType.Clipped is what is used for the vast
54 majority of Polygon related tests. The basic logic for an
55 intersection is "is the target shape inside POLYAREA.contours and NOT
56 fully enclosed in any of POLYAREA.contours.next... (the holes)".
58 The polygon dicer (NoHolesPolygonDicer and r_NoHolesPolygonDicer)
59 emits a series of "simple" PLINE shapes. That is, the PLINE isn't
60 linked to any other "holes" oulines). That's the meaning of the first
61 test in r_NoHolesPolygonDicer. It is testing to see if the PLINE
62 contour (the first, making it a solid outline) has a valid next
63 pointer (which would point to one or more holes). The dicer works by
64 recursively chopping the polygon in half through the first hole it
65 sees (which is guaranteed to eliminate at least that one hole). The
66 dicer output is used for HIDs which cannot render things with holes
67 (which would require erasure).
71 /* special polygon editing routines
86 #include "crosshair.h"
101 #ifdef HAVE_LIBDMALLOC
105 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5 : (x) - 0.5)))
107 #define UNSUBTRACT_BLOAT 10
108 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100
109 #define SUBTRACT_LINE_BATCH_SIZE 20
111 /* ---------------------------------------------------------------------------
116 static double circleVerticies
[] = {
118 0.98768834059513777, 0.15643446504023087,
120 /* adjustment to make the segments
121 * outline the circle rather than connect
122 * points on the circle
123 * 1 - cos(\alpha/2) < (\alpha/2)^2/2 */
124 static double radius_adjustment
= (M_PI
/CIRC_SEGS
)*(M_PI
/CIRC_SEGS
)/2;
127 polygon_point_idx (PolygonTypePtr polygon
, PointTypePtr point
)
129 assert (point
>= polygon
->Points
);
130 assert (point
<= polygon
->Points
+ polygon
->PointN
);
131 return ((char *)point
- (char *)polygon
->Points
) / sizeof (PointType
);
134 /* Find contour number: 0 for outer, 1 for first hole etc.. */
136 polygon_point_contour (PolygonTypePtr polygon
, Cardinal point
)
139 Cardinal contour
= 0;
141 for (i
= 0; i
< polygon
->HoleIndexN
; i
++)
142 if (point
>= polygon
->HoleIndex
[i
])
148 next_contour_point (PolygonTypePtr polygon
, Cardinal point
)
151 Cardinal this_contour_start
;
152 Cardinal next_contour_start
;
154 contour
= polygon_point_contour (polygon
, point
);
156 this_contour_start
= (contour
== 0) ? 0 :
157 polygon
->HoleIndex
[contour
- 1];
159 (contour
== polygon
->HoleIndexN
) ? polygon
->PointN
:
160 polygon
->HoleIndex
[contour
];
162 /* Wrap back to the start of the contour we're in if we pass the end */
163 if (++point
== next_contour_start
)
164 point
= this_contour_start
;
170 prev_contour_point (PolygonTypePtr polygon
, Cardinal point
)
173 Cardinal prev_contour_end
;
174 Cardinal this_contour_end
;
176 contour
= polygon_point_contour (polygon
, point
);
178 prev_contour_end
= (contour
== 0) ? 0 :
179 polygon
->HoleIndex
[contour
- 1];
181 (contour
== polygon
->HoleIndexN
) ? polygon
->PointN
- 1:
182 polygon
->HoleIndex
[contour
] - 1;
184 /* Wrap back to the start of the contour we're in if we pass the end */
185 if (point
== prev_contour_end
)
186 point
= this_contour_end
;
194 add_noholes_polyarea (PLINE
*pline
, void *user_data
)
196 PolygonType
*poly
= user_data
;
198 /* Prepend the pline into the NoHoles linked list */
199 pline
->next
= poly
->NoHoles
;
200 poly
->NoHoles
= pline
;
204 ComputeNoHoles (PolygonType
*poly
)
206 poly_FreeContours (&poly
->NoHoles
);
208 NoHolesPolygonDicer (poly
, NULL
, add_noholes_polyarea
, poly
);
210 printf ("Compute_noholes caught poly->Clipped = NULL\n");
211 poly
->NoHolesValid
= 1;
215 biggest (POLYAREA
* p
)
217 POLYAREA
*n
, *top
= NULL
;
227 if (n
->contours
->area
< PCB
->IsleArea
)
231 poly_DelContour (&n
->contours
);
242 if (n
->contours
->area
> big
)
245 big
= n
->contours
->area
;
248 while ((n
= n
->f
) != p
);
253 tree
= top
->contour_tree
;
254 top
->contours
= p
->contours
;
255 top
->contour_tree
= p
->contour_tree
;
257 p
->contour_tree
= tree
;
265 ContourToPoly (PLINE
* contour
)
268 poly_PreContour (contour
, TRUE
);
269 assert (contour
->Flags
.orient
== PLF_DIR
);
270 if (!(p
= poly_Create ()))
272 poly_InclContour (p
, contour
);
273 assert (poly_Valid (p
));
278 original_poly (PolygonType
* p
)
280 PLINE
*contour
= NULL
;
286 if ((np
= poly_Create ()) == NULL
)
289 /* first make initial polygon contour */
290 for (n
= 0; n
< p
->PointN
; n
++)
292 /* No current contour? Make a new one starting at point */
293 /* (or) Add point to existing contour */
295 v
[0] = p
->Points
[n
].X
;
296 v
[1] = p
->Points
[n
].Y
;
299 if ((contour
= poly_NewContour (v
)) == NULL
)
304 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
307 /* Is current point last in contour? If so process it. */
308 if (n
== p
->PointN
- 1 ||
309 (hole
< p
->HoleIndexN
&& n
== p
->HoleIndex
[hole
] - 1))
311 poly_PreContour (contour
, TRUE
);
313 /* make sure it is a positive contour (outer) or negative (hole) */
314 if (contour
->Flags
.orient
!= (hole
? PLF_INV
: PLF_DIR
))
315 poly_InvContour (contour
);
316 assert (contour
->Flags
.orient
== (hole
? PLF_INV
: PLF_DIR
));
318 poly_InclContour (np
, contour
);
320 assert (poly_Valid (np
));
329 PolygonToPoly (PolygonType
*p
)
331 return original_poly (p
);
335 RectPoly (LocationType x1
, LocationType x2
, LocationType y1
, LocationType y2
)
337 PLINE
*contour
= NULL
;
344 if ((contour
= poly_NewContour (v
)) == NULL
)
348 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
351 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
354 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
355 return ContourToPoly (contour
);
359 OctagonPoly (LocationType x
, LocationType y
, BDimension radius
)
361 PLINE
*contour
= NULL
;
364 v
[0] = x
+ ROUND (radius
* 0.5);
365 v
[1] = y
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
366 if ((contour
= poly_NewContour (v
)) == NULL
)
368 v
[0] = x
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
369 v
[1] = y
+ ROUND (radius
* 0.5);
370 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
371 v
[0] = x
- (v
[0] - x
);
372 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
373 v
[0] = x
- ROUND (radius
* 0.5);
374 v
[1] = y
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
375 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
376 v
[1] = y
- (v
[1] - y
);
377 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
378 v
[0] = x
- ROUND (radius
* TAN_22_5_DEGREE_2
);
379 v
[1] = y
- ROUND (radius
* 0.5);
380 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
381 v
[0] = x
- (v
[0] - x
);
382 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
383 v
[0] = x
+ ROUND (radius
* 0.5);
384 v
[1] = y
- ROUND (radius
* TAN_22_5_DEGREE_2
);
385 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
386 return ContourToPoly (contour
);
389 /* add verticies in a fractional-circle starting from v
390 * centered at X, Y and going counter-clockwise
391 * does not include the first point
392 * last argument is 1 for a full circle
393 * 2 for a half circle
394 * or 4 for a quarter circle
397 frac_circle (PLINE
* c
, LocationType X
, LocationType Y
, Vector v
, int range
)
402 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
403 /* move vector to origin */
404 e1
= (v
[0] - X
) * (1 + radius_adjustment
);
405 e2
= (v
[1] - Y
) * (1 + radius_adjustment
);
407 /* NB: the caller adds the last vertex, hence the -1 */
408 range
= range
== 1 ? CIRC_SEGS
-1 : (CIRC_SEGS
/ range
) - 1;
409 for (i
= 0; i
< range
; i
++)
411 /* rotate the vector */
412 t1
= e1
* circleVerticies
[2] - e2
* circleVerticies
[3];
413 e2
= e1
* circleVerticies
[3] + e2
* circleVerticies
[2];
415 v
[0] = X
+ ROUND (e1
);
416 v
[1] = Y
+ ROUND (e2
);
417 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
421 /* create a circle approximation from lines */
423 CirclePoly (LocationType x
, LocationType y
, BDimension radius
)
432 if ((contour
= poly_NewContour (v
)) == NULL
)
434 frac_circle (contour
, x
, y
, v
, 1);
435 contour
->is_round
= TRUE
;
438 contour
->radius
= radius
;
439 return ContourToPoly (contour
);
442 /* make a rounded-corner rectangle with radius t beyond x1,x2,y1,y2 rectangle */
444 RoundRect (LocationType x1
, LocationType x2
, LocationType y1
, LocationType y2
,
447 PLINE
*contour
= NULL
;
454 if ((contour
= poly_NewContour (v
)) == NULL
)
456 frac_circle (contour
, x1
, y1
, v
, 4);
459 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
460 frac_circle (contour
, x2
, y1
, v
, 4);
463 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
464 frac_circle (contour
, x2
, y2
, v
, 4);
467 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
468 frac_circle (contour
, x1
, y2
, v
, 4);
469 return ContourToPoly (contour
);
474 ArcPolyNoIntersect (ArcType
* a
, BDimension thick
)
476 PLINE
*contour
= NULL
;
481 double ang
, da
, rx
, ry
;
483 static const double delta_th
= 0.02; /* polygon diverges from modelled arc
484 no more than delta_th * thick */
491 a
->StartAngle
+= a
->Delta
;
492 a
->Delta
= -a
->Delta
;
494 half
= (thick
+ 1) / 2;
495 ends
= GetArcEnds (a
);
496 /* start with inner radius */
497 rx
= MAX (a
->Width
- half
, 0);
498 ry
= MAX (a
->Height
- half
, 0);
501 segs
= a
->Delta
* M_PI
/ 360
502 * sqrt(sqrt((double)rx
*rx
+ (double)ry
*ry
)/delta_th
/2/thick
);
503 segs
= MAX(segs
, a
->Delta
/ ARC_ANGLE
);
506 da
= (1.0 * a
->Delta
) / segs
;
507 radius_adj
= (M_PI
*da
/360)*(M_PI
*da
/360)/2;
508 v
[0] = a
->X
- rx
* cos (ang
* M180
);
509 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
510 if ((contour
= poly_NewContour (v
)) == NULL
)
512 for (i
= 0; i
< segs
- 1; i
++)
515 v
[0] = a
->X
- rx
* cos (ang
* M180
);
516 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
517 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
519 /* find last point */
520 ang
= a
->StartAngle
+ a
->Delta
;
521 v
[0] = a
->X
- rx
* cos (ang
* M180
) * (1 - radius_adj
);
522 v
[1] = a
->Y
+ ry
* sin (ang
* M180
) * (1 - radius_adj
);
523 /* add the round cap at the end */
524 frac_circle (contour
, ends
->X2
, ends
->Y2
, v
, 2);
525 /* and now do the outer arc (going backwards) */
526 rx
= (a
->Width
+ half
) * (1+radius_adj
);
527 ry
= (a
->Width
+ half
) * (1+radius_adj
);
529 for (i
= 0; i
< segs
; 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
));
536 /* now add other round cap */
538 v
[0] = a
->X
- rx
* cos (ang
* M180
) * (1 - radius_adj
);
539 v
[1] = a
->Y
+ ry
* sin (ang
* M180
) * (1 - radius_adj
);
540 frac_circle (contour
, ends
->X1
, ends
->Y1
, v
, 2);
541 /* now we have the whole contour */
542 if (!(np
= ContourToPoly (contour
)))
547 #define MIN_CLEARANCE_BEFORE_BISECT 10.
549 ArcPoly (ArcType
* a
, BDimension thick
)
553 POLYAREA
*tmp1
, *tmp2
, *res
;
555 delta
= (a
->Delta
< 0) ? -a
->Delta
: a
->Delta
;
557 /* If the arc segment would self-intersect, we need to construct it as the union of
558 two non-intersecting segments */
560 if (2 * M_PI
* a
->Width
* (1. - (double)delta
/ 360.) - thick
< MIN_CLEARANCE_BEFORE_BISECT
)
562 int half_delta
= a
->Delta
/ 2;
565 seg1
.Delta
= half_delta
;
566 seg2
.Delta
-= half_delta
;
567 seg2
.StartAngle
+= half_delta
;
569 tmp1
= ArcPolyNoIntersect (&seg1
, thick
);
570 tmp2
= ArcPolyNoIntersect (&seg2
, thick
);
571 poly_Boolean_free (tmp1
, tmp2
, &res
, PBO_UNITE
);
575 return ArcPolyNoIntersect (a
, thick
);
579 LinePoly (LineType
* L
, BDimension thick
)
581 PLINE
*contour
= NULL
;
585 long half
;LineType _l
=*L
,*l
=&_l
;
589 half
= (thick
+ 1) / 2;
591 sqrt (SQUARE (l
->Point1
.X
- l
->Point2
.X
) +
592 SQUARE (l
->Point1
.Y
- l
->Point2
.Y
));
593 if (!TEST_FLAG (SQUAREFLAG
,l
))
594 if (d
== 0) /* line is a point */
595 return CirclePoly (l
->Point1
.X
, l
->Point1
.Y
, half
);
599 dx
= (l
->Point1
.Y
- l
->Point2
.Y
) * d
;
600 dy
= (l
->Point2
.X
- l
->Point1
.X
) * d
;
607 if (TEST_FLAG (SQUAREFLAG
,l
))/* take into account the ends */
614 v
[0] = l
->Point1
.X
- dx
;
615 v
[1] = l
->Point1
.Y
- dy
;
616 if ((contour
= poly_NewContour (v
)) == NULL
)
618 v
[0] = l
->Point2
.X
- dx
;
619 v
[1] = l
->Point2
.Y
- dy
;
620 if (TEST_FLAG (SQUAREFLAG
,l
))
621 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
623 frac_circle (contour
, l
->Point2
.X
, l
->Point2
.Y
, v
, 2);
624 v
[0] = l
->Point2
.X
+ dx
;
625 v
[1] = l
->Point2
.Y
+ dy
;
626 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
627 v
[0] = l
->Point1
.X
+ dx
;
628 v
[1] = l
->Point1
.Y
+ dy
;
629 if (TEST_FLAG (SQUAREFLAG
,l
))
630 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
632 frac_circle (contour
, l
->Point1
.X
, l
->Point1
.Y
, v
, 2);
633 /* now we have the line contour */
634 if (!(np
= ContourToPoly (contour
)))
639 /* make a rounded-corner rectangle */
641 SquarePadPoly (PadType
* pad
, BDimension clear
)
643 PLINE
*contour
= NULL
;
649 PadType _t
=*pad
,*t
=&_t
;
650 PadType _c
=*pad
,*c
=&_c
;
651 int halfthick
= (pad
->Thickness
+ 1) / 2;
652 int halfclear
= (clear
+ 1) / 2;
655 sqrt (SQUARE (pad
->Point1
.X
- pad
->Point2
.X
) +
656 SQUARE (pad
->Point1
.Y
- pad
->Point2
.Y
));
659 double a
= halfthick
/ d
;
660 tx
= (t
->Point1
.Y
- t
->Point2
.Y
) * a
;
661 ty
= (t
->Point2
.X
- t
->Point1
.X
) * a
;
663 cx
= (c
->Point1
.Y
- c
->Point2
.Y
) * a
;
664 cy
= (c
->Point2
.X
- c
->Point1
.X
) * a
;
688 v
[0] = c
->Point1
.X
- tx
;
689 v
[1] = c
->Point1
.Y
- ty
;
690 if ((contour
= poly_NewContour (v
)) == NULL
)
692 frac_circle (contour
, (t
->Point1
.X
- tx
), (t
->Point1
.Y
- ty
), v
, 4);
694 v
[0] = t
->Point2
.X
- cx
;
695 v
[1] = t
->Point2
.Y
- cy
;
696 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
697 frac_circle (contour
, (t
->Point2
.X
- tx
), (t
->Point2
.Y
- ty
), v
, 4);
699 v
[0] = c
->Point2
.X
+ tx
;
700 v
[1] = c
->Point2
.Y
+ ty
;
701 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
702 frac_circle (contour
, (t
->Point2
.X
+ tx
), (t
->Point2
.Y
+ ty
), v
, 4);
704 v
[0] = t
->Point1
.X
+ cx
;
705 v
[1] = t
->Point1
.Y
+ cy
;
706 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
707 frac_circle (contour
, (t
->Point1
.X
+ tx
), (t
->Point1
.Y
+ ty
), v
, 4);
709 /* now we have the line contour */
710 if (!(np
= ContourToPoly (contour
)))
715 /* clear np1 from the polygon */
717 Subtract (POLYAREA
* np1
, PolygonType
* p
, bool fnp
)
719 POLYAREA
*merged
= NULL
, *np
= np1
;
729 assert (poly_Valid (p
->Clipped
));
730 assert (poly_Valid (np
));
732 x
= poly_Boolean_free (p
->Clipped
, np
, &merged
, PBO_SUB
);
735 x
= poly_Boolean (p
->Clipped
, np
, &merged
, PBO_SUB
);
736 poly_Free (&p
->Clipped
);
738 assert (!merged
|| poly_Valid (merged
));
741 fprintf (stderr
, "Error while clipping PBO_SUB: %d\n", x
);
744 if (p
->NoHoles
) printf ("Just leaked in Subtract\n");
748 p
->Clipped
= biggest (merged
);
749 assert (!p
->Clipped
|| poly_Valid (p
->Clipped
));
751 Message ("Polygon cleared out of existence near (%d, %d)\n",
752 (p
->BoundingBox
.X1
+ p
->BoundingBox
.X2
) / 2,
753 (p
->BoundingBox
.Y1
+ p
->BoundingBox
.Y2
) / 2);
757 /* create a polygon of the pin clearance */
759 PinPoly (PinType
* pin
, BDimension thick
, BDimension clear
)
763 if (TEST_FLAG (SQUAREFLAG
, pin
))
765 size
= (thick
+ 1) / 2;
766 return RoundRect (pin
->X
- size
, pin
->X
+ size
, pin
->Y
- size
,
767 pin
->Y
+ size
, (clear
+ 1) / 2);
771 size
= (thick
+ clear
+ 1) / 2;
772 if (TEST_FLAG (OCTAGONFLAG
, pin
))
774 return OctagonPoly (pin
->X
, pin
->Y
, size
+ size
);
777 return CirclePoly (pin
->X
, pin
->Y
, size
);
781 BoxPolyBloated (BoxType
*box
, BDimension bloat
)
783 return RectPoly (box
->X1
- bloat
, box
->X2
+ bloat
,
784 box
->Y1
- bloat
, box
->Y2
+ bloat
);
787 /* remove the pin clearance from the polygon */
789 SubtractPin (DataType
* d
, PinType
* pin
, LayerType
* l
, PolygonType
* p
)
794 if (pin
->Clearance
== 0)
796 i
= GetLayerNumber (d
, l
);
797 if (TEST_THERM (i
, pin
))
799 np
= ThermPoly ((PCBTypePtr
) (d
->pcb
), pin
, i
);
805 np
= PinPoly (pin
, pin
->Thickness
, pin
->Clearance
);
809 return Subtract (np
, p
, TRUE
);
813 SubtractLine (LineType
* line
, PolygonType
* p
)
817 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
819 if (!(np
= LinePoly (line
, line
->Thickness
+ line
->Clearance
)))
821 return Subtract (np
, p
, true);
825 SubtractArc (ArcType
* arc
, PolygonType
* p
)
829 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
831 if (!(np
= ArcPoly (arc
, arc
->Thickness
+ arc
->Clearance
)))
833 return Subtract (np
, p
, true);
837 SubtractText (TextType
* text
, PolygonType
* p
)
840 const BoxType
*b
= &text
->BoundingBox
;
842 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
844 if (!(np
= RoundRect (b
->X1
+ PCB
->Bloat
, b
->X2
- PCB
->Bloat
,
845 b
->Y1
+ PCB
->Bloat
, b
->Y2
- PCB
->Bloat
, PCB
->Bloat
)))
847 return Subtract (np
, p
, true);
851 SubtractPad (PadType
* pad
, PolygonType
* p
)
855 if (pad
->Clearance
== 0)
857 if (TEST_FLAG (SQUAREFLAG
, pad
))
860 (np
= SquarePadPoly (pad
, pad
->Thickness
+ pad
->Clearance
)))
866 (np
= LinePoly ((LineType
*) pad
, pad
->Thickness
+ pad
->Clearance
)))
869 return Subtract (np
, p
, true);
874 const BoxType
*other
;
877 PolygonType
*polygon
;
879 POLYAREA
*accumulate
;
885 subtract_accumulated (struct cpInfo
*info
, PolygonTypePtr polygon
)
887 if (info
->accumulate
== NULL
)
889 Subtract (info
->accumulate
, polygon
, true);
890 info
->accumulate
= NULL
;
891 info
->batch_size
= 0;
895 pin_sub_callback (const BoxType
* b
, void *cl
)
897 PinTypePtr pin
= (PinTypePtr
) b
;
898 struct cpInfo
*info
= (struct cpInfo
*) cl
;
899 PolygonTypePtr polygon
;
904 /* don't subtract the object that was put back! */
905 if (b
== info
->other
)
907 polygon
= info
->polygon
;
909 if (pin
->Clearance
== 0)
911 i
= GetLayerNumber (info
->data
, info
->layer
);
912 if (TEST_THERM (i
, pin
))
914 np
= ThermPoly ((PCBTypePtr
) (info
->data
->pcb
), pin
, i
);
920 np
= PinPoly (pin
, pin
->Thickness
, pin
->Clearance
);
922 longjmp (info
->env
, 1);
925 poly_Boolean_free (info
->accumulate
, np
, &merged
, PBO_UNITE
);
926 info
->accumulate
= merged
;
930 if (info
->batch_size
== SUBTRACT_PIN_VIA_BATCH_SIZE
)
931 subtract_accumulated (info
, polygon
);
937 arc_sub_callback (const BoxType
* b
, void *cl
)
939 ArcTypePtr arc
= (ArcTypePtr
) b
;
940 struct cpInfo
*info
= (struct cpInfo
*) cl
;
941 PolygonTypePtr polygon
;
943 /* don't subtract the object that was put back! */
944 if (b
== info
->other
)
946 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
948 polygon
= info
->polygon
;
949 if (SubtractArc (arc
, polygon
) < 0)
950 longjmp (info
->env
, 1);
955 pad_sub_callback (const BoxType
* b
, void *cl
)
957 PadTypePtr pad
= (PadTypePtr
) b
;
958 struct cpInfo
*info
= (struct cpInfo
*) cl
;
959 PolygonTypePtr polygon
;
961 /* don't subtract the object that was put back! */
962 if (b
== info
->other
)
964 if (pad
->Clearance
== 0)
966 polygon
= info
->polygon
;
967 if (XOR (TEST_FLAG (ONSOLDERFLAG
, pad
), !info
->solder
))
969 if (SubtractPad (pad
, polygon
) < 0)
970 longjmp (info
->env
, 1);
977 line_sub_callback (const BoxType
* b
, void *cl
)
979 LineTypePtr line
= (LineTypePtr
) b
;
980 struct cpInfo
*info
= (struct cpInfo
*) cl
;
981 PolygonTypePtr polygon
;
985 /* don't subtract the object that was put back! */
986 if (b
== info
->other
)
988 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
990 polygon
= info
->polygon
;
992 if (!(np
= LinePoly (line
, line
->Thickness
+ line
->Clearance
)))
993 longjmp (info
->env
, 1);
995 poly_Boolean_free (info
->accumulate
, np
, &merged
, PBO_UNITE
);
996 info
->accumulate
= merged
;
999 if (info
->batch_size
== SUBTRACT_LINE_BATCH_SIZE
)
1000 subtract_accumulated (info
, polygon
);
1006 text_sub_callback (const BoxType
* b
, void *cl
)
1008 TextTypePtr text
= (TextTypePtr
) b
;
1009 struct cpInfo
*info
= (struct cpInfo
*) cl
;
1010 PolygonTypePtr polygon
;
1012 /* don't subtract the object that was put back! */
1013 if (b
== info
->other
)
1015 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
1017 polygon
= info
->polygon
;
1018 if (SubtractText (text
, polygon
) < 0)
1019 longjmp (info
->env
, 1);
1024 Group (DataTypePtr Data
, Cardinal layer
)
1027 for (i
= 0; i
< max_group
; i
++)
1028 for (j
= 0; j
< ((PCBType
*) (Data
->pcb
))->LayerGroups
.Number
[i
]; j
++)
1029 if (layer
== ((PCBType
*) (Data
->pcb
))->LayerGroups
.Entries
[i
][j
])
1035 clearPoly (DataTypePtr Data
, LayerTypePtr Layer
, PolygonType
* polygon
,
1036 const BoxType
* here
, BDimension expand
)
1043 if (!TEST_FLAG (CLEARPOLYFLAG
, polygon
)
1044 || GetLayerNumber (Data
, Layer
) >= max_copper_layer
)
1046 group
= Group (Data
, GetLayerNumber (Data
, Layer
));
1047 info
.solder
= (group
== Group (Data
, solder_silk_layer
));
1051 info
.polygon
= polygon
;
1053 region
= clip_box (here
, &polygon
->BoundingBox
);
1055 region
= polygon
->BoundingBox
;
1056 region
= bloat_box (®ion
, expand
);
1058 if (setjmp (info
.env
) == 0)
1061 info
.accumulate
= NULL
;
1062 info
.batch_size
= 0;
1063 if (info
.solder
|| group
== Group (Data
, component_silk_layer
))
1064 r
+= r_search (Data
->pad_tree
, ®ion
, NULL
, pad_sub_callback
, &info
);
1065 GROUP_LOOP (Data
, group
);
1068 r_search (layer
->line_tree
, ®ion
, NULL
, line_sub_callback
,
1070 subtract_accumulated (&info
, polygon
);
1072 r_search (layer
->arc_tree
, ®ion
, NULL
, arc_sub_callback
, &info
);
1074 r_search (layer
->text_tree
, ®ion
, NULL
, text_sub_callback
, &info
);
1077 r
+= r_search (Data
->via_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
1078 r
+= r_search (Data
->pin_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
1079 subtract_accumulated (&info
, polygon
);
1081 polygon
->NoHolesValid
= 0;
1086 Unsubtract (POLYAREA
* np1
, PolygonType
* p
)
1088 POLYAREA
*merged
= NULL
, *np
= np1
;
1089 POLYAREA
*orig_poly
, *clipped_np
;
1092 assert (p
&& p
->Clipped
);
1094 orig_poly
= original_poly (p
);
1096 x
= poly_Boolean_free (np
, orig_poly
, &clipped_np
, PBO_ISECT
);
1099 fprintf (stderr
, "Error while clipping PBO_ISECT: %d\n", x
);
1100 poly_Free (&clipped_np
);
1104 x
= poly_Boolean_free (p
->Clipped
, clipped_np
, &merged
, PBO_UNITE
);
1107 fprintf (stderr
, "Error while clipping PBO_UNITE: %d\n", x
);
1108 poly_Free (&merged
);
1111 p
->Clipped
= biggest (merged
);
1112 assert (!p
->Clipped
|| poly_Valid (p
->Clipped
));
1117 if (p
->NoHoles
) printf ("Just leaked in Unsubtract\n");
1123 UnsubtractPin (PinType
* pin
, LayerType
* l
, PolygonType
* p
)
1127 /* overlap a bit to prevent gaps from rounding errors */
1128 np
= BoxPolyBloated (&pin
->BoundingBox
, UNSUBTRACT_BLOAT
);
1132 if (!Unsubtract (np
, p
))
1134 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pin
, 2 * UNSUBTRACT_BLOAT
);
1139 UnsubtractArc (ArcType
* arc
, LayerType
* l
, PolygonType
* p
)
1143 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
1146 /* overlap a bit to prevent gaps from rounding errors */
1147 np
= BoxPolyBloated (&arc
->BoundingBox
, UNSUBTRACT_BLOAT
);
1151 if (!Unsubtract (np
, p
))
1153 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) arc
, 2 * UNSUBTRACT_BLOAT
);
1158 UnsubtractLine (LineType
* line
, LayerType
* l
, PolygonType
* p
)
1162 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
1165 /* overlap a bit to prevent notches from rounding errors */
1166 np
= BoxPolyBloated (&line
->BoundingBox
, UNSUBTRACT_BLOAT
);
1170 if (!Unsubtract (np
, p
))
1172 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) line
, 2 * UNSUBTRACT_BLOAT
);
1177 UnsubtractText (TextType
* text
, LayerType
* l
, PolygonType
* p
)
1181 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
1184 /* overlap a bit to prevent notches from rounding errors */
1185 np
= BoxPolyBloated (&text
->BoundingBox
, UNSUBTRACT_BLOAT
);
1189 if (!Unsubtract (np
, p
))
1191 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) text
, 2 * UNSUBTRACT_BLOAT
);
1196 UnsubtractPad (PadType
* pad
, LayerType
* l
, PolygonType
* p
)
1200 /* overlap a bit to prevent notches from rounding errors */
1201 np
= BoxPolyBloated (&pad
->BoundingBox
, UNSUBTRACT_BLOAT
);
1205 if (!Unsubtract (np
, p
))
1207 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pad
, 2 * UNSUBTRACT_BLOAT
);
1211 static bool inhibit
= false;
1214 InitClip (DataTypePtr Data
, LayerTypePtr layer
, PolygonType
* p
)
1219 poly_Free (&p
->Clipped
);
1220 p
->Clipped
= original_poly (p
);
1221 poly_FreeContours (&p
->NoHoles
);
1224 assert (poly_Valid (p
->Clipped
));
1225 if (TEST_FLAG (CLEARPOLYFLAG
, p
))
1226 clearPoly (Data
, layer
, p
, NULL
, 0);
1228 p
->NoHolesValid
= 0;
1232 /* --------------------------------------------------------------------------
1233 * remove redundant polygon points. Any point that lies on the straight
1234 * line between the points on either side of it is redundant.
1235 * returns true if any points are removed
1238 RemoveExcessPolygonPoints (LayerTypePtr Layer
, PolygonTypePtr Polygon
)
1241 Cardinal n
, prev
, next
;
1243 bool changed
= false;
1248 for (n
= 0; n
< Polygon
->PointN
; n
++)
1250 prev
= prev_contour_point (Polygon
, n
);
1251 next
= next_contour_point (Polygon
, n
);
1252 p
= &Polygon
->Points
[n
];
1254 line
.Point1
= Polygon
->Points
[prev
];
1255 line
.Point2
= Polygon
->Points
[next
];
1257 if (IsPointOnLine ((float) p
->X
, (float) p
->Y
, 0.0, &line
))
1259 RemoveObject (POLYGONPOINT_TYPE
, Layer
, Polygon
, p
);
1266 /* ---------------------------------------------------------------------------
1267 * returns the index of the polygon point which is the end
1268 * point of the segment with the lowest distance to the passed
1272 GetLowestDistancePolygonPoint (PolygonTypePtr Polygon
, LocationType X
,
1275 double mindistance
= (double) MAX_COORD
* MAX_COORD
;
1276 PointTypePtr ptr1
, ptr2
;
1277 Cardinal n
, result
= 0;
1279 /* we calculate the distance to each segment and choose the
1280 * shortest distance. If the closest approach between the
1281 * given point and the projected line (i.e. the segment extended)
1282 * is not on the segment, then the distance is the distance
1283 * to the segment end point.
1286 for (n
= 0; n
< Polygon
->PointN
; n
++)
1288 register double u
, dx
, dy
;
1289 ptr1
= &Polygon
->Points
[prev_contour_point (Polygon
, n
)];
1290 ptr2
= &Polygon
->Points
[n
];
1292 dx
= ptr2
->X
- ptr1
->X
;
1293 dy
= ptr2
->Y
- ptr1
->Y
;
1294 if (dx
!= 0.0 || dy
!= 0.0)
1296 /* projected intersection is at P1 + u(P2 - P1) */
1297 u
= ((X
- ptr1
->X
) * dx
+ (Y
- ptr1
->Y
) * dy
) / (dx
* dx
+ dy
* dy
);
1300 { /* ptr1 is closest point */
1301 u
= SQUARE (X
- ptr1
->X
) + SQUARE (Y
- ptr1
->Y
);
1304 { /* ptr2 is closest point */
1305 u
= SQUARE (X
- ptr2
->X
) + SQUARE (Y
- ptr2
->Y
);
1308 { /* projected intersection is closest point */
1309 u
= SQUARE (X
- ptr1
->X
* (1.0 - u
) - u
* ptr2
->X
) +
1310 SQUARE (Y
- ptr1
->Y
* (1.0 - u
) - u
* ptr2
->Y
);
1312 if (u
< mindistance
)
1322 /* ---------------------------------------------------------------------------
1323 * go back to the previous point of the polygon
1326 GoToPreviousPoint (void)
1328 switch (Crosshair
.AttachedPolygon
.PointN
)
1330 /* do nothing if mode has just been entered */
1334 /* reset number of points and 'LINE_MODE' state */
1336 Crosshair
.AttachedPolygon
.PointN
= 0;
1337 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1341 /* back-up one point */
1344 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1345 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
- 2;
1347 Crosshair
.AttachedPolygon
.PointN
--;
1348 Crosshair
.AttachedLine
.Point1
.X
= points
[n
].X
;
1349 Crosshair
.AttachedLine
.Point1
.Y
= points
[n
].Y
;
1355 /* ---------------------------------------------------------------------------
1356 * close polygon if possible
1361 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1363 /* check number of points */
1366 /* if 45 degree lines are what we want do a quick check
1367 * if closing the polygon makes sense
1369 if (!TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
1373 dx
= abs (Crosshair
.AttachedPolygon
.Points
[n
- 1].X
-
1374 Crosshair
.AttachedPolygon
.Points
[0].X
);
1375 dy
= abs (Crosshair
.AttachedPolygon
.Points
[n
- 1].Y
-
1376 Crosshair
.AttachedPolygon
.Points
[0].Y
);
1377 if (!(dx
== 0 || dy
== 0 || dx
== dy
))
1381 ("Cannot close polygon because 45 degree lines are requested.\n"));
1385 CopyAttachedPolygonToLayer ();
1389 Message (_("A polygon has to have at least 3 points\n"));
1392 /* ---------------------------------------------------------------------------
1393 * moves the data of the attached (new) polygon to the current layer
1396 CopyAttachedPolygonToLayer (void)
1398 PolygonTypePtr polygon
;
1401 /* move data to layer and clear attached struct */
1402 polygon
= CreateNewPolygon (CURRENT
, NoFlags ());
1403 saveID
= polygon
->ID
;
1404 *polygon
= Crosshair
.AttachedPolygon
;
1405 polygon
->ID
= saveID
;
1406 SET_FLAG (CLEARPOLYFLAG
, polygon
);
1407 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1408 SET_FLAG (FULLPOLYFLAG
, polygon
);
1409 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1410 SetPolygonBoundingBox (polygon
);
1411 if (!CURRENT
->polygon_tree
)
1412 CURRENT
->polygon_tree
= r_create_tree (NULL
, 0, 0);
1413 r_insert_entry (CURRENT
->polygon_tree
, (BoxType
*) polygon
, 0);
1414 InitClip (PCB
->Data
, CURRENT
, polygon
);
1415 DrawPolygon (CURRENT
, polygon
, 0);
1416 SetChangedFlag (true);
1418 /* reset state of attached line */
1419 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1422 /* add to undo list */
1423 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
, polygon
, polygon
);
1424 IncrementUndoSerialNumber ();
1427 /* find polygon holes in range, then call the callback function for
1428 * each hole. If the callback returns non-zero, stop
1432 PolygonHoles (PolygonType
*polygon
, const BoxType
*range
,
1433 int (*callback
) (PLINE
*contour
, void *user_data
),
1436 POLYAREA
*pa
= polygon
->Clipped
;
1438 /* If this hole is so big the polygon doesn't exist, then it's not
1443 for (pl
= pa
->contours
->next
; pl
; pl
= pl
->next
)
1445 if (range
!= NULL
&&
1446 (pl
->xmin
> range
->X2
|| pl
->xmax
< range
->X1
||
1447 pl
->ymin
> range
->Y2
|| pl
->ymax
< range
->Y1
))
1449 if (callback (pl
, user_data
))
1463 int (*callback
) (DataTypePtr
, LayerTypePtr
, PolygonTypePtr
, int, void *,
1468 subtract_plow (DataTypePtr Data
, LayerTypePtr Layer
, PolygonTypePtr Polygon
,
1469 int type
, void *ptr1
, void *ptr2
)
1471 if (!Polygon
->Clipped
)
1477 SubtractPin (Data
, (PinTypePtr
) ptr2
, Layer
, Polygon
);
1478 Polygon
->NoHolesValid
= 0;
1481 SubtractLine ((LineTypePtr
) ptr2
, Polygon
);
1482 Polygon
->NoHolesValid
= 0;
1485 SubtractArc ((ArcTypePtr
) ptr2
, Polygon
);
1486 Polygon
->NoHolesValid
= 0;
1489 SubtractPad ((PadTypePtr
) ptr2
, Polygon
);
1490 Polygon
->NoHolesValid
= 0;
1493 SubtractText ((TextTypePtr
) ptr2
, Polygon
);
1494 Polygon
->NoHolesValid
= 0;
1501 add_plow (DataTypePtr Data
, LayerTypePtr Layer
, PolygonTypePtr Polygon
,
1502 int type
, void *ptr1
, void *ptr2
)
1508 UnsubtractPin ((PinTypePtr
) ptr2
, Layer
, Polygon
);
1511 UnsubtractLine ((LineTypePtr
) ptr2
, Layer
, Polygon
);
1514 UnsubtractArc ((ArcTypePtr
) ptr2
, Layer
, Polygon
);
1517 UnsubtractPad ((PadTypePtr
) ptr2
, Layer
, Polygon
);
1520 UnsubtractText ((TextTypePtr
) ptr2
, Layer
, Polygon
);
1527 plow_callback (const BoxType
* b
, void *cl
)
1529 struct plow_info
*plow
= (struct plow_info
*) cl
;
1530 PolygonTypePtr polygon
= (PolygonTypePtr
) b
;
1532 if (TEST_FLAG (CLEARPOLYFLAG
, polygon
))
1533 return plow
->callback (plow
->data
, plow
->layer
, polygon
, plow
->type
,
1534 plow
->ptr1
, plow
->ptr2
);
1539 PlowsPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
,
1540 int (*call_back
) (DataTypePtr data
, LayerTypePtr lay
,
1541 PolygonTypePtr poly
, int type
, void *ptr1
,
1544 BoxType sb
= ((PinTypePtr
) ptr2
)->BoundingBox
;
1546 struct plow_info info
;
1552 info
.callback
= call_back
;
1557 if (type
== PIN_TYPE
|| ptr1
== ptr2
|| ptr1
== NULL
)
1559 LAYER_LOOP (Data
, max_copper_layer
);
1563 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1569 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1570 ((LayerTypePtr
) ptr1
))));
1574 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1582 /* the cast works equally well for lines and arcs */
1583 if (!TEST_FLAG (CLEARLINEFLAG
, (LineTypePtr
) ptr2
))
1585 /* silk doesn't plow */
1586 if (GetLayerNumber (Data
, ptr1
) >= max_copper_layer
)
1588 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1589 ((LayerTypePtr
) ptr1
))));
1592 r
+= r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1598 Cardinal group
= GetLayerGroupNumberByNumber (
1599 TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ?
1600 solder_silk_layer
: component_silk_layer
);
1601 GROUP_LOOP (Data
, group
);
1605 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1613 PIN_LOOP ((ElementType
*) ptr1
);
1615 PlowsPolygon (Data
, PIN_TYPE
, ptr1
, pin
, call_back
);
1618 PAD_LOOP ((ElementType
*) ptr1
);
1620 PlowsPolygon (Data
, PAD_TYPE
, ptr1
, pad
, call_back
);
1630 RestoreToPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1632 if (type
== POLYGON_TYPE
)
1633 InitClip (PCB
->Data
, (LayerTypePtr
) ptr1
, (PolygonTypePtr
) ptr2
);
1635 PlowsPolygon (Data
, type
, ptr1
, ptr2
, add_plow
);
1639 ClearFromPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1641 if (type
== POLYGON_TYPE
)
1642 InitClip (PCB
->Data
, (LayerTypePtr
) ptr1
, (PolygonTypePtr
) ptr2
);
1644 PlowsPolygon (Data
, type
, ptr1
, ptr2
, subtract_plow
);
1648 isects (POLYAREA
* a
, PolygonTypePtr p
, bool fr
)
1652 ans
= Touching (a
, p
->Clipped
);
1653 /* argument may be register, so we must copy it */
1662 IsPointInPolygon (LocationType X
, LocationType Y
, BDimension r
,
1669 if (poly_CheckInside (p
->Clipped
, v
))
1673 if (!(c
= CirclePoly (X
, Y
, r
)))
1675 return isects (c
, p
, true);
1680 IsPointInPolygonIgnoreHoles (LocationType X
, LocationType Y
, PolygonTypePtr p
)
1685 return poly_InsideContour (p
->Clipped
->contours
, v
);
1689 IsRectangleInPolygon (LocationType X1
, LocationType Y1
, LocationType X2
,
1690 LocationType Y2
, PolygonTypePtr p
)
1694 (s
= RectPoly (min (X1
, X2
), max (X1
, X2
), min (Y1
, Y2
), max (Y1
, Y2
))))
1696 return isects (s
, p
, true);
1699 /* NB: This function will free the passed POLYAREA.
1700 * It must only be passed a single POLYAREA (pa->f == pa->b == pa)
1703 r_NoHolesPolygonDicer (POLYAREA
* pa
,
1704 void (*emit
) (PLINE
*, void *), void *user_data
)
1706 PLINE
*p
= pa
->contours
;
1708 if (!pa
->contours
->next
) /* no holes */
1710 pa
->contours
= NULL
; /* The callback now owns the contour */
1711 /* Don't bother removing it from the POLYAREA's rtree
1712 since we're going to free the POLYAREA below anyway */
1713 emit (p
, user_data
);
1719 POLYAREA
*poly2
, *left
, *right
;
1721 /* make a rectangle of the left region slicing through the middle of the first hole */
1722 poly2
= RectPoly (p
->xmin
, (p
->next
->xmin
+ p
->next
->xmax
) / 2,
1724 poly_AndSubtract_free (pa
, poly2
, &left
, &right
);
1727 POLYAREA
*cur
, *next
;
1732 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1733 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1734 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1736 while ((cur
= next
) != left
);
1740 POLYAREA
*cur
, *next
;
1745 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1746 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1747 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1749 while ((cur
= next
) != right
);
1755 NoHolesPolygonDicer (PolygonTypePtr p
, const BoxType
* clip
,
1756 void (*emit
) (PLINE
*, void *), void *user_data
)
1758 POLYAREA
*save
, *ans
, *cur
, *next
;
1760 ans
= save
= poly_Create ();
1761 /* copy the main poly only */
1762 poly_Copy1 (save
, p
->Clipped
);
1763 /* clip to the bounding box */
1766 POLYAREA
*cbox
= RectPoly (clip
->X1
, clip
->X2
, clip
->Y1
, clip
->Y2
);
1769 int r
= poly_Boolean_free (save
, cbox
, &ans
, PBO_ISECT
);
1778 * NB: Could be more than one piece (because of the clip above)
1784 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1785 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1786 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1788 while ((cur
= next
) != save
);
1791 /* make a polygon split into multiple parts into multiple polygons */
1793 MorphPolygon (LayerTypePtr layer
, PolygonTypePtr poly
)
1795 POLYAREA
*p
, *start
;
1799 if (!poly
->Clipped
|| TEST_FLAG (LOCKFLAG
, poly
))
1801 if (poly
->Clipped
->f
== poly
->Clipped
)
1803 ErasePolygon (poly
);
1804 start
= p
= poly
->Clipped
;
1805 /* This is ugly. The creation of the new polygons can cause
1806 * all of the polygon pointers (including the one we're called
1807 * with to change if there is a realloc in GetPolygonMemory().
1808 * That will invalidate our original "poly" argument, potentially
1809 * inside the loop. We need to steal the Clipped pointer and
1810 * hide it from the Remove call so that it still exists while
1811 * we do this dirty work.
1813 poly
->Clipped
= NULL
;
1814 if (poly
->NoHoles
) printf ("Just leaked in MorpyPolygon\n");
1815 poly
->NoHoles
= NULL
;
1816 flags
= poly
->Flags
;
1817 RemovePolygon (layer
, poly
);
1824 if (p
->contours
->area
> PCB
->IsleArea
)
1826 new = CreateNewPolygon (layer
, flags
);
1830 v
= &p
->contours
->head
;
1831 CreateNewPointInPolygon (new, v
->point
[0], v
->point
[1]);
1832 for (v
= v
->next
; v
!= &p
->contours
->head
; v
= v
->next
)
1833 CreateNewPointInPolygon (new, v
->point
[0], v
->point
[1]);
1834 new->BoundingBox
.X1
= p
->contours
->xmin
;
1835 new->BoundingBox
.X2
= p
->contours
->xmax
+ 1;
1836 new->BoundingBox
.Y1
= p
->contours
->ymin
;
1837 new->BoundingBox
.Y2
= p
->contours
->ymax
+ 1;
1838 AddObjectToCreateUndoList (POLYGON_TYPE
, layer
, new, new);
1840 p
= p
->f
; /* go to next pline */
1841 new->Clipped
->b
= new->Clipped
->f
= new->Clipped
; /* unlink from others */
1842 r_insert_entry (layer
->polygon_tree
, (BoxType
*) new, 0);
1843 DrawPolygon (layer
, new, 0);
1850 poly_DelContour (&t
->contours
);
1856 IncrementUndoSerialNumber ();
1860 void debug_pline (PLINE
*pl
)
1863 fprintf (stderr
, "\txmin %d xmax %d ymin %d ymax %d\n",
1864 pl
->xmin
, pl
->xmax
, pl
->ymin
, pl
->ymax
);
1868 fprintf(stderr
, "\t\tvnode: %d,%d\n", v
->point
[0], v
->point
[1]);
1876 debug_polyarea (POLYAREA
*p
)
1880 fprintf (stderr
, "POLYAREA %p\n", p
);
1881 for (pl
=p
->contours
; pl
; pl
=pl
->next
)
1886 debug_polygon (PolygonType
*p
)
1890 fprintf (stderr
, "POLYGON %p %d pts\n", p
, p
->PointN
);
1891 for (i
=0; i
<p
->PointN
; i
++)
1892 fprintf(stderr
, "\t%d: %d, %d\n", i
, p
->Points
[i
].X
, p
->Points
[i
].Y
);
1895 fprintf (stderr
, "%d holes, starting at indices\n", p
->HoleIndexN
);
1896 for (i
=0; i
<p
->HoleIndexN
; i
++)
1897 fprintf(stderr
, "\t%d: %d\n", i
, p
->HoleIndex
[i
]);
1900 fprintf (stderr
, "it has no holes\n");
1904 debug_polyarea (pa
);
1906 if (pa
== p
->Clipped
)
1911 /* Convert a POLYAREA (and all linked POLYAREA) to
1912 * raw PCB polygons on the given layer.
1915 PolyToPolygonsOnLayer (DataType
*Destination
, LayerType
*Layer
,
1916 POLYAREA
*Input
, FlagType Flags
)
1918 PolygonType
*Polygon
;
1930 Polygon
= CreateNewPolygon (Layer
, Flags
);
1932 pline
= pa
->contours
;
1938 CreateNewHoleInPolygon (Polygon
);
1941 node
= &pline
->head
;
1944 CreateNewPointInPolygon (Polygon
, node
->point
[0],
1947 while ((node
= node
->next
) != &pline
->head
);
1950 while ((pline
= pline
->next
) != NULL
);
1952 InitClip (Destination
, Layer
, Polygon
);
1953 SetPolygonBoundingBox (Polygon
);
1954 if (!Layer
->polygon_tree
)
1955 Layer
->polygon_tree
= r_create_tree (NULL
, 0, 0);
1956 r_insert_entry (Layer
->polygon_tree
, (BoxType
*) Polygon
, 0);
1958 DrawPolygon (Layer
, Polygon
, 0);
1959 /* add to undo list */
1960 AddObjectToCreateUndoList (POLYGON_TYPE
, Layer
, Polygon
, Polygon
);
1962 while ((pa
= pa
->f
) != Input
);
1964 SetChangedFlag (true);