find.c: Avoid repeated lookup of layer pointer by number
[geda-pcb/pcjc2.git] / src / find.c
blobdae0a11bac037e74d25822cc95e477e19697b4a0
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 <stdlib.h>
69 #ifdef HAVE_STRING_H
70 #include <string.h>
71 #endif
72 #include <math.h>
73 #include <setjmp.h>
74 #include <assert.h>
76 #ifdef HAVE_SYS_TIMES_H
77 #include <sys/times.h>
78 #endif
80 #include "global.h"
82 #include "crosshair.h"
83 #include "data.h"
84 #include "draw.h"
85 #include "error.h"
86 #include "find.h"
87 #include "mymem.h"
88 #include "misc.h"
89 #include "rtree.h"
90 #include "polygon.h"
91 #include "pcb-printf.h"
92 #include "search.h"
93 #include "set.h"
94 #include "undo.h"
95 #include "rats.h"
97 #ifdef HAVE_LIBDMALLOC
98 #include <dmalloc.h>
99 #endif
101 #undef DEBUG
103 /* ---------------------------------------------------------------------------
104 * some local macros
107 #define EXPAND_BOUNDS(p) if (Bloat > 0) {\
108 (p)->BoundingBox.X1 -= Bloat; \
109 (p)->BoundingBox.X2 += Bloat; \
110 (p)->BoundingBox.Y1 -= Bloat; \
111 (p)->BoundingBox.Y2 += Bloat;}
113 #define SEPARATE(FP) \
115 int i; \
116 fputc('#', (FP)); \
117 for (i = Settings.CharPerLine; i; i--) \
118 fputc('=', (FP)); \
119 fputc('\n', (FP)); \
122 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
123 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
124 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
125 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
126 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
127 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
128 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
130 #define IS_PV_ON_RAT(PV, Rat) \
131 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
133 #define IS_PV_ON_ARC(PV, Arc) \
134 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
135 IsArcInRectangle( \
136 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
137 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
138 (Arc)) : \
139 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
141 #define IS_PV_ON_PAD(PV,Pad) \
142 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
144 static DrcViolationType
145 *pcb_drc_violation_new (const char *title,
146 const char *explanation,
147 Coord x, Coord y,
148 Angle angle,
149 bool have_measured,
150 Coord measured_value,
151 Coord required_value,
152 int object_count,
153 long int *object_id_list,
154 int *object_type_list)
156 DrcViolationType *violation = (DrcViolationType *)malloc (sizeof (DrcViolationType));
158 violation->title = strdup (title);
159 violation->explanation = strdup (explanation);
160 violation->x = x;
161 violation->y = y;
162 violation->angle = angle;
163 violation->have_measured = have_measured;
164 violation->measured_value = measured_value;
165 violation->required_value = required_value;
166 violation->object_count = object_count;
167 violation->object_id_list = object_id_list;
168 violation->object_type_list = object_type_list;
170 return violation;
173 static void
174 pcb_drc_violation_free (DrcViolationType *violation)
176 free (violation->title);
177 free (violation->explanation);
178 free (violation);
181 static GString *drc_dialog_message;
182 static void
183 reset_drc_dialog_message(void)
185 if (drc_dialog_message)
186 g_string_free (drc_dialog_message, FALSE);
187 drc_dialog_message = g_string_new ("");
188 if (gui->drc_gui != NULL)
190 gui->drc_gui->reset_drc_dialog_message ();
193 static void
194 append_drc_dialog_message(const char *fmt, ...)
196 gchar *new_str;
197 va_list ap;
198 va_start (ap, fmt);
199 new_str = pcb_vprintf (fmt, ap);
200 g_string_append (drc_dialog_message, new_str);
201 va_end (ap);
202 g_free (new_str);
205 static void GotoError (void);
207 static void
208 append_drc_violation (DrcViolationType *violation)
210 if (gui->drc_gui != NULL)
212 gui->drc_gui->append_drc_violation (violation);
214 else
216 /* Fallback to formatting the violation message as text */
217 append_drc_dialog_message ("%s\n", violation->title);
218 append_drc_dialog_message (_("%m+near %$mD\n"),
219 Settings.grid_unit->allow,
220 violation->x, violation->y);
221 GotoError ();
224 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_violations )
226 Message (_("WARNING! Design Rule error - %s\n"), violation->title);
227 Message (_("%m+near location %$mD\n"),
228 Settings.grid_unit->allow,
229 violation->x, violation->y);
233 * message when asked about continuing DRC checks after next
234 * violation is found.
236 #define DRC_CONTINUE _("Press Next to continue DRC checking")
237 #define DRC_NEXT _("Next")
238 #define DRC_CANCEL _("Cancel")
240 static int
241 throw_drc_dialog(void)
243 int r;
245 if (gui->drc_gui != NULL)
247 r = gui->drc_gui->throw_drc_dialog ();
249 else
251 /* Fallback to formatting the violation message as text */
252 append_drc_dialog_message (DRC_CONTINUE);
253 r = gui->confirm_dialog (drc_dialog_message->str, DRC_CANCEL, DRC_NEXT);
254 reset_drc_dialog_message();
256 return r;
259 /* ---------------------------------------------------------------------------
260 * some local types
262 * the two 'dummy' structs for PVs and Pads are necessary for creating
263 * connection lists which include the element's name
265 typedef struct
267 void **Data; /* pointer to index data */
268 Cardinal Location, /* currently used position */
269 DrawLocation, Number, /* number of objects in list */
270 Size;
271 } ListType;
273 /* ---------------------------------------------------------------------------
274 * some local identifiers
276 static Coord Bloat = 0;
277 static int TheFlag = FOUNDFLAG;
278 static void *thing_ptr1, *thing_ptr2, *thing_ptr3;
279 static int thing_type;
280 static bool User = false; /* user action causing this */
281 static bool drc = false; /* whether to stop if finding something not found */
282 static bool IsBad = false;
283 static Cardinal drcerr_count; /* count of drc errors */
284 static Cardinal TotalP, TotalV, NumberOfPads[2];
285 static ListType LineList[MAX_LAYER], /* list of objects to */
286 PolygonList[MAX_LAYER], ArcList[MAX_LAYER], PadList[2], RatList, PVList;
288 /* ---------------------------------------------------------------------------
289 * some local prototypes
291 static bool LookupLOConnectionsToPVList (bool);
292 static bool LookupLOConnectionsToLOList (bool);
293 static bool LookupPVConnectionsToLOList (bool);
294 static bool LookupPVConnectionsToPVList (void);
295 static bool LookupLOConnectionsToLine (LineType *, Cardinal, bool);
296 static bool LookupLOConnectionsToPad (PadType *, Cardinal);
297 static bool LookupLOConnectionsToPolygon (PolygonType *, Cardinal);
298 static bool LookupLOConnectionsToArc (ArcType *, Cardinal);
299 static bool LookupLOConnectionsToRatEnd (PointType *, Cardinal);
300 static bool IsRatPointOnLineEnd (PointType *, LineType *);
301 static bool ArcArcIntersect (ArcType *, ArcType *);
302 static bool PrepareNextLoop (FILE *);
303 static bool PrintElementConnections (ElementType *, FILE *, bool);
304 static bool ListsEmpty (bool);
305 static bool DoIt (bool, bool);
306 static void PrintElementNameList (ElementType *, FILE *);
307 static void PrintConnectionElementName (ElementType *, FILE *);
308 static void PrintConnectionListEntry (char *, ElementType *,
309 bool, FILE *);
310 static void PrintPadConnections (Cardinal, FILE *, bool);
311 static void PrintPinConnections (FILE *, bool);
312 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *,
313 FILE *);
314 static void DrawNewConnections (void);
315 static void DumpList (void);
316 static void LocateError (Coord *, Coord *);
317 static void BuildObjectList (int *, long int **, int **);
318 static void GotoError (void);
319 static bool DRCFind (int, void *, void *, void *);
320 static bool ListStart (int, void *, void *, void *);
321 static bool SetThing (int, void *, void *, void *);
322 static bool IsArcInPolygon (ArcType *, PolygonType *);
323 static bool IsLineInPolygon (LineType *, PolygonType *);
324 static bool IsPadInPolygon (PadType *, PolygonType *);
325 static bool IsPolygonInPolygon (PolygonType *, PolygonType *);
327 /* ---------------------------------------------------------------------------
328 * some of the 'pad' routines are the same as for lines because the 'pad'
329 * struct starts with a line struct. See global.h for details
331 bool
332 LinePadIntersect (LineType *Line, PadType *Pad)
334 return LineLineIntersect ((Line), (LineType *)Pad);
337 bool
338 ArcPadIntersect (ArcType *Arc, PadType *Pad)
340 return LineArcIntersect ((LineType *) (Pad), (Arc));
343 static bool
344 add_object_to_list (ListType *list, int type, void *ptr1, void *ptr2, void *ptr3)
346 AnyObjectType *object = (AnyObjectType *)ptr2;
348 if (User)
349 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3);
351 SET_FLAG (TheFlag, object);
352 LIST_ENTRY (list, list->Number) = object;
353 list->Number++;
355 #ifdef DEBUG
356 if (list.Number > list.Size)
357 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type, list.Number, list.Size);
358 #endif
360 if (drc && !TEST_FLAG (SELECTEDFLAG, object))
361 return (SetThing (type, ptr1, ptr2, ptr3));
362 return false;
365 static bool
366 ADD_PV_TO_LIST (PinType *Pin)
368 return add_object_to_list (&PVList, Pin->Element ? PIN_TYPE : VIA_TYPE,
369 Pin->Element ? Pin->Element : Pin, Pin, Pin);
372 static bool
373 ADD_PAD_TO_LIST (Cardinal L, PadType *Pad)
375 return add_object_to_list (&PadList[L], PAD_TYPE, Pad->Element, Pad, Pad);
378 static bool
379 ADD_LINE_TO_LIST (Cardinal L, LineType *Ptr)
381 return add_object_to_list (&LineList[L], LINE_TYPE, LAYER_PTR (L), Ptr, Ptr);
384 static bool
385 ADD_ARC_TO_LIST (Cardinal L, ArcType *Ptr)
387 return add_object_to_list (&ArcList[L], ARC_TYPE, LAYER_PTR (L), Ptr, Ptr);
390 static bool
391 ADD_RAT_TO_LIST (RatType *Ptr)
393 return add_object_to_list (&RatList, RATLINE_TYPE, Ptr, Ptr, Ptr);
396 static bool
397 ADD_POLYGON_TO_LIST (Cardinal L, PolygonType *Ptr)
399 return add_object_to_list (&PolygonList[L], POLYGON_TYPE, LAYER_PTR (L), Ptr, Ptr);
402 bool
403 PinLineIntersect (PinType *PV, LineType *Line)
405 /* IsLineInRectangle already has Bloat factor */
406 return TEST_FLAG (SQUAREFLAG,
407 PV) ? IsLineInRectangle (PV->X - (PIN_SIZE (PV) + 1) / 2,
408 PV->Y - (PIN_SIZE (PV) + 1) / 2,
409 PV->X + (PIN_SIZE (PV) + 1) / 2,
410 PV->Y + (PIN_SIZE (PV) + 1) / 2,
411 Line) : IsPointInPad (PV->X,
412 PV->Y,
413 MAX (PIN_SIZE (PV)
415 2.0 +
416 Bloat,
417 0.0),
418 (PadType *)Line);
422 bool
423 SetThing (int type, void *ptr1, void *ptr2, void *ptr3)
425 thing_ptr1 = ptr1;
426 thing_ptr2 = ptr2;
427 thing_ptr3 = ptr3;
428 thing_type = type;
429 if (type == PIN_TYPE && ptr1 == NULL)
431 thing_ptr1 = ptr3;
432 thing_type = VIA_TYPE;
434 return true;
437 bool
438 BoxBoxIntersection (BoxType *b1, BoxType *b2)
440 if (b2->X2 < b1->X1 || b2->X1 > b1->X2)
441 return false;
442 if (b2->Y2 < b1->Y1 || b2->Y1 > b1->Y2)
443 return false;
444 return true;
447 static bool
448 PadPadIntersect (PadType *p1, PadType *p2)
450 return LinePadIntersect ((LineType *) p1, p2);
453 static inline bool
454 PV_TOUCH_PV (PinType *PV1, PinType *PV2)
456 double t1, t2;
457 BoxType b1, b2;
459 t1 = MAX (PV1->Thickness / 2.0 + Bloat, 0);
460 t2 = MAX (PV2->Thickness / 2.0 + Bloat, 0);
461 if (IsPointOnPin (PV1->X, PV1->Y, t1, PV2)
462 || IsPointOnPin (PV2->X, PV2->Y, t2, PV1))
463 return true;
464 if (!TEST_FLAG (SQUAREFLAG, PV1) || !TEST_FLAG (SQUAREFLAG, PV2))
465 return false;
466 /* check for square/square overlap */
467 b1.X1 = PV1->X - t1;
468 b1.X2 = PV1->X + t1;
469 b1.Y1 = PV1->Y - t1;
470 b1.Y2 = PV1->Y + t1;
471 t2 = PV2->Thickness / 2.0;
472 b2.X1 = PV2->X - t2;
473 b2.X2 = PV2->X + t2;
474 b2.Y1 = PV2->Y - t2;
475 b2.Y2 = PV2->Y + t2;
476 return BoxBoxIntersection (&b1, &b2);
479 /* ---------------------------------------------------------------------------
480 * releases all allocated memory
482 static void
483 FreeLayoutLookupMemory (void)
485 Cardinal i;
487 for (i = 0; i < max_copper_layer; i++)
489 free (LineList[i].Data);
490 LineList[i].Data = NULL;
491 free (ArcList[i].Data);
492 ArcList[i].Data = NULL;
493 free (PolygonList[i].Data);
494 PolygonList[i].Data = NULL;
496 free (PVList.Data);
497 PVList.Data = NULL;
498 free (RatList.Data);
499 RatList.Data = NULL;
502 static void
503 FreeComponentLookupMemory (void)
505 free (PadList[0].Data);
506 PadList[0].Data = NULL;
507 free (PadList[1].Data);
508 PadList[1].Data = NULL;
511 /* ---------------------------------------------------------------------------
512 * allocates memory for component related stacks ...
513 * initializes index and sorts it by X1 and X2
515 static void
516 InitComponentLookup (void)
518 Cardinal i;
520 /* initialize pad data; start by counting the total number
521 * on each of the two possible layers
523 NumberOfPads[COMPONENT_LAYER] = NumberOfPads[SOLDER_LAYER] = 0;
524 ALLPAD_LOOP (PCB->Data);
526 if (TEST_FLAG (ONSOLDERFLAG, pad))
527 NumberOfPads[SOLDER_LAYER]++;
528 else
529 NumberOfPads[COMPONENT_LAYER]++;
531 ENDALL_LOOP;
532 for (i = 0; i < 2; i++)
534 /* allocate memory for working list */
535 PadList[i].Data = (void **)calloc (NumberOfPads[i], sizeof (PadType *));
537 /* clear some struct members */
538 PadList[i].Location = 0;
539 PadList[i].DrawLocation = 0;
540 PadList[i].Number = 0;
541 PadList[i].Size = NumberOfPads[i];
545 /* ---------------------------------------------------------------------------
546 * allocates memory for component related stacks ...
547 * initializes index and sorts it by X1 and X2
549 static void
550 InitLayoutLookup (void)
552 Cardinal i;
554 /* initialize line arc and polygon data */
555 for (i = 0; i < max_copper_layer; i++)
557 LayerType *layer = LAYER_PTR (i);
559 if (layer->LineN)
561 /* allocate memory for line pointer lists */
562 LineList[i].Data = (void **)calloc (layer->LineN, sizeof (LineType *));
563 LineList[i].Size = layer->LineN;
565 if (layer->ArcN)
567 ArcList[i].Data = (void **)calloc (layer->ArcN, sizeof (ArcType *));
568 ArcList[i].Size = layer->ArcN;
572 /* allocate memory for polygon list */
573 if (layer->PolygonN)
575 PolygonList[i].Data = (void **)calloc (layer->PolygonN, sizeof (PolygonType *));
576 PolygonList[i].Size = layer->PolygonN;
579 /* clear some struct members */
580 LineList[i].Location = 0;
581 LineList[i].DrawLocation = 0;
582 LineList[i].Number = 0;
583 ArcList[i].Location = 0;
584 ArcList[i].DrawLocation = 0;
585 ArcList[i].Number = 0;
586 PolygonList[i].Location = 0;
587 PolygonList[i].DrawLocation = 0;
588 PolygonList[i].Number = 0;
591 if (PCB->Data->pin_tree)
592 TotalP = PCB->Data->pin_tree->size;
593 else
594 TotalP = 0;
595 if (PCB->Data->via_tree)
596 TotalV = PCB->Data->via_tree->size;
597 else
598 TotalV = 0;
599 /* allocate memory for 'new PV to check' list and clear struct */
600 PVList.Data = (void **)calloc (TotalP + TotalV, sizeof (PinType *));
601 PVList.Size = TotalP + TotalV;
602 PVList.Location = 0;
603 PVList.DrawLocation = 0;
604 PVList.Number = 0;
605 /* Initialize ratline data */
606 RatList.Data = (void **)calloc (PCB->Data->RatN, sizeof (RatType *));
607 RatList.Size = PCB->Data->RatN;
608 RatList.Location = 0;
609 RatList.DrawLocation = 0;
610 RatList.Number = 0;
613 struct pv_info
615 Cardinal layer;
616 PinType pv;
617 jmp_buf env;
620 static int
621 LOCtoPVline_callback (const BoxType * b, void *cl)
623 LineType *line = (LineType *) b;
624 struct pv_info *i = (struct pv_info *) cl;
626 if (!TEST_FLAG (TheFlag, line) && PinLineIntersect (&i->pv, line) &&
627 !TEST_FLAG (HOLEFLAG, &i->pv))
629 if (ADD_LINE_TO_LIST (i->layer, line))
630 longjmp (i->env, 1);
632 return 0;
635 static int
636 LOCtoPVarc_callback (const BoxType * b, void *cl)
638 ArcType *arc = (ArcType *) b;
639 struct pv_info *i = (struct pv_info *) cl;
641 if (!TEST_FLAG (TheFlag, arc) && IS_PV_ON_ARC (&i->pv, arc) &&
642 !TEST_FLAG (HOLEFLAG, &i->pv))
644 if (ADD_ARC_TO_LIST (i->layer, arc))
645 longjmp (i->env, 1);
647 return 0;
650 static int
651 LOCtoPVpad_callback (const BoxType * b, void *cl)
653 PadType *pad = (PadType *) b;
654 struct pv_info *i = (struct pv_info *) cl;
656 if (!TEST_FLAG (TheFlag, pad) && IS_PV_ON_PAD (&i->pv, pad) &&
657 !TEST_FLAG (HOLEFLAG, &i->pv) &&
658 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER :
659 COMPONENT_LAYER, pad))
660 longjmp (i->env, 1);
661 return 0;
664 static int
665 LOCtoPVrat_callback (const BoxType * b, void *cl)
667 RatType *rat = (RatType *) b;
668 struct pv_info *i = (struct pv_info *) cl;
670 if (!TEST_FLAG (TheFlag, rat) && IS_PV_ON_RAT (&i->pv, rat) &&
671 ADD_RAT_TO_LIST (rat))
672 longjmp (i->env, 1);
673 return 0;
675 static int
676 LOCtoPVpoly_callback (const BoxType * b, void *cl)
678 PolygonType *polygon = (PolygonType *) b;
679 struct pv_info *i = (struct pv_info *) cl;
681 /* if the pin doesn't have a therm and polygon is clearing
682 * then it can't touch due to clearance, so skip the expensive
683 * test. If it does have a therm, you still need to test
684 * because it might not be inside the polygon, or it could
685 * be on an edge such that it doesn't actually touch.
687 if (!TEST_FLAG (TheFlag, polygon) && !TEST_FLAG (HOLEFLAG, &i->pv) &&
688 (TEST_THERM (i->layer, &i->pv) ||
689 !TEST_FLAG (CLEARPOLYFLAG,
690 polygon)
691 || !i->pv.Clearance))
693 double wide = MAX (0.5 * i->pv.Thickness + Bloat, 0);
694 if (TEST_FLAG (SQUAREFLAG, &i->pv))
696 Coord x1 = i->pv.X - (i->pv.Thickness + 1 + Bloat) / 2;
697 Coord x2 = i->pv.X + (i->pv.Thickness + 1 + Bloat) / 2;
698 Coord y1 = i->pv.Y - (i->pv.Thickness + 1 + Bloat) / 2;
699 Coord y2 = i->pv.Y + (i->pv.Thickness + 1 + Bloat) / 2;
700 if (IsRectangleInPolygon (x1, y1, x2, y2, polygon)
701 && ADD_POLYGON_TO_LIST (i->layer, polygon))
702 longjmp (i->env, 1);
704 else if (TEST_FLAG (OCTAGONFLAG, &i->pv))
706 POLYAREA *oct = OctagonPoly (i->pv.X, i->pv.Y, i->pv.Thickness / 2);
707 if (isects (oct, polygon, true)
708 && ADD_POLYGON_TO_LIST (i->layer, polygon))
709 longjmp (i->env, 1);
711 else if (IsPointInPolygon (i->pv.X, i->pv.Y, wide,
712 polygon)
713 && ADD_POLYGON_TO_LIST (i->layer, polygon))
714 longjmp (i->env, 1);
716 return 0;
719 /* ---------------------------------------------------------------------------
720 * checks if a PV is connected to LOs, if it is, the LO is added to
721 * the appropriate list and the 'used' flag is set
723 static bool
724 LookupLOConnectionsToPVList (bool AndRats)
726 Cardinal layer_no;
727 struct pv_info info;
729 /* loop over all PVs currently on list */
730 while (PVList.Location < PVList.Number)
732 /* get pointer to data */
733 info.pv = *(PVLIST_ENTRY (PVList.Location));
734 EXPAND_BOUNDS (&info.pv);
736 /* check pads */
737 if (setjmp (info.env) == 0)
738 r_search (PCB->Data->pad_tree, (BoxType *) & info.pv, NULL,
739 LOCtoPVpad_callback, &info);
740 else
741 return true;
743 /* now all lines, arcs and polygons of the several layers */
744 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
746 LayerType *layer = LAYER_PTR (layer_no);
748 if (layer->no_drc)
749 continue;
751 info.layer = layer_no;
752 /* add touching lines */
753 if (setjmp (info.env) == 0)
754 r_search (layer->line_tree, (BoxType *) & info.pv,
755 NULL, LOCtoPVline_callback, &info);
756 else
757 return true;
758 /* add touching arcs */
759 if (setjmp (info.env) == 0)
760 r_search (layer->arc_tree, (BoxType *) & info.pv,
761 NULL, LOCtoPVarc_callback, &info);
762 else
763 return true;
764 /* check all polygons */
765 if (setjmp (info.env) == 0)
766 r_search (layer->polygon_tree, (BoxType *) & info.pv,
767 NULL, LOCtoPVpoly_callback, &info);
768 else
769 return true;
771 /* Check for rat-lines that may intersect the PV */
772 if (AndRats)
774 if (setjmp (info.env) == 0)
775 r_search (PCB->Data->rat_tree, (BoxType *) & info.pv, NULL,
776 LOCtoPVrat_callback, &info);
777 else
778 return true;
780 PVList.Location++;
782 return false;
785 /* ---------------------------------------------------------------------------
786 * find all connections between LO at the current list position and new LOs
788 static bool
789 LookupLOConnectionsToLOList (bool AndRats)
791 bool done;
792 Cardinal i, group, layer, ratposition,
793 lineposition[MAX_LAYER],
794 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2];
796 /* copy the current LO list positions; the original data is changed
797 * by 'LookupPVConnectionsToLOList()' which has to check the same
798 * list entries plus the new ones
800 for (i = 0; i < max_copper_layer; i++)
802 lineposition[i] = LineList[i].Location;
803 polyposition[i] = PolygonList[i].Location;
804 arcposition[i] = ArcList[i].Location;
806 for (i = 0; i < 2; i++)
807 padposition[i] = PadList[i].Location;
808 ratposition = RatList.Location;
810 /* loop over all new LOs in the list; recurse until no
811 * more new connections in the layergroup were found
815 Cardinal *position;
817 if (AndRats)
819 position = &ratposition;
820 for (; *position < RatList.Number; (*position)++)
822 group = RATLIST_ENTRY (*position)->group1;
823 if (LookupLOConnectionsToRatEnd
824 (&(RATLIST_ENTRY (*position)->Point1), group))
825 return (true);
826 group = RATLIST_ENTRY (*position)->group2;
827 if (LookupLOConnectionsToRatEnd
828 (&(RATLIST_ENTRY (*position)->Point2), group))
829 return (true);
832 /* loop over all layergroups */
833 for (group = 0; group < max_group; group++)
835 Cardinal entry;
837 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
839 layer = PCB->LayerGroups.Entries[group][entry];
841 /* be aware that the layer number equal max_copper_layer
842 * and max_copper_layer+1 have a special meaning for pads
844 if (layer < max_copper_layer)
846 /* try all new lines */
847 position = &lineposition[layer];
848 for (; *position < LineList[layer].Number; (*position)++)
849 if (LookupLOConnectionsToLine
850 (LINELIST_ENTRY (layer, *position), group, true))
851 return (true);
853 /* try all new arcs */
854 position = &arcposition[layer];
855 for (; *position < ArcList[layer].Number; (*position)++)
856 if (LookupLOConnectionsToArc
857 (ARCLIST_ENTRY (layer, *position), group))
858 return (true);
860 /* try all new polygons */
861 position = &polyposition[layer];
862 for (; *position < PolygonList[layer].Number; (*position)++)
863 if (LookupLOConnectionsToPolygon
864 (POLYGONLIST_ENTRY (layer, *position), group))
865 return (true);
867 else
869 /* try all new pads */
870 layer -= max_copper_layer;
871 if (layer > 1)
873 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
874 layer, max_copper_layer);
875 return false;
877 position = &padposition[layer];
878 for (; *position < PadList[layer].Number; (*position)++)
879 if (LookupLOConnectionsToPad
880 (PADLIST_ENTRY (layer, *position), group))
881 return (true);
886 /* check if all lists are done; Later for-loops
887 * may have changed the prior lists
889 done = !AndRats || ratposition >= RatList.Number;
890 done = done && padposition[0] >= PadList[0].Number &&
891 padposition[1] >= PadList[1].Number;
892 for (layer = 0; layer < max_copper_layer; layer++)
893 done = done &&
894 lineposition[layer] >= LineList[layer].Number &&
895 arcposition[layer] >= ArcList[layer].Number &&
896 polyposition[layer] >= PolygonList[layer].Number;
898 while (!done);
899 return (false);
902 static int
903 pv_pv_callback (const BoxType * b, void *cl)
905 PinType *pin = (PinType *) b;
906 struct pv_info *i = (struct pv_info *) cl;
908 if (!TEST_FLAG (TheFlag, pin) && PV_TOUCH_PV (&i->pv, pin))
910 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, &i->pv))
912 SET_FLAG (WARNFLAG, pin);
913 Settings.RatWarn = true;
914 if (pin->Element)
915 Message (_("WARNING: Hole too close to pin.\n"));
916 else
917 Message (_("WARNING: Hole too close to via.\n"));
919 else if (ADD_PV_TO_LIST (pin))
920 longjmp (i->env, 1);
922 return 0;
925 /* ---------------------------------------------------------------------------
926 * searches for new PVs that are connected to PVs on the list
928 static bool
929 LookupPVConnectionsToPVList (void)
931 Cardinal save_place;
932 struct pv_info info;
935 /* loop over all PVs on list */
936 save_place = PVList.Location;
937 while (PVList.Location < PVList.Number)
939 /* get pointer to data */
940 info.pv = *(PVLIST_ENTRY (PVList.Location));
941 EXPAND_BOUNDS (&info.pv);
942 if (setjmp (info.env) == 0)
943 r_search (PCB->Data->via_tree, (BoxType *) & info.pv, NULL,
944 pv_pv_callback, &info);
945 else
946 return true;
947 if (setjmp (info.env) == 0)
948 r_search (PCB->Data->pin_tree, (BoxType *) & info.pv, NULL,
949 pv_pv_callback, &info);
950 else
951 return true;
952 PVList.Location++;
954 PVList.Location = save_place;
955 return (false);
958 struct lo_info
960 Cardinal layer;
961 LineType line;
962 PadType pad;
963 ArcType arc;
964 PolygonType polygon;
965 RatType rat;
966 jmp_buf env;
969 static int
970 pv_line_callback (const BoxType * b, void *cl)
972 PinType *pv = (PinType *) b;
973 struct lo_info *i = (struct lo_info *) cl;
975 if (!TEST_FLAG (TheFlag, pv) && PinLineIntersect (pv, &i->line))
977 if (TEST_FLAG (HOLEFLAG, pv))
979 SET_FLAG (WARNFLAG, pv);
980 Settings.RatWarn = true;
981 Message (_("WARNING: Hole too close to line.\n"));
983 else if (ADD_PV_TO_LIST (pv))
984 longjmp (i->env, 1);
986 return 0;
989 static int
990 pv_pad_callback (const BoxType * b, void *cl)
992 PinType *pv = (PinType *) b;
993 struct lo_info *i = (struct lo_info *) cl;
995 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_PAD (pv, &i->pad))
997 if (TEST_FLAG (HOLEFLAG, pv))
999 SET_FLAG (WARNFLAG, pv);
1000 Settings.RatWarn = true;
1001 Message (_("WARNING: Hole too close to pad.\n"));
1003 else if (ADD_PV_TO_LIST (pv))
1004 longjmp (i->env, 1);
1006 return 0;
1009 static int
1010 pv_arc_callback (const BoxType * b, void *cl)
1012 PinType *pv = (PinType *) b;
1013 struct lo_info *i = (struct lo_info *) cl;
1015 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_ARC (pv, &i->arc))
1017 if (TEST_FLAG (HOLEFLAG, pv))
1019 SET_FLAG (WARNFLAG, pv);
1020 Settings.RatWarn = true;
1021 Message (_("WARNING: Hole touches arc.\n"));
1023 else if (ADD_PV_TO_LIST (pv))
1024 longjmp (i->env, 1);
1026 return 0;
1029 static int
1030 pv_poly_callback (const BoxType * b, void *cl)
1032 PinType *pv = (PinType *) b;
1033 struct lo_info *i = (struct lo_info *) cl;
1035 /* note that holes in polygons are ok, so they don't generate warnings. */
1036 if (!TEST_FLAG (TheFlag, pv) && !TEST_FLAG (HOLEFLAG, pv) &&
1037 (TEST_THERM (i->layer, pv) ||
1038 !TEST_FLAG (CLEARPOLYFLAG, &i->polygon) ||
1039 !pv->Clearance))
1041 if (TEST_FLAG (SQUAREFLAG, pv))
1043 Coord x1, x2, y1, y2;
1044 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1045 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1046 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1047 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1048 if (IsRectangleInPolygon (x1, y1, x2, y2, &i->polygon)
1049 && ADD_PV_TO_LIST (pv))
1050 longjmp (i->env, 1);
1052 else if (TEST_FLAG (OCTAGONFLAG, pv))
1054 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2);
1055 if (isects (oct, &i->polygon, true) && ADD_PV_TO_LIST (pv))
1056 longjmp (i->env, 1);
1058 else
1060 if (IsPointInPolygon
1061 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, &i->polygon)
1062 && ADD_PV_TO_LIST (pv))
1063 longjmp (i->env, 1);
1066 return 0;
1069 static int
1070 pv_rat_callback (const BoxType * b, void *cl)
1072 PinType *pv = (PinType *) b;
1073 struct lo_info *i = (struct lo_info *) cl;
1075 /* rats can't cause DRC so there is no early exit */
1076 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_RAT (pv, &i->rat))
1077 ADD_PV_TO_LIST (pv);
1078 return 0;
1081 /* ---------------------------------------------------------------------------
1082 * searches for new PVs that are connected to NEW LOs on the list
1083 * This routine updates the position counter of the lists too.
1085 static bool
1086 LookupPVConnectionsToLOList (bool AndRats)
1088 Cardinal layer_no;
1089 struct lo_info info;
1091 /* loop over all layers */
1092 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
1094 LayerType *layer = LAYER_PTR (layer_no);
1096 if (layer->no_drc)
1097 continue;
1098 /* do nothing if there are no PV's */
1099 if (TotalP + TotalV == 0)
1101 LineList[layer_no].Location = LineList[layer_no].Number;
1102 ArcList[layer_no].Location = ArcList[layer_no].Number;
1103 PolygonList[layer_no].Location = PolygonList[layer_no].Number;
1104 continue;
1107 /* check all lines */
1108 while (LineList[layer_no].Location < LineList[layer_no].Number)
1110 info.line = *(LINELIST_ENTRY (layer_no, LineList[layer_no].Location));
1111 EXPAND_BOUNDS (&info.line);
1112 if (setjmp (info.env) == 0)
1113 r_search (PCB->Data->via_tree, (BoxType *) & info.line, NULL,
1114 pv_line_callback, &info);
1115 else
1116 return true;
1117 if (setjmp (info.env) == 0)
1118 r_search (PCB->Data->pin_tree, (BoxType *) & info.line, NULL,
1119 pv_line_callback, &info);
1120 else
1121 return true;
1122 LineList[layer_no].Location++;
1125 /* check all arcs */
1126 while (ArcList[layer_no].Location < ArcList[layer_no].Number)
1128 info.arc = *(ARCLIST_ENTRY (layer_no, ArcList[layer_no].Location));
1129 EXPAND_BOUNDS (&info.arc);
1130 if (setjmp (info.env) == 0)
1131 r_search (PCB->Data->via_tree, (BoxType *) & info.arc, NULL,
1132 pv_arc_callback, &info);
1133 else
1134 return true;
1135 if (setjmp (info.env) == 0)
1136 r_search (PCB->Data->pin_tree, (BoxType *) & info.arc, NULL,
1137 pv_arc_callback, &info);
1138 else
1139 return true;
1140 ArcList[layer_no].Location++;
1143 /* now all polygons */
1144 info.layer = layer_no;
1145 while (PolygonList[layer_no].Location < PolygonList[layer_no].Number)
1147 info.polygon =
1148 *(POLYGONLIST_ENTRY (layer_no, PolygonList[layer_no].Location));
1149 EXPAND_BOUNDS (&info.polygon);
1150 if (setjmp (info.env) == 0)
1151 r_search (PCB->Data->via_tree, (BoxType *) & info.polygon, NULL,
1152 pv_poly_callback, &info);
1153 else
1154 return true;
1155 if (setjmp (info.env) == 0)
1156 r_search (PCB->Data->pin_tree, (BoxType *) & info.polygon, NULL,
1157 pv_poly_callback, &info);
1158 else
1159 return true;
1160 PolygonList[layer_no].Location++;
1164 /* loop over all pad-layers */
1165 for (layer_no = 0; layer_no < 2; layer_no++)
1167 /* do nothing if there are no PV's */
1168 if (TotalP + TotalV == 0)
1170 PadList[layer_no].Location = PadList[layer_no].Number;
1171 continue;
1174 /* check all pads; for a detailed description see
1175 * the handling of lines in this subroutine
1177 while (PadList[layer_no].Location < PadList[layer_no].Number)
1179 info.pad = *(PADLIST_ENTRY (layer_no, PadList[layer_no].Location));
1180 EXPAND_BOUNDS (&info.pad);
1181 if (setjmp (info.env) == 0)
1182 r_search (PCB->Data->via_tree, (BoxType *) & info.pad, NULL,
1183 pv_pad_callback, &info);
1184 else
1185 return true;
1186 if (setjmp (info.env) == 0)
1187 r_search (PCB->Data->pin_tree, (BoxType *) & info.pad, NULL,
1188 pv_pad_callback, &info);
1189 else
1190 return true;
1191 PadList[layer_no].Location++;
1195 /* do nothing if there are no PV's */
1196 if (TotalP + TotalV == 0)
1197 RatList.Location = RatList.Number;
1199 /* check all rat-lines */
1200 if (AndRats)
1202 while (RatList.Location < RatList.Number)
1204 info.rat = *(RATLIST_ENTRY (RatList.Location));
1205 r_search_pt (PCB->Data->via_tree, & info.rat.Point1, 1, NULL,
1206 pv_rat_callback, &info);
1207 r_search_pt (PCB->Data->via_tree, & info.rat.Point2, 1, NULL,
1208 pv_rat_callback, &info);
1209 r_search_pt (PCB->Data->pin_tree, & info.rat.Point1, 1, NULL,
1210 pv_rat_callback, &info);
1211 r_search_pt (PCB->Data->pin_tree, & info.rat.Point2, 1, NULL,
1212 pv_rat_callback, &info);
1214 RatList.Location++;
1217 return (false);
1220 /* reduce arc start angle and delta to 0..360 */
1221 static void
1222 normalize_angles (Angle *sa, Angle *d)
1224 if (*d < 0)
1226 *sa += *d;
1227 *d = - *d;
1229 if (*d > 360) /* full circle */
1230 *d = 360;
1231 *sa = NormalizeAngle (*sa);
1234 static int
1235 radius_crosses_arc (double x, double y, ArcType *arc)
1237 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG;
1238 Angle sa = arc->StartAngle, d = arc->Delta;
1240 normalize_angles (&sa, &d);
1241 if (alpha < 0)
1242 alpha += 360;
1243 if (sa <= alpha)
1244 return (sa + d) >= alpha;
1245 return (sa + d - 360) >= alpha;
1248 static void
1249 get_arc_ends (Coord *box, ArcType *arc)
1251 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle);
1252 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle);
1253 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta));
1254 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta));
1256 /* ---------------------------------------------------------------------------
1257 * check if two arcs intersect
1258 * first we check for circle intersections,
1259 * then find the actual points of intersection
1260 * and test them to see if they are on arcs
1262 * consider a, the distance from the center of arc 1
1263 * to the point perpendicular to the intersecting points.
1265 * a = (r1^2 - r2^2 + l^2)/(2l)
1267 * the perpendicular distance to the point of intersection
1268 * is then
1270 * d = sqrt(r1^2 - a^2)
1272 * the points of intersection would then be
1274 * x = X1 + a/l dx +- d/l dy
1275 * y = Y1 + a/l dy -+ d/l dx
1277 * where dx = X2 - X1 and dy = Y2 - Y1
1281 static bool
1282 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2)
1284 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl;
1285 Coord pdx, pdy;
1286 Coord box[8];
1288 t = 0.5 * Arc1->Thickness + Bloat;
1289 t2 = 0.5 * Arc2->Thickness;
1290 t1 = t2 + Bloat;
1292 /* too thin arc */
1293 if (t < 0 || t1 < 0)
1294 return false;
1296 /* try the end points first */
1297 get_arc_ends (&box[0], Arc1);
1298 get_arc_ends (&box[4], Arc2);
1299 if (IsPointOnArc (box[0], box[1], t, Arc2)
1300 || IsPointOnArc (box[2], box[3], t, Arc2)
1301 || IsPointOnArc (box[4], box[5], t, Arc1)
1302 || IsPointOnArc (box[6], box[7], t, Arc1))
1303 return true;
1305 pdx = Arc2->X - Arc1->X;
1306 pdy = Arc2->Y - Arc1->Y;
1307 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y);
1308 /* concentric arcs, simpler intersection conditions */
1309 if (dl < 0.5)
1311 if ((Arc1->Width - t >= Arc2->Width - t2
1312 && Arc1->Width - t <= Arc2->Width + t2)
1313 || (Arc1->Width + t >= Arc2->Width - t2
1314 && Arc1->Width + t <= Arc2->Width + t2))
1316 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta;
1317 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta;
1318 /* NB the endpoints have already been checked,
1319 so we just compare the angles */
1321 normalize_angles (&sa1, &d1);
1322 normalize_angles (&sa2, &d2);
1323 /* sa1 == sa2 was caught when checking endpoints */
1324 if (sa1 > sa2)
1325 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2)
1326 return true;
1327 if (sa2 > sa1)
1328 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1)
1329 return true;
1331 return false;
1333 r1 = Arc1->Width;
1334 r2 = Arc2->Width;
1335 /* arcs centerlines are too far or too near */
1336 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1)
1338 /* check the nearest to the other arc's center point */
1339 dx = pdx * r1 / dl;
1340 dy = pdy * r1 / dl;
1341 if (dl + r1 < r2) /* Arc1 inside Arc2 */
1343 dx = - dx;
1344 dy = - dy;
1347 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1)
1348 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2))
1349 return true;
1351 dx = - pdx * r2 / dl;
1352 dy = - pdy * r2 / dl;
1353 if (dl + r2 < r1) /* Arc2 inside Arc1 */
1355 dx = - dx;
1356 dy = - dy;
1359 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2)
1360 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1))
1361 return true;
1362 return false;
1365 l = dl * dl;
1366 r1 *= r1;
1367 r2 *= r2;
1368 a = 0.5 * (r1 - r2 + l) / l;
1369 r1 = r1 / l;
1370 d = r1 - a * a;
1371 /* the circles are too far apart to touch or probably just touch:
1372 check the nearest point */
1373 if (d < 0)
1374 d = 0;
1375 else
1376 d = sqrt (d);
1377 x = Arc1->X + a * pdx;
1378 y = Arc1->Y + a * pdy;
1379 dx = d * pdx;
1380 dy = d * pdy;
1381 if (radius_crosses_arc (x + dy, y - dx, Arc1)
1382 && IsPointOnArc (x + dy, y - dx, t, Arc2))
1383 return true;
1384 if (radius_crosses_arc (x + dy, y - dx, Arc2)
1385 && IsPointOnArc (x + dy, y - dx, t1, Arc1))
1386 return true;
1388 if (radius_crosses_arc (x - dy, y + dx, Arc1)
1389 && IsPointOnArc (x - dy, y + dx, t, Arc2))
1390 return true;
1391 if (radius_crosses_arc (x - dy, y + dx, Arc2)
1392 && IsPointOnArc (x - dy, y + dx, t1, Arc1))
1393 return true;
1394 return false;
1397 /* ---------------------------------------------------------------------------
1398 * Tests if point is same as line end point
1400 static bool
1401 IsRatPointOnLineEnd (PointType *Point, LineType *Line)
1403 if ((Point->X == Line->Point1.X
1404 && Point->Y == Line->Point1.Y)
1405 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y))
1406 return (true);
1407 return (false);
1410 static void
1411 form_slanted_rectangle (PointType p[4], LineType *l)
1412 /* writes vertices of a squared line */
1414 double dwx = 0, dwy = 0;
1415 if (l->Point1.Y == l->Point2.Y)
1416 dwx = l->Thickness / 2.0;
1417 else if (l->Point1.X == l->Point2.X)
1418 dwy = l->Thickness / 2.0;
1419 else
1421 Coord dX = l->Point2.X - l->Point1.X;
1422 Coord dY = l->Point2.Y - l->Point1.Y;
1423 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y);
1424 dwx = l->Thickness / 2.0 / r * dX;
1425 dwy = l->Thickness / 2.0 / r * dY;
1427 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx;
1428 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx;
1429 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx;
1430 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx;
1432 /* ---------------------------------------------------------------------------
1433 * checks if two lines intersect
1434 * from news FAQ:
1436 * Let A,B,C,D be 2-space position vectors. Then the directed line
1437 * segments AB & CD are given by:
1439 * AB=A+r(B-A), r in [0,1]
1440 * CD=C+s(D-C), s in [0,1]
1442 * If AB & CD intersect, then
1444 * A+r(B-A)=C+s(D-C), or
1446 * XA+r(XB-XA)=XC+s(XD-XC)
1447 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1449 * Solving the above for r and s yields
1451 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1452 * r = ----------------------------- (eqn 1)
1453 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1455 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1456 * s = ----------------------------- (eqn 2)
1457 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1459 * Let I be the position vector of the intersection point, then
1461 * I=A+r(B-A) or
1463 * XI=XA+r(XB-XA)
1464 * YI=YA+r(YB-YA)
1466 * By examining the values of r & s, you can also determine some
1467 * other limiting conditions:
1469 * If 0<=r<=1 & 0<=s<=1, intersection exists
1470 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1472 * If the denominator in eqn 1 is zero, AB & CD are parallel
1473 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1475 * If the intersection point of the 2 lines are needed (lines in this
1476 * context mean infinite lines) regardless whether the two line
1477 * segments intersect, then
1479 * If r>1, I is located on extension of AB
1480 * If r<0, I is located on extension of BA
1481 * If s>1, I is located on extension of CD
1482 * If s<0, I is located on extension of DC
1484 * Also note that the denominators of eqn 1 & 2 are identical.
1487 bool
1488 LineLineIntersect (LineType *Line1, LineType *Line2)
1490 double s, r;
1491 double line1_dx, line1_dy, line2_dx, line2_dy,
1492 point1_dx, point1_dy;
1493 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */
1495 PointType p[4];
1496 form_slanted_rectangle (p, Line1);
1497 return IsLineInQuadrangle (p, Line2);
1499 /* here come only round Line1 because IsLineInQuadrangle()
1500 calls LineLineIntersect() with first argument rounded*/
1501 if (TEST_FLAG (SQUAREFLAG, Line2))
1503 PointType p[4];
1504 form_slanted_rectangle (p, Line2);
1505 return IsLineInQuadrangle (p, Line1);
1507 /* now all lines are round */
1509 /* Check endpoints: this provides a quick exit, catches
1510 * cases where the "real" lines don't intersect but the
1511 * thick lines touch, and ensures that the dx/dy business
1512 * below does not cause a divide-by-zero. */
1513 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y,
1514 MAX (Line2->Thickness / 2 + Bloat, 0),
1515 (PadType *) Line1)
1516 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y,
1517 MAX (Line2->Thickness / 2 + Bloat, 0),
1518 (PadType *) Line1)
1519 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y,
1520 MAX (Line1->Thickness / 2 + Bloat, 0),
1521 (PadType *) Line2)
1522 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y,
1523 MAX (Line1->Thickness / 2 + Bloat, 0),
1524 (PadType *) Line2))
1525 return true;
1527 /* setup some constants */
1528 line1_dx = Line1->Point2.X - Line1->Point1.X;
1529 line1_dy = Line1->Point2.Y - Line1->Point1.Y;
1530 line2_dx = Line2->Point2.X - Line2->Point1.X;
1531 line2_dy = Line2->Point2.Y - Line2->Point1.Y;
1532 point1_dx = Line1->Point1.X - Line2->Point1.X;
1533 point1_dy = Line1->Point1.Y - Line2->Point1.Y;
1535 /* If either line is a point, we have failed already, since the
1536 * endpoint check above will have caught an "intersection". */
1537 if ((line1_dx == 0 && line1_dy == 0)
1538 || (line2_dx == 0 && line2_dy == 0))
1539 return false;
1541 /* set s to cross product of Line1 and the line
1542 * Line1.Point1--Line2.Point1 (as vectors) */
1543 s = point1_dy * line1_dx - point1_dx * line1_dy;
1545 /* set r to cross product of both lines (as vectors) */
1546 r = line1_dx * line2_dy - line1_dy * line2_dx;
1548 /* No cross product means parallel lines, or maybe Line2 is
1549 * zero-length. In either case, since we did a bounding-box
1550 * check before getting here, the above IsPointInPad() checks
1551 * will have caught any intersections. */
1552 if (r == 0.0)
1553 return false;
1555 s /= r;
1556 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r;
1558 /* intersection is at least on AB */
1559 if (r >= 0.0 && r <= 1.0)
1560 return (s >= 0.0 && s <= 1.0);
1562 /* intersection is at least on CD */
1563 /* [removed this case since it always returns false --asp] */
1564 return false;
1567 /*---------------------------------------------------
1569 * Check for line intersection with an arc
1571 * Mostly this is like the circle/line intersection
1572 * found in IsPointOnLine (search.c) see the detailed
1573 * discussion for the basics there.
1575 * Since this is only an arc, not a full circle we need
1576 * to find the actual points of intersection with the
1577 * circle, and see if they are on the arc.
1579 * To do this, we translate along the line from the point Q
1580 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1581 * but it's handy to normalize with respect to l, the line
1582 * length so a single projection is done (e.g. we don't first
1583 * find the point Q
1585 * The projection is now of the form
1587 * Px = X1 + (r +- r2)(X2 - X1)
1588 * Py = Y1 + (r +- r2)(Y2 - Y1)
1590 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1591 * note that this is the variable d, not the symbol d described in IsPointOnLine
1592 * (variable d = symbol d * l)
1594 * The end points are hell so they are checked individually
1596 bool
1597 LineArcIntersect (LineType *Line, ArcType *Arc)
1599 double dx, dy, dx1, dy1, l, d, r, r2, Radius;
1600 BoxType *box;
1602 dx = Line->Point2.X - Line->Point1.X;
1603 dy = Line->Point2.Y - Line->Point1.Y;
1604 dx1 = Line->Point1.X - Arc->X;
1605 dy1 = Line->Point1.Y - Arc->Y;
1606 l = dx * dx + dy * dy;
1607 d = dx * dy1 - dy * dx1;
1608 d *= d;
1610 /* use the larger diameter circle first */
1611 Radius =
1612 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0);
1613 Radius *= Radius;
1614 r2 = Radius * l - d;
1615 /* projection doesn't even intersect circle when r2 < 0 */
1616 if (r2 < 0)
1617 return (false);
1618 /* check the ends of the line in case the projected point */
1619 /* of intersection is beyond the line end */
1620 if (IsPointOnArc
1621 (Line->Point1.X, Line->Point1.Y,
1622 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1623 return (true);
1624 if (IsPointOnArc
1625 (Line->Point2.X, Line->Point2.Y,
1626 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1627 return (true);
1628 if (l == 0.0)
1629 return (false);
1630 r2 = sqrt (r2);
1631 Radius = -(dx * dx1 + dy * dy1);
1632 r = (Radius + r2) / l;
1633 if (r >= 0 && r <= 1
1634 && IsPointOnArc (Line->Point1.X + r * dx,
1635 Line->Point1.Y + r * dy,
1636 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1637 return (true);
1638 r = (Radius - r2) / l;
1639 if (r >= 0 && r <= 1
1640 && IsPointOnArc (Line->Point1.X + r * dx,
1641 Line->Point1.Y + r * dy,
1642 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1643 return (true);
1644 /* check arc end points */
1645 box = GetArcEnds (Arc);
1646 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1647 return true;
1648 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1649 return true;
1650 return false;
1653 static int
1654 LOCtoArcLine_callback (const BoxType * b, void *cl)
1656 LineType *line = (LineType *) b;
1657 struct lo_info *i = (struct lo_info *) cl;
1659 if (!TEST_FLAG (TheFlag, line) && LineArcIntersect (line, &i->arc))
1661 if (ADD_LINE_TO_LIST (i->layer, line))
1662 longjmp (i->env, 1);
1664 return 0;
1667 static int
1668 LOCtoArcArc_callback (const BoxType * b, void *cl)
1670 ArcType *arc = (ArcType *) b;
1671 struct lo_info *i = (struct lo_info *) cl;
1673 if (!arc->Thickness)
1674 return 0;
1675 if (!TEST_FLAG (TheFlag, arc) && ArcArcIntersect (&i->arc, arc))
1677 if (ADD_ARC_TO_LIST (i->layer, arc))
1678 longjmp (i->env, 1);
1680 return 0;
1683 static int
1684 LOCtoArcPad_callback (const BoxType * b, void *cl)
1686 PadType *pad = (PadType *) b;
1687 struct lo_info *i = (struct lo_info *) cl;
1689 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1690 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1691 && ArcPadIntersect (&i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1692 longjmp (i->env, 1);
1693 return 0;
1696 /* ---------------------------------------------------------------------------
1697 * searches all LOs that are connected to the given arc on the given
1698 * layergroup. All found connections are added to the list
1700 * the notation that is used is:
1701 * Xij means Xj at arc i
1703 static bool
1704 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup)
1706 Cardinal entry;
1707 struct lo_info info;
1709 info.arc = *Arc;
1710 EXPAND_BOUNDS (&info.arc);
1711 /* loop over all layers of the group */
1712 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1714 Cardinal layer_no;
1715 LayerType *layer;
1716 GList *i;
1718 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1719 layer = LAYER_PTR (layer_no);
1721 /* handle normal layers */
1722 if (layer_no < max_copper_layer)
1724 info.layer = layer_no;
1725 /* add arcs */
1726 if (setjmp (info.env) == 0)
1727 r_search (layer->line_tree, &info.arc.BoundingBox,
1728 NULL, LOCtoArcLine_callback, &info);
1729 else
1730 return true;
1732 if (setjmp (info.env) == 0)
1733 r_search (layer->arc_tree, &info.arc.BoundingBox,
1734 NULL, LOCtoArcArc_callback, &info);
1735 else
1736 return true;
1738 /* now check all polygons */
1739 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1741 PolygonType *polygon = i->data;
1742 if (!TEST_FLAG (TheFlag, polygon) && IsArcInPolygon (Arc, polygon)
1743 && ADD_POLYGON_TO_LIST (layer_no, polygon))
1744 return true;
1747 else
1749 info.layer = layer_no - max_copper_layer;
1750 if (setjmp (info.env) == 0)
1751 r_search (PCB->Data->pad_tree, &info.arc.BoundingBox, NULL,
1752 LOCtoArcPad_callback, &info);
1753 else
1754 return true;
1757 return (false);
1760 static int
1761 LOCtoLineLine_callback (const BoxType * b, void *cl)
1763 LineType *line = (LineType *) b;
1764 struct lo_info *i = (struct lo_info *) cl;
1766 if (!TEST_FLAG (TheFlag, line) && LineLineIntersect (&i->line, line))
1768 if (ADD_LINE_TO_LIST (i->layer, line))
1769 longjmp (i->env, 1);
1771 return 0;
1774 static int
1775 LOCtoLineArc_callback (const BoxType * b, void *cl)
1777 ArcType *arc = (ArcType *) b;
1778 struct lo_info *i = (struct lo_info *) cl;
1780 if (!arc->Thickness)
1781 return 0;
1782 if (!TEST_FLAG (TheFlag, arc) && LineArcIntersect (&i->line, arc))
1784 if (ADD_ARC_TO_LIST (i->layer, arc))
1785 longjmp (i->env, 1);
1787 return 0;
1790 static int
1791 LOCtoLineRat_callback (const BoxType * b, void *cl)
1793 RatType *rat = (RatType *) b;
1794 struct lo_info *i = (struct lo_info *) cl;
1796 if (!TEST_FLAG (TheFlag, rat))
1798 if ((rat->group1 == i->layer)
1799 && IsRatPointOnLineEnd (&rat->Point1, &i->line))
1801 if (ADD_RAT_TO_LIST (rat))
1802 longjmp (i->env, 1);
1804 else if ((rat->group2 == i->layer)
1805 && IsRatPointOnLineEnd (&rat->Point2, &i->line))
1807 if (ADD_RAT_TO_LIST (rat))
1808 longjmp (i->env, 1);
1811 return 0;
1814 static int
1815 LOCtoLinePad_callback (const BoxType * b, void *cl)
1817 PadType *pad = (PadType *) b;
1818 struct lo_info *i = (struct lo_info *) cl;
1820 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1821 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1822 && LinePadIntersect (&i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1823 longjmp (i->env, 1);
1824 return 0;
1827 /* ---------------------------------------------------------------------------
1828 * searches all LOs that are connected to the given line on the given
1829 * layergroup. All found connections are added to the list
1831 * the notation that is used is:
1832 * Xij means Xj at line i
1834 static bool
1835 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup,
1836 bool PolysTo)
1838 Cardinal entry;
1839 struct lo_info info;
1841 info.line = *Line;
1842 info.layer = LayerGroup;
1843 EXPAND_BOUNDS (&info.line)
1844 /* add the new rat lines */
1845 if (setjmp (info.env) == 0)
1846 r_search (PCB->Data->rat_tree, &info.line.BoundingBox, NULL,
1847 LOCtoLineRat_callback, &info);
1848 else
1849 return true;
1851 /* loop over all layers of the group */
1852 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1854 Cardinal layer_no;
1855 LayerType *layer;
1857 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1858 layer = LAYER_PTR (layer_no);
1860 /* handle normal layers */
1861 if (layer_no < max_copper_layer)
1863 info.layer = layer_no;
1864 /* add lines */
1865 if (setjmp (info.env) == 0)
1866 r_search (layer->line_tree, (BoxType *) & info.line,
1867 NULL, LOCtoLineLine_callback, &info);
1868 else
1869 return true;
1870 /* add arcs */
1871 if (setjmp (info.env) == 0)
1872 r_search (layer->arc_tree, (BoxType *) & info.line,
1873 NULL, LOCtoLineArc_callback, &info);
1874 else
1875 return true;
1876 /* now check all polygons */
1877 if (PolysTo)
1879 GList *i;
1880 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1882 PolygonType *polygon = i->data;
1883 if (!TEST_FLAG
1884 (TheFlag, polygon) && IsLineInPolygon (Line, polygon)
1885 && ADD_POLYGON_TO_LIST (layer_no, polygon))
1886 return true;
1890 else
1892 /* handle special 'pad' layers */
1893 info.layer = layer_no - max_copper_layer;
1894 if (setjmp (info.env) == 0)
1895 r_search (PCB->Data->pad_tree, &info.line.BoundingBox, NULL,
1896 LOCtoLinePad_callback, &info);
1897 else
1898 return true;
1901 return (false);
1904 struct rat_info
1906 Cardinal layer;
1907 PointType *Point;
1908 jmp_buf env;
1911 static int
1912 LOCtoRat_callback (const BoxType * b, void *cl)
1914 LineType *line = (LineType *) b;
1915 struct rat_info *i = (struct rat_info *) cl;
1917 if (!TEST_FLAG (TheFlag, line) &&
1918 ((line->Point1.X == i->Point->X &&
1919 line->Point1.Y == i->Point->Y) ||
1920 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y)))
1922 if (ADD_LINE_TO_LIST (i->layer, line))
1923 longjmp (i->env, 1);
1925 return 0;
1927 static int
1928 PolygonToRat_callback (const BoxType * b, void *cl)
1930 PolygonType *polygon = (PolygonType *) b;
1931 struct rat_info *i = (struct rat_info *) cl;
1933 if (!TEST_FLAG (TheFlag, polygon) && polygon->Clipped &&
1934 (i->Point->X == polygon->Clipped->contours->head.point[0]) &&
1935 (i->Point->Y == polygon->Clipped->contours->head.point[1]))
1937 if (ADD_POLYGON_TO_LIST (i->layer, polygon))
1938 longjmp (i->env, 1);
1940 return 0;
1943 static int
1944 LOCtoPad_callback (const BoxType * b, void *cl)
1946 PadType *pad = (PadType *) b;
1947 struct rat_info *i = (struct rat_info *) cl;
1949 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1950 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER) &&
1951 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) ||
1952 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) ||
1953 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X &&
1954 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) &&
1955 ADD_PAD_TO_LIST (i->layer, pad))
1956 longjmp (i->env, 1);
1957 return 0;
1960 /* ---------------------------------------------------------------------------
1961 * searches all LOs that are connected to the given rat-line on the given
1962 * layergroup. All found connections are added to the list
1964 * the notation that is used is:
1965 * Xij means Xj at line i
1967 static bool
1968 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup)
1970 Cardinal entry;
1971 struct rat_info info;
1973 info.Point = Point;
1974 /* loop over all layers of this group */
1975 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1977 Cardinal layer_no;
1978 LayerType *layer;
1980 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1981 layer = LAYER_PTR (layer_no);
1982 /* handle normal layers
1983 rats don't ever touch
1984 arcs by definition
1987 if (layer_no < max_copper_layer)
1989 info.layer = layer_no;
1990 if (setjmp (info.env) == 0)
1991 r_search_pt (layer->line_tree, Point, 1, NULL,
1992 LOCtoRat_callback, &info);
1993 else
1994 return true;
1995 if (setjmp (info.env) == 0)
1996 r_search_pt (layer->polygon_tree, Point, 1,
1997 NULL, PolygonToRat_callback, &info);
1999 else
2001 /* handle special 'pad' layers */
2002 info.layer = layer_no - max_copper_layer;
2003 if (setjmp (info.env) == 0)
2004 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL,
2005 LOCtoPad_callback, &info);
2006 else
2007 return true;
2010 return (false);
2013 static int
2014 LOCtoPadLine_callback (const BoxType * b, void *cl)
2016 LineType *line = (LineType *) b;
2017 struct lo_info *i = (struct lo_info *) cl;
2019 if (!TEST_FLAG (TheFlag, line) && LinePadIntersect (line, &i->pad))
2021 if (ADD_LINE_TO_LIST (i->layer, line))
2022 longjmp (i->env, 1);
2024 return 0;
2027 static int
2028 LOCtoPadArc_callback (const BoxType * b, void *cl)
2030 ArcType *arc = (ArcType *) b;
2031 struct lo_info *i = (struct lo_info *) cl;
2033 if (!arc->Thickness)
2034 return 0;
2035 if (!TEST_FLAG (TheFlag, arc) && ArcPadIntersect (arc, &i->pad))
2037 if (ADD_ARC_TO_LIST (i->layer, arc))
2038 longjmp (i->env, 1);
2040 return 0;
2043 static int
2044 LOCtoPadPoly_callback (const BoxType * b, void *cl)
2046 PolygonType *polygon = (PolygonType *) b;
2047 struct lo_info *i = (struct lo_info *) cl;
2050 if (!TEST_FLAG (TheFlag, polygon) &&
2051 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad.Clearance))
2053 if (IsPadInPolygon (&i->pad, polygon) &&
2054 ADD_POLYGON_TO_LIST (i->layer, polygon))
2055 longjmp (i->env, 1);
2057 return 0;
2060 static int
2061 LOCtoPadRat_callback (const BoxType * b, void *cl)
2063 RatType *rat = (RatType *) b;
2064 struct lo_info *i = (struct lo_info *) cl;
2066 if (!TEST_FLAG (TheFlag, rat))
2068 if (rat->group1 == i->layer &&
2069 ((rat->Point1.X == i->pad.Point1.X && rat->Point1.Y == i->pad.Point1.Y) ||
2070 (rat->Point1.X == i->pad.Point2.X && rat->Point1.Y == i->pad.Point2.Y) ||
2071 (rat->Point1.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2072 rat->Point1.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2074 if (ADD_RAT_TO_LIST (rat))
2075 longjmp (i->env, 1);
2077 else if (rat->group2 == i->layer &&
2078 ((rat->Point2.X == i->pad.Point1.X && rat->Point2.Y == i->pad.Point1.Y) ||
2079 (rat->Point2.X == i->pad.Point2.X && rat->Point2.Y == i->pad.Point2.Y) ||
2080 (rat->Point2.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2081 rat->Point2.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2083 if (ADD_RAT_TO_LIST (rat))
2084 longjmp (i->env, 1);
2087 return 0;
2090 static int
2091 LOCtoPadPad_callback (const BoxType * b, void *cl)
2093 PadType *pad = (PadType *) b;
2094 struct lo_info *i = (struct lo_info *) cl;
2096 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2097 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2098 && PadPadIntersect (pad, &i->pad) && ADD_PAD_TO_LIST (i->layer, pad))
2099 longjmp (i->env, 1);
2100 return 0;
2103 /* ---------------------------------------------------------------------------
2104 * searches all LOs that are connected to the given pad on the given
2105 * layergroup. All found connections are added to the list
2107 static bool
2108 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup)
2110 Cardinal entry;
2111 struct lo_info info;
2113 if (!TEST_FLAG (SQUAREFLAG, Pad))
2114 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, false));
2116 info.pad = *Pad;
2117 EXPAND_BOUNDS (&info.pad);
2118 /* add the new rat lines */
2119 info.layer = LayerGroup;
2120 if (setjmp (info.env) == 0)
2121 r_search (PCB->Data->rat_tree, &info.pad.BoundingBox, NULL,
2122 LOCtoPadRat_callback, &info);
2123 else
2124 return true;
2126 /* loop over all layers of the group */
2127 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2129 Cardinal layer_no;
2130 LayerType *layer;
2132 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2133 layer = LAYER_PTR (layer_no);
2134 /* handle normal layers */
2135 if (layer_no < max_copper_layer)
2137 info.layer = layer_no;
2138 /* add lines */
2139 if (setjmp (info.env) == 0)
2140 r_search (layer->line_tree, &info.pad.BoundingBox,
2141 NULL, LOCtoPadLine_callback, &info);
2142 else
2143 return true;
2144 /* add arcs */
2145 if (setjmp (info.env) == 0)
2146 r_search (layer->arc_tree, &info.pad.BoundingBox,
2147 NULL, LOCtoPadArc_callback, &info);
2148 else
2149 return true;
2150 /* add polygons */
2151 if (setjmp (info.env) == 0)
2152 r_search (layer->polygon_tree, &info.pad.BoundingBox,
2153 NULL, LOCtoPadPoly_callback, &info);
2154 else
2155 return true;
2157 else
2159 /* handle special 'pad' layers */
2160 info.layer = layer_no - max_copper_layer;
2161 if (setjmp (info.env) == 0)
2162 r_search (PCB->Data->pad_tree, (BoxType *) & info.pad, NULL,
2163 LOCtoPadPad_callback, &info);
2164 else
2165 return true;
2169 return (false);
2172 static int
2173 LOCtoPolyLine_callback (const BoxType * b, void *cl)
2175 LineType *line = (LineType *) b;
2176 struct lo_info *i = (struct lo_info *) cl;
2178 if (!TEST_FLAG (TheFlag, line) && IsLineInPolygon (line, &i->polygon))
2180 if (ADD_LINE_TO_LIST (i->layer, line))
2181 longjmp (i->env, 1);
2183 return 0;
2186 static int
2187 LOCtoPolyArc_callback (const BoxType * b, void *cl)
2189 ArcType *arc = (ArcType *) b;
2190 struct lo_info *i = (struct lo_info *) cl;
2192 if (!arc->Thickness)
2193 return 0;
2194 if (!TEST_FLAG (TheFlag, arc) && IsArcInPolygon (arc, &i->polygon))
2196 if (ADD_ARC_TO_LIST (i->layer, arc))
2197 longjmp (i->env, 1);
2199 return 0;
2202 static int
2203 LOCtoPolyPad_callback (const BoxType * b, void *cl)
2205 PadType *pad = (PadType *) b;
2206 struct lo_info *i = (struct lo_info *) cl;
2208 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2209 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2210 && IsPadInPolygon (pad, &i->polygon))
2212 if (ADD_PAD_TO_LIST (i->layer, pad))
2213 longjmp (i->env, 1);
2215 return 0;
2218 static int
2219 LOCtoPolyRat_callback (const BoxType * b, void *cl)
2221 RatType *rat = (RatType *) b;
2222 struct lo_info *i = (struct lo_info *) cl;
2224 if (!TEST_FLAG (TheFlag, rat))
2226 if ((rat->Point1.X == (i->polygon.Clipped->contours->head.point[0]) &&
2227 rat->Point1.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2228 rat->group1 == i->layer) ||
2229 (rat->Point2.X == (i->polygon.Clipped->contours->head.point[0]) &&
2230 rat->Point2.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2231 rat->group2 == i->layer))
2232 if (ADD_RAT_TO_LIST (rat))
2233 longjmp (i->env, 1);
2235 return 0;
2239 /* ---------------------------------------------------------------------------
2240 * looks up LOs that are connected to the given polygon
2241 * on the given layergroup. All found connections are added to the list
2243 static bool
2244 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup)
2246 Cardinal entry;
2247 struct lo_info info;
2249 if (!Polygon->Clipped)
2250 return false;
2251 info.polygon = *Polygon;
2252 EXPAND_BOUNDS (&info.polygon);
2253 info.layer = LayerGroup;
2254 /* check rats */
2255 if (setjmp (info.env) == 0)
2256 r_search (PCB->Data->rat_tree, (BoxType *) & info.polygon, NULL,
2257 LOCtoPolyRat_callback, &info);
2258 else
2259 return true;
2260 /* loop over all layers of the group */
2261 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2263 Cardinal layer_no;
2264 LayerType *layer;
2266 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2267 layer = LAYER_PTR (layer_no);
2269 /* handle normal layers */
2270 if (layer_no < max_copper_layer)
2272 GList *i;
2274 /* check all polygons */
2275 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
2277 PolygonType *polygon = i->data;
2278 if (!TEST_FLAG (TheFlag, polygon)
2279 && IsPolygonInPolygon (polygon, Polygon)
2280 && ADD_POLYGON_TO_LIST (layer_no, polygon))
2281 return true;
2284 info.layer = layer_no;
2285 /* check all lines */
2286 if (setjmp (info.env) == 0)
2287 r_search (layer->line_tree,
2288 (BoxType *) & info.polygon, NULL,
2289 LOCtoPolyLine_callback, &info);
2290 else
2291 return true;
2292 /* check all arcs */
2293 if (setjmp (info.env) == 0)
2294 r_search (layer->arc_tree, (BoxType *) & info.polygon,
2295 NULL, LOCtoPolyArc_callback, &info);
2296 else
2297 return true;
2299 else
2301 info.layer = layer_no - max_copper_layer;
2302 if (setjmp (info.env) == 0)
2303 r_search (PCB->Data->pad_tree, (BoxType *) & info.polygon,
2304 NULL, LOCtoPolyPad_callback, &info);
2305 else
2306 return true;
2309 return (false);
2312 /* ---------------------------------------------------------------------------
2313 * checks if an arc has a connection to a polygon
2315 * - first check if the arc can intersect with the polygon by
2316 * evaluating the bounding boxes
2317 * - check the two end points of the arc. If none of them matches
2318 * - check all segments of the polygon against the arc.
2320 static bool
2321 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon)
2323 BoxType *Box = (BoxType *) Arc;
2325 /* arcs with clearance never touch polys */
2326 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc))
2327 return false;
2328 if (!Polygon->Clipped)
2329 return false;
2330 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2331 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2332 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2333 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2335 POLYAREA *ap;
2337 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat)))
2338 return false; /* error */
2339 return isects (ap, Polygon, true);
2341 return false;
2344 /* ---------------------------------------------------------------------------
2345 * checks if a line has a connection to a polygon
2347 * - first check if the line can intersect with the polygon by
2348 * evaluating the bounding boxes
2349 * - check the two end points of the line. If none of them matches
2350 * - check all segments of the polygon against the line.
2352 static bool
2353 IsLineInPolygon (LineType *Line, PolygonType *Polygon)
2355 BoxType *Box = (BoxType *) Line;
2356 POLYAREA *lp;
2358 /* lines with clearance never touch polygons */
2359 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line))
2360 return false;
2361 if (!Polygon->Clipped)
2362 return false;
2363 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y))
2365 Coord wid = (Line->Thickness + Bloat + 1) / 2;
2366 Coord x1, x2, y1, y2;
2368 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid;
2369 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid;
2370 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid;
2371 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid;
2372 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon);
2374 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2375 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2376 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2377 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2379 if (!(lp = LinePoly (Line, Line->Thickness + Bloat)))
2380 return FALSE; /* error */
2381 return isects (lp, Polygon, true);
2383 return false;
2386 /* ---------------------------------------------------------------------------
2387 * checks if a pad connects to a non-clearing polygon
2389 * The polygon is assumed to already have been proven non-clearing
2391 static bool
2392 IsPadInPolygon (PadType *pad, PolygonType *polygon)
2394 return IsLineInPolygon ((LineType *) pad, polygon);
2397 /* ---------------------------------------------------------------------------
2398 * checks if a polygon has a connection to a second one
2400 * First check all points out of P1 against P2 and vice versa.
2401 * If both fail check all lines of P1 against the ones of P2
2403 static bool
2404 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2)
2406 if (!P1->Clipped || !P2->Clipped)
2407 return false;
2408 assert (P1->Clipped->contours);
2409 assert (P2->Clipped->contours);
2411 /* first check if both bounding boxes intersect. If not, return quickly */
2412 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax ||
2413 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin ||
2414 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax ||
2415 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin)
2416 return false;
2418 /* first check un-bloated case */
2419 if (isects (P1->Clipped, P2, false))
2420 return TRUE;
2422 /* now the difficult case of bloated */
2423 if (Bloat > 0)
2425 PLINE *c;
2426 for (c = P1->Clipped->contours; c; c = c->next)
2428 LineType line;
2429 VNODE *v = &c->head;
2430 if (c->xmin - Bloat <= P2->Clipped->contours->xmax &&
2431 c->xmax + Bloat >= P2->Clipped->contours->xmin &&
2432 c->ymin - Bloat <= P2->Clipped->contours->ymax &&
2433 c->ymax + Bloat >= P2->Clipped->contours->ymin)
2436 line.Point1.X = v->point[0];
2437 line.Point1.Y = v->point[1];
2438 line.Thickness = 2 * Bloat;
2439 line.Clearance = 0;
2440 line.Flags = NoFlags ();
2441 for (v = v->next; v != &c->head; v = v->next)
2443 line.Point2.X = v->point[0];
2444 line.Point2.Y = v->point[1];
2445 SetLineBoundingBox (&line);
2446 if (IsLineInPolygon (&line, P2))
2447 return (true);
2448 line.Point1.X = line.Point2.X;
2449 line.Point1.Y = line.Point2.Y;
2455 return (false);
2458 /* ---------------------------------------------------------------------------
2459 * writes the several names of an element to a file
2461 static void
2462 PrintElementNameList (ElementType *Element, FILE * FP)
2464 static DynamicStringType cname, pname, vname;
2466 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element)));
2467 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element)));
2468 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element)));
2469 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data);
2472 /* ---------------------------------------------------------------------------
2473 * writes the several names of an element to a file
2475 static void
2476 PrintConnectionElementName (ElementType *Element, FILE * FP)
2478 fputs ("Element", FP);
2479 PrintElementNameList (Element, FP);
2480 fputs ("{\n", FP);
2483 /* ---------------------------------------------------------------------------
2484 * prints one {pin,pad,via}/element entry of connection lists
2486 static void
2487 PrintConnectionListEntry (char *ObjName, ElementType *Element,
2488 bool FirstOne, FILE * FP)
2490 static DynamicStringType oname;
2492 CreateQuotedString (&oname, ObjName);
2493 if (FirstOne)
2494 fprintf (FP, "\t%s\n\t{\n", oname.Data);
2495 else
2497 fprintf (FP, "\t\t%s ", oname.Data);
2498 if (Element)
2499 PrintElementNameList (Element, FP);
2500 else
2501 fputs ("(__VIA__)\n", FP);
2505 /* ---------------------------------------------------------------------------
2506 * prints all found connections of a pads to file FP
2507 * the connections are stacked in 'PadList'
2509 static void
2510 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst)
2512 Cardinal i;
2513 PadType *ptr;
2515 if (!PadList[Layer].Number)
2516 return;
2518 /* the starting pad */
2519 if (IsFirst)
2521 ptr = PADLIST_ENTRY (Layer, 0);
2522 if (ptr != NULL)
2523 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP);
2524 else
2525 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2528 /* we maybe have to start with i=1 if we are handling the
2529 * starting-pad itself
2531 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++)
2533 ptr = PADLIST_ENTRY (Layer, i);
2534 if (ptr != NULL)
2535 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP);
2536 else
2537 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2541 /* ---------------------------------------------------------------------------
2542 * prints all found connections of a pin to file FP
2543 * the connections are stacked in 'PVList'
2545 static void
2546 PrintPinConnections (FILE * FP, bool IsFirst)
2548 Cardinal i;
2549 PinType *pv;
2551 if (!PVList.Number)
2552 return;
2554 if (IsFirst)
2556 /* the starting pin */
2557 pv = PVLIST_ENTRY (0);
2558 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP);
2561 /* we maybe have to start with i=1 if we are handling the
2562 * starting-pin itself
2564 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++)
2566 /* get the elements name or assume that its a via */
2567 pv = PVLIST_ENTRY (i);
2568 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP);
2572 /* ---------------------------------------------------------------------------
2573 * checks if all lists of new objects are handled
2575 static bool
2576 ListsEmpty (bool AndRats)
2578 bool empty;
2579 int i;
2581 empty = (PVList.Location >= PVList.Number);
2582 if (AndRats)
2583 empty = empty && (RatList.Location >= RatList.Number);
2584 for (i = 0; i < max_copper_layer && empty; i++)
2585 if (!LAYER_PTR (i)->no_drc)
2586 empty = empty && LineList[i].Location >= LineList[i].Number
2587 && ArcList[i].Location >= ArcList[i].Number
2588 && PolygonList[i].Location >= PolygonList[i].Number;
2589 return (empty);
2592 static void
2593 reassign_no_drc_flags (void)
2595 int layer;
2597 for (layer = 0; layer < max_copper_layer; layer++)
2599 LayerType *l = LAYER_PTR (layer);
2600 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL;
2607 /* ---------------------------------------------------------------------------
2608 * loops till no more connections are found
2610 static bool
2611 DoIt (bool AndRats, bool AndDraw)
2613 bool newone = false;
2614 reassign_no_drc_flags ();
2617 /* lookup connections; these are the steps (2) to (4)
2618 * from the description
2620 newone = LookupPVConnectionsToPVList () ||
2621 LookupLOConnectionsToPVList (AndRats) ||
2622 LookupLOConnectionsToLOList (AndRats) ||
2623 LookupPVConnectionsToLOList (AndRats);
2624 if (AndDraw)
2625 DrawNewConnections ();
2627 while (!newone && !ListsEmpty (AndRats));
2628 if (AndDraw)
2629 Draw ();
2630 return (newone);
2633 /* ---------------------------------------------------------------------------
2634 * prints all unused pins of an element to file FP
2636 static bool
2637 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP)
2639 bool first = true;
2640 Cardinal number;
2641 static DynamicStringType oname;
2643 /* check all pins in element */
2645 PIN_LOOP (Element);
2647 if (!TEST_FLAG (HOLEFLAG, pin))
2649 /* pin might have bee checked before, add to list if not */
2650 if (!TEST_FLAG (TheFlag, pin) && FP)
2652 int i;
2653 if (ADD_PV_TO_LIST (pin))
2654 return true;
2655 DoIt (true, true);
2656 number = PadList[COMPONENT_LAYER].Number
2657 + PadList[SOLDER_LAYER].Number + PVList.Number;
2658 /* the pin has no connection if it's the only
2659 * list entry; don't count vias
2661 for (i = 0; i < PVList.Number; i++)
2662 if (!PVLIST_ENTRY (i)->Element)
2663 number--;
2664 if (number == 1)
2666 /* output of element name if not already done */
2667 if (first)
2669 PrintConnectionElementName (Element, FP);
2670 first = false;
2673 /* write name to list and draw selected object */
2674 CreateQuotedString (&oname, (char *)EMPTY (pin->Name));
2675 fprintf (FP, "\t%s\n", oname.Data);
2676 SET_FLAG (SELECTEDFLAG, pin);
2677 DrawPin (pin);
2680 /* reset found objects for the next pin */
2681 if (PrepareNextLoop (FP))
2682 return (true);
2686 END_LOOP;
2688 /* check all pads in element */
2689 PAD_LOOP (Element);
2691 /* lookup pad in list */
2692 /* pad might has bee checked before, add to list if not */
2693 if (!TEST_FLAG (TheFlag, pad) && FP)
2695 int i;
2696 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad)
2697 ? SOLDER_LAYER : COMPONENT_LAYER, pad))
2698 return true;
2699 DoIt (true, true);
2700 number = PadList[COMPONENT_LAYER].Number
2701 + PadList[SOLDER_LAYER].Number + PVList.Number;
2702 /* the pin has no connection if it's the only
2703 * list entry; don't count vias
2705 for (i = 0; i < PVList.Number; i++)
2706 if (!PVLIST_ENTRY (i)->Element)
2707 number--;
2708 if (number == 1)
2710 /* output of element name if not already done */
2711 if (first)
2713 PrintConnectionElementName (Element, FP);
2714 first = false;
2717 /* write name to list and draw selected object */
2718 CreateQuotedString (&oname, (char *)EMPTY (pad->Name));
2719 fprintf (FP, "\t%s\n", oname.Data);
2720 SET_FLAG (SELECTEDFLAG, pad);
2721 DrawPad (pad);
2724 /* reset found objects for the next pin */
2725 if (PrepareNextLoop (FP))
2726 return (true);
2729 END_LOOP;
2731 /* print separator if element has unused pins or pads */
2732 if (!first)
2734 fputs ("}\n\n", FP);
2735 SEPARATE (FP);
2737 return (false);
2740 /* ---------------------------------------------------------------------------
2741 * resets some flags for looking up the next pin/pad
2743 static bool
2744 PrepareNextLoop (FILE * FP)
2746 Cardinal layer;
2748 /* reset found LOs for the next pin */
2749 for (layer = 0; layer < max_copper_layer; layer++)
2751 LineList[layer].Location = LineList[layer].Number = 0;
2752 ArcList[layer].Location = ArcList[layer].Number = 0;
2753 PolygonList[layer].Location = PolygonList[layer].Number = 0;
2756 /* reset found pads */
2757 for (layer = 0; layer < 2; layer++)
2758 PadList[layer].Location = PadList[layer].Number = 0;
2760 /* reset PVs */
2761 PVList.Number = PVList.Location = 0;
2762 RatList.Number = RatList.Location = 0;
2764 return (false);
2767 /* ---------------------------------------------------------------------------
2768 * finds all connections to the pins of the passed element.
2769 * The result is written to file FP
2770 * Returns true if operation was aborted
2772 static bool
2773 PrintElementConnections (ElementType *Element, FILE * FP, bool AndDraw)
2775 PrintConnectionElementName (Element, FP);
2777 /* check all pins in element */
2778 PIN_LOOP (Element);
2780 /* pin might have been checked before, add to list if not */
2781 if (TEST_FLAG (TheFlag, pin))
2783 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP);
2784 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2785 continue;
2787 if (ADD_PV_TO_LIST (pin))
2788 return true;
2789 DoIt (true, AndDraw);
2790 /* printout all found connections */
2791 PrintPinConnections (FP, true);
2792 PrintPadConnections (COMPONENT_LAYER, FP, false);
2793 PrintPadConnections (SOLDER_LAYER, FP, false);
2794 fputs ("\t}\n", FP);
2795 if (PrepareNextLoop (FP))
2796 return (true);
2798 END_LOOP;
2800 /* check all pads in element */
2801 PAD_LOOP (Element);
2803 Cardinal layer;
2804 /* pad might have been checked before, add to list if not */
2805 if (TEST_FLAG (TheFlag, pad))
2807 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP);
2808 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2809 continue;
2811 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER;
2812 if (ADD_PAD_TO_LIST (layer, pad))
2813 return true;
2814 DoIt (true, AndDraw);
2815 /* print all found connections */
2816 PrintPadConnections (layer, FP, true);
2817 PrintPadConnections (layer ==
2818 (COMPONENT_LAYER ? SOLDER_LAYER : COMPONENT_LAYER),
2819 FP, false);
2820 PrintPinConnections (FP, false);
2821 fputs ("\t}\n", FP);
2822 if (PrepareNextLoop (FP))
2823 return (true);
2825 END_LOOP;
2826 fputs ("}\n\n", FP);
2827 return (false);
2830 /* ---------------------------------------------------------------------------
2831 * draws all new connections which have been found since the
2832 * routine was called the last time
2834 static void
2835 DrawNewConnections (void)
2837 int i;
2838 Cardinal position;
2840 /* decrement 'i' to keep layerstack order */
2841 for (i = max_copper_layer - 1; i != -1; i--)
2843 Cardinal layer = LayerStack[i];
2845 if (PCB->Data->Layer[layer].On)
2847 /* draw all new lines */
2848 position = LineList[layer].DrawLocation;
2849 for (; position < LineList[layer].Number; position++)
2850 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position));
2851 LineList[layer].DrawLocation = LineList[layer].Number;
2853 /* draw all new arcs */
2854 position = ArcList[layer].DrawLocation;
2855 for (; position < ArcList[layer].Number; position++)
2856 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position));
2857 ArcList[layer].DrawLocation = ArcList[layer].Number;
2859 /* draw all new polygons */
2860 position = PolygonList[layer].DrawLocation;
2861 for (; position < PolygonList[layer].Number; position++)
2862 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position));
2863 PolygonList[layer].DrawLocation = PolygonList[layer].Number;
2867 /* draw all new pads */
2868 if (PCB->PinOn)
2869 for (i = 0; i < 2; i++)
2871 position = PadList[i].DrawLocation;
2873 for (; position < PadList[i].Number; position++)
2874 DrawPad (PADLIST_ENTRY (i, position));
2875 PadList[i].DrawLocation = PadList[i].Number;
2878 /* draw all new PVs; 'PVList' holds a list of pointers to the
2879 * sorted array pointers to PV data
2881 while (PVList.DrawLocation < PVList.Number)
2883 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation);
2885 if (TEST_FLAG (PINFLAG, pv))
2887 if (PCB->PinOn)
2888 DrawPin (pv);
2890 else if (PCB->ViaOn)
2891 DrawVia (pv);
2892 PVList.DrawLocation++;
2894 /* draw the new rat-lines */
2895 if (PCB->RatOn)
2897 position = RatList.DrawLocation;
2898 for (; position < RatList.Number; position++)
2899 DrawRat (RATLIST_ENTRY (position));
2900 RatList.DrawLocation = RatList.Number;
2904 /* ---------------------------------------------------------------------------
2905 * find all connections to pins within one element
2907 void
2908 LookupElementConnections (ElementType *Element, FILE * FP)
2910 /* reset all currently marked connections */
2911 User = true;
2912 TheFlag = FOUNDFLAG;
2913 ClearFlagOnAllObjects (true, FOUNDFLAG);
2914 InitConnectionLookup ();
2915 PrintElementConnections (Element, FP, true);
2916 SetChangedFlag (true);
2917 if (Settings.RingBellWhenFinished)
2918 gui->beep ();
2919 FreeConnectionLookupMemory ();
2920 IncrementUndoSerialNumber ();
2921 User = false;
2922 Draw ();
2925 /* ---------------------------------------------------------------------------
2926 * find all connections to pins of all element
2928 void
2929 LookupConnectionsToAllElements (FILE * FP)
2931 /* reset all currently marked connections */
2932 User = false;
2933 TheFlag = FOUNDFLAG;
2934 ClearFlagOnAllObjects (false, FOUNDFLAG);
2935 InitConnectionLookup ();
2937 ELEMENT_LOOP (PCB->Data);
2939 /* break if abort dialog returned true */
2940 if (PrintElementConnections (element, FP, false))
2941 break;
2942 SEPARATE (FP);
2943 if (Settings.ResetAfterElement && n != 1)
2944 ClearFlagOnAllObjects (false, FOUNDFLAG);
2946 END_LOOP;
2947 if (Settings.RingBellWhenFinished)
2948 gui->beep ();
2949 ClearFlagOnAllObjects (false, FOUNDFLAG);
2950 FreeConnectionLookupMemory ();
2951 Redraw ();
2954 /*---------------------------------------------------------------------------
2955 * add the starting object to the list of found objects
2957 static bool
2958 ListStart (int type, void *ptr1, void *ptr2, void *ptr3)
2960 DumpList ();
2961 switch (type)
2963 case PIN_TYPE:
2964 case VIA_TYPE:
2966 if (ADD_PV_TO_LIST ((PinType *) ptr2))
2967 return true;
2968 break;
2971 case RATLINE_TYPE:
2973 if (ADD_RAT_TO_LIST ((RatType *) ptr1))
2974 return true;
2975 break;
2978 case LINE_TYPE:
2980 int layer = GetLayerNumber (PCB->Data,
2981 (LayerType *) ptr1);
2983 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2))
2984 return true;
2985 break;
2988 case ARC_TYPE:
2990 int layer = GetLayerNumber (PCB->Data,
2991 (LayerType *) ptr1);
2993 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2))
2994 return true;
2995 break;
2998 case POLYGON_TYPE:
3000 int layer = GetLayerNumber (PCB->Data,
3001 (LayerType *) ptr1);
3003 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2))
3004 return true;
3005 break;
3008 case PAD_TYPE:
3010 PadType *pad = (PadType *) ptr2;
3011 if (ADD_PAD_TO_LIST
3012 (TEST_FLAG
3013 (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER, pad))
3014 return true;
3015 break;
3018 return (false);
3022 /* ---------------------------------------------------------------------------
3023 * looks up all connections from the object at the given coordinates
3024 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3025 * the objects are re-drawn if AndDraw is true
3026 * also the action is marked as undoable if AndDraw is true
3028 void
3029 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int which_flag,
3030 bool AndRats)
3032 void *ptr1, *ptr2, *ptr3;
3033 char *name;
3034 int type;
3036 /* check if there are any pins or pads at that position */
3038 reassign_no_drc_flags ();
3040 type
3041 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range);
3042 if (type == NO_TYPE)
3044 type = SearchObjectByLocation (
3045 LOOKUP_MORE & ~(AndRats ? RATLINE_TYPE : 0),
3046 &ptr1, &ptr2, &ptr3, X, Y, Range);
3047 if (type == NO_TYPE)
3048 return;
3049 if (type & SILK_TYPE)
3051 int laynum = GetLayerNumber (PCB->Data,
3052 (LayerType *) ptr1);
3054 /* don't mess with non-conducting objects! */
3055 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc)
3056 return;
3060 name = ConnectionName (type, ptr1, ptr2);
3061 hid_actionl ("NetlistShow", name, NULL);
3063 TheFlag = which_flag;
3064 User = AndDraw;
3065 InitConnectionLookup ();
3067 /* now add the object to the appropriate list and start scanning
3068 * This is step (1) from the description
3070 ListStart (type, ptr1, ptr2, ptr3);
3071 DoIt (AndRats, AndDraw);
3072 if (User)
3073 IncrementUndoSerialNumber ();
3074 User = false;
3076 /* we are done */
3077 if (AndDraw)
3078 Draw ();
3079 if (AndDraw && Settings.RingBellWhenFinished)
3080 gui->beep ();
3081 FreeConnectionLookupMemory ();
3084 /* ---------------------------------------------------------------------------
3085 * find connections for rats nesting
3086 * assumes InitConnectionLookup() has already been done
3088 void
3089 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3,
3090 bool undo, int flag, bool AndRats)
3092 User = undo;
3093 TheFlag = flag;
3094 DumpList ();
3095 ListStart (type, ptr1, ptr2, ptr3);
3096 DoIt (AndRats, false);
3097 User = false;
3100 /* ---------------------------------------------------------------------------
3101 * find all unused pins of all element
3103 void
3104 LookupUnusedPins (FILE * FP)
3106 /* reset all currently marked connections */
3107 User = true;
3108 TheFlag = FOUNDFLAG;
3109 ClearFlagOnAllObjects (true, FOUNDFLAG);
3110 InitConnectionLookup ();
3112 ELEMENT_LOOP (PCB->Data);
3114 /* break if abort dialog returned true;
3115 * passing NULL as filedescriptor discards the normal output
3117 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP))
3118 break;
3120 END_LOOP;
3122 if (Settings.RingBellWhenFinished)
3123 gui->beep ();
3124 FreeConnectionLookupMemory ();
3125 IncrementUndoSerialNumber ();
3126 User = false;
3127 Draw ();
3130 /* ---------------------------------------------------------------------------
3131 * resets all used flags of pins and vias
3133 bool
3134 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag)
3136 bool change = false;
3138 VIA_LOOP (PCB->Data);
3140 if (TEST_FLAG (flag, via))
3142 if (AndDraw)
3143 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3144 CLEAR_FLAG (flag, via);
3145 if (AndDraw)
3146 DrawVia (via);
3147 change = true;
3150 END_LOOP;
3151 ELEMENT_LOOP (PCB->Data);
3153 PIN_LOOP (element);
3155 if (TEST_FLAG (flag, pin))
3157 if (AndDraw)
3158 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3159 CLEAR_FLAG (flag, pin);
3160 if (AndDraw)
3161 DrawPin (pin);
3162 change = true;
3165 END_LOOP;
3166 PAD_LOOP (element);
3168 if (TEST_FLAG (flag, pad))
3170 if (AndDraw)
3171 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3172 CLEAR_FLAG (flag, pad);
3173 if (AndDraw)
3174 DrawPad (pad);
3175 change = true;
3178 END_LOOP;
3180 END_LOOP;
3181 if (change)
3182 SetChangedFlag (true);
3183 return change;
3186 /* ---------------------------------------------------------------------------
3187 * resets all used flags of LOs
3189 bool
3190 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag)
3192 bool change = false;
3194 RAT_LOOP (PCB->Data);
3196 if (TEST_FLAG (flag, line))
3198 if (AndDraw)
3199 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
3200 CLEAR_FLAG (flag, line);
3201 if (AndDraw)
3202 DrawRat (line);
3203 change = true;
3206 END_LOOP;
3207 COPPERLINE_LOOP (PCB->Data);
3209 if (TEST_FLAG (flag, line))
3211 if (AndDraw)
3212 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3213 CLEAR_FLAG (flag, line);
3214 if (AndDraw)
3215 DrawLine (layer, line);
3216 change = true;
3219 ENDALL_LOOP;
3220 COPPERARC_LOOP (PCB->Data);
3222 if (TEST_FLAG (flag, arc))
3224 if (AndDraw)
3225 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3226 CLEAR_FLAG (flag, arc);
3227 if (AndDraw)
3228 DrawArc (layer, arc);
3229 change = true;
3232 ENDALL_LOOP;
3233 COPPERPOLYGON_LOOP (PCB->Data);
3235 if (TEST_FLAG (flag, polygon))
3237 if (AndDraw)
3238 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3239 CLEAR_FLAG (flag, polygon);
3240 if (AndDraw)
3241 DrawPolygon (layer, polygon);
3242 change = true;
3245 ENDALL_LOOP;
3246 if (change)
3247 SetChangedFlag (true);
3248 return change;
3251 /* ---------------------------------------------------------------------------
3252 * resets all found connections
3254 bool
3255 ClearFlagOnAllObjects (bool AndDraw, int flag)
3257 bool change = false;
3259 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change;
3260 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change;
3262 return change;
3265 /*----------------------------------------------------------------------------
3266 * Dumps the list contents
3268 static void
3269 DumpList (void)
3271 Cardinal i;
3273 for (i = 0; i < 2; i++)
3275 PadList[i].Number = 0;
3276 PadList[i].Location = 0;
3277 PadList[i].DrawLocation = 0;
3280 PVList.Number = 0;
3281 PVList.Location = 0;
3283 for (i = 0; i < max_copper_layer; i++)
3285 LineList[i].Location = 0;
3286 LineList[i].DrawLocation = 0;
3287 LineList[i].Number = 0;
3288 ArcList[i].Location = 0;
3289 ArcList[i].DrawLocation = 0;
3290 ArcList[i].Number = 0;
3291 PolygonList[i].Location = 0;
3292 PolygonList[i].DrawLocation = 0;
3293 PolygonList[i].Number = 0;
3295 RatList.Number = 0;
3296 RatList.Location = 0;
3297 RatList.DrawLocation = 0;
3300 /*-----------------------------------------------------------------------------
3301 * Check for DRC violations on a single net starting from the pad or pin
3302 * sees if the connectivity changes when everything is bloated, or shrunk
3304 static bool
3305 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
3307 Coord x, y;
3308 int object_count;
3309 long int *object_id_list;
3310 int *object_type_list;
3311 DrcViolationType *violation;
3313 if (PCB->Shrink != 0)
3315 Bloat = -PCB->Shrink;
3316 TheFlag = DRCFLAG | SELECTEDFLAG;
3317 ListStart (What, ptr1, ptr2, ptr3);
3318 DoIt (true, false);
3319 /* ok now the shrunk net has the SELECTEDFLAG set */
3320 DumpList ();
3321 TheFlag = FOUNDFLAG;
3322 ListStart (What, ptr1, ptr2, ptr3);
3323 Bloat = 0;
3324 drc = true; /* abort the search if we find anything not already found */
3325 if (DoIt (true, false))
3327 DumpList ();
3328 /* make the flag changes undoable */
3329 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3330 ClearFlagOnAllObjects (false, TheFlag);
3331 User = true;
3332 drc = false;
3333 Bloat = -PCB->Shrink;
3334 TheFlag = SELECTEDFLAG;
3335 ListStart (What, ptr1, ptr2, ptr3);
3336 DoIt (true, true);
3337 DumpList ();
3338 ListStart (What, ptr1, ptr2, ptr3);
3339 TheFlag = FOUNDFLAG;
3340 Bloat = 0;
3341 drc = true;
3342 DoIt (true, true);
3343 DumpList ();
3344 User = false;
3345 drc = false;
3346 drcerr_count++;
3347 LocateError (&x, &y);
3348 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3349 violation = pcb_drc_violation_new (_("Potential for broken trace"),
3350 _("Insufficient overlap between objects can lead to broken tracks\n"
3351 "due to registration errors with old wheel style photo-plotters."),
3352 x, y,
3353 0, /* ANGLE OF ERROR UNKNOWN */
3354 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3355 0, /* MAGNITUDE OF ERROR UNKNOWN */
3356 PCB->Shrink,
3357 object_count,
3358 object_id_list,
3359 object_type_list);
3360 append_drc_violation (violation);
3361 pcb_drc_violation_free (violation);
3362 free (object_id_list);
3363 free (object_type_list);
3365 if (!throw_drc_dialog())
3366 return (true);
3367 IncrementUndoSerialNumber ();
3368 Undo (true);
3370 DumpList ();
3372 /* now check the bloated condition */
3373 drc = false;
3374 ClearFlagOnAllObjects (false, TheFlag);
3375 TheFlag = FOUNDFLAG;
3376 ListStart (What, ptr1, ptr2, ptr3);
3377 Bloat = PCB->Bloat;
3378 drc = true;
3379 while (DoIt (true, false))
3381 DumpList ();
3382 /* make the flag changes undoable */
3383 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3384 ClearFlagOnAllObjects (false, TheFlag);
3385 User = true;
3386 drc = false;
3387 Bloat = 0;
3388 TheFlag = SELECTEDFLAG;
3389 ListStart (What, ptr1, ptr2, ptr3);
3390 DoIt (true, true);
3391 DumpList ();
3392 TheFlag = FOUNDFLAG;
3393 ListStart (What, ptr1, ptr2, ptr3);
3394 Bloat = PCB->Bloat;
3395 drc = true;
3396 DoIt (true, true);
3397 DumpList ();
3398 drcerr_count++;
3399 LocateError (&x, &y);
3400 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3401 violation = pcb_drc_violation_new (_("Copper areas too close"),
3402 _("Circuits that are too close may bridge during imaging, etching,\n"
3403 "plating, or soldering processes resulting in a direct short."),
3404 x, y,
3405 0, /* ANGLE OF ERROR UNKNOWN */
3406 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3407 0, /* MAGNITUDE OF ERROR UNKNOWN */
3408 PCB->Bloat,
3409 object_count,
3410 object_id_list,
3411 object_type_list);
3412 append_drc_violation (violation);
3413 pcb_drc_violation_free (violation);
3414 free (object_id_list);
3415 free (object_type_list);
3416 User = false;
3417 drc = false;
3418 if (!throw_drc_dialog())
3419 return (true);
3420 IncrementUndoSerialNumber ();
3421 Undo (true);
3422 /* highlight the rest of the encroaching net so it's not reported again */
3423 TheFlag |= SELECTEDFLAG;
3424 Bloat = 0;
3425 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3);
3426 DoIt (true, true);
3427 DumpList ();
3428 drc = true;
3429 Bloat = PCB->Bloat;
3430 ListStart (What, ptr1, ptr2, ptr3);
3432 drc = false;
3433 DumpList ();
3434 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3435 ClearFlagOnAllObjects (false, TheFlag);
3436 return (false);
3439 /* DRC clearance callback */
3441 static int
3442 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon,
3443 int type, void *ptr1, void *ptr2)
3445 char *message;
3446 Coord x, y;
3447 int object_count;
3448 long int *object_id_list;
3449 int *object_type_list;
3450 DrcViolationType *violation;
3452 LineType *line = (LineType *) ptr2;
3453 ArcType *arc = (ArcType *) ptr2;
3454 PinType *pin = (PinType *) ptr2;
3455 PadType *pad = (PadType *) ptr2;
3457 thing_type = type;
3458 thing_ptr1 = ptr1;
3459 thing_ptr2 = ptr2;
3460 thing_ptr3 = ptr2;
3461 switch (type)
3463 case LINE_TYPE:
3464 if (line->Clearance < 2 * PCB->Bloat)
3466 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3467 SET_FLAG (TheFlag, line);
3468 message = _("Line with insufficient clearance inside polygon\n");
3469 goto doIsBad;
3471 break;
3472 case ARC_TYPE:
3473 if (arc->Clearance < 2 * PCB->Bloat)
3475 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3476 SET_FLAG (TheFlag, arc);
3477 message = _("Arc with insufficient clearance inside polygon\n");
3478 goto doIsBad;
3480 break;
3481 case PAD_TYPE:
3482 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
3483 if (IsPadInPolygon(pad,polygon))
3485 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3486 SET_FLAG (TheFlag, pad);
3487 message = _("Pad with insufficient clearance inside polygon\n");
3488 goto doIsBad;
3490 break;
3491 case PIN_TYPE:
3492 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3494 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3495 SET_FLAG (TheFlag, pin);
3496 message = _("Pin with insufficient clearance inside polygon\n");
3497 goto doIsBad;
3499 break;
3500 case VIA_TYPE:
3501 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3503 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3504 SET_FLAG (TheFlag, pin);
3505 message = _("Via with insufficient clearance inside polygon\n");
3506 goto doIsBad;
3508 break;
3509 default:
3510 Message ("hace: Bad Plow object in callback\n");
3512 return 0;
3514 doIsBad:
3515 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3516 SET_FLAG (FOUNDFLAG, polygon);
3517 DrawPolygon (layer, polygon);
3518 DrawObject (type, ptr1, ptr2);
3519 drcerr_count++;
3520 LocateError (&x, &y);
3521 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3522 violation = pcb_drc_violation_new (message,
3523 _("Circuits that are too close may bridge during imaging, etching,\n"
3524 "plating, or soldering processes resulting in a direct short."),
3525 x, y,
3526 0, /* ANGLE OF ERROR UNKNOWN */
3527 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3528 0, /* MAGNITUDE OF ERROR UNKNOWN */
3529 PCB->Bloat,
3530 object_count,
3531 object_id_list,
3532 object_type_list);
3533 append_drc_violation (violation);
3534 pcb_drc_violation_free (violation);
3535 free (object_id_list);
3536 free (object_type_list);
3537 if (!throw_drc_dialog())
3539 IsBad = true;
3540 return 1;
3542 IncrementUndoSerialNumber ();
3543 Undo (true);
3544 return 0;
3547 /*-----------------------------------------------------------------------------
3548 * Check for DRC violations
3549 * see if the connectivity changes when everything is bloated, or shrunk
3552 DRCAll (void)
3554 Coord x, y;
3555 int object_count;
3556 long int *object_id_list;
3557 int *object_type_list;
3558 DrcViolationType *violation;
3559 int tmpcnt;
3560 int nopastecnt = 0;
3562 reset_drc_dialog_message();
3564 IsBad = false;
3565 drcerr_count = 0;
3566 SaveStackAndVisibility ();
3567 ResetStackAndVisibility ();
3568 hid_action ("LayersChanged");
3569 InitConnectionLookup ();
3571 TheFlag = FOUNDFLAG | DRCFLAG | SELECTEDFLAG;
3573 if (ClearFlagOnAllObjects (true, TheFlag))
3575 IncrementUndoSerialNumber ();
3576 Draw ();
3579 User = false;
3581 ELEMENT_LOOP (PCB->Data);
3583 PIN_LOOP (element);
3585 if (!TEST_FLAG (DRCFLAG, pin)
3586 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin))
3588 IsBad = true;
3589 break;
3592 END_LOOP;
3593 if (IsBad)
3594 break;
3595 PAD_LOOP (element);
3598 /* count up how many pads have no solderpaste openings */
3599 if (TEST_FLAG (NOPASTEFLAG, pad))
3600 nopastecnt++;
3602 if (!TEST_FLAG (DRCFLAG, pad)
3603 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad))
3605 IsBad = true;
3606 break;
3609 END_LOOP;
3610 if (IsBad)
3611 break;
3613 END_LOOP;
3614 if (!IsBad)
3615 VIA_LOOP (PCB->Data);
3617 if (!TEST_FLAG (DRCFLAG, via)
3618 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via))
3620 IsBad = true;
3621 break;
3624 END_LOOP;
3626 TheFlag = (IsBad) ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG);
3627 ClearFlagOnAllObjects (false, TheFlag);
3628 TheFlag = SELECTEDFLAG;
3629 /* check minimum widths and polygon clearances */
3630 if (!IsBad)
3632 COPPERLINE_LOOP (PCB->Data);
3634 /* check line clearances in polygons */
3635 PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback);
3636 if (IsBad)
3637 break;
3638 if (line->Thickness < PCB->minWid)
3640 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3641 SET_FLAG (TheFlag, line);
3642 DrawLine (layer, line);
3643 drcerr_count++;
3644 SetThing (LINE_TYPE, layer, line, line);
3645 LocateError (&x, &y);
3646 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3647 violation = pcb_drc_violation_new (_("Line width is too thin"),
3648 _("Process specifications dictate a minimum feature-width\n"
3649 "that can reliably be reproduced"),
3650 x, y,
3651 0, /* ANGLE OF ERROR UNKNOWN */
3652 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3653 line->Thickness,
3654 PCB->minWid,
3655 object_count,
3656 object_id_list,
3657 object_type_list);
3658 append_drc_violation (violation);
3659 pcb_drc_violation_free (violation);
3660 free (object_id_list);
3661 free (object_type_list);
3662 if (!throw_drc_dialog())
3664 IsBad = true;
3665 break;
3667 IncrementUndoSerialNumber ();
3668 Undo (false);
3671 ENDALL_LOOP;
3673 if (!IsBad)
3675 COPPERARC_LOOP (PCB->Data);
3677 PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback);
3678 if (IsBad)
3679 break;
3680 if (arc->Thickness < PCB->minWid)
3682 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3683 SET_FLAG (TheFlag, arc);
3684 DrawArc (layer, arc);
3685 drcerr_count++;
3686 SetThing (ARC_TYPE, layer, arc, arc);
3687 LocateError (&x, &y);
3688 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3689 violation = pcb_drc_violation_new (_("Arc width is too thin"),
3690 _("Process specifications dictate a minimum feature-width\n"
3691 "that can reliably be reproduced"),
3692 x, y,
3693 0, /* ANGLE OF ERROR UNKNOWN */
3694 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3695 arc->Thickness,
3696 PCB->minWid,
3697 object_count,
3698 object_id_list,
3699 object_type_list);
3700 append_drc_violation (violation);
3701 pcb_drc_violation_free (violation);
3702 free (object_id_list);
3703 free (object_type_list);
3704 if (!throw_drc_dialog())
3706 IsBad = true;
3707 break;
3709 IncrementUndoSerialNumber ();
3710 Undo (false);
3713 ENDALL_LOOP;
3715 if (!IsBad)
3717 ALLPIN_LOOP (PCB->Data);
3719 PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback);
3720 if (IsBad)
3721 break;
3722 if (!TEST_FLAG (HOLEFLAG, pin) &&
3723 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing)
3725 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3726 SET_FLAG (TheFlag, pin);
3727 DrawPin (pin);
3728 drcerr_count++;
3729 SetThing (PIN_TYPE, element, pin, pin);
3730 LocateError (&x, &y);
3731 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3732 violation = pcb_drc_violation_new (_("Pin annular ring too small"),
3733 _("Annular rings that are too small may erode during etching,\n"
3734 "resulting in a broken connection"),
3735 x, y,
3736 0, /* ANGLE OF ERROR UNKNOWN */
3737 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3738 (pin->Thickness - pin->DrillingHole) / 2,
3739 PCB->minRing,
3740 object_count,
3741 object_id_list,
3742 object_type_list);
3743 append_drc_violation (violation);
3744 pcb_drc_violation_free (violation);
3745 free (object_id_list);
3746 free (object_type_list);
3747 if (!throw_drc_dialog())
3749 IsBad = true;
3750 break;
3752 IncrementUndoSerialNumber ();
3753 Undo (false);
3755 if (pin->DrillingHole < PCB->minDrill)
3757 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3758 SET_FLAG (TheFlag, pin);
3759 DrawPin (pin);
3760 drcerr_count++;
3761 SetThing (PIN_TYPE, element, pin, pin);
3762 LocateError (&x, &y);
3763 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3764 violation = pcb_drc_violation_new (_("Pin drill size is too small"),
3765 _("Process rules dictate the minimum drill size which can be used"),
3766 x, y,
3767 0, /* ANGLE OF ERROR UNKNOWN */
3768 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3769 pin->DrillingHole,
3770 PCB->minDrill,
3771 object_count,
3772 object_id_list,
3773 object_type_list);
3774 append_drc_violation (violation);
3775 pcb_drc_violation_free (violation);
3776 free (object_id_list);
3777 free (object_type_list);
3778 if (!throw_drc_dialog())
3780 IsBad = true;
3781 break;
3783 IncrementUndoSerialNumber ();
3784 Undo (false);
3787 ENDALL_LOOP;
3789 if (!IsBad)
3791 ALLPAD_LOOP (PCB->Data);
3793 PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback);
3794 if (IsBad)
3795 break;
3796 if (pad->Thickness < PCB->minWid)
3798 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3799 SET_FLAG (TheFlag, pad);
3800 DrawPad (pad);
3801 drcerr_count++;
3802 SetThing (PAD_TYPE, element, pad, pad);
3803 LocateError (&x, &y);
3804 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3805 violation = pcb_drc_violation_new (_("Pad is too thin"),
3806 _("Pads which are too thin may erode during etching,\n"
3807 "resulting in a broken or unreliable connection"),
3808 x, y,
3809 0, /* ANGLE OF ERROR UNKNOWN */
3810 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3811 pad->Thickness,
3812 PCB->minWid,
3813 object_count,
3814 object_id_list,
3815 object_type_list);
3816 append_drc_violation (violation);
3817 pcb_drc_violation_free (violation);
3818 free (object_id_list);
3819 free (object_type_list);
3820 if (!throw_drc_dialog())
3822 IsBad = true;
3823 break;
3825 IncrementUndoSerialNumber ();
3826 Undo (false);
3829 ENDALL_LOOP;
3831 if (!IsBad)
3833 VIA_LOOP (PCB->Data);
3835 PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback);
3836 if (IsBad)
3837 break;
3838 if (!TEST_FLAG (HOLEFLAG, via) &&
3839 via->Thickness - via->DrillingHole < 2 * PCB->minRing)
3841 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3842 SET_FLAG (TheFlag, via);
3843 DrawVia (via);
3844 drcerr_count++;
3845 SetThing (VIA_TYPE, via, via, via);
3846 LocateError (&x, &y);
3847 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3848 violation = pcb_drc_violation_new (_("Via annular ring too small"),
3849 _("Annular rings that are too small may erode during etching,\n"
3850 "resulting in a broken connection"),
3851 x, y,
3852 0, /* ANGLE OF ERROR UNKNOWN */
3853 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3854 (via->Thickness - via->DrillingHole) / 2,
3855 PCB->minRing,
3856 object_count,
3857 object_id_list,
3858 object_type_list);
3859 append_drc_violation (violation);
3860 pcb_drc_violation_free (violation);
3861 free (object_id_list);
3862 free (object_type_list);
3863 if (!throw_drc_dialog())
3865 IsBad = true;
3866 break;
3868 IncrementUndoSerialNumber ();
3869 Undo (false);
3871 if (via->DrillingHole < PCB->minDrill)
3873 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3874 SET_FLAG (TheFlag, via);
3875 DrawVia (via);
3876 drcerr_count++;
3877 SetThing (VIA_TYPE, via, via, via);
3878 LocateError (&x, &y);
3879 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3880 violation = pcb_drc_violation_new (_("Via drill size is too small"),
3881 _("Process rules dictate the minimum drill size which can be used"),
3882 x, y,
3883 0, /* ANGLE OF ERROR UNKNOWN */
3884 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3885 via->DrillingHole,
3886 PCB->minDrill,
3887 object_count,
3888 object_id_list,
3889 object_type_list);
3890 append_drc_violation (violation);
3891 pcb_drc_violation_free (violation);
3892 free (object_id_list);
3893 free (object_type_list);
3894 if (!throw_drc_dialog())
3896 IsBad = true;
3897 break;
3899 IncrementUndoSerialNumber ();
3900 Undo (false);
3903 END_LOOP;
3906 FreeConnectionLookupMemory ();
3907 TheFlag = FOUNDFLAG;
3908 Bloat = 0;
3910 /* check silkscreen minimum widths outside of elements */
3911 /* XXX - need to check text and polygons too! */
3912 TheFlag = SELECTEDFLAG;
3913 if (!IsBad)
3915 SILKLINE_LOOP (PCB->Data);
3917 if (line->Thickness < PCB->minSlk)
3919 SET_FLAG (TheFlag, line);
3920 DrawLine (layer, line);
3921 drcerr_count++;
3922 SetThing (LINE_TYPE, layer, line, line);
3923 LocateError (&x, &y);
3924 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3925 violation = pcb_drc_violation_new (_("Silk line is too thin"),
3926 _("Process specifications dictate a minimum silkscreen feature-width\n"
3927 "that can reliably be reproduced"),
3928 x, y,
3929 0, /* ANGLE OF ERROR UNKNOWN */
3930 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3931 line->Thickness,
3932 PCB->minSlk,
3933 object_count,
3934 object_id_list,
3935 object_type_list);
3936 append_drc_violation (violation);
3937 pcb_drc_violation_free (violation);
3938 free (object_id_list);
3939 free (object_type_list);
3940 if (!throw_drc_dialog())
3942 IsBad = true;
3943 break;
3947 ENDALL_LOOP;
3950 /* check silkscreen minimum widths inside of elements */
3951 /* XXX - need to check text and polygons too! */
3952 TheFlag = SELECTEDFLAG;
3953 if (!IsBad)
3955 ELEMENT_LOOP (PCB->Data);
3957 tmpcnt = 0;
3958 ELEMENTLINE_LOOP (element);
3960 if (line->Thickness < PCB->minSlk)
3961 tmpcnt++;
3963 END_LOOP;
3964 if (tmpcnt > 0)
3966 char *title;
3967 char *name;
3968 char *buffer;
3969 int buflen;
3971 SET_FLAG (TheFlag, element);
3972 DrawElement (element);
3973 drcerr_count++;
3974 SetThing (ELEMENT_TYPE, element, element, element);
3975 LocateError (&x, &y);
3976 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3978 title = _("Element %s has %i silk lines which are too thin");
3979 name = (char *)UNKNOWN (NAMEONPCB_NAME (element));
3981 /* -4 is for the %s and %i place-holders */
3982 /* +11 is the max printed length for a 32 bit integer */
3983 /* +1 is for the \0 termination */
3984 buflen = strlen (title) - 4 + strlen (name) + 11 + 1;
3985 buffer = (char *)malloc (buflen);
3986 snprintf (buffer, buflen, title, name, tmpcnt);
3988 violation = pcb_drc_violation_new (buffer,
3989 _("Process specifications dictate a minimum silkscreen\n"
3990 "feature-width that can reliably be reproduced"),
3991 x, y,
3992 0, /* ANGLE OF ERROR UNKNOWN */
3993 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3994 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
3995 PCB->minSlk,
3996 object_count,
3997 object_id_list,
3998 object_type_list);
3999 free (buffer);
4000 append_drc_violation (violation);
4001 pcb_drc_violation_free (violation);
4002 free (object_id_list);
4003 free (object_type_list);
4004 if (!throw_drc_dialog())
4006 IsBad = true;
4007 break;
4011 END_LOOP;
4015 if (IsBad)
4017 IncrementUndoSerialNumber ();
4021 RestoreStackAndVisibility ();
4022 hid_action ("LayersChanged");
4023 gui->invalidate_all ();
4025 if (nopastecnt > 0)
4027 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4028 nopastecnt,
4029 nopastecnt > 1 ? "s have" : " has");
4031 return IsBad ? -drcerr_count : drcerr_count;
4034 /*----------------------------------------------------------------------------
4035 * Locate the coordinatates of offending item (thing)
4037 static void
4038 LocateError (Coord *x, Coord *y)
4040 switch (thing_type)
4042 case LINE_TYPE:
4044 LineType *line = (LineType *) thing_ptr3;
4045 *x = (line->Point1.X + line->Point2.X) / 2;
4046 *y = (line->Point1.Y + line->Point2.Y) / 2;
4047 break;
4049 case ARC_TYPE:
4051 ArcType *arc = (ArcType *) thing_ptr3;
4052 *x = arc->X;
4053 *y = arc->Y;
4054 break;
4056 case POLYGON_TYPE:
4058 PolygonType *polygon = (PolygonType *) thing_ptr3;
4059 *x =
4060 (polygon->Clipped->contours->xmin +
4061 polygon->Clipped->contours->xmax) / 2;
4062 *y =
4063 (polygon->Clipped->contours->ymin +
4064 polygon->Clipped->contours->ymax) / 2;
4065 break;
4067 case PIN_TYPE:
4068 case VIA_TYPE:
4070 PinType *pin = (PinType *) thing_ptr3;
4071 *x = pin->X;
4072 *y = pin->Y;
4073 break;
4075 case PAD_TYPE:
4077 PadType *pad = (PadType *) thing_ptr3;
4078 *x = (pad->Point1.X + pad->Point2.X) / 2;
4079 *y = (pad->Point1.Y + pad->Point2.Y) / 2;
4080 break;
4082 case ELEMENT_TYPE:
4084 ElementType *element = (ElementType *) thing_ptr3;
4085 *x = element->MarkX;
4086 *y = element->MarkY;
4087 break;
4089 default:
4090 return;
4095 /*----------------------------------------------------------------------------
4096 * Build a list of the of offending items by ID. (Currently just "thing")
4098 static void
4099 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
4101 *object_count = 0;
4102 *object_id_list = NULL;
4103 *object_type_list = NULL;
4105 switch (thing_type)
4107 case LINE_TYPE:
4108 case ARC_TYPE:
4109 case POLYGON_TYPE:
4110 case PIN_TYPE:
4111 case VIA_TYPE:
4112 case PAD_TYPE:
4113 case ELEMENT_TYPE:
4114 case RATLINE_TYPE:
4115 *object_count = 1;
4116 *object_id_list = (long int *)malloc (sizeof (long int));
4117 *object_type_list = (int *)malloc (sizeof (int));
4118 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
4119 **object_type_list = thing_type;
4120 return;
4122 default:
4123 fprintf (stderr,
4124 _("Internal error in BuildObjectList: unknown object type %i\n"),
4125 thing_type);
4130 /*----------------------------------------------------------------------------
4131 * center the display to show the offending item (thing)
4133 static void
4134 GotoError (void)
4136 Coord X, Y;
4138 LocateError (&X, &Y);
4140 switch (thing_type)
4142 case LINE_TYPE:
4143 case ARC_TYPE:
4144 case POLYGON_TYPE:
4145 ChangeGroupVisibility (
4146 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1),
4147 true, true);
4149 CenterDisplay (X, Y);
4152 void
4153 InitConnectionLookup (void)
4155 InitComponentLookup ();
4156 InitLayoutLookup ();
4159 void
4160 FreeConnectionLookupMemory (void)
4162 FreeComponentLookupMemory ();
4163 FreeLayoutLookupMemory ();