find.c: Tidy up some macro definitions
[geda-pcb/pcjc2.git] / src / find.c
blob3d1e59624bb2e61b9904fb1550f3fe7a3c4d0f38
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;
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 = 0; layer < max_copper_layer; layer++)
746 if (LAYER_PTR (layer)->no_drc)
747 continue;
748 info.layer = layer;
749 /* add touching lines */
750 if (setjmp (info.env) == 0)
751 r_search (LAYER_PTR (layer)->line_tree, (BoxType *) & info.pv,
752 NULL, LOCtoPVline_callback, &info);
753 else
754 return true;
755 /* add touching arcs */
756 if (setjmp (info.env) == 0)
757 r_search (LAYER_PTR (layer)->arc_tree, (BoxType *) & info.pv,
758 NULL, LOCtoPVarc_callback, &info);
759 else
760 return true;
761 /* check all polygons */
762 if (setjmp (info.env) == 0)
763 r_search (LAYER_PTR (layer)->polygon_tree, (BoxType *) & info.pv,
764 NULL, LOCtoPVpoly_callback, &info);
765 else
766 return true;
768 /* Check for rat-lines that may intersect the PV */
769 if (AndRats)
771 if (setjmp (info.env) == 0)
772 r_search (PCB->Data->rat_tree, (BoxType *) & info.pv, NULL,
773 LOCtoPVrat_callback, &info);
774 else
775 return true;
777 PVList.Location++;
779 return false;
782 /* ---------------------------------------------------------------------------
783 * find all connections between LO at the current list position and new LOs
785 static bool
786 LookupLOConnectionsToLOList (bool AndRats)
788 bool done;
789 Cardinal i, group, layer, ratposition,
790 lineposition[MAX_LAYER],
791 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2];
793 /* copy the current LO list positions; the original data is changed
794 * by 'LookupPVConnectionsToLOList()' which has to check the same
795 * list entries plus the new ones
797 for (i = 0; i < max_copper_layer; i++)
799 lineposition[i] = LineList[i].Location;
800 polyposition[i] = PolygonList[i].Location;
801 arcposition[i] = ArcList[i].Location;
803 for (i = 0; i < 2; i++)
804 padposition[i] = PadList[i].Location;
805 ratposition = RatList.Location;
807 /* loop over all new LOs in the list; recurse until no
808 * more new connections in the layergroup were found
812 Cardinal *position;
814 if (AndRats)
816 position = &ratposition;
817 for (; *position < RatList.Number; (*position)++)
819 group = RATLIST_ENTRY (*position)->group1;
820 if (LookupLOConnectionsToRatEnd
821 (&(RATLIST_ENTRY (*position)->Point1), group))
822 return (true);
823 group = RATLIST_ENTRY (*position)->group2;
824 if (LookupLOConnectionsToRatEnd
825 (&(RATLIST_ENTRY (*position)->Point2), group))
826 return (true);
829 /* loop over all layergroups */
830 for (group = 0; group < max_group; group++)
832 Cardinal entry;
834 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
836 layer = PCB->LayerGroups.Entries[group][entry];
838 /* be aware that the layer number equal max_copper_layer
839 * and max_copper_layer+1 have a special meaning for pads
841 if (layer < max_copper_layer)
843 /* try all new lines */
844 position = &lineposition[layer];
845 for (; *position < LineList[layer].Number; (*position)++)
846 if (LookupLOConnectionsToLine
847 (LINELIST_ENTRY (layer, *position), group, true))
848 return (true);
850 /* try all new arcs */
851 position = &arcposition[layer];
852 for (; *position < ArcList[layer].Number; (*position)++)
853 if (LookupLOConnectionsToArc
854 (ARCLIST_ENTRY (layer, *position), group))
855 return (true);
857 /* try all new polygons */
858 position = &polyposition[layer];
859 for (; *position < PolygonList[layer].Number; (*position)++)
860 if (LookupLOConnectionsToPolygon
861 (POLYGONLIST_ENTRY (layer, *position), group))
862 return (true);
864 else
866 /* try all new pads */
867 layer -= max_copper_layer;
868 if (layer > 1)
870 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
871 layer, max_copper_layer);
872 return false;
874 position = &padposition[layer];
875 for (; *position < PadList[layer].Number; (*position)++)
876 if (LookupLOConnectionsToPad
877 (PADLIST_ENTRY (layer, *position), group))
878 return (true);
883 /* check if all lists are done; Later for-loops
884 * may have changed the prior lists
886 done = !AndRats || ratposition >= RatList.Number;
887 done = done && padposition[0] >= PadList[0].Number &&
888 padposition[1] >= PadList[1].Number;
889 for (layer = 0; layer < max_copper_layer; layer++)
890 done = done &&
891 lineposition[layer] >= LineList[layer].Number &&
892 arcposition[layer] >= ArcList[layer].Number &&
893 polyposition[layer] >= PolygonList[layer].Number;
895 while (!done);
896 return (false);
899 static int
900 pv_pv_callback (const BoxType * b, void *cl)
902 PinType *pin = (PinType *) b;
903 struct pv_info *i = (struct pv_info *) cl;
905 if (!TEST_FLAG (TheFlag, pin) && PV_TOUCH_PV (&i->pv, pin))
907 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, &i->pv))
909 SET_FLAG (WARNFLAG, pin);
910 Settings.RatWarn = true;
911 if (pin->Element)
912 Message (_("WARNING: Hole too close to pin.\n"));
913 else
914 Message (_("WARNING: Hole too close to via.\n"));
916 else if (ADD_PV_TO_LIST (pin))
917 longjmp (i->env, 1);
919 return 0;
922 /* ---------------------------------------------------------------------------
923 * searches for new PVs that are connected to PVs on the list
925 static bool
926 LookupPVConnectionsToPVList (void)
928 Cardinal save_place;
929 struct pv_info info;
932 /* loop over all PVs on list */
933 save_place = PVList.Location;
934 while (PVList.Location < PVList.Number)
936 /* get pointer to data */
937 info.pv = *(PVLIST_ENTRY (PVList.Location));
938 EXPAND_BOUNDS (&info.pv);
939 if (setjmp (info.env) == 0)
940 r_search (PCB->Data->via_tree, (BoxType *) & info.pv, NULL,
941 pv_pv_callback, &info);
942 else
943 return true;
944 if (setjmp (info.env) == 0)
945 r_search (PCB->Data->pin_tree, (BoxType *) & info.pv, NULL,
946 pv_pv_callback, &info);
947 else
948 return true;
949 PVList.Location++;
951 PVList.Location = save_place;
952 return (false);
955 struct lo_info
957 Cardinal layer;
958 LineType line;
959 PadType pad;
960 ArcType arc;
961 PolygonType polygon;
962 RatType rat;
963 jmp_buf env;
966 static int
967 pv_line_callback (const BoxType * b, void *cl)
969 PinType *pv = (PinType *) b;
970 struct lo_info *i = (struct lo_info *) cl;
972 if (!TEST_FLAG (TheFlag, pv) && PinLineIntersect (pv, &i->line))
974 if (TEST_FLAG (HOLEFLAG, pv))
976 SET_FLAG (WARNFLAG, pv);
977 Settings.RatWarn = true;
978 Message (_("WARNING: Hole too close to line.\n"));
980 else if (ADD_PV_TO_LIST (pv))
981 longjmp (i->env, 1);
983 return 0;
986 static int
987 pv_pad_callback (const BoxType * b, void *cl)
989 PinType *pv = (PinType *) b;
990 struct lo_info *i = (struct lo_info *) cl;
992 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_PAD (pv, &i->pad))
994 if (TEST_FLAG (HOLEFLAG, pv))
996 SET_FLAG (WARNFLAG, pv);
997 Settings.RatWarn = true;
998 Message (_("WARNING: Hole too close to pad.\n"));
1000 else if (ADD_PV_TO_LIST (pv))
1001 longjmp (i->env, 1);
1003 return 0;
1006 static int
1007 pv_arc_callback (const BoxType * b, void *cl)
1009 PinType *pv = (PinType *) b;
1010 struct lo_info *i = (struct lo_info *) cl;
1012 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_ARC (pv, &i->arc))
1014 if (TEST_FLAG (HOLEFLAG, pv))
1016 SET_FLAG (WARNFLAG, pv);
1017 Settings.RatWarn = true;
1018 Message (_("WARNING: Hole touches arc.\n"));
1020 else if (ADD_PV_TO_LIST (pv))
1021 longjmp (i->env, 1);
1023 return 0;
1026 static int
1027 pv_poly_callback (const BoxType * b, void *cl)
1029 PinType *pv = (PinType *) b;
1030 struct lo_info *i = (struct lo_info *) cl;
1032 /* note that holes in polygons are ok, so they don't generate warnings. */
1033 if (!TEST_FLAG (TheFlag, pv) && !TEST_FLAG (HOLEFLAG, pv) &&
1034 (TEST_THERM (i->layer, pv) ||
1035 !TEST_FLAG (CLEARPOLYFLAG, &i->polygon) ||
1036 !pv->Clearance))
1038 if (TEST_FLAG (SQUAREFLAG, pv))
1040 Coord x1, x2, y1, y2;
1041 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1042 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1043 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1044 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1045 if (IsRectangleInPolygon (x1, y1, x2, y2, &i->polygon)
1046 && ADD_PV_TO_LIST (pv))
1047 longjmp (i->env, 1);
1049 else if (TEST_FLAG (OCTAGONFLAG, pv))
1051 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2);
1052 if (isects (oct, &i->polygon, true) && ADD_PV_TO_LIST (pv))
1053 longjmp (i->env, 1);
1055 else
1057 if (IsPointInPolygon
1058 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, &i->polygon)
1059 && ADD_PV_TO_LIST (pv))
1060 longjmp (i->env, 1);
1063 return 0;
1066 static int
1067 pv_rat_callback (const BoxType * b, void *cl)
1069 PinType *pv = (PinType *) b;
1070 struct lo_info *i = (struct lo_info *) cl;
1072 /* rats can't cause DRC so there is no early exit */
1073 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_RAT (pv, &i->rat))
1074 ADD_PV_TO_LIST (pv);
1075 return 0;
1078 /* ---------------------------------------------------------------------------
1079 * searches for new PVs that are connected to NEW LOs on the list
1080 * This routine updates the position counter of the lists too.
1082 static bool
1083 LookupPVConnectionsToLOList (bool AndRats)
1085 Cardinal layer;
1086 struct lo_info info;
1088 /* loop over all layers */
1089 for (layer = 0; layer < max_copper_layer; layer++)
1091 if (LAYER_PTR (layer)->no_drc)
1092 continue;
1093 /* do nothing if there are no PV's */
1094 if (TotalP + TotalV == 0)
1096 LineList[layer].Location = LineList[layer].Number;
1097 ArcList[layer].Location = ArcList[layer].Number;
1098 PolygonList[layer].Location = PolygonList[layer].Number;
1099 continue;
1102 /* check all lines */
1103 while (LineList[layer].Location < LineList[layer].Number)
1105 info.line = *(LINELIST_ENTRY (layer, LineList[layer].Location));
1106 EXPAND_BOUNDS (&info.line);
1107 if (setjmp (info.env) == 0)
1108 r_search (PCB->Data->via_tree, (BoxType *) & info.line, NULL,
1109 pv_line_callback, &info);
1110 else
1111 return true;
1112 if (setjmp (info.env) == 0)
1113 r_search (PCB->Data->pin_tree, (BoxType *) & info.line, NULL,
1114 pv_line_callback, &info);
1115 else
1116 return true;
1117 LineList[layer].Location++;
1120 /* check all arcs */
1121 while (ArcList[layer].Location < ArcList[layer].Number)
1123 info.arc = *(ARCLIST_ENTRY (layer, ArcList[layer].Location));
1124 EXPAND_BOUNDS (&info.arc);
1125 if (setjmp (info.env) == 0)
1126 r_search (PCB->Data->via_tree, (BoxType *) & info.arc, NULL,
1127 pv_arc_callback, &info);
1128 else
1129 return true;
1130 if (setjmp (info.env) == 0)
1131 r_search (PCB->Data->pin_tree, (BoxType *) & info.arc, NULL,
1132 pv_arc_callback, &info);
1133 else
1134 return true;
1135 ArcList[layer].Location++;
1138 /* now all polygons */
1139 info.layer = layer;
1140 while (PolygonList[layer].Location < PolygonList[layer].Number)
1142 info.polygon =
1143 *(POLYGONLIST_ENTRY (layer, PolygonList[layer].Location));
1144 EXPAND_BOUNDS (&info.polygon);
1145 if (setjmp (info.env) == 0)
1146 r_search (PCB->Data->via_tree, (BoxType *) & info.polygon, NULL,
1147 pv_poly_callback, &info);
1148 else
1149 return true;
1150 if (setjmp (info.env) == 0)
1151 r_search (PCB->Data->pin_tree, (BoxType *) & info.polygon, NULL,
1152 pv_poly_callback, &info);
1153 else
1154 return true;
1155 PolygonList[layer].Location++;
1159 /* loop over all pad-layers */
1160 for (layer = 0; layer < 2; layer++)
1162 /* do nothing if there are no PV's */
1163 if (TotalP + TotalV == 0)
1165 PadList[layer].Location = PadList[layer].Number;
1166 continue;
1169 /* check all pads; for a detailed description see
1170 * the handling of lines in this subroutine
1172 while (PadList[layer].Location < PadList[layer].Number)
1174 info.pad = *(PADLIST_ENTRY (layer, PadList[layer].Location));
1175 EXPAND_BOUNDS (&info.pad);
1176 if (setjmp (info.env) == 0)
1177 r_search (PCB->Data->via_tree, (BoxType *) & info.pad, NULL,
1178 pv_pad_callback, &info);
1179 else
1180 return true;
1181 if (setjmp (info.env) == 0)
1182 r_search (PCB->Data->pin_tree, (BoxType *) & info.pad, NULL,
1183 pv_pad_callback, &info);
1184 else
1185 return true;
1186 PadList[layer].Location++;
1190 /* do nothing if there are no PV's */
1191 if (TotalP + TotalV == 0)
1192 RatList.Location = RatList.Number;
1194 /* check all rat-lines */
1195 if (AndRats)
1197 while (RatList.Location < RatList.Number)
1199 info.rat = *(RATLIST_ENTRY (RatList.Location));
1200 r_search_pt (PCB->Data->via_tree, & info.rat.Point1, 1, NULL,
1201 pv_rat_callback, &info);
1202 r_search_pt (PCB->Data->via_tree, & info.rat.Point2, 1, NULL,
1203 pv_rat_callback, &info);
1204 r_search_pt (PCB->Data->pin_tree, & info.rat.Point1, 1, NULL,
1205 pv_rat_callback, &info);
1206 r_search_pt (PCB->Data->pin_tree, & info.rat.Point2, 1, NULL,
1207 pv_rat_callback, &info);
1209 RatList.Location++;
1212 return (false);
1215 /* reduce arc start angle and delta to 0..360 */
1216 static void
1217 normalize_angles (Angle *sa, Angle *d)
1219 if (*d < 0)
1221 *sa += *d;
1222 *d = - *d;
1224 if (*d > 360) /* full circle */
1225 *d = 360;
1226 *sa = NormalizeAngle (*sa);
1229 static int
1230 radius_crosses_arc (double x, double y, ArcType *arc)
1232 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG;
1233 Angle sa = arc->StartAngle, d = arc->Delta;
1235 normalize_angles (&sa, &d);
1236 if (alpha < 0)
1237 alpha += 360;
1238 if (sa <= alpha)
1239 return (sa + d) >= alpha;
1240 return (sa + d - 360) >= alpha;
1243 static void
1244 get_arc_ends (Coord *box, ArcType *arc)
1246 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle);
1247 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle);
1248 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta));
1249 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta));
1251 /* ---------------------------------------------------------------------------
1252 * check if two arcs intersect
1253 * first we check for circle intersections,
1254 * then find the actual points of intersection
1255 * and test them to see if they are on arcs
1257 * consider a, the distance from the center of arc 1
1258 * to the point perpendicular to the intersecting points.
1260 * a = (r1^2 - r2^2 + l^2)/(2l)
1262 * the perpendicular distance to the point of intersection
1263 * is then
1265 * d = sqrt(r1^2 - a^2)
1267 * the points of intersection would then be
1269 * x = X1 + a/l dx +- d/l dy
1270 * y = Y1 + a/l dy -+ d/l dx
1272 * where dx = X2 - X1 and dy = Y2 - Y1
1276 static bool
1277 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2)
1279 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl;
1280 Coord pdx, pdy;
1281 Coord box[8];
1283 t = 0.5 * Arc1->Thickness + Bloat;
1284 t2 = 0.5 * Arc2->Thickness;
1285 t1 = t2 + Bloat;
1287 /* too thin arc */
1288 if (t < 0 || t1 < 0)
1289 return false;
1291 /* try the end points first */
1292 get_arc_ends (&box[0], Arc1);
1293 get_arc_ends (&box[4], Arc2);
1294 if (IsPointOnArc (box[0], box[1], t, Arc2)
1295 || IsPointOnArc (box[2], box[3], t, Arc2)
1296 || IsPointOnArc (box[4], box[5], t, Arc1)
1297 || IsPointOnArc (box[6], box[7], t, Arc1))
1298 return true;
1300 pdx = Arc2->X - Arc1->X;
1301 pdy = Arc2->Y - Arc1->Y;
1302 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y);
1303 /* concentric arcs, simpler intersection conditions */
1304 if (dl < 0.5)
1306 if ((Arc1->Width - t >= Arc2->Width - t2
1307 && Arc1->Width - t <= Arc2->Width + t2)
1308 || (Arc1->Width + t >= Arc2->Width - t2
1309 && Arc1->Width + t <= Arc2->Width + t2))
1311 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta;
1312 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta;
1313 /* NB the endpoints have already been checked,
1314 so we just compare the angles */
1316 normalize_angles (&sa1, &d1);
1317 normalize_angles (&sa2, &d2);
1318 /* sa1 == sa2 was caught when checking endpoints */
1319 if (sa1 > sa2)
1320 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2)
1321 return true;
1322 if (sa2 > sa1)
1323 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1)
1324 return true;
1326 return false;
1328 r1 = Arc1->Width;
1329 r2 = Arc2->Width;
1330 /* arcs centerlines are too far or too near */
1331 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1)
1333 /* check the nearest to the other arc's center point */
1334 dx = pdx * r1 / dl;
1335 dy = pdy * r1 / dl;
1336 if (dl + r1 < r2) /* Arc1 inside Arc2 */
1338 dx = - dx;
1339 dy = - dy;
1342 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1)
1343 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2))
1344 return true;
1346 dx = - pdx * r2 / dl;
1347 dy = - pdy * r2 / dl;
1348 if (dl + r2 < r1) /* Arc2 inside Arc1 */
1350 dx = - dx;
1351 dy = - dy;
1354 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2)
1355 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1))
1356 return true;
1357 return false;
1360 l = dl * dl;
1361 r1 *= r1;
1362 r2 *= r2;
1363 a = 0.5 * (r1 - r2 + l) / l;
1364 r1 = r1 / l;
1365 d = r1 - a * a;
1366 /* the circles are too far apart to touch or probably just touch:
1367 check the nearest point */
1368 if (d < 0)
1369 d = 0;
1370 else
1371 d = sqrt (d);
1372 x = Arc1->X + a * pdx;
1373 y = Arc1->Y + a * pdy;
1374 dx = d * pdx;
1375 dy = d * pdy;
1376 if (radius_crosses_arc (x + dy, y - dx, Arc1)
1377 && IsPointOnArc (x + dy, y - dx, t, Arc2))
1378 return true;
1379 if (radius_crosses_arc (x + dy, y - dx, Arc2)
1380 && IsPointOnArc (x + dy, y - dx, t1, Arc1))
1381 return true;
1383 if (radius_crosses_arc (x - dy, y + dx, Arc1)
1384 && IsPointOnArc (x - dy, y + dx, t, Arc2))
1385 return true;
1386 if (radius_crosses_arc (x - dy, y + dx, Arc2)
1387 && IsPointOnArc (x - dy, y + dx, t1, Arc1))
1388 return true;
1389 return false;
1392 /* ---------------------------------------------------------------------------
1393 * Tests if point is same as line end point
1395 static bool
1396 IsRatPointOnLineEnd (PointType *Point, LineType *Line)
1398 if ((Point->X == Line->Point1.X
1399 && Point->Y == Line->Point1.Y)
1400 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y))
1401 return (true);
1402 return (false);
1405 static void
1406 form_slanted_rectangle (PointType p[4], LineType *l)
1407 /* writes vertices of a squared line */
1409 double dwx = 0, dwy = 0;
1410 if (l->Point1.Y == l->Point2.Y)
1411 dwx = l->Thickness / 2.0;
1412 else if (l->Point1.X == l->Point2.X)
1413 dwy = l->Thickness / 2.0;
1414 else
1416 Coord dX = l->Point2.X - l->Point1.X;
1417 Coord dY = l->Point2.Y - l->Point1.Y;
1418 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y);
1419 dwx = l->Thickness / 2.0 / r * dX;
1420 dwy = l->Thickness / 2.0 / r * dY;
1422 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx;
1423 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx;
1424 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx;
1425 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx;
1427 /* ---------------------------------------------------------------------------
1428 * checks if two lines intersect
1429 * from news FAQ:
1431 * Let A,B,C,D be 2-space position vectors. Then the directed line
1432 * segments AB & CD are given by:
1434 * AB=A+r(B-A), r in [0,1]
1435 * CD=C+s(D-C), s in [0,1]
1437 * If AB & CD intersect, then
1439 * A+r(B-A)=C+s(D-C), or
1441 * XA+r(XB-XA)=XC+s(XD-XC)
1442 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1444 * Solving the above for r and s yields
1446 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1447 * r = ----------------------------- (eqn 1)
1448 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1450 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1451 * s = ----------------------------- (eqn 2)
1452 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1454 * Let I be the position vector of the intersection point, then
1456 * I=A+r(B-A) or
1458 * XI=XA+r(XB-XA)
1459 * YI=YA+r(YB-YA)
1461 * By examining the values of r & s, you can also determine some
1462 * other limiting conditions:
1464 * If 0<=r<=1 & 0<=s<=1, intersection exists
1465 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1467 * If the denominator in eqn 1 is zero, AB & CD are parallel
1468 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1470 * If the intersection point of the 2 lines are needed (lines in this
1471 * context mean infinite lines) regardless whether the two line
1472 * segments intersect, then
1474 * If r>1, I is located on extension of AB
1475 * If r<0, I is located on extension of BA
1476 * If s>1, I is located on extension of CD
1477 * If s<0, I is located on extension of DC
1479 * Also note that the denominators of eqn 1 & 2 are identical.
1482 bool
1483 LineLineIntersect (LineType *Line1, LineType *Line2)
1485 double s, r;
1486 double line1_dx, line1_dy, line2_dx, line2_dy,
1487 point1_dx, point1_dy;
1488 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */
1490 PointType p[4];
1491 form_slanted_rectangle (p, Line1);
1492 return IsLineInQuadrangle (p, Line2);
1494 /* here come only round Line1 because IsLineInQuadrangle()
1495 calls LineLineIntersect() with first argument rounded*/
1496 if (TEST_FLAG (SQUAREFLAG, Line2))
1498 PointType p[4];
1499 form_slanted_rectangle (p, Line2);
1500 return IsLineInQuadrangle (p, Line1);
1502 /* now all lines are round */
1504 /* Check endpoints: this provides a quick exit, catches
1505 * cases where the "real" lines don't intersect but the
1506 * thick lines touch, and ensures that the dx/dy business
1507 * below does not cause a divide-by-zero. */
1508 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y,
1509 MAX (Line2->Thickness / 2 + Bloat, 0),
1510 (PadType *) Line1)
1511 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y,
1512 MAX (Line2->Thickness / 2 + Bloat, 0),
1513 (PadType *) Line1)
1514 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y,
1515 MAX (Line1->Thickness / 2 + Bloat, 0),
1516 (PadType *) Line2)
1517 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y,
1518 MAX (Line1->Thickness / 2 + Bloat, 0),
1519 (PadType *) Line2))
1520 return true;
1522 /* setup some constants */
1523 line1_dx = Line1->Point2.X - Line1->Point1.X;
1524 line1_dy = Line1->Point2.Y - Line1->Point1.Y;
1525 line2_dx = Line2->Point2.X - Line2->Point1.X;
1526 line2_dy = Line2->Point2.Y - Line2->Point1.Y;
1527 point1_dx = Line1->Point1.X - Line2->Point1.X;
1528 point1_dy = Line1->Point1.Y - Line2->Point1.Y;
1530 /* If either line is a point, we have failed already, since the
1531 * endpoint check above will have caught an "intersection". */
1532 if ((line1_dx == 0 && line1_dy == 0)
1533 || (line2_dx == 0 && line2_dy == 0))
1534 return false;
1536 /* set s to cross product of Line1 and the line
1537 * Line1.Point1--Line2.Point1 (as vectors) */
1538 s = point1_dy * line1_dx - point1_dx * line1_dy;
1540 /* set r to cross product of both lines (as vectors) */
1541 r = line1_dx * line2_dy - line1_dy * line2_dx;
1543 /* No cross product means parallel lines, or maybe Line2 is
1544 * zero-length. In either case, since we did a bounding-box
1545 * check before getting here, the above IsPointInPad() checks
1546 * will have caught any intersections. */
1547 if (r == 0.0)
1548 return false;
1550 s /= r;
1551 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r;
1553 /* intersection is at least on AB */
1554 if (r >= 0.0 && r <= 1.0)
1555 return (s >= 0.0 && s <= 1.0);
1557 /* intersection is at least on CD */
1558 /* [removed this case since it always returns false --asp] */
1559 return false;
1562 /*---------------------------------------------------
1564 * Check for line intersection with an arc
1566 * Mostly this is like the circle/line intersection
1567 * found in IsPointOnLine (search.c) see the detailed
1568 * discussion for the basics there.
1570 * Since this is only an arc, not a full circle we need
1571 * to find the actual points of intersection with the
1572 * circle, and see if they are on the arc.
1574 * To do this, we translate along the line from the point Q
1575 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1576 * but it's handy to normalize with respect to l, the line
1577 * length so a single projection is done (e.g. we don't first
1578 * find the point Q
1580 * The projection is now of the form
1582 * Px = X1 + (r +- r2)(X2 - X1)
1583 * Py = Y1 + (r +- r2)(Y2 - Y1)
1585 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1586 * note that this is the variable d, not the symbol d described in IsPointOnLine
1587 * (variable d = symbol d * l)
1589 * The end points are hell so they are checked individually
1591 bool
1592 LineArcIntersect (LineType *Line, ArcType *Arc)
1594 double dx, dy, dx1, dy1, l, d, r, r2, Radius;
1595 BoxType *box;
1597 dx = Line->Point2.X - Line->Point1.X;
1598 dy = Line->Point2.Y - Line->Point1.Y;
1599 dx1 = Line->Point1.X - Arc->X;
1600 dy1 = Line->Point1.Y - Arc->Y;
1601 l = dx * dx + dy * dy;
1602 d = dx * dy1 - dy * dx1;
1603 d *= d;
1605 /* use the larger diameter circle first */
1606 Radius =
1607 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0);
1608 Radius *= Radius;
1609 r2 = Radius * l - d;
1610 /* projection doesn't even intersect circle when r2 < 0 */
1611 if (r2 < 0)
1612 return (false);
1613 /* check the ends of the line in case the projected point */
1614 /* of intersection is beyond the line end */
1615 if (IsPointOnArc
1616 (Line->Point1.X, Line->Point1.Y,
1617 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1618 return (true);
1619 if (IsPointOnArc
1620 (Line->Point2.X, Line->Point2.Y,
1621 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1622 return (true);
1623 if (l == 0.0)
1624 return (false);
1625 r2 = sqrt (r2);
1626 Radius = -(dx * dx1 + dy * dy1);
1627 r = (Radius + r2) / l;
1628 if (r >= 0 && r <= 1
1629 && IsPointOnArc (Line->Point1.X + r * dx,
1630 Line->Point1.Y + r * dy,
1631 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1632 return (true);
1633 r = (Radius - r2) / l;
1634 if (r >= 0 && r <= 1
1635 && IsPointOnArc (Line->Point1.X + r * dx,
1636 Line->Point1.Y + r * dy,
1637 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1638 return (true);
1639 /* check arc end points */
1640 box = GetArcEnds (Arc);
1641 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1642 return true;
1643 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1644 return true;
1645 return false;
1648 static int
1649 LOCtoArcLine_callback (const BoxType * b, void *cl)
1651 LineType *line = (LineType *) b;
1652 struct lo_info *i = (struct lo_info *) cl;
1654 if (!TEST_FLAG (TheFlag, line) && LineArcIntersect (line, &i->arc))
1656 if (ADD_LINE_TO_LIST (i->layer, line))
1657 longjmp (i->env, 1);
1659 return 0;
1662 static int
1663 LOCtoArcArc_callback (const BoxType * b, void *cl)
1665 ArcType *arc = (ArcType *) b;
1666 struct lo_info *i = (struct lo_info *) cl;
1668 if (!arc->Thickness)
1669 return 0;
1670 if (!TEST_FLAG (TheFlag, arc) && ArcArcIntersect (&i->arc, arc))
1672 if (ADD_ARC_TO_LIST (i->layer, arc))
1673 longjmp (i->env, 1);
1675 return 0;
1678 static int
1679 LOCtoArcPad_callback (const BoxType * b, void *cl)
1681 PadType *pad = (PadType *) b;
1682 struct lo_info *i = (struct lo_info *) cl;
1684 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1685 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1686 && ArcPadIntersect (&i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1687 longjmp (i->env, 1);
1688 return 0;
1691 /* ---------------------------------------------------------------------------
1692 * searches all LOs that are connected to the given arc on the given
1693 * layergroup. All found connections are added to the list
1695 * the notation that is used is:
1696 * Xij means Xj at arc i
1698 static bool
1699 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup)
1701 Cardinal entry;
1702 struct lo_info info;
1704 info.arc = *Arc;
1705 EXPAND_BOUNDS (&info.arc);
1706 /* loop over all layers of the group */
1707 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1709 Cardinal layer;
1710 GList *i;
1712 layer = PCB->LayerGroups.Entries[LayerGroup][entry];
1714 /* handle normal layers */
1715 if (layer < max_copper_layer)
1717 info.layer = layer;
1718 /* add arcs */
1719 if (setjmp (info.env) == 0)
1720 r_search (LAYER_PTR (layer)->line_tree, &info.arc.BoundingBox,
1721 NULL, LOCtoArcLine_callback, &info);
1722 else
1723 return true;
1725 if (setjmp (info.env) == 0)
1726 r_search (LAYER_PTR (layer)->arc_tree, &info.arc.BoundingBox,
1727 NULL, LOCtoArcArc_callback, &info);
1728 else
1729 return true;
1731 /* now check all polygons */
1732 for (i = PCB->Data->Layer[layer].Polygon;
1733 i != NULL; i = g_list_next (i))
1735 PolygonType *polygon = i->data;
1736 if (!TEST_FLAG (TheFlag, polygon) && IsArcInPolygon (Arc, polygon)
1737 && ADD_POLYGON_TO_LIST (layer, polygon))
1738 return true;
1741 else
1743 info.layer = layer - max_copper_layer;
1744 if (setjmp (info.env) == 0)
1745 r_search (PCB->Data->pad_tree, &info.arc.BoundingBox, NULL,
1746 LOCtoArcPad_callback, &info);
1747 else
1748 return true;
1751 return (false);
1754 static int
1755 LOCtoLineLine_callback (const BoxType * b, void *cl)
1757 LineType *line = (LineType *) b;
1758 struct lo_info *i = (struct lo_info *) cl;
1760 if (!TEST_FLAG (TheFlag, line) && LineLineIntersect (&i->line, line))
1762 if (ADD_LINE_TO_LIST (i->layer, line))
1763 longjmp (i->env, 1);
1765 return 0;
1768 static int
1769 LOCtoLineArc_callback (const BoxType * b, void *cl)
1771 ArcType *arc = (ArcType *) b;
1772 struct lo_info *i = (struct lo_info *) cl;
1774 if (!arc->Thickness)
1775 return 0;
1776 if (!TEST_FLAG (TheFlag, arc) && LineArcIntersect (&i->line, arc))
1778 if (ADD_ARC_TO_LIST (i->layer, arc))
1779 longjmp (i->env, 1);
1781 return 0;
1784 static int
1785 LOCtoLineRat_callback (const BoxType * b, void *cl)
1787 RatType *rat = (RatType *) b;
1788 struct lo_info *i = (struct lo_info *) cl;
1790 if (!TEST_FLAG (TheFlag, rat))
1792 if ((rat->group1 == i->layer)
1793 && IsRatPointOnLineEnd (&rat->Point1, &i->line))
1795 if (ADD_RAT_TO_LIST (rat))
1796 longjmp (i->env, 1);
1798 else if ((rat->group2 == i->layer)
1799 && IsRatPointOnLineEnd (&rat->Point2, &i->line))
1801 if (ADD_RAT_TO_LIST (rat))
1802 longjmp (i->env, 1);
1805 return 0;
1808 static int
1809 LOCtoLinePad_callback (const BoxType * b, void *cl)
1811 PadType *pad = (PadType *) b;
1812 struct lo_info *i = (struct lo_info *) cl;
1814 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1815 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1816 && LinePadIntersect (&i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1817 longjmp (i->env, 1);
1818 return 0;
1821 /* ---------------------------------------------------------------------------
1822 * searches all LOs that are connected to the given line on the given
1823 * layergroup. All found connections are added to the list
1825 * the notation that is used is:
1826 * Xij means Xj at line i
1828 static bool
1829 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup,
1830 bool PolysTo)
1832 Cardinal entry;
1833 struct lo_info info;
1835 info.line = *Line;
1836 info.layer = LayerGroup;
1837 EXPAND_BOUNDS (&info.line)
1838 /* add the new rat lines */
1839 if (setjmp (info.env) == 0)
1840 r_search (PCB->Data->rat_tree, &info.line.BoundingBox, NULL,
1841 LOCtoLineRat_callback, &info);
1842 else
1843 return true;
1845 /* loop over all layers of the group */
1846 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1848 Cardinal layer;
1850 layer = PCB->LayerGroups.Entries[LayerGroup][entry];
1852 /* handle normal layers */
1853 if (layer < max_copper_layer)
1855 info.layer = layer;
1856 /* add lines */
1857 if (setjmp (info.env) == 0)
1858 r_search (LAYER_PTR (layer)->line_tree, (BoxType *) & info.line,
1859 NULL, LOCtoLineLine_callback, &info);
1860 else
1861 return true;
1862 /* add arcs */
1863 if (setjmp (info.env) == 0)
1864 r_search (LAYER_PTR (layer)->arc_tree, (BoxType *) & info.line,
1865 NULL, LOCtoLineArc_callback, &info);
1866 else
1867 return true;
1868 /* now check all polygons */
1869 if (PolysTo)
1871 GList *i;
1872 for (i = PCB->Data->Layer[layer].Polygon;
1873 i != NULL; i = g_list_next (i))
1875 PolygonType *polygon = i->data;
1876 if (!TEST_FLAG
1877 (TheFlag, polygon) && IsLineInPolygon (Line, polygon)
1878 && ADD_POLYGON_TO_LIST (layer, polygon))
1879 return true;
1883 else
1885 /* handle special 'pad' layers */
1886 info.layer = layer - max_copper_layer;
1887 if (setjmp (info.env) == 0)
1888 r_search (PCB->Data->pad_tree, &info.line.BoundingBox, NULL,
1889 LOCtoLinePad_callback, &info);
1890 else
1891 return true;
1894 return (false);
1897 struct rat_info
1899 Cardinal layer;
1900 PointType *Point;
1901 jmp_buf env;
1904 static int
1905 LOCtoRat_callback (const BoxType * b, void *cl)
1907 LineType *line = (LineType *) b;
1908 struct rat_info *i = (struct rat_info *) cl;
1910 if (!TEST_FLAG (TheFlag, line) &&
1911 ((line->Point1.X == i->Point->X &&
1912 line->Point1.Y == i->Point->Y) ||
1913 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y)))
1915 if (ADD_LINE_TO_LIST (i->layer, line))
1916 longjmp (i->env, 1);
1918 return 0;
1920 static int
1921 PolygonToRat_callback (const BoxType * b, void *cl)
1923 PolygonType *polygon = (PolygonType *) b;
1924 struct rat_info *i = (struct rat_info *) cl;
1926 if (!TEST_FLAG (TheFlag, polygon) && polygon->Clipped &&
1927 (i->Point->X == polygon->Clipped->contours->head.point[0]) &&
1928 (i->Point->Y == polygon->Clipped->contours->head.point[1]))
1930 if (ADD_POLYGON_TO_LIST (i->layer, polygon))
1931 longjmp (i->env, 1);
1933 return 0;
1936 static int
1937 LOCtoPad_callback (const BoxType * b, void *cl)
1939 PadType *pad = (PadType *) b;
1940 struct rat_info *i = (struct rat_info *) cl;
1942 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1943 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER) &&
1944 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) ||
1945 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) ||
1946 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X &&
1947 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) &&
1948 ADD_PAD_TO_LIST (i->layer, pad))
1949 longjmp (i->env, 1);
1950 return 0;
1953 /* ---------------------------------------------------------------------------
1954 * searches all LOs that are connected to the given rat-line on the given
1955 * layergroup. All found connections are added to the list
1957 * the notation that is used is:
1958 * Xij means Xj at line i
1960 static bool
1961 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup)
1963 Cardinal entry;
1964 struct rat_info info;
1966 info.Point = Point;
1967 /* loop over all layers of this group */
1968 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1970 Cardinal layer;
1972 layer = PCB->LayerGroups.Entries[LayerGroup][entry];
1973 /* handle normal layers
1974 rats don't ever touch
1975 arcs by definition
1978 if (layer < max_copper_layer)
1980 info.layer = layer;
1981 if (setjmp (info.env) == 0)
1982 r_search_pt (LAYER_PTR (layer)->line_tree, Point, 1, NULL,
1983 LOCtoRat_callback, &info);
1984 else
1985 return true;
1986 if (setjmp (info.env) == 0)
1987 r_search_pt (LAYER_PTR (layer)->polygon_tree, Point, 1,
1988 NULL, PolygonToRat_callback, &info);
1990 else
1992 /* handle special 'pad' layers */
1993 info.layer = layer - max_copper_layer;
1994 if (setjmp (info.env) == 0)
1995 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL,
1996 LOCtoPad_callback, &info);
1997 else
1998 return true;
2001 return (false);
2004 static int
2005 LOCtoPadLine_callback (const BoxType * b, void *cl)
2007 LineType *line = (LineType *) b;
2008 struct lo_info *i = (struct lo_info *) cl;
2010 if (!TEST_FLAG (TheFlag, line) && LinePadIntersect (line, &i->pad))
2012 if (ADD_LINE_TO_LIST (i->layer, line))
2013 longjmp (i->env, 1);
2015 return 0;
2018 static int
2019 LOCtoPadArc_callback (const BoxType * b, void *cl)
2021 ArcType *arc = (ArcType *) b;
2022 struct lo_info *i = (struct lo_info *) cl;
2024 if (!arc->Thickness)
2025 return 0;
2026 if (!TEST_FLAG (TheFlag, arc) && ArcPadIntersect (arc, &i->pad))
2028 if (ADD_ARC_TO_LIST (i->layer, arc))
2029 longjmp (i->env, 1);
2031 return 0;
2034 static int
2035 LOCtoPadPoly_callback (const BoxType * b, void *cl)
2037 PolygonType *polygon = (PolygonType *) b;
2038 struct lo_info *i = (struct lo_info *) cl;
2041 if (!TEST_FLAG (TheFlag, polygon) &&
2042 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad.Clearance))
2044 if (IsPadInPolygon (&i->pad, polygon) &&
2045 ADD_POLYGON_TO_LIST (i->layer, polygon))
2046 longjmp (i->env, 1);
2048 return 0;
2051 static int
2052 LOCtoPadRat_callback (const BoxType * b, void *cl)
2054 RatType *rat = (RatType *) b;
2055 struct lo_info *i = (struct lo_info *) cl;
2057 if (!TEST_FLAG (TheFlag, rat))
2059 if (rat->group1 == i->layer &&
2060 ((rat->Point1.X == i->pad.Point1.X && rat->Point1.Y == i->pad.Point1.Y) ||
2061 (rat->Point1.X == i->pad.Point2.X && rat->Point1.Y == i->pad.Point2.Y) ||
2062 (rat->Point1.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2063 rat->Point1.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2065 if (ADD_RAT_TO_LIST (rat))
2066 longjmp (i->env, 1);
2068 else if (rat->group2 == i->layer &&
2069 ((rat->Point2.X == i->pad.Point1.X && rat->Point2.Y == i->pad.Point1.Y) ||
2070 (rat->Point2.X == i->pad.Point2.X && rat->Point2.Y == i->pad.Point2.Y) ||
2071 (rat->Point2.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2072 rat->Point2.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2074 if (ADD_RAT_TO_LIST (rat))
2075 longjmp (i->env, 1);
2078 return 0;
2081 static int
2082 LOCtoPadPad_callback (const BoxType * b, void *cl)
2084 PadType *pad = (PadType *) b;
2085 struct lo_info *i = (struct lo_info *) cl;
2087 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2088 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2089 && PadPadIntersect (pad, &i->pad) && ADD_PAD_TO_LIST (i->layer, pad))
2090 longjmp (i->env, 1);
2091 return 0;
2094 /* ---------------------------------------------------------------------------
2095 * searches all LOs that are connected to the given pad on the given
2096 * layergroup. All found connections are added to the list
2098 static bool
2099 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup)
2101 Cardinal entry;
2102 struct lo_info info;
2104 if (!TEST_FLAG (SQUAREFLAG, Pad))
2105 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, false));
2107 info.pad = *Pad;
2108 EXPAND_BOUNDS (&info.pad);
2109 /* add the new rat lines */
2110 info.layer = LayerGroup;
2111 if (setjmp (info.env) == 0)
2112 r_search (PCB->Data->rat_tree, &info.pad.BoundingBox, NULL,
2113 LOCtoPadRat_callback, &info);
2114 else
2115 return true;
2117 /* loop over all layers of the group */
2118 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2120 Cardinal layer;
2122 layer = PCB->LayerGroups.Entries[LayerGroup][entry];
2123 /* handle normal layers */
2124 if (layer < max_copper_layer)
2126 info.layer = layer;
2127 /* add lines */
2128 if (setjmp (info.env) == 0)
2129 r_search (LAYER_PTR (layer)->line_tree, &info.pad.BoundingBox,
2130 NULL, LOCtoPadLine_callback, &info);
2131 else
2132 return true;
2133 /* add arcs */
2134 if (setjmp (info.env) == 0)
2135 r_search (LAYER_PTR (layer)->arc_tree, &info.pad.BoundingBox,
2136 NULL, LOCtoPadArc_callback, &info);
2137 else
2138 return true;
2139 /* add polygons */
2140 if (setjmp (info.env) == 0)
2141 r_search (LAYER_PTR (layer)->polygon_tree, &info.pad.BoundingBox,
2142 NULL, LOCtoPadPoly_callback, &info);
2143 else
2144 return true;
2146 else
2148 /* handle special 'pad' layers */
2149 info.layer = layer - max_copper_layer;
2150 if (setjmp (info.env) == 0)
2151 r_search (PCB->Data->pad_tree, (BoxType *) & info.pad, NULL,
2152 LOCtoPadPad_callback, &info);
2153 else
2154 return true;
2158 return (false);
2161 static int
2162 LOCtoPolyLine_callback (const BoxType * b, void *cl)
2164 LineType *line = (LineType *) b;
2165 struct lo_info *i = (struct lo_info *) cl;
2167 if (!TEST_FLAG (TheFlag, line) && IsLineInPolygon (line, &i->polygon))
2169 if (ADD_LINE_TO_LIST (i->layer, line))
2170 longjmp (i->env, 1);
2172 return 0;
2175 static int
2176 LOCtoPolyArc_callback (const BoxType * b, void *cl)
2178 ArcType *arc = (ArcType *) b;
2179 struct lo_info *i = (struct lo_info *) cl;
2181 if (!arc->Thickness)
2182 return 0;
2183 if (!TEST_FLAG (TheFlag, arc) && IsArcInPolygon (arc, &i->polygon))
2185 if (ADD_ARC_TO_LIST (i->layer, arc))
2186 longjmp (i->env, 1);
2188 return 0;
2191 static int
2192 LOCtoPolyPad_callback (const BoxType * b, void *cl)
2194 PadType *pad = (PadType *) b;
2195 struct lo_info *i = (struct lo_info *) cl;
2197 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2198 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2199 && IsPadInPolygon (pad, &i->polygon))
2201 if (ADD_PAD_TO_LIST (i->layer, pad))
2202 longjmp (i->env, 1);
2204 return 0;
2207 static int
2208 LOCtoPolyRat_callback (const BoxType * b, void *cl)
2210 RatType *rat = (RatType *) b;
2211 struct lo_info *i = (struct lo_info *) cl;
2213 if (!TEST_FLAG (TheFlag, rat))
2215 if ((rat->Point1.X == (i->polygon.Clipped->contours->head.point[0]) &&
2216 rat->Point1.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2217 rat->group1 == i->layer) ||
2218 (rat->Point2.X == (i->polygon.Clipped->contours->head.point[0]) &&
2219 rat->Point2.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2220 rat->group2 == i->layer))
2221 if (ADD_RAT_TO_LIST (rat))
2222 longjmp (i->env, 1);
2224 return 0;
2228 /* ---------------------------------------------------------------------------
2229 * looks up LOs that are connected to the given polygon
2230 * on the given layergroup. All found connections are added to the list
2232 static bool
2233 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup)
2235 Cardinal entry;
2236 struct lo_info info;
2238 if (!Polygon->Clipped)
2239 return false;
2240 info.polygon = *Polygon;
2241 EXPAND_BOUNDS (&info.polygon);
2242 info.layer = LayerGroup;
2243 /* check rats */
2244 if (setjmp (info.env) == 0)
2245 r_search (PCB->Data->rat_tree, (BoxType *) & info.polygon, NULL,
2246 LOCtoPolyRat_callback, &info);
2247 else
2248 return true;
2249 /* loop over all layers of the group */
2250 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2252 Cardinal layer;
2254 layer = PCB->LayerGroups.Entries[LayerGroup][entry];
2256 /* handle normal layers */
2257 if (layer < max_copper_layer)
2259 GList *i;
2261 /* check all polygons */
2262 for (i = PCB->Data->Layer[layer].Polygon;
2263 i != NULL; i = g_list_next (i))
2265 PolygonType *polygon = i->data;
2266 if (!TEST_FLAG (TheFlag, polygon)
2267 && IsPolygonInPolygon (polygon, Polygon)
2268 && ADD_POLYGON_TO_LIST (layer, polygon))
2269 return true;
2272 info.layer = layer;
2273 /* check all lines */
2274 if (setjmp (info.env) == 0)
2275 r_search (LAYER_PTR (layer)->line_tree,
2276 (BoxType *) & info.polygon, NULL,
2277 LOCtoPolyLine_callback, &info);
2278 else
2279 return true;
2280 /* check all arcs */
2281 if (setjmp (info.env) == 0)
2282 r_search (LAYER_PTR (layer)->arc_tree, (BoxType *) & info.polygon,
2283 NULL, LOCtoPolyArc_callback, &info);
2284 else
2285 return true;
2287 else
2289 info.layer = layer - max_copper_layer;
2290 if (setjmp (info.env) == 0)
2291 r_search (PCB->Data->pad_tree, (BoxType *) & info.polygon,
2292 NULL, LOCtoPolyPad_callback, &info);
2293 else
2294 return true;
2297 return (false);
2300 /* ---------------------------------------------------------------------------
2301 * checks if an arc has a connection to a polygon
2303 * - first check if the arc can intersect with the polygon by
2304 * evaluating the bounding boxes
2305 * - check the two end points of the arc. If none of them matches
2306 * - check all segments of the polygon against the arc.
2308 static bool
2309 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon)
2311 BoxType *Box = (BoxType *) Arc;
2313 /* arcs with clearance never touch polys */
2314 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc))
2315 return false;
2316 if (!Polygon->Clipped)
2317 return false;
2318 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2319 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2320 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2321 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2323 POLYAREA *ap;
2325 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat)))
2326 return false; /* error */
2327 return isects (ap, Polygon, true);
2329 return false;
2332 /* ---------------------------------------------------------------------------
2333 * checks if a line has a connection to a polygon
2335 * - first check if the line can intersect with the polygon by
2336 * evaluating the bounding boxes
2337 * - check the two end points of the line. If none of them matches
2338 * - check all segments of the polygon against the line.
2340 static bool
2341 IsLineInPolygon (LineType *Line, PolygonType *Polygon)
2343 BoxType *Box = (BoxType *) Line;
2344 POLYAREA *lp;
2346 /* lines with clearance never touch polygons */
2347 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line))
2348 return false;
2349 if (!Polygon->Clipped)
2350 return false;
2351 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y))
2353 Coord wid = (Line->Thickness + Bloat + 1) / 2;
2354 Coord x1, x2, y1, y2;
2356 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid;
2357 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid;
2358 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid;
2359 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid;
2360 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon);
2362 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2363 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2364 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2365 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2367 if (!(lp = LinePoly (Line, Line->Thickness + Bloat)))
2368 return FALSE; /* error */
2369 return isects (lp, Polygon, true);
2371 return false;
2374 /* ---------------------------------------------------------------------------
2375 * checks if a pad connects to a non-clearing polygon
2377 * The polygon is assumed to already have been proven non-clearing
2379 static bool
2380 IsPadInPolygon (PadType *pad, PolygonType *polygon)
2382 return IsLineInPolygon ((LineType *) pad, polygon);
2385 /* ---------------------------------------------------------------------------
2386 * checks if a polygon has a connection to a second one
2388 * First check all points out of P1 against P2 and vice versa.
2389 * If both fail check all lines of P1 against the ones of P2
2391 static bool
2392 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2)
2394 if (!P1->Clipped || !P2->Clipped)
2395 return false;
2396 assert (P1->Clipped->contours);
2397 assert (P2->Clipped->contours);
2399 /* first check if both bounding boxes intersect. If not, return quickly */
2400 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax ||
2401 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin ||
2402 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax ||
2403 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin)
2404 return false;
2406 /* first check un-bloated case */
2407 if (isects (P1->Clipped, P2, false))
2408 return TRUE;
2410 /* now the difficult case of bloated */
2411 if (Bloat > 0)
2413 PLINE *c;
2414 for (c = P1->Clipped->contours; c; c = c->next)
2416 LineType line;
2417 VNODE *v = &c->head;
2418 if (c->xmin - Bloat <= P2->Clipped->contours->xmax &&
2419 c->xmax + Bloat >= P2->Clipped->contours->xmin &&
2420 c->ymin - Bloat <= P2->Clipped->contours->ymax &&
2421 c->ymax + Bloat >= P2->Clipped->contours->ymin)
2424 line.Point1.X = v->point[0];
2425 line.Point1.Y = v->point[1];
2426 line.Thickness = 2 * Bloat;
2427 line.Clearance = 0;
2428 line.Flags = NoFlags ();
2429 for (v = v->next; v != &c->head; v = v->next)
2431 line.Point2.X = v->point[0];
2432 line.Point2.Y = v->point[1];
2433 SetLineBoundingBox (&line);
2434 if (IsLineInPolygon (&line, P2))
2435 return (true);
2436 line.Point1.X = line.Point2.X;
2437 line.Point1.Y = line.Point2.Y;
2443 return (false);
2446 /* ---------------------------------------------------------------------------
2447 * writes the several names of an element to a file
2449 static void
2450 PrintElementNameList (ElementType *Element, FILE * FP)
2452 static DynamicStringType cname, pname, vname;
2454 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element)));
2455 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element)));
2456 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element)));
2457 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data);
2460 /* ---------------------------------------------------------------------------
2461 * writes the several names of an element to a file
2463 static void
2464 PrintConnectionElementName (ElementType *Element, FILE * FP)
2466 fputs ("Element", FP);
2467 PrintElementNameList (Element, FP);
2468 fputs ("{\n", FP);
2471 /* ---------------------------------------------------------------------------
2472 * prints one {pin,pad,via}/element entry of connection lists
2474 static void
2475 PrintConnectionListEntry (char *ObjName, ElementType *Element,
2476 bool FirstOne, FILE * FP)
2478 static DynamicStringType oname;
2480 CreateQuotedString (&oname, ObjName);
2481 if (FirstOne)
2482 fprintf (FP, "\t%s\n\t{\n", oname.Data);
2483 else
2485 fprintf (FP, "\t\t%s ", oname.Data);
2486 if (Element)
2487 PrintElementNameList (Element, FP);
2488 else
2489 fputs ("(__VIA__)\n", FP);
2493 /* ---------------------------------------------------------------------------
2494 * prints all found connections of a pads to file FP
2495 * the connections are stacked in 'PadList'
2497 static void
2498 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst)
2500 Cardinal i;
2501 PadType *ptr;
2503 if (!PadList[Layer].Number)
2504 return;
2506 /* the starting pad */
2507 if (IsFirst)
2509 ptr = PADLIST_ENTRY (Layer, 0);
2510 if (ptr != NULL)
2511 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP);
2512 else
2513 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2516 /* we maybe have to start with i=1 if we are handling the
2517 * starting-pad itself
2519 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++)
2521 ptr = PADLIST_ENTRY (Layer, i);
2522 if (ptr != NULL)
2523 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP);
2524 else
2525 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2529 /* ---------------------------------------------------------------------------
2530 * prints all found connections of a pin to file FP
2531 * the connections are stacked in 'PVList'
2533 static void
2534 PrintPinConnections (FILE * FP, bool IsFirst)
2536 Cardinal i;
2537 PinType *pv;
2539 if (!PVList.Number)
2540 return;
2542 if (IsFirst)
2544 /* the starting pin */
2545 pv = PVLIST_ENTRY (0);
2546 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP);
2549 /* we maybe have to start with i=1 if we are handling the
2550 * starting-pin itself
2552 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++)
2554 /* get the elements name or assume that its a via */
2555 pv = PVLIST_ENTRY (i);
2556 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP);
2560 /* ---------------------------------------------------------------------------
2561 * checks if all lists of new objects are handled
2563 static bool
2564 ListsEmpty (bool AndRats)
2566 bool empty;
2567 int i;
2569 empty = (PVList.Location >= PVList.Number);
2570 if (AndRats)
2571 empty = empty && (RatList.Location >= RatList.Number);
2572 for (i = 0; i < max_copper_layer && empty; i++)
2573 if (!LAYER_PTR (i)->no_drc)
2574 empty = empty && LineList[i].Location >= LineList[i].Number
2575 && ArcList[i].Location >= ArcList[i].Number
2576 && PolygonList[i].Location >= PolygonList[i].Number;
2577 return (empty);
2580 static void
2581 reassign_no_drc_flags (void)
2583 int layer;
2585 for (layer = 0; layer < max_copper_layer; layer++)
2587 LayerType *l = LAYER_PTR (layer);
2588 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL;
2595 /* ---------------------------------------------------------------------------
2596 * loops till no more connections are found
2598 static bool
2599 DoIt (bool AndRats, bool AndDraw)
2601 bool newone = false;
2602 reassign_no_drc_flags ();
2605 /* lookup connections; these are the steps (2) to (4)
2606 * from the description
2608 newone = LookupPVConnectionsToPVList () ||
2609 LookupLOConnectionsToPVList (AndRats) ||
2610 LookupLOConnectionsToLOList (AndRats) ||
2611 LookupPVConnectionsToLOList (AndRats);
2612 if (AndDraw)
2613 DrawNewConnections ();
2615 while (!newone && !ListsEmpty (AndRats));
2616 if (AndDraw)
2617 Draw ();
2618 return (newone);
2621 /* ---------------------------------------------------------------------------
2622 * prints all unused pins of an element to file FP
2624 static bool
2625 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP)
2627 bool first = true;
2628 Cardinal number;
2629 static DynamicStringType oname;
2631 /* check all pins in element */
2633 PIN_LOOP (Element);
2635 if (!TEST_FLAG (HOLEFLAG, pin))
2637 /* pin might have bee checked before, add to list if not */
2638 if (!TEST_FLAG (TheFlag, pin) && FP)
2640 int i;
2641 if (ADD_PV_TO_LIST (pin))
2642 return true;
2643 DoIt (true, true);
2644 number = PadList[COMPONENT_LAYER].Number
2645 + PadList[SOLDER_LAYER].Number + PVList.Number;
2646 /* the pin has no connection if it's the only
2647 * list entry; don't count vias
2649 for (i = 0; i < PVList.Number; i++)
2650 if (!PVLIST_ENTRY (i)->Element)
2651 number--;
2652 if (number == 1)
2654 /* output of element name if not already done */
2655 if (first)
2657 PrintConnectionElementName (Element, FP);
2658 first = false;
2661 /* write name to list and draw selected object */
2662 CreateQuotedString (&oname, (char *)EMPTY (pin->Name));
2663 fprintf (FP, "\t%s\n", oname.Data);
2664 SET_FLAG (SELECTEDFLAG, pin);
2665 DrawPin (pin);
2668 /* reset found objects for the next pin */
2669 if (PrepareNextLoop (FP))
2670 return (true);
2674 END_LOOP;
2676 /* check all pads in element */
2677 PAD_LOOP (Element);
2679 /* lookup pad in list */
2680 /* pad might has bee checked before, add to list if not */
2681 if (!TEST_FLAG (TheFlag, pad) && FP)
2683 int i;
2684 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad)
2685 ? SOLDER_LAYER : COMPONENT_LAYER, pad))
2686 return true;
2687 DoIt (true, true);
2688 number = PadList[COMPONENT_LAYER].Number
2689 + PadList[SOLDER_LAYER].Number + PVList.Number;
2690 /* the pin has no connection if it's the only
2691 * list entry; don't count vias
2693 for (i = 0; i < PVList.Number; i++)
2694 if (!PVLIST_ENTRY (i)->Element)
2695 number--;
2696 if (number == 1)
2698 /* output of element name if not already done */
2699 if (first)
2701 PrintConnectionElementName (Element, FP);
2702 first = false;
2705 /* write name to list and draw selected object */
2706 CreateQuotedString (&oname, (char *)EMPTY (pad->Name));
2707 fprintf (FP, "\t%s\n", oname.Data);
2708 SET_FLAG (SELECTEDFLAG, pad);
2709 DrawPad (pad);
2712 /* reset found objects for the next pin */
2713 if (PrepareNextLoop (FP))
2714 return (true);
2717 END_LOOP;
2719 /* print separator if element has unused pins or pads */
2720 if (!first)
2722 fputs ("}\n\n", FP);
2723 SEPARATE (FP);
2725 return (false);
2728 /* ---------------------------------------------------------------------------
2729 * resets some flags for looking up the next pin/pad
2731 static bool
2732 PrepareNextLoop (FILE * FP)
2734 Cardinal layer;
2736 /* reset found LOs for the next pin */
2737 for (layer = 0; layer < max_copper_layer; layer++)
2739 LineList[layer].Location = LineList[layer].Number = 0;
2740 ArcList[layer].Location = ArcList[layer].Number = 0;
2741 PolygonList[layer].Location = PolygonList[layer].Number = 0;
2744 /* reset found pads */
2745 for (layer = 0; layer < 2; layer++)
2746 PadList[layer].Location = PadList[layer].Number = 0;
2748 /* reset PVs */
2749 PVList.Number = PVList.Location = 0;
2750 RatList.Number = RatList.Location = 0;
2752 return (false);
2755 /* ---------------------------------------------------------------------------
2756 * finds all connections to the pins of the passed element.
2757 * The result is written to file FP
2758 * Returns true if operation was aborted
2760 static bool
2761 PrintElementConnections (ElementType *Element, FILE * FP, bool AndDraw)
2763 PrintConnectionElementName (Element, FP);
2765 /* check all pins in element */
2766 PIN_LOOP (Element);
2768 /* pin might have been checked before, add to list if not */
2769 if (TEST_FLAG (TheFlag, pin))
2771 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP);
2772 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2773 continue;
2775 if (ADD_PV_TO_LIST (pin))
2776 return true;
2777 DoIt (true, AndDraw);
2778 /* printout all found connections */
2779 PrintPinConnections (FP, true);
2780 PrintPadConnections (COMPONENT_LAYER, FP, false);
2781 PrintPadConnections (SOLDER_LAYER, FP, false);
2782 fputs ("\t}\n", FP);
2783 if (PrepareNextLoop (FP))
2784 return (true);
2786 END_LOOP;
2788 /* check all pads in element */
2789 PAD_LOOP (Element);
2791 Cardinal layer;
2792 /* pad might have been checked before, add to list if not */
2793 if (TEST_FLAG (TheFlag, pad))
2795 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP);
2796 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2797 continue;
2799 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER;
2800 if (ADD_PAD_TO_LIST (layer, pad))
2801 return true;
2802 DoIt (true, AndDraw);
2803 /* print all found connections */
2804 PrintPadConnections (layer, FP, true);
2805 PrintPadConnections (layer ==
2806 (COMPONENT_LAYER ? SOLDER_LAYER : COMPONENT_LAYER),
2807 FP, false);
2808 PrintPinConnections (FP, false);
2809 fputs ("\t}\n", FP);
2810 if (PrepareNextLoop (FP))
2811 return (true);
2813 END_LOOP;
2814 fputs ("}\n\n", FP);
2815 return (false);
2818 /* ---------------------------------------------------------------------------
2819 * draws all new connections which have been found since the
2820 * routine was called the last time
2822 static void
2823 DrawNewConnections (void)
2825 int i;
2826 Cardinal position;
2828 /* decrement 'i' to keep layerstack order */
2829 for (i = max_copper_layer - 1; i != -1; i--)
2831 Cardinal layer = LayerStack[i];
2833 if (PCB->Data->Layer[layer].On)
2835 /* draw all new lines */
2836 position = LineList[layer].DrawLocation;
2837 for (; position < LineList[layer].Number; position++)
2838 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position));
2839 LineList[layer].DrawLocation = LineList[layer].Number;
2841 /* draw all new arcs */
2842 position = ArcList[layer].DrawLocation;
2843 for (; position < ArcList[layer].Number; position++)
2844 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position));
2845 ArcList[layer].DrawLocation = ArcList[layer].Number;
2847 /* draw all new polygons */
2848 position = PolygonList[layer].DrawLocation;
2849 for (; position < PolygonList[layer].Number; position++)
2850 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position));
2851 PolygonList[layer].DrawLocation = PolygonList[layer].Number;
2855 /* draw all new pads */
2856 if (PCB->PinOn)
2857 for (i = 0; i < 2; i++)
2859 position = PadList[i].DrawLocation;
2861 for (; position < PadList[i].Number; position++)
2862 DrawPad (PADLIST_ENTRY (i, position));
2863 PadList[i].DrawLocation = PadList[i].Number;
2866 /* draw all new PVs; 'PVList' holds a list of pointers to the
2867 * sorted array pointers to PV data
2869 while (PVList.DrawLocation < PVList.Number)
2871 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation);
2873 if (TEST_FLAG (PINFLAG, pv))
2875 if (PCB->PinOn)
2876 DrawPin (pv);
2878 else if (PCB->ViaOn)
2879 DrawVia (pv);
2880 PVList.DrawLocation++;
2882 /* draw the new rat-lines */
2883 if (PCB->RatOn)
2885 position = RatList.DrawLocation;
2886 for (; position < RatList.Number; position++)
2887 DrawRat (RATLIST_ENTRY (position));
2888 RatList.DrawLocation = RatList.Number;
2892 /* ---------------------------------------------------------------------------
2893 * find all connections to pins within one element
2895 void
2896 LookupElementConnections (ElementType *Element, FILE * FP)
2898 /* reset all currently marked connections */
2899 User = true;
2900 TheFlag = FOUNDFLAG;
2901 ClearFlagOnAllObjects (true, FOUNDFLAG);
2902 InitConnectionLookup ();
2903 PrintElementConnections (Element, FP, true);
2904 SetChangedFlag (true);
2905 if (Settings.RingBellWhenFinished)
2906 gui->beep ();
2907 FreeConnectionLookupMemory ();
2908 IncrementUndoSerialNumber ();
2909 User = false;
2910 Draw ();
2913 /* ---------------------------------------------------------------------------
2914 * find all connections to pins of all element
2916 void
2917 LookupConnectionsToAllElements (FILE * FP)
2919 /* reset all currently marked connections */
2920 User = false;
2921 TheFlag = FOUNDFLAG;
2922 ClearFlagOnAllObjects (false, FOUNDFLAG);
2923 InitConnectionLookup ();
2925 ELEMENT_LOOP (PCB->Data);
2927 /* break if abort dialog returned true */
2928 if (PrintElementConnections (element, FP, false))
2929 break;
2930 SEPARATE (FP);
2931 if (Settings.ResetAfterElement && n != 1)
2932 ClearFlagOnAllObjects (false, FOUNDFLAG);
2934 END_LOOP;
2935 if (Settings.RingBellWhenFinished)
2936 gui->beep ();
2937 ClearFlagOnAllObjects (false, FOUNDFLAG);
2938 FreeConnectionLookupMemory ();
2939 Redraw ();
2942 /*---------------------------------------------------------------------------
2943 * add the starting object to the list of found objects
2945 static bool
2946 ListStart (int type, void *ptr1, void *ptr2, void *ptr3)
2948 DumpList ();
2949 switch (type)
2951 case PIN_TYPE:
2952 case VIA_TYPE:
2954 if (ADD_PV_TO_LIST ((PinType *) ptr2))
2955 return true;
2956 break;
2959 case RATLINE_TYPE:
2961 if (ADD_RAT_TO_LIST ((RatType *) ptr1))
2962 return true;
2963 break;
2966 case LINE_TYPE:
2968 int layer = GetLayerNumber (PCB->Data,
2969 (LayerType *) ptr1);
2971 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2))
2972 return true;
2973 break;
2976 case ARC_TYPE:
2978 int layer = GetLayerNumber (PCB->Data,
2979 (LayerType *) ptr1);
2981 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2))
2982 return true;
2983 break;
2986 case POLYGON_TYPE:
2988 int layer = GetLayerNumber (PCB->Data,
2989 (LayerType *) ptr1);
2991 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2))
2992 return true;
2993 break;
2996 case PAD_TYPE:
2998 PadType *pad = (PadType *) ptr2;
2999 if (ADD_PAD_TO_LIST
3000 (TEST_FLAG
3001 (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER, pad))
3002 return true;
3003 break;
3006 return (false);
3010 /* ---------------------------------------------------------------------------
3011 * looks up all connections from the object at the given coordinates
3012 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3013 * the objects are re-drawn if AndDraw is true
3014 * also the action is marked as undoable if AndDraw is true
3016 void
3017 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int which_flag,
3018 bool AndRats)
3020 void *ptr1, *ptr2, *ptr3;
3021 char *name;
3022 int type;
3024 /* check if there are any pins or pads at that position */
3026 reassign_no_drc_flags ();
3028 type
3029 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range);
3030 if (type == NO_TYPE)
3032 type = SearchObjectByLocation (
3033 LOOKUP_MORE & ~(AndRats ? RATLINE_TYPE : 0),
3034 &ptr1, &ptr2, &ptr3, X, Y, Range);
3035 if (type == NO_TYPE)
3036 return;
3037 if (type & SILK_TYPE)
3039 int laynum = GetLayerNumber (PCB->Data,
3040 (LayerType *) ptr1);
3042 /* don't mess with non-conducting objects! */
3043 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc)
3044 return;
3048 name = ConnectionName (type, ptr1, ptr2);
3049 hid_actionl ("NetlistShow", name, NULL);
3051 TheFlag = which_flag;
3052 User = AndDraw;
3053 InitConnectionLookup ();
3055 /* now add the object to the appropriate list and start scanning
3056 * This is step (1) from the description
3058 ListStart (type, ptr1, ptr2, ptr3);
3059 DoIt (AndRats, AndDraw);
3060 if (User)
3061 IncrementUndoSerialNumber ();
3062 User = false;
3064 /* we are done */
3065 if (AndDraw)
3066 Draw ();
3067 if (AndDraw && Settings.RingBellWhenFinished)
3068 gui->beep ();
3069 FreeConnectionLookupMemory ();
3072 /* ---------------------------------------------------------------------------
3073 * find connections for rats nesting
3074 * assumes InitConnectionLookup() has already been done
3076 void
3077 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3,
3078 bool undo, int flag, bool AndRats)
3080 User = undo;
3081 TheFlag = flag;
3082 DumpList ();
3083 ListStart (type, ptr1, ptr2, ptr3);
3084 DoIt (AndRats, false);
3085 User = false;
3088 /* ---------------------------------------------------------------------------
3089 * find all unused pins of all element
3091 void
3092 LookupUnusedPins (FILE * FP)
3094 /* reset all currently marked connections */
3095 User = true;
3096 TheFlag = FOUNDFLAG;
3097 ClearFlagOnAllObjects (true, FOUNDFLAG);
3098 InitConnectionLookup ();
3100 ELEMENT_LOOP (PCB->Data);
3102 /* break if abort dialog returned true;
3103 * passing NULL as filedescriptor discards the normal output
3105 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP))
3106 break;
3108 END_LOOP;
3110 if (Settings.RingBellWhenFinished)
3111 gui->beep ();
3112 FreeConnectionLookupMemory ();
3113 IncrementUndoSerialNumber ();
3114 User = false;
3115 Draw ();
3118 /* ---------------------------------------------------------------------------
3119 * resets all used flags of pins and vias
3121 bool
3122 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag)
3124 bool change = false;
3126 VIA_LOOP (PCB->Data);
3128 if (TEST_FLAG (flag, via))
3130 if (AndDraw)
3131 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3132 CLEAR_FLAG (flag, via);
3133 if (AndDraw)
3134 DrawVia (via);
3135 change = true;
3138 END_LOOP;
3139 ELEMENT_LOOP (PCB->Data);
3141 PIN_LOOP (element);
3143 if (TEST_FLAG (flag, pin))
3145 if (AndDraw)
3146 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3147 CLEAR_FLAG (flag, pin);
3148 if (AndDraw)
3149 DrawPin (pin);
3150 change = true;
3153 END_LOOP;
3154 PAD_LOOP (element);
3156 if (TEST_FLAG (flag, pad))
3158 if (AndDraw)
3159 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3160 CLEAR_FLAG (flag, pad);
3161 if (AndDraw)
3162 DrawPad (pad);
3163 change = true;
3166 END_LOOP;
3168 END_LOOP;
3169 if (change)
3170 SetChangedFlag (true);
3171 return change;
3174 /* ---------------------------------------------------------------------------
3175 * resets all used flags of LOs
3177 bool
3178 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag)
3180 bool change = false;
3182 RAT_LOOP (PCB->Data);
3184 if (TEST_FLAG (flag, line))
3186 if (AndDraw)
3187 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
3188 CLEAR_FLAG (flag, line);
3189 if (AndDraw)
3190 DrawRat (line);
3191 change = true;
3194 END_LOOP;
3195 COPPERLINE_LOOP (PCB->Data);
3197 if (TEST_FLAG (flag, line))
3199 if (AndDraw)
3200 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3201 CLEAR_FLAG (flag, line);
3202 if (AndDraw)
3203 DrawLine (layer, line);
3204 change = true;
3207 ENDALL_LOOP;
3208 COPPERARC_LOOP (PCB->Data);
3210 if (TEST_FLAG (flag, arc))
3212 if (AndDraw)
3213 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3214 CLEAR_FLAG (flag, arc);
3215 if (AndDraw)
3216 DrawArc (layer, arc);
3217 change = true;
3220 ENDALL_LOOP;
3221 COPPERPOLYGON_LOOP (PCB->Data);
3223 if (TEST_FLAG (flag, polygon))
3225 if (AndDraw)
3226 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3227 CLEAR_FLAG (flag, polygon);
3228 if (AndDraw)
3229 DrawPolygon (layer, polygon);
3230 change = true;
3233 ENDALL_LOOP;
3234 if (change)
3235 SetChangedFlag (true);
3236 return change;
3239 /* ---------------------------------------------------------------------------
3240 * resets all found connections
3242 bool
3243 ClearFlagOnAllObjects (bool AndDraw, int flag)
3245 bool change = false;
3247 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change;
3248 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change;
3250 return change;
3253 /*----------------------------------------------------------------------------
3254 * Dumps the list contents
3256 static void
3257 DumpList (void)
3259 Cardinal i;
3261 for (i = 0; i < 2; i++)
3263 PadList[i].Number = 0;
3264 PadList[i].Location = 0;
3265 PadList[i].DrawLocation = 0;
3268 PVList.Number = 0;
3269 PVList.Location = 0;
3271 for (i = 0; i < max_copper_layer; i++)
3273 LineList[i].Location = 0;
3274 LineList[i].DrawLocation = 0;
3275 LineList[i].Number = 0;
3276 ArcList[i].Location = 0;
3277 ArcList[i].DrawLocation = 0;
3278 ArcList[i].Number = 0;
3279 PolygonList[i].Location = 0;
3280 PolygonList[i].DrawLocation = 0;
3281 PolygonList[i].Number = 0;
3283 RatList.Number = 0;
3284 RatList.Location = 0;
3285 RatList.DrawLocation = 0;
3288 /*-----------------------------------------------------------------------------
3289 * Check for DRC violations on a single net starting from the pad or pin
3290 * sees if the connectivity changes when everything is bloated, or shrunk
3292 static bool
3293 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
3295 Coord x, y;
3296 int object_count;
3297 long int *object_id_list;
3298 int *object_type_list;
3299 DrcViolationType *violation;
3301 if (PCB->Shrink != 0)
3303 Bloat = -PCB->Shrink;
3304 TheFlag = DRCFLAG | SELECTEDFLAG;
3305 ListStart (What, ptr1, ptr2, ptr3);
3306 DoIt (true, false);
3307 /* ok now the shrunk net has the SELECTEDFLAG set */
3308 DumpList ();
3309 TheFlag = FOUNDFLAG;
3310 ListStart (What, ptr1, ptr2, ptr3);
3311 Bloat = 0;
3312 drc = true; /* abort the search if we find anything not already found */
3313 if (DoIt (true, false))
3315 DumpList ();
3316 /* make the flag changes undoable */
3317 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3318 ClearFlagOnAllObjects (false, TheFlag);
3319 User = true;
3320 drc = false;
3321 Bloat = -PCB->Shrink;
3322 TheFlag = SELECTEDFLAG;
3323 ListStart (What, ptr1, ptr2, ptr3);
3324 DoIt (true, true);
3325 DumpList ();
3326 ListStart (What, ptr1, ptr2, ptr3);
3327 TheFlag = FOUNDFLAG;
3328 Bloat = 0;
3329 drc = true;
3330 DoIt (true, true);
3331 DumpList ();
3332 User = false;
3333 drc = false;
3334 drcerr_count++;
3335 LocateError (&x, &y);
3336 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3337 violation = pcb_drc_violation_new (_("Potential for broken trace"),
3338 _("Insufficient overlap between objects can lead to broken tracks\n"
3339 "due to registration errors with old wheel style photo-plotters."),
3340 x, y,
3341 0, /* ANGLE OF ERROR UNKNOWN */
3342 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3343 0, /* MAGNITUDE OF ERROR UNKNOWN */
3344 PCB->Shrink,
3345 object_count,
3346 object_id_list,
3347 object_type_list);
3348 append_drc_violation (violation);
3349 pcb_drc_violation_free (violation);
3350 free (object_id_list);
3351 free (object_type_list);
3353 if (!throw_drc_dialog())
3354 return (true);
3355 IncrementUndoSerialNumber ();
3356 Undo (true);
3358 DumpList ();
3360 /* now check the bloated condition */
3361 drc = false;
3362 ClearFlagOnAllObjects (false, TheFlag);
3363 TheFlag = FOUNDFLAG;
3364 ListStart (What, ptr1, ptr2, ptr3);
3365 Bloat = PCB->Bloat;
3366 drc = true;
3367 while (DoIt (true, false))
3369 DumpList ();
3370 /* make the flag changes undoable */
3371 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3372 ClearFlagOnAllObjects (false, TheFlag);
3373 User = true;
3374 drc = false;
3375 Bloat = 0;
3376 TheFlag = SELECTEDFLAG;
3377 ListStart (What, ptr1, ptr2, ptr3);
3378 DoIt (true, true);
3379 DumpList ();
3380 TheFlag = FOUNDFLAG;
3381 ListStart (What, ptr1, ptr2, ptr3);
3382 Bloat = PCB->Bloat;
3383 drc = true;
3384 DoIt (true, true);
3385 DumpList ();
3386 drcerr_count++;
3387 LocateError (&x, &y);
3388 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3389 violation = pcb_drc_violation_new (_("Copper areas too close"),
3390 _("Circuits that are too close may bridge during imaging, etching,\n"
3391 "plating, or soldering processes resulting in a direct short."),
3392 x, y,
3393 0, /* ANGLE OF ERROR UNKNOWN */
3394 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3395 0, /* MAGNITUDE OF ERROR UNKNOWN */
3396 PCB->Bloat,
3397 object_count,
3398 object_id_list,
3399 object_type_list);
3400 append_drc_violation (violation);
3401 pcb_drc_violation_free (violation);
3402 free (object_id_list);
3403 free (object_type_list);
3404 User = false;
3405 drc = false;
3406 if (!throw_drc_dialog())
3407 return (true);
3408 IncrementUndoSerialNumber ();
3409 Undo (true);
3410 /* highlight the rest of the encroaching net so it's not reported again */
3411 TheFlag |= SELECTEDFLAG;
3412 Bloat = 0;
3413 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3);
3414 DoIt (true, true);
3415 DumpList ();
3416 drc = true;
3417 Bloat = PCB->Bloat;
3418 ListStart (What, ptr1, ptr2, ptr3);
3420 drc = false;
3421 DumpList ();
3422 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3423 ClearFlagOnAllObjects (false, TheFlag);
3424 return (false);
3427 /* DRC clearance callback */
3429 static int
3430 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon,
3431 int type, void *ptr1, void *ptr2)
3433 char *message;
3434 Coord x, y;
3435 int object_count;
3436 long int *object_id_list;
3437 int *object_type_list;
3438 DrcViolationType *violation;
3440 LineType *line = (LineType *) ptr2;
3441 ArcType *arc = (ArcType *) ptr2;
3442 PinType *pin = (PinType *) ptr2;
3443 PadType *pad = (PadType *) ptr2;
3445 thing_type = type;
3446 thing_ptr1 = ptr1;
3447 thing_ptr2 = ptr2;
3448 thing_ptr3 = ptr2;
3449 switch (type)
3451 case LINE_TYPE:
3452 if (line->Clearance < 2 * PCB->Bloat)
3454 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3455 SET_FLAG (TheFlag, line);
3456 message = _("Line with insufficient clearance inside polygon\n");
3457 goto doIsBad;
3459 break;
3460 case ARC_TYPE:
3461 if (arc->Clearance < 2 * PCB->Bloat)
3463 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3464 SET_FLAG (TheFlag, arc);
3465 message = _("Arc with insufficient clearance inside polygon\n");
3466 goto doIsBad;
3468 break;
3469 case PAD_TYPE:
3470 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
3471 if (IsPadInPolygon(pad,polygon))
3473 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3474 SET_FLAG (TheFlag, pad);
3475 message = _("Pad with insufficient clearance inside polygon\n");
3476 goto doIsBad;
3478 break;
3479 case PIN_TYPE:
3480 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3482 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3483 SET_FLAG (TheFlag, pin);
3484 message = _("Pin with insufficient clearance inside polygon\n");
3485 goto doIsBad;
3487 break;
3488 case VIA_TYPE:
3489 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3491 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3492 SET_FLAG (TheFlag, pin);
3493 message = _("Via with insufficient clearance inside polygon\n");
3494 goto doIsBad;
3496 break;
3497 default:
3498 Message ("hace: Bad Plow object in callback\n");
3500 return 0;
3502 doIsBad:
3503 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3504 SET_FLAG (FOUNDFLAG, polygon);
3505 DrawPolygon (layer, polygon);
3506 DrawObject (type, ptr1, ptr2);
3507 drcerr_count++;
3508 LocateError (&x, &y);
3509 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3510 violation = pcb_drc_violation_new (message,
3511 _("Circuits that are too close may bridge during imaging, etching,\n"
3512 "plating, or soldering processes resulting in a direct short."),
3513 x, y,
3514 0, /* ANGLE OF ERROR UNKNOWN */
3515 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3516 0, /* MAGNITUDE OF ERROR UNKNOWN */
3517 PCB->Bloat,
3518 object_count,
3519 object_id_list,
3520 object_type_list);
3521 append_drc_violation (violation);
3522 pcb_drc_violation_free (violation);
3523 free (object_id_list);
3524 free (object_type_list);
3525 if (!throw_drc_dialog())
3527 IsBad = true;
3528 return 1;
3530 IncrementUndoSerialNumber ();
3531 Undo (true);
3532 return 0;
3535 /*-----------------------------------------------------------------------------
3536 * Check for DRC violations
3537 * see if the connectivity changes when everything is bloated, or shrunk
3540 DRCAll (void)
3542 Coord x, y;
3543 int object_count;
3544 long int *object_id_list;
3545 int *object_type_list;
3546 DrcViolationType *violation;
3547 int tmpcnt;
3548 int nopastecnt = 0;
3550 reset_drc_dialog_message();
3552 IsBad = false;
3553 drcerr_count = 0;
3554 SaveStackAndVisibility ();
3555 ResetStackAndVisibility ();
3556 hid_action ("LayersChanged");
3557 InitConnectionLookup ();
3559 TheFlag = FOUNDFLAG | DRCFLAG | SELECTEDFLAG;
3561 if (ClearFlagOnAllObjects (true, TheFlag))
3563 IncrementUndoSerialNumber ();
3564 Draw ();
3567 User = false;
3569 ELEMENT_LOOP (PCB->Data);
3571 PIN_LOOP (element);
3573 if (!TEST_FLAG (DRCFLAG, pin)
3574 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin))
3576 IsBad = true;
3577 break;
3580 END_LOOP;
3581 if (IsBad)
3582 break;
3583 PAD_LOOP (element);
3586 /* count up how many pads have no solderpaste openings */
3587 if (TEST_FLAG (NOPASTEFLAG, pad))
3588 nopastecnt++;
3590 if (!TEST_FLAG (DRCFLAG, pad)
3591 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad))
3593 IsBad = true;
3594 break;
3597 END_LOOP;
3598 if (IsBad)
3599 break;
3601 END_LOOP;
3602 if (!IsBad)
3603 VIA_LOOP (PCB->Data);
3605 if (!TEST_FLAG (DRCFLAG, via)
3606 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via))
3608 IsBad = true;
3609 break;
3612 END_LOOP;
3614 TheFlag = (IsBad) ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG);
3615 ClearFlagOnAllObjects (false, TheFlag);
3616 TheFlag = SELECTEDFLAG;
3617 /* check minimum widths and polygon clearances */
3618 if (!IsBad)
3620 COPPERLINE_LOOP (PCB->Data);
3622 /* check line clearances in polygons */
3623 PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback);
3624 if (IsBad)
3625 break;
3626 if (line->Thickness < PCB->minWid)
3628 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3629 SET_FLAG (TheFlag, line);
3630 DrawLine (layer, line);
3631 drcerr_count++;
3632 SetThing (LINE_TYPE, layer, line, line);
3633 LocateError (&x, &y);
3634 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3635 violation = pcb_drc_violation_new (_("Line width is too thin"),
3636 _("Process specifications dictate a minimum feature-width\n"
3637 "that can reliably be reproduced"),
3638 x, y,
3639 0, /* ANGLE OF ERROR UNKNOWN */
3640 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3641 line->Thickness,
3642 PCB->minWid,
3643 object_count,
3644 object_id_list,
3645 object_type_list);
3646 append_drc_violation (violation);
3647 pcb_drc_violation_free (violation);
3648 free (object_id_list);
3649 free (object_type_list);
3650 if (!throw_drc_dialog())
3652 IsBad = true;
3653 break;
3655 IncrementUndoSerialNumber ();
3656 Undo (false);
3659 ENDALL_LOOP;
3661 if (!IsBad)
3663 COPPERARC_LOOP (PCB->Data);
3665 PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback);
3666 if (IsBad)
3667 break;
3668 if (arc->Thickness < PCB->minWid)
3670 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3671 SET_FLAG (TheFlag, arc);
3672 DrawArc (layer, arc);
3673 drcerr_count++;
3674 SetThing (ARC_TYPE, layer, arc, arc);
3675 LocateError (&x, &y);
3676 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3677 violation = pcb_drc_violation_new (_("Arc width is too thin"),
3678 _("Process specifications dictate a minimum feature-width\n"
3679 "that can reliably be reproduced"),
3680 x, y,
3681 0, /* ANGLE OF ERROR UNKNOWN */
3682 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3683 arc->Thickness,
3684 PCB->minWid,
3685 object_count,
3686 object_id_list,
3687 object_type_list);
3688 append_drc_violation (violation);
3689 pcb_drc_violation_free (violation);
3690 free (object_id_list);
3691 free (object_type_list);
3692 if (!throw_drc_dialog())
3694 IsBad = true;
3695 break;
3697 IncrementUndoSerialNumber ();
3698 Undo (false);
3701 ENDALL_LOOP;
3703 if (!IsBad)
3705 ALLPIN_LOOP (PCB->Data);
3707 PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback);
3708 if (IsBad)
3709 break;
3710 if (!TEST_FLAG (HOLEFLAG, pin) &&
3711 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing)
3713 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3714 SET_FLAG (TheFlag, pin);
3715 DrawPin (pin);
3716 drcerr_count++;
3717 SetThing (PIN_TYPE, element, pin, pin);
3718 LocateError (&x, &y);
3719 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3720 violation = pcb_drc_violation_new (_("Pin annular ring too small"),
3721 _("Annular rings that are too small may erode during etching,\n"
3722 "resulting in a broken connection"),
3723 x, y,
3724 0, /* ANGLE OF ERROR UNKNOWN */
3725 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3726 (pin->Thickness - pin->DrillingHole) / 2,
3727 PCB->minRing,
3728 object_count,
3729 object_id_list,
3730 object_type_list);
3731 append_drc_violation (violation);
3732 pcb_drc_violation_free (violation);
3733 free (object_id_list);
3734 free (object_type_list);
3735 if (!throw_drc_dialog())
3737 IsBad = true;
3738 break;
3740 IncrementUndoSerialNumber ();
3741 Undo (false);
3743 if (pin->DrillingHole < PCB->minDrill)
3745 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3746 SET_FLAG (TheFlag, pin);
3747 DrawPin (pin);
3748 drcerr_count++;
3749 SetThing (PIN_TYPE, element, pin, pin);
3750 LocateError (&x, &y);
3751 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3752 violation = pcb_drc_violation_new (_("Pin drill size is too small"),
3753 _("Process rules dictate the minimum drill size which can be used"),
3754 x, y,
3755 0, /* ANGLE OF ERROR UNKNOWN */
3756 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3757 pin->DrillingHole,
3758 PCB->minDrill,
3759 object_count,
3760 object_id_list,
3761 object_type_list);
3762 append_drc_violation (violation);
3763 pcb_drc_violation_free (violation);
3764 free (object_id_list);
3765 free (object_type_list);
3766 if (!throw_drc_dialog())
3768 IsBad = true;
3769 break;
3771 IncrementUndoSerialNumber ();
3772 Undo (false);
3775 ENDALL_LOOP;
3777 if (!IsBad)
3779 ALLPAD_LOOP (PCB->Data);
3781 PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback);
3782 if (IsBad)
3783 break;
3784 if (pad->Thickness < PCB->minWid)
3786 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3787 SET_FLAG (TheFlag, pad);
3788 DrawPad (pad);
3789 drcerr_count++;
3790 SetThing (PAD_TYPE, element, pad, pad);
3791 LocateError (&x, &y);
3792 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3793 violation = pcb_drc_violation_new (_("Pad is too thin"),
3794 _("Pads which are too thin may erode during etching,\n"
3795 "resulting in a broken or unreliable connection"),
3796 x, y,
3797 0, /* ANGLE OF ERROR UNKNOWN */
3798 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3799 pad->Thickness,
3800 PCB->minWid,
3801 object_count,
3802 object_id_list,
3803 object_type_list);
3804 append_drc_violation (violation);
3805 pcb_drc_violation_free (violation);
3806 free (object_id_list);
3807 free (object_type_list);
3808 if (!throw_drc_dialog())
3810 IsBad = true;
3811 break;
3813 IncrementUndoSerialNumber ();
3814 Undo (false);
3817 ENDALL_LOOP;
3819 if (!IsBad)
3821 VIA_LOOP (PCB->Data);
3823 PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback);
3824 if (IsBad)
3825 break;
3826 if (!TEST_FLAG (HOLEFLAG, via) &&
3827 via->Thickness - via->DrillingHole < 2 * PCB->minRing)
3829 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3830 SET_FLAG (TheFlag, via);
3831 DrawVia (via);
3832 drcerr_count++;
3833 SetThing (VIA_TYPE, via, via, via);
3834 LocateError (&x, &y);
3835 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3836 violation = pcb_drc_violation_new (_("Via annular ring too small"),
3837 _("Annular rings that are too small may erode during etching,\n"
3838 "resulting in a broken connection"),
3839 x, y,
3840 0, /* ANGLE OF ERROR UNKNOWN */
3841 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3842 (via->Thickness - via->DrillingHole) / 2,
3843 PCB->minRing,
3844 object_count,
3845 object_id_list,
3846 object_type_list);
3847 append_drc_violation (violation);
3848 pcb_drc_violation_free (violation);
3849 free (object_id_list);
3850 free (object_type_list);
3851 if (!throw_drc_dialog())
3853 IsBad = true;
3854 break;
3856 IncrementUndoSerialNumber ();
3857 Undo (false);
3859 if (via->DrillingHole < PCB->minDrill)
3861 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3862 SET_FLAG (TheFlag, via);
3863 DrawVia (via);
3864 drcerr_count++;
3865 SetThing (VIA_TYPE, via, via, via);
3866 LocateError (&x, &y);
3867 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3868 violation = pcb_drc_violation_new (_("Via drill size is too small"),
3869 _("Process rules dictate the minimum drill size which can be used"),
3870 x, y,
3871 0, /* ANGLE OF ERROR UNKNOWN */
3872 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3873 via->DrillingHole,
3874 PCB->minDrill,
3875 object_count,
3876 object_id_list,
3877 object_type_list);
3878 append_drc_violation (violation);
3879 pcb_drc_violation_free (violation);
3880 free (object_id_list);
3881 free (object_type_list);
3882 if (!throw_drc_dialog())
3884 IsBad = true;
3885 break;
3887 IncrementUndoSerialNumber ();
3888 Undo (false);
3891 END_LOOP;
3894 FreeConnectionLookupMemory ();
3895 TheFlag = FOUNDFLAG;
3896 Bloat = 0;
3898 /* check silkscreen minimum widths outside of elements */
3899 /* XXX - need to check text and polygons too! */
3900 TheFlag = SELECTEDFLAG;
3901 if (!IsBad)
3903 SILKLINE_LOOP (PCB->Data);
3905 if (line->Thickness < PCB->minSlk)
3907 SET_FLAG (TheFlag, line);
3908 DrawLine (layer, line);
3909 drcerr_count++;
3910 SetThing (LINE_TYPE, layer, line, line);
3911 LocateError (&x, &y);
3912 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3913 violation = pcb_drc_violation_new (_("Silk line is too thin"),
3914 _("Process specifications dictate a minimum silkscreen feature-width\n"
3915 "that can reliably be reproduced"),
3916 x, y,
3917 0, /* ANGLE OF ERROR UNKNOWN */
3918 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3919 line->Thickness,
3920 PCB->minSlk,
3921 object_count,
3922 object_id_list,
3923 object_type_list);
3924 append_drc_violation (violation);
3925 pcb_drc_violation_free (violation);
3926 free (object_id_list);
3927 free (object_type_list);
3928 if (!throw_drc_dialog())
3930 IsBad = true;
3931 break;
3935 ENDALL_LOOP;
3938 /* check silkscreen minimum widths inside of elements */
3939 /* XXX - need to check text and polygons too! */
3940 TheFlag = SELECTEDFLAG;
3941 if (!IsBad)
3943 ELEMENT_LOOP (PCB->Data);
3945 tmpcnt = 0;
3946 ELEMENTLINE_LOOP (element);
3948 if (line->Thickness < PCB->minSlk)
3949 tmpcnt++;
3951 END_LOOP;
3952 if (tmpcnt > 0)
3954 char *title;
3955 char *name;
3956 char *buffer;
3957 int buflen;
3959 SET_FLAG (TheFlag, element);
3960 DrawElement (element);
3961 drcerr_count++;
3962 SetThing (ELEMENT_TYPE, element, element, element);
3963 LocateError (&x, &y);
3964 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3966 title = _("Element %s has %i silk lines which are too thin");
3967 name = (char *)UNKNOWN (NAMEONPCB_NAME (element));
3969 /* -4 is for the %s and %i place-holders */
3970 /* +11 is the max printed length for a 32 bit integer */
3971 /* +1 is for the \0 termination */
3972 buflen = strlen (title) - 4 + strlen (name) + 11 + 1;
3973 buffer = (char *)malloc (buflen);
3974 snprintf (buffer, buflen, title, name, tmpcnt);
3976 violation = pcb_drc_violation_new (buffer,
3977 _("Process specifications dictate a minimum silkscreen\n"
3978 "feature-width that can reliably be reproduced"),
3979 x, y,
3980 0, /* ANGLE OF ERROR UNKNOWN */
3981 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3982 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
3983 PCB->minSlk,
3984 object_count,
3985 object_id_list,
3986 object_type_list);
3987 free (buffer);
3988 append_drc_violation (violation);
3989 pcb_drc_violation_free (violation);
3990 free (object_id_list);
3991 free (object_type_list);
3992 if (!throw_drc_dialog())
3994 IsBad = true;
3995 break;
3999 END_LOOP;
4003 if (IsBad)
4005 IncrementUndoSerialNumber ();
4009 RestoreStackAndVisibility ();
4010 hid_action ("LayersChanged");
4011 gui->invalidate_all ();
4013 if (nopastecnt > 0)
4015 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4016 nopastecnt,
4017 nopastecnt > 1 ? "s have" : " has");
4019 return IsBad ? -drcerr_count : drcerr_count;
4022 /*----------------------------------------------------------------------------
4023 * Locate the coordinatates of offending item (thing)
4025 static void
4026 LocateError (Coord *x, Coord *y)
4028 switch (thing_type)
4030 case LINE_TYPE:
4032 LineType *line = (LineType *) thing_ptr3;
4033 *x = (line->Point1.X + line->Point2.X) / 2;
4034 *y = (line->Point1.Y + line->Point2.Y) / 2;
4035 break;
4037 case ARC_TYPE:
4039 ArcType *arc = (ArcType *) thing_ptr3;
4040 *x = arc->X;
4041 *y = arc->Y;
4042 break;
4044 case POLYGON_TYPE:
4046 PolygonType *polygon = (PolygonType *) thing_ptr3;
4047 *x =
4048 (polygon->Clipped->contours->xmin +
4049 polygon->Clipped->contours->xmax) / 2;
4050 *y =
4051 (polygon->Clipped->contours->ymin +
4052 polygon->Clipped->contours->ymax) / 2;
4053 break;
4055 case PIN_TYPE:
4056 case VIA_TYPE:
4058 PinType *pin = (PinType *) thing_ptr3;
4059 *x = pin->X;
4060 *y = pin->Y;
4061 break;
4063 case PAD_TYPE:
4065 PadType *pad = (PadType *) thing_ptr3;
4066 *x = (pad->Point1.X + pad->Point2.X) / 2;
4067 *y = (pad->Point1.Y + pad->Point2.Y) / 2;
4068 break;
4070 case ELEMENT_TYPE:
4072 ElementType *element = (ElementType *) thing_ptr3;
4073 *x = element->MarkX;
4074 *y = element->MarkY;
4075 break;
4077 default:
4078 return;
4083 /*----------------------------------------------------------------------------
4084 * Build a list of the of offending items by ID. (Currently just "thing")
4086 static void
4087 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
4089 *object_count = 0;
4090 *object_id_list = NULL;
4091 *object_type_list = NULL;
4093 switch (thing_type)
4095 case LINE_TYPE:
4096 case ARC_TYPE:
4097 case POLYGON_TYPE:
4098 case PIN_TYPE:
4099 case VIA_TYPE:
4100 case PAD_TYPE:
4101 case ELEMENT_TYPE:
4102 case RATLINE_TYPE:
4103 *object_count = 1;
4104 *object_id_list = (long int *)malloc (sizeof (long int));
4105 *object_type_list = (int *)malloc (sizeof (int));
4106 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
4107 **object_type_list = thing_type;
4108 return;
4110 default:
4111 fprintf (stderr,
4112 _("Internal error in BuildObjectList: unknown object type %i\n"),
4113 thing_type);
4118 /*----------------------------------------------------------------------------
4119 * center the display to show the offending item (thing)
4121 static void
4122 GotoError (void)
4124 Coord X, Y;
4126 LocateError (&X, &Y);
4128 switch (thing_type)
4130 case LINE_TYPE:
4131 case ARC_TYPE:
4132 case POLYGON_TYPE:
4133 ChangeGroupVisibility (
4134 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1),
4135 true, true);
4137 CenterDisplay (X, Y);
4140 void
4141 InitConnectionLookup (void)
4143 InitComponentLookup ();
4144 InitLayoutLookup ();
4147 void
4148 FreeConnectionLookupMemory (void)
4150 FreeComponentLookupMemory ();
4151 FreeLayoutLookupMemory ();