find.c: Remove file-global "IsBad", use PlowsPolygons() return value.
[geda-pcb/pcjc2.git] / src / find.c
blobdd38281053492bbe5a1d276485658e1ba28bb00a
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 SEPARATE(FP) \
109 int i; \
110 fputc('#', (FP)); \
111 for (i = Settings.CharPerLine; i; i--) \
112 fputc('=', (FP)); \
113 fputc('\n', (FP)); \
116 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
117 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
118 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
119 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
120 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
121 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
122 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
124 #define IS_PV_ON_RAT(PV, Rat) \
125 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
127 #define IS_PV_ON_ARC(PV, Arc) \
128 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
129 IsArcInRectangle( \
130 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
131 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
132 (Arc)) : \
133 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
135 #define IS_PV_ON_PAD(PV,Pad) \
136 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
138 static DrcViolationType
139 *pcb_drc_violation_new (const char *title,
140 const char *explanation,
141 Coord x, Coord y,
142 Angle angle,
143 bool have_measured,
144 Coord measured_value,
145 Coord required_value,
146 int object_count,
147 long int *object_id_list,
148 int *object_type_list)
150 DrcViolationType *violation = (DrcViolationType *)malloc (sizeof (DrcViolationType));
152 violation->title = strdup (title);
153 violation->explanation = strdup (explanation);
154 violation->x = x;
155 violation->y = y;
156 violation->angle = angle;
157 violation->have_measured = have_measured;
158 violation->measured_value = measured_value;
159 violation->required_value = required_value;
160 violation->object_count = object_count;
161 violation->object_id_list = object_id_list;
162 violation->object_type_list = object_type_list;
164 return violation;
167 static void
168 pcb_drc_violation_free (DrcViolationType *violation)
170 free (violation->title);
171 free (violation->explanation);
172 free (violation);
175 static GString *drc_dialog_message;
176 static void
177 reset_drc_dialog_message(void)
179 if (drc_dialog_message)
180 g_string_free (drc_dialog_message, FALSE);
181 drc_dialog_message = g_string_new ("");
182 if (gui->drc_gui != NULL)
184 gui->drc_gui->reset_drc_dialog_message ();
187 static void
188 append_drc_dialog_message(const char *fmt, ...)
190 gchar *new_str;
191 va_list ap;
192 va_start (ap, fmt);
193 new_str = pcb_vprintf (fmt, ap);
194 g_string_append (drc_dialog_message, new_str);
195 va_end (ap);
196 g_free (new_str);
199 static void GotoError (void);
201 static void
202 append_drc_violation (DrcViolationType *violation)
204 if (gui->drc_gui != NULL)
206 gui->drc_gui->append_drc_violation (violation);
208 else
210 /* Fallback to formatting the violation message as text */
211 append_drc_dialog_message ("%s\n", violation->title);
212 append_drc_dialog_message (_("%m+near %$mD\n"),
213 Settings.grid_unit->allow,
214 violation->x, violation->y);
215 GotoError ();
218 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_violations )
220 Message (_("WARNING! Design Rule error - %s\n"), violation->title);
221 Message (_("%m+near location %$mD\n"),
222 Settings.grid_unit->allow,
223 violation->x, violation->y);
227 * message when asked about continuing DRC checks after next
228 * violation is found.
230 #define DRC_CONTINUE _("Press Next to continue DRC checking")
231 #define DRC_NEXT _("Next")
232 #define DRC_CANCEL _("Cancel")
234 static int
235 throw_drc_dialog(void)
237 int r;
239 if (gui->drc_gui != NULL)
241 r = gui->drc_gui->throw_drc_dialog ();
243 else
245 /* Fallback to formatting the violation message as text */
246 append_drc_dialog_message (DRC_CONTINUE);
247 r = gui->confirm_dialog (drc_dialog_message->str, DRC_CANCEL, DRC_NEXT);
248 reset_drc_dialog_message();
250 return r;
253 /* ---------------------------------------------------------------------------
254 * some local types
256 * the two 'dummy' structs for PVs and Pads are necessary for creating
257 * connection lists which include the element's name
259 typedef struct
261 void **Data; /* pointer to index data */
262 Cardinal Location, /* currently used position */
263 DrawLocation, Number, /* number of objects in list */
264 Size;
265 } ListType;
267 /* ---------------------------------------------------------------------------
268 * some local identifiers
270 static Coord Bloat = 0;
271 static int TheFlag = FOUNDFLAG;
272 static void *thing_ptr1, *thing_ptr2, *thing_ptr3;
273 static int thing_type;
274 static bool User = false; /* user action causing this */
275 static bool drc = false; /* whether to stop if finding something not found */
276 static Cardinal drcerr_count; /* count of drc errors */
277 static Cardinal TotalP, TotalV, NumberOfPads[2];
278 static ListType LineList[MAX_LAYER], /* list of objects to */
279 PolygonList[MAX_LAYER], ArcList[MAX_LAYER], PadList[2], RatList, PVList;
281 /* ---------------------------------------------------------------------------
282 * some local prototypes
284 static bool LookupLOConnectionsToPVList (bool);
285 static bool LookupLOConnectionsToLOList (bool);
286 static bool LookupPVConnectionsToLOList (bool);
287 static bool LookupPVConnectionsToPVList (void);
288 static bool LookupLOConnectionsToLine (LineType *, Cardinal, bool);
289 static bool LookupLOConnectionsToPad (PadType *, Cardinal);
290 static bool LookupLOConnectionsToPolygon (PolygonType *, Cardinal);
291 static bool LookupLOConnectionsToArc (ArcType *, Cardinal);
292 static bool LookupLOConnectionsToRatEnd (PointType *, Cardinal);
293 static bool IsRatPointOnLineEnd (PointType *, LineType *);
294 static bool ArcArcIntersect (ArcType *, ArcType *);
295 static bool PrepareNextLoop (FILE *);
296 static bool PrintElementConnections (ElementType *, FILE *, bool);
297 static bool ListsEmpty (bool);
298 static bool DoIt (bool, bool);
299 static void PrintElementNameList (ElementType *, FILE *);
300 static void PrintConnectionElementName (ElementType *, FILE *);
301 static void PrintConnectionListEntry (char *, ElementType *,
302 bool, FILE *);
303 static void PrintPadConnections (Cardinal, FILE *, bool);
304 static void PrintPinConnections (FILE *, bool);
305 static bool PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *,
306 FILE *);
307 static void DrawNewConnections (void);
308 static void DumpList (void);
309 static void LocateError (Coord *, Coord *);
310 static void BuildObjectList (int *, long int **, int **);
311 static void GotoError (void);
312 static bool DRCFind (int, void *, void *, void *);
313 static bool ListStart (int, void *, void *, void *);
314 static bool SetThing (int, void *, void *, void *);
315 static bool IsArcInPolygon (ArcType *, PolygonType *);
316 static bool IsLineInPolygon (LineType *, PolygonType *);
317 static bool IsPadInPolygon (PadType *, PolygonType *);
318 static bool IsPolygonInPolygon (PolygonType *, PolygonType *);
320 /* ---------------------------------------------------------------------------
321 * some of the 'pad' routines are the same as for lines because the 'pad'
322 * struct starts with a line struct. See global.h for details
324 bool
325 LinePadIntersect (LineType *Line, PadType *Pad)
327 return LineLineIntersect ((Line), (LineType *)Pad);
330 bool
331 ArcPadIntersect (ArcType *Arc, PadType *Pad)
333 return LineArcIntersect ((LineType *) (Pad), (Arc));
336 static bool
337 add_object_to_list (ListType *list, int type, void *ptr1, void *ptr2, void *ptr3)
339 AnyObjectType *object = (AnyObjectType *)ptr2;
341 if (User)
342 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3);
344 SET_FLAG (TheFlag, object);
345 LIST_ENTRY (list, list->Number) = object;
346 list->Number++;
348 #ifdef DEBUG
349 if (list.Number > list.Size)
350 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type, list.Number, list.Size);
351 #endif
353 if (drc && !TEST_FLAG (SELECTEDFLAG, object))
354 return (SetThing (type, ptr1, ptr2, ptr3));
355 return false;
358 static bool
359 ADD_PV_TO_LIST (PinType *Pin)
361 return add_object_to_list (&PVList, Pin->Element ? PIN_TYPE : VIA_TYPE,
362 Pin->Element ? Pin->Element : Pin, Pin, Pin);
365 static bool
366 ADD_PAD_TO_LIST (Cardinal L, PadType *Pad)
368 return add_object_to_list (&PadList[L], PAD_TYPE, Pad->Element, Pad, Pad);
371 static bool
372 ADD_LINE_TO_LIST (Cardinal L, LineType *Ptr)
374 return add_object_to_list (&LineList[L], LINE_TYPE, LAYER_PTR (L), Ptr, Ptr);
377 static bool
378 ADD_ARC_TO_LIST (Cardinal L, ArcType *Ptr)
380 return add_object_to_list (&ArcList[L], ARC_TYPE, LAYER_PTR (L), Ptr, Ptr);
383 static bool
384 ADD_RAT_TO_LIST (RatType *Ptr)
386 return add_object_to_list (&RatList, RATLINE_TYPE, Ptr, Ptr, Ptr);
389 static bool
390 ADD_POLYGON_TO_LIST (Cardinal L, PolygonType *Ptr)
392 return add_object_to_list (&PolygonList[L], POLYGON_TYPE, LAYER_PTR (L), Ptr, Ptr);
395 static BoxType
396 expand_bounds (BoxType *box_in)
398 BoxType box_out = *box_in;
400 if (Bloat > 0)
402 box_out.X1 -= Bloat;
403 box_out.X2 += Bloat;
404 box_out.Y1 -= Bloat;
405 box_out.Y2 += Bloat;
408 return box_out;
411 bool
412 PinLineIntersect (PinType *PV, LineType *Line)
414 /* IsLineInRectangle already has Bloat factor */
415 return TEST_FLAG (SQUAREFLAG,
416 PV) ? IsLineInRectangle (PV->X - (PIN_SIZE (PV) + 1) / 2,
417 PV->Y - (PIN_SIZE (PV) + 1) / 2,
418 PV->X + (PIN_SIZE (PV) + 1) / 2,
419 PV->Y + (PIN_SIZE (PV) + 1) / 2,
420 Line) : IsPointInPad (PV->X,
421 PV->Y,
422 MAX (PIN_SIZE (PV)
424 2.0 +
425 Bloat,
426 0.0),
427 (PadType *)Line);
431 bool
432 SetThing (int type, void *ptr1, void *ptr2, void *ptr3)
434 thing_ptr1 = ptr1;
435 thing_ptr2 = ptr2;
436 thing_ptr3 = ptr3;
437 thing_type = type;
438 if (type == PIN_TYPE && ptr1 == NULL)
440 thing_ptr1 = ptr3;
441 thing_type = VIA_TYPE;
443 return true;
446 bool
447 BoxBoxIntersection (BoxType *b1, BoxType *b2)
449 if (b2->X2 < b1->X1 || b2->X1 > b1->X2)
450 return false;
451 if (b2->Y2 < b1->Y1 || b2->Y1 > b1->Y2)
452 return false;
453 return true;
456 static bool
457 PadPadIntersect (PadType *p1, PadType *p2)
459 return LinePadIntersect ((LineType *) p1, p2);
462 static inline bool
463 PV_TOUCH_PV (PinType *PV1, PinType *PV2)
465 double t1, t2;
466 BoxType b1, b2;
468 t1 = MAX (PV1->Thickness / 2.0 + Bloat, 0);
469 t2 = MAX (PV2->Thickness / 2.0 + Bloat, 0);
470 if (IsPointOnPin (PV1->X, PV1->Y, t1, PV2)
471 || IsPointOnPin (PV2->X, PV2->Y, t2, PV1))
472 return true;
473 if (!TEST_FLAG (SQUAREFLAG, PV1) || !TEST_FLAG (SQUAREFLAG, PV2))
474 return false;
475 /* check for square/square overlap */
476 b1.X1 = PV1->X - t1;
477 b1.X2 = PV1->X + t1;
478 b1.Y1 = PV1->Y - t1;
479 b1.Y2 = PV1->Y + t1;
480 t2 = PV2->Thickness / 2.0;
481 b2.X1 = PV2->X - t2;
482 b2.X2 = PV2->X + t2;
483 b2.Y1 = PV2->Y - t2;
484 b2.Y2 = PV2->Y + t2;
485 return BoxBoxIntersection (&b1, &b2);
488 /* ---------------------------------------------------------------------------
489 * releases all allocated memory
491 static void
492 FreeLayoutLookupMemory (void)
494 Cardinal i;
496 for (i = 0; i < max_copper_layer; i++)
498 free (LineList[i].Data);
499 LineList[i].Data = NULL;
500 free (ArcList[i].Data);
501 ArcList[i].Data = NULL;
502 free (PolygonList[i].Data);
503 PolygonList[i].Data = NULL;
505 free (PVList.Data);
506 PVList.Data = NULL;
507 free (RatList.Data);
508 RatList.Data = NULL;
511 static void
512 FreeComponentLookupMemory (void)
514 free (PadList[0].Data);
515 PadList[0].Data = NULL;
516 free (PadList[1].Data);
517 PadList[1].Data = NULL;
520 /* ---------------------------------------------------------------------------
521 * allocates memory for component related stacks ...
522 * initializes index and sorts it by X1 and X2
524 static void
525 InitComponentLookup (void)
527 Cardinal i;
529 /* initialize pad data; start by counting the total number
530 * on each of the two possible layers
532 NumberOfPads[COMPONENT_LAYER] = NumberOfPads[SOLDER_LAYER] = 0;
533 ALLPAD_LOOP (PCB->Data);
535 if (TEST_FLAG (ONSOLDERFLAG, pad))
536 NumberOfPads[SOLDER_LAYER]++;
537 else
538 NumberOfPads[COMPONENT_LAYER]++;
540 ENDALL_LOOP;
541 for (i = 0; i < 2; i++)
543 /* allocate memory for working list */
544 PadList[i].Data = (void **)calloc (NumberOfPads[i], sizeof (PadType *));
546 /* clear some struct members */
547 PadList[i].Location = 0;
548 PadList[i].DrawLocation = 0;
549 PadList[i].Number = 0;
550 PadList[i].Size = NumberOfPads[i];
554 /* ---------------------------------------------------------------------------
555 * allocates memory for component related stacks ...
556 * initializes index and sorts it by X1 and X2
558 static void
559 InitLayoutLookup (void)
561 Cardinal i;
563 /* initialize line arc and polygon data */
564 for (i = 0; i < max_copper_layer; i++)
566 LayerType *layer = LAYER_PTR (i);
568 if (layer->LineN)
570 /* allocate memory for line pointer lists */
571 LineList[i].Data = (void **)calloc (layer->LineN, sizeof (LineType *));
572 LineList[i].Size = layer->LineN;
574 if (layer->ArcN)
576 ArcList[i].Data = (void **)calloc (layer->ArcN, sizeof (ArcType *));
577 ArcList[i].Size = layer->ArcN;
581 /* allocate memory for polygon list */
582 if (layer->PolygonN)
584 PolygonList[i].Data = (void **)calloc (layer->PolygonN, sizeof (PolygonType *));
585 PolygonList[i].Size = layer->PolygonN;
588 /* clear some struct members */
589 LineList[i].Location = 0;
590 LineList[i].DrawLocation = 0;
591 LineList[i].Number = 0;
592 ArcList[i].Location = 0;
593 ArcList[i].DrawLocation = 0;
594 ArcList[i].Number = 0;
595 PolygonList[i].Location = 0;
596 PolygonList[i].DrawLocation = 0;
597 PolygonList[i].Number = 0;
600 if (PCB->Data->pin_tree)
601 TotalP = PCB->Data->pin_tree->size;
602 else
603 TotalP = 0;
604 if (PCB->Data->via_tree)
605 TotalV = PCB->Data->via_tree->size;
606 else
607 TotalV = 0;
608 /* allocate memory for 'new PV to check' list and clear struct */
609 PVList.Data = (void **)calloc (TotalP + TotalV, sizeof (PinType *));
610 PVList.Size = TotalP + TotalV;
611 PVList.Location = 0;
612 PVList.DrawLocation = 0;
613 PVList.Number = 0;
614 /* Initialize ratline data */
615 RatList.Data = (void **)calloc (PCB->Data->RatN, sizeof (RatType *));
616 RatList.Size = PCB->Data->RatN;
617 RatList.Location = 0;
618 RatList.DrawLocation = 0;
619 RatList.Number = 0;
622 struct pv_info
624 Cardinal layer;
625 PinType pv;
626 jmp_buf env;
629 static int
630 LOCtoPVline_callback (const BoxType * b, void *cl)
632 LineType *line = (LineType *) b;
633 struct pv_info *i = (struct pv_info *) cl;
635 if (!TEST_FLAG (TheFlag, line) && PinLineIntersect (&i->pv, line) &&
636 !TEST_FLAG (HOLEFLAG, &i->pv))
638 if (ADD_LINE_TO_LIST (i->layer, line))
639 longjmp (i->env, 1);
641 return 0;
644 static int
645 LOCtoPVarc_callback (const BoxType * b, void *cl)
647 ArcType *arc = (ArcType *) b;
648 struct pv_info *i = (struct pv_info *) cl;
650 if (!TEST_FLAG (TheFlag, arc) && IS_PV_ON_ARC (&i->pv, arc) &&
651 !TEST_FLAG (HOLEFLAG, &i->pv))
653 if (ADD_ARC_TO_LIST (i->layer, arc))
654 longjmp (i->env, 1);
656 return 0;
659 static int
660 LOCtoPVpad_callback (const BoxType * b, void *cl)
662 PadType *pad = (PadType *) b;
663 struct pv_info *i = (struct pv_info *) cl;
665 if (!TEST_FLAG (TheFlag, pad) && IS_PV_ON_PAD (&i->pv, pad) &&
666 !TEST_FLAG (HOLEFLAG, &i->pv) &&
667 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER :
668 COMPONENT_LAYER, pad))
669 longjmp (i->env, 1);
670 return 0;
673 static int
674 LOCtoPVrat_callback (const BoxType * b, void *cl)
676 RatType *rat = (RatType *) b;
677 struct pv_info *i = (struct pv_info *) cl;
679 if (!TEST_FLAG (TheFlag, rat) && IS_PV_ON_RAT (&i->pv, rat) &&
680 ADD_RAT_TO_LIST (rat))
681 longjmp (i->env, 1);
682 return 0;
684 static int
685 LOCtoPVpoly_callback (const BoxType * b, void *cl)
687 PolygonType *polygon = (PolygonType *) b;
688 struct pv_info *i = (struct pv_info *) cl;
690 /* if the pin doesn't have a therm and polygon is clearing
691 * then it can't touch due to clearance, so skip the expensive
692 * test. If it does have a therm, you still need to test
693 * because it might not be inside the polygon, or it could
694 * be on an edge such that it doesn't actually touch.
696 if (!TEST_FLAG (TheFlag, polygon) && !TEST_FLAG (HOLEFLAG, &i->pv) &&
697 (TEST_THERM (i->layer, &i->pv) ||
698 !TEST_FLAG (CLEARPOLYFLAG,
699 polygon)
700 || !i->pv.Clearance))
702 double wide = MAX (0.5 * i->pv.Thickness + Bloat, 0);
703 if (TEST_FLAG (SQUAREFLAG, &i->pv))
705 Coord x1 = i->pv.X - (i->pv.Thickness + 1 + Bloat) / 2;
706 Coord x2 = i->pv.X + (i->pv.Thickness + 1 + Bloat) / 2;
707 Coord y1 = i->pv.Y - (i->pv.Thickness + 1 + Bloat) / 2;
708 Coord y2 = i->pv.Y + (i->pv.Thickness + 1 + Bloat) / 2;
709 if (IsRectangleInPolygon (x1, y1, x2, y2, polygon)
710 && ADD_POLYGON_TO_LIST (i->layer, polygon))
711 longjmp (i->env, 1);
713 else if (TEST_FLAG (OCTAGONFLAG, &i->pv))
715 POLYAREA *oct = OctagonPoly (i->pv.X, i->pv.Y, i->pv.Thickness / 2);
716 if (isects (oct, polygon, true)
717 && ADD_POLYGON_TO_LIST (i->layer, polygon))
718 longjmp (i->env, 1);
720 else if (IsPointInPolygon (i->pv.X, i->pv.Y, wide,
721 polygon)
722 && ADD_POLYGON_TO_LIST (i->layer, polygon))
723 longjmp (i->env, 1);
725 return 0;
728 /* ---------------------------------------------------------------------------
729 * checks if a PV is connected to LOs, if it is, the LO is added to
730 * the appropriate list and the 'used' flag is set
732 static bool
733 LookupLOConnectionsToPVList (bool AndRats)
735 Cardinal layer_no;
736 struct pv_info info;
738 /* loop over all PVs currently on list */
739 while (PVList.Location < PVList.Number)
741 BoxType search_box;
743 /* get pointer to data */
744 info.pv = *(PVLIST_ENTRY (PVList.Location));
745 search_box = expand_bounds (&info.pv.BoundingBox);
747 /* check pads */
748 if (setjmp (info.env) == 0)
749 r_search (PCB->Data->pad_tree, &search_box, NULL,
750 LOCtoPVpad_callback, &info);
751 else
752 return true;
754 /* now all lines, arcs and polygons of the several layers */
755 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
757 LayerType *layer = LAYER_PTR (layer_no);
759 if (layer->no_drc)
760 continue;
762 info.layer = layer_no;
764 /* add touching lines */
765 if (setjmp (info.env) == 0)
766 r_search (layer->line_tree, &search_box,
767 NULL, LOCtoPVline_callback, &info);
768 else
769 return true;
770 /* add touching arcs */
771 if (setjmp (info.env) == 0)
772 r_search (layer->arc_tree, &search_box,
773 NULL, LOCtoPVarc_callback, &info);
774 else
775 return true;
776 /* check all polygons */
777 if (setjmp (info.env) == 0)
778 r_search (layer->polygon_tree, &search_box,
779 NULL, LOCtoPVpoly_callback, &info);
780 else
781 return true;
783 /* Check for rat-lines that may intersect the PV */
784 if (AndRats)
786 if (setjmp (info.env) == 0)
787 r_search (PCB->Data->rat_tree, &search_box, NULL,
788 LOCtoPVrat_callback, &info);
789 else
790 return true;
792 PVList.Location++;
794 return false;
797 /* ---------------------------------------------------------------------------
798 * find all connections between LO at the current list position and new LOs
800 static bool
801 LookupLOConnectionsToLOList (bool AndRats)
803 bool done;
804 Cardinal i, group, layer, ratposition,
805 lineposition[MAX_LAYER],
806 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2];
808 /* copy the current LO list positions; the original data is changed
809 * by 'LookupPVConnectionsToLOList()' which has to check the same
810 * list entries plus the new ones
812 for (i = 0; i < max_copper_layer; i++)
814 lineposition[i] = LineList[i].Location;
815 polyposition[i] = PolygonList[i].Location;
816 arcposition[i] = ArcList[i].Location;
818 for (i = 0; i < 2; i++)
819 padposition[i] = PadList[i].Location;
820 ratposition = RatList.Location;
822 /* loop over all new LOs in the list; recurse until no
823 * more new connections in the layergroup were found
827 Cardinal *position;
829 if (AndRats)
831 position = &ratposition;
832 for (; *position < RatList.Number; (*position)++)
834 group = RATLIST_ENTRY (*position)->group1;
835 if (LookupLOConnectionsToRatEnd
836 (&(RATLIST_ENTRY (*position)->Point1), group))
837 return (true);
838 group = RATLIST_ENTRY (*position)->group2;
839 if (LookupLOConnectionsToRatEnd
840 (&(RATLIST_ENTRY (*position)->Point2), group))
841 return (true);
844 /* loop over all layergroups */
845 for (group = 0; group < max_group; group++)
847 Cardinal entry;
849 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
851 layer = PCB->LayerGroups.Entries[group][entry];
853 /* be aware that the layer number equal max_copper_layer
854 * and max_copper_layer+1 have a special meaning for pads
856 if (layer < max_copper_layer)
858 /* try all new lines */
859 position = &lineposition[layer];
860 for (; *position < LineList[layer].Number; (*position)++)
861 if (LookupLOConnectionsToLine
862 (LINELIST_ENTRY (layer, *position), group, true))
863 return (true);
865 /* try all new arcs */
866 position = &arcposition[layer];
867 for (; *position < ArcList[layer].Number; (*position)++)
868 if (LookupLOConnectionsToArc
869 (ARCLIST_ENTRY (layer, *position), group))
870 return (true);
872 /* try all new polygons */
873 position = &polyposition[layer];
874 for (; *position < PolygonList[layer].Number; (*position)++)
875 if (LookupLOConnectionsToPolygon
876 (POLYGONLIST_ENTRY (layer, *position), group))
877 return (true);
879 else
881 /* try all new pads */
882 layer -= max_copper_layer;
883 if (layer > 1)
885 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
886 layer, max_copper_layer);
887 return false;
889 position = &padposition[layer];
890 for (; *position < PadList[layer].Number; (*position)++)
891 if (LookupLOConnectionsToPad
892 (PADLIST_ENTRY (layer, *position), group))
893 return (true);
898 /* check if all lists are done; Later for-loops
899 * may have changed the prior lists
901 done = !AndRats || ratposition >= RatList.Number;
902 done = done && padposition[0] >= PadList[0].Number &&
903 padposition[1] >= PadList[1].Number;
904 for (layer = 0; layer < max_copper_layer; layer++)
905 done = done &&
906 lineposition[layer] >= LineList[layer].Number &&
907 arcposition[layer] >= ArcList[layer].Number &&
908 polyposition[layer] >= PolygonList[layer].Number;
910 while (!done);
911 return (false);
914 static int
915 pv_pv_callback (const BoxType * b, void *cl)
917 PinType *pin = (PinType *) b;
918 struct pv_info *i = (struct pv_info *) cl;
920 if (!TEST_FLAG (TheFlag, pin) && PV_TOUCH_PV (&i->pv, pin))
922 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, &i->pv))
924 SET_FLAG (WARNFLAG, pin);
925 Settings.RatWarn = true;
926 if (pin->Element)
927 Message (_("WARNING: Hole too close to pin.\n"));
928 else
929 Message (_("WARNING: Hole too close to via.\n"));
931 else if (ADD_PV_TO_LIST (pin))
932 longjmp (i->env, 1);
934 return 0;
937 /* ---------------------------------------------------------------------------
938 * searches for new PVs that are connected to PVs on the list
940 static bool
941 LookupPVConnectionsToPVList (void)
943 Cardinal save_place;
944 struct pv_info info;
947 /* loop over all PVs on list */
948 save_place = PVList.Location;
949 while (PVList.Location < PVList.Number)
951 BoxType search_box;
953 /* get pointer to data */
954 info.pv = *(PVLIST_ENTRY (PVList.Location));
955 search_box = expand_bounds ((BoxType *)&info.pv);
957 if (setjmp (info.env) == 0)
958 r_search (PCB->Data->via_tree, &search_box, NULL,
959 pv_pv_callback, &info);
960 else
961 return true;
962 if (setjmp (info.env) == 0)
963 r_search (PCB->Data->pin_tree, &search_box, NULL,
964 pv_pv_callback, &info);
965 else
966 return true;
967 PVList.Location++;
969 PVList.Location = save_place;
970 return (false);
973 struct lo_info
975 Cardinal layer;
976 LineType line;
977 PadType pad;
978 ArcType arc;
979 PolygonType polygon;
980 RatType rat;
981 jmp_buf env;
984 static int
985 pv_line_callback (const BoxType * b, void *cl)
987 PinType *pv = (PinType *) b;
988 struct lo_info *i = (struct lo_info *) cl;
990 if (!TEST_FLAG (TheFlag, pv) && PinLineIntersect (pv, &i->line))
992 if (TEST_FLAG (HOLEFLAG, pv))
994 SET_FLAG (WARNFLAG, pv);
995 Settings.RatWarn = true;
996 Message (_("WARNING: Hole too close to line.\n"));
998 else if (ADD_PV_TO_LIST (pv))
999 longjmp (i->env, 1);
1001 return 0;
1004 static int
1005 pv_pad_callback (const BoxType * b, void *cl)
1007 PinType *pv = (PinType *) b;
1008 struct lo_info *i = (struct lo_info *) cl;
1010 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_PAD (pv, &i->pad))
1012 if (TEST_FLAG (HOLEFLAG, pv))
1014 SET_FLAG (WARNFLAG, pv);
1015 Settings.RatWarn = true;
1016 Message (_("WARNING: Hole too close to pad.\n"));
1018 else if (ADD_PV_TO_LIST (pv))
1019 longjmp (i->env, 1);
1021 return 0;
1024 static int
1025 pv_arc_callback (const BoxType * b, void *cl)
1027 PinType *pv = (PinType *) b;
1028 struct lo_info *i = (struct lo_info *) cl;
1030 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_ARC (pv, &i->arc))
1032 if (TEST_FLAG (HOLEFLAG, pv))
1034 SET_FLAG (WARNFLAG, pv);
1035 Settings.RatWarn = true;
1036 Message (_("WARNING: Hole touches arc.\n"));
1038 else if (ADD_PV_TO_LIST (pv))
1039 longjmp (i->env, 1);
1041 return 0;
1044 static int
1045 pv_poly_callback (const BoxType * b, void *cl)
1047 PinType *pv = (PinType *) b;
1048 struct lo_info *i = (struct lo_info *) cl;
1050 /* note that holes in polygons are ok, so they don't generate warnings. */
1051 if (!TEST_FLAG (TheFlag, pv) && !TEST_FLAG (HOLEFLAG, pv) &&
1052 (TEST_THERM (i->layer, pv) ||
1053 !TEST_FLAG (CLEARPOLYFLAG, &i->polygon) ||
1054 !pv->Clearance))
1056 if (TEST_FLAG (SQUAREFLAG, pv))
1058 Coord x1, x2, y1, y2;
1059 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1060 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1061 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1062 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1063 if (IsRectangleInPolygon (x1, y1, x2, y2, &i->polygon)
1064 && ADD_PV_TO_LIST (pv))
1065 longjmp (i->env, 1);
1067 else if (TEST_FLAG (OCTAGONFLAG, pv))
1069 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2);
1070 if (isects (oct, &i->polygon, true) && ADD_PV_TO_LIST (pv))
1071 longjmp (i->env, 1);
1073 else
1075 if (IsPointInPolygon
1076 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, &i->polygon)
1077 && ADD_PV_TO_LIST (pv))
1078 longjmp (i->env, 1);
1081 return 0;
1084 static int
1085 pv_rat_callback (const BoxType * b, void *cl)
1087 PinType *pv = (PinType *) b;
1088 struct lo_info *i = (struct lo_info *) cl;
1090 /* rats can't cause DRC so there is no early exit */
1091 if (!TEST_FLAG (TheFlag, pv) && IS_PV_ON_RAT (pv, &i->rat))
1092 ADD_PV_TO_LIST (pv);
1093 return 0;
1096 /* ---------------------------------------------------------------------------
1097 * searches for new PVs that are connected to NEW LOs on the list
1098 * This routine updates the position counter of the lists too.
1100 static bool
1101 LookupPVConnectionsToLOList (bool AndRats)
1103 Cardinal layer_no;
1104 struct lo_info info;
1106 /* loop over all layers */
1107 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
1109 LayerType *layer = LAYER_PTR (layer_no);
1111 if (layer->no_drc)
1112 continue;
1113 /* do nothing if there are no PV's */
1114 if (TotalP + TotalV == 0)
1116 LineList[layer_no].Location = LineList[layer_no].Number;
1117 ArcList[layer_no].Location = ArcList[layer_no].Number;
1118 PolygonList[layer_no].Location = PolygonList[layer_no].Number;
1119 continue;
1122 /* check all lines */
1123 while (LineList[layer_no].Location < LineList[layer_no].Number)
1125 BoxType search_box;
1127 info.line = *(LINELIST_ENTRY (layer_no, LineList[layer_no].Location));
1128 search_box = expand_bounds ((BoxType *)&info.line);
1130 if (setjmp (info.env) == 0)
1131 r_search (PCB->Data->via_tree, &search_box, NULL,
1132 pv_line_callback, &info);
1133 else
1134 return true;
1135 if (setjmp (info.env) == 0)
1136 r_search (PCB->Data->pin_tree, &search_box, NULL,
1137 pv_line_callback, &info);
1138 else
1139 return true;
1140 LineList[layer_no].Location++;
1143 /* check all arcs */
1144 while (ArcList[layer_no].Location < ArcList[layer_no].Number)
1146 BoxType search_box;
1148 info.arc = *(ARCLIST_ENTRY (layer_no, ArcList[layer_no].Location));
1149 search_box = expand_bounds ((BoxType *)&info.arc);
1151 if (setjmp (info.env) == 0)
1152 r_search (PCB->Data->via_tree, &search_box, NULL,
1153 pv_arc_callback, &info);
1154 else
1155 return true;
1156 if (setjmp (info.env) == 0)
1157 r_search (PCB->Data->pin_tree, &search_box, NULL,
1158 pv_arc_callback, &info);
1159 else
1160 return true;
1161 ArcList[layer_no].Location++;
1164 /* now all polygons */
1165 info.layer = layer_no;
1166 while (PolygonList[layer_no].Location < PolygonList[layer_no].Number)
1168 BoxType search_box;
1170 info.polygon = *(POLYGONLIST_ENTRY (layer_no, PolygonList[layer_no].Location));
1171 search_box = expand_bounds ((BoxType *)&info.polygon);
1173 if (setjmp (info.env) == 0)
1174 r_search (PCB->Data->via_tree, &search_box, NULL,
1175 pv_poly_callback, &info);
1176 else
1177 return true;
1178 if (setjmp (info.env) == 0)
1179 r_search (PCB->Data->pin_tree, &search_box, NULL,
1180 pv_poly_callback, &info);
1181 else
1182 return true;
1183 PolygonList[layer_no].Location++;
1187 /* loop over all pad-layers */
1188 for (layer_no = 0; layer_no < 2; layer_no++)
1190 /* do nothing if there are no PV's */
1191 if (TotalP + TotalV == 0)
1193 PadList[layer_no].Location = PadList[layer_no].Number;
1194 continue;
1197 /* check all pads; for a detailed description see
1198 * the handling of lines in this subroutine
1200 while (PadList[layer_no].Location < PadList[layer_no].Number)
1202 BoxType search_box;
1204 info.pad = *(PADLIST_ENTRY (layer_no, PadList[layer_no].Location));
1205 search_box = expand_bounds ((BoxType *)&info.pad);
1207 if (setjmp (info.env) == 0)
1208 r_search (PCB->Data->via_tree, &search_box, NULL,
1209 pv_pad_callback, &info);
1210 else
1211 return true;
1212 if (setjmp (info.env) == 0)
1213 r_search (PCB->Data->pin_tree, &search_box, NULL,
1214 pv_pad_callback, &info);
1215 else
1216 return true;
1217 PadList[layer_no].Location++;
1221 /* do nothing if there are no PV's */
1222 if (TotalP + TotalV == 0)
1223 RatList.Location = RatList.Number;
1225 /* check all rat-lines */
1226 if (AndRats)
1228 while (RatList.Location < RatList.Number)
1230 info.rat = *(RATLIST_ENTRY (RatList.Location));
1231 r_search_pt (PCB->Data->via_tree, & info.rat.Point1, 1, NULL,
1232 pv_rat_callback, &info);
1233 r_search_pt (PCB->Data->via_tree, & info.rat.Point2, 1, NULL,
1234 pv_rat_callback, &info);
1235 r_search_pt (PCB->Data->pin_tree, & info.rat.Point1, 1, NULL,
1236 pv_rat_callback, &info);
1237 r_search_pt (PCB->Data->pin_tree, & info.rat.Point2, 1, NULL,
1238 pv_rat_callback, &info);
1240 RatList.Location++;
1243 return (false);
1246 /* reduce arc start angle and delta to 0..360 */
1247 static void
1248 normalize_angles (Angle *sa, Angle *d)
1250 if (*d < 0)
1252 *sa += *d;
1253 *d = - *d;
1255 if (*d > 360) /* full circle */
1256 *d = 360;
1257 *sa = NormalizeAngle (*sa);
1260 static int
1261 radius_crosses_arc (double x, double y, ArcType *arc)
1263 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG;
1264 Angle sa = arc->StartAngle, d = arc->Delta;
1266 normalize_angles (&sa, &d);
1267 if (alpha < 0)
1268 alpha += 360;
1269 if (sa <= alpha)
1270 return (sa + d) >= alpha;
1271 return (sa + d - 360) >= alpha;
1274 static void
1275 get_arc_ends (Coord *box, ArcType *arc)
1277 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle);
1278 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle);
1279 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta));
1280 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta));
1282 /* ---------------------------------------------------------------------------
1283 * check if two arcs intersect
1284 * first we check for circle intersections,
1285 * then find the actual points of intersection
1286 * and test them to see if they are on arcs
1288 * consider a, the distance from the center of arc 1
1289 * to the point perpendicular to the intersecting points.
1291 * a = (r1^2 - r2^2 + l^2)/(2l)
1293 * the perpendicular distance to the point of intersection
1294 * is then
1296 * d = sqrt(r1^2 - a^2)
1298 * the points of intersection would then be
1300 * x = X1 + a/l dx +- d/l dy
1301 * y = Y1 + a/l dy -+ d/l dx
1303 * where dx = X2 - X1 and dy = Y2 - Y1
1307 static bool
1308 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2)
1310 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl;
1311 Coord pdx, pdy;
1312 Coord box[8];
1314 t = 0.5 * Arc1->Thickness + Bloat;
1315 t2 = 0.5 * Arc2->Thickness;
1316 t1 = t2 + Bloat;
1318 /* too thin arc */
1319 if (t < 0 || t1 < 0)
1320 return false;
1322 /* try the end points first */
1323 get_arc_ends (&box[0], Arc1);
1324 get_arc_ends (&box[4], Arc2);
1325 if (IsPointOnArc (box[0], box[1], t, Arc2)
1326 || IsPointOnArc (box[2], box[3], t, Arc2)
1327 || IsPointOnArc (box[4], box[5], t, Arc1)
1328 || IsPointOnArc (box[6], box[7], t, Arc1))
1329 return true;
1331 pdx = Arc2->X - Arc1->X;
1332 pdy = Arc2->Y - Arc1->Y;
1333 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y);
1334 /* concentric arcs, simpler intersection conditions */
1335 if (dl < 0.5)
1337 if ((Arc1->Width - t >= Arc2->Width - t2
1338 && Arc1->Width - t <= Arc2->Width + t2)
1339 || (Arc1->Width + t >= Arc2->Width - t2
1340 && Arc1->Width + t <= Arc2->Width + t2))
1342 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta;
1343 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta;
1344 /* NB the endpoints have already been checked,
1345 so we just compare the angles */
1347 normalize_angles (&sa1, &d1);
1348 normalize_angles (&sa2, &d2);
1349 /* sa1 == sa2 was caught when checking endpoints */
1350 if (sa1 > sa2)
1351 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2)
1352 return true;
1353 if (sa2 > sa1)
1354 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1)
1355 return true;
1357 return false;
1359 r1 = Arc1->Width;
1360 r2 = Arc2->Width;
1361 /* arcs centerlines are too far or too near */
1362 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1)
1364 /* check the nearest to the other arc's center point */
1365 dx = pdx * r1 / dl;
1366 dy = pdy * r1 / dl;
1367 if (dl + r1 < r2) /* Arc1 inside Arc2 */
1369 dx = - dx;
1370 dy = - dy;
1373 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1)
1374 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2))
1375 return true;
1377 dx = - pdx * r2 / dl;
1378 dy = - pdy * r2 / dl;
1379 if (dl + r2 < r1) /* Arc2 inside Arc1 */
1381 dx = - dx;
1382 dy = - dy;
1385 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2)
1386 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1))
1387 return true;
1388 return false;
1391 l = dl * dl;
1392 r1 *= r1;
1393 r2 *= r2;
1394 a = 0.5 * (r1 - r2 + l) / l;
1395 r1 = r1 / l;
1396 d = r1 - a * a;
1397 /* the circles are too far apart to touch or probably just touch:
1398 check the nearest point */
1399 if (d < 0)
1400 d = 0;
1401 else
1402 d = sqrt (d);
1403 x = Arc1->X + a * pdx;
1404 y = Arc1->Y + a * pdy;
1405 dx = d * pdx;
1406 dy = d * pdy;
1407 if (radius_crosses_arc (x + dy, y - dx, Arc1)
1408 && IsPointOnArc (x + dy, y - dx, t, Arc2))
1409 return true;
1410 if (radius_crosses_arc (x + dy, y - dx, Arc2)
1411 && IsPointOnArc (x + dy, y - dx, t1, Arc1))
1412 return true;
1414 if (radius_crosses_arc (x - dy, y + dx, Arc1)
1415 && IsPointOnArc (x - dy, y + dx, t, Arc2))
1416 return true;
1417 if (radius_crosses_arc (x - dy, y + dx, Arc2)
1418 && IsPointOnArc (x - dy, y + dx, t1, Arc1))
1419 return true;
1420 return false;
1423 /* ---------------------------------------------------------------------------
1424 * Tests if point is same as line end point
1426 static bool
1427 IsRatPointOnLineEnd (PointType *Point, LineType *Line)
1429 if ((Point->X == Line->Point1.X
1430 && Point->Y == Line->Point1.Y)
1431 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y))
1432 return (true);
1433 return (false);
1436 static void
1437 form_slanted_rectangle (PointType p[4], LineType *l)
1438 /* writes vertices of a squared line */
1440 double dwx = 0, dwy = 0;
1441 if (l->Point1.Y == l->Point2.Y)
1442 dwx = l->Thickness / 2.0;
1443 else if (l->Point1.X == l->Point2.X)
1444 dwy = l->Thickness / 2.0;
1445 else
1447 Coord dX = l->Point2.X - l->Point1.X;
1448 Coord dY = l->Point2.Y - l->Point1.Y;
1449 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y);
1450 dwx = l->Thickness / 2.0 / r * dX;
1451 dwy = l->Thickness / 2.0 / r * dY;
1453 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx;
1454 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx;
1455 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx;
1456 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx;
1458 /* ---------------------------------------------------------------------------
1459 * checks if two lines intersect
1460 * from news FAQ:
1462 * Let A,B,C,D be 2-space position vectors. Then the directed line
1463 * segments AB & CD are given by:
1465 * AB=A+r(B-A), r in [0,1]
1466 * CD=C+s(D-C), s in [0,1]
1468 * If AB & CD intersect, then
1470 * A+r(B-A)=C+s(D-C), or
1472 * XA+r(XB-XA)=XC+s(XD-XC)
1473 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1475 * Solving the above for r and s yields
1477 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1478 * r = ----------------------------- (eqn 1)
1479 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1481 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1482 * s = ----------------------------- (eqn 2)
1483 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1485 * Let I be the position vector of the intersection point, then
1487 * I=A+r(B-A) or
1489 * XI=XA+r(XB-XA)
1490 * YI=YA+r(YB-YA)
1492 * By examining the values of r & s, you can also determine some
1493 * other limiting conditions:
1495 * If 0<=r<=1 & 0<=s<=1, intersection exists
1496 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1498 * If the denominator in eqn 1 is zero, AB & CD are parallel
1499 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1501 * If the intersection point of the 2 lines are needed (lines in this
1502 * context mean infinite lines) regardless whether the two line
1503 * segments intersect, then
1505 * If r>1, I is located on extension of AB
1506 * If r<0, I is located on extension of BA
1507 * If s>1, I is located on extension of CD
1508 * If s<0, I is located on extension of DC
1510 * Also note that the denominators of eqn 1 & 2 are identical.
1513 bool
1514 LineLineIntersect (LineType *Line1, LineType *Line2)
1516 double s, r;
1517 double line1_dx, line1_dy, line2_dx, line2_dy,
1518 point1_dx, point1_dy;
1519 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */
1521 PointType p[4];
1522 form_slanted_rectangle (p, Line1);
1523 return IsLineInQuadrangle (p, Line2);
1525 /* here come only round Line1 because IsLineInQuadrangle()
1526 calls LineLineIntersect() with first argument rounded*/
1527 if (TEST_FLAG (SQUAREFLAG, Line2))
1529 PointType p[4];
1530 form_slanted_rectangle (p, Line2);
1531 return IsLineInQuadrangle (p, Line1);
1533 /* now all lines are round */
1535 /* Check endpoints: this provides a quick exit, catches
1536 * cases where the "real" lines don't intersect but the
1537 * thick lines touch, and ensures that the dx/dy business
1538 * below does not cause a divide-by-zero. */
1539 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y,
1540 MAX (Line2->Thickness / 2 + Bloat, 0),
1541 (PadType *) Line1)
1542 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y,
1543 MAX (Line2->Thickness / 2 + Bloat, 0),
1544 (PadType *) Line1)
1545 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y,
1546 MAX (Line1->Thickness / 2 + Bloat, 0),
1547 (PadType *) Line2)
1548 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y,
1549 MAX (Line1->Thickness / 2 + Bloat, 0),
1550 (PadType *) Line2))
1551 return true;
1553 /* setup some constants */
1554 line1_dx = Line1->Point2.X - Line1->Point1.X;
1555 line1_dy = Line1->Point2.Y - Line1->Point1.Y;
1556 line2_dx = Line2->Point2.X - Line2->Point1.X;
1557 line2_dy = Line2->Point2.Y - Line2->Point1.Y;
1558 point1_dx = Line1->Point1.X - Line2->Point1.X;
1559 point1_dy = Line1->Point1.Y - Line2->Point1.Y;
1561 /* If either line is a point, we have failed already, since the
1562 * endpoint check above will have caught an "intersection". */
1563 if ((line1_dx == 0 && line1_dy == 0)
1564 || (line2_dx == 0 && line2_dy == 0))
1565 return false;
1567 /* set s to cross product of Line1 and the line
1568 * Line1.Point1--Line2.Point1 (as vectors) */
1569 s = point1_dy * line1_dx - point1_dx * line1_dy;
1571 /* set r to cross product of both lines (as vectors) */
1572 r = line1_dx * line2_dy - line1_dy * line2_dx;
1574 /* No cross product means parallel lines, or maybe Line2 is
1575 * zero-length. In either case, since we did a bounding-box
1576 * check before getting here, the above IsPointInPad() checks
1577 * will have caught any intersections. */
1578 if (r == 0.0)
1579 return false;
1581 s /= r;
1582 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r;
1584 /* intersection is at least on AB */
1585 if (r >= 0.0 && r <= 1.0)
1586 return (s >= 0.0 && s <= 1.0);
1588 /* intersection is at least on CD */
1589 /* [removed this case since it always returns false --asp] */
1590 return false;
1593 /*---------------------------------------------------
1595 * Check for line intersection with an arc
1597 * Mostly this is like the circle/line intersection
1598 * found in IsPointOnLine (search.c) see the detailed
1599 * discussion for the basics there.
1601 * Since this is only an arc, not a full circle we need
1602 * to find the actual points of intersection with the
1603 * circle, and see if they are on the arc.
1605 * To do this, we translate along the line from the point Q
1606 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1607 * but it's handy to normalize with respect to l, the line
1608 * length so a single projection is done (e.g. we don't first
1609 * find the point Q
1611 * The projection is now of the form
1613 * Px = X1 + (r +- r2)(X2 - X1)
1614 * Py = Y1 + (r +- r2)(Y2 - Y1)
1616 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1617 * note that this is the variable d, not the symbol d described in IsPointOnLine
1618 * (variable d = symbol d * l)
1620 * The end points are hell so they are checked individually
1622 bool
1623 LineArcIntersect (LineType *Line, ArcType *Arc)
1625 double dx, dy, dx1, dy1, l, d, r, r2, Radius;
1626 BoxType *box;
1628 dx = Line->Point2.X - Line->Point1.X;
1629 dy = Line->Point2.Y - Line->Point1.Y;
1630 dx1 = Line->Point1.X - Arc->X;
1631 dy1 = Line->Point1.Y - Arc->Y;
1632 l = dx * dx + dy * dy;
1633 d = dx * dy1 - dy * dx1;
1634 d *= d;
1636 /* use the larger diameter circle first */
1637 Radius =
1638 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0);
1639 Radius *= Radius;
1640 r2 = Radius * l - d;
1641 /* projection doesn't even intersect circle when r2 < 0 */
1642 if (r2 < 0)
1643 return (false);
1644 /* check the ends of the line in case the projected point */
1645 /* of intersection is beyond the line end */
1646 if (IsPointOnArc
1647 (Line->Point1.X, Line->Point1.Y,
1648 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1649 return (true);
1650 if (IsPointOnArc
1651 (Line->Point2.X, Line->Point2.Y,
1652 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1653 return (true);
1654 if (l == 0.0)
1655 return (false);
1656 r2 = sqrt (r2);
1657 Radius = -(dx * dx1 + dy * dy1);
1658 r = (Radius + r2) / l;
1659 if (r >= 0 && r <= 1
1660 && IsPointOnArc (Line->Point1.X + r * dx,
1661 Line->Point1.Y + r * dy,
1662 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1663 return (true);
1664 r = (Radius - r2) / l;
1665 if (r >= 0 && r <= 1
1666 && IsPointOnArc (Line->Point1.X + r * dx,
1667 Line->Point1.Y + r * dy,
1668 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1669 return (true);
1670 /* check arc end points */
1671 box = GetArcEnds (Arc);
1672 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1673 return true;
1674 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1675 return true;
1676 return false;
1679 static int
1680 LOCtoArcLine_callback (const BoxType * b, void *cl)
1682 LineType *line = (LineType *) b;
1683 struct lo_info *i = (struct lo_info *) cl;
1685 if (!TEST_FLAG (TheFlag, line) && LineArcIntersect (line, &i->arc))
1687 if (ADD_LINE_TO_LIST (i->layer, line))
1688 longjmp (i->env, 1);
1690 return 0;
1693 static int
1694 LOCtoArcArc_callback (const BoxType * b, void *cl)
1696 ArcType *arc = (ArcType *) b;
1697 struct lo_info *i = (struct lo_info *) cl;
1699 if (!arc->Thickness)
1700 return 0;
1701 if (!TEST_FLAG (TheFlag, arc) && ArcArcIntersect (&i->arc, arc))
1703 if (ADD_ARC_TO_LIST (i->layer, arc))
1704 longjmp (i->env, 1);
1706 return 0;
1709 static int
1710 LOCtoArcPad_callback (const BoxType * b, void *cl)
1712 PadType *pad = (PadType *) b;
1713 struct lo_info *i = (struct lo_info *) cl;
1715 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1716 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1717 && ArcPadIntersect (&i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1718 longjmp (i->env, 1);
1719 return 0;
1722 /* ---------------------------------------------------------------------------
1723 * searches all LOs that are connected to the given arc on the given
1724 * layergroup. All found connections are added to the list
1726 * the notation that is used is:
1727 * Xij means Xj at arc i
1729 static bool
1730 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup)
1732 Cardinal entry;
1733 struct lo_info info;
1734 BoxType search_box;
1736 info.arc = *Arc;
1737 search_box = expand_bounds ((BoxType *)&info.arc);
1739 /* loop over all layers of the group */
1740 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1742 Cardinal layer_no;
1743 LayerType *layer;
1744 GList *i;
1746 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1747 layer = LAYER_PTR (layer_no);
1749 /* handle normal layers */
1750 if (layer_no < max_copper_layer)
1752 info.layer = layer_no;
1753 /* add arcs */
1754 if (setjmp (info.env) == 0)
1755 r_search (layer->line_tree, &search_box,
1756 NULL, LOCtoArcLine_callback, &info);
1757 else
1758 return true;
1760 if (setjmp (info.env) == 0)
1761 r_search (layer->arc_tree, &search_box,
1762 NULL, LOCtoArcArc_callback, &info);
1763 else
1764 return true;
1766 /* now check all polygons */
1767 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1769 PolygonType *polygon = i->data;
1770 if (!TEST_FLAG (TheFlag, polygon) && IsArcInPolygon (Arc, polygon)
1771 && ADD_POLYGON_TO_LIST (layer_no, polygon))
1772 return true;
1775 else
1777 info.layer = layer_no - max_copper_layer;
1778 if (setjmp (info.env) == 0)
1779 r_search (PCB->Data->pad_tree, &search_box, NULL,
1780 LOCtoArcPad_callback, &info);
1781 else
1782 return true;
1785 return (false);
1788 static int
1789 LOCtoLineLine_callback (const BoxType * b, void *cl)
1791 LineType *line = (LineType *) b;
1792 struct lo_info *i = (struct lo_info *) cl;
1794 if (!TEST_FLAG (TheFlag, line) && LineLineIntersect (&i->line, line))
1796 if (ADD_LINE_TO_LIST (i->layer, line))
1797 longjmp (i->env, 1);
1799 return 0;
1802 static int
1803 LOCtoLineArc_callback (const BoxType * b, void *cl)
1805 ArcType *arc = (ArcType *) b;
1806 struct lo_info *i = (struct lo_info *) cl;
1808 if (!arc->Thickness)
1809 return 0;
1810 if (!TEST_FLAG (TheFlag, arc) && LineArcIntersect (&i->line, arc))
1812 if (ADD_ARC_TO_LIST (i->layer, arc))
1813 longjmp (i->env, 1);
1815 return 0;
1818 static int
1819 LOCtoLineRat_callback (const BoxType * b, void *cl)
1821 RatType *rat = (RatType *) b;
1822 struct lo_info *i = (struct lo_info *) cl;
1824 if (!TEST_FLAG (TheFlag, rat))
1826 if ((rat->group1 == i->layer)
1827 && IsRatPointOnLineEnd (&rat->Point1, &i->line))
1829 if (ADD_RAT_TO_LIST (rat))
1830 longjmp (i->env, 1);
1832 else if ((rat->group2 == i->layer)
1833 && IsRatPointOnLineEnd (&rat->Point2, &i->line))
1835 if (ADD_RAT_TO_LIST (rat))
1836 longjmp (i->env, 1);
1839 return 0;
1842 static int
1843 LOCtoLinePad_callback (const BoxType * b, void *cl)
1845 PadType *pad = (PadType *) b;
1846 struct lo_info *i = (struct lo_info *) cl;
1848 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1849 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
1850 && LinePadIntersect (&i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad))
1851 longjmp (i->env, 1);
1852 return 0;
1855 /* ---------------------------------------------------------------------------
1856 * searches all LOs that are connected to the given line on the given
1857 * layergroup. All found connections are added to the list
1859 * the notation that is used is:
1860 * Xij means Xj at line i
1862 static bool
1863 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup,
1864 bool PolysTo)
1866 Cardinal entry;
1867 struct lo_info info;
1868 BoxType search_box;
1870 info.layer = LayerGroup;
1871 info.line = *Line;
1872 search_box = expand_bounds ((BoxType *)&info.line);
1874 /* add the new rat lines */
1875 if (setjmp (info.env) == 0)
1876 r_search (PCB->Data->rat_tree, &search_box, NULL,
1877 LOCtoLineRat_callback, &info);
1878 else
1879 return true;
1881 /* loop over all layers of the group */
1882 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1884 Cardinal layer_no;
1885 LayerType *layer;
1887 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1888 layer = LAYER_PTR (layer_no);
1890 /* handle normal layers */
1891 if (layer_no < max_copper_layer)
1893 info.layer = layer_no;
1894 /* add lines */
1895 if (setjmp (info.env) == 0)
1896 r_search (layer->line_tree, &search_box,
1897 NULL, LOCtoLineLine_callback, &info);
1898 else
1899 return true;
1900 /* add arcs */
1901 if (setjmp (info.env) == 0)
1902 r_search (layer->arc_tree, &search_box,
1903 NULL, LOCtoLineArc_callback, &info);
1904 else
1905 return true;
1906 /* now check all polygons */
1907 if (PolysTo)
1909 GList *i;
1910 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1912 PolygonType *polygon = i->data;
1913 if (!TEST_FLAG
1914 (TheFlag, polygon) && IsLineInPolygon (Line, polygon)
1915 && ADD_POLYGON_TO_LIST (layer_no, polygon))
1916 return true;
1920 else
1922 /* handle special 'pad' layers */
1923 info.layer = layer_no - max_copper_layer;
1924 if (setjmp (info.env) == 0)
1925 r_search (PCB->Data->pad_tree, &search_box, NULL,
1926 LOCtoLinePad_callback, &info);
1927 else
1928 return true;
1931 return (false);
1934 struct rat_info
1936 Cardinal layer;
1937 PointType *Point;
1938 jmp_buf env;
1941 static int
1942 LOCtoRat_callback (const BoxType * b, void *cl)
1944 LineType *line = (LineType *) b;
1945 struct rat_info *i = (struct rat_info *) cl;
1947 if (!TEST_FLAG (TheFlag, line) &&
1948 ((line->Point1.X == i->Point->X &&
1949 line->Point1.Y == i->Point->Y) ||
1950 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y)))
1952 if (ADD_LINE_TO_LIST (i->layer, line))
1953 longjmp (i->env, 1);
1955 return 0;
1957 static int
1958 PolygonToRat_callback (const BoxType * b, void *cl)
1960 PolygonType *polygon = (PolygonType *) b;
1961 struct rat_info *i = (struct rat_info *) cl;
1963 if (!TEST_FLAG (TheFlag, polygon) && polygon->Clipped &&
1964 (i->Point->X == polygon->Clipped->contours->head.point[0]) &&
1965 (i->Point->Y == polygon->Clipped->contours->head.point[1]))
1967 if (ADD_POLYGON_TO_LIST (i->layer, polygon))
1968 longjmp (i->env, 1);
1970 return 0;
1973 static int
1974 LOCtoPad_callback (const BoxType * b, void *cl)
1976 PadType *pad = (PadType *) b;
1977 struct rat_info *i = (struct rat_info *) cl;
1979 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
1980 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER) &&
1981 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) ||
1982 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) ||
1983 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X &&
1984 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) &&
1985 ADD_PAD_TO_LIST (i->layer, pad))
1986 longjmp (i->env, 1);
1987 return 0;
1990 /* ---------------------------------------------------------------------------
1991 * searches all LOs that are connected to the given rat-line on the given
1992 * layergroup. All found connections are added to the list
1994 * the notation that is used is:
1995 * Xij means Xj at line i
1997 static bool
1998 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup)
2000 Cardinal entry;
2001 struct rat_info info;
2003 info.Point = Point;
2004 /* loop over all layers of this group */
2005 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2007 Cardinal layer_no;
2008 LayerType *layer;
2010 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2011 layer = LAYER_PTR (layer_no);
2012 /* handle normal layers
2013 rats don't ever touch
2014 arcs by definition
2017 if (layer_no < max_copper_layer)
2019 info.layer = layer_no;
2020 if (setjmp (info.env) == 0)
2021 r_search_pt (layer->line_tree, Point, 1, NULL,
2022 LOCtoRat_callback, &info);
2023 else
2024 return true;
2025 if (setjmp (info.env) == 0)
2026 r_search_pt (layer->polygon_tree, Point, 1,
2027 NULL, PolygonToRat_callback, &info);
2029 else
2031 /* handle special 'pad' layers */
2032 info.layer = layer_no - max_copper_layer;
2033 if (setjmp (info.env) == 0)
2034 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL,
2035 LOCtoPad_callback, &info);
2036 else
2037 return true;
2040 return (false);
2043 static int
2044 LOCtoPadLine_callback (const BoxType * b, void *cl)
2046 LineType *line = (LineType *) b;
2047 struct lo_info *i = (struct lo_info *) cl;
2049 if (!TEST_FLAG (TheFlag, line) && LinePadIntersect (line, &i->pad))
2051 if (ADD_LINE_TO_LIST (i->layer, line))
2052 longjmp (i->env, 1);
2054 return 0;
2057 static int
2058 LOCtoPadArc_callback (const BoxType * b, void *cl)
2060 ArcType *arc = (ArcType *) b;
2061 struct lo_info *i = (struct lo_info *) cl;
2063 if (!arc->Thickness)
2064 return 0;
2065 if (!TEST_FLAG (TheFlag, arc) && ArcPadIntersect (arc, &i->pad))
2067 if (ADD_ARC_TO_LIST (i->layer, arc))
2068 longjmp (i->env, 1);
2070 return 0;
2073 static int
2074 LOCtoPadPoly_callback (const BoxType * b, void *cl)
2076 PolygonType *polygon = (PolygonType *) b;
2077 struct lo_info *i = (struct lo_info *) cl;
2080 if (!TEST_FLAG (TheFlag, polygon) &&
2081 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad.Clearance))
2083 if (IsPadInPolygon (&i->pad, polygon) &&
2084 ADD_POLYGON_TO_LIST (i->layer, polygon))
2085 longjmp (i->env, 1);
2087 return 0;
2090 static int
2091 LOCtoPadRat_callback (const BoxType * b, void *cl)
2093 RatType *rat = (RatType *) b;
2094 struct lo_info *i = (struct lo_info *) cl;
2096 if (!TEST_FLAG (TheFlag, rat))
2098 if (rat->group1 == i->layer &&
2099 ((rat->Point1.X == i->pad.Point1.X && rat->Point1.Y == i->pad.Point1.Y) ||
2100 (rat->Point1.X == i->pad.Point2.X && rat->Point1.Y == i->pad.Point2.Y) ||
2101 (rat->Point1.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2102 rat->Point1.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2104 if (ADD_RAT_TO_LIST (rat))
2105 longjmp (i->env, 1);
2107 else if (rat->group2 == i->layer &&
2108 ((rat->Point2.X == i->pad.Point1.X && rat->Point2.Y == i->pad.Point1.Y) ||
2109 (rat->Point2.X == i->pad.Point2.X && rat->Point2.Y == i->pad.Point2.Y) ||
2110 (rat->Point2.X == (i->pad.Point1.X + i->pad.Point2.X) / 2 &&
2111 rat->Point2.Y == (i->pad.Point1.Y + i->pad.Point2.Y) / 2)))
2113 if (ADD_RAT_TO_LIST (rat))
2114 longjmp (i->env, 1);
2117 return 0;
2120 static int
2121 LOCtoPadPad_callback (const BoxType * b, void *cl)
2123 PadType *pad = (PadType *) b;
2124 struct lo_info *i = (struct lo_info *) cl;
2126 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2127 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2128 && PadPadIntersect (pad, &i->pad) && ADD_PAD_TO_LIST (i->layer, pad))
2129 longjmp (i->env, 1);
2130 return 0;
2133 /* ---------------------------------------------------------------------------
2134 * searches all LOs that are connected to the given pad on the given
2135 * layergroup. All found connections are added to the list
2137 static bool
2138 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup)
2140 Cardinal entry;
2141 struct lo_info info;
2142 BoxType search_box;
2144 if (!TEST_FLAG (SQUAREFLAG, Pad))
2145 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, false));
2147 info.pad = *Pad;
2148 search_box = expand_bounds ((BoxType *)&info.pad);
2150 /* add the new rat lines */
2151 info.layer = LayerGroup;
2153 if (setjmp (info.env) == 0)
2154 r_search (PCB->Data->rat_tree, &search_box, NULL,
2155 LOCtoPadRat_callback, &info);
2156 else
2157 return true;
2159 /* loop over all layers of the group */
2160 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2162 Cardinal layer_no;
2163 LayerType *layer;
2165 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2166 layer = LAYER_PTR (layer_no);
2167 /* handle normal layers */
2168 if (layer_no < max_copper_layer)
2170 info.layer = layer_no;
2171 /* add lines */
2172 if (setjmp (info.env) == 0)
2173 r_search (layer->line_tree, &search_box,
2174 NULL, LOCtoPadLine_callback, &info);
2175 else
2176 return true;
2177 /* add arcs */
2178 if (setjmp (info.env) == 0)
2179 r_search (layer->arc_tree, &search_box,
2180 NULL, LOCtoPadArc_callback, &info);
2181 else
2182 return true;
2183 /* add polygons */
2184 if (setjmp (info.env) == 0)
2185 r_search (layer->polygon_tree, &search_box,
2186 NULL, LOCtoPadPoly_callback, &info);
2187 else
2188 return true;
2190 else
2192 /* handle special 'pad' layers */
2193 info.layer = layer_no - max_copper_layer;
2194 if (setjmp (info.env) == 0)
2195 r_search (PCB->Data->pad_tree, &search_box, NULL,
2196 LOCtoPadPad_callback, &info);
2197 else
2198 return true;
2202 return (false);
2205 static int
2206 LOCtoPolyLine_callback (const BoxType * b, void *cl)
2208 LineType *line = (LineType *) b;
2209 struct lo_info *i = (struct lo_info *) cl;
2211 if (!TEST_FLAG (TheFlag, line) && IsLineInPolygon (line, &i->polygon))
2213 if (ADD_LINE_TO_LIST (i->layer, line))
2214 longjmp (i->env, 1);
2216 return 0;
2219 static int
2220 LOCtoPolyArc_callback (const BoxType * b, void *cl)
2222 ArcType *arc = (ArcType *) b;
2223 struct lo_info *i = (struct lo_info *) cl;
2225 if (!arc->Thickness)
2226 return 0;
2227 if (!TEST_FLAG (TheFlag, arc) && IsArcInPolygon (arc, &i->polygon))
2229 if (ADD_ARC_TO_LIST (i->layer, arc))
2230 longjmp (i->env, 1);
2232 return 0;
2235 static int
2236 LOCtoPolyPad_callback (const BoxType * b, void *cl)
2238 PadType *pad = (PadType *) b;
2239 struct lo_info *i = (struct lo_info *) cl;
2241 if (!TEST_FLAG (TheFlag, pad) && i->layer ==
2242 (TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER)
2243 && IsPadInPolygon (pad, &i->polygon))
2245 if (ADD_PAD_TO_LIST (i->layer, pad))
2246 longjmp (i->env, 1);
2248 return 0;
2251 static int
2252 LOCtoPolyRat_callback (const BoxType * b, void *cl)
2254 RatType *rat = (RatType *) b;
2255 struct lo_info *i = (struct lo_info *) cl;
2257 if (!TEST_FLAG (TheFlag, rat))
2259 if ((rat->Point1.X == (i->polygon.Clipped->contours->head.point[0]) &&
2260 rat->Point1.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2261 rat->group1 == i->layer) ||
2262 (rat->Point2.X == (i->polygon.Clipped->contours->head.point[0]) &&
2263 rat->Point2.Y == (i->polygon.Clipped->contours->head.point[1]) &&
2264 rat->group2 == i->layer))
2265 if (ADD_RAT_TO_LIST (rat))
2266 longjmp (i->env, 1);
2268 return 0;
2272 /* ---------------------------------------------------------------------------
2273 * looks up LOs that are connected to the given polygon
2274 * on the given layergroup. All found connections are added to the list
2276 static bool
2277 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup)
2279 Cardinal entry;
2280 struct lo_info info;
2281 BoxType search_box;
2283 if (!Polygon->Clipped)
2284 return false;
2285 info.polygon = *Polygon;
2286 search_box = expand_bounds ((BoxType *)&info.polygon);
2288 info.layer = LayerGroup;
2289 /* check rats */
2290 if (setjmp (info.env) == 0)
2291 r_search (PCB->Data->rat_tree, &search_box, NULL,
2292 LOCtoPolyRat_callback, &info);
2293 else
2294 return true;
2296 /* loop over all layers of the group */
2297 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2299 Cardinal layer_no;
2300 LayerType *layer;
2302 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2303 layer = LAYER_PTR (layer_no);
2305 /* handle normal layers */
2306 if (layer_no < max_copper_layer)
2308 GList *i;
2310 /* check all polygons */
2311 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
2313 PolygonType *polygon = i->data;
2314 if (!TEST_FLAG (TheFlag, polygon)
2315 && IsPolygonInPolygon (polygon, Polygon)
2316 && ADD_POLYGON_TO_LIST (layer_no, polygon))
2317 return true;
2320 info.layer = layer_no;
2321 /* check all lines */
2322 if (setjmp (info.env) == 0)
2323 r_search (layer->line_tree, &search_box,
2324 NULL, LOCtoPolyLine_callback, &info);
2325 else
2326 return true;
2327 /* check all arcs */
2328 if (setjmp (info.env) == 0)
2329 r_search (layer->arc_tree, &search_box,
2330 NULL, LOCtoPolyArc_callback, &info);
2331 else
2332 return true;
2334 else
2336 info.layer = layer_no - max_copper_layer;
2337 if (setjmp (info.env) == 0)
2338 r_search (PCB->Data->pad_tree, &search_box,
2339 NULL, LOCtoPolyPad_callback, &info);
2340 else
2341 return true;
2344 return (false);
2347 /* ---------------------------------------------------------------------------
2348 * checks if an arc has a connection to a polygon
2350 * - first check if the arc can intersect with the polygon by
2351 * evaluating the bounding boxes
2352 * - check the two end points of the arc. If none of them matches
2353 * - check all segments of the polygon against the arc.
2355 static bool
2356 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon)
2358 BoxType *Box = (BoxType *) Arc;
2360 /* arcs with clearance never touch polys */
2361 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc))
2362 return false;
2363 if (!Polygon->Clipped)
2364 return false;
2365 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2366 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2367 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2368 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2370 POLYAREA *ap;
2372 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat)))
2373 return false; /* error */
2374 return isects (ap, Polygon, true);
2376 return false;
2379 /* ---------------------------------------------------------------------------
2380 * checks if a line has a connection to a polygon
2382 * - first check if the line can intersect with the polygon by
2383 * evaluating the bounding boxes
2384 * - check the two end points of the line. If none of them matches
2385 * - check all segments of the polygon against the line.
2387 static bool
2388 IsLineInPolygon (LineType *Line, PolygonType *Polygon)
2390 BoxType *Box = (BoxType *) Line;
2391 POLYAREA *lp;
2393 /* lines with clearance never touch polygons */
2394 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line))
2395 return false;
2396 if (!Polygon->Clipped)
2397 return false;
2398 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y))
2400 Coord wid = (Line->Thickness + Bloat + 1) / 2;
2401 Coord x1, x2, y1, y2;
2403 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid;
2404 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid;
2405 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid;
2406 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid;
2407 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon);
2409 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2410 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2411 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2412 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2414 if (!(lp = LinePoly (Line, Line->Thickness + Bloat)))
2415 return FALSE; /* error */
2416 return isects (lp, Polygon, true);
2418 return false;
2421 /* ---------------------------------------------------------------------------
2422 * checks if a pad connects to a non-clearing polygon
2424 * The polygon is assumed to already have been proven non-clearing
2426 static bool
2427 IsPadInPolygon (PadType *pad, PolygonType *polygon)
2429 return IsLineInPolygon ((LineType *) pad, polygon);
2432 /* ---------------------------------------------------------------------------
2433 * checks if a polygon has a connection to a second one
2435 * First check all points out of P1 against P2 and vice versa.
2436 * If both fail check all lines of P1 against the ones of P2
2438 static bool
2439 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2)
2441 if (!P1->Clipped || !P2->Clipped)
2442 return false;
2443 assert (P1->Clipped->contours);
2444 assert (P2->Clipped->contours);
2446 /* first check if both bounding boxes intersect. If not, return quickly */
2447 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax ||
2448 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin ||
2449 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax ||
2450 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin)
2451 return false;
2453 /* first check un-bloated case */
2454 if (isects (P1->Clipped, P2, false))
2455 return TRUE;
2457 /* now the difficult case of bloated */
2458 if (Bloat > 0)
2460 PLINE *c;
2461 for (c = P1->Clipped->contours; c; c = c->next)
2463 LineType line;
2464 VNODE *v = &c->head;
2465 if (c->xmin - Bloat <= P2->Clipped->contours->xmax &&
2466 c->xmax + Bloat >= P2->Clipped->contours->xmin &&
2467 c->ymin - Bloat <= P2->Clipped->contours->ymax &&
2468 c->ymax + Bloat >= P2->Clipped->contours->ymin)
2471 line.Point1.X = v->point[0];
2472 line.Point1.Y = v->point[1];
2473 line.Thickness = 2 * Bloat;
2474 line.Clearance = 0;
2475 line.Flags = NoFlags ();
2476 for (v = v->next; v != &c->head; v = v->next)
2478 line.Point2.X = v->point[0];
2479 line.Point2.Y = v->point[1];
2480 SetLineBoundingBox (&line);
2481 if (IsLineInPolygon (&line, P2))
2482 return (true);
2483 line.Point1.X = line.Point2.X;
2484 line.Point1.Y = line.Point2.Y;
2490 return (false);
2493 /* ---------------------------------------------------------------------------
2494 * writes the several names of an element to a file
2496 static void
2497 PrintElementNameList (ElementType *Element, FILE * FP)
2499 static DynamicStringType cname, pname, vname;
2501 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element)));
2502 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element)));
2503 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element)));
2504 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data);
2507 /* ---------------------------------------------------------------------------
2508 * writes the several names of an element to a file
2510 static void
2511 PrintConnectionElementName (ElementType *Element, FILE * FP)
2513 fputs ("Element", FP);
2514 PrintElementNameList (Element, FP);
2515 fputs ("{\n", FP);
2518 /* ---------------------------------------------------------------------------
2519 * prints one {pin,pad,via}/element entry of connection lists
2521 static void
2522 PrintConnectionListEntry (char *ObjName, ElementType *Element,
2523 bool FirstOne, FILE * FP)
2525 static DynamicStringType oname;
2527 CreateQuotedString (&oname, ObjName);
2528 if (FirstOne)
2529 fprintf (FP, "\t%s\n\t{\n", oname.Data);
2530 else
2532 fprintf (FP, "\t\t%s ", oname.Data);
2533 if (Element)
2534 PrintElementNameList (Element, FP);
2535 else
2536 fputs ("(__VIA__)\n", FP);
2540 /* ---------------------------------------------------------------------------
2541 * prints all found connections of a pads to file FP
2542 * the connections are stacked in 'PadList'
2544 static void
2545 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst)
2547 Cardinal i;
2548 PadType *ptr;
2550 if (!PadList[Layer].Number)
2551 return;
2553 /* the starting pad */
2554 if (IsFirst)
2556 ptr = PADLIST_ENTRY (Layer, 0);
2557 if (ptr != NULL)
2558 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP);
2559 else
2560 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2563 /* we maybe have to start with i=1 if we are handling the
2564 * starting-pad itself
2566 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++)
2568 ptr = PADLIST_ENTRY (Layer, i);
2569 if (ptr != NULL)
2570 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP);
2571 else
2572 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2576 /* ---------------------------------------------------------------------------
2577 * prints all found connections of a pin to file FP
2578 * the connections are stacked in 'PVList'
2580 static void
2581 PrintPinConnections (FILE * FP, bool IsFirst)
2583 Cardinal i;
2584 PinType *pv;
2586 if (!PVList.Number)
2587 return;
2589 if (IsFirst)
2591 /* the starting pin */
2592 pv = PVLIST_ENTRY (0);
2593 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP);
2596 /* we maybe have to start with i=1 if we are handling the
2597 * starting-pin itself
2599 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++)
2601 /* get the elements name or assume that its a via */
2602 pv = PVLIST_ENTRY (i);
2603 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP);
2607 /* ---------------------------------------------------------------------------
2608 * checks if all lists of new objects are handled
2610 static bool
2611 ListsEmpty (bool AndRats)
2613 bool empty;
2614 int i;
2616 empty = (PVList.Location >= PVList.Number);
2617 if (AndRats)
2618 empty = empty && (RatList.Location >= RatList.Number);
2619 for (i = 0; i < max_copper_layer && empty; i++)
2620 if (!LAYER_PTR (i)->no_drc)
2621 empty = empty && LineList[i].Location >= LineList[i].Number
2622 && ArcList[i].Location >= ArcList[i].Number
2623 && PolygonList[i].Location >= PolygonList[i].Number;
2624 return (empty);
2627 static void
2628 reassign_no_drc_flags (void)
2630 int layer;
2632 for (layer = 0; layer < max_copper_layer; layer++)
2634 LayerType *l = LAYER_PTR (layer);
2635 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL;
2642 /* ---------------------------------------------------------------------------
2643 * loops till no more connections are found
2645 static bool
2646 DoIt (bool AndRats, bool AndDraw)
2648 bool newone = false;
2649 reassign_no_drc_flags ();
2652 /* lookup connections; these are the steps (2) to (4)
2653 * from the description
2655 newone = LookupPVConnectionsToPVList () ||
2656 LookupLOConnectionsToPVList (AndRats) ||
2657 LookupLOConnectionsToLOList (AndRats) ||
2658 LookupPVConnectionsToLOList (AndRats);
2659 if (AndDraw)
2660 DrawNewConnections ();
2662 while (!newone && !ListsEmpty (AndRats));
2663 if (AndDraw)
2664 Draw ();
2665 return (newone);
2668 /* ---------------------------------------------------------------------------
2669 * prints all unused pins of an element to file FP
2671 static bool
2672 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP)
2674 bool first = true;
2675 Cardinal number;
2676 static DynamicStringType oname;
2678 /* check all pins in element */
2680 PIN_LOOP (Element);
2682 if (!TEST_FLAG (HOLEFLAG, pin))
2684 /* pin might have bee checked before, add to list if not */
2685 if (!TEST_FLAG (TheFlag, pin) && FP)
2687 int i;
2688 if (ADD_PV_TO_LIST (pin))
2689 return true;
2690 DoIt (true, true);
2691 number = PadList[COMPONENT_LAYER].Number
2692 + PadList[SOLDER_LAYER].Number + PVList.Number;
2693 /* the pin has no connection if it's the only
2694 * list entry; don't count vias
2696 for (i = 0; i < PVList.Number; i++)
2697 if (!PVLIST_ENTRY (i)->Element)
2698 number--;
2699 if (number == 1)
2701 /* output of element name if not already done */
2702 if (first)
2704 PrintConnectionElementName (Element, FP);
2705 first = false;
2708 /* write name to list and draw selected object */
2709 CreateQuotedString (&oname, (char *)EMPTY (pin->Name));
2710 fprintf (FP, "\t%s\n", oname.Data);
2711 SET_FLAG (SELECTEDFLAG, pin);
2712 DrawPin (pin);
2715 /* reset found objects for the next pin */
2716 if (PrepareNextLoop (FP))
2717 return (true);
2721 END_LOOP;
2723 /* check all pads in element */
2724 PAD_LOOP (Element);
2726 /* lookup pad in list */
2727 /* pad might has bee checked before, add to list if not */
2728 if (!TEST_FLAG (TheFlag, pad) && FP)
2730 int i;
2731 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad)
2732 ? SOLDER_LAYER : COMPONENT_LAYER, pad))
2733 return true;
2734 DoIt (true, true);
2735 number = PadList[COMPONENT_LAYER].Number
2736 + PadList[SOLDER_LAYER].Number + PVList.Number;
2737 /* the pin has no connection if it's the only
2738 * list entry; don't count vias
2740 for (i = 0; i < PVList.Number; i++)
2741 if (!PVLIST_ENTRY (i)->Element)
2742 number--;
2743 if (number == 1)
2745 /* output of element name if not already done */
2746 if (first)
2748 PrintConnectionElementName (Element, FP);
2749 first = false;
2752 /* write name to list and draw selected object */
2753 CreateQuotedString (&oname, (char *)EMPTY (pad->Name));
2754 fprintf (FP, "\t%s\n", oname.Data);
2755 SET_FLAG (SELECTEDFLAG, pad);
2756 DrawPad (pad);
2759 /* reset found objects for the next pin */
2760 if (PrepareNextLoop (FP))
2761 return (true);
2764 END_LOOP;
2766 /* print separator if element has unused pins or pads */
2767 if (!first)
2769 fputs ("}\n\n", FP);
2770 SEPARATE (FP);
2772 return (false);
2775 /* ---------------------------------------------------------------------------
2776 * resets some flags for looking up the next pin/pad
2778 static bool
2779 PrepareNextLoop (FILE * FP)
2781 Cardinal layer;
2783 /* reset found LOs for the next pin */
2784 for (layer = 0; layer < max_copper_layer; layer++)
2786 LineList[layer].Location = LineList[layer].Number = 0;
2787 ArcList[layer].Location = ArcList[layer].Number = 0;
2788 PolygonList[layer].Location = PolygonList[layer].Number = 0;
2791 /* reset found pads */
2792 for (layer = 0; layer < 2; layer++)
2793 PadList[layer].Location = PadList[layer].Number = 0;
2795 /* reset PVs */
2796 PVList.Number = PVList.Location = 0;
2797 RatList.Number = RatList.Location = 0;
2799 return (false);
2802 /* ---------------------------------------------------------------------------
2803 * finds all connections to the pins of the passed element.
2804 * The result is written to file FP
2805 * Returns true if operation was aborted
2807 static bool
2808 PrintElementConnections (ElementType *Element, FILE * FP, bool AndDraw)
2810 PrintConnectionElementName (Element, FP);
2812 /* check all pins in element */
2813 PIN_LOOP (Element);
2815 /* pin might have been checked before, add to list if not */
2816 if (TEST_FLAG (TheFlag, pin))
2818 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP);
2819 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2820 continue;
2822 if (ADD_PV_TO_LIST (pin))
2823 return true;
2824 DoIt (true, AndDraw);
2825 /* printout all found connections */
2826 PrintPinConnections (FP, true);
2827 PrintPadConnections (COMPONENT_LAYER, FP, false);
2828 PrintPadConnections (SOLDER_LAYER, FP, false);
2829 fputs ("\t}\n", FP);
2830 if (PrepareNextLoop (FP))
2831 return (true);
2833 END_LOOP;
2835 /* check all pads in element */
2836 PAD_LOOP (Element);
2838 Cardinal layer;
2839 /* pad might have been checked before, add to list if not */
2840 if (TEST_FLAG (TheFlag, pad))
2842 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP);
2843 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2844 continue;
2846 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER;
2847 if (ADD_PAD_TO_LIST (layer, pad))
2848 return true;
2849 DoIt (true, AndDraw);
2850 /* print all found connections */
2851 PrintPadConnections (layer, FP, true);
2852 PrintPadConnections (layer ==
2853 (COMPONENT_LAYER ? SOLDER_LAYER : COMPONENT_LAYER),
2854 FP, false);
2855 PrintPinConnections (FP, false);
2856 fputs ("\t}\n", FP);
2857 if (PrepareNextLoop (FP))
2858 return (true);
2860 END_LOOP;
2861 fputs ("}\n\n", FP);
2862 return (false);
2865 /* ---------------------------------------------------------------------------
2866 * draws all new connections which have been found since the
2867 * routine was called the last time
2869 static void
2870 DrawNewConnections (void)
2872 int i;
2873 Cardinal position;
2875 /* decrement 'i' to keep layerstack order */
2876 for (i = max_copper_layer - 1; i != -1; i--)
2878 Cardinal layer = LayerStack[i];
2880 if (PCB->Data->Layer[layer].On)
2882 /* draw all new lines */
2883 position = LineList[layer].DrawLocation;
2884 for (; position < LineList[layer].Number; position++)
2885 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position));
2886 LineList[layer].DrawLocation = LineList[layer].Number;
2888 /* draw all new arcs */
2889 position = ArcList[layer].DrawLocation;
2890 for (; position < ArcList[layer].Number; position++)
2891 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position));
2892 ArcList[layer].DrawLocation = ArcList[layer].Number;
2894 /* draw all new polygons */
2895 position = PolygonList[layer].DrawLocation;
2896 for (; position < PolygonList[layer].Number; position++)
2897 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position));
2898 PolygonList[layer].DrawLocation = PolygonList[layer].Number;
2902 /* draw all new pads */
2903 if (PCB->PinOn)
2904 for (i = 0; i < 2; i++)
2906 position = PadList[i].DrawLocation;
2908 for (; position < PadList[i].Number; position++)
2909 DrawPad (PADLIST_ENTRY (i, position));
2910 PadList[i].DrawLocation = PadList[i].Number;
2913 /* draw all new PVs; 'PVList' holds a list of pointers to the
2914 * sorted array pointers to PV data
2916 while (PVList.DrawLocation < PVList.Number)
2918 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation);
2920 if (TEST_FLAG (PINFLAG, pv))
2922 if (PCB->PinOn)
2923 DrawPin (pv);
2925 else if (PCB->ViaOn)
2926 DrawVia (pv);
2927 PVList.DrawLocation++;
2929 /* draw the new rat-lines */
2930 if (PCB->RatOn)
2932 position = RatList.DrawLocation;
2933 for (; position < RatList.Number; position++)
2934 DrawRat (RATLIST_ENTRY (position));
2935 RatList.DrawLocation = RatList.Number;
2939 /* ---------------------------------------------------------------------------
2940 * find all connections to pins within one element
2942 void
2943 LookupElementConnections (ElementType *Element, FILE * FP)
2945 /* reset all currently marked connections */
2946 User = true;
2947 TheFlag = FOUNDFLAG;
2948 ClearFlagOnAllObjects (true, FOUNDFLAG);
2949 InitConnectionLookup ();
2950 PrintElementConnections (Element, FP, true);
2951 SetChangedFlag (true);
2952 if (Settings.RingBellWhenFinished)
2953 gui->beep ();
2954 FreeConnectionLookupMemory ();
2955 IncrementUndoSerialNumber ();
2956 User = false;
2957 Draw ();
2960 /* ---------------------------------------------------------------------------
2961 * find all connections to pins of all element
2963 void
2964 LookupConnectionsToAllElements (FILE * FP)
2966 /* reset all currently marked connections */
2967 User = false;
2968 TheFlag = FOUNDFLAG;
2969 ClearFlagOnAllObjects (false, FOUNDFLAG);
2970 InitConnectionLookup ();
2972 ELEMENT_LOOP (PCB->Data);
2974 /* break if abort dialog returned true */
2975 if (PrintElementConnections (element, FP, false))
2976 break;
2977 SEPARATE (FP);
2978 if (Settings.ResetAfterElement && n != 1)
2979 ClearFlagOnAllObjects (false, FOUNDFLAG);
2981 END_LOOP;
2982 if (Settings.RingBellWhenFinished)
2983 gui->beep ();
2984 ClearFlagOnAllObjects (false, FOUNDFLAG);
2985 FreeConnectionLookupMemory ();
2986 Redraw ();
2989 /*---------------------------------------------------------------------------
2990 * add the starting object to the list of found objects
2992 static bool
2993 ListStart (int type, void *ptr1, void *ptr2, void *ptr3)
2995 DumpList ();
2996 switch (type)
2998 case PIN_TYPE:
2999 case VIA_TYPE:
3001 if (ADD_PV_TO_LIST ((PinType *) ptr2))
3002 return true;
3003 break;
3006 case RATLINE_TYPE:
3008 if (ADD_RAT_TO_LIST ((RatType *) ptr1))
3009 return true;
3010 break;
3013 case LINE_TYPE:
3015 int layer = GetLayerNumber (PCB->Data,
3016 (LayerType *) ptr1);
3018 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2))
3019 return true;
3020 break;
3023 case ARC_TYPE:
3025 int layer = GetLayerNumber (PCB->Data,
3026 (LayerType *) ptr1);
3028 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2))
3029 return true;
3030 break;
3033 case POLYGON_TYPE:
3035 int layer = GetLayerNumber (PCB->Data,
3036 (LayerType *) ptr1);
3038 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2))
3039 return true;
3040 break;
3043 case PAD_TYPE:
3045 PadType *pad = (PadType *) ptr2;
3046 if (ADD_PAD_TO_LIST
3047 (TEST_FLAG
3048 (ONSOLDERFLAG, pad) ? SOLDER_LAYER : COMPONENT_LAYER, pad))
3049 return true;
3050 break;
3053 return (false);
3057 /* ---------------------------------------------------------------------------
3058 * looks up all connections from the object at the given coordinates
3059 * the TheFlag (normally 'FOUNDFLAG') is set for all objects found
3060 * the objects are re-drawn if AndDraw is true
3061 * also the action is marked as undoable if AndDraw is true
3063 void
3064 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int which_flag,
3065 bool AndRats)
3067 void *ptr1, *ptr2, *ptr3;
3068 char *name;
3069 int type;
3071 /* check if there are any pins or pads at that position */
3073 reassign_no_drc_flags ();
3075 type
3076 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range);
3077 if (type == NO_TYPE)
3079 type = SearchObjectByLocation (
3080 LOOKUP_MORE & ~(AndRats ? RATLINE_TYPE : 0),
3081 &ptr1, &ptr2, &ptr3, X, Y, Range);
3082 if (type == NO_TYPE)
3083 return;
3084 if (type & SILK_TYPE)
3086 int laynum = GetLayerNumber (PCB->Data,
3087 (LayerType *) ptr1);
3089 /* don't mess with non-conducting objects! */
3090 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc)
3091 return;
3095 name = ConnectionName (type, ptr1, ptr2);
3096 hid_actionl ("NetlistShow", name, NULL);
3098 TheFlag = which_flag;
3099 User = AndDraw;
3100 InitConnectionLookup ();
3102 /* now add the object to the appropriate list and start scanning
3103 * This is step (1) from the description
3105 ListStart (type, ptr1, ptr2, ptr3);
3106 DoIt (AndRats, AndDraw);
3107 if (User)
3108 IncrementUndoSerialNumber ();
3109 User = false;
3111 /* we are done */
3112 if (AndDraw)
3113 Draw ();
3114 if (AndDraw && Settings.RingBellWhenFinished)
3115 gui->beep ();
3116 FreeConnectionLookupMemory ();
3119 /* ---------------------------------------------------------------------------
3120 * find connections for rats nesting
3121 * assumes InitConnectionLookup() has already been done
3123 void
3124 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3,
3125 bool undo, int flag, bool AndRats)
3127 User = undo;
3128 TheFlag = flag;
3129 DumpList ();
3130 ListStart (type, ptr1, ptr2, ptr3);
3131 DoIt (AndRats, false);
3132 User = false;
3135 /* ---------------------------------------------------------------------------
3136 * find all unused pins of all element
3138 void
3139 LookupUnusedPins (FILE * FP)
3141 /* reset all currently marked connections */
3142 User = true;
3143 TheFlag = FOUNDFLAG;
3144 ClearFlagOnAllObjects (true, FOUNDFLAG);
3145 InitConnectionLookup ();
3147 ELEMENT_LOOP (PCB->Data);
3149 /* break if abort dialog returned true;
3150 * passing NULL as filedescriptor discards the normal output
3152 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP))
3153 break;
3155 END_LOOP;
3157 if (Settings.RingBellWhenFinished)
3158 gui->beep ();
3159 FreeConnectionLookupMemory ();
3160 IncrementUndoSerialNumber ();
3161 User = false;
3162 Draw ();
3165 /* ---------------------------------------------------------------------------
3166 * resets all used flags of pins and vias
3168 bool
3169 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag)
3171 bool change = false;
3173 VIA_LOOP (PCB->Data);
3175 if (TEST_FLAG (flag, via))
3177 if (AndDraw)
3178 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3179 CLEAR_FLAG (flag, via);
3180 if (AndDraw)
3181 DrawVia (via);
3182 change = true;
3185 END_LOOP;
3186 ELEMENT_LOOP (PCB->Data);
3188 PIN_LOOP (element);
3190 if (TEST_FLAG (flag, pin))
3192 if (AndDraw)
3193 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3194 CLEAR_FLAG (flag, pin);
3195 if (AndDraw)
3196 DrawPin (pin);
3197 change = true;
3200 END_LOOP;
3201 PAD_LOOP (element);
3203 if (TEST_FLAG (flag, pad))
3205 if (AndDraw)
3206 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3207 CLEAR_FLAG (flag, pad);
3208 if (AndDraw)
3209 DrawPad (pad);
3210 change = true;
3213 END_LOOP;
3215 END_LOOP;
3216 if (change)
3217 SetChangedFlag (true);
3218 return change;
3221 /* ---------------------------------------------------------------------------
3222 * resets all used flags of LOs
3224 bool
3225 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag)
3227 bool change = false;
3229 RAT_LOOP (PCB->Data);
3231 if (TEST_FLAG (flag, line))
3233 if (AndDraw)
3234 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
3235 CLEAR_FLAG (flag, line);
3236 if (AndDraw)
3237 DrawRat (line);
3238 change = true;
3241 END_LOOP;
3242 COPPERLINE_LOOP (PCB->Data);
3244 if (TEST_FLAG (flag, line))
3246 if (AndDraw)
3247 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3248 CLEAR_FLAG (flag, line);
3249 if (AndDraw)
3250 DrawLine (layer, line);
3251 change = true;
3254 ENDALL_LOOP;
3255 COPPERARC_LOOP (PCB->Data);
3257 if (TEST_FLAG (flag, arc))
3259 if (AndDraw)
3260 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3261 CLEAR_FLAG (flag, arc);
3262 if (AndDraw)
3263 DrawArc (layer, arc);
3264 change = true;
3267 ENDALL_LOOP;
3268 COPPERPOLYGON_LOOP (PCB->Data);
3270 if (TEST_FLAG (flag, polygon))
3272 if (AndDraw)
3273 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3274 CLEAR_FLAG (flag, polygon);
3275 if (AndDraw)
3276 DrawPolygon (layer, polygon);
3277 change = true;
3280 ENDALL_LOOP;
3281 if (change)
3282 SetChangedFlag (true);
3283 return change;
3286 /* ---------------------------------------------------------------------------
3287 * resets all found connections
3289 bool
3290 ClearFlagOnAllObjects (bool AndDraw, int flag)
3292 bool change = false;
3294 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change;
3295 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change;
3297 return change;
3300 /*----------------------------------------------------------------------------
3301 * Dumps the list contents
3303 static void
3304 DumpList (void)
3306 Cardinal i;
3308 for (i = 0; i < 2; i++)
3310 PadList[i].Number = 0;
3311 PadList[i].Location = 0;
3312 PadList[i].DrawLocation = 0;
3315 PVList.Number = 0;
3316 PVList.Location = 0;
3318 for (i = 0; i < max_copper_layer; i++)
3320 LineList[i].Location = 0;
3321 LineList[i].DrawLocation = 0;
3322 LineList[i].Number = 0;
3323 ArcList[i].Location = 0;
3324 ArcList[i].DrawLocation = 0;
3325 ArcList[i].Number = 0;
3326 PolygonList[i].Location = 0;
3327 PolygonList[i].DrawLocation = 0;
3328 PolygonList[i].Number = 0;
3330 RatList.Number = 0;
3331 RatList.Location = 0;
3332 RatList.DrawLocation = 0;
3335 /*-----------------------------------------------------------------------------
3336 * Check for DRC violations on a single net starting from the pad or pin
3337 * sees if the connectivity changes when everything is bloated, or shrunk
3339 static bool
3340 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
3342 Coord x, y;
3343 int object_count;
3344 long int *object_id_list;
3345 int *object_type_list;
3346 DrcViolationType *violation;
3348 if (PCB->Shrink != 0)
3350 Bloat = -PCB->Shrink;
3351 TheFlag = DRCFLAG | SELECTEDFLAG;
3352 ListStart (What, ptr1, ptr2, ptr3);
3353 DoIt (true, false);
3354 /* ok now the shrunk net has the SELECTEDFLAG set */
3355 DumpList ();
3356 TheFlag = FOUNDFLAG;
3357 ListStart (What, ptr1, ptr2, ptr3);
3358 Bloat = 0;
3359 drc = true; /* abort the search if we find anything not already found */
3360 if (DoIt (true, false))
3362 DumpList ();
3363 /* make the flag changes undoable */
3364 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3365 ClearFlagOnAllObjects (false, TheFlag);
3366 User = true;
3367 drc = false;
3368 Bloat = -PCB->Shrink;
3369 TheFlag = SELECTEDFLAG;
3370 ListStart (What, ptr1, ptr2, ptr3);
3371 DoIt (true, true);
3372 DumpList ();
3373 ListStart (What, ptr1, ptr2, ptr3);
3374 TheFlag = FOUNDFLAG;
3375 Bloat = 0;
3376 drc = true;
3377 DoIt (true, true);
3378 DumpList ();
3379 User = false;
3380 drc = false;
3381 drcerr_count++;
3382 LocateError (&x, &y);
3383 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3384 violation = pcb_drc_violation_new (_("Potential for broken trace"),
3385 _("Insufficient overlap between objects can lead to broken tracks\n"
3386 "due to registration errors with old wheel style photo-plotters."),
3387 x, y,
3388 0, /* ANGLE OF ERROR UNKNOWN */
3389 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3390 0, /* MAGNITUDE OF ERROR UNKNOWN */
3391 PCB->Shrink,
3392 object_count,
3393 object_id_list,
3394 object_type_list);
3395 append_drc_violation (violation);
3396 pcb_drc_violation_free (violation);
3397 free (object_id_list);
3398 free (object_type_list);
3400 if (!throw_drc_dialog())
3401 return (true);
3402 IncrementUndoSerialNumber ();
3403 Undo (true);
3405 DumpList ();
3407 /* now check the bloated condition */
3408 drc = false;
3409 ClearFlagOnAllObjects (false, TheFlag);
3410 TheFlag = FOUNDFLAG;
3411 ListStart (What, ptr1, ptr2, ptr3);
3412 Bloat = PCB->Bloat;
3413 drc = true;
3414 while (DoIt (true, false))
3416 DumpList ();
3417 /* make the flag changes undoable */
3418 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3419 ClearFlagOnAllObjects (false, TheFlag);
3420 User = true;
3421 drc = false;
3422 Bloat = 0;
3423 TheFlag = SELECTEDFLAG;
3424 ListStart (What, ptr1, ptr2, ptr3);
3425 DoIt (true, true);
3426 DumpList ();
3427 TheFlag = FOUNDFLAG;
3428 ListStart (What, ptr1, ptr2, ptr3);
3429 Bloat = PCB->Bloat;
3430 drc = true;
3431 DoIt (true, true);
3432 DumpList ();
3433 drcerr_count++;
3434 LocateError (&x, &y);
3435 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3436 violation = pcb_drc_violation_new (_("Copper areas too close"),
3437 _("Circuits that are too close may bridge during imaging, etching,\n"
3438 "plating, or soldering processes resulting in a direct short."),
3439 x, y,
3440 0, /* ANGLE OF ERROR UNKNOWN */
3441 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3442 0, /* MAGNITUDE OF ERROR UNKNOWN */
3443 PCB->Bloat,
3444 object_count,
3445 object_id_list,
3446 object_type_list);
3447 append_drc_violation (violation);
3448 pcb_drc_violation_free (violation);
3449 free (object_id_list);
3450 free (object_type_list);
3451 User = false;
3452 drc = false;
3453 if (!throw_drc_dialog())
3454 return (true);
3455 IncrementUndoSerialNumber ();
3456 Undo (true);
3457 /* highlight the rest of the encroaching net so it's not reported again */
3458 TheFlag |= SELECTEDFLAG;
3459 Bloat = 0;
3460 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3);
3461 DoIt (true, true);
3462 DumpList ();
3463 drc = true;
3464 Bloat = PCB->Bloat;
3465 ListStart (What, ptr1, ptr2, ptr3);
3467 drc = false;
3468 DumpList ();
3469 TheFlag = FOUNDFLAG | SELECTEDFLAG;
3470 ClearFlagOnAllObjects (false, TheFlag);
3471 return (false);
3474 /* DRC clearance callback */
3476 static int
3477 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon,
3478 int type, void *ptr1, void *ptr2)
3480 char *message;
3481 Coord x, y;
3482 int object_count;
3483 long int *object_id_list;
3484 int *object_type_list;
3485 DrcViolationType *violation;
3487 LineType *line = (LineType *) ptr2;
3488 ArcType *arc = (ArcType *) ptr2;
3489 PinType *pin = (PinType *) ptr2;
3490 PadType *pad = (PadType *) ptr2;
3492 thing_type = type;
3493 thing_ptr1 = ptr1;
3494 thing_ptr2 = ptr2;
3495 thing_ptr3 = ptr2;
3496 switch (type)
3498 case LINE_TYPE:
3499 if (line->Clearance < 2 * PCB->Bloat)
3501 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3502 SET_FLAG (TheFlag, line);
3503 message = _("Line with insufficient clearance inside polygon\n");
3504 goto doIsBad;
3506 break;
3507 case ARC_TYPE:
3508 if (arc->Clearance < 2 * PCB->Bloat)
3510 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3511 SET_FLAG (TheFlag, arc);
3512 message = _("Arc with insufficient clearance inside polygon\n");
3513 goto doIsBad;
3515 break;
3516 case PAD_TYPE:
3517 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
3518 if (IsPadInPolygon(pad,polygon))
3520 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3521 SET_FLAG (TheFlag, pad);
3522 message = _("Pad with insufficient clearance inside polygon\n");
3523 goto doIsBad;
3525 break;
3526 case PIN_TYPE:
3527 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3529 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3530 SET_FLAG (TheFlag, pin);
3531 message = _("Pin with insufficient clearance inside polygon\n");
3532 goto doIsBad;
3534 break;
3535 case VIA_TYPE:
3536 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3538 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3539 SET_FLAG (TheFlag, pin);
3540 message = _("Via with insufficient clearance inside polygon\n");
3541 goto doIsBad;
3543 break;
3544 default:
3545 Message ("hace: Bad Plow object in callback\n");
3547 return 0;
3549 doIsBad:
3550 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3551 SET_FLAG (FOUNDFLAG, polygon);
3552 DrawPolygon (layer, polygon);
3553 DrawObject (type, ptr1, ptr2);
3554 drcerr_count++;
3555 LocateError (&x, &y);
3556 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3557 violation = pcb_drc_violation_new (message,
3558 _("Circuits that are too close may bridge during imaging, etching,\n"
3559 "plating, or soldering processes resulting in a direct short."),
3560 x, y,
3561 0, /* ANGLE OF ERROR UNKNOWN */
3562 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3563 0, /* MAGNITUDE OF ERROR UNKNOWN */
3564 PCB->Bloat,
3565 object_count,
3566 object_id_list,
3567 object_type_list);
3568 append_drc_violation (violation);
3569 pcb_drc_violation_free (violation);
3570 free (object_id_list);
3571 free (object_type_list);
3573 if (!throw_drc_dialog())
3574 return 1;
3576 IncrementUndoSerialNumber ();
3577 Undo (true);
3578 return 0;
3581 /*-----------------------------------------------------------------------------
3582 * Check for DRC violations
3583 * see if the connectivity changes when everything is bloated, or shrunk
3586 DRCAll (void)
3588 Coord x, y;
3589 int object_count;
3590 long int *object_id_list;
3591 int *object_type_list;
3592 DrcViolationType *violation;
3593 int tmpcnt;
3594 int nopastecnt = 0;
3595 bool IsBad;
3597 reset_drc_dialog_message();
3599 IsBad = false;
3600 drcerr_count = 0;
3601 SaveStackAndVisibility ();
3602 ResetStackAndVisibility ();
3603 hid_action ("LayersChanged");
3604 InitConnectionLookup ();
3606 TheFlag = FOUNDFLAG | DRCFLAG | SELECTEDFLAG;
3608 if (ClearFlagOnAllObjects (true, TheFlag))
3610 IncrementUndoSerialNumber ();
3611 Draw ();
3614 User = false;
3616 ELEMENT_LOOP (PCB->Data);
3618 PIN_LOOP (element);
3620 if (!TEST_FLAG (DRCFLAG, pin)
3621 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin))
3623 IsBad = true;
3624 break;
3627 END_LOOP;
3628 if (IsBad)
3629 break;
3630 PAD_LOOP (element);
3633 /* count up how many pads have no solderpaste openings */
3634 if (TEST_FLAG (NOPASTEFLAG, pad))
3635 nopastecnt++;
3637 if (!TEST_FLAG (DRCFLAG, pad)
3638 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad))
3640 IsBad = true;
3641 break;
3644 END_LOOP;
3645 if (IsBad)
3646 break;
3648 END_LOOP;
3649 if (!IsBad)
3650 VIA_LOOP (PCB->Data);
3652 if (!TEST_FLAG (DRCFLAG, via)
3653 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via))
3655 IsBad = true;
3656 break;
3659 END_LOOP;
3661 TheFlag = (IsBad) ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG);
3662 ClearFlagOnAllObjects (false, TheFlag);
3663 TheFlag = SELECTEDFLAG;
3664 /* check minimum widths and polygon clearances */
3665 if (!IsBad)
3667 COPPERLINE_LOOP (PCB->Data);
3669 /* check line clearances in polygons */
3670 if (PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback))
3672 IsBad = true;
3673 break;
3675 if (line->Thickness < PCB->minWid)
3677 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3678 SET_FLAG (TheFlag, line);
3679 DrawLine (layer, line);
3680 drcerr_count++;
3681 SetThing (LINE_TYPE, layer, line, line);
3682 LocateError (&x, &y);
3683 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3684 violation = pcb_drc_violation_new (_("Line width is too thin"),
3685 _("Process specifications dictate a minimum feature-width\n"
3686 "that can reliably be reproduced"),
3687 x, y,
3688 0, /* ANGLE OF ERROR UNKNOWN */
3689 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3690 line->Thickness,
3691 PCB->minWid,
3692 object_count,
3693 object_id_list,
3694 object_type_list);
3695 append_drc_violation (violation);
3696 pcb_drc_violation_free (violation);
3697 free (object_id_list);
3698 free (object_type_list);
3699 if (!throw_drc_dialog())
3701 IsBad = true;
3702 break;
3704 IncrementUndoSerialNumber ();
3705 Undo (false);
3708 ENDALL_LOOP;
3710 if (!IsBad)
3712 COPPERARC_LOOP (PCB->Data);
3714 if (PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback))
3716 IsBad = true;
3717 break;
3719 if (arc->Thickness < PCB->minWid)
3721 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3722 SET_FLAG (TheFlag, arc);
3723 DrawArc (layer, arc);
3724 drcerr_count++;
3725 SetThing (ARC_TYPE, layer, arc, arc);
3726 LocateError (&x, &y);
3727 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3728 violation = pcb_drc_violation_new (_("Arc width is too thin"),
3729 _("Process specifications dictate a minimum feature-width\n"
3730 "that can reliably be reproduced"),
3731 x, y,
3732 0, /* ANGLE OF ERROR UNKNOWN */
3733 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3734 arc->Thickness,
3735 PCB->minWid,
3736 object_count,
3737 object_id_list,
3738 object_type_list);
3739 append_drc_violation (violation);
3740 pcb_drc_violation_free (violation);
3741 free (object_id_list);
3742 free (object_type_list);
3743 if (!throw_drc_dialog())
3745 IsBad = true;
3746 break;
3748 IncrementUndoSerialNumber ();
3749 Undo (false);
3752 ENDALL_LOOP;
3754 if (!IsBad)
3756 ALLPIN_LOOP (PCB->Data);
3758 if (PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback))
3760 IsBad = true;
3761 break;
3763 if (!TEST_FLAG (HOLEFLAG, pin) &&
3764 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing)
3766 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3767 SET_FLAG (TheFlag, pin);
3768 DrawPin (pin);
3769 drcerr_count++;
3770 SetThing (PIN_TYPE, element, pin, pin);
3771 LocateError (&x, &y);
3772 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3773 violation = pcb_drc_violation_new (_("Pin annular ring too small"),
3774 _("Annular rings that are too small may erode during etching,\n"
3775 "resulting in a broken connection"),
3776 x, y,
3777 0, /* ANGLE OF ERROR UNKNOWN */
3778 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3779 (pin->Thickness - pin->DrillingHole) / 2,
3780 PCB->minRing,
3781 object_count,
3782 object_id_list,
3783 object_type_list);
3784 append_drc_violation (violation);
3785 pcb_drc_violation_free (violation);
3786 free (object_id_list);
3787 free (object_type_list);
3788 if (!throw_drc_dialog())
3790 IsBad = true;
3791 break;
3793 IncrementUndoSerialNumber ();
3794 Undo (false);
3796 if (pin->DrillingHole < PCB->minDrill)
3798 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3799 SET_FLAG (TheFlag, pin);
3800 DrawPin (pin);
3801 drcerr_count++;
3802 SetThing (PIN_TYPE, element, pin, pin);
3803 LocateError (&x, &y);
3804 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3805 violation = pcb_drc_violation_new (_("Pin drill size is too small"),
3806 _("Process rules dictate the minimum drill size which can be used"),
3807 x, y,
3808 0, /* ANGLE OF ERROR UNKNOWN */
3809 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3810 pin->DrillingHole,
3811 PCB->minDrill,
3812 object_count,
3813 object_id_list,
3814 object_type_list);
3815 append_drc_violation (violation);
3816 pcb_drc_violation_free (violation);
3817 free (object_id_list);
3818 free (object_type_list);
3819 if (!throw_drc_dialog())
3821 IsBad = true;
3822 break;
3824 IncrementUndoSerialNumber ();
3825 Undo (false);
3828 ENDALL_LOOP;
3830 if (!IsBad)
3832 ALLPAD_LOOP (PCB->Data);
3834 if (PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback))
3836 IsBad = true;
3837 break;
3839 if (pad->Thickness < PCB->minWid)
3841 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3842 SET_FLAG (TheFlag, pad);
3843 DrawPad (pad);
3844 drcerr_count++;
3845 SetThing (PAD_TYPE, element, pad, pad);
3846 LocateError (&x, &y);
3847 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3848 violation = pcb_drc_violation_new (_("Pad is too thin"),
3849 _("Pads which are too thin may erode during etching,\n"
3850 "resulting in a broken or unreliable connection"),
3851 x, y,
3852 0, /* ANGLE OF ERROR UNKNOWN */
3853 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3854 pad->Thickness,
3855 PCB->minWid,
3856 object_count,
3857 object_id_list,
3858 object_type_list);
3859 append_drc_violation (violation);
3860 pcb_drc_violation_free (violation);
3861 free (object_id_list);
3862 free (object_type_list);
3863 if (!throw_drc_dialog())
3865 IsBad = true;
3866 break;
3868 IncrementUndoSerialNumber ();
3869 Undo (false);
3872 ENDALL_LOOP;
3874 if (!IsBad)
3876 VIA_LOOP (PCB->Data);
3878 if (PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback))
3880 IsBad = true;
3881 break;
3883 if (!TEST_FLAG (HOLEFLAG, via) &&
3884 via->Thickness - via->DrillingHole < 2 * PCB->minRing)
3886 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3887 SET_FLAG (TheFlag, via);
3888 DrawVia (via);
3889 drcerr_count++;
3890 SetThing (VIA_TYPE, via, via, via);
3891 LocateError (&x, &y);
3892 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3893 violation = pcb_drc_violation_new (_("Via annular ring too small"),
3894 _("Annular rings that are too small may erode during etching,\n"
3895 "resulting in a broken connection"),
3896 x, y,
3897 0, /* ANGLE OF ERROR UNKNOWN */
3898 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3899 (via->Thickness - via->DrillingHole) / 2,
3900 PCB->minRing,
3901 object_count,
3902 object_id_list,
3903 object_type_list);
3904 append_drc_violation (violation);
3905 pcb_drc_violation_free (violation);
3906 free (object_id_list);
3907 free (object_type_list);
3908 if (!throw_drc_dialog())
3910 IsBad = true;
3911 break;
3913 IncrementUndoSerialNumber ();
3914 Undo (false);
3916 if (via->DrillingHole < PCB->minDrill)
3918 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3919 SET_FLAG (TheFlag, via);
3920 DrawVia (via);
3921 drcerr_count++;
3922 SetThing (VIA_TYPE, via, via, via);
3923 LocateError (&x, &y);
3924 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3925 violation = pcb_drc_violation_new (_("Via drill size is too small"),
3926 _("Process rules dictate the minimum drill size which can be used"),
3927 x, y,
3928 0, /* ANGLE OF ERROR UNKNOWN */
3929 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3930 via->DrillingHole,
3931 PCB->minDrill,
3932 object_count,
3933 object_id_list,
3934 object_type_list);
3935 append_drc_violation (violation);
3936 pcb_drc_violation_free (violation);
3937 free (object_id_list);
3938 free (object_type_list);
3939 if (!throw_drc_dialog())
3941 IsBad = true;
3942 break;
3944 IncrementUndoSerialNumber ();
3945 Undo (false);
3948 END_LOOP;
3951 FreeConnectionLookupMemory ();
3952 TheFlag = FOUNDFLAG;
3953 Bloat = 0;
3955 /* check silkscreen minimum widths outside of elements */
3956 /* XXX - need to check text and polygons too! */
3957 TheFlag = SELECTEDFLAG;
3958 if (!IsBad)
3960 SILKLINE_LOOP (PCB->Data);
3962 if (line->Thickness < PCB->minSlk)
3964 SET_FLAG (TheFlag, line);
3965 DrawLine (layer, line);
3966 drcerr_count++;
3967 SetThing (LINE_TYPE, layer, line, line);
3968 LocateError (&x, &y);
3969 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3970 violation = pcb_drc_violation_new (_("Silk line is too thin"),
3971 _("Process specifications dictate a minimum silkscreen feature-width\n"
3972 "that can reliably be reproduced"),
3973 x, y,
3974 0, /* ANGLE OF ERROR UNKNOWN */
3975 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3976 line->Thickness,
3977 PCB->minSlk,
3978 object_count,
3979 object_id_list,
3980 object_type_list);
3981 append_drc_violation (violation);
3982 pcb_drc_violation_free (violation);
3983 free (object_id_list);
3984 free (object_type_list);
3985 if (!throw_drc_dialog())
3987 IsBad = true;
3988 break;
3992 ENDALL_LOOP;
3995 /* check silkscreen minimum widths inside of elements */
3996 /* XXX - need to check text and polygons too! */
3997 TheFlag = SELECTEDFLAG;
3998 if (!IsBad)
4000 ELEMENT_LOOP (PCB->Data);
4002 tmpcnt = 0;
4003 ELEMENTLINE_LOOP (element);
4005 if (line->Thickness < PCB->minSlk)
4006 tmpcnt++;
4008 END_LOOP;
4009 if (tmpcnt > 0)
4011 char *title;
4012 char *name;
4013 char *buffer;
4014 int buflen;
4016 SET_FLAG (TheFlag, element);
4017 DrawElement (element);
4018 drcerr_count++;
4019 SetThing (ELEMENT_TYPE, element, element, element);
4020 LocateError (&x, &y);
4021 BuildObjectList (&object_count, &object_id_list, &object_type_list);
4023 title = _("Element %s has %i silk lines which are too thin");
4024 name = (char *)UNKNOWN (NAMEONPCB_NAME (element));
4026 /* -4 is for the %s and %i place-holders */
4027 /* +11 is the max printed length for a 32 bit integer */
4028 /* +1 is for the \0 termination */
4029 buflen = strlen (title) - 4 + strlen (name) + 11 + 1;
4030 buffer = (char *)malloc (buflen);
4031 snprintf (buffer, buflen, title, name, tmpcnt);
4033 violation = pcb_drc_violation_new (buffer,
4034 _("Process specifications dictate a minimum silkscreen\n"
4035 "feature-width that can reliably be reproduced"),
4036 x, y,
4037 0, /* ANGLE OF ERROR UNKNOWN */
4038 TRUE, /* MEASUREMENT OF ERROR KNOWN */
4039 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4040 PCB->minSlk,
4041 object_count,
4042 object_id_list,
4043 object_type_list);
4044 free (buffer);
4045 append_drc_violation (violation);
4046 pcb_drc_violation_free (violation);
4047 free (object_id_list);
4048 free (object_type_list);
4049 if (!throw_drc_dialog())
4051 IsBad = true;
4052 break;
4056 END_LOOP;
4060 if (IsBad)
4062 IncrementUndoSerialNumber ();
4066 RestoreStackAndVisibility ();
4067 hid_action ("LayersChanged");
4068 gui->invalidate_all ();
4070 if (nopastecnt > 0)
4072 Message (_("Warning: %d pad%s the nopaste flag set.\n"),
4073 nopastecnt,
4074 nopastecnt > 1 ? "s have" : " has");
4076 return IsBad ? -drcerr_count : drcerr_count;
4079 /*----------------------------------------------------------------------------
4080 * Locate the coordinatates of offending item (thing)
4082 static void
4083 LocateError (Coord *x, Coord *y)
4085 switch (thing_type)
4087 case LINE_TYPE:
4089 LineType *line = (LineType *) thing_ptr3;
4090 *x = (line->Point1.X + line->Point2.X) / 2;
4091 *y = (line->Point1.Y + line->Point2.Y) / 2;
4092 break;
4094 case ARC_TYPE:
4096 ArcType *arc = (ArcType *) thing_ptr3;
4097 *x = arc->X;
4098 *y = arc->Y;
4099 break;
4101 case POLYGON_TYPE:
4103 PolygonType *polygon = (PolygonType *) thing_ptr3;
4104 *x =
4105 (polygon->Clipped->contours->xmin +
4106 polygon->Clipped->contours->xmax) / 2;
4107 *y =
4108 (polygon->Clipped->contours->ymin +
4109 polygon->Clipped->contours->ymax) / 2;
4110 break;
4112 case PIN_TYPE:
4113 case VIA_TYPE:
4115 PinType *pin = (PinType *) thing_ptr3;
4116 *x = pin->X;
4117 *y = pin->Y;
4118 break;
4120 case PAD_TYPE:
4122 PadType *pad = (PadType *) thing_ptr3;
4123 *x = (pad->Point1.X + pad->Point2.X) / 2;
4124 *y = (pad->Point1.Y + pad->Point2.Y) / 2;
4125 break;
4127 case ELEMENT_TYPE:
4129 ElementType *element = (ElementType *) thing_ptr3;
4130 *x = element->MarkX;
4131 *y = element->MarkY;
4132 break;
4134 default:
4135 return;
4140 /*----------------------------------------------------------------------------
4141 * Build a list of the of offending items by ID. (Currently just "thing")
4143 static void
4144 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
4146 *object_count = 0;
4147 *object_id_list = NULL;
4148 *object_type_list = NULL;
4150 switch (thing_type)
4152 case LINE_TYPE:
4153 case ARC_TYPE:
4154 case POLYGON_TYPE:
4155 case PIN_TYPE:
4156 case VIA_TYPE:
4157 case PAD_TYPE:
4158 case ELEMENT_TYPE:
4159 case RATLINE_TYPE:
4160 *object_count = 1;
4161 *object_id_list = (long int *)malloc (sizeof (long int));
4162 *object_type_list = (int *)malloc (sizeof (int));
4163 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
4164 **object_type_list = thing_type;
4165 return;
4167 default:
4168 fprintf (stderr,
4169 _("Internal error in BuildObjectList: unknown object type %i\n"),
4170 thing_type);
4175 /*----------------------------------------------------------------------------
4176 * center the display to show the offending item (thing)
4178 static void
4179 GotoError (void)
4181 Coord X, Y;
4183 LocateError (&X, &Y);
4185 switch (thing_type)
4187 case LINE_TYPE:
4188 case ARC_TYPE:
4189 case POLYGON_TYPE:
4190 ChangeGroupVisibility (
4191 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1),
4192 true, true);
4194 CenterDisplay (X, Y);
4197 void
4198 InitConnectionLookup (void)
4200 InitComponentLookup ();
4201 InitLayoutLookup ();
4204 void
4205 FreeConnectionLookupMemory (void)
4207 FreeComponentLookupMemory ();
4208 FreeLayoutLookupMemory ();