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 int OldFlag
= FOUNDFLAG
;
289 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
290 static int thing_type
;
291 static bool User
= false; /* user action causing this */
292 static bool drc
= false; /* whether to stop if finding something not found */
293 static bool IsBad
= false;
294 static Cardinal drcerr_count
; /* count of drc errors */
295 static Cardinal TotalP
, TotalV
, NumberOfPads
[2];
296 static ListType LineList
[MAX_LAYER
], /* list of objects to */
297 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
299 /* ---------------------------------------------------------------------------
300 * some local prototypes
302 static bool LookupLOConnectionsToPVList (bool);
303 static bool LookupLOConnectionsToLOList (bool);
304 static bool LookupPVConnectionsToLOList (bool);
305 static bool LookupPVConnectionsToPVList (void);
306 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, bool);
307 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
);
308 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
);
309 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
);
310 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
);
311 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
312 static bool ArcArcIntersect (ArcType
*, ArcType
*);
313 static bool PrepareNextLoop (FILE *);
314 static bool PrintElementConnections (ElementType
*, FILE *, bool);
315 static bool ListsEmpty (bool);
316 static bool DoIt (bool, bool);
317 static void PrintElementNameList (ElementType
*, FILE *);
318 static void PrintConnectionElementName (ElementType
*, FILE *);
319 static void PrintConnectionListEntry (char *, ElementType
*,
321 static void PrintPadConnections (Cardinal
, FILE *, bool);
322 static void PrintPinConnections (FILE *, bool);
323 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*,
325 static void DrawNewConnections (void);
326 static void DumpList (void);
327 static void LocateError (Coord
*, Coord
*);
328 static void BuildObjectList (int *, long int **, int **);
329 static void GotoError (void);
330 static bool DRCFind (int, void *, void *, void *);
331 static bool ListStart (int, void *, void *, void *);
332 static bool LOTouchesLine (LineType
*Line
, Cardinal LayerGroup
);
333 static bool PVTouchesLine (LineType
*line
);
334 static bool SetThing (int, void *, void *, void *);
336 /* ---------------------------------------------------------------------------
337 * some of the 'pad' routines are the same as for lines because the 'pad'
338 * struct starts with a line struct. See global.h for details
341 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
343 return LineLineIntersect ((Line
), (LineType
*)Pad
);
347 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
349 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
353 ADD_PV_TO_LIST (PinType
*Pin
)
356 AddObjectToFlagUndoList (Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
357 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
);
358 SET_FLAG (TheFlag
, Pin
);
359 PVLIST_ENTRY (PVList
.Number
) = Pin
;
362 if (PVList
.Number
> PVList
.Size
)
363 printf ("ADD_PV_TO_LIST overflow! num=%d size=%d\n", PVList
.Number
,
366 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pin
))
367 return (SetThing (PIN_TYPE
, Pin
->Element
, Pin
, Pin
));
372 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
)
375 AddObjectToFlagUndoList (PAD_TYPE
, Pad
->Element
, Pad
, Pad
);
376 SET_FLAG (TheFlag
, Pad
);
377 PADLIST_ENTRY ((L
), PadList
[(L
)].Number
) = Pad
;
378 PadList
[(L
)].Number
++;
380 if (PadList
[(L
)].Number
> PadList
[(L
)].Size
)
381 printf ("ADD_PAD_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
382 PadList
[(L
)].Number
, PadList
[(L
)].Size
);
384 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, Pad
))
385 return (SetThing (PAD_TYPE
, Pad
->Element
, Pad
, Pad
));
390 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
)
393 AddObjectToFlagUndoList (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
394 SET_FLAG (TheFlag
, (Ptr
));
395 LINELIST_ENTRY ((L
), LineList
[(L
)].Number
) = (Ptr
);
396 LineList
[(L
)].Number
++;
398 if (LineList
[(L
)].Number
> LineList
[(L
)].Size
)
399 printf ("ADD_LINE_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
400 LineList
[(L
)].Number
, LineList
[(L
)].Size
);
402 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
403 return (SetThing (LINE_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
408 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
)
411 AddObjectToFlagUndoList (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
412 SET_FLAG (TheFlag
, (Ptr
));
413 ARCLIST_ENTRY ((L
), ArcList
[(L
)].Number
) = (Ptr
);
414 ArcList
[(L
)].Number
++;
416 if (ArcList
[(L
)].Number
> ArcList
[(L
)].Size
)
417 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
418 ArcList
[(L
)].Number
, ArcList
[(L
)].Size
);
420 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
421 return (SetThing (ARC_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
426 ADD_RAT_TO_LIST (RatType
*Ptr
)
429 AddObjectToFlagUndoList (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
));
430 SET_FLAG (TheFlag
, (Ptr
));
431 RATLIST_ENTRY (RatList
.Number
) = (Ptr
);
434 if (RatList
.Number
> RatList
.Size
)
435 printf ("ADD_RAT_TO_LIST overflow! num=%d size=%d\n",
436 RatList
.Number
, RatList
.Size
);
438 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
439 return (SetThing (RATLINE_TYPE
, (Ptr
), (Ptr
), (Ptr
)));
444 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
)
447 AddObjectToFlagUndoList (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
));
448 SET_FLAG (TheFlag
, (Ptr
));
449 POLYGONLIST_ENTRY ((L
), PolygonList
[(L
)].Number
) = (Ptr
);
450 PolygonList
[(L
)].Number
++;
452 if (PolygonList
[(L
)].Number
> PolygonList
[(L
)].Size
)
453 printf ("ADD_ARC_TO_LIST overflow! lay=%d, num=%d size=%d\n", L
,
454 PolygonList
[(L
)].Number
, PolygonList
[(L
)].Size
);
456 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, (Ptr
)))
457 return (SetThing (POLYGON_TYPE
, LAYER_PTR (L
), (Ptr
), (Ptr
)));
462 PinLineIntersect (PinType
*PV
, LineType
*Line
)
464 /* IsLineInRectangle already has Bloat factor */
465 return TEST_FLAG (SQUAREFLAG
,
466 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
467 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
468 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
469 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
470 Line
) : IsPointInPad (PV
->X
,
482 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
488 if (type
== PIN_TYPE
&& ptr1
== NULL
)
491 thing_type
= VIA_TYPE
;
497 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
499 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
501 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
507 PadPadIntersect (PadType
*p1
, PadType
*p2
)
509 return LinePadIntersect ((LineType
*) p1
, p2
);
513 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
518 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
519 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
520 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
521 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
523 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
525 /* check for square/square overlap */
530 t2
= PV2
->Thickness
/ 2.0;
535 return BoxBoxIntersection (&b1
, &b2
);
538 /* ---------------------------------------------------------------------------
539 * releases all allocated memory
542 FreeLayoutLookupMemory (void)
546 for (i
= 0; i
< max_copper_layer
; i
++)
548 free (LineList
[i
].Data
);
549 LineList
[i
].Data
= NULL
;
550 free (ArcList
[i
].Data
);
551 ArcList
[i
].Data
= NULL
;
552 free (PolygonList
[i
].Data
);
553 PolygonList
[i
].Data
= NULL
;
562 FreeComponentLookupMemory (void)
564 free (PadList
[0].Data
);
565 PadList
[0].Data
= NULL
;
566 free (PadList
[1].Data
);
567 PadList
[1].Data
= NULL
;
570 /* ---------------------------------------------------------------------------
571 * allocates memory for component related stacks ...
572 * initializes index and sorts it by X1 and X2
575 InitComponentLookup (void)
579 /* initialize pad data; start by counting the total number
580 * on each of the two possible layers
582 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
583 ALLPAD_LOOP (PCB
->Data
);
585 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
586 NumberOfPads
[SOLDER_LAYER
]++;
588 NumberOfPads
[COMPONENT_LAYER
]++;
591 for (i
= 0; i
< 2; i
++)
593 /* allocate memory for working list */
594 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
596 /* clear some struct members */
597 PadList
[i
].Location
= 0;
598 PadList
[i
].DrawLocation
= 0;
599 PadList
[i
].Number
= 0;
600 PadList
[i
].Size
= NumberOfPads
[i
];
604 /* ---------------------------------------------------------------------------
605 * allocates memory for component related stacks ...
606 * initializes index and sorts it by X1 and X2
609 InitLayoutLookup (void)
613 /* initialize line arc and polygon data */
614 for (i
= 0; i
< max_copper_layer
; i
++)
616 LayerType
*layer
= LAYER_PTR (i
);
620 /* allocate memory for line pointer lists */
621 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
622 LineList
[i
].Size
= layer
->LineN
;
626 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
627 ArcList
[i
].Size
= layer
->ArcN
;
631 /* allocate memory for polygon list */
634 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
635 PolygonList
[i
].Size
= layer
->PolygonN
;
638 /* clear some struct members */
639 LineList
[i
].Location
= 0;
640 LineList
[i
].DrawLocation
= 0;
641 LineList
[i
].Number
= 0;
642 ArcList
[i
].Location
= 0;
643 ArcList
[i
].DrawLocation
= 0;
644 ArcList
[i
].Number
= 0;
645 PolygonList
[i
].Location
= 0;
646 PolygonList
[i
].DrawLocation
= 0;
647 PolygonList
[i
].Number
= 0;
650 if (PCB
->Data
->pin_tree
)
651 TotalP
= PCB
->Data
->pin_tree
->size
;
654 if (PCB
->Data
->via_tree
)
655 TotalV
= PCB
->Data
->via_tree
->size
;
658 /* allocate memory for 'new PV to check' list and clear struct */
659 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
660 PVList
.Size
= TotalP
+ TotalV
;
662 PVList
.DrawLocation
= 0;
664 /* Initialize ratline data */
665 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
666 RatList
.Size
= PCB
->Data
->RatN
;
667 RatList
.Location
= 0;
668 RatList
.DrawLocation
= 0;
680 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
682 LineType
*line
= (LineType
*) b
;
683 struct pv_info
*i
= (struct pv_info
*) cl
;
685 if (!TEST_FLAG (TheFlag
, line
) && PinLineIntersect (&i
->pv
, line
) &&
686 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
688 if (ADD_LINE_TO_LIST (i
->layer
, line
))
695 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
697 ArcType
*arc
= (ArcType
*) b
;
698 struct pv_info
*i
= (struct pv_info
*) cl
;
700 if (!TEST_FLAG (TheFlag
, arc
) && IS_PV_ON_ARC (&i
->pv
, arc
) &&
701 !TEST_FLAG (HOLEFLAG
, &i
->pv
))
703 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
710 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
712 PadType
*pad
= (PadType
*) b
;
713 struct pv_info
*i
= (struct pv_info
*) cl
;
715 if (!TEST_FLAG (TheFlag
, pad
) && IS_PV_ON_PAD (&i
->pv
, pad
) &&
716 !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
717 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
718 COMPONENT_LAYER
, pad
))
724 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
726 RatType
*rat
= (RatType
*) b
;
727 struct pv_info
*i
= (struct pv_info
*) cl
;
729 if (!TEST_FLAG (TheFlag
, rat
) && IS_PV_ON_RAT (&i
->pv
, rat
) &&
730 ADD_RAT_TO_LIST (rat
))
735 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
737 PolygonType
*polygon
= (PolygonType
*) b
;
738 struct pv_info
*i
= (struct pv_info
*) cl
;
740 /* if the pin doesn't have a therm and polygon is clearing
741 * then it can't touch due to clearance, so skip the expensive
742 * test. If it does have a therm, you still need to test
743 * because it might not be inside the polygon, or it could
744 * be on an edge such that it doesn't actually touch.
746 if (!TEST_FLAG (TheFlag
, polygon
) && !TEST_FLAG (HOLEFLAG
, &i
->pv
) &&
747 (TEST_THERM (i
->layer
, &i
->pv
) ||
748 !TEST_FLAG (CLEARPOLYFLAG
,
750 || !i
->pv
.Clearance
))
752 double wide
= MAX (0.5 * i
->pv
.Thickness
+ Bloat
, 0);
753 if (TEST_FLAG (SQUAREFLAG
, &i
->pv
))
755 Coord x1
= i
->pv
.X
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
756 Coord x2
= i
->pv
.X
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
757 Coord y1
= i
->pv
.Y
- (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
758 Coord y2
= i
->pv
.Y
+ (i
->pv
.Thickness
+ 1 + Bloat
) / 2;
759 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
760 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
763 else if (TEST_FLAG (OCTAGONFLAG
, &i
->pv
))
765 POLYAREA
*oct
= OctagonPoly (i
->pv
.X
, i
->pv
.Y
, i
->pv
.Thickness
/ 2);
766 if (isects (oct
, polygon
, true)
767 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
770 else if (IsPointInPolygon (i
->pv
.X
, i
->pv
.Y
, wide
,
772 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
778 /* ---------------------------------------------------------------------------
779 * checks if a PV is connected to LOs, if it is, the LO is added to
780 * the appropriate list and the 'used' flag is set
783 LookupLOConnectionsToPVList (bool AndRats
)
788 /* loop over all PVs currently on list */
789 while (PVList
.Location
< PVList
.Number
)
791 /* get pointer to data */
792 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
793 EXPAND_BOUNDS (&info
.pv
);
796 if (setjmp (info
.env
) == 0)
797 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pv
, NULL
,
798 LOCtoPVpad_callback
, &info
);
802 /* now all lines, arcs and polygons of the several layers */
803 for (layer
= 0; layer
< max_copper_layer
; layer
++)
805 if (LAYER_PTR (layer
)->no_drc
)
808 /* add touching lines */
809 if (setjmp (info
.env
) == 0)
810 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.pv
,
811 NULL
, LOCtoPVline_callback
, &info
);
814 /* add touching arcs */
815 if (setjmp (info
.env
) == 0)
816 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.pv
,
817 NULL
, LOCtoPVarc_callback
, &info
);
820 /* check all polygons */
821 if (setjmp (info
.env
) == 0)
822 r_search (LAYER_PTR (layer
)->polygon_tree
, (BoxType
*) & info
.pv
,
823 NULL
, LOCtoPVpoly_callback
, &info
);
827 /* Check for rat-lines that may intersect the PV */
830 if (setjmp (info
.env
) == 0)
831 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.pv
, NULL
,
832 LOCtoPVrat_callback
, &info
);
841 /* ---------------------------------------------------------------------------
842 * find all connections between LO at the current list position and new LOs
845 LookupLOConnectionsToLOList (bool AndRats
)
848 Cardinal i
, group
, layer
, ratposition
,
849 lineposition
[MAX_LAYER
],
850 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
852 /* copy the current LO list positions; the original data is changed
853 * by 'LookupPVConnectionsToLOList()' which has to check the same
854 * list entries plus the new ones
856 for (i
= 0; i
< max_copper_layer
; i
++)
858 lineposition
[i
] = LineList
[i
].Location
;
859 polyposition
[i
] = PolygonList
[i
].Location
;
860 arcposition
[i
] = ArcList
[i
].Location
;
862 for (i
= 0; i
< 2; i
++)
863 padposition
[i
] = PadList
[i
].Location
;
864 ratposition
= RatList
.Location
;
866 /* loop over all new LOs in the list; recurse until no
867 * more new connections in the layergroup were found
875 position
= &ratposition
;
876 for (; *position
< RatList
.Number
; (*position
)++)
878 group
= RATLIST_ENTRY (*position
)->group1
;
879 if (LookupLOConnectionsToRatEnd
880 (&(RATLIST_ENTRY (*position
)->Point1
), group
))
882 group
= RATLIST_ENTRY (*position
)->group2
;
883 if (LookupLOConnectionsToRatEnd
884 (&(RATLIST_ENTRY (*position
)->Point2
), group
))
888 /* loop over all layergroups */
889 for (group
= 0; group
< max_group
; group
++)
893 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
895 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
897 /* be aware that the layer number equal max_copper_layer
898 * and max_copper_layer+1 have a special meaning for pads
900 if (layer
< max_copper_layer
)
902 /* try all new lines */
903 position
= &lineposition
[layer
];
904 for (; *position
< LineList
[layer
].Number
; (*position
)++)
905 if (LookupLOConnectionsToLine
906 (LINELIST_ENTRY (layer
, *position
), group
, true))
909 /* try all new arcs */
910 position
= &arcposition
[layer
];
911 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
912 if (LookupLOConnectionsToArc
913 (ARCLIST_ENTRY (layer
, *position
), group
))
916 /* try all new polygons */
917 position
= &polyposition
[layer
];
918 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
919 if (LookupLOConnectionsToPolygon
920 (POLYGONLIST_ENTRY (layer
, *position
), group
))
925 /* try all new pads */
926 layer
-= max_copper_layer
;
929 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
930 layer
, max_copper_layer
);
933 position
= &padposition
[layer
];
934 for (; *position
< PadList
[layer
].Number
; (*position
)++)
935 if (LookupLOConnectionsToPad
936 (PADLIST_ENTRY (layer
, *position
), group
))
942 /* check if all lists are done; Later for-loops
943 * may have changed the prior lists
945 done
= !AndRats
|| ratposition
>= RatList
.Number
;
946 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
947 padposition
[1] >= PadList
[1].Number
;
948 for (layer
= 0; layer
< max_copper_layer
; layer
++)
950 lineposition
[layer
] >= LineList
[layer
].Number
&&
951 arcposition
[layer
] >= ArcList
[layer
].Number
&&
952 polyposition
[layer
] >= PolygonList
[layer
].Number
;
959 pv_pv_callback (const BoxType
* b
, void *cl
)
961 PinType
*pin
= (PinType
*) b
;
962 struct pv_info
*i
= (struct pv_info
*) cl
;
964 if (!TEST_FLAG (TheFlag
, pin
) && PV_TOUCH_PV (&i
->pv
, pin
))
966 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, &i
->pv
))
968 SET_FLAG (WARNFLAG
, pin
);
969 Settings
.RatWarn
= true;
971 Message (_("WARNING: Hole too close to pin.\n"));
973 Message (_("WARNING: Hole too close to via.\n"));
975 else if (ADD_PV_TO_LIST (pin
))
981 /* ---------------------------------------------------------------------------
982 * searches for new PVs that are connected to PVs on the list
985 LookupPVConnectionsToPVList (void)
991 /* loop over all PVs on list */
992 save_place
= PVList
.Location
;
993 while (PVList
.Location
< PVList
.Number
)
995 /* get pointer to data */
996 info
.pv
= *(PVLIST_ENTRY (PVList
.Location
));
997 EXPAND_BOUNDS (&info
.pv
);
998 if (setjmp (info
.env
) == 0)
999 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pv
, NULL
,
1000 pv_pv_callback
, &info
);
1003 if (setjmp (info
.env
) == 0)
1004 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pv
, NULL
,
1005 pv_pv_callback
, &info
);
1010 PVList
.Location
= save_place
;
1020 PolygonType polygon
;
1026 pv_line_callback (const BoxType
* b
, void *cl
)
1028 PinType
*pv
= (PinType
*) b
;
1029 struct lo_info
*i
= (struct lo_info
*) cl
;
1031 if (!TEST_FLAG (TheFlag
, pv
) && PinLineIntersect (pv
, &i
->line
))
1033 if (TEST_FLAG (HOLEFLAG
, pv
))
1035 SET_FLAG (WARNFLAG
, pv
);
1036 Settings
.RatWarn
= true;
1037 Message (_("WARNING: Hole too close to line.\n"));
1039 else if (ADD_PV_TO_LIST (pv
))
1040 longjmp (i
->env
, 1);
1046 pv_pad_callback (const BoxType
* b
, void *cl
)
1048 PinType
*pv
= (PinType
*) b
;
1049 struct lo_info
*i
= (struct lo_info
*) cl
;
1051 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_PAD (pv
, &i
->pad
))
1053 if (TEST_FLAG (HOLEFLAG
, pv
))
1055 SET_FLAG (WARNFLAG
, pv
);
1056 Settings
.RatWarn
= true;
1057 Message (_("WARNING: Hole too close to pad.\n"));
1059 else if (ADD_PV_TO_LIST (pv
))
1060 longjmp (i
->env
, 1);
1066 pv_arc_callback (const BoxType
* b
, void *cl
)
1068 PinType
*pv
= (PinType
*) b
;
1069 struct lo_info
*i
= (struct lo_info
*) cl
;
1071 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_ARC (pv
, &i
->arc
))
1073 if (TEST_FLAG (HOLEFLAG
, pv
))
1075 SET_FLAG (WARNFLAG
, pv
);
1076 Settings
.RatWarn
= true;
1077 Message (_("WARNING: Hole touches arc.\n"));
1079 else if (ADD_PV_TO_LIST (pv
))
1080 longjmp (i
->env
, 1);
1086 pv_poly_callback (const BoxType
* b
, void *cl
)
1088 PinType
*pv
= (PinType
*) b
;
1089 struct lo_info
*i
= (struct lo_info
*) cl
;
1091 /* note that holes in polygons are ok, so they don't generate warnings. */
1092 if (!TEST_FLAG (TheFlag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1093 (TEST_THERM (i
->layer
, pv
) ||
1094 !TEST_FLAG (CLEARPOLYFLAG
, &i
->polygon
) ||
1097 if (TEST_FLAG (SQUAREFLAG
, pv
))
1099 Coord x1
, x2
, y1
, y2
;
1100 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1101 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1102 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1103 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1104 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, &i
->polygon
)
1105 && ADD_PV_TO_LIST (pv
))
1106 longjmp (i
->env
, 1);
1108 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1110 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1111 if (isects (oct
, &i
->polygon
, true) && ADD_PV_TO_LIST (pv
))
1112 longjmp (i
->env
, 1);
1116 if (IsPointInPolygon
1117 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, &i
->polygon
)
1118 && ADD_PV_TO_LIST (pv
))
1119 longjmp (i
->env
, 1);
1126 pv_rat_callback (const BoxType
* b
, void *cl
)
1128 PinType
*pv
= (PinType
*) b
;
1129 struct lo_info
*i
= (struct lo_info
*) cl
;
1131 /* rats can't cause DRC so there is no early exit */
1132 if (!TEST_FLAG (TheFlag
, pv
) && IS_PV_ON_RAT (pv
, &i
->rat
))
1133 ADD_PV_TO_LIST (pv
);
1137 /* ---------------------------------------------------------------------------
1138 * searches for new PVs that are connected to NEW LOs on the list
1139 * This routine updates the position counter of the lists too.
1142 LookupPVConnectionsToLOList (bool AndRats
)
1145 struct lo_info info
;
1147 /* loop over all layers */
1148 for (layer
= 0; layer
< max_copper_layer
; layer
++)
1150 if (LAYER_PTR (layer
)->no_drc
)
1152 /* do nothing if there are no PV's */
1153 if (TotalP
+ TotalV
== 0)
1155 LineList
[layer
].Location
= LineList
[layer
].Number
;
1156 ArcList
[layer
].Location
= ArcList
[layer
].Number
;
1157 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
;
1161 /* check all lines */
1162 while (LineList
[layer
].Location
< LineList
[layer
].Number
)
1164 info
.line
= *(LINELIST_ENTRY (layer
, LineList
[layer
].Location
));
1165 EXPAND_BOUNDS (&info
.line
);
1166 if (setjmp (info
.env
) == 0)
1167 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1168 pv_line_callback
, &info
);
1171 if (setjmp (info
.env
) == 0)
1172 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1173 pv_line_callback
, &info
);
1176 LineList
[layer
].Location
++;
1179 /* check all arcs */
1180 while (ArcList
[layer
].Location
< ArcList
[layer
].Number
)
1182 info
.arc
= *(ARCLIST_ENTRY (layer
, ArcList
[layer
].Location
));
1183 EXPAND_BOUNDS (&info
.arc
);
1184 if (setjmp (info
.env
) == 0)
1185 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.arc
, NULL
,
1186 pv_arc_callback
, &info
);
1189 if (setjmp (info
.env
) == 0)
1190 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.arc
, NULL
,
1191 pv_arc_callback
, &info
);
1194 ArcList
[layer
].Location
++;
1197 /* now all polygons */
1199 while (PolygonList
[layer
].Location
< PolygonList
[layer
].Number
)
1202 *(POLYGONLIST_ENTRY (layer
, PolygonList
[layer
].Location
));
1203 EXPAND_BOUNDS (&info
.polygon
);
1204 if (setjmp (info
.env
) == 0)
1205 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.polygon
, NULL
,
1206 pv_poly_callback
, &info
);
1209 if (setjmp (info
.env
) == 0)
1210 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.polygon
, NULL
,
1211 pv_poly_callback
, &info
);
1214 PolygonList
[layer
].Location
++;
1218 /* loop over all pad-layers */
1219 for (layer
= 0; layer
< 2; layer
++)
1221 /* do nothing if there are no PV's */
1222 if (TotalP
+ TotalV
== 0)
1224 PadList
[layer
].Location
= PadList
[layer
].Number
;
1228 /* check all pads; for a detailed description see
1229 * the handling of lines in this subroutine
1231 while (PadList
[layer
].Location
< PadList
[layer
].Number
)
1233 info
.pad
= *(PADLIST_ENTRY (layer
, PadList
[layer
].Location
));
1234 EXPAND_BOUNDS (&info
.pad
);
1235 if (setjmp (info
.env
) == 0)
1236 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.pad
, NULL
,
1237 pv_pad_callback
, &info
);
1240 if (setjmp (info
.env
) == 0)
1241 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.pad
, NULL
,
1242 pv_pad_callback
, &info
);
1245 PadList
[layer
].Location
++;
1249 /* do nothing if there are no PV's */
1250 if (TotalP
+ TotalV
== 0)
1251 RatList
.Location
= RatList
.Number
;
1253 /* check all rat-lines */
1256 while (RatList
.Location
< RatList
.Number
)
1258 info
.rat
= *(RATLIST_ENTRY (RatList
.Location
));
1259 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point1
, 1, NULL
,
1260 pv_rat_callback
, &info
);
1261 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
.Point2
, 1, NULL
,
1262 pv_rat_callback
, &info
);
1263 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point1
, 1, NULL
,
1264 pv_rat_callback
, &info
);
1265 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
.Point2
, 1, NULL
,
1266 pv_rat_callback
, &info
);
1275 pv_touch_callback (const BoxType
* b
, void *cl
)
1277 PinType
*pin
= (PinType
*) b
;
1278 struct lo_info
*i
= (struct lo_info
*) cl
;
1280 if (!TEST_FLAG (TheFlag
, pin
) && PinLineIntersect (pin
, &i
->line
))
1281 longjmp (i
->env
, 1);
1286 PVTouchesLine (LineType
*line
)
1288 struct lo_info info
;
1291 EXPAND_BOUNDS (&info
.line
);
1292 if (setjmp (info
.env
) == 0)
1293 r_search (PCB
->Data
->via_tree
, (BoxType
*) & info
.line
, NULL
,
1294 pv_touch_callback
, &info
);
1297 if (setjmp (info
.env
) == 0)
1298 r_search (PCB
->Data
->pin_tree
, (BoxType
*) & info
.line
, NULL
,
1299 pv_touch_callback
, &info
);
1306 /* reduce arc start angle and delta to 0..360 */
1308 normalize_angles (Angle
*sa
, Angle
*d
)
1315 if (*d
> 360) /* full circle */
1317 *sa
= NormalizeAngle (*sa
);
1321 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1323 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1324 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1326 normalize_angles (&sa
, &d
);
1330 return (sa
+ d
) >= alpha
;
1331 return (sa
+ d
- 360) >= alpha
;
1335 get_arc_ends (Coord
*box
, ArcType
*arc
)
1337 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1338 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1339 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1340 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1342 /* ---------------------------------------------------------------------------
1343 * check if two arcs intersect
1344 * first we check for circle intersections,
1345 * then find the actual points of intersection
1346 * and test them to see if they are on arcs
1348 * consider a, the distance from the center of arc 1
1349 * to the point perpendicular to the intersecting points.
1351 * a = (r1^2 - r2^2 + l^2)/(2l)
1353 * the perpendicular distance to the point of intersection
1356 * d = sqrt(r1^2 - a^2)
1358 * the points of intersection would then be
1360 * x = X1 + a/l dx +- d/l dy
1361 * y = Y1 + a/l dy -+ d/l dx
1363 * where dx = X2 - X1 and dy = Y2 - Y1
1368 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1370 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1374 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1375 t2
= 0.5 * Arc2
->Thickness
;
1379 if (t
< 0 || t1
< 0)
1382 /* try the end points first */
1383 get_arc_ends (&box
[0], Arc1
);
1384 get_arc_ends (&box
[4], Arc2
);
1385 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1386 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1387 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1388 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1391 pdx
= Arc2
->X
- Arc1
->X
;
1392 pdy
= Arc2
->Y
- Arc1
->Y
;
1393 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1394 /* concentric arcs, simpler intersection conditions */
1397 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1398 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1399 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1400 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1402 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1403 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1404 /* NB the endpoints have already been checked,
1405 so we just compare the angles */
1407 normalize_angles (&sa1
, &d1
);
1408 normalize_angles (&sa2
, &d2
);
1409 /* sa1 == sa2 was caught when checking endpoints */
1411 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1414 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1421 /* arcs centerlines are too far or too near */
1422 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1424 /* check the nearest to the other arc's center point */
1427 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1433 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1434 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1437 dx
= - pdx
* r2
/ dl
;
1438 dy
= - pdy
* r2
/ dl
;
1439 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1445 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1446 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1454 a
= 0.5 * (r1
- r2
+ l
) / l
;
1457 /* the circles are too far apart to touch or probably just touch:
1458 check the nearest point */
1463 x
= Arc1
->X
+ a
* pdx
;
1464 y
= Arc1
->Y
+ a
* pdy
;
1467 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1468 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1470 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1471 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1474 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1475 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1477 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1478 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1483 /* ---------------------------------------------------------------------------
1484 * Tests if point is same as line end point
1487 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1489 if ((Point
->X
== Line
->Point1
.X
1490 && Point
->Y
== Line
->Point1
.Y
)
1491 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1497 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1498 /* writes vertices of a squared line */
1500 double dwx
= 0, dwy
= 0;
1501 if (l
->Point1
.Y
== l
->Point2
.Y
)
1502 dwx
= l
->Thickness
/ 2.0;
1503 else if (l
->Point1
.X
== l
->Point2
.X
)
1504 dwy
= l
->Thickness
/ 2.0;
1507 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1508 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1509 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1510 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1511 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1513 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1514 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1515 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1516 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1518 /* ---------------------------------------------------------------------------
1519 * checks if two lines intersect
1522 * Let A,B,C,D be 2-space position vectors. Then the directed line
1523 * segments AB & CD are given by:
1525 * AB=A+r(B-A), r in [0,1]
1526 * CD=C+s(D-C), s in [0,1]
1528 * If AB & CD intersect, then
1530 * A+r(B-A)=C+s(D-C), or
1532 * XA+r(XB-XA)=XC+s(XD-XC)
1533 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1535 * Solving the above for r and s yields
1537 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1538 * r = ----------------------------- (eqn 1)
1539 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1541 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1542 * s = ----------------------------- (eqn 2)
1543 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1545 * Let I be the position vector of the intersection point, then
1552 * By examining the values of r & s, you can also determine some
1553 * other limiting conditions:
1555 * If 0<=r<=1 & 0<=s<=1, intersection exists
1556 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1558 * If the denominator in eqn 1 is zero, AB & CD are parallel
1559 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1561 * If the intersection point of the 2 lines are needed (lines in this
1562 * context mean infinite lines) regardless whether the two line
1563 * segments intersect, then
1565 * If r>1, I is located on extension of AB
1566 * If r<0, I is located on extension of BA
1567 * If s>1, I is located on extension of CD
1568 * If s<0, I is located on extension of DC
1570 * Also note that the denominators of eqn 1 & 2 are identical.
1574 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1577 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1578 point1_dx
, point1_dy
;
1579 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1582 form_slanted_rectangle (p
, Line1
);
1583 return IsLineInQuadrangle (p
, Line2
);
1585 /* here come only round Line1 because IsLineInQuadrangle()
1586 calls LineLineIntersect() with first argument rounded*/
1587 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1590 form_slanted_rectangle (p
, Line2
);
1591 return IsLineInQuadrangle (p
, Line1
);
1593 /* now all lines are round */
1595 /* Check endpoints: this provides a quick exit, catches
1596 * cases where the "real" lines don't intersect but the
1597 * thick lines touch, and ensures that the dx/dy business
1598 * below does not cause a divide-by-zero. */
1599 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1600 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1602 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1603 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1605 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1606 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1608 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1609 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1613 /* setup some constants */
1614 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1615 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1616 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1617 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1618 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1619 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1621 /* If either line is a point, we have failed already, since the
1622 * endpoint check above will have caught an "intersection". */
1623 if ((line1_dx
== 0 && line1_dy
== 0)
1624 || (line2_dx
== 0 && line2_dy
== 0))
1627 /* set s to cross product of Line1 and the line
1628 * Line1.Point1--Line2.Point1 (as vectors) */
1629 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1631 /* set r to cross product of both lines (as vectors) */
1632 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1634 /* No cross product means parallel lines, or maybe Line2 is
1635 * zero-length. In either case, since we did a bounding-box
1636 * check before getting here, the above IsPointInPad() checks
1637 * will have caught any intersections. */
1642 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1644 /* intersection is at least on AB */
1645 if (r
>= 0.0 && r
<= 1.0)
1646 return (s
>= 0.0 && s
<= 1.0);
1648 /* intersection is at least on CD */
1649 /* [removed this case since it always returns false --asp] */
1653 /*---------------------------------------------------
1655 * Check for line intersection with an arc
1657 * Mostly this is like the circle/line intersection
1658 * found in IsPointOnLine (search.c) see the detailed
1659 * discussion for the basics there.
1661 * Since this is only an arc, not a full circle we need
1662 * to find the actual points of intersection with the
1663 * circle, and see if they are on the arc.
1665 * To do this, we translate along the line from the point Q
1666 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1667 * but it's handy to normalize with respect to l, the line
1668 * length so a single projection is done (e.g. we don't first
1671 * The projection is now of the form
1673 * Px = X1 + (r +- r2)(X2 - X1)
1674 * Py = Y1 + (r +- r2)(Y2 - Y1)
1676 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1677 * note that this is the variable d, not the symbol d described in IsPointOnLine
1678 * (variable d = symbol d * l)
1680 * The end points are hell so they are checked individually
1683 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1685 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1688 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1689 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1690 dx1
= Line
->Point1
.X
- Arc
->X
;
1691 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1692 l
= dx
* dx
+ dy
* dy
;
1693 d
= dx
* dy1
- dy
* dx1
;
1696 /* use the larger diameter circle first */
1698 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1700 r2
= Radius
* l
- d
;
1701 /* projection doesn't even intersect circle when r2 < 0 */
1704 /* check the ends of the line in case the projected point */
1705 /* of intersection is beyond the line end */
1707 (Line
->Point1
.X
, Line
->Point1
.Y
,
1708 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1711 (Line
->Point2
.X
, Line
->Point2
.Y
,
1712 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1717 Radius
= -(dx
* dx1
+ dy
* dy1
);
1718 r
= (Radius
+ r2
) / l
;
1719 if (r
>= 0 && r
<= 1
1720 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1721 Line
->Point1
.Y
+ r
* dy
,
1722 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1724 r
= (Radius
- r2
) / l
;
1725 if (r
>= 0 && r
<= 1
1726 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1727 Line
->Point1
.Y
+ r
* dy
,
1728 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1730 /* check arc end points */
1731 box
= GetArcEnds (Arc
);
1732 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1734 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1740 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1742 LineType
*line
= (LineType
*) b
;
1743 struct lo_info
*i
= (struct lo_info
*) cl
;
1745 if (!TEST_FLAG (TheFlag
, line
) && LineArcIntersect (line
, &i
->arc
))
1747 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1748 longjmp (i
->env
, 1);
1754 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1756 ArcType
*arc
= (ArcType
*) b
;
1757 struct lo_info
*i
= (struct lo_info
*) cl
;
1759 if (!arc
->Thickness
)
1761 if (!TEST_FLAG (TheFlag
, arc
) && ArcArcIntersect (&i
->arc
, arc
))
1763 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1764 longjmp (i
->env
, 1);
1770 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1772 PadType
*pad
= (PadType
*) b
;
1773 struct lo_info
*i
= (struct lo_info
*) cl
;
1775 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1776 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1777 && ArcPadIntersect (&i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1778 longjmp (i
->env
, 1);
1782 /* ---------------------------------------------------------------------------
1783 * searches all LOs that are connected to the given arc on the given
1784 * layergroup. All found connections are added to the list
1786 * the notation that is used is:
1787 * Xij means Xj at arc i
1790 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
)
1793 struct lo_info info
;
1796 EXPAND_BOUNDS (&info
.arc
);
1797 /* loop over all layers of the group */
1798 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1803 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1805 /* handle normal layers */
1806 if (layer
< max_copper_layer
)
1810 if (setjmp (info
.env
) == 0)
1811 r_search (LAYER_PTR (layer
)->line_tree
, &info
.arc
.BoundingBox
,
1812 NULL
, LOCtoArcLine_callback
, &info
);
1816 if (setjmp (info
.env
) == 0)
1817 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.arc
.BoundingBox
,
1818 NULL
, LOCtoArcArc_callback
, &info
);
1822 /* now check all polygons */
1823 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1824 i
!= NULL
; i
= g_list_next (i
))
1826 PolygonType
*polygon
= i
->data
;
1827 if (!TEST_FLAG (TheFlag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1828 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1834 info
.layer
= layer
- max_copper_layer
;
1835 if (setjmp (info
.env
) == 0)
1836 r_search (PCB
->Data
->pad_tree
, &info
.arc
.BoundingBox
, NULL
,
1837 LOCtoArcPad_callback
, &info
);
1846 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1848 LineType
*line
= (LineType
*) b
;
1849 struct lo_info
*i
= (struct lo_info
*) cl
;
1851 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1853 if (ADD_LINE_TO_LIST (i
->layer
, line
))
1854 longjmp (i
->env
, 1);
1860 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1862 ArcType
*arc
= (ArcType
*) b
;
1863 struct lo_info
*i
= (struct lo_info
*) cl
;
1865 if (!arc
->Thickness
)
1867 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
1869 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
1870 longjmp (i
->env
, 1);
1876 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1878 RatType
*rat
= (RatType
*) b
;
1879 struct lo_info
*i
= (struct lo_info
*) cl
;
1881 if (!TEST_FLAG (TheFlag
, rat
))
1883 if ((rat
->group1
== i
->layer
)
1884 && IsRatPointOnLineEnd (&rat
->Point1
, &i
->line
))
1886 if (ADD_RAT_TO_LIST (rat
))
1887 longjmp (i
->env
, 1);
1889 else if ((rat
->group2
== i
->layer
)
1890 && IsRatPointOnLineEnd (&rat
->Point2
, &i
->line
))
1892 if (ADD_RAT_TO_LIST (rat
))
1893 longjmp (i
->env
, 1);
1900 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1902 PadType
*pad
= (PadType
*) b
;
1903 struct lo_info
*i
= (struct lo_info
*) cl
;
1905 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
1906 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1907 && LinePadIntersect (&i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
1908 longjmp (i
->env
, 1);
1912 /* ---------------------------------------------------------------------------
1913 * searches all LOs that are connected to the given line on the given
1914 * layergroup. All found connections are added to the list
1916 * the notation that is used is:
1917 * Xij means Xj at line i
1920 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1924 struct lo_info info
;
1927 info
.layer
= LayerGroup
;
1928 EXPAND_BOUNDS (&info
.line
)
1929 /* add the new rat lines */
1930 if (setjmp (info
.env
) == 0)
1931 r_search (PCB
->Data
->rat_tree
, &info
.line
.BoundingBox
, NULL
,
1932 LOCtoLineRat_callback
, &info
);
1936 /* loop over all layers of the group */
1937 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1941 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1943 /* handle normal layers */
1944 if (layer
< max_copper_layer
)
1948 if (setjmp (info
.env
) == 0)
1949 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
1950 NULL
, LOCtoLineLine_callback
, &info
);
1954 if (setjmp (info
.env
) == 0)
1955 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
1956 NULL
, LOCtoLineArc_callback
, &info
);
1959 /* now check all polygons */
1963 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
1964 i
!= NULL
; i
= g_list_next (i
))
1966 PolygonType
*polygon
= i
->data
;
1968 (TheFlag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1969 && ADD_POLYGON_TO_LIST (layer
, polygon
))
1976 /* handle special 'pad' layers */
1977 info
.layer
= layer
- max_copper_layer
;
1978 if (setjmp (info
.env
) == 0)
1979 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
1980 LOCtoLinePad_callback
, &info
);
1989 LOT_Linecallback (const BoxType
* b
, void *cl
)
1991 LineType
*line
= (LineType
*) b
;
1992 struct lo_info
*i
= (struct lo_info
*) cl
;
1994 if (!TEST_FLAG (TheFlag
, line
) && LineLineIntersect (&i
->line
, line
))
1995 longjmp (i
->env
, 1);
2000 LOT_Arccallback (const BoxType
* b
, void *cl
)
2002 ArcType
*arc
= (ArcType
*) b
;
2003 struct lo_info
*i
= (struct lo_info
*) cl
;
2005 if (!arc
->Thickness
)
2007 if (!TEST_FLAG (TheFlag
, arc
) && LineArcIntersect (&i
->line
, arc
))
2008 longjmp (i
->env
, 1);
2013 LOT_Padcallback (const BoxType
* b
, void *cl
)
2015 PadType
*pad
= (PadType
*) b
;
2016 struct lo_info
*i
= (struct lo_info
*) cl
;
2018 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2019 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2020 && LinePadIntersect (&i
->line
, pad
))
2021 longjmp (i
->env
, 1);
2026 LOTouchesLine (LineType
*Line
, Cardinal LayerGroup
)
2029 struct lo_info info
;
2032 /* the maximum possible distance */
2035 EXPAND_BOUNDS (&info
.line
);
2037 /* loop over all layers of the group */
2038 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2040 Cardinal layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2042 /* handle normal layers */
2043 if (layer
< max_copper_layer
)
2047 /* find the first line that touches coordinates */
2049 if (setjmp (info
.env
) == 0)
2050 r_search (LAYER_PTR (layer
)->line_tree
, (BoxType
*) & info
.line
,
2051 NULL
, LOT_Linecallback
, &info
);
2054 if (setjmp (info
.env
) == 0)
2055 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.line
,
2056 NULL
, LOT_Arccallback
, &info
);
2060 /* now check all polygons */
2061 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
2062 i
!= NULL
; i
= g_list_next (i
))
2064 PolygonType
*polygon
= i
->data
;
2065 if (!TEST_FLAG (TheFlag
, polygon
)
2066 && IsLineInPolygon (Line
, polygon
))
2072 /* handle special 'pad' layers */
2073 info
.layer
= layer
- max_copper_layer
;
2074 if (setjmp (info
.env
) == 0)
2075 r_search (PCB
->Data
->pad_tree
, &info
.line
.BoundingBox
, NULL
,
2076 LOT_Padcallback
, &info
);
2092 LOCtoRat_callback (const BoxType
* b
, void *cl
)
2094 LineType
*line
= (LineType
*) b
;
2095 struct rat_info
*i
= (struct rat_info
*) cl
;
2097 if (!TEST_FLAG (TheFlag
, line
) &&
2098 ((line
->Point1
.X
== i
->Point
->X
&&
2099 line
->Point1
.Y
== i
->Point
->Y
) ||
2100 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
2102 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2103 longjmp (i
->env
, 1);
2108 PolygonToRat_callback (const BoxType
* b
, void *cl
)
2110 PolygonType
*polygon
= (PolygonType
*) b
;
2111 struct rat_info
*i
= (struct rat_info
*) cl
;
2113 if (!TEST_FLAG (TheFlag
, polygon
) && polygon
->Clipped
&&
2114 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
2115 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
2117 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2118 longjmp (i
->env
, 1);
2124 LOCtoPad_callback (const BoxType
* b
, void *cl
)
2126 PadType
*pad
= (PadType
*) b
;
2127 struct rat_info
*i
= (struct rat_info
*) cl
;
2129 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2130 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
2131 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
2132 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
2133 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
2134 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
2135 ADD_PAD_TO_LIST (i
->layer
, pad
))
2136 longjmp (i
->env
, 1);
2140 /* ---------------------------------------------------------------------------
2141 * searches all LOs that are connected to the given rat-line on the given
2142 * layergroup. All found connections are added to the list
2144 * the notation that is used is:
2145 * Xij means Xj at line i
2148 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
)
2151 struct rat_info info
;
2154 /* loop over all layers of this group */
2155 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2159 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2160 /* handle normal layers
2161 rats don't ever touch
2165 if (layer
< max_copper_layer
)
2168 if (setjmp (info
.env
) == 0)
2169 r_search_pt (LAYER_PTR (layer
)->line_tree
, Point
, 1, NULL
,
2170 LOCtoRat_callback
, &info
);
2173 if (setjmp (info
.env
) == 0)
2174 r_search_pt (LAYER_PTR (layer
)->polygon_tree
, Point
, 1,
2175 NULL
, PolygonToRat_callback
, &info
);
2179 /* handle special 'pad' layers */
2180 info
.layer
= layer
- max_copper_layer
;
2181 if (setjmp (info
.env
) == 0)
2182 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2183 LOCtoPad_callback
, &info
);
2192 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2194 LineType
*line
= (LineType
*) b
;
2195 struct lo_info
*i
= (struct lo_info
*) cl
;
2197 if (!TEST_FLAG (TheFlag
, line
) && LinePadIntersect (line
, &i
->pad
))
2199 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2200 longjmp (i
->env
, 1);
2206 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2208 ArcType
*arc
= (ArcType
*) b
;
2209 struct lo_info
*i
= (struct lo_info
*) cl
;
2211 if (!arc
->Thickness
)
2213 if (!TEST_FLAG (TheFlag
, arc
) && ArcPadIntersect (arc
, &i
->pad
))
2215 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2216 longjmp (i
->env
, 1);
2222 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2224 PolygonType
*polygon
= (PolygonType
*) b
;
2225 struct lo_info
*i
= (struct lo_info
*) cl
;
2228 if (!TEST_FLAG (TheFlag
, polygon
) &&
2229 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
.Clearance
))
2231 if (IsPadInPolygon (&i
->pad
, polygon
) &&
2232 ADD_POLYGON_TO_LIST (i
->layer
, polygon
))
2233 longjmp (i
->env
, 1);
2239 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2241 RatType
*rat
= (RatType
*) b
;
2242 struct lo_info
*i
= (struct lo_info
*) cl
;
2244 if (!TEST_FLAG (TheFlag
, rat
))
2246 if (rat
->group1
== i
->layer
&&
2247 ((rat
->Point1
.X
== i
->pad
.Point1
.X
&& rat
->Point1
.Y
== i
->pad
.Point1
.Y
) ||
2248 (rat
->Point1
.X
== i
->pad
.Point2
.X
&& rat
->Point1
.Y
== i
->pad
.Point2
.Y
) ||
2249 (rat
->Point1
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2250 rat
->Point1
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2252 if (ADD_RAT_TO_LIST (rat
))
2253 longjmp (i
->env
, 1);
2255 else if (rat
->group2
== i
->layer
&&
2256 ((rat
->Point2
.X
== i
->pad
.Point1
.X
&& rat
->Point2
.Y
== i
->pad
.Point1
.Y
) ||
2257 (rat
->Point2
.X
== i
->pad
.Point2
.X
&& rat
->Point2
.Y
== i
->pad
.Point2
.Y
) ||
2258 (rat
->Point2
.X
== (i
->pad
.Point1
.X
+ i
->pad
.Point2
.X
) / 2 &&
2259 rat
->Point2
.Y
== (i
->pad
.Point1
.Y
+ i
->pad
.Point2
.Y
) / 2)))
2261 if (ADD_RAT_TO_LIST (rat
))
2262 longjmp (i
->env
, 1);
2269 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2271 PadType
*pad
= (PadType
*) b
;
2272 struct lo_info
*i
= (struct lo_info
*) cl
;
2274 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2275 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2276 && PadPadIntersect (pad
, &i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
))
2277 longjmp (i
->env
, 1);
2281 /* ---------------------------------------------------------------------------
2282 * searches all LOs that are connected to the given pad on the given
2283 * layergroup. All found connections are added to the list
2286 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
)
2289 struct lo_info info
;
2291 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2292 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, false));
2295 EXPAND_BOUNDS (&info
.pad
);
2296 /* add the new rat lines */
2297 info
.layer
= LayerGroup
;
2298 if (setjmp (info
.env
) == 0)
2299 r_search (PCB
->Data
->rat_tree
, &info
.pad
.BoundingBox
, NULL
,
2300 LOCtoPadRat_callback
, &info
);
2304 /* loop over all layers of the group */
2305 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2309 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2310 /* handle normal layers */
2311 if (layer
< max_copper_layer
)
2315 if (setjmp (info
.env
) == 0)
2316 r_search (LAYER_PTR (layer
)->line_tree
, &info
.pad
.BoundingBox
,
2317 NULL
, LOCtoPadLine_callback
, &info
);
2321 if (setjmp (info
.env
) == 0)
2322 r_search (LAYER_PTR (layer
)->arc_tree
, &info
.pad
.BoundingBox
,
2323 NULL
, LOCtoPadArc_callback
, &info
);
2327 if (setjmp (info
.env
) == 0)
2328 r_search (LAYER_PTR (layer
)->polygon_tree
, &info
.pad
.BoundingBox
,
2329 NULL
, LOCtoPadPoly_callback
, &info
);
2335 /* handle special 'pad' layers */
2336 info
.layer
= layer
- max_copper_layer
;
2337 if (setjmp (info
.env
) == 0)
2338 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.pad
, NULL
,
2339 LOCtoPadPad_callback
, &info
);
2349 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2351 LineType
*line
= (LineType
*) b
;
2352 struct lo_info
*i
= (struct lo_info
*) cl
;
2354 if (!TEST_FLAG (TheFlag
, line
) && IsLineInPolygon (line
, &i
->polygon
))
2356 if (ADD_LINE_TO_LIST (i
->layer
, line
))
2357 longjmp (i
->env
, 1);
2363 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2365 ArcType
*arc
= (ArcType
*) b
;
2366 struct lo_info
*i
= (struct lo_info
*) cl
;
2368 if (!arc
->Thickness
)
2370 if (!TEST_FLAG (TheFlag
, arc
) && IsArcInPolygon (arc
, &i
->polygon
))
2372 if (ADD_ARC_TO_LIST (i
->layer
, arc
))
2373 longjmp (i
->env
, 1);
2379 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2381 PadType
*pad
= (PadType
*) b
;
2382 struct lo_info
*i
= (struct lo_info
*) cl
;
2384 if (!TEST_FLAG (TheFlag
, pad
) && i
->layer
==
2385 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2386 && IsPadInPolygon (pad
, &i
->polygon
))
2388 if (ADD_PAD_TO_LIST (i
->layer
, pad
))
2389 longjmp (i
->env
, 1);
2395 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2397 RatType
*rat
= (RatType
*) b
;
2398 struct lo_info
*i
= (struct lo_info
*) cl
;
2400 if (!TEST_FLAG (TheFlag
, rat
))
2402 if ((rat
->Point1
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2403 rat
->Point1
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2404 rat
->group1
== i
->layer
) ||
2405 (rat
->Point2
.X
== (i
->polygon
.Clipped
->contours
->head
.point
[0]) &&
2406 rat
->Point2
.Y
== (i
->polygon
.Clipped
->contours
->head
.point
[1]) &&
2407 rat
->group2
== i
->layer
))
2408 if (ADD_RAT_TO_LIST (rat
))
2409 longjmp (i
->env
, 1);
2415 /* ---------------------------------------------------------------------------
2416 * looks up LOs that are connected to the given polygon
2417 * on the given layergroup. All found connections are added to the list
2420 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
)
2423 struct lo_info info
;
2425 if (!Polygon
->Clipped
)
2427 info
.polygon
= *Polygon
;
2428 EXPAND_BOUNDS (&info
.polygon
);
2429 info
.layer
= LayerGroup
;
2431 if (setjmp (info
.env
) == 0)
2432 r_search (PCB
->Data
->rat_tree
, (BoxType
*) & info
.polygon
, NULL
,
2433 LOCtoPolyRat_callback
, &info
);
2436 /* loop over all layers of the group */
2437 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2441 layer
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2443 /* handle normal layers */
2444 if (layer
< max_copper_layer
)
2448 /* check all polygons */
2449 for (i
= PCB
->Data
->Layer
[layer
].Polygon
;
2450 i
!= NULL
; i
= g_list_next (i
))
2452 PolygonType
*polygon
= i
->data
;
2453 if (!TEST_FLAG (TheFlag
, polygon
)
2454 && IsPolygonInPolygon (polygon
, Polygon
)
2455 && ADD_POLYGON_TO_LIST (layer
, polygon
))
2460 /* check all lines */
2461 if (setjmp (info
.env
) == 0)
2462 r_search (LAYER_PTR (layer
)->line_tree
,
2463 (BoxType
*) & info
.polygon
, NULL
,
2464 LOCtoPolyLine_callback
, &info
);
2467 /* check all arcs */
2468 if (setjmp (info
.env
) == 0)
2469 r_search (LAYER_PTR (layer
)->arc_tree
, (BoxType
*) & info
.polygon
,
2470 NULL
, LOCtoPolyArc_callback
, &info
);
2476 info
.layer
= layer
- max_copper_layer
;
2477 if (setjmp (info
.env
) == 0)
2478 r_search (PCB
->Data
->pad_tree
, (BoxType
*) & info
.polygon
,
2479 NULL
, LOCtoPolyPad_callback
, &info
);
2487 /* ---------------------------------------------------------------------------
2488 * checks if an arc has a connection to a polygon
2490 * - first check if the arc can intersect with the polygon by
2491 * evaluating the bounding boxes
2492 * - check the two end points of the arc. If none of them matches
2493 * - check all segments of the polygon against the arc.
2496 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2498 BoxType
*Box
= (BoxType
*) Arc
;
2500 /* arcs with clearance never touch polys */
2501 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2503 if (!Polygon
->Clipped
)
2505 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2506 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2507 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2508 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2512 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2513 return false; /* error */
2514 return isects (ap
, Polygon
, true);
2519 /* ---------------------------------------------------------------------------
2520 * checks if a line has a connection to a polygon
2522 * - first check if the line can intersect with the polygon by
2523 * evaluating the bounding boxes
2524 * - check the two end points of the line. If none of them matches
2525 * - check all segments of the polygon against the line.
2528 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2530 BoxType
*Box
= (BoxType
*) Line
;
2533 /* lines with clearance never touch polygons */
2534 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2536 if (!Polygon
->Clipped
)
2538 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2540 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2541 Coord x1
, x2
, y1
, y2
;
2543 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2544 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2545 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2546 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2547 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2549 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2550 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2551 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2552 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2554 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2555 return FALSE
; /* error */
2556 return isects (lp
, Polygon
, true);
2561 /* ---------------------------------------------------------------------------
2562 * checks if a pad connects to a non-clearing polygon
2564 * The polygon is assumed to already have been proven non-clearing
2567 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2569 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2572 /* ---------------------------------------------------------------------------
2573 * checks if a polygon has a connection to a second one
2575 * First check all points out of P1 against P2 and vice versa.
2576 * If both fail check all lines of P1 against the ones of P2
2579 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2581 if (!P1
->Clipped
|| !P2
->Clipped
)
2583 assert (P1
->Clipped
->contours
);
2584 assert (P2
->Clipped
->contours
);
2586 /* first check if both bounding boxes intersect. If not, return quickly */
2587 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2588 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2589 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2590 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2593 /* first check un-bloated case */
2594 if (isects (P1
->Clipped
, P2
, false))
2597 /* now the difficult case of bloated */
2601 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2604 VNODE
*v
= &c
->head
;
2605 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2606 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2607 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2608 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2611 line
.Point1
.X
= v
->point
[0];
2612 line
.Point1
.Y
= v
->point
[1];
2613 line
.Thickness
= 2 * Bloat
;
2615 line
.Flags
= NoFlags ();
2616 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2618 line
.Point2
.X
= v
->point
[0];
2619 line
.Point2
.Y
= v
->point
[1];
2620 SetLineBoundingBox (&line
);
2621 if (IsLineInPolygon (&line
, P2
))
2623 line
.Point1
.X
= line
.Point2
.X
;
2624 line
.Point1
.Y
= line
.Point2
.Y
;
2633 /* ---------------------------------------------------------------------------
2634 * writes the several names of an element to a file
2637 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2639 static DynamicStringType cname
, pname
, vname
;
2641 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2642 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2643 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2644 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2647 /* ---------------------------------------------------------------------------
2648 * writes the several names of an element to a file
2651 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2653 fputs ("Element", FP
);
2654 PrintElementNameList (Element
, FP
);
2658 /* ---------------------------------------------------------------------------
2659 * prints one {pin,pad,via}/element entry of connection lists
2662 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2663 bool FirstOne
, FILE * FP
)
2665 static DynamicStringType oname
;
2667 CreateQuotedString (&oname
, ObjName
);
2669 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2672 fprintf (FP
, "\t\t%s ", oname
.Data
);
2674 PrintElementNameList (Element
, FP
);
2676 fputs ("(__VIA__)\n", FP
);
2680 /* ---------------------------------------------------------------------------
2681 * prints all found connections of a pads to file FP
2682 * the connections are stacked in 'PadList'
2685 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2690 if (!PadList
[Layer
].Number
)
2693 /* the starting pad */
2696 ptr
= PADLIST_ENTRY (Layer
, 0);
2698 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2700 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2703 /* we maybe have to start with i=1 if we are handling the
2704 * starting-pad itself
2706 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2708 ptr
= PADLIST_ENTRY (Layer
, i
);
2710 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2712 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2716 /* ---------------------------------------------------------------------------
2717 * prints all found connections of a pin to file FP
2718 * the connections are stacked in 'PVList'
2721 PrintPinConnections (FILE * FP
, bool IsFirst
)
2731 /* the starting pin */
2732 pv
= PVLIST_ENTRY (0);
2733 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2736 /* we maybe have to start with i=1 if we are handling the
2737 * starting-pin itself
2739 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2741 /* get the elements name or assume that its a via */
2742 pv
= PVLIST_ENTRY (i
);
2743 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2747 /* ---------------------------------------------------------------------------
2748 * checks if all lists of new objects are handled
2751 ListsEmpty (bool AndRats
)
2756 empty
= (PVList
.Location
>= PVList
.Number
);
2758 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2759 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2760 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2761 && ArcList
[i
].Location
>= ArcList
[i
].Number
2762 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2767 reassign_no_drc_flags (void)
2771 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2773 LayerType
*l
= LAYER_PTR (layer
);
2774 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2781 /* ---------------------------------------------------------------------------
2782 * loops till no more connections are found
2785 DoIt (bool AndRats
, bool AndDraw
)
2787 bool newone
= false;
2788 reassign_no_drc_flags ();
2791 /* lookup connections; these are the steps (2) to (4)
2792 * from the description
2794 newone
= LookupPVConnectionsToPVList () ||
2795 LookupLOConnectionsToPVList (AndRats
) ||
2796 LookupLOConnectionsToLOList (AndRats
) ||
2797 LookupPVConnectionsToLOList (AndRats
);
2799 DrawNewConnections ();
2801 while (!newone
&& !ListsEmpty (AndRats
));
2807 /* returns true if nothing un-found touches the passed line
2808 * returns false if it would touch something not yet found
2809 * doesn't include rat-lines in the search
2813 lineClear (LineType
*line
, Cardinal group
)
2815 if (LOTouchesLine (line
, group
))
2817 if (PVTouchesLine (line
))
2822 /* ---------------------------------------------------------------------------
2823 * prints all unused pins of an element to file FP
2826 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
)
2830 static DynamicStringType oname
;
2832 /* check all pins in element */
2836 if (!TEST_FLAG (HOLEFLAG
, pin
))
2838 /* pin might have bee checked before, add to list if not */
2839 if (!TEST_FLAG (TheFlag
, pin
) && FP
)
2842 if (ADD_PV_TO_LIST (pin
))
2845 number
= PadList
[COMPONENT_LAYER
].Number
2846 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2847 /* the pin has no connection if it's the only
2848 * list entry; don't count vias
2850 for (i
= 0; i
< PVList
.Number
; i
++)
2851 if (!PVLIST_ENTRY (i
)->Element
)
2855 /* output of element name if not already done */
2858 PrintConnectionElementName (Element
, FP
);
2862 /* write name to list and draw selected object */
2863 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2864 fprintf (FP
, "\t%s\n", oname
.Data
);
2865 SET_FLAG (SELECTEDFLAG
, pin
);
2869 /* reset found objects for the next pin */
2870 if (PrepareNextLoop (FP
))
2877 /* check all pads in element */
2880 /* lookup pad in list */
2881 /* pad might has bee checked before, add to list if not */
2882 if (!TEST_FLAG (TheFlag
, pad
) && FP
)
2885 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2886 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
2889 number
= PadList
[COMPONENT_LAYER
].Number
2890 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2891 /* the pin has no connection if it's the only
2892 * list entry; don't count vias
2894 for (i
= 0; i
< PVList
.Number
; i
++)
2895 if (!PVLIST_ENTRY (i
)->Element
)
2899 /* output of element name if not already done */
2902 PrintConnectionElementName (Element
, FP
);
2906 /* write name to list and draw selected object */
2907 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2908 fprintf (FP
, "\t%s\n", oname
.Data
);
2909 SET_FLAG (SELECTEDFLAG
, pad
);
2913 /* reset found objects for the next pin */
2914 if (PrepareNextLoop (FP
))
2920 /* print separator if element has unused pins or pads */
2923 fputs ("}\n\n", FP
);
2929 /* ---------------------------------------------------------------------------
2930 * resets some flags for looking up the next pin/pad
2933 PrepareNextLoop (FILE * FP
)
2937 /* reset found LOs for the next pin */
2938 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2940 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2941 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2942 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2945 /* reset found pads */
2946 for (layer
= 0; layer
< 2; layer
++)
2947 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2950 PVList
.Number
= PVList
.Location
= 0;
2951 RatList
.Number
= RatList
.Location
= 0;
2956 /* ---------------------------------------------------------------------------
2957 * finds all connections to the pins of the passed element.
2958 * The result is written to file FP
2959 * Returns true if operation was aborted
2962 PrintElementConnections (ElementType
*Element
, FILE * FP
, bool AndDraw
)
2964 PrintConnectionElementName (Element
, FP
);
2966 /* check all pins in element */
2969 /* pin might have been checked before, add to list if not */
2970 if (TEST_FLAG (TheFlag
, pin
))
2972 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2973 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2976 if (ADD_PV_TO_LIST (pin
))
2978 DoIt (true, AndDraw
);
2979 /* printout all found connections */
2980 PrintPinConnections (FP
, true);
2981 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
2982 PrintPadConnections (SOLDER_LAYER
, FP
, false);
2983 fputs ("\t}\n", FP
);
2984 if (PrepareNextLoop (FP
))
2989 /* check all pads in element */
2993 /* pad might have been checked before, add to list if not */
2994 if (TEST_FLAG (TheFlag
, pad
))
2996 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2997 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
3000 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
3001 if (ADD_PAD_TO_LIST (layer
, pad
))
3003 DoIt (true, AndDraw
);
3004 /* print all found connections */
3005 PrintPadConnections (layer
, FP
, true);
3006 PrintPadConnections (layer
==
3007 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
3009 PrintPinConnections (FP
, false);
3010 fputs ("\t}\n", FP
);
3011 if (PrepareNextLoop (FP
))
3015 fputs ("}\n\n", FP
);
3019 /* ---------------------------------------------------------------------------
3020 * draws all new connections which have been found since the
3021 * routine was called the last time
3024 DrawNewConnections (void)
3029 /* decrement 'i' to keep layerstack order */
3030 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
3032 Cardinal layer
= LayerStack
[i
];
3034 if (PCB
->Data
->Layer
[layer
].On
)
3036 /* draw all new lines */
3037 position
= LineList
[layer
].DrawLocation
;
3038 for (; position
< LineList
[layer
].Number
; position
++)
3039 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
3040 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
3042 /* draw all new arcs */
3043 position
= ArcList
[layer
].DrawLocation
;
3044 for (; position
< ArcList
[layer
].Number
; position
++)
3045 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
3046 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
3048 /* draw all new polygons */
3049 position
= PolygonList
[layer
].DrawLocation
;
3050 for (; position
< PolygonList
[layer
].Number
; position
++)
3051 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
3052 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
3056 /* draw all new pads */
3058 for (i
= 0; i
< 2; i
++)
3060 position
= PadList
[i
].DrawLocation
;
3062 for (; position
< PadList
[i
].Number
; position
++)
3063 DrawPad (PADLIST_ENTRY (i
, position
));
3064 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
3067 /* draw all new PVs; 'PVList' holds a list of pointers to the
3068 * sorted array pointers to PV data
3070 while (PVList
.DrawLocation
< PVList
.Number
)
3072 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
3074 if (TEST_FLAG (PINFLAG
, pv
))
3079 else if (PCB
->ViaOn
)
3081 PVList
.DrawLocation
++;
3083 /* draw the new rat-lines */
3086 position
= RatList
.DrawLocation
;
3087 for (; position
< RatList
.Number
; position
++)
3088 DrawRat (RATLIST_ENTRY (position
));
3089 RatList
.DrawLocation
= RatList
.Number
;
3093 /* ---------------------------------------------------------------------------
3094 * find all connections to pins within one element
3097 LookupElementConnections (ElementType
*Element
, FILE * FP
)
3099 /* reset all currently marked connections */
3101 TheFlag
= FOUNDFLAG
;
3102 ResetConnections (true);
3103 InitConnectionLookup ();
3104 PrintElementConnections (Element
, FP
, true);
3105 SetChangedFlag (true);
3106 if (Settings
.RingBellWhenFinished
)
3108 FreeConnectionLookupMemory ();
3109 IncrementUndoSerialNumber ();
3114 /* ---------------------------------------------------------------------------
3115 * find all connections to pins of all element
3118 LookupConnectionsToAllElements (FILE * FP
)
3120 /* reset all currently marked connections */
3122 TheFlag
= FOUNDFLAG
;
3123 ResetConnections (false);
3124 InitConnectionLookup ();
3126 ELEMENT_LOOP (PCB
->Data
);
3128 /* break if abort dialog returned true */
3129 if (PrintElementConnections (element
, FP
, false))
3132 if (Settings
.ResetAfterElement
&& n
!= 1)
3133 ResetConnections (false);
3136 if (Settings
.RingBellWhenFinished
)
3138 ResetConnections (false);
3139 FreeConnectionLookupMemory ();
3143 /*---------------------------------------------------------------------------
3144 * add the starting object to the list of found objects
3147 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
3155 if (ADD_PV_TO_LIST ((PinType
*) ptr2
))
3162 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
))
3169 int layer
= GetLayerNumber (PCB
->Data
,
3170 (LayerType
*) ptr1
);
3172 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
))
3179 int layer
= GetLayerNumber (PCB
->Data
,
3180 (LayerType
*) ptr1
);
3182 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
))
3189 int layer
= GetLayerNumber (PCB
->Data
,
3190 (LayerType
*) ptr1
);
3192 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
))
3199 PadType
*pad
= (PadType
*) ptr2
;
3202 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
))
3211 /* ---------------------------------------------------------------------------
3212 * looks up all connections from the object at the given coordinates
3213 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3214 * the objects are re-drawn if AndDraw is true
3215 * also the action is marked as undoable if AndDraw is true
3218 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int which_flag
)
3220 void *ptr1
, *ptr2
, *ptr3
;
3224 /* check if there are any pins or pads at that position */
3226 reassign_no_drc_flags ();
3229 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3230 if (type
== NO_TYPE
)
3234 SearchObjectByLocation
3235 (LOOKUP_MORE
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3236 if (type
== NO_TYPE
)
3238 if (type
& SILK_TYPE
)
3240 int laynum
= GetLayerNumber (PCB
->Data
,
3241 (LayerType
*) ptr1
);
3243 /* don't mess with non-conducting objects! */
3244 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3250 name
= ConnectionName (type
, ptr1
, ptr2
);
3251 hid_actionl ("NetlistShow", name
, NULL
);
3254 TheFlag
= which_flag
;
3256 InitConnectionLookup ();
3258 /* now add the object to the appropriate list and start scanning
3259 * This is step (1) from the description
3261 ListStart (type
, ptr1
, ptr2
, ptr3
);
3262 DoIt (true, AndDraw
);
3264 IncrementUndoSerialNumber ();
3270 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3272 FreeConnectionLookupMemory ();
3275 /* ---------------------------------------------------------------------------
3276 * find connections for rats nesting
3277 * assumes InitConnectionLookup() has already been done
3280 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3281 bool undo
, bool AndRats
)
3285 ListStart (type
, ptr1
, ptr2
, ptr3
);
3286 DoIt (AndRats
, false);
3290 /* ---------------------------------------------------------------------------
3291 * find all unused pins of all element
3294 LookupUnusedPins (FILE * FP
)
3296 /* reset all currently marked connections */
3298 ResetConnections (true);
3299 InitConnectionLookup ();
3301 ELEMENT_LOOP (PCB
->Data
);
3303 /* break if abort dialog returned true;
3304 * passing NULL as filedescriptor discards the normal output
3306 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
))
3311 if (Settings
.RingBellWhenFinished
)
3313 FreeConnectionLookupMemory ();
3314 IncrementUndoSerialNumber ();
3319 /* ---------------------------------------------------------------------------
3320 * resets all used flags of pins and vias
3323 ResetFoundPinsViasAndPads (bool AndDraw
)
3325 bool change
= false;
3327 VIA_LOOP (PCB
->Data
);
3329 if (TEST_FLAG (TheFlag
, via
))
3332 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3333 CLEAR_FLAG (TheFlag
, via
);
3340 ELEMENT_LOOP (PCB
->Data
);
3344 if (TEST_FLAG (TheFlag
, pin
))
3347 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3348 CLEAR_FLAG (TheFlag
, pin
);
3357 if (TEST_FLAG (TheFlag
, pad
))
3360 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3361 CLEAR_FLAG (TheFlag
, pad
);
3371 SetChangedFlag (true);
3375 /* ---------------------------------------------------------------------------
3376 * resets all used flags of LOs
3379 ResetFoundLinesAndPolygons (bool AndDraw
)
3381 bool change
= false;
3383 RAT_LOOP (PCB
->Data
);
3385 if (TEST_FLAG (TheFlag
, line
))
3388 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3389 CLEAR_FLAG (TheFlag
, line
);
3396 COPPERLINE_LOOP (PCB
->Data
);
3398 if (TEST_FLAG (TheFlag
, line
))
3401 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3402 CLEAR_FLAG (TheFlag
, line
);
3404 DrawLine (layer
, line
);
3409 COPPERARC_LOOP (PCB
->Data
);
3411 if (TEST_FLAG (TheFlag
, arc
))
3414 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3415 CLEAR_FLAG (TheFlag
, arc
);
3417 DrawArc (layer
, arc
);
3422 COPPERPOLYGON_LOOP (PCB
->Data
);
3424 if (TEST_FLAG (TheFlag
, polygon
))
3427 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3428 CLEAR_FLAG (TheFlag
, polygon
);
3430 DrawPolygon (layer
, polygon
);
3436 SetChangedFlag (true);
3440 /* ---------------------------------------------------------------------------
3441 * resets all found connections
3444 ResetConnections (bool AndDraw
)
3446 bool change
= false;
3448 change
= ResetFoundPinsViasAndPads (AndDraw
) || change
;
3449 change
= ResetFoundLinesAndPolygons (AndDraw
) || change
;
3454 /*----------------------------------------------------------------------------
3455 * Dumps the list contents
3462 for (i
= 0; i
< 2; i
++)
3464 PadList
[i
].Number
= 0;
3465 PadList
[i
].Location
= 0;
3466 PadList
[i
].DrawLocation
= 0;
3470 PVList
.Location
= 0;
3472 for (i
= 0; i
< max_copper_layer
; i
++)
3474 LineList
[i
].Location
= 0;
3475 LineList
[i
].DrawLocation
= 0;
3476 LineList
[i
].Number
= 0;
3477 ArcList
[i
].Location
= 0;
3478 ArcList
[i
].DrawLocation
= 0;
3479 ArcList
[i
].Number
= 0;
3480 PolygonList
[i
].Location
= 0;
3481 PolygonList
[i
].DrawLocation
= 0;
3482 PolygonList
[i
].Number
= 0;
3485 RatList
.Location
= 0;
3486 RatList
.DrawLocation
= 0;
3489 /*-----------------------------------------------------------------------------
3490 * Check for DRC violations on a single net starting from the pad or pin
3491 * sees if the connectivity changes when everything is bloated, or shrunk
3494 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3498 long int *object_id_list
;
3499 int *object_type_list
;
3500 DrcViolationType
*violation
;
3502 if (PCB
->Shrink
!= 0)
3504 Bloat
= -PCB
->Shrink
;
3505 TheFlag
= DRCFLAG
| SELECTEDFLAG
;
3506 ListStart (What
, ptr1
, ptr2
, ptr3
);
3508 /* ok now the shrunk net has the SELECTEDFLAG set */
3510 TheFlag
= FOUNDFLAG
;
3511 ListStart (What
, ptr1
, ptr2
, ptr3
);
3513 drc
= true; /* abort the search if we find anything not already found */
3514 if (DoIt (true, false))
3517 /* make the flag changes undoable */
3518 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3519 ResetConnections (false);
3522 Bloat
= -PCB
->Shrink
;
3523 TheFlag
= SELECTEDFLAG
;
3524 ListStart (What
, ptr1
, ptr2
, ptr3
);
3527 ListStart (What
, ptr1
, ptr2
, ptr3
);
3528 TheFlag
= FOUNDFLAG
;
3536 LocateError (&x
, &y
);
3537 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3538 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3539 _("Insufficient overlap between objects can lead to broken tracks\n"
3540 "due to registration errors with old wheel style photo-plotters."),
3542 0, /* ANGLE OF ERROR UNKNOWN */
3543 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3544 0, /* MAGNITUDE OF ERROR UNKNOWN */
3549 append_drc_violation (violation
);
3550 pcb_drc_violation_free (violation
);
3551 free (object_id_list
);
3552 free (object_type_list
);
3554 if (!throw_drc_dialog())
3556 IncrementUndoSerialNumber ();
3561 /* now check the bloated condition */
3563 ResetConnections (false);
3564 TheFlag
= FOUNDFLAG
;
3565 ListStart (What
, ptr1
, ptr2
, ptr3
);
3568 while (DoIt (true, false))
3571 /* make the flag changes undoable */
3572 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3573 ResetConnections (false);
3577 TheFlag
= SELECTEDFLAG
;
3578 ListStart (What
, ptr1
, ptr2
, ptr3
);
3581 TheFlag
= FOUNDFLAG
;
3582 ListStart (What
, ptr1
, ptr2
, ptr3
);
3588 LocateError (&x
, &y
);
3589 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3590 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3591 _("Circuits that are too close may bridge during imaging, etching,\n"
3592 "plating, or soldering processes resulting in a direct short."),
3594 0, /* ANGLE OF ERROR UNKNOWN */
3595 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3596 0, /* MAGNITUDE OF ERROR UNKNOWN */
3601 append_drc_violation (violation
);
3602 pcb_drc_violation_free (violation
);
3603 free (object_id_list
);
3604 free (object_type_list
);
3607 if (!throw_drc_dialog())
3609 IncrementUndoSerialNumber ();
3611 /* highlight the rest of the encroaching net so it's not reported again */
3612 TheFlag
|= SELECTEDFLAG
;
3614 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
);
3619 ListStart (What
, ptr1
, ptr2
, ptr3
);
3623 TheFlag
= FOUNDFLAG
| SELECTEDFLAG
;
3624 ResetConnections (false);
3628 /*----------------------------------------------------------------------------
3629 * set up a temporary flag to use
3632 SaveFindFlag (int NewFlag
)
3638 /*----------------------------------------------------------------------------
3642 RestoreFindFlag (void)
3647 /* DRC clearance callback */
3650 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3651 int type
, void *ptr1
, void *ptr2
)
3656 long int *object_id_list
;
3657 int *object_type_list
;
3658 DrcViolationType
*violation
;
3660 LineType
*line
= (LineType
*) ptr2
;
3661 ArcType
*arc
= (ArcType
*) ptr2
;
3662 PinType
*pin
= (PinType
*) ptr2
;
3663 PadType
*pad
= (PadType
*) ptr2
;
3672 if (line
->Clearance
< 2 * PCB
->Bloat
)
3674 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3675 SET_FLAG (TheFlag
, line
);
3676 message
= _("Line with insufficient clearance inside polygon\n");
3681 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3683 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3684 SET_FLAG (TheFlag
, arc
);
3685 message
= _("Arc with insufficient clearance inside polygon\n");
3690 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3691 if (IsPadInPolygon(pad
,polygon
))
3693 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3694 SET_FLAG (TheFlag
, pad
);
3695 message
= _("Pad with insufficient clearance inside polygon\n");
3700 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3702 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3703 SET_FLAG (TheFlag
, pin
);
3704 message
= _("Pin with insufficient clearance inside polygon\n");
3709 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3711 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3712 SET_FLAG (TheFlag
, pin
);
3713 message
= _("Via with insufficient clearance inside polygon\n");
3718 Message ("hace: Bad Plow object in callback\n");
3723 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3724 SET_FLAG (FOUNDFLAG
, polygon
);
3725 DrawPolygon (layer
, polygon
);
3726 DrawObject (type
, ptr1
, ptr2
);
3728 LocateError (&x
, &y
);
3729 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3730 violation
= pcb_drc_violation_new (message
,
3731 _("Circuits that are too close may bridge during imaging, etching,\n"
3732 "plating, or soldering processes resulting in a direct short."),
3734 0, /* ANGLE OF ERROR UNKNOWN */
3735 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3736 0, /* MAGNITUDE OF ERROR UNKNOWN */
3741 append_drc_violation (violation
);
3742 pcb_drc_violation_free (violation
);
3743 free (object_id_list
);
3744 free (object_type_list
);
3745 if (!throw_drc_dialog())
3750 IncrementUndoSerialNumber ();
3755 /*-----------------------------------------------------------------------------
3756 * Check for DRC violations
3757 * see if the connectivity changes when everything is bloated, or shrunk
3764 long int *object_id_list
;
3765 int *object_type_list
;
3766 DrcViolationType
*violation
;
3770 reset_drc_dialog_message();
3774 SaveStackAndVisibility ();
3775 ResetStackAndVisibility ();
3776 hid_action ("LayersChanged");
3777 InitConnectionLookup ();
3779 TheFlag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3781 if (ResetConnections (true))
3783 IncrementUndoSerialNumber ();
3789 ELEMENT_LOOP (PCB
->Data
);
3793 if (!TEST_FLAG (DRCFLAG
, pin
)
3794 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3806 /* count up how many pads have no solderpaste openings */
3807 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3810 if (!TEST_FLAG (DRCFLAG
, pad
)
3811 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3823 VIA_LOOP (PCB
->Data
);
3825 if (!TEST_FLAG (DRCFLAG
, via
)
3826 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3834 TheFlag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3835 ResetConnections (false);
3836 TheFlag
= SELECTEDFLAG
;
3837 /* check minimum widths and polygon clearances */
3840 COPPERLINE_LOOP (PCB
->Data
);
3842 /* check line clearances in polygons */
3843 PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
);
3846 if (line
->Thickness
< PCB
->minWid
)
3848 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3849 SET_FLAG (TheFlag
, line
);
3850 DrawLine (layer
, line
);
3852 SetThing (LINE_TYPE
, layer
, line
, line
);
3853 LocateError (&x
, &y
);
3854 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3855 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3856 _("Process specifications dictate a minimum feature-width\n"
3857 "that can reliably be reproduced"),
3859 0, /* ANGLE OF ERROR UNKNOWN */
3860 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3866 append_drc_violation (violation
);
3867 pcb_drc_violation_free (violation
);
3868 free (object_id_list
);
3869 free (object_type_list
);
3870 if (!throw_drc_dialog())
3875 IncrementUndoSerialNumber ();
3883 COPPERARC_LOOP (PCB
->Data
);
3885 PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
);
3888 if (arc
->Thickness
< PCB
->minWid
)
3890 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3891 SET_FLAG (TheFlag
, arc
);
3892 DrawArc (layer
, arc
);
3894 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3895 LocateError (&x
, &y
);
3896 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3897 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3898 _("Process specifications dictate a minimum feature-width\n"
3899 "that can reliably be reproduced"),
3901 0, /* ANGLE OF ERROR UNKNOWN */
3902 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3908 append_drc_violation (violation
);
3909 pcb_drc_violation_free (violation
);
3910 free (object_id_list
);
3911 free (object_type_list
);
3912 if (!throw_drc_dialog())
3917 IncrementUndoSerialNumber ();
3925 ALLPIN_LOOP (PCB
->Data
);
3927 PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
);
3930 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3931 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3933 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3934 SET_FLAG (TheFlag
, pin
);
3937 SetThing (PIN_TYPE
, element
, pin
, pin
);
3938 LocateError (&x
, &y
);
3939 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3940 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3941 _("Annular rings that are too small may erode during etching,\n"
3942 "resulting in a broken connection"),
3944 0, /* ANGLE OF ERROR UNKNOWN */
3945 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3946 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3951 append_drc_violation (violation
);
3952 pcb_drc_violation_free (violation
);
3953 free (object_id_list
);
3954 free (object_type_list
);
3955 if (!throw_drc_dialog())
3960 IncrementUndoSerialNumber ();
3963 if (pin
->DrillingHole
< PCB
->minDrill
)
3965 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3966 SET_FLAG (TheFlag
, pin
);
3969 SetThing (PIN_TYPE
, element
, pin
, pin
);
3970 LocateError (&x
, &y
);
3971 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3972 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3973 _("Process rules dictate the minimum drill size which can be used"),
3975 0, /* ANGLE OF ERROR UNKNOWN */
3976 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3982 append_drc_violation (violation
);
3983 pcb_drc_violation_free (violation
);
3984 free (object_id_list
);
3985 free (object_type_list
);
3986 if (!throw_drc_dialog())
3991 IncrementUndoSerialNumber ();
3999 ALLPAD_LOOP (PCB
->Data
);
4001 PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
);
4004 if (pad
->Thickness
< PCB
->minWid
)
4006 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
4007 SET_FLAG (TheFlag
, pad
);
4010 SetThing (PAD_TYPE
, element
, pad
, pad
);
4011 LocateError (&x
, &y
);
4012 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4013 violation
= pcb_drc_violation_new (_("Pad is too thin"),
4014 _("Pads which are too thin may erode during etching,\n"
4015 "resulting in a broken or unreliable connection"),
4017 0, /* ANGLE OF ERROR UNKNOWN */
4018 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4024 append_drc_violation (violation
);
4025 pcb_drc_violation_free (violation
);
4026 free (object_id_list
);
4027 free (object_type_list
);
4028 if (!throw_drc_dialog())
4033 IncrementUndoSerialNumber ();
4041 VIA_LOOP (PCB
->Data
);
4043 PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
);
4046 if (!TEST_FLAG (HOLEFLAG
, via
) &&
4047 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
4049 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
4050 SET_FLAG (TheFlag
, via
);
4053 SetThing (VIA_TYPE
, via
, via
, via
);
4054 LocateError (&x
, &y
);
4055 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4056 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
4057 _("Annular rings that are too small may erode during etching,\n"
4058 "resulting in a broken connection"),
4060 0, /* ANGLE OF ERROR UNKNOWN */
4061 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4062 (via
->Thickness
- via
->DrillingHole
) / 2,
4067 append_drc_violation (violation
);
4068 pcb_drc_violation_free (violation
);
4069 free (object_id_list
);
4070 free (object_type_list
);
4071 if (!throw_drc_dialog())
4076 IncrementUndoSerialNumber ();
4079 if (via
->DrillingHole
< PCB
->minDrill
)
4081 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
4082 SET_FLAG (TheFlag
, via
);
4085 SetThing (VIA_TYPE
, via
, via
, via
);
4086 LocateError (&x
, &y
);
4087 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4088 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
4089 _("Process rules dictate the minimum drill size which can be used"),
4091 0, /* ANGLE OF ERROR UNKNOWN */
4092 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4098 append_drc_violation (violation
);
4099 pcb_drc_violation_free (violation
);
4100 free (object_id_list
);
4101 free (object_type_list
);
4102 if (!throw_drc_dialog())
4107 IncrementUndoSerialNumber ();
4114 FreeConnectionLookupMemory ();
4115 TheFlag
= FOUNDFLAG
;
4118 /* check silkscreen minimum widths outside of elements */
4119 /* XXX - need to check text and polygons too! */
4120 TheFlag
= SELECTEDFLAG
;
4123 SILKLINE_LOOP (PCB
->Data
);
4125 if (line
->Thickness
< PCB
->minSlk
)
4127 SET_FLAG (TheFlag
, line
);
4128 DrawLine (layer
, line
);
4130 SetThing (LINE_TYPE
, layer
, line
, line
);
4131 LocateError (&x
, &y
);
4132 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4133 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
4134 _("Process specifications dictate a minimum silkscreen feature-width\n"
4135 "that can reliably be reproduced"),
4137 0, /* ANGLE OF ERROR UNKNOWN */
4138 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4144 append_drc_violation (violation
);
4145 pcb_drc_violation_free (violation
);
4146 free (object_id_list
);
4147 free (object_type_list
);
4148 if (!throw_drc_dialog())
4158 /* check silkscreen minimum widths inside of elements */
4159 /* XXX - need to check text and polygons too! */
4160 TheFlag
= SELECTEDFLAG
;
4163 ELEMENT_LOOP (PCB
->Data
);
4166 ELEMENTLINE_LOOP (element
);
4168 if (line
->Thickness
< PCB
->minSlk
)
4179 SET_FLAG (TheFlag
, element
);
4180 DrawElement (element
);
4182 SetThing (ELEMENT_TYPE
, element
, element
, element
);
4183 LocateError (&x
, &y
);
4184 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4186 title
= _("Element %s has %i silk lines which are too thin");
4187 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
4189 /* -4 is for the %s and %i place-holders */
4190 /* +11 is the max printed length for a 32 bit integer */
4191 /* +1 is for the \0 termination */
4192 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
4193 buffer
= (char *)malloc (buflen
);
4194 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
4196 violation
= pcb_drc_violation_new (buffer
,
4197 _("Process specifications dictate a minimum silkscreen\n"
4198 "feature-width that can reliably be reproduced"),
4200 0, /* ANGLE OF ERROR UNKNOWN */
4201 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4202 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4208 append_drc_violation (violation
);
4209 pcb_drc_violation_free (violation
);
4210 free (object_id_list
);
4211 free (object_type_list
);
4212 if (!throw_drc_dialog())
4225 IncrementUndoSerialNumber ();
4229 RestoreStackAndVisibility ();
4230 hid_action ("LayersChanged");
4231 gui
->invalidate_all ();
4235 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4237 nopastecnt
> 1 ? "s have" : " has");
4239 return IsBad
? -drcerr_count
: drcerr_count
;
4242 /*----------------------------------------------------------------------------
4243 * Locate the coordinatates of offending item (thing)
4246 LocateError (Coord
*x
, Coord
*y
)
4252 LineType
*line
= (LineType
*) thing_ptr3
;
4253 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4254 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4259 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4266 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4268 (polygon
->Clipped
->contours
->xmin
+
4269 polygon
->Clipped
->contours
->xmax
) / 2;
4271 (polygon
->Clipped
->contours
->ymin
+
4272 polygon
->Clipped
->contours
->ymax
) / 2;
4278 PinType
*pin
= (PinType
*) thing_ptr3
;
4285 PadType
*pad
= (PadType
*) thing_ptr3
;
4286 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4287 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4292 ElementType
*element
= (ElementType
*) thing_ptr3
;
4293 *x
= element
->MarkX
;
4294 *y
= element
->MarkY
;
4303 /*----------------------------------------------------------------------------
4304 * Build a list of the of offending items by ID. (Currently just "thing")
4307 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4310 *object_id_list
= NULL
;
4311 *object_type_list
= NULL
;
4324 *object_id_list
= (long int *)malloc (sizeof (long int));
4325 *object_type_list
= (int *)malloc (sizeof (int));
4326 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4327 **object_type_list
= thing_type
;
4332 _("Internal error in BuildObjectList: unknown object type %i\n"),
4338 /*----------------------------------------------------------------------------
4339 * center the display to show the offending item (thing)
4346 LocateError (&X
, &Y
);
4353 ChangeGroupVisibility (
4354 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4357 CenterDisplay (X
, Y
);
4361 InitConnectionLookup (void)
4363 InitComponentLookup ();
4364 InitLayoutLookup ();
4368 FreeConnectionLookupMemory (void)
4370 FreeComponentLookupMemory ();
4371 FreeLayoutLookupMemory ();