find.c: Remove unnecessary PIN/VIA test from SetThing()
[geda-pcb/pcjc2.git] / src / find.c
blobd10499de5a672779f2ae4ddd08c4351765243a57
1 /*
3 * COPYRIGHT
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
30 * short description:
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
56 * to X,Y
58 * Intersection of line <--> line:
59 * - see the description of 'LineLineIntersect()'
62 /* routines to find connections between pins, vias, lines...
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
68 #include <setjmp.h>
69 #include <assert.h>
71 #include "global.h"
73 #include "data.h"
74 #include "draw.h"
75 #include "error.h"
76 #include "find.h"
77 #include "misc.h"
78 #include "rtree.h"
79 #include "polygon.h"
80 #include "pcb-printf.h"
81 #include "search.h"
82 #include "set.h"
83 #include "undo.h"
84 #include "rats.h"
86 #ifdef HAVE_LIBDMALLOC
87 #include <dmalloc.h>
88 #endif
90 #undef DEBUG
92 /* ---------------------------------------------------------------------------
93 * some local macros
96 #define SEPARATE(FP) \
97 { \
98 int i; \
99 fputc('#', (FP)); \
100 for (i = Settings.CharPerLine; i; i--) \
101 fputc('=', (FP)); \
102 fputc('\n', (FP)); \
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)) ? \
118 IsArcInRectangle( \
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), \
121 (Arc)) : \
122 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
124 #define IS_PV_ON_PAD(PV,Pad) \
125 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
127 static DrcViolationType
128 *pcb_drc_violation_new (const char *title,
129 const char *explanation,
130 Coord x, Coord y,
131 Angle angle,
132 bool have_measured,
133 Coord measured_value,
134 Coord required_value,
135 int object_count,
136 long int *object_id_list,
137 int *object_type_list)
139 DrcViolationType *violation = (DrcViolationType *)malloc (sizeof (DrcViolationType));
141 violation->title = strdup (title);
142 violation->explanation = strdup (explanation);
143 violation->x = x;
144 violation->y = y;
145 violation->angle = angle;
146 violation->have_measured = have_measured;
147 violation->measured_value = measured_value;
148 violation->required_value = required_value;
149 violation->object_count = object_count;
150 violation->object_id_list = object_id_list;
151 violation->object_type_list = object_type_list;
153 return violation;
156 static void
157 pcb_drc_violation_free (DrcViolationType *violation)
159 free (violation->title);
160 free (violation->explanation);
161 free (violation);
164 static GString *drc_dialog_message;
165 static void
166 reset_drc_dialog_message(void)
168 if (drc_dialog_message)
169 g_string_free (drc_dialog_message, FALSE);
170 drc_dialog_message = g_string_new ("");
171 if (gui->drc_gui != NULL)
173 gui->drc_gui->reset_drc_dialog_message ();
176 static void
177 append_drc_dialog_message(const char *fmt, ...)
179 gchar *new_str;
180 va_list ap;
181 va_start (ap, fmt);
182 new_str = pcb_vprintf (fmt, ap);
183 g_string_append (drc_dialog_message, new_str);
184 va_end (ap);
185 g_free (new_str);
188 static void GotoError (void);
190 static void
191 append_drc_violation (DrcViolationType *violation)
193 if (gui->drc_gui != NULL)
195 gui->drc_gui->append_drc_violation (violation);
197 else
199 /* Fallback to formatting the violation message as text */
200 append_drc_dialog_message ("%s\n", violation->title);
201 append_drc_dialog_message (_("%m+near %$mD\n"),
202 Settings.grid_unit->allow,
203 violation->x, violation->y);
204 GotoError ();
207 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_violations )
209 Message (_("WARNING! Design Rule error - %s\n"), violation->title);
210 Message (_("%m+near location %$mD\n"),
211 Settings.grid_unit->allow,
212 violation->x, violation->y);
216 * message when asked about continuing DRC checks after next
217 * violation is found.
219 #define DRC_CONTINUE _("Press Next to continue DRC checking")
220 #define DRC_NEXT _("Next")
221 #define DRC_CANCEL _("Cancel")
223 static int
224 throw_drc_dialog(void)
226 int r;
228 if (gui->drc_gui != NULL)
230 r = gui->drc_gui->throw_drc_dialog ();
232 else
234 /* Fallback to formatting the violation message as text */
235 append_drc_dialog_message (DRC_CONTINUE);
236 r = gui->confirm_dialog (drc_dialog_message->str, DRC_CANCEL, DRC_NEXT);
237 reset_drc_dialog_message();
239 return r;
242 /* ---------------------------------------------------------------------------
243 * some local types
245 * the two 'dummy' structs for PVs and Pads are necessary for creating
246 * connection lists which include the element's name
248 typedef struct
250 void **Data; /* pointer to index data */
251 Cardinal Location, /* currently used position */
252 DrawLocation, Number, /* number of objects in list */
253 Size;
254 } ListType;
256 /* ---------------------------------------------------------------------------
257 * some local identifiers
259 static Coord Bloat = 0;
260 static void *thing_ptr1, *thing_ptr2, *thing_ptr3;
261 static int thing_type;
262 static bool User = false; /* user action causing this */
263 static bool drc = false; /* whether to stop if finding something not found */
264 static Cardinal drcerr_count; /* count of drc errors */
265 static Cardinal TotalP, TotalV;
266 static ListType LineList[MAX_LAYER], /* list of objects to */
267 PolygonList[MAX_LAYER], ArcList[MAX_LAYER], PadList[2], RatList, PVList;
269 /* ---------------------------------------------------------------------------
270 * some local prototypes
272 static bool LookupLOConnectionsToLine (LineType *, Cardinal, int, bool, bool);
273 static bool LookupLOConnectionsToPad (PadType *, Cardinal, int, bool);
274 static bool LookupLOConnectionsToPolygon (PolygonType *, Cardinal, int, bool);
275 static bool LookupLOConnectionsToArc (ArcType *, Cardinal, int, bool);
276 static bool LookupLOConnectionsToRatEnd (PointType *, Cardinal, int);
277 static bool IsRatPointOnLineEnd (PointType *, LineType *);
278 static bool ArcArcIntersect (ArcType *, ArcType *);
279 static bool PrepareNextLoop (FILE *);
280 static void DrawNewConnections (void);
281 static void DumpList (void);
282 static void LocateError (Coord *, Coord *);
283 static void BuildObjectList (int *, long int **, int **);
284 static bool SetThing (int, void *, void *, void *);
285 static bool IsArcInPolygon (ArcType *, PolygonType *);
286 static bool IsLineInPolygon (LineType *, PolygonType *);
287 static bool IsPadInPolygon (PadType *, PolygonType *);
288 static bool IsPolygonInPolygon (PolygonType *, PolygonType *);
290 /* ---------------------------------------------------------------------------
291 * some of the 'pad' routines are the same as for lines because the 'pad'
292 * struct starts with a line struct. See global.h for details
294 bool
295 LinePadIntersect (LineType *Line, PadType *Pad)
297 return LineLineIntersect ((Line), (LineType *)Pad);
300 bool
301 ArcPadIntersect (ArcType *Arc, PadType *Pad)
303 return LineArcIntersect ((LineType *) (Pad), (Arc));
306 static bool
307 add_object_to_list (ListType *list, int type, void *ptr1, void *ptr2, void *ptr3, int flag)
309 AnyObjectType *object = (AnyObjectType *)ptr2;
311 if (User)
312 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3);
314 SET_FLAG (flag, object);
315 LIST_ENTRY (list, list->Number) = object;
316 list->Number++;
318 #ifdef DEBUG
319 if (list.Number > list.Size)
320 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type, list.Number, list.Size);
321 #endif
323 if (drc && !TEST_FLAG (SELECTEDFLAG, object))
324 return (SetThing (type, ptr1, ptr2, ptr3));
325 return false;
328 static bool
329 ADD_PV_TO_LIST (PinType *Pin, int flag)
331 return add_object_to_list (&PVList, Pin->Element ? PIN_TYPE : VIA_TYPE,
332 Pin->Element ? Pin->Element : Pin, Pin, Pin, flag);
335 static bool
336 ADD_PAD_TO_LIST (Cardinal L, PadType *Pad, int flag)
338 return add_object_to_list (&PadList[L], PAD_TYPE, Pad->Element, Pad, Pad, flag);
341 static bool
342 ADD_LINE_TO_LIST (Cardinal L, LineType *Ptr, int flag)
344 return add_object_to_list (&LineList[L], LINE_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
347 static bool
348 ADD_ARC_TO_LIST (Cardinal L, ArcType *Ptr, int flag)
350 return add_object_to_list (&ArcList[L], ARC_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
353 static bool
354 ADD_RAT_TO_LIST (RatType *Ptr, int flag)
356 return add_object_to_list (&RatList, RATLINE_TYPE, Ptr, Ptr, Ptr, flag);
359 static bool
360 ADD_POLYGON_TO_LIST (Cardinal L, PolygonType *Ptr, int flag)
362 return add_object_to_list (&PolygonList[L], POLYGON_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
365 static BoxType
366 expand_bounds (BoxType *box_in)
368 BoxType box_out = *box_in;
370 if (Bloat > 0)
372 box_out.X1 -= Bloat;
373 box_out.X2 += Bloat;
374 box_out.Y1 -= Bloat;
375 box_out.Y2 += Bloat;
378 return box_out;
381 bool
382 PinLineIntersect (PinType *PV, LineType *Line)
384 /* IsLineInRectangle already has Bloat factor */
385 return TEST_FLAG (SQUAREFLAG,
386 PV) ? IsLineInRectangle (PV->X - (PIN_SIZE (PV) + 1) / 2,
387 PV->Y - (PIN_SIZE (PV) + 1) / 2,
388 PV->X + (PIN_SIZE (PV) + 1) / 2,
389 PV->Y + (PIN_SIZE (PV) + 1) / 2,
390 Line) : IsPointInPad (PV->X,
391 PV->Y,
392 MAX (PIN_SIZE (PV)
394 2.0 +
395 Bloat,
396 0.0),
397 (PadType *)Line);
401 bool
402 SetThing (int type, void *ptr1, void *ptr2, void *ptr3)
404 thing_ptr1 = ptr1;
405 thing_ptr2 = ptr2;
406 thing_ptr3 = ptr3;
407 thing_type = type;
408 return true;
411 bool
412 BoxBoxIntersection (BoxType *b1, BoxType *b2)
414 if (b2->X2 < b1->X1 || b2->X1 > b1->X2)
415 return false;
416 if (b2->Y2 < b1->Y1 || b2->Y1 > b1->Y2)
417 return false;
418 return true;
421 static bool
422 PadPadIntersect (PadType *p1, PadType *p2)
424 return LinePadIntersect ((LineType *) p1, p2);
427 static inline bool
428 PV_TOUCH_PV (PinType *PV1, PinType *PV2)
430 double t1, t2;
431 BoxType b1, b2;
433 t1 = MAX (PV1->Thickness / 2.0 + Bloat, 0);
434 t2 = MAX (PV2->Thickness / 2.0 + Bloat, 0);
435 if (IsPointOnPin (PV1->X, PV1->Y, t1, PV2)
436 || IsPointOnPin (PV2->X, PV2->Y, t2, PV1))
437 return true;
438 if (!TEST_FLAG (SQUAREFLAG, PV1) || !TEST_FLAG (SQUAREFLAG, PV2))
439 return false;
440 /* check for square/square overlap */
441 b1.X1 = PV1->X - t1;
442 b1.X2 = PV1->X + t1;
443 b1.Y1 = PV1->Y - t1;
444 b1.Y2 = PV1->Y + t1;
445 t2 = PV2->Thickness / 2.0;
446 b2.X1 = PV2->X - t2;
447 b2.X2 = PV2->X + t2;
448 b2.Y1 = PV2->Y - t2;
449 b2.Y2 = PV2->Y + t2;
450 return BoxBoxIntersection (&b1, &b2);
453 /* ---------------------------------------------------------------------------
454 * releases all allocated memory
456 static void
457 FreeLayoutLookupMemory (void)
459 Cardinal i;
461 for (i = 0; i < max_copper_layer; i++)
463 free (LineList[i].Data);
464 LineList[i].Data = NULL;
465 free (ArcList[i].Data);
466 ArcList[i].Data = NULL;
467 free (PolygonList[i].Data);
468 PolygonList[i].Data = NULL;
470 free (PVList.Data);
471 PVList.Data = NULL;
472 free (RatList.Data);
473 RatList.Data = NULL;
476 static void
477 FreeComponentLookupMemory (void)
479 free (PadList[0].Data);
480 PadList[0].Data = NULL;
481 free (PadList[1].Data);
482 PadList[1].Data = NULL;
485 /* ---------------------------------------------------------------------------
486 * allocates memory for component related stacks ...
487 * initializes index and sorts it by X1 and X2
489 static void
490 InitComponentLookup (void)
492 Cardinal NumberOfPads[2];
493 Cardinal i;
495 /* initialize pad data; start by counting the total number
496 * on each of the two possible layers
498 NumberOfPads[COMPONENT_LAYER] = NumberOfPads[SOLDER_LAYER] = 0;
499 ALLPAD_LOOP (PCB->Data);
501 if (TEST_FLAG (ONSOLDERFLAG, pad))
502 NumberOfPads[SOLDER_LAYER]++;
503 else
504 NumberOfPads[COMPONENT_LAYER]++;
506 ENDALL_LOOP;
507 for (i = 0; i < 2; i++)
509 /* allocate memory for working list */
510 PadList[i].Data = (void **)calloc (NumberOfPads[i], sizeof (PadType *));
512 /* clear some struct members */
513 PadList[i].Location = 0;
514 PadList[i].DrawLocation = 0;
515 PadList[i].Number = 0;
516 PadList[i].Size = NumberOfPads[i];
520 /* ---------------------------------------------------------------------------
521 * allocates memory for component related stacks ...
522 * initializes index and sorts it by X1 and X2
524 static void
525 InitLayoutLookup (void)
527 Cardinal i;
529 /* initialize line arc and polygon data */
530 for (i = 0; i < max_copper_layer; i++)
532 LayerType *layer = LAYER_PTR (i);
534 if (layer->LineN)
536 /* allocate memory for line pointer lists */
537 LineList[i].Data = (void **)calloc (layer->LineN, sizeof (LineType *));
538 LineList[i].Size = layer->LineN;
540 if (layer->ArcN)
542 ArcList[i].Data = (void **)calloc (layer->ArcN, sizeof (ArcType *));
543 ArcList[i].Size = layer->ArcN;
547 /* allocate memory for polygon list */
548 if (layer->PolygonN)
550 PolygonList[i].Data = (void **)calloc (layer->PolygonN, sizeof (PolygonType *));
551 PolygonList[i].Size = layer->PolygonN;
554 /* clear some struct members */
555 LineList[i].Location = 0;
556 LineList[i].DrawLocation = 0;
557 LineList[i].Number = 0;
558 ArcList[i].Location = 0;
559 ArcList[i].DrawLocation = 0;
560 ArcList[i].Number = 0;
561 PolygonList[i].Location = 0;
562 PolygonList[i].DrawLocation = 0;
563 PolygonList[i].Number = 0;
566 if (PCB->Data->pin_tree)
567 TotalP = PCB->Data->pin_tree->size;
568 else
569 TotalP = 0;
570 if (PCB->Data->via_tree)
571 TotalV = PCB->Data->via_tree->size;
572 else
573 TotalV = 0;
574 /* allocate memory for 'new PV to check' list and clear struct */
575 PVList.Data = (void **)calloc (TotalP + TotalV, sizeof (PinType *));
576 PVList.Size = TotalP + TotalV;
577 PVList.Location = 0;
578 PVList.DrawLocation = 0;
579 PVList.Number = 0;
580 /* Initialize ratline data */
581 RatList.Data = (void **)calloc (PCB->Data->RatN, sizeof (RatType *));
582 RatList.Size = PCB->Data->RatN;
583 RatList.Location = 0;
584 RatList.DrawLocation = 0;
585 RatList.Number = 0;
588 struct pv_info
590 Cardinal layer;
591 PinType *pv;
592 int flag;
593 jmp_buf env;
596 static int
597 LOCtoPVline_callback (const BoxType * b, void *cl)
599 LineType *line = (LineType *) b;
600 struct pv_info *i = (struct pv_info *) cl;
602 if (!TEST_FLAG (i->flag, line) && PinLineIntersect (i->pv, line) &&
603 !TEST_FLAG (HOLEFLAG, i->pv))
605 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
606 longjmp (i->env, 1);
608 return 0;
611 static int
612 LOCtoPVarc_callback (const BoxType * b, void *cl)
614 ArcType *arc = (ArcType *) b;
615 struct pv_info *i = (struct pv_info *) cl;
617 if (!TEST_FLAG (i->flag, arc) && IS_PV_ON_ARC (i->pv, arc) &&
618 !TEST_FLAG (HOLEFLAG, i->pv))
620 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
621 longjmp (i->env, 1);
623 return 0;
626 static int
627 LOCtoPVpad_callback (const BoxType * b, void *cl)
629 PadType *pad = (PadType *) b;
630 struct pv_info *i = (struct pv_info *) cl;
632 if (!TEST_FLAG (i->flag, pad) && IS_PV_ON_PAD (i->pv, pad) &&
633 !TEST_FLAG (HOLEFLAG, i->pv) &&
634 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER :
635 COMPONENT_LAYER, pad, i->flag))
636 longjmp (i->env, 1);
637 return 0;
640 static int
641 LOCtoPVrat_callback (const BoxType * b, void *cl)
643 RatType *rat = (RatType *) b;
644 struct pv_info *i = (struct pv_info *) cl;
646 if (!TEST_FLAG (i->flag, rat) && IS_PV_ON_RAT (i->pv, rat) &&
647 ADD_RAT_TO_LIST (rat, i->flag))
648 longjmp (i->env, 1);
649 return 0;
651 static int
652 LOCtoPVpoly_callback (const BoxType * b, void *cl)
654 PolygonType *polygon = (PolygonType *) b;
655 struct pv_info *i = (struct pv_info *) cl;
657 /* if the pin doesn't have a therm and polygon is clearing
658 * then it can't touch due to clearance, so skip the expensive
659 * test. If it does have a therm, you still need to test
660 * because it might not be inside the polygon, or it could
661 * be on an edge such that it doesn't actually touch.
663 if (!TEST_FLAG (i->flag, polygon) && !TEST_FLAG (HOLEFLAG, i->pv) &&
664 (TEST_THERM (i->layer, i->pv) ||
665 !TEST_FLAG (CLEARPOLYFLAG,
666 polygon)
667 || !i->pv->Clearance))
669 double wide = MAX (0.5 * i->pv->Thickness + Bloat, 0);
670 if (TEST_FLAG (SQUAREFLAG, i->pv))
672 Coord x1 = i->pv->X - (i->pv->Thickness + 1 + Bloat) / 2;
673 Coord x2 = i->pv->X + (i->pv->Thickness + 1 + Bloat) / 2;
674 Coord y1 = i->pv->Y - (i->pv->Thickness + 1 + Bloat) / 2;
675 Coord y2 = i->pv->Y + (i->pv->Thickness + 1 + Bloat) / 2;
676 if (IsRectangleInPolygon (x1, y1, x2, y2, polygon)
677 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
678 longjmp (i->env, 1);
680 else if (TEST_FLAG (OCTAGONFLAG, i->pv))
682 POLYAREA *oct = OctagonPoly (i->pv->X, i->pv->Y, i->pv->Thickness / 2);
683 if (isects (oct, polygon, true)
684 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
685 longjmp (i->env, 1);
687 else if (IsPointInPolygon (i->pv->X, i->pv->Y, wide,
688 polygon)
689 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
690 longjmp (i->env, 1);
692 return 0;
695 /* ---------------------------------------------------------------------------
696 * checks if a PV is connected to LOs, if it is, the LO is added to
697 * the appropriate list and the 'used' flag is set
699 static bool
700 LookupLOConnectionsToPVList (int flag, bool AndRats)
702 Cardinal layer_no;
703 struct pv_info info;
705 info.flag = flag;
707 /* loop over all PVs currently on list */
708 while (PVList.Location < PVList.Number)
710 BoxType search_box;
712 /* get pointer to data */
713 info.pv = PVLIST_ENTRY (PVList.Location);
714 search_box = expand_bounds (&info.pv->BoundingBox);
716 /* check pads */
717 if (setjmp (info.env) == 0)
718 r_search (PCB->Data->pad_tree, &search_box, NULL,
719 LOCtoPVpad_callback, &info);
720 else
721 return true;
723 /* now all lines, arcs and polygons of the several layers */
724 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
726 LayerType *layer = LAYER_PTR (layer_no);
728 if (layer->no_drc)
729 continue;
731 info.layer = layer_no;
733 /* add touching lines */
734 if (setjmp (info.env) == 0)
735 r_search (layer->line_tree, &search_box,
736 NULL, LOCtoPVline_callback, &info);
737 else
738 return true;
739 /* add touching arcs */
740 if (setjmp (info.env) == 0)
741 r_search (layer->arc_tree, &search_box,
742 NULL, LOCtoPVarc_callback, &info);
743 else
744 return true;
745 /* check all polygons */
746 if (setjmp (info.env) == 0)
747 r_search (layer->polygon_tree, &search_box,
748 NULL, LOCtoPVpoly_callback, &info);
749 else
750 return true;
752 /* Check for rat-lines that may intersect the PV */
753 if (AndRats)
755 if (setjmp (info.env) == 0)
756 r_search (PCB->Data->rat_tree, &search_box, NULL,
757 LOCtoPVrat_callback, &info);
758 else
759 return true;
761 PVList.Location++;
763 return false;
766 /* ---------------------------------------------------------------------------
767 * find all connections between LO at the current list position and new LOs
769 static bool
770 LookupLOConnectionsToLOList (int flag, bool AndRats)
772 bool done;
773 Cardinal i, group, layer, ratposition,
774 lineposition[MAX_LAYER],
775 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2];
777 /* copy the current LO list positions; the original data is changed
778 * by 'LookupPVConnectionsToLOList()' which has to check the same
779 * list entries plus the new ones
781 for (i = 0; i < max_copper_layer; i++)
783 lineposition[i] = LineList[i].Location;
784 polyposition[i] = PolygonList[i].Location;
785 arcposition[i] = ArcList[i].Location;
787 for (i = 0; i < 2; i++)
788 padposition[i] = PadList[i].Location;
789 ratposition = RatList.Location;
791 /* loop over all new LOs in the list; recurse until no
792 * more new connections in the layergroup were found
796 Cardinal *position;
798 if (AndRats)
800 position = &ratposition;
801 for (; *position < RatList.Number; (*position)++)
803 group = RATLIST_ENTRY (*position)->group1;
804 if (LookupLOConnectionsToRatEnd
805 (&(RATLIST_ENTRY (*position)->Point1), group, flag))
806 return (true);
807 group = RATLIST_ENTRY (*position)->group2;
808 if (LookupLOConnectionsToRatEnd
809 (&(RATLIST_ENTRY (*position)->Point2), group, flag))
810 return (true);
813 /* loop over all layergroups */
814 for (group = 0; group < max_group; group++)
816 Cardinal entry;
818 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
820 layer = PCB->LayerGroups.Entries[group][entry];
822 /* be aware that the layer number equal max_copper_layer
823 * and max_copper_layer+1 have a special meaning for pads
825 if (layer < max_copper_layer)
827 /* try all new lines */
828 position = &lineposition[layer];
829 for (; *position < LineList[layer].Number; (*position)++)
830 if (LookupLOConnectionsToLine
831 (LINELIST_ENTRY (layer, *position), group, flag, true, AndRats))
832 return (true);
834 /* try all new arcs */
835 position = &arcposition[layer];
836 for (; *position < ArcList[layer].Number; (*position)++)
837 if (LookupLOConnectionsToArc
838 (ARCLIST_ENTRY (layer, *position), group, flag, AndRats))
839 return (true);
841 /* try all new polygons */
842 position = &polyposition[layer];
843 for (; *position < PolygonList[layer].Number; (*position)++)
844 if (LookupLOConnectionsToPolygon
845 (POLYGONLIST_ENTRY (layer, *position), group, flag, AndRats))
846 return (true);
848 else
850 /* try all new pads */
851 layer -= max_copper_layer;
852 if (layer > 1)
854 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
855 layer, max_copper_layer);
856 return false;
858 position = &padposition[layer];
859 for (; *position < PadList[layer].Number; (*position)++)
860 if (LookupLOConnectionsToPad
861 (PADLIST_ENTRY (layer, *position), group, flag, AndRats))
862 return (true);
867 /* check if all lists are done; Later for-loops
868 * may have changed the prior lists
870 done = !AndRats || ratposition >= RatList.Number;
871 done = done && padposition[0] >= PadList[0].Number &&
872 padposition[1] >= PadList[1].Number;
873 for (layer = 0; layer < max_copper_layer; layer++)
874 done = done &&
875 lineposition[layer] >= LineList[layer].Number &&
876 arcposition[layer] >= ArcList[layer].Number &&
877 polyposition[layer] >= PolygonList[layer].Number;
879 while (!done);
880 return (false);
883 static int
884 pv_pv_callback (const BoxType * b, void *cl)
886 PinType *pin = (PinType *) b;
887 struct pv_info *i = (struct pv_info *) cl;
889 if (!TEST_FLAG (i->flag, pin) && PV_TOUCH_PV (i->pv, pin))
891 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, i->pv))
893 SET_FLAG (WARNFLAG, pin);
894 Settings.RatWarn = true;
895 if (pin->Element)
896 Message (_("WARNING: Hole too close to pin.\n"));
897 else
898 Message (_("WARNING: Hole too close to via.\n"));
900 else if (ADD_PV_TO_LIST (pin, i->flag))
901 longjmp (i->env, 1);
903 return 0;
906 /* ---------------------------------------------------------------------------
907 * searches for new PVs that are connected to PVs on the list
909 static bool
910 LookupPVConnectionsToPVList (int flag)
912 Cardinal save_place;
913 struct pv_info info;
915 info.flag = flag;
917 /* loop over all PVs on list */
918 save_place = PVList.Location;
919 while (PVList.Location < PVList.Number)
921 BoxType search_box;
923 /* get pointer to data */
924 info.pv = PVLIST_ENTRY (PVList.Location);
925 search_box = expand_bounds ((BoxType *)info.pv);
927 if (setjmp (info.env) == 0)
928 r_search (PCB->Data->via_tree, &search_box, NULL,
929 pv_pv_callback, &info);
930 else
931 return true;
932 if (setjmp (info.env) == 0)
933 r_search (PCB->Data->pin_tree, &search_box, NULL,
934 pv_pv_callback, &info);
935 else
936 return true;
937 PVList.Location++;
939 PVList.Location = save_place;
940 return (false);
943 struct lo_info
945 Cardinal layer;
946 LineType *line;
947 PadType *pad;
948 ArcType *arc;
949 PolygonType *polygon;
950 RatType *rat;
951 int flag;
952 jmp_buf env;
955 static int
956 pv_line_callback (const BoxType * b, void *cl)
958 PinType *pv = (PinType *) b;
959 struct lo_info *i = (struct lo_info *) cl;
961 if (!TEST_FLAG (i->flag, pv) && PinLineIntersect (pv, i->line))
963 if (TEST_FLAG (HOLEFLAG, pv))
965 SET_FLAG (WARNFLAG, pv);
966 Settings.RatWarn = true;
967 Message (_("WARNING: Hole too close to line.\n"));
969 else if (ADD_PV_TO_LIST (pv, i->flag))
970 longjmp (i->env, 1);
972 return 0;
975 static int
976 pv_pad_callback (const BoxType * b, void *cl)
978 PinType *pv = (PinType *) b;
979 struct lo_info *i = (struct lo_info *) cl;
981 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_PAD (pv, i->pad))
983 if (TEST_FLAG (HOLEFLAG, pv))
985 SET_FLAG (WARNFLAG, pv);
986 Settings.RatWarn = true;
987 Message (_("WARNING: Hole too close to pad.\n"));
989 else if (ADD_PV_TO_LIST (pv, i->flag))
990 longjmp (i->env, 1);
992 return 0;
995 static int
996 pv_arc_callback (const BoxType * b, void *cl)
998 PinType *pv = (PinType *) b;
999 struct lo_info *i = (struct lo_info *) cl;
1001 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_ARC (pv, i->arc))
1003 if (TEST_FLAG (HOLEFLAG, pv))
1005 SET_FLAG (WARNFLAG, pv);
1006 Settings.RatWarn = true;
1007 Message (_("WARNING: Hole touches arc.\n"));
1009 else if (ADD_PV_TO_LIST (pv, i->flag))
1010 longjmp (i->env, 1);
1012 return 0;
1015 static int
1016 pv_poly_callback (const BoxType * b, void *cl)
1018 PinType *pv = (PinType *) b;
1019 struct lo_info *i = (struct lo_info *) cl;
1021 /* note that holes in polygons are ok, so they don't generate warnings. */
1022 if (!TEST_FLAG (i->flag, pv) && !TEST_FLAG (HOLEFLAG, pv) &&
1023 (TEST_THERM (i->layer, pv) ||
1024 !TEST_FLAG (CLEARPOLYFLAG, i->polygon) ||
1025 !pv->Clearance))
1027 if (TEST_FLAG (SQUAREFLAG, pv))
1029 Coord x1, x2, y1, y2;
1030 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1031 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1032 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1033 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1034 if (IsRectangleInPolygon (x1, y1, x2, y2, i->polygon)
1035 && ADD_PV_TO_LIST (pv, i->flag))
1036 longjmp (i->env, 1);
1038 else if (TEST_FLAG (OCTAGONFLAG, pv))
1040 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2);
1041 if (isects (oct, i->polygon, true) && ADD_PV_TO_LIST (pv, i->flag))
1042 longjmp (i->env, 1);
1044 else
1046 if (IsPointInPolygon
1047 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, i->polygon)
1048 && ADD_PV_TO_LIST (pv, i->flag))
1049 longjmp (i->env, 1);
1052 return 0;
1055 static int
1056 pv_rat_callback (const BoxType * b, void *cl)
1058 PinType *pv = (PinType *) b;
1059 struct lo_info *i = (struct lo_info *) cl;
1061 /* rats can't cause DRC so there is no early exit */
1062 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_RAT (pv, i->rat))
1063 ADD_PV_TO_LIST (pv, i->flag);
1064 return 0;
1067 /* ---------------------------------------------------------------------------
1068 * searches for new PVs that are connected to NEW LOs on the list
1069 * This routine updates the position counter of the lists too.
1071 static bool
1072 LookupPVConnectionsToLOList (int flag, bool AndRats)
1074 Cardinal layer_no;
1075 struct lo_info info;
1077 info.flag = flag;
1079 /* loop over all layers */
1080 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
1082 LayerType *layer = LAYER_PTR (layer_no);
1084 if (layer->no_drc)
1085 continue;
1086 /* do nothing if there are no PV's */
1087 if (TotalP + TotalV == 0)
1089 LineList[layer_no].Location = LineList[layer_no].Number;
1090 ArcList[layer_no].Location = ArcList[layer_no].Number;
1091 PolygonList[layer_no].Location = PolygonList[layer_no].Number;
1092 continue;
1095 /* check all lines */
1096 while (LineList[layer_no].Location < LineList[layer_no].Number)
1098 BoxType search_box;
1100 info.line = LINELIST_ENTRY (layer_no, LineList[layer_no].Location);
1101 search_box = expand_bounds ((BoxType *)info.line);
1103 if (setjmp (info.env) == 0)
1104 r_search (PCB->Data->via_tree, &search_box, NULL,
1105 pv_line_callback, &info);
1106 else
1107 return true;
1108 if (setjmp (info.env) == 0)
1109 r_search (PCB->Data->pin_tree, &search_box, NULL,
1110 pv_line_callback, &info);
1111 else
1112 return true;
1113 LineList[layer_no].Location++;
1116 /* check all arcs */
1117 while (ArcList[layer_no].Location < ArcList[layer_no].Number)
1119 BoxType search_box;
1121 info.arc = ARCLIST_ENTRY (layer_no, ArcList[layer_no].Location);
1122 search_box = expand_bounds ((BoxType *)info.arc);
1124 if (setjmp (info.env) == 0)
1125 r_search (PCB->Data->via_tree, &search_box, NULL,
1126 pv_arc_callback, &info);
1127 else
1128 return true;
1129 if (setjmp (info.env) == 0)
1130 r_search (PCB->Data->pin_tree, &search_box, NULL,
1131 pv_arc_callback, &info);
1132 else
1133 return true;
1134 ArcList[layer_no].Location++;
1137 /* now all polygons */
1138 info.layer = layer_no;
1139 while (PolygonList[layer_no].Location < PolygonList[layer_no].Number)
1141 BoxType search_box;
1143 info.polygon = POLYGONLIST_ENTRY (layer_no, PolygonList[layer_no].Location);
1144 search_box = expand_bounds ((BoxType *)info.polygon);
1146 if (setjmp (info.env) == 0)
1147 r_search (PCB->Data->via_tree, &search_box, NULL,
1148 pv_poly_callback, &info);
1149 else
1150 return true;
1151 if (setjmp (info.env) == 0)
1152 r_search (PCB->Data->pin_tree, &search_box, NULL,
1153 pv_poly_callback, &info);
1154 else
1155 return true;
1156 PolygonList[layer_no].Location++;
1160 /* loop over all pad-layers */
1161 for (layer_no = 0; layer_no < 2; layer_no++)
1163 /* do nothing if there are no PV's */
1164 if (TotalP + TotalV == 0)
1166 PadList[layer_no].Location = PadList[layer_no].Number;
1167 continue;
1170 /* check all pads; for a detailed description see
1171 * the handling of lines in this subroutine
1173 while (PadList[layer_no].Location < PadList[layer_no].Number)
1175 BoxType search_box;
1177 info.pad = PADLIST_ENTRY (layer_no, PadList[layer_no].Location);
1178 search_box = expand_bounds ((BoxType *)info.pad);
1180 if (setjmp (info.env) == 0)
1181 r_search (PCB->Data->via_tree, &search_box, NULL,
1182 pv_pad_callback, &info);
1183 else
1184 return true;
1185 if (setjmp (info.env) == 0)
1186 r_search (PCB->Data->pin_tree, &search_box, NULL,
1187 pv_pad_callback, &info);
1188 else
1189 return true;
1190 PadList[layer_no].Location++;
1194 /* do nothing if there are no PV's */
1195 if (TotalP + TotalV == 0)
1196 RatList.Location = RatList.Number;
1198 /* check all rat-lines */
1199 if (AndRats)
1201 while (RatList.Location < RatList.Number)
1203 info.rat = RATLIST_ENTRY (RatList.Location);
1204 r_search_pt (PCB->Data->via_tree, & info.rat->Point1, 1, NULL,
1205 pv_rat_callback, &info);
1206 r_search_pt (PCB->Data->via_tree, & info.rat->Point2, 1, NULL,
1207 pv_rat_callback, &info);
1208 r_search_pt (PCB->Data->pin_tree, & info.rat->Point1, 1, NULL,
1209 pv_rat_callback, &info);
1210 r_search_pt (PCB->Data->pin_tree, & info.rat->Point2, 1, NULL,
1211 pv_rat_callback, &info);
1213 RatList.Location++;
1216 return (false);
1219 /* reduce arc start angle and delta to 0..360 */
1220 static void
1221 normalize_angles (Angle *sa, Angle *d)
1223 if (*d < 0)
1225 *sa += *d;
1226 *d = - *d;
1228 if (*d > 360) /* full circle */
1229 *d = 360;
1230 *sa = NormalizeAngle (*sa);
1233 static int
1234 radius_crosses_arc (double x, double y, ArcType *arc)
1236 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG;
1237 Angle sa = arc->StartAngle, d = arc->Delta;
1239 normalize_angles (&sa, &d);
1240 if (alpha < 0)
1241 alpha += 360;
1242 if (sa <= alpha)
1243 return (sa + d) >= alpha;
1244 return (sa + d - 360) >= alpha;
1247 static void
1248 get_arc_ends (Coord *box, ArcType *arc)
1250 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle);
1251 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle);
1252 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta));
1253 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta));
1255 /* ---------------------------------------------------------------------------
1256 * check if two arcs intersect
1257 * first we check for circle intersections,
1258 * then find the actual points of intersection
1259 * and test them to see if they are on arcs
1261 * consider a, the distance from the center of arc 1
1262 * to the point perpendicular to the intersecting points.
1264 * a = (r1^2 - r2^2 + l^2)/(2l)
1266 * the perpendicular distance to the point of intersection
1267 * is then
1269 * d = sqrt(r1^2 - a^2)
1271 * the points of intersection would then be
1273 * x = X1 + a/l dx +- d/l dy
1274 * y = Y1 + a/l dy -+ d/l dx
1276 * where dx = X2 - X1 and dy = Y2 - Y1
1280 static bool
1281 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2)
1283 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl;
1284 Coord pdx, pdy;
1285 Coord box[8];
1287 t = 0.5 * Arc1->Thickness + Bloat;
1288 t2 = 0.5 * Arc2->Thickness;
1289 t1 = t2 + Bloat;
1291 /* too thin arc */
1292 if (t < 0 || t1 < 0)
1293 return false;
1295 /* try the end points first */
1296 get_arc_ends (&box[0], Arc1);
1297 get_arc_ends (&box[4], Arc2);
1298 if (IsPointOnArc (box[0], box[1], t, Arc2)
1299 || IsPointOnArc (box[2], box[3], t, Arc2)
1300 || IsPointOnArc (box[4], box[5], t, Arc1)
1301 || IsPointOnArc (box[6], box[7], t, Arc1))
1302 return true;
1304 pdx = Arc2->X - Arc1->X;
1305 pdy = Arc2->Y - Arc1->Y;
1306 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y);
1307 /* concentric arcs, simpler intersection conditions */
1308 if (dl < 0.5)
1310 if ((Arc1->Width - t >= Arc2->Width - t2
1311 && Arc1->Width - t <= Arc2->Width + t2)
1312 || (Arc1->Width + t >= Arc2->Width - t2
1313 && Arc1->Width + t <= Arc2->Width + t2))
1315 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta;
1316 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta;
1317 /* NB the endpoints have already been checked,
1318 so we just compare the angles */
1320 normalize_angles (&sa1, &d1);
1321 normalize_angles (&sa2, &d2);
1322 /* sa1 == sa2 was caught when checking endpoints */
1323 if (sa1 > sa2)
1324 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2)
1325 return true;
1326 if (sa2 > sa1)
1327 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1)
1328 return true;
1330 return false;
1332 r1 = Arc1->Width;
1333 r2 = Arc2->Width;
1334 /* arcs centerlines are too far or too near */
1335 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1)
1337 /* check the nearest to the other arc's center point */
1338 dx = pdx * r1 / dl;
1339 dy = pdy * r1 / dl;
1340 if (dl + r1 < r2) /* Arc1 inside Arc2 */
1342 dx = - dx;
1343 dy = - dy;
1346 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1)
1347 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2))
1348 return true;
1350 dx = - pdx * r2 / dl;
1351 dy = - pdy * r2 / dl;
1352 if (dl + r2 < r1) /* Arc2 inside Arc1 */
1354 dx = - dx;
1355 dy = - dy;
1358 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2)
1359 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1))
1360 return true;
1361 return false;
1364 l = dl * dl;
1365 r1 *= r1;
1366 r2 *= r2;
1367 a = 0.5 * (r1 - r2 + l) / l;
1368 r1 = r1 / l;
1369 d = r1 - a * a;
1370 /* the circles are too far apart to touch or probably just touch:
1371 check the nearest point */
1372 if (d < 0)
1373 d = 0;
1374 else
1375 d = sqrt (d);
1376 x = Arc1->X + a * pdx;
1377 y = Arc1->Y + a * pdy;
1378 dx = d * pdx;
1379 dy = d * pdy;
1380 if (radius_crosses_arc (x + dy, y - dx, Arc1)
1381 && IsPointOnArc (x + dy, y - dx, t, Arc2))
1382 return true;
1383 if (radius_crosses_arc (x + dy, y - dx, Arc2)
1384 && IsPointOnArc (x + dy, y - dx, t1, Arc1))
1385 return true;
1387 if (radius_crosses_arc (x - dy, y + dx, Arc1)
1388 && IsPointOnArc (x - dy, y + dx, t, Arc2))
1389 return true;
1390 if (radius_crosses_arc (x - dy, y + dx, Arc2)
1391 && IsPointOnArc (x - dy, y + dx, t1, Arc1))
1392 return true;
1393 return false;
1396 /* ---------------------------------------------------------------------------
1397 * Tests if point is same as line end point
1399 static bool
1400 IsRatPointOnLineEnd (PointType *Point, LineType *Line)
1402 if ((Point->X == Line->Point1.X
1403 && Point->Y == Line->Point1.Y)
1404 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y))
1405 return (true);
1406 return (false);
1409 static void
1410 form_slanted_rectangle (PointType p[4], LineType *l)
1411 /* writes vertices of a squared line */
1413 double dwx = 0, dwy = 0;
1414 if (l->Point1.Y == l->Point2.Y)
1415 dwx = l->Thickness / 2.0;
1416 else if (l->Point1.X == l->Point2.X)
1417 dwy = l->Thickness / 2.0;
1418 else
1420 Coord dX = l->Point2.X - l->Point1.X;
1421 Coord dY = l->Point2.Y - l->Point1.Y;
1422 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y);
1423 dwx = l->Thickness / 2.0 / r * dX;
1424 dwy = l->Thickness / 2.0 / r * dY;
1426 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx;
1427 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx;
1428 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx;
1429 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx;
1431 /* ---------------------------------------------------------------------------
1432 * checks if two lines intersect
1433 * from news FAQ:
1435 * Let A,B,C,D be 2-space position vectors. Then the directed line
1436 * segments AB & CD are given by:
1438 * AB=A+r(B-A), r in [0,1]
1439 * CD=C+s(D-C), s in [0,1]
1441 * If AB & CD intersect, then
1443 * A+r(B-A)=C+s(D-C), or
1445 * XA+r(XB-XA)=XC+s(XD-XC)
1446 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1448 * Solving the above for r and s yields
1450 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1451 * r = ----------------------------- (eqn 1)
1452 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1454 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1455 * s = ----------------------------- (eqn 2)
1456 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1458 * Let I be the position vector of the intersection point, then
1460 * I=A+r(B-A) or
1462 * XI=XA+r(XB-XA)
1463 * YI=YA+r(YB-YA)
1465 * By examining the values of r & s, you can also determine some
1466 * other limiting conditions:
1468 * If 0<=r<=1 & 0<=s<=1, intersection exists
1469 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1471 * If the denominator in eqn 1 is zero, AB & CD are parallel
1472 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1474 * If the intersection point of the 2 lines are needed (lines in this
1475 * context mean infinite lines) regardless whether the two line
1476 * segments intersect, then
1478 * If r>1, I is located on extension of AB
1479 * If r<0, I is located on extension of BA
1480 * If s>1, I is located on extension of CD
1481 * If s<0, I is located on extension of DC
1483 * Also note that the denominators of eqn 1 & 2 are identical.
1486 bool
1487 LineLineIntersect (LineType *Line1, LineType *Line2)
1489 double s, r;
1490 double line1_dx, line1_dy, line2_dx, line2_dy,
1491 point1_dx, point1_dy;
1492 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */
1494 PointType p[4];
1495 form_slanted_rectangle (p, Line1);
1496 return IsLineInQuadrangle (p, Line2);
1498 /* here come only round Line1 because IsLineInQuadrangle()
1499 calls LineLineIntersect() with first argument rounded*/
1500 if (TEST_FLAG (SQUAREFLAG, Line2))
1502 PointType p[4];
1503 form_slanted_rectangle (p, Line2);
1504 return IsLineInQuadrangle (p, Line1);
1506 /* now all lines are round */
1508 /* Check endpoints: this provides a quick exit, catches
1509 * cases where the "real" lines don't intersect but the
1510 * thick lines touch, and ensures that the dx/dy business
1511 * below does not cause a divide-by-zero. */
1512 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y,
1513 MAX (Line2->Thickness / 2 + Bloat, 0),
1514 (PadType *) Line1)
1515 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y,
1516 MAX (Line2->Thickness / 2 + Bloat, 0),
1517 (PadType *) Line1)
1518 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y,
1519 MAX (Line1->Thickness / 2 + Bloat, 0),
1520 (PadType *) Line2)
1521 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y,
1522 MAX (Line1->Thickness / 2 + Bloat, 0),
1523 (PadType *) Line2))
1524 return true;
1526 /* setup some constants */
1527 line1_dx = Line1->Point2.X - Line1->Point1.X;
1528 line1_dy = Line1->Point2.Y - Line1->Point1.Y;
1529 line2_dx = Line2->Point2.X - Line2->Point1.X;
1530 line2_dy = Line2->Point2.Y - Line2->Point1.Y;
1531 point1_dx = Line1->Point1.X - Line2->Point1.X;
1532 point1_dy = Line1->Point1.Y - Line2->Point1.Y;
1534 /* If either line is a point, we have failed already, since the
1535 * endpoint check above will have caught an "intersection". */
1536 if ((line1_dx == 0 && line1_dy == 0)
1537 || (line2_dx == 0 && line2_dy == 0))
1538 return false;
1540 /* set s to cross product of Line1 and the line
1541 * Line1.Point1--Line2.Point1 (as vectors) */
1542 s = point1_dy * line1_dx - point1_dx * line1_dy;
1544 /* set r to cross product of both lines (as vectors) */
1545 r = line1_dx * line2_dy - line1_dy * line2_dx;
1547 /* No cross product means parallel lines, or maybe Line2 is
1548 * zero-length. In either case, since we did a bounding-box
1549 * check before getting here, the above IsPointInPad() checks
1550 * will have caught any intersections. */
1551 if (r == 0.0)
1552 return false;
1554 s /= r;
1555 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r;
1557 /* intersection is at least on AB */
1558 if (r >= 0.0 && r <= 1.0)
1559 return (s >= 0.0 && s <= 1.0);
1561 /* intersection is at least on CD */
1562 /* [removed this case since it always returns false --asp] */
1563 return false;
1566 /*---------------------------------------------------
1568 * Check for line intersection with an arc
1570 * Mostly this is like the circle/line intersection
1571 * found in IsPointOnLine (search.c) see the detailed
1572 * discussion for the basics there.
1574 * Since this is only an arc, not a full circle we need
1575 * to find the actual points of intersection with the
1576 * circle, and see if they are on the arc.
1578 * To do this, we translate along the line from the point Q
1579 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1580 * but it's handy to normalize with respect to l, the line
1581 * length so a single projection is done (e.g. we don't first
1582 * find the point Q
1584 * The projection is now of the form
1586 * Px = X1 + (r +- r2)(X2 - X1)
1587 * Py = Y1 + (r +- r2)(Y2 - Y1)
1589 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1590 * note that this is the variable d, not the symbol d described in IsPointOnLine
1591 * (variable d = symbol d * l)
1593 * The end points are hell so they are checked individually
1595 bool
1596 LineArcIntersect (LineType *Line, ArcType *Arc)
1598 double dx, dy, dx1, dy1, l, d, r, r2, Radius;
1599 BoxType *box;
1601 dx = Line->Point2.X - Line->Point1.X;
1602 dy = Line->Point2.Y - Line->Point1.Y;
1603 dx1 = Line->Point1.X - Arc->X;
1604 dy1 = Line->Point1.Y - Arc->Y;
1605 l = dx * dx + dy * dy;
1606 d = dx * dy1 - dy * dx1;
1607 d *= d;
1609 /* use the larger diameter circle first */
1610 Radius =
1611 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0);
1612 Radius *= Radius;
1613 r2 = Radius * l - d;
1614 /* projection doesn't even intersect circle when r2 < 0 */
1615 if (r2 < 0)
1616 return (false);
1617 /* check the ends of the line in case the projected point */
1618 /* of intersection is beyond the line end */
1619 if (IsPointOnArc
1620 (Line->Point1.X, Line->Point1.Y,
1621 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1622 return (true);
1623 if (IsPointOnArc
1624 (Line->Point2.X, Line->Point2.Y,
1625 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1626 return (true);
1627 if (l == 0.0)
1628 return (false);
1629 r2 = sqrt (r2);
1630 Radius = -(dx * dx1 + dy * dy1);
1631 r = (Radius + r2) / l;
1632 if (r >= 0 && r <= 1
1633 && IsPointOnArc (Line->Point1.X + r * dx,
1634 Line->Point1.Y + r * dy,
1635 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1636 return (true);
1637 r = (Radius - r2) / l;
1638 if (r >= 0 && r <= 1
1639 && IsPointOnArc (Line->Point1.X + r * dx,
1640 Line->Point1.Y + r * dy,
1641 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1642 return (true);
1643 /* check arc end points */
1644 box = GetArcEnds (Arc);
1645 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1646 return true;
1647 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1648 return true;
1649 return false;
1652 static int
1653 LOCtoArcLine_callback (const BoxType * b, void *cl)
1655 LineType *line = (LineType *) b;
1656 struct lo_info *i = (struct lo_info *) cl;
1658 if (!TEST_FLAG (i->flag, line) && LineArcIntersect (line, i->arc))
1660 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1661 longjmp (i->env, 1);
1663 return 0;
1666 static int
1667 LOCtoArcArc_callback (const BoxType * b, void *cl)
1669 ArcType *arc = (ArcType *) b;
1670 struct lo_info *i = (struct lo_info *) cl;
1672 if (!arc->Thickness)
1673 return 0;
1674 if (!TEST_FLAG (i->flag, arc) && ArcArcIntersect (i->arc, arc))
1676 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
1677 longjmp (i->env, 1);
1679 return 0;
1682 static int
1683 LOCtoArcPad_callback (const BoxType * b, void *cl)
1685 PadType *pad = (PadType *) b;
1686 struct lo_info *i = (struct lo_info *) cl;
1688 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1689 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1690 && ArcPadIntersect (i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
1691 longjmp (i->env, 1);
1692 return 0;
1695 /* ---------------------------------------------------------------------------
1696 * searches all LOs that are connected to the given arc on the given
1697 * layergroup. All found connections are added to the list
1699 * the notation that is used is:
1700 * Xij means Xj at arc i
1702 static bool
1703 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup, int flag, bool AndRats)
1705 Cardinal entry;
1706 struct lo_info info;
1707 BoxType search_box;
1709 info.flag = flag;
1710 info.arc = Arc;
1711 search_box = expand_bounds ((BoxType *)info.arc);
1713 /* loop over all layers of the group */
1714 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1716 Cardinal layer_no;
1717 LayerType *layer;
1718 GList *i;
1720 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1721 layer = LAYER_PTR (layer_no);
1723 /* handle normal layers */
1724 if (layer_no < max_copper_layer)
1726 info.layer = layer_no;
1727 /* add arcs */
1728 if (setjmp (info.env) == 0)
1729 r_search (layer->line_tree, &search_box,
1730 NULL, LOCtoArcLine_callback, &info);
1731 else
1732 return true;
1734 if (setjmp (info.env) == 0)
1735 r_search (layer->arc_tree, &search_box,
1736 NULL, LOCtoArcArc_callback, &info);
1737 else
1738 return true;
1740 /* now check all polygons */
1741 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1743 PolygonType *polygon = i->data;
1744 if (!TEST_FLAG (flag, polygon) && IsArcInPolygon (Arc, polygon)
1745 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
1746 return true;
1749 else
1751 info.layer = layer_no - max_copper_layer;
1752 if (setjmp (info.env) == 0)
1753 r_search (PCB->Data->pad_tree, &search_box, NULL,
1754 LOCtoArcPad_callback, &info);
1755 else
1756 return true;
1759 return (false);
1762 static int
1763 LOCtoLineLine_callback (const BoxType * b, void *cl)
1765 LineType *line = (LineType *) b;
1766 struct lo_info *i = (struct lo_info *) cl;
1768 if (!TEST_FLAG (i->flag, line) && LineLineIntersect (i->line, line))
1770 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1771 longjmp (i->env, 1);
1773 return 0;
1776 static int
1777 LOCtoLineArc_callback (const BoxType * b, void *cl)
1779 ArcType *arc = (ArcType *) b;
1780 struct lo_info *i = (struct lo_info *) cl;
1782 if (!arc->Thickness)
1783 return 0;
1784 if (!TEST_FLAG (i->flag, arc) && LineArcIntersect (i->line, arc))
1786 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
1787 longjmp (i->env, 1);
1789 return 0;
1792 static int
1793 LOCtoLineRat_callback (const BoxType * b, void *cl)
1795 RatType *rat = (RatType *) b;
1796 struct lo_info *i = (struct lo_info *) cl;
1798 if (!TEST_FLAG (i->flag, rat))
1800 if ((rat->group1 == i->layer)
1801 && IsRatPointOnLineEnd (&rat->Point1, i->line))
1803 if (ADD_RAT_TO_LIST (rat, i->flag))
1804 longjmp (i->env, 1);
1806 else if ((rat->group2 == i->layer)
1807 && IsRatPointOnLineEnd (&rat->Point2, i->line))
1809 if (ADD_RAT_TO_LIST (rat, i->flag))
1810 longjmp (i->env, 1);
1813 return 0;
1816 static int
1817 LOCtoLinePad_callback (const BoxType * b, void *cl)
1819 PadType *pad = (PadType *) b;
1820 struct lo_info *i = (struct lo_info *) cl;
1822 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1823 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1824 && LinePadIntersect (i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
1825 longjmp (i->env, 1);
1826 return 0;
1829 /* ---------------------------------------------------------------------------
1830 * searches all LOs that are connected to the given line on the given
1831 * layergroup. All found connections are added to the list
1833 * the notation that is used is:
1834 * Xij means Xj at line i
1836 static bool
1837 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup,
1838 int flag, bool PolysTo, bool AndRats)
1840 Cardinal entry;
1841 struct lo_info info;
1842 BoxType search_box;
1844 info.flag = flag;
1845 info.layer = LayerGroup;
1846 info.line = Line;
1847 search_box = expand_bounds ((BoxType *)info.line);
1849 if (AndRats)
1851 /* add the new rat lines */
1852 if (setjmp (info.env) == 0)
1853 r_search (PCB->Data->rat_tree, &search_box, NULL,
1854 LOCtoLineRat_callback, &info);
1855 else
1856 return true;
1859 /* loop over all layers of the group */
1860 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1862 Cardinal layer_no;
1863 LayerType *layer;
1865 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1866 layer = LAYER_PTR (layer_no);
1868 /* handle normal layers */
1869 if (layer_no < max_copper_layer)
1871 info.layer = layer_no;
1872 /* add lines */
1873 if (setjmp (info.env) == 0)
1874 r_search (layer->line_tree, &search_box,
1875 NULL, LOCtoLineLine_callback, &info);
1876 else
1877 return true;
1878 /* add arcs */
1879 if (setjmp (info.env) == 0)
1880 r_search (layer->arc_tree, &search_box,
1881 NULL, LOCtoLineArc_callback, &info);
1882 else
1883 return true;
1884 /* now check all polygons */
1885 if (PolysTo)
1887 GList *i;
1888 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1890 PolygonType *polygon = i->data;
1891 if (!TEST_FLAG (flag, polygon) && IsLineInPolygon (Line, polygon)
1892 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
1893 return true;
1897 else
1899 /* handle special 'pad' layers */
1900 info.layer = layer_no - max_copper_layer;
1901 if (setjmp (info.env) == 0)
1902 r_search (PCB->Data->pad_tree, &search_box, NULL,
1903 LOCtoLinePad_callback, &info);
1904 else
1905 return true;
1908 return (false);
1911 struct rat_info
1913 Cardinal layer;
1914 PointType *Point;
1915 int flag;
1916 jmp_buf env;
1919 static int
1920 LOCtoRat_callback (const BoxType * b, void *cl)
1922 LineType *line = (LineType *) b;
1923 struct rat_info *i = (struct rat_info *) cl;
1925 if (!TEST_FLAG (i->flag, line) &&
1926 ((line->Point1.X == i->Point->X &&
1927 line->Point1.Y == i->Point->Y) ||
1928 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y)))
1930 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1931 longjmp (i->env, 1);
1933 return 0;
1935 static int
1936 PolygonToRat_callback (const BoxType * b, void *cl)
1938 PolygonType *polygon = (PolygonType *) b;
1939 struct rat_info *i = (struct rat_info *) cl;
1941 if (!TEST_FLAG (i->flag, polygon) && polygon->Clipped &&
1942 (i->Point->X == polygon->Clipped->contours->head.point[0]) &&
1943 (i->Point->Y == polygon->Clipped->contours->head.point[1]))
1945 if (ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
1946 longjmp (i->env, 1);
1948 return 0;
1951 static int
1952 LOCtoPad_callback (const BoxType * b, void *cl)
1954 PadType *pad = (PadType *) b;
1955 struct rat_info *i = (struct rat_info *) cl;
1957 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1958 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER) &&
1959 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) ||
1960 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) ||
1961 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X &&
1962 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) &&
1963 ADD_PAD_TO_LIST (i->layer, pad, i->flag))
1964 longjmp (i->env, 1);
1965 return 0;
1968 /* ---------------------------------------------------------------------------
1969 * searches all LOs that are connected to the given rat-line on the given
1970 * layergroup. All found connections are added to the list
1972 * the notation that is used is:
1973 * Xij means Xj at line i
1975 static bool
1976 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup, int flag)
1978 Cardinal entry;
1979 struct rat_info info;
1981 info.flag = flag;
1982 info.Point = Point;
1983 /* loop over all layers of this group */
1984 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1986 Cardinal layer_no;
1987 LayerType *layer;
1989 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1990 layer = LAYER_PTR (layer_no);
1991 /* handle normal layers
1992 rats don't ever touch
1993 arcs by definition
1996 if (layer_no < max_copper_layer)
1998 info.layer = layer_no;
1999 if (setjmp (info.env) == 0)
2000 r_search_pt (layer->line_tree, Point, 1, NULL,
2001 LOCtoRat_callback, &info);
2002 else
2003 return true;
2004 if (setjmp (info.env) == 0)
2005 r_search_pt (layer->polygon_tree, Point, 1,
2006 NULL, PolygonToRat_callback, &info);
2008 else
2010 /* handle special 'pad' layers */
2011 info.layer = layer_no - max_copper_layer;
2012 if (setjmp (info.env) == 0)
2013 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL,
2014 LOCtoPad_callback, &info);
2015 else
2016 return true;
2019 return (false);
2022 static int
2023 LOCtoPadLine_callback (const BoxType * b, void *cl)
2025 LineType *line = (LineType *) b;
2026 struct lo_info *i = (struct lo_info *) cl;
2028 if (!TEST_FLAG (i->flag, line) && LinePadIntersect (line, i->pad))
2030 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
2031 longjmp (i->env, 1);
2033 return 0;
2036 static int
2037 LOCtoPadArc_callback (const BoxType * b, void *cl)
2039 ArcType *arc = (ArcType *) b;
2040 struct lo_info *i = (struct lo_info *) cl;
2042 if (!arc->Thickness)
2043 return 0;
2044 if (!TEST_FLAG (i->flag, arc) && ArcPadIntersect (arc, i->pad))
2046 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
2047 longjmp (i->env, 1);
2049 return 0;
2052 static int
2053 LOCtoPadPoly_callback (const BoxType * b, void *cl)
2055 PolygonType *polygon = (PolygonType *) b;
2056 struct lo_info *i = (struct lo_info *) cl;
2059 if (!TEST_FLAG (i->flag, polygon) &&
2060 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad->Clearance))
2062 if (IsPadInPolygon (i->pad, polygon) &&
2063 ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
2064 longjmp (i->env, 1);
2066 return 0;
2069 static int
2070 LOCtoPadRat_callback (const BoxType * b, void *cl)
2072 RatType *rat = (RatType *) b;
2073 struct lo_info *i = (struct lo_info *) cl;
2075 if (!TEST_FLAG (i->flag, rat))
2077 if (rat->group1 == i->layer &&
2078 ((rat->Point1.X == i->pad->Point1.X && rat->Point1.Y == i->pad->Point1.Y) ||
2079 (rat->Point1.X == i->pad->Point2.X && rat->Point1.Y == i->pad->Point2.Y) ||
2080 (rat->Point1.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 &&
2081 rat->Point1.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2)))
2083 if (ADD_RAT_TO_LIST (rat, i->flag))
2084 longjmp (i->env, 1);
2086 else if (rat->group2 == i->layer &&
2087 ((rat->Point2.X == i->pad->Point1.X && rat->Point2.Y == i->pad->Point1.Y) ||
2088 (rat->Point2.X == i->pad->Point2.X && rat->Point2.Y == i->pad->Point2.Y) ||
2089 (rat->Point2.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 &&
2090 rat->Point2.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2)))
2092 if (ADD_RAT_TO_LIST (rat, i->flag))
2093 longjmp (i->env, 1);
2096 return 0;
2099 static int
2100 LOCtoPadPad_callback (const BoxType * b, void *cl)
2102 PadType *pad = (PadType *) b;
2103 struct lo_info *i = (struct lo_info *) cl;
2105 if (!TEST_FLAG (i->flag, pad) && i->layer ==
2106 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2107 && PadPadIntersect (pad, i->pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
2108 longjmp (i->env, 1);
2109 return 0;
2112 /* ---------------------------------------------------------------------------
2113 * searches all LOs that are connected to the given pad on the given
2114 * layergroup. All found connections are added to the list
2116 static bool
2117 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup, int flag, bool AndRats)
2119 Cardinal entry;
2120 struct lo_info info;
2121 BoxType search_box;
2123 if (!TEST_FLAG (SQUAREFLAG, Pad))
2124 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, flag, false, AndRats));
2126 info.flag = flag;
2127 info.pad = Pad;
2128 search_box = expand_bounds ((BoxType *)info.pad);
2130 /* add the new rat lines */
2131 info.layer = LayerGroup;
2133 if (AndRats)
2135 if (setjmp (info.env) == 0)
2136 r_search (PCB->Data->rat_tree, &search_box, NULL,
2137 LOCtoPadRat_callback, &info);
2138 else
2139 return true;
2142 /* loop over all layers of the group */
2143 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2145 Cardinal layer_no;
2146 LayerType *layer;
2148 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2149 layer = LAYER_PTR (layer_no);
2150 /* handle normal layers */
2151 if (layer_no < max_copper_layer)
2153 info.layer = layer_no;
2154 /* add lines */
2155 if (setjmp (info.env) == 0)
2156 r_search (layer->line_tree, &search_box,
2157 NULL, LOCtoPadLine_callback, &info);
2158 else
2159 return true;
2160 /* add arcs */
2161 if (setjmp (info.env) == 0)
2162 r_search (layer->arc_tree, &search_box,
2163 NULL, LOCtoPadArc_callback, &info);
2164 else
2165 return true;
2166 /* add polygons */
2167 if (setjmp (info.env) == 0)
2168 r_search (layer->polygon_tree, &search_box,
2169 NULL, LOCtoPadPoly_callback, &info);
2170 else
2171 return true;
2173 else
2175 /* handle special 'pad' layers */
2176 info.layer = layer_no - max_copper_layer;
2177 if (setjmp (info.env) == 0)
2178 r_search (PCB->Data->pad_tree, &search_box, NULL,
2179 LOCtoPadPad_callback, &info);
2180 else
2181 return true;
2185 return (false);
2188 static int
2189 LOCtoPolyLine_callback (const BoxType * b, void *cl)
2191 LineType *line = (LineType *) b;
2192 struct lo_info *i = (struct lo_info *) cl;
2194 if (!TEST_FLAG (i->flag, line) && IsLineInPolygon (line, i->polygon))
2196 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
2197 longjmp (i->env, 1);
2199 return 0;
2202 static int
2203 LOCtoPolyArc_callback (const BoxType * b, void *cl)
2205 ArcType *arc = (ArcType *) b;
2206 struct lo_info *i = (struct lo_info *) cl;
2208 if (!arc->Thickness)
2209 return 0;
2210 if (!TEST_FLAG (i->flag, arc) && IsArcInPolygon (arc, i->polygon))
2212 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
2213 longjmp (i->env, 1);
2215 return 0;
2218 static int
2219 LOCtoPolyPad_callback (const BoxType * b, void *cl)
2221 PadType *pad = (PadType *) b;
2222 struct lo_info *i = (struct lo_info *) cl;
2224 if (!TEST_FLAG (i->flag, pad) && i->layer ==
2225 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2226 && IsPadInPolygon (pad, i->polygon))
2228 if (ADD_PAD_TO_LIST (i->layer, pad, i->flag))
2229 longjmp (i->env, 1);
2231 return 0;
2234 static int
2235 LOCtoPolyRat_callback (const BoxType * b, void *cl)
2237 RatType *rat = (RatType *) b;
2238 struct lo_info *i = (struct lo_info *) cl;
2240 if (!TEST_FLAG (i->flag, rat))
2242 if ((rat->Point1.X == (i->polygon->Clipped->contours->head.point[0]) &&
2243 rat->Point1.Y == (i->polygon->Clipped->contours->head.point[1]) &&
2244 rat->group1 == i->layer) ||
2245 (rat->Point2.X == (i->polygon->Clipped->contours->head.point[0]) &&
2246 rat->Point2.Y == (i->polygon->Clipped->contours->head.point[1]) &&
2247 rat->group2 == i->layer))
2248 if (ADD_RAT_TO_LIST (rat, i->flag))
2249 longjmp (i->env, 1);
2251 return 0;
2255 /* ---------------------------------------------------------------------------
2256 * looks up LOs that are connected to the given polygon
2257 * on the given layergroup. All found connections are added to the list
2259 static bool
2260 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup, int flag, bool AndRats)
2262 Cardinal entry;
2263 struct lo_info info;
2264 BoxType search_box;
2266 if (!Polygon->Clipped)
2267 return false;
2269 info.flag = flag;
2270 info.polygon = Polygon;
2271 search_box = expand_bounds ((BoxType *)info.polygon);
2273 info.layer = LayerGroup;
2275 /* check rats */
2276 if (AndRats)
2278 if (setjmp (info.env) == 0)
2279 r_search (PCB->Data->rat_tree, &search_box, NULL,
2280 LOCtoPolyRat_callback, &info);
2281 else
2282 return true;
2285 /* loop over all layers of the group */
2286 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2288 Cardinal layer_no;
2289 LayerType *layer;
2291 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2292 layer = LAYER_PTR (layer_no);
2294 /* handle normal layers */
2295 if (layer_no < max_copper_layer)
2297 GList *i;
2299 /* check all polygons */
2300 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
2302 PolygonType *polygon = i->data;
2303 if (!TEST_FLAG (flag, polygon)
2304 && IsPolygonInPolygon (polygon, Polygon)
2305 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
2306 return true;
2309 info.layer = layer_no;
2310 /* check all lines */
2311 if (setjmp (info.env) == 0)
2312 r_search (layer->line_tree, &search_box,
2313 NULL, LOCtoPolyLine_callback, &info);
2314 else
2315 return true;
2316 /* check all arcs */
2317 if (setjmp (info.env) == 0)
2318 r_search (layer->arc_tree, &search_box,
2319 NULL, LOCtoPolyArc_callback, &info);
2320 else
2321 return true;
2323 else
2325 info.layer = layer_no - max_copper_layer;
2326 if (setjmp (info.env) == 0)
2327 r_search (PCB->Data->pad_tree, &search_box,
2328 NULL, LOCtoPolyPad_callback, &info);
2329 else
2330 return true;
2333 return (false);
2336 /* ---------------------------------------------------------------------------
2337 * checks if an arc has a connection to a polygon
2339 * - first check if the arc can intersect with the polygon by
2340 * evaluating the bounding boxes
2341 * - check the two end points of the arc. If none of them matches
2342 * - check all segments of the polygon against the arc.
2344 static bool
2345 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon)
2347 BoxType *Box = (BoxType *) Arc;
2349 /* arcs with clearance never touch polys */
2350 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc))
2351 return false;
2352 if (!Polygon->Clipped)
2353 return false;
2354 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2355 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2356 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2357 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2359 POLYAREA *ap;
2361 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat)))
2362 return false; /* error */
2363 return isects (ap, Polygon, true);
2365 return false;
2368 /* ---------------------------------------------------------------------------
2369 * checks if a line has a connection to a polygon
2371 * - first check if the line can intersect with the polygon by
2372 * evaluating the bounding boxes
2373 * - check the two end points of the line. If none of them matches
2374 * - check all segments of the polygon against the line.
2376 static bool
2377 IsLineInPolygon (LineType *Line, PolygonType *Polygon)
2379 BoxType *Box = (BoxType *) Line;
2380 POLYAREA *lp;
2382 /* lines with clearance never touch polygons */
2383 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line))
2384 return false;
2385 if (!Polygon->Clipped)
2386 return false;
2387 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y))
2389 Coord wid = (Line->Thickness + Bloat + 1) / 2;
2390 Coord x1, x2, y1, y2;
2392 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid;
2393 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid;
2394 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid;
2395 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid;
2396 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon);
2398 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2399 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2400 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2401 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2403 if (!(lp = LinePoly (Line, Line->Thickness + Bloat)))
2404 return FALSE; /* error */
2405 return isects (lp, Polygon, true);
2407 return false;
2410 /* ---------------------------------------------------------------------------
2411 * checks if a pad connects to a non-clearing polygon
2413 * The polygon is assumed to already have been proven non-clearing
2415 static bool
2416 IsPadInPolygon (PadType *pad, PolygonType *polygon)
2418 return IsLineInPolygon ((LineType *) pad, polygon);
2421 /* ---------------------------------------------------------------------------
2422 * checks if a polygon has a connection to a second one
2424 * First check all points out of P1 against P2 and vice versa.
2425 * If both fail check all lines of P1 against the ones of P2
2427 static bool
2428 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2)
2430 if (!P1->Clipped || !P2->Clipped)
2431 return false;
2432 assert (P1->Clipped->contours);
2433 assert (P2->Clipped->contours);
2435 /* first check if both bounding boxes intersect. If not, return quickly */
2436 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax ||
2437 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin ||
2438 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax ||
2439 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin)
2440 return false;
2442 /* first check un-bloated case */
2443 if (isects (P1->Clipped, P2, false))
2444 return TRUE;
2446 /* now the difficult case of bloated */
2447 if (Bloat > 0)
2449 PLINE *c;
2450 for (c = P1->Clipped->contours; c; c = c->next)
2452 LineType line;
2453 VNODE *v = &c->head;
2454 if (c->xmin - Bloat <= P2->Clipped->contours->xmax &&
2455 c->xmax + Bloat >= P2->Clipped->contours->xmin &&
2456 c->ymin - Bloat <= P2->Clipped->contours->ymax &&
2457 c->ymax + Bloat >= P2->Clipped->contours->ymin)
2460 line.Point1.X = v->point[0];
2461 line.Point1.Y = v->point[1];
2462 line.Thickness = 2 * Bloat;
2463 line.Clearance = 0;
2464 line.Flags = NoFlags ();
2465 for (v = v->next; v != &c->head; v = v->next)
2467 line.Point2.X = v->point[0];
2468 line.Point2.Y = v->point[1];
2469 SetLineBoundingBox (&line);
2470 if (IsLineInPolygon (&line, P2))
2471 return (true);
2472 line.Point1.X = line.Point2.X;
2473 line.Point1.Y = line.Point2.Y;
2479 return (false);
2482 /* ---------------------------------------------------------------------------
2483 * writes the several names of an element to a file
2485 static void
2486 PrintElementNameList (ElementType *Element, FILE * FP)
2488 static DynamicStringType cname, pname, vname;
2490 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element)));
2491 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element)));
2492 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element)));
2493 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data);
2496 /* ---------------------------------------------------------------------------
2497 * writes the several names of an element to a file
2499 static void
2500 PrintConnectionElementName (ElementType *Element, FILE * FP)
2502 fputs ("Element", FP);
2503 PrintElementNameList (Element, FP);
2504 fputs ("{\n", FP);
2507 /* ---------------------------------------------------------------------------
2508 * prints one {pin,pad,via}/element entry of connection lists
2510 static void
2511 PrintConnectionListEntry (char *ObjName, ElementType *Element,
2512 bool FirstOne, FILE * FP)
2514 static DynamicStringType oname;
2516 CreateQuotedString (&oname, ObjName);
2517 if (FirstOne)
2518 fprintf (FP, "\t%s\n\t{\n", oname.Data);
2519 else
2521 fprintf (FP, "\t\t%s ", oname.Data);
2522 if (Element)
2523 PrintElementNameList (Element, FP);
2524 else
2525 fputs ("(__VIA__)\n", FP);
2529 /* ---------------------------------------------------------------------------
2530 * prints all found connections of a pads to file FP
2531 * the connections are stacked in 'PadList'
2533 static void
2534 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst)
2536 Cardinal i;
2537 PadType *ptr;
2539 if (!PadList[Layer].Number)
2540 return;
2542 /* the starting pad */
2543 if (IsFirst)
2545 ptr = PADLIST_ENTRY (Layer, 0);
2546 if (ptr != NULL)
2547 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP);
2548 else
2549 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2552 /* we maybe have to start with i=1 if we are handling the
2553 * starting-pad itself
2555 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++)
2557 ptr = PADLIST_ENTRY (Layer, i);
2558 if (ptr != NULL)
2559 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP);
2560 else
2561 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2565 /* ---------------------------------------------------------------------------
2566 * prints all found connections of a pin to file FP
2567 * the connections are stacked in 'PVList'
2569 static void
2570 PrintPinConnections (FILE * FP, bool IsFirst)
2572 Cardinal i;
2573 PinType *pv;
2575 if (!PVList.Number)
2576 return;
2578 if (IsFirst)
2580 /* the starting pin */
2581 pv = PVLIST_ENTRY (0);
2582 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP);
2585 /* we maybe have to start with i=1 if we are handling the
2586 * starting-pin itself
2588 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++)
2590 /* get the elements name or assume that its a via */
2591 pv = PVLIST_ENTRY (i);
2592 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP);
2596 /* ---------------------------------------------------------------------------
2597 * checks if all lists of new objects are handled
2599 static bool
2600 ListsEmpty (bool AndRats)
2602 bool empty;
2603 int i;
2605 empty = (PVList.Location >= PVList.Number);
2606 if (AndRats)
2607 empty = empty && (RatList.Location >= RatList.Number);
2608 for (i = 0; i < max_copper_layer && empty; i++)
2609 if (!LAYER_PTR (i)->no_drc)
2610 empty = empty && LineList[i].Location >= LineList[i].Number
2611 && ArcList[i].Location >= ArcList[i].Number
2612 && PolygonList[i].Location >= PolygonList[i].Number;
2613 return (empty);
2616 static void
2617 reassign_no_drc_flags (void)
2619 int layer;
2621 for (layer = 0; layer < max_copper_layer; layer++)
2623 LayerType *l = LAYER_PTR (layer);
2624 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL;
2631 /* ---------------------------------------------------------------------------
2632 * loops till no more connections are found
2634 static bool
2635 DoIt (int flag, bool AndRats, bool AndDraw)
2637 bool newone = false;
2638 reassign_no_drc_flags ();
2641 /* lookup connections; these are the steps (2) to (4)
2642 * from the description
2644 newone = LookupPVConnectionsToPVList (flag) ||
2645 LookupLOConnectionsToPVList (flag, AndRats) ||
2646 LookupLOConnectionsToLOList (flag, AndRats) ||
2647 LookupPVConnectionsToLOList (flag, AndRats);
2648 if (AndDraw)
2649 DrawNewConnections ();
2651 while (!newone && !ListsEmpty (AndRats));
2652 if (AndDraw)
2653 Draw ();
2654 return (newone);
2657 /* ---------------------------------------------------------------------------
2658 * prints all unused pins of an element to file FP
2660 static bool
2661 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP, int flag)
2663 bool first = true;
2664 Cardinal number;
2665 static DynamicStringType oname;
2667 /* check all pins in element */
2669 PIN_LOOP (Element);
2671 if (!TEST_FLAG (HOLEFLAG, pin))
2673 /* pin might have bee checked before, add to list if not */
2674 if (!TEST_FLAG (flag, pin) && FP)
2676 int i;
2677 if (ADD_PV_TO_LIST (pin, flag))
2678 return true;
2679 DoIt (flag, true, true);
2680 number = PadList[COMPONENT_LAYER].Number
2681 + PadList[SOLDER_LAYER].Number + PVList.Number;
2682 /* the pin has no connection if it's the only
2683 * list entry; don't count vias
2685 for (i = 0; i < PVList.Number; i++)
2686 if (!PVLIST_ENTRY (i)->Element)
2687 number--;
2688 if (number == 1)
2690 /* output of element name if not already done */
2691 if (first)
2693 PrintConnectionElementName (Element, FP);
2694 first = false;
2697 /* write name to list and draw selected object */
2698 CreateQuotedString (&oname, (char *)EMPTY (pin->Name));
2699 fprintf (FP, "\t%s\n", oname.Data);
2700 SET_FLAG (SELECTEDFLAG, pin);
2701 DrawPin (pin);
2704 /* reset found objects for the next pin */
2705 if (PrepareNextLoop (FP))
2706 return (true);
2710 END_LOOP;
2712 /* check all pads in element */
2713 PAD_LOOP (Element);
2715 /* lookup pad in list */
2716 /* pad might has bee checked before, add to list if not */
2717 if (!TEST_FLAG (flag, pad) && FP)
2719 int i;
2720 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad)
2721 ? SOLDER_LAYER : COMPONENT_LAYER, pad, flag))
2722 return true;
2723 DoIt (flag, true, true);
2724 number = PadList[COMPONENT_LAYER].Number
2725 + PadList[SOLDER_LAYER].Number + PVList.Number;
2726 /* the pin has no connection if it's the only
2727 * list entry; don't count vias
2729 for (i = 0; i < PVList.Number; i++)
2730 if (!PVLIST_ENTRY (i)->Element)
2731 number--;
2732 if (number == 1)
2734 /* output of element name if not already done */
2735 if (first)
2737 PrintConnectionElementName (Element, FP);
2738 first = false;
2741 /* write name to list and draw selected object */
2742 CreateQuotedString (&oname, (char *)EMPTY (pad->Name));
2743 fprintf (FP, "\t%s\n", oname.Data);
2744 SET_FLAG (SELECTEDFLAG, pad);
2745 DrawPad (pad);
2748 /* reset found objects for the next pin */
2749 if (PrepareNextLoop (FP))
2750 return (true);
2753 END_LOOP;
2755 /* print separator if element has unused pins or pads */
2756 if (!first)
2758 fputs ("}\n\n", FP);
2759 SEPARATE (FP);
2761 return (false);
2764 /* ---------------------------------------------------------------------------
2765 * resets some flags for looking up the next pin/pad
2767 static bool
2768 PrepareNextLoop (FILE * FP)
2770 Cardinal layer;
2772 /* reset found LOs for the next pin */
2773 for (layer = 0; layer < max_copper_layer; layer++)
2775 LineList[layer].Location = LineList[layer].Number = 0;
2776 ArcList[layer].Location = ArcList[layer].Number = 0;
2777 PolygonList[layer].Location = PolygonList[layer].Number = 0;
2780 /* reset found pads */
2781 for (layer = 0; layer < 2; layer++)
2782 PadList[layer].Location = PadList[layer].Number = 0;
2784 /* reset PVs */
2785 PVList.Number = PVList.Location = 0;
2786 RatList.Number = RatList.Location = 0;
2788 return (false);
2791 /* ---------------------------------------------------------------------------
2792 * finds all connections to the pins of the passed element.
2793 * The result is written to file FP
2794 * Returns true if operation was aborted
2796 static bool
2797 PrintElementConnections (ElementType *Element, FILE * FP, int flag, bool AndDraw)
2799 PrintConnectionElementName (Element, FP);
2801 /* check all pins in element */
2802 PIN_LOOP (Element);
2804 /* pin might have been checked before, add to list if not */
2805 if (TEST_FLAG (flag, pin))
2807 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP);
2808 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2809 continue;
2811 if (ADD_PV_TO_LIST (pin, flag))
2812 return true;
2813 DoIt (flag, true, AndDraw);
2814 /* printout all found connections */
2815 PrintPinConnections (FP, true);
2816 PrintPadConnections (COMPONENT_LAYER, FP, false);
2817 PrintPadConnections (SOLDER_LAYER, FP, false);
2818 fputs ("\t}\n", FP);
2819 if (PrepareNextLoop (FP))
2820 return (true);
2822 END_LOOP;
2824 /* check all pads in element */
2825 PAD_LOOP (Element);
2827 Cardinal layer;
2828 /* pad might have been checked before, add to list if not */
2829 if (TEST_FLAG (flag, pad))
2831 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP);
2832 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2833 continue;
2835 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER;
2836 if (ADD_PAD_TO_LIST (layer, pad, flag))
2837 return true;
2838 DoIt (flag, true, AndDraw);
2839 /* print all found connections */
2840 PrintPadConnections (layer, FP, true);
2841 PrintPadConnections (layer ==
2842 (COMPONENT_LAYER ? SOLDER_LAYER : COMPONENT_LAYER),
2843 FP, false);
2844 PrintPinConnections (FP, false);
2845 fputs ("\t}\n", FP);
2846 if (PrepareNextLoop (FP))
2847 return (true);
2849 END_LOOP;
2850 fputs ("}\n\n", FP);
2851 return (false);
2854 /* ---------------------------------------------------------------------------
2855 * draws all new connections which have been found since the
2856 * routine was called the last time
2858 static void
2859 DrawNewConnections (void)
2861 int i;
2862 Cardinal position;
2864 /* decrement 'i' to keep layerstack order */
2865 for (i = max_copper_layer - 1; i != -1; i--)
2867 Cardinal layer = LayerStack[i];
2869 if (PCB->Data->Layer[layer].On)
2871 /* draw all new lines */
2872 position = LineList[layer].DrawLocation;
2873 for (; position < LineList[layer].Number; position++)
2874 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position));
2875 LineList[layer].DrawLocation = LineList[layer].Number;
2877 /* draw all new arcs */
2878 position = ArcList[layer].DrawLocation;
2879 for (; position < ArcList[layer].Number; position++)
2880 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position));
2881 ArcList[layer].DrawLocation = ArcList[layer].Number;
2883 /* draw all new polygons */
2884 position = PolygonList[layer].DrawLocation;
2885 for (; position < PolygonList[layer].Number; position++)
2886 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position));
2887 PolygonList[layer].DrawLocation = PolygonList[layer].Number;
2891 /* draw all new pads */
2892 if (PCB->PinOn)
2893 for (i = 0; i < 2; i++)
2895 position = PadList[i].DrawLocation;
2897 for (; position < PadList[i].Number; position++)
2898 DrawPad (PADLIST_ENTRY (i, position));
2899 PadList[i].DrawLocation = PadList[i].Number;
2902 /* draw all new PVs; 'PVList' holds a list of pointers to the
2903 * sorted array pointers to PV data
2905 while (PVList.DrawLocation < PVList.Number)
2907 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation);
2909 if (TEST_FLAG (PINFLAG, pv))
2911 if (PCB->PinOn)
2912 DrawPin (pv);
2914 else if (PCB->ViaOn)
2915 DrawVia (pv);
2916 PVList.DrawLocation++;
2918 /* draw the new rat-lines */
2919 if (PCB->RatOn)
2921 position = RatList.DrawLocation;
2922 for (; position < RatList.Number; position++)
2923 DrawRat (RATLIST_ENTRY (position));
2924 RatList.DrawLocation = RatList.Number;
2928 /* ---------------------------------------------------------------------------
2929 * find all connections to pins within one element
2931 void
2932 LookupElementConnections (ElementType *Element, FILE * FP)
2934 /* reset all currently marked connections */
2935 User = true;
2936 ClearFlagOnAllObjects (true, FOUNDFLAG);
2937 InitConnectionLookup ();
2938 PrintElementConnections (Element, FP, FOUNDFLAG, true);
2939 SetChangedFlag (true);
2940 if (Settings.RingBellWhenFinished)
2941 gui->beep ();
2942 FreeConnectionLookupMemory ();
2943 IncrementUndoSerialNumber ();
2944 User = false;
2945 Draw ();
2948 /* ---------------------------------------------------------------------------
2949 * find all connections to pins of all element
2951 void
2952 LookupConnectionsToAllElements (FILE * FP)
2954 /* reset all currently marked connections */
2955 User = false;
2956 ClearFlagOnAllObjects (false, FOUNDFLAG);
2957 InitConnectionLookup ();
2959 ELEMENT_LOOP (PCB->Data);
2961 /* break if abort dialog returned true */
2962 if (PrintElementConnections (element, FP, FOUNDFLAG, false))
2963 break;
2964 SEPARATE (FP);
2965 if (Settings.ResetAfterElement && n != 1)
2966 ClearFlagOnAllObjects (false, FOUNDFLAG);
2968 END_LOOP;
2969 if (Settings.RingBellWhenFinished)
2970 gui->beep ();
2971 ClearFlagOnAllObjects (false, FOUNDFLAG);
2972 FreeConnectionLookupMemory ();
2973 Redraw ();
2976 /*---------------------------------------------------------------------------
2977 * add the starting object to the list of found objects
2979 static bool
2980 ListStart (int type, void *ptr1, void *ptr2, void *ptr3, int flag)
2982 DumpList ();
2983 switch (type)
2985 case PIN_TYPE:
2986 case VIA_TYPE:
2988 if (ADD_PV_TO_LIST ((PinType *) ptr2, flag))
2989 return true;
2990 break;
2993 case RATLINE_TYPE:
2995 if (ADD_RAT_TO_LIST ((RatType *) ptr1, flag))
2996 return true;
2997 break;
3000 case LINE_TYPE:
3002 int layer = GetLayerNumber (PCB->Data,
3003 (LayerType *) ptr1);
3005 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2, flag))
3006 return true;
3007 break;
3010 case ARC_TYPE:
3012 int layer = GetLayerNumber (PCB->Data,
3013 (LayerType *) ptr1);
3015 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2, flag))
3016 return true;
3017 break;
3020 case POLYGON_TYPE:
3022 int layer = GetLayerNumber (PCB->Data,
3023 (LayerType *) ptr1);
3025 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2, flag))
3026 return true;
3027 break;
3030 case PAD_TYPE:
3032 PadType *pad = (PadType *) ptr2;
3033 if (ADD_PAD_TO_LIST
3034 (TEST_FLAG
3035 (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER, pad, flag))
3036 return true;
3037 break;
3040 return (false);
3044 /* ---------------------------------------------------------------------------
3045 * looks up all connections from the object at the given coordinates
3046 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3047 * the objects are re-drawn if AndDraw is true
3048 * also the action is marked as undoable if AndDraw is true
3050 void
3051 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int flag,
3052 bool AndRats)
3054 void *ptr1, *ptr2, *ptr3;
3055 char *name;
3056 int type;
3058 /* check if there are any pins or pads at that position */
3060 reassign_no_drc_flags ();
3062 type
3063 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range);
3064 if (type == NO_TYPE)
3066 type = SearchObjectByLocation (
3067 LOOKUP_MORE & ~(AndRats ? 0 : RATLINE_TYPE),
3068 &ptr1, &ptr2, &ptr3, X, Y, Range);
3069 if (type == NO_TYPE)
3070 return;
3071 if (type & SILK_TYPE)
3073 int laynum = GetLayerNumber (PCB->Data,
3074 (LayerType *) ptr1);
3076 /* don't mess with non-conducting objects! */
3077 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc)
3078 return;
3082 name = ConnectionName (type, ptr1, ptr2);
3083 hid_actionl ("NetlistShow", name, NULL);
3085 User = AndDraw;
3086 InitConnectionLookup ();
3088 /* now add the object to the appropriate list and start scanning
3089 * This is step (1) from the description
3091 ListStart (type, ptr1, ptr2, ptr3, flag);
3092 DoIt (flag, AndRats, AndDraw);
3093 if (User)
3094 IncrementUndoSerialNumber ();
3095 User = false;
3097 /* we are done */
3098 if (AndDraw)
3099 Draw ();
3100 if (AndDraw && Settings.RingBellWhenFinished)
3101 gui->beep ();
3102 FreeConnectionLookupMemory ();
3105 /* ---------------------------------------------------------------------------
3106 * find connections for rats nesting
3107 * assumes InitConnectionLookup() has already been done
3109 void
3110 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3,
3111 bool undo, int flag, bool AndRats)
3113 User = undo;
3114 DumpList ();
3115 ListStart (type, ptr1, ptr2, ptr3, flag);
3116 DoIt (flag, AndRats, false);
3117 User = false;
3120 /* ---------------------------------------------------------------------------
3121 * find all unused pins of all element
3123 void
3124 LookupUnusedPins (FILE * FP)
3126 /* reset all currently marked connections */
3127 User = true;
3128 ClearFlagOnAllObjects (true, FOUNDFLAG);
3129 InitConnectionLookup ();
3131 ELEMENT_LOOP (PCB->Data);
3133 /* break if abort dialog returned true;
3134 * passing NULL as filedescriptor discards the normal output
3136 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP, FOUNDFLAG))
3137 break;
3139 END_LOOP;
3141 if (Settings.RingBellWhenFinished)
3142 gui->beep ();
3143 FreeConnectionLookupMemory ();
3144 IncrementUndoSerialNumber ();
3145 User = false;
3146 Draw ();
3149 /* ---------------------------------------------------------------------------
3150 * resets all used flags of pins and vias
3152 bool
3153 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag)
3155 bool change = false;
3157 VIA_LOOP (PCB->Data);
3159 if (TEST_FLAG (flag, via))
3161 if (AndDraw)
3162 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3163 CLEAR_FLAG (flag, via);
3164 if (AndDraw)
3165 DrawVia (via);
3166 change = true;
3169 END_LOOP;
3170 ELEMENT_LOOP (PCB->Data);
3172 PIN_LOOP (element);
3174 if (TEST_FLAG (flag, pin))
3176 if (AndDraw)
3177 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3178 CLEAR_FLAG (flag, pin);
3179 if (AndDraw)
3180 DrawPin (pin);
3181 change = true;
3184 END_LOOP;
3185 PAD_LOOP (element);
3187 if (TEST_FLAG (flag, pad))
3189 if (AndDraw)
3190 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3191 CLEAR_FLAG (flag, pad);
3192 if (AndDraw)
3193 DrawPad (pad);
3194 change = true;
3197 END_LOOP;
3199 END_LOOP;
3200 if (change)
3201 SetChangedFlag (true);
3202 return change;
3205 /* ---------------------------------------------------------------------------
3206 * resets all used flags of LOs
3208 bool
3209 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag)
3211 bool change = false;
3213 RAT_LOOP (PCB->Data);
3215 if (TEST_FLAG (flag, line))
3217 if (AndDraw)
3218 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
3219 CLEAR_FLAG (flag, line);
3220 if (AndDraw)
3221 DrawRat (line);
3222 change = true;
3225 END_LOOP;
3226 COPPERLINE_LOOP (PCB->Data);
3228 if (TEST_FLAG (flag, line))
3230 if (AndDraw)
3231 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3232 CLEAR_FLAG (flag, line);
3233 if (AndDraw)
3234 DrawLine (layer, line);
3235 change = true;
3238 ENDALL_LOOP;
3239 COPPERARC_LOOP (PCB->Data);
3241 if (TEST_FLAG (flag, arc))
3243 if (AndDraw)
3244 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3245 CLEAR_FLAG (flag, arc);
3246 if (AndDraw)
3247 DrawArc (layer, arc);
3248 change = true;
3251 ENDALL_LOOP;
3252 COPPERPOLYGON_LOOP (PCB->Data);
3254 if (TEST_FLAG (flag, polygon))
3256 if (AndDraw)
3257 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3258 CLEAR_FLAG (flag, polygon);
3259 if (AndDraw)
3260 DrawPolygon (layer, polygon);
3261 change = true;
3264 ENDALL_LOOP;
3265 if (change)
3266 SetChangedFlag (true);
3267 return change;
3270 /* ---------------------------------------------------------------------------
3271 * resets all found connections
3273 bool
3274 ClearFlagOnAllObjects (bool AndDraw, int flag)
3276 bool change = false;
3278 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change;
3279 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change;
3281 return change;
3284 /*----------------------------------------------------------------------------
3285 * Dumps the list contents
3287 static void
3288 DumpList (void)
3290 Cardinal i;
3292 for (i = 0; i < 2; i++)
3294 PadList[i].Number = 0;
3295 PadList[i].Location = 0;
3296 PadList[i].DrawLocation = 0;
3299 PVList.Number = 0;
3300 PVList.Location = 0;
3302 for (i = 0; i < max_copper_layer; i++)
3304 LineList[i].Location = 0;
3305 LineList[i].DrawLocation = 0;
3306 LineList[i].Number = 0;
3307 ArcList[i].Location = 0;
3308 ArcList[i].DrawLocation = 0;
3309 ArcList[i].Number = 0;
3310 PolygonList[i].Location = 0;
3311 PolygonList[i].DrawLocation = 0;
3312 PolygonList[i].Number = 0;
3314 RatList.Number = 0;
3315 RatList.Location = 0;
3316 RatList.DrawLocation = 0;
3319 struct drc_info
3321 int flag;
3324 /*-----------------------------------------------------------------------------
3325 * Check for DRC violations on a single net starting from the pad or pin
3326 * sees if the connectivity changes when everything is bloated, or shrunk
3328 static bool
3329 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
3331 Coord x, y;
3332 int object_count;
3333 long int *object_id_list;
3334 int *object_type_list;
3335 DrcViolationType *violation;
3336 int flag;
3338 if (PCB->Shrink != 0)
3340 Bloat = -PCB->Shrink;
3341 flag = DRCFLAG | SELECTEDFLAG;
3342 ListStart (What, ptr1, ptr2, ptr3, flag);
3343 DoIt (flag, true, false);
3344 /* ok now the shrunk net has the SELECTEDFLAG set */
3345 DumpList ();
3346 flag = FOUNDFLAG;
3347 ListStart (What, ptr1, ptr2, ptr3, flag);
3348 Bloat = 0;
3349 drc = true; /* abort the search if we find anything not already found */
3350 if (DoIt (flag, true, false))
3352 DumpList ();
3353 /* make the flag changes undoable */
3354 flag = FOUNDFLAG | SELECTEDFLAG;
3355 ClearFlagOnAllObjects (false, flag);
3356 User = true;
3357 drc = false;
3358 Bloat = -PCB->Shrink;
3359 flag = SELECTEDFLAG;
3360 ListStart (What, ptr1, ptr2, ptr3, flag);
3361 DoIt (flag, true, true);
3362 DumpList ();
3363 ListStart (What, ptr1, ptr2, ptr3, flag);
3364 flag = FOUNDFLAG;
3365 Bloat = 0;
3366 drc = true;
3367 DoIt (flag, true, true);
3368 DumpList ();
3369 User = false;
3370 drc = false;
3371 drcerr_count++;
3372 LocateError (&x, &y);
3373 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3374 violation = pcb_drc_violation_new (_("Potential for broken trace"),
3375 _("Insufficient overlap between objects can lead to broken tracks\n"
3376 "due to registration errors with old wheel style photo-plotters."),
3377 x, y,
3378 0, /* ANGLE OF ERROR UNKNOWN */
3379 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3380 0, /* MAGNITUDE OF ERROR UNKNOWN */
3381 PCB->Shrink,
3382 object_count,
3383 object_id_list,
3384 object_type_list);
3385 append_drc_violation (violation);
3386 pcb_drc_violation_free (violation);
3387 free (object_id_list);
3388 free (object_type_list);
3390 if (!throw_drc_dialog())
3391 return (true);
3392 IncrementUndoSerialNumber ();
3393 Undo (true);
3395 DumpList ();
3397 /* now check the bloated condition */
3398 drc = false;
3399 ClearFlagOnAllObjects (false, flag);
3400 flag = FOUNDFLAG;
3401 ListStart (What, ptr1, ptr2, ptr3, flag);
3402 Bloat = PCB->Bloat;
3403 drc = true;
3404 while (DoIt (flag, true, false))
3406 DumpList ();
3407 /* make the flag changes undoable */
3408 flag = FOUNDFLAG | SELECTEDFLAG;
3409 ClearFlagOnAllObjects (false, flag);
3410 User = true;
3411 drc = false;
3412 Bloat = 0;
3413 flag = SELECTEDFLAG;
3414 ListStart (What, ptr1, ptr2, ptr3, flag);
3415 DoIt (flag, true, true);
3416 DumpList ();
3417 flag = FOUNDFLAG;
3418 ListStart (What, ptr1, ptr2, ptr3, flag);
3419 Bloat = PCB->Bloat;
3420 drc = true;
3421 DoIt (flag, true, true);
3422 DumpList ();
3423 drcerr_count++;
3424 LocateError (&x, &y);
3425 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3426 violation = pcb_drc_violation_new (_("Copper areas too close"),
3427 _("Circuits that are too close may bridge during imaging, etching,\n"
3428 "plating, or soldering processes resulting in a direct short."),
3429 x, y,
3430 0, /* ANGLE OF ERROR UNKNOWN */
3431 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3432 0, /* MAGNITUDE OF ERROR UNKNOWN */
3433 PCB->Bloat,
3434 object_count,
3435 object_id_list,
3436 object_type_list);
3437 append_drc_violation (violation);
3438 pcb_drc_violation_free (violation);
3439 free (object_id_list);
3440 free (object_type_list);
3441 User = false;
3442 drc = false;
3443 if (!throw_drc_dialog())
3444 return (true);
3445 IncrementUndoSerialNumber ();
3446 Undo (true);
3447 /* highlight the rest of the encroaching net so it's not reported again */
3448 flag |= SELECTEDFLAG;
3449 Bloat = 0;
3450 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3, flag);
3451 DoIt (flag, true, true);
3452 DumpList ();
3453 drc = true;
3454 Bloat = PCB->Bloat;
3455 ListStart (What, ptr1, ptr2, ptr3, flag);
3457 drc = false;
3458 DumpList ();
3459 flag = FOUNDFLAG | SELECTEDFLAG;
3460 ClearFlagOnAllObjects (false, flag);
3461 return (false);
3464 /* DRC clearance callback */
3466 static int
3467 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon,
3468 int type, void *ptr1, void *ptr2, void *userdata)
3470 struct drc_info *i = (struct drc_info *) userdata;
3471 char *message;
3472 Coord x, y;
3473 int object_count;
3474 long int *object_id_list;
3475 int *object_type_list;
3476 DrcViolationType *violation;
3478 LineType *line = (LineType *) ptr2;
3479 ArcType *arc = (ArcType *) ptr2;
3480 PinType *pin = (PinType *) ptr2;
3481 PadType *pad = (PadType *) ptr2;
3483 thing_type = type;
3484 thing_ptr1 = ptr1;
3485 thing_ptr2 = ptr2;
3486 thing_ptr3 = ptr2;
3487 switch (type)
3489 case LINE_TYPE:
3490 if (line->Clearance < 2 * PCB->Bloat)
3492 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3493 SET_FLAG (i->flag, line);
3494 message = _("Line with insufficient clearance inside polygon\n");
3495 goto doIsBad;
3497 break;
3498 case ARC_TYPE:
3499 if (arc->Clearance < 2 * PCB->Bloat)
3501 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3502 SET_FLAG (i->flag, arc);
3503 message = _("Arc with insufficient clearance inside polygon\n");
3504 goto doIsBad;
3506 break;
3507 case PAD_TYPE:
3508 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
3509 if (IsPadInPolygon(pad,polygon))
3511 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3512 SET_FLAG (i->flag, pad);
3513 message = _("Pad with insufficient clearance inside polygon\n");
3514 goto doIsBad;
3516 break;
3517 case PIN_TYPE:
3518 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3520 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3521 SET_FLAG (i->flag, pin);
3522 message = _("Pin with insufficient clearance inside polygon\n");
3523 goto doIsBad;
3525 break;
3526 case VIA_TYPE:
3527 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3529 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3530 SET_FLAG (i->flag, pin);
3531 message = _("Via with insufficient clearance inside polygon\n");
3532 goto doIsBad;
3534 break;
3535 default:
3536 Message ("hace: Bad Plow object in callback\n");
3538 return 0;
3540 doIsBad:
3541 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3542 SET_FLAG (FOUNDFLAG, polygon);
3543 DrawPolygon (layer, polygon);
3544 DrawObject (type, ptr1, ptr2);
3545 drcerr_count++;
3546 LocateError (&x, &y);
3547 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3548 violation = pcb_drc_violation_new (message,
3549 _("Circuits that are too close may bridge during imaging, etching,\n"
3550 "plating, or soldering processes resulting in a direct short."),
3551 x, y,
3552 0, /* ANGLE OF ERROR UNKNOWN */
3553 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3554 0, /* MAGNITUDE OF ERROR UNKNOWN */
3555 PCB->Bloat,
3556 object_count,
3557 object_id_list,
3558 object_type_list);
3559 append_drc_violation (violation);
3560 pcb_drc_violation_free (violation);
3561 free (object_id_list);
3562 free (object_type_list);
3564 if (!throw_drc_dialog())
3565 return 1;
3567 IncrementUndoSerialNumber ();
3568 Undo (true);
3569 return 0;
3572 /*-----------------------------------------------------------------------------
3573 * Check for DRC violations
3574 * see if the connectivity changes when everything is bloated, or shrunk
3577 DRCAll (void)
3579 Coord x, y;
3580 int object_count;
3581 long int *object_id_list;
3582 int *object_type_list;
3583 DrcViolationType *violation;
3584 int tmpcnt;
3585 int nopastecnt = 0;
3586 bool IsBad;
3587 int flag;
3588 struct drc_info info;
3590 reset_drc_dialog_message();
3592 IsBad = false;
3593 drcerr_count = 0;
3594 SaveStackAndVisibility ();
3595 ResetStackAndVisibility ();
3596 hid_action ("LayersChanged");
3597 InitConnectionLookup ();
3599 flag = FOUNDFLAG | DRCFLAG | SELECTEDFLAG;
3601 if (ClearFlagOnAllObjects (true, flag))
3603 IncrementUndoSerialNumber ();
3604 Draw ();
3607 User = false;
3609 ELEMENT_LOOP (PCB->Data);
3611 PIN_LOOP (element);
3613 if (!TEST_FLAG (DRCFLAG, pin)
3614 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin))
3616 IsBad = true;
3617 break;
3620 END_LOOP;
3621 if (IsBad)
3622 break;
3623 PAD_LOOP (element);
3626 /* count up how many pads have no solderpaste openings */
3627 if (TEST_FLAG (NOPASTEFLAG, pad))
3628 nopastecnt++;
3630 if (!TEST_FLAG (DRCFLAG, pad)
3631 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad))
3633 IsBad = true;
3634 break;
3637 END_LOOP;
3638 if (IsBad)
3639 break;
3641 END_LOOP;
3642 if (!IsBad)
3643 VIA_LOOP (PCB->Data);
3645 if (!TEST_FLAG (DRCFLAG, via)
3646 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via))
3648 IsBad = true;
3649 break;
3652 END_LOOP;
3654 flag = (IsBad) ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG);
3655 ClearFlagOnAllObjects (false, flag);
3656 flag = SELECTEDFLAG;
3657 info.flag = flag;
3658 /* check minimum widths and polygon clearances */
3659 if (!IsBad)
3661 COPPERLINE_LOOP (PCB->Data);
3663 /* check line clearances in polygons */
3664 if (PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback, &info))
3666 IsBad = true;
3667 break;
3669 if (line->Thickness < PCB->minWid)
3671 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3672 SET_FLAG (flag, line);
3673 DrawLine (layer, line);
3674 drcerr_count++;
3675 SetThing (LINE_TYPE, layer, line, line);
3676 LocateError (&x, &y);
3677 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3678 violation = pcb_drc_violation_new (_("Line width is too thin"),
3679 _("Process specifications dictate a minimum feature-width\n"
3680 "that can reliably be reproduced"),
3681 x, y,
3682 0, /* ANGLE OF ERROR UNKNOWN */
3683 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3684 line->Thickness,
3685 PCB->minWid,
3686 object_count,
3687 object_id_list,
3688 object_type_list);
3689 append_drc_violation (violation);
3690 pcb_drc_violation_free (violation);
3691 free (object_id_list);
3692 free (object_type_list);
3693 if (!throw_drc_dialog())
3695 IsBad = true;
3696 break;
3698 IncrementUndoSerialNumber ();
3699 Undo (false);
3702 ENDALL_LOOP;
3704 if (!IsBad)
3706 COPPERARC_LOOP (PCB->Data);
3708 if (PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback, &info))
3710 IsBad = true;
3711 break;
3713 if (arc->Thickness < PCB->minWid)
3715 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3716 SET_FLAG (flag, arc);
3717 DrawArc (layer, arc);
3718 drcerr_count++;
3719 SetThing (ARC_TYPE, layer, arc, arc);
3720 LocateError (&x, &y);
3721 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3722 violation = pcb_drc_violation_new (_("Arc width is too thin"),
3723 _("Process specifications dictate a minimum feature-width\n"
3724 "that can reliably be reproduced"),
3725 x, y,
3726 0, /* ANGLE OF ERROR UNKNOWN */
3727 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3728 arc->Thickness,
3729 PCB->minWid,
3730 object_count,
3731 object_id_list,
3732 object_type_list);
3733 append_drc_violation (violation);
3734 pcb_drc_violation_free (violation);
3735 free (object_id_list);
3736 free (object_type_list);
3737 if (!throw_drc_dialog())
3739 IsBad = true;
3740 break;
3742 IncrementUndoSerialNumber ();
3743 Undo (false);
3746 ENDALL_LOOP;
3748 if (!IsBad)
3750 ALLPIN_LOOP (PCB->Data);
3752 if (PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback, &info))
3754 IsBad = true;
3755 break;
3757 if (!TEST_FLAG (HOLEFLAG, pin) &&
3758 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing)
3760 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3761 SET_FLAG (flag, pin);
3762 DrawPin (pin);
3763 drcerr_count++;
3764 SetThing (PIN_TYPE, element, pin, pin);
3765 LocateError (&x, &y);
3766 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3767 violation = pcb_drc_violation_new (_("Pin annular ring too small"),
3768 _("Annular rings that are too small may erode during etching,\n"
3769 "resulting in a broken connection"),
3770 x, y,
3771 0, /* ANGLE OF ERROR UNKNOWN */
3772 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3773 (pin->Thickness - pin->DrillingHole) / 2,
3774 PCB->minRing,
3775 object_count,
3776 object_id_list,
3777 object_type_list);
3778 append_drc_violation (violation);
3779 pcb_drc_violation_free (violation);
3780 free (object_id_list);
3781 free (object_type_list);
3782 if (!throw_drc_dialog())
3784 IsBad = true;
3785 break;
3787 IncrementUndoSerialNumber ();
3788 Undo (false);
3790 if (pin->DrillingHole < PCB->minDrill)
3792 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3793 SET_FLAG (flag, pin);
3794 DrawPin (pin);
3795 drcerr_count++;
3796 SetThing (PIN_TYPE, element, pin, pin);
3797 LocateError (&x, &y);
3798 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3799 violation = pcb_drc_violation_new (_("Pin drill size is too small"),
3800 _("Process rules dictate the minimum drill size which can be used"),
3801 x, y,
3802 0, /* ANGLE OF ERROR UNKNOWN */
3803 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3804 pin->DrillingHole,
3805 PCB->minDrill,
3806 object_count,
3807 object_id_list,
3808 object_type_list);
3809 append_drc_violation (violation);
3810 pcb_drc_violation_free (violation);
3811 free (object_id_list);
3812 free (object_type_list);
3813 if (!throw_drc_dialog())
3815 IsBad = true;
3816 break;
3818 IncrementUndoSerialNumber ();
3819 Undo (false);
3822 ENDALL_LOOP;
3824 if (!IsBad)
3826 ALLPAD_LOOP (PCB->Data);
3828 if (PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback, &info))
3830 IsBad = true;
3831 break;
3833 if (pad->Thickness < PCB->minWid)
3835 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3836 SET_FLAG (flag, pad);
3837 DrawPad (pad);
3838 drcerr_count++;
3839 SetThing (PAD_TYPE, element, pad, pad);
3840 LocateError (&x, &y);
3841 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3842 violation = pcb_drc_violation_new (_("Pad is too thin"),
3843 _("Pads which are too thin may erode during etching,\n"
3844 "resulting in a broken or unreliable connection"),
3845 x, y,
3846 0, /* ANGLE OF ERROR UNKNOWN */
3847 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3848 pad->Thickness,
3849 PCB->minWid,
3850 object_count,
3851 object_id_list,
3852 object_type_list);
3853 append_drc_violation (violation);
3854 pcb_drc_violation_free (violation);
3855 free (object_id_list);
3856 free (object_type_list);
3857 if (!throw_drc_dialog())
3859 IsBad = true;
3860 break;
3862 IncrementUndoSerialNumber ();
3863 Undo (false);
3866 ENDALL_LOOP;
3868 if (!IsBad)
3870 VIA_LOOP (PCB->Data);
3872 if (PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback, &info))
3874 IsBad = true;
3875 break;
3877 if (!TEST_FLAG (HOLEFLAG, via) &&
3878 via->Thickness - via->DrillingHole < 2 * PCB->minRing)
3880 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3881 SET_FLAG (flag, via);
3882 DrawVia (via);
3883 drcerr_count++;
3884 SetThing (VIA_TYPE, via, via, via);
3885 LocateError (&x, &y);
3886 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3887 violation = pcb_drc_violation_new (_("Via annular ring too small"),
3888 _("Annular rings that are too small may erode during etching,\n"
3889 "resulting in a broken connection"),
3890 x, y,
3891 0, /* ANGLE OF ERROR UNKNOWN */
3892 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3893 (via->Thickness - via->DrillingHole) / 2,
3894 PCB->minRing,
3895 object_count,
3896 object_id_list,
3897 object_type_list);
3898 append_drc_violation (violation);
3899 pcb_drc_violation_free (violation);
3900 free (object_id_list);
3901 free (object_type_list);
3902 if (!throw_drc_dialog())
3904 IsBad = true;
3905 break;
3907 IncrementUndoSerialNumber ();
3908 Undo (false);
3910 if (via->DrillingHole < PCB->minDrill)
3912 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3913 SET_FLAG (flag, via);
3914 DrawVia (via);
3915 drcerr_count++;
3916 SetThing (VIA_TYPE, via, via, via);
3917 LocateError (&x, &y);
3918 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3919 violation = pcb_drc_violation_new (_("Via drill size is too small"),
3920 _("Process rules dictate the minimum drill size which can be used"),
3921 x, y,
3922 0, /* ANGLE OF ERROR UNKNOWN */
3923 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3924 via->DrillingHole,
3925 PCB->minDrill,
3926 object_count,
3927 object_id_list,
3928 object_type_list);
3929 append_drc_violation (violation);
3930 pcb_drc_violation_free (violation);
3931 free (object_id_list);
3932 free (object_type_list);
3933 if (!throw_drc_dialog())
3935 IsBad = true;
3936 break;
3938 IncrementUndoSerialNumber ();
3939 Undo (false);
3942 END_LOOP;
3945 FreeConnectionLookupMemory ();
3946 flag = FOUNDFLAG;
3947 Bloat = 0;
3949 /* check silkscreen minimum widths outside of elements */
3950 /* XXX - need to check text and polygons too! */
3951 flag = SELECTEDFLAG;
3952 if (!IsBad)
3954 SILKLINE_LOOP (PCB->Data);
3956 if (line->Thickness < PCB->minSlk)
3958 SET_FLAG (flag, line);
3959 DrawLine (layer, line);
3960 drcerr_count++;
3961 SetThing (LINE_TYPE, layer, line, line);
3962 LocateError (&x, &y);
3963 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3964 violation = pcb_drc_violation_new (_("Silk line is too thin"),
3965 _("Process specifications dictate a minimum silkscreen feature-width\n"
3966 "that can reliably be reproduced"),
3967 x, y,
3968 0, /* ANGLE OF ERROR UNKNOWN */
3969 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3970 line->Thickness,
3971 PCB->minSlk,
3972 object_count,
3973 object_id_list,
3974 object_type_list);
3975 append_drc_violation (violation);
3976 pcb_drc_violation_free (violation);
3977 free (object_id_list);
3978 free (object_type_list);
3979 if (!throw_drc_dialog())
3981 IsBad = true;
3982 break;
3986 ENDALL_LOOP;
3989 /* check silkscreen minimum widths inside of elements */
3990 /* XXX - need to check text and polygons too! */
3991 flag = SELECTEDFLAG;
3992 if (!IsBad)
3994 ELEMENT_LOOP (PCB->Data);
3996 tmpcnt = 0;
3997 ELEMENTLINE_LOOP (element);
3999 if (line->Thickness < PCB->minSlk)
4000 tmpcnt++;
4002 END_LOOP;
4003 if (tmpcnt > 0)
4005 char *title;
4006 char *name;
4007 char *buffer;
4008 int buflen;
4010 SET_FLAG (flag, element);
4011 DrawElement (element);
4012 drcerr_count++;
4013 SetThing (ELEMENT_TYPE, element, element, element);
4014 LocateError (&x, &y);
4015 BuildObjectList (&object_count, &object_id_list, &object_type_list);
4017 title = _("Element %s has %i silk lines which are too thin");
4018 name = (char *)UNKNOWN (NAMEONPCB_NAME (element));
4020 /* -4 is for the %s and %i place-holders */
4021 /* +11 is the max printed length for a 32 bit integer */
4022 /* +1 is for the \0 termination */
4023 buflen = strlen (title) - 4 + strlen (name) + 11 + 1;
4024 buffer = (char *)malloc (buflen);
4025 snprintf (buffer, buflen, title, name, tmpcnt);
4027 violation = pcb_drc_violation_new (buffer,
4028 _("Process specifications dictate a minimum silkscreen\n"
4029 "feature-width that can reliably be reproduced"),
4030 x, y,
4031 0, /* ANGLE OF ERROR UNKNOWN */
4032 TRUE, /* MEASUREMENT OF ERROR KNOWN */
4033 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4034 PCB->minSlk,
4035 object_count,
4036 object_id_list,
4037 object_type_list);
4038 free (buffer);
4039 append_drc_violation (violation);
4040 pcb_drc_violation_free (violation);
4041 free (object_id_list);
4042 free (object_type_list);
4043 if (!throw_drc_dialog())
4045 IsBad = true;
4046 break;
4050 END_LOOP;
4054 if (IsBad)
4056 IncrementUndoSerialNumber ();
4060 RestoreStackAndVisibility ();
4061 hid_action ("LayersChanged");
4062 gui->invalidate_all ();
4064 if (nopastecnt > 0)
4066 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4067 nopastecnt,
4068 nopastecnt > 1 ? "s have" : " has");
4070 return IsBad ? -drcerr_count : drcerr_count;
4073 /*----------------------------------------------------------------------------
4074 * Locate the coordinatates of offending item (thing)
4076 static void
4077 LocateError (Coord *x, Coord *y)
4079 switch (thing_type)
4081 case LINE_TYPE:
4083 LineType *line = (LineType *) thing_ptr3;
4084 *x = (line->Point1.X + line->Point2.X) / 2;
4085 *y = (line->Point1.Y + line->Point2.Y) / 2;
4086 break;
4088 case ARC_TYPE:
4090 ArcType *arc = (ArcType *) thing_ptr3;
4091 *x = arc->X;
4092 *y = arc->Y;
4093 break;
4095 case POLYGON_TYPE:
4097 PolygonType *polygon = (PolygonType *) thing_ptr3;
4098 *x =
4099 (polygon->Clipped->contours->xmin +
4100 polygon->Clipped->contours->xmax) / 2;
4101 *y =
4102 (polygon->Clipped->contours->ymin +
4103 polygon->Clipped->contours->ymax) / 2;
4104 break;
4106 case PIN_TYPE:
4107 case VIA_TYPE:
4109 PinType *pin = (PinType *) thing_ptr3;
4110 *x = pin->X;
4111 *y = pin->Y;
4112 break;
4114 case PAD_TYPE:
4116 PadType *pad = (PadType *) thing_ptr3;
4117 *x = (pad->Point1.X + pad->Point2.X) / 2;
4118 *y = (pad->Point1.Y + pad->Point2.Y) / 2;
4119 break;
4121 case ELEMENT_TYPE:
4123 ElementType *element = (ElementType *) thing_ptr3;
4124 *x = element->MarkX;
4125 *y = element->MarkY;
4126 break;
4128 default:
4129 return;
4134 /*----------------------------------------------------------------------------
4135 * Build a list of the of offending items by ID. (Currently just "thing")
4137 static void
4138 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
4140 *object_count = 0;
4141 *object_id_list = NULL;
4142 *object_type_list = NULL;
4144 switch (thing_type)
4146 case LINE_TYPE:
4147 case ARC_TYPE:
4148 case POLYGON_TYPE:
4149 case PIN_TYPE:
4150 case VIA_TYPE:
4151 case PAD_TYPE:
4152 case ELEMENT_TYPE:
4153 case RATLINE_TYPE:
4154 *object_count = 1;
4155 *object_id_list = (long int *)malloc (sizeof (long int));
4156 *object_type_list = (int *)malloc (sizeof (int));
4157 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
4158 **object_type_list = thing_type;
4159 return;
4161 default:
4162 fprintf (stderr,
4163 _("Internal error in BuildObjectList: unknown object type %i\n"),
4164 thing_type);
4169 /*----------------------------------------------------------------------------
4170 * center the display to show the offending item (thing)
4172 static void
4173 GotoError (void)
4175 Coord X, Y;
4177 LocateError (&X, &Y);
4179 switch (thing_type)
4181 case LINE_TYPE:
4182 case ARC_TYPE:
4183 case POLYGON_TYPE:
4184 ChangeGroupVisibility (
4185 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1),
4186 true, true);
4188 CenterDisplay (X, Y);
4191 void
4192 InitConnectionLookup (void)
4194 InitComponentLookup ();
4195 InitLayoutLookup ();
4198 void
4199 FreeConnectionLookupMemory (void)
4201 FreeComponentLookupMemory ();
4202 FreeLayoutLookupMemory ();