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 PADLIST_ENTRY(L,I) \
123 (((PadType **)PadList[(L)].Data)[(I)])
125 #define LINELIST_ENTRY(L,I) \
126 (((LineType **)LineList[(L)].Data)[(I)])
128 #define ARCLIST_ENTRY(L,I) \
129 (((ArcType **)ArcList[(L)].Data)[(I)])
131 #define RATLIST_ENTRY(I) \
132 (((RatType **)RatList.Data)[(I)])
134 #define POLYGONLIST_ENTRY(L,I) \
135 (((PolygonType **)PolygonList[(L)].Data)[(I)])
137 #define PVLIST_ENTRY(I) \
138 (((PinType **)PVList.Data)[(I)])
140 #define IS_PV_ON_RAT(PV, Rat) \
141 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
143 #define IS_PV_ON_ARC(PV, Arc) \
144 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
146 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
147 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
149 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
151 #define IS_PV_ON_PAD(PV,Pad) \
152 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
154 static DrcViolationType
155 *pcb_drc_violation_new (const char *title
,
156 const char *explanation
,
160 Coord measured_value
,
161 Coord required_value
,
163 long int *object_id_list
,
164 int *object_type_list
)
166 DrcViolationType
*violation
= (DrcViolationType
*)malloc (sizeof (DrcViolationType
));
168 violation
->title
= strdup (title
);
169 violation
->explanation
= strdup (explanation
);
172 violation
->angle
= angle
;
173 violation
->have_measured
= have_measured
;
174 violation
->measured_value
= measured_value
;
175 violation
->required_value
= required_value
;
176 violation
->object_count
= object_count
;
177 violation
->object_id_list
= object_id_list
;
178 violation
->object_type_list
= object_type_list
;
184 pcb_drc_violation_free (DrcViolationType
*violation
)
186 free (violation
->title
);
187 free (violation
->explanation
);
191 static GString
*drc_dialog_message
;
193 reset_drc_dialog_message(void)
195 if (drc_dialog_message
)
196 g_string_free (drc_dialog_message
, FALSE
);
197 drc_dialog_message
= g_string_new ("");
198 if (gui
->drc_gui
!= NULL
)
200 gui
->drc_gui
->reset_drc_dialog_message ();
204 append_drc_dialog_message(const char *fmt
, ...)
209 new_str
= pcb_vprintf (fmt
, ap
);
210 g_string_append (drc_dialog_message
, new_str
);
215 static void GotoError (void);
218 append_drc_violation (DrcViolationType
*violation
)
220 if (gui
->drc_gui
!= NULL
)
222 gui
->drc_gui
->append_drc_violation (violation
);
226 /* Fallback to formatting the violation message as text */
227 append_drc_dialog_message ("%s\n", violation
->title
);
228 append_drc_dialog_message (_("%m+near %$mD\n"),
229 Settings
.grid_unit
->allow
,
230 violation
->x
, violation
->y
);
234 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
236 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
237 Message (_("%m+near location %$mD\n"),
238 Settings
.grid_unit
->allow
,
239 violation
->x
, violation
->y
);
243 * message when asked about continuing DRC checks after next
244 * violation is found.
246 #define DRC_CONTINUE _("Press Next to continue DRC checking")
247 #define DRC_NEXT _("Next")
248 #define DRC_CANCEL _("Cancel")
251 throw_drc_dialog(void)
255 if (gui
->drc_gui
!= NULL
)
257 r
= gui
->drc_gui
->throw_drc_dialog ();
261 /* Fallback to formatting the violation message as text */
262 append_drc_dialog_message (DRC_CONTINUE
);
263 r
= gui
->confirm_dialog (drc_dialog_message
->str
, DRC_CANCEL
, DRC_NEXT
);
264 reset_drc_dialog_message();
269 /* ---------------------------------------------------------------------------
272 * the two 'dummy' structs for PVs and Pads are necessary for creating
273 * connection lists which include the element's name
277 void **Data
; /* pointer to index data */
278 Cardinal Location
, /* currently used position */
279 DrawLocation
, Number
, /* number of objects in list */
283 /* ---------------------------------------------------------------------------
284 * some local identifiers
286 static Coord Bloat
= 0;
287 static int TheFlag
= FOUNDFLAG
;
288 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
289 static int thing_type
;
290 static bool User
= false; /* user action causing this */
291 static bool drc
= false; /* whether to stop if finding something not found */
292 static bool IsBad
= false;
293 static Cardinal drcerr_count
; /* count of drc errors */
294 static Cardinal TotalP
, TotalV
, NumberOfPads
[2];
295 static ListType LineList
[MAX_LAYER
], /* list of objects to */
296 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
298 /* ---------------------------------------------------------------------------
299 * some local prototypes
301 static bool LookupLOConnectionsToPVList (bool);
302 static bool LookupLOConnectionsToLOList (bool);
303 static bool LookupPVConnectionsToLOList (bool);
304 static bool LookupPVConnectionsToPVList (void);
305 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, bool);
306 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
);
307 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
);
308 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
);
309 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
);
310 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
311 static bool ArcArcIntersect (ArcType
*, ArcType
*);
312 static bool PrepareNextLoop (FILE *);
313 static bool PrintElementConnections (ElementType
*, FILE *, bool);
314 static bool ListsEmpty (bool);
315 static bool DoIt (bool, bool);
316 static void PrintElementNameList (ElementType
*, FILE *);
317 static void PrintConnectionElementName (ElementType
*, FILE *);
318 static void PrintConnectionListEntry (char *, ElementType
*,
320 static void PrintPadConnections (Cardinal
, FILE *, bool);
321 static void PrintPinConnections (FILE *, bool);
322 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*,
324 static void DrawNewConnections (void);
325 static void DumpList (void);
326 static void LocateError (Coord
*, Coord
*);
327 static void BuildObjectList (int *, long int **, int **);
328 static void GotoError (void);
329 static bool DRCFind (int, void *, void *, void *);
330 static bool ListStart (int, void *, void *, void *);
331 static bool SetThing (int, void *, void *, void *);
332 static bool IsArcInPolygon (ArcType
*, PolygonType
*);
333 static bool IsLineInPolygon (LineType
*, PolygonType
*);
334 static bool IsPadInPolygon (PadType
*, PolygonType
*);
335 static bool IsPolygonInPolygon (PolygonType
*, PolygonType
*);
337 /* ---------------------------------------------------------------------------
338 * some of the 'pad' routines are the same as for lines because the 'pad'
339 * struct starts with a line struct. See global.h for details
342 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
344 return LineLineIntersect ((Line
), (LineType
*)Pad
);
348 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
350 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
354 ADD_PV_TO_LIST (PinType
*Pin
)
357 AddObjectToFlagUndoList (Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
358 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
);
359 SET_FLAG (TheFlag
, Pin
);
360 PVLIST_ENTRY (PVList
.Number
) = Pin
;
363 if (PVList
.Number
> PVList
.Size
)
364 printf ("ADD_PV_TO_LIST overflow! num=%d size=%d\n", PVList
.Number
,
367 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pin
))
368 return (SetThing (PIN_TYPE
, Pin
->Element
, Pin
, Pin
));
373 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
)
376 AddObjectToFlagUndoList (PAD_TYPE
, Pad
->Element
, Pad
, Pad
);
377 SET_FLAG (TheFlag
, Pad
);
378 PADLIST_ENTRY ((L
), PadList
[(L
)].Number
) = Pad
;
379 PadList
[(L
)].Number
++;
381 if (PadList
[(L
)].Number
> PadList
[(L
)].Size
)
382 printf ("ADD_PAD_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
383 PadList
[(L
)].Number
, PadList
[(L
)].Size
);
385 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pad
))
386 return (SetThing (PAD_TYPE
, Pad
->Element
, Pad
, Pad
));
391 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
)
394 AddObjectToFlagUndoList (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
395 SET_FLAG (TheFlag
, (Ptr
));
396 LINELIST_ENTRY ((L
), LineList
[(L
)].Number
) = (Ptr
);
397 LineList
[(L
)].Number
++;
399 if (LineList
[(L
)].Number
> LineList
[(L
)].Size
)
400 printf ("ADD_LINE_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
401 LineList
[(L
)].Number
, LineList
[(L
)].Size
);
403 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
404 return (SetThing (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
409 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
)
412 AddObjectToFlagUndoList (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
413 SET_FLAG (TheFlag
, (Ptr
));
414 ARCLIST_ENTRY ((L
), ArcList
[(L
)].Number
) = (Ptr
);
415 ArcList
[(L
)].Number
++;
417 if (ArcList
[(L
)].Number
> ArcList
[(L
)].Size
)
418 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
419 ArcList
[(L
)].Number
, ArcList
[(L
)].Size
);
421 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
422 return (SetThing (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
427 ADD_RAT_TO_LIST (RatType
*Ptr
)
430 AddObjectToFlagUndoList (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
));
431 SET_FLAG (TheFlag
, (Ptr
));
432 RATLIST_ENTRY (RatList
.Number
) = (Ptr
);
435 if (RatList
.Number
> RatList
.Size
)
436 printf ("ADD_RAT_TO_LIST overflow! num=%d size=%d\n",
437 RatList
.Number
, RatList
.Size
);
439 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
440 return (SetThing (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
)));
445 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
)
448 AddObjectToFlagUndoList (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
449 SET_FLAG (TheFlag
, (Ptr
));
450 POLYGONLIST_ENTRY ((L
), PolygonList
[(L
)].Number
) = (Ptr
);
451 PolygonList
[(L
)].Number
++;
453 if (PolygonList
[(L
)].Number
> PolygonList
[(L
)].Size
)
454 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
455 PolygonList
[(L
)].Number
, PolygonList
[(L
)].Size
);
457 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
458 return (SetThing (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
463 PinLineIntersect (PinType
*PV
, LineType
*Line
)
465 /* IsLineInRectangle already has Bloat factor */
466 return TEST_FLAG (SQUAREFLAG
,
467 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
468 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
469 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
470 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
471 Line
) : IsPointInPad (PV
->X
,
483 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
489 if (type
== PIN_TYPE
&& ptr1
== NULL
)
492 thing_type
= VIA_TYPE
;
498 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
500 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
502 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
508 PadPadIntersect (PadType
*p1
, PadType
*p2
)
510 return LinePadIntersect ((LineType
*) p1
, p2
);
514 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
519 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
520 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
521 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
522 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
524 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
526 /* check for square/square overlap */
531 t2
= PV2
->Thickness
/ 2.0;
536 return BoxBoxIntersection (&b1
, &b2
);
539 /* ---------------------------------------------------------------------------
540 * releases all allocated memory
543 FreeLayoutLookupMemory (void)
547 for (i
= 0; i
< max_copper_layer
; i
++)
549 free (LineList
[i
].Data
);
550 LineList
[i
].Data
= NULL
;
551 free (ArcList
[i
].Data
);
552 ArcList
[i
].Data
= NULL
;
553 free (PolygonList
[i
].Data
);
554 PolygonList
[i
].Data
= NULL
;
563 FreeComponentLookupMemory (void)
565 free (PadList
[0].Data
);
566 PadList
[0].Data
= NULL
;
567 free (PadList
[1].Data
);
568 PadList
[1].Data
= NULL
;
571 /* ---------------------------------------------------------------------------
572 * allocates memory for component related stacks ...
573 * initializes index and sorts it by X1 and X2
576 InitComponentLookup (void)
580 /* initialize pad data; start by counting the total number
581 * on each of the two possible layers
583 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
584 ALLPAD_LOOP (PCB
->Data
);
586 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
587 NumberOfPads
[SOLDER_LAYER
]++;
589 NumberOfPads
[COMPONENT_LAYER
]++;
592 for (i
= 0; i
< 2; i
++)
594 /* allocate memory for working list */
595 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
597 /* clear some struct members */
598 PadList
[i
].Location
= 0;
599 PadList
[i
].DrawLocation
= 0;
600 PadList
[i
].Number
= 0;
601 PadList
[i
].Size
= NumberOfPads
[i
];
605 /* ---------------------------------------------------------------------------
606 * allocates memory for component related stacks ...
607 * initializes index and sorts it by X1 and X2
610 InitLayoutLookup (void)
614 /* initialize line arc and polygon data */
615 for (i
= 0; i
< max_copper_layer
; i
++)
617 LayerType
*layer
= LAYER_PTR (i
);
621 /* allocate memory for line pointer lists */
622 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
623 LineList
[i
].Size
= layer
->LineN
;
627 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
628 ArcList
[i
].Size
= layer
->ArcN
;
632 /* allocate memory for polygon list */
635 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
636 PolygonList
[i
].Size
= layer
->PolygonN
;
639 /* clear some struct members */
640 LineList
[i
].Location
= 0;
641 LineList
[i
].DrawLocation
= 0;
642 LineList
[i
].Number
= 0;
643 ArcList
[i
].Location
= 0;
644 ArcList
[i
].DrawLocation
= 0;
645 ArcList
[i
].Number
= 0;
646 PolygonList
[i
].Location
= 0;
647 PolygonList
[i
].DrawLocation
= 0;
648 PolygonList
[i
].Number
= 0;
651 if (PCB
->Data
->pin_tree
)
652 TotalP
= PCB
->Data
->pin_tree
->size
;
655 if (PCB
->Data
->via_tree
)
656 TotalV
= PCB
->Data
->via_tree
->size
;
659 /* allocate memory for 'new PV to check' list and clear struct */
660 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
661 PVList
.Size
= TotalP
+ TotalV
;
663 PVList
.DrawLocation
= 0;
665 /* Initialize ratline data */
666 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
667 RatList
.Size
= PCB
->Data
->RatN
;
668 RatList
.Location
= 0;
669 RatList
.DrawLocation
= 0;
681 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
683 LineType
*line
= (LineType
*) b
;
684 struct pv_info
*i
= (struct pv_info
*) cl
;
686 if (!TEST_FLAG (TheFlag
, line
) && PinLineIntersect (&i
->pv
, line
) &&
687 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
689 if (ADD_LINE_TO_LIST (i
->layer
, line
))
696 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
698 ArcType
*arc
= (ArcType
*) b
;
699 struct pv_info
*i
= (struct pv_info
*) cl
;
701 if (!TEST_FLAG (TheFlag
, arc
) && IS_PV_ON_ARC (&i
->pv
, arc
) &&
702 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
704 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
711 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
713 PadType
*pad
= (PadType
*) b
;
714 struct pv_info
*i
= (struct pv_info
*) cl
;
716 if (!TEST_FLAG (TheFlag
, pad
) && IS_PV_ON_PAD (&i
->pv
, pad
) &&
717 !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
718 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
719 COMPONENT_LAYER
, pad
))
725 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
727 RatType
*rat
= (RatType
*) b
;
728 struct pv_info
*i
= (struct pv_info
*) cl
;
730 if (!TEST_FLAG (TheFlag
, rat
) && IS_PV_ON_RAT (&i
->pv
, rat
) &&
731 ADD_RAT_TO_LIST (rat
))
736 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
738 PolygonType
*polygon
= (PolygonType
*) b
;
739 struct pv_info
*i
= (struct pv_info
*) cl
;
741 /* if the pin doesn't have a therm and polygon is clearing
742 * then it can't touch due to clearance, so skip the expensive
743 * test. If it does have a therm, you still need to test
744 * because it might not be inside the polygon, or it could
745 * be on an edge such that it doesn't actually touch.
747 if (!TEST_FLAG (TheFlag
, polygon
) && !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
748 (TEST_THERM (i
->layer
, &i
->pv
) ||
749 !TEST_FLAG (CLEARPOLYFLAG
,
751 || !i
->pv
.Clearance
))
753 double wide
= MAX (0.5 * i
->pv
.Thickness
+ Bloat
, 0);
754 if (TEST_FLAG (SQUAREFLAG
, &i
->pv
))
756 Coord x1
= i
->pv
.X
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
757 Coord x2
= i
->pv
.X
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
758 Coord y1
= i
->pv
.Y
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
759 Coord y2
= i
->pv
.Y
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
760 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
761 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
764 else if (TEST_FLAG (OCTAGONFLAG
, &i
->pv
))
766 POLYAREA
*oct
= OctagonPoly (i
->pv
.X
, i
->pv
.Y
, i
->pv
.Thickness
/ 2);
767 if (isects (oct
, polygon
, true)
768 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
771 else if (IsPointInPolygon (i
->pv
.X
, i
->pv
.Y
, wide
,
773 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
779 /* ---------------------------------------------------------------------------
780 * checks if a PV is connected to LOs, if it is, the LO is added to
781 * the appropriate list and the 'used' flag is set
784 LookupLOConnectionsToPVList (bool AndRats
)
789 /* loop over all PVs currently on list */
790 while (PVList
.Location
< PVList
.Number
)
792 /* get pointer to data */
793 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
794 EXPAND_BOUNDS (&info
.pv
);
797 if (setjmp (info
.env
) == 0)
798 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pv
, NULL
,
799 LOCtoPVpad_callback
, &info
);
803 /* now all lines, arcs and polygons of the several layers */
804 for (layer
= 0; layer
< max_copper_layer
; layer
++)
806 if (LAYER_PTR (layer
)->no_drc
)
809 /* add touching lines */
810 if (setjmp (info
.env
) == 0)
811 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.pv
,
812 NULL
, LOCtoPVline_callback
, &info
);
815 /* add touching arcs */
816 if (setjmp (info
.env
) == 0)
817 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.pv
,
818 NULL
, LOCtoPVarc_callback
, &info
);
821 /* check all polygons */
822 if (setjmp (info
.env
) == 0)
823 r_search (LAYER_PTR (layer
)->polygon_tree
, (BoxType
*) & info
.pv
,
824 NULL
, LOCtoPVpoly_callback
, &info
);
828 /* Check for rat-lines that may intersect the PV */
831 if (setjmp (info
.env
) == 0)
832 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.pv
, NULL
,
833 LOCtoPVrat_callback
, &info
);
842 /* ---------------------------------------------------------------------------
843 * find all connections between LO at the current list position and new LOs
846 LookupLOConnectionsToLOList (bool AndRats
)
849 Cardinal i
, group
, layer
, ratposition
,
850 lineposition
[MAX_LAYER
],
851 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
853 /* copy the current LO list positions; the original data is changed
854 * by 'LookupPVConnectionsToLOList()' which has to check the same
855 * list entries plus the new ones
857 for (i
= 0; i
< max_copper_layer
; i
++)
859 lineposition
[i
] = LineList
[i
].Location
;
860 polyposition
[i
] = PolygonList
[i
].Location
;
861 arcposition
[i
] = ArcList
[i
].Location
;
863 for (i
= 0; i
< 2; i
++)
864 padposition
[i
] = PadList
[i
].Location
;
865 ratposition
= RatList
.Location
;
867 /* loop over all new LOs in the list; recurse until no
868 * more new connections in the layergroup were found
876 position
= &ratposition
;
877 for (; *position
< RatList
.Number
; (*position
)++)
879 group
= RATLIST_ENTRY (*position
)->group1
;
880 if (LookupLOConnectionsToRatEnd
881 (&(RATLIST_ENTRY (*position
)->Point1
), group
))
883 group
= RATLIST_ENTRY (*position
)->group2
;
884 if (LookupLOConnectionsToRatEnd
885 (&(RATLIST_ENTRY (*position
)->Point2
), group
))
889 /* loop over all layergroups */
890 for (group
= 0; group
< max_group
; group
++)
894 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
896 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
898 /* be aware that the layer number equal max_copper_layer
899 * and max_copper_layer+1 have a special meaning for pads
901 if (layer
< max_copper_layer
)
903 /* try all new lines */
904 position
= &lineposition
[layer
];
905 for (; *position
< LineList
[layer
].Number
; (*position
)++)
906 if (LookupLOConnectionsToLine
907 (LINELIST_ENTRY (layer
, *position
), group
, true))
910 /* try all new arcs */
911 position
= &arcposition
[layer
];
912 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
913 if (LookupLOConnectionsToArc
914 (ARCLIST_ENTRY (layer
, *position
), group
))
917 /* try all new polygons */
918 position
= &polyposition
[layer
];
919 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
920 if (LookupLOConnectionsToPolygon
921 (POLYGONLIST_ENTRY (layer
, *position
), group
))
926 /* try all new pads */
927 layer
-= max_copper_layer
;
930 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
931 layer
, max_copper_layer
);
934 position
= &padposition
[layer
];
935 for (; *position
< PadList
[layer
].Number
; (*position
)++)
936 if (LookupLOConnectionsToPad
937 (PADLIST_ENTRY (layer
, *position
), group
))
943 /* check if all lists are done; Later for-loops
944 * may have changed the prior lists
946 done
= !AndRats
|| ratposition
>= RatList
.Number
;
947 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
948 padposition
[1] >= PadList
[1].Number
;
949 for (layer
= 0; layer
< max_copper_layer
; layer
++)
951 lineposition
[layer
] >= LineList
[layer
].Number
&&
952 arcposition
[layer
] >= ArcList
[layer
].Number
&&
953 polyposition
[layer
] >= PolygonList
[layer
].Number
;
960 pv_pv_callback (const BoxType
* b
, void *cl
)
962 PinType
*pin
= (PinType
*) b
;
963 struct pv_info
*i
= (struct pv_info
*) cl
;
965 if (!TEST_FLAG (TheFlag
, pin
) && PV_TOUCH_PV (&i
->pv
, pin
))
967 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, &i
->pv
))
969 SET_FLAG (WARNFLAG
, pin
);
970 Settings
.RatWarn
= true;
972 Message (_("WARNING: Hole too close to pin.\n"));
974 Message (_("WARNING: Hole too close to via.\n"));
976 else if (ADD_PV_TO_LIST (pin
))
982 /* ---------------------------------------------------------------------------
983 * searches for new PVs that are connected to PVs on the list
986 LookupPVConnectionsToPVList (void)
992 /* loop over all PVs on list */
993 save_place
= PVList
.Location
;
994 while (PVList
.Location
< PVList
.Number
)
996 /* get pointer to data */
997 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
998 EXPAND_BOUNDS (&info
.pv
);
999 if (setjmp (info
.env
) == 0)
1000 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pv
, NULL
,
1001 pv_pv_callback
, &info
);
1004 if (setjmp (info
.env
) == 0)
1005 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pv
, NULL
,
1006 pv_pv_callback
, &info
);
1011 PVList
.Location
= save_place
;
1021 PolygonType polygon
;
1027 pv_line_callback (const BoxType
* b
, void *cl
)
1029 PinType
*pv
= (PinType
*) b
;
1030 struct lo_info
*i
= (struct lo_info
*) cl
;
1032 if (!TEST_FLAG (TheFlag
, pv
) && PinLineIntersect (pv
, &i
->line
))
1034 if (TEST_FLAG (HOLEFLAG
, pv
))
1036 SET_FLAG (WARNFLAG
, pv
);
1037 Settings
.RatWarn
= true;
1038 Message (_("WARNING: Hole too close to line.\n"));
1040 else if (ADD_PV_TO_LIST (pv
))
1041 longjmp (i
->env
, 1);
1047 pv_pad_callback (const BoxType
* b
, void *cl
)
1049 PinType
*pv
= (PinType
*) b
;
1050 struct lo_info
*i
= (struct lo_info
*) cl
;
1052 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_PAD (pv
, &i
->pad
))
1054 if (TEST_FLAG (HOLEFLAG
, pv
))
1056 SET_FLAG (WARNFLAG
, pv
);
1057 Settings
.RatWarn
= true;
1058 Message (_("WARNING: Hole too close to pad.\n"));
1060 else if (ADD_PV_TO_LIST (pv
))
1061 longjmp (i
->env
, 1);
1067 pv_arc_callback (const BoxType
* b
, void *cl
)
1069 PinType
*pv
= (PinType
*) b
;
1070 struct lo_info
*i
= (struct lo_info
*) cl
;
1072 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_ARC (pv
, &i
->arc
))
1074 if (TEST_FLAG (HOLEFLAG
, pv
))
1076 SET_FLAG (WARNFLAG
, pv
);
1077 Settings
.RatWarn
= true;
1078 Message (_("WARNING: Hole touches arc.\n"));
1080 else if (ADD_PV_TO_LIST (pv
))
1081 longjmp (i
->env
, 1);
1087 pv_poly_callback (const BoxType
* b
, void *cl
)
1089 PinType
*pv
= (PinType
*) b
;
1090 struct lo_info
*i
= (struct lo_info
*) cl
;
1092 /* note that holes in polygons are ok, so they don't generate warnings. */
1093 if (!TEST_FLAG (TheFlag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1094 (TEST_THERM (i
->layer
, pv
) ||
1095 !TEST_FLAG (CLEARPOLYFLAG
, &i
->polygon
) ||
1098 if (TEST_FLAG (SQUAREFLAG
, pv
))
1100 Coord x1
, x2
, y1
, y2
;
1101 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1102 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1103 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1104 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1105 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, &i
->polygon
)
1106 && ADD_PV_TO_LIST (pv
))
1107 longjmp (i
->env
, 1);
1109 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1111 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1112 if (isects (oct
, &i
->polygon
, true) && ADD_PV_TO_LIST (pv
))
1113 longjmp (i
->env
, 1);
1117 if (IsPointInPolygon
1118 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, &i
->polygon
)
1119 && ADD_PV_TO_LIST (pv
))
1120 longjmp (i
->env
, 1);
1127 pv_rat_callback (const BoxType
* b
, void *cl
)
1129 PinType
*pv
= (PinType
*) b
;
1130 struct lo_info
*i
= (struct lo_info
*) cl
;
1132 /* rats can't cause DRC so there is no early exit */
1133 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_RAT (pv
, &i
->rat
))
1134 ADD_PV_TO_LIST (pv
);
1138 /* ---------------------------------------------------------------------------
1139 * searches for new PVs that are connected to NEW LOs on the list
1140 * This routine updates the position counter of the lists too.
1143 LookupPVConnectionsToLOList (bool AndRats
)
1146 struct lo_info info
;
1148 /* loop over all layers */
1149 for (layer
= 0; layer
< max_copper_layer
; layer
++)
1151 if (LAYER_PTR (layer
)->no_drc
)
1153 /* do nothing if there are no PV's */
1154 if (TotalP
+ TotalV
== 0)
1156 LineList
[layer
].Location
= LineList
[layer
].Number
;
1157 ArcList
[layer
].Location
= ArcList
[layer
].Number
;
1158 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
;
1162 /* check all lines */
1163 while (LineList
[layer
].Location
< LineList
[layer
].Number
)
1165 info
.line
= *(LINELIST_ENTRY (layer
, LineList
[layer
].Location
));
1166 EXPAND_BOUNDS (&info
.line
);
1167 if (setjmp (info
.env
) == 0)
1168 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1169 pv_line_callback
, &info
);
1172 if (setjmp (info
.env
) == 0)
1173 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1174 pv_line_callback
, &info
);
1177 LineList
[layer
].Location
++;
1180 /* check all arcs */
1181 while (ArcList
[layer
].Location
< ArcList
[layer
].Number
)
1183 info
.arc
= *(ARCLIST_ENTRY (layer
, ArcList
[layer
].Location
));
1184 EXPAND_BOUNDS (&info
.arc
);
1185 if (setjmp (info
.env
) == 0)
1186 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.arc
, NULL
,
1187 pv_arc_callback
, &info
);
1190 if (setjmp (info
.env
) == 0)
1191 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.arc
, NULL
,
1192 pv_arc_callback
, &info
);
1195 ArcList
[layer
].Location
++;
1198 /* now all polygons */
1200 while (PolygonList
[layer
].Location
< PolygonList
[layer
].Number
)
1203 *(POLYGONLIST_ENTRY (layer
, PolygonList
[layer
].Location
));
1204 EXPAND_BOUNDS (&info
.polygon
);
1205 if (setjmp (info
.env
) == 0)
1206 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.polygon
, NULL
,
1207 pv_poly_callback
, &info
);
1210 if (setjmp (info
.env
) == 0)
1211 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.polygon
, NULL
,
1212 pv_poly_callback
, &info
);
1215 PolygonList
[layer
].Location
++;
1219 /* loop over all pad-layers */
1220 for (layer
= 0; layer
< 2; layer
++)
1222 /* do nothing if there are no PV's */
1223 if (TotalP
+ TotalV
== 0)
1225 PadList
[layer
].Location
= PadList
[layer
].Number
;
1229 /* check all pads; for a detailed description see
1230 * the handling of lines in this subroutine
1232 while (PadList
[layer
].Location
< PadList
[layer
].Number
)
1234 info
.pad
= *(PADLIST_ENTRY (layer
, PadList
[layer
].Location
));
1235 EXPAND_BOUNDS (&info
.pad
);
1236 if (setjmp (info
.env
) == 0)
1237 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pad
, NULL
,
1238 pv_pad_callback
, &info
);
1241 if (setjmp (info
.env
) == 0)
1242 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pad
, NULL
,
1243 pv_pad_callback
, &info
);
1246 PadList
[layer
].Location
++;
1250 /* do nothing if there are no PV's */
1251 if (TotalP
+ TotalV
== 0)
1252 RatList
.Location
= RatList
.Number
;
1254 /* check all rat-lines */
1257 while (RatList
.Location
< RatList
.Number
)
1259 info
.rat
= *(RATLIST_ENTRY (RatList
.Location
));
1260 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point1
, 1, NULL
,
1261 pv_rat_callback
, &info
);
1262 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point2
, 1, NULL
,
1263 pv_rat_callback
, &info
);
1264 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point1
, 1, NULL
,
1265 pv_rat_callback
, &info
);
1266 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point2
, 1, NULL
,
1267 pv_rat_callback
, &info
);
1276 pv_touch_callback (const BoxType
* b
, void *cl
)
1278 PinType
*pin
= (PinType
*) b
;
1279 struct lo_info
*i
= (struct lo_info
*) cl
;
1281 if (!TEST_FLAG (TheFlag
, pin
) && PinLineIntersect (pin
, &i
->line
))
1282 longjmp (i
->env
, 1);
1286 /* reduce arc start angle and delta to 0..360 */
1288 normalize_angles (Angle
*sa
, Angle
*d
)
1295 if (*d
> 360) /* full circle */
1297 *sa
= NormalizeAngle (*sa
);
1301 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1303 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1304 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1306 normalize_angles (&sa
, &d
);
1310 return (sa
+ d
) >= alpha
;
1311 return (sa
+ d
- 360) >= alpha
;
1315 get_arc_ends (Coord
*box
, ArcType
*arc
)
1317 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1318 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1319 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1320 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1322 /* ---------------------------------------------------------------------------
1323 * check if two arcs intersect
1324 * first we check for circle intersections,
1325 * then find the actual points of intersection
1326 * and test them to see if they are on arcs
1328 * consider a, the distance from the center of arc 1
1329 * to the point perpendicular to the intersecting points.
1331 * a = (r1^2 - r2^2 + l^2)/(2l)
1333 * the perpendicular distance to the point of intersection
1336 * d = sqrt(r1^2 - a^2)
1338 * the points of intersection would then be
1340 * x = X1 + a/l dx +- d/l dy
1341 * y = Y1 + a/l dy -+ d/l dx
1343 * where dx = X2 - X1 and dy = Y2 - Y1
1348 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1350 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1354 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1355 t2
= 0.5 * Arc2
->Thickness
;
1359 if (t
< 0 || t1
< 0)
1362 /* try the end points first */
1363 get_arc_ends (&box
[0], Arc1
);
1364 get_arc_ends (&box
[4], Arc2
);
1365 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1366 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1367 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1368 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1371 pdx
= Arc2
->X
- Arc1
->X
;
1372 pdy
= Arc2
->Y
- Arc1
->Y
;
1373 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1374 /* concentric arcs, simpler intersection conditions */
1377 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1378 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1379 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1380 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1382 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1383 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1384 /* NB the endpoints have already been checked,
1385 so we just compare the angles */
1387 normalize_angles (&sa1
, &d1
);
1388 normalize_angles (&sa2
, &d2
);
1389 /* sa1 == sa2 was caught when checking endpoints */
1391 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1394 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1401 /* arcs centerlines are too far or too near */
1402 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1404 /* check the nearest to the other arc's center point */
1407 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1413 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1414 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1417 dx
= - pdx
* r2
/ dl
;
1418 dy
= - pdy
* r2
/ dl
;
1419 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1425 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1426 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1434 a
= 0.5 * (r1
- r2
+ l
) / l
;
1437 /* the circles are too far apart to touch or probably just touch:
1438 check the nearest point */
1443 x
= Arc1
->X
+ a
* pdx
;
1444 y
= Arc1
->Y
+ a
* pdy
;
1447 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1448 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1450 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1451 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1454 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1455 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1457 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1458 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1463 /* ---------------------------------------------------------------------------
1464 * Tests if point is same as line end point
1467 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1469 if ((Point
->X
== Line
->Point1
.X
1470 && Point
->Y
== Line
->Point1
.Y
)
1471 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1477 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1478 /* writes vertices of a squared line */
1480 double dwx
= 0, dwy
= 0;
1481 if (l
->Point1
.Y
== l
->Point2
.Y
)
1482 dwx
= l
->Thickness
/ 2.0;
1483 else if (l
->Point1
.X
== l
->Point2
.X
)
1484 dwy
= l
->Thickness
/ 2.0;
1487 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1488 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1489 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1490 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1491 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1493 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1494 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1495 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1496 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1498 /* ---------------------------------------------------------------------------
1499 * checks if two lines intersect
1502 * Let A,B,C,D be 2-space position vectors. Then the directed line
1503 * segments AB & CD are given by:
1505 * AB=A+r(B-A), r in [0,1]
1506 * CD=C+s(D-C), s in [0,1]
1508 * If AB & CD intersect, then
1510 * A+r(B-A)=C+s(D-C), or
1512 * XA+r(XB-XA)=XC+s(XD-XC)
1513 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1515 * Solving the above for r and s yields
1517 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1518 * r = ----------------------------- (eqn 1)
1519 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1521 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1522 * s = ----------------------------- (eqn 2)
1523 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1525 * Let I be the position vector of the intersection point, then
1532 * By examining the values of r & s, you can also determine some
1533 * other limiting conditions:
1535 * If 0<=r<=1 & 0<=s<=1, intersection exists
1536 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1538 * If the denominator in eqn 1 is zero, AB & CD are parallel
1539 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1541 * If the intersection point of the 2 lines are needed (lines in this
1542 * context mean infinite lines) regardless whether the two line
1543 * segments intersect, then
1545 * If r>1, I is located on extension of AB
1546 * If r<0, I is located on extension of BA
1547 * If s>1, I is located on extension of CD
1548 * If s<0, I is located on extension of DC
1550 * Also note that the denominators of eqn 1 & 2 are identical.
1554 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1557 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1558 point1_dx
, point1_dy
;
1559 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1562 form_slanted_rectangle (p
, Line1
);
1563 return IsLineInQuadrangle (p
, Line2
);
1565 /* here come only round Line1 because IsLineInQuadrangle()
1566 calls LineLineIntersect() with first argument rounded*/
1567 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1570 form_slanted_rectangle (p
, Line2
);
1571 return IsLineInQuadrangle (p
, Line1
);
1573 /* now all lines are round */
1575 /* Check endpoints: this provides a quick exit, catches
1576 * cases where the "real" lines don't intersect but the
1577 * thick lines touch, and ensures that the dx/dy business
1578 * below does not cause a divide-by-zero. */
1579 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1580 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1582 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1583 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1585 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1586 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1588 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1589 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1593 /* setup some constants */
1594 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1595 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1596 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1597 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1598 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1599 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1601 /* If either line is a point, we have failed already, since the
1602 * endpoint check above will have caught an "intersection". */
1603 if ((line1_dx
== 0 && line1_dy
== 0)
1604 || (line2_dx
== 0 && line2_dy
== 0))
1607 /* set s to cross product of Line1 and the line
1608 * Line1.Point1--Line2.Point1 (as vectors) */
1609 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1611 /* set r to cross product of both lines (as vectors) */
1612 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1614 /* No cross product means parallel lines, or maybe Line2 is
1615 * zero-length. In either case, since we did a bounding-box
1616 * check before getting here, the above IsPointInPad() checks
1617 * will have caught any intersections. */
1622 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1624 /* intersection is at least on AB */
1625 if (r
>= 0.0 && r
<= 1.0)
1626 return (s
>= 0.0 && s
<= 1.0);
1628 /* intersection is at least on CD */
1629 /* [removed this case since it always returns false --asp] */
1633 /*---------------------------------------------------
1635 * Check for line intersection with an arc
1637 * Mostly this is like the circle/line intersection
1638 * found in IsPointOnLine (search.c) see the detailed
1639 * discussion for the basics there.
1641 * Since this is only an arc, not a full circle we need
1642 * to find the actual points of intersection with the
1643 * circle, and see if they are on the arc.
1645 * To do this, we translate along the line from the point Q
1646 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1647 * but it's handy to normalize with respect to l, the line
1648 * length so a single projection is done (e.g. we don't first
1651 * The projection is now of the form
1653 * Px = X1 + (r +- r2)(X2 - X1)
1654 * Py = Y1 + (r +- r2)(Y2 - Y1)
1656 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1657 * note that this is the variable d, not the symbol d described in IsPointOnLine
1658 * (variable d = symbol d * l)
1660 * The end points are hell so they are checked individually
1663 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1665 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1668 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1669 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1670 dx1
= Line
->Point1
.X
- Arc
->X
;
1671 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1672 l
= dx
* dx
+ dy
* dy
;
1673 d
= dx
* dy1
- dy
* dx1
;
1676 /* use the larger diameter circle first */
1678 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1680 r2
= Radius
* l
- d
;
1681 /* projection doesn't even intersect circle when r2 < 0 */
1684 /* check the ends of the line in case the projected point */
1685 /* of intersection is beyond the line end */
1687 (Line
->Point1
.X
, Line
->Point1
.Y
,
1688 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1691 (Line
->Point2
.X
, Line
->Point2
.Y
,
1692 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1697 Radius
= -(dx
* dx1
+ dy
* dy1
);
1698 r
= (Radius
+ r2
) / l
;
1699 if (r
>= 0 && r
<= 1
1700 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1701 Line
->Point1
.Y
+ r
* dy
,
1702 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1704 r
= (Radius
- r2
) / l
;
1705 if (r
>= 0 && r
<= 1
1706 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1707 Line
->Point1
.Y
+ r
* dy
,
1708 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1710 /* check arc end points */
1711 box
= GetArcEnds (Arc
);
1712 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1714 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1720 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1722 LineType
*line
= (LineType
*) b
;
1723 struct lo_info
*i
= (struct lo_info
*) cl
;
1725 if (!TEST_FLAG (TheFlag
, line
) && LineArcIntersect (line
, &i
->arc
))
1727 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1728 longjmp (i
->env
, 1);
1734 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1736 ArcType
*arc
= (ArcType
*) b
;
1737 struct lo_info
*i
= (struct lo_info
*) cl
;
1739 if (!arc
->Thickness
)
1741 if (!TEST_FLAG (TheFlag
, arc
) && ArcArcIntersect (&i
->arc
, arc
))
1743 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1744 longjmp (i
->env
, 1);
1750 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1752 PadType
*pad
= (PadType
*) b
;
1753 struct lo_info
*i
= (struct lo_info
*) cl
;
1755 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1756 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1757 && ArcPadIntersect (&i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1758 longjmp (i
->env
, 1);
1762 /* ---------------------------------------------------------------------------
1763 * searches all LOs that are connected to the given arc on the given
1764 * layergroup. All found connections are added to the list
1766 * the notation that is used is:
1767 * Xij means Xj at arc i
1770 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
)
1773 struct lo_info info
;
1776 EXPAND_BOUNDS (&info
.arc
);
1777 /* loop over all layers of the group */
1778 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1783 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1785 /* handle normal layers */
1786 if (layer
< max_copper_layer
)
1790 if (setjmp (info
.env
) == 0)
1791 r_search (LAYER_PTR (layer
)->line_tree
, &info
.arc
.BoundingBox
,
1792 NULL
, LOCtoArcLine_callback
, &info
);
1796 if (setjmp (info
.env
) == 0)
1797 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.arc
.BoundingBox
,
1798 NULL
, LOCtoArcArc_callback
, &info
);
1802 /* now check all polygons */
1803 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1804 i
!= NULL
; i
= g_list_next (i
))
1806 PolygonType
*polygon
= i
->data
;
1807 if (!TEST_FLAG (TheFlag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1808 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1814 info
.layer
= layer
- max_copper_layer
;
1815 if (setjmp (info
.env
) == 0)
1816 r_search (PCB
->Data
->pad_tree
, &info
.arc
.BoundingBox
, NULL
,
1817 LOCtoArcPad_callback
, &info
);
1826 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1828 LineType
*line
= (LineType
*) b
;
1829 struct lo_info
*i
= (struct lo_info
*) cl
;
1831 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1833 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1834 longjmp (i
->env
, 1);
1840 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1842 ArcType
*arc
= (ArcType
*) b
;
1843 struct lo_info
*i
= (struct lo_info
*) cl
;
1845 if (!arc
->Thickness
)
1847 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
1849 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1850 longjmp (i
->env
, 1);
1856 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1858 RatType
*rat
= (RatType
*) b
;
1859 struct lo_info
*i
= (struct lo_info
*) cl
;
1861 if (!TEST_FLAG (TheFlag
, rat
))
1863 if ((rat
->group1
== i
->layer
)
1864 && IsRatPointOnLineEnd (&rat
->Point1
, &i
->line
))
1866 if (ADD_RAT_TO_LIST (rat
))
1867 longjmp (i
->env
, 1);
1869 else if ((rat
->group2
== i
->layer
)
1870 && IsRatPointOnLineEnd (&rat
->Point2
, &i
->line
))
1872 if (ADD_RAT_TO_LIST (rat
))
1873 longjmp (i
->env
, 1);
1880 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1882 PadType
*pad
= (PadType
*) b
;
1883 struct lo_info
*i
= (struct lo_info
*) cl
;
1885 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1886 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1887 && LinePadIntersect (&i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1888 longjmp (i
->env
, 1);
1892 /* ---------------------------------------------------------------------------
1893 * searches all LOs that are connected to the given line on the given
1894 * layergroup. All found connections are added to the list
1896 * the notation that is used is:
1897 * Xij means Xj at line i
1900 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1904 struct lo_info info
;
1907 info
.layer
= LayerGroup
;
1908 EXPAND_BOUNDS (&info
.line
)
1909 /* add the new rat lines */
1910 if (setjmp (info
.env
) == 0)
1911 r_search (PCB
->Data
->rat_tree
, &info
.line
.BoundingBox
, NULL
,
1912 LOCtoLineRat_callback
, &info
);
1916 /* loop over all layers of the group */
1917 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1921 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1923 /* handle normal layers */
1924 if (layer
< max_copper_layer
)
1928 if (setjmp (info
.env
) == 0)
1929 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
1930 NULL
, LOCtoLineLine_callback
, &info
);
1934 if (setjmp (info
.env
) == 0)
1935 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
1936 NULL
, LOCtoLineArc_callback
, &info
);
1939 /* now check all polygons */
1943 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1944 i
!= NULL
; i
= g_list_next (i
))
1946 PolygonType
*polygon
= i
->data
;
1948 (TheFlag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1949 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1956 /* handle special 'pad' layers */
1957 info
.layer
= layer
- max_copper_layer
;
1958 if (setjmp (info
.env
) == 0)
1959 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
1960 LOCtoLinePad_callback
, &info
);
1976 LOCtoRat_callback (const BoxType
* b
, void *cl
)
1978 LineType
*line
= (LineType
*) b
;
1979 struct rat_info
*i
= (struct rat_info
*) cl
;
1981 if (!TEST_FLAG (TheFlag
, line
) &&
1982 ((line
->Point1
.X
== i
->Point
->X
&&
1983 line
->Point1
.Y
== i
->Point
->Y
) ||
1984 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
1986 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1987 longjmp (i
->env
, 1);
1992 PolygonToRat_callback (const BoxType
* b
, void *cl
)
1994 PolygonType
*polygon
= (PolygonType
*) b
;
1995 struct rat_info
*i
= (struct rat_info
*) cl
;
1997 if (!TEST_FLAG (TheFlag
, polygon
) && polygon
->Clipped
&&
1998 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
1999 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
2001 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2002 longjmp (i
->env
, 1);
2008 LOCtoPad_callback (const BoxType
* b
, void *cl
)
2010 PadType
*pad
= (PadType
*) b
;
2011 struct rat_info
*i
= (struct rat_info
*) cl
;
2013 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2014 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
2015 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
2016 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
2017 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
2018 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
2019 ADD_PAD_TO_LIST (i
->layer
, pad
))
2020 longjmp (i
->env
, 1);
2024 /* ---------------------------------------------------------------------------
2025 * searches all LOs that are connected to the given rat-line on the given
2026 * layergroup. All found connections are added to the list
2028 * the notation that is used is:
2029 * Xij means Xj at line i
2032 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
)
2035 struct rat_info info
;
2038 /* loop over all layers of this group */
2039 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2043 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2044 /* handle normal layers
2045 rats don't ever touch
2049 if (layer
< max_copper_layer
)
2052 if (setjmp (info
.env
) == 0)
2053 r_search_pt (LAYER_PTR (layer
)->line_tree
, Point
, 1, NULL
,
2054 LOCtoRat_callback
, &info
);
2057 if (setjmp (info
.env
) == 0)
2058 r_search_pt (LAYER_PTR (layer
)->polygon_tree
, Point
, 1,
2059 NULL
, PolygonToRat_callback
, &info
);
2063 /* handle special 'pad' layers */
2064 info
.layer
= layer
- max_copper_layer
;
2065 if (setjmp (info
.env
) == 0)
2066 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2067 LOCtoPad_callback
, &info
);
2076 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2078 LineType
*line
= (LineType
*) b
;
2079 struct lo_info
*i
= (struct lo_info
*) cl
;
2081 if (!TEST_FLAG (TheFlag
, line
) && LinePadIntersect (line
, &i
->pad
))
2083 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2084 longjmp (i
->env
, 1);
2090 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2092 ArcType
*arc
= (ArcType
*) b
;
2093 struct lo_info
*i
= (struct lo_info
*) cl
;
2095 if (!arc
->Thickness
)
2097 if (!TEST_FLAG (TheFlag
, arc
) && ArcPadIntersect (arc
, &i
->pad
))
2099 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2100 longjmp (i
->env
, 1);
2106 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2108 PolygonType
*polygon
= (PolygonType
*) b
;
2109 struct lo_info
*i
= (struct lo_info
*) cl
;
2112 if (!TEST_FLAG (TheFlag
, polygon
) &&
2113 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
.Clearance
))
2115 if (IsPadInPolygon (&i
->pad
, polygon
) &&
2116 ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2117 longjmp (i
->env
, 1);
2123 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2125 RatType
*rat
= (RatType
*) b
;
2126 struct lo_info
*i
= (struct lo_info
*) cl
;
2128 if (!TEST_FLAG (TheFlag
, rat
))
2130 if (rat
->group1
== i
->layer
&&
2131 ((rat
->Point1
.X
== i
->pad
.Point1
.X
&& rat
->Point1
.Y
== i
->pad
.Point1
.Y
) ||
2132 (rat
->Point1
.X
== i
->pad
.Point2
.X
&& rat
->Point1
.Y
== i
->pad
.Point2
.Y
) ||
2133 (rat
->Point1
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2134 rat
->Point1
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2136 if (ADD_RAT_TO_LIST (rat
))
2137 longjmp (i
->env
, 1);
2139 else if (rat
->group2
== i
->layer
&&
2140 ((rat
->Point2
.X
== i
->pad
.Point1
.X
&& rat
->Point2
.Y
== i
->pad
.Point1
.Y
) ||
2141 (rat
->Point2
.X
== i
->pad
.Point2
.X
&& rat
->Point2
.Y
== i
->pad
.Point2
.Y
) ||
2142 (rat
->Point2
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2143 rat
->Point2
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2145 if (ADD_RAT_TO_LIST (rat
))
2146 longjmp (i
->env
, 1);
2153 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2155 PadType
*pad
= (PadType
*) b
;
2156 struct lo_info
*i
= (struct lo_info
*) cl
;
2158 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2159 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2160 && PadPadIntersect (pad
, &i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2161 longjmp (i
->env
, 1);
2165 /* ---------------------------------------------------------------------------
2166 * searches all LOs that are connected to the given pad on the given
2167 * layergroup. All found connections are added to the list
2170 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
)
2173 struct lo_info info
;
2175 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2176 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, false));
2179 EXPAND_BOUNDS (&info
.pad
);
2180 /* add the new rat lines */
2181 info
.layer
= LayerGroup
;
2182 if (setjmp (info
.env
) == 0)
2183 r_search (PCB
->Data
->rat_tree
, &info
.pad
.BoundingBox
, NULL
,
2184 LOCtoPadRat_callback
, &info
);
2188 /* loop over all layers of the group */
2189 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2193 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2194 /* handle normal layers */
2195 if (layer
< max_copper_layer
)
2199 if (setjmp (info
.env
) == 0)
2200 r_search (LAYER_PTR (layer
)->line_tree
, &info
.pad
.BoundingBox
,
2201 NULL
, LOCtoPadLine_callback
, &info
);
2205 if (setjmp (info
.env
) == 0)
2206 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.pad
.BoundingBox
,
2207 NULL
, LOCtoPadArc_callback
, &info
);
2211 if (setjmp (info
.env
) == 0)
2212 r_search (LAYER_PTR (layer
)->polygon_tree
, &info
.pad
.BoundingBox
,
2213 NULL
, LOCtoPadPoly_callback
, &info
);
2219 /* handle special 'pad' layers */
2220 info
.layer
= layer
- max_copper_layer
;
2221 if (setjmp (info
.env
) == 0)
2222 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pad
, NULL
,
2223 LOCtoPadPad_callback
, &info
);
2233 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2235 LineType
*line
= (LineType
*) b
;
2236 struct lo_info
*i
= (struct lo_info
*) cl
;
2238 if (!TEST_FLAG (TheFlag
, line
) && IsLineInPolygon (line
, &i
->polygon
))
2240 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2241 longjmp (i
->env
, 1);
2247 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2249 ArcType
*arc
= (ArcType
*) b
;
2250 struct lo_info
*i
= (struct lo_info
*) cl
;
2252 if (!arc
->Thickness
)
2254 if (!TEST_FLAG (TheFlag
, arc
) && IsArcInPolygon (arc
, &i
->polygon
))
2256 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2257 longjmp (i
->env
, 1);
2263 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2265 PadType
*pad
= (PadType
*) b
;
2266 struct lo_info
*i
= (struct lo_info
*) cl
;
2268 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2269 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2270 && IsPadInPolygon (pad
, &i
->polygon
))
2272 if (ADD_PAD_TO_LIST (i
->layer
, pad
))
2273 longjmp (i
->env
, 1);
2279 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2281 RatType
*rat
= (RatType
*) b
;
2282 struct lo_info
*i
= (struct lo_info
*) cl
;
2284 if (!TEST_FLAG (TheFlag
, rat
))
2286 if ((rat
->Point1
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2287 rat
->Point1
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2288 rat
->group1
== i
->layer
) ||
2289 (rat
->Point2
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2290 rat
->Point2
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2291 rat
->group2
== i
->layer
))
2292 if (ADD_RAT_TO_LIST (rat
))
2293 longjmp (i
->env
, 1);
2299 /* ---------------------------------------------------------------------------
2300 * looks up LOs that are connected to the given polygon
2301 * on the given layergroup. All found connections are added to the list
2304 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
)
2307 struct lo_info info
;
2309 if (!Polygon
->Clipped
)
2311 info
.polygon
= *Polygon
;
2312 EXPAND_BOUNDS (&info
.polygon
);
2313 info
.layer
= LayerGroup
;
2315 if (setjmp (info
.env
) == 0)
2316 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.polygon
, NULL
,
2317 LOCtoPolyRat_callback
, &info
);
2320 /* loop over all layers of the group */
2321 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2325 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2327 /* handle normal layers */
2328 if (layer
< max_copper_layer
)
2332 /* check all polygons */
2333 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
2334 i
!= NULL
; i
= g_list_next (i
))
2336 PolygonType
*polygon
= i
->data
;
2337 if (!TEST_FLAG (TheFlag
, polygon
)
2338 && IsPolygonInPolygon (polygon
, Polygon
)
2339 && ADD_POLYGON_TO_LIST (layer
, polygon
))
2344 /* check all lines */
2345 if (setjmp (info
.env
) == 0)
2346 r_search (LAYER_PTR (layer
)->line_tree
,
2347 (BoxType
*) & info
.polygon
, NULL
,
2348 LOCtoPolyLine_callback
, &info
);
2351 /* check all arcs */
2352 if (setjmp (info
.env
) == 0)
2353 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.polygon
,
2354 NULL
, LOCtoPolyArc_callback
, &info
);
2360 info
.layer
= layer
- max_copper_layer
;
2361 if (setjmp (info
.env
) == 0)
2362 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.polygon
,
2363 NULL
, LOCtoPolyPad_callback
, &info
);
2371 /* ---------------------------------------------------------------------------
2372 * checks if an arc has a connection to a polygon
2374 * - first check if the arc can intersect with the polygon by
2375 * evaluating the bounding boxes
2376 * - check the two end points of the arc. If none of them matches
2377 * - check all segments of the polygon against the arc.
2380 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2382 BoxType
*Box
= (BoxType
*) Arc
;
2384 /* arcs with clearance never touch polys */
2385 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2387 if (!Polygon
->Clipped
)
2389 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2390 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2391 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2392 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2396 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2397 return false; /* error */
2398 return isects (ap
, Polygon
, true);
2403 /* ---------------------------------------------------------------------------
2404 * checks if a line has a connection to a polygon
2406 * - first check if the line can intersect with the polygon by
2407 * evaluating the bounding boxes
2408 * - check the two end points of the line. If none of them matches
2409 * - check all segments of the polygon against the line.
2412 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2414 BoxType
*Box
= (BoxType
*) Line
;
2417 /* lines with clearance never touch polygons */
2418 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2420 if (!Polygon
->Clipped
)
2422 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2424 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2425 Coord x1
, x2
, y1
, y2
;
2427 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2428 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2429 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2430 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2431 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2433 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2434 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2435 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2436 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2438 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2439 return FALSE
; /* error */
2440 return isects (lp
, Polygon
, true);
2445 /* ---------------------------------------------------------------------------
2446 * checks if a pad connects to a non-clearing polygon
2448 * The polygon is assumed to already have been proven non-clearing
2451 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2453 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2456 /* ---------------------------------------------------------------------------
2457 * checks if a polygon has a connection to a second one
2459 * First check all points out of P1 against P2 and vice versa.
2460 * If both fail check all lines of P1 against the ones of P2
2463 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2465 if (!P1
->Clipped
|| !P2
->Clipped
)
2467 assert (P1
->Clipped
->contours
);
2468 assert (P2
->Clipped
->contours
);
2470 /* first check if both bounding boxes intersect. If not, return quickly */
2471 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2472 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2473 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2474 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2477 /* first check un-bloated case */
2478 if (isects (P1
->Clipped
, P2
, false))
2481 /* now the difficult case of bloated */
2485 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2488 VNODE
*v
= &c
->head
;
2489 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2490 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2491 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2492 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2495 line
.Point1
.X
= v
->point
[0];
2496 line
.Point1
.Y
= v
->point
[1];
2497 line
.Thickness
= 2 * Bloat
;
2499 line
.Flags
= NoFlags ();
2500 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2502 line
.Point2
.X
= v
->point
[0];
2503 line
.Point2
.Y
= v
->point
[1];
2504 SetLineBoundingBox (&line
);
2505 if (IsLineInPolygon (&line
, P2
))
2507 line
.Point1
.X
= line
.Point2
.X
;
2508 line
.Point1
.Y
= line
.Point2
.Y
;
2517 /* ---------------------------------------------------------------------------
2518 * writes the several names of an element to a file
2521 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2523 static DynamicStringType cname
, pname
, vname
;
2525 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2526 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2527 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2528 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2531 /* ---------------------------------------------------------------------------
2532 * writes the several names of an element to a file
2535 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2537 fputs ("Element", FP
);
2538 PrintElementNameList (Element
, FP
);
2542 /* ---------------------------------------------------------------------------
2543 * prints one {pin,pad,via}/element entry of connection lists
2546 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2547 bool FirstOne
, FILE * FP
)
2549 static DynamicStringType oname
;
2551 CreateQuotedString (&oname
, ObjName
);
2553 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2556 fprintf (FP
, "\t\t%s ", oname
.Data
);
2558 PrintElementNameList (Element
, FP
);
2560 fputs ("(__VIA__)\n", FP
);
2564 /* ---------------------------------------------------------------------------
2565 * prints all found connections of a pads to file FP
2566 * the connections are stacked in 'PadList'
2569 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2574 if (!PadList
[Layer
].Number
)
2577 /* the starting pad */
2580 ptr
= PADLIST_ENTRY (Layer
, 0);
2582 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2584 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2587 /* we maybe have to start with i=1 if we are handling the
2588 * starting-pad itself
2590 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2592 ptr
= PADLIST_ENTRY (Layer
, i
);
2594 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2596 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2600 /* ---------------------------------------------------------------------------
2601 * prints all found connections of a pin to file FP
2602 * the connections are stacked in 'PVList'
2605 PrintPinConnections (FILE * FP
, bool IsFirst
)
2615 /* the starting pin */
2616 pv
= PVLIST_ENTRY (0);
2617 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2620 /* we maybe have to start with i=1 if we are handling the
2621 * starting-pin itself
2623 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2625 /* get the elements name or assume that its a via */
2626 pv
= PVLIST_ENTRY (i
);
2627 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2631 /* ---------------------------------------------------------------------------
2632 * checks if all lists of new objects are handled
2635 ListsEmpty (bool AndRats
)
2640 empty
= (PVList
.Location
>= PVList
.Number
);
2642 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2643 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2644 if (!LAYER_PTR (i
)->no_drc
)
2645 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2646 && ArcList
[i
].Location
>= ArcList
[i
].Number
2647 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2652 reassign_no_drc_flags (void)
2656 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2658 LayerType
*l
= LAYER_PTR (layer
);
2659 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2666 /* ---------------------------------------------------------------------------
2667 * loops till no more connections are found
2670 DoIt (bool AndRats
, bool AndDraw
)
2672 bool newone
= false;
2673 reassign_no_drc_flags ();
2676 /* lookup connections; these are the steps (2) to (4)
2677 * from the description
2679 newone
= LookupPVConnectionsToPVList () ||
2680 LookupLOConnectionsToPVList (AndRats
) ||
2681 LookupLOConnectionsToLOList (AndRats
) ||
2682 LookupPVConnectionsToLOList (AndRats
);
2684 DrawNewConnections ();
2686 while (!newone
&& !ListsEmpty (AndRats
));
2692 /* ---------------------------------------------------------------------------
2693 * prints all unused pins of an element to file FP
2696 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
)
2700 static DynamicStringType oname
;
2702 /* check all pins in element */
2706 if (!TEST_FLAG (HOLEFLAG
, pin
))
2708 /* pin might have bee checked before, add to list if not */
2709 if (!TEST_FLAG (TheFlag
, pin
) && FP
)
2712 if (ADD_PV_TO_LIST (pin
))
2715 number
= PadList
[COMPONENT_LAYER
].Number
2716 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2717 /* the pin has no connection if it's the only
2718 * list entry; don't count vias
2720 for (i
= 0; i
< PVList
.Number
; i
++)
2721 if (!PVLIST_ENTRY (i
)->Element
)
2725 /* output of element name if not already done */
2728 PrintConnectionElementName (Element
, FP
);
2732 /* write name to list and draw selected object */
2733 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2734 fprintf (FP
, "\t%s\n", oname
.Data
);
2735 SET_FLAG (SELECTEDFLAG
, pin
);
2739 /* reset found objects for the next pin */
2740 if (PrepareNextLoop (FP
))
2747 /* check all pads in element */
2750 /* lookup pad in list */
2751 /* pad might has bee checked before, add to list if not */
2752 if (!TEST_FLAG (TheFlag
, pad
) && FP
)
2755 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2756 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
2759 number
= PadList
[COMPONENT_LAYER
].Number
2760 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2761 /* the pin has no connection if it's the only
2762 * list entry; don't count vias
2764 for (i
= 0; i
< PVList
.Number
; i
++)
2765 if (!PVLIST_ENTRY (i
)->Element
)
2769 /* output of element name if not already done */
2772 PrintConnectionElementName (Element
, FP
);
2776 /* write name to list and draw selected object */
2777 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2778 fprintf (FP
, "\t%s\n", oname
.Data
);
2779 SET_FLAG (SELECTEDFLAG
, pad
);
2783 /* reset found objects for the next pin */
2784 if (PrepareNextLoop (FP
))
2790 /* print separator if element has unused pins or pads */
2793 fputs ("}\n\n", FP
);
2799 /* ---------------------------------------------------------------------------
2800 * resets some flags for looking up the next pin/pad
2803 PrepareNextLoop (FILE * FP
)
2807 /* reset found LOs for the next pin */
2808 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2810 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2811 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2812 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2815 /* reset found pads */
2816 for (layer
= 0; layer
< 2; layer
++)
2817 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2820 PVList
.Number
= PVList
.Location
= 0;
2821 RatList
.Number
= RatList
.Location
= 0;
2826 /* ---------------------------------------------------------------------------
2827 * finds all connections to the pins of the passed element.
2828 * The result is written to file FP
2829 * Returns true if operation was aborted
2832 PrintElementConnections (ElementType
*Element
, FILE * FP
, bool AndDraw
)
2834 PrintConnectionElementName (Element
, FP
);
2836 /* check all pins in element */
2839 /* pin might have been checked before, add to list if not */
2840 if (TEST_FLAG (TheFlag
, pin
))
2842 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2843 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2846 if (ADD_PV_TO_LIST (pin
))
2848 DoIt (true, AndDraw
);
2849 /* printout all found connections */
2850 PrintPinConnections (FP
, true);
2851 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
2852 PrintPadConnections (SOLDER_LAYER
, FP
, false);
2853 fputs ("\t}\n", FP
);
2854 if (PrepareNextLoop (FP
))
2859 /* check all pads in element */
2863 /* pad might have been checked before, add to list if not */
2864 if (TEST_FLAG (TheFlag
, pad
))
2866 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2867 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2870 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
2871 if (ADD_PAD_TO_LIST (layer
, pad
))
2873 DoIt (true, AndDraw
);
2874 /* print all found connections */
2875 PrintPadConnections (layer
, FP
, true);
2876 PrintPadConnections (layer
==
2877 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
2879 PrintPinConnections (FP
, false);
2880 fputs ("\t}\n", FP
);
2881 if (PrepareNextLoop (FP
))
2885 fputs ("}\n\n", FP
);
2889 /* ---------------------------------------------------------------------------
2890 * draws all new connections which have been found since the
2891 * routine was called the last time
2894 DrawNewConnections (void)
2899 /* decrement 'i' to keep layerstack order */
2900 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
2902 Cardinal layer
= LayerStack
[i
];
2904 if (PCB
->Data
->Layer
[layer
].On
)
2906 /* draw all new lines */
2907 position
= LineList
[layer
].DrawLocation
;
2908 for (; position
< LineList
[layer
].Number
; position
++)
2909 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
2910 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
2912 /* draw all new arcs */
2913 position
= ArcList
[layer
].DrawLocation
;
2914 for (; position
< ArcList
[layer
].Number
; position
++)
2915 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
2916 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
2918 /* draw all new polygons */
2919 position
= PolygonList
[layer
].DrawLocation
;
2920 for (; position
< PolygonList
[layer
].Number
; position
++)
2921 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
2922 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
2926 /* draw all new pads */
2928 for (i
= 0; i
< 2; i
++)
2930 position
= PadList
[i
].DrawLocation
;
2932 for (; position
< PadList
[i
].Number
; position
++)
2933 DrawPad (PADLIST_ENTRY (i
, position
));
2934 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
2937 /* draw all new PVs; 'PVList' holds a list of pointers to the
2938 * sorted array pointers to PV data
2940 while (PVList
.DrawLocation
< PVList
.Number
)
2942 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
2944 if (TEST_FLAG (PINFLAG
, pv
))
2949 else if (PCB
->ViaOn
)
2951 PVList
.DrawLocation
++;
2953 /* draw the new rat-lines */
2956 position
= RatList
.DrawLocation
;
2957 for (; position
< RatList
.Number
; position
++)
2958 DrawRat (RATLIST_ENTRY (position
));
2959 RatList
.DrawLocation
= RatList
.Number
;
2963 /* ---------------------------------------------------------------------------
2964 * find all connections to pins within one element
2967 LookupElementConnections (ElementType
*Element
, FILE * FP
)
2969 /* reset all currently marked connections */
2971 TheFlag
= FOUNDFLAG
;
2972 ResetConnections (true, FOUNDFLAG
);
2973 InitConnectionLookup ();
2974 PrintElementConnections (Element
, FP
, true);
2975 SetChangedFlag (true);
2976 if (Settings
.RingBellWhenFinished
)
2978 FreeConnectionLookupMemory ();
2979 IncrementUndoSerialNumber ();
2984 /* ---------------------------------------------------------------------------
2985 * find all connections to pins of all element
2988 LookupConnectionsToAllElements (FILE * FP
)
2990 /* reset all currently marked connections */
2992 TheFlag
= FOUNDFLAG
;
2993 ResetConnections (false, FOUNDFLAG
);
2994 InitConnectionLookup ();
2996 ELEMENT_LOOP (PCB
->Data
);
2998 /* break if abort dialog returned true */
2999 if (PrintElementConnections (element
, FP
, false))
3002 if (Settings
.ResetAfterElement
&& n
!= 1)
3003 ResetConnections (false, FOUNDFLAG
);
3006 if (Settings
.RingBellWhenFinished
)
3008 ResetConnections (false, FOUNDFLAG
);
3009 FreeConnectionLookupMemory ();
3013 /*---------------------------------------------------------------------------
3014 * add the starting object to the list of found objects
3017 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
3025 if (ADD_PV_TO_LIST ((PinType
*) ptr2
))
3032 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
))
3039 int layer
= GetLayerNumber (PCB
->Data
,
3040 (LayerType
*) ptr1
);
3042 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
))
3049 int layer
= GetLayerNumber (PCB
->Data
,
3050 (LayerType
*) ptr1
);
3052 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
))
3059 int layer
= GetLayerNumber (PCB
->Data
,
3060 (LayerType
*) ptr1
);
3062 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
))
3069 PadType
*pad
= (PadType
*) ptr2
;
3072 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3081 /* ---------------------------------------------------------------------------
3082 * looks up all connections from the object at the given coordinates
3083 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3084 * the objects are re-drawn if AndDraw is true
3085 * also the action is marked as undoable if AndDraw is true
3088 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int which_flag
,
3091 void *ptr1
, *ptr2
, *ptr3
;
3095 /* check if there are any pins or pads at that position */
3097 reassign_no_drc_flags ();
3100 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3101 if (type
== NO_TYPE
)
3103 type
= SearchObjectByLocation (
3104 LOOKUP_MORE
& ~(AndRats
? RATLINE_TYPE
: 0),
3105 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3106 if (type
== NO_TYPE
)
3108 if (type
& SILK_TYPE
)
3110 int laynum
= GetLayerNumber (PCB
->Data
,
3111 (LayerType
*) ptr1
);
3113 /* don't mess with non-conducting objects! */
3114 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3119 name
= ConnectionName (type
, ptr1
, ptr2
);
3120 hid_actionl ("NetlistShow", name
, NULL
);
3122 TheFlag
= which_flag
;
3124 InitConnectionLookup ();
3126 /* now add the object to the appropriate list and start scanning
3127 * This is step (1) from the description
3129 ListStart (type
, ptr1
, ptr2
, ptr3
);
3130 DoIt (AndRats
, AndDraw
);
3132 IncrementUndoSerialNumber ();
3138 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3140 FreeConnectionLookupMemory ();
3143 /* ---------------------------------------------------------------------------
3144 * find connections for rats nesting
3145 * assumes InitConnectionLookup() has already been done
3148 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3149 bool undo
, int flag
, bool AndRats
)
3154 ListStart (type
, ptr1
, ptr2
, ptr3
);
3155 DoIt (AndRats
, false);
3159 /* ---------------------------------------------------------------------------
3160 * find all unused pins of all element
3163 LookupUnusedPins (FILE * FP
)
3165 /* reset all currently marked connections */
3167 TheFlag
= FOUNDFLAG
;
3168 ResetConnections (true, FOUNDFLAG
);
3169 InitConnectionLookup ();
3171 ELEMENT_LOOP (PCB
->Data
);
3173 /* break if abort dialog returned true;
3174 * passing NULL as filedescriptor discards the normal output
3176 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
))
3181 if (Settings
.RingBellWhenFinished
)
3183 FreeConnectionLookupMemory ();
3184 IncrementUndoSerialNumber ();
3189 /* ---------------------------------------------------------------------------
3190 * resets all used flags of pins and vias
3193 ResetFoundPinsViasAndPads (bool AndDraw
, int flag
)
3195 bool change
= false;
3197 VIA_LOOP (PCB
->Data
);
3199 if (TEST_FLAG (flag
, via
))
3202 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3203 CLEAR_FLAG (flag
, via
);
3210 ELEMENT_LOOP (PCB
->Data
);
3214 if (TEST_FLAG (flag
, pin
))
3217 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3218 CLEAR_FLAG (flag
, pin
);
3227 if (TEST_FLAG (flag
, pad
))
3230 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3231 CLEAR_FLAG (flag
, pad
);
3241 SetChangedFlag (true);
3245 /* ---------------------------------------------------------------------------
3246 * resets all used flags of LOs
3249 ResetFoundLinesAndPolygons (bool AndDraw
, int flag
)
3251 bool change
= false;
3253 RAT_LOOP (PCB
->Data
);
3255 if (TEST_FLAG (flag
, line
))
3258 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3259 CLEAR_FLAG (flag
, line
);
3266 COPPERLINE_LOOP (PCB
->Data
);
3268 if (TEST_FLAG (flag
, line
))
3271 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3272 CLEAR_FLAG (flag
, line
);
3274 DrawLine (layer
, line
);
3279 COPPERARC_LOOP (PCB
->Data
);
3281 if (TEST_FLAG (flag
, arc
))
3284 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3285 CLEAR_FLAG (flag
, arc
);
3287 DrawArc (layer
, arc
);
3292 COPPERPOLYGON_LOOP (PCB
->Data
);
3294 if (TEST_FLAG (flag
, polygon
))
3297 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3298 CLEAR_FLAG (flag
, polygon
);
3300 DrawPolygon (layer
, polygon
);
3306 SetChangedFlag (true);
3310 /* ---------------------------------------------------------------------------
3311 * resets all found connections
3314 ResetConnections (bool AndDraw
, int flag
)
3316 bool change
= false;
3318 change
= ResetFoundPinsViasAndPads (AndDraw
, flag
) || change
;
3319 change
= ResetFoundLinesAndPolygons (AndDraw
, flag
) || change
;
3324 /*----------------------------------------------------------------------------
3325 * Dumps the list contents
3332 for (i
= 0; i
< 2; i
++)
3334 PadList
[i
].Number
= 0;
3335 PadList
[i
].Location
= 0;
3336 PadList
[i
].DrawLocation
= 0;
3340 PVList
.Location
= 0;
3342 for (i
= 0; i
< max_copper_layer
; i
++)
3344 LineList
[i
].Location
= 0;
3345 LineList
[i
].DrawLocation
= 0;
3346 LineList
[i
].Number
= 0;
3347 ArcList
[i
].Location
= 0;
3348 ArcList
[i
].DrawLocation
= 0;
3349 ArcList
[i
].Number
= 0;
3350 PolygonList
[i
].Location
= 0;
3351 PolygonList
[i
].DrawLocation
= 0;
3352 PolygonList
[i
].Number
= 0;
3355 RatList
.Location
= 0;
3356 RatList
.DrawLocation
= 0;
3359 /*-----------------------------------------------------------------------------
3360 * Check for DRC violations on a single net starting from the pad or pin
3361 * sees if the connectivity changes when everything is bloated, or shrunk
3364 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3368 long int *object_id_list
;
3369 int *object_type_list
;
3370 DrcViolationType
*violation
;
3372 if (PCB
->Shrink
!= 0)
3374 Bloat
= -PCB
->Shrink
;
3375 TheFlag
= DRCFLAG
| SELECTEDFLAG
;
3376 ListStart (What
, ptr1
, ptr2
, ptr3
);
3378 /* ok now the shrunk net has the SELECTEDFLAG set */
3380 TheFlag
= FOUNDFLAG
;
3381 ListStart (What
, ptr1
, ptr2
, ptr3
);
3383 drc
= true; /* abort the search if we find anything not already found */
3384 if (DoIt (true, false))
3387 /* make the flag changes undoable */
3388 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3389 ResetConnections (false, TheFlag
);
3392 Bloat
= -PCB
->Shrink
;
3393 TheFlag
= SELECTEDFLAG
;
3394 ListStart (What
, ptr1
, ptr2
, ptr3
);
3397 ListStart (What
, ptr1
, ptr2
, ptr3
);
3398 TheFlag
= FOUNDFLAG
;
3406 LocateError (&x
, &y
);
3407 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3408 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3409 _("Insufficient overlap between objects can lead to broken tracks\n"
3410 "due to registration errors with old wheel style photo-plotters."),
3412 0, /* ANGLE OF ERROR UNKNOWN */
3413 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3414 0, /* MAGNITUDE OF ERROR UNKNOWN */
3419 append_drc_violation (violation
);
3420 pcb_drc_violation_free (violation
);
3421 free (object_id_list
);
3422 free (object_type_list
);
3424 if (!throw_drc_dialog())
3426 IncrementUndoSerialNumber ();
3431 /* now check the bloated condition */
3433 ResetConnections (false, TheFlag
);
3434 TheFlag
= FOUNDFLAG
;
3435 ListStart (What
, ptr1
, ptr2
, ptr3
);
3438 while (DoIt (true, false))
3441 /* make the flag changes undoable */
3442 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3443 ResetConnections (false, TheFlag
);
3447 TheFlag
= SELECTEDFLAG
;
3448 ListStart (What
, ptr1
, ptr2
, ptr3
);
3451 TheFlag
= FOUNDFLAG
;
3452 ListStart (What
, ptr1
, ptr2
, ptr3
);
3458 LocateError (&x
, &y
);
3459 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3460 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3461 _("Circuits that are too close may bridge during imaging, etching,\n"
3462 "plating, or soldering processes resulting in a direct short."),
3464 0, /* ANGLE OF ERROR UNKNOWN */
3465 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3466 0, /* MAGNITUDE OF ERROR UNKNOWN */
3471 append_drc_violation (violation
);
3472 pcb_drc_violation_free (violation
);
3473 free (object_id_list
);
3474 free (object_type_list
);
3477 if (!throw_drc_dialog())
3479 IncrementUndoSerialNumber ();
3481 /* highlight the rest of the encroaching net so it's not reported again */
3482 TheFlag
|= SELECTEDFLAG
;
3484 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
);
3489 ListStart (What
, ptr1
, ptr2
, ptr3
);
3493 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3494 ResetConnections (false, TheFlag
);
3498 /* DRC clearance callback */
3501 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3502 int type
, void *ptr1
, void *ptr2
)
3507 long int *object_id_list
;
3508 int *object_type_list
;
3509 DrcViolationType
*violation
;
3511 LineType
*line
= (LineType
*) ptr2
;
3512 ArcType
*arc
= (ArcType
*) ptr2
;
3513 PinType
*pin
= (PinType
*) ptr2
;
3514 PadType
*pad
= (PadType
*) ptr2
;
3523 if (line
->Clearance
< 2 * PCB
->Bloat
)
3525 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3526 SET_FLAG (TheFlag
, line
);
3527 message
= _("Line with insufficient clearance inside polygon\n");
3532 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3534 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3535 SET_FLAG (TheFlag
, arc
);
3536 message
= _("Arc with insufficient clearance inside polygon\n");
3541 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3542 if (IsPadInPolygon(pad
,polygon
))
3544 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3545 SET_FLAG (TheFlag
, pad
);
3546 message
= _("Pad with insufficient clearance inside polygon\n");
3551 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3553 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3554 SET_FLAG (TheFlag
, pin
);
3555 message
= _("Pin with insufficient clearance inside polygon\n");
3560 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3562 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3563 SET_FLAG (TheFlag
, pin
);
3564 message
= _("Via with insufficient clearance inside polygon\n");
3569 Message ("hace: Bad Plow object in callback\n");
3574 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3575 SET_FLAG (FOUNDFLAG
, polygon
);
3576 DrawPolygon (layer
, polygon
);
3577 DrawObject (type
, ptr1
, ptr2
);
3579 LocateError (&x
, &y
);
3580 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3581 violation
= pcb_drc_violation_new (message
,
3582 _("Circuits that are too close may bridge during imaging, etching,\n"
3583 "plating, or soldering processes resulting in a direct short."),
3585 0, /* ANGLE OF ERROR UNKNOWN */
3586 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3587 0, /* MAGNITUDE OF ERROR UNKNOWN */
3592 append_drc_violation (violation
);
3593 pcb_drc_violation_free (violation
);
3594 free (object_id_list
);
3595 free (object_type_list
);
3596 if (!throw_drc_dialog())
3601 IncrementUndoSerialNumber ();
3606 /*-----------------------------------------------------------------------------
3607 * Check for DRC violations
3608 * see if the connectivity changes when everything is bloated, or shrunk
3615 long int *object_id_list
;
3616 int *object_type_list
;
3617 DrcViolationType
*violation
;
3621 reset_drc_dialog_message();
3625 SaveStackAndVisibility ();
3626 ResetStackAndVisibility ();
3627 hid_action ("LayersChanged");
3628 InitConnectionLookup ();
3630 TheFlag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3632 if (ResetConnections (true, TheFlag
))
3634 IncrementUndoSerialNumber ();
3640 ELEMENT_LOOP (PCB
->Data
);
3644 if (!TEST_FLAG (DRCFLAG
, pin
)
3645 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3657 /* count up how many pads have no solderpaste openings */
3658 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3661 if (!TEST_FLAG (DRCFLAG
, pad
)
3662 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3674 VIA_LOOP (PCB
->Data
);
3676 if (!TEST_FLAG (DRCFLAG
, via
)
3677 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3685 TheFlag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3686 ResetConnections (false, TheFlag
);
3687 TheFlag
= SELECTEDFLAG
;
3688 /* check minimum widths and polygon clearances */
3691 COPPERLINE_LOOP (PCB
->Data
);
3693 /* check line clearances in polygons */
3694 PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
);
3697 if (line
->Thickness
< PCB
->minWid
)
3699 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3700 SET_FLAG (TheFlag
, line
);
3701 DrawLine (layer
, line
);
3703 SetThing (LINE_TYPE
, layer
, line
, line
);
3704 LocateError (&x
, &y
);
3705 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3706 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3707 _("Process specifications dictate a minimum feature-width\n"
3708 "that can reliably be reproduced"),
3710 0, /* ANGLE OF ERROR UNKNOWN */
3711 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3717 append_drc_violation (violation
);
3718 pcb_drc_violation_free (violation
);
3719 free (object_id_list
);
3720 free (object_type_list
);
3721 if (!throw_drc_dialog())
3726 IncrementUndoSerialNumber ();
3734 COPPERARC_LOOP (PCB
->Data
);
3736 PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
);
3739 if (arc
->Thickness
< PCB
->minWid
)
3741 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3742 SET_FLAG (TheFlag
, arc
);
3743 DrawArc (layer
, arc
);
3745 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3746 LocateError (&x
, &y
);
3747 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3748 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3749 _("Process specifications dictate a minimum feature-width\n"
3750 "that can reliably be reproduced"),
3752 0, /* ANGLE OF ERROR UNKNOWN */
3753 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3759 append_drc_violation (violation
);
3760 pcb_drc_violation_free (violation
);
3761 free (object_id_list
);
3762 free (object_type_list
);
3763 if (!throw_drc_dialog())
3768 IncrementUndoSerialNumber ();
3776 ALLPIN_LOOP (PCB
->Data
);
3778 PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
);
3781 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3782 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3784 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3785 SET_FLAG (TheFlag
, pin
);
3788 SetThing (PIN_TYPE
, element
, pin
, pin
);
3789 LocateError (&x
, &y
);
3790 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3791 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3792 _("Annular rings that are too small may erode during etching,\n"
3793 "resulting in a broken connection"),
3795 0, /* ANGLE OF ERROR UNKNOWN */
3796 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3797 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3802 append_drc_violation (violation
);
3803 pcb_drc_violation_free (violation
);
3804 free (object_id_list
);
3805 free (object_type_list
);
3806 if (!throw_drc_dialog())
3811 IncrementUndoSerialNumber ();
3814 if (pin
->DrillingHole
< PCB
->minDrill
)
3816 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3817 SET_FLAG (TheFlag
, pin
);
3820 SetThing (PIN_TYPE
, element
, pin
, pin
);
3821 LocateError (&x
, &y
);
3822 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3823 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3824 _("Process rules dictate the minimum drill size which can be used"),
3826 0, /* ANGLE OF ERROR UNKNOWN */
3827 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3833 append_drc_violation (violation
);
3834 pcb_drc_violation_free (violation
);
3835 free (object_id_list
);
3836 free (object_type_list
);
3837 if (!throw_drc_dialog())
3842 IncrementUndoSerialNumber ();
3850 ALLPAD_LOOP (PCB
->Data
);
3852 PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
);
3855 if (pad
->Thickness
< PCB
->minWid
)
3857 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3858 SET_FLAG (TheFlag
, pad
);
3861 SetThing (PAD_TYPE
, element
, pad
, pad
);
3862 LocateError (&x
, &y
);
3863 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3864 violation
= pcb_drc_violation_new (_("Pad is too thin"),
3865 _("Pads which are too thin may erode during etching,\n"
3866 "resulting in a broken or unreliable connection"),
3868 0, /* ANGLE OF ERROR UNKNOWN */
3869 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3875 append_drc_violation (violation
);
3876 pcb_drc_violation_free (violation
);
3877 free (object_id_list
);
3878 free (object_type_list
);
3879 if (!throw_drc_dialog())
3884 IncrementUndoSerialNumber ();
3892 VIA_LOOP (PCB
->Data
);
3894 PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
);
3897 if (!TEST_FLAG (HOLEFLAG
, via
) &&
3898 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
3900 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3901 SET_FLAG (TheFlag
, via
);
3904 SetThing (VIA_TYPE
, via
, via
, via
);
3905 LocateError (&x
, &y
);
3906 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3907 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
3908 _("Annular rings that are too small may erode during etching,\n"
3909 "resulting in a broken connection"),
3911 0, /* ANGLE OF ERROR UNKNOWN */
3912 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3913 (via
->Thickness
- via
->DrillingHole
) / 2,
3918 append_drc_violation (violation
);
3919 pcb_drc_violation_free (violation
);
3920 free (object_id_list
);
3921 free (object_type_list
);
3922 if (!throw_drc_dialog())
3927 IncrementUndoSerialNumber ();
3930 if (via
->DrillingHole
< PCB
->minDrill
)
3932 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3933 SET_FLAG (TheFlag
, via
);
3936 SetThing (VIA_TYPE
, via
, via
, via
);
3937 LocateError (&x
, &y
);
3938 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3939 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
3940 _("Process rules dictate the minimum drill size which can be used"),
3942 0, /* ANGLE OF ERROR UNKNOWN */
3943 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3949 append_drc_violation (violation
);
3950 pcb_drc_violation_free (violation
);
3951 free (object_id_list
);
3952 free (object_type_list
);
3953 if (!throw_drc_dialog())
3958 IncrementUndoSerialNumber ();
3965 FreeConnectionLookupMemory ();
3966 TheFlag
= FOUNDFLAG
;
3969 /* check silkscreen minimum widths outside of elements */
3970 /* XXX - need to check text and polygons too! */
3971 TheFlag
= SELECTEDFLAG
;
3974 SILKLINE_LOOP (PCB
->Data
);
3976 if (line
->Thickness
< PCB
->minSlk
)
3978 SET_FLAG (TheFlag
, line
);
3979 DrawLine (layer
, line
);
3981 SetThing (LINE_TYPE
, layer
, line
, line
);
3982 LocateError (&x
, &y
);
3983 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3984 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
3985 _("Process specifications dictate a minimum silkscreen feature-width\n"
3986 "that can reliably be reproduced"),
3988 0, /* ANGLE OF ERROR UNKNOWN */
3989 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3995 append_drc_violation (violation
);
3996 pcb_drc_violation_free (violation
);
3997 free (object_id_list
);
3998 free (object_type_list
);
3999 if (!throw_drc_dialog())
4009 /* check silkscreen minimum widths inside of elements */
4010 /* XXX - need to check text and polygons too! */
4011 TheFlag
= SELECTEDFLAG
;
4014 ELEMENT_LOOP (PCB
->Data
);
4017 ELEMENTLINE_LOOP (element
);
4019 if (line
->Thickness
< PCB
->minSlk
)
4030 SET_FLAG (TheFlag
, element
);
4031 DrawElement (element
);
4033 SetThing (ELEMENT_TYPE
, element
, element
, element
);
4034 LocateError (&x
, &y
);
4035 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4037 title
= _("Element %s has %i silk lines which are too thin");
4038 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
4040 /* -4 is for the %s and %i place-holders */
4041 /* +11 is the max printed length for a 32 bit integer */
4042 /* +1 is for the \0 termination */
4043 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
4044 buffer
= (char *)malloc (buflen
);
4045 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
4047 violation
= pcb_drc_violation_new (buffer
,
4048 _("Process specifications dictate a minimum silkscreen\n"
4049 "feature-width that can reliably be reproduced"),
4051 0, /* ANGLE OF ERROR UNKNOWN */
4052 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4053 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4059 append_drc_violation (violation
);
4060 pcb_drc_violation_free (violation
);
4061 free (object_id_list
);
4062 free (object_type_list
);
4063 if (!throw_drc_dialog())
4076 IncrementUndoSerialNumber ();
4080 RestoreStackAndVisibility ();
4081 hid_action ("LayersChanged");
4082 gui
->invalidate_all ();
4086 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4088 nopastecnt
> 1 ? "s have" : " has");
4090 return IsBad
? -drcerr_count
: drcerr_count
;
4093 /*----------------------------------------------------------------------------
4094 * Locate the coordinatates of offending item (thing)
4097 LocateError (Coord
*x
, Coord
*y
)
4103 LineType
*line
= (LineType
*) thing_ptr3
;
4104 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4105 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4110 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4117 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4119 (polygon
->Clipped
->contours
->xmin
+
4120 polygon
->Clipped
->contours
->xmax
) / 2;
4122 (polygon
->Clipped
->contours
->ymin
+
4123 polygon
->Clipped
->contours
->ymax
) / 2;
4129 PinType
*pin
= (PinType
*) thing_ptr3
;
4136 PadType
*pad
= (PadType
*) thing_ptr3
;
4137 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4138 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4143 ElementType
*element
= (ElementType
*) thing_ptr3
;
4144 *x
= element
->MarkX
;
4145 *y
= element
->MarkY
;
4154 /*----------------------------------------------------------------------------
4155 * Build a list of the of offending items by ID. (Currently just "thing")
4158 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4161 *object_id_list
= NULL
;
4162 *object_type_list
= NULL
;
4175 *object_id_list
= (long int *)malloc (sizeof (long int));
4176 *object_type_list
= (int *)malloc (sizeof (int));
4177 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4178 **object_type_list
= thing_type
;
4183 _("Internal error in BuildObjectList: unknown object type %i\n"),
4189 /*----------------------------------------------------------------------------
4190 * center the display to show the offending item (thing)
4197 LocateError (&X
, &Y
);
4204 ChangeGroupVisibility (
4205 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4208 CenterDisplay (X
, Y
);
4212 InitConnectionLookup (void)
4214 InitComponentLookup ();
4215 InitLayoutLookup ();
4219 FreeConnectionLookupMemory (void)
4221 FreeComponentLookupMemory ();
4222 FreeLayoutLookupMemory ();