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 #define BOTTOM_LAYER 0
130 static DrcViolationType
131 *pcb_drc_violation_new (const char *title
,
132 const char *explanation
,
136 Coord measured_value
,
137 Coord required_value
,
139 long int *object_id_list
,
140 int *object_type_list
)
142 DrcViolationType
*violation
= (DrcViolationType
*)malloc (sizeof (DrcViolationType
));
144 violation
->title
= strdup (title
);
145 violation
->explanation
= strdup (explanation
);
148 violation
->angle
= angle
;
149 violation
->have_measured
= have_measured
;
150 violation
->measured_value
= measured_value
;
151 violation
->required_value
= required_value
;
152 violation
->object_count
= object_count
;
153 violation
->object_id_list
= object_id_list
;
154 violation
->object_type_list
= object_type_list
;
160 pcb_drc_violation_free (DrcViolationType
*violation
)
162 free (violation
->title
);
163 free (violation
->explanation
);
167 static GString
*drc_dialog_message
;
169 reset_drc_dialog_message(void)
171 if (drc_dialog_message
)
172 g_string_free (drc_dialog_message
, FALSE
);
173 drc_dialog_message
= g_string_new ("");
174 if (gui
->drc_gui
!= NULL
)
176 gui
->drc_gui
->reset_drc_dialog_message ();
180 append_drc_dialog_message(const char *fmt
, ...)
185 new_str
= pcb_vprintf (fmt
, ap
);
186 g_string_append (drc_dialog_message
, new_str
);
191 static void GotoError (void);
194 append_drc_violation (DrcViolationType
*violation
)
196 if (gui
->drc_gui
!= NULL
)
198 gui
->drc_gui
->append_drc_violation (violation
);
202 /* Fallback to formatting the violation message as text */
203 append_drc_dialog_message ("%s\n", violation
->title
);
204 append_drc_dialog_message (_("%m+near %$mD\n"),
205 Settings
.grid_unit
->allow
,
206 violation
->x
, violation
->y
);
210 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_violations
)
212 Message (_("WARNING! Design Rule error - %s\n"), violation
->title
);
213 Message (_("%m+near location %$mD\n"),
214 Settings
.grid_unit
->allow
,
215 violation
->x
, violation
->y
);
219 * message when asked about continuing DRC checks after next
220 * violation is found.
222 #define DRC_CONTINUE _("Press Next to continue DRC checking")
223 #define DRC_NEXT _("Next")
224 #define DRC_CANCEL _("Cancel")
227 throw_drc_dialog(void)
231 if (gui
->drc_gui
!= NULL
)
233 r
= gui
->drc_gui
->throw_drc_dialog ();
237 /* Fallback to formatting the violation message as text */
238 append_drc_dialog_message (DRC_CONTINUE
);
239 r
= gui
->confirm_dialog (drc_dialog_message
->str
, DRC_CANCEL
, DRC_NEXT
);
240 reset_drc_dialog_message();
245 /* ---------------------------------------------------------------------------
248 * the two 'dummy' structs for PVs and Pads are necessary for creating
249 * connection lists which include the element's name
253 void **Data
; /* pointer to index data */
254 Cardinal Location
, /* currently used position */
255 DrawLocation
, Number
, /* number of objects in list */
259 /* ---------------------------------------------------------------------------
260 * some local identifiers
262 static Coord Bloat
= 0;
263 static void *thing_ptr1
, *thing_ptr2
, *thing_ptr3
;
264 static int thing_type
;
265 static bool User
= false; /* user action causing this */
266 static bool drc
= false; /* whether to stop if finding something not found */
267 static Cardinal drcerr_count
; /* count of drc errors */
268 static Cardinal TotalP
, TotalV
;
269 static ListType LineList
[MAX_LAYER
], /* list of objects to */
270 PolygonList
[MAX_LAYER
], ArcList
[MAX_LAYER
], PadList
[2], RatList
, PVList
;
272 /* ---------------------------------------------------------------------------
273 * some local prototypes
275 static bool LookupLOConnectionsToLine (LineType
*, Cardinal
, int, bool, bool);
276 static bool LookupLOConnectionsToPad (PadType
*, Cardinal
, int, bool);
277 static bool LookupLOConnectionsToPolygon (PolygonType
*, Cardinal
, int, bool);
278 static bool LookupLOConnectionsToArc (ArcType
*, Cardinal
, int, bool);
279 static bool LookupLOConnectionsToRatEnd (PointType
*, Cardinal
, int);
280 static bool IsRatPointOnLineEnd (PointType
*, LineType
*);
281 static bool ArcArcIntersect (ArcType
*, ArcType
*);
282 static bool PrepareNextLoop (FILE *);
283 static void DrawNewConnections (void);
284 static void DumpList (void);
285 static void LocateError (Coord
*, Coord
*);
286 static void BuildObjectList (int *, long int **, int **);
287 static bool SetThing (int, void *, void *, void *);
288 static bool IsArcInPolygon (ArcType
*, PolygonType
*);
289 static bool IsLineInPolygon (LineType
*, PolygonType
*);
290 static bool IsPadInPolygon (PadType
*, PolygonType
*);
291 static bool IsPolygonInPolygon (PolygonType
*, PolygonType
*);
293 /* ---------------------------------------------------------------------------
294 * some of the 'pad' routines are the same as for lines because the 'pad'
295 * struct starts with a line struct. See global.h for details
298 LinePadIntersect (LineType
*Line
, PadType
*Pad
)
300 return LineLineIntersect ((Line
), (LineType
*)Pad
);
304 ArcPadIntersect (ArcType
*Arc
, PadType
*Pad
)
306 return LineArcIntersect ((LineType
*) (Pad
), (Arc
));
310 add_object_to_list (ListType
*list
, int type
, void *ptr1
, void *ptr2
, void *ptr3
, int flag
)
312 AnyObjectType
*object
= (AnyObjectType
*)ptr2
;
315 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
317 SET_FLAG (flag
, object
);
318 LIST_ENTRY (list
, list
->Number
) = object
;
322 if (list
.Number
> list
.Size
)
323 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type
, list
.Number
, list
.Size
);
326 if (drc
&& !TEST_FLAG (SELECTEDFLAG
, object
))
327 return (SetThing (type
, ptr1
, ptr2
, ptr3
));
332 ADD_PV_TO_LIST (PinType
*Pin
, int flag
)
334 return add_object_to_list (&PVList
, Pin
->Element
? PIN_TYPE
: VIA_TYPE
,
335 Pin
->Element
? Pin
->Element
: Pin
, Pin
, Pin
, flag
);
339 ADD_PAD_TO_LIST (Cardinal L
, PadType
*Pad
, int flag
)
341 return add_object_to_list (&PadList
[L
], PAD_TYPE
, Pad
->Element
, Pad
, Pad
, flag
);
345 ADD_LINE_TO_LIST (Cardinal L
, LineType
*Ptr
, int flag
)
347 return add_object_to_list (&LineList
[L
], LINE_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
351 ADD_ARC_TO_LIST (Cardinal L
, ArcType
*Ptr
, int flag
)
353 return add_object_to_list (&ArcList
[L
], ARC_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
357 ADD_RAT_TO_LIST (RatType
*Ptr
, int flag
)
359 return add_object_to_list (&RatList
, RATLINE_TYPE
, Ptr
, Ptr
, Ptr
, flag
);
363 ADD_POLYGON_TO_LIST (Cardinal L
, PolygonType
*Ptr
, int flag
)
365 return add_object_to_list (&PolygonList
[L
], POLYGON_TYPE
, LAYER_PTR (L
), Ptr
, Ptr
, flag
);
369 expand_bounds (BoxType
*box_in
)
371 BoxType box_out
= *box_in
;
385 PinLineIntersect (PinType
*PV
, LineType
*Line
)
387 /* IsLineInRectangle already has Bloat factor */
388 return TEST_FLAG (SQUAREFLAG
,
389 PV
) ? IsLineInRectangle (PV
->X
- (PIN_SIZE (PV
) + 1) / 2,
390 PV
->Y
- (PIN_SIZE (PV
) + 1) / 2,
391 PV
->X
+ (PIN_SIZE (PV
) + 1) / 2,
392 PV
->Y
+ (PIN_SIZE (PV
) + 1) / 2,
393 Line
) : IsPointInPad (PV
->X
,
405 SetThing (int type
, void *ptr1
, void *ptr2
, void *ptr3
)
415 BoxBoxIntersection (BoxType
*b1
, BoxType
*b2
)
417 if (b2
->X2
< b1
->X1
|| b2
->X1
> b1
->X2
)
419 if (b2
->Y2
< b1
->Y1
|| b2
->Y1
> b1
->Y2
)
425 PadPadIntersect (PadType
*p1
, PadType
*p2
)
427 return LinePadIntersect ((LineType
*) p1
, p2
);
431 PV_TOUCH_PV (PinType
*PV1
, PinType
*PV2
)
436 t1
= MAX (PV1
->Thickness
/ 2.0 + Bloat
, 0);
437 t2
= MAX (PV2
->Thickness
/ 2.0 + Bloat
, 0);
438 if (IsPointOnPin (PV1
->X
, PV1
->Y
, t1
, PV2
)
439 || IsPointOnPin (PV2
->X
, PV2
->Y
, t2
, PV1
))
441 if (!TEST_FLAG (SQUAREFLAG
, PV1
) || !TEST_FLAG (SQUAREFLAG
, PV2
))
443 /* check for square/square overlap */
448 t2
= PV2
->Thickness
/ 2.0;
453 return BoxBoxIntersection (&b1
, &b2
);
456 /* ---------------------------------------------------------------------------
457 * releases all allocated memory
460 FreeLayoutLookupMemory (void)
464 for (i
= 0; i
< max_copper_layer
; i
++)
466 free (LineList
[i
].Data
);
467 LineList
[i
].Data
= NULL
;
468 free (ArcList
[i
].Data
);
469 ArcList
[i
].Data
= NULL
;
470 free (PolygonList
[i
].Data
);
471 PolygonList
[i
].Data
= NULL
;
480 FreeComponentLookupMemory (void)
482 free (PadList
[0].Data
);
483 PadList
[0].Data
= NULL
;
484 free (PadList
[1].Data
);
485 PadList
[1].Data
= NULL
;
488 /* ---------------------------------------------------------------------------
489 * allocates memory for component related stacks ...
490 * initializes index and sorts it by X1 and X2
493 InitComponentLookup (void)
495 Cardinal NumberOfPads
[2];
498 /* initialize pad data; start by counting the total number
499 * on each of the two possible layers
501 NumberOfPads
[TOP_SIDE
] = NumberOfPads
[BOTTOM_SIDE
] = 0;
502 ALLPAD_LOOP (PCB
->Data
);
504 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
505 NumberOfPads
[BOTTOM_SIDE
]++;
507 NumberOfPads
[TOP_SIDE
]++;
510 for (i
= 0; i
< 2; i
++)
512 /* allocate memory for working list */
513 PadList
[i
].Data
= (void **)calloc (NumberOfPads
[i
], sizeof (PadType
*));
515 /* clear some struct members */
516 PadList
[i
].Location
= 0;
517 PadList
[i
].DrawLocation
= 0;
518 PadList
[i
].Number
= 0;
519 PadList
[i
].Size
= NumberOfPads
[i
];
523 /* ---------------------------------------------------------------------------
524 * allocates memory for component related stacks ...
525 * initializes index and sorts it by X1 and X2
528 InitLayoutLookup (void)
532 /* initialize line arc and polygon data */
533 for (i
= 0; i
< max_copper_layer
; i
++)
535 LayerType
*layer
= LAYER_PTR (i
);
539 /* allocate memory for line pointer lists */
540 LineList
[i
].Data
= (void **)calloc (layer
->LineN
, sizeof (LineType
*));
541 LineList
[i
].Size
= layer
->LineN
;
545 ArcList
[i
].Data
= (void **)calloc (layer
->ArcN
, sizeof (ArcType
*));
546 ArcList
[i
].Size
= layer
->ArcN
;
550 /* allocate memory for polygon list */
553 PolygonList
[i
].Data
= (void **)calloc (layer
->PolygonN
, sizeof (PolygonType
*));
554 PolygonList
[i
].Size
= layer
->PolygonN
;
557 /* clear some struct members */
558 LineList
[i
].Location
= 0;
559 LineList
[i
].DrawLocation
= 0;
560 LineList
[i
].Number
= 0;
561 ArcList
[i
].Location
= 0;
562 ArcList
[i
].DrawLocation
= 0;
563 ArcList
[i
].Number
= 0;
564 PolygonList
[i
].Location
= 0;
565 PolygonList
[i
].DrawLocation
= 0;
566 PolygonList
[i
].Number
= 0;
569 if (PCB
->Data
->pin_tree
)
570 TotalP
= PCB
->Data
->pin_tree
->size
;
573 if (PCB
->Data
->via_tree
)
574 TotalV
= PCB
->Data
->via_tree
->size
;
577 /* allocate memory for 'new PV to check' list and clear struct */
578 PVList
.Data
= (void **)calloc (TotalP
+ TotalV
, sizeof (PinType
*));
579 PVList
.Size
= TotalP
+ TotalV
;
581 PVList
.DrawLocation
= 0;
583 /* Initialize ratline data */
584 RatList
.Data
= (void **)calloc (PCB
->Data
->RatN
, sizeof (RatType
*));
585 RatList
.Size
= PCB
->Data
->RatN
;
586 RatList
.Location
= 0;
587 RatList
.DrawLocation
= 0;
600 LOCtoPVline_callback (const BoxType
* b
, void *cl
)
602 LineType
*line
= (LineType
*) b
;
603 struct pv_info
*i
= (struct pv_info
*) cl
;
605 if (!TEST_FLAG (i
->flag
, line
) && PinLineIntersect (i
->pv
, line
) &&
606 !TEST_FLAG (HOLEFLAG
, i
->pv
))
608 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
615 LOCtoPVarc_callback (const BoxType
* b
, void *cl
)
617 ArcType
*arc
= (ArcType
*) b
;
618 struct pv_info
*i
= (struct pv_info
*) cl
;
620 if (!TEST_FLAG (i
->flag
, arc
) && IS_PV_ON_ARC (i
->pv
, arc
) &&
621 !TEST_FLAG (HOLEFLAG
, i
->pv
))
623 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
630 LOCtoPVpad_callback (const BoxType
* b
, void *cl
)
632 PadType
*pad
= (PadType
*) b
;
633 struct pv_info
*i
= (struct pv_info
*) cl
;
635 if (!TEST_FLAG (i
->flag
, pad
) && IS_PV_ON_PAD (i
->pv
, pad
) &&
636 !TEST_FLAG (HOLEFLAG
, i
->pv
) &&
637 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
:
638 TOP_SIDE
, pad
, i
->flag
))
644 LOCtoPVrat_callback (const BoxType
* b
, void *cl
)
646 RatType
*rat
= (RatType
*) b
;
647 struct pv_info
*i
= (struct pv_info
*) cl
;
649 if (!TEST_FLAG (i
->flag
, rat
) && IS_PV_ON_RAT (i
->pv
, rat
) &&
650 ADD_RAT_TO_LIST (rat
, i
->flag
))
655 LOCtoPVpoly_callback (const BoxType
* b
, void *cl
)
657 PolygonType
*polygon
= (PolygonType
*) b
;
658 struct pv_info
*i
= (struct pv_info
*) cl
;
660 /* if the pin doesn't have a therm and polygon is clearing
661 * then it can't touch due to clearance, so skip the expensive
662 * test. If it does have a therm, you still need to test
663 * because it might not be inside the polygon, or it could
664 * be on an edge such that it doesn't actually touch.
666 if (!TEST_FLAG (i
->flag
, polygon
) && !TEST_FLAG (HOLEFLAG
, i
->pv
) &&
667 (TEST_THERM (i
->layer
, i
->pv
) ||
668 !TEST_FLAG (CLEARPOLYFLAG
,
670 || !i
->pv
->Clearance
))
672 double wide
= MAX (0.5 * i
->pv
->Thickness
+ Bloat
, 0);
673 if (TEST_FLAG (SQUAREFLAG
, i
->pv
))
675 Coord x1
= i
->pv
->X
- (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
676 Coord x2
= i
->pv
->X
+ (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
677 Coord y1
= i
->pv
->Y
- (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
678 Coord y2
= i
->pv
->Y
+ (i
->pv
->Thickness
+ 1 + Bloat
) / 2;
679 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, polygon
)
680 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
683 else if (TEST_FLAG (OCTAGONFLAG
, i
->pv
))
685 POLYAREA
*oct
= OctagonPoly (i
->pv
->X
, i
->pv
->Y
, i
->pv
->Thickness
/ 2);
686 if (isects (oct
, polygon
, true)
687 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
690 else if (IsPointInPolygon (i
->pv
->X
, i
->pv
->Y
, wide
,
692 && ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
698 /* ---------------------------------------------------------------------------
699 * checks if a PV is connected to LOs, if it is, the LO is added to
700 * the appropriate list and the 'used' flag is set
703 LookupLOConnectionsToPVList (int flag
, bool AndRats
)
710 /* loop over all PVs currently on list */
711 while (PVList
.Location
< PVList
.Number
)
715 /* get pointer to data */
716 info
.pv
= PVLIST_ENTRY (PVList
.Location
);
717 search_box
= expand_bounds (&info
.pv
->BoundingBox
);
720 if (setjmp (info
.env
) == 0)
721 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
722 LOCtoPVpad_callback
, &info
);
726 /* now all lines, arcs and polygons of the several layers */
727 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
729 LayerType
*layer
= LAYER_PTR (layer_no
);
734 info
.layer
= layer_no
;
736 /* add touching lines */
737 if (setjmp (info
.env
) == 0)
738 r_search (layer
->line_tree
, &search_box
,
739 NULL
, LOCtoPVline_callback
, &info
);
742 /* add touching arcs */
743 if (setjmp (info
.env
) == 0)
744 r_search (layer
->arc_tree
, &search_box
,
745 NULL
, LOCtoPVarc_callback
, &info
);
748 /* check all polygons */
749 if (setjmp (info
.env
) == 0)
750 r_search (layer
->polygon_tree
, &search_box
,
751 NULL
, LOCtoPVpoly_callback
, &info
);
755 /* Check for rat-lines that may intersect the PV */
758 if (setjmp (info
.env
) == 0)
759 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
760 LOCtoPVrat_callback
, &info
);
769 /* ---------------------------------------------------------------------------
770 * find all connections between LO at the current list position and new LOs
773 LookupLOConnectionsToLOList (int flag
, bool AndRats
)
776 Cardinal i
, group
, layer
, ratposition
,
777 lineposition
[MAX_LAYER
],
778 polyposition
[MAX_LAYER
], arcposition
[MAX_LAYER
], padposition
[2];
780 /* copy the current LO list positions; the original data is changed
781 * by 'LookupPVConnectionsToLOList()' which has to check the same
782 * list entries plus the new ones
784 for (i
= 0; i
< max_copper_layer
; i
++)
786 lineposition
[i
] = LineList
[i
].Location
;
787 polyposition
[i
] = PolygonList
[i
].Location
;
788 arcposition
[i
] = ArcList
[i
].Location
;
790 for (i
= 0; i
< 2; i
++)
791 padposition
[i
] = PadList
[i
].Location
;
792 ratposition
= RatList
.Location
;
794 /* loop over all new LOs in the list; recurse until no
795 * more new connections in the layergroup were found
803 position
= &ratposition
;
804 for (; *position
< RatList
.Number
; (*position
)++)
806 group
= RATLIST_ENTRY (*position
)->group1
;
807 if (LookupLOConnectionsToRatEnd
808 (&(RATLIST_ENTRY (*position
)->Point1
), group
, flag
))
810 group
= RATLIST_ENTRY (*position
)->group2
;
811 if (LookupLOConnectionsToRatEnd
812 (&(RATLIST_ENTRY (*position
)->Point2
), group
, flag
))
816 /* loop over all layergroups */
817 for (group
= 0; group
< max_group
; group
++)
821 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[group
]; entry
++)
823 layer
= PCB
->LayerGroups
.Entries
[group
][entry
];
825 /* be aware that the layer number equal max_copper_layer
826 * and max_copper_layer+1 have a special meaning for pads
828 if (layer
< max_copper_layer
)
830 /* try all new lines */
831 position
= &lineposition
[layer
];
832 for (; *position
< LineList
[layer
].Number
; (*position
)++)
833 if (LookupLOConnectionsToLine
834 (LINELIST_ENTRY (layer
, *position
), group
, flag
, true, AndRats
))
837 /* try all new arcs */
838 position
= &arcposition
[layer
];
839 for (; *position
< ArcList
[layer
].Number
; (*position
)++)
840 if (LookupLOConnectionsToArc
841 (ARCLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
844 /* try all new polygons */
845 position
= &polyposition
[layer
];
846 for (; *position
< PolygonList
[layer
].Number
; (*position
)++)
847 if (LookupLOConnectionsToPolygon
848 (POLYGONLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
853 /* try all new pads */
854 layer
-= max_copper_layer
;
857 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
858 layer
, max_copper_layer
);
861 position
= &padposition
[layer
];
862 for (; *position
< PadList
[layer
].Number
; (*position
)++)
863 if (LookupLOConnectionsToPad
864 (PADLIST_ENTRY (layer
, *position
), group
, flag
, AndRats
))
870 /* check if all lists are done; Later for-loops
871 * may have changed the prior lists
873 done
= !AndRats
|| ratposition
>= RatList
.Number
;
874 done
= done
&& padposition
[0] >= PadList
[0].Number
&&
875 padposition
[1] >= PadList
[1].Number
;
876 for (layer
= 0; layer
< max_copper_layer
; layer
++)
878 lineposition
[layer
] >= LineList
[layer
].Number
&&
879 arcposition
[layer
] >= ArcList
[layer
].Number
&&
880 polyposition
[layer
] >= PolygonList
[layer
].Number
;
887 pv_pv_callback (const BoxType
* b
, void *cl
)
889 PinType
*pin
= (PinType
*) b
;
890 struct pv_info
*i
= (struct pv_info
*) cl
;
892 if (!TEST_FLAG (i
->flag
, pin
) && PV_TOUCH_PV (i
->pv
, pin
))
894 if (TEST_FLAG (HOLEFLAG
, pin
) || TEST_FLAG (HOLEFLAG
, i
->pv
))
896 SET_FLAG (WARNFLAG
, pin
);
897 Settings
.RatWarn
= true;
899 Message (_("WARNING: Hole too close to pin.\n"));
901 Message (_("WARNING: Hole too close to via.\n"));
903 else if (ADD_PV_TO_LIST (pin
, i
->flag
))
909 /* ---------------------------------------------------------------------------
910 * searches for new PVs that are connected to PVs on the list
913 LookupPVConnectionsToPVList (int flag
)
920 /* loop over all PVs on list */
921 save_place
= PVList
.Location
;
922 while (PVList
.Location
< PVList
.Number
)
926 /* get pointer to data */
927 info
.pv
= PVLIST_ENTRY (PVList
.Location
);
928 search_box
= expand_bounds ((BoxType
*)info
.pv
);
930 if (setjmp (info
.env
) == 0)
931 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
932 pv_pv_callback
, &info
);
935 if (setjmp (info
.env
) == 0)
936 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
937 pv_pv_callback
, &info
);
942 PVList
.Location
= save_place
;
952 PolygonType
*polygon
;
959 pv_line_callback (const BoxType
* b
, void *cl
)
961 PinType
*pv
= (PinType
*) b
;
962 struct lo_info
*i
= (struct lo_info
*) cl
;
964 if (!TEST_FLAG (i
->flag
, pv
) && PinLineIntersect (pv
, i
->line
))
966 if (TEST_FLAG (HOLEFLAG
, pv
))
968 SET_FLAG (WARNFLAG
, pv
);
969 Settings
.RatWarn
= true;
970 Message (_("WARNING: Hole too close to line.\n"));
972 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
979 pv_pad_callback (const BoxType
* b
, void *cl
)
981 PinType
*pv
= (PinType
*) b
;
982 struct lo_info
*i
= (struct lo_info
*) cl
;
984 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_PAD (pv
, i
->pad
))
986 if (TEST_FLAG (HOLEFLAG
, pv
))
988 SET_FLAG (WARNFLAG
, pv
);
989 Settings
.RatWarn
= true;
990 Message (_("WARNING: Hole too close to pad.\n"));
992 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
999 pv_arc_callback (const BoxType
* b
, void *cl
)
1001 PinType
*pv
= (PinType
*) b
;
1002 struct lo_info
*i
= (struct lo_info
*) cl
;
1004 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_ARC (pv
, i
->arc
))
1006 if (TEST_FLAG (HOLEFLAG
, pv
))
1008 SET_FLAG (WARNFLAG
, pv
);
1009 Settings
.RatWarn
= true;
1010 Message (_("WARNING: Hole touches arc.\n"));
1012 else if (ADD_PV_TO_LIST (pv
, i
->flag
))
1013 longjmp (i
->env
, 1);
1019 pv_poly_callback (const BoxType
* b
, void *cl
)
1021 PinType
*pv
= (PinType
*) b
;
1022 struct lo_info
*i
= (struct lo_info
*) cl
;
1024 /* note that holes in polygons are ok, so they don't generate warnings. */
1025 if (!TEST_FLAG (i
->flag
, pv
) && !TEST_FLAG (HOLEFLAG
, pv
) &&
1026 (TEST_THERM (i
->layer
, pv
) ||
1027 !TEST_FLAG (CLEARPOLYFLAG
, i
->polygon
) ||
1030 if (TEST_FLAG (SQUAREFLAG
, pv
))
1032 Coord x1
, x2
, y1
, y2
;
1033 x1
= pv
->X
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1034 x2
= pv
->X
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1035 y1
= pv
->Y
- (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1036 y2
= pv
->Y
+ (PIN_SIZE (pv
) + 1 + Bloat
) / 2;
1037 if (IsRectangleInPolygon (x1
, y1
, x2
, y2
, i
->polygon
)
1038 && ADD_PV_TO_LIST (pv
, i
->flag
))
1039 longjmp (i
->env
, 1);
1041 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
1043 POLYAREA
*oct
= OctagonPoly (pv
->X
, pv
->Y
, PIN_SIZE (pv
) / 2);
1044 if (isects (oct
, i
->polygon
, true) && ADD_PV_TO_LIST (pv
, i
->flag
))
1045 longjmp (i
->env
, 1);
1049 if (IsPointInPolygon
1050 (pv
->X
, pv
->Y
, PIN_SIZE (pv
) * 0.5 + Bloat
, i
->polygon
)
1051 && ADD_PV_TO_LIST (pv
, i
->flag
))
1052 longjmp (i
->env
, 1);
1059 pv_rat_callback (const BoxType
* b
, void *cl
)
1061 PinType
*pv
= (PinType
*) b
;
1062 struct lo_info
*i
= (struct lo_info
*) cl
;
1064 /* rats can't cause DRC so there is no early exit */
1065 if (!TEST_FLAG (i
->flag
, pv
) && IS_PV_ON_RAT (pv
, i
->rat
))
1066 ADD_PV_TO_LIST (pv
, i
->flag
);
1070 /* ---------------------------------------------------------------------------
1071 * searches for new PVs that are connected to NEW LOs on the list
1072 * This routine updates the position counter of the lists too.
1075 LookupPVConnectionsToLOList (int flag
, bool AndRats
)
1078 struct lo_info info
;
1082 /* loop over all layers */
1083 for (layer_no
= 0; layer_no
< max_copper_layer
; layer_no
++)
1085 LayerType
*layer
= LAYER_PTR (layer_no
);
1089 /* do nothing if there are no PV's */
1090 if (TotalP
+ TotalV
== 0)
1092 LineList
[layer_no
].Location
= LineList
[layer_no
].Number
;
1093 ArcList
[layer_no
].Location
= ArcList
[layer_no
].Number
;
1094 PolygonList
[layer_no
].Location
= PolygonList
[layer_no
].Number
;
1098 /* check all lines */
1099 while (LineList
[layer_no
].Location
< LineList
[layer_no
].Number
)
1103 info
.line
= LINELIST_ENTRY (layer_no
, LineList
[layer_no
].Location
);
1104 search_box
= expand_bounds ((BoxType
*)info
.line
);
1106 if (setjmp (info
.env
) == 0)
1107 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1108 pv_line_callback
, &info
);
1111 if (setjmp (info
.env
) == 0)
1112 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1113 pv_line_callback
, &info
);
1116 LineList
[layer_no
].Location
++;
1119 /* check all arcs */
1120 while (ArcList
[layer_no
].Location
< ArcList
[layer_no
].Number
)
1124 info
.arc
= ARCLIST_ENTRY (layer_no
, ArcList
[layer_no
].Location
);
1125 search_box
= expand_bounds ((BoxType
*)info
.arc
);
1127 if (setjmp (info
.env
) == 0)
1128 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1129 pv_arc_callback
, &info
);
1132 if (setjmp (info
.env
) == 0)
1133 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1134 pv_arc_callback
, &info
);
1137 ArcList
[layer_no
].Location
++;
1140 /* now all polygons */
1141 info
.layer
= layer_no
;
1142 while (PolygonList
[layer_no
].Location
< PolygonList
[layer_no
].Number
)
1146 info
.polygon
= POLYGONLIST_ENTRY (layer_no
, PolygonList
[layer_no
].Location
);
1147 search_box
= expand_bounds ((BoxType
*)info
.polygon
);
1149 if (setjmp (info
.env
) == 0)
1150 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1151 pv_poly_callback
, &info
);
1154 if (setjmp (info
.env
) == 0)
1155 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1156 pv_poly_callback
, &info
);
1159 PolygonList
[layer_no
].Location
++;
1163 /* loop over all pad-layers */
1164 for (layer_no
= 0; layer_no
< 2; layer_no
++)
1166 /* do nothing if there are no PV's */
1167 if (TotalP
+ TotalV
== 0)
1169 PadList
[layer_no
].Location
= PadList
[layer_no
].Number
;
1173 /* check all pads; for a detailed description see
1174 * the handling of lines in this subroutine
1176 while (PadList
[layer_no
].Location
< PadList
[layer_no
].Number
)
1180 info
.pad
= PADLIST_ENTRY (layer_no
, PadList
[layer_no
].Location
);
1181 search_box
= expand_bounds ((BoxType
*)info
.pad
);
1183 if (setjmp (info
.env
) == 0)
1184 r_search (PCB
->Data
->via_tree
, &search_box
, NULL
,
1185 pv_pad_callback
, &info
);
1188 if (setjmp (info
.env
) == 0)
1189 r_search (PCB
->Data
->pin_tree
, &search_box
, NULL
,
1190 pv_pad_callback
, &info
);
1193 PadList
[layer_no
].Location
++;
1197 /* do nothing if there are no PV's */
1198 if (TotalP
+ TotalV
== 0)
1199 RatList
.Location
= RatList
.Number
;
1201 /* check all rat-lines */
1204 while (RatList
.Location
< RatList
.Number
)
1206 info
.rat
= RATLIST_ENTRY (RatList
.Location
);
1207 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
->Point1
, 1, NULL
,
1208 pv_rat_callback
, &info
);
1209 r_search_pt (PCB
->Data
->via_tree
, & info
.rat
->Point2
, 1, NULL
,
1210 pv_rat_callback
, &info
);
1211 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
->Point1
, 1, NULL
,
1212 pv_rat_callback
, &info
);
1213 r_search_pt (PCB
->Data
->pin_tree
, & info
.rat
->Point2
, 1, NULL
,
1214 pv_rat_callback
, &info
);
1222 /* reduce arc start angle and delta to 0..360 */
1224 normalize_angles (Angle
*sa
, Angle
*d
)
1231 if (*d
> 360) /* full circle */
1233 *sa
= NormalizeAngle (*sa
);
1237 radius_crosses_arc (double x
, double y
, ArcType
*arc
)
1239 double alpha
= atan2 (y
- arc
->Y
, -x
+ arc
->X
) * RAD_TO_DEG
;
1240 Angle sa
= arc
->StartAngle
, d
= arc
->Delta
;
1242 normalize_angles (&sa
, &d
);
1246 return (sa
+ d
) >= alpha
;
1247 return (sa
+ d
- 360) >= alpha
;
1251 get_arc_ends (Coord
*box
, ArcType
*arc
)
1253 box
[0] = arc
->X
- arc
->Width
* cos (M180
* arc
->StartAngle
);
1254 box
[1] = arc
->Y
+ arc
->Height
* sin (M180
* arc
->StartAngle
);
1255 box
[2] = arc
->X
- arc
->Width
* cos (M180
* (arc
->StartAngle
+ arc
->Delta
));
1256 box
[3] = arc
->Y
+ arc
->Height
* sin (M180
* (arc
->StartAngle
+ arc
->Delta
));
1258 /* ---------------------------------------------------------------------------
1259 * check if two arcs intersect
1260 * first we check for circle intersections,
1261 * then find the actual points of intersection
1262 * and test them to see if they are on arcs
1264 * consider a, the distance from the center of arc 1
1265 * to the point perpendicular to the intersecting points.
1267 * a = (r1^2 - r2^2 + l^2)/(2l)
1269 * the perpendicular distance to the point of intersection
1272 * d = sqrt(r1^2 - a^2)
1274 * the points of intersection would then be
1276 * x = X1 + a/l dx +- d/l dy
1277 * y = Y1 + a/l dy -+ d/l dx
1279 * where dx = X2 - X1 and dy = Y2 - Y1
1284 ArcArcIntersect (ArcType
*Arc1
, ArcType
*Arc2
)
1286 double x
, y
, dx
, dy
, r1
, r2
, a
, d
, l
, t
, t1
, t2
, dl
;
1290 t
= 0.5 * Arc1
->Thickness
+ Bloat
;
1291 t2
= 0.5 * Arc2
->Thickness
;
1295 if (t
< 0 || t1
< 0)
1298 /* try the end points first */
1299 get_arc_ends (&box
[0], Arc1
);
1300 get_arc_ends (&box
[4], Arc2
);
1301 if (IsPointOnArc (box
[0], box
[1], t
, Arc2
)
1302 || IsPointOnArc (box
[2], box
[3], t
, Arc2
)
1303 || IsPointOnArc (box
[4], box
[5], t
, Arc1
)
1304 || IsPointOnArc (box
[6], box
[7], t
, Arc1
))
1307 pdx
= Arc2
->X
- Arc1
->X
;
1308 pdy
= Arc2
->Y
- Arc1
->Y
;
1309 dl
= Distance (Arc1
->X
, Arc1
->Y
, Arc2
->X
, Arc2
->Y
);
1310 /* concentric arcs, simpler intersection conditions */
1313 if ((Arc1
->Width
- t
>= Arc2
->Width
- t2
1314 && Arc1
->Width
- t
<= Arc2
->Width
+ t2
)
1315 || (Arc1
->Width
+ t
>= Arc2
->Width
- t2
1316 && Arc1
->Width
+ t
<= Arc2
->Width
+ t2
))
1318 Angle sa1
= Arc1
->StartAngle
, d1
= Arc1
->Delta
;
1319 Angle sa2
= Arc2
->StartAngle
, d2
= Arc2
->Delta
;
1320 /* NB the endpoints have already been checked,
1321 so we just compare the angles */
1323 normalize_angles (&sa1
, &d1
);
1324 normalize_angles (&sa2
, &d2
);
1325 /* sa1 == sa2 was caught when checking endpoints */
1327 if (sa1
< sa2
+ d2
|| sa1
+ d1
- 360 > sa2
)
1330 if (sa2
< sa1
+ d1
|| sa2
+ d2
- 360 > sa1
)
1337 /* arcs centerlines are too far or too near */
1338 if (dl
> r1
+ r2
|| dl
+ r1
< r2
|| dl
+ r2
< r1
)
1340 /* check the nearest to the other arc's center point */
1343 if (dl
+ r1
< r2
) /* Arc1 inside Arc2 */
1349 if (radius_crosses_arc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, Arc1
)
1350 && IsPointOnArc (Arc1
->X
+ dx
, Arc1
->Y
+ dy
, t
, Arc2
))
1353 dx
= - pdx
* r2
/ dl
;
1354 dy
= - pdy
* r2
/ dl
;
1355 if (dl
+ r2
< r1
) /* Arc2 inside Arc1 */
1361 if (radius_crosses_arc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, Arc2
)
1362 && IsPointOnArc (Arc2
->X
+ dx
, Arc2
->Y
+ dy
, t1
, Arc1
))
1370 a
= 0.5 * (r1
- r2
+ l
) / l
;
1373 /* the circles are too far apart to touch or probably just touch:
1374 check the nearest point */
1379 x
= Arc1
->X
+ a
* pdx
;
1380 y
= Arc1
->Y
+ a
* pdy
;
1383 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc1
)
1384 && IsPointOnArc (x
+ dy
, y
- dx
, t
, Arc2
))
1386 if (radius_crosses_arc (x
+ dy
, y
- dx
, Arc2
)
1387 && IsPointOnArc (x
+ dy
, y
- dx
, t1
, Arc1
))
1390 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc1
)
1391 && IsPointOnArc (x
- dy
, y
+ dx
, t
, Arc2
))
1393 if (radius_crosses_arc (x
- dy
, y
+ dx
, Arc2
)
1394 && IsPointOnArc (x
- dy
, y
+ dx
, t1
, Arc1
))
1399 /* ---------------------------------------------------------------------------
1400 * Tests if point is same as line end point
1403 IsRatPointOnLineEnd (PointType
*Point
, LineType
*Line
)
1405 if ((Point
->X
== Line
->Point1
.X
1406 && Point
->Y
== Line
->Point1
.Y
)
1407 || (Point
->X
== Line
->Point2
.X
&& Point
->Y
== Line
->Point2
.Y
))
1413 form_slanted_rectangle (PointType p
[4], LineType
*l
)
1414 /* writes vertices of a squared line */
1416 double dwx
= 0, dwy
= 0;
1417 if (l
->Point1
.Y
== l
->Point2
.Y
)
1418 dwx
= l
->Thickness
/ 2.0;
1419 else if (l
->Point1
.X
== l
->Point2
.X
)
1420 dwy
= l
->Thickness
/ 2.0;
1423 Coord dX
= l
->Point2
.X
- l
->Point1
.X
;
1424 Coord dY
= l
->Point2
.Y
- l
->Point1
.Y
;
1425 double r
= Distance (l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1426 dwx
= l
->Thickness
/ 2.0 / r
* dX
;
1427 dwy
= l
->Thickness
/ 2.0 / r
* dY
;
1429 p
[0].X
= l
->Point1
.X
- dwx
+ dwy
; p
[0].Y
= l
->Point1
.Y
- dwy
- dwx
;
1430 p
[1].X
= l
->Point1
.X
- dwx
- dwy
; p
[1].Y
= l
->Point1
.Y
- dwy
+ dwx
;
1431 p
[2].X
= l
->Point2
.X
+ dwx
- dwy
; p
[2].Y
= l
->Point2
.Y
+ dwy
+ dwx
;
1432 p
[3].X
= l
->Point2
.X
+ dwx
+ dwy
; p
[3].Y
= l
->Point2
.Y
+ dwy
- dwx
;
1434 /* ---------------------------------------------------------------------------
1435 * checks if two lines intersect
1438 * Let A,B,C,D be 2-space position vectors. Then the directed line
1439 * segments AB & CD are given by:
1441 * AB=A+r(B-A), r in [0,1]
1442 * CD=C+s(D-C), s in [0,1]
1444 * If AB & CD intersect, then
1446 * A+r(B-A)=C+s(D-C), or
1448 * XA+r(XB-XA)=XC+s(XD-XC)
1449 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1451 * Solving the above for r and s yields
1453 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1454 * r = ----------------------------- (eqn 1)
1455 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1457 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1458 * s = ----------------------------- (eqn 2)
1459 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1461 * Let I be the position vector of the intersection point, then
1468 * By examining the values of r & s, you can also determine some
1469 * other limiting conditions:
1471 * If 0<=r<=1 & 0<=s<=1, intersection exists
1472 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1474 * If the denominator in eqn 1 is zero, AB & CD are parallel
1475 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1477 * If the intersection point of the 2 lines are needed (lines in this
1478 * context mean infinite lines) regardless whether the two line
1479 * segments intersect, then
1481 * If r>1, I is located on extension of AB
1482 * If r<0, I is located on extension of BA
1483 * If s>1, I is located on extension of CD
1484 * If s<0, I is located on extension of DC
1486 * Also note that the denominators of eqn 1 & 2 are identical.
1490 LineLineIntersect (LineType
*Line1
, LineType
*Line2
)
1493 double line1_dx
, line1_dy
, line2_dx
, line2_dy
,
1494 point1_dx
, point1_dy
;
1495 if (TEST_FLAG (SQUAREFLAG
, Line1
))/* pretty reckless recursion */
1498 form_slanted_rectangle (p
, Line1
);
1499 return IsLineInQuadrangle (p
, Line2
);
1501 /* here come only round Line1 because IsLineInQuadrangle()
1502 calls LineLineIntersect() with first argument rounded*/
1503 if (TEST_FLAG (SQUAREFLAG
, Line2
))
1506 form_slanted_rectangle (p
, Line2
);
1507 return IsLineInQuadrangle (p
, Line1
);
1509 /* now all lines are round */
1511 /* Check endpoints: this provides a quick exit, catches
1512 * cases where the "real" lines don't intersect but the
1513 * thick lines touch, and ensures that the dx/dy business
1514 * below does not cause a divide-by-zero. */
1515 if (IsPointInPad (Line2
->Point1
.X
, Line2
->Point1
.Y
,
1516 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1518 || IsPointInPad (Line2
->Point2
.X
, Line2
->Point2
.Y
,
1519 MAX (Line2
->Thickness
/ 2 + Bloat
, 0),
1521 || IsPointInPad (Line1
->Point1
.X
, Line1
->Point1
.Y
,
1522 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1524 || IsPointInPad (Line1
->Point2
.X
, Line1
->Point2
.Y
,
1525 MAX (Line1
->Thickness
/ 2 + Bloat
, 0),
1529 /* setup some constants */
1530 line1_dx
= Line1
->Point2
.X
- Line1
->Point1
.X
;
1531 line1_dy
= Line1
->Point2
.Y
- Line1
->Point1
.Y
;
1532 line2_dx
= Line2
->Point2
.X
- Line2
->Point1
.X
;
1533 line2_dy
= Line2
->Point2
.Y
- Line2
->Point1
.Y
;
1534 point1_dx
= Line1
->Point1
.X
- Line2
->Point1
.X
;
1535 point1_dy
= Line1
->Point1
.Y
- Line2
->Point1
.Y
;
1537 /* If either line is a point, we have failed already, since the
1538 * endpoint check above will have caught an "intersection". */
1539 if ((line1_dx
== 0 && line1_dy
== 0)
1540 || (line2_dx
== 0 && line2_dy
== 0))
1543 /* set s to cross product of Line1 and the line
1544 * Line1.Point1--Line2.Point1 (as vectors) */
1545 s
= point1_dy
* line1_dx
- point1_dx
* line1_dy
;
1547 /* set r to cross product of both lines (as vectors) */
1548 r
= line1_dx
* line2_dy
- line1_dy
* line2_dx
;
1550 /* No cross product means parallel lines, or maybe Line2 is
1551 * zero-length. In either case, since we did a bounding-box
1552 * check before getting here, the above IsPointInPad() checks
1553 * will have caught any intersections. */
1558 r
= (point1_dy
* line2_dx
- point1_dx
* line2_dy
) / r
;
1560 /* intersection is at least on AB */
1561 if (r
>= 0.0 && r
<= 1.0)
1562 return (s
>= 0.0 && s
<= 1.0);
1564 /* intersection is at least on CD */
1565 /* [removed this case since it always returns false --asp] */
1569 /*---------------------------------------------------
1571 * Check for line intersection with an arc
1573 * Mostly this is like the circle/line intersection
1574 * found in IsPointOnLine (search.c) see the detailed
1575 * discussion for the basics there.
1577 * Since this is only an arc, not a full circle we need
1578 * to find the actual points of intersection with the
1579 * circle, and see if they are on the arc.
1581 * To do this, we translate along the line from the point Q
1582 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1583 * but it's handy to normalize with respect to l, the line
1584 * length so a single projection is done (e.g. we don't first
1587 * The projection is now of the form
1589 * Px = X1 + (r +- r2)(X2 - X1)
1590 * Py = Y1 + (r +- r2)(Y2 - Y1)
1592 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1593 * note that this is the variable d, not the symbol d described in IsPointOnLine
1594 * (variable d = symbol d * l)
1596 * The end points are hell so they are checked individually
1599 LineArcIntersect (LineType
*Line
, ArcType
*Arc
)
1601 double dx
, dy
, dx1
, dy1
, l
, d
, r
, r2
, Radius
;
1604 dx
= Line
->Point2
.X
- Line
->Point1
.X
;
1605 dy
= Line
->Point2
.Y
- Line
->Point1
.Y
;
1606 dx1
= Line
->Point1
.X
- Arc
->X
;
1607 dy1
= Line
->Point1
.Y
- Arc
->Y
;
1608 l
= dx
* dx
+ dy
* dy
;
1609 d
= dx
* dy1
- dy
* dx1
;
1612 /* use the larger diameter circle first */
1614 Arc
->Width
+ MAX (0.5 * (Arc
->Thickness
+ Line
->Thickness
) + Bloat
, 0.0);
1616 r2
= Radius
* l
- d
;
1617 /* projection doesn't even intersect circle when r2 < 0 */
1620 /* check the ends of the line in case the projected point */
1621 /* of intersection is beyond the line end */
1623 (Line
->Point1
.X
, Line
->Point1
.Y
,
1624 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1627 (Line
->Point2
.X
, Line
->Point2
.Y
,
1628 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1633 Radius
= -(dx
* dx1
+ dy
* dy1
);
1634 r
= (Radius
+ r2
) / l
;
1635 if (r
>= 0 && r
<= 1
1636 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1637 Line
->Point1
.Y
+ r
* dy
,
1638 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1640 r
= (Radius
- r2
) / l
;
1641 if (r
>= 0 && r
<= 1
1642 && IsPointOnArc (Line
->Point1
.X
+ r
* dx
,
1643 Line
->Point1
.Y
+ r
* dy
,
1644 MAX (0.5 * Line
->Thickness
+ Bloat
, 0.0), Arc
))
1646 /* check arc end points */
1647 box
= GetArcEnds (Arc
);
1648 if (IsPointInPad (box
->X1
, box
->Y1
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1650 if (IsPointInPad (box
->X2
, box
->Y2
, Arc
->Thickness
* 0.5 + Bloat
, (PadType
*)Line
))
1656 LOCtoArcLine_callback (const BoxType
* b
, void *cl
)
1658 LineType
*line
= (LineType
*) b
;
1659 struct lo_info
*i
= (struct lo_info
*) cl
;
1661 if (!TEST_FLAG (i
->flag
, line
) && LineArcIntersect (line
, i
->arc
))
1663 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1664 longjmp (i
->env
, 1);
1670 LOCtoArcArc_callback (const BoxType
* b
, void *cl
)
1672 ArcType
*arc
= (ArcType
*) b
;
1673 struct lo_info
*i
= (struct lo_info
*) cl
;
1675 if (!arc
->Thickness
)
1677 if (!TEST_FLAG (i
->flag
, arc
) && ArcArcIntersect (i
->arc
, arc
))
1679 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
1680 longjmp (i
->env
, 1);
1686 LOCtoArcPad_callback (const BoxType
* b
, void *cl
)
1688 PadType
*pad
= (PadType
*) b
;
1689 struct lo_info
*i
= (struct lo_info
*) cl
;
1691 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1692 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
)
1693 && ArcPadIntersect (i
->arc
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1694 longjmp (i
->env
, 1);
1698 /* ---------------------------------------------------------------------------
1699 * searches all LOs that are connected to the given arc on the given
1700 * layergroup. All found connections are added to the list
1702 * the notation that is used is:
1703 * Xij means Xj at arc i
1706 LookupLOConnectionsToArc (ArcType
*Arc
, Cardinal LayerGroup
, int flag
, bool AndRats
)
1709 struct lo_info info
;
1714 search_box
= expand_bounds ((BoxType
*)info
.arc
);
1716 /* loop over all layers of the group */
1717 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1723 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1724 layer
= LAYER_PTR (layer_no
);
1726 /* handle normal layers */
1727 if (layer_no
< max_copper_layer
)
1729 info
.layer
= layer_no
;
1731 if (setjmp (info
.env
) == 0)
1732 r_search (layer
->line_tree
, &search_box
,
1733 NULL
, LOCtoArcLine_callback
, &info
);
1737 if (setjmp (info
.env
) == 0)
1738 r_search (layer
->arc_tree
, &search_box
,
1739 NULL
, LOCtoArcArc_callback
, &info
);
1743 /* now check all polygons */
1744 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1746 PolygonType
*polygon
= i
->data
;
1747 if (!TEST_FLAG (flag
, polygon
) && IsArcInPolygon (Arc
, polygon
)
1748 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
1754 info
.layer
= layer_no
- max_copper_layer
;
1755 if (setjmp (info
.env
) == 0)
1756 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
1757 LOCtoArcPad_callback
, &info
);
1766 LOCtoLineLine_callback (const BoxType
* b
, void *cl
)
1768 LineType
*line
= (LineType
*) b
;
1769 struct lo_info
*i
= (struct lo_info
*) cl
;
1771 if (!TEST_FLAG (i
->flag
, line
) && LineLineIntersect (i
->line
, line
))
1773 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1774 longjmp (i
->env
, 1);
1780 LOCtoLineArc_callback (const BoxType
* b
, void *cl
)
1782 ArcType
*arc
= (ArcType
*) b
;
1783 struct lo_info
*i
= (struct lo_info
*) cl
;
1785 if (!arc
->Thickness
)
1787 if (!TEST_FLAG (i
->flag
, arc
) && LineArcIntersect (i
->line
, arc
))
1789 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
1790 longjmp (i
->env
, 1);
1796 LOCtoLineRat_callback (const BoxType
* b
, void *cl
)
1798 RatType
*rat
= (RatType
*) b
;
1799 struct lo_info
*i
= (struct lo_info
*) cl
;
1801 if (!TEST_FLAG (i
->flag
, rat
))
1803 if ((rat
->group1
== i
->layer
)
1804 && IsRatPointOnLineEnd (&rat
->Point1
, i
->line
))
1806 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
1807 longjmp (i
->env
, 1);
1809 else if ((rat
->group2
== i
->layer
)
1810 && IsRatPointOnLineEnd (&rat
->Point2
, i
->line
))
1812 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
1813 longjmp (i
->env
, 1);
1820 LOCtoLinePad_callback (const BoxType
* b
, void *cl
)
1822 PadType
*pad
= (PadType
*) b
;
1823 struct lo_info
*i
= (struct lo_info
*) cl
;
1825 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1826 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
)
1827 && LinePadIntersect (i
->line
, pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1828 longjmp (i
->env
, 1);
1832 /* ---------------------------------------------------------------------------
1833 * searches all LOs that are connected to the given line on the given
1834 * layergroup. All found connections are added to the list
1836 * the notation that is used is:
1837 * Xij means Xj at line i
1840 LookupLOConnectionsToLine (LineType
*Line
, Cardinal LayerGroup
,
1841 int flag
, bool PolysTo
, bool AndRats
)
1844 struct lo_info info
;
1848 info
.layer
= LayerGroup
;
1850 search_box
= expand_bounds ((BoxType
*)info
.line
);
1854 /* add the new rat lines */
1855 if (setjmp (info
.env
) == 0)
1856 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
1857 LOCtoLineRat_callback
, &info
);
1862 /* loop over all layers of the group */
1863 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1868 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1869 layer
= LAYER_PTR (layer_no
);
1871 /* handle normal layers */
1872 if (layer_no
< max_copper_layer
)
1874 info
.layer
= layer_no
;
1876 if (setjmp (info
.env
) == 0)
1877 r_search (layer
->line_tree
, &search_box
,
1878 NULL
, LOCtoLineLine_callback
, &info
);
1882 if (setjmp (info
.env
) == 0)
1883 r_search (layer
->arc_tree
, &search_box
,
1884 NULL
, LOCtoLineArc_callback
, &info
);
1887 /* now check all polygons */
1891 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
1893 PolygonType
*polygon
= i
->data
;
1894 if (!TEST_FLAG (flag
, polygon
) && IsLineInPolygon (Line
, polygon
)
1895 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
1902 /* handle special 'pad' layers */
1903 info
.layer
= layer_no
- max_copper_layer
;
1904 if (setjmp (info
.env
) == 0)
1905 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
1906 LOCtoLinePad_callback
, &info
);
1923 LOCtoRat_callback (const BoxType
* b
, void *cl
)
1925 LineType
*line
= (LineType
*) b
;
1926 struct rat_info
*i
= (struct rat_info
*) cl
;
1928 if (!TEST_FLAG (i
->flag
, line
) &&
1929 ((line
->Point1
.X
== i
->Point
->X
&&
1930 line
->Point1
.Y
== i
->Point
->Y
) ||
1931 (line
->Point2
.X
== i
->Point
->X
&& line
->Point2
.Y
== i
->Point
->Y
)))
1933 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
1934 longjmp (i
->env
, 1);
1939 PolygonToRat_callback (const BoxType
* b
, void *cl
)
1941 PolygonType
*polygon
= (PolygonType
*) b
;
1942 struct rat_info
*i
= (struct rat_info
*) cl
;
1944 if (!TEST_FLAG (i
->flag
, polygon
) && polygon
->Clipped
&&
1945 (i
->Point
->X
== polygon
->Clipped
->contours
->head
.point
[0]) &&
1946 (i
->Point
->Y
== polygon
->Clipped
->contours
->head
.point
[1]))
1948 if (ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
1949 longjmp (i
->env
, 1);
1955 LOCtoPad_callback (const BoxType
* b
, void *cl
)
1957 PadType
*pad
= (PadType
*) b
;
1958 struct rat_info
*i
= (struct rat_info
*) cl
;
1960 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
1961 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
) &&
1962 ((pad
->Point1
.X
== i
->Point
->X
&& pad
->Point1
.Y
== i
->Point
->Y
) ||
1963 (pad
->Point2
.X
== i
->Point
->X
&& pad
->Point2
.Y
== i
->Point
->Y
) ||
1964 ((pad
->Point1
.X
+ pad
->Point2
.X
) / 2 == i
->Point
->X
&&
1965 (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2 == i
->Point
->Y
)) &&
1966 ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
1967 longjmp (i
->env
, 1);
1971 /* ---------------------------------------------------------------------------
1972 * searches all LOs that are connected to the given rat-line on the given
1973 * layergroup. All found connections are added to the list
1975 * the notation that is used is:
1976 * Xij means Xj at line i
1979 LookupLOConnectionsToRatEnd (PointType
*Point
, Cardinal LayerGroup
, int flag
)
1982 struct rat_info info
;
1986 /* loop over all layers of this group */
1987 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
1992 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
1993 layer
= LAYER_PTR (layer_no
);
1994 /* handle normal layers
1995 rats don't ever touch
1999 if (layer_no
< max_copper_layer
)
2001 info
.layer
= layer_no
;
2002 if (setjmp (info
.env
) == 0)
2003 r_search_pt (layer
->line_tree
, Point
, 1, NULL
,
2004 LOCtoRat_callback
, &info
);
2007 if (setjmp (info
.env
) == 0)
2008 r_search_pt (layer
->polygon_tree
, Point
, 1,
2009 NULL
, PolygonToRat_callback
, &info
);
2013 /* handle special 'pad' layers */
2014 info
.layer
= layer_no
- max_copper_layer
;
2015 if (setjmp (info
.env
) == 0)
2016 r_search_pt (PCB
->Data
->pad_tree
, Point
, 1, NULL
,
2017 LOCtoPad_callback
, &info
);
2026 LOCtoPadLine_callback (const BoxType
* b
, void *cl
)
2028 LineType
*line
= (LineType
*) b
;
2029 struct lo_info
*i
= (struct lo_info
*) cl
;
2031 if (!TEST_FLAG (i
->flag
, line
) && LinePadIntersect (line
, i
->pad
))
2033 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
2034 longjmp (i
->env
, 1);
2040 LOCtoPadArc_callback (const BoxType
* b
, void *cl
)
2042 ArcType
*arc
= (ArcType
*) b
;
2043 struct lo_info
*i
= (struct lo_info
*) cl
;
2045 if (!arc
->Thickness
)
2047 if (!TEST_FLAG (i
->flag
, arc
) && ArcPadIntersect (arc
, i
->pad
))
2049 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
2050 longjmp (i
->env
, 1);
2056 LOCtoPadPoly_callback (const BoxType
* b
, void *cl
)
2058 PolygonType
*polygon
= (PolygonType
*) b
;
2059 struct lo_info
*i
= (struct lo_info
*) cl
;
2062 if (!TEST_FLAG (i
->flag
, polygon
) &&
2063 (!TEST_FLAG (CLEARPOLYFLAG
, polygon
) || !i
->pad
->Clearance
))
2065 if (IsPadInPolygon (i
->pad
, polygon
) &&
2066 ADD_POLYGON_TO_LIST (i
->layer
, polygon
, i
->flag
))
2067 longjmp (i
->env
, 1);
2073 LOCtoPadRat_callback (const BoxType
* b
, void *cl
)
2075 RatType
*rat
= (RatType
*) b
;
2076 struct lo_info
*i
= (struct lo_info
*) cl
;
2078 if (!TEST_FLAG (i
->flag
, rat
))
2080 if (rat
->group1
== i
->layer
&&
2081 ((rat
->Point1
.X
== i
->pad
->Point1
.X
&& rat
->Point1
.Y
== i
->pad
->Point1
.Y
) ||
2082 (rat
->Point1
.X
== i
->pad
->Point2
.X
&& rat
->Point1
.Y
== i
->pad
->Point2
.Y
) ||
2083 (rat
->Point1
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
2084 rat
->Point1
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2)))
2086 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2087 longjmp (i
->env
, 1);
2089 else if (rat
->group2
== i
->layer
&&
2090 ((rat
->Point2
.X
== i
->pad
->Point1
.X
&& rat
->Point2
.Y
== i
->pad
->Point1
.Y
) ||
2091 (rat
->Point2
.X
== i
->pad
->Point2
.X
&& rat
->Point2
.Y
== i
->pad
->Point2
.Y
) ||
2092 (rat
->Point2
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
2093 rat
->Point2
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2)))
2095 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2096 longjmp (i
->env
, 1);
2103 LOCtoPadPad_callback (const BoxType
* b
, void *cl
)
2105 PadType
*pad
= (PadType
*) b
;
2106 struct lo_info
*i
= (struct lo_info
*) cl
;
2108 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
2109 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
)
2110 && PadPadIntersect (pad
, i
->pad
) && ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
2111 longjmp (i
->env
, 1);
2115 /* ---------------------------------------------------------------------------
2116 * searches all LOs that are connected to the given pad on the given
2117 * layergroup. All found connections are added to the list
2120 LookupLOConnectionsToPad (PadType
*Pad
, Cardinal LayerGroup
, int flag
, bool AndRats
)
2123 struct lo_info info
;
2126 if (!TEST_FLAG (SQUAREFLAG
, Pad
))
2127 return (LookupLOConnectionsToLine ((LineType
*) Pad
, LayerGroup
, flag
, false, AndRats
));
2131 search_box
= expand_bounds ((BoxType
*)info
.pad
);
2133 /* add the new rat lines */
2134 info
.layer
= LayerGroup
;
2138 if (setjmp (info
.env
) == 0)
2139 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
2140 LOCtoPadRat_callback
, &info
);
2145 /* loop over all layers of the group */
2146 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2151 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2152 layer
= LAYER_PTR (layer_no
);
2153 /* handle normal layers */
2154 if (layer_no
< max_copper_layer
)
2156 info
.layer
= layer_no
;
2158 if (setjmp (info
.env
) == 0)
2159 r_search (layer
->line_tree
, &search_box
,
2160 NULL
, LOCtoPadLine_callback
, &info
);
2164 if (setjmp (info
.env
) == 0)
2165 r_search (layer
->arc_tree
, &search_box
,
2166 NULL
, LOCtoPadArc_callback
, &info
);
2170 if (setjmp (info
.env
) == 0)
2171 r_search (layer
->polygon_tree
, &search_box
,
2172 NULL
, LOCtoPadPoly_callback
, &info
);
2178 /* handle special 'pad' layers */
2179 info
.layer
= layer_no
- max_copper_layer
;
2180 if (setjmp (info
.env
) == 0)
2181 r_search (PCB
->Data
->pad_tree
, &search_box
, NULL
,
2182 LOCtoPadPad_callback
, &info
);
2192 LOCtoPolyLine_callback (const BoxType
* b
, void *cl
)
2194 LineType
*line
= (LineType
*) b
;
2195 struct lo_info
*i
= (struct lo_info
*) cl
;
2197 if (!TEST_FLAG (i
->flag
, line
) && IsLineInPolygon (line
, i
->polygon
))
2199 if (ADD_LINE_TO_LIST (i
->layer
, line
, i
->flag
))
2200 longjmp (i
->env
, 1);
2206 LOCtoPolyArc_callback (const BoxType
* b
, void *cl
)
2208 ArcType
*arc
= (ArcType
*) b
;
2209 struct lo_info
*i
= (struct lo_info
*) cl
;
2211 if (!arc
->Thickness
)
2213 if (!TEST_FLAG (i
->flag
, arc
) && IsArcInPolygon (arc
, i
->polygon
))
2215 if (ADD_ARC_TO_LIST (i
->layer
, arc
, i
->flag
))
2216 longjmp (i
->env
, 1);
2222 LOCtoPolyPad_callback (const BoxType
* b
, void *cl
)
2224 PadType
*pad
= (PadType
*) b
;
2225 struct lo_info
*i
= (struct lo_info
*) cl
;
2227 if (!TEST_FLAG (i
->flag
, pad
) && i
->layer
==
2228 (TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
)
2229 && IsPadInPolygon (pad
, i
->polygon
))
2231 if (ADD_PAD_TO_LIST (i
->layer
, pad
, i
->flag
))
2232 longjmp (i
->env
, 1);
2238 LOCtoPolyRat_callback (const BoxType
* b
, void *cl
)
2240 RatType
*rat
= (RatType
*) b
;
2241 struct lo_info
*i
= (struct lo_info
*) cl
;
2243 if (!TEST_FLAG (i
->flag
, rat
))
2245 if ((rat
->Point1
.X
== (i
->polygon
->Clipped
->contours
->head
.point
[0]) &&
2246 rat
->Point1
.Y
== (i
->polygon
->Clipped
->contours
->head
.point
[1]) &&
2247 rat
->group1
== i
->layer
) ||
2248 (rat
->Point2
.X
== (i
->polygon
->Clipped
->contours
->head
.point
[0]) &&
2249 rat
->Point2
.Y
== (i
->polygon
->Clipped
->contours
->head
.point
[1]) &&
2250 rat
->group2
== i
->layer
))
2251 if (ADD_RAT_TO_LIST (rat
, i
->flag
))
2252 longjmp (i
->env
, 1);
2258 /* ---------------------------------------------------------------------------
2259 * looks up LOs that are connected to the given polygon
2260 * on the given layergroup. All found connections are added to the list
2263 LookupLOConnectionsToPolygon (PolygonType
*Polygon
, Cardinal LayerGroup
, int flag
, bool AndRats
)
2266 struct lo_info info
;
2269 if (!Polygon
->Clipped
)
2273 info
.polygon
= Polygon
;
2274 search_box
= expand_bounds ((BoxType
*)info
.polygon
);
2276 info
.layer
= LayerGroup
;
2281 if (setjmp (info
.env
) == 0)
2282 r_search (PCB
->Data
->rat_tree
, &search_box
, NULL
,
2283 LOCtoPolyRat_callback
, &info
);
2288 /* loop over all layers of the group */
2289 for (entry
= 0; entry
< PCB
->LayerGroups
.Number
[LayerGroup
]; entry
++)
2294 layer_no
= PCB
->LayerGroups
.Entries
[LayerGroup
][entry
];
2295 layer
= LAYER_PTR (layer_no
);
2297 /* handle normal layers */
2298 if (layer_no
< max_copper_layer
)
2302 /* check all polygons */
2303 for (i
= layer
->Polygon
; i
!= NULL
; i
= g_list_next (i
))
2305 PolygonType
*polygon
= i
->data
;
2306 if (!TEST_FLAG (flag
, polygon
)
2307 && IsPolygonInPolygon (polygon
, Polygon
)
2308 && ADD_POLYGON_TO_LIST (layer_no
, polygon
, flag
))
2312 info
.layer
= layer_no
;
2313 /* check all lines */
2314 if (setjmp (info
.env
) == 0)
2315 r_search (layer
->line_tree
, &search_box
,
2316 NULL
, LOCtoPolyLine_callback
, &info
);
2319 /* check all arcs */
2320 if (setjmp (info
.env
) == 0)
2321 r_search (layer
->arc_tree
, &search_box
,
2322 NULL
, LOCtoPolyArc_callback
, &info
);
2328 info
.layer
= layer_no
- max_copper_layer
;
2329 if (setjmp (info
.env
) == 0)
2330 r_search (PCB
->Data
->pad_tree
, &search_box
,
2331 NULL
, LOCtoPolyPad_callback
, &info
);
2339 /* ---------------------------------------------------------------------------
2340 * checks if an arc has a connection to a polygon
2342 * - first check if the arc can intersect with the polygon by
2343 * evaluating the bounding boxes
2344 * - check the two end points of the arc. If none of them matches
2345 * - check all segments of the polygon against the arc.
2348 IsArcInPolygon (ArcType
*Arc
, PolygonType
*Polygon
)
2350 BoxType
*Box
= (BoxType
*) Arc
;
2352 /* arcs with clearance never touch polys */
2353 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Arc
))
2355 if (!Polygon
->Clipped
)
2357 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2358 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2359 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2360 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2364 if (!(ap
= ArcPoly (Arc
, Arc
->Thickness
+ Bloat
)))
2365 return false; /* error */
2366 return isects (ap
, Polygon
, true);
2371 /* ---------------------------------------------------------------------------
2372 * checks if a line has a connection to a polygon
2374 * - first check if the line can intersect with the polygon by
2375 * evaluating the bounding boxes
2376 * - check the two end points of the line. If none of them matches
2377 * - check all segments of the polygon against the line.
2380 IsLineInPolygon (LineType
*Line
, PolygonType
*Polygon
)
2382 BoxType
*Box
= (BoxType
*) Line
;
2385 /* lines with clearance never touch polygons */
2386 if (TEST_FLAG (CLEARPOLYFLAG
, Polygon
) && TEST_FLAG (CLEARLINEFLAG
, Line
))
2388 if (!Polygon
->Clipped
)
2390 if (TEST_FLAG(SQUAREFLAG
,Line
)&&(Line
->Point1
.X
==Line
->Point2
.X
||Line
->Point1
.Y
==Line
->Point2
.Y
))
2392 Coord wid
= (Line
->Thickness
+ Bloat
+ 1) / 2;
2393 Coord x1
, x2
, y1
, y2
;
2395 x1
= MIN (Line
->Point1
.X
, Line
->Point2
.X
) - wid
;
2396 y1
= MIN (Line
->Point1
.Y
, Line
->Point2
.Y
) - wid
;
2397 x2
= MAX (Line
->Point1
.X
, Line
->Point2
.X
) + wid
;
2398 y2
= MAX (Line
->Point1
.Y
, Line
->Point2
.Y
) + wid
;
2399 return IsRectangleInPolygon (x1
, y1
, x2
, y2
, Polygon
);
2401 if (Box
->X1
<= Polygon
->Clipped
->contours
->xmax
+ Bloat
2402 && Box
->X2
>= Polygon
->Clipped
->contours
->xmin
- Bloat
2403 && Box
->Y1
<= Polygon
->Clipped
->contours
->ymax
+ Bloat
2404 && Box
->Y2
>= Polygon
->Clipped
->contours
->ymin
- Bloat
)
2406 if (!(lp
= LinePoly (Line
, Line
->Thickness
+ Bloat
)))
2407 return FALSE
; /* error */
2408 return isects (lp
, Polygon
, true);
2413 /* ---------------------------------------------------------------------------
2414 * checks if a pad connects to a non-clearing polygon
2416 * The polygon is assumed to already have been proven non-clearing
2419 IsPadInPolygon (PadType
*pad
, PolygonType
*polygon
)
2421 return IsLineInPolygon ((LineType
*) pad
, polygon
);
2424 /* ---------------------------------------------------------------------------
2425 * checks if a polygon has a connection to a second one
2427 * First check all points out of P1 against P2 and vice versa.
2428 * If both fail check all lines of P1 against the ones of P2
2431 IsPolygonInPolygon (PolygonType
*P1
, PolygonType
*P2
)
2433 if (!P1
->Clipped
|| !P2
->Clipped
)
2435 assert (P1
->Clipped
->contours
);
2436 assert (P2
->Clipped
->contours
);
2438 /* first check if both bounding boxes intersect. If not, return quickly */
2439 if (P1
->Clipped
->contours
->xmin
- Bloat
> P2
->Clipped
->contours
->xmax
||
2440 P1
->Clipped
->contours
->xmax
+ Bloat
< P2
->Clipped
->contours
->xmin
||
2441 P1
->Clipped
->contours
->ymin
- Bloat
> P2
->Clipped
->contours
->ymax
||
2442 P1
->Clipped
->contours
->ymax
+ Bloat
< P2
->Clipped
->contours
->ymin
)
2445 /* first check un-bloated case */
2446 if (isects (P1
->Clipped
, P2
, false))
2449 /* now the difficult case of bloated */
2453 for (c
= P1
->Clipped
->contours
; c
; c
= c
->next
)
2456 VNODE
*v
= &c
->head
;
2457 if (c
->xmin
- Bloat
<= P2
->Clipped
->contours
->xmax
&&
2458 c
->xmax
+ Bloat
>= P2
->Clipped
->contours
->xmin
&&
2459 c
->ymin
- Bloat
<= P2
->Clipped
->contours
->ymax
&&
2460 c
->ymax
+ Bloat
>= P2
->Clipped
->contours
->ymin
)
2463 line
.Point1
.X
= v
->point
[0];
2464 line
.Point1
.Y
= v
->point
[1];
2465 line
.Thickness
= 2 * Bloat
;
2467 line
.Flags
= NoFlags ();
2468 for (v
= v
->next
; v
!= &c
->head
; v
= v
->next
)
2470 line
.Point2
.X
= v
->point
[0];
2471 line
.Point2
.Y
= v
->point
[1];
2472 SetLineBoundingBox (&line
);
2473 if (IsLineInPolygon (&line
, P2
))
2475 line
.Point1
.X
= line
.Point2
.X
;
2476 line
.Point1
.Y
= line
.Point2
.Y
;
2485 /* ---------------------------------------------------------------------------
2486 * writes the several names of an element to a file
2489 PrintElementNameList (ElementType
*Element
, FILE * FP
)
2491 static DynamicStringType cname
, pname
, vname
;
2493 CreateQuotedString (&cname
, (char *)EMPTY (DESCRIPTION_NAME (Element
)));
2494 CreateQuotedString (&pname
, (char *)EMPTY (NAMEONPCB_NAME (Element
)));
2495 CreateQuotedString (&vname
, (char *)EMPTY (VALUE_NAME (Element
)));
2496 fprintf (FP
, "(%s %s %s)\n", cname
.Data
, pname
.Data
, vname
.Data
);
2499 /* ---------------------------------------------------------------------------
2500 * writes the several names of an element to a file
2503 PrintConnectionElementName (ElementType
*Element
, FILE * FP
)
2505 fputs ("Element", FP
);
2506 PrintElementNameList (Element
, FP
);
2510 /* ---------------------------------------------------------------------------
2511 * prints one {pin,pad,via}/element entry of connection lists
2514 PrintConnectionListEntry (char *ObjName
, ElementType
*Element
,
2515 bool FirstOne
, FILE * FP
)
2517 static DynamicStringType oname
;
2519 CreateQuotedString (&oname
, ObjName
);
2521 fprintf (FP
, "\t%s\n\t{\n", oname
.Data
);
2524 fprintf (FP
, "\t\t%s ", oname
.Data
);
2526 PrintElementNameList (Element
, FP
);
2528 fputs ("(__VIA__)\n", FP
);
2532 /* ---------------------------------------------------------------------------
2533 * prints all found connections of a pads to file FP
2534 * the connections are stacked in 'PadList'
2537 PrintPadConnections (Cardinal Layer
, FILE * FP
, bool IsFirst
)
2542 if (!PadList
[Layer
].Number
)
2545 /* the starting pad */
2548 ptr
= PADLIST_ENTRY (Layer
, 0);
2550 PrintConnectionListEntry ((char *)UNKNOWN (ptr
->Name
), NULL
, true, FP
);
2552 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2555 /* we maybe have to start with i=1 if we are handling the
2556 * starting-pad itself
2558 for (i
= IsFirst
? 1 : 0; i
< PadList
[Layer
].Number
; i
++)
2560 ptr
= PADLIST_ENTRY (Layer
, i
);
2562 PrintConnectionListEntry ((char *)EMPTY (ptr
->Name
), (ElementType
*)ptr
->Element
, false, FP
);
2564 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2568 /* ---------------------------------------------------------------------------
2569 * prints all found connections of a pin to file FP
2570 * the connections are stacked in 'PVList'
2573 PrintPinConnections (FILE * FP
, bool IsFirst
)
2583 /* the starting pin */
2584 pv
= PVLIST_ENTRY (0);
2585 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), NULL
, true, FP
);
2588 /* we maybe have to start with i=1 if we are handling the
2589 * starting-pin itself
2591 for (i
= IsFirst
? 1 : 0; i
< PVList
.Number
; i
++)
2593 /* get the elements name or assume that its a via */
2594 pv
= PVLIST_ENTRY (i
);
2595 PrintConnectionListEntry ((char *)EMPTY (pv
->Name
), (ElementType
*)pv
->Element
, false, FP
);
2599 /* ---------------------------------------------------------------------------
2600 * checks if all lists of new objects are handled
2603 ListsEmpty (bool AndRats
)
2608 empty
= (PVList
.Location
>= PVList
.Number
);
2610 empty
= empty
&& (RatList
.Location
>= RatList
.Number
);
2611 for (i
= 0; i
< max_copper_layer
&& empty
; i
++)
2612 if (!LAYER_PTR (i
)->no_drc
)
2613 empty
= empty
&& LineList
[i
].Location
>= LineList
[i
].Number
2614 && ArcList
[i
].Location
>= ArcList
[i
].Number
2615 && PolygonList
[i
].Location
>= PolygonList
[i
].Number
;
2620 reassign_no_drc_flags (void)
2624 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2626 LayerType
*l
= LAYER_PTR (layer
);
2627 l
->no_drc
= AttributeGet (l
, "PCB::skip-drc") != NULL
;
2634 /* ---------------------------------------------------------------------------
2635 * loops till no more connections are found
2638 DoIt (int flag
, bool AndRats
, bool AndDraw
)
2640 bool newone
= false;
2641 reassign_no_drc_flags ();
2644 /* lookup connections; these are the steps (2) to (4)
2645 * from the description
2647 newone
= LookupPVConnectionsToPVList (flag
) ||
2648 LookupLOConnectionsToPVList (flag
, AndRats
) ||
2649 LookupLOConnectionsToLOList (flag
, AndRats
) ||
2650 LookupPVConnectionsToLOList (flag
, AndRats
);
2652 DrawNewConnections ();
2654 while (!newone
&& !ListsEmpty (AndRats
));
2660 /* ---------------------------------------------------------------------------
2661 * prints all unused pins of an element to file FP
2664 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType
*Element
, FILE * FP
, int flag
)
2668 static DynamicStringType oname
;
2670 /* check all pins in element */
2674 if (!TEST_FLAG (HOLEFLAG
, pin
))
2676 /* pin might have bee checked before, add to list if not */
2677 if (!TEST_FLAG (flag
, pin
) && FP
)
2680 if (ADD_PV_TO_LIST (pin
, flag
))
2682 DoIt (flag
, true, true);
2683 number
= PadList
[TOP_SIDE
].Number
2684 + PadList
[BOTTOM_SIDE
].Number
+ PVList
.Number
;
2685 /* the pin has no connection if it's the only
2686 * list entry; don't count vias
2688 for (i
= 0; i
< PVList
.Number
; i
++)
2689 if (!PVLIST_ENTRY (i
)->Element
)
2693 /* output of element name if not already done */
2696 PrintConnectionElementName (Element
, FP
);
2700 /* write name to list and draw selected object */
2701 CreateQuotedString (&oname
, (char *)EMPTY (pin
->Name
));
2702 fprintf (FP
, "\t%s\n", oname
.Data
);
2703 SET_FLAG (SELECTEDFLAG
, pin
);
2707 /* reset found objects for the next pin */
2708 if (PrepareNextLoop (FP
))
2715 /* check all pads in element */
2718 /* lookup pad in list */
2719 /* pad might has bee checked before, add to list if not */
2720 if (!TEST_FLAG (flag
, pad
) && FP
)
2723 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG
, pad
)
2724 ? BOTTOM_SIDE
: TOP_SIDE
, pad
, flag
))
2726 DoIt (flag
, true, true);
2727 number
= PadList
[TOP_SIDE
].Number
2728 + PadList
[BOTTOM_SIDE
].Number
+ PVList
.Number
;
2729 /* the pin has no connection if it's the only
2730 * list entry; don't count vias
2732 for (i
= 0; i
< PVList
.Number
; i
++)
2733 if (!PVLIST_ENTRY (i
)->Element
)
2737 /* output of element name if not already done */
2740 PrintConnectionElementName (Element
, FP
);
2744 /* write name to list and draw selected object */
2745 CreateQuotedString (&oname
, (char *)EMPTY (pad
->Name
));
2746 fprintf (FP
, "\t%s\n", oname
.Data
);
2747 SET_FLAG (SELECTEDFLAG
, pad
);
2751 /* reset found objects for the next pin */
2752 if (PrepareNextLoop (FP
))
2758 /* print separator if element has unused pins or pads */
2761 fputs ("}\n\n", FP
);
2767 /* ---------------------------------------------------------------------------
2768 * resets some flags for looking up the next pin/pad
2771 PrepareNextLoop (FILE * FP
)
2775 /* reset found LOs for the next pin */
2776 for (layer
= 0; layer
< max_copper_layer
; layer
++)
2778 LineList
[layer
].Location
= LineList
[layer
].Number
= 0;
2779 ArcList
[layer
].Location
= ArcList
[layer
].Number
= 0;
2780 PolygonList
[layer
].Location
= PolygonList
[layer
].Number
= 0;
2783 /* reset found pads */
2784 for (layer
= 0; layer
< 2; layer
++)
2785 PadList
[layer
].Location
= PadList
[layer
].Number
= 0;
2788 PVList
.Number
= PVList
.Location
= 0;
2789 RatList
.Number
= RatList
.Location
= 0;
2794 /* ---------------------------------------------------------------------------
2795 * finds all connections to the pins of the passed element.
2796 * The result is written to file FP
2797 * Returns true if operation was aborted
2800 PrintElementConnections (ElementType
*Element
, FILE * FP
, int flag
, bool AndDraw
)
2802 PrintConnectionElementName (Element
, FP
);
2804 /* check all pins in element */
2807 /* pin might have been checked before, add to list if not */
2808 if (TEST_FLAG (flag
, pin
))
2810 PrintConnectionListEntry ((char *)EMPTY (pin
->Name
), NULL
, true, FP
);
2811 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2814 if (ADD_PV_TO_LIST (pin
, flag
))
2816 DoIt (flag
, true, AndDraw
);
2817 /* printout all found connections */
2818 PrintPinConnections (FP
, true);
2819 PrintPadConnections (TOP_SIDE
, FP
, false);
2820 PrintPadConnections (BOTTOM_SIDE
, FP
, false);
2821 fputs ("\t}\n", FP
);
2822 if (PrepareNextLoop (FP
))
2827 /* check all pads in element */
2831 /* pad might have been checked before, add to list if not */
2832 if (TEST_FLAG (flag
, pad
))
2834 PrintConnectionListEntry ((char *)EMPTY (pad
->Name
), NULL
, true, FP
);
2835 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP
);
2838 layer
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
;
2839 if (ADD_PAD_TO_LIST (layer
, pad
, flag
))
2841 DoIt (flag
, true, AndDraw
);
2842 /* print all found connections */
2843 PrintPadConnections (layer
, FP
, true);
2844 PrintPadConnections (layer
==
2845 (TOP_SIDE
? BOTTOM_SIDE
: TOP_SIDE
),
2847 PrintPinConnections (FP
, false);
2848 fputs ("\t}\n", FP
);
2849 if (PrepareNextLoop (FP
))
2853 fputs ("}\n\n", FP
);
2857 /* ---------------------------------------------------------------------------
2858 * draws all new connections which have been found since the
2859 * routine was called the last time
2862 DrawNewConnections (void)
2867 /* decrement 'i' to keep layerstack order */
2868 for (i
= max_copper_layer
- 1; i
!= -1; i
--)
2870 Cardinal layer
= LayerStack
[i
];
2872 if (PCB
->Data
->Layer
[layer
].On
)
2874 /* draw all new lines */
2875 position
= LineList
[layer
].DrawLocation
;
2876 for (; position
< LineList
[layer
].Number
; position
++)
2877 DrawLine (LAYER_PTR (layer
), LINELIST_ENTRY (layer
, position
));
2878 LineList
[layer
].DrawLocation
= LineList
[layer
].Number
;
2880 /* draw all new arcs */
2881 position
= ArcList
[layer
].DrawLocation
;
2882 for (; position
< ArcList
[layer
].Number
; position
++)
2883 DrawArc (LAYER_PTR (layer
), ARCLIST_ENTRY (layer
, position
));
2884 ArcList
[layer
].DrawLocation
= ArcList
[layer
].Number
;
2886 /* draw all new polygons */
2887 position
= PolygonList
[layer
].DrawLocation
;
2888 for (; position
< PolygonList
[layer
].Number
; position
++)
2889 DrawPolygon (LAYER_PTR (layer
), POLYGONLIST_ENTRY (layer
, position
));
2890 PolygonList
[layer
].DrawLocation
= PolygonList
[layer
].Number
;
2894 /* draw all new pads */
2896 for (i
= 0; i
< 2; i
++)
2898 position
= PadList
[i
].DrawLocation
;
2900 for (; position
< PadList
[i
].Number
; position
++)
2901 DrawPad (PADLIST_ENTRY (i
, position
));
2902 PadList
[i
].DrawLocation
= PadList
[i
].Number
;
2905 /* draw all new PVs; 'PVList' holds a list of pointers to the
2906 * sorted array pointers to PV data
2908 while (PVList
.DrawLocation
< PVList
.Number
)
2910 PinType
*pv
= PVLIST_ENTRY (PVList
.DrawLocation
);
2912 if (TEST_FLAG (PINFLAG
, pv
))
2917 else if (PCB
->ViaOn
)
2919 PVList
.DrawLocation
++;
2921 /* draw the new rat-lines */
2924 position
= RatList
.DrawLocation
;
2925 for (; position
< RatList
.Number
; position
++)
2926 DrawRat (RATLIST_ENTRY (position
));
2927 RatList
.DrawLocation
= RatList
.Number
;
2931 /* ---------------------------------------------------------------------------
2932 * find all connections to pins within one element
2935 LookupElementConnections (ElementType
*Element
, FILE * FP
)
2937 /* reset all currently marked connections */
2939 ClearFlagOnAllObjects (true, FOUNDFLAG
);
2940 InitConnectionLookup ();
2941 PrintElementConnections (Element
, FP
, FOUNDFLAG
, true);
2942 SetChangedFlag (true);
2943 if (Settings
.RingBellWhenFinished
)
2945 FreeConnectionLookupMemory ();
2946 IncrementUndoSerialNumber ();
2951 /* ---------------------------------------------------------------------------
2952 * find all connections to pins of all element
2955 LookupConnectionsToAllElements (FILE * FP
)
2957 /* reset all currently marked connections */
2959 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2960 InitConnectionLookup ();
2962 ELEMENT_LOOP (PCB
->Data
);
2964 /* break if abort dialog returned true */
2965 if (PrintElementConnections (element
, FP
, FOUNDFLAG
, false))
2968 if (Settings
.ResetAfterElement
&& n
!= 1)
2969 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2972 if (Settings
.RingBellWhenFinished
)
2974 ClearFlagOnAllObjects (false, FOUNDFLAG
);
2975 FreeConnectionLookupMemory ();
2979 /*---------------------------------------------------------------------------
2980 * add the starting object to the list of found objects
2983 ListStart (int type
, void *ptr1
, void *ptr2
, void *ptr3
, int flag
)
2991 if (ADD_PV_TO_LIST ((PinType
*) ptr2
, flag
))
2998 if (ADD_RAT_TO_LIST ((RatType
*) ptr1
, flag
))
3005 int layer
= GetLayerNumber (PCB
->Data
,
3006 (LayerType
*) ptr1
);
3008 if (ADD_LINE_TO_LIST (layer
, (LineType
*) ptr2
, flag
))
3015 int layer
= GetLayerNumber (PCB
->Data
,
3016 (LayerType
*) ptr1
);
3018 if (ADD_ARC_TO_LIST (layer
, (ArcType
*) ptr2
, flag
))
3025 int layer
= GetLayerNumber (PCB
->Data
,
3026 (LayerType
*) ptr1
);
3028 if (ADD_POLYGON_TO_LIST (layer
, (PolygonType
*) ptr2
, flag
))
3035 PadType
*pad
= (PadType
*) ptr2
;
3038 (ONSOLDERFLAG
, pad
) ? BOTTOM_SIDE
: TOP_SIDE
, pad
, flag
))
3047 /* ---------------------------------------------------------------------------
3048 * looks up all connections from the object at the given coordinates
3049 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3050 * the objects are re-drawn if AndDraw is true
3051 * also the action is marked as undoable if AndDraw is true
3054 LookupConnection (Coord X
, Coord Y
, bool AndDraw
, Coord Range
, int flag
,
3057 void *ptr1
, *ptr2
, *ptr3
;
3061 /* check if there are any pins or pads at that position */
3063 reassign_no_drc_flags ();
3066 = SearchObjectByLocation (LOOKUP_FIRST
, &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3067 if (type
== NO_TYPE
)
3069 type
= SearchObjectByLocation (
3070 LOOKUP_MORE
& ~(AndRats
? 0 : RATLINE_TYPE
),
3071 &ptr1
, &ptr2
, &ptr3
, X
, Y
, Range
);
3072 if (type
== NO_TYPE
)
3074 if (type
& SILK_TYPE
)
3076 int laynum
= GetLayerNumber (PCB
->Data
,
3077 (LayerType
*) ptr1
);
3079 /* don't mess with non-conducting objects! */
3080 if (laynum
>= max_copper_layer
|| ((LayerType
*)ptr1
)->no_drc
)
3085 name
= ConnectionName (type
, ptr1
, ptr2
);
3086 hid_actionl ("NetlistShow", name
, NULL
);
3089 InitConnectionLookup ();
3091 /* now add the object to the appropriate list and start scanning
3092 * This is step (1) from the description
3094 ListStart (type
, ptr1
, ptr2
, ptr3
, flag
);
3095 DoIt (flag
, AndRats
, AndDraw
);
3097 IncrementUndoSerialNumber ();
3103 if (AndDraw
&& Settings
.RingBellWhenFinished
)
3105 FreeConnectionLookupMemory ();
3108 /* ---------------------------------------------------------------------------
3109 * find connections for rats nesting
3110 * assumes InitConnectionLookup() has already been done
3113 RatFindHook (int type
, void *ptr1
, void *ptr2
, void *ptr3
,
3114 bool undo
, int flag
, bool AndRats
)
3118 ListStart (type
, ptr1
, ptr2
, ptr3
, flag
);
3119 DoIt (flag
, AndRats
, false);
3123 /* ---------------------------------------------------------------------------
3124 * find all unused pins of all element
3127 LookupUnusedPins (FILE * FP
)
3129 /* reset all currently marked connections */
3131 ClearFlagOnAllObjects (true, FOUNDFLAG
);
3132 InitConnectionLookup ();
3134 ELEMENT_LOOP (PCB
->Data
);
3136 /* break if abort dialog returned true;
3137 * passing NULL as filedescriptor discards the normal output
3139 if (PrintAndSelectUnusedPinsAndPadsOfElement (element
, FP
, FOUNDFLAG
))
3144 if (Settings
.RingBellWhenFinished
)
3146 FreeConnectionLookupMemory ();
3147 IncrementUndoSerialNumber ();
3152 /* ---------------------------------------------------------------------------
3153 * resets all used flags of pins and vias
3156 ClearFlagOnPinsViasAndPads (bool AndDraw
, int flag
)
3158 bool change
= false;
3160 VIA_LOOP (PCB
->Data
);
3162 if (TEST_FLAG (flag
, via
))
3165 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3166 CLEAR_FLAG (flag
, via
);
3173 ELEMENT_LOOP (PCB
->Data
);
3177 if (TEST_FLAG (flag
, pin
))
3180 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3181 CLEAR_FLAG (flag
, pin
);
3190 if (TEST_FLAG (flag
, pad
))
3193 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3194 CLEAR_FLAG (flag
, pad
);
3204 SetChangedFlag (true);
3208 /* ---------------------------------------------------------------------------
3209 * resets all used flags of LOs
3212 ClearFlagOnLinesAndPolygons (bool AndDraw
, int flag
)
3214 bool change
= false;
3216 RAT_LOOP (PCB
->Data
);
3218 if (TEST_FLAG (flag
, line
))
3221 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
3222 CLEAR_FLAG (flag
, line
);
3229 COPPERLINE_LOOP (PCB
->Data
);
3231 if (TEST_FLAG (flag
, line
))
3234 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3235 CLEAR_FLAG (flag
, line
);
3237 DrawLine (layer
, line
);
3242 COPPERARC_LOOP (PCB
->Data
);
3244 if (TEST_FLAG (flag
, arc
))
3247 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3248 CLEAR_FLAG (flag
, arc
);
3250 DrawArc (layer
, arc
);
3255 COPPERPOLYGON_LOOP (PCB
->Data
);
3257 if (TEST_FLAG (flag
, polygon
))
3260 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3261 CLEAR_FLAG (flag
, polygon
);
3263 DrawPolygon (layer
, polygon
);
3269 SetChangedFlag (true);
3273 /* ---------------------------------------------------------------------------
3274 * resets all found connections
3277 ClearFlagOnAllObjects (bool AndDraw
, int flag
)
3279 bool change
= false;
3281 change
= ClearFlagOnPinsViasAndPads (AndDraw
, flag
) || change
;
3282 change
= ClearFlagOnLinesAndPolygons (AndDraw
, flag
) || change
;
3287 /*----------------------------------------------------------------------------
3288 * Dumps the list contents
3295 for (i
= 0; i
< 2; i
++)
3297 PadList
[i
].Number
= 0;
3298 PadList
[i
].Location
= 0;
3299 PadList
[i
].DrawLocation
= 0;
3303 PVList
.Location
= 0;
3305 for (i
= 0; i
< max_copper_layer
; i
++)
3307 LineList
[i
].Location
= 0;
3308 LineList
[i
].DrawLocation
= 0;
3309 LineList
[i
].Number
= 0;
3310 ArcList
[i
].Location
= 0;
3311 ArcList
[i
].DrawLocation
= 0;
3312 ArcList
[i
].Number
= 0;
3313 PolygonList
[i
].Location
= 0;
3314 PolygonList
[i
].DrawLocation
= 0;
3315 PolygonList
[i
].Number
= 0;
3318 RatList
.Location
= 0;
3319 RatList
.DrawLocation
= 0;
3327 /*-----------------------------------------------------------------------------
3328 * Check for DRC violations on a single net starting from the pad or pin
3329 * sees if the connectivity changes when everything is bloated, or shrunk
3332 DRCFind (int What
, void *ptr1
, void *ptr2
, void *ptr3
)
3336 long int *object_id_list
;
3337 int *object_type_list
;
3338 DrcViolationType
*violation
;
3341 if (PCB
->Shrink
!= 0)
3343 Bloat
= -PCB
->Shrink
;
3344 ListStart (What
, ptr1
, ptr2
, ptr3
, DRCFLAG
| SELECTEDFLAG
);
3345 DoIt (DRCFLAG
| SELECTEDFLAG
, true, false);
3346 /* ok now the shrunk net has the SELECTEDFLAG set */
3348 ListStart (What
, ptr1
, ptr2
, ptr3
, FOUNDFLAG
);
3350 drc
= true; /* abort the search if we find anything not already found */
3351 if (DoIt (FOUNDFLAG
, true, false))
3354 /* make the flag changes undoable */
3355 ClearFlagOnAllObjects (false, FOUNDFLAG
| SELECTEDFLAG
);
3358 Bloat
= -PCB
->Shrink
;
3359 ListStart (What
, ptr1
, ptr2
, ptr3
, SELECTEDFLAG
);
3360 DoIt (SELECTEDFLAG
, true, true);
3362 ListStart (What
, ptr1
, ptr2
, ptr3
, FOUNDFLAG
);
3365 DoIt (FOUNDFLAG
, true, true);
3370 LocateError (&x
, &y
);
3371 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3372 violation
= pcb_drc_violation_new (_("Potential for broken trace"),
3373 _("Insufficient overlap between objects can lead to broken tracks\n"
3374 "due to registration errors with old wheel style photo-plotters."),
3376 0, /* ANGLE OF ERROR UNKNOWN */
3377 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3378 0, /* MAGNITUDE OF ERROR UNKNOWN */
3383 append_drc_violation (violation
);
3384 pcb_drc_violation_free (violation
);
3385 free (object_id_list
);
3386 free (object_type_list
);
3388 if (!throw_drc_dialog())
3390 IncrementUndoSerialNumber ();
3395 /* now check the bloated condition */
3397 ClearFlagOnAllObjects (false, FOUNDFLAG
| SELECTEDFLAG
);
3399 ListStart (What
, ptr1
, ptr2
, ptr3
, SELECTEDFLAG
);
3400 DoIt (SELECTEDFLAG
, true, false);
3403 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3406 while (DoIt (flag
, true, false))
3409 /* make the flag changes undoable */
3410 ClearFlagOnAllObjects (false, FOUNDFLAG
| SELECTEDFLAG
);
3414 ListStart (What
, ptr1
, ptr2
, ptr3
, SELECTEDFLAG
);
3415 DoIt (SELECTEDFLAG
, true, true);
3417 ListStart (What
, ptr1
, ptr2
, ptr3
, FOUNDFLAG
);
3420 DoIt (FOUNDFLAG
, true, true);
3423 LocateError (&x
, &y
);
3424 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3425 violation
= pcb_drc_violation_new (_("Copper areas too close"),
3426 _("Circuits that are too close may bridge during imaging, etching,\n"
3427 "plating, or soldering processes resulting in a direct short."),
3429 0, /* ANGLE OF ERROR UNKNOWN */
3430 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3431 0, /* MAGNITUDE OF ERROR UNKNOWN */
3436 append_drc_violation (violation
);
3437 pcb_drc_violation_free (violation
);
3438 free (object_id_list
);
3439 free (object_type_list
);
3442 if (!throw_drc_dialog())
3444 IncrementUndoSerialNumber ();
3446 /* highlight the rest of the encroaching net so it's not reported again */
3447 flag
= FOUNDFLAG
| SELECTEDFLAG
;
3449 ListStart (thing_type
, thing_ptr1
, thing_ptr2
, thing_ptr3
, flag
);
3450 DoIt (flag
, true, true);
3454 ListStart (What
, ptr1
, ptr2
, ptr3
, flag
);
3458 ClearFlagOnAllObjects (false, FOUNDFLAG
| SELECTEDFLAG
);
3462 /* DRC clearance callback */
3465 drc_callback (DataType
*data
, LayerType
*layer
, PolygonType
*polygon
,
3466 int type
, void *ptr1
, void *ptr2
, void *userdata
)
3468 struct drc_info
*i
= (struct drc_info
*) userdata
;
3472 long int *object_id_list
;
3473 int *object_type_list
;
3474 DrcViolationType
*violation
;
3476 LineType
*line
= (LineType
*) ptr2
;
3477 ArcType
*arc
= (ArcType
*) ptr2
;
3478 PinType
*pin
= (PinType
*) ptr2
;
3479 PadType
*pad
= (PadType
*) ptr2
;
3481 SetThing (type
, ptr1
, ptr2
, ptr2
);
3486 if (line
->Clearance
< 2 * PCB
->Bloat
)
3488 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3489 SET_FLAG (i
->flag
, line
);
3490 message
= _("Line with insufficient clearance inside polygon\n");
3495 if (arc
->Clearance
< 2 * PCB
->Bloat
)
3497 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3498 SET_FLAG (i
->flag
, arc
);
3499 message
= _("Arc with insufficient clearance inside polygon\n");
3504 if (pad
->Clearance
&& pad
->Clearance
< 2 * PCB
->Bloat
)
3505 if (IsPadInPolygon(pad
,polygon
))
3507 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3508 SET_FLAG (i
->flag
, pad
);
3509 message
= _("Pad with insufficient clearance inside polygon\n");
3514 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3516 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3517 SET_FLAG (i
->flag
, pin
);
3518 message
= _("Pin with insufficient clearance inside polygon\n");
3523 if (pin
->Clearance
&& pin
->Clearance
< 2 * PCB
->Bloat
)
3525 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr2
);
3526 SET_FLAG (i
->flag
, pin
);
3527 message
= _("Via with insufficient clearance inside polygon\n");
3532 Message ("hace: Bad Plow object in callback\n");
3537 AddObjectToFlagUndoList (POLYGON_TYPE
, layer
, polygon
, polygon
);
3538 SET_FLAG (FOUNDFLAG
, polygon
);
3539 DrawPolygon (layer
, polygon
);
3540 DrawObject (type
, ptr1
, ptr2
);
3542 LocateError (&x
, &y
);
3543 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3544 violation
= pcb_drc_violation_new (message
,
3545 _("Circuits that are too close may bridge during imaging, etching,\n"
3546 "plating, or soldering processes resulting in a direct short."),
3548 0, /* ANGLE OF ERROR UNKNOWN */
3549 FALSE
, /* MEASUREMENT OF ERROR UNKNOWN */
3550 0, /* MAGNITUDE OF ERROR UNKNOWN */
3555 append_drc_violation (violation
);
3556 pcb_drc_violation_free (violation
);
3557 free (object_id_list
);
3558 free (object_type_list
);
3560 if (!throw_drc_dialog())
3563 IncrementUndoSerialNumber ();
3568 /*-----------------------------------------------------------------------------
3569 * Check for DRC violations
3570 * see if the connectivity changes when everything is bloated, or shrunk
3577 long int *object_id_list
;
3578 int *object_type_list
;
3579 DrcViolationType
*violation
;
3583 struct drc_info info
;
3585 reset_drc_dialog_message();
3589 SaveStackAndVisibility ();
3590 ResetStackAndVisibility ();
3591 hid_action ("LayersChanged");
3592 InitConnectionLookup ();
3594 if (ClearFlagOnAllObjects (true, FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
))
3596 IncrementUndoSerialNumber ();
3602 ELEMENT_LOOP (PCB
->Data
);
3606 if (!TEST_FLAG (DRCFLAG
, pin
)
3607 && DRCFind (PIN_TYPE
, (void *) element
, (void *) pin
, (void *) pin
))
3619 /* count up how many pads have no solderpaste openings */
3620 if (TEST_FLAG (NOPASTEFLAG
, pad
))
3623 if (!TEST_FLAG (DRCFLAG
, pad
)
3624 && DRCFind (PAD_TYPE
, (void *) element
, (void *) pad
, (void *) pad
))
3636 VIA_LOOP (PCB
->Data
);
3638 if (!TEST_FLAG (DRCFLAG
, via
)
3639 && DRCFind (VIA_TYPE
, (void *) via
, (void *) via
, (void *) via
))
3647 ClearFlagOnAllObjects (false, IsBad
? DRCFLAG
: (FOUNDFLAG
| DRCFLAG
| SELECTEDFLAG
));
3648 info
.flag
= SELECTEDFLAG
;
3649 /* check minimum widths and polygon clearances */
3652 COPPERLINE_LOOP (PCB
->Data
);
3654 /* check line clearances in polygons */
3655 if (PlowsPolygon (PCB
->Data
, LINE_TYPE
, layer
, line
, drc_callback
, &info
))
3660 if (line
->Thickness
< PCB
->minWid
)
3662 AddObjectToFlagUndoList (LINE_TYPE
, layer
, line
, line
);
3663 SET_FLAG (SELECTEDFLAG
, line
);
3664 DrawLine (layer
, line
);
3666 SetThing (LINE_TYPE
, layer
, line
, line
);
3667 LocateError (&x
, &y
);
3668 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3669 violation
= pcb_drc_violation_new (_("Line width is too thin"),
3670 _("Process specifications dictate a minimum feature-width\n"
3671 "that can reliably be reproduced"),
3673 0, /* ANGLE OF ERROR UNKNOWN */
3674 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3680 append_drc_violation (violation
);
3681 pcb_drc_violation_free (violation
);
3682 free (object_id_list
);
3683 free (object_type_list
);
3684 if (!throw_drc_dialog())
3689 IncrementUndoSerialNumber ();
3697 COPPERARC_LOOP (PCB
->Data
);
3699 if (PlowsPolygon (PCB
->Data
, ARC_TYPE
, layer
, arc
, drc_callback
, &info
))
3704 if (arc
->Thickness
< PCB
->minWid
)
3706 AddObjectToFlagUndoList (ARC_TYPE
, layer
, arc
, arc
);
3707 SET_FLAG (SELECTEDFLAG
, arc
);
3708 DrawArc (layer
, arc
);
3710 SetThing (ARC_TYPE
, layer
, arc
, arc
);
3711 LocateError (&x
, &y
);
3712 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3713 violation
= pcb_drc_violation_new (_("Arc width is too thin"),
3714 _("Process specifications dictate a minimum feature-width\n"
3715 "that can reliably be reproduced"),
3717 0, /* ANGLE OF ERROR UNKNOWN */
3718 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3724 append_drc_violation (violation
);
3725 pcb_drc_violation_free (violation
);
3726 free (object_id_list
);
3727 free (object_type_list
);
3728 if (!throw_drc_dialog())
3733 IncrementUndoSerialNumber ();
3741 ALLPIN_LOOP (PCB
->Data
);
3743 if (PlowsPolygon (PCB
->Data
, PIN_TYPE
, element
, pin
, drc_callback
, &info
))
3748 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
3749 pin
->Thickness
- pin
->DrillingHole
< 2 * PCB
->minRing
)
3751 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3752 SET_FLAG (SELECTEDFLAG
, pin
);
3755 SetThing (PIN_TYPE
, element
, pin
, pin
);
3756 LocateError (&x
, &y
);
3757 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3758 violation
= pcb_drc_violation_new (_("Pin annular ring too small"),
3759 _("Annular rings that are too small may erode during etching,\n"
3760 "resulting in a broken connection"),
3762 0, /* ANGLE OF ERROR UNKNOWN */
3763 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3764 (pin
->Thickness
- pin
->DrillingHole
) / 2,
3769 append_drc_violation (violation
);
3770 pcb_drc_violation_free (violation
);
3771 free (object_id_list
);
3772 free (object_type_list
);
3773 if (!throw_drc_dialog())
3778 IncrementUndoSerialNumber ();
3781 if (pin
->DrillingHole
< PCB
->minDrill
)
3783 AddObjectToFlagUndoList (PIN_TYPE
, element
, pin
, pin
);
3784 SET_FLAG (SELECTEDFLAG
, pin
);
3787 SetThing (PIN_TYPE
, element
, pin
, pin
);
3788 LocateError (&x
, &y
);
3789 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3790 violation
= pcb_drc_violation_new (_("Pin drill size is too small"),
3791 _("Process rules dictate the minimum drill size which can be used"),
3793 0, /* ANGLE OF ERROR UNKNOWN */
3794 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3800 append_drc_violation (violation
);
3801 pcb_drc_violation_free (violation
);
3802 free (object_id_list
);
3803 free (object_type_list
);
3804 if (!throw_drc_dialog())
3809 IncrementUndoSerialNumber ();
3817 ALLPAD_LOOP (PCB
->Data
);
3819 if (PlowsPolygon (PCB
->Data
, PAD_TYPE
, element
, pad
, drc_callback
, &info
))
3824 if (pad
->Thickness
< PCB
->minWid
)
3826 AddObjectToFlagUndoList (PAD_TYPE
, element
, pad
, pad
);
3827 SET_FLAG (SELECTEDFLAG
, pad
);
3830 SetThing (PAD_TYPE
, element
, pad
, pad
);
3831 LocateError (&x
, &y
);
3832 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3833 violation
= pcb_drc_violation_new (_("Pad is too thin"),
3834 _("Pads which are too thin may erode during etching,\n"
3835 "resulting in a broken or unreliable connection"),
3837 0, /* ANGLE OF ERROR UNKNOWN */
3838 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3844 append_drc_violation (violation
);
3845 pcb_drc_violation_free (violation
);
3846 free (object_id_list
);
3847 free (object_type_list
);
3848 if (!throw_drc_dialog())
3853 IncrementUndoSerialNumber ();
3861 VIA_LOOP (PCB
->Data
);
3863 if (PlowsPolygon (PCB
->Data
, VIA_TYPE
, via
, via
, drc_callback
, &info
))
3868 if (!TEST_FLAG (HOLEFLAG
, via
) &&
3869 via
->Thickness
- via
->DrillingHole
< 2 * PCB
->minRing
)
3871 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3872 SET_FLAG (SELECTEDFLAG
, via
);
3875 SetThing (VIA_TYPE
, via
, via
, via
);
3876 LocateError (&x
, &y
);
3877 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3878 violation
= pcb_drc_violation_new (_("Via annular ring too small"),
3879 _("Annular rings that are too small may erode during etching,\n"
3880 "resulting in a broken connection"),
3882 0, /* ANGLE OF ERROR UNKNOWN */
3883 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3884 (via
->Thickness
- via
->DrillingHole
) / 2,
3889 append_drc_violation (violation
);
3890 pcb_drc_violation_free (violation
);
3891 free (object_id_list
);
3892 free (object_type_list
);
3893 if (!throw_drc_dialog())
3898 IncrementUndoSerialNumber ();
3901 if (via
->DrillingHole
< PCB
->minDrill
)
3903 AddObjectToFlagUndoList (VIA_TYPE
, via
, via
, via
);
3904 SET_FLAG (SELECTEDFLAG
, via
);
3907 SetThing (VIA_TYPE
, via
, via
, via
);
3908 LocateError (&x
, &y
);
3909 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3910 violation
= pcb_drc_violation_new (_("Via drill size is too small"),
3911 _("Process rules dictate the minimum drill size which can be used"),
3913 0, /* ANGLE OF ERROR UNKNOWN */
3914 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3920 append_drc_violation (violation
);
3921 pcb_drc_violation_free (violation
);
3922 free (object_id_list
);
3923 free (object_type_list
);
3924 if (!throw_drc_dialog())
3929 IncrementUndoSerialNumber ();
3936 FreeConnectionLookupMemory ();
3939 /* check silkscreen minimum widths outside of elements */
3940 /* XXX - need to check text and polygons too! */
3943 SILKLINE_LOOP (PCB
->Data
);
3945 if (line
->Thickness
< PCB
->minSlk
)
3947 SET_FLAG (SELECTEDFLAG
, line
);
3948 DrawLine (layer
, line
);
3950 SetThing (LINE_TYPE
, layer
, line
, line
);
3951 LocateError (&x
, &y
);
3952 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
3953 violation
= pcb_drc_violation_new (_("Silk line is too thin"),
3954 _("Process specifications dictate a minimum silkscreen feature-width\n"
3955 "that can reliably be reproduced"),
3957 0, /* ANGLE OF ERROR UNKNOWN */
3958 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
3964 append_drc_violation (violation
);
3965 pcb_drc_violation_free (violation
);
3966 free (object_id_list
);
3967 free (object_type_list
);
3968 if (!throw_drc_dialog())
3978 /* check silkscreen minimum widths inside of elements */
3979 /* XXX - need to check text and polygons too! */
3982 ELEMENT_LOOP (PCB
->Data
);
3985 ELEMENTLINE_LOOP (element
);
3987 if (line
->Thickness
< PCB
->minSlk
)
3998 SET_FLAG (SELECTEDFLAG
, element
);
3999 DrawElement (element
);
4001 SetThing (ELEMENT_TYPE
, element
, element
, element
);
4002 LocateError (&x
, &y
);
4003 BuildObjectList (&object_count
, &object_id_list
, &object_type_list
);
4005 title
= _("Element %s has %i silk lines which are too thin");
4006 name
= (char *)UNKNOWN (NAMEONPCB_NAME (element
));
4008 /* -4 is for the %s and %i place-holders */
4009 /* +11 is the max printed length for a 32 bit integer */
4010 /* +1 is for the \0 termination */
4011 buflen
= strlen (title
) - 4 + strlen (name
) + 11 + 1;
4012 buffer
= (char *)malloc (buflen
);
4013 snprintf (buffer
, buflen
, title
, name
, tmpcnt
);
4015 violation
= pcb_drc_violation_new (buffer
,
4016 _("Process specifications dictate a minimum silkscreen\n"
4017 "feature-width that can reliably be reproduced"),
4019 0, /* ANGLE OF ERROR UNKNOWN */
4020 TRUE
, /* MEASUREMENT OF ERROR KNOWN */
4021 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4027 append_drc_violation (violation
);
4028 pcb_drc_violation_free (violation
);
4029 free (object_id_list
);
4030 free (object_type_list
);
4031 if (!throw_drc_dialog())
4044 IncrementUndoSerialNumber ();
4048 RestoreStackAndVisibility ();
4049 hid_action ("LayersChanged");
4050 gui
->invalidate_all ();
4054 Message (ngettext ("Warning: %d pad has the nopaste flag set.\n",
4055 "Warning: %d pads have the nopaste flag set.\n",
4056 nopastecnt
), nopastecnt
);
4058 return IsBad
? -drcerr_count
: drcerr_count
;
4061 /*----------------------------------------------------------------------------
4062 * Locate the coordinatates of offending item (thing)
4065 LocateError (Coord
*x
, Coord
*y
)
4071 LineType
*line
= (LineType
*) thing_ptr3
;
4072 *x
= (line
->Point1
.X
+ line
->Point2
.X
) / 2;
4073 *y
= (line
->Point1
.Y
+ line
->Point2
.Y
) / 2;
4078 ArcType
*arc
= (ArcType
*) thing_ptr3
;
4085 PolygonType
*polygon
= (PolygonType
*) thing_ptr3
;
4087 (polygon
->Clipped
->contours
->xmin
+
4088 polygon
->Clipped
->contours
->xmax
) / 2;
4090 (polygon
->Clipped
->contours
->ymin
+
4091 polygon
->Clipped
->contours
->ymax
) / 2;
4097 PinType
*pin
= (PinType
*) thing_ptr3
;
4104 PadType
*pad
= (PadType
*) thing_ptr3
;
4105 *x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
4106 *y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
4111 ElementType
*element
= (ElementType
*) thing_ptr3
;
4112 *x
= element
->MarkX
;
4113 *y
= element
->MarkY
;
4122 /*----------------------------------------------------------------------------
4123 * Build a list of the of offending items by ID. (Currently just "thing")
4126 BuildObjectList (int *object_count
, long int **object_id_list
, int **object_type_list
)
4129 *object_id_list
= NULL
;
4130 *object_type_list
= NULL
;
4143 *object_id_list
= (long int *)malloc (sizeof (long int));
4144 *object_type_list
= (int *)malloc (sizeof (int));
4145 **object_id_list
= ((AnyObjectType
*)thing_ptr3
)->ID
;
4146 **object_type_list
= thing_type
;
4151 _("Internal error in BuildObjectList: unknown object type %i\n"),
4157 /*----------------------------------------------------------------------------
4158 * center the display to show the offending item (thing)
4165 LocateError (&X
, &Y
);
4172 ChangeGroupVisibility (
4173 GetLayerNumber (PCB
->Data
, (LayerType
*) thing_ptr1
),
4176 CenterDisplay (X
, Y
);
4180 InitConnectionLookup (void)
4182 InitComponentLookup ();
4183 InitLayoutLookup ();
4187 FreeConnectionLookupMemory (void)
4189 FreeComponentLookupMemory ();
4190 FreeLayoutLookupMemory ();