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...
80 #include "pcb-printf.h"
86 #ifdef HAVE_LIBDMALLOC
92 /* ---------------------------------------------------------------------------
96 #define SEPARATE(FP) \
100 for (i = Settings.CharPerLine; i; i--) \
105 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
106 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
107 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
108 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
109 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
110 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
111 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
113 #define IS_PV_ON_RAT(PV, Rat) \
114 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
116 #define IS_PV_ON_ARC(PV, Arc) \
117 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
119 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
120 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
122 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
124 #define IS_PV_ON_PAD(PV,Pad) \
125 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
127 static DrcViolationType
128 *pcb_drc_violation_new (const char *title
,
129 const char *explanation
,
133 Coord measured_value
,
134 Coord required_value
,
136 long int *object_id_list
,
137 int *object_type_list
)
139 DrcViolationType
*violation
= (DrcViolationType
*)malloc (sizeof (DrcViolationType
));
141 violation
->title
= strdup (title
);
142 violation
->explanation
= strdup (explanation
);
145 violation
->angle
= angle
;
146 violation
->have_measured
= have_measured
;
147 violation
->measured_value
= measured_value
;
148 violation
->required_value
= required_value
;
149 violation
->object_count
= object_count
;
150 violation
->object_id_list
= object_id_list
;
151 violation
->object_type_list
= object_type_list
;
157 pcb_drc_violation_free (DrcViolationType
*violation
)
159 free (violation
->title
);
160 free (violation
->explanation
);
164 static GString
*drc_dialog_message
;
166 reset_drc_dialog_message(void)
168 if (drc_dialog_message
)
169 g_string_free (drc_dialog_message
, FALSE
);
170 drc_dialog_message
= g_string_new ("");
171 if (gui
->drc_gui
!= NULL
)
173 gui
->drc_gui
->reset_drc_dialog_message ();
177 append_drc_dialog_message(const char *fmt
, ...)
182 new_str
= pcb_vprintf (fmt
, ap
);
183 g_string_append (drc_dialog_message
, new_str
);
188 static void GotoError (void);
191 append_drc_violation (DrcViolationType
*violation
)
193 if (gui
->drc_gui
!= NULL
)
195 gui
->drc_gui
->append_drc_violation (violation
);
199 /* Fallback to formatting the violation message as text */
200 append_drc_dialog_message ("%s\n", violation
->title
);
201 append_drc_dialog_message (_("%m+near %$mD\n"),
202 Settings
.grid_unit
->allow
,
203 violation
->x
, violation
->y
);
207 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
209 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
210 Message (_("%m+near location %$mD\n"),
211 Settings
.grid_unit
->allow
,
212 violation
->x
, violation
->y
);
216 * message when asked about continuing DRC checks after next
217 * violation is found.
219 #define DRC_CONTINUE _("Press Next to continue DRC checking")
220 #define DRC_NEXT _("Next")
221 #define DRC_CANCEL _("Cancel")
224 throw_drc_dialog(void)
228 if (gui
->drc_gui
!= NULL
)
230 r
= gui
->drc_gui
->throw_drc_dialog ();
234 /* Fallback to formatting the violation message as text */
235 append_drc_dialog_message (DRC_CONTINUE
);
236 r
= gui
->confirm_dialog (drc_dialog_message
->str
, DRC_CANCEL
, DRC_NEXT
);
237 reset_drc_dialog_message();
242 /* ---------------------------------------------------------------------------
245 * the two 'dummy' structs for PVs and Pads are necessary for creating
246 * connection lists which include the element's name
250 void **Data
; /* pointer to index data */
251 Cardinal Location
, /* currently used position */
252 DrawLocation
, Number
, /* number of objects in list */
256 /* ---------------------------------------------------------------------------
257 * some local identifiers
259 static Coord Bloat
= 0;
260 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
261 static int thing_type
;
262 static bool User
= false; /* user action causing this */
263 static bool drc
= false; /* whether to stop if finding something not found */
264 static Cardinal drcerr_count
; /* count of drc errors */
265 static Cardinal TotalP
, TotalV
;
266 static ListType LineList
[MAX_LAYER
], /* list of objects to */
267 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
269 /* ---------------------------------------------------------------------------
270 * some local prototypes
272 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, int, bool, bool);
273 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
, int, bool);
274 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
, int, bool);
275 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
, int, bool);
276 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
, int);
277 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
278 static bool ArcArcIntersect (ArcType
*, ArcType
*);
279 static bool PrepareNextLoop (FILE *);
280 static void DrawNewConnections (void);
281 static void DumpList (void);
282 static void LocateError (Coord
*, Coord
*);
283 static void BuildObjectList (int *, long int **, int **);
284 static bool SetThing (int, void *, void *, void *);
285 static bool IsArcInPolygon (ArcType
*, PolygonType
*);
286 static bool IsLineInPolygon (LineType
*, PolygonType
*);
287 static bool IsPadInPolygon (PadType
*, PolygonType
*);
288 static bool IsPolygonInPolygon (PolygonType
*, PolygonType
*);
290 /* ---------------------------------------------------------------------------
291 * some of the 'pad' routines are the same as for lines because the 'pad'
292 * struct starts with a line struct. See global.h for details
295 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
297 return LineLineIntersect ((Line
), (LineType
*)Pad
);
301 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
303 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
307 add_object_to_list (ListType
*list
, int type
, void *ptr1
, void *ptr2
, void *ptr3
, int flag
)
309 AnyObjectType
*object
= (AnyObjectType
*)ptr2
;
312 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
314 SET_FLAG (flag
, object
);
315 LIST_ENTRY (list
, list
->Number
) = object
;
319 if (list
.Number
> list
.Size
)
320 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type
, list
.Number
, list
.Size
);
323 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, object
))
324 return (SetThing (type
, ptr1
, ptr2
, ptr3
));
329 ADD_PV_TO_LIST (PinType
*Pin
, int flag
)
331 return add_object_to_list (&PVList
, Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
332 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
, flag
);
336 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
, int flag
)
338 return add_object_to_list (&PadList
[L
], PAD_TYPE
, Pad
->Element
, Pad
, Pad
, flag
);
342 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
, int flag
)
344 return add_object_to_list (&LineList
[L
], LINE_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
348 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
, int flag
)
350 return add_object_to_list (&ArcList
[L
], ARC_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
354 ADD_RAT_TO_LIST (RatType
*Ptr
, int flag
)
356 return add_object_to_list (&RatList
, RATLINE_TYPE
, Ptr
, Ptr
, Ptr
, flag
);
360 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
, int flag
)
362 return add_object_to_list (&PolygonList
[L
], POLYGON_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
366 expand_bounds (BoxType
*box_in
)
368 BoxType box_out
= *box_in
;
382 PinLineIntersect (PinType
*PV
, LineType
*Line
)
384 /* IsLineInRectangle already has Bloat factor */
385 return TEST_FLAG (SQUAREFLAG
,
386 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
387 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
388 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
389 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
390 Line
) : IsPointInPad (PV
->X
,
402 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
412 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
414 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
416 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
422 PadPadIntersect (PadType
*p1
, PadType
*p2
)
424 return LinePadIntersect ((LineType
*) p1
, p2
);
428 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
433 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
434 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
435 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
436 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
438 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
440 /* check for square/square overlap */
445 t2
= PV2
->Thickness
/ 2.0;
450 return BoxBoxIntersection (&b1
, &b2
);
453 /* ---------------------------------------------------------------------------
454 * releases all allocated memory
457 FreeLayoutLookupMemory (void)
461 for (i
= 0; i
< max_copper_layer
; i
++)
463 free (LineList
[i
].Data
);
464 LineList
[i
].Data
= NULL
;
465 free (ArcList
[i
].Data
);
466 ArcList
[i
].Data
= NULL
;
467 free (PolygonList
[i
].Data
);
468 PolygonList
[i
].Data
= NULL
;
477 FreeComponentLookupMemory (void)
479 free (PadList
[0].Data
);
480 PadList
[0].Data
= NULL
;
481 free (PadList
[1].Data
);
482 PadList
[1].Data
= NULL
;
485 /* ---------------------------------------------------------------------------
486 * allocates memory for component related stacks ...
487 * initializes index and sorts it by X1 and X2
490 InitComponentLookup (void)
492 Cardinal NumberOfPads
[2];
495 /* initialize pad data; start by counting the total number
496 * on each of the two possible layers
498 NumberOfPads
[COMPONENT_LAYER
] = NumberOfPads
[SOLDER_LAYER
] = 0;
499 ALLPAD_LOOP (PCB
->Data
);
501 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
502 NumberOfPads
[SOLDER_LAYER
]++;
504 NumberOfPads
[COMPONENT_LAYER
]++;
507 for (i
= 0; i
< 2; i
++)
509 /* allocate memory for working list */
510 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
512 /* clear some struct members */
513 PadList
[i
].Location
= 0;
514 PadList
[i
].DrawLocation
= 0;
515 PadList
[i
].Number
= 0;
516 PadList
[i
].Size
= NumberOfPads
[i
];
520 /* ---------------------------------------------------------------------------
521 * allocates memory for component related stacks ...
522 * initializes index and sorts it by X1 and X2
525 InitLayoutLookup (void)
529 /* initialize line arc and polygon data */
530 for (i
= 0; i
< max_copper_layer
; i
++)
532 LayerType
*layer
= LAYER_PTR (i
);
536 /* allocate memory for line pointer lists */
537 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
538 LineList
[i
].Size
= layer
->LineN
;
542 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
543 ArcList
[i
].Size
= layer
->ArcN
;
547 /* allocate memory for polygon list */
550 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
551 PolygonList
[i
].Size
= layer
->PolygonN
;
554 /* clear some struct members */
555 LineList
[i
].Location
= 0;
556 LineList
[i
].DrawLocation
= 0;
557 LineList
[i
].Number
= 0;
558 ArcList
[i
].Location
= 0;
559 ArcList
[i
].DrawLocation
= 0;
560 ArcList
[i
].Number
= 0;
561 PolygonList
[i
].Location
= 0;
562 PolygonList
[i
].DrawLocation
= 0;
563 PolygonList
[i
].Number
= 0;
566 if (PCB
->Data
->pin_tree
)
567 TotalP
= PCB
->Data
->pin_tree
->size
;
570 if (PCB
->Data
->via_tree
)
571 TotalV
= PCB
->Data
->via_tree
->size
;
574 /* allocate memory for 'new PV to check' list and clear struct */
575 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
576 PVList
.Size
= TotalP
+ TotalV
;
578 PVList
.DrawLocation
= 0;
580 /* Initialize ratline data */
581 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
582 RatList
.Size
= PCB
->Data
->RatN
;
583 RatList
.Location
= 0;
584 RatList
.DrawLocation
= 0;
597 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
599 LineType
*line
= (LineType
*) b
;
600 struct pv_info
*i
= (struct pv_info
*) cl
;
602 if (!TEST_FLAG (i
->flag
, line
) && PinLineIntersect (i
->pv
, line
) &&
603 !TEST_FLAG (HOLEFLAG
, i
->pv
))
605 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
612 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
614 ArcType
*arc
= (ArcType
*) b
;
615 struct pv_info
*i
= (struct pv_info
*) cl
;
617 if (!TEST_FLAG (i
->flag
, arc
) && IS_PV_ON_ARC (i
->pv
, arc
) &&
618 !TEST_FLAG (HOLEFLAG
, i
->pv
))
620 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
627 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
629 PadType
*pad
= (PadType
*) b
;
630 struct pv_info
*i
= (struct pv_info
*) cl
;
632 if (!TEST_FLAG (i
->flag
, pad
) && IS_PV_ON_PAD (i
->pv
, pad
) &&
633 !TEST_FLAG (HOLEFLAG
, i
->pv
) &&
634 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
:
635 COMPONENT_LAYER
, pad
, i
->flag
))
641 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
643 RatType
*rat
= (RatType
*) b
;
644 struct pv_info
*i
= (struct pv_info
*) cl
;
646 if (!TEST_FLAG (i
->flag
, rat
) && IS_PV_ON_RAT (i
->pv
, rat
) &&
647 ADD_RAT_TO_LIST (rat
, i
->flag
))
652 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
654 PolygonType
*polygon
= (PolygonType
*) b
;
655 struct pv_info
*i
= (struct pv_info
*) cl
;
657 /* if the pin doesn't have a therm and polygon is clearing
658 * then it can't touch due to clearance, so skip the expensive
659 * test. If it does have a therm, you still need to test
660 * because it might not be inside the polygon, or it could
661 * be on an edge such that it doesn't actually touch.
663 if (!TEST_FLAG (i
->flag
, polygon
) && !TEST_FLAG (HOLEFLAG
, i
->pv
) &&
664 (TEST_THERM (i
->layer
, i
->pv
) ||
665 !TEST_FLAG (CLEARPOLYFLAG
,
667 || !i
->pv
->Clearance
))
669 double wide
= MAX (0.5 * i
->pv
->Thickness
+ Bloat
, 0);
670 if (TEST_FLAG (SQUAREFLAG
, i
->pv
))
672 Coord x1
= i
->pv
->X
- (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
673 Coord x2
= i
->pv
->X
+ (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
674 Coord y1
= i
->pv
->Y
- (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
675 Coord y2
= i
->pv
->Y
+ (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
676 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
677 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
680 else if (TEST_FLAG (OCTAGONFLAG
, i
->pv
))
682 POLYAREA
*oct
= OctagonPoly (i
->pv
->X
, i
->pv
->Y
, i
->pv
->Thickness
/ 2);
683 if (isects (oct
, polygon
, true)
684 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
687 else if (IsPointInPolygon (i
->pv
->X
, i
->pv
->Y
, wide
,
689 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
695 /* ---------------------------------------------------------------------------
696 * checks if a PV is connected to LOs, if it is, the LO is added to
697 * the appropriate list and the 'used' flag is set
700 LookupLOConnectionsToPVList (int flag
, bool AndRats
)
707 /* loop over all PVs currently on list */
708 while (PVList
.Location
< PVList
.Number
)
712 /* get pointer to data */
713 info
.pv
= PVLIST_ENTRY (PVList
.Location
);
714 search_box
= expand_bounds (&info
.pv
->BoundingBox
);
717 if (setjmp (info
.env
) == 0)
718 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
719 LOCtoPVpad_callback
, &info
);
723 /* now all lines, arcs and polygons of the several layers */
724 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
726 LayerType
*layer
= LAYER_PTR (layer_no
);
731 info
.layer
= layer_no
;
733 /* add touching lines */
734 if (setjmp (info
.env
) == 0)
735 r_search (layer
->line_tree
, &search_box
,
736 NULL
, LOCtoPVline_callback
, &info
);
739 /* add touching arcs */
740 if (setjmp (info
.env
) == 0)
741 r_search (layer
->arc_tree
, &search_box
,
742 NULL
, LOCtoPVarc_callback
, &info
);
745 /* check all polygons */
746 if (setjmp (info
.env
) == 0)
747 r_search (layer
->polygon_tree
, &search_box
,
748 NULL
, LOCtoPVpoly_callback
, &info
);
752 /* Check for rat-lines that may intersect the PV */
755 if (setjmp (info
.env
) == 0)
756 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
757 LOCtoPVrat_callback
, &info
);
766 /* ---------------------------------------------------------------------------
767 * find all connections between LO at the current list position and new LOs
770 LookupLOConnectionsToLOList (int flag
, bool AndRats
)
773 Cardinal i
, group
, layer
, ratposition
,
774 lineposition
[MAX_LAYER
],
775 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
777 /* copy the current LO list positions; the original data is changed
778 * by 'LookupPVConnectionsToLOList()' which has to check the same
779 * list entries plus the new ones
781 for (i
= 0; i
< max_copper_layer
; i
++)
783 lineposition
[i
] = LineList
[i
].Location
;
784 polyposition
[i
] = PolygonList
[i
].Location
;
785 arcposition
[i
] = ArcList
[i
].Location
;
787 for (i
= 0; i
< 2; i
++)
788 padposition
[i
] = PadList
[i
].Location
;
789 ratposition
= RatList
.Location
;
791 /* loop over all new LOs in the list; recurse until no
792 * more new connections in the layergroup were found
800 position
= &ratposition
;
801 for (; *position
< RatList
.Number
; (*position
)++)
803 group
= RATLIST_ENTRY (*position
)->group1
;
804 if (LookupLOConnectionsToRatEnd
805 (&(RATLIST_ENTRY (*position
)->Point1
), group
, flag
))
807 group
= RATLIST_ENTRY (*position
)->group2
;
808 if (LookupLOConnectionsToRatEnd
809 (&(RATLIST_ENTRY (*position
)->Point2
), group
, flag
))
813 /* loop over all layergroups */
814 for (group
= 0; group
< max_group
; group
++)
818 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
820 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
822 /* be aware that the layer number equal max_copper_layer
823 * and max_copper_layer+1 have a special meaning for pads
825 if (layer
< max_copper_layer
)
827 /* try all new lines */
828 position
= &lineposition
[layer
];
829 for (; *position
< LineList
[layer
].Number
; (*position
)++)
830 if (LookupLOConnectionsToLine
831 (LINELIST_ENTRY (layer
, *position
), group
, flag
, true, AndRats
))
834 /* try all new arcs */
835 position
= &arcposition
[layer
];
836 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
837 if (LookupLOConnectionsToArc
838 (ARCLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
841 /* try all new polygons */
842 position
= &polyposition
[layer
];
843 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
844 if (LookupLOConnectionsToPolygon
845 (POLYGONLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
850 /* try all new pads */
851 layer
-= max_copper_layer
;
854 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
855 layer
, max_copper_layer
);
858 position
= &padposition
[layer
];
859 for (; *position
< PadList
[layer
].Number
; (*position
)++)
860 if (LookupLOConnectionsToPad
861 (PADLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
867 /* check if all lists are done; Later for-loops
868 * may have changed the prior lists
870 done
= !AndRats
|| ratposition
>= RatList
.Number
;
871 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
872 padposition
[1] >= PadList
[1].Number
;
873 for (layer
= 0; layer
< max_copper_layer
; layer
++)
875 lineposition
[layer
] >= LineList
[layer
].Number
&&
876 arcposition
[layer
] >= ArcList
[layer
].Number
&&
877 polyposition
[layer
] >= PolygonList
[layer
].Number
;
884 pv_pv_callback (const BoxType
* b
, void *cl
)
886 PinType
*pin
= (PinType
*) b
;
887 struct pv_info
*i
= (struct pv_info
*) cl
;
889 if (!TEST_FLAG (i
->flag
, pin
) && PV_TOUCH_PV (i
->pv
, pin
))
891 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, i
->pv
))
893 SET_FLAG (WARNFLAG
, pin
);
894 Settings
.RatWarn
= true;
896 Message (_("WARNING: Hole too close to pin.\n"));
898 Message (_("WARNING: Hole too close to via.\n"));
900 else if (ADD_PV_TO_LIST (pin
, i
->flag
))
906 /* ---------------------------------------------------------------------------
907 * searches for new PVs that are connected to PVs on the list
910 LookupPVConnectionsToPVList (int flag
)
917 /* loop over all PVs on list */
918 save_place
= PVList
.Location
;
919 while (PVList
.Location
< PVList
.Number
)
923 /* get pointer to data */
924 info
.pv
= PVLIST_ENTRY (PVList
.Location
);
925 search_box
= expand_bounds ((BoxType
*)info
.pv
);
927 if (setjmp (info
.env
) == 0)
928 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
929 pv_pv_callback
, &info
);
932 if (setjmp (info
.env
) == 0)
933 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
934 pv_pv_callback
, &info
);
939 PVList
.Location
= save_place
;
949 PolygonType
*polygon
;
956 pv_line_callback (const BoxType
* b
, void *cl
)
958 PinType
*pv
= (PinType
*) b
;
959 struct lo_info
*i
= (struct lo_info
*) cl
;
961 if (!TEST_FLAG (i
->flag
, pv
) && PinLineIntersect (pv
, i
->line
))
963 if (TEST_FLAG (HOLEFLAG
, pv
))
965 SET_FLAG (WARNFLAG
, pv
);
966 Settings
.RatWarn
= true;
967 Message (_("WARNING: Hole too close to line.\n"));
969 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
976 pv_pad_callback (const BoxType
* b
, void *cl
)
978 PinType
*pv
= (PinType
*) b
;
979 struct lo_info
*i
= (struct lo_info
*) cl
;
981 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_PAD (pv
, i
->pad
))
983 if (TEST_FLAG (HOLEFLAG
, pv
))
985 SET_FLAG (WARNFLAG
, pv
);
986 Settings
.RatWarn
= true;
987 Message (_("WARNING: Hole too close to pad.\n"));
989 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
996 pv_arc_callback (const BoxType
* b
, void *cl
)
998 PinType
*pv
= (PinType
*) b
;
999 struct lo_info
*i
= (struct lo_info
*) cl
;
1001 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_ARC (pv
, i
->arc
))
1003 if (TEST_FLAG (HOLEFLAG
, pv
))
1005 SET_FLAG (WARNFLAG
, pv
);
1006 Settings
.RatWarn
= true;
1007 Message (_("WARNING: Hole touches arc.\n"));
1009 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
1010 longjmp (i
->env
, 1);
1016 pv_poly_callback (const BoxType
* b
, void *cl
)
1018 PinType
*pv
= (PinType
*) b
;
1019 struct lo_info
*i
= (struct lo_info
*) cl
;
1021 /* note that holes in polygons are ok, so they don't generate warnings. */
1022 if (!TEST_FLAG (i
->flag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1023 (TEST_THERM (i
->layer
, pv
) ||
1024 !TEST_FLAG (CLEARPOLYFLAG
, i
->polygon
) ||
1027 if (TEST_FLAG (SQUAREFLAG
, pv
))
1029 Coord x1
, x2
, y1
, y2
;
1030 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1031 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1032 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1033 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1034 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, i
->polygon
)
1035 && ADD_PV_TO_LIST (pv
, i
->flag
))
1036 longjmp (i
->env
, 1);
1038 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1040 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1041 if (isects (oct
, i
->polygon
, true) && ADD_PV_TO_LIST (pv
, i
->flag
))
1042 longjmp (i
->env
, 1);
1046 if (IsPointInPolygon
1047 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, i
->polygon
)
1048 && ADD_PV_TO_LIST (pv
, i
->flag
))
1049 longjmp (i
->env
, 1);
1056 pv_rat_callback (const BoxType
* b
, void *cl
)
1058 PinType
*pv
= (PinType
*) b
;
1059 struct lo_info
*i
= (struct lo_info
*) cl
;
1061 /* rats can't cause DRC so there is no early exit */
1062 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_RAT (pv
, i
->rat
))
1063 ADD_PV_TO_LIST (pv
, i
->flag
);
1067 /* ---------------------------------------------------------------------------
1068 * searches for new PVs that are connected to NEW LOs on the list
1069 * This routine updates the position counter of the lists too.
1072 LookupPVConnectionsToLOList (int flag
, bool AndRats
)
1075 struct lo_info info
;
1079 /* loop over all layers */
1080 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
1082 LayerType
*layer
= LAYER_PTR (layer_no
);
1086 /* do nothing if there are no PV's */
1087 if (TotalP
+ TotalV
== 0)
1089 LineList
[layer_no
].Location
= LineList
[layer_no
].Number
;
1090 ArcList
[layer_no
].Location
= ArcList
[layer_no
].Number
;
1091 PolygonList
[layer_no
].Location
= PolygonList
[layer_no
].Number
;
1095 /* check all lines */
1096 while (LineList
[layer_no
].Location
< LineList
[layer_no
].Number
)
1100 info
.line
= LINELIST_ENTRY (layer_no
, LineList
[layer_no
].Location
);
1101 search_box
= expand_bounds ((BoxType
*)info
.line
);
1103 if (setjmp (info
.env
) == 0)
1104 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1105 pv_line_callback
, &info
);
1108 if (setjmp (info
.env
) == 0)
1109 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1110 pv_line_callback
, &info
);
1113 LineList
[layer_no
].Location
++;
1116 /* check all arcs */
1117 while (ArcList
[layer_no
].Location
< ArcList
[layer_no
].Number
)
1121 info
.arc
= ARCLIST_ENTRY (layer_no
, ArcList
[layer_no
].Location
);
1122 search_box
= expand_bounds ((BoxType
*)info
.arc
);
1124 if (setjmp (info
.env
) == 0)
1125 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1126 pv_arc_callback
, &info
);
1129 if (setjmp (info
.env
) == 0)
1130 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1131 pv_arc_callback
, &info
);
1134 ArcList
[layer_no
].Location
++;
1137 /* now all polygons */
1138 info
.layer
= layer_no
;
1139 while (PolygonList
[layer_no
].Location
< PolygonList
[layer_no
].Number
)
1143 info
.polygon
= POLYGONLIST_ENTRY (layer_no
, PolygonList
[layer_no
].Location
);
1144 search_box
= expand_bounds ((BoxType
*)info
.polygon
);
1146 if (setjmp (info
.env
) == 0)
1147 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1148 pv_poly_callback
, &info
);
1151 if (setjmp (info
.env
) == 0)
1152 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1153 pv_poly_callback
, &info
);
1156 PolygonList
[layer_no
].Location
++;
1160 /* loop over all pad-layers */
1161 for (layer_no
= 0; layer_no
< 2; layer_no
++)
1163 /* do nothing if there are no PV's */
1164 if (TotalP
+ TotalV
== 0)
1166 PadList
[layer_no
].Location
= PadList
[layer_no
].Number
;
1170 /* check all pads; for a detailed description see
1171 * the handling of lines in this subroutine
1173 while (PadList
[layer_no
].Location
< PadList
[layer_no
].Number
)
1177 info
.pad
= PADLIST_ENTRY (layer_no
, PadList
[layer_no
].Location
);
1178 search_box
= expand_bounds ((BoxType
*)info
.pad
);
1180 if (setjmp (info
.env
) == 0)
1181 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1182 pv_pad_callback
, &info
);
1185 if (setjmp (info
.env
) == 0)
1186 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1187 pv_pad_callback
, &info
);
1190 PadList
[layer_no
].Location
++;
1194 /* do nothing if there are no PV's */
1195 if (TotalP
+ TotalV
== 0)
1196 RatList
.Location
= RatList
.Number
;
1198 /* check all rat-lines */
1201 while (RatList
.Location
< RatList
.Number
)
1203 info
.rat
= RATLIST_ENTRY (RatList
.Location
);
1204 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
->Point1
, 1, NULL
,
1205 pv_rat_callback
, &info
);
1206 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
->Point2
, 1, NULL
,
1207 pv_rat_callback
, &info
);
1208 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
->Point1
, 1, NULL
,
1209 pv_rat_callback
, &info
);
1210 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
->Point2
, 1, NULL
,
1211 pv_rat_callback
, &info
);
1219 /* reduce arc start angle and delta to 0..360 */
1221 normalize_angles (Angle
*sa
, Angle
*d
)
1228 if (*d
> 360) /* full circle */
1230 *sa
= NormalizeAngle (*sa
);
1234 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1236 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1237 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1239 normalize_angles (&sa
, &d
);
1243 return (sa
+ d
) >= alpha
;
1244 return (sa
+ d
- 360) >= alpha
;
1248 get_arc_ends (Coord
*box
, ArcType
*arc
)
1250 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1251 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1252 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1253 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1255 /* ---------------------------------------------------------------------------
1256 * check if two arcs intersect
1257 * first we check for circle intersections,
1258 * then find the actual points of intersection
1259 * and test them to see if they are on arcs
1261 * consider a, the distance from the center of arc 1
1262 * to the point perpendicular to the intersecting points.
1264 * a = (r1^2 - r2^2 + l^2)/(2l)
1266 * the perpendicular distance to the point of intersection
1269 * d = sqrt(r1^2 - a^2)
1271 * the points of intersection would then be
1273 * x = X1 + a/l dx +- d/l dy
1274 * y = Y1 + a/l dy -+ d/l dx
1276 * where dx = X2 - X1 and dy = Y2 - Y1
1281 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1283 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1287 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1288 t2
= 0.5 * Arc2
->Thickness
;
1292 if (t
< 0 || t1
< 0)
1295 /* try the end points first */
1296 get_arc_ends (&box
[0], Arc1
);
1297 get_arc_ends (&box
[4], Arc2
);
1298 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1299 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1300 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1301 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1304 pdx
= Arc2
->X
- Arc1
->X
;
1305 pdy
= Arc2
->Y
- Arc1
->Y
;
1306 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1307 /* concentric arcs, simpler intersection conditions */
1310 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1311 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1312 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1313 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1315 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1316 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1317 /* NB the endpoints have already been checked,
1318 so we just compare the angles */
1320 normalize_angles (&sa1
, &d1
);
1321 normalize_angles (&sa2
, &d2
);
1322 /* sa1 == sa2 was caught when checking endpoints */
1324 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1327 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1334 /* arcs centerlines are too far or too near */
1335 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1337 /* check the nearest to the other arc's center point */
1340 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1346 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1347 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1350 dx
= - pdx
* r2
/ dl
;
1351 dy
= - pdy
* r2
/ dl
;
1352 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1358 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1359 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1367 a
= 0.5 * (r1
- r2
+ l
) / l
;
1370 /* the circles are too far apart to touch or probably just touch:
1371 check the nearest point */
1376 x
= Arc1
->X
+ a
* pdx
;
1377 y
= Arc1
->Y
+ a
* pdy
;
1380 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1381 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1383 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1384 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1387 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1388 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1390 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1391 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1396 /* ---------------------------------------------------------------------------
1397 * Tests if point is same as line end point
1400 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1402 if ((Point
->X
== Line
->Point1
.X
1403 && Point
->Y
== Line
->Point1
.Y
)
1404 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1410 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1411 /* writes vertices of a squared line */
1413 double dwx
= 0, dwy
= 0;
1414 if (l
->Point1
.Y
== l
->Point2
.Y
)
1415 dwx
= l
->Thickness
/ 2.0;
1416 else if (l
->Point1
.X
== l
->Point2
.X
)
1417 dwy
= l
->Thickness
/ 2.0;
1420 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1421 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1422 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1423 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1424 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1426 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1427 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1428 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1429 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1431 /* ---------------------------------------------------------------------------
1432 * checks if two lines intersect
1435 * Let A,B,C,D be 2-space position vectors. Then the directed line
1436 * segments AB & CD are given by:
1438 * AB=A+r(B-A), r in [0,1]
1439 * CD=C+s(D-C), s in [0,1]
1441 * If AB & CD intersect, then
1443 * A+r(B-A)=C+s(D-C), or
1445 * XA+r(XB-XA)=XC+s(XD-XC)
1446 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1448 * Solving the above for r and s yields
1450 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1451 * r = ----------------------------- (eqn 1)
1452 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1454 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1455 * s = ----------------------------- (eqn 2)
1456 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1458 * Let I be the position vector of the intersection point, then
1465 * By examining the values of r & s, you can also determine some
1466 * other limiting conditions:
1468 * If 0<=r<=1 & 0<=s<=1, intersection exists
1469 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1471 * If the denominator in eqn 1 is zero, AB & CD are parallel
1472 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1474 * If the intersection point of the 2 lines are needed (lines in this
1475 * context mean infinite lines) regardless whether the two line
1476 * segments intersect, then
1478 * If r>1, I is located on extension of AB
1479 * If r<0, I is located on extension of BA
1480 * If s>1, I is located on extension of CD
1481 * If s<0, I is located on extension of DC
1483 * Also note that the denominators of eqn 1 & 2 are identical.
1487 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1490 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1491 point1_dx
, point1_dy
;
1492 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1495 form_slanted_rectangle (p
, Line1
);
1496 return IsLineInQuadrangle (p
, Line2
);
1498 /* here come only round Line1 because IsLineInQuadrangle()
1499 calls LineLineIntersect() with first argument rounded*/
1500 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1503 form_slanted_rectangle (p
, Line2
);
1504 return IsLineInQuadrangle (p
, Line1
);
1506 /* now all lines are round */
1508 /* Check endpoints: this provides a quick exit, catches
1509 * cases where the "real" lines don't intersect but the
1510 * thick lines touch, and ensures that the dx/dy business
1511 * below does not cause a divide-by-zero. */
1512 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1513 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1515 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1516 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1518 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1519 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1521 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1522 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1526 /* setup some constants */
1527 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1528 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1529 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1530 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1531 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1532 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1534 /* If either line is a point, we have failed already, since the
1535 * endpoint check above will have caught an "intersection". */
1536 if ((line1_dx
== 0 && line1_dy
== 0)
1537 || (line2_dx
== 0 && line2_dy
== 0))
1540 /* set s to cross product of Line1 and the line
1541 * Line1.Point1--Line2.Point1 (as vectors) */
1542 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1544 /* set r to cross product of both lines (as vectors) */
1545 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1547 /* No cross product means parallel lines, or maybe Line2 is
1548 * zero-length. In either case, since we did a bounding-box
1549 * check before getting here, the above IsPointInPad() checks
1550 * will have caught any intersections. */
1555 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1557 /* intersection is at least on AB */
1558 if (r
>= 0.0 && r
<= 1.0)
1559 return (s
>= 0.0 && s
<= 1.0);
1561 /* intersection is at least on CD */
1562 /* [removed this case since it always returns false --asp] */
1566 /*---------------------------------------------------
1568 * Check for line intersection with an arc
1570 * Mostly this is like the circle/line intersection
1571 * found in IsPointOnLine (search.c) see the detailed
1572 * discussion for the basics there.
1574 * Since this is only an arc, not a full circle we need
1575 * to find the actual points of intersection with the
1576 * circle, and see if they are on the arc.
1578 * To do this, we translate along the line from the point Q
1579 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1580 * but it's handy to normalize with respect to l, the line
1581 * length so a single projection is done (e.g. we don't first
1584 * The projection is now of the form
1586 * Px = X1 + (r +- r2)(X2 - X1)
1587 * Py = Y1 + (r +- r2)(Y2 - Y1)
1589 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1590 * note that this is the variable d, not the symbol d described in IsPointOnLine
1591 * (variable d = symbol d * l)
1593 * The end points are hell so they are checked individually
1596 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1598 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1601 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1602 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1603 dx1
= Line
->Point1
.X
- Arc
->X
;
1604 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1605 l
= dx
* dx
+ dy
* dy
;
1606 d
= dx
* dy1
- dy
* dx1
;
1609 /* use the larger diameter circle first */
1611 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1613 r2
= Radius
* l
- d
;
1614 /* projection doesn't even intersect circle when r2 < 0 */
1617 /* check the ends of the line in case the projected point */
1618 /* of intersection is beyond the line end */
1620 (Line
->Point1
.X
, Line
->Point1
.Y
,
1621 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1624 (Line
->Point2
.X
, Line
->Point2
.Y
,
1625 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1630 Radius
= -(dx
* dx1
+ dy
* dy1
);
1631 r
= (Radius
+ r2
) / l
;
1632 if (r
>= 0 && r
<= 1
1633 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1634 Line
->Point1
.Y
+ r
* dy
,
1635 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1637 r
= (Radius
- r2
) / l
;
1638 if (r
>= 0 && r
<= 1
1639 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1640 Line
->Point1
.Y
+ r
* dy
,
1641 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1643 /* check arc end points */
1644 box
= GetArcEnds (Arc
);
1645 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1647 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1653 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1655 LineType
*line
= (LineType
*) b
;
1656 struct lo_info
*i
= (struct lo_info
*) cl
;
1658 if (!TEST_FLAG (i
->flag
, line
) && LineArcIntersect (line
, i
->arc
))
1660 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1661 longjmp (i
->env
, 1);
1667 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1669 ArcType
*arc
= (ArcType
*) b
;
1670 struct lo_info
*i
= (struct lo_info
*) cl
;
1672 if (!arc
->Thickness
)
1674 if (!TEST_FLAG (i
->flag
, arc
) && ArcArcIntersect (i
->arc
, arc
))
1676 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
1677 longjmp (i
->env
, 1);
1683 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1685 PadType
*pad
= (PadType
*) b
;
1686 struct lo_info
*i
= (struct lo_info
*) cl
;
1688 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1689 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1690 && ArcPadIntersect (i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1691 longjmp (i
->env
, 1);
1695 /* ---------------------------------------------------------------------------
1696 * searches all LOs that are connected to the given arc on the given
1697 * layergroup. All found connections are added to the list
1699 * the notation that is used is:
1700 * Xij means Xj at arc i
1703 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
, int flag
, bool AndRats
)
1706 struct lo_info info
;
1711 search_box
= expand_bounds ((BoxType
*)info
.arc
);
1713 /* loop over all layers of the group */
1714 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1720 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1721 layer
= LAYER_PTR (layer_no
);
1723 /* handle normal layers */
1724 if (layer_no
< max_copper_layer
)
1726 info
.layer
= layer_no
;
1728 if (setjmp (info
.env
) == 0)
1729 r_search (layer
->line_tree
, &search_box
,
1730 NULL
, LOCtoArcLine_callback
, &info
);
1734 if (setjmp (info
.env
) == 0)
1735 r_search (layer
->arc_tree
, &search_box
,
1736 NULL
, LOCtoArcArc_callback
, &info
);
1740 /* now check all polygons */
1741 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1743 PolygonType
*polygon
= i
->data
;
1744 if (!TEST_FLAG (flag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1745 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
1751 info
.layer
= layer_no
- max_copper_layer
;
1752 if (setjmp (info
.env
) == 0)
1753 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
1754 LOCtoArcPad_callback
, &info
);
1763 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1765 LineType
*line
= (LineType
*) b
;
1766 struct lo_info
*i
= (struct lo_info
*) cl
;
1768 if (!TEST_FLAG (i
->flag
, line
) && LineLineIntersect (i
->line
, line
))
1770 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1771 longjmp (i
->env
, 1);
1777 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1779 ArcType
*arc
= (ArcType
*) b
;
1780 struct lo_info
*i
= (struct lo_info
*) cl
;
1782 if (!arc
->Thickness
)
1784 if (!TEST_FLAG (i
->flag
, arc
) && LineArcIntersect (i
->line
, arc
))
1786 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
1787 longjmp (i
->env
, 1);
1793 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1795 RatType
*rat
= (RatType
*) b
;
1796 struct lo_info
*i
= (struct lo_info
*) cl
;
1798 if (!TEST_FLAG (i
->flag
, rat
))
1800 if ((rat
->group1
== i
->layer
)
1801 && IsRatPointOnLineEnd (&rat
->Point1
, i
->line
))
1803 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
1804 longjmp (i
->env
, 1);
1806 else if ((rat
->group2
== i
->layer
)
1807 && IsRatPointOnLineEnd (&rat
->Point2
, i
->line
))
1809 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
1810 longjmp (i
->env
, 1);
1817 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1819 PadType
*pad
= (PadType
*) b
;
1820 struct lo_info
*i
= (struct lo_info
*) cl
;
1822 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1823 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
1824 && LinePadIntersect (i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1825 longjmp (i
->env
, 1);
1829 /* ---------------------------------------------------------------------------
1830 * searches all LOs that are connected to the given line on the given
1831 * layergroup. All found connections are added to the list
1833 * the notation that is used is:
1834 * Xij means Xj at line i
1837 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1838 int flag
, bool PolysTo
, bool AndRats
)
1841 struct lo_info info
;
1845 info
.layer
= LayerGroup
;
1847 search_box
= expand_bounds ((BoxType
*)info
.line
);
1851 /* add the new rat lines */
1852 if (setjmp (info
.env
) == 0)
1853 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
1854 LOCtoLineRat_callback
, &info
);
1859 /* loop over all layers of the group */
1860 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1865 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1866 layer
= LAYER_PTR (layer_no
);
1868 /* handle normal layers */
1869 if (layer_no
< max_copper_layer
)
1871 info
.layer
= layer_no
;
1873 if (setjmp (info
.env
) == 0)
1874 r_search (layer
->line_tree
, &search_box
,
1875 NULL
, LOCtoLineLine_callback
, &info
);
1879 if (setjmp (info
.env
) == 0)
1880 r_search (layer
->arc_tree
, &search_box
,
1881 NULL
, LOCtoLineArc_callback
, &info
);
1884 /* now check all polygons */
1888 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1890 PolygonType
*polygon
= i
->data
;
1891 if (!TEST_FLAG (flag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1892 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
1899 /* handle special 'pad' layers */
1900 info
.layer
= layer_no
- max_copper_layer
;
1901 if (setjmp (info
.env
) == 0)
1902 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
1903 LOCtoLinePad_callback
, &info
);
1920 LOCtoRat_callback (const BoxType
* b
, void *cl
)
1922 LineType
*line
= (LineType
*) b
;
1923 struct rat_info
*i
= (struct rat_info
*) cl
;
1925 if (!TEST_FLAG (i
->flag
, line
) &&
1926 ((line
->Point1
.X
== i
->Point
->X
&&
1927 line
->Point1
.Y
== i
->Point
->Y
) ||
1928 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
1930 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1931 longjmp (i
->env
, 1);
1936 PolygonToRat_callback (const BoxType
* b
, void *cl
)
1938 PolygonType
*polygon
= (PolygonType
*) b
;
1939 struct rat_info
*i
= (struct rat_info
*) cl
;
1941 if (!TEST_FLAG (i
->flag
, polygon
) && polygon
->Clipped
&&
1942 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
1943 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
1945 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
1946 longjmp (i
->env
, 1);
1952 LOCtoPad_callback (const BoxType
* b
, void *cl
)
1954 PadType
*pad
= (PadType
*) b
;
1955 struct rat_info
*i
= (struct rat_info
*) cl
;
1957 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1958 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
) &&
1959 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
1960 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
1961 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
1962 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
1963 ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1964 longjmp (i
->env
, 1);
1968 /* ---------------------------------------------------------------------------
1969 * searches all LOs that are connected to the given rat-line on the given
1970 * layergroup. All found connections are added to the list
1972 * the notation that is used is:
1973 * Xij means Xj at line i
1976 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
, int flag
)
1979 struct rat_info info
;
1983 /* loop over all layers of this group */
1984 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1989 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1990 layer
= LAYER_PTR (layer_no
);
1991 /* handle normal layers
1992 rats don't ever touch
1996 if (layer_no
< max_copper_layer
)
1998 info
.layer
= layer_no
;
1999 if (setjmp (info
.env
) == 0)
2000 r_search_pt (layer
->line_tree
, Point
, 1, NULL
,
2001 LOCtoRat_callback
, &info
);
2004 if (setjmp (info
.env
) == 0)
2005 r_search_pt (layer
->polygon_tree
, Point
, 1,
2006 NULL
, PolygonToRat_callback
, &info
);
2010 /* handle special 'pad' layers */
2011 info
.layer
= layer_no
- max_copper_layer
;
2012 if (setjmp (info
.env
) == 0)
2013 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2014 LOCtoPad_callback
, &info
);
2023 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2025 LineType
*line
= (LineType
*) b
;
2026 struct lo_info
*i
= (struct lo_info
*) cl
;
2028 if (!TEST_FLAG (i
->flag
, line
) && LinePadIntersect (line
, i
->pad
))
2030 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
2031 longjmp (i
->env
, 1);
2037 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2039 ArcType
*arc
= (ArcType
*) b
;
2040 struct lo_info
*i
= (struct lo_info
*) cl
;
2042 if (!arc
->Thickness
)
2044 if (!TEST_FLAG (i
->flag
, arc
) && ArcPadIntersect (arc
, i
->pad
))
2046 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
2047 longjmp (i
->env
, 1);
2053 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2055 PolygonType
*polygon
= (PolygonType
*) b
;
2056 struct lo_info
*i
= (struct lo_info
*) cl
;
2059 if (!TEST_FLAG (i
->flag
, polygon
) &&
2060 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
->Clearance
))
2062 if (IsPadInPolygon (i
->pad
, polygon
) &&
2063 ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
2064 longjmp (i
->env
, 1);
2070 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2072 RatType
*rat
= (RatType
*) b
;
2073 struct lo_info
*i
= (struct lo_info
*) cl
;
2075 if (!TEST_FLAG (i
->flag
, rat
))
2077 if (rat
->group1
== i
->layer
&&
2078 ((rat
->Point1
.X
== i
->pad
->Point1
.X
&& rat
->Point1
.Y
== i
->pad
->Point1
.Y
) ||
2079 (rat
->Point1
.X
== i
->pad
->Point2
.X
&& rat
->Point1
.Y
== i
->pad
->Point2
.Y
) ||
2080 (rat
->Point1
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
2081 rat
->Point1
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2)))
2083 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2084 longjmp (i
->env
, 1);
2086 else if (rat
->group2
== i
->layer
&&
2087 ((rat
->Point2
.X
== i
->pad
->Point1
.X
&& rat
->Point2
.Y
== i
->pad
->Point1
.Y
) ||
2088 (rat
->Point2
.X
== i
->pad
->Point2
.X
&& rat
->Point2
.Y
== i
->pad
->Point2
.Y
) ||
2089 (rat
->Point2
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
2090 rat
->Point2
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2)))
2092 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2093 longjmp (i
->env
, 1);
2100 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2102 PadType
*pad
= (PadType
*) b
;
2103 struct lo_info
*i
= (struct lo_info
*) cl
;
2105 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
2106 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2107 && PadPadIntersect (pad
, i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
2108 longjmp (i
->env
, 1);
2112 /* ---------------------------------------------------------------------------
2113 * searches all LOs that are connected to the given pad on the given
2114 * layergroup. All found connections are added to the list
2117 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
, int flag
, bool AndRats
)
2120 struct lo_info info
;
2123 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2124 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, flag
, false, AndRats
));
2128 search_box
= expand_bounds ((BoxType
*)info
.pad
);
2130 /* add the new rat lines */
2131 info
.layer
= LayerGroup
;
2135 if (setjmp (info
.env
) == 0)
2136 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
2137 LOCtoPadRat_callback
, &info
);
2142 /* loop over all layers of the group */
2143 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2148 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2149 layer
= LAYER_PTR (layer_no
);
2150 /* handle normal layers */
2151 if (layer_no
< max_copper_layer
)
2153 info
.layer
= layer_no
;
2155 if (setjmp (info
.env
) == 0)
2156 r_search (layer
->line_tree
, &search_box
,
2157 NULL
, LOCtoPadLine_callback
, &info
);
2161 if (setjmp (info
.env
) == 0)
2162 r_search (layer
->arc_tree
, &search_box
,
2163 NULL
, LOCtoPadArc_callback
, &info
);
2167 if (setjmp (info
.env
) == 0)
2168 r_search (layer
->polygon_tree
, &search_box
,
2169 NULL
, LOCtoPadPoly_callback
, &info
);
2175 /* handle special 'pad' layers */
2176 info
.layer
= layer_no
- max_copper_layer
;
2177 if (setjmp (info
.env
) == 0)
2178 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
2179 LOCtoPadPad_callback
, &info
);
2189 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2191 LineType
*line
= (LineType
*) b
;
2192 struct lo_info
*i
= (struct lo_info
*) cl
;
2194 if (!TEST_FLAG (i
->flag
, line
) && IsLineInPolygon (line
, i
->polygon
))
2196 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
2197 longjmp (i
->env
, 1);
2203 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2205 ArcType
*arc
= (ArcType
*) b
;
2206 struct lo_info
*i
= (struct lo_info
*) cl
;
2208 if (!arc
->Thickness
)
2210 if (!TEST_FLAG (i
->flag
, arc
) && IsArcInPolygon (arc
, i
->polygon
))
2212 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
2213 longjmp (i
->env
, 1);
2219 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2221 PadType
*pad
= (PadType
*) b
;
2222 struct lo_info
*i
= (struct lo_info
*) cl
;
2224 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
2225 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
)
2226 && IsPadInPolygon (pad
, i
->polygon
))
2228 if (ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
2229 longjmp (i
->env
, 1);
2235 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2237 RatType
*rat
= (RatType
*) b
;
2238 struct lo_info
*i
= (struct lo_info
*) cl
;
2240 if (!TEST_FLAG (i
->flag
, rat
))
2242 if ((rat
->Point1
.X
== (i
->polygon
->Clipped
->contours
->head
.point
[0]) &&
2243 rat
->Point1
.Y
== (i
->polygon
->Clipped
->contours
->head
.point
[1]) &&
2244 rat
->group1
== i
->layer
) ||
2245 (rat
->Point2
.X
== (i
->polygon
->Clipped
->contours
->head
.point
[0]) &&
2246 rat
->Point2
.Y
== (i
->polygon
->Clipped
->contours
->head
.point
[1]) &&
2247 rat
->group2
== i
->layer
))
2248 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2249 longjmp (i
->env
, 1);
2255 /* ---------------------------------------------------------------------------
2256 * looks up LOs that are connected to the given polygon
2257 * on the given layergroup. All found connections are added to the list
2260 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
, int flag
, bool AndRats
)
2263 struct lo_info info
;
2266 if (!Polygon
->Clipped
)
2270 info
.polygon
= Polygon
;
2271 search_box
= expand_bounds ((BoxType
*)info
.polygon
);
2273 info
.layer
= LayerGroup
;
2278 if (setjmp (info
.env
) == 0)
2279 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
2280 LOCtoPolyRat_callback
, &info
);
2285 /* loop over all layers of the group */
2286 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2291 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2292 layer
= LAYER_PTR (layer_no
);
2294 /* handle normal layers */
2295 if (layer_no
< max_copper_layer
)
2299 /* check all polygons */
2300 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
2302 PolygonType
*polygon
= i
->data
;
2303 if (!TEST_FLAG (flag
, polygon
)
2304 && IsPolygonInPolygon (polygon
, Polygon
)
2305 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
2309 info
.layer
= layer_no
;
2310 /* check all lines */
2311 if (setjmp (info
.env
) == 0)
2312 r_search (layer
->line_tree
, &search_box
,
2313 NULL
, LOCtoPolyLine_callback
, &info
);
2316 /* check all arcs */
2317 if (setjmp (info
.env
) == 0)
2318 r_search (layer
->arc_tree
, &search_box
,
2319 NULL
, LOCtoPolyArc_callback
, &info
);
2325 info
.layer
= layer_no
- max_copper_layer
;
2326 if (setjmp (info
.env
) == 0)
2327 r_search (PCB
->Data
->pad_tree
, &search_box
,
2328 NULL
, LOCtoPolyPad_callback
, &info
);
2336 /* ---------------------------------------------------------------------------
2337 * checks if an arc has a connection to a polygon
2339 * - first check if the arc can intersect with the polygon by
2340 * evaluating the bounding boxes
2341 * - check the two end points of the arc. If none of them matches
2342 * - check all segments of the polygon against the arc.
2345 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2347 BoxType
*Box
= (BoxType
*) Arc
;
2349 /* arcs with clearance never touch polys */
2350 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2352 if (!Polygon
->Clipped
)
2354 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2355 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2356 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2357 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2361 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2362 return false; /* error */
2363 return isects (ap
, Polygon
, true);
2368 /* ---------------------------------------------------------------------------
2369 * checks if a line has a connection to a polygon
2371 * - first check if the line can intersect with the polygon by
2372 * evaluating the bounding boxes
2373 * - check the two end points of the line. If none of them matches
2374 * - check all segments of the polygon against the line.
2377 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2379 BoxType
*Box
= (BoxType
*) Line
;
2382 /* lines with clearance never touch polygons */
2383 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2385 if (!Polygon
->Clipped
)
2387 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2389 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2390 Coord x1
, x2
, y1
, y2
;
2392 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2393 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2394 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2395 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2396 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2398 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2399 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2400 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2401 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2403 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2404 return FALSE
; /* error */
2405 return isects (lp
, Polygon
, true);
2410 /* ---------------------------------------------------------------------------
2411 * checks if a pad connects to a non-clearing polygon
2413 * The polygon is assumed to already have been proven non-clearing
2416 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2418 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2421 /* ---------------------------------------------------------------------------
2422 * checks if a polygon has a connection to a second one
2424 * First check all points out of P1 against P2 and vice versa.
2425 * If both fail check all lines of P1 against the ones of P2
2428 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2430 if (!P1
->Clipped
|| !P2
->Clipped
)
2432 assert (P1
->Clipped
->contours
);
2433 assert (P2
->Clipped
->contours
);
2435 /* first check if both bounding boxes intersect. If not, return quickly */
2436 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2437 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2438 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2439 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2442 /* first check un-bloated case */
2443 if (isects (P1
->Clipped
, P2
, false))
2446 /* now the difficult case of bloated */
2450 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2453 VNODE
*v
= &c
->head
;
2454 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2455 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2456 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2457 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2460 line
.Point1
.X
= v
->point
[0];
2461 line
.Point1
.Y
= v
->point
[1];
2462 line
.Thickness
= 2 * Bloat
;
2464 line
.Flags
= NoFlags ();
2465 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2467 line
.Point2
.X
= v
->point
[0];
2468 line
.Point2
.Y
= v
->point
[1];
2469 SetLineBoundingBox (&line
);
2470 if (IsLineInPolygon (&line
, P2
))
2472 line
.Point1
.X
= line
.Point2
.X
;
2473 line
.Point1
.Y
= line
.Point2
.Y
;
2482 /* ---------------------------------------------------------------------------
2483 * writes the several names of an element to a file
2486 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2488 static DynamicStringType cname
, pname
, vname
;
2490 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2491 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2492 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2493 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2496 /* ---------------------------------------------------------------------------
2497 * writes the several names of an element to a file
2500 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2502 fputs ("Element", FP
);
2503 PrintElementNameList (Element
, FP
);
2507 /* ---------------------------------------------------------------------------
2508 * prints one {pin,pad,via}/element entry of connection lists
2511 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2512 bool FirstOne
, FILE * FP
)
2514 static DynamicStringType oname
;
2516 CreateQuotedString (&oname
, ObjName
);
2518 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2521 fprintf (FP
, "\t\t%s ", oname
.Data
);
2523 PrintElementNameList (Element
, FP
);
2525 fputs ("(__VIA__)\n", FP
);
2529 /* ---------------------------------------------------------------------------
2530 * prints all found connections of a pads to file FP
2531 * the connections are stacked in 'PadList'
2534 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2539 if (!PadList
[Layer
].Number
)
2542 /* the starting pad */
2545 ptr
= PADLIST_ENTRY (Layer
, 0);
2547 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2549 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2552 /* we maybe have to start with i=1 if we are handling the
2553 * starting-pad itself
2555 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2557 ptr
= PADLIST_ENTRY (Layer
, i
);
2559 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2561 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2565 /* ---------------------------------------------------------------------------
2566 * prints all found connections of a pin to file FP
2567 * the connections are stacked in 'PVList'
2570 PrintPinConnections (FILE * FP
, bool IsFirst
)
2580 /* the starting pin */
2581 pv
= PVLIST_ENTRY (0);
2582 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2585 /* we maybe have to start with i=1 if we are handling the
2586 * starting-pin itself
2588 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2590 /* get the elements name or assume that its a via */
2591 pv
= PVLIST_ENTRY (i
);
2592 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2596 /* ---------------------------------------------------------------------------
2597 * checks if all lists of new objects are handled
2600 ListsEmpty (bool AndRats
)
2605 empty
= (PVList
.Location
>= PVList
.Number
);
2607 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2608 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2609 if (!LAYER_PTR (i
)->no_drc
)
2610 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2611 && ArcList
[i
].Location
>= ArcList
[i
].Number
2612 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2617 reassign_no_drc_flags (void)
2621 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2623 LayerType
*l
= LAYER_PTR (layer
);
2624 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2631 /* ---------------------------------------------------------------------------
2632 * loops till no more connections are found
2635 DoIt (int flag
, bool AndRats
, bool AndDraw
)
2637 bool newone
= false;
2638 reassign_no_drc_flags ();
2641 /* lookup connections; these are the steps (2) to (4)
2642 * from the description
2644 newone
= LookupPVConnectionsToPVList (flag
) ||
2645 LookupLOConnectionsToPVList (flag
, AndRats
) ||
2646 LookupLOConnectionsToLOList (flag
, AndRats
) ||
2647 LookupPVConnectionsToLOList (flag
, AndRats
);
2649 DrawNewConnections ();
2651 while (!newone
&& !ListsEmpty (AndRats
));
2657 /* ---------------------------------------------------------------------------
2658 * prints all unused pins of an element to file FP
2661 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
, int flag
)
2665 static DynamicStringType oname
;
2667 /* check all pins in element */
2671 if (!TEST_FLAG (HOLEFLAG
, pin
))
2673 /* pin might have bee checked before, add to list if not */
2674 if (!TEST_FLAG (flag
, pin
) && FP
)
2677 if (ADD_PV_TO_LIST (pin
, flag
))
2679 DoIt (flag
, true, true);
2680 number
= PadList
[COMPONENT_LAYER
].Number
2681 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2682 /* the pin has no connection if it's the only
2683 * list entry; don't count vias
2685 for (i
= 0; i
< PVList
.Number
; i
++)
2686 if (!PVLIST_ENTRY (i
)->Element
)
2690 /* output of element name if not already done */
2693 PrintConnectionElementName (Element
, FP
);
2697 /* write name to list and draw selected object */
2698 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2699 fprintf (FP
, "\t%s\n", oname
.Data
);
2700 SET_FLAG (SELECTEDFLAG
, pin
);
2704 /* reset found objects for the next pin */
2705 if (PrepareNextLoop (FP
))
2712 /* check all pads in element */
2715 /* lookup pad in list */
2716 /* pad might has bee checked before, add to list if not */
2717 if (!TEST_FLAG (flag
, pad
) && FP
)
2720 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2721 ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
, flag
))
2723 DoIt (flag
, true, true);
2724 number
= PadList
[COMPONENT_LAYER
].Number
2725 + PadList
[SOLDER_LAYER
].Number
+ PVList
.Number
;
2726 /* the pin has no connection if it's the only
2727 * list entry; don't count vias
2729 for (i
= 0; i
< PVList
.Number
; i
++)
2730 if (!PVLIST_ENTRY (i
)->Element
)
2734 /* output of element name if not already done */
2737 PrintConnectionElementName (Element
, FP
);
2741 /* write name to list and draw selected object */
2742 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2743 fprintf (FP
, "\t%s\n", oname
.Data
);
2744 SET_FLAG (SELECTEDFLAG
, pad
);
2748 /* reset found objects for the next pin */
2749 if (PrepareNextLoop (FP
))
2755 /* print separator if element has unused pins or pads */
2758 fputs ("}\n\n", FP
);
2764 /* ---------------------------------------------------------------------------
2765 * resets some flags for looking up the next pin/pad
2768 PrepareNextLoop (FILE * FP
)
2772 /* reset found LOs for the next pin */
2773 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2775 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2776 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2777 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2780 /* reset found pads */
2781 for (layer
= 0; layer
< 2; layer
++)
2782 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2785 PVList
.Number
= PVList
.Location
= 0;
2786 RatList
.Number
= RatList
.Location
= 0;
2791 /* ---------------------------------------------------------------------------
2792 * finds all connections to the pins of the passed element.
2793 * The result is written to file FP
2794 * Returns true if operation was aborted
2797 PrintElementConnections (ElementType
*Element
, FILE * FP
, int flag
, bool AndDraw
)
2799 PrintConnectionElementName (Element
, FP
);
2801 /* check all pins in element */
2804 /* pin might have been checked before, add to list if not */
2805 if (TEST_FLAG (flag
, pin
))
2807 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2808 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2811 if (ADD_PV_TO_LIST (pin
, flag
))
2813 DoIt (flag
, true, AndDraw
);
2814 /* printout all found connections */
2815 PrintPinConnections (FP
, true);
2816 PrintPadConnections (COMPONENT_LAYER
, FP
, false);
2817 PrintPadConnections (SOLDER_LAYER
, FP
, false);
2818 fputs ("\t}\n", FP
);
2819 if (PrepareNextLoop (FP
))
2824 /* check all pads in element */
2828 /* pad might have been checked before, add to list if not */
2829 if (TEST_FLAG (flag
, pad
))
2831 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2832 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2835 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
;
2836 if (ADD_PAD_TO_LIST (layer
, pad
, flag
))
2838 DoIt (flag
, true, AndDraw
);
2839 /* print all found connections */
2840 PrintPadConnections (layer
, FP
, true);
2841 PrintPadConnections (layer
==
2842 (COMPONENT_LAYER
? SOLDER_LAYER
: COMPONENT_LAYER
),
2844 PrintPinConnections (FP
, false);
2845 fputs ("\t}\n", FP
);
2846 if (PrepareNextLoop (FP
))
2850 fputs ("}\n\n", FP
);
2854 /* ---------------------------------------------------------------------------
2855 * draws all new connections which have been found since the
2856 * routine was called the last time
2859 DrawNewConnections (void)
2864 /* decrement 'i' to keep layerstack order */
2865 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
2867 Cardinal layer
= LayerStack
[i
];
2869 if (PCB
->Data
->Layer
[layer
].On
)
2871 /* draw all new lines */
2872 position
= LineList
[layer
].DrawLocation
;
2873 for (; position
< LineList
[layer
].Number
; position
++)
2874 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
2875 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
2877 /* draw all new arcs */
2878 position
= ArcList
[layer
].DrawLocation
;
2879 for (; position
< ArcList
[layer
].Number
; position
++)
2880 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
2881 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
2883 /* draw all new polygons */
2884 position
= PolygonList
[layer
].DrawLocation
;
2885 for (; position
< PolygonList
[layer
].Number
; position
++)
2886 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
2887 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
2891 /* draw all new pads */
2893 for (i
= 0; i
< 2; i
++)
2895 position
= PadList
[i
].DrawLocation
;
2897 for (; position
< PadList
[i
].Number
; position
++)
2898 DrawPad (PADLIST_ENTRY (i
, position
));
2899 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
2902 /* draw all new PVs; 'PVList' holds a list of pointers to the
2903 * sorted array pointers to PV data
2905 while (PVList
.DrawLocation
< PVList
.Number
)
2907 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
2909 if (TEST_FLAG (PINFLAG
, pv
))
2914 else if (PCB
->ViaOn
)
2916 PVList
.DrawLocation
++;
2918 /* draw the new rat-lines */
2921 position
= RatList
.DrawLocation
;
2922 for (; position
< RatList
.Number
; position
++)
2923 DrawRat (RATLIST_ENTRY (position
));
2924 RatList
.DrawLocation
= RatList
.Number
;
2928 /* ---------------------------------------------------------------------------
2929 * find all connections to pins within one element
2932 LookupElementConnections (ElementType
*Element
, FILE * FP
)
2934 /* reset all currently marked connections */
2936 ClearFlagOnAllObjects (true, FOUNDFLAG
);
2937 InitConnectionLookup ();
2938 PrintElementConnections (Element
, FP
, FOUNDFLAG
, true);
2939 SetChangedFlag (true);
2940 if (Settings
.RingBellWhenFinished
)
2942 FreeConnectionLookupMemory ();
2943 IncrementUndoSerialNumber ();
2948 /* ---------------------------------------------------------------------------
2949 * find all connections to pins of all element
2952 LookupConnectionsToAllElements (FILE * FP
)
2954 /* reset all currently marked connections */
2956 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2957 InitConnectionLookup ();
2959 ELEMENT_LOOP (PCB
->Data
);
2961 /* break if abort dialog returned true */
2962 if (PrintElementConnections (element
, FP
, FOUNDFLAG
, false))
2965 if (Settings
.ResetAfterElement
&& n
!= 1)
2966 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2969 if (Settings
.RingBellWhenFinished
)
2971 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2972 FreeConnectionLookupMemory ();
2976 /*---------------------------------------------------------------------------
2977 * add the starting object to the list of found objects
2980 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
, int flag
)
2988 if (ADD_PV_TO_LIST ((PinType
*) ptr2
, flag
))
2995 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
, flag
))
3002 int layer
= GetLayerNumber (PCB
->Data
,
3003 (LayerType
*) ptr1
);
3005 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
, flag
))
3012 int layer
= GetLayerNumber (PCB
->Data
,
3013 (LayerType
*) ptr1
);
3015 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
, flag
))
3022 int layer
= GetLayerNumber (PCB
->Data
,
3023 (LayerType
*) ptr1
);
3025 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
, flag
))
3032 PadType
*pad
= (PadType
*) ptr2
;
3035 (ONSOLDERFLAG
, pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
, pad
, flag
))
3044 /* ---------------------------------------------------------------------------
3045 * looks up all connections from the object at the given coordinates
3046 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3047 * the objects are re-drawn if AndDraw is true
3048 * also the action is marked as undoable if AndDraw is true
3051 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int flag
,
3054 void *ptr1
, *ptr2
, *ptr3
;
3058 /* check if there are any pins or pads at that position */
3060 reassign_no_drc_flags ();
3063 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3064 if (type
== NO_TYPE
)
3066 type
= SearchObjectByLocation (
3067 LOOKUP_MORE
& ~(AndRats
? 0 : RATLINE_TYPE
),
3068 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3069 if (type
== NO_TYPE
)
3071 if (type
& SILK_TYPE
)
3073 int laynum
= GetLayerNumber (PCB
->Data
,
3074 (LayerType
*) ptr1
);
3076 /* don't mess with non-conducting objects! */
3077 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3082 name
= ConnectionName (type
, ptr1
, ptr2
);
3083 hid_actionl ("NetlistShow", name
, NULL
);
3086 InitConnectionLookup ();
3088 /* now add the object to the appropriate list and start scanning
3089 * This is step (1) from the description
3091 ListStart (type
, ptr1
, ptr2
, ptr3
, flag
);
3092 DoIt (flag
, AndRats
, AndDraw
);
3094 IncrementUndoSerialNumber ();
3100 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3102 FreeConnectionLookupMemory ();
3105 /* ---------------------------------------------------------------------------
3106 * find connections for rats nesting
3107 * assumes InitConnectionLookup() has already been done
3110 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3111 bool undo
, int flag
, bool AndRats
)
3115 ListStart (type
, ptr1
, ptr2
, ptr3
, flag
);
3116 DoIt (flag
, AndRats
, false);
3120 /* ---------------------------------------------------------------------------
3121 * find all unused pins of all element
3124 LookupUnusedPins (FILE * FP
)
3126 /* reset all currently marked connections */
3128 ClearFlagOnAllObjects (true, FOUNDFLAG
);
3129 InitConnectionLookup ();
3131 ELEMENT_LOOP (PCB
->Data
);
3133 /* break if abort dialog returned true;
3134 * passing NULL as filedescriptor discards the normal output
3136 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
, FOUNDFLAG
))
3141 if (Settings
.RingBellWhenFinished
)
3143 FreeConnectionLookupMemory ();
3144 IncrementUndoSerialNumber ();
3149 /* ---------------------------------------------------------------------------
3150 * resets all used flags of pins and vias
3153 ClearFlagOnPinsViasAndPads (bool AndDraw
, int flag
)
3155 bool change
= false;
3157 VIA_LOOP (PCB
->Data
);
3159 if (TEST_FLAG (flag
, via
))
3162 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3163 CLEAR_FLAG (flag
, via
);
3170 ELEMENT_LOOP (PCB
->Data
);
3174 if (TEST_FLAG (flag
, pin
))
3177 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3178 CLEAR_FLAG (flag
, pin
);
3187 if (TEST_FLAG (flag
, pad
))
3190 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3191 CLEAR_FLAG (flag
, pad
);
3201 SetChangedFlag (true);
3205 /* ---------------------------------------------------------------------------
3206 * resets all used flags of LOs
3209 ClearFlagOnLinesAndPolygons (bool AndDraw
, int flag
)
3211 bool change
= false;
3213 RAT_LOOP (PCB
->Data
);
3215 if (TEST_FLAG (flag
, line
))
3218 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3219 CLEAR_FLAG (flag
, line
);
3226 COPPERLINE_LOOP (PCB
->Data
);
3228 if (TEST_FLAG (flag
, line
))
3231 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3232 CLEAR_FLAG (flag
, line
);
3234 DrawLine (layer
, line
);
3239 COPPERARC_LOOP (PCB
->Data
);
3241 if (TEST_FLAG (flag
, arc
))
3244 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3245 CLEAR_FLAG (flag
, arc
);
3247 DrawArc (layer
, arc
);
3252 COPPERPOLYGON_LOOP (PCB
->Data
);
3254 if (TEST_FLAG (flag
, polygon
))
3257 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3258 CLEAR_FLAG (flag
, polygon
);
3260 DrawPolygon (layer
, polygon
);
3266 SetChangedFlag (true);
3270 /* ---------------------------------------------------------------------------
3271 * resets all found connections
3274 ClearFlagOnAllObjects (bool AndDraw
, int flag
)
3276 bool change
= false;
3278 change
= ClearFlagOnPinsViasAndPads (AndDraw
, flag
) || change
;
3279 change
= ClearFlagOnLinesAndPolygons (AndDraw
, flag
) || change
;
3284 /*----------------------------------------------------------------------------
3285 * Dumps the list contents
3292 for (i
= 0; i
< 2; i
++)
3294 PadList
[i
].Number
= 0;
3295 PadList
[i
].Location
= 0;
3296 PadList
[i
].DrawLocation
= 0;
3300 PVList
.Location
= 0;
3302 for (i
= 0; i
< max_copper_layer
; i
++)
3304 LineList
[i
].Location
= 0;
3305 LineList
[i
].DrawLocation
= 0;
3306 LineList
[i
].Number
= 0;
3307 ArcList
[i
].Location
= 0;
3308 ArcList
[i
].DrawLocation
= 0;
3309 ArcList
[i
].Number
= 0;
3310 PolygonList
[i
].Location
= 0;
3311 PolygonList
[i
].DrawLocation
= 0;
3312 PolygonList
[i
].Number
= 0;
3315 RatList
.Location
= 0;
3316 RatList
.DrawLocation
= 0;
3324 /*-----------------------------------------------------------------------------
3325 * Check for DRC violations on a single net starting from the pad or pin
3326 * sees if the connectivity changes when everything is bloated, or shrunk
3329 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3333 long int *object_id_list
;
3334 int *object_type_list
;
3335 DrcViolationType
*violation
;
3338 if (PCB
->Shrink
!= 0)
3340 Bloat
= -PCB
->Shrink
;
3341 flag
= DRCFLAG
| SELECTEDFLAG
;
3342 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3343 DoIt (flag
, true, false);
3344 /* ok now the shrunk net has the SELECTEDFLAG set */
3347 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3349 drc
= true; /* abort the search if we find anything not already found */
3350 if (DoIt (flag
, true, false))
3353 /* make the flag changes undoable */
3354 flag
= FOUNDFLAG
| SELECTEDFLAG
;
3355 ClearFlagOnAllObjects (false, flag
);
3358 Bloat
= -PCB
->Shrink
;
3359 flag
= SELECTEDFLAG
;
3360 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3361 DoIt (flag
, true, true);
3363 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3367 DoIt (flag
, true, true);
3372 LocateError (&x
, &y
);
3373 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3374 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3375 _("Insufficient overlap between objects can lead to broken tracks\n"
3376 "due to registration errors with old wheel style photo-plotters."),
3378 0, /* ANGLE OF ERROR UNKNOWN */
3379 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3380 0, /* MAGNITUDE OF ERROR UNKNOWN */
3385 append_drc_violation (violation
);
3386 pcb_drc_violation_free (violation
);
3387 free (object_id_list
);
3388 free (object_type_list
);
3390 if (!throw_drc_dialog())
3392 IncrementUndoSerialNumber ();
3397 /* now check the bloated condition */
3399 ClearFlagOnAllObjects (false, flag
);
3401 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3404 while (DoIt (flag
, true, false))
3407 /* make the flag changes undoable */
3408 flag
= FOUNDFLAG
| SELECTEDFLAG
;
3409 ClearFlagOnAllObjects (false, flag
);
3413 flag
= SELECTEDFLAG
;
3414 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3415 DoIt (flag
, true, true);
3418 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3421 DoIt (flag
, true, true);
3424 LocateError (&x
, &y
);
3425 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3426 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3427 _("Circuits that are too close may bridge during imaging, etching,\n"
3428 "plating, or soldering processes resulting in a direct short."),
3430 0, /* ANGLE OF ERROR UNKNOWN */
3431 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3432 0, /* MAGNITUDE OF ERROR UNKNOWN */
3437 append_drc_violation (violation
);
3438 pcb_drc_violation_free (violation
);
3439 free (object_id_list
);
3440 free (object_type_list
);
3443 if (!throw_drc_dialog())
3445 IncrementUndoSerialNumber ();
3447 /* highlight the rest of the encroaching net so it's not reported again */
3448 flag
|= SELECTEDFLAG
;
3450 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
, flag
);
3451 DoIt (flag
, true, true);
3455 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3459 flag
= FOUNDFLAG
| SELECTEDFLAG
;
3460 ClearFlagOnAllObjects (false, flag
);
3464 /* DRC clearance callback */
3467 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3468 int type
, void *ptr1
, void *ptr2
, void *userdata
)
3470 struct drc_info
*i
= (struct drc_info
*) userdata
;
3474 long int *object_id_list
;
3475 int *object_type_list
;
3476 DrcViolationType
*violation
;
3478 LineType
*line
= (LineType
*) ptr2
;
3479 ArcType
*arc
= (ArcType
*) ptr2
;
3480 PinType
*pin
= (PinType
*) ptr2
;
3481 PadType
*pad
= (PadType
*) ptr2
;
3490 if (line
->Clearance
< 2 * PCB
->Bloat
)
3492 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3493 SET_FLAG (i
->flag
, line
);
3494 message
= _("Line with insufficient clearance inside polygon\n");
3499 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3501 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3502 SET_FLAG (i
->flag
, arc
);
3503 message
= _("Arc with insufficient clearance inside polygon\n");
3508 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3509 if (IsPadInPolygon(pad
,polygon
))
3511 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3512 SET_FLAG (i
->flag
, pad
);
3513 message
= _("Pad with insufficient clearance inside polygon\n");
3518 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3520 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3521 SET_FLAG (i
->flag
, pin
);
3522 message
= _("Pin with insufficient clearance inside polygon\n");
3527 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3529 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3530 SET_FLAG (i
->flag
, pin
);
3531 message
= _("Via with insufficient clearance inside polygon\n");
3536 Message ("hace: Bad Plow object in callback\n");
3541 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3542 SET_FLAG (FOUNDFLAG
, polygon
);
3543 DrawPolygon (layer
, polygon
);
3544 DrawObject (type
, ptr1
, ptr2
);
3546 LocateError (&x
, &y
);
3547 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3548 violation
= pcb_drc_violation_new (message
,
3549 _("Circuits that are too close may bridge during imaging, etching,\n"
3550 "plating, or soldering processes resulting in a direct short."),
3552 0, /* ANGLE OF ERROR UNKNOWN */
3553 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3554 0, /* MAGNITUDE OF ERROR UNKNOWN */
3559 append_drc_violation (violation
);
3560 pcb_drc_violation_free (violation
);
3561 free (object_id_list
);
3562 free (object_type_list
);
3564 if (!throw_drc_dialog())
3567 IncrementUndoSerialNumber ();
3572 /*-----------------------------------------------------------------------------
3573 * Check for DRC violations
3574 * see if the connectivity changes when everything is bloated, or shrunk
3581 long int *object_id_list
;
3582 int *object_type_list
;
3583 DrcViolationType
*violation
;
3588 struct drc_info info
;
3590 reset_drc_dialog_message();
3594 SaveStackAndVisibility ();
3595 ResetStackAndVisibility ();
3596 hid_action ("LayersChanged");
3597 InitConnectionLookup ();
3599 flag
= FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
;
3601 if (ClearFlagOnAllObjects (true, flag
))
3603 IncrementUndoSerialNumber ();
3609 ELEMENT_LOOP (PCB
->Data
);
3613 if (!TEST_FLAG (DRCFLAG
, pin
)
3614 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3626 /* count up how many pads have no solderpaste openings */
3627 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3630 if (!TEST_FLAG (DRCFLAG
, pad
)
3631 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3643 VIA_LOOP (PCB
->Data
);
3645 if (!TEST_FLAG (DRCFLAG
, via
)
3646 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3654 flag
= (IsBad
) ? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
);
3655 ClearFlagOnAllObjects (false, flag
);
3656 flag
= SELECTEDFLAG
;
3658 /* check minimum widths and polygon clearances */
3661 COPPERLINE_LOOP (PCB
->Data
);
3663 /* check line clearances in polygons */
3664 if (PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
, &info
))
3669 if (line
->Thickness
< PCB
->minWid
)
3671 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3672 SET_FLAG (flag
, line
);
3673 DrawLine (layer
, line
);
3675 SetThing (LINE_TYPE
, layer
, line
, line
);
3676 LocateError (&x
, &y
);
3677 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3678 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3679 _("Process specifications dictate a minimum feature-width\n"
3680 "that can reliably be reproduced"),
3682 0, /* ANGLE OF ERROR UNKNOWN */
3683 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3689 append_drc_violation (violation
);
3690 pcb_drc_violation_free (violation
);
3691 free (object_id_list
);
3692 free (object_type_list
);
3693 if (!throw_drc_dialog())
3698 IncrementUndoSerialNumber ();
3706 COPPERARC_LOOP (PCB
->Data
);
3708 if (PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
, &info
))
3713 if (arc
->Thickness
< PCB
->minWid
)
3715 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3716 SET_FLAG (flag
, arc
);
3717 DrawArc (layer
, arc
);
3719 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3720 LocateError (&x
, &y
);
3721 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3722 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3723 _("Process specifications dictate a minimum feature-width\n"
3724 "that can reliably be reproduced"),
3726 0, /* ANGLE OF ERROR UNKNOWN */
3727 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3733 append_drc_violation (violation
);
3734 pcb_drc_violation_free (violation
);
3735 free (object_id_list
);
3736 free (object_type_list
);
3737 if (!throw_drc_dialog())
3742 IncrementUndoSerialNumber ();
3750 ALLPIN_LOOP (PCB
->Data
);
3752 if (PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
, &info
))
3757 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3758 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3760 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3761 SET_FLAG (flag
, pin
);
3764 SetThing (PIN_TYPE
, element
, pin
, pin
);
3765 LocateError (&x
, &y
);
3766 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3767 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3768 _("Annular rings that are too small may erode during etching,\n"
3769 "resulting in a broken connection"),
3771 0, /* ANGLE OF ERROR UNKNOWN */
3772 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3773 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3778 append_drc_violation (violation
);
3779 pcb_drc_violation_free (violation
);
3780 free (object_id_list
);
3781 free (object_type_list
);
3782 if (!throw_drc_dialog())
3787 IncrementUndoSerialNumber ();
3790 if (pin
->DrillingHole
< PCB
->minDrill
)
3792 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3793 SET_FLAG (flag
, pin
);
3796 SetThing (PIN_TYPE
, element
, pin
, pin
);
3797 LocateError (&x
, &y
);
3798 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3799 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3800 _("Process rules dictate the minimum drill size which can be used"),
3802 0, /* ANGLE OF ERROR UNKNOWN */
3803 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3809 append_drc_violation (violation
);
3810 pcb_drc_violation_free (violation
);
3811 free (object_id_list
);
3812 free (object_type_list
);
3813 if (!throw_drc_dialog())
3818 IncrementUndoSerialNumber ();
3826 ALLPAD_LOOP (PCB
->Data
);
3828 if (PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
, &info
))
3833 if (pad
->Thickness
< PCB
->minWid
)
3835 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3836 SET_FLAG (flag
, pad
);
3839 SetThing (PAD_TYPE
, element
, pad
, pad
);
3840 LocateError (&x
, &y
);
3841 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3842 violation
= pcb_drc_violation_new (_("Pad is too thin"),
3843 _("Pads which are too thin may erode during etching,\n"
3844 "resulting in a broken or unreliable connection"),
3846 0, /* ANGLE OF ERROR UNKNOWN */
3847 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3853 append_drc_violation (violation
);
3854 pcb_drc_violation_free (violation
);
3855 free (object_id_list
);
3856 free (object_type_list
);
3857 if (!throw_drc_dialog())
3862 IncrementUndoSerialNumber ();
3870 VIA_LOOP (PCB
->Data
);
3872 if (PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
, &info
))
3877 if (!TEST_FLAG (HOLEFLAG
, via
) &&
3878 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
3880 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3881 SET_FLAG (flag
, via
);
3884 SetThing (VIA_TYPE
, via
, via
, via
);
3885 LocateError (&x
, &y
);
3886 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3887 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
3888 _("Annular rings that are too small may erode during etching,\n"
3889 "resulting in a broken connection"),
3891 0, /* ANGLE OF ERROR UNKNOWN */
3892 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3893 (via
->Thickness
- via
->DrillingHole
) / 2,
3898 append_drc_violation (violation
);
3899 pcb_drc_violation_free (violation
);
3900 free (object_id_list
);
3901 free (object_type_list
);
3902 if (!throw_drc_dialog())
3907 IncrementUndoSerialNumber ();
3910 if (via
->DrillingHole
< PCB
->minDrill
)
3912 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3913 SET_FLAG (flag
, via
);
3916 SetThing (VIA_TYPE
, via
, via
, via
);
3917 LocateError (&x
, &y
);
3918 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3919 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
3920 _("Process rules dictate the minimum drill size which can be used"),
3922 0, /* ANGLE OF ERROR UNKNOWN */
3923 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3929 append_drc_violation (violation
);
3930 pcb_drc_violation_free (violation
);
3931 free (object_id_list
);
3932 free (object_type_list
);
3933 if (!throw_drc_dialog())
3938 IncrementUndoSerialNumber ();
3945 FreeConnectionLookupMemory ();
3949 /* check silkscreen minimum widths outside of elements */
3950 /* XXX - need to check text and polygons too! */
3951 flag
= SELECTEDFLAG
;
3954 SILKLINE_LOOP (PCB
->Data
);
3956 if (line
->Thickness
< PCB
->minSlk
)
3958 SET_FLAG (flag
, line
);
3959 DrawLine (layer
, line
);
3961 SetThing (LINE_TYPE
, layer
, line
, line
);
3962 LocateError (&x
, &y
);
3963 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3964 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
3965 _("Process specifications dictate a minimum silkscreen feature-width\n"
3966 "that can reliably be reproduced"),
3968 0, /* ANGLE OF ERROR UNKNOWN */
3969 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3975 append_drc_violation (violation
);
3976 pcb_drc_violation_free (violation
);
3977 free (object_id_list
);
3978 free (object_type_list
);
3979 if (!throw_drc_dialog())
3989 /* check silkscreen minimum widths inside of elements */
3990 /* XXX - need to check text and polygons too! */
3991 flag
= SELECTEDFLAG
;
3994 ELEMENT_LOOP (PCB
->Data
);
3997 ELEMENTLINE_LOOP (element
);
3999 if (line
->Thickness
< PCB
->minSlk
)
4010 SET_FLAG (flag
, element
);
4011 DrawElement (element
);
4013 SetThing (ELEMENT_TYPE
, element
, element
, element
);
4014 LocateError (&x
, &y
);
4015 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4017 title
= _("Element %s has %i silk lines which are too thin");
4018 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
4020 /* -4 is for the %s and %i place-holders */
4021 /* +11 is the max printed length for a 32 bit integer */
4022 /* +1 is for the \0 termination */
4023 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
4024 buffer
= (char *)malloc (buflen
);
4025 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
4027 violation
= pcb_drc_violation_new (buffer
,
4028 _("Process specifications dictate a minimum silkscreen\n"
4029 "feature-width that can reliably be reproduced"),
4031 0, /* ANGLE OF ERROR UNKNOWN */
4032 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4033 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4039 append_drc_violation (violation
);
4040 pcb_drc_violation_free (violation
);
4041 free (object_id_list
);
4042 free (object_type_list
);
4043 if (!throw_drc_dialog())
4056 IncrementUndoSerialNumber ();
4060 RestoreStackAndVisibility ();
4061 hid_action ("LayersChanged");
4062 gui
->invalidate_all ();
4066 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4068 nopastecnt
> 1 ? "s have" : " has");
4070 return IsBad
? -drcerr_count
: drcerr_count
;
4073 /*----------------------------------------------------------------------------
4074 * Locate the coordinatates of offending item (thing)
4077 LocateError (Coord
*x
, Coord
*y
)
4083 LineType
*line
= (LineType
*) thing_ptr3
;
4084 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4085 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4090 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4097 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4099 (polygon
->Clipped
->contours
->xmin
+
4100 polygon
->Clipped
->contours
->xmax
) / 2;
4102 (polygon
->Clipped
->contours
->ymin
+
4103 polygon
->Clipped
->contours
->ymax
) / 2;
4109 PinType
*pin
= (PinType
*) thing_ptr3
;
4116 PadType
*pad
= (PadType
*) thing_ptr3
;
4117 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4118 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4123 ElementType
*element
= (ElementType
*) thing_ptr3
;
4124 *x
= element
->MarkX
;
4125 *y
= element
->MarkY
;
4134 /*----------------------------------------------------------------------------
4135 * Build a list of the of offending items by ID. (Currently just "thing")
4138 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4141 *object_id_list
= NULL
;
4142 *object_type_list
= NULL
;
4155 *object_id_list
= (long int *)malloc (sizeof (long int));
4156 *object_type_list
= (int *)malloc (sizeof (int));
4157 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4158 **object_type_list
= thing_type
;
4163 _("Internal error in BuildObjectList: unknown object type %i\n"),
4169 /*----------------------------------------------------------------------------
4170 * center the display to show the offending item (thing)
4177 LocateError (&X
, &Y
);
4184 ChangeGroupVisibility (
4185 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4188 CenterDisplay (X
, Y
);
4192 InitConnectionLookup (void)
4194 InitComponentLookup ();
4195 InitLayoutLookup ();
4199 FreeConnectionLookupMemory (void)
4201 FreeComponentLookupMemory ();
4202 FreeLayoutLookupMemory ();