5 * PCB, interactive printed circuit board design
6 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Contact addresses for paper mail and Email:
23 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
24 * Thomas.Nau@rz.uni-ulm.de
31 * - lists for pins and vias, lines, arcs, pads and for polygons are created.
32 * Every object that has to be checked is added to its list.
33 * Coarse searching is accomplished with the data rtrees.
34 * - there's no 'speed-up' mechanism for polygons because they are not used
35 * as often as other objects
36 * - the maximum distance between line and pin ... would depend on the angle
37 * between them. To speed up computation the limit is set to one half
38 * of the thickness of the objects (cause of square pins).
40 * PV: means pin or via (objects that connect layers)
41 * LO: all non PV objects (layer objects like lines, arcs, polygons, pads)
43 * 1. first, the LO or PV at the given coordinates is looked up
44 * 2. all LO connections to that PV are looked up next
45 * 3. lookup of all LOs connected to LOs from (2).
46 * This step is repeated until no more new connections are found.
47 * 4. lookup all PVs connected to the LOs from (2) and (3)
48 * 5. start again with (1) for all new PVs from (4)
50 * Intersection of line <--> circle:
51 * - calculate the signed distance from the line to the center,
52 * return false if abs(distance) > R
53 * - get the distance from the line <--> distancevector intersection to
54 * (X1,Y1) in range [0,1], return true if 0 <= distance <= 1
55 * - depending on (r > 1.0 or r < 0.0) check the distance of X2,Y2 or X1,Y1
58 * Intersection of line <--> line:
59 * - see the description of 'LineLineIntersect()'
62 /* routines to find connections between pins, vias, lines...
76 #ifdef HAVE_SYS_TIMES_H
77 #include <sys/times.h>
82 #include "crosshair.h"
91 #include "pcb-printf.h"
97 #ifdef HAVE_LIBDMALLOC
103 /* ---------------------------------------------------------------------------
107 #define EXPAND_BOUNDS(p) if (Bloat > 0) {\
108 (p)->BoundingBox.X1 -= Bloat; \
109 (p)->BoundingBox.X2 += Bloat; \
110 (p)->BoundingBox.Y1 -= Bloat; \
111 (p)->BoundingBox.Y2 += Bloat;}
113 #define SEPARATE(FP) \
117 for (i = Settings.CharPerLine; i; i--) \
122 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
123 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
124 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
125 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
126 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
127 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
128 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
130 #define IS_PV_ON_RAT(PV, Rat) \
131 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
133 #define IS_PV_ON_ARC(PV, Arc) \
134 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
136 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
137 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
139 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
141 #define IS_PV_ON_PAD(PV,Pad) \
142 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
144 static DrcViolationType
145 *pcb_drc_violation_new (const char *title
,
146 const char *explanation
,
150 Coord measured_value
,
151 Coord required_value
,
153 long int *object_id_list
,
154 int *object_type_list
)
156 DrcViolationType
*violation
= (DrcViolationType
*)malloc (sizeof (DrcViolationType
));
158 violation
->title
= strdup (title
);
159 violation
->explanation
= strdup (explanation
);
162 violation
->angle
= angle
;
163 violation
->have_measured
= have_measured
;
164 violation
->measured_value
= measured_value
;
165 violation
->required_value
= required_value
;
166 violation
->object_count
= object_count
;
167 violation
->object_id_list
= object_id_list
;
168 violation
->object_type_list
= object_type_list
;
174 pcb_drc_violation_free (DrcViolationType
*violation
)
176 free (violation
->title
);
177 free (violation
->explanation
);
181 static GString
*drc_dialog_message
;
183 reset_drc_dialog_message(void)
185 if (drc_dialog_message
)
186 g_string_free (drc_dialog_message
, FALSE
);
187 drc_dialog_message
= g_string_new ("");
188 if (gui
->drc_gui
!= NULL
)
190 gui
->drc_gui
->reset_drc_dialog_message ();
194 append_drc_dialog_message(const char *fmt
, ...)
199 new_str
= pcb_vprintf (fmt
, ap
);
200 g_string_append (drc_dialog_message
, new_str
);
205 static void GotoError (void);
208 append_drc_violation (DrcViolationType
*violation
)
210 if (gui
->drc_gui
!= NULL
)
212 gui
->drc_gui
->append_drc_violation (violation
);
216 /* Fallback to formatting the violation message as text */
217 append_drc_dialog_message ("%s\n", violation
->title
);
218 append_drc_dialog_message (_("%m+near %$mD\n"),
219 Settings
.grid_unit
->allow
,
220 violation
->x
, violation
->y
);
224 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
226 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
227 Message (_("%m+near location %$mD\n"),
228 Settings
.grid_unit
->allow
,
229 violation
->x
, violation
->y
);
233 * message when asked about continuing DRC checks after next
234 * violation is found.
236 #define DRC_CONTINUE _("Press Next to continue DRC checking")
237 #define DRC_NEXT _("Next")
238 #define DRC_CANCEL _("Cancel")
241 throw_drc_dialog(void)
245 if (gui
->drc_gui
!= NULL
)
247 r
= gui
->drc_gui
->throw_drc_dialog ();
251 /* Fallback to formatting the violation message as text */
252 append_drc_dialog_message (DRC_CONTINUE
);
253 r
= gui
->confirm_dialog (drc_dialog_message
->str
, DRC_CANCEL
, DRC_NEXT
);
254 reset_drc_dialog_message();
259 /* ---------------------------------------------------------------------------
262 * the two 'dummy' structs for PVs and Pads are necessary for creating
263 * connection lists which include the element's name
267 void **Data
; /* pointer to index data */
268 Cardinal Location
, /* currently used position */
269 DrawLocation
, Number
, /* number of objects in list */
273 /* ---------------------------------------------------------------------------
274 * some local identifiers
276 static Coord Bloat
= 0;
277 static int TheFlag
= FOUNDFLAG
;
278 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
279 static int thing_type
;
280 static bool User
= false; /* user action causing this */
281 static bool drc
= false; /* whether to stop if finding something not found */
282 static bool IsBad
= false;
283 static Cardinal drcerr_count
; /* count of drc errors */
284 static Cardinal TotalP
, TotalV
, NumberOfPads
[2];
285 static ListType LineList
[MAX_LAYER
], /* list of objects to */
286 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
288 /* ---------------------------------------------------------------------------
289 * some local prototypes
291 static bool LookupLOConnectionsToPVList (bool);
292 static bool LookupLOConnectionsToLOList (bool);
293 static bool LookupPVConnectionsToLOList (bool);
294 static bool LookupPVConnectionsToPVList (void);
295 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, bool);
296 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
);
297 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
);
298 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
);
299 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
);
300 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
301 static bool ArcArcIntersect (ArcType
*, ArcType
*);
302 static bool PrepareNextLoop (FILE *);
303 static bool PrintElementConnections (ElementType
*, FILE *, bool);
304 static bool ListsEmpty (bool);
305 static bool DoIt (bool, bool);
306 static void PrintElementNameList (ElementType
*, FILE *);
307 static void PrintConnectionElementName (ElementType
*, FILE *);
308 static void PrintConnectionListEntry (char *, ElementType
*,
310 static void PrintPadConnections (Cardinal
, FILE *, bool);
311 static void PrintPinConnections (FILE *, bool);
312 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*,
314 static void DrawNewConnections (void);
315 static void DumpList (void);
316 static void LocateError (Coord
*, Coord
*);
317 static void BuildObjectList (int *, long int **, int **);
318 static void GotoError (void);
319 static bool DRCFind (int, void *, void *, void *);
320 static bool ListStart (int, void *, void *, void *);
321 static bool SetThing (int, void *, void *, void *);
322 static bool IsArcInPolygon (ArcType
*, PolygonType
*);
323 static bool IsLineInPolygon (LineType
*, PolygonType
*);
324 static bool IsPadInPolygon (PadType
*, PolygonType
*);
325 static bool IsPolygonInPolygon (PolygonType
*, PolygonType
*);
327 /* ---------------------------------------------------------------------------
328 * some of the 'pad' routines are the same as for lines because the 'pad'
329 * struct starts with a line struct. See global.h for details
332 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
334 return LineLineIntersect ((Line
), (LineType
*)Pad
);
338 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
340 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
344 add_object_to_list (ListType
*list
, int type
, void *ptr1
, void *ptr2
, void *ptr3
)
346 AnyObjectType
*object
= (AnyObjectType
*)ptr2
;
349 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
351 SET_FLAG (TheFlag
, object
);
352 LIST_ENTRY (list
, list
->Number
) = object
;
356 if (list
.Number
> list
.Size
)
357 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type
, list
.Number
, list
.Size
);
360 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, object
))
361 return (SetThing (type
, ptr1
, ptr2
, ptr3
));
366 ADD_PV_TO_LIST (PinType
*Pin
)
368 return add_object_to_list (&PVList
, Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
369 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
);
373 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
)
375 return add_object_to_list (&PadList
[L
], PAD_TYPE
, Pad
->Element
, Pad
, Pad
);
379 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
)
381 return add_object_to_list (&LineList
[L
], LINE_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
385 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
)
387 return add_object_to_list (&ArcList
[L
], ARC_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
391 ADD_RAT_TO_LIST (RatType
*Ptr
)
393 return add_object_to_list (&RatList
, RATLINE_TYPE
, Ptr
, Ptr
, Ptr
);
397 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
)
399 return add_object_to_list (&PolygonList
[L
], POLYGON_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
);
403 PinLineIntersect (PinType
*PV
, LineType
*Line
)
405 /* IsLineInRectangle already has Bloat factor */
406 return TEST_FLAG (SQUAREFLAG
,
407 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
408 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
409 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
410 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
411 Line
) : IsPointInPad (PV
->X
,
423 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
429 if (type
== PIN_TYPE
&& ptr1
== NULL
)
432 thing_type
= VIA_TYPE
;
438 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
440 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
442 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
448 PadPadIntersect (PadType
*p1
, PadType
*p2
)
450 return LinePadIntersect ((LineType
*) p1
, p2
);
454 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
459 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
460 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
461 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
462 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
464 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
466 /* check for square/square overlap */
471 t2
= PV2
->Thickness
/ 2.0;
476 return BoxBoxIntersection (&b1
, &b2
);
479 /* ---------------------------------------------------------------------------
480 * releases all allocated memory
483 FreeLayoutLookupMemory (void)
487 for (i
= 0; i
< max_copper_layer
; i
++)
489 free (LineList
[i
].Data
);
490 LineList
[i
].Data
= NULL
;
491 free (ArcList
[i
].Data
);
492 ArcList
[i
].Data
= NULL
;
493 free (PolygonList
[i
].Data
);
494 PolygonList
[i
].Data
= NULL
;
503 FreeComponentLookupMemory (void)
505 free (PadList
[0].Data
);
506 PadList
[0].Data
= NULL
;
507 free (PadList
[1].Data
);
508 PadList
[1].Data
= NULL
;
511 /* ---------------------------------------------------------------------------
512 * allocates memory for component related stacks ...
513 * initializes index and sorts it by X1 and X2
516 InitComponentLookup (void)
520 /* initialize pad data; start by counting the total number
521 * on each of the two possible layers
523 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
524 ALLPAD_LOOP (PCB
->Data
);
526 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
527 NumberOfPads
[SOLDER_LAYER
]++;
529 NumberOfPads
[COMPONENT_LAYER
]++;
532 for (i
= 0; i
< 2; i
++)
534 /* allocate memory for working list */
535 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
537 /* clear some struct members */
538 PadList
[i
].Location
= 0;
539 PadList
[i
].DrawLocation
= 0;
540 PadList
[i
].Number
= 0;
541 PadList
[i
].Size
= NumberOfPads
[i
];
545 /* ---------------------------------------------------------------------------
546 * allocates memory for component related stacks ...
547 * initializes index and sorts it by X1 and X2
550 InitLayoutLookup (void)
554 /* initialize line arc and polygon data */
555 for (i
= 0; i
< max_copper_layer
; i
++)
557 LayerType
*layer
= LAYER_PTR (i
);
561 /* allocate memory for line pointer lists */
562 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
563 LineList
[i
].Size
= layer
->LineN
;
567 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
568 ArcList
[i
].Size
= layer
->ArcN
;
572 /* allocate memory for polygon list */
575 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
576 PolygonList
[i
].Size
= layer
->PolygonN
;
579 /* clear some struct members */
580 LineList
[i
].Location
= 0;
581 LineList
[i
].DrawLocation
= 0;
582 LineList
[i
].Number
= 0;
583 ArcList
[i
].Location
= 0;
584 ArcList
[i
].DrawLocation
= 0;
585 ArcList
[i
].Number
= 0;
586 PolygonList
[i
].Location
= 0;
587 PolygonList
[i
].DrawLocation
= 0;
588 PolygonList
[i
].Number
= 0;
591 if (PCB
->Data
->pin_tree
)
592 TotalP
= PCB
->Data
->pin_tree
->size
;
595 if (PCB
->Data
->via_tree
)
596 TotalV
= PCB
->Data
->via_tree
->size
;
599 /* allocate memory for 'new PV to check' list and clear struct */
600 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
601 PVList
.Size
= TotalP
+ TotalV
;
603 PVList
.DrawLocation
= 0;
605 /* Initialize ratline data */
606 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
607 RatList
.Size
= PCB
->Data
->RatN
;
608 RatList
.Location
= 0;
609 RatList
.DrawLocation
= 0;
621 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
623 LineType
*line
= (LineType
*) b
;
624 struct pv_info
*i
= (struct pv_info
*) cl
;
626 if (!TEST_FLAG (TheFlag
, line
) && PinLineIntersect (&i
->pv
, line
) &&
627 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
629 if (ADD_LINE_TO_LIST (i
->layer
, line
))
636 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
638 ArcType
*arc
= (ArcType
*) b
;
639 struct pv_info
*i
= (struct pv_info
*) cl
;
641 if (!TEST_FLAG (TheFlag
, arc
) && IS_PV_ON_ARC (&i
->pv
, arc
) &&
642 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
644 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
651 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
653 PadType
*pad
= (PadType
*) b
;
654 struct pv_info
*i
= (struct pv_info
*) cl
;
656 if (!TEST_FLAG (TheFlag
, pad
) && IS_PV_ON_PAD (&i
->pv
, pad
) &&
657 !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
658 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
659 COMPONENT_LAYER
, pad
))
665 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
667 RatType
*rat
= (RatType
*) b
;
668 struct pv_info
*i
= (struct pv_info
*) cl
;
670 if (!TEST_FLAG (TheFlag
, rat
) && IS_PV_ON_RAT (&i
->pv
, rat
) &&
671 ADD_RAT_TO_LIST (rat
))
676 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
678 PolygonType
*polygon
= (PolygonType
*) b
;
679 struct pv_info
*i
= (struct pv_info
*) cl
;
681 /* if the pin doesn't have a therm and polygon is clearing
682 * then it can't touch due to clearance, so skip the expensive
683 * test. If it does have a therm, you still need to test
684 * because it might not be inside the polygon, or it could
685 * be on an edge such that it doesn't actually touch.
687 if (!TEST_FLAG (TheFlag
, polygon
) && !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
688 (TEST_THERM (i
->layer
, &i
->pv
) ||
689 !TEST_FLAG (CLEARPOLYFLAG
,
691 || !i
->pv
.Clearance
))
693 double wide
= MAX (0.5 * i
->pv
.Thickness
+ Bloat
, 0);
694 if (TEST_FLAG (SQUAREFLAG
, &i
->pv
))
696 Coord x1
= i
->pv
.X
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
697 Coord x2
= i
->pv
.X
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
698 Coord y1
= i
->pv
.Y
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
699 Coord y2
= i
->pv
.Y
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
700 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
701 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
704 else if (TEST_FLAG (OCTAGONFLAG
, &i
->pv
))
706 POLYAREA
*oct
= OctagonPoly (i
->pv
.X
, i
->pv
.Y
, i
->pv
.Thickness
/ 2);
707 if (isects (oct
, polygon
, true)
708 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
711 else if (IsPointInPolygon (i
->pv
.X
, i
->pv
.Y
, wide
,
713 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
719 /* ---------------------------------------------------------------------------
720 * checks if a PV is connected to LOs, if it is, the LO is added to
721 * the appropriate list and the 'used' flag is set
724 LookupLOConnectionsToPVList (bool AndRats
)
729 /* loop over all PVs currently on list */
730 while (PVList
.Location
< PVList
.Number
)
732 /* get pointer to data */
733 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
734 EXPAND_BOUNDS (&info
.pv
);
737 if (setjmp (info
.env
) == 0)
738 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pv
, NULL
,
739 LOCtoPVpad_callback
, &info
);
743 /* now all lines, arcs and polygons of the several layers */
744 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
746 LayerType
*layer
= LAYER_PTR (layer_no
);
751 info
.layer
= layer_no
;
752 /* add touching lines */
753 if (setjmp (info
.env
) == 0)
754 r_search (layer
->line_tree
, (BoxType
*) & info
.pv
,
755 NULL
, LOCtoPVline_callback
, &info
);
758 /* add touching arcs */
759 if (setjmp (info
.env
) == 0)
760 r_search (layer
->arc_tree
, (BoxType
*) & info
.pv
,
761 NULL
, LOCtoPVarc_callback
, &info
);
764 /* check all polygons */
765 if (setjmp (info
.env
) == 0)
766 r_search (layer
->polygon_tree
, (BoxType
*) & info
.pv
,
767 NULL
, LOCtoPVpoly_callback
, &info
);
771 /* Check for rat-lines that may intersect the PV */
774 if (setjmp (info
.env
) == 0)
775 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.pv
, NULL
,
776 LOCtoPVrat_callback
, &info
);
785 /* ---------------------------------------------------------------------------
786 * find all connections between LO at the current list position and new LOs
789 LookupLOConnectionsToLOList (bool AndRats
)
792 Cardinal i
, group
, layer
, ratposition
,
793 lineposition
[MAX_LAYER
],
794 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
796 /* copy the current LO list positions; the original data is changed
797 * by 'LookupPVConnectionsToLOList()' which has to check the same
798 * list entries plus the new ones
800 for (i
= 0; i
< max_copper_layer
; i
++)
802 lineposition
[i
] = LineList
[i
].Location
;
803 polyposition
[i
] = PolygonList
[i
].Location
;
804 arcposition
[i
] = ArcList
[i
].Location
;
806 for (i
= 0; i
< 2; i
++)
807 padposition
[i
] = PadList
[i
].Location
;
808 ratposition
= RatList
.Location
;
810 /* loop over all new LOs in the list; recurse until no
811 * more new connections in the layergroup were found
819 position
= &ratposition
;
820 for (; *position
< RatList
.Number
; (*position
)++)
822 group
= RATLIST_ENTRY (*position
)->group1
;
823 if (LookupLOConnectionsToRatEnd
824 (&(RATLIST_ENTRY (*position
)->Point1
), group
))
826 group
= RATLIST_ENTRY (*position
)->group2
;
827 if (LookupLOConnectionsToRatEnd
828 (&(RATLIST_ENTRY (*position
)->Point2
), group
))
832 /* loop over all layergroups */
833 for (group
= 0; group
< max_group
; group
++)
837 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
839 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
841 /* be aware that the layer number equal max_copper_layer
842 * and max_copper_layer+1 have a special meaning for pads
844 if (layer
< max_copper_layer
)
846 /* try all new lines */
847 position
= &lineposition
[layer
];
848 for (; *position
< LineList
[layer
].Number
; (*position
)++)
849 if (LookupLOConnectionsToLine
850 (LINELIST_ENTRY (layer
, *position
), group
, true))
853 /* try all new arcs */
854 position
= &arcposition
[layer
];
855 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
856 if (LookupLOConnectionsToArc
857 (ARCLIST_ENTRY (layer
, *position
), group
))
860 /* try all new polygons */
861 position
= &polyposition
[layer
];
862 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
863 if (LookupLOConnectionsToPolygon
864 (POLYGONLIST_ENTRY (layer
, *position
), group
))
869 /* try all new pads */
870 layer
-= max_copper_layer
;
873 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
874 layer
, max_copper_layer
);
877 position
= &padposition
[layer
];
878 for (; *position
< PadList
[layer
].Number
; (*position
)++)
879 if (LookupLOConnectionsToPad
880 (PADLIST_ENTRY (layer
, *position
), group
))
886 /* check if all lists are done; Later for-loops
887 * may have changed the prior lists
889 done
= !AndRats
|| ratposition
>= RatList
.Number
;
890 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
891 padposition
[1] >= PadList
[1].Number
;
892 for (layer
= 0; layer
< max_copper_layer
; layer
++)
894 lineposition
[layer
] >= LineList
[layer
].Number
&&
895 arcposition
[layer
] >= ArcList
[layer
].Number
&&
896 polyposition
[layer
] >= PolygonList
[layer
].Number
;
903 pv_pv_callback (const BoxType
* b
, void *cl
)
905 PinType
*pin
= (PinType
*) b
;
906 struct pv_info
*i
= (struct pv_info
*) cl
;
908 if (!TEST_FLAG (TheFlag
, pin
) && PV_TOUCH_PV (&i
->pv
, pin
))
910 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, &i
->pv
))
912 SET_FLAG (WARNFLAG
, pin
);
913 Settings
.RatWarn
= true;
915 Message (_("WARNING: Hole too close to pin.\n"));
917 Message (_("WARNING: Hole too close to via.\n"));
919 else if (ADD_PV_TO_LIST (pin
))
925 /* ---------------------------------------------------------------------------
926 * searches for new PVs that are connected to PVs on the list
929 LookupPVConnectionsToPVList (void)
935 /* loop over all PVs on list */
936 save_place
= PVList
.Location
;
937 while (PVList
.Location
< PVList
.Number
)
939 /* get pointer to data */
940 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
941 EXPAND_BOUNDS (&info
.pv
);
942 if (setjmp (info
.env
) == 0)
943 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pv
, NULL
,
944 pv_pv_callback
, &info
);
947 if (setjmp (info
.env
) == 0)
948 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pv
, NULL
,
949 pv_pv_callback
, &info
);
954 PVList
.Location
= save_place
;
970 pv_line_callback (const BoxType
* b
, void *cl
)
972 PinType
*pv
= (PinType
*) b
;
973 struct lo_info
*i
= (struct lo_info
*) cl
;
975 if (!TEST_FLAG (TheFlag
, pv
) && PinLineIntersect (pv
, &i
->line
))
977 if (TEST_FLAG (HOLEFLAG
, pv
))
979 SET_FLAG (WARNFLAG
, pv
);
980 Settings
.RatWarn
= true;
981 Message (_("WARNING: Hole too close to line.\n"));
983 else if (ADD_PV_TO_LIST (pv
))
990 pv_pad_callback (const BoxType
* b
, void *cl
)
992 PinType
*pv
= (PinType
*) b
;
993 struct lo_info
*i
= (struct lo_info
*) cl
;
995 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_PAD (pv
, &i
->pad
))
997 if (TEST_FLAG (HOLEFLAG
, pv
))
999 SET_FLAG (WARNFLAG
, pv
);
1000 Settings
.RatWarn
= true;
1001 Message (_("WARNING: Hole too close to pad.\n"));
1003 else if (ADD_PV_TO_LIST (pv
))
1004 longjmp (i
->env
, 1);
1010 pv_arc_callback (const BoxType
* b
, void *cl
)
1012 PinType
*pv
= (PinType
*) b
;
1013 struct lo_info
*i
= (struct lo_info
*) cl
;
1015 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_ARC (pv
, &i
->arc
))
1017 if (TEST_FLAG (HOLEFLAG
, pv
))
1019 SET_FLAG (WARNFLAG
, pv
);
1020 Settings
.RatWarn
= true;
1021 Message (_("WARNING: Hole touches arc.\n"));
1023 else if (ADD_PV_TO_LIST (pv
))
1024 longjmp (i
->env
, 1);
1030 pv_poly_callback (const BoxType
* b
, void *cl
)
1032 PinType
*pv
= (PinType
*) b
;
1033 struct lo_info
*i
= (struct lo_info
*) cl
;
1035 /* note that holes in polygons are ok, so they don't generate warnings. */
1036 if (!TEST_FLAG (TheFlag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1037 (TEST_THERM (i
->layer
, pv
) ||
1038 !TEST_FLAG (CLEARPOLYFLAG
, &i
->polygon
) ||
1041 if (TEST_FLAG (SQUAREFLAG
, pv
))
1043 Coord x1
, x2
, y1
, y2
;
1044 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1045 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1046 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1047 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1048 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, &i
->polygon
)
1049 && ADD_PV_TO_LIST (pv
))
1050 longjmp (i
->env
, 1);
1052 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1054 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1055 if (isects (oct
, &i
->polygon
, true) && ADD_PV_TO_LIST (pv
))
1056 longjmp (i
->env
, 1);
1060 if (IsPointInPolygon
1061 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, &i
->polygon
)
1062 && ADD_PV_TO_LIST (pv
))
1063 longjmp (i
->env
, 1);
1070 pv_rat_callback (const BoxType
* b
, void *cl
)
1072 PinType
*pv
= (PinType
*) b
;
1073 struct lo_info
*i
= (struct lo_info
*) cl
;
1075 /* rats can't cause DRC so there is no early exit */
1076 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_RAT (pv
, &i
->rat
))
1077 ADD_PV_TO_LIST (pv
);
1081 /* ---------------------------------------------------------------------------
1082 * searches for new PVs that are connected to NEW LOs on the list
1083 * This routine updates the position counter of the lists too.
1086 LookupPVConnectionsToLOList (bool AndRats
)
1089 struct lo_info info
;
1091 /* loop over all layers */
1092 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
1094 LayerType
*layer
= LAYER_PTR (layer_no
);
1098 /* do nothing if there are no PV's */
1099 if (TotalP
+ TotalV
== 0)
1101 LineList
[layer_no
].Location
= LineList
[layer_no
].Number
;
1102 ArcList
[layer_no
].Location
= ArcList
[layer_no
].Number
;
1103 PolygonList
[layer_no
].Location
= PolygonList
[layer_no
].Number
;
1107 /* check all lines */
1108 while (LineList
[layer_no
].Location
< LineList
[layer_no
].Number
)
1110 info
.line
= *(LINELIST_ENTRY (layer_no
, LineList
[layer_no
].Location
));
1111 EXPAND_BOUNDS (&info
.line
);
1112 if (setjmp (info
.env
) == 0)
1113 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1114 pv_line_callback
, &info
);
1117 if (setjmp (info
.env
) == 0)
1118 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1119 pv_line_callback
, &info
);
1122 LineList
[layer_no
].Location
++;
1125 /* check all arcs */
1126 while (ArcList
[layer_no
].Location
< ArcList
[layer_no
].Number
)
1128 info
.arc
= *(ARCLIST_ENTRY (layer_no
, ArcList
[layer_no
].Location
));
1129 EXPAND_BOUNDS (&info
.arc
);
1130 if (setjmp (info
.env
) == 0)
1131 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.arc
, NULL
,
1132 pv_arc_callback
, &info
);
1135 if (setjmp (info
.env
) == 0)
1136 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.arc
, NULL
,
1137 pv_arc_callback
, &info
);
1140 ArcList
[layer_no
].Location
++;
1143 /* now all polygons */
1144 info
.layer
= layer_no
;
1145 while (PolygonList
[layer_no
].Location
< PolygonList
[layer_no
].Number
)
1148 *(POLYGONLIST_ENTRY (layer_no
, PolygonList
[layer_no
].Location
));
1149 EXPAND_BOUNDS (&info
.polygon
);
1150 if (setjmp (info
.env
) == 0)
1151 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.polygon
, NULL
,
1152 pv_poly_callback
, &info
);
1155 if (setjmp (info
.env
) == 0)
1156 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.polygon
, NULL
,
1157 pv_poly_callback
, &info
);
1160 PolygonList
[layer_no
].Location
++;
1164 /* loop over all pad-layers */
1165 for (layer_no
= 0; layer_no
< 2; layer_no
++)
1167 /* do nothing if there are no PV's */
1168 if (TotalP
+ TotalV
== 0)
1170 PadList
[layer_no
].Location
= PadList
[layer_no
].Number
;
1174 /* check all pads; for a detailed description see
1175 * the handling of lines in this subroutine
1177 while (PadList
[layer_no
].Location
< PadList
[layer_no
].Number
)
1179 info
.pad
= *(PADLIST_ENTRY (layer_no
, PadList
[layer_no
].Location
));
1180 EXPAND_BOUNDS (&info
.pad
);
1181 if (setjmp (info
.env
) == 0)
1182 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pad
, NULL
,
1183 pv_pad_callback
, &info
);
1186 if (setjmp (info
.env
) == 0)
1187 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pad
, NULL
,
1188 pv_pad_callback
, &info
);
1191 PadList
[layer_no
].Location
++;
1195 /* do nothing if there are no PV's */
1196 if (TotalP
+ TotalV
== 0)
1197 RatList
.Location
= RatList
.Number
;
1199 /* check all rat-lines */
1202 while (RatList
.Location
< RatList
.Number
)
1204 info
.rat
= *(RATLIST_ENTRY (RatList
.Location
));
1205 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point1
, 1, NULL
,
1206 pv_rat_callback
, &info
);
1207 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point2
, 1, NULL
,
1208 pv_rat_callback
, &info
);
1209 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point1
, 1, NULL
,
1210 pv_rat_callback
, &info
);
1211 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point2
, 1, NULL
,
1212 pv_rat_callback
, &info
);
1220 /* reduce arc start angle and delta to 0..360 */
1222 normalize_angles (Angle
*sa
, Angle
*d
)
1229 if (*d
> 360) /* full circle */
1231 *sa
= NormalizeAngle (*sa
);
1235 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1237 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1238 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1240 normalize_angles (&sa
, &d
);
1244 return (sa
+ d
) >= alpha
;
1245 return (sa
+ d
- 360) >= alpha
;
1249 get_arc_ends (Coord
*box
, ArcType
*arc
)
1251 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1252 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1253 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1254 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1256 /* ---------------------------------------------------------------------------
1257 * check if two arcs intersect
1258 * first we check for circle intersections,
1259 * then find the actual points of intersection
1260 * and test them to see if they are on arcs
1262 * consider a, the distance from the center of arc 1
1263 * to the point perpendicular to the intersecting points.
1265 * a = (r1^2 - r2^2 + l^2)/(2l)
1267 * the perpendicular distance to the point of intersection
1270 * d = sqrt(r1^2 - a^2)
1272 * the points of intersection would then be
1274 * x = X1 + a/l dx +- d/l dy
1275 * y = Y1 + a/l dy -+ d/l dx
1277 * where dx = X2 - X1 and dy = Y2 - Y1
1282 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1284 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1288 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1289 t2
= 0.5 * Arc2
->Thickness
;
1293 if (t
< 0 || t1
< 0)
1296 /* try the end points first */
1297 get_arc_ends (&box
[0], Arc1
);
1298 get_arc_ends (&box
[4], Arc2
);
1299 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1300 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1301 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1302 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1305 pdx
= Arc2
->X
- Arc1
->X
;
1306 pdy
= Arc2
->Y
- Arc1
->Y
;
1307 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1308 /* concentric arcs, simpler intersection conditions */
1311 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1312 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1313 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1314 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1316 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1317 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1318 /* NB the endpoints have already been checked,
1319 so we just compare the angles */
1321 normalize_angles (&sa1
, &d1
);
1322 normalize_angles (&sa2
, &d2
);
1323 /* sa1 == sa2 was caught when checking endpoints */
1325 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1328 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1335 /* arcs centerlines are too far or too near */
1336 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1338 /* check the nearest to the other arc's center point */
1341 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1347 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1348 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1351 dx
= - pdx
* r2
/ dl
;
1352 dy
= - pdy
* r2
/ dl
;
1353 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1359 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1360 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1368 a
= 0.5 * (r1
- r2
+ l
) / l
;
1371 /* the circles are too far apart to touch or probably just touch:
1372 check the nearest point */
1377 x
= Arc1
->X
+ a
* pdx
;
1378 y
= Arc1
->Y
+ a
* pdy
;
1381 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1382 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1384 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1385 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1388 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1389 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1391 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1392 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1397 /* ---------------------------------------------------------------------------
1398 * Tests if point is same as line end point
1401 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1403 if ((Point
->X
== Line
->Point1
.X
1404 && Point
->Y
== Line
->Point1
.Y
)
1405 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1411 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1412 /* writes vertices of a squared line */
1414 double dwx
= 0, dwy
= 0;
1415 if (l
->Point1
.Y
== l
->Point2
.Y
)
1416 dwx
= l
->Thickness
/ 2.0;
1417 else if (l
->Point1
.X
== l
->Point2
.X
)
1418 dwy
= l
->Thickness
/ 2.0;
1421 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1422 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1423 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1424 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1425 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1427 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1428 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1429 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1430 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1432 /* ---------------------------------------------------------------------------
1433 * checks if two lines intersect
1436 * Let A,B,C,D be 2-space position vectors. Then the directed line
1437 * segments AB & CD are given by:
1439 * AB=A+r(B-A), r in [0,1]
1440 * CD=C+s(D-C), s in [0,1]
1442 * If AB & CD intersect, then
1444 * A+r(B-A)=C+s(D-C), or
1446 * XA+r(XB-XA)=XC+s(XD-XC)
1447 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1449 * Solving the above for r and s yields
1451 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1452 * r = ----------------------------- (eqn 1)
1453 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1455 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1456 * s = ----------------------------- (eqn 2)
1457 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1459 * Let I be the position vector of the intersection point, then
1466 * By examining the values of r & s, you can also determine some
1467 * other limiting conditions:
1469 * If 0<=r<=1 & 0<=s<=1, intersection exists
1470 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1472 * If the denominator in eqn 1 is zero, AB & CD are parallel
1473 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1475 * If the intersection point of the 2 lines are needed (lines in this
1476 * context mean infinite lines) regardless whether the two line
1477 * segments intersect, then
1479 * If r>1, I is located on extension of AB
1480 * If r<0, I is located on extension of BA
1481 * If s>1, I is located on extension of CD
1482 * If s<0, I is located on extension of DC
1484 * Also note that the denominators of eqn 1 & 2 are identical.
1488 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1491 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1492 point1_dx
, point1_dy
;
1493 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1496 form_slanted_rectangle (p
, Line1
);
1497 return IsLineInQuadrangle (p
, Line2
);
1499 /* here come only round Line1 because IsLineInQuadrangle()
1500 calls LineLineIntersect() with first argument rounded*/
1501 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1504 form_slanted_rectangle (p
, Line2
);
1505 return IsLineInQuadrangle (p
, Line1
);
1507 /* now all lines are round */
1509 /* Check endpoints: this provides a quick exit, catches
1510 * cases where the "real" lines don't intersect but the
1511 * thick lines touch, and ensures that the dx/dy business
1512 * below does not cause a divide-by-zero. */
1513 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1514 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1516 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1517 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1519 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1520 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1522 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1523 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1527 /* setup some constants */
1528 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1529 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1530 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1531 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1532 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1533 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1535 /* If either line is a point, we have failed already, since the
1536 * endpoint check above will have caught an "intersection". */
1537 if ((line1_dx
== 0 && line1_dy
== 0)
1538 || (line2_dx
== 0 && line2_dy
== 0))
1541 /* set s to cross product of Line1 and the line
1542 * Line1.Point1--Line2.Point1 (as vectors) */
1543 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1545 /* set r to cross product of both lines (as vectors) */
1546 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1548 /* No cross product means parallel lines, or maybe Line2 is
1549 * zero-length. In either case, since we did a bounding-box
1550 * check before getting here, the above IsPointInPad() checks
1551 * will have caught any intersections. */
1556 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1558 /* intersection is at least on AB */
1559 if (r
>= 0.0 && r
<= 1.0)
1560 return (s
>= 0.0 && s
<= 1.0);
1562 /* intersection is at least on CD */
1563 /* [removed this case since it always returns false --asp] */
1567 /*---------------------------------------------------
1569 * Check for line intersection with an arc
1571 * Mostly this is like the circle/line intersection
1572 * found in IsPointOnLine (search.c) see the detailed
1573 * discussion for the basics there.
1575 * Since this is only an arc, not a full circle we need
1576 * to find the actual points of intersection with the
1577 * circle, and see if they are on the arc.
1579 * To do this, we translate along the line from the point Q
1580 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1581 * but it's handy to normalize with respect to l, the line
1582 * length so a single projection is done (e.g. we don't first
1585 * The projection is now of the form
1587 * Px = X1 + (r +- r2)(X2 - X1)
1588 * Py = Y1 + (r +- r2)(Y2 - Y1)
1590 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1591 * note that this is the variable d, not the symbol d described in IsPointOnLine
1592 * (variable d = symbol d * l)
1594 * The end points are hell so they are checked individually
1597 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1599 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1602 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1603 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1604 dx1
= Line
->Point1
.X
- Arc
->X
;
1605 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1606 l
= dx
* dx
+ dy
* dy
;
1607 d
= dx
* dy1
- dy
* dx1
;
1610 /* use the larger diameter circle first */
1612 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1614 r2
= Radius
* l
- d
;
1615 /* projection doesn't even intersect circle when r2 < 0 */
1618 /* check the ends of the line in case the projected point */
1619 /* of intersection is beyond the line end */
1621 (Line
->Point1
.X
, Line
->Point1
.Y
,
1622 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1625 (Line
->Point2
.X
, Line
->Point2
.Y
,
1626 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1631 Radius
= -(dx
* dx1
+ dy
* dy1
);
1632 r
= (Radius
+ r2
) / l
;
1633 if (r
>= 0 && r
<= 1
1634 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1635 Line
->Point1
.Y
+ r
* dy
,
1636 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1638 r
= (Radius
- r2
) / l
;
1639 if (r
>= 0 && r
<= 1
1640 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1641 Line
->Point1
.Y
+ r
* dy
,
1642 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1644 /* check arc end points */
1645 box
= GetArcEnds (Arc
);
1646 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1648 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1654 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1656 LineType
*line
= (LineType
*) b
;
1657 struct lo_info
*i
= (struct lo_info
*) cl
;
1659 if (!TEST_FLAG (TheFlag
, line
) && LineArcIntersect (line
, &i
->arc
))
1661 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1662 longjmp (i
->env
, 1);
1668 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1670 ArcType
*arc
= (ArcType
*) b
;
1671 struct lo_info
*i
= (struct lo_info
*) cl
;
1673 if (!arc
->Thickness
)
1675 if (!TEST_FLAG (TheFlag
, arc
) && ArcArcIntersect (&i
->arc
, arc
))
1677 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1678 longjmp (i
->env
, 1);
1684 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1686 PadType
*pad
= (PadType
*) b
;
1687 struct lo_info
*i
= (struct lo_info
*) cl
;
1689 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1690 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1691 && ArcPadIntersect (&i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1692 longjmp (i
->env
, 1);
1696 /* ---------------------------------------------------------------------------
1697 * searches all LOs that are connected to the given arc on the given
1698 * layergroup. All found connections are added to the list
1700 * the notation that is used is:
1701 * Xij means Xj at arc i
1704 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
)
1707 struct lo_info info
;
1710 EXPAND_BOUNDS (&info
.arc
);
1711 /* loop over all layers of the group */
1712 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1718 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1719 layer
= LAYER_PTR (layer_no
);
1721 /* handle normal layers */
1722 if (layer_no
< max_copper_layer
)
1724 info
.layer
= layer_no
;
1726 if (setjmp (info
.env
) == 0)
1727 r_search (layer
->line_tree
, &info
.arc
.BoundingBox
,
1728 NULL
, LOCtoArcLine_callback
, &info
);
1732 if (setjmp (info
.env
) == 0)
1733 r_search (layer
->arc_tree
, &info
.arc
.BoundingBox
,
1734 NULL
, LOCtoArcArc_callback
, &info
);
1738 /* now check all polygons */
1739 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1741 PolygonType
*polygon
= i
->data
;
1742 if (!TEST_FLAG (TheFlag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1743 && ADD_POLYGON_TO_LIST (layer_no
, polygon
))
1749 info
.layer
= layer_no
- max_copper_layer
;
1750 if (setjmp (info
.env
) == 0)
1751 r_search (PCB
->Data
->pad_tree
, &info
.arc
.BoundingBox
, NULL
,
1752 LOCtoArcPad_callback
, &info
);
1761 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1763 LineType
*line
= (LineType
*) b
;
1764 struct lo_info
*i
= (struct lo_info
*) cl
;
1766 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1768 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1769 longjmp (i
->env
, 1);
1775 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1777 ArcType
*arc
= (ArcType
*) b
;
1778 struct lo_info
*i
= (struct lo_info
*) cl
;
1780 if (!arc
->Thickness
)
1782 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
1784 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1785 longjmp (i
->env
, 1);
1791 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1793 RatType
*rat
= (RatType
*) b
;
1794 struct lo_info
*i
= (struct lo_info
*) cl
;
1796 if (!TEST_FLAG (TheFlag
, rat
))
1798 if ((rat
->group1
== i
->layer
)
1799 && IsRatPointOnLineEnd (&rat
->Point1
, &i
->line
))
1801 if (ADD_RAT_TO_LIST (rat
))
1802 longjmp (i
->env
, 1);
1804 else if ((rat
->group2
== i
->layer
)
1805 && IsRatPointOnLineEnd (&rat
->Point2
, &i
->line
))
1807 if (ADD_RAT_TO_LIST (rat
))
1808 longjmp (i
->env
, 1);
1815 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1817 PadType
*pad
= (PadType
*) b
;
1818 struct lo_info
*i
= (struct lo_info
*) cl
;
1820 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1821 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1822 && LinePadIntersect (&i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1823 longjmp (i
->env
, 1);
1827 /* ---------------------------------------------------------------------------
1828 * searches all LOs that are connected to the given line on the given
1829 * layergroup. All found connections are added to the list
1831 * the notation that is used is:
1832 * Xij means Xj at line i
1835 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1839 struct lo_info info
;
1842 info
.layer
= LayerGroup
;
1843 EXPAND_BOUNDS (&info
.line
)
1844 /* add the new rat lines */
1845 if (setjmp (info
.env
) == 0)
1846 r_search (PCB
->Data
->rat_tree
, &info
.line
.BoundingBox
, NULL
,
1847 LOCtoLineRat_callback
, &info
);
1851 /* loop over all layers of the group */
1852 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1857 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1858 layer
= LAYER_PTR (layer_no
);
1860 /* handle normal layers */
1861 if (layer_no
< max_copper_layer
)
1863 info
.layer
= layer_no
;
1865 if (setjmp (info
.env
) == 0)
1866 r_search (layer
->line_tree
, (BoxType
*) & info
.line
,
1867 NULL
, LOCtoLineLine_callback
, &info
);
1871 if (setjmp (info
.env
) == 0)
1872 r_search (layer
->arc_tree
, (BoxType
*) & info
.line
,
1873 NULL
, LOCtoLineArc_callback
, &info
);
1876 /* now check all polygons */
1880 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1882 PolygonType
*polygon
= i
->data
;
1884 (TheFlag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1885 && ADD_POLYGON_TO_LIST (layer_no
, polygon
))
1892 /* handle special 'pad' layers */
1893 info
.layer
= layer_no
- max_copper_layer
;
1894 if (setjmp (info
.env
) == 0)
1895 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
1896 LOCtoLinePad_callback
, &info
);
1912 LOCtoRat_callback (const BoxType
* b
, void *cl
)
1914 LineType
*line
= (LineType
*) b
;
1915 struct rat_info
*i
= (struct rat_info
*) cl
;
1917 if (!TEST_FLAG (TheFlag
, line
) &&
1918 ((line
->Point1
.X
== i
->Point
->X
&&
1919 line
->Point1
.Y
== i
->Point
->Y
) ||
1920 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
1922 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1923 longjmp (i
->env
, 1);
1928 PolygonToRat_callback (const BoxType
* b
, void *cl
)
1930 PolygonType
*polygon
= (PolygonType
*) b
;
1931 struct rat_info
*i
= (struct rat_info
*) cl
;
1933 if (!TEST_FLAG (TheFlag
, polygon
) && polygon
->Clipped
&&
1934 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
1935 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
1937 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
1938 longjmp (i
->env
, 1);
1944 LOCtoPad_callback (const BoxType
* b
, void *cl
)
1946 PadType
*pad
= (PadType
*) b
;
1947 struct rat_info
*i
= (struct rat_info
*) cl
;
1949 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1950 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
1951 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
1952 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
1953 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
1954 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
1955 ADD_PAD_TO_LIST (i
->layer
, pad
))
1956 longjmp (i
->env
, 1);
1960 /* ---------------------------------------------------------------------------
1961 * searches all LOs that are connected to the given rat-line on the given
1962 * layergroup. All found connections are added to the list
1964 * the notation that is used is:
1965 * Xij means Xj at line i
1968 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
)
1971 struct rat_info info
;
1974 /* loop over all layers of this group */
1975 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1980 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1981 layer
= LAYER_PTR (layer_no
);
1982 /* handle normal layers
1983 rats don't ever touch
1987 if (layer_no
< max_copper_layer
)
1989 info
.layer
= layer_no
;
1990 if (setjmp (info
.env
) == 0)
1991 r_search_pt (layer
->line_tree
, Point
, 1, NULL
,
1992 LOCtoRat_callback
, &info
);
1995 if (setjmp (info
.env
) == 0)
1996 r_search_pt (layer
->polygon_tree
, Point
, 1,
1997 NULL
, PolygonToRat_callback
, &info
);
2001 /* handle special 'pad' layers */
2002 info
.layer
= layer_no
- max_copper_layer
;
2003 if (setjmp (info
.env
) == 0)
2004 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2005 LOCtoPad_callback
, &info
);
2014 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2016 LineType
*line
= (LineType
*) b
;
2017 struct lo_info
*i
= (struct lo_info
*) cl
;
2019 if (!TEST_FLAG (TheFlag
, line
) && LinePadIntersect (line
, &i
->pad
))
2021 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2022 longjmp (i
->env
, 1);
2028 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2030 ArcType
*arc
= (ArcType
*) b
;
2031 struct lo_info
*i
= (struct lo_info
*) cl
;
2033 if (!arc
->Thickness
)
2035 if (!TEST_FLAG (TheFlag
, arc
) && ArcPadIntersect (arc
, &i
->pad
))
2037 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2038 longjmp (i
->env
, 1);
2044 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2046 PolygonType
*polygon
= (PolygonType
*) b
;
2047 struct lo_info
*i
= (struct lo_info
*) cl
;
2050 if (!TEST_FLAG (TheFlag
, polygon
) &&
2051 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
.Clearance
))
2053 if (IsPadInPolygon (&i
->pad
, polygon
) &&
2054 ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2055 longjmp (i
->env
, 1);
2061 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2063 RatType
*rat
= (RatType
*) b
;
2064 struct lo_info
*i
= (struct lo_info
*) cl
;
2066 if (!TEST_FLAG (TheFlag
, rat
))
2068 if (rat
->group1
== i
->layer
&&
2069 ((rat
->Point1
.X
== i
->pad
.Point1
.X
&& rat
->Point1
.Y
== i
->pad
.Point1
.Y
) ||
2070 (rat
->Point1
.X
== i
->pad
.Point2
.X
&& rat
->Point1
.Y
== i
->pad
.Point2
.Y
) ||
2071 (rat
->Point1
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2072 rat
->Point1
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2074 if (ADD_RAT_TO_LIST (rat
))
2075 longjmp (i
->env
, 1);
2077 else if (rat
->group2
== i
->layer
&&
2078 ((rat
->Point2
.X
== i
->pad
.Point1
.X
&& rat
->Point2
.Y
== i
->pad
.Point1
.Y
) ||
2079 (rat
->Point2
.X
== i
->pad
.Point2
.X
&& rat
->Point2
.Y
== i
->pad
.Point2
.Y
) ||
2080 (rat
->Point2
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2081 rat
->Point2
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2083 if (ADD_RAT_TO_LIST (rat
))
2084 longjmp (i
->env
, 1);
2091 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2093 PadType
*pad
= (PadType
*) b
;
2094 struct lo_info
*i
= (struct lo_info
*) cl
;
2096 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2097 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2098 && PadPadIntersect (pad
, &i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2099 longjmp (i
->env
, 1);
2103 /* ---------------------------------------------------------------------------
2104 * searches all LOs that are connected to the given pad on the given
2105 * layergroup. All found connections are added to the list
2108 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
)
2111 struct lo_info info
;
2113 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2114 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, false));
2117 EXPAND_BOUNDS (&info
.pad
);
2118 /* add the new rat lines */
2119 info
.layer
= LayerGroup
;
2120 if (setjmp (info
.env
) == 0)
2121 r_search (PCB
->Data
->rat_tree
, &info
.pad
.BoundingBox
, NULL
,
2122 LOCtoPadRat_callback
, &info
);
2126 /* loop over all layers of the group */
2127 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2132 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2133 layer
= LAYER_PTR (layer_no
);
2134 /* handle normal layers */
2135 if (layer_no
< max_copper_layer
)
2137 info
.layer
= layer_no
;
2139 if (setjmp (info
.env
) == 0)
2140 r_search (layer
->line_tree
, &info
.pad
.BoundingBox
,
2141 NULL
, LOCtoPadLine_callback
, &info
);
2145 if (setjmp (info
.env
) == 0)
2146 r_search (layer
->arc_tree
, &info
.pad
.BoundingBox
,
2147 NULL
, LOCtoPadArc_callback
, &info
);
2151 if (setjmp (info
.env
) == 0)
2152 r_search (layer
->polygon_tree
, &info
.pad
.BoundingBox
,
2153 NULL
, LOCtoPadPoly_callback
, &info
);
2159 /* handle special 'pad' layers */
2160 info
.layer
= layer_no
- max_copper_layer
;
2161 if (setjmp (info
.env
) == 0)
2162 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pad
, NULL
,
2163 LOCtoPadPad_callback
, &info
);
2173 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2175 LineType
*line
= (LineType
*) b
;
2176 struct lo_info
*i
= (struct lo_info
*) cl
;
2178 if (!TEST_FLAG (TheFlag
, line
) && IsLineInPolygon (line
, &i
->polygon
))
2180 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2181 longjmp (i
->env
, 1);
2187 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2189 ArcType
*arc
= (ArcType
*) b
;
2190 struct lo_info
*i
= (struct lo_info
*) cl
;
2192 if (!arc
->Thickness
)
2194 if (!TEST_FLAG (TheFlag
, arc
) && IsArcInPolygon (arc
, &i
->polygon
))
2196 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2197 longjmp (i
->env
, 1);
2203 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2205 PadType
*pad
= (PadType
*) b
;
2206 struct lo_info
*i
= (struct lo_info
*) cl
;
2208 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2209 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2210 && IsPadInPolygon (pad
, &i
->polygon
))
2212 if (ADD_PAD_TO_LIST (i
->layer
, pad
))
2213 longjmp (i
->env
, 1);
2219 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2221 RatType
*rat
= (RatType
*) b
;
2222 struct lo_info
*i
= (struct lo_info
*) cl
;
2224 if (!TEST_FLAG (TheFlag
, rat
))
2226 if ((rat
->Point1
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2227 rat
->Point1
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2228 rat
->group1
== i
->layer
) ||
2229 (rat
->Point2
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2230 rat
->Point2
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2231 rat
->group2
== i
->layer
))
2232 if (ADD_RAT_TO_LIST (rat
))
2233 longjmp (i
->env
, 1);
2239 /* ---------------------------------------------------------------------------
2240 * looks up LOs that are connected to the given polygon
2241 * on the given layergroup. All found connections are added to the list
2244 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
)
2247 struct lo_info info
;
2249 if (!Polygon
->Clipped
)
2251 info
.polygon
= *Polygon
;
2252 EXPAND_BOUNDS (&info
.polygon
);
2253 info
.layer
= LayerGroup
;
2255 if (setjmp (info
.env
) == 0)
2256 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.polygon
, NULL
,
2257 LOCtoPolyRat_callback
, &info
);
2260 /* loop over all layers of the group */
2261 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2266 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2267 layer
= LAYER_PTR (layer_no
);
2269 /* handle normal layers */
2270 if (layer_no
< max_copper_layer
)
2274 /* check all polygons */
2275 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
2277 PolygonType
*polygon
= i
->data
;
2278 if (!TEST_FLAG (TheFlag
, polygon
)
2279 && IsPolygonInPolygon (polygon
, Polygon
)
2280 && ADD_POLYGON_TO_LIST (layer_no
, polygon
))
2284 info
.layer
= layer_no
;
2285 /* check all lines */
2286 if (setjmp (info
.env
) == 0)
2287 r_search (layer
->line_tree
,
2288 (BoxType
*) & info
.polygon
, NULL
,
2289 LOCtoPolyLine_callback
, &info
);
2292 /* check all arcs */
2293 if (setjmp (info
.env
) == 0)
2294 r_search (layer
->arc_tree
, (BoxType
*) & info
.polygon
,
2295 NULL
, LOCtoPolyArc_callback
, &info
);
2301 info
.layer
= layer_no
- max_copper_layer
;
2302 if (setjmp (info
.env
) == 0)
2303 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.polygon
,
2304 NULL
, LOCtoPolyPad_callback
, &info
);
2312 /* ---------------------------------------------------------------------------
2313 * checks if an arc has a connection to a polygon
2315 * - first check if the arc can intersect with the polygon by
2316 * evaluating the bounding boxes
2317 * - check the two end points of the arc. If none of them matches
2318 * - check all segments of the polygon against the arc.
2321 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2323 BoxType
*Box
= (BoxType
*) Arc
;
2325 /* arcs with clearance never touch polys */
2326 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2328 if (!Polygon
->Clipped
)
2330 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2331 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2332 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2333 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2337 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2338 return false; /* error */
2339 return isects (ap
, Polygon
, true);
2344 /* ---------------------------------------------------------------------------
2345 * checks if a line has a connection to a polygon
2347 * - first check if the line can intersect with the polygon by
2348 * evaluating the bounding boxes
2349 * - check the two end points of the line. If none of them matches
2350 * - check all segments of the polygon against the line.
2353 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2355 BoxType
*Box
= (BoxType
*) Line
;
2358 /* lines with clearance never touch polygons */
2359 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2361 if (!Polygon
->Clipped
)
2363 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2365 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2366 Coord x1
, x2
, y1
, y2
;
2368 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2369 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2370 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2371 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2372 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2374 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2375 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2376 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2377 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2379 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2380 return FALSE
; /* error */
2381 return isects (lp
, Polygon
, true);
2386 /* ---------------------------------------------------------------------------
2387 * checks if a pad connects to a non-clearing polygon
2389 * The polygon is assumed to already have been proven non-clearing
2392 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2394 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2397 /* ---------------------------------------------------------------------------
2398 * checks if a polygon has a connection to a second one
2400 * First check all points out of P1 against P2 and vice versa.
2401 * If both fail check all lines of P1 against the ones of P2
2404 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2406 if (!P1
->Clipped
|| !P2
->Clipped
)
2408 assert (P1
->Clipped
->contours
);
2409 assert (P2
->Clipped
->contours
);
2411 /* first check if both bounding boxes intersect. If not, return quickly */
2412 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2413 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2414 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2415 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2418 /* first check un-bloated case */
2419 if (isects (P1
->Clipped
, P2
, false))
2422 /* now the difficult case of bloated */
2426 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2429 VNODE
*v
= &c
->head
;
2430 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2431 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2432 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2433 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2436 line
.Point1
.X
= v
->point
[0];
2437 line
.Point1
.Y
= v
->point
[1];
2438 line
.Thickness
= 2 * Bloat
;
2440 line
.Flags
= NoFlags ();
2441 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2443 line
.Point2
.X
= v
->point
[0];
2444 line
.Point2
.Y
= v
->point
[1];
2445 SetLineBoundingBox (&line
);
2446 if (IsLineInPolygon (&line
, P2
))
2448 line
.Point1
.X
= line
.Point2
.X
;
2449 line
.Point1
.Y
= line
.Point2
.Y
;
2458 /* ---------------------------------------------------------------------------
2459 * writes the several names of an element to a file
2462 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2464 static DynamicStringType cname
, pname
, vname
;
2466 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2467 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2468 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2469 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2472 /* ---------------------------------------------------------------------------
2473 * writes the several names of an element to a file
2476 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2478 fputs ("Element", FP
);
2479 PrintElementNameList (Element
, FP
);
2483 /* ---------------------------------------------------------------------------
2484 * prints one {pin,pad,via}/element entry of connection lists
2487 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2488 bool FirstOne
, FILE * FP
)
2490 static DynamicStringType oname
;
2492 CreateQuotedString (&oname
, ObjName
);
2494 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2497 fprintf (FP
, "\t\t%s ", oname
.Data
);
2499 PrintElementNameList (Element
, FP
);
2501 fputs ("(__VIA__)\n", FP
);
2505 /* ---------------------------------------------------------------------------
2506 * prints all found connections of a pads to file FP
2507 * the connections are stacked in 'PadList'
2510 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2515 if (!PadList
[Layer
].Number
)
2518 /* the starting pad */
2521 ptr
= PADLIST_ENTRY (Layer
, 0);
2523 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2525 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2528 /* we maybe have to start with i=1 if we are handling the
2529 * starting-pad itself
2531 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2533 ptr
= PADLIST_ENTRY (Layer
, i
);
2535 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2537 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2541 /* ---------------------------------------------------------------------------
2542 * prints all found connections of a pin to file FP
2543 * the connections are stacked in 'PVList'
2546 PrintPinConnections (FILE * FP
, bool IsFirst
)
2556 /* the starting pin */
2557 pv
= PVLIST_ENTRY (0);
2558 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2561 /* we maybe have to start with i=1 if we are handling the
2562 * starting-pin itself
2564 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2566 /* get the elements name or assume that its a via */
2567 pv
= PVLIST_ENTRY (i
);
2568 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2572 /* ---------------------------------------------------------------------------
2573 * checks if all lists of new objects are handled
2576 ListsEmpty (bool AndRats
)
2581 empty
= (PVList
.Location
>= PVList
.Number
);
2583 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2584 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2585 if (!LAYER_PTR (i
)->no_drc
)
2586 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2587 && ArcList
[i
].Location
>= ArcList
[i
].Number
2588 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2593 reassign_no_drc_flags (void)
2597 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2599 LayerType
*l
= LAYER_PTR (layer
);
2600 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2607 /* ---------------------------------------------------------------------------
2608 * loops till no more connections are found
2611 DoIt (bool AndRats
, bool AndDraw
)
2613 bool newone
= false;
2614 reassign_no_drc_flags ();
2617 /* lookup connections; these are the steps (2) to (4)
2618 * from the description
2620 newone
= LookupPVConnectionsToPVList () ||
2621 LookupLOConnectionsToPVList (AndRats
) ||
2622 LookupLOConnectionsToLOList (AndRats
) ||
2623 LookupPVConnectionsToLOList (AndRats
);
2625 DrawNewConnections ();
2627 while (!newone
&& !ListsEmpty (AndRats
));
2633 /* ---------------------------------------------------------------------------
2634 * prints all unused pins of an element to file FP
2637 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
)
2641 static DynamicStringType oname
;
2643 /* check all pins in element */
2647 if (!TEST_FLAG (HOLEFLAG
, pin
))
2649 /* pin might have bee checked before, add to list if not */
2650 if (!TEST_FLAG (TheFlag
, pin
) && FP
)
2653 if (ADD_PV_TO_LIST (pin
))
2656 number
= PadList
[COMPONENT_LAYER
].Number
2657 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2658 /* the pin has no connection if it's the only
2659 * list entry; don't count vias
2661 for (i
= 0; i
< PVList
.Number
; i
++)
2662 if (!PVLIST_ENTRY (i
)->Element
)
2666 /* output of element name if not already done */
2669 PrintConnectionElementName (Element
, FP
);
2673 /* write name to list and draw selected object */
2674 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2675 fprintf (FP
, "\t%s\n", oname
.Data
);
2676 SET_FLAG (SELECTEDFLAG
, pin
);
2680 /* reset found objects for the next pin */
2681 if (PrepareNextLoop (FP
))
2688 /* check all pads in element */
2691 /* lookup pad in list */
2692 /* pad might has bee checked before, add to list if not */
2693 if (!TEST_FLAG (TheFlag
, pad
) && FP
)
2696 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2697 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
2700 number
= PadList
[COMPONENT_LAYER
].Number
2701 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2702 /* the pin has no connection if it's the only
2703 * list entry; don't count vias
2705 for (i
= 0; i
< PVList
.Number
; i
++)
2706 if (!PVLIST_ENTRY (i
)->Element
)
2710 /* output of element name if not already done */
2713 PrintConnectionElementName (Element
, FP
);
2717 /* write name to list and draw selected object */
2718 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2719 fprintf (FP
, "\t%s\n", oname
.Data
);
2720 SET_FLAG (SELECTEDFLAG
, pad
);
2724 /* reset found objects for the next pin */
2725 if (PrepareNextLoop (FP
))
2731 /* print separator if element has unused pins or pads */
2734 fputs ("}\n\n", FP
);
2740 /* ---------------------------------------------------------------------------
2741 * resets some flags for looking up the next pin/pad
2744 PrepareNextLoop (FILE * FP
)
2748 /* reset found LOs for the next pin */
2749 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2751 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2752 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2753 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2756 /* reset found pads */
2757 for (layer
= 0; layer
< 2; layer
++)
2758 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2761 PVList
.Number
= PVList
.Location
= 0;
2762 RatList
.Number
= RatList
.Location
= 0;
2767 /* ---------------------------------------------------------------------------
2768 * finds all connections to the pins of the passed element.
2769 * The result is written to file FP
2770 * Returns true if operation was aborted
2773 PrintElementConnections (ElementType
*Element
, FILE * FP
, bool AndDraw
)
2775 PrintConnectionElementName (Element
, FP
);
2777 /* check all pins in element */
2780 /* pin might have been checked before, add to list if not */
2781 if (TEST_FLAG (TheFlag
, pin
))
2783 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2784 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2787 if (ADD_PV_TO_LIST (pin
))
2789 DoIt (true, AndDraw
);
2790 /* printout all found connections */
2791 PrintPinConnections (FP
, true);
2792 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
2793 PrintPadConnections (SOLDER_LAYER
, FP
, false);
2794 fputs ("\t}\n", FP
);
2795 if (PrepareNextLoop (FP
))
2800 /* check all pads in element */
2804 /* pad might have been checked before, add to list if not */
2805 if (TEST_FLAG (TheFlag
, pad
))
2807 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2808 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2811 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
2812 if (ADD_PAD_TO_LIST (layer
, pad
))
2814 DoIt (true, AndDraw
);
2815 /* print all found connections */
2816 PrintPadConnections (layer
, FP
, true);
2817 PrintPadConnections (layer
==
2818 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
2820 PrintPinConnections (FP
, false);
2821 fputs ("\t}\n", FP
);
2822 if (PrepareNextLoop (FP
))
2826 fputs ("}\n\n", FP
);
2830 /* ---------------------------------------------------------------------------
2831 * draws all new connections which have been found since the
2832 * routine was called the last time
2835 DrawNewConnections (void)
2840 /* decrement 'i' to keep layerstack order */
2841 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
2843 Cardinal layer
= LayerStack
[i
];
2845 if (PCB
->Data
->Layer
[layer
].On
)
2847 /* draw all new lines */
2848 position
= LineList
[layer
].DrawLocation
;
2849 for (; position
< LineList
[layer
].Number
; position
++)
2850 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
2851 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
2853 /* draw all new arcs */
2854 position
= ArcList
[layer
].DrawLocation
;
2855 for (; position
< ArcList
[layer
].Number
; position
++)
2856 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
2857 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
2859 /* draw all new polygons */
2860 position
= PolygonList
[layer
].DrawLocation
;
2861 for (; position
< PolygonList
[layer
].Number
; position
++)
2862 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
2863 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
2867 /* draw all new pads */
2869 for (i
= 0; i
< 2; i
++)
2871 position
= PadList
[i
].DrawLocation
;
2873 for (; position
< PadList
[i
].Number
; position
++)
2874 DrawPad (PADLIST_ENTRY (i
, position
));
2875 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
2878 /* draw all new PVs; 'PVList' holds a list of pointers to the
2879 * sorted array pointers to PV data
2881 while (PVList
.DrawLocation
< PVList
.Number
)
2883 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
2885 if (TEST_FLAG (PINFLAG
, pv
))
2890 else if (PCB
->ViaOn
)
2892 PVList
.DrawLocation
++;
2894 /* draw the new rat-lines */
2897 position
= RatList
.DrawLocation
;
2898 for (; position
< RatList
.Number
; position
++)
2899 DrawRat (RATLIST_ENTRY (position
));
2900 RatList
.DrawLocation
= RatList
.Number
;
2904 /* ---------------------------------------------------------------------------
2905 * find all connections to pins within one element
2908 LookupElementConnections (ElementType
*Element
, FILE * FP
)
2910 /* reset all currently marked connections */
2912 TheFlag
= FOUNDFLAG
;
2913 ClearFlagOnAllObjects (true, FOUNDFLAG
);
2914 InitConnectionLookup ();
2915 PrintElementConnections (Element
, FP
, true);
2916 SetChangedFlag (true);
2917 if (Settings
.RingBellWhenFinished
)
2919 FreeConnectionLookupMemory ();
2920 IncrementUndoSerialNumber ();
2925 /* ---------------------------------------------------------------------------
2926 * find all connections to pins of all element
2929 LookupConnectionsToAllElements (FILE * FP
)
2931 /* reset all currently marked connections */
2933 TheFlag
= FOUNDFLAG
;
2934 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2935 InitConnectionLookup ();
2937 ELEMENT_LOOP (PCB
->Data
);
2939 /* break if abort dialog returned true */
2940 if (PrintElementConnections (element
, FP
, false))
2943 if (Settings
.ResetAfterElement
&& n
!= 1)
2944 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2947 if (Settings
.RingBellWhenFinished
)
2949 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2950 FreeConnectionLookupMemory ();
2954 /*---------------------------------------------------------------------------
2955 * add the starting object to the list of found objects
2958 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
2966 if (ADD_PV_TO_LIST ((PinType
*) ptr2
))
2973 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
))
2980 int layer
= GetLayerNumber (PCB
->Data
,
2981 (LayerType
*) ptr1
);
2983 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
))
2990 int layer
= GetLayerNumber (PCB
->Data
,
2991 (LayerType
*) ptr1
);
2993 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
))
3000 int layer
= GetLayerNumber (PCB
->Data
,
3001 (LayerType
*) ptr1
);
3003 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
))
3010 PadType
*pad
= (PadType
*) ptr2
;
3013 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3022 /* ---------------------------------------------------------------------------
3023 * looks up all connections from the object at the given coordinates
3024 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3025 * the objects are re-drawn if AndDraw is true
3026 * also the action is marked as undoable if AndDraw is true
3029 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int which_flag
,
3032 void *ptr1
, *ptr2
, *ptr3
;
3036 /* check if there are any pins or pads at that position */
3038 reassign_no_drc_flags ();
3041 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3042 if (type
== NO_TYPE
)
3044 type
= SearchObjectByLocation (
3045 LOOKUP_MORE
& ~(AndRats
? RATLINE_TYPE
: 0),
3046 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3047 if (type
== NO_TYPE
)
3049 if (type
& SILK_TYPE
)
3051 int laynum
= GetLayerNumber (PCB
->Data
,
3052 (LayerType
*) ptr1
);
3054 /* don't mess with non-conducting objects! */
3055 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3060 name
= ConnectionName (type
, ptr1
, ptr2
);
3061 hid_actionl ("NetlistShow", name
, NULL
);
3063 TheFlag
= which_flag
;
3065 InitConnectionLookup ();
3067 /* now add the object to the appropriate list and start scanning
3068 * This is step (1) from the description
3070 ListStart (type
, ptr1
, ptr2
, ptr3
);
3071 DoIt (AndRats
, AndDraw
);
3073 IncrementUndoSerialNumber ();
3079 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3081 FreeConnectionLookupMemory ();
3084 /* ---------------------------------------------------------------------------
3085 * find connections for rats nesting
3086 * assumes InitConnectionLookup() has already been done
3089 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3090 bool undo
, int flag
, bool AndRats
)
3095 ListStart (type
, ptr1
, ptr2
, ptr3
);
3096 DoIt (AndRats
, false);
3100 /* ---------------------------------------------------------------------------
3101 * find all unused pins of all element
3104 LookupUnusedPins (FILE * FP
)
3106 /* reset all currently marked connections */
3108 TheFlag
= FOUNDFLAG
;
3109 ClearFlagOnAllObjects (true, FOUNDFLAG
);
3110 InitConnectionLookup ();
3112 ELEMENT_LOOP (PCB
->Data
);
3114 /* break if abort dialog returned true;
3115 * passing NULL as filedescriptor discards the normal output
3117 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
))
3122 if (Settings
.RingBellWhenFinished
)
3124 FreeConnectionLookupMemory ();
3125 IncrementUndoSerialNumber ();
3130 /* ---------------------------------------------------------------------------
3131 * resets all used flags of pins and vias
3134 ClearFlagOnPinsViasAndPads (bool AndDraw
, int flag
)
3136 bool change
= false;
3138 VIA_LOOP (PCB
->Data
);
3140 if (TEST_FLAG (flag
, via
))
3143 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3144 CLEAR_FLAG (flag
, via
);
3151 ELEMENT_LOOP (PCB
->Data
);
3155 if (TEST_FLAG (flag
, pin
))
3158 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3159 CLEAR_FLAG (flag
, pin
);
3168 if (TEST_FLAG (flag
, pad
))
3171 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3172 CLEAR_FLAG (flag
, pad
);
3182 SetChangedFlag (true);
3186 /* ---------------------------------------------------------------------------
3187 * resets all used flags of LOs
3190 ClearFlagOnLinesAndPolygons (bool AndDraw
, int flag
)
3192 bool change
= false;
3194 RAT_LOOP (PCB
->Data
);
3196 if (TEST_FLAG (flag
, line
))
3199 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3200 CLEAR_FLAG (flag
, line
);
3207 COPPERLINE_LOOP (PCB
->Data
);
3209 if (TEST_FLAG (flag
, line
))
3212 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3213 CLEAR_FLAG (flag
, line
);
3215 DrawLine (layer
, line
);
3220 COPPERARC_LOOP (PCB
->Data
);
3222 if (TEST_FLAG (flag
, arc
))
3225 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3226 CLEAR_FLAG (flag
, arc
);
3228 DrawArc (layer
, arc
);
3233 COPPERPOLYGON_LOOP (PCB
->Data
);
3235 if (TEST_FLAG (flag
, polygon
))
3238 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3239 CLEAR_FLAG (flag
, polygon
);
3241 DrawPolygon (layer
, polygon
);
3247 SetChangedFlag (true);
3251 /* ---------------------------------------------------------------------------
3252 * resets all found connections
3255 ClearFlagOnAllObjects (bool AndDraw
, int flag
)
3257 bool change
= false;
3259 change
= ClearFlagOnPinsViasAndPads (AndDraw
, flag
) || change
;
3260 change
= ClearFlagOnLinesAndPolygons (AndDraw
, flag
) || change
;
3265 /*----------------------------------------------------------------------------
3266 * Dumps the list contents
3273 for (i
= 0; i
< 2; i
++)
3275 PadList
[i
].Number
= 0;
3276 PadList
[i
].Location
= 0;
3277 PadList
[i
].DrawLocation
= 0;
3281 PVList
.Location
= 0;
3283 for (i
= 0; i
< max_copper_layer
; i
++)
3285 LineList
[i
].Location
= 0;
3286 LineList
[i
].DrawLocation
= 0;
3287 LineList
[i
].Number
= 0;
3288 ArcList
[i
].Location
= 0;
3289 ArcList
[i
].DrawLocation
= 0;
3290 ArcList
[i
].Number
= 0;
3291 PolygonList
[i
].Location
= 0;
3292 PolygonList
[i
].DrawLocation
= 0;
3293 PolygonList
[i
].Number
= 0;
3296 RatList
.Location
= 0;
3297 RatList
.DrawLocation
= 0;
3300 /*-----------------------------------------------------------------------------
3301 * Check for DRC violations on a single net starting from the pad or pin
3302 * sees if the connectivity changes when everything is bloated, or shrunk
3305 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3309 long int *object_id_list
;
3310 int *object_type_list
;
3311 DrcViolationType
*violation
;
3313 if (PCB
->Shrink
!= 0)
3315 Bloat
= -PCB
->Shrink
;
3316 TheFlag
= DRCFLAG
| SELECTEDFLAG
;
3317 ListStart (What
, ptr1
, ptr2
, ptr3
);
3319 /* ok now the shrunk net has the SELECTEDFLAG set */
3321 TheFlag
= FOUNDFLAG
;
3322 ListStart (What
, ptr1
, ptr2
, ptr3
);
3324 drc
= true; /* abort the search if we find anything not already found */
3325 if (DoIt (true, false))
3328 /* make the flag changes undoable */
3329 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3330 ClearFlagOnAllObjects (false, TheFlag
);
3333 Bloat
= -PCB
->Shrink
;
3334 TheFlag
= SELECTEDFLAG
;
3335 ListStart (What
, ptr1
, ptr2
, ptr3
);
3338 ListStart (What
, ptr1
, ptr2
, ptr3
);
3339 TheFlag
= FOUNDFLAG
;
3347 LocateError (&x
, &y
);
3348 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3349 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3350 _("Insufficient overlap between objects can lead to broken tracks\n"
3351 "due to registration errors with old wheel style photo-plotters."),
3353 0, /* ANGLE OF ERROR UNKNOWN */
3354 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3355 0, /* MAGNITUDE OF ERROR UNKNOWN */
3360 append_drc_violation (violation
);
3361 pcb_drc_violation_free (violation
);
3362 free (object_id_list
);
3363 free (object_type_list
);
3365 if (!throw_drc_dialog())
3367 IncrementUndoSerialNumber ();
3372 /* now check the bloated condition */
3374 ClearFlagOnAllObjects (false, TheFlag
);
3375 TheFlag
= FOUNDFLAG
;
3376 ListStart (What
, ptr1
, ptr2
, ptr3
);
3379 while (DoIt (true, false))
3382 /* make the flag changes undoable */
3383 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3384 ClearFlagOnAllObjects (false, TheFlag
);
3388 TheFlag
= SELECTEDFLAG
;
3389 ListStart (What
, ptr1
, ptr2
, ptr3
);
3392 TheFlag
= FOUNDFLAG
;
3393 ListStart (What
, ptr1
, ptr2
, ptr3
);
3399 LocateError (&x
, &y
);
3400 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3401 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3402 _("Circuits that are too close may bridge during imaging, etching,\n"
3403 "plating, or soldering processes resulting in a direct short."),
3405 0, /* ANGLE OF ERROR UNKNOWN */
3406 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3407 0, /* MAGNITUDE OF ERROR UNKNOWN */
3412 append_drc_violation (violation
);
3413 pcb_drc_violation_free (violation
);
3414 free (object_id_list
);
3415 free (object_type_list
);
3418 if (!throw_drc_dialog())
3420 IncrementUndoSerialNumber ();
3422 /* highlight the rest of the encroaching net so it's not reported again */
3423 TheFlag
|= SELECTEDFLAG
;
3425 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
);
3430 ListStart (What
, ptr1
, ptr2
, ptr3
);
3434 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3435 ClearFlagOnAllObjects (false, TheFlag
);
3439 /* DRC clearance callback */
3442 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3443 int type
, void *ptr1
, void *ptr2
)
3448 long int *object_id_list
;
3449 int *object_type_list
;
3450 DrcViolationType
*violation
;
3452 LineType
*line
= (LineType
*) ptr2
;
3453 ArcType
*arc
= (ArcType
*) ptr2
;
3454 PinType
*pin
= (PinType
*) ptr2
;
3455 PadType
*pad
= (PadType
*) ptr2
;
3464 if (line
->Clearance
< 2 * PCB
->Bloat
)
3466 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3467 SET_FLAG (TheFlag
, line
);
3468 message
= _("Line with insufficient clearance inside polygon\n");
3473 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3475 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3476 SET_FLAG (TheFlag
, arc
);
3477 message
= _("Arc with insufficient clearance inside polygon\n");
3482 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3483 if (IsPadInPolygon(pad
,polygon
))
3485 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3486 SET_FLAG (TheFlag
, pad
);
3487 message
= _("Pad with insufficient clearance inside polygon\n");
3492 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3494 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3495 SET_FLAG (TheFlag
, pin
);
3496 message
= _("Pin with insufficient clearance inside polygon\n");
3501 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3503 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3504 SET_FLAG (TheFlag
, pin
);
3505 message
= _("Via with insufficient clearance inside polygon\n");
3510 Message ("hace: Bad Plow object in callback\n");
3515 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3516 SET_FLAG (FOUNDFLAG
, polygon
);
3517 DrawPolygon (layer
, polygon
);
3518 DrawObject (type
, ptr1
, ptr2
);
3520 LocateError (&x
, &y
);
3521 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3522 violation
= pcb_drc_violation_new (message
,
3523 _("Circuits that are too close may bridge during imaging, etching,\n"
3524 "plating, or soldering processes resulting in a direct short."),
3526 0, /* ANGLE OF ERROR UNKNOWN */
3527 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3528 0, /* MAGNITUDE OF ERROR UNKNOWN */
3533 append_drc_violation (violation
);
3534 pcb_drc_violation_free (violation
);
3535 free (object_id_list
);
3536 free (object_type_list
);
3537 if (!throw_drc_dialog())
3542 IncrementUndoSerialNumber ();
3547 /*-----------------------------------------------------------------------------
3548 * Check for DRC violations
3549 * see if the connectivity changes when everything is bloated, or shrunk
3556 long int *object_id_list
;
3557 int *object_type_list
;
3558 DrcViolationType
*violation
;
3562 reset_drc_dialog_message();
3566 SaveStackAndVisibility ();
3567 ResetStackAndVisibility ();
3568 hid_action ("LayersChanged");
3569 InitConnectionLookup ();
3571 TheFlag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3573 if (ClearFlagOnAllObjects (true, TheFlag
))
3575 IncrementUndoSerialNumber ();
3581 ELEMENT_LOOP (PCB
->Data
);
3585 if (!TEST_FLAG (DRCFLAG
, pin
)
3586 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3598 /* count up how many pads have no solderpaste openings */
3599 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3602 if (!TEST_FLAG (DRCFLAG
, pad
)
3603 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3615 VIA_LOOP (PCB
->Data
);
3617 if (!TEST_FLAG (DRCFLAG
, via
)
3618 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3626 TheFlag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3627 ClearFlagOnAllObjects (false, TheFlag
);
3628 TheFlag
= SELECTEDFLAG
;
3629 /* check minimum widths and polygon clearances */
3632 COPPERLINE_LOOP (PCB
->Data
);
3634 /* check line clearances in polygons */
3635 PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
);
3638 if (line
->Thickness
< PCB
->minWid
)
3640 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3641 SET_FLAG (TheFlag
, line
);
3642 DrawLine (layer
, line
);
3644 SetThing (LINE_TYPE
, layer
, line
, line
);
3645 LocateError (&x
, &y
);
3646 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3647 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3648 _("Process specifications dictate a minimum feature-width\n"
3649 "that can reliably be reproduced"),
3651 0, /* ANGLE OF ERROR UNKNOWN */
3652 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3658 append_drc_violation (violation
);
3659 pcb_drc_violation_free (violation
);
3660 free (object_id_list
);
3661 free (object_type_list
);
3662 if (!throw_drc_dialog())
3667 IncrementUndoSerialNumber ();
3675 COPPERARC_LOOP (PCB
->Data
);
3677 PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
);
3680 if (arc
->Thickness
< PCB
->minWid
)
3682 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3683 SET_FLAG (TheFlag
, arc
);
3684 DrawArc (layer
, arc
);
3686 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3687 LocateError (&x
, &y
);
3688 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3689 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3690 _("Process specifications dictate a minimum feature-width\n"
3691 "that can reliably be reproduced"),
3693 0, /* ANGLE OF ERROR UNKNOWN */
3694 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3700 append_drc_violation (violation
);
3701 pcb_drc_violation_free (violation
);
3702 free (object_id_list
);
3703 free (object_type_list
);
3704 if (!throw_drc_dialog())
3709 IncrementUndoSerialNumber ();
3717 ALLPIN_LOOP (PCB
->Data
);
3719 PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
);
3722 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3723 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3725 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3726 SET_FLAG (TheFlag
, pin
);
3729 SetThing (PIN_TYPE
, element
, pin
, pin
);
3730 LocateError (&x
, &y
);
3731 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3732 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3733 _("Annular rings that are too small may erode during etching,\n"
3734 "resulting in a broken connection"),
3736 0, /* ANGLE OF ERROR UNKNOWN */
3737 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3738 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3743 append_drc_violation (violation
);
3744 pcb_drc_violation_free (violation
);
3745 free (object_id_list
);
3746 free (object_type_list
);
3747 if (!throw_drc_dialog())
3752 IncrementUndoSerialNumber ();
3755 if (pin
->DrillingHole
< PCB
->minDrill
)
3757 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3758 SET_FLAG (TheFlag
, pin
);
3761 SetThing (PIN_TYPE
, element
, pin
, pin
);
3762 LocateError (&x
, &y
);
3763 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3764 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3765 _("Process rules dictate the minimum drill size which can be used"),
3767 0, /* ANGLE OF ERROR UNKNOWN */
3768 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3774 append_drc_violation (violation
);
3775 pcb_drc_violation_free (violation
);
3776 free (object_id_list
);
3777 free (object_type_list
);
3778 if (!throw_drc_dialog())
3783 IncrementUndoSerialNumber ();
3791 ALLPAD_LOOP (PCB
->Data
);
3793 PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
);
3796 if (pad
->Thickness
< PCB
->minWid
)
3798 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3799 SET_FLAG (TheFlag
, pad
);
3802 SetThing (PAD_TYPE
, element
, pad
, pad
);
3803 LocateError (&x
, &y
);
3804 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3805 violation
= pcb_drc_violation_new (_("Pad is too thin"),
3806 _("Pads which are too thin may erode during etching,\n"
3807 "resulting in a broken or unreliable connection"),
3809 0, /* ANGLE OF ERROR UNKNOWN */
3810 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3816 append_drc_violation (violation
);
3817 pcb_drc_violation_free (violation
);
3818 free (object_id_list
);
3819 free (object_type_list
);
3820 if (!throw_drc_dialog())
3825 IncrementUndoSerialNumber ();
3833 VIA_LOOP (PCB
->Data
);
3835 PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
);
3838 if (!TEST_FLAG (HOLEFLAG
, via
) &&
3839 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
3841 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3842 SET_FLAG (TheFlag
, via
);
3845 SetThing (VIA_TYPE
, via
, via
, via
);
3846 LocateError (&x
, &y
);
3847 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3848 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
3849 _("Annular rings that are too small may erode during etching,\n"
3850 "resulting in a broken connection"),
3852 0, /* ANGLE OF ERROR UNKNOWN */
3853 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3854 (via
->Thickness
- via
->DrillingHole
) / 2,
3859 append_drc_violation (violation
);
3860 pcb_drc_violation_free (violation
);
3861 free (object_id_list
);
3862 free (object_type_list
);
3863 if (!throw_drc_dialog())
3868 IncrementUndoSerialNumber ();
3871 if (via
->DrillingHole
< PCB
->minDrill
)
3873 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3874 SET_FLAG (TheFlag
, via
);
3877 SetThing (VIA_TYPE
, via
, via
, via
);
3878 LocateError (&x
, &y
);
3879 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3880 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
3881 _("Process rules dictate the minimum drill size which can be used"),
3883 0, /* ANGLE OF ERROR UNKNOWN */
3884 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3890 append_drc_violation (violation
);
3891 pcb_drc_violation_free (violation
);
3892 free (object_id_list
);
3893 free (object_type_list
);
3894 if (!throw_drc_dialog())
3899 IncrementUndoSerialNumber ();
3906 FreeConnectionLookupMemory ();
3907 TheFlag
= FOUNDFLAG
;
3910 /* check silkscreen minimum widths outside of elements */
3911 /* XXX - need to check text and polygons too! */
3912 TheFlag
= SELECTEDFLAG
;
3915 SILKLINE_LOOP (PCB
->Data
);
3917 if (line
->Thickness
< PCB
->minSlk
)
3919 SET_FLAG (TheFlag
, line
);
3920 DrawLine (layer
, line
);
3922 SetThing (LINE_TYPE
, layer
, line
, line
);
3923 LocateError (&x
, &y
);
3924 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3925 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
3926 _("Process specifications dictate a minimum silkscreen feature-width\n"
3927 "that can reliably be reproduced"),
3929 0, /* ANGLE OF ERROR UNKNOWN */
3930 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3936 append_drc_violation (violation
);
3937 pcb_drc_violation_free (violation
);
3938 free (object_id_list
);
3939 free (object_type_list
);
3940 if (!throw_drc_dialog())
3950 /* check silkscreen minimum widths inside of elements */
3951 /* XXX - need to check text and polygons too! */
3952 TheFlag
= SELECTEDFLAG
;
3955 ELEMENT_LOOP (PCB
->Data
);
3958 ELEMENTLINE_LOOP (element
);
3960 if (line
->Thickness
< PCB
->minSlk
)
3971 SET_FLAG (TheFlag
, element
);
3972 DrawElement (element
);
3974 SetThing (ELEMENT_TYPE
, element
, element
, element
);
3975 LocateError (&x
, &y
);
3976 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3978 title
= _("Element %s has %i silk lines which are too thin");
3979 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
3981 /* -4 is for the %s and %i place-holders */
3982 /* +11 is the max printed length for a 32 bit integer */
3983 /* +1 is for the \0 termination */
3984 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
3985 buffer
= (char *)malloc (buflen
);
3986 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
3988 violation
= pcb_drc_violation_new (buffer
,
3989 _("Process specifications dictate a minimum silkscreen\n"
3990 "feature-width that can reliably be reproduced"),
3992 0, /* ANGLE OF ERROR UNKNOWN */
3993 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3994 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4000 append_drc_violation (violation
);
4001 pcb_drc_violation_free (violation
);
4002 free (object_id_list
);
4003 free (object_type_list
);
4004 if (!throw_drc_dialog())
4017 IncrementUndoSerialNumber ();
4021 RestoreStackAndVisibility ();
4022 hid_action ("LayersChanged");
4023 gui
->invalidate_all ();
4027 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4029 nopastecnt
> 1 ? "s have" : " has");
4031 return IsBad
? -drcerr_count
: drcerr_count
;
4034 /*----------------------------------------------------------------------------
4035 * Locate the coordinatates of offending item (thing)
4038 LocateError (Coord
*x
, Coord
*y
)
4044 LineType
*line
= (LineType
*) thing_ptr3
;
4045 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4046 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4051 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4058 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4060 (polygon
->Clipped
->contours
->xmin
+
4061 polygon
->Clipped
->contours
->xmax
) / 2;
4063 (polygon
->Clipped
->contours
->ymin
+
4064 polygon
->Clipped
->contours
->ymax
) / 2;
4070 PinType
*pin
= (PinType
*) thing_ptr3
;
4077 PadType
*pad
= (PadType
*) thing_ptr3
;
4078 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4079 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4084 ElementType
*element
= (ElementType
*) thing_ptr3
;
4085 *x
= element
->MarkX
;
4086 *y
= element
->MarkY
;
4095 /*----------------------------------------------------------------------------
4096 * Build a list of the of offending items by ID. (Currently just "thing")
4099 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4102 *object_id_list
= NULL
;
4103 *object_type_list
= NULL
;
4116 *object_id_list
= (long int *)malloc (sizeof (long int));
4117 *object_type_list
= (int *)malloc (sizeof (int));
4118 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4119 **object_type_list
= thing_type
;
4124 _("Internal error in BuildObjectList: unknown object type %i\n"),
4130 /*----------------------------------------------------------------------------
4131 * center the display to show the offending item (thing)
4138 LocateError (&X
, &Y
);
4145 ChangeGroupVisibility (
4146 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4149 CenterDisplay (X
, Y
);
4153 InitConnectionLookup (void)
4155 InitComponentLookup ();
4156 InitLayoutLookup ();
4160 FreeConnectionLookupMemory (void)
4162 FreeComponentLookupMemory ();
4163 FreeLayoutLookupMemory ();