5 * PCB, interactive printed circuit board design
6 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Contact addresses for paper mail and Email:
23 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
24 * Thomas.Nau@rz.uni-ulm.de
31 * - lists for pins and vias, lines, arcs, pads and for polygons are created.
32 * Every object that has to be checked is added to its list.
33 * Coarse searching is accomplished with the data rtrees.
34 * - there's no 'speed-up' mechanism for polygons because they are not used
35 * as often as other objects
36 * - the maximum distance between line and pin ... would depend on the angle
37 * between them. To speed up computation the limit is set to one half
38 * of the thickness of the objects (cause of square pins).
40 * PV: means pin or via (objects that connect layers)
41 * LO: all non PV objects (layer objects like lines, arcs, polygons, pads)
43 * 1. first, the LO or PV at the given coordinates is looked up
44 * 2. all LO connections to that PV are looked up next
45 * 3. lookup of all LOs connected to LOs from (2).
46 * This step is repeated until no more new connections are found.
47 * 4. lookup all PVs connected to the LOs from (2) and (3)
48 * 5. start again with (1) for all new PVs from (4)
50 * Intersection of line <--> circle:
51 * - calculate the signed distance from the line to the center,
52 * return false if abs(distance) > R
53 * - get the distance from the line <--> distancevector intersection to
54 * (X1,Y1) in range [0,1], return true if 0 <= distance <= 1
55 * - depending on (r > 1.0 or r < 0.0) check the distance of X2,Y2 or X1,Y1
58 * Intersection of line <--> line:
59 * - see the description of 'LineLineIntersect()'
62 /* routines to find connections between pins, vias, lines...
76 #ifdef HAVE_SYS_TIMES_H
77 #include <sys/times.h>
82 #include "crosshair.h"
91 #include "pcb-printf.h"
97 #ifdef HAVE_LIBDMALLOC
103 /* ---------------------------------------------------------------------------
107 #define EXPAND_BOUNDS(p) if (Bloat > 0) {\
108 (p)->BoundingBox.X1 -= Bloat; \
109 (p)->BoundingBox.X2 += Bloat; \
110 (p)->BoundingBox.Y1 -= Bloat; \
111 (p)->BoundingBox.Y2 += Bloat;}
113 #define SEPARATE(FP) \
117 for (i = Settings.CharPerLine; i; i--) \
122 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
123 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
124 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
125 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
126 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
127 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
128 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
130 #define IS_PV_ON_RAT(PV, Rat) \
131 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
133 #define IS_PV_ON_ARC(PV, Arc) \
134 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
136 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
137 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
139 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
141 #define IS_PV_ON_PAD(PV,Pad) \
142 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
144 static DrcViolationType
145 *pcb_drc_violation_new (const char *title
,
146 const char *explanation
,
150 Coord measured_value
,
151 Coord required_value
,
153 long int *object_id_list
,
154 int *object_type_list
)
156 DrcViolationType
*violation
= (DrcViolationType
*)malloc (sizeof (DrcViolationType
));
158 violation
->title
= strdup (title
);
159 violation
->explanation
= strdup (explanation
);
162 violation
->angle
= angle
;
163 violation
->have_measured
= have_measured
;
164 violation
->measured_value
= measured_value
;
165 violation
->required_value
= required_value
;
166 violation
->object_count
= object_count
;
167 violation
->object_id_list
= object_id_list
;
168 violation
->object_type_list
= object_type_list
;
174 pcb_drc_violation_free (DrcViolationType
*violation
)
176 free (violation
->title
);
177 free (violation
->explanation
);
181 static GString
*drc_dialog_message
;
183 reset_drc_dialog_message(void)
185 if (drc_dialog_message
)
186 g_string_free (drc_dialog_message
, FALSE
);
187 drc_dialog_message
= g_string_new ("");
188 if (gui
->drc_gui
!= NULL
)
190 gui
->drc_gui
->reset_drc_dialog_message ();
194 append_drc_dialog_message(const char *fmt
, ...)
199 new_str
= pcb_vprintf (fmt
, ap
);
200 g_string_append (drc_dialog_message
, new_str
);
205 static void GotoError (void);
208 append_drc_violation (DrcViolationType
*violation
)
210 if (gui
->drc_gui
!= NULL
)
212 gui
->drc_gui
->append_drc_violation (violation
);
216 /* Fallback to formatting the violation message as text */
217 append_drc_dialog_message ("%s\n", violation
->title
);
218 append_drc_dialog_message (_("%m+near %$mD\n"),
219 Settings
.grid_unit
->allow
,
220 violation
->x
, violation
->y
);
224 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
226 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
227 Message (_("%m+near location %$mD\n"),
228 Settings
.grid_unit
->allow
,
229 violation
->x
, violation
->y
);
233 * message when asked about continuing DRC checks after next
234 * violation is found.
236 #define DRC_CONTINUE _("Press Next to continue DRC checking")
237 #define DRC_NEXT _("Next")
238 #define DRC_CANCEL _("Cancel")
241 throw_drc_dialog(void)
245 if (gui
->drc_gui
!= NULL
)
247 r
= gui
->drc_gui
->throw_drc_dialog ();
251 /* Fallback to formatting the violation message as text */
252 append_drc_dialog_message (DRC_CONTINUE
);
253 r
= gui
->confirm_dialog (drc_dialog_message
->str
, DRC_CANCEL
, DRC_NEXT
);
254 reset_drc_dialog_message();
259 /* ---------------------------------------------------------------------------
262 * the two 'dummy' structs for PVs and Pads are necessary for creating
263 * connection lists which include the element's name
267 void **Data
; /* pointer to index data */
268 Cardinal Location
, /* currently used position */
269 DrawLocation
, Number
, /* number of objects in list */
273 /* ---------------------------------------------------------------------------
274 * some local identifiers
276 static Coord Bloat
= 0;
277 static int TheFlag
= FOUNDFLAG
;
278 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
279 static int thing_type
;
280 static bool User
= false; /* user action causing this */
281 static bool drc
= false; /* whether to stop if finding something not found */
282 static bool IsBad
= false;
283 static Cardinal drcerr_count
; /* count of drc errors */
284 static Cardinal TotalP
, TotalV
, NumberOfPads
[2];
285 static ListType LineList
[MAX_LAYER
], /* list of objects to */
286 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
288 /* ---------------------------------------------------------------------------
289 * some local prototypes
291 static bool LookupLOConnectionsToPVList (bool);
292 static bool LookupLOConnectionsToLOList (bool);
293 static bool LookupPVConnectionsToLOList (bool);
294 static bool LookupPVConnectionsToPVList (void);
295 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, bool);
296 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
);
297 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
);
298 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
);
299 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
);
300 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
301 static bool ArcArcIntersect (ArcType
*, ArcType
*);
302 static bool PrepareNextLoop (FILE *);
303 static bool PrintElementConnections (ElementType
*, FILE *, bool);
304 static bool ListsEmpty (bool);
305 static bool DoIt (bool, bool);
306 static void PrintElementNameList (ElementType
*, FILE *);
307 static void PrintConnectionElementName (ElementType
*, FILE *);
308 static void PrintConnectionListEntry (char *, ElementType
*,
310 static void PrintPadConnections (Cardinal
, FILE *, bool);
311 static void PrintPinConnections (FILE *, bool);
312 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*,
314 static void DrawNewConnections (void);
315 static void DumpList (void);
316 static void LocateError (Coord
*, Coord
*);
317 static void BuildObjectList (int *, long int **, int **);
318 static void GotoError (void);
319 static bool DRCFind (int, void *, void *, void *);
320 static bool ListStart (int, void *, void *, void *);
321 static bool SetThing (int, void *, void *, void *);
322 static bool IsArcInPolygon (ArcType
*, PolygonType
*);
323 static bool IsLineInPolygon (LineType
*, PolygonType
*);
324 static bool IsPadInPolygon (PadType
*, PolygonType
*);
325 static bool IsPolygonInPolygon (PolygonType
*, PolygonType
*);
327 /* ---------------------------------------------------------------------------
328 * some of the 'pad' routines are the same as for lines because the 'pad'
329 * struct starts with a line struct. See global.h for details
332 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
334 return LineLineIntersect ((Line
), (LineType
*)Pad
);
338 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
340 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
344 add_object_to_list (ListType
*list
, int type
, void *ptr1
, void *ptr2
, void *ptr3
)
346 AnyObjectType
*object
= (AnyObjectType
*)ptr2
;
349 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
351 SET_FLAG (TheFlag
, object
);
352 LIST_ENTRY (list
, list
->Number
) = object
;
356 if (list
.Number
> list
.Size
)
357 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type
, list
.Number
, list
.Size
);
360 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, object
))
361 return (SetThing (type
, ptr1
, ptr2
, ptr3
));
366 ADD_PV_TO_LIST (PinType
*Pin
)
368 return add_object_to_list (&PVList
, Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
369 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
);
373 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
)
375 return add_object_to_list (&PadList
[L
], PAD_TYPE
, Pad
->Element
, Pad
, Pad
);
379 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
)
381 return add_object_to_list (&LineList
[L
], LINE_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
385 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
)
387 return add_object_to_list (&ArcList
[L
], ARC_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
391 ADD_RAT_TO_LIST (RatType
*Ptr
)
393 return add_object_to_list (&RatList
, RATLINE_TYPE
, Ptr
, Ptr
, Ptr
);
397 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
)
399 return add_object_to_list (&PolygonList
[L
], POLYGON_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
403 PinLineIntersect (PinType
*PV
, LineType
*Line
)
405 /* IsLineInRectangle already has Bloat factor */
406 return TEST_FLAG (SQUAREFLAG
,
407 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
408 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
409 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
410 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
411 Line
) : IsPointInPad (PV
->X
,
423 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
429 if (type
== PIN_TYPE
&& ptr1
== NULL
)
432 thing_type
= VIA_TYPE
;
438 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
440 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
442 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
448 PadPadIntersect (PadType
*p1
, PadType
*p2
)
450 return LinePadIntersect ((LineType
*) p1
, p2
);
454 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
459 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
460 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
461 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
462 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
464 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
466 /* check for square/square overlap */
471 t2
= PV2
->Thickness
/ 2.0;
476 return BoxBoxIntersection (&b1
, &b2
);
479 /* ---------------------------------------------------------------------------
480 * releases all allocated memory
483 FreeLayoutLookupMemory (void)
487 for (i
= 0; i
< max_copper_layer
; i
++)
489 free (LineList
[i
].Data
);
490 LineList
[i
].Data
= NULL
;
491 free (ArcList
[i
].Data
);
492 ArcList
[i
].Data
= NULL
;
493 free (PolygonList
[i
].Data
);
494 PolygonList
[i
].Data
= NULL
;
503 FreeComponentLookupMemory (void)
505 free (PadList
[0].Data
);
506 PadList
[0].Data
= NULL
;
507 free (PadList
[1].Data
);
508 PadList
[1].Data
= NULL
;
511 /* ---------------------------------------------------------------------------
512 * allocates memory for component related stacks ...
513 * initializes index and sorts it by X1 and X2
516 InitComponentLookup (void)
520 /* initialize pad data; start by counting the total number
521 * on each of the two possible layers
523 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
524 ALLPAD_LOOP (PCB
->Data
);
526 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
527 NumberOfPads
[SOLDER_LAYER
]++;
529 NumberOfPads
[COMPONENT_LAYER
]++;
532 for (i
= 0; i
< 2; i
++)
534 /* allocate memory for working list */
535 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
537 /* clear some struct members */
538 PadList
[i
].Location
= 0;
539 PadList
[i
].DrawLocation
= 0;
540 PadList
[i
].Number
= 0;
541 PadList
[i
].Size
= NumberOfPads
[i
];
545 /* ---------------------------------------------------------------------------
546 * allocates memory for component related stacks ...
547 * initializes index and sorts it by X1 and X2
550 InitLayoutLookup (void)
554 /* initialize line arc and polygon data */
555 for (i
= 0; i
< max_copper_layer
; i
++)
557 LayerType
*layer
= LAYER_PTR (i
);
561 /* allocate memory for line pointer lists */
562 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
563 LineList
[i
].Size
= layer
->LineN
;
567 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
568 ArcList
[i
].Size
= layer
->ArcN
;
572 /* allocate memory for polygon list */
575 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
576 PolygonList
[i
].Size
= layer
->PolygonN
;
579 /* clear some struct members */
580 LineList
[i
].Location
= 0;
581 LineList
[i
].DrawLocation
= 0;
582 LineList
[i
].Number
= 0;
583 ArcList
[i
].Location
= 0;
584 ArcList
[i
].DrawLocation
= 0;
585 ArcList
[i
].Number
= 0;
586 PolygonList
[i
].Location
= 0;
587 PolygonList
[i
].DrawLocation
= 0;
588 PolygonList
[i
].Number
= 0;
591 if (PCB
->Data
->pin_tree
)
592 TotalP
= PCB
->Data
->pin_tree
->size
;
595 if (PCB
->Data
->via_tree
)
596 TotalV
= PCB
->Data
->via_tree
->size
;
599 /* allocate memory for 'new PV to check' list and clear struct */
600 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
601 PVList
.Size
= TotalP
+ TotalV
;
603 PVList
.DrawLocation
= 0;
605 /* Initialize ratline data */
606 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
607 RatList
.Size
= PCB
->Data
->RatN
;
608 RatList
.Location
= 0;
609 RatList
.DrawLocation
= 0;
621 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
623 LineType
*line
= (LineType
*) b
;
624 struct pv_info
*i
= (struct pv_info
*) cl
;
626 if (!TEST_FLAG (TheFlag
, line
) && PinLineIntersect (&i
->pv
, line
) &&
627 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
629 if (ADD_LINE_TO_LIST (i
->layer
, line
))
636 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
638 ArcType
*arc
= (ArcType
*) b
;
639 struct pv_info
*i
= (struct pv_info
*) cl
;
641 if (!TEST_FLAG (TheFlag
, arc
) && IS_PV_ON_ARC (&i
->pv
, arc
) &&
642 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
644 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
651 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
653 PadType
*pad
= (PadType
*) b
;
654 struct pv_info
*i
= (struct pv_info
*) cl
;
656 if (!TEST_FLAG (TheFlag
, pad
) && IS_PV_ON_PAD (&i
->pv
, pad
) &&
657 !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
658 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
659 COMPONENT_LAYER
, pad
))
665 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
667 RatType
*rat
= (RatType
*) b
;
668 struct pv_info
*i
= (struct pv_info
*) cl
;
670 if (!TEST_FLAG (TheFlag
, rat
) && IS_PV_ON_RAT (&i
->pv
, rat
) &&
671 ADD_RAT_TO_LIST (rat
))
676 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
678 PolygonType
*polygon
= (PolygonType
*) b
;
679 struct pv_info
*i
= (struct pv_info
*) cl
;
681 /* if the pin doesn't have a therm and polygon is clearing
682 * then it can't touch due to clearance, so skip the expensive
683 * test. If it does have a therm, you still need to test
684 * because it might not be inside the polygon, or it could
685 * be on an edge such that it doesn't actually touch.
687 if (!TEST_FLAG (TheFlag
, polygon
) && !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
688 (TEST_THERM (i
->layer
, &i
->pv
) ||
689 !TEST_FLAG (CLEARPOLYFLAG
,
691 || !i
->pv
.Clearance
))
693 double wide
= MAX (0.5 * i
->pv
.Thickness
+ Bloat
, 0);
694 if (TEST_FLAG (SQUAREFLAG
, &i
->pv
))
696 Coord x1
= i
->pv
.X
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
697 Coord x2
= i
->pv
.X
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
698 Coord y1
= i
->pv
.Y
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
699 Coord y2
= i
->pv
.Y
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
700 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
701 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
704 else if (TEST_FLAG (OCTAGONFLAG
, &i
->pv
))
706 POLYAREA
*oct
= OctagonPoly (i
->pv
.X
, i
->pv
.Y
, i
->pv
.Thickness
/ 2);
707 if (isects (oct
, polygon
, true)
708 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
711 else if (IsPointInPolygon (i
->pv
.X
, i
->pv
.Y
, wide
,
713 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
719 /* ---------------------------------------------------------------------------
720 * checks if a PV is connected to LOs, if it is, the LO is added to
721 * the appropriate list and the 'used' flag is set
724 LookupLOConnectionsToPVList (bool AndRats
)
729 /* loop over all PVs currently on list */
730 while (PVList
.Location
< PVList
.Number
)
732 /* get pointer to data */
733 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
734 EXPAND_BOUNDS (&info
.pv
);
737 if (setjmp (info
.env
) == 0)
738 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pv
, NULL
,
739 LOCtoPVpad_callback
, &info
);
743 /* now all lines, arcs and polygons of the several layers */
744 for (layer
= 0; layer
< max_copper_layer
; layer
++)
746 if (LAYER_PTR (layer
)->no_drc
)
749 /* add touching lines */
750 if (setjmp (info
.env
) == 0)
751 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.pv
,
752 NULL
, LOCtoPVline_callback
, &info
);
755 /* add touching arcs */
756 if (setjmp (info
.env
) == 0)
757 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.pv
,
758 NULL
, LOCtoPVarc_callback
, &info
);
761 /* check all polygons */
762 if (setjmp (info
.env
) == 0)
763 r_search (LAYER_PTR (layer
)->polygon_tree
, (BoxType
*) & info
.pv
,
764 NULL
, LOCtoPVpoly_callback
, &info
);
768 /* Check for rat-lines that may intersect the PV */
771 if (setjmp (info
.env
) == 0)
772 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.pv
, NULL
,
773 LOCtoPVrat_callback
, &info
);
782 /* ---------------------------------------------------------------------------
783 * find all connections between LO at the current list position and new LOs
786 LookupLOConnectionsToLOList (bool AndRats
)
789 Cardinal i
, group
, layer
, ratposition
,
790 lineposition
[MAX_LAYER
],
791 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
793 /* copy the current LO list positions; the original data is changed
794 * by 'LookupPVConnectionsToLOList()' which has to check the same
795 * list entries plus the new ones
797 for (i
= 0; i
< max_copper_layer
; i
++)
799 lineposition
[i
] = LineList
[i
].Location
;
800 polyposition
[i
] = PolygonList
[i
].Location
;
801 arcposition
[i
] = ArcList
[i
].Location
;
803 for (i
= 0; i
< 2; i
++)
804 padposition
[i
] = PadList
[i
].Location
;
805 ratposition
= RatList
.Location
;
807 /* loop over all new LOs in the list; recurse until no
808 * more new connections in the layergroup were found
816 position
= &ratposition
;
817 for (; *position
< RatList
.Number
; (*position
)++)
819 group
= RATLIST_ENTRY (*position
)->group1
;
820 if (LookupLOConnectionsToRatEnd
821 (&(RATLIST_ENTRY (*position
)->Point1
), group
))
823 group
= RATLIST_ENTRY (*position
)->group2
;
824 if (LookupLOConnectionsToRatEnd
825 (&(RATLIST_ENTRY (*position
)->Point2
), group
))
829 /* loop over all layergroups */
830 for (group
= 0; group
< max_group
; group
++)
834 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
836 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
838 /* be aware that the layer number equal max_copper_layer
839 * and max_copper_layer+1 have a special meaning for pads
841 if (layer
< max_copper_layer
)
843 /* try all new lines */
844 position
= &lineposition
[layer
];
845 for (; *position
< LineList
[layer
].Number
; (*position
)++)
846 if (LookupLOConnectionsToLine
847 (LINELIST_ENTRY (layer
, *position
), group
, true))
850 /* try all new arcs */
851 position
= &arcposition
[layer
];
852 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
853 if (LookupLOConnectionsToArc
854 (ARCLIST_ENTRY (layer
, *position
), group
))
857 /* try all new polygons */
858 position
= &polyposition
[layer
];
859 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
860 if (LookupLOConnectionsToPolygon
861 (POLYGONLIST_ENTRY (layer
, *position
), group
))
866 /* try all new pads */
867 layer
-= max_copper_layer
;
870 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
871 layer
, max_copper_layer
);
874 position
= &padposition
[layer
];
875 for (; *position
< PadList
[layer
].Number
; (*position
)++)
876 if (LookupLOConnectionsToPad
877 (PADLIST_ENTRY (layer
, *position
), group
))
883 /* check if all lists are done; Later for-loops
884 * may have changed the prior lists
886 done
= !AndRats
|| ratposition
>= RatList
.Number
;
887 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
888 padposition
[1] >= PadList
[1].Number
;
889 for (layer
= 0; layer
< max_copper_layer
; layer
++)
891 lineposition
[layer
] >= LineList
[layer
].Number
&&
892 arcposition
[layer
] >= ArcList
[layer
].Number
&&
893 polyposition
[layer
] >= PolygonList
[layer
].Number
;
900 pv_pv_callback (const BoxType
* b
, void *cl
)
902 PinType
*pin
= (PinType
*) b
;
903 struct pv_info
*i
= (struct pv_info
*) cl
;
905 if (!TEST_FLAG (TheFlag
, pin
) && PV_TOUCH_PV (&i
->pv
, pin
))
907 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, &i
->pv
))
909 SET_FLAG (WARNFLAG
, pin
);
910 Settings
.RatWarn
= true;
912 Message (_("WARNING: Hole too close to pin.\n"));
914 Message (_("WARNING: Hole too close to via.\n"));
916 else if (ADD_PV_TO_LIST (pin
))
922 /* ---------------------------------------------------------------------------
923 * searches for new PVs that are connected to PVs on the list
926 LookupPVConnectionsToPVList (void)
932 /* loop over all PVs on list */
933 save_place
= PVList
.Location
;
934 while (PVList
.Location
< PVList
.Number
)
936 /* get pointer to data */
937 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
938 EXPAND_BOUNDS (&info
.pv
);
939 if (setjmp (info
.env
) == 0)
940 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pv
, NULL
,
941 pv_pv_callback
, &info
);
944 if (setjmp (info
.env
) == 0)
945 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pv
, NULL
,
946 pv_pv_callback
, &info
);
951 PVList
.Location
= save_place
;
967 pv_line_callback (const BoxType
* b
, void *cl
)
969 PinType
*pv
= (PinType
*) b
;
970 struct lo_info
*i
= (struct lo_info
*) cl
;
972 if (!TEST_FLAG (TheFlag
, pv
) && PinLineIntersect (pv
, &i
->line
))
974 if (TEST_FLAG (HOLEFLAG
, pv
))
976 SET_FLAG (WARNFLAG
, pv
);
977 Settings
.RatWarn
= true;
978 Message (_("WARNING: Hole too close to line.\n"));
980 else if (ADD_PV_TO_LIST (pv
))
987 pv_pad_callback (const BoxType
* b
, void *cl
)
989 PinType
*pv
= (PinType
*) b
;
990 struct lo_info
*i
= (struct lo_info
*) cl
;
992 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_PAD (pv
, &i
->pad
))
994 if (TEST_FLAG (HOLEFLAG
, pv
))
996 SET_FLAG (WARNFLAG
, pv
);
997 Settings
.RatWarn
= true;
998 Message (_("WARNING: Hole too close to pad.\n"));
1000 else if (ADD_PV_TO_LIST (pv
))
1001 longjmp (i
->env
, 1);
1007 pv_arc_callback (const BoxType
* b
, void *cl
)
1009 PinType
*pv
= (PinType
*) b
;
1010 struct lo_info
*i
= (struct lo_info
*) cl
;
1012 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_ARC (pv
, &i
->arc
))
1014 if (TEST_FLAG (HOLEFLAG
, pv
))
1016 SET_FLAG (WARNFLAG
, pv
);
1017 Settings
.RatWarn
= true;
1018 Message (_("WARNING: Hole touches arc.\n"));
1020 else if (ADD_PV_TO_LIST (pv
))
1021 longjmp (i
->env
, 1);
1027 pv_poly_callback (const BoxType
* b
, void *cl
)
1029 PinType
*pv
= (PinType
*) b
;
1030 struct lo_info
*i
= (struct lo_info
*) cl
;
1032 /* note that holes in polygons are ok, so they don't generate warnings. */
1033 if (!TEST_FLAG (TheFlag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1034 (TEST_THERM (i
->layer
, pv
) ||
1035 !TEST_FLAG (CLEARPOLYFLAG
, &i
->polygon
) ||
1038 if (TEST_FLAG (SQUAREFLAG
, pv
))
1040 Coord x1
, x2
, y1
, y2
;
1041 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1042 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1043 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1044 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1045 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, &i
->polygon
)
1046 && ADD_PV_TO_LIST (pv
))
1047 longjmp (i
->env
, 1);
1049 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1051 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1052 if (isects (oct
, &i
->polygon
, true) && ADD_PV_TO_LIST (pv
))
1053 longjmp (i
->env
, 1);
1057 if (IsPointInPolygon
1058 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, &i
->polygon
)
1059 && ADD_PV_TO_LIST (pv
))
1060 longjmp (i
->env
, 1);
1067 pv_rat_callback (const BoxType
* b
, void *cl
)
1069 PinType
*pv
= (PinType
*) b
;
1070 struct lo_info
*i
= (struct lo_info
*) cl
;
1072 /* rats can't cause DRC so there is no early exit */
1073 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_RAT (pv
, &i
->rat
))
1074 ADD_PV_TO_LIST (pv
);
1078 /* ---------------------------------------------------------------------------
1079 * searches for new PVs that are connected to NEW LOs on the list
1080 * This routine updates the position counter of the lists too.
1083 LookupPVConnectionsToLOList (bool AndRats
)
1086 struct lo_info info
;
1088 /* loop over all layers */
1089 for (layer
= 0; layer
< max_copper_layer
; layer
++)
1091 if (LAYER_PTR (layer
)->no_drc
)
1093 /* do nothing if there are no PV's */
1094 if (TotalP
+ TotalV
== 0)
1096 LineList
[layer
].Location
= LineList
[layer
].Number
;
1097 ArcList
[layer
].Location
= ArcList
[layer
].Number
;
1098 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
;
1102 /* check all lines */
1103 while (LineList
[layer
].Location
< LineList
[layer
].Number
)
1105 info
.line
= *(LINELIST_ENTRY (layer
, LineList
[layer
].Location
));
1106 EXPAND_BOUNDS (&info
.line
);
1107 if (setjmp (info
.env
) == 0)
1108 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1109 pv_line_callback
, &info
);
1112 if (setjmp (info
.env
) == 0)
1113 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1114 pv_line_callback
, &info
);
1117 LineList
[layer
].Location
++;
1120 /* check all arcs */
1121 while (ArcList
[layer
].Location
< ArcList
[layer
].Number
)
1123 info
.arc
= *(ARCLIST_ENTRY (layer
, ArcList
[layer
].Location
));
1124 EXPAND_BOUNDS (&info
.arc
);
1125 if (setjmp (info
.env
) == 0)
1126 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.arc
, NULL
,
1127 pv_arc_callback
, &info
);
1130 if (setjmp (info
.env
) == 0)
1131 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.arc
, NULL
,
1132 pv_arc_callback
, &info
);
1135 ArcList
[layer
].Location
++;
1138 /* now all polygons */
1140 while (PolygonList
[layer
].Location
< PolygonList
[layer
].Number
)
1143 *(POLYGONLIST_ENTRY (layer
, PolygonList
[layer
].Location
));
1144 EXPAND_BOUNDS (&info
.polygon
);
1145 if (setjmp (info
.env
) == 0)
1146 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.polygon
, NULL
,
1147 pv_poly_callback
, &info
);
1150 if (setjmp (info
.env
) == 0)
1151 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.polygon
, NULL
,
1152 pv_poly_callback
, &info
);
1155 PolygonList
[layer
].Location
++;
1159 /* loop over all pad-layers */
1160 for (layer
= 0; layer
< 2; layer
++)
1162 /* do nothing if there are no PV's */
1163 if (TotalP
+ TotalV
== 0)
1165 PadList
[layer
].Location
= PadList
[layer
].Number
;
1169 /* check all pads; for a detailed description see
1170 * the handling of lines in this subroutine
1172 while (PadList
[layer
].Location
< PadList
[layer
].Number
)
1174 info
.pad
= *(PADLIST_ENTRY (layer
, PadList
[layer
].Location
));
1175 EXPAND_BOUNDS (&info
.pad
);
1176 if (setjmp (info
.env
) == 0)
1177 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pad
, NULL
,
1178 pv_pad_callback
, &info
);
1181 if (setjmp (info
.env
) == 0)
1182 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pad
, NULL
,
1183 pv_pad_callback
, &info
);
1186 PadList
[layer
].Location
++;
1190 /* do nothing if there are no PV's */
1191 if (TotalP
+ TotalV
== 0)
1192 RatList
.Location
= RatList
.Number
;
1194 /* check all rat-lines */
1197 while (RatList
.Location
< RatList
.Number
)
1199 info
.rat
= *(RATLIST_ENTRY (RatList
.Location
));
1200 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point1
, 1, NULL
,
1201 pv_rat_callback
, &info
);
1202 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point2
, 1, NULL
,
1203 pv_rat_callback
, &info
);
1204 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point1
, 1, NULL
,
1205 pv_rat_callback
, &info
);
1206 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point2
, 1, NULL
,
1207 pv_rat_callback
, &info
);
1215 /* reduce arc start angle and delta to 0..360 */
1217 normalize_angles (Angle
*sa
, Angle
*d
)
1224 if (*d
> 360) /* full circle */
1226 *sa
= NormalizeAngle (*sa
);
1230 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1232 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1233 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1235 normalize_angles (&sa
, &d
);
1239 return (sa
+ d
) >= alpha
;
1240 return (sa
+ d
- 360) >= alpha
;
1244 get_arc_ends (Coord
*box
, ArcType
*arc
)
1246 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1247 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1248 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1249 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1251 /* ---------------------------------------------------------------------------
1252 * check if two arcs intersect
1253 * first we check for circle intersections,
1254 * then find the actual points of intersection
1255 * and test them to see if they are on arcs
1257 * consider a, the distance from the center of arc 1
1258 * to the point perpendicular to the intersecting points.
1260 * a = (r1^2 - r2^2 + l^2)/(2l)
1262 * the perpendicular distance to the point of intersection
1265 * d = sqrt(r1^2 - a^2)
1267 * the points of intersection would then be
1269 * x = X1 + a/l dx +- d/l dy
1270 * y = Y1 + a/l dy -+ d/l dx
1272 * where dx = X2 - X1 and dy = Y2 - Y1
1277 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1279 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1283 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1284 t2
= 0.5 * Arc2
->Thickness
;
1288 if (t
< 0 || t1
< 0)
1291 /* try the end points first */
1292 get_arc_ends (&box
[0], Arc1
);
1293 get_arc_ends (&box
[4], Arc2
);
1294 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1295 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1296 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1297 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1300 pdx
= Arc2
->X
- Arc1
->X
;
1301 pdy
= Arc2
->Y
- Arc1
->Y
;
1302 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1303 /* concentric arcs, simpler intersection conditions */
1306 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1307 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1308 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1309 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1311 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1312 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1313 /* NB the endpoints have already been checked,
1314 so we just compare the angles */
1316 normalize_angles (&sa1
, &d1
);
1317 normalize_angles (&sa2
, &d2
);
1318 /* sa1 == sa2 was caught when checking endpoints */
1320 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1323 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1330 /* arcs centerlines are too far or too near */
1331 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1333 /* check the nearest to the other arc's center point */
1336 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1342 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1343 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1346 dx
= - pdx
* r2
/ dl
;
1347 dy
= - pdy
* r2
/ dl
;
1348 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1354 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1355 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1363 a
= 0.5 * (r1
- r2
+ l
) / l
;
1366 /* the circles are too far apart to touch or probably just touch:
1367 check the nearest point */
1372 x
= Arc1
->X
+ a
* pdx
;
1373 y
= Arc1
->Y
+ a
* pdy
;
1376 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1377 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1379 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1380 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1383 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1384 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1386 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1387 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1392 /* ---------------------------------------------------------------------------
1393 * Tests if point is same as line end point
1396 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1398 if ((Point
->X
== Line
->Point1
.X
1399 && Point
->Y
== Line
->Point1
.Y
)
1400 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1406 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1407 /* writes vertices of a squared line */
1409 double dwx
= 0, dwy
= 0;
1410 if (l
->Point1
.Y
== l
->Point2
.Y
)
1411 dwx
= l
->Thickness
/ 2.0;
1412 else if (l
->Point1
.X
== l
->Point2
.X
)
1413 dwy
= l
->Thickness
/ 2.0;
1416 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1417 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1418 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1419 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1420 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1422 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1423 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1424 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1425 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1427 /* ---------------------------------------------------------------------------
1428 * checks if two lines intersect
1431 * Let A,B,C,D be 2-space position vectors. Then the directed line
1432 * segments AB & CD are given by:
1434 * AB=A+r(B-A), r in [0,1]
1435 * CD=C+s(D-C), s in [0,1]
1437 * If AB & CD intersect, then
1439 * A+r(B-A)=C+s(D-C), or
1441 * XA+r(XB-XA)=XC+s(XD-XC)
1442 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1444 * Solving the above for r and s yields
1446 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1447 * r = ----------------------------- (eqn 1)
1448 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1450 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1451 * s = ----------------------------- (eqn 2)
1452 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1454 * Let I be the position vector of the intersection point, then
1461 * By examining the values of r & s, you can also determine some
1462 * other limiting conditions:
1464 * If 0<=r<=1 & 0<=s<=1, intersection exists
1465 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1467 * If the denominator in eqn 1 is zero, AB & CD are parallel
1468 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1470 * If the intersection point of the 2 lines are needed (lines in this
1471 * context mean infinite lines) regardless whether the two line
1472 * segments intersect, then
1474 * If r>1, I is located on extension of AB
1475 * If r<0, I is located on extension of BA
1476 * If s>1, I is located on extension of CD
1477 * If s<0, I is located on extension of DC
1479 * Also note that the denominators of eqn 1 & 2 are identical.
1483 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1486 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1487 point1_dx
, point1_dy
;
1488 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1491 form_slanted_rectangle (p
, Line1
);
1492 return IsLineInQuadrangle (p
, Line2
);
1494 /* here come only round Line1 because IsLineInQuadrangle()
1495 calls LineLineIntersect() with first argument rounded*/
1496 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1499 form_slanted_rectangle (p
, Line2
);
1500 return IsLineInQuadrangle (p
, Line1
);
1502 /* now all lines are round */
1504 /* Check endpoints: this provides a quick exit, catches
1505 * cases where the "real" lines don't intersect but the
1506 * thick lines touch, and ensures that the dx/dy business
1507 * below does not cause a divide-by-zero. */
1508 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1509 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1511 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1512 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1514 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1515 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1517 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1518 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1522 /* setup some constants */
1523 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1524 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1525 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1526 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1527 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1528 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1530 /* If either line is a point, we have failed already, since the
1531 * endpoint check above will have caught an "intersection". */
1532 if ((line1_dx
== 0 && line1_dy
== 0)
1533 || (line2_dx
== 0 && line2_dy
== 0))
1536 /* set s to cross product of Line1 and the line
1537 * Line1.Point1--Line2.Point1 (as vectors) */
1538 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1540 /* set r to cross product of both lines (as vectors) */
1541 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1543 /* No cross product means parallel lines, or maybe Line2 is
1544 * zero-length. In either case, since we did a bounding-box
1545 * check before getting here, the above IsPointInPad() checks
1546 * will have caught any intersections. */
1551 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1553 /* intersection is at least on AB */
1554 if (r
>= 0.0 && r
<= 1.0)
1555 return (s
>= 0.0 && s
<= 1.0);
1557 /* intersection is at least on CD */
1558 /* [removed this case since it always returns false --asp] */
1562 /*---------------------------------------------------
1564 * Check for line intersection with an arc
1566 * Mostly this is like the circle/line intersection
1567 * found in IsPointOnLine (search.c) see the detailed
1568 * discussion for the basics there.
1570 * Since this is only an arc, not a full circle we need
1571 * to find the actual points of intersection with the
1572 * circle, and see if they are on the arc.
1574 * To do this, we translate along the line from the point Q
1575 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1576 * but it's handy to normalize with respect to l, the line
1577 * length so a single projection is done (e.g. we don't first
1580 * The projection is now of the form
1582 * Px = X1 + (r +- r2)(X2 - X1)
1583 * Py = Y1 + (r +- r2)(Y2 - Y1)
1585 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1586 * note that this is the variable d, not the symbol d described in IsPointOnLine
1587 * (variable d = symbol d * l)
1589 * The end points are hell so they are checked individually
1592 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1594 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1597 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1598 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1599 dx1
= Line
->Point1
.X
- Arc
->X
;
1600 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1601 l
= dx
* dx
+ dy
* dy
;
1602 d
= dx
* dy1
- dy
* dx1
;
1605 /* use the larger diameter circle first */
1607 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1609 r2
= Radius
* l
- d
;
1610 /* projection doesn't even intersect circle when r2 < 0 */
1613 /* check the ends of the line in case the projected point */
1614 /* of intersection is beyond the line end */
1616 (Line
->Point1
.X
, Line
->Point1
.Y
,
1617 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1620 (Line
->Point2
.X
, Line
->Point2
.Y
,
1621 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1626 Radius
= -(dx
* dx1
+ dy
* dy1
);
1627 r
= (Radius
+ r2
) / l
;
1628 if (r
>= 0 && r
<= 1
1629 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1630 Line
->Point1
.Y
+ r
* dy
,
1631 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1633 r
= (Radius
- r2
) / l
;
1634 if (r
>= 0 && r
<= 1
1635 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1636 Line
->Point1
.Y
+ r
* dy
,
1637 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1639 /* check arc end points */
1640 box
= GetArcEnds (Arc
);
1641 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1643 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1649 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1651 LineType
*line
= (LineType
*) b
;
1652 struct lo_info
*i
= (struct lo_info
*) cl
;
1654 if (!TEST_FLAG (TheFlag
, line
) && LineArcIntersect (line
, &i
->arc
))
1656 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1657 longjmp (i
->env
, 1);
1663 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1665 ArcType
*arc
= (ArcType
*) b
;
1666 struct lo_info
*i
= (struct lo_info
*) cl
;
1668 if (!arc
->Thickness
)
1670 if (!TEST_FLAG (TheFlag
, arc
) && ArcArcIntersect (&i
->arc
, arc
))
1672 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1673 longjmp (i
->env
, 1);
1679 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1681 PadType
*pad
= (PadType
*) b
;
1682 struct lo_info
*i
= (struct lo_info
*) cl
;
1684 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1685 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1686 && ArcPadIntersect (&i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1687 longjmp (i
->env
, 1);
1691 /* ---------------------------------------------------------------------------
1692 * searches all LOs that are connected to the given arc on the given
1693 * layergroup. All found connections are added to the list
1695 * the notation that is used is:
1696 * Xij means Xj at arc i
1699 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
)
1702 struct lo_info info
;
1705 EXPAND_BOUNDS (&info
.arc
);
1706 /* loop over all layers of the group */
1707 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1712 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1714 /* handle normal layers */
1715 if (layer
< max_copper_layer
)
1719 if (setjmp (info
.env
) == 0)
1720 r_search (LAYER_PTR (layer
)->line_tree
, &info
.arc
.BoundingBox
,
1721 NULL
, LOCtoArcLine_callback
, &info
);
1725 if (setjmp (info
.env
) == 0)
1726 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.arc
.BoundingBox
,
1727 NULL
, LOCtoArcArc_callback
, &info
);
1731 /* now check all polygons */
1732 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1733 i
!= NULL
; i
= g_list_next (i
))
1735 PolygonType
*polygon
= i
->data
;
1736 if (!TEST_FLAG (TheFlag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1737 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1743 info
.layer
= layer
- max_copper_layer
;
1744 if (setjmp (info
.env
) == 0)
1745 r_search (PCB
->Data
->pad_tree
, &info
.arc
.BoundingBox
, NULL
,
1746 LOCtoArcPad_callback
, &info
);
1755 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1757 LineType
*line
= (LineType
*) b
;
1758 struct lo_info
*i
= (struct lo_info
*) cl
;
1760 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1762 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1763 longjmp (i
->env
, 1);
1769 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1771 ArcType
*arc
= (ArcType
*) b
;
1772 struct lo_info
*i
= (struct lo_info
*) cl
;
1774 if (!arc
->Thickness
)
1776 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
1778 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1779 longjmp (i
->env
, 1);
1785 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1787 RatType
*rat
= (RatType
*) b
;
1788 struct lo_info
*i
= (struct lo_info
*) cl
;
1790 if (!TEST_FLAG (TheFlag
, rat
))
1792 if ((rat
->group1
== i
->layer
)
1793 && IsRatPointOnLineEnd (&rat
->Point1
, &i
->line
))
1795 if (ADD_RAT_TO_LIST (rat
))
1796 longjmp (i
->env
, 1);
1798 else if ((rat
->group2
== i
->layer
)
1799 && IsRatPointOnLineEnd (&rat
->Point2
, &i
->line
))
1801 if (ADD_RAT_TO_LIST (rat
))
1802 longjmp (i
->env
, 1);
1809 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1811 PadType
*pad
= (PadType
*) b
;
1812 struct lo_info
*i
= (struct lo_info
*) cl
;
1814 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1815 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1816 && LinePadIntersect (&i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1817 longjmp (i
->env
, 1);
1821 /* ---------------------------------------------------------------------------
1822 * searches all LOs that are connected to the given line on the given
1823 * layergroup. All found connections are added to the list
1825 * the notation that is used is:
1826 * Xij means Xj at line i
1829 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1833 struct lo_info info
;
1836 info
.layer
= LayerGroup
;
1837 EXPAND_BOUNDS (&info
.line
)
1838 /* add the new rat lines */
1839 if (setjmp (info
.env
) == 0)
1840 r_search (PCB
->Data
->rat_tree
, &info
.line
.BoundingBox
, NULL
,
1841 LOCtoLineRat_callback
, &info
);
1845 /* loop over all layers of the group */
1846 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1850 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1852 /* handle normal layers */
1853 if (layer
< max_copper_layer
)
1857 if (setjmp (info
.env
) == 0)
1858 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
1859 NULL
, LOCtoLineLine_callback
, &info
);
1863 if (setjmp (info
.env
) == 0)
1864 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
1865 NULL
, LOCtoLineArc_callback
, &info
);
1868 /* now check all polygons */
1872 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1873 i
!= NULL
; i
= g_list_next (i
))
1875 PolygonType
*polygon
= i
->data
;
1877 (TheFlag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1878 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1885 /* handle special 'pad' layers */
1886 info
.layer
= layer
- max_copper_layer
;
1887 if (setjmp (info
.env
) == 0)
1888 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
1889 LOCtoLinePad_callback
, &info
);
1905 LOCtoRat_callback (const BoxType
* b
, void *cl
)
1907 LineType
*line
= (LineType
*) b
;
1908 struct rat_info
*i
= (struct rat_info
*) cl
;
1910 if (!TEST_FLAG (TheFlag
, line
) &&
1911 ((line
->Point1
.X
== i
->Point
->X
&&
1912 line
->Point1
.Y
== i
->Point
->Y
) ||
1913 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
1915 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1916 longjmp (i
->env
, 1);
1921 PolygonToRat_callback (const BoxType
* b
, void *cl
)
1923 PolygonType
*polygon
= (PolygonType
*) b
;
1924 struct rat_info
*i
= (struct rat_info
*) cl
;
1926 if (!TEST_FLAG (TheFlag
, polygon
) && polygon
->Clipped
&&
1927 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
1928 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
1930 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
1931 longjmp (i
->env
, 1);
1937 LOCtoPad_callback (const BoxType
* b
, void *cl
)
1939 PadType
*pad
= (PadType
*) b
;
1940 struct rat_info
*i
= (struct rat_info
*) cl
;
1942 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1943 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
1944 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
1945 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
1946 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
1947 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
1948 ADD_PAD_TO_LIST (i
->layer
, pad
))
1949 longjmp (i
->env
, 1);
1953 /* ---------------------------------------------------------------------------
1954 * searches all LOs that are connected to the given rat-line on the given
1955 * layergroup. All found connections are added to the list
1957 * the notation that is used is:
1958 * Xij means Xj at line i
1961 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
)
1964 struct rat_info info
;
1967 /* loop over all layers of this group */
1968 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1972 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1973 /* handle normal layers
1974 rats don't ever touch
1978 if (layer
< max_copper_layer
)
1981 if (setjmp (info
.env
) == 0)
1982 r_search_pt (LAYER_PTR (layer
)->line_tree
, Point
, 1, NULL
,
1983 LOCtoRat_callback
, &info
);
1986 if (setjmp (info
.env
) == 0)
1987 r_search_pt (LAYER_PTR (layer
)->polygon_tree
, Point
, 1,
1988 NULL
, PolygonToRat_callback
, &info
);
1992 /* handle special 'pad' layers */
1993 info
.layer
= layer
- max_copper_layer
;
1994 if (setjmp (info
.env
) == 0)
1995 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
1996 LOCtoPad_callback
, &info
);
2005 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2007 LineType
*line
= (LineType
*) b
;
2008 struct lo_info
*i
= (struct lo_info
*) cl
;
2010 if (!TEST_FLAG (TheFlag
, line
) && LinePadIntersect (line
, &i
->pad
))
2012 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2013 longjmp (i
->env
, 1);
2019 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2021 ArcType
*arc
= (ArcType
*) b
;
2022 struct lo_info
*i
= (struct lo_info
*) cl
;
2024 if (!arc
->Thickness
)
2026 if (!TEST_FLAG (TheFlag
, arc
) && ArcPadIntersect (arc
, &i
->pad
))
2028 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2029 longjmp (i
->env
, 1);
2035 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2037 PolygonType
*polygon
= (PolygonType
*) b
;
2038 struct lo_info
*i
= (struct lo_info
*) cl
;
2041 if (!TEST_FLAG (TheFlag
, polygon
) &&
2042 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
.Clearance
))
2044 if (IsPadInPolygon (&i
->pad
, polygon
) &&
2045 ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2046 longjmp (i
->env
, 1);
2052 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2054 RatType
*rat
= (RatType
*) b
;
2055 struct lo_info
*i
= (struct lo_info
*) cl
;
2057 if (!TEST_FLAG (TheFlag
, rat
))
2059 if (rat
->group1
== i
->layer
&&
2060 ((rat
->Point1
.X
== i
->pad
.Point1
.X
&& rat
->Point1
.Y
== i
->pad
.Point1
.Y
) ||
2061 (rat
->Point1
.X
== i
->pad
.Point2
.X
&& rat
->Point1
.Y
== i
->pad
.Point2
.Y
) ||
2062 (rat
->Point1
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2063 rat
->Point1
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2065 if (ADD_RAT_TO_LIST (rat
))
2066 longjmp (i
->env
, 1);
2068 else if (rat
->group2
== i
->layer
&&
2069 ((rat
->Point2
.X
== i
->pad
.Point1
.X
&& rat
->Point2
.Y
== i
->pad
.Point1
.Y
) ||
2070 (rat
->Point2
.X
== i
->pad
.Point2
.X
&& rat
->Point2
.Y
== i
->pad
.Point2
.Y
) ||
2071 (rat
->Point2
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2072 rat
->Point2
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2074 if (ADD_RAT_TO_LIST (rat
))
2075 longjmp (i
->env
, 1);
2082 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2084 PadType
*pad
= (PadType
*) b
;
2085 struct lo_info
*i
= (struct lo_info
*) cl
;
2087 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2088 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2089 && PadPadIntersect (pad
, &i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2090 longjmp (i
->env
, 1);
2094 /* ---------------------------------------------------------------------------
2095 * searches all LOs that are connected to the given pad on the given
2096 * layergroup. All found connections are added to the list
2099 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
)
2102 struct lo_info info
;
2104 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2105 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, false));
2108 EXPAND_BOUNDS (&info
.pad
);
2109 /* add the new rat lines */
2110 info
.layer
= LayerGroup
;
2111 if (setjmp (info
.env
) == 0)
2112 r_search (PCB
->Data
->rat_tree
, &info
.pad
.BoundingBox
, NULL
,
2113 LOCtoPadRat_callback
, &info
);
2117 /* loop over all layers of the group */
2118 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2122 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2123 /* handle normal layers */
2124 if (layer
< max_copper_layer
)
2128 if (setjmp (info
.env
) == 0)
2129 r_search (LAYER_PTR (layer
)->line_tree
, &info
.pad
.BoundingBox
,
2130 NULL
, LOCtoPadLine_callback
, &info
);
2134 if (setjmp (info
.env
) == 0)
2135 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.pad
.BoundingBox
,
2136 NULL
, LOCtoPadArc_callback
, &info
);
2140 if (setjmp (info
.env
) == 0)
2141 r_search (LAYER_PTR (layer
)->polygon_tree
, &info
.pad
.BoundingBox
,
2142 NULL
, LOCtoPadPoly_callback
, &info
);
2148 /* handle special 'pad' layers */
2149 info
.layer
= layer
- max_copper_layer
;
2150 if (setjmp (info
.env
) == 0)
2151 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pad
, NULL
,
2152 LOCtoPadPad_callback
, &info
);
2162 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2164 LineType
*line
= (LineType
*) b
;
2165 struct lo_info
*i
= (struct lo_info
*) cl
;
2167 if (!TEST_FLAG (TheFlag
, line
) && IsLineInPolygon (line
, &i
->polygon
))
2169 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2170 longjmp (i
->env
, 1);
2176 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2178 ArcType
*arc
= (ArcType
*) b
;
2179 struct lo_info
*i
= (struct lo_info
*) cl
;
2181 if (!arc
->Thickness
)
2183 if (!TEST_FLAG (TheFlag
, arc
) && IsArcInPolygon (arc
, &i
->polygon
))
2185 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2186 longjmp (i
->env
, 1);
2192 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2194 PadType
*pad
= (PadType
*) b
;
2195 struct lo_info
*i
= (struct lo_info
*) cl
;
2197 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2198 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2199 && IsPadInPolygon (pad
, &i
->polygon
))
2201 if (ADD_PAD_TO_LIST (i
->layer
, pad
))
2202 longjmp (i
->env
, 1);
2208 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2210 RatType
*rat
= (RatType
*) b
;
2211 struct lo_info
*i
= (struct lo_info
*) cl
;
2213 if (!TEST_FLAG (TheFlag
, rat
))
2215 if ((rat
->Point1
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2216 rat
->Point1
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2217 rat
->group1
== i
->layer
) ||
2218 (rat
->Point2
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2219 rat
->Point2
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2220 rat
->group2
== i
->layer
))
2221 if (ADD_RAT_TO_LIST (rat
))
2222 longjmp (i
->env
, 1);
2228 /* ---------------------------------------------------------------------------
2229 * looks up LOs that are connected to the given polygon
2230 * on the given layergroup. All found connections are added to the list
2233 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
)
2236 struct lo_info info
;
2238 if (!Polygon
->Clipped
)
2240 info
.polygon
= *Polygon
;
2241 EXPAND_BOUNDS (&info
.polygon
);
2242 info
.layer
= LayerGroup
;
2244 if (setjmp (info
.env
) == 0)
2245 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.polygon
, NULL
,
2246 LOCtoPolyRat_callback
, &info
);
2249 /* loop over all layers of the group */
2250 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2254 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2256 /* handle normal layers */
2257 if (layer
< max_copper_layer
)
2261 /* check all polygons */
2262 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
2263 i
!= NULL
; i
= g_list_next (i
))
2265 PolygonType
*polygon
= i
->data
;
2266 if (!TEST_FLAG (TheFlag
, polygon
)
2267 && IsPolygonInPolygon (polygon
, Polygon
)
2268 && ADD_POLYGON_TO_LIST (layer
, polygon
))
2273 /* check all lines */
2274 if (setjmp (info
.env
) == 0)
2275 r_search (LAYER_PTR (layer
)->line_tree
,
2276 (BoxType
*) & info
.polygon
, NULL
,
2277 LOCtoPolyLine_callback
, &info
);
2280 /* check all arcs */
2281 if (setjmp (info
.env
) == 0)
2282 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.polygon
,
2283 NULL
, LOCtoPolyArc_callback
, &info
);
2289 info
.layer
= layer
- max_copper_layer
;
2290 if (setjmp (info
.env
) == 0)
2291 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.polygon
,
2292 NULL
, LOCtoPolyPad_callback
, &info
);
2300 /* ---------------------------------------------------------------------------
2301 * checks if an arc has a connection to a polygon
2303 * - first check if the arc can intersect with the polygon by
2304 * evaluating the bounding boxes
2305 * - check the two end points of the arc. If none of them matches
2306 * - check all segments of the polygon against the arc.
2309 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2311 BoxType
*Box
= (BoxType
*) Arc
;
2313 /* arcs with clearance never touch polys */
2314 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2316 if (!Polygon
->Clipped
)
2318 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2319 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2320 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2321 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2325 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2326 return false; /* error */
2327 return isects (ap
, Polygon
, true);
2332 /* ---------------------------------------------------------------------------
2333 * checks if a line has a connection to a polygon
2335 * - first check if the line can intersect with the polygon by
2336 * evaluating the bounding boxes
2337 * - check the two end points of the line. If none of them matches
2338 * - check all segments of the polygon against the line.
2341 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2343 BoxType
*Box
= (BoxType
*) Line
;
2346 /* lines with clearance never touch polygons */
2347 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2349 if (!Polygon
->Clipped
)
2351 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2353 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2354 Coord x1
, x2
, y1
, y2
;
2356 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2357 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2358 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2359 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2360 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2362 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2363 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2364 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2365 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2367 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2368 return FALSE
; /* error */
2369 return isects (lp
, Polygon
, true);
2374 /* ---------------------------------------------------------------------------
2375 * checks if a pad connects to a non-clearing polygon
2377 * The polygon is assumed to already have been proven non-clearing
2380 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2382 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2385 /* ---------------------------------------------------------------------------
2386 * checks if a polygon has a connection to a second one
2388 * First check all points out of P1 against P2 and vice versa.
2389 * If both fail check all lines of P1 against the ones of P2
2392 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2394 if (!P1
->Clipped
|| !P2
->Clipped
)
2396 assert (P1
->Clipped
->contours
);
2397 assert (P2
->Clipped
->contours
);
2399 /* first check if both bounding boxes intersect. If not, return quickly */
2400 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2401 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2402 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2403 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2406 /* first check un-bloated case */
2407 if (isects (P1
->Clipped
, P2
, false))
2410 /* now the difficult case of bloated */
2414 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2417 VNODE
*v
= &c
->head
;
2418 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2419 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2420 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2421 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2424 line
.Point1
.X
= v
->point
[0];
2425 line
.Point1
.Y
= v
->point
[1];
2426 line
.Thickness
= 2 * Bloat
;
2428 line
.Flags
= NoFlags ();
2429 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2431 line
.Point2
.X
= v
->point
[0];
2432 line
.Point2
.Y
= v
->point
[1];
2433 SetLineBoundingBox (&line
);
2434 if (IsLineInPolygon (&line
, P2
))
2436 line
.Point1
.X
= line
.Point2
.X
;
2437 line
.Point1
.Y
= line
.Point2
.Y
;
2446 /* ---------------------------------------------------------------------------
2447 * writes the several names of an element to a file
2450 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2452 static DynamicStringType cname
, pname
, vname
;
2454 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2455 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2456 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2457 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2460 /* ---------------------------------------------------------------------------
2461 * writes the several names of an element to a file
2464 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2466 fputs ("Element", FP
);
2467 PrintElementNameList (Element
, FP
);
2471 /* ---------------------------------------------------------------------------
2472 * prints one {pin,pad,via}/element entry of connection lists
2475 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2476 bool FirstOne
, FILE * FP
)
2478 static DynamicStringType oname
;
2480 CreateQuotedString (&oname
, ObjName
);
2482 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2485 fprintf (FP
, "\t\t%s ", oname
.Data
);
2487 PrintElementNameList (Element
, FP
);
2489 fputs ("(__VIA__)\n", FP
);
2493 /* ---------------------------------------------------------------------------
2494 * prints all found connections of a pads to file FP
2495 * the connections are stacked in 'PadList'
2498 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2503 if (!PadList
[Layer
].Number
)
2506 /* the starting pad */
2509 ptr
= PADLIST_ENTRY (Layer
, 0);
2511 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2513 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2516 /* we maybe have to start with i=1 if we are handling the
2517 * starting-pad itself
2519 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2521 ptr
= PADLIST_ENTRY (Layer
, i
);
2523 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2525 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2529 /* ---------------------------------------------------------------------------
2530 * prints all found connections of a pin to file FP
2531 * the connections are stacked in 'PVList'
2534 PrintPinConnections (FILE * FP
, bool IsFirst
)
2544 /* the starting pin */
2545 pv
= PVLIST_ENTRY (0);
2546 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2549 /* we maybe have to start with i=1 if we are handling the
2550 * starting-pin itself
2552 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2554 /* get the elements name or assume that its a via */
2555 pv
= PVLIST_ENTRY (i
);
2556 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2560 /* ---------------------------------------------------------------------------
2561 * checks if all lists of new objects are handled
2564 ListsEmpty (bool AndRats
)
2569 empty
= (PVList
.Location
>= PVList
.Number
);
2571 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2572 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2573 if (!LAYER_PTR (i
)->no_drc
)
2574 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2575 && ArcList
[i
].Location
>= ArcList
[i
].Number
2576 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2581 reassign_no_drc_flags (void)
2585 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2587 LayerType
*l
= LAYER_PTR (layer
);
2588 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2595 /* ---------------------------------------------------------------------------
2596 * loops till no more connections are found
2599 DoIt (bool AndRats
, bool AndDraw
)
2601 bool newone
= false;
2602 reassign_no_drc_flags ();
2605 /* lookup connections; these are the steps (2) to (4)
2606 * from the description
2608 newone
= LookupPVConnectionsToPVList () ||
2609 LookupLOConnectionsToPVList (AndRats
) ||
2610 LookupLOConnectionsToLOList (AndRats
) ||
2611 LookupPVConnectionsToLOList (AndRats
);
2613 DrawNewConnections ();
2615 while (!newone
&& !ListsEmpty (AndRats
));
2621 /* ---------------------------------------------------------------------------
2622 * prints all unused pins of an element to file FP
2625 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
)
2629 static DynamicStringType oname
;
2631 /* check all pins in element */
2635 if (!TEST_FLAG (HOLEFLAG
, pin
))
2637 /* pin might have bee checked before, add to list if not */
2638 if (!TEST_FLAG (TheFlag
, pin
) && FP
)
2641 if (ADD_PV_TO_LIST (pin
))
2644 number
= PadList
[COMPONENT_LAYER
].Number
2645 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2646 /* the pin has no connection if it's the only
2647 * list entry; don't count vias
2649 for (i
= 0; i
< PVList
.Number
; i
++)
2650 if (!PVLIST_ENTRY (i
)->Element
)
2654 /* output of element name if not already done */
2657 PrintConnectionElementName (Element
, FP
);
2661 /* write name to list and draw selected object */
2662 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2663 fprintf (FP
, "\t%s\n", oname
.Data
);
2664 SET_FLAG (SELECTEDFLAG
, pin
);
2668 /* reset found objects for the next pin */
2669 if (PrepareNextLoop (FP
))
2676 /* check all pads in element */
2679 /* lookup pad in list */
2680 /* pad might has bee checked before, add to list if not */
2681 if (!TEST_FLAG (TheFlag
, pad
) && FP
)
2684 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2685 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
2688 number
= PadList
[COMPONENT_LAYER
].Number
2689 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2690 /* the pin has no connection if it's the only
2691 * list entry; don't count vias
2693 for (i
= 0; i
< PVList
.Number
; i
++)
2694 if (!PVLIST_ENTRY (i
)->Element
)
2698 /* output of element name if not already done */
2701 PrintConnectionElementName (Element
, FP
);
2705 /* write name to list and draw selected object */
2706 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2707 fprintf (FP
, "\t%s\n", oname
.Data
);
2708 SET_FLAG (SELECTEDFLAG
, pad
);
2712 /* reset found objects for the next pin */
2713 if (PrepareNextLoop (FP
))
2719 /* print separator if element has unused pins or pads */
2722 fputs ("}\n\n", FP
);
2728 /* ---------------------------------------------------------------------------
2729 * resets some flags for looking up the next pin/pad
2732 PrepareNextLoop (FILE * FP
)
2736 /* reset found LOs for the next pin */
2737 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2739 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2740 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2741 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2744 /* reset found pads */
2745 for (layer
= 0; layer
< 2; layer
++)
2746 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2749 PVList
.Number
= PVList
.Location
= 0;
2750 RatList
.Number
= RatList
.Location
= 0;
2755 /* ---------------------------------------------------------------------------
2756 * finds all connections to the pins of the passed element.
2757 * The result is written to file FP
2758 * Returns true if operation was aborted
2761 PrintElementConnections (ElementType
*Element
, FILE * FP
, bool AndDraw
)
2763 PrintConnectionElementName (Element
, FP
);
2765 /* check all pins in element */
2768 /* pin might have been checked before, add to list if not */
2769 if (TEST_FLAG (TheFlag
, pin
))
2771 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2772 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2775 if (ADD_PV_TO_LIST (pin
))
2777 DoIt (true, AndDraw
);
2778 /* printout all found connections */
2779 PrintPinConnections (FP
, true);
2780 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
2781 PrintPadConnections (SOLDER_LAYER
, FP
, false);
2782 fputs ("\t}\n", FP
);
2783 if (PrepareNextLoop (FP
))
2788 /* check all pads in element */
2792 /* pad might have been checked before, add to list if not */
2793 if (TEST_FLAG (TheFlag
, pad
))
2795 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2796 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2799 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
2800 if (ADD_PAD_TO_LIST (layer
, pad
))
2802 DoIt (true, AndDraw
);
2803 /* print all found connections */
2804 PrintPadConnections (layer
, FP
, true);
2805 PrintPadConnections (layer
==
2806 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
2808 PrintPinConnections (FP
, false);
2809 fputs ("\t}\n", FP
);
2810 if (PrepareNextLoop (FP
))
2814 fputs ("}\n\n", FP
);
2818 /* ---------------------------------------------------------------------------
2819 * draws all new connections which have been found since the
2820 * routine was called the last time
2823 DrawNewConnections (void)
2828 /* decrement 'i' to keep layerstack order */
2829 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
2831 Cardinal layer
= LayerStack
[i
];
2833 if (PCB
->Data
->Layer
[layer
].On
)
2835 /* draw all new lines */
2836 position
= LineList
[layer
].DrawLocation
;
2837 for (; position
< LineList
[layer
].Number
; position
++)
2838 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
2839 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
2841 /* draw all new arcs */
2842 position
= ArcList
[layer
].DrawLocation
;
2843 for (; position
< ArcList
[layer
].Number
; position
++)
2844 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
2845 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
2847 /* draw all new polygons */
2848 position
= PolygonList
[layer
].DrawLocation
;
2849 for (; position
< PolygonList
[layer
].Number
; position
++)
2850 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
2851 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
2855 /* draw all new pads */
2857 for (i
= 0; i
< 2; i
++)
2859 position
= PadList
[i
].DrawLocation
;
2861 for (; position
< PadList
[i
].Number
; position
++)
2862 DrawPad (PADLIST_ENTRY (i
, position
));
2863 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
2866 /* draw all new PVs; 'PVList' holds a list of pointers to the
2867 * sorted array pointers to PV data
2869 while (PVList
.DrawLocation
< PVList
.Number
)
2871 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
2873 if (TEST_FLAG (PINFLAG
, pv
))
2878 else if (PCB
->ViaOn
)
2880 PVList
.DrawLocation
++;
2882 /* draw the new rat-lines */
2885 position
= RatList
.DrawLocation
;
2886 for (; position
< RatList
.Number
; position
++)
2887 DrawRat (RATLIST_ENTRY (position
));
2888 RatList
.DrawLocation
= RatList
.Number
;
2892 /* ---------------------------------------------------------------------------
2893 * find all connections to pins within one element
2896 LookupElementConnections (ElementType
*Element
, FILE * FP
)
2898 /* reset all currently marked connections */
2900 TheFlag
= FOUNDFLAG
;
2901 ClearFlagOnAllObjects (true, FOUNDFLAG
);
2902 InitConnectionLookup ();
2903 PrintElementConnections (Element
, FP
, true);
2904 SetChangedFlag (true);
2905 if (Settings
.RingBellWhenFinished
)
2907 FreeConnectionLookupMemory ();
2908 IncrementUndoSerialNumber ();
2913 /* ---------------------------------------------------------------------------
2914 * find all connections to pins of all element
2917 LookupConnectionsToAllElements (FILE * FP
)
2919 /* reset all currently marked connections */
2921 TheFlag
= FOUNDFLAG
;
2922 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2923 InitConnectionLookup ();
2925 ELEMENT_LOOP (PCB
->Data
);
2927 /* break if abort dialog returned true */
2928 if (PrintElementConnections (element
, FP
, false))
2931 if (Settings
.ResetAfterElement
&& n
!= 1)
2932 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2935 if (Settings
.RingBellWhenFinished
)
2937 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2938 FreeConnectionLookupMemory ();
2942 /*---------------------------------------------------------------------------
2943 * add the starting object to the list of found objects
2946 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
2954 if (ADD_PV_TO_LIST ((PinType
*) ptr2
))
2961 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
))
2968 int layer
= GetLayerNumber (PCB
->Data
,
2969 (LayerType
*) ptr1
);
2971 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
))
2978 int layer
= GetLayerNumber (PCB
->Data
,
2979 (LayerType
*) ptr1
);
2981 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
))
2988 int layer
= GetLayerNumber (PCB
->Data
,
2989 (LayerType
*) ptr1
);
2991 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
))
2998 PadType
*pad
= (PadType
*) ptr2
;
3001 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3010 /* ---------------------------------------------------------------------------
3011 * looks up all connections from the object at the given coordinates
3012 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3013 * the objects are re-drawn if AndDraw is true
3014 * also the action is marked as undoable if AndDraw is true
3017 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int which_flag
,
3020 void *ptr1
, *ptr2
, *ptr3
;
3024 /* check if there are any pins or pads at that position */
3026 reassign_no_drc_flags ();
3029 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3030 if (type
== NO_TYPE
)
3032 type
= SearchObjectByLocation (
3033 LOOKUP_MORE
& ~(AndRats
? RATLINE_TYPE
: 0),
3034 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3035 if (type
== NO_TYPE
)
3037 if (type
& SILK_TYPE
)
3039 int laynum
= GetLayerNumber (PCB
->Data
,
3040 (LayerType
*) ptr1
);
3042 /* don't mess with non-conducting objects! */
3043 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3048 name
= ConnectionName (type
, ptr1
, ptr2
);
3049 hid_actionl ("NetlistShow", name
, NULL
);
3051 TheFlag
= which_flag
;
3053 InitConnectionLookup ();
3055 /* now add the object to the appropriate list and start scanning
3056 * This is step (1) from the description
3058 ListStart (type
, ptr1
, ptr2
, ptr3
);
3059 DoIt (AndRats
, AndDraw
);
3061 IncrementUndoSerialNumber ();
3067 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3069 FreeConnectionLookupMemory ();
3072 /* ---------------------------------------------------------------------------
3073 * find connections for rats nesting
3074 * assumes InitConnectionLookup() has already been done
3077 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3078 bool undo
, int flag
, bool AndRats
)
3083 ListStart (type
, ptr1
, ptr2
, ptr3
);
3084 DoIt (AndRats
, false);
3088 /* ---------------------------------------------------------------------------
3089 * find all unused pins of all element
3092 LookupUnusedPins (FILE * FP
)
3094 /* reset all currently marked connections */
3096 TheFlag
= FOUNDFLAG
;
3097 ClearFlagOnAllObjects (true, FOUNDFLAG
);
3098 InitConnectionLookup ();
3100 ELEMENT_LOOP (PCB
->Data
);
3102 /* break if abort dialog returned true;
3103 * passing NULL as filedescriptor discards the normal output
3105 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
))
3110 if (Settings
.RingBellWhenFinished
)
3112 FreeConnectionLookupMemory ();
3113 IncrementUndoSerialNumber ();
3118 /* ---------------------------------------------------------------------------
3119 * resets all used flags of pins and vias
3122 ClearFlagOnPinsViasAndPads (bool AndDraw
, int flag
)
3124 bool change
= false;
3126 VIA_LOOP (PCB
->Data
);
3128 if (TEST_FLAG (flag
, via
))
3131 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3132 CLEAR_FLAG (flag
, via
);
3139 ELEMENT_LOOP (PCB
->Data
);
3143 if (TEST_FLAG (flag
, pin
))
3146 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3147 CLEAR_FLAG (flag
, pin
);
3156 if (TEST_FLAG (flag
, pad
))
3159 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3160 CLEAR_FLAG (flag
, pad
);
3170 SetChangedFlag (true);
3174 /* ---------------------------------------------------------------------------
3175 * resets all used flags of LOs
3178 ClearFlagOnLinesAndPolygons (bool AndDraw
, int flag
)
3180 bool change
= false;
3182 RAT_LOOP (PCB
->Data
);
3184 if (TEST_FLAG (flag
, line
))
3187 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3188 CLEAR_FLAG (flag
, line
);
3195 COPPERLINE_LOOP (PCB
->Data
);
3197 if (TEST_FLAG (flag
, line
))
3200 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3201 CLEAR_FLAG (flag
, line
);
3203 DrawLine (layer
, line
);
3208 COPPERARC_LOOP (PCB
->Data
);
3210 if (TEST_FLAG (flag
, arc
))
3213 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3214 CLEAR_FLAG (flag
, arc
);
3216 DrawArc (layer
, arc
);
3221 COPPERPOLYGON_LOOP (PCB
->Data
);
3223 if (TEST_FLAG (flag
, polygon
))
3226 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3227 CLEAR_FLAG (flag
, polygon
);
3229 DrawPolygon (layer
, polygon
);
3235 SetChangedFlag (true);
3239 /* ---------------------------------------------------------------------------
3240 * resets all found connections
3243 ClearFlagOnAllObjects (bool AndDraw
, int flag
)
3245 bool change
= false;
3247 change
= ClearFlagOnPinsViasAndPads (AndDraw
, flag
) || change
;
3248 change
= ClearFlagOnLinesAndPolygons (AndDraw
, flag
) || change
;
3253 /*----------------------------------------------------------------------------
3254 * Dumps the list contents
3261 for (i
= 0; i
< 2; i
++)
3263 PadList
[i
].Number
= 0;
3264 PadList
[i
].Location
= 0;
3265 PadList
[i
].DrawLocation
= 0;
3269 PVList
.Location
= 0;
3271 for (i
= 0; i
< max_copper_layer
; i
++)
3273 LineList
[i
].Location
= 0;
3274 LineList
[i
].DrawLocation
= 0;
3275 LineList
[i
].Number
= 0;
3276 ArcList
[i
].Location
= 0;
3277 ArcList
[i
].DrawLocation
= 0;
3278 ArcList
[i
].Number
= 0;
3279 PolygonList
[i
].Location
= 0;
3280 PolygonList
[i
].DrawLocation
= 0;
3281 PolygonList
[i
].Number
= 0;
3284 RatList
.Location
= 0;
3285 RatList
.DrawLocation
= 0;
3288 /*-----------------------------------------------------------------------------
3289 * Check for DRC violations on a single net starting from the pad or pin
3290 * sees if the connectivity changes when everything is bloated, or shrunk
3293 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3297 long int *object_id_list
;
3298 int *object_type_list
;
3299 DrcViolationType
*violation
;
3301 if (PCB
->Shrink
!= 0)
3303 Bloat
= -PCB
->Shrink
;
3304 TheFlag
= DRCFLAG
| SELECTEDFLAG
;
3305 ListStart (What
, ptr1
, ptr2
, ptr3
);
3307 /* ok now the shrunk net has the SELECTEDFLAG set */
3309 TheFlag
= FOUNDFLAG
;
3310 ListStart (What
, ptr1
, ptr2
, ptr3
);
3312 drc
= true; /* abort the search if we find anything not already found */
3313 if (DoIt (true, false))
3316 /* make the flag changes undoable */
3317 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3318 ClearFlagOnAllObjects (false, TheFlag
);
3321 Bloat
= -PCB
->Shrink
;
3322 TheFlag
= SELECTEDFLAG
;
3323 ListStart (What
, ptr1
, ptr2
, ptr3
);
3326 ListStart (What
, ptr1
, ptr2
, ptr3
);
3327 TheFlag
= FOUNDFLAG
;
3335 LocateError (&x
, &y
);
3336 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3337 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3338 _("Insufficient overlap between objects can lead to broken tracks\n"
3339 "due to registration errors with old wheel style photo-plotters."),
3341 0, /* ANGLE OF ERROR UNKNOWN */
3342 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3343 0, /* MAGNITUDE OF ERROR UNKNOWN */
3348 append_drc_violation (violation
);
3349 pcb_drc_violation_free (violation
);
3350 free (object_id_list
);
3351 free (object_type_list
);
3353 if (!throw_drc_dialog())
3355 IncrementUndoSerialNumber ();
3360 /* now check the bloated condition */
3362 ClearFlagOnAllObjects (false, TheFlag
);
3363 TheFlag
= FOUNDFLAG
;
3364 ListStart (What
, ptr1
, ptr2
, ptr3
);
3367 while (DoIt (true, false))
3370 /* make the flag changes undoable */
3371 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3372 ClearFlagOnAllObjects (false, TheFlag
);
3376 TheFlag
= SELECTEDFLAG
;
3377 ListStart (What
, ptr1
, ptr2
, ptr3
);
3380 TheFlag
= FOUNDFLAG
;
3381 ListStart (What
, ptr1
, ptr2
, ptr3
);
3387 LocateError (&x
, &y
);
3388 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3389 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3390 _("Circuits that are too close may bridge during imaging, etching,\n"
3391 "plating, or soldering processes resulting in a direct short."),
3393 0, /* ANGLE OF ERROR UNKNOWN */
3394 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3395 0, /* MAGNITUDE OF ERROR UNKNOWN */
3400 append_drc_violation (violation
);
3401 pcb_drc_violation_free (violation
);
3402 free (object_id_list
);
3403 free (object_type_list
);
3406 if (!throw_drc_dialog())
3408 IncrementUndoSerialNumber ();
3410 /* highlight the rest of the encroaching net so it's not reported again */
3411 TheFlag
|= SELECTEDFLAG
;
3413 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
);
3418 ListStart (What
, ptr1
, ptr2
, ptr3
);
3422 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3423 ClearFlagOnAllObjects (false, TheFlag
);
3427 /* DRC clearance callback */
3430 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3431 int type
, void *ptr1
, void *ptr2
)
3436 long int *object_id_list
;
3437 int *object_type_list
;
3438 DrcViolationType
*violation
;
3440 LineType
*line
= (LineType
*) ptr2
;
3441 ArcType
*arc
= (ArcType
*) ptr2
;
3442 PinType
*pin
= (PinType
*) ptr2
;
3443 PadType
*pad
= (PadType
*) ptr2
;
3452 if (line
->Clearance
< 2 * PCB
->Bloat
)
3454 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3455 SET_FLAG (TheFlag
, line
);
3456 message
= _("Line with insufficient clearance inside polygon\n");
3461 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3463 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3464 SET_FLAG (TheFlag
, arc
);
3465 message
= _("Arc with insufficient clearance inside polygon\n");
3470 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3471 if (IsPadInPolygon(pad
,polygon
))
3473 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3474 SET_FLAG (TheFlag
, pad
);
3475 message
= _("Pad with insufficient clearance inside polygon\n");
3480 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3482 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3483 SET_FLAG (TheFlag
, pin
);
3484 message
= _("Pin with insufficient clearance inside polygon\n");
3489 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3491 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3492 SET_FLAG (TheFlag
, pin
);
3493 message
= _("Via with insufficient clearance inside polygon\n");
3498 Message ("hace: Bad Plow object in callback\n");
3503 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3504 SET_FLAG (FOUNDFLAG
, polygon
);
3505 DrawPolygon (layer
, polygon
);
3506 DrawObject (type
, ptr1
, ptr2
);
3508 LocateError (&x
, &y
);
3509 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3510 violation
= pcb_drc_violation_new (message
,
3511 _("Circuits that are too close may bridge during imaging, etching,\n"
3512 "plating, or soldering processes resulting in a direct short."),
3514 0, /* ANGLE OF ERROR UNKNOWN */
3515 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3516 0, /* MAGNITUDE OF ERROR UNKNOWN */
3521 append_drc_violation (violation
);
3522 pcb_drc_violation_free (violation
);
3523 free (object_id_list
);
3524 free (object_type_list
);
3525 if (!throw_drc_dialog())
3530 IncrementUndoSerialNumber ();
3535 /*-----------------------------------------------------------------------------
3536 * Check for DRC violations
3537 * see if the connectivity changes when everything is bloated, or shrunk
3544 long int *object_id_list
;
3545 int *object_type_list
;
3546 DrcViolationType
*violation
;
3550 reset_drc_dialog_message();
3554 SaveStackAndVisibility ();
3555 ResetStackAndVisibility ();
3556 hid_action ("LayersChanged");
3557 InitConnectionLookup ();
3559 TheFlag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3561 if (ClearFlagOnAllObjects (true, TheFlag
))
3563 IncrementUndoSerialNumber ();
3569 ELEMENT_LOOP (PCB
->Data
);
3573 if (!TEST_FLAG (DRCFLAG
, pin
)
3574 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3586 /* count up how many pads have no solderpaste openings */
3587 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3590 if (!TEST_FLAG (DRCFLAG
, pad
)
3591 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3603 VIA_LOOP (PCB
->Data
);
3605 if (!TEST_FLAG (DRCFLAG
, via
)
3606 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3614 TheFlag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3615 ClearFlagOnAllObjects (false, TheFlag
);
3616 TheFlag
= SELECTEDFLAG
;
3617 /* check minimum widths and polygon clearances */
3620 COPPERLINE_LOOP (PCB
->Data
);
3622 /* check line clearances in polygons */
3623 PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
);
3626 if (line
->Thickness
< PCB
->minWid
)
3628 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3629 SET_FLAG (TheFlag
, line
);
3630 DrawLine (layer
, line
);
3632 SetThing (LINE_TYPE
, layer
, line
, line
);
3633 LocateError (&x
, &y
);
3634 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3635 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3636 _("Process specifications dictate a minimum feature-width\n"
3637 "that can reliably be reproduced"),
3639 0, /* ANGLE OF ERROR UNKNOWN */
3640 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3646 append_drc_violation (violation
);
3647 pcb_drc_violation_free (violation
);
3648 free (object_id_list
);
3649 free (object_type_list
);
3650 if (!throw_drc_dialog())
3655 IncrementUndoSerialNumber ();
3663 COPPERARC_LOOP (PCB
->Data
);
3665 PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
);
3668 if (arc
->Thickness
< PCB
->minWid
)
3670 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3671 SET_FLAG (TheFlag
, arc
);
3672 DrawArc (layer
, arc
);
3674 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3675 LocateError (&x
, &y
);
3676 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3677 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3678 _("Process specifications dictate a minimum feature-width\n"
3679 "that can reliably be reproduced"),
3681 0, /* ANGLE OF ERROR UNKNOWN */
3682 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3688 append_drc_violation (violation
);
3689 pcb_drc_violation_free (violation
);
3690 free (object_id_list
);
3691 free (object_type_list
);
3692 if (!throw_drc_dialog())
3697 IncrementUndoSerialNumber ();
3705 ALLPIN_LOOP (PCB
->Data
);
3707 PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
);
3710 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3711 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3713 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3714 SET_FLAG (TheFlag
, pin
);
3717 SetThing (PIN_TYPE
, element
, pin
, pin
);
3718 LocateError (&x
, &y
);
3719 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3720 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3721 _("Annular rings that are too small may erode during etching,\n"
3722 "resulting in a broken connection"),
3724 0, /* ANGLE OF ERROR UNKNOWN */
3725 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3726 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3731 append_drc_violation (violation
);
3732 pcb_drc_violation_free (violation
);
3733 free (object_id_list
);
3734 free (object_type_list
);
3735 if (!throw_drc_dialog())
3740 IncrementUndoSerialNumber ();
3743 if (pin
->DrillingHole
< PCB
->minDrill
)
3745 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3746 SET_FLAG (TheFlag
, pin
);
3749 SetThing (PIN_TYPE
, element
, pin
, pin
);
3750 LocateError (&x
, &y
);
3751 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3752 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3753 _("Process rules dictate the minimum drill size which can be used"),
3755 0, /* ANGLE OF ERROR UNKNOWN */
3756 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3762 append_drc_violation (violation
);
3763 pcb_drc_violation_free (violation
);
3764 free (object_id_list
);
3765 free (object_type_list
);
3766 if (!throw_drc_dialog())
3771 IncrementUndoSerialNumber ();
3779 ALLPAD_LOOP (PCB
->Data
);
3781 PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
);
3784 if (pad
->Thickness
< PCB
->minWid
)
3786 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3787 SET_FLAG (TheFlag
, pad
);
3790 SetThing (PAD_TYPE
, element
, pad
, pad
);
3791 LocateError (&x
, &y
);
3792 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3793 violation
= pcb_drc_violation_new (_("Pad is too thin"),
3794 _("Pads which are too thin may erode during etching,\n"
3795 "resulting in a broken or unreliable connection"),
3797 0, /* ANGLE OF ERROR UNKNOWN */
3798 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3804 append_drc_violation (violation
);
3805 pcb_drc_violation_free (violation
);
3806 free (object_id_list
);
3807 free (object_type_list
);
3808 if (!throw_drc_dialog())
3813 IncrementUndoSerialNumber ();
3821 VIA_LOOP (PCB
->Data
);
3823 PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
);
3826 if (!TEST_FLAG (HOLEFLAG
, via
) &&
3827 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
3829 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3830 SET_FLAG (TheFlag
, via
);
3833 SetThing (VIA_TYPE
, via
, via
, via
);
3834 LocateError (&x
, &y
);
3835 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3836 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
3837 _("Annular rings that are too small may erode during etching,\n"
3838 "resulting in a broken connection"),
3840 0, /* ANGLE OF ERROR UNKNOWN */
3841 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3842 (via
->Thickness
- via
->DrillingHole
) / 2,
3847 append_drc_violation (violation
);
3848 pcb_drc_violation_free (violation
);
3849 free (object_id_list
);
3850 free (object_type_list
);
3851 if (!throw_drc_dialog())
3856 IncrementUndoSerialNumber ();
3859 if (via
->DrillingHole
< PCB
->minDrill
)
3861 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3862 SET_FLAG (TheFlag
, via
);
3865 SetThing (VIA_TYPE
, via
, via
, via
);
3866 LocateError (&x
, &y
);
3867 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3868 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
3869 _("Process rules dictate the minimum drill size which can be used"),
3871 0, /* ANGLE OF ERROR UNKNOWN */
3872 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3878 append_drc_violation (violation
);
3879 pcb_drc_violation_free (violation
);
3880 free (object_id_list
);
3881 free (object_type_list
);
3882 if (!throw_drc_dialog())
3887 IncrementUndoSerialNumber ();
3894 FreeConnectionLookupMemory ();
3895 TheFlag
= FOUNDFLAG
;
3898 /* check silkscreen minimum widths outside of elements */
3899 /* XXX - need to check text and polygons too! */
3900 TheFlag
= SELECTEDFLAG
;
3903 SILKLINE_LOOP (PCB
->Data
);
3905 if (line
->Thickness
< PCB
->minSlk
)
3907 SET_FLAG (TheFlag
, line
);
3908 DrawLine (layer
, line
);
3910 SetThing (LINE_TYPE
, layer
, line
, line
);
3911 LocateError (&x
, &y
);
3912 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3913 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
3914 _("Process specifications dictate a minimum silkscreen feature-width\n"
3915 "that can reliably be reproduced"),
3917 0, /* ANGLE OF ERROR UNKNOWN */
3918 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3924 append_drc_violation (violation
);
3925 pcb_drc_violation_free (violation
);
3926 free (object_id_list
);
3927 free (object_type_list
);
3928 if (!throw_drc_dialog())
3938 /* check silkscreen minimum widths inside of elements */
3939 /* XXX - need to check text and polygons too! */
3940 TheFlag
= SELECTEDFLAG
;
3943 ELEMENT_LOOP (PCB
->Data
);
3946 ELEMENTLINE_LOOP (element
);
3948 if (line
->Thickness
< PCB
->minSlk
)
3959 SET_FLAG (TheFlag
, element
);
3960 DrawElement (element
);
3962 SetThing (ELEMENT_TYPE
, element
, element
, element
);
3963 LocateError (&x
, &y
);
3964 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3966 title
= _("Element %s has %i silk lines which are too thin");
3967 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
3969 /* -4 is for the %s and %i place-holders */
3970 /* +11 is the max printed length for a 32 bit integer */
3971 /* +1 is for the \0 termination */
3972 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
3973 buffer
= (char *)malloc (buflen
);
3974 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
3976 violation
= pcb_drc_violation_new (buffer
,
3977 _("Process specifications dictate a minimum silkscreen\n"
3978 "feature-width that can reliably be reproduced"),
3980 0, /* ANGLE OF ERROR UNKNOWN */
3981 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3982 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
3988 append_drc_violation (violation
);
3989 pcb_drc_violation_free (violation
);
3990 free (object_id_list
);
3991 free (object_type_list
);
3992 if (!throw_drc_dialog())
4005 IncrementUndoSerialNumber ();
4009 RestoreStackAndVisibility ();
4010 hid_action ("LayersChanged");
4011 gui
->invalidate_all ();
4015 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4017 nopastecnt
> 1 ? "s have" : " has");
4019 return IsBad
? -drcerr_count
: drcerr_count
;
4022 /*----------------------------------------------------------------------------
4023 * Locate the coordinatates of offending item (thing)
4026 LocateError (Coord
*x
, Coord
*y
)
4032 LineType
*line
= (LineType
*) thing_ptr3
;
4033 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4034 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4039 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4046 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4048 (polygon
->Clipped
->contours
->xmin
+
4049 polygon
->Clipped
->contours
->xmax
) / 2;
4051 (polygon
->Clipped
->contours
->ymin
+
4052 polygon
->Clipped
->contours
->ymax
) / 2;
4058 PinType
*pin
= (PinType
*) thing_ptr3
;
4065 PadType
*pad
= (PadType
*) thing_ptr3
;
4066 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4067 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4072 ElementType
*element
= (ElementType
*) thing_ptr3
;
4073 *x
= element
->MarkX
;
4074 *y
= element
->MarkY
;
4083 /*----------------------------------------------------------------------------
4084 * Build a list of the of offending items by ID. (Currently just "thing")
4087 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4090 *object_id_list
= NULL
;
4091 *object_type_list
= NULL
;
4104 *object_id_list
= (long int *)malloc (sizeof (long int));
4105 *object_type_list
= (int *)malloc (sizeof (int));
4106 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4107 **object_type_list
= thing_type
;
4112 _("Internal error in BuildObjectList: unknown object type %i\n"),
4118 /*----------------------------------------------------------------------------
4119 * center the display to show the offending item (thing)
4126 LocateError (&X
, &Y
);
4133 ChangeGroupVisibility (
4134 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4137 CenterDisplay (X
, Y
);
4141 InitConnectionLookup (void)
4143 InitComponentLookup ();
4144 InitLayoutLookup ();
4148 FreeConnectionLookupMemory (void)
4150 FreeComponentLookupMemory ();
4151 FreeLayoutLookupMemory ();