7 * PCB, interactive printed circuit board design
8 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 * Contact addresses for paper mail and Email:
25 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
26 * Thomas.Nau@rz.uni-ulm.de
33 * - lists for pins and vias, lines, arcs, pads and for polygons are created.
34 * Every object that has to be checked is added to its list.
35 * Coarse searching is accomplished with the data rtrees.
36 * - there's no 'speed-up' mechanism for polygons because they are not used
37 * as often as other objects
38 * - the maximum distance between line and pin ... would depend on the angle
39 * between them. To speed up computation the limit is set to one half
40 * of the thickness of the objects (cause of square pins).
42 * PV: means pin or via (objects that connect layers)
43 * LO: all non PV objects (layer objects like lines, arcs, polygons, pads)
45 * 1. first, the LO or PV at the given coordinates is looked up
46 * 2. all LO connections to that PV are looked up next
47 * 3. lookup of all LOs connected to LOs from (2).
48 * This step is repeated until no more new connections are found.
49 * 4. lookup all PVs connected to the LOs from (2) and (3)
50 * 5. start again with (1) for all new PVs from (4)
52 * Intersection of line <--> circle:
53 * - calculate the signed distance from the line to the center,
54 * return false if abs(distance) > R
55 * - get the distance from the line <--> distancevector intersection to
56 * (X1,Y1) in range [0,1], return true if 0 <= distance <= 1
57 * - depending on (r > 1.0 or r < 0.0) check the distance of X2,Y2 or X1,Y1
60 * Intersection of line <--> line:
61 * - see the description of 'LineLineIntersect()'
64 /* routines to find connections between pins, vias, lines...
78 #ifdef HAVE_SYS_TIMES_H
79 #include <sys/times.h>
84 #include "crosshair.h"
98 #ifdef HAVE_LIBDMALLOC
109 /* ---------------------------------------------------------------------------
113 #define EXPAND_BOUNDS(p) if (Bloat > 0) {\
114 (p)->BoundingBox.X1 -= Bloat; \
115 (p)->BoundingBox.X2 += Bloat; \
116 (p)->BoundingBox.Y1 -= Bloat; \
117 (p)->BoundingBox.Y2 += Bloat;}
119 #define SEPARATE(FP) \
123 for (i = Settings.CharPerLine; i; i--) \
128 #define PADLIST_ENTRY(L,I) \
129 (((PadTypePtr *)PadList[(L)].Data)[(I)])
131 #define LINELIST_ENTRY(L,I) \
132 (((LineTypePtr *)LineList[(L)].Data)[(I)])
134 #define ARCLIST_ENTRY(L,I) \
135 (((ArcTypePtr *)ArcList[(L)].Data)[(I)])
137 #define RATLIST_ENTRY(I) \
138 (((RatTypePtr *)RatList.Data)[(I)])
140 #define POLYGONLIST_ENTRY(L,I) \
141 (((PolygonTypePtr *)PolygonList[(L)].Data)[(I)])
143 #define PVLIST_ENTRY(I) \
144 (((PinTypePtr *)PVList.Data)[(I)])
146 #define IS_PV_ON_RAT(PV, Rat) \
147 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
149 #define IS_PV_ON_ARC(PV, Arc) \
150 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
152 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
153 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
155 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + fBloat,0.0), (Arc)))
157 #define IS_PV_ON_PAD(PV,Pad) \
158 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
160 #define LENGTH_TO_HUMAN(value) (Settings.grid_units_mm ? ((value) / 100000.0 * 25.4) : ((value) / 100.0))
161 #define LENGTH_DIGITS (Settings.grid_units_mm ? 4 : 2)
162 #define LENGTH_UNITS_STRING (Settings.grid_units_mm ? "mm" : "mils")
165 static DrcViolationType
166 *pcb_drc_violation_new (char *title
,
171 double measured_value
,
172 double required_value
,
174 const char *value_units
,
176 long int *object_id_list
,
177 int *object_type_list
)
179 DrcViolationType
*violation
= malloc (sizeof (DrcViolationType
));
181 violation
->title
= strdup (title
);
182 violation
->explanation
= strdup (explanation
);
185 violation
->angle
= angle
;
186 violation
->have_measured
= have_measured
;
187 violation
->measured_value
= measured_value
;
188 violation
->required_value
= required_value
;
189 violation
->value_digits
= value_digits
;
190 violation
->value_units
= value_units
;
191 violation
->object_count
= object_count
;
192 violation
->object_id_list
= object_id_list
;
193 violation
->object_type_list
= object_type_list
;
199 pcb_drc_violation_free (DrcViolationType
*violation
)
201 free (violation
->title
);
202 free (violation
->explanation
);
206 static char drc_dialog_message
[289] = {0};
208 reset_drc_dialog_message(void)
210 drc_dialog_message
[0] = 0;
211 if (gui
->drc_gui
!= NULL
)
213 gui
->drc_gui
->reset_drc_dialog_message ();
217 static void append_drc_dialog_message(const char *fmt
, ...)
218 __attribute__ ((format (printf
, 1, 2)));
221 append_drc_dialog_message(const char *fmt
, ...)
223 size_t len
= strlen (drc_dialog_message
),
224 remained
= sizeof (drc_dialog_message
) - len
- 1;
227 #ifdef HAVE_VSNPRINTF
228 vsnprintf (drc_dialog_message
+ len
, remained
, fmt
, ap
);
230 vsprintf (drc_dialog_message
+ len
, fmt
, ap
);
235 static void GotoError (void);
238 append_drc_violation (DrcViolationType
*violation
)
240 if (gui
->drc_gui
!= NULL
)
242 gui
->drc_gui
->append_drc_violation (violation
);
246 /* Fallback to formatting the violation message as text */
247 append_drc_dialog_message ("%s\n", violation
->title
);
248 append_drc_dialog_message (_("near (%.*f, %.*f)\n"),
249 LENGTH_DIGITS
, LENGTH_TO_HUMAN (violation
->x
),
250 LENGTH_DIGITS
, LENGTH_TO_HUMAN (violation
->y
));
254 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
256 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
257 Message (_("near location (%.*f, %.*f)\n"),
258 LENGTH_DIGITS
, LENGTH_TO_HUMAN (violation
->x
),
259 LENGTH_DIGITS
, LENGTH_TO_HUMAN (violation
->y
));
263 * message when asked about continuing DRC checks after next
264 * violation is found.
266 #define DRC_CONTINUE _("Press Next to continue DRC checking")
267 #define DRC_NEXT _("Next")
268 #define DRC_CANCEL _("Cancel")
271 throw_drc_dialog(void)
275 if (gui
->drc_gui
!= NULL
)
277 r
= gui
->drc_gui
->throw_drc_dialog ();
281 /* Fallback to formatting the violation message as text */
282 append_drc_dialog_message (DRC_CONTINUE
);
283 r
= gui
->confirm_dialog (drc_dialog_message
, DRC_CANCEL
, DRC_NEXT
);
284 reset_drc_dialog_message();
289 /* ---------------------------------------------------------------------------
292 * the two 'dummy' structs for PVs and Pads are necessary for creating
293 * connection lists which include the element's name
297 void **Data
; /* pointer to index data */
298 Cardinal Location
, /* currently used position */
299 DrawLocation
, Number
, /* number of objects in list */
302 ListType
, *ListTypePtr
;
304 /* ---------------------------------------------------------------------------
305 * some local identifiers
307 static float fBloat
= 0.0;
308 static LocationType Bloat
= 0;
309 static int TheFlag
= FOUNDFLAG
;
310 static int OldFlag
= FOUNDFLAG
;
311 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
312 static int thing_type
;
313 static bool User
= false; /* user action causing this */
314 static bool drc
= false; /* whether to stop if finding something not found */
315 static bool IsBad
= false;
316 static Cardinal drcerr_count
; /* count of drc errors */
317 static Cardinal TotalP
, TotalV
, NumberOfPads
[2];
318 static ListType LineList
[MAX_LAYER
], /* list of objects to */
319 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
321 /* ---------------------------------------------------------------------------
322 * some local prototypes
324 static bool LookupLOConnectionsToPVList (bool);
325 static bool LookupLOConnectionsToLOList (bool);
326 static bool LookupPVConnectionsToLOList (bool);
327 static bool LookupPVConnectionsToPVList (void);
328 static bool LookupLOConnectionsToLine (LineTypePtr
, Cardinal
, bool);
329 static bool LookupLOConnectionsToPad (PadTypePtr
, Cardinal
);
330 static bool LookupLOConnectionsToPolygon (PolygonTypePtr
, Cardinal
);
331 static bool LookupLOConnectionsToArc (ArcTypePtr
, Cardinal
);
332 static bool LookupLOConnectionsToRatEnd (PointTypePtr
, Cardinal
);
333 static bool IsRatPointOnLineEnd (PointTypePtr
, LineTypePtr
);
334 static bool ArcArcIntersect (ArcTypePtr
, ArcTypePtr
);
335 static bool PrepareNextLoop (FILE *);
336 static bool PrintElementConnections (ElementTypePtr
, FILE *, bool);
337 static bool ListsEmpty (bool);
338 static bool DoIt (bool, bool);
339 static void PrintElementNameList (ElementTypePtr
, FILE *);
340 static void PrintConnectionElementName (ElementTypePtr
, FILE *);
341 static void PrintConnectionListEntry (char *, ElementTypePtr
,
343 static void PrintPadConnections (Cardinal
, FILE *, bool);
344 static void PrintPinConnections (FILE *, bool);
345 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementTypePtr
,
347 static void DrawNewConnections (void);
348 static void ResetConnections (bool);
349 static void DumpList (void);
350 static void LocateError (LocationType
*, LocationType
*);
351 static void BuildObjectList (int *, long int **, int **);
352 static void GotoError (void);
353 static bool DRCFind (int, void *, void *, void *);
354 static bool ListStart (int, void *, void *, void *);
355 static bool LOTouchesLine (LineTypePtr Line
, Cardinal LayerGroup
);
356 static bool PVTouchesLine (LineTypePtr line
);
357 static bool SetThing (int, void *, void *, void *);
359 /* ---------------------------------------------------------------------------
360 * some of the 'pad' routines are the same as for lines because the 'pad'
361 * struct starts with a line struct. See global.h for details
364 LinePadIntersect (LineTypePtr Line
, PadTypePtr Pad
)
366 return LineLineIntersect ((Line
), (LineTypePtr
)Pad
);
370 ArcPadIntersect (ArcTypePtr Arc
, PadTypePtr Pad
)
372 return LineArcIntersect ((LineTypePtr
) (Pad
), (Arc
));
376 ADD_PV_TO_LIST (PinTypePtr Pin
)
379 AddObjectToFlagUndoList (Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
380 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
);
381 SET_FLAG (TheFlag
, Pin
);
382 PVLIST_ENTRY (PVList
.Number
) = Pin
;
385 if (PVList
.Number
> PVList
.Size
)
386 printf ("ADD_PV_TO_LIST overflow! num=%d size=%d\n", PVList
.Number
,
389 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pin
))
390 return (SetThing (PIN_TYPE
, Pin
->Element
, Pin
, Pin
));
395 ADD_PAD_TO_LIST (Cardinal L
, PadTypePtr Pad
)
398 AddObjectToFlagUndoList (PAD_TYPE
, Pad
->Element
, Pad
, Pad
);
399 SET_FLAG (TheFlag
, Pad
);
400 PADLIST_ENTRY ((L
), PadList
[(L
)].Number
) = Pad
;
401 PadList
[(L
)].Number
++;
403 if (PadList
[(L
)].Number
> PadList
[(L
)].Size
)
404 printf ("ADD_PAD_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
405 PadList
[(L
)].Number
, PadList
[(L
)].Size
);
407 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pad
))
408 return (SetThing (PAD_TYPE
, Pad
->Element
, Pad
, Pad
));
413 ADD_LINE_TO_LIST (Cardinal L
, LineTypePtr Ptr
)
416 AddObjectToFlagUndoList (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
417 SET_FLAG (TheFlag
, (Ptr
));
418 LINELIST_ENTRY ((L
), LineList
[(L
)].Number
) = (Ptr
);
419 LineList
[(L
)].Number
++;
421 if (LineList
[(L
)].Number
> LineList
[(L
)].Size
)
422 printf ("ADD_LINE_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
423 LineList
[(L
)].Number
, LineList
[(L
)].Size
);
425 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
426 return (SetThing (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
431 ADD_ARC_TO_LIST (Cardinal L
, ArcTypePtr Ptr
)
434 AddObjectToFlagUndoList (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
435 SET_FLAG (TheFlag
, (Ptr
));
436 ARCLIST_ENTRY ((L
), ArcList
[(L
)].Number
) = (Ptr
);
437 ArcList
[(L
)].Number
++;
439 if (ArcList
[(L
)].Number
> ArcList
[(L
)].Size
)
440 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
441 ArcList
[(L
)].Number
, ArcList
[(L
)].Size
);
443 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
444 return (SetThing (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
449 ADD_RAT_TO_LIST (RatTypePtr Ptr
)
452 AddObjectToFlagUndoList (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
));
453 SET_FLAG (TheFlag
, (Ptr
));
454 RATLIST_ENTRY (RatList
.Number
) = (Ptr
);
457 if (RatList
.Number
> RatList
.Size
)
458 printf ("ADD_RAT_TO_LIST overflow! num=%d size=%d\n",
459 RatList
.Number
, RatList
.Size
);
461 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
462 return (SetThing (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
)));
467 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonTypePtr Ptr
)
470 AddObjectToFlagUndoList (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
471 SET_FLAG (TheFlag
, (Ptr
));
472 POLYGONLIST_ENTRY ((L
), PolygonList
[(L
)].Number
) = (Ptr
);
473 PolygonList
[(L
)].Number
++;
475 if (PolygonList
[(L
)].Number
> PolygonList
[(L
)].Size
)
476 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
477 PolygonList
[(L
)].Number
, PolygonList
[(L
)].Size
);
479 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
480 return (SetThing (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
485 PinLineIntersect (PinTypePtr PV
, LineTypePtr Line
)
487 /* IsLineInRectangle already has Bloat factor */
488 return TEST_FLAG (SQUAREFLAG
,
489 PV
) ? IsLineInRectangle (PV
->X
- (PV
->Thickness
+ 1) / 2,
490 PV
->Y
- (PV
->Thickness
+ 1) / 2,
491 PV
->X
+ (PV
->Thickness
+ 1) / 2,
492 PV
->Y
+ (PV
->Thickness
+ 1) / 2,
493 Line
) : IsPointInPad (PV
->X
,
506 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
512 if (type
== PIN_TYPE
&& ptr1
== NULL
)
515 thing_type
= VIA_TYPE
;
521 BoxBoxIntersection (BoxTypePtr b1
, BoxTypePtr b2
)
523 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
525 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
531 PadPadIntersect (PadTypePtr p1
, PadTypePtr p2
)
533 return LinePadIntersect ((LineTypePtr
) p1
, p2
);
537 PV_TOUCH_PV (PinTypePtr PV1
, PinTypePtr PV2
)
542 t1
= MAX (PV1
->Thickness
/ 2.0 + fBloat
, 0);
543 t2
= MAX (PV2
->Thickness
/ 2.0 + fBloat
, 0);
544 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
545 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
547 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
549 /* check for square/square overlap */
554 t2
= PV2
->Thickness
/ 2.0;
559 return BoxBoxIntersection (&b1
, &b2
);
562 /* ---------------------------------------------------------------------------
563 * releases all allocated memory
566 FreeLayoutLookupMemory (void)
570 for (i
= 0; i
< max_layer
; i
++)
572 MYFREE (LineList
[i
].Data
);
573 MYFREE (ArcList
[i
].Data
);
574 MYFREE (PolygonList
[i
].Data
);
576 MYFREE (PVList
.Data
);
577 MYFREE (RatList
.Data
);
581 FreeComponentLookupMemory (void)
583 MYFREE (PadList
[0].Data
);
584 MYFREE (PadList
[1].Data
);
587 /* ---------------------------------------------------------------------------
588 * allocates memory for component related stacks ...
589 * initializes index and sorts it by X1 and X2
592 InitComponentLookup (void)
596 /* initialize pad data; start by counting the total number
597 * on each of the two possible layers
599 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
600 ALLPAD_LOOP (PCB
->Data
);
602 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
603 NumberOfPads
[SOLDER_LAYER
]++;
605 NumberOfPads
[COMPONENT_LAYER
]++;
608 for (i
= 0; i
< 2; i
++)
610 /* allocate memory for working list */
612 (void **) MyCalloc (NumberOfPads
[i
], sizeof (PadTypePtr
),
613 "InitComponentLookup()");
615 /* clear some struct members */
616 PadList
[i
].Location
= 0;
617 PadList
[i
].DrawLocation
= 0;
618 PadList
[i
].Number
= 0;
619 PadList
[i
].Size
= NumberOfPads
[i
];
623 /* ---------------------------------------------------------------------------
624 * allocates memory for component related stacks ...
625 * initializes index and sorts it by X1 and X2
628 InitLayoutLookup (void)
632 /* initialize line arc and polygon data */
633 for (i
= 0; i
< max_layer
; i
++)
635 LayerTypePtr layer
= LAYER_PTR (i
);
639 /* allocate memory for line pointer lists */
641 (void **) MyCalloc (layer
->LineN
, sizeof (LineTypePtr
),
642 "InitLayoutLookup()");
643 LineList
[i
].Size
= layer
->LineN
;
648 (void **) MyCalloc (layer
->ArcN
, sizeof (ArcTypePtr
),
649 "InitLayoutLookup()");
650 ArcList
[i
].Size
= layer
->ArcN
;
654 /* allocate memory for polygon list */
657 PolygonList
[i
].Data
= (void **) MyCalloc (layer
->PolygonN
,
658 sizeof (PolygonTypePtr
),
659 "InitLayoutLookup()");
660 PolygonList
[i
].Size
= layer
->PolygonN
;
663 /* clear some struct members */
664 LineList
[i
].Location
= 0;
665 LineList
[i
].DrawLocation
= 0;
666 LineList
[i
].Number
= 0;
667 ArcList
[i
].Location
= 0;
668 ArcList
[i
].DrawLocation
= 0;
669 ArcList
[i
].Number
= 0;
670 PolygonList
[i
].Location
= 0;
671 PolygonList
[i
].DrawLocation
= 0;
672 PolygonList
[i
].Number
= 0;
675 if (PCB
->Data
->pin_tree
)
676 TotalP
= PCB
->Data
->pin_tree
->size
;
679 if (PCB
->Data
->via_tree
)
680 TotalV
= PCB
->Data
->via_tree
->size
;
683 /* allocate memory for 'new PV to check' list and clear struct */
684 PVList
.Data
= (void **) MyCalloc (TotalP
+ TotalV
, sizeof (PinTypePtr
),
685 "InitLayoutLookup()");
686 PVList
.Size
= TotalP
+ TotalV
;
688 PVList
.DrawLocation
= 0;
690 /* Initialize ratline data */
691 RatList
.Data
= (void **) MyCalloc (PCB
->Data
->RatN
, sizeof (RatTypePtr
),
692 "InitLayoutLookup()");
693 RatList
.Size
= PCB
->Data
->RatN
;
694 RatList
.Location
= 0;
695 RatList
.DrawLocation
= 0;
707 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
709 LineTypePtr line
= (LineTypePtr
) b
;
710 struct pv_info
*i
= (struct pv_info
*) cl
;
712 if (!TEST_FLAG (TheFlag
, line
) && PinLineIntersect (&i
->pv
, line
))
714 if (ADD_LINE_TO_LIST (i
->layer
, line
))
721 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
723 ArcTypePtr arc
= (ArcTypePtr
) b
;
724 struct pv_info
*i
= (struct pv_info
*) cl
;
726 if (!TEST_FLAG (TheFlag
, arc
) && IS_PV_ON_ARC (&i
->pv
, arc
))
728 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
735 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
737 PadTypePtr pad
= (PadTypePtr
) b
;
738 struct pv_info
*i
= (struct pv_info
*) cl
;
740 if (!TEST_FLAG (TheFlag
, pad
) && IS_PV_ON_PAD (&i
->pv
, pad
) &&
741 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
742 COMPONENT_LAYER
, pad
))
748 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
750 RatTypePtr rat
= (RatTypePtr
) b
;
751 struct pv_info
*i
= (struct pv_info
*) cl
;
753 if (!TEST_FLAG (TheFlag
, rat
) && IS_PV_ON_RAT (&i
->pv
, rat
) &&
754 ADD_RAT_TO_LIST (rat
))
759 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
761 PolygonTypePtr polygon
= (PolygonTypePtr
) b
;
762 struct pv_info
*i
= (struct pv_info
*) cl
;
764 /* if the pin doesn't have a therm and polygon is clearing
765 * then it can't touch due to clearance, so skip the expensive
766 * test. If it does have a therm, you still need to test
767 * because it might not be inside the polygon, or it could
768 * be on an edge such that it doesn't actually touch.
770 if (!TEST_FLAG (TheFlag
, polygon
) && (TEST_THERM (i
->layer
, &i
->pv
)
771 || !TEST_FLAG (CLEARPOLYFLAG
,
773 || !i
->pv
.Clearance
))
775 float wide
= 0.5 * i
->pv
.Thickness
+ fBloat
;
776 wide
= MAX (wide
, 0);
777 if (TEST_FLAG (SQUAREFLAG
, &i
->pv
))
779 LocationType x1
= i
->pv
.X
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
780 LocationType x2
= i
->pv
.X
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
781 LocationType y1
= i
->pv
.Y
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
782 LocationType y2
= i
->pv
.Y
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
783 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
784 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
787 else if (TEST_FLAG (OCTAGONFLAG
, &i
->pv
))
789 POLYAREA
*oct
= OctagonPoly (i
->pv
.X
, i
->pv
.Y
, i
->pv
.Thickness
/ 2);
790 if (isects (oct
, polygon
, true)
791 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
794 else if (IsPointInPolygon (i
->pv
.X
, i
->pv
.Y
, wide
,
796 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
802 /* ---------------------------------------------------------------------------
803 * checks if a PV is connected to LOs, if it is, the LO is added to
804 * the appropriate list and the 'used' flag is set
807 LookupLOConnectionsToPVList (bool AndRats
)
812 /* loop over all PVs currently on list */
813 while (PVList
.Location
< PVList
.Number
)
815 /* get pointer to data */
816 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
817 EXPAND_BOUNDS (&info
.pv
);
820 if (setjmp (info
.env
) == 0)
821 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pv
, NULL
,
822 LOCtoPVpad_callback
, &info
);
826 /* now all lines, arcs and polygons of the several layers */
827 for (layer
= 0; layer
< max_layer
; layer
++)
830 /* add touching lines */
831 if (setjmp (info
.env
) == 0)
832 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.pv
,
833 NULL
, LOCtoPVline_callback
, &info
);
836 /* add touching arcs */
837 if (setjmp (info
.env
) == 0)
838 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.pv
,
839 NULL
, LOCtoPVarc_callback
, &info
);
842 /* check all polygons */
843 if (setjmp (info
.env
) == 0)
844 r_search (LAYER_PTR (layer
)->polygon_tree
, (BoxType
*) & info
.pv
,
845 NULL
, LOCtoPVpoly_callback
, &info
);
849 /* Check for rat-lines that may intersect the PV */
852 if (setjmp (info
.env
) == 0)
853 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.pv
, NULL
,
854 LOCtoPVrat_callback
, &info
);
863 /* ---------------------------------------------------------------------------
864 * find all connections between LO at the current list position and new LOs
867 LookupLOConnectionsToLOList (bool AndRats
)
870 Cardinal i
, group
, layer
, ratposition
,
871 lineposition
[MAX_LAYER
],
872 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
874 /* copy the current LO list positions; the original data is changed
875 * by 'LookupPVConnectionsToLOList()' which has to check the same
876 * list entries plus the new ones
878 for (i
= 0; i
< max_layer
; i
++)
880 lineposition
[i
] = LineList
[i
].Location
;
881 polyposition
[i
] = PolygonList
[i
].Location
;
882 arcposition
[i
] = ArcList
[i
].Location
;
884 for (i
= 0; i
< 2; i
++)
885 padposition
[i
] = PadList
[i
].Location
;
886 ratposition
= RatList
.Location
;
888 /* loop over all new LOs in the list; recurse until no
889 * more new connections in the layergroup were found
897 position
= &ratposition
;
898 for (; *position
< RatList
.Number
; (*position
)++)
900 group
= RATLIST_ENTRY (*position
)->group1
;
901 if (LookupLOConnectionsToRatEnd
902 (&(RATLIST_ENTRY (*position
)->Point1
), group
))
904 group
= RATLIST_ENTRY (*position
)->group2
;
905 if (LookupLOConnectionsToRatEnd
906 (&(RATLIST_ENTRY (*position
)->Point2
), group
))
910 /* loop over all layergroups */
911 for (group
= 0; group
< max_layer
; group
++)
915 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
917 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
919 /* be aware that the layer number equal max_layer
920 * and max_layer+1 have a special meaning for pads
922 if (layer
< max_layer
)
924 /* try all new lines */
925 position
= &lineposition
[layer
];
926 for (; *position
< LineList
[layer
].Number
; (*position
)++)
927 if (LookupLOConnectionsToLine
928 (LINELIST_ENTRY (layer
, *position
), group
, true))
931 /* try all new arcs */
932 position
= &arcposition
[layer
];
933 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
934 if (LookupLOConnectionsToArc
935 (ARCLIST_ENTRY (layer
, *position
), group
))
938 /* try all new polygons */
939 position
= &polyposition
[layer
];
940 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
941 if (LookupLOConnectionsToPolygon
942 (POLYGONLIST_ENTRY (layer
, *position
), group
))
947 /* try all new pads */
951 Message (_("bad layer number %d max_layer=%d in find.c\n"),
955 position
= &padposition
[layer
];
956 for (; *position
< PadList
[layer
].Number
; (*position
)++)
957 if (LookupLOConnectionsToPad
958 (PADLIST_ENTRY (layer
, *position
), group
))
964 /* check if all lists are done; Later for-loops
965 * may have changed the prior lists
967 done
= !AndRats
|| ratposition
>= RatList
.Number
;
968 for (layer
= 0; layer
< max_layer
+ 2; layer
++)
970 if (layer
< max_layer
)
972 lineposition
[layer
] >= LineList
[layer
].Number
973 && arcposition
[layer
] >= ArcList
[layer
].Number
974 && polyposition
[layer
] >= PolygonList
[layer
].Number
;
977 && padposition
[layer
- max_layer
] >=
978 PadList
[layer
- max_layer
].Number
;
986 pv_pv_callback (const BoxType
* b
, void *cl
)
988 PinTypePtr pin
= (PinTypePtr
) b
;
989 struct pv_info
*i
= (struct pv_info
*) cl
;
991 if (!TEST_FLAG (TheFlag
, pin
) && PV_TOUCH_PV (&i
->pv
, pin
))
993 if (TEST_FLAG (HOLEFLAG
, pin
))
995 SET_FLAG (WARNFLAG
, pin
);
996 Settings
.RatWarn
= true;
998 Message (_("WARNING: Hole too close to pin.\n"));
1000 Message (_("WARNING: Hole too close to via.\n"));
1002 if (ADD_PV_TO_LIST (pin
))
1003 longjmp (i
->env
, 1);
1008 /* ---------------------------------------------------------------------------
1009 * searches for new PVs that are connected to PVs on the list
1012 LookupPVConnectionsToPVList (void)
1014 Cardinal save_place
;
1015 struct pv_info info
;
1018 /* loop over all PVs on list */
1019 save_place
= PVList
.Location
;
1020 while (PVList
.Location
< PVList
.Number
)
1022 /* get pointer to data */
1023 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
1024 EXPAND_BOUNDS (&info
.pv
);
1025 if (setjmp (info
.env
) == 0)
1026 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pv
, NULL
,
1027 pv_pv_callback
, &info
);
1030 if (setjmp (info
.env
) == 0)
1031 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pv
, NULL
,
1032 pv_pv_callback
, &info
);
1037 PVList
.Location
= save_place
;
1047 PolygonType polygon
;
1053 pv_line_callback (const BoxType
* b
, void *cl
)
1055 PinTypePtr pv
= (PinTypePtr
) b
;
1056 struct lo_info
*i
= (struct lo_info
*) cl
;
1058 if (!TEST_FLAG (TheFlag
, pv
) && PinLineIntersect (pv
, &i
->line
))
1060 if (TEST_FLAG (HOLEFLAG
, pv
))
1062 SET_FLAG (WARNFLAG
, pv
);
1063 Settings
.RatWarn
= true;
1064 Message (_("WARNING: Hole too close to line.\n"));
1066 if (ADD_PV_TO_LIST (pv
))
1067 longjmp (i
->env
, 1);
1073 pv_pad_callback (const BoxType
* b
, void *cl
)
1075 PinTypePtr pv
= (PinTypePtr
) b
;
1076 struct lo_info
*i
= (struct lo_info
*) cl
;
1078 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_PAD (pv
, &i
->pad
))
1080 if (TEST_FLAG (HOLEFLAG
, pv
))
1082 SET_FLAG (WARNFLAG
, pv
);
1083 Settings
.RatWarn
= true;
1084 Message (_("WARNING: Hole too close to pad.\n"));
1086 if (ADD_PV_TO_LIST (pv
))
1087 longjmp (i
->env
, 1);
1093 pv_arc_callback (const BoxType
* b
, void *cl
)
1095 PinTypePtr pv
= (PinTypePtr
) b
;
1096 struct lo_info
*i
= (struct lo_info
*) cl
;
1098 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_ARC (pv
, &i
->arc
))
1100 if (TEST_FLAG (HOLEFLAG
, pv
))
1102 SET_FLAG (WARNFLAG
, pv
);
1103 Settings
.RatWarn
= true;
1104 Message (_("WARNING: Hole touches arc.\n"));
1106 if (ADD_PV_TO_LIST (pv
))
1107 longjmp (i
->env
, 1);
1113 pv_poly_callback (const BoxType
* b
, void *cl
)
1115 PinTypePtr pv
= (PinTypePtr
) b
;
1116 struct lo_info
*i
= (struct lo_info
*) cl
;
1118 /* note that holes in polygons are ok */
1119 if (!TEST_FLAG (TheFlag
, pv
) && (TEST_THERM (i
->layer
, pv
) ||
1120 !TEST_FLAG (CLEARPOLYFLAG
, &i
->polygon
) ||
1123 if (TEST_FLAG (SQUAREFLAG
, pv
))
1125 LocationType x1
, x2
, y1
, y2
;
1126 x1
= pv
->X
- (pv
->Thickness
+ 1 + Bloat
) / 2;
1127 x2
= pv
->X
+ (pv
->Thickness
+ 1 + Bloat
) / 2;
1128 y1
= pv
->Y
- (pv
->Thickness
+ 1 + Bloat
) / 2;
1129 y2
= pv
->Y
+ (pv
->Thickness
+ 1 + Bloat
) / 2;
1130 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, &i
->polygon
)
1131 && ADD_PV_TO_LIST (pv
))
1132 longjmp (i
->env
, 1);
1134 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1136 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, pv
->Thickness
/ 2);
1137 if (isects (oct
, &i
->polygon
, true) && ADD_PV_TO_LIST (pv
))
1138 longjmp (i
->env
, 1);
1142 if (IsPointInPolygon
1143 (pv
->X
, pv
->Y
, pv
->Thickness
* 0.5 + fBloat
, &i
->polygon
)
1144 && ADD_PV_TO_LIST (pv
))
1145 longjmp (i
->env
, 1);
1152 pv_rat_callback (const BoxType
* b
, void *cl
)
1154 PinTypePtr pv
= (PinTypePtr
) b
;
1155 struct lo_info
*i
= (struct lo_info
*) cl
;
1157 /* rats can't cause DRC so there is no early exit */
1158 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_RAT (pv
, &i
->rat
))
1159 ADD_PV_TO_LIST (pv
);
1163 /* ---------------------------------------------------------------------------
1164 * searches for new PVs that are connected to NEW LOs on the list
1165 * This routine updates the position counter of the lists too.
1168 LookupPVConnectionsToLOList (bool AndRats
)
1171 struct lo_info info
;
1173 /* loop over all layers */
1174 for (layer
= 0; layer
< max_layer
; layer
++)
1176 /* do nothing if there are no PV's */
1177 if (TotalP
+ TotalV
== 0)
1179 LineList
[layer
].Location
= LineList
[layer
].Number
;
1180 ArcList
[layer
].Location
= ArcList
[layer
].Number
;
1181 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
;
1185 /* check all lines */
1186 while (LineList
[layer
].Location
< LineList
[layer
].Number
)
1188 info
.line
= *(LINELIST_ENTRY (layer
, LineList
[layer
].Location
));
1189 EXPAND_BOUNDS (&info
.line
);
1190 if (setjmp (info
.env
) == 0)
1191 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1192 pv_line_callback
, &info
);
1195 if (setjmp (info
.env
) == 0)
1196 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1197 pv_line_callback
, &info
);
1200 LineList
[layer
].Location
++;
1203 /* check all arcs */
1204 while (ArcList
[layer
].Location
< ArcList
[layer
].Number
)
1206 info
.arc
= *(ARCLIST_ENTRY (layer
, ArcList
[layer
].Location
));
1207 EXPAND_BOUNDS (&info
.arc
);
1208 if (setjmp (info
.env
) == 0)
1209 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.arc
, NULL
,
1210 pv_arc_callback
, &info
);
1213 if (setjmp (info
.env
) == 0)
1214 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.arc
, NULL
,
1215 pv_arc_callback
, &info
);
1218 ArcList
[layer
].Location
++;
1221 /* now all polygons */
1223 while (PolygonList
[layer
].Location
< PolygonList
[layer
].Number
)
1226 *(POLYGONLIST_ENTRY (layer
, PolygonList
[layer
].Location
));
1227 EXPAND_BOUNDS (&info
.polygon
);
1228 if (setjmp (info
.env
) == 0)
1229 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.polygon
, NULL
,
1230 pv_poly_callback
, &info
);
1233 if (setjmp (info
.env
) == 0)
1234 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.polygon
, NULL
,
1235 pv_poly_callback
, &info
);
1238 PolygonList
[layer
].Location
++;
1242 /* loop over all pad-layers */
1243 for (layer
= 0; layer
< 2; layer
++)
1245 /* do nothing if there are no PV's */
1246 if (TotalP
+ TotalV
== 0)
1248 PadList
[layer
].Location
= PadList
[layer
].Number
;
1252 /* check all pads; for a detailed description see
1253 * the handling of lines in this subroutine
1255 while (PadList
[layer
].Location
< PadList
[layer
].Number
)
1257 info
.pad
= *(PADLIST_ENTRY (layer
, PadList
[layer
].Location
));
1258 EXPAND_BOUNDS (&info
.pad
);
1259 if (setjmp (info
.env
) == 0)
1260 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pad
, NULL
,
1261 pv_pad_callback
, &info
);
1264 if (setjmp (info
.env
) == 0)
1265 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pad
, NULL
,
1266 pv_pad_callback
, &info
);
1269 PadList
[layer
].Location
++;
1273 /* do nothing if there are no PV's */
1274 if (TotalP
+ TotalV
== 0)
1275 RatList
.Location
= RatList
.Number
;
1277 /* check all rat-lines */
1280 while (RatList
.Location
< RatList
.Number
)
1282 info
.rat
= *(RATLIST_ENTRY (RatList
.Location
));
1283 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point1
, 1, NULL
,
1284 pv_rat_callback
, &info
);
1285 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point2
, 1, NULL
,
1286 pv_rat_callback
, &info
);
1287 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point1
, 1, NULL
,
1288 pv_rat_callback
, &info
);
1289 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point2
, 1, NULL
,
1290 pv_rat_callback
, &info
);
1299 pv_touch_callback (const BoxType
* b
, void *cl
)
1301 PinTypePtr pin
= (PinTypePtr
) b
;
1302 struct lo_info
*i
= (struct lo_info
*) cl
;
1304 if (!TEST_FLAG (TheFlag
, pin
) && PinLineIntersect (pin
, &i
->line
))
1305 longjmp (i
->env
, 1);
1310 PVTouchesLine (LineTypePtr line
)
1312 struct lo_info info
;
1315 EXPAND_BOUNDS (&info
.line
);
1316 if (setjmp (info
.env
) == 0)
1317 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1318 pv_touch_callback
, &info
);
1321 if (setjmp (info
.env
) == 0)
1322 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1323 pv_touch_callback
, &info
);
1330 /* reduce arc start angle and delta to 0..360 */
1332 normalize_angles (int *sa
, int *d
)
1339 if (*d
> 360) /* full circle */
1342 *sa
= 360 - ((-*sa
) % 360);
1348 radius_crosses_arc (double x
, double y
, ArcTypePtr arc
)
1350 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1351 int sa
= arc
->StartAngle
, d
= arc
->Delta
;
1353 normalize_angles (&sa
, &d
);
1356 if ((double)sa
<= alpha
)
1357 return (double)(sa
+ d
) >= alpha
;
1358 return (double)(sa
+ d
- 360) >= alpha
;
1362 get_arc_ends (double *box
, ArcTypePtr arc
)
1364 double ca
, sa
, angle
;
1366 angle
= arc
->StartAngle
;
1370 box
[0] = arc
->X
- arc
->Width
* ca
;
1371 box
[1] = arc
->Y
+ arc
->Height
* sa
;
1373 angle
= arc
->StartAngle
+ arc
->Delta
;
1377 box
[2] = arc
->X
- arc
->Width
* ca
;
1378 box
[3] = arc
->Y
+ arc
->Height
* sa
;
1380 /* ---------------------------------------------------------------------------
1381 * check if two arcs intersect
1382 * first we check for circle intersections,
1383 * then find the actual points of intersection
1384 * and test them to see if they are on arcs
1386 * consider a, the distance from the center of arc 1
1387 * to the point perpendicular to the intersecting points.
1389 * a = (r1^2 - r2^2 + l^2)/(2l)
1391 * the perpendicular distance to the point of intersection
1394 * d = sqrt(r1^2 - a^2)
1396 * the points of intersection would then be
1398 * x = X1 + a/l dx +- d/l dy
1399 * y = Y1 + a/l dy -+ d/l dx
1401 * where dx = X2 - X1 and dy = Y2 - Y1
1406 ArcArcIntersect (ArcTypePtr Arc1
, ArcTypePtr Arc2
)
1408 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1409 LocationType pdx
, pdy
;
1412 t
= 0.5 * Arc1
->Thickness
+ fBloat
;
1413 if (t
< 0) /* too thin arc */
1415 t2
= 0.5 * Arc2
->Thickness
;
1417 if (t1
< 0) /* too thin arc */
1419 /* try the end points first */
1420 get_arc_ends (box
, Arc1
);
1421 if (IsPointOnArc ((float) box
[0], (float) box
[1], (float)t
, Arc2
)
1422 || IsPointOnArc ((float) box
[2], (float) box
[3], (float)t
, Arc2
))
1425 get_arc_ends (box
, Arc2
);
1426 if (IsPointOnArc ((float) box
[0], (float) box
[1], (float)t1
, Arc1
)
1427 || IsPointOnArc ((float) box
[2], (float) box
[3], (float)t1
, Arc1
))
1429 pdx
= Arc2
->X
- Arc1
->X
;
1430 pdy
= Arc2
->Y
- Arc1
->Y
;
1431 l
= pdx
* pdx
+ pdy
* pdy
;
1432 /* concentric arcs, simpler intersection conditions */
1435 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1436 && Arc1
->Width
- t
<=
1438 || (Arc1
->Width
+ t
>=
1439 Arc2
->Width
- t2
&& Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1441 int sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1442 int sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1443 /* NB the endpoints have already been checked,
1444 so we just compare the angles */
1446 normalize_angles (&sa1
, &d1
);
1447 normalize_angles (&sa2
, &d2
);
1448 /* cases like sa1 == sa2 are catched when checking the endpoints */
1453 if (sa1
+ d1
> 360 && sa1
+ d1
- 360 > sa2
)
1460 if (sa2
+ d2
> 360 && sa2
+ d2
- 360 > sa1
)
1469 if (dl
> r1
+ r2
|| dl
+ r1
< r2
1470 || dl
+ r2
< r1
) /* arcs centerlines are too far or too near */
1472 /* check the nearst to the other arc center point */
1475 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1481 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1482 && IsPointOnArc ((float)(Arc1
->X
+ dx
), (float)(Arc1
->Y
+ dy
),
1486 dx
= - pdx
* r2
/ dl
;
1487 dy
= - pdy
* r2
/ dl
;
1488 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1494 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1495 && IsPointOnArc ((float)(Arc2
->X
+ dx
), (float)(Arc2
->Y
+ dy
),
1503 a
= 0.5 * (r1
- r2
+ l
) / l
;
1506 /* the circles are too far apart to touch or probably just touch:
1507 check the nearest point */
1512 x
= Arc1
->X
+ a
* pdx
;
1513 y
= Arc1
->Y
+ a
* pdy
;
1516 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1517 && IsPointOnArc ((float)(x
+ dy
), (float)(y
- dx
), (float)t
, Arc2
))
1519 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1520 && IsPointOnArc ((float)(x
+ dy
), (float)(y
- dx
), (float)t1
, Arc1
))
1523 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1524 && IsPointOnArc ((float)(x
- dy
), (float)(y
+ dx
), (float)t
, Arc2
))
1526 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1527 && IsPointOnArc ((float)(x
- dy
), (float)(y
+ dx
), (float)t1
, Arc1
))
1532 /* ---------------------------------------------------------------------------
1533 * Tests if point is same as line end point
1536 IsRatPointOnLineEnd (PointTypePtr Point
, LineTypePtr Line
)
1538 if ((Point
->X
== Line
->Point1
.X
1539 && Point
->Y
== Line
->Point1
.Y
)
1540 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1546 form_slanted_rectangle(PointType p
[4],LineTypePtr l
)
1547 /* writes vertices of a squared line */
1549 int dX
= l
->Point2
.X
- l
->Point1
.X
, dY
= l
->Point2
.Y
- l
->Point1
.Y
,
1554 dwx
= w
/ 2; dwy
= 0;
1558 dwx
= 0; dwy
= w
/ 2;
1561 {double r
= sqrt (dX
* (double) dX
+ dY
* (double) dY
) * 2;
1562 dwx
= w
/ r
* dX
; dwy
= w
/ r
* dY
;
1564 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1565 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1566 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1567 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1569 /* ---------------------------------------------------------------------------
1570 * checks if two lines intersect
1573 * Let A,B,C,D be 2-space position vectors. Then the directed line
1574 * segments AB & CD are given by:
1576 * AB=A+r(B-A), r in [0,1]
1577 * CD=C+s(D-C), s in [0,1]
1579 * If AB & CD intersect, then
1581 * A+r(B-A)=C+s(D-C), or
1583 * XA+r(XB-XA)=XC+s(XD-XC)
1584 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1586 * Solving the above for r and s yields
1588 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1589 * r = ----------------------------- (eqn 1)
1590 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1592 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1593 * s = ----------------------------- (eqn 2)
1594 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1596 * Let I be the position vector of the intersection point, then
1603 * By examining the values of r & s, you can also determine some
1604 * other limiting conditions:
1606 * If 0<=r<=1 & 0<=s<=1, intersection exists
1607 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1609 * If the denominator in eqn 1 is zero, AB & CD are parallel
1610 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1612 * If the intersection point of the 2 lines are needed (lines in this
1613 * context mean infinite lines) regardless whether the two line
1614 * segments intersect, then
1616 * If r>1, I is located on extension of AB
1617 * If r<0, I is located on extension of BA
1618 * If s>1, I is located on extension of CD
1619 * If s<0, I is located on extension of DC
1621 * Also note that the denominators of eqn 1 & 2 are identical.
1625 LineLineIntersect (LineTypePtr Line1
, LineTypePtr Line2
)
1627 register float dx
, dy
, dx1
, dy1
, s
, r
;
1628 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1630 PointType p
[4];form_slanted_rectangle(p
,Line1
);
1631 return IsLineInQuadrangle(p
,Line2
);
1633 /* here come only round Line1 because IsLineInQuadrangle()
1634 calls LineLineIntersect() with first argument rounded*/
1635 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1637 PointType p
[4];form_slanted_rectangle(p
,Line2
);
1638 return IsLineInQuadrangle(p
,Line1
);
1640 /* now all lines are round */
1643 if (Line1
->BoundingBox
.X1
- Bloat
> Line2
->BoundBoxing
.X2
1644 || Line1
->BoundingBox
.X2
+ Bloat
< Line2
->BoundingBox
.X1
1645 || Line1
->BoundingBox
.Y1
- Bloat
< Line2
->BoundingBox
.Y2
1646 || Line1
->BoundingBox
.Y2
+ Bloat
< Line2
->BoundingBox
.Y1
)
1650 /* setup some constants */
1651 dx
= (float) (Line1
->Point2
.X
- Line1
->Point1
.X
);
1652 dy
= (float) (Line1
->Point2
.Y
- Line1
->Point1
.Y
);
1653 dx1
= (float) (Line1
->Point1
.X
- Line2
->Point1
.X
);
1654 dy1
= (float) (Line1
->Point1
.Y
- Line2
->Point1
.Y
);
1655 s
= dy1
* dx
- dx1
* dy
;
1658 dx
* (float) (Line2
->Point2
.Y
-
1660 dy
* (float) (Line2
->Point2
.X
- Line2
->Point1
.X
);
1662 /* handle parallel lines */
1665 /* at least one of the two end points of one segment
1666 * has to have a minimum distance to the other segment
1668 * a first quick check is to see if the distance between
1669 * the two lines is less then their half total thickness
1671 register float distance
;
1673 /* perhaps line 1 is really just a point */
1674 if ((dx
== 0) && (dy
== 0))
1678 MAX (Line1
->Thickness
/ 2 +
1680 (PadTypePtr
) Line2
);
1681 s
= s
* s
/ (dx
* dx
+ dy
* dy
);
1686 (Line1
->Thickness
+ Line2
->Thickness
) + fBloat
, 0.0);
1687 distance
*= distance
;
1690 if (IsPointInPad (Line2
->Point1
.
1700 || IsPointInPad (Line2
->
1706 / 2 + Bloat
, 0), (PadTypePtr
) Line1
))
1708 return ((IsPointInPad (Line1
->Point1
.
1718 || IsPointInPad (Line1
->
1724 / 2 + Bloat
, 0), (PadTypePtr
) Line2
)));
1731 (float) (Line2
->Point2
.X
-
1733 dx1
* (float) (Line2
->Point2
.Y
- Line2
->Point1
.Y
)) / r
;
1735 /* intersection is at least on AB */
1736 if (r
>= 0.0 && r
<= 1.0)
1738 if (s
>= 0.0 && s
<= 1.0)
1741 /* intersection on AB and extension of CD */
1749 (PadTypePtr
)Line1
) :
1753 MAX (0.5 * Line2
->Thickness
+ fBloat
, 0.0), (PadTypePtr
)Line1
));
1756 /* intersection is at least on CD */
1757 if (s
>= 0.0 && s
<= 1.0)
1759 /* intersection on CD and extension of AB */
1764 MAX (Line1
->Thickness
/
1766 (PadTypePtr
)Line2
) :
1770 MAX (Line1
->Thickness
/ 2.0 + fBloat
, 0.0), (PadTypePtr
)Line2
));
1773 /* no intersection of zero-width lines but maybe of thick lines;
1774 * Must check each end point to exclude intersection
1776 if (IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1777 Line1
->Thickness
/ 2.0 + fBloat
, (PadTypePtr
)Line2
))
1779 if (IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1780 Line1
->Thickness
/ 2.0 + fBloat
, (PadTypePtr
)Line2
))
1782 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1783 Line2
->Thickness
/ 2.0 + fBloat
, (PadTypePtr
)Line1
))
1785 return IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1786 Line2
->Thickness
/ 2.0 + fBloat
, (PadTypePtr
)Line1
);
1790 /*---------------------------------------------------
1792 * Check for line intersection with an arc
1794 * Mostly this is like the circle/line intersection
1795 * found in IsPointOnLine (search.c) see the detailed
1796 * discussion for the basics there.
1798 * Since this is only an arc, not a full circle we need
1799 * to find the actual points of intersection with the
1800 * circle, and see if they are on the arc.
1802 * To do this, we translate along the line from the point Q
1803 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1804 * but it's handy to normalize with respect to l, the line
1805 * length so a single projection is done (e.g. we don't first
1808 * The projection is now of the form
1810 * Px = X1 + (r +- r2)(X2 - X1)
1811 * Py = Y1 + (r +- r2)(Y2 - Y1)
1813 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1814 * note that this is the variable d, not the symbol d described in IsPointOnLine
1815 * (variable d = symbol d * l)
1817 * The end points are hell so they are checked individually
1820 LineArcIntersect (LineTypePtr Line
, ArcTypePtr Arc
)
1822 register float dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1825 dx
= (float) (Line
->Point2
.X
- Line
->Point1
.X
);
1826 dy
= (float) (Line
->Point2
.Y
- Line
->Point1
.Y
);
1827 dx1
= (float) (Line
->Point1
.X
- Arc
->X
);
1828 dy1
= (float) (Line
->Point1
.Y
- Arc
->Y
);
1829 l
= dx
* dx
+ dy
* dy
;
1830 d
= dx
* dy1
- dy
* dx1
;
1833 /* use the larger diameter circle first */
1835 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + fBloat
, 0.0);
1837 r2
= Radius
* l
- d
;
1838 /* projection doesn't even intersect circle when r2 < 0 */
1841 /* check the ends of the line in case the projected point */
1842 /* of intersection is beyond the line end */
1844 (Line
->Point1
.X
, Line
->Point1
.Y
,
1845 MAX (0.5 * Line
->Thickness
+ fBloat
, 0.0), Arc
))
1848 (Line
->Point2
.X
, Line
->Point2
.Y
,
1849 MAX (0.5 * Line
->Thickness
+ fBloat
, 0.0), Arc
))
1854 Radius
= -(dx
* dx1
+ dy
* dy1
);
1855 r
= (Radius
+ r2
) / l
;
1856 if (r
>= 0 && r
<= 1
1857 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1858 Line
->Point1
.Y
+ r
* dy
,
1859 MAX (0.5 * Line
->Thickness
+ fBloat
, 0.0), Arc
))
1861 r
= (Radius
- r2
) / l
;
1862 if (r
>= 0 && r
<= 1
1863 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1864 Line
->Point1
.Y
+ r
* dy
,
1865 MAX (0.5 * Line
->Thickness
+ fBloat
, 0.0), Arc
))
1867 /* check arc end points */
1868 box
= GetArcEnds (Arc
);
1869 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + fBloat
, (PadTypePtr
)Line
))
1871 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + fBloat
, (PadTypePtr
)Line
))
1877 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1879 LineTypePtr line
= (LineTypePtr
) b
;
1880 struct lo_info
*i
= (struct lo_info
*) cl
;
1882 if (!TEST_FLAG (TheFlag
, line
) && LineArcIntersect (line
, &i
->arc
))
1884 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1885 longjmp (i
->env
, 1);
1891 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1893 ArcTypePtr arc
= (ArcTypePtr
) b
;
1894 struct lo_info
*i
= (struct lo_info
*) cl
;
1896 if (!arc
->Thickness
)
1898 if (!TEST_FLAG (TheFlag
, arc
) && ArcArcIntersect (&i
->arc
, arc
))
1900 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1901 longjmp (i
->env
, 1);
1907 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1909 PadTypePtr pad
= (PadTypePtr
) b
;
1910 struct lo_info
*i
= (struct lo_info
*) cl
;
1912 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1913 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1914 && ArcPadIntersect (&i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1915 longjmp (i
->env
, 1);
1919 /* ---------------------------------------------------------------------------
1920 * searches all LOs that are connected to the given arc on the given
1921 * layergroup. All found connections are added to the list
1923 * the notation that is used is:
1924 * Xij means Xj at arc i
1927 LookupLOConnectionsToArc (ArcTypePtr Arc
, Cardinal LayerGroup
)
1930 LocationType xlow
, xhigh
;
1931 struct lo_info info
;
1933 /* the maximum possible distance */
1934 xlow
= Arc
->BoundingBox
.X1
- MAX (MAX_PADSIZE
, MAX_LINESIZE
) / 2;
1935 xhigh
= Arc
->BoundingBox
.X2
+ MAX (MAX_PADSIZE
, MAX_LINESIZE
) / 2;
1938 EXPAND_BOUNDS (&info
.arc
);
1939 /* loop over all layers of the group */
1940 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1944 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1946 /* handle normal layers */
1947 if (layer
< max_layer
)
1949 PolygonTypePtr polygon
;
1953 if (setjmp (info
.env
) == 0)
1954 r_search (LAYER_PTR (layer
)->line_tree
, &info
.arc
.BoundingBox
,
1955 NULL
, LOCtoArcLine_callback
, &info
);
1959 if (setjmp (info
.env
) == 0)
1960 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.arc
.BoundingBox
,
1961 NULL
, LOCtoArcArc_callback
, &info
);
1965 /* now check all polygons */
1967 polygon
= PCB
->Data
->Layer
[layer
].Polygon
;
1968 for (; i
< PCB
->Data
->Layer
[layer
].PolygonN
; i
++, polygon
++)
1969 if (!TEST_FLAG (TheFlag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1970 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1975 info
.layer
= layer
- max_layer
;
1976 if (setjmp (info
.env
) == 0)
1977 r_search (PCB
->Data
->pad_tree
, &info
.arc
.BoundingBox
, NULL
,
1978 LOCtoArcPad_callback
, &info
);
1987 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1989 LineTypePtr line
= (LineTypePtr
) b
;
1990 struct lo_info
*i
= (struct lo_info
*) cl
;
1992 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1994 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1995 longjmp (i
->env
, 1);
2001 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
2003 ArcTypePtr arc
= (ArcTypePtr
) b
;
2004 struct lo_info
*i
= (struct lo_info
*) cl
;
2006 if (!arc
->Thickness
)
2008 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
2010 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2011 longjmp (i
->env
, 1);
2017 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
2019 RatTypePtr rat
= (RatTypePtr
) b
;
2020 struct lo_info
*i
= (struct lo_info
*) cl
;
2022 if (!TEST_FLAG (TheFlag
, rat
))
2024 if ((rat
->group1
== i
->layer
)
2025 && IsRatPointOnLineEnd (&rat
->Point1
, &i
->line
))
2027 if (ADD_RAT_TO_LIST (rat
))
2028 longjmp (i
->env
, 1);
2030 else if ((rat
->group2
== i
->layer
)
2031 && IsRatPointOnLineEnd (&rat
->Point2
, &i
->line
))
2033 if (ADD_RAT_TO_LIST (rat
))
2034 longjmp (i
->env
, 1);
2041 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
2043 PadTypePtr pad
= (PadTypePtr
) b
;
2044 struct lo_info
*i
= (struct lo_info
*) cl
;
2046 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2047 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2048 && LinePadIntersect (&i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2049 longjmp (i
->env
, 1);
2053 /* ---------------------------------------------------------------------------
2054 * searches all LOs that are connected to the given line on the given
2055 * layergroup. All found connections are added to the list
2057 * the notation that is used is:
2058 * Xij means Xj at line i
2061 LookupLOConnectionsToLine (LineTypePtr Line
, Cardinal LayerGroup
,
2065 struct lo_info info
;
2068 info
.layer
= LayerGroup
;
2069 EXPAND_BOUNDS (&info
.line
)
2070 /* add the new rat lines */
2071 if (setjmp (info
.env
) == 0)
2072 r_search (PCB
->Data
->rat_tree
, &info
.line
.BoundingBox
, NULL
,
2073 LOCtoLineRat_callback
, &info
);
2077 /* loop over all layers of the group */
2078 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2082 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2084 /* handle normal layers */
2085 if (layer
< max_layer
)
2087 PolygonTypePtr polygon
;
2091 if (setjmp (info
.env
) == 0)
2092 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
2093 NULL
, LOCtoLineLine_callback
, &info
);
2097 if (setjmp (info
.env
) == 0)
2098 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
2099 NULL
, LOCtoLineArc_callback
, &info
);
2102 /* now check all polygons */
2106 polygon
= PCB
->Data
->Layer
[layer
].Polygon
;
2107 for (; i
< PCB
->Data
->Layer
[layer
].PolygonN
; i
++, polygon
++)
2109 (TheFlag
, polygon
) && IsLineInPolygon (Line
, polygon
)
2110 && ADD_POLYGON_TO_LIST (layer
, polygon
))
2116 /* handle special 'pad' layers */
2117 info
.layer
= layer
- max_layer
;
2118 if (setjmp (info
.env
) == 0)
2119 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
2120 LOCtoLinePad_callback
, &info
);
2129 LOT_Linecallback (const BoxType
* b
, void *cl
)
2131 LineTypePtr line
= (LineTypePtr
) b
;
2132 struct lo_info
*i
= (struct lo_info
*) cl
;
2134 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
2135 longjmp (i
->env
, 1);
2140 LOT_Arccallback (const BoxType
* b
, void *cl
)
2142 ArcTypePtr arc
= (ArcTypePtr
) b
;
2143 struct lo_info
*i
= (struct lo_info
*) cl
;
2145 if (!arc
->Thickness
)
2147 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
2148 longjmp (i
->env
, 1);
2153 LOT_Padcallback (const BoxType
* b
, void *cl
)
2155 PadTypePtr pad
= (PadTypePtr
) b
;
2156 struct lo_info
*i
= (struct lo_info
*) cl
;
2158 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2159 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2160 && LinePadIntersect (&i
->line
, pad
))
2161 longjmp (i
->env
, 1);
2166 LOTouchesLine (LineTypePtr Line
, Cardinal LayerGroup
)
2170 struct lo_info info
;
2173 /* the maximum possible distance */
2176 EXPAND_BOUNDS (&info
.line
);
2178 /* loop over all layers of the group */
2179 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2181 Cardinal layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2183 /* handle normal layers */
2184 if (layer
< max_layer
)
2186 PolygonTypePtr polygon
;
2188 /* find the first line that touches coordinates */
2190 if (setjmp (info
.env
) == 0)
2191 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
2192 NULL
, LOT_Linecallback
, &info
);
2195 if (setjmp (info
.env
) == 0)
2196 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
2197 NULL
, LOT_Arccallback
, &info
);
2201 /* now check all polygons */
2203 polygon
= PCB
->Data
->Layer
[layer
].Polygon
;
2204 for (; i
< PCB
->Data
->Layer
[layer
].PolygonN
; i
++, polygon
++)
2205 if (!TEST_FLAG (TheFlag
, polygon
)
2206 && IsLineInPolygon (Line
, polygon
))
2211 /* handle special 'pad' layers */
2212 info
.layer
= layer
- max_layer
;
2213 if (setjmp (info
.env
) == 0)
2214 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
2215 LOT_Padcallback
, &info
);
2231 LOCtoRat_callback (const BoxType
* b
, void *cl
)
2233 LineTypePtr line
= (LineTypePtr
) b
;
2234 struct rat_info
*i
= (struct rat_info
*) cl
;
2236 if (!TEST_FLAG (TheFlag
, line
) &&
2237 ((line
->Point1
.X
== i
->Point
->X
&&
2238 line
->Point1
.Y
== i
->Point
->Y
) ||
2239 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
2241 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2242 longjmp (i
->env
, 1);
2247 PolygonToRat_callback (const BoxType
* b
, void *cl
)
2249 PolygonTypePtr polygon
= (PolygonTypePtr
) b
;
2250 struct rat_info
*i
= (struct rat_info
*) cl
;
2252 if (!TEST_FLAG (TheFlag
, polygon
) && polygon
->Clipped
&&
2253 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
2254 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
2256 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2257 longjmp (i
->env
, 1);
2263 LOCtoPad_callback (const BoxType
* b
, void *cl
)
2265 PadTypePtr pad
= (PadTypePtr
) b
;
2266 struct rat_info
*i
= (struct rat_info
*) cl
;
2268 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2269 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
2270 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
2271 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
2272 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
2273 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
2274 ADD_PAD_TO_LIST (i
->layer
, pad
))
2275 longjmp (i
->env
, 1);
2279 /* ---------------------------------------------------------------------------
2280 * searches all LOs that are connected to the given rat-line on the given
2281 * layergroup. All found connections are added to the list
2283 * the notation that is used is:
2284 * Xij means Xj at line i
2287 LookupLOConnectionsToRatEnd (PointTypePtr Point
, Cardinal LayerGroup
)
2290 struct rat_info info
;
2293 /* loop over all layers of this group */
2294 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2298 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2299 /* handle normal layers
2300 rats don't ever touch
2304 if (layer
< max_layer
)
2307 if (setjmp (info
.env
) == 0)
2308 r_search_pt (LAYER_PTR (layer
)->line_tree
, Point
, 1, NULL
,
2309 LOCtoRat_callback
, &info
);
2312 if (setjmp (info
.env
) == 0)
2313 r_search_pt (LAYER_PTR (layer
)->polygon_tree
, Point
, 1,
2314 NULL
, PolygonToRat_callback
, &info
);
2318 /* handle special 'pad' layers */
2319 info
.layer
= layer
- max_layer
;
2320 if (setjmp (info
.env
) == 0)
2321 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2322 LOCtoPad_callback
, &info
);
2331 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2333 LineTypePtr line
= (LineTypePtr
) b
;
2334 struct lo_info
*i
= (struct lo_info
*) cl
;
2336 if (!TEST_FLAG (TheFlag
, line
) && LinePadIntersect (line
, &i
->pad
))
2338 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2339 longjmp (i
->env
, 1);
2345 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2347 ArcTypePtr arc
= (ArcTypePtr
) b
;
2348 struct lo_info
*i
= (struct lo_info
*) cl
;
2350 if (!arc
->Thickness
)
2352 if (!TEST_FLAG (TheFlag
, arc
) && ArcPadIntersect (arc
, &i
->pad
))
2354 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2355 longjmp (i
->env
, 1);
2361 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2363 PolygonTypePtr polygon
= (PolygonTypePtr
) b
;
2364 struct lo_info
*i
= (struct lo_info
*) cl
;
2367 if (!TEST_FLAG (TheFlag
, polygon
) &&
2368 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
.Clearance
))
2370 if (IsPadInPolygon (&i
->pad
, polygon
) &&
2371 ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2372 longjmp (i
->env
, 1);
2378 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2380 RatTypePtr rat
= (RatTypePtr
) b
;
2381 struct lo_info
*i
= (struct lo_info
*) cl
;
2383 if (!TEST_FLAG (TheFlag
, rat
))
2385 if (rat
->group1
== i
->layer
&&
2386 ((rat
->Point1
.X
== i
->pad
.Point1
.X
&& rat
->Point1
.Y
== i
->pad
.Point1
.Y
) ||
2387 (rat
->Point1
.X
== i
->pad
.Point2
.X
&& rat
->Point1
.Y
== i
->pad
.Point2
.Y
) ||
2388 (rat
->Point1
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2389 rat
->Point1
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2391 if (ADD_RAT_TO_LIST (rat
))
2392 longjmp (i
->env
, 1);
2394 else if (rat
->group2
== i
->layer
&&
2395 ((rat
->Point2
.X
== i
->pad
.Point1
.X
&& rat
->Point2
.Y
== i
->pad
.Point1
.Y
) ||
2396 (rat
->Point2
.X
== i
->pad
.Point2
.X
&& rat
->Point2
.Y
== i
->pad
.Point2
.Y
) ||
2397 (rat
->Point2
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2398 rat
->Point2
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2400 if (ADD_RAT_TO_LIST (rat
))
2401 longjmp (i
->env
, 1);
2408 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2410 PadTypePtr pad
= (PadTypePtr
) b
;
2411 struct lo_info
*i
= (struct lo_info
*) cl
;
2413 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2414 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2415 && PadPadIntersect (pad
, &i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2416 longjmp (i
->env
, 1);
2420 /* ---------------------------------------------------------------------------
2421 * searches all LOs that are connected to the given pad on the given
2422 * layergroup. All found connections are added to the list
2425 LookupLOConnectionsToPad (PadTypePtr Pad
, Cardinal LayerGroup
)
2428 struct lo_info info
;
2430 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2431 return (LookupLOConnectionsToLine ((LineTypePtr
) Pad
, LayerGroup
, false));
2434 EXPAND_BOUNDS (&info
.pad
);
2435 /* add the new rat lines */
2436 info
.layer
= LayerGroup
;
2437 if (setjmp (info
.env
) == 0)
2438 r_search (PCB
->Data
->rat_tree
, &info
.pad
.BoundingBox
, NULL
,
2439 LOCtoPadRat_callback
, &info
);
2443 /* loop over all layers of the group */
2444 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2448 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2449 /* handle normal layers */
2450 if (layer
< max_layer
)
2454 if (setjmp (info
.env
) == 0)
2455 r_search (LAYER_PTR (layer
)->line_tree
, &info
.pad
.BoundingBox
,
2456 NULL
, LOCtoPadLine_callback
, &info
);
2460 if (setjmp (info
.env
) == 0)
2461 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.pad
.BoundingBox
,
2462 NULL
, LOCtoPadArc_callback
, &info
);
2466 if (setjmp (info
.env
) == 0)
2467 r_search (LAYER_PTR (layer
)->polygon_tree
, &info
.pad
.BoundingBox
,
2468 NULL
, LOCtoPadPoly_callback
, &info
);
2474 /* handle special 'pad' layers */
2475 info
.layer
= layer
- max_layer
;
2476 if (setjmp (info
.env
) == 0)
2477 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pad
, NULL
,
2478 LOCtoPadPad_callback
, &info
);
2488 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2490 LineTypePtr line
= (LineTypePtr
) b
;
2491 struct lo_info
*i
= (struct lo_info
*) cl
;
2493 if (!TEST_FLAG (TheFlag
, line
) && IsLineInPolygon (line
, &i
->polygon
))
2495 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2496 longjmp (i
->env
, 1);
2502 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2504 ArcTypePtr arc
= (ArcTypePtr
) b
;
2505 struct lo_info
*i
= (struct lo_info
*) cl
;
2507 if (!arc
->Thickness
)
2509 if (!TEST_FLAG (TheFlag
, arc
) && IsArcInPolygon (arc
, &i
->polygon
))
2511 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2512 longjmp (i
->env
, 1);
2518 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2520 PadTypePtr pad
= (PadTypePtr
) b
;
2521 struct lo_info
*i
= (struct lo_info
*) cl
;
2523 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2524 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2525 && IsPadInPolygon (pad
, &i
->polygon
))
2527 if (ADD_PAD_TO_LIST (i
->layer
, pad
))
2528 longjmp (i
->env
, 1);
2534 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2536 RatTypePtr rat
= (RatTypePtr
) b
;
2537 struct lo_info
*i
= (struct lo_info
*) cl
;
2539 if (!TEST_FLAG (TheFlag
, rat
))
2541 if ((rat
->Point1
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2542 rat
->Point1
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2543 rat
->group1
== i
->layer
) ||
2544 (rat
->Point2
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2545 rat
->Point2
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2546 rat
->group2
== i
->layer
))
2547 if (ADD_RAT_TO_LIST (rat
))
2548 longjmp (i
->env
, 1);
2554 /* ---------------------------------------------------------------------------
2555 * looks up LOs that are connected to the given polygon
2556 * on the given layergroup. All found connections are added to the list
2559 LookupLOConnectionsToPolygon (PolygonTypePtr Polygon
, Cardinal LayerGroup
)
2562 struct lo_info info
;
2564 if (!Polygon
->Clipped
)
2566 info
.polygon
= *Polygon
;
2567 EXPAND_BOUNDS (&info
.polygon
);
2568 info
.layer
= LayerGroup
;
2570 if (setjmp (info
.env
) == 0)
2571 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.polygon
, NULL
,
2572 LOCtoPolyRat_callback
, &info
);
2575 /* loop over all layers of the group */
2576 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2580 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2582 /* handle normal layers */
2583 if (layer
< max_layer
)
2585 PolygonTypePtr polygon
;
2587 /* check all polygons */
2589 polygon
= PCB
->Data
->Layer
[layer
].Polygon
;
2590 for (i
= 0; i
< PCB
->Data
->Layer
[layer
].PolygonN
; i
++, polygon
++)
2591 if (!TEST_FLAG (TheFlag
, polygon
)
2592 && IsPolygonInPolygon (polygon
, Polygon
)
2593 && ADD_POLYGON_TO_LIST (layer
, polygon
))
2597 /* check all lines */
2598 if (setjmp (info
.env
) == 0)
2599 r_search (LAYER_PTR (layer
)->line_tree
,
2600 (BoxType
*) & info
.polygon
, NULL
,
2601 LOCtoPolyLine_callback
, &info
);
2604 /* check all arcs */
2605 if (setjmp (info
.env
) == 0)
2606 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.polygon
,
2607 NULL
, LOCtoPolyArc_callback
, &info
);
2613 info
.layer
= layer
- max_layer
;
2614 if (setjmp (info
.env
) == 0)
2615 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.polygon
,
2616 NULL
, LOCtoPolyPad_callback
, &info
);
2624 /* ---------------------------------------------------------------------------
2625 * checks if an arc has a connection to a polygon
2627 * - first check if the arc can intersect with the polygon by
2628 * evaluating the bounding boxes
2629 * - check the two end points of the arc. If none of them matches
2630 * - check all segments of the polygon against the arc.
2633 IsArcInPolygon (ArcTypePtr Arc
, PolygonTypePtr Polygon
)
2635 BoxTypePtr Box
= (BoxType
*) Arc
;
2637 /* arcs with clearance never touch polys */
2638 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2640 if (!Polygon
->Clipped
)
2642 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2643 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2644 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2645 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2649 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2650 return false; /* error */
2651 return isects (ap
, Polygon
, true);
2656 /* ---------------------------------------------------------------------------
2657 * checks if a line has a connection to a polygon
2659 * - first check if the line can intersect with the polygon by
2660 * evaluating the bounding boxes
2661 * - check the two end points of the line. If none of them matches
2662 * - check all segments of the polygon against the line.
2665 IsLineInPolygon (LineTypePtr Line
, PolygonTypePtr Polygon
)
2667 BoxTypePtr Box
= (BoxType
*) Line
;
2670 /* lines with clearance never touch polygons */
2671 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2673 if (!Polygon
->Clipped
)
2675 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2677 BDimension wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2678 LocationType x1
, x2
, y1
, y2
;
2680 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2681 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2682 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2683 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2684 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2686 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2687 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2688 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2689 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2691 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2692 return FALSE
; /* error */
2693 return isects (lp
, Polygon
, true);
2698 /* ---------------------------------------------------------------------------
2699 * checks if a pad connects to a non-clearing polygon
2701 * The polygon is assumed to already have been proven non-clearing
2704 IsPadInPolygon (PadTypePtr pad
, PolygonTypePtr polygon
)
2706 return IsLineInPolygon ((LineTypePtr
) pad
, polygon
);
2709 /* ---------------------------------------------------------------------------
2710 * checks if a polygon has a connection to a second one
2712 * First check all points out of P1 against P2 and vice versa.
2713 * If both fail check all lines of P1 against the ones of P2
2716 IsPolygonInPolygon (PolygonTypePtr P1
, PolygonTypePtr P2
)
2718 if (!P1
->Clipped
|| !P2
->Clipped
)
2720 assert (P1
->Clipped
->contours
);
2721 assert (P2
->Clipped
->contours
);
2723 /* first check if both bounding boxes intersect. If not, return quickly */
2724 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2725 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2726 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2727 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2730 /* first check un-bloated case */
2731 if (isects (P1
->Clipped
, P2
, false))
2734 /* now the difficult case of bloated */
2738 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2741 VNODE
*v
= &c
->head
;
2742 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2743 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2744 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2745 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2748 line
.Point1
.X
= v
->point
[0];
2749 line
.Point1
.Y
= v
->point
[1];
2750 line
.Thickness
= 2 * Bloat
;
2752 line
.Flags
= NoFlags ();
2753 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2755 line
.Point2
.X
= v
->point
[0];
2756 line
.Point2
.Y
= v
->point
[1];
2757 SetLineBoundingBox (&line
);
2758 if (IsLineInPolygon (&line
, P2
))
2760 line
.Point1
.X
= line
.Point2
.X
;
2761 line
.Point1
.Y
= line
.Point2
.Y
;
2770 /* ---------------------------------------------------------------------------
2771 * writes the several names of an element to a file
2774 PrintElementNameList (ElementTypePtr Element
, FILE * FP
)
2776 static DynamicStringType cname
, pname
, vname
;
2778 CreateQuotedString (&cname
, EMPTY (DESCRIPTION_NAME (Element
)));
2779 CreateQuotedString (&pname
, EMPTY (NAMEONPCB_NAME (Element
)));
2780 CreateQuotedString (&vname
, EMPTY (VALUE_NAME (Element
)));
2781 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2784 /* ---------------------------------------------------------------------------
2785 * writes the several names of an element to a file
2788 PrintConnectionElementName (ElementTypePtr Element
, FILE * FP
)
2790 fputs ("Element", FP
);
2791 PrintElementNameList (Element
, FP
);
2795 /* ---------------------------------------------------------------------------
2796 * prints one {pin,pad,via}/element entry of connection lists
2799 PrintConnectionListEntry (char *ObjName
, ElementTypePtr Element
,
2800 bool FirstOne
, FILE * FP
)
2802 static DynamicStringType oname
;
2804 CreateQuotedString (&oname
, ObjName
);
2806 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2809 fprintf (FP
, "\t\t%s ", oname
.Data
);
2811 PrintElementNameList (Element
, FP
);
2813 fputs ("(__VIA__)\n", FP
);
2817 /* ---------------------------------------------------------------------------
2818 * prints all found connections of a pads to file FP
2819 * the connections are stacked in 'PadList'
2822 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2827 if (!PadList
[Layer
].Number
)
2830 /* the starting pad */
2833 ptr
= PADLIST_ENTRY (Layer
, 0);
2835 PrintConnectionListEntry (UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2837 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2840 /* we maybe have to start with i=1 if we are handling the
2841 * starting-pad itself
2843 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2845 ptr
= PADLIST_ENTRY (Layer
, i
);
2847 PrintConnectionListEntry (EMPTY (ptr
->Name
), ptr
->Element
, false, FP
);
2849 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2853 /* ---------------------------------------------------------------------------
2854 * prints all found connections of a pin to file FP
2855 * the connections are stacked in 'PVList'
2858 PrintPinConnections (FILE * FP
, bool IsFirst
)
2868 /* the starting pin */
2869 pv
= PVLIST_ENTRY (0);
2870 PrintConnectionListEntry (EMPTY (pv
->Name
), NULL
, true, FP
);
2873 /* we maybe have to start with i=1 if we are handling the
2874 * starting-pin itself
2876 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2878 /* get the elements name or assume that its a via */
2879 pv
= PVLIST_ENTRY (i
);
2880 PrintConnectionListEntry (EMPTY (pv
->Name
), pv
->Element
, false, FP
);
2884 /* ---------------------------------------------------------------------------
2885 * checks if all lists of new objects are handled
2888 ListsEmpty (bool AndRats
)
2893 empty
= (PVList
.Location
>= PVList
.Number
);
2895 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2896 for (i
= 0; i
< max_layer
&& empty
; i
++)
2897 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2898 && ArcList
[i
].Location
>= ArcList
[i
].Number
2899 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2903 /* ---------------------------------------------------------------------------
2904 * loops till no more connections are found
2907 DoIt (bool AndRats
, bool AndDraw
)
2912 /* lookup connections; these are the steps (2) to (4)
2913 * from the description
2915 new = LookupPVConnectionsToPVList ();
2917 new = LookupLOConnectionsToPVList (AndRats
);
2919 new = LookupLOConnectionsToLOList (AndRats
);
2921 new = LookupPVConnectionsToLOList (AndRats
);
2923 DrawNewConnections ();
2925 while (!new && !ListsEmpty (AndRats
));
2931 /* returns true if nothing un-found touches the passed line
2932 * returns false if it would touch something not yet found
2933 * doesn't include rat-lines in the search
2937 lineClear (LineTypePtr line
, Cardinal group
)
2939 if (LOTouchesLine (line
, group
))
2941 if (PVTouchesLine (line
))
2946 /* ---------------------------------------------------------------------------
2947 * prints all unused pins of an element to file FP
2950 PrintAndSelectUnusedPinsAndPadsOfElement (ElementTypePtr Element
, FILE * FP
)
2954 static DynamicStringType oname
;
2956 /* check all pins in element */
2960 if (!TEST_FLAG (HOLEFLAG
, pin
))
2962 /* pin might have bee checked before, add to list if not */
2963 if (!TEST_FLAG (TheFlag
, pin
) && FP
)
2966 if (ADD_PV_TO_LIST (pin
))
2969 number
= PadList
[COMPONENT_LAYER
].Number
2970 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2971 /* the pin has no connection if it's the only
2972 * list entry; don't count vias
2974 for (i
= 0; i
< PVList
.Number
; i
++)
2975 if (!PVLIST_ENTRY (i
)->Element
)
2979 /* output of element name if not already done */
2982 PrintConnectionElementName (Element
, FP
);
2986 /* write name to list and draw selected object */
2987 CreateQuotedString (&oname
, EMPTY (pin
->Name
));
2988 fprintf (FP
, "\t%s\n", oname
.Data
);
2989 SET_FLAG (SELECTEDFLAG
, pin
);
2993 /* reset found objects for the next pin */
2994 if (PrepareNextLoop (FP
))
3001 /* check all pads in element */
3004 /* lookup pad in list */
3005 /* pad might has bee checked before, add to list if not */
3006 if (!TEST_FLAG (TheFlag
, pad
) && FP
)
3009 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
3010 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3013 number
= PadList
[COMPONENT_LAYER
].Number
3014 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
3015 /* the pin has no connection if it's the only
3016 * list entry; don't count vias
3018 for (i
= 0; i
< PVList
.Number
; i
++)
3019 if (!PVLIST_ENTRY (i
)->Element
)
3023 /* output of element name if not already done */
3026 PrintConnectionElementName (Element
, FP
);
3030 /* write name to list and draw selected object */
3031 CreateQuotedString (&oname
, EMPTY (pad
->Name
));
3032 fprintf (FP
, "\t%s\n", oname
.Data
);
3033 SET_FLAG (SELECTEDFLAG
, pad
);
3037 /* reset found objects for the next pin */
3038 if (PrepareNextLoop (FP
))
3044 /* print separator if element has unused pins or pads */
3047 fputs ("}\n\n", FP
);
3053 /* ---------------------------------------------------------------------------
3054 * resets some flags for looking up the next pin/pad
3057 PrepareNextLoop (FILE * FP
)
3061 /* reset found LOs for the next pin */
3062 for (layer
= 0; layer
< max_layer
; layer
++)
3064 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
3065 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
3066 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
3069 /* reset found pads */
3070 for (layer
= 0; layer
< 2; layer
++)
3071 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
3074 PVList
.Number
= PVList
.Location
= 0;
3075 RatList
.Number
= RatList
.Location
= 0;
3080 /* ---------------------------------------------------------------------------
3081 * finds all connections to the pins of the passed element.
3082 * The result is written to file FP
3083 * Returns true if operation was aborted
3086 PrintElementConnections (ElementTypePtr Element
, FILE * FP
, bool AndDraw
)
3088 PrintConnectionElementName (Element
, FP
);
3090 /* check all pins in element */
3093 /* pin might have been checked before, add to list if not */
3094 if (TEST_FLAG (TheFlag
, pin
))
3096 PrintConnectionListEntry (EMPTY (pin
->Name
), NULL
, true, FP
);
3097 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
3100 if (ADD_PV_TO_LIST (pin
))
3102 DoIt (true, AndDraw
);
3103 /* printout all found connections */
3104 PrintPinConnections (FP
, true);
3105 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
3106 PrintPadConnections (SOLDER_LAYER
, FP
, false);
3107 fputs ("\t}\n", FP
);
3108 if (PrepareNextLoop (FP
))
3113 /* check all pads in element */
3117 /* pad might have been checked before, add to list if not */
3118 if (TEST_FLAG (TheFlag
, pad
))
3120 PrintConnectionListEntry (EMPTY (pad
->Name
), NULL
, true, FP
);
3121 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
3124 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
3125 if (ADD_PAD_TO_LIST (layer
, pad
))
3127 DoIt (true, AndDraw
);
3128 /* print all found connections */
3129 PrintPadConnections (layer
, FP
, true);
3130 PrintPadConnections (layer
==
3131 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
3133 PrintPinConnections (FP
, false);
3134 fputs ("\t}\n", FP
);
3135 if (PrepareNextLoop (FP
))
3139 fputs ("}\n\n", FP
);
3143 /* ---------------------------------------------------------------------------
3144 * draws all new connections which have been found since the
3145 * routine was called the last time
3148 DrawNewConnections (void)
3153 /* decrement 'i' to keep layerstack order */
3154 for (i
= max_layer
- 1; i
!= -1; i
--)
3156 Cardinal layer
= LayerStack
[i
];
3158 if (PCB
->Data
->Layer
[layer
].On
)
3160 /* draw all new lines */
3161 position
= LineList
[layer
].DrawLocation
;
3162 for (; position
< LineList
[layer
].Number
; position
++)
3163 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
), 0);
3164 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
3166 /* draw all new arcs */
3167 position
= ArcList
[layer
].DrawLocation
;
3168 for (; position
< ArcList
[layer
].Number
; position
++)
3169 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
), 0);
3170 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
3172 /* draw all new polygons */
3173 position
= PolygonList
[layer
].DrawLocation
;
3174 for (; position
< PolygonList
[layer
].Number
; position
++)
3176 (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
), 0);
3177 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
3181 /* draw all new pads */
3183 for (i
= 0; i
< 2; i
++)
3185 position
= PadList
[i
].DrawLocation
;
3187 for (; position
< PadList
[i
].Number
; position
++)
3188 DrawPad (PADLIST_ENTRY (i
, position
), 0);
3189 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
3192 /* draw all new PVs; 'PVList' holds a list of pointers to the
3193 * sorted array pointers to PV data
3195 while (PVList
.DrawLocation
< PVList
.Number
)
3197 PinTypePtr pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
3199 if (TEST_FLAG (PINFLAG
, pv
))
3204 else if (PCB
->ViaOn
)
3206 PVList
.DrawLocation
++;
3208 /* draw the new rat-lines */
3211 position
= RatList
.DrawLocation
;
3212 for (; position
< RatList
.Number
; position
++)
3213 DrawRat (RATLIST_ENTRY (position
), 0);
3214 RatList
.DrawLocation
= RatList
.Number
;
3218 /* ---------------------------------------------------------------------------
3219 * find all connections to pins within one element
3222 LookupElementConnections (ElementTypePtr Element
, FILE * FP
)
3224 /* reset all currently marked connections */
3226 TheFlag
= FOUNDFLAG
;
3227 ResetConnections (true);
3228 InitConnectionLookup ();
3229 PrintElementConnections (Element
, FP
, true);
3230 SetChangedFlag (true);
3231 if (Settings
.RingBellWhenFinished
)
3233 FreeConnectionLookupMemory ();
3234 IncrementUndoSerialNumber ();
3239 /* ---------------------------------------------------------------------------
3240 * find all connections to pins of all element
3243 LookupConnectionsToAllElements (FILE * FP
)
3245 /* reset all currently marked connections */
3247 TheFlag
= FOUNDFLAG
;
3248 ResetConnections (false);
3249 InitConnectionLookup ();
3251 ELEMENT_LOOP (PCB
->Data
);
3253 /* break if abort dialog returned true */
3254 if (PrintElementConnections (element
, FP
, false))
3257 if (Settings
.ResetAfterElement
&& n
!= 1)
3258 ResetConnections (false);
3261 if (Settings
.RingBellWhenFinished
)
3263 ResetConnections (false);
3264 FreeConnectionLookupMemory ();
3265 ClearAndRedrawOutput ();
3268 /*---------------------------------------------------------------------------
3269 * add the starting object to the list of found objects
3272 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
3280 if (ADD_PV_TO_LIST ((PinTypePtr
) ptr2
))
3287 if (ADD_RAT_TO_LIST ((RatTypePtr
) ptr1
))
3294 int layer
= GetLayerNumber (PCB
->Data
,
3295 (LayerTypePtr
) ptr1
);
3297 if (ADD_LINE_TO_LIST (layer
, (LineTypePtr
) ptr2
))
3304 int layer
= GetLayerNumber (PCB
->Data
,
3305 (LayerTypePtr
) ptr1
);
3307 if (ADD_ARC_TO_LIST (layer
, (ArcTypePtr
) ptr2
))
3314 int layer
= GetLayerNumber (PCB
->Data
,
3315 (LayerTypePtr
) ptr1
);
3317 if (ADD_POLYGON_TO_LIST (layer
, (PolygonTypePtr
) ptr2
))
3324 PadTypePtr pad
= (PadTypePtr
) ptr2
;
3327 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3336 /* ---------------------------------------------------------------------------
3337 * looks up all connections from the object at the given coordinates
3338 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3339 * the objects are re-drawn if AndDraw is true
3340 * also the action is marked as undoable if AndDraw is true
3343 LookupConnection (LocationType X
, LocationType Y
, bool AndDraw
,
3344 BDimension Range
, int which_flag
)
3346 void *ptr1
, *ptr2
, *ptr3
;
3350 /* check if there are any pins or pads at that position */
3354 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3355 if (type
== NO_TYPE
)
3359 SearchObjectByLocation
3360 (LOOKUP_MORE
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3361 if (type
== NO_TYPE
)
3363 if (type
& SILK_TYPE
)
3365 int laynum
= GetLayerNumber (PCB
->Data
,
3366 (LayerTypePtr
) ptr1
);
3368 /* don't mess with silk objects! */
3369 if (laynum
>= max_layer
)
3375 name
= ConnectionName (type
, ptr1
, ptr2
);
3376 hid_actionl ("NetlistShow", name
, NULL
);
3379 TheFlag
= which_flag
;
3381 InitConnectionLookup ();
3383 /* now add the object to the appropriate list and start scanning
3384 * This is step (1) from the description
3386 ListStart (type
, ptr1
, ptr2
, ptr3
);
3387 DoIt (true, AndDraw
);
3389 IncrementUndoSerialNumber ();
3395 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3397 FreeConnectionLookupMemory ();
3400 /* ---------------------------------------------------------------------------
3401 * find connections for rats nesting
3402 * assumes InitConnectionLookup() has already been done
3406 (int type
, void *ptr1
, void *ptr2
, void *ptr3
, bool undo
,
3411 ListStart (type
, ptr1
, ptr2
, ptr3
);
3412 DoIt (AndRats
, false);
3416 /* ---------------------------------------------------------------------------
3417 * find all unused pins of all element
3420 LookupUnusedPins (FILE * FP
)
3422 /* reset all currently marked connections */
3424 SaveUndoSerialNumber ();
3425 ResetConnections (true);
3426 RestoreUndoSerialNumber ();
3427 InitConnectionLookup ();
3429 ELEMENT_LOOP (PCB
->Data
);
3431 /* break if abort dialog returned true;
3432 * passing NULL as filedescriptor discards the normal output
3434 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
))
3439 if (Settings
.RingBellWhenFinished
)
3441 FreeConnectionLookupMemory ();
3442 IncrementUndoSerialNumber ();
3447 /* ---------------------------------------------------------------------------
3448 * resets all used flags of pins and vias
3451 ResetFoundPinsViasAndPads (bool AndDraw
)
3453 bool change
= false;
3456 VIA_LOOP (PCB
->Data
);
3458 if (TEST_FLAG (TheFlag
, via
))
3461 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3462 CLEAR_FLAG (TheFlag
, via
);
3469 ELEMENT_LOOP (PCB
->Data
);
3473 if (TEST_FLAG (TheFlag
, pin
))
3476 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3477 CLEAR_FLAG (TheFlag
, pin
);
3486 if (TEST_FLAG (TheFlag
, pad
))
3489 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3490 CLEAR_FLAG (TheFlag
, pad
);
3501 SetChangedFlag (true);
3504 IncrementUndoSerialNumber ();
3510 /* ---------------------------------------------------------------------------
3511 * resets all used flags of LOs
3514 ResetFoundLinesAndPolygons (bool AndDraw
)
3516 bool change
= false;
3519 RAT_LOOP (PCB
->Data
);
3521 if (TEST_FLAG (TheFlag
, line
))
3524 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3525 CLEAR_FLAG (TheFlag
, line
);
3532 COPPERLINE_LOOP (PCB
->Data
);
3534 if (TEST_FLAG (TheFlag
, line
))
3537 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3538 CLEAR_FLAG (TheFlag
, line
);
3540 DrawLine (layer
, line
, 0);
3545 COPPERARC_LOOP (PCB
->Data
);
3547 if (TEST_FLAG (TheFlag
, arc
))
3550 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3551 CLEAR_FLAG (TheFlag
, arc
);
3553 DrawArc (layer
, arc
, 0);
3558 COPPERPOLYGON_LOOP (PCB
->Data
);
3560 if (TEST_FLAG (TheFlag
, polygon
))
3563 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3564 CLEAR_FLAG (TheFlag
, polygon
);
3566 DrawPolygon (layer
, polygon
, 0);
3573 SetChangedFlag (true);
3576 IncrementUndoSerialNumber ();
3582 /* ---------------------------------------------------------------------------
3583 * resets all found connections
3586 ResetConnections (bool AndDraw
)
3589 SaveUndoSerialNumber ();
3590 ResetFoundPinsViasAndPads (AndDraw
);
3592 RestoreUndoSerialNumber ();
3593 ResetFoundLinesAndPolygons (AndDraw
);
3596 /*----------------------------------------------------------------------------
3597 * Dumps the list contents
3604 for (i
= 0; i
< 2; i
++)
3606 PadList
[i
].Number
= 0;
3607 PadList
[i
].Location
= 0;
3608 PadList
[i
].DrawLocation
= 0;
3612 PVList
.Location
= 0;
3614 for (i
= 0; i
< max_layer
; i
++)
3616 LineList
[i
].Location
= 0;
3617 LineList
[i
].DrawLocation
= 0;
3618 LineList
[i
].Number
= 0;
3619 ArcList
[i
].Location
= 0;
3620 ArcList
[i
].DrawLocation
= 0;
3621 ArcList
[i
].Number
= 0;
3622 PolygonList
[i
].Location
= 0;
3623 PolygonList
[i
].DrawLocation
= 0;
3624 PolygonList
[i
].Number
= 0;
3627 RatList
.Location
= 0;
3628 RatList
.DrawLocation
= 0;
3631 /*-----------------------------------------------------------------------------
3632 * Check for DRC violations on a single net starting from the pad or pin
3633 * sees if the connectivity changes when everything is bloated, or shrunk
3636 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3640 long int *object_id_list
;
3641 int *object_type_list
;
3642 DrcViolationType
*violation
;
3644 if (PCB
->Shrink
!= 0)
3646 Bloat
= -PCB
->Shrink
;
3647 fBloat
= (float) -PCB
->Shrink
;
3648 TheFlag
= DRCFLAG
| SELECTEDFLAG
;
3649 ListStart (What
, ptr1
, ptr2
, ptr3
);
3651 /* ok now the shrunk net has the SELECTEDFLAG set */
3653 TheFlag
= FOUNDFLAG
;
3654 ListStart (What
, ptr1
, ptr2
, ptr3
);
3657 drc
= true; /* abort the search if we find anything not already found */
3658 if (DoIt (true, false))
3661 /* make the flag changes undoable */
3662 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3663 ResetConnections (false);
3666 Bloat
= -PCB
->Shrink
;
3667 fBloat
= (float) -PCB
->Shrink
;
3668 TheFlag
= SELECTEDFLAG
;
3669 RestoreUndoSerialNumber ();
3670 ListStart (What
, ptr1
, ptr2
, ptr3
);
3673 ListStart (What
, ptr1
, ptr2
, ptr3
);
3674 TheFlag
= FOUNDFLAG
;
3683 LocateError (&x
, &y
);
3684 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3685 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3686 _("Insufficient overlap between objects can lead to broken tracks\n"
3687 "due to registration errors with old wheel style photo-plotters."),
3689 0, /* ANGLE OF ERROR UNKNOWN */
3690 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3691 0, /* MAGNITUDE OF ERROR UNKNOWN */
3692 LENGTH_TO_HUMAN(PCB
->Shrink
),
3694 LENGTH_UNITS_STRING
,
3698 append_drc_violation (violation
);
3699 pcb_drc_violation_free (violation
);
3700 free (object_id_list
);
3701 free (object_type_list
);
3703 if (!throw_drc_dialog())
3705 IncrementUndoSerialNumber ();
3710 /* now check the bloated condition */
3712 ResetConnections (false);
3713 TheFlag
= FOUNDFLAG
;
3714 ListStart (What
, ptr1
, ptr2
, ptr3
);
3716 fBloat
= (float) PCB
->Bloat
;
3718 while (DoIt (true, false))
3721 /* make the flag changes undoable */
3722 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3723 ResetConnections (false);
3728 RestoreUndoSerialNumber ();
3729 TheFlag
= SELECTEDFLAG
;
3730 ListStart (What
, ptr1
, ptr2
, ptr3
);
3733 TheFlag
= FOUNDFLAG
;
3734 ListStart (What
, ptr1
, ptr2
, ptr3
);
3736 fBloat
= (float) PCB
->Bloat
;
3741 LocateError (&x
, &y
);
3742 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3743 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3744 _("Circuits that are too close may bridge during imaging, etching,\n"
3745 "plating, or soldering processes resulting in a direct short."),
3747 0, /* ANGLE OF ERROR UNKNOWN */
3748 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3749 0, /* MAGNITUDE OF ERROR UNKNOWN */
3750 LENGTH_TO_HUMAN(PCB
->Bloat
),
3752 LENGTH_UNITS_STRING
,
3756 append_drc_violation (violation
);
3757 pcb_drc_violation_free (violation
);
3758 free (object_id_list
);
3759 free (object_type_list
);
3762 if (!throw_drc_dialog())
3764 IncrementUndoSerialNumber ();
3766 /* highlight the rest of the encroaching net so it's not reported again */
3767 TheFlag
|= SELECTEDFLAG
;
3770 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
);
3775 fBloat
= (float) PCB
->Bloat
;
3776 ListStart (What
, ptr1
, ptr2
, ptr3
);
3780 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3781 ResetConnections (false);
3785 /*----------------------------------------------------------------------------
3786 * set up a temporary flag to use
3789 SaveFindFlag (int NewFlag
)
3795 /*----------------------------------------------------------------------------
3799 RestoreFindFlag (void)
3804 /* DRC clearance callback */
3807 drc_callback (DataTypePtr data
, LayerTypePtr layer
, PolygonTypePtr polygon
,
3808 int type
, void *ptr1
, void *ptr2
)
3813 long int *object_id_list
;
3814 int *object_type_list
;
3815 DrcViolationType
*violation
;
3817 LineTypePtr line
= (LineTypePtr
) ptr2
;
3818 ArcTypePtr arc
= (ArcTypePtr
) ptr2
;
3819 PinTypePtr pin
= (PinTypePtr
) ptr2
;
3820 PadTypePtr pad
= (PadTypePtr
) ptr2
;
3829 if (line
->Clearance
< 2 * PCB
->Bloat
)
3831 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3832 SET_FLAG (TheFlag
, line
);
3833 message
= _("Line with insufficient clearance inside polygon\n");
3838 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3840 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3841 SET_FLAG (TheFlag
, arc
);
3842 message
= _("Arc with insufficient clearance inside polygon\n");
3847 if (pad
->Clearance
< 2 * PCB
->Bloat
)
3848 if (IsPadInPolygon(pad
,polygon
))
3850 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3851 SET_FLAG (TheFlag
, pad
);
3852 message
= _("Pad with insufficient clearance inside polygon\n");
3857 if (pin
->Clearance
< 2 * PCB
->Bloat
)
3859 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3860 SET_FLAG (TheFlag
, pin
);
3861 message
= _("Pin with insufficient clearance inside polygon\n");
3866 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3868 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3869 SET_FLAG (TheFlag
, pin
);
3870 message
= _("Via with insufficient clearance inside polygon\n");
3875 Message ("hace: Bad Plow object in callback\n");
3880 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3881 SET_FLAG (FOUNDFLAG
, polygon
);
3882 DrawPolygon (layer
, polygon
, 0);
3883 DrawObject (type
, ptr1
, ptr2
, 0);
3885 LocateError (&x
, &y
);
3886 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3887 violation
= pcb_drc_violation_new (message
,
3888 _("Circuits that are too close may bridge during imaging, etching,\n"
3889 "plating, or soldering processes resulting in a direct short."),
3891 0, /* ANGLE OF ERROR UNKNOWN */
3892 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3893 0, /* MAGNITUDE OF ERROR UNKNOWN */
3894 LENGTH_TO_HUMAN(PCB
->Bloat
),
3896 LENGTH_UNITS_STRING
,
3900 append_drc_violation (violation
);
3901 pcb_drc_violation_free (violation
);
3902 free (object_id_list
);
3903 free (object_type_list
);
3904 if (!throw_drc_dialog())
3909 IncrementUndoSerialNumber ();
3914 /*-----------------------------------------------------------------------------
3915 * Check for DRC violations
3916 * see if the connectivity changes when everything is bloated, or shrunk
3923 long int *object_id_list
;
3924 int *object_type_list
;
3925 DrcViolationType
*violation
;
3929 reset_drc_dialog_message();
3933 SaveStackAndVisibility ();
3934 ResetStackAndVisibility ();
3935 hid_action ("LayersChanged");
3936 InitConnectionLookup ();
3938 TheFlag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3940 ResetConnections (true);
3944 ELEMENT_LOOP (PCB
->Data
);
3948 if (!TEST_FLAG (DRCFLAG
, pin
)
3949 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3961 /* count up how many pads have no solderpaste openings */
3962 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3965 if (!TEST_FLAG (DRCFLAG
, pad
)
3966 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3978 VIA_LOOP (PCB
->Data
);
3980 if (!TEST_FLAG (DRCFLAG
, via
)
3981 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3989 TheFlag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3990 ResetConnections (false);
3991 TheFlag
= SELECTEDFLAG
;
3992 /* check minimum widths and polygon clearances */
3995 COPPERLINE_LOOP (PCB
->Data
);
3997 /* check line clearances in polygons */
3998 PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
);
4001 if (line
->Thickness
< PCB
->minWid
)
4003 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
4004 SET_FLAG (TheFlag
, line
);
4005 DrawLine (layer
, line
, 0);
4007 SetThing (LINE_TYPE
, layer
, line
, line
);
4008 LocateError (&x
, &y
);
4009 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4010 violation
= pcb_drc_violation_new (_("Line width is too thin"),
4011 _("Process specifications dictate a minimum feature-width\n"
4012 "that can reliably be reproduced"),
4014 0, /* ANGLE OF ERROR UNKNOWN */
4015 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4016 LENGTH_TO_HUMAN(line
->Thickness
),
4017 LENGTH_TO_HUMAN(PCB
->minWid
),
4019 LENGTH_UNITS_STRING
,
4023 append_drc_violation (violation
);
4024 pcb_drc_violation_free (violation
);
4025 free (object_id_list
);
4026 free (object_type_list
);
4027 if (!throw_drc_dialog())
4032 IncrementUndoSerialNumber ();
4040 COPPERARC_LOOP (PCB
->Data
);
4042 PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
);
4045 if (arc
->Thickness
< PCB
->minWid
)
4047 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
4048 SET_FLAG (TheFlag
, arc
);
4049 DrawArc (layer
, arc
, 0);
4051 SetThing (ARC_TYPE
, layer
, arc
, arc
);
4052 LocateError (&x
, &y
);
4053 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4054 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
4055 _("Process specifications dictate a minimum feature-width\n"
4056 "that can reliably be reproduced"),
4058 0, /* ANGLE OF ERROR UNKNOWN */
4059 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4060 LENGTH_TO_HUMAN(arc
->Thickness
),
4061 LENGTH_TO_HUMAN(PCB
->minWid
),
4063 LENGTH_UNITS_STRING
,
4067 append_drc_violation (violation
);
4068 pcb_drc_violation_free (violation
);
4069 free (object_id_list
);
4070 free (object_type_list
);
4071 if (!throw_drc_dialog())
4076 IncrementUndoSerialNumber ();
4084 ALLPIN_LOOP (PCB
->Data
);
4086 PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
);
4089 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
4090 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
4092 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
4093 SET_FLAG (TheFlag
, pin
);
4096 SetThing (PIN_TYPE
, element
, pin
, pin
);
4097 LocateError (&x
, &y
);
4098 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4099 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
4100 _("Annular rings that are too small may erode during etching,\n"
4101 "resulting in a broken connection"),
4103 0, /* ANGLE OF ERROR UNKNOWN */
4104 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4105 LENGTH_TO_HUMAN((pin
->Thickness
- pin
->DrillingHole
) / 2),
4106 LENGTH_TO_HUMAN(PCB
->minRing
),
4108 LENGTH_UNITS_STRING
,
4112 append_drc_violation (violation
);
4113 pcb_drc_violation_free (violation
);
4114 free (object_id_list
);
4115 free (object_type_list
);
4116 if (!throw_drc_dialog())
4121 IncrementUndoSerialNumber ();
4124 if (pin
->DrillingHole
< PCB
->minDrill
)
4126 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
4127 SET_FLAG (TheFlag
, pin
);
4130 SetThing (PIN_TYPE
, element
, pin
, pin
);
4131 LocateError (&x
, &y
);
4132 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4133 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
4134 _("Process rules dictate the minimum drill size which can be used"),
4136 0, /* ANGLE OF ERROR UNKNOWN */
4137 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4138 LENGTH_TO_HUMAN(pin
->DrillingHole
),
4139 LENGTH_TO_HUMAN(PCB
->minDrill
),
4141 LENGTH_UNITS_STRING
,
4145 append_drc_violation (violation
);
4146 pcb_drc_violation_free (violation
);
4147 free (object_id_list
);
4148 free (object_type_list
);
4149 if (!throw_drc_dialog())
4154 IncrementUndoSerialNumber ();
4162 ALLPAD_LOOP (PCB
->Data
);
4164 PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
);
4167 if (pad
->Thickness
< PCB
->minWid
)
4169 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
4170 SET_FLAG (TheFlag
, pad
);
4173 SetThing (PAD_TYPE
, element
, pad
, pad
);
4174 LocateError (&x
, &y
);
4175 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4176 violation
= pcb_drc_violation_new (_("Pad is too thin"),
4177 _("Pads which are too thin may erode during etching,\n"
4178 "resulting in a broken or unreliable connection"),
4180 0, /* ANGLE OF ERROR UNKNOWN */
4181 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4182 LENGTH_TO_HUMAN(pad
->Thickness
),
4183 LENGTH_TO_HUMAN(PCB
->minWid
),
4185 LENGTH_UNITS_STRING
,
4189 append_drc_violation (violation
);
4190 pcb_drc_violation_free (violation
);
4191 free (object_id_list
);
4192 free (object_type_list
);
4193 if (!throw_drc_dialog())
4198 IncrementUndoSerialNumber ();
4206 VIA_LOOP (PCB
->Data
);
4208 PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
);
4211 if (!TEST_FLAG (HOLEFLAG
, via
) &&
4212 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
4214 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
4215 SET_FLAG (TheFlag
, via
);
4218 SetThing (VIA_TYPE
, via
, via
, via
);
4219 LocateError (&x
, &y
);
4220 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4221 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
4222 _("Annular rings that are too small may erode during etching,\n"
4223 "resulting in a broken connection"),
4225 0, /* ANGLE OF ERROR UNKNOWN */
4226 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4227 LENGTH_TO_HUMAN((via
->Thickness
- via
->DrillingHole
) / 2),
4228 LENGTH_TO_HUMAN(PCB
->minRing
),
4230 LENGTH_UNITS_STRING
,
4234 append_drc_violation (violation
);
4235 pcb_drc_violation_free (violation
);
4236 free (object_id_list
);
4237 free (object_type_list
);
4238 if (!throw_drc_dialog())
4243 IncrementUndoSerialNumber ();
4246 if (via
->DrillingHole
< PCB
->minDrill
)
4248 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
4249 SET_FLAG (TheFlag
, via
);
4252 SetThing (VIA_TYPE
, via
, via
, via
);
4253 LocateError (&x
, &y
);
4254 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4255 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
4256 _("Process rules dictate the minimum drill size which can be used"),
4258 0, /* ANGLE OF ERROR UNKNOWN */
4259 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4260 LENGTH_TO_HUMAN(via
->DrillingHole
),
4261 LENGTH_TO_HUMAN(PCB
->minDrill
),
4263 LENGTH_UNITS_STRING
,
4267 append_drc_violation (violation
);
4268 pcb_drc_violation_free (violation
);
4269 free (object_id_list
);
4270 free (object_type_list
);
4271 if (!throw_drc_dialog())
4276 IncrementUndoSerialNumber ();
4283 FreeConnectionLookupMemory ();
4284 TheFlag
= FOUNDFLAG
;
4288 /* check silkscreen minimum widths outside of elements */
4289 /* XXX - need to check text and polygons too! */
4290 TheFlag
= SELECTEDFLAG
;
4293 SILKLINE_LOOP (PCB
->Data
);
4295 if (line
->Thickness
< PCB
->minSlk
)
4297 SET_FLAG (TheFlag
, line
);
4298 DrawLine (layer
, line
, 0);
4300 SetThing (LINE_TYPE
, layer
, line
, line
);
4301 LocateError (&x
, &y
);
4302 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4303 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
4304 _("Process specifications dictate a minimum silkscreen feature-width\n"
4305 "that can reliably be reproduced"),
4307 0, /* ANGLE OF ERROR UNKNOWN */
4308 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4309 LENGTH_TO_HUMAN(line
->Thickness
),
4310 LENGTH_TO_HUMAN(PCB
->minSlk
),
4312 LENGTH_UNITS_STRING
,
4316 append_drc_violation (violation
);
4317 pcb_drc_violation_free (violation
);
4318 free (object_id_list
);
4319 free (object_type_list
);
4320 if (!throw_drc_dialog())
4330 /* check silkscreen minimum widths inside of elements */
4331 /* XXX - need to check text and polygons too! */
4332 TheFlag
= SELECTEDFLAG
;
4335 ELEMENT_LOOP (PCB
->Data
);
4338 ELEMENTLINE_LOOP (element
);
4340 if (line
->Thickness
< PCB
->minSlk
)
4351 SET_FLAG (TheFlag
, element
);
4352 DrawElement (element
, 0);
4354 SetThing (ELEMENT_TYPE
, element
, element
, element
);
4355 LocateError (&x
, &y
);
4356 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4358 title
= _("Element %s has %i silk lines which are too thin");
4359 name
= UNKNOWN (NAMEONPCB_NAME (element
));
4361 /* -4 is for the %s and %i place-holders */
4362 /* +11 is the max printed length for a 32 bit integer */
4363 /* +1 is for the \0 termination */
4364 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
4365 buffer
= malloc (buflen
);
4366 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
4368 violation
= pcb_drc_violation_new (buffer
,
4369 _("Process specifications dictate a minimum silkscreen\n"
4370 "feature-width that can reliably be reproduced"),
4372 0, /* ANGLE OF ERROR UNKNOWN */
4373 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4374 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4375 LENGTH_TO_HUMAN(PCB
->minSlk
),
4377 LENGTH_UNITS_STRING
,
4382 append_drc_violation (violation
);
4383 pcb_drc_violation_free (violation
);
4384 free (object_id_list
);
4385 free (object_type_list
);
4386 if (!throw_drc_dialog())
4399 IncrementUndoSerialNumber ();
4403 RestoreStackAndVisibility ();
4404 hid_action ("LayersChanged");
4405 gui
->invalidate_all ();
4409 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4411 nopastecnt
> 1 ? "s have" : " has");
4413 return IsBad
? -drcerr_count
: drcerr_count
;
4416 /*----------------------------------------------------------------------------
4417 * Locate the coordinatates of offending item (thing)
4420 LocateError (LocationType
*x
, LocationType
*y
)
4426 LineTypePtr line
= (LineTypePtr
) thing_ptr3
;
4427 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4428 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4433 ArcTypePtr arc
= (ArcTypePtr
) thing_ptr3
;
4440 PolygonTypePtr polygon
= (PolygonTypePtr
) thing_ptr3
;
4442 (polygon
->Clipped
->contours
->xmin
+
4443 polygon
->Clipped
->contours
->xmax
) / 2;
4445 (polygon
->Clipped
->contours
->ymin
+
4446 polygon
->Clipped
->contours
->ymax
) / 2;
4452 PinTypePtr pin
= (PinTypePtr
) thing_ptr3
;
4459 PadTypePtr pad
= (PadTypePtr
) thing_ptr3
;
4460 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4461 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4466 ElementTypePtr element
= (ElementTypePtr
) thing_ptr3
;
4467 *x
= element
->MarkX
;
4468 *y
= element
->MarkY
;
4477 /*----------------------------------------------------------------------------
4478 * Build a list of the of offending items by ID. (Currently just "thing")
4481 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4484 *object_id_list
= NULL
;
4496 *object_id_list
= malloc (sizeof (long int));
4497 *object_type_list
= malloc (sizeof (int));
4498 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4499 **object_type_list
= thing_type
;
4508 /*----------------------------------------------------------------------------
4509 * center the display to show the offending item (thing)
4516 LocateError (&X
, &Y
);
4523 ChangeGroupVisibility (GetLayerNumber
4524 (PCB
->Data
, (LayerTypePtr
) thing_ptr1
), true,
4527 CenterDisplay (X
, Y
, false);
4531 InitConnectionLookup (void)
4533 InitComponentLookup ();
4534 InitLayoutLookup ();
4538 FreeConnectionLookupMemory (void)
4540 FreeComponentLookupMemory ();
4541 FreeLayoutLookupMemory ();