6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
32 Here's a brief tour of the data and life of a polygon, courtesy of Ben
35 A PCB PolygonType contains an array of points outlining the polygon.
36 This is what is manipulated by the UI and stored in the saved PCB.
38 A PolygonType also contains a POLYAREA called 'Clipped' which is
39 computed dynamically by InitClip every time a board is loaded. The
40 point array is coverted to a POLYAREA by original_poly and then holes
41 are cut in it by clearPoly. After that it is maintained dynamically
42 as parts are added, moved or removed (this is why sometimes bugs can
43 be fixed by just re-loading the board).
45 A POLYAREA consists of a linked list of PLINE structures. The head of
46 that list is POLYAREA.contours. The first contour is an outline of a
47 filled region. All of the subsequent PLINEs are holes cut out of that
48 first contour. POLYAREAs are in a doubly-linked list and each member
49 of the list is an independent (non-overlapping) area with its own
50 outline and holes. The function biggest() finds the largest POLYAREA
51 so that PolygonType.Clipped points to that shape. The rest of the
52 polygon still exists, it's just ignored when turning the polygon into
55 The first POLYAREA in PolygonType.Clipped is what is used for the vast
56 majority of Polygon related tests. The basic logic for an
57 intersection is "is the target shape inside POLYAREA.contours and NOT
58 fully enclosed in any of POLYAREA.contours.next... (the holes)".
60 The polygon dicer (NoHolesPolygonDicer and r_NoHolesPolygonDicer)
61 emits a series of "simple" PLINE shapes. That is, the PLINE isn't
62 linked to any other "holes" oulines). That's the meaning of the first
63 test in r_NoHolesPolygonDicer. It is testing to see if the PLINE
64 contour (the first, making it a solid outline) has a valid next
65 pointer (which would point to one or more holes). The dicer works by
66 recursively chopping the polygon in half through the first hole it
67 sees (which is guaranteed to eliminate at least that one hole). The
68 dicer output is used for HIDs which cannot render things with holes
69 (which would require erasure).
73 /* special polygon editing routines
88 #include "crosshair.h"
103 #ifdef HAVE_LIBDMALLOC
109 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5 : (x) - 0.5)))
111 #define UNSUBTRACT_BLOAT 10
113 /* ---------------------------------------------------------------------------
118 static double circleVerticies
[] = {
120 0.98768834059513777, 0.15643446504023087,
124 polygon_point_idx (PolygonTypePtr polygon
, PointTypePtr point
)
126 assert (point
>= polygon
->Points
);
127 assert (point
<= polygon
->Points
+ polygon
->PointN
);
128 return ((char *)point
- (char *)polygon
->Points
) / sizeof (PointType
);
131 /* Find contour number: 0 for outer, 1 for first hole etc.. */
133 polygon_point_contour (PolygonTypePtr polygon
, Cardinal point
)
136 Cardinal contour
= 0;
138 for (i
= 0; i
< polygon
->HoleIndexN
; i
++)
139 if (point
>= polygon
->HoleIndex
[i
])
145 next_contour_point (PolygonTypePtr polygon
, Cardinal point
)
148 Cardinal this_contour_start
;
149 Cardinal next_contour_start
;
151 contour
= polygon_point_contour (polygon
, point
);
153 this_contour_start
= (contour
== 0) ? 0 :
154 polygon
->HoleIndex
[contour
- 1];
156 (contour
== polygon
->HoleIndexN
) ? polygon
->PointN
:
157 polygon
->HoleIndex
[contour
];
159 /* Wrap back to the start of the contour we're in if we pass the end */
160 if (++point
== next_contour_start
)
161 point
= this_contour_start
;
167 prev_contour_point (PolygonTypePtr polygon
, Cardinal point
)
170 Cardinal prev_contour_end
;
171 Cardinal this_contour_end
;
173 contour
= polygon_point_contour (polygon
, point
);
175 prev_contour_end
= (contour
== 0) ? 0 :
176 polygon
->HoleIndex
[contour
- 1];
178 (contour
== polygon
->HoleIndexN
) ? polygon
->PointN
- 1:
179 polygon
->HoleIndex
[contour
] - 1;
181 /* Wrap back to the start of the contour we're in if we pass the end */
182 if (point
== prev_contour_end
)
183 point
= this_contour_end
;
191 add_noholes_polyarea (PLINE
*pline
, void *user_data
)
193 PolygonType
*poly
= user_data
;
195 /* Prepend the pline into the NoHoles linked list */
196 pline
->next
= poly
->NoHoles
;
197 poly
->NoHoles
= pline
;
201 ComputeNoHoles (PolygonType
*poly
)
203 poly_FreeContours (&poly
->NoHoles
);
205 NoHolesPolygonDicer (poly
, NULL
, add_noholes_polyarea
, poly
);
207 printf ("Compute_noholes caught poly->Clipped = NULL\n");
208 poly
->NoHolesValid
= 1;
212 biggest (POLYAREA
* p
)
214 POLYAREA
*n
, *top
= NULL
;
223 if (n
->contours
->area
< PCB
->IsleArea
)
227 poly_DelContour (&n
->contours
);
238 if (n
->contours
->area
> big
)
241 big
= n
->contours
->area
;
244 while ((n
= n
->f
) != p
);
249 top
->contours
= p
->contours
;
258 ContourToPoly (PLINE
* contour
)
261 poly_PreContour (contour
, TRUE
);
262 assert (contour
->Flags
.orient
== PLF_DIR
);
263 if (!(p
= poly_Create ()))
265 poly_InclContour (p
, contour
);
266 assert (poly_Valid (p
));
271 original_poly (PolygonType
* p
)
273 PLINE
*contour
= NULL
;
279 if ((np
= poly_Create ()) == NULL
)
282 /* first make initial polygon contour */
283 for (n
= 0; n
< p
->PointN
; n
++)
285 /* No current contour? Make a new one starting at point */
286 /* (or) Add point to existing contour */
288 v
[0] = p
->Points
[n
].X
;
289 v
[1] = p
->Points
[n
].Y
;
292 if ((contour
= poly_NewContour (v
)) == NULL
)
297 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
300 /* Is current point last in contour? If so process it. */
301 if (n
== p
->PointN
- 1 ||
302 (hole
< p
->HoleIndexN
&& n
== p
->HoleIndex
[hole
] - 1))
304 poly_PreContour (contour
, TRUE
);
306 /* make sure it is a positive contour (outer) or negative (hole) */
307 if (contour
->Flags
.orient
!= (hole
? PLF_INV
: PLF_DIR
))
308 poly_InvContour (contour
);
309 assert (contour
->Flags
.orient
== (hole
? PLF_INV
: PLF_DIR
));
311 poly_InclContour (np
, contour
);
313 assert (poly_Valid (np
));
322 PolygonToPoly (PolygonType
*p
)
324 return original_poly (p
);
328 RectPoly (LocationType x1
, LocationType x2
, LocationType y1
, LocationType y2
)
330 PLINE
*contour
= NULL
;
337 if ((contour
= poly_NewContour (v
)) == NULL
)
341 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
344 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
347 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
348 return ContourToPoly (contour
);
352 OctagonPoly (LocationType x
, LocationType y
, BDimension radius
)
354 PLINE
*contour
= NULL
;
357 v
[0] = x
+ ROUND (radius
* 0.5);
358 v
[1] = y
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
359 if ((contour
= poly_NewContour (v
)) == NULL
)
361 v
[0] = x
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
362 v
[1] = y
+ ROUND (radius
* 0.5);
363 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
364 v
[0] = x
- (v
[0] - x
);
365 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
366 v
[0] = x
- ROUND (radius
* 0.5);
367 v
[1] = y
+ ROUND (radius
* TAN_22_5_DEGREE_2
);
368 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
369 v
[1] = y
- (v
[1] - y
);
370 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
371 v
[0] = x
- ROUND (radius
* TAN_22_5_DEGREE_2
);
372 v
[1] = y
- ROUND (radius
* 0.5);
373 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
374 v
[0] = x
- (v
[0] - x
);
375 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
376 v
[0] = x
+ ROUND (radius
* 0.5);
377 v
[1] = y
- ROUND (radius
* TAN_22_5_DEGREE_2
);
378 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
379 return ContourToPoly (contour
);
382 /* add verticies in a fractional-circle starting from v
383 * centered at X, Y and going counter-clockwise
384 * does not include the first point
385 * last argument is 1 for a full circle
386 * 2 for a half circle
387 * or 4 for a quarter circle
390 frac_circle (PLINE
* c
, LocationType X
, LocationType Y
, Vector v
, int range
)
395 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
396 /* move vector to origin */
400 /* NB: the caller adds the last vertex, hence the -1 */
401 range
= CIRC_SEGS
/ range
- 1;
402 for (i
= 0; i
< range
; i
++)
404 /* rotate the vector */
405 t1
= e1
* circleVerticies
[2] - e2
* circleVerticies
[3];
406 e2
= e1
* circleVerticies
[3] + e2
* circleVerticies
[2];
408 v
[0] = X
+ ROUND (e1
);
409 v
[1] = Y
+ ROUND (e2
);
410 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
414 /* create a circle approximation from lines */
416 CirclePoly (LocationType x
, LocationType y
, BDimension radius
)
425 if ((contour
= poly_NewContour (v
)) == NULL
)
427 frac_circle (contour
, x
, y
, v
, 1);
428 contour
->is_round
= TRUE
;
431 contour
->radius
= radius
;
432 return ContourToPoly (contour
);
435 /* make a rounded-corner rectangle with radius t beyond x1,x2,y1,y2 rectangle */
437 RoundRect (LocationType x1
, LocationType x2
, LocationType y1
, LocationType y2
,
440 PLINE
*contour
= NULL
;
447 if ((contour
= poly_NewContour (v
)) == NULL
)
449 frac_circle (contour
, x1
, y1
, v
, 4);
452 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
453 frac_circle (contour
, x2
, y1
, v
, 4);
456 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
457 frac_circle (contour
, x2
, y2
, v
, 4);
460 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
461 frac_circle (contour
, x1
, y2
, v
, 4);
462 return ContourToPoly (contour
);
467 ArcPolyNoIntersect (ArcType
* a
, BDimension thick
)
469 PLINE
*contour
= NULL
;
474 double ang
, da
, rx
, ry
;
481 a
->StartAngle
+= a
->Delta
;
482 a
->Delta
= -a
->Delta
;
484 half
= (thick
+ 1) / 2;
485 ends
= GetArcEnds (a
);
486 /* start with inner radius */
487 rx
= MAX (a
->Width
- half
, 0);
488 ry
= MAX (a
->Height
- half
, 0);
489 segs
= a
->Delta
/ ARC_ANGLE
;
491 da
= (1.0 * a
->Delta
) / segs
;
492 v
[0] = a
->X
- rx
* cos (ang
* M180
);
493 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
494 if ((contour
= poly_NewContour (v
)) == NULL
)
496 for (i
= 0; i
< segs
- 1; i
++)
499 v
[0] = a
->X
- rx
* cos (ang
* M180
);
500 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
501 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
503 /* find last point */
504 ang
= a
->StartAngle
+ a
->Delta
;
505 v
[0] = a
->X
- rx
* cos (ang
* M180
);
506 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
507 /* add the round cap at the end */
508 frac_circle (contour
, ends
->X2
, ends
->Y2
, v
, 2);
509 /* and now do the outer arc (going backwards) */
510 rx
= a
->Width
+ half
;
511 ry
= a
->Width
+ half
;
513 for (i
= 0; i
< segs
; 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
));
520 /* now add other round cap */
522 v
[0] = a
->X
- rx
* cos (ang
* M180
);
523 v
[1] = a
->Y
+ ry
* sin (ang
* M180
);
524 frac_circle (contour
, ends
->X1
, ends
->Y1
, v
, 2);
525 /* now we have the whole contour */
526 if (!(np
= ContourToPoly (contour
)))
531 #define MIN_CLEARANCE_BEFORE_BISECT 10.
533 ArcPoly (ArcType
* a
, BDimension thick
)
537 POLYAREA
*tmp1
, *tmp2
, *res
;
539 delta
= (a
->Delta
< 0) ? -a
->Delta
: a
->Delta
;
541 /* If the arc segment would self-intersect, we need to construct it as the union of
542 two non-intersecting segments */
544 if (2 * M_PI
* a
->Width
* (1. - (double)delta
/ 360.) - thick
< MIN_CLEARANCE_BEFORE_BISECT
)
546 int half_delta
= a
->Delta
/ 2;
549 seg1
.Delta
= half_delta
;
550 seg2
.Delta
-= half_delta
;
551 seg2
.StartAngle
+= half_delta
;
553 tmp1
= ArcPolyNoIntersect (&seg1
, thick
);
554 tmp2
= ArcPolyNoIntersect (&seg2
, thick
);
555 poly_Boolean_free (tmp1
, tmp2
, &res
, PBO_UNITE
);
559 return ArcPolyNoIntersect (a
, thick
);
563 LinePoly (LineType
* L
, BDimension thick
)
565 PLINE
*contour
= NULL
;
569 long half
;LineType _l
=*L
,*l
=&_l
;
573 half
= (thick
+ 1) / 2;
575 sqrt (SQUARE (l
->Point1
.X
- l
->Point2
.X
) +
576 SQUARE (l
->Point1
.Y
- l
->Point2
.Y
));
577 if (!TEST_FLAG (SQUAREFLAG
,l
))
578 if (d
== 0) /* line is a point */
579 return CirclePoly (l
->Point1
.X
, l
->Point1
.Y
, half
);
583 dx
= (l
->Point1
.Y
- l
->Point2
.Y
) * d
;
584 dy
= (l
->Point2
.X
- l
->Point1
.X
) * d
;
591 if (TEST_FLAG (SQUAREFLAG
,l
))/* take into account the ends */
598 v
[0] = l
->Point1
.X
- dx
;
599 v
[1] = l
->Point1
.Y
- dy
;
600 if ((contour
= poly_NewContour (v
)) == NULL
)
602 v
[0] = l
->Point2
.X
- dx
;
603 v
[1] = l
->Point2
.Y
- dy
;
604 if (TEST_FLAG (SQUAREFLAG
,l
))
605 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
607 frac_circle (contour
, l
->Point2
.X
, l
->Point2
.Y
, v
, 2);
608 v
[0] = l
->Point2
.X
+ dx
;
609 v
[1] = l
->Point2
.Y
+ dy
;
610 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
611 v
[0] = l
->Point1
.X
+ dx
;
612 v
[1] = l
->Point1
.Y
+ dy
;
613 if (TEST_FLAG (SQUAREFLAG
,l
))
614 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
616 frac_circle (contour
, l
->Point1
.X
, l
->Point1
.Y
, v
, 2);
617 /* now we have the line contour */
618 if (!(np
= ContourToPoly (contour
)))
623 /* make a rounded-corner rectangle */
625 SquarePadPoly (PadType
* pad
, BDimension clear
)
627 PLINE
*contour
= NULL
;
633 PadType _t
=*pad
,*t
=&_t
;
634 PadType _c
=*pad
,*c
=&_c
;
635 int halfthick
= (pad
->Thickness
+ 1) / 2;
636 int halfclear
= (clear
+ 1) / 2;
639 sqrt (SQUARE (pad
->Point1
.X
- pad
->Point2
.X
) +
640 SQUARE (pad
->Point1
.Y
- pad
->Point2
.Y
));
643 double a
= halfthick
/ d
;
644 tx
= (t
->Point1
.Y
- t
->Point2
.Y
) * a
;
645 ty
= (t
->Point2
.X
- t
->Point1
.X
) * a
;
647 cx
= (c
->Point1
.Y
- c
->Point2
.Y
) * a
;
648 cy
= (c
->Point2
.X
- c
->Point1
.X
) * a
;
672 v
[0] = c
->Point1
.X
- tx
;
673 v
[1] = c
->Point1
.Y
- ty
;
674 if ((contour
= poly_NewContour (v
)) == NULL
)
676 frac_circle (contour
, (t
->Point1
.X
- tx
), (t
->Point1
.Y
- ty
), v
, 4);
678 v
[0] = t
->Point2
.X
- cx
;
679 v
[1] = t
->Point2
.Y
- cy
;
680 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
681 frac_circle (contour
, (t
->Point2
.X
- tx
), (t
->Point2
.Y
- ty
), v
, 4);
683 v
[0] = c
->Point2
.X
+ tx
;
684 v
[1] = c
->Point2
.Y
+ ty
;
685 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
686 frac_circle (contour
, (t
->Point2
.X
+ tx
), (t
->Point2
.Y
+ ty
), v
, 4);
688 v
[0] = t
->Point1
.X
+ cx
;
689 v
[1] = t
->Point1
.Y
+ cy
;
690 poly_InclVertex (contour
->head
.prev
, poly_CreateNode (v
));
691 frac_circle (contour
, (t
->Point1
.X
+ tx
), (t
->Point1
.Y
+ ty
), v
, 4);
693 /* now we have the line contour */
694 if (!(np
= ContourToPoly (contour
)))
699 /* clear np1 from the polygon */
701 Subtract (POLYAREA
* np1
, PolygonType
* p
, bool fnp
)
703 POLYAREA
*merged
= NULL
, *np
= np1
;
713 assert (poly_Valid (p
->Clipped
));
714 assert (poly_Valid (np
));
716 x
= poly_Boolean_free (p
->Clipped
, np
, &merged
, PBO_SUB
);
719 x
= poly_Boolean (p
->Clipped
, np
, &merged
, PBO_SUB
);
720 poly_Free (&p
->Clipped
);
722 assert (!merged
|| poly_Valid (merged
));
725 fprintf (stderr
, "Error while clipping PBO_SUB: %d\n", x
);
728 if (p
->NoHoles
) printf ("Just leaked in Subtract\n");
732 p
->Clipped
= biggest (merged
);
733 assert (!p
->Clipped
|| poly_Valid (p
->Clipped
));
735 Message ("Polygon cleared out of existence near (%d, %d)\n",
736 (p
->BoundingBox
.X1
+ p
->BoundingBox
.X2
) / 2,
737 (p
->BoundingBox
.Y1
+ p
->BoundingBox
.Y2
) / 2);
741 /* create a polygon of the pin clearance */
743 PinPoly (PinType
* pin
, BDimension thick
, BDimension clear
)
747 if (TEST_FLAG (SQUAREFLAG
, pin
))
749 size
= (thick
+ 1) / 2;
750 return RoundRect (pin
->X
- size
, pin
->X
+ size
, pin
->Y
- size
,
751 pin
->Y
+ size
, (clear
+ 1) / 2);
755 size
= (thick
+ clear
+ 1) / 2;
756 if (TEST_FLAG (OCTAGONFLAG
, pin
))
758 return OctagonPoly (pin
->X
, pin
->Y
, size
+ size
);
761 return CirclePoly (pin
->X
, pin
->Y
, size
);
765 BoxPolyBloated (BoxType
*box
, BDimension bloat
)
767 return RectPoly (box
->X1
- bloat
, box
->X2
+ bloat
,
768 box
->Y1
- bloat
, box
->Y2
+ bloat
);
771 /* remove the pin clearance from the polygon */
773 SubtractPin (DataType
* d
, PinType
* pin
, LayerType
* l
, PolygonType
* p
)
778 if (pin
->Clearance
== 0)
780 i
= GetLayerNumber (d
, l
);
781 if (TEST_THERM (i
, pin
))
783 np
= ThermPoly ((PCBTypePtr
) (d
->pcb
), pin
, i
);
789 np
= PinPoly (pin
, pin
->Thickness
, pin
->Clearance
);
793 return Subtract (np
, p
, TRUE
);
797 SubtractLine (LineType
* line
, PolygonType
* p
)
801 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
803 if (!(np
= LinePoly (line
, line
->Thickness
+ line
->Clearance
)))
805 return Subtract (np
, p
, true);
809 SubtractArc (ArcType
* arc
, PolygonType
* p
)
813 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
815 if (!(np
= ArcPoly (arc
, arc
->Thickness
+ arc
->Clearance
)))
817 return Subtract (np
, p
, true);
821 SubtractText (TextType
* text
, PolygonType
* p
)
824 const BoxType
*b
= &text
->BoundingBox
;
826 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
828 if (!(np
= RoundRect (b
->X1
+ PCB
->Bloat
, b
->X2
- PCB
->Bloat
,
829 b
->Y1
+ PCB
->Bloat
, b
->Y2
- PCB
->Bloat
, PCB
->Bloat
)))
831 return Subtract (np
, p
, true);
835 SubtractPad (PadType
* pad
, PolygonType
* p
)
839 if (pad
->Clearance
== 0)
841 if (TEST_FLAG (SQUAREFLAG
, pad
))
844 (np
= SquarePadPoly (pad
, pad
->Thickness
+ pad
->Clearance
)))
850 (np
= LinePoly ((LineType
*) pad
, pad
->Thickness
+ pad
->Clearance
)))
853 return Subtract (np
, p
, true);
858 const BoxType
*other
;
861 PolygonType
*polygon
;
867 pin_sub_callback (const BoxType
* b
, void *cl
)
869 PinTypePtr pin
= (PinTypePtr
) b
;
870 struct cpInfo
*info
= (struct cpInfo
*) cl
;
871 PolygonTypePtr polygon
;
873 /* don't subtract the object that was put back! */
874 if (b
== info
->other
)
876 polygon
= info
->polygon
;
877 if (SubtractPin (info
->data
, pin
, info
->layer
, polygon
) < 0)
878 longjmp (info
->env
, 1);
883 arc_sub_callback (const BoxType
* b
, void *cl
)
885 ArcTypePtr arc
= (ArcTypePtr
) b
;
886 struct cpInfo
*info
= (struct cpInfo
*) cl
;
887 PolygonTypePtr polygon
;
889 /* don't subtract the object that was put back! */
890 if (b
== info
->other
)
892 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
894 polygon
= info
->polygon
;
895 if (SubtractArc (arc
, polygon
) < 0)
896 longjmp (info
->env
, 1);
901 pad_sub_callback (const BoxType
* b
, void *cl
)
903 PadTypePtr pad
= (PadTypePtr
) b
;
904 struct cpInfo
*info
= (struct cpInfo
*) cl
;
905 PolygonTypePtr polygon
;
907 /* don't subtract the object that was put back! */
908 if (b
== info
->other
)
910 if (pad
->Clearance
== 0)
912 polygon
= info
->polygon
;
913 if (XOR (TEST_FLAG (ONSOLDERFLAG
, pad
), !info
->solder
))
915 if (SubtractPad (pad
, polygon
) < 0)
916 longjmp (info
->env
, 1);
923 line_sub_callback (const BoxType
* b
, void *cl
)
925 LineTypePtr line
= (LineTypePtr
) b
;
926 struct cpInfo
*info
= (struct cpInfo
*) cl
;
927 PolygonTypePtr polygon
;
929 /* don't subtract the object that was put back! */
930 if (b
== info
->other
)
932 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
934 polygon
= info
->polygon
;
935 if (SubtractLine (line
, polygon
) < 0)
936 longjmp (info
->env
, 1);
941 text_sub_callback (const BoxType
* b
, void *cl
)
943 TextTypePtr text
= (TextTypePtr
) b
;
944 struct cpInfo
*info
= (struct cpInfo
*) cl
;
945 PolygonTypePtr polygon
;
947 /* don't subtract the object that was put back! */
948 if (b
== info
->other
)
950 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
952 polygon
= info
->polygon
;
953 if (SubtractText (text
, polygon
) < 0)
954 longjmp (info
->env
, 1);
959 Group (DataTypePtr Data
, Cardinal layer
)
962 for (i
= 0; i
< max_layer
; i
++)
963 for (j
= 0; j
< ((PCBType
*) (Data
->pcb
))->LayerGroups
.Number
[i
]; j
++)
964 if (layer
== ((PCBType
*) (Data
->pcb
))->LayerGroups
.Entries
[i
][j
])
970 clearPoly (DataTypePtr Data
, LayerTypePtr Layer
, PolygonType
* polygon
,
971 const BoxType
* here
, BDimension expand
)
978 if (!TEST_FLAG (CLEARPOLYFLAG
, polygon
)
979 || GetLayerNumber (Data
, Layer
) >= max_layer
)
981 group
= Group (Data
, GetLayerNumber (Data
, Layer
));
982 info
.solder
= (group
== Group (Data
, max_layer
+ SOLDER_LAYER
));
986 info
.polygon
= polygon
;
988 region
= clip_box (here
, &polygon
->BoundingBox
);
990 region
= polygon
->BoundingBox
;
991 region
= bloat_box (®ion
, expand
);
993 if (setjmp (info
.env
) == 0)
995 r
= r_search (Data
->via_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
996 r
+= r_search (Data
->pin_tree
, ®ion
, NULL
, pin_sub_callback
, &info
);
997 GROUP_LOOP (Data
, group
);
1000 r_search (layer
->line_tree
, ®ion
, NULL
, line_sub_callback
,
1003 r_search (layer
->arc_tree
, ®ion
, NULL
, arc_sub_callback
, &info
);
1005 r_search (layer
->text_tree
, ®ion
, NULL
, text_sub_callback
, &info
);
1008 if (info
.solder
|| group
== Group (Data
, max_layer
+ COMPONENT_LAYER
))
1009 r
+= r_search (Data
->pad_tree
, ®ion
, NULL
, pad_sub_callback
, &info
);
1011 polygon
->NoHolesValid
= 0;
1016 Unsubtract (POLYAREA
* np1
, PolygonType
* p
)
1018 POLYAREA
*merged
= NULL
, *np
= np1
;
1019 POLYAREA
*orig_poly
, *clipped_np
;
1022 assert (p
&& p
->Clipped
);
1024 orig_poly
= original_poly (p
);
1026 x
= poly_Boolean_free (np
, orig_poly
, &clipped_np
, PBO_ISECT
);
1029 fprintf (stderr
, "Error while clipping PBO_ISECT: %d\n", x
);
1030 poly_Free (&clipped_np
);
1034 x
= poly_Boolean_free (p
->Clipped
, clipped_np
, &merged
, PBO_UNITE
);
1037 fprintf (stderr
, "Error while clipping PBO_UNITE: %d\n", x
);
1038 poly_Free (&merged
);
1041 p
->Clipped
= biggest (merged
);
1042 assert (!p
->Clipped
|| poly_Valid (p
->Clipped
));
1047 if (p
->NoHoles
) printf ("Just leaked in Unsubtract\n");
1053 UnsubtractPin (PinType
* pin
, LayerType
* l
, PolygonType
* p
)
1057 /* overlap a bit to prevent gaps from rounding errors */
1058 np
= BoxPolyBloated (&pin
->BoundingBox
, UNSUBTRACT_BLOAT
);
1062 if (!Unsubtract (np
, p
))
1064 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pin
, 2 * UNSUBTRACT_BLOAT
);
1069 UnsubtractArc (ArcType
* arc
, LayerType
* l
, PolygonType
* p
)
1073 if (!TEST_FLAG (CLEARLINEFLAG
, arc
))
1076 /* overlap a bit to prevent gaps from rounding errors */
1077 np
= BoxPolyBloated (&arc
->BoundingBox
, UNSUBTRACT_BLOAT
);
1081 if (!Unsubtract (np
, p
))
1083 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) arc
, 2 * UNSUBTRACT_BLOAT
);
1088 UnsubtractLine (LineType
* line
, LayerType
* l
, PolygonType
* p
)
1092 if (!TEST_FLAG (CLEARLINEFLAG
, line
))
1095 /* overlap a bit to prevent notches from rounding errors */
1096 np
= BoxPolyBloated (&line
->BoundingBox
, UNSUBTRACT_BLOAT
);
1100 if (!Unsubtract (np
, p
))
1102 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) line
, 2 * UNSUBTRACT_BLOAT
);
1107 UnsubtractText (TextType
* text
, LayerType
* l
, PolygonType
* p
)
1111 if (!TEST_FLAG (CLEARLINEFLAG
, text
))
1114 /* overlap a bit to prevent notches from rounding errors */
1115 np
= BoxPolyBloated (&text
->BoundingBox
, UNSUBTRACT_BLOAT
);
1119 if (!Unsubtract (np
, p
))
1121 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) text
, 2 * UNSUBTRACT_BLOAT
);
1126 UnsubtractPad (PadType
* pad
, LayerType
* l
, PolygonType
* p
)
1130 /* overlap a bit to prevent notches from rounding errors */
1131 np
= BoxPolyBloated (&pad
->BoundingBox
, UNSUBTRACT_BLOAT
);
1135 if (!Unsubtract (np
, p
))
1137 clearPoly (PCB
->Data
, l
, p
, (const BoxType
*) pad
, 2 * UNSUBTRACT_BLOAT
);
1141 static bool inhibit
= false;
1144 InitClip (DataTypePtr Data
, LayerTypePtr layer
, PolygonType
* p
)
1149 poly_Free (&p
->Clipped
);
1150 p
->Clipped
= original_poly (p
);
1151 poly_FreeContours (&p
->NoHoles
);
1154 assert (poly_Valid (p
->Clipped
));
1155 if (TEST_FLAG (CLEARPOLYFLAG
, p
))
1156 clearPoly (Data
, layer
, p
, NULL
, 0);
1158 p
->NoHolesValid
= 0;
1162 /* --------------------------------------------------------------------------
1163 * remove redundant polygon points. Any point that lies on the straight
1164 * line between the points on either side of it is redundant.
1165 * returns true if any points are removed
1168 RemoveExcessPolygonPoints (LayerTypePtr Layer
, PolygonTypePtr Polygon
)
1171 Cardinal n
, prev
, next
;
1173 bool changed
= false;
1178 for (n
= 0; n
< Polygon
->PointN
; n
++)
1180 prev
= prev_contour_point (Polygon
, n
);
1181 next
= next_contour_point (Polygon
, n
);
1182 p
= &Polygon
->Points
[n
];
1184 line
.Point1
= Polygon
->Points
[prev
];
1185 line
.Point2
= Polygon
->Points
[next
];
1187 if (IsPointOnLine ((float) p
->X
, (float) p
->Y
, 0.0, &line
))
1189 RemoveObject (POLYGONPOINT_TYPE
, Layer
, Polygon
, p
);
1196 /* ---------------------------------------------------------------------------
1197 * returns the index of the polygon point which is the end
1198 * point of the segment with the lowest distance to the passed
1202 GetLowestDistancePolygonPoint (PolygonTypePtr Polygon
, LocationType X
,
1205 double mindistance
= (double) MAX_COORD
* MAX_COORD
;
1206 PointTypePtr ptr1
, ptr2
;
1207 Cardinal n
, result
= 0;
1209 /* we calculate the distance to each segment and choose the
1210 * shortest distance. If the closest approach between the
1211 * given point and the projected line (i.e. the segment extended)
1212 * is not on the segment, then the distance is the distance
1213 * to the segment end point.
1216 for (n
= 0; n
< Polygon
->PointN
; n
++)
1218 register double u
, dx
, dy
;
1219 ptr1
= &Polygon
->Points
[prev_contour_point (Polygon
, n
)];
1220 ptr2
= &Polygon
->Points
[n
];
1222 dx
= ptr2
->X
- ptr1
->X
;
1223 dy
= ptr2
->Y
- ptr1
->Y
;
1224 if (dx
!= 0.0 || dy
!= 0.0)
1226 /* projected intersection is at P1 + u(P2 - P1) */
1227 u
= ((X
- ptr1
->X
) * dx
+ (Y
- ptr1
->Y
) * dy
) / (dx
* dx
+ dy
* dy
);
1230 { /* ptr1 is closest point */
1231 u
= SQUARE (X
- ptr1
->X
) + SQUARE (Y
- ptr1
->Y
);
1234 { /* ptr2 is closest point */
1235 u
= SQUARE (X
- ptr2
->X
) + SQUARE (Y
- ptr2
->Y
);
1238 { /* projected intersection is closest point */
1239 u
= SQUARE (X
- ptr1
->X
* (1.0 - u
) - u
* ptr2
->X
) +
1240 SQUARE (Y
- ptr1
->Y
* (1.0 - u
) - u
* ptr2
->Y
);
1242 if (u
< mindistance
)
1252 /* ---------------------------------------------------------------------------
1253 * go back to the previous point of the polygon
1256 GoToPreviousPoint (void)
1258 switch (Crosshair
.AttachedPolygon
.PointN
)
1260 /* do nothing if mode has just been entered */
1264 /* reset number of points and 'LINE_MODE' state */
1266 Crosshair
.AttachedPolygon
.PointN
= 0;
1267 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1271 /* back-up one point */
1274 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1275 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
- 2;
1277 Crosshair
.AttachedPolygon
.PointN
--;
1278 Crosshair
.AttachedLine
.Point1
.X
= points
[n
].X
;
1279 Crosshair
.AttachedLine
.Point1
.Y
= points
[n
].Y
;
1285 /* ---------------------------------------------------------------------------
1286 * close polygon if possible
1291 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1293 /* check number of points */
1296 /* if 45 degree lines are what we want do a quick check
1297 * if closing the polygon makes sense
1299 if (!TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
1303 dx
= abs (Crosshair
.AttachedPolygon
.Points
[n
- 1].X
-
1304 Crosshair
.AttachedPolygon
.Points
[0].X
);
1305 dy
= abs (Crosshair
.AttachedPolygon
.Points
[n
- 1].Y
-
1306 Crosshair
.AttachedPolygon
.Points
[0].Y
);
1307 if (!(dx
== 0 || dy
== 0 || dx
== dy
))
1311 ("Cannot close polygon because 45 degree lines are requested.\n"));
1315 CopyAttachedPolygonToLayer ();
1319 Message (_("A polygon has to have at least 3 points\n"));
1322 /* ---------------------------------------------------------------------------
1323 * moves the data of the attached (new) polygon to the current layer
1326 CopyAttachedPolygonToLayer (void)
1328 PolygonTypePtr polygon
;
1331 /* move data to layer and clear attached struct */
1332 polygon
= CreateNewPolygon (CURRENT
, NoFlags ());
1333 saveID
= polygon
->ID
;
1334 *polygon
= Crosshair
.AttachedPolygon
;
1335 polygon
->ID
= saveID
;
1336 SET_FLAG (CLEARPOLYFLAG
, polygon
);
1337 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1338 SET_FLAG (FULLPOLYFLAG
, polygon
);
1339 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1340 SetPolygonBoundingBox (polygon
);
1341 if (!CURRENT
->polygon_tree
)
1342 CURRENT
->polygon_tree
= r_create_tree (NULL
, 0, 0);
1343 r_insert_entry (CURRENT
->polygon_tree
, (BoxType
*) polygon
, 0);
1344 InitClip (PCB
->Data
, CURRENT
, polygon
);
1345 DrawPolygon (CURRENT
, polygon
, 0);
1346 SetChangedFlag (true);
1348 /* reset state of attached line */
1349 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1352 /* add to undo list */
1353 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
, polygon
, polygon
);
1354 IncrementUndoSerialNumber ();
1357 /* find polygon holes in range, then call the callback function for
1358 * each hole. If the callback returns non-zero, stop
1362 PolygonHoles (PolygonType
*polygon
, const BoxType
*range
,
1363 int (*callback
) (PLINE
*contour
, void *user_data
),
1366 POLYAREA
*pa
= polygon
->Clipped
;
1368 /* If this hole is so big the polygon doesn't exist, then it's not
1373 for (pl
= pa
->contours
->next
; pl
; pl
= pl
->next
)
1375 if (range
!= NULL
&&
1376 (pl
->xmin
> range
->X2
|| pl
->xmax
< range
->X1
||
1377 pl
->ymin
> range
->Y2
|| pl
->ymax
< range
->Y1
))
1379 if (callback (pl
, user_data
))
1393 int (*callback
) (DataTypePtr
, LayerTypePtr
, PolygonTypePtr
, int, void *,
1398 subtract_plow (DataTypePtr Data
, LayerTypePtr Layer
, PolygonTypePtr Polygon
,
1399 int type
, void *ptr1
, void *ptr2
)
1401 if (!Polygon
->Clipped
)
1407 SubtractPin (Data
, (PinTypePtr
) ptr2
, Layer
, Polygon
);
1408 Polygon
->NoHolesValid
= 0;
1411 SubtractLine ((LineTypePtr
) ptr2
, Polygon
);
1412 Polygon
->NoHolesValid
= 0;
1415 SubtractArc ((ArcTypePtr
) ptr2
, Polygon
);
1416 Polygon
->NoHolesValid
= 0;
1419 SubtractPad ((PadTypePtr
) ptr2
, Polygon
);
1420 Polygon
->NoHolesValid
= 0;
1423 SubtractText ((TextTypePtr
) ptr2
, Polygon
);
1424 Polygon
->NoHolesValid
= 0;
1431 add_plow (DataTypePtr Data
, LayerTypePtr Layer
, PolygonTypePtr Polygon
,
1432 int type
, void *ptr1
, void *ptr2
)
1438 UnsubtractPin ((PinTypePtr
) ptr2
, Layer
, Polygon
);
1441 UnsubtractLine ((LineTypePtr
) ptr2
, Layer
, Polygon
);
1444 UnsubtractArc ((ArcTypePtr
) ptr2
, Layer
, Polygon
);
1447 UnsubtractPad ((PadTypePtr
) ptr2
, Layer
, Polygon
);
1450 UnsubtractText ((TextTypePtr
) ptr2
, Layer
, Polygon
);
1457 plow_callback (const BoxType
* b
, void *cl
)
1459 struct plow_info
*plow
= (struct plow_info
*) cl
;
1460 PolygonTypePtr polygon
= (PolygonTypePtr
) b
;
1462 if (TEST_FLAG (CLEARPOLYFLAG
, polygon
))
1463 return plow
->callback (plow
->data
, plow
->layer
, polygon
, plow
->type
,
1464 plow
->ptr1
, plow
->ptr2
);
1469 PlowsPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
,
1470 int (*call_back
) (DataTypePtr data
, LayerTypePtr lay
,
1471 PolygonTypePtr poly
, int type
, void *ptr1
,
1474 BoxType sb
= ((PinTypePtr
) ptr2
)->BoundingBox
;
1476 struct plow_info info
;
1482 info
.callback
= call_back
;
1487 if (type
== PIN_TYPE
|| ptr1
== ptr2
|| ptr1
== NULL
)
1489 LAYER_LOOP (Data
, max_layer
);
1493 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1499 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1500 ((LayerTypePtr
) ptr1
))));
1504 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1512 /* the cast works equally well for lines and arcs */
1513 if (!TEST_FLAG (CLEARLINEFLAG
, (LineTypePtr
) ptr2
))
1515 /* silk doesn't plow */
1516 if (GetLayerNumber (Data
, ptr1
) >= max_layer
)
1518 GROUP_LOOP (Data
, GetLayerGroupNumberByNumber (GetLayerNumber (Data
,
1519 ((LayerTypePtr
) ptr1
))));
1522 r
+= r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1528 Cardinal group
= TEST_FLAG (ONSOLDERFLAG
,
1529 (PadType
*) ptr2
) ? SOLDER_LAYER
:
1531 group
= GetLayerGroupNumberByNumber (max_layer
+ group
);
1532 GROUP_LOOP (Data
, group
);
1536 r_search (layer
->polygon_tree
, &sb
, NULL
, plow_callback
, &info
);
1544 PIN_LOOP ((ElementType
*) ptr1
);
1546 PlowsPolygon (Data
, PIN_TYPE
, ptr1
, pin
, call_back
);
1549 PAD_LOOP ((ElementType
*) ptr1
);
1551 PlowsPolygon (Data
, PAD_TYPE
, ptr1
, pad
, call_back
);
1561 RestoreToPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1563 if (type
== POLYGON_TYPE
)
1564 InitClip (PCB
->Data
, (LayerTypePtr
) ptr1
, (PolygonTypePtr
) ptr2
);
1566 PlowsPolygon (Data
, type
, ptr1
, ptr2
, add_plow
);
1570 ClearFromPolygon (DataType
* Data
, int type
, void *ptr1
, void *ptr2
)
1572 if (type
== POLYGON_TYPE
)
1573 InitClip (PCB
->Data
, (LayerTypePtr
) ptr1
, (PolygonTypePtr
) ptr2
);
1575 PlowsPolygon (Data
, type
, ptr1
, ptr2
, subtract_plow
);
1579 isects (POLYAREA
* a
, PolygonTypePtr p
, bool fr
)
1583 ans
= Touching (a
, p
->Clipped
);
1584 /* argument may be register, so we must copy it */
1593 IsPointInPolygon (LocationType X
, LocationType Y
, BDimension r
,
1600 if (poly_CheckInside (p
->Clipped
, v
))
1604 if (!(c
= CirclePoly (X
, Y
, r
)))
1606 return isects (c
, p
, true);
1611 IsPointInPolygonIgnoreHoles (LocationType X
, LocationType Y
, PolygonTypePtr p
)
1616 return poly_InsideContour (p
->Clipped
->contours
, v
);
1620 IsRectangleInPolygon (LocationType X1
, LocationType Y1
, LocationType X2
,
1621 LocationType Y2
, PolygonTypePtr p
)
1625 (s
= RectPoly (min (X1
, X2
), max (X1
, X2
), min (Y1
, Y2
), max (Y1
, Y2
))))
1627 return isects (s
, p
, true);
1630 /* NB: This function will free the passed POLYAREA.
1631 * It must only be passed a single POLYAREA (pa->f == pa->b == pa)
1634 r_NoHolesPolygonDicer (POLYAREA
* pa
,
1635 void (*emit
) (PLINE
*, void *), void *user_data
)
1637 PLINE
*p
= pa
->contours
;
1639 if (!pa
->contours
->next
) /* no holes */
1641 pa
->contours
= NULL
; /* The callback now owns the contour */
1642 emit (p
, user_data
);
1648 POLYAREA
*poly2
, *left
, *right
;
1650 /* make a rectangle of the left region slicing through the middle of the first hole */
1651 poly2
= RectPoly (p
->xmin
, (p
->next
->xmin
+ p
->next
->xmax
) / 2,
1653 poly_AndSubtract_free (pa
, poly2
, &left
, &right
);
1656 POLYAREA
*cur
, *next
;
1661 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1662 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1663 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1665 while ((cur
= next
) != left
);
1669 POLYAREA
*cur
, *next
;
1674 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1675 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1676 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1678 while ((cur
= next
) != right
);
1684 NoHolesPolygonDicer (PolygonTypePtr p
, const BoxType
* clip
,
1685 void (*emit
) (PLINE
*, void *), void *user_data
)
1687 POLYAREA
*save
, *ans
, *cur
, *next
;
1689 ans
= save
= poly_Create ();
1690 /* copy the main poly only */
1691 poly_Copy1 (save
, p
->Clipped
);
1692 /* clip to the bounding box */
1695 POLYAREA
*cbox
= RectPoly (clip
->X1
, clip
->X2
, clip
->Y1
, clip
->Y2
);
1698 int r
= poly_Boolean_free (save
, cbox
, &ans
, PBO_ISECT
);
1707 * NB: Could be more than one piece (because of the clip above)
1713 cur
->f
= cur
->b
= cur
; /* Detach this polygon piece */
1714 r_NoHolesPolygonDicer (cur
, emit
, user_data
);
1715 /* NB: The POLYAREA was freed by its use in the recursive dicer */
1717 while ((cur
= next
) != save
);
1720 /* make a polygon split into multiple parts into multiple polygons */
1722 MorphPolygon (LayerTypePtr layer
, PolygonTypePtr poly
)
1724 POLYAREA
*p
, *start
;
1728 if (!poly
->Clipped
|| TEST_FLAG (LOCKFLAG
, poly
))
1730 if (poly
->Clipped
->f
== poly
->Clipped
)
1732 ErasePolygon (poly
);
1733 start
= p
= poly
->Clipped
;
1734 /* This is ugly. The creation of the new polygons can cause
1735 * all of the polygon pointers (including the one we're called
1736 * with to change if there is a realloc in GetPolygonMemory().
1737 * That will invalidate our original "poly" argument, potentially
1738 * inside the loop. We need to steal the Clipped pointer and
1739 * hide it from the Remove call so that it still exists while
1740 * we do this dirty work.
1742 poly
->Clipped
= NULL
;
1743 if (poly
->NoHoles
) printf ("Just leaked in MorpyPolygon\n");
1744 poly
->NoHoles
= NULL
;
1745 flags
= poly
->Flags
;
1746 RemovePolygon (layer
, poly
);
1753 if (p
->contours
->area
> PCB
->IsleArea
)
1755 new = CreateNewPolygon (layer
, flags
);
1759 v
= &p
->contours
->head
;
1760 CreateNewPointInPolygon (new, v
->point
[0], v
->point
[1]);
1761 for (v
= v
->next
; v
!= &p
->contours
->head
; v
= v
->next
)
1762 CreateNewPointInPolygon (new, v
->point
[0], v
->point
[1]);
1763 new->BoundingBox
.X1
= p
->contours
->xmin
;
1764 new->BoundingBox
.X2
= p
->contours
->xmax
+ 1;
1765 new->BoundingBox
.Y1
= p
->contours
->ymin
;
1766 new->BoundingBox
.Y2
= p
->contours
->ymax
+ 1;
1767 AddObjectToCreateUndoList (POLYGON_TYPE
, layer
, new, new);
1769 p
= p
->f
; /* go to next pline */
1770 new->Clipped
->b
= new->Clipped
->f
= new->Clipped
; /* unlink from others */
1771 r_insert_entry (layer
->polygon_tree
, (BoxType
*) new, 0);
1772 DrawPolygon (layer
, new, 0);
1779 poly_DelContour (&t
->contours
);
1785 IncrementUndoSerialNumber ();
1789 void debug_pline (PLINE
*pl
)
1792 fprintf (stderr
, "\txmin %d xmax %d ymin %d ymax %d\n",
1793 pl
->xmin
, pl
->xmax
, pl
->ymin
, pl
->ymax
);
1797 fprintf(stderr
, "\t\tvnode: %d,%d\n", v
->point
[0], v
->point
[1]);
1805 debug_polyarea (POLYAREA
*p
)
1809 fprintf (stderr
, "POLYAREA %p\n", p
);
1810 for (pl
=p
->contours
; pl
; pl
=pl
->next
)
1815 debug_polygon (PolygonType
*p
)
1819 fprintf (stderr
, "POLYGON %p %d pts\n", p
, p
->PointN
);
1820 for (i
=0; i
<p
->PointN
; i
++)
1821 fprintf(stderr
, "\t%d: %d, %d\n", i
, p
->Points
[i
].X
, p
->Points
[i
].Y
);
1824 fprintf (stderr
, "%d holes, starting at indices\n", p
->HoleIndexN
);
1825 for (i
=0; i
<p
->HoleIndexN
; i
++)
1826 fprintf(stderr
, "\t%d: %d\n", i
, p
->HoleIndex
[i
]);
1829 fprintf (stderr
, "it has no holes\n");
1833 debug_polyarea (pa
);
1835 if (pa
== p
->Clipped
)
1840 /* Convert a POLYAREA (and all linked POLYAREA) to
1841 * raw PCB polygons on the given layer.
1844 PolyToPolygonsOnLayer (DataType
*Destination
, LayerType
*Layer
,
1845 POLYAREA
*Input
, FlagType Flags
)
1847 PolygonType
*Polygon
;
1859 Polygon
= CreateNewPolygon (Layer
, Flags
);
1861 pline
= pa
->contours
;
1867 CreateNewHoleInPolygon (Polygon
);
1870 node
= &pline
->head
;
1873 CreateNewPointInPolygon (Polygon
, node
->point
[0],
1876 while ((node
= node
->next
) != &pline
->head
);
1879 while ((pline
= pline
->next
) != NULL
);
1881 InitClip (Destination
, Layer
, Polygon
);
1882 SetPolygonBoundingBox (Polygon
);
1883 if (!Layer
->polygon_tree
)
1884 Layer
->polygon_tree
= r_create_tree (NULL
, 0, 0);
1885 r_insert_entry (Layer
->polygon_tree
, (BoxType
*) Polygon
, 0);
1887 DrawPolygon (Layer
, Polygon
, 0);
1888 /* add to undo list */
1889 AddObjectToCreateUndoList (POLYGON_TYPE
, Layer
, Polygon
, Polygon
);
1891 while ((pa
= pa
->f
) != Input
);
1893 SetChangedFlag (true);