src/hid/lesstif/menu.c: Added doxygen comments for GetXY().
[geda-pcb/pcjc2.git] / src / find.c
blob92f9d6d31801c64c4fd0c0a5f467f990e7ae1468
1 /*!
2 * \file src/find.c
4 * \brief Routines to find connections between pins, vias, lines ...
6 * Short description:\n
7 * <ul>
8 * <li> Lists for pins and vias, lines, arcs, pads and for polygons are
9 * created.\n
10 * Every object that has to be checked is added to its list.\n
11 * Coarse searching is accomplished with the data rtrees.</li>
12 * <li> There's no 'speed-up' mechanism for polygons because they are
13 * not used as often as other objects.</li>
14 * <li> The maximum distance between line and pin ... would depend on
15 * the angle between them. To speed up computation the limit is set
16 * to one half of the thickness of the objects (cause of square
17 * pins).</li>
18 * </ul>
20 * PV: means pin or via (objects that connect layers).\n
21 * LO: all non PV objects (layer objects like lines, arcs, polygons,
22 * pads).
24 * <ol>
25 * <li> First, the LO or PV at the given coordinates is looked
26 * up.</li>
27 * <li> All LO connections to that PV are looked up next.</li>
28 * <li> Lookup of all LOs connected to LOs from (2).\n
29 * This step is repeated until no more new connections are found.</li>
30 * <li> Lookup all PVs connected to the LOs from (2) and (3).</li>
31 * <li> Start again with (1) for all new PVs from (4).</li>
32 * </ol>
34 * Intersection of line <--> circle:\n
35 * <ul>
36 * <li> Calculate the signed distance from the line to the center,
37 * return false if abs(distance) > R.</li>
38 * <li> Get the distance from the line <--> distancevector intersection
39 * to (X1,Y1) in range [0,1], return true if 0 <= distance <= 1.</li>
40 * <li> Depending on (r > 1.0 or r < 0.0) check the distance of X2,Y2 or
41 * X1,Y1 to X,Y.</li>
42 * </ul>
44 * Intersection of line <--> line:\n
45 * <ul>
46 * <li> See the description of 'LineLineIntersect()'.</li>
47 * </ul>
49 * <hr>
51 * <h1><b>Copyright.</b></h1>\n
53 * PCB, interactive printed circuit board design
55 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
57 * This program is free software; you can redistribute it and/or modify
58 * it under the terms of the GNU General Public License as published by
59 * the Free Software Foundation; either version 2 of the License, or
60 * (at your option) any later version.
62 * This program is distributed in the hope that it will be useful,
63 * but WITHOUT ANY WARRANTY; without even the implied warranty of
64 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
65 * GNU General Public License for more details.
67 * You should have received a copy of the GNU General Public License
68 * along with this program; if not, write to the Free Software
69 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
71 * Contact addresses for paper mail and Email:
72 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
73 * Thomas.Nau@rz.uni-ulm.de
76 #ifdef HAVE_CONFIG_H
77 #include "config.h"
78 #endif
80 #include <setjmp.h>
81 #include <assert.h>
83 #include "global.h"
85 #include "data.h"
86 #include "draw.h"
87 #include "error.h"
88 #include "find.h"
89 #include "misc.h"
90 #include "rtree.h"
91 #include "polygon.h"
92 #include "pcb-printf.h"
93 #include "search.h"
94 #include "set.h"
95 #include "undo.h"
96 #include "rats.h"
98 #ifdef HAVE_LIBDMALLOC
99 #include <dmalloc.h>
100 #endif
102 #undef DEBUG
104 /* ---------------------------------------------------------------------------
105 * some local macros
108 #define SEPARATE(FP) \
110 int i; \
111 fputc('#', (FP)); \
112 for (i = Settings.CharPerLine; i; i--) \
113 fputc('=', (FP)); \
114 fputc('\n', (FP)); \
117 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)])
118 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)])
119 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)])
120 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)])
121 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)])
122 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)])
123 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)])
125 #define IS_PV_ON_RAT(PV, Rat) \
126 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat)))
128 #define IS_PV_ON_ARC(PV, Arc) \
129 (TEST_FLAG(SQUAREFLAG, (PV)) ? \
130 IsArcInRectangle( \
131 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \
132 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \
133 (Arc)) : \
134 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc)))
136 #define IS_PV_ON_PAD(PV,Pad) \
137 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
140 static DrcViolationType
141 *pcb_drc_violation_new (const char *title,
142 const char *explanation,
143 Coord x, Coord y,
144 Angle angle,
145 bool have_measured,
146 Coord measured_value,
147 Coord required_value,
148 int object_count,
149 long int *object_id_list,
150 int *object_type_list)
152 DrcViolationType *violation = (DrcViolationType *)malloc (sizeof (DrcViolationType));
154 violation->title = strdup (title);
155 violation->explanation = strdup (explanation);
156 violation->x = x;
157 violation->y = y;
158 violation->angle = angle;
159 violation->have_measured = have_measured;
160 violation->measured_value = measured_value;
161 violation->required_value = required_value;
162 violation->object_count = object_count;
163 violation->object_id_list = object_id_list;
164 violation->object_type_list = object_type_list;
166 return violation;
169 static void
170 pcb_drc_violation_free (DrcViolationType *violation)
172 free (violation->title);
173 free (violation->explanation);
174 free (violation);
177 static GString *drc_dialog_message;
178 static void
179 reset_drc_dialog_message(void)
181 if (drc_dialog_message)
182 g_string_free (drc_dialog_message, FALSE);
183 drc_dialog_message = g_string_new ("");
184 if (gui->drc_gui != NULL)
186 gui->drc_gui->reset_drc_dialog_message ();
189 static void
190 append_drc_dialog_message(const char *fmt, ...)
192 gchar *new_str;
193 va_list ap;
194 va_start (ap, fmt);
195 new_str = pcb_vprintf (fmt, ap);
196 g_string_append (drc_dialog_message, new_str);
197 va_end (ap);
198 g_free (new_str);
201 static void GotoError (void);
203 static void
204 append_drc_violation (DrcViolationType *violation)
206 if (gui->drc_gui != NULL)
208 gui->drc_gui->append_drc_violation (violation);
210 else
212 /* Fallback to formatting the violation message as text */
213 append_drc_dialog_message ("%s\n", violation->title);
214 append_drc_dialog_message (_("%m+near %$mD\n"),
215 Settings.grid_unit->allow,
216 violation->x, violation->y);
217 GotoError ();
220 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_violations )
222 Message (_("WARNING! Design Rule error - %s\n"), violation->title);
223 Message (_("%m+near location %$mD\n"),
224 Settings.grid_unit->allow,
225 violation->x, violation->y);
229 #define DRC_CONTINUE _("Press Next to continue DRC checking")
230 #define DRC_NEXT _("Next")
231 #define DRC_CANCEL _("Cancel")
234 * \brief Message when asked about continuing DRC checks after next
235 * violation is found.
237 static int
238 throw_drc_dialog(void)
240 int r;
242 if (gui->drc_gui != NULL)
244 r = gui->drc_gui->throw_drc_dialog ();
246 else
248 /* Fallback to formatting the violation message as text */
249 append_drc_dialog_message (DRC_CONTINUE);
250 r = gui->confirm_dialog (drc_dialog_message->str, DRC_CANCEL, DRC_NEXT);
251 reset_drc_dialog_message();
253 return r;
257 * \brief Some local types.
259 * The two 'dummy' structs for PVs and Pads are necessary for creating
260 * connection lists which include the element's name.
262 typedef struct
264 void **Data; /*!< Pointer to index data. */
265 Cardinal Location, /*!< Currently used position. */
266 DrawLocation, Number, /*!< Number of objects in list. */
267 Size;
268 } ListType;
270 /* ---------------------------------------------------------------------------
271 * some local identifiers
273 static Coord Bloat = 0;
274 static void *thing_ptr1, *thing_ptr2, *thing_ptr3;
275 static int thing_type;
276 static bool User = false; /*!< User action causing this. */
277 static bool drc = false; /*!< Whether to stop if finding something not found. */
278 static Cardinal drcerr_count; /*!< Count of drc errors */
279 static Cardinal TotalP, TotalV;
280 static ListType LineList[MAX_LAYER], /*!< List of objects to. */
281 PolygonList[MAX_LAYER], ArcList[MAX_LAYER], PadList[2], RatList, PVList;
283 /* ---------------------------------------------------------------------------
284 * some local prototypes
286 static bool LookupLOConnectionsToLine (LineType *, Cardinal, int, bool, bool);
287 static bool LookupLOConnectionsToPad (PadType *, Cardinal, int, bool);
288 static bool LookupLOConnectionsToPolygon (PolygonType *, Cardinal, int, bool);
289 static bool LookupLOConnectionsToArc (ArcType *, Cardinal, int, bool);
290 static bool LookupLOConnectionsToRatEnd (PointType *, Cardinal, int);
291 static bool IsRatPointOnLineEnd (PointType *, LineType *);
292 static bool ArcArcIntersect (ArcType *, ArcType *);
293 static bool PrepareNextLoop (FILE *);
294 static void DrawNewConnections (void);
295 static void DumpList (void);
296 static void LocateError (Coord *, Coord *);
297 static void BuildObjectList (int *, long int **, int **);
298 static bool SetThing (int, void *, void *, void *);
299 static bool IsArcInPolygon (ArcType *, PolygonType *);
300 static bool IsLineInPolygon (LineType *, PolygonType *);
301 static bool IsPadInPolygon (PadType *, PolygonType *);
302 static bool IsPolygonInPolygon (PolygonType *, PolygonType *);
305 * \brief.
307 * Some of the 'pad' routines are the same as for lines because the 'pad'
308 * struct starts with a line struct. See global.h for details.
310 bool
311 LinePadIntersect (LineType *Line, PadType *Pad)
313 return LineLineIntersect ((Line), (LineType *)Pad);
316 bool
317 ArcPadIntersect (ArcType *Arc, PadType *Pad)
319 return LineArcIntersect ((LineType *) (Pad), (Arc));
322 static bool
323 add_object_to_list (ListType *list, int type, void *ptr1, void *ptr2, void *ptr3, int flag)
325 AnyObjectType *object = (AnyObjectType *)ptr2;
327 if (User)
328 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3);
330 SET_FLAG (flag, object);
331 LIST_ENTRY (list, list->Number) = object;
332 list->Number++;
334 #ifdef DEBUG
335 if (list.Number > list.Size)
336 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type, list.Number, list.Size);
337 #endif
339 if (drc && !TEST_FLAG (SELECTEDFLAG, object))
340 return (SetThing (type, ptr1, ptr2, ptr3));
341 return false;
344 static bool
345 ADD_PV_TO_LIST (PinType *Pin, int flag)
347 return add_object_to_list (&PVList, Pin->Element ? PIN_TYPE : VIA_TYPE,
348 Pin->Element ? Pin->Element : Pin, Pin, Pin, flag);
351 static bool
352 ADD_PAD_TO_LIST (Cardinal L, PadType *Pad, int flag)
354 return add_object_to_list (&PadList[L], PAD_TYPE, Pad->Element, Pad, Pad, flag);
357 static bool
358 ADD_LINE_TO_LIST (Cardinal L, LineType *Ptr, int flag)
360 return add_object_to_list (&LineList[L], LINE_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
363 static bool
364 ADD_ARC_TO_LIST (Cardinal L, ArcType *Ptr, int flag)
366 return add_object_to_list (&ArcList[L], ARC_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
369 static bool
370 ADD_RAT_TO_LIST (RatType *Ptr, int flag)
372 return add_object_to_list (&RatList, RATLINE_TYPE, Ptr, Ptr, Ptr, flag);
375 static bool
376 ADD_POLYGON_TO_LIST (Cardinal L, PolygonType *Ptr, int flag)
378 return add_object_to_list (&PolygonList[L], POLYGON_TYPE, LAYER_PTR (L), Ptr, Ptr, flag);
381 static BoxType
382 expand_bounds (BoxType *box_in)
384 BoxType box_out = *box_in;
386 if (Bloat > 0)
388 box_out.X1 -= Bloat;
389 box_out.X2 += Bloat;
390 box_out.Y1 -= Bloat;
391 box_out.Y2 += Bloat;
394 return box_out;
397 bool
398 PinLineIntersect (PinType *PV, LineType *Line)
400 /* IsLineInRectangle already has Bloat factor */
401 return TEST_FLAG (SQUAREFLAG,
402 PV) ? IsLineInRectangle (PV->X - (PIN_SIZE (PV) + 1) / 2,
403 PV->Y - (PIN_SIZE (PV) + 1) / 2,
404 PV->X + (PIN_SIZE (PV) + 1) / 2,
405 PV->Y + (PIN_SIZE (PV) + 1) / 2,
406 Line) : IsPointInPad (PV->X,
407 PV->Y,
408 MAX (PIN_SIZE (PV)
410 2.0 +
411 Bloat,
412 0.0),
413 (PadType *)Line);
417 bool
418 SetThing (int type, void *ptr1, void *ptr2, void *ptr3)
420 thing_ptr1 = ptr1;
421 thing_ptr2 = ptr2;
422 thing_ptr3 = ptr3;
423 thing_type = type;
424 return true;
427 bool
428 BoxBoxIntersection (BoxType *b1, BoxType *b2)
430 if (b2->X2 < b1->X1 || b2->X1 > b1->X2)
431 return false;
432 if (b2->Y2 < b1->Y1 || b2->Y1 > b1->Y2)
433 return false;
434 return true;
437 static bool
438 PadPadIntersect (PadType *p1, PadType *p2)
440 return LinePadIntersect ((LineType *) p1, p2);
443 static inline bool
444 PV_TOUCH_PV (PinType *PV1, PinType *PV2)
446 double t1, t2;
447 BoxType b1, b2;
449 t1 = MAX (PV1->Thickness / 2.0 + Bloat, 0);
450 t2 = MAX (PV2->Thickness / 2.0 + Bloat, 0);
451 if (IsPointOnPin (PV1->X, PV1->Y, t1, PV2)
452 || IsPointOnPin (PV2->X, PV2->Y, t2, PV1))
453 return true;
454 if (!TEST_FLAG (SQUAREFLAG, PV1) || !TEST_FLAG (SQUAREFLAG, PV2))
455 return false;
456 /* check for square/square overlap */
457 b1.X1 = PV1->X - t1;
458 b1.X2 = PV1->X + t1;
459 b1.Y1 = PV1->Y - t1;
460 b1.Y2 = PV1->Y + t1;
461 t2 = PV2->Thickness / 2.0;
462 b2.X1 = PV2->X - t2;
463 b2.X2 = PV2->X + t2;
464 b2.Y1 = PV2->Y - t2;
465 b2.Y2 = PV2->Y + t2;
466 return BoxBoxIntersection (&b1, &b2);
470 * \brief Releases all allocated memory.
472 static void
473 FreeLayoutLookupMemory (void)
475 Cardinal i;
477 for (i = 0; i < max_copper_layer; i++)
479 free (LineList[i].Data);
480 LineList[i].Data = NULL;
481 free (ArcList[i].Data);
482 ArcList[i].Data = NULL;
483 free (PolygonList[i].Data);
484 PolygonList[i].Data = NULL;
486 free (PVList.Data);
487 PVList.Data = NULL;
488 free (RatList.Data);
489 RatList.Data = NULL;
492 static void
493 FreeComponentLookupMemory (void)
495 free (PadList[0].Data);
496 PadList[0].Data = NULL;
497 free (PadList[1].Data);
498 PadList[1].Data = NULL;
502 * \brief Allocates memory for component related stacks ...
504 * Initializes index and sorts it by X1 and X2.
506 static void
507 InitComponentLookup (void)
509 Cardinal NumberOfPads[2];
510 Cardinal i;
512 /* initialize pad data; start by counting the total number
513 * on each of the two possible layers
515 NumberOfPads[TOP_SIDE] = NumberOfPads[BOTTOM_SIDE] = 0;
516 ALLPAD_LOOP (PCB->Data);
518 if (TEST_FLAG (ONSOLDERFLAG, pad))
519 NumberOfPads[BOTTOM_SIDE]++;
520 else
521 NumberOfPads[TOP_SIDE]++;
523 ENDALL_LOOP;
524 for (i = 0; i < 2; i++)
526 /* allocate memory for working list */
527 PadList[i].Data = (void **)calloc (NumberOfPads[i], sizeof (PadType *));
529 /* clear some struct members */
530 PadList[i].Location = 0;
531 PadList[i].DrawLocation = 0;
532 PadList[i].Number = 0;
533 PadList[i].Size = NumberOfPads[i];
538 * \brief Allocates memory for layout related stacks ...
540 * Initializes index and sorts it by X1 and X2.
542 static void
543 InitLayoutLookup (void)
545 Cardinal i;
547 /* initialize line arc and polygon data */
548 for (i = 0; i < max_copper_layer; i++)
550 LayerType *layer = LAYER_PTR (i);
552 if (layer->LineN)
554 /* allocate memory for line pointer lists */
555 LineList[i].Data = (void **)calloc (layer->LineN, sizeof (LineType *));
556 LineList[i].Size = layer->LineN;
558 if (layer->ArcN)
560 ArcList[i].Data = (void **)calloc (layer->ArcN, sizeof (ArcType *));
561 ArcList[i].Size = layer->ArcN;
565 /* allocate memory for polygon list */
566 if (layer->PolygonN)
568 PolygonList[i].Data = (void **)calloc (layer->PolygonN, sizeof (PolygonType *));
569 PolygonList[i].Size = layer->PolygonN;
572 /* clear some struct members */
573 LineList[i].Location = 0;
574 LineList[i].DrawLocation = 0;
575 LineList[i].Number = 0;
576 ArcList[i].Location = 0;
577 ArcList[i].DrawLocation = 0;
578 ArcList[i].Number = 0;
579 PolygonList[i].Location = 0;
580 PolygonList[i].DrawLocation = 0;
581 PolygonList[i].Number = 0;
584 if (PCB->Data->pin_tree)
585 TotalP = PCB->Data->pin_tree->size;
586 else
587 TotalP = 0;
588 if (PCB->Data->via_tree)
589 TotalV = PCB->Data->via_tree->size;
590 else
591 TotalV = 0;
592 /* allocate memory for 'new PV to check' list and clear struct */
593 PVList.Data = (void **)calloc (TotalP + TotalV, sizeof (PinType *));
594 PVList.Size = TotalP + TotalV;
595 PVList.Location = 0;
596 PVList.DrawLocation = 0;
597 PVList.Number = 0;
598 /* Initialize ratline data */
599 RatList.Data = (void **)calloc (PCB->Data->RatN, sizeof (RatType *));
600 RatList.Size = PCB->Data->RatN;
601 RatList.Location = 0;
602 RatList.DrawLocation = 0;
603 RatList.Number = 0;
606 struct pv_info
608 Cardinal layer;
609 PinType *pv;
610 int flag;
611 jmp_buf env;
614 static int
615 LOCtoPVline_callback (const BoxType * b, void *cl)
617 LineType *line = (LineType *) b;
618 struct pv_info *i = (struct pv_info *) cl;
620 if (!TEST_FLAG (i->flag, line) && PinLineIntersect (i->pv, line) &&
621 !TEST_FLAG (HOLEFLAG, i->pv))
623 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
624 longjmp (i->env, 1);
626 return 0;
629 static int
630 LOCtoPVarc_callback (const BoxType * b, void *cl)
632 ArcType *arc = (ArcType *) b;
633 struct pv_info *i = (struct pv_info *) cl;
635 if (!TEST_FLAG (i->flag, arc) && IS_PV_ON_ARC (i->pv, arc) &&
636 !TEST_FLAG (HOLEFLAG, i->pv))
638 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
639 longjmp (i->env, 1);
641 return 0;
644 static int
645 LOCtoPVpad_callback (const BoxType * b, void *cl)
647 PadType *pad = (PadType *) b;
648 struct pv_info *i = (struct pv_info *) cl;
650 if (!TEST_FLAG (i->flag, pad) && IS_PV_ON_PAD (i->pv, pad) &&
651 !TEST_FLAG (HOLEFLAG, i->pv) &&
652 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE :
653 TOP_SIDE, pad, i->flag))
654 longjmp (i->env, 1);
655 return 0;
658 static int
659 LOCtoPVrat_callback (const BoxType * b, void *cl)
661 RatType *rat = (RatType *) b;
662 struct pv_info *i = (struct pv_info *) cl;
664 if (!TEST_FLAG (i->flag, rat) && IS_PV_ON_RAT (i->pv, rat) &&
665 ADD_RAT_TO_LIST (rat, i->flag))
666 longjmp (i->env, 1);
667 return 0;
669 static int
670 LOCtoPVpoly_callback (const BoxType * b, void *cl)
672 PolygonType *polygon = (PolygonType *) b;
673 struct pv_info *i = (struct pv_info *) cl;
675 /* if the pin doesn't have a therm and polygon is clearing
676 * then it can't touch due to clearance, so skip the expensive
677 * test. If it does have a therm, you still need to test
678 * because it might not be inside the polygon, or it could
679 * be on an edge such that it doesn't actually touch.
681 if (!TEST_FLAG (i->flag, polygon) && !TEST_FLAG (HOLEFLAG, i->pv) &&
682 (TEST_THERM (i->layer, i->pv) ||
683 !TEST_FLAG (CLEARPOLYFLAG,
684 polygon)
685 || !i->pv->Clearance))
687 double wide = MAX (0.5 * i->pv->Thickness + Bloat, 0);
688 if (TEST_FLAG (SQUAREFLAG, i->pv))
690 Coord x1 = i->pv->X - (i->pv->Thickness + 1 + Bloat) / 2;
691 Coord x2 = i->pv->X + (i->pv->Thickness + 1 + Bloat) / 2;
692 Coord y1 = i->pv->Y - (i->pv->Thickness + 1 + Bloat) / 2;
693 Coord y2 = i->pv->Y + (i->pv->Thickness + 1 + Bloat) / 2;
694 if (IsRectangleInPolygon (x1, y1, x2, y2, polygon)
695 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
696 longjmp (i->env, 1);
698 else if (TEST_FLAG (OCTAGONFLAG, i->pv))
700 POLYAREA *oct = OctagonPoly (i->pv->X, i->pv->Y, i->pv->Thickness / 2);
701 if (isects (oct, polygon, true)
702 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
703 longjmp (i->env, 1);
705 else if (IsPointInPolygon (i->pv->X, i->pv->Y, wide,
706 polygon)
707 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
708 longjmp (i->env, 1);
710 return 0;
714 * \brief Checks if a PV is connected to LOs, if it is, the LO is added
715 * to the appropriate list and the 'used' flag is set.
717 static bool
718 LookupLOConnectionsToPVList (int flag, bool AndRats)
720 Cardinal layer_no;
721 struct pv_info info;
723 info.flag = flag;
725 /* loop over all PVs currently on list */
726 while (PVList.Location < PVList.Number)
728 BoxType search_box;
730 /* get pointer to data */
731 info.pv = PVLIST_ENTRY (PVList.Location);
732 search_box = expand_bounds (&info.pv->BoundingBox);
734 /* check pads */
735 if (setjmp (info.env) == 0)
736 r_search (PCB->Data->pad_tree, &search_box, NULL,
737 LOCtoPVpad_callback, &info);
738 else
739 return true;
741 /* now all lines, arcs and polygons of the several layers */
742 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
744 LayerType *layer = LAYER_PTR (layer_no);
746 if (layer->no_drc)
747 continue;
749 info.layer = layer_no;
751 /* add touching lines */
752 if (setjmp (info.env) == 0)
753 r_search (layer->line_tree, &search_box,
754 NULL, LOCtoPVline_callback, &info);
755 else
756 return true;
757 /* add touching arcs */
758 if (setjmp (info.env) == 0)
759 r_search (layer->arc_tree, &search_box,
760 NULL, LOCtoPVarc_callback, &info);
761 else
762 return true;
763 /* check all polygons */
764 if (setjmp (info.env) == 0)
765 r_search (layer->polygon_tree, &search_box,
766 NULL, LOCtoPVpoly_callback, &info);
767 else
768 return true;
770 /* Check for rat-lines that may intersect the PV */
771 if (AndRats)
773 if (setjmp (info.env) == 0)
774 r_search (PCB->Data->rat_tree, &search_box, NULL,
775 LOCtoPVrat_callback, &info);
776 else
777 return true;
779 PVList.Location++;
781 return false;
785 * \brief Find all connections between LO at the current list position
786 * and new LOs.
788 static bool
789 LookupLOConnectionsToLOList (int flag, bool AndRats)
791 bool done;
792 Cardinal i, group, layer, ratposition,
793 lineposition[MAX_LAYER],
794 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2];
796 /* copy the current LO list positions; the original data is changed
797 * by 'LookupPVConnectionsToLOList()' which has to check the same
798 * list entries plus the new ones
800 for (i = 0; i < max_copper_layer; i++)
802 lineposition[i] = LineList[i].Location;
803 polyposition[i] = PolygonList[i].Location;
804 arcposition[i] = ArcList[i].Location;
806 for (i = 0; i < 2; i++)
807 padposition[i] = PadList[i].Location;
808 ratposition = RatList.Location;
810 /* loop over all new LOs in the list; recurse until no
811 * more new connections in the layergroup were found
815 Cardinal *position;
817 if (AndRats)
819 position = &ratposition;
820 for (; *position < RatList.Number; (*position)++)
822 group = RATLIST_ENTRY (*position)->group1;
823 if (LookupLOConnectionsToRatEnd
824 (&(RATLIST_ENTRY (*position)->Point1), group, flag))
825 return (true);
826 group = RATLIST_ENTRY (*position)->group2;
827 if (LookupLOConnectionsToRatEnd
828 (&(RATLIST_ENTRY (*position)->Point2), group, flag))
829 return (true);
832 /* loop over all layergroups */
833 for (group = 0; group < max_group; group++)
835 Cardinal entry;
837 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
839 layer = PCB->LayerGroups.Entries[group][entry];
841 /* be aware that the layer number equal max_copper_layer
842 * and max_copper_layer+1 have a special meaning for pads
844 if (layer < max_copper_layer)
846 /* try all new lines */
847 position = &lineposition[layer];
848 for (; *position < LineList[layer].Number; (*position)++)
849 if (LookupLOConnectionsToLine
850 (LINELIST_ENTRY (layer, *position), group, flag, true, AndRats))
851 return (true);
853 /* try all new arcs */
854 position = &arcposition[layer];
855 for (; *position < ArcList[layer].Number; (*position)++)
856 if (LookupLOConnectionsToArc
857 (ARCLIST_ENTRY (layer, *position), group, flag, AndRats))
858 return (true);
860 /* try all new polygons */
861 position = &polyposition[layer];
862 for (; *position < PolygonList[layer].Number; (*position)++)
863 if (LookupLOConnectionsToPolygon
864 (POLYGONLIST_ENTRY (layer, *position), group, flag, AndRats))
865 return (true);
867 else
869 /* try all new pads */
870 layer -= max_copper_layer;
871 if (layer > 1)
873 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"),
874 layer, max_copper_layer);
875 return false;
877 position = &padposition[layer];
878 for (; *position < PadList[layer].Number; (*position)++)
879 if (LookupLOConnectionsToPad
880 (PADLIST_ENTRY (layer, *position), group, flag, AndRats))
881 return (true);
886 /* check if all lists are done; Later for-loops
887 * may have changed the prior lists
889 done = !AndRats || ratposition >= RatList.Number;
890 done = done && padposition[0] >= PadList[0].Number &&
891 padposition[1] >= PadList[1].Number;
892 for (layer = 0; layer < max_copper_layer; layer++)
893 done = done &&
894 lineposition[layer] >= LineList[layer].Number &&
895 arcposition[layer] >= ArcList[layer].Number &&
896 polyposition[layer] >= PolygonList[layer].Number;
898 while (!done);
899 return (false);
902 static int
903 pv_pv_callback (const BoxType * b, void *cl)
905 PinType *pin = (PinType *) b;
906 struct pv_info *i = (struct pv_info *) cl;
908 if (!TEST_FLAG (i->flag, pin) && PV_TOUCH_PV (i->pv, pin))
910 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, i->pv))
912 SET_FLAG (WARNFLAG, pin);
913 Settings.RatWarn = true;
914 if (pin->Element)
915 Message (_("WARNING: Hole too close to pin.\n"));
916 else
917 Message (_("WARNING: Hole too close to via.\n"));
919 else if (ADD_PV_TO_LIST (pin, i->flag))
920 longjmp (i->env, 1);
922 return 0;
926 * \brief Searches for new PVs that are connected to PVs on the list.
928 static bool
929 LookupPVConnectionsToPVList (int flag)
931 Cardinal save_place;
932 struct pv_info info;
934 info.flag = flag;
936 /* loop over all PVs on list */
937 save_place = PVList.Location;
938 while (PVList.Location < PVList.Number)
940 BoxType search_box;
942 /* get pointer to data */
943 info.pv = PVLIST_ENTRY (PVList.Location);
944 search_box = expand_bounds ((BoxType *)info.pv);
946 if (setjmp (info.env) == 0)
947 r_search (PCB->Data->via_tree, &search_box, NULL,
948 pv_pv_callback, &info);
949 else
950 return true;
951 if (setjmp (info.env) == 0)
952 r_search (PCB->Data->pin_tree, &search_box, NULL,
953 pv_pv_callback, &info);
954 else
955 return true;
956 PVList.Location++;
958 PVList.Location = save_place;
959 return (false);
962 struct lo_info
964 Cardinal layer;
965 LineType *line;
966 PadType *pad;
967 ArcType *arc;
968 PolygonType *polygon;
969 RatType *rat;
970 int flag;
971 jmp_buf env;
974 static int
975 pv_line_callback (const BoxType * b, void *cl)
977 PinType *pv = (PinType *) b;
978 struct lo_info *i = (struct lo_info *) cl;
980 if (!TEST_FLAG (i->flag, pv) && PinLineIntersect (pv, i->line))
982 if (TEST_FLAG (HOLEFLAG, pv))
984 SET_FLAG (WARNFLAG, pv);
985 Settings.RatWarn = true;
986 Message (_("WARNING: Hole too close to line.\n"));
988 else if (ADD_PV_TO_LIST (pv, i->flag))
989 longjmp (i->env, 1);
991 return 0;
994 static int
995 pv_pad_callback (const BoxType * b, void *cl)
997 PinType *pv = (PinType *) b;
998 struct lo_info *i = (struct lo_info *) cl;
1000 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_PAD (pv, i->pad))
1002 if (TEST_FLAG (HOLEFLAG, pv))
1004 SET_FLAG (WARNFLAG, pv);
1005 Settings.RatWarn = true;
1006 Message (_("WARNING: Hole too close to pad.\n"));
1008 else if (ADD_PV_TO_LIST (pv, i->flag))
1009 longjmp (i->env, 1);
1011 return 0;
1014 static int
1015 pv_arc_callback (const BoxType * b, void *cl)
1017 PinType *pv = (PinType *) b;
1018 struct lo_info *i = (struct lo_info *) cl;
1020 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_ARC (pv, i->arc))
1022 if (TEST_FLAG (HOLEFLAG, pv))
1024 SET_FLAG (WARNFLAG, pv);
1025 Settings.RatWarn = true;
1026 Message (_("WARNING: Hole touches arc.\n"));
1028 else if (ADD_PV_TO_LIST (pv, i->flag))
1029 longjmp (i->env, 1);
1031 return 0;
1034 static int
1035 pv_poly_callback (const BoxType * b, void *cl)
1037 PinType *pv = (PinType *) b;
1038 struct lo_info *i = (struct lo_info *) cl;
1040 /* note that holes in polygons are ok, so they don't generate warnings. */
1041 if (!TEST_FLAG (i->flag, pv) && !TEST_FLAG (HOLEFLAG, pv) &&
1042 (TEST_THERM (i->layer, pv) ||
1043 !TEST_FLAG (CLEARPOLYFLAG, i->polygon) ||
1044 !pv->Clearance))
1046 if (TEST_FLAG (SQUAREFLAG, pv))
1048 Coord x1, x2, y1, y2;
1049 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1050 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1051 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2;
1052 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2;
1053 if (IsRectangleInPolygon (x1, y1, x2, y2, i->polygon)
1054 && ADD_PV_TO_LIST (pv, i->flag))
1055 longjmp (i->env, 1);
1057 else if (TEST_FLAG (OCTAGONFLAG, pv))
1059 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2);
1060 if (isects (oct, i->polygon, true) && ADD_PV_TO_LIST (pv, i->flag))
1061 longjmp (i->env, 1);
1063 else
1065 if (IsPointInPolygon
1066 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, i->polygon)
1067 && ADD_PV_TO_LIST (pv, i->flag))
1068 longjmp (i->env, 1);
1071 return 0;
1074 static int
1075 pv_rat_callback (const BoxType * b, void *cl)
1077 PinType *pv = (PinType *) b;
1078 struct lo_info *i = (struct lo_info *) cl;
1080 /* rats can't cause DRC so there is no early exit */
1081 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_RAT (pv, i->rat))
1082 ADD_PV_TO_LIST (pv, i->flag);
1083 return 0;
1087 * \brief Searches for new PVs that are connected to NEW LOs on the list.
1089 * This routine updates the position counter of the lists too.
1091 static bool
1092 LookupPVConnectionsToLOList (int flag, bool AndRats)
1094 Cardinal layer_no;
1095 struct lo_info info;
1097 info.flag = flag;
1099 /* loop over all layers */
1100 for (layer_no = 0; layer_no < max_copper_layer; layer_no++)
1102 LayerType *layer = LAYER_PTR (layer_no);
1104 if (layer->no_drc)
1105 continue;
1106 /* do nothing if there are no PV's */
1107 if (TotalP + TotalV == 0)
1109 LineList[layer_no].Location = LineList[layer_no].Number;
1110 ArcList[layer_no].Location = ArcList[layer_no].Number;
1111 PolygonList[layer_no].Location = PolygonList[layer_no].Number;
1112 continue;
1115 /* check all lines */
1116 while (LineList[layer_no].Location < LineList[layer_no].Number)
1118 BoxType search_box;
1120 info.line = LINELIST_ENTRY (layer_no, LineList[layer_no].Location);
1121 search_box = expand_bounds ((BoxType *)info.line);
1123 if (setjmp (info.env) == 0)
1124 r_search (PCB->Data->via_tree, &search_box, NULL,
1125 pv_line_callback, &info);
1126 else
1127 return true;
1128 if (setjmp (info.env) == 0)
1129 r_search (PCB->Data->pin_tree, &search_box, NULL,
1130 pv_line_callback, &info);
1131 else
1132 return true;
1133 LineList[layer_no].Location++;
1136 /* check all arcs */
1137 while (ArcList[layer_no].Location < ArcList[layer_no].Number)
1139 BoxType search_box;
1141 info.arc = ARCLIST_ENTRY (layer_no, ArcList[layer_no].Location);
1142 search_box = expand_bounds ((BoxType *)info.arc);
1144 if (setjmp (info.env) == 0)
1145 r_search (PCB->Data->via_tree, &search_box, NULL,
1146 pv_arc_callback, &info);
1147 else
1148 return true;
1149 if (setjmp (info.env) == 0)
1150 r_search (PCB->Data->pin_tree, &search_box, NULL,
1151 pv_arc_callback, &info);
1152 else
1153 return true;
1154 ArcList[layer_no].Location++;
1157 /* now all polygons */
1158 info.layer = layer_no;
1159 while (PolygonList[layer_no].Location < PolygonList[layer_no].Number)
1161 BoxType search_box;
1163 info.polygon = POLYGONLIST_ENTRY (layer_no, PolygonList[layer_no].Location);
1164 search_box = expand_bounds ((BoxType *)info.polygon);
1166 if (setjmp (info.env) == 0)
1167 r_search (PCB->Data->via_tree, &search_box, NULL,
1168 pv_poly_callback, &info);
1169 else
1170 return true;
1171 if (setjmp (info.env) == 0)
1172 r_search (PCB->Data->pin_tree, &search_box, NULL,
1173 pv_poly_callback, &info);
1174 else
1175 return true;
1176 PolygonList[layer_no].Location++;
1180 /* loop over all pad-layers */
1181 for (layer_no = 0; layer_no < 2; layer_no++)
1183 /* do nothing if there are no PV's */
1184 if (TotalP + TotalV == 0)
1186 PadList[layer_no].Location = PadList[layer_no].Number;
1187 continue;
1190 /* check all pads; for a detailed description see
1191 * the handling of lines in this subroutine
1193 while (PadList[layer_no].Location < PadList[layer_no].Number)
1195 BoxType search_box;
1197 info.pad = PADLIST_ENTRY (layer_no, PadList[layer_no].Location);
1198 search_box = expand_bounds ((BoxType *)info.pad);
1200 if (setjmp (info.env) == 0)
1201 r_search (PCB->Data->via_tree, &search_box, NULL,
1202 pv_pad_callback, &info);
1203 else
1204 return true;
1205 if (setjmp (info.env) == 0)
1206 r_search (PCB->Data->pin_tree, &search_box, NULL,
1207 pv_pad_callback, &info);
1208 else
1209 return true;
1210 PadList[layer_no].Location++;
1214 /* do nothing if there are no PV's */
1215 if (TotalP + TotalV == 0)
1216 RatList.Location = RatList.Number;
1218 /* check all rat-lines */
1219 if (AndRats)
1221 while (RatList.Location < RatList.Number)
1223 info.rat = RATLIST_ENTRY (RatList.Location);
1224 r_search_pt (PCB->Data->via_tree, & info.rat->Point1, 1, NULL,
1225 pv_rat_callback, &info);
1226 r_search_pt (PCB->Data->via_tree, & info.rat->Point2, 1, NULL,
1227 pv_rat_callback, &info);
1228 r_search_pt (PCB->Data->pin_tree, & info.rat->Point1, 1, NULL,
1229 pv_rat_callback, &info);
1230 r_search_pt (PCB->Data->pin_tree, & info.rat->Point2, 1, NULL,
1231 pv_rat_callback, &info);
1233 RatList.Location++;
1236 return (false);
1240 * \brief Reduce arc start angle and delta to 0..360.
1242 static void
1243 normalize_angles (Angle *sa, Angle *d)
1245 if (*d < 0)
1247 *sa += *d;
1248 *d = - *d;
1250 if (*d > 360) /* full circle */
1251 *d = 360;
1252 *sa = NormalizeAngle (*sa);
1255 static int
1256 radius_crosses_arc (double x, double y, ArcType *arc)
1258 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG;
1259 Angle sa = arc->StartAngle, d = arc->Delta;
1261 normalize_angles (&sa, &d);
1262 if (alpha < 0)
1263 alpha += 360;
1264 if (sa <= alpha)
1265 return (sa + d) >= alpha;
1266 return (sa + d - 360) >= alpha;
1269 static void
1270 get_arc_ends (Coord *box, ArcType *arc)
1272 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle);
1273 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle);
1274 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta));
1275 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta));
1279 * \brief Check if two arcs intersect.
1281 * First we check for circle intersections,
1282 * then find the actual points of intersection
1283 * and test them to see if they are on arcs.
1285 * Consider a, the distance from the center of arc 1
1286 * to the point perpendicular to the intersecting points.
1288 * \ta = (r1^2 - r2^2 + l^2)/(2l)
1290 * The perpendicular distance to the point of intersection
1291 * is then:
1293 * \td = sqrt(r1^2 - a^2)
1295 * The points of intersection would then be:
1297 * \tx = X1 + a/l dx +- d/l dy
1299 * \ty = Y1 + a/l dy -+ d/l dx
1301 * Where dx = X2 - X1 and dy = Y2 - Y1.
1303 static bool
1304 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2)
1306 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl;
1307 Coord pdx, pdy;
1308 Coord box[8];
1310 t = 0.5 * Arc1->Thickness + Bloat;
1311 t2 = 0.5 * Arc2->Thickness;
1312 t1 = t2 + Bloat;
1314 /* too thin arc */
1315 if (t < 0 || t1 < 0)
1316 return false;
1318 /* try the end points first */
1319 get_arc_ends (&box[0], Arc1);
1320 get_arc_ends (&box[4], Arc2);
1321 if (IsPointOnArc (box[0], box[1], t, Arc2)
1322 || IsPointOnArc (box[2], box[3], t, Arc2)
1323 || IsPointOnArc (box[4], box[5], t, Arc1)
1324 || IsPointOnArc (box[6], box[7], t, Arc1))
1325 return true;
1327 pdx = Arc2->X - Arc1->X;
1328 pdy = Arc2->Y - Arc1->Y;
1329 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y);
1330 /* concentric arcs, simpler intersection conditions */
1331 if (dl < 0.5)
1333 if ((Arc1->Width - t >= Arc2->Width - t2
1334 && Arc1->Width - t <= Arc2->Width + t2)
1335 || (Arc1->Width + t >= Arc2->Width - t2
1336 && Arc1->Width + t <= Arc2->Width + t2))
1338 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta;
1339 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta;
1340 /* NB the endpoints have already been checked,
1341 so we just compare the angles */
1343 normalize_angles (&sa1, &d1);
1344 normalize_angles (&sa2, &d2);
1345 /* sa1 == sa2 was caught when checking endpoints */
1346 if (sa1 > sa2)
1347 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2)
1348 return true;
1349 if (sa2 > sa1)
1350 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1)
1351 return true;
1353 return false;
1355 r1 = Arc1->Width;
1356 r2 = Arc2->Width;
1357 /* arcs centerlines are too far or too near */
1358 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1)
1360 /* check the nearest to the other arc's center point */
1361 dx = pdx * r1 / dl;
1362 dy = pdy * r1 / dl;
1363 if (dl + r1 < r2) /* Arc1 inside Arc2 */
1365 dx = - dx;
1366 dy = - dy;
1369 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1)
1370 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2))
1371 return true;
1373 dx = - pdx * r2 / dl;
1374 dy = - pdy * r2 / dl;
1375 if (dl + r2 < r1) /* Arc2 inside Arc1 */
1377 dx = - dx;
1378 dy = - dy;
1381 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2)
1382 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1))
1383 return true;
1384 return false;
1387 l = dl * dl;
1388 r1 *= r1;
1389 r2 *= r2;
1390 a = 0.5 * (r1 - r2 + l) / l;
1391 r1 = r1 / l;
1392 d = r1 - a * a;
1393 /* the circles are too far apart to touch or probably just touch:
1394 check the nearest point */
1395 if (d < 0)
1396 d = 0;
1397 else
1398 d = sqrt (d);
1399 x = Arc1->X + a * pdx;
1400 y = Arc1->Y + a * pdy;
1401 dx = d * pdx;
1402 dy = d * pdy;
1403 if (radius_crosses_arc (x + dy, y - dx, Arc1)
1404 && IsPointOnArc (x + dy, y - dx, t, Arc2))
1405 return true;
1406 if (radius_crosses_arc (x + dy, y - dx, Arc2)
1407 && IsPointOnArc (x + dy, y - dx, t1, Arc1))
1408 return true;
1410 if (radius_crosses_arc (x - dy, y + dx, Arc1)
1411 && IsPointOnArc (x - dy, y + dx, t, Arc2))
1412 return true;
1413 if (radius_crosses_arc (x - dy, y + dx, Arc2)
1414 && IsPointOnArc (x - dy, y + dx, t1, Arc1))
1415 return true;
1416 return false;
1420 * \brief Tests if point is same as line end point.
1422 static bool
1423 IsRatPointOnLineEnd (PointType *Point, LineType *Line)
1425 if ((Point->X == Line->Point1.X
1426 && Point->Y == Line->Point1.Y)
1427 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y))
1428 return (true);
1429 return (false);
1433 * \brief Writes vertices of a squared line.
1435 static void
1436 form_slanted_rectangle (PointType p[4], LineType *l)
1438 double dwx = 0, dwy = 0;
1439 if (l->Point1.Y == l->Point2.Y)
1440 dwx = l->Thickness / 2.0;
1441 else if (l->Point1.X == l->Point2.X)
1442 dwy = l->Thickness / 2.0;
1443 else
1445 Coord dX = l->Point2.X - l->Point1.X;
1446 Coord dY = l->Point2.Y - l->Point1.Y;
1447 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y);
1448 dwx = l->Thickness / 2.0 / r * dX;
1449 dwy = l->Thickness / 2.0 / r * dY;
1451 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx;
1452 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx;
1453 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx;
1454 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx;
1458 * \brief Checks if two lines intersect.
1460 * <pre>
1461 * From news FAQ:
1463 * Let A,B,C,D be 2-space position vectors.
1465 * Then the directed line segments AB & CD are given by:
1467 * AB=A+r(B-A), r in [0,1]
1469 * CD=C+s(D-C), s in [0,1]
1471 * If AB & CD intersect, then
1473 * A+r(B-A)=C+s(D-C), or
1475 * XA+r(XB-XA)=XC+s*(XD-XC)
1477 * YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
1479 * Solving the above for r and s yields
1481 * (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
1482 * r = ----------------------------- (eqn 1)
1483 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1485 * (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
1486 * s = ----------------------------- (eqn 2)
1487 * (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
1489 * Let I be the position vector of the intersection point, then:
1491 * I=A+r(B-A) or
1493 * XI=XA+r(XB-XA)
1495 * YI=YA+r(YB-YA)
1497 * By examining the values of r & s, you can also determine some
1498 * other limiting conditions:
1500 * If 0<=r<=1 & 0<=s<=1, intersection exists
1502 * r<0 or r>1 or s<0 or s>1 line segments do not intersect
1504 * If the denominator in eqn 1 is zero, AB & CD are parallel
1506 * If the numerator in eqn 1 is also zero, AB & CD are coincident
1508 * If the intersection point of the 2 lines are needed (lines in this
1509 * context mean infinite lines) regardless whether the two line
1510 * segments intersect, then
1512 * If r>1, I is located on extension of AB
1513 * If r<0, I is located on extension of BA
1514 * If s>1, I is located on extension of CD
1515 * If s<0, I is located on extension of DC
1517 * Also note that the denominators of eqn 1 & 2 are identical.
1518 * </pre>
1520 bool
1521 LineLineIntersect (LineType *Line1, LineType *Line2)
1523 double s, r;
1524 double line1_dx, line1_dy, line2_dx, line2_dy,
1525 point1_dx, point1_dy;
1526 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */
1528 PointType p[4];
1529 form_slanted_rectangle (p, Line1);
1530 return IsLineInQuadrangle (p, Line2);
1532 /* here come only round Line1 because IsLineInQuadrangle()
1533 calls LineLineIntersect() with first argument rounded*/
1534 if (TEST_FLAG (SQUAREFLAG, Line2))
1536 PointType p[4];
1537 form_slanted_rectangle (p, Line2);
1538 return IsLineInQuadrangle (p, Line1);
1540 /* now all lines are round */
1542 /* Check endpoints: this provides a quick exit, catches
1543 * cases where the "real" lines don't intersect but the
1544 * thick lines touch, and ensures that the dx/dy business
1545 * below does not cause a divide-by-zero. */
1546 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y,
1547 MAX (Line2->Thickness / 2 + Bloat, 0),
1548 (PadType *) Line1)
1549 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y,
1550 MAX (Line2->Thickness / 2 + Bloat, 0),
1551 (PadType *) Line1)
1552 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y,
1553 MAX (Line1->Thickness / 2 + Bloat, 0),
1554 (PadType *) Line2)
1555 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y,
1556 MAX (Line1->Thickness / 2 + Bloat, 0),
1557 (PadType *) Line2))
1558 return true;
1560 /* setup some constants */
1561 line1_dx = Line1->Point2.X - Line1->Point1.X;
1562 line1_dy = Line1->Point2.Y - Line1->Point1.Y;
1563 line2_dx = Line2->Point2.X - Line2->Point1.X;
1564 line2_dy = Line2->Point2.Y - Line2->Point1.Y;
1565 point1_dx = Line1->Point1.X - Line2->Point1.X;
1566 point1_dy = Line1->Point1.Y - Line2->Point1.Y;
1568 /* If either line is a point, we have failed already, since the
1569 * endpoint check above will have caught an "intersection". */
1570 if ((line1_dx == 0 && line1_dy == 0)
1571 || (line2_dx == 0 && line2_dy == 0))
1572 return false;
1574 /* set s to cross product of Line1 and the line
1575 * Line1.Point1--Line2.Point1 (as vectors) */
1576 s = point1_dy * line1_dx - point1_dx * line1_dy;
1578 /* set r to cross product of both lines (as vectors) */
1579 r = line1_dx * line2_dy - line1_dy * line2_dx;
1581 /* No cross product means parallel lines, or maybe Line2 is
1582 * zero-length. In either case, since we did a bounding-box
1583 * check before getting here, the above IsPointInPad() checks
1584 * will have caught any intersections. */
1585 if (r == 0.0)
1586 return false;
1588 s /= r;
1589 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r;
1591 /* intersection is at least on AB */
1592 if (r >= 0.0 && r <= 1.0)
1593 return (s >= 0.0 && s <= 1.0);
1595 /* intersection is at least on CD */
1596 /* [removed this case since it always returns false --asp] */
1597 return false;
1601 * \brief Check for line intersection with an arc.
1603 * Mostly this is like the circle/line intersection
1604 * found in IsPointOnLine (search.c) see the detailed
1605 * discussion for the basics there.
1607 * Since this is only an arc, not a full circle we need
1608 * to find the actual points of intersection with the
1609 * circle, and see if they are on the arc.
1611 * To do this, we translate along the line from the point Q
1612 * plus or minus a distance delta = sqrt(Radius^2 - d^2)
1613 * but it's handy to normalize with respect to l, the line
1614 * length so a single projection is done (e.g. we don't first
1615 * find the point Q.
1617 * <pre>
1618 * The projection is now of the form:
1620 * Px = X1 + (r +- r2)(X2 - X1)
1621 * Py = Y1 + (r +- r2)(Y2 - Y1)
1622 * </pre>
1624 * Where r2 sqrt(Radius^2 l^2 - d^2)/l^2
1625 * note that this is the variable d, not the symbol d described in
1626 * IsPointOnLine (variable d = symbol d * l).
1628 * The end points are hell so they are checked individually.
1630 bool
1631 LineArcIntersect (LineType *Line, ArcType *Arc)
1633 double dx, dy, dx1, dy1, l, d, r, r2, Radius;
1634 BoxType *box;
1636 dx = Line->Point2.X - Line->Point1.X;
1637 dy = Line->Point2.Y - Line->Point1.Y;
1638 dx1 = Line->Point1.X - Arc->X;
1639 dy1 = Line->Point1.Y - Arc->Y;
1640 l = dx * dx + dy * dy;
1641 d = dx * dy1 - dy * dx1;
1642 d *= d;
1644 /* use the larger diameter circle first */
1645 Radius =
1646 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0);
1647 Radius *= Radius;
1648 r2 = Radius * l - d;
1649 /* projection doesn't even intersect circle when r2 < 0 */
1650 if (r2 < 0)
1651 return (false);
1652 /* check the ends of the line in case the projected point */
1653 /* of intersection is beyond the line end */
1654 if (IsPointOnArc
1655 (Line->Point1.X, Line->Point1.Y,
1656 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1657 return (true);
1658 if (IsPointOnArc
1659 (Line->Point2.X, Line->Point2.Y,
1660 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1661 return (true);
1662 if (l == 0.0)
1663 return (false);
1664 r2 = sqrt (r2);
1665 Radius = -(dx * dx1 + dy * dy1);
1666 r = (Radius + r2) / l;
1667 if (r >= 0 && r <= 1
1668 && IsPointOnArc (Line->Point1.X + r * dx,
1669 Line->Point1.Y + r * dy,
1670 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1671 return (true);
1672 r = (Radius - r2) / l;
1673 if (r >= 0 && r <= 1
1674 && IsPointOnArc (Line->Point1.X + r * dx,
1675 Line->Point1.Y + r * dy,
1676 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc))
1677 return (true);
1678 /* check arc end points */
1679 box = GetArcEnds (Arc);
1680 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1681 return true;
1682 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line))
1683 return true;
1684 return false;
1687 static int
1688 LOCtoArcLine_callback (const BoxType * b, void *cl)
1690 LineType *line = (LineType *) b;
1691 struct lo_info *i = (struct lo_info *) cl;
1693 if (!TEST_FLAG (i->flag, line) && LineArcIntersect (line, i->arc))
1695 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1696 longjmp (i->env, 1);
1698 return 0;
1701 static int
1702 LOCtoArcArc_callback (const BoxType * b, void *cl)
1704 ArcType *arc = (ArcType *) b;
1705 struct lo_info *i = (struct lo_info *) cl;
1707 if (!arc->Thickness)
1708 return 0;
1709 if (!TEST_FLAG (i->flag, arc) && ArcArcIntersect (i->arc, arc))
1711 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
1712 longjmp (i->env, 1);
1714 return 0;
1717 static int
1718 LOCtoArcPad_callback (const BoxType * b, void *cl)
1720 PadType *pad = (PadType *) b;
1721 struct lo_info *i = (struct lo_info *) cl;
1723 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1724 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE)
1725 && ArcPadIntersect (i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
1726 longjmp (i->env, 1);
1727 return 0;
1731 * \brief Searches all LOs that are connected to the given arc on the
1732 * given layergroup.
1734 * All found connections are added to the list.
1736 * The notation that is used is:\n
1737 * Xij means Xj at arc i.
1739 static bool
1740 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup, int flag, bool AndRats)
1742 Cardinal entry;
1743 struct lo_info info;
1744 BoxType search_box;
1746 info.flag = flag;
1747 info.arc = Arc;
1748 search_box = expand_bounds ((BoxType *)info.arc);
1750 /* loop over all layers of the group */
1751 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1753 Cardinal layer_no;
1754 LayerType *layer;
1755 GList *i;
1757 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1758 layer = LAYER_PTR (layer_no);
1760 /* handle normal layers */
1761 if (layer_no < max_copper_layer)
1763 info.layer = layer_no;
1764 /* add arcs */
1765 if (setjmp (info.env) == 0)
1766 r_search (layer->line_tree, &search_box,
1767 NULL, LOCtoArcLine_callback, &info);
1768 else
1769 return true;
1771 if (setjmp (info.env) == 0)
1772 r_search (layer->arc_tree, &search_box,
1773 NULL, LOCtoArcArc_callback, &info);
1774 else
1775 return true;
1777 /* now check all polygons */
1778 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1780 PolygonType *polygon = i->data;
1781 if (!TEST_FLAG (flag, polygon) && IsArcInPolygon (Arc, polygon)
1782 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
1783 return true;
1786 else
1788 info.layer = layer_no - max_copper_layer;
1789 if (setjmp (info.env) == 0)
1790 r_search (PCB->Data->pad_tree, &search_box, NULL,
1791 LOCtoArcPad_callback, &info);
1792 else
1793 return true;
1796 return (false);
1799 static int
1800 LOCtoLineLine_callback (const BoxType * b, void *cl)
1802 LineType *line = (LineType *) b;
1803 struct lo_info *i = (struct lo_info *) cl;
1805 if (!TEST_FLAG (i->flag, line) && LineLineIntersect (i->line, line))
1807 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1808 longjmp (i->env, 1);
1810 return 0;
1813 static int
1814 LOCtoLineArc_callback (const BoxType * b, void *cl)
1816 ArcType *arc = (ArcType *) b;
1817 struct lo_info *i = (struct lo_info *) cl;
1819 if (!arc->Thickness)
1820 return 0;
1821 if (!TEST_FLAG (i->flag, arc) && LineArcIntersect (i->line, arc))
1823 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
1824 longjmp (i->env, 1);
1826 return 0;
1829 static int
1830 LOCtoLineRat_callback (const BoxType * b, void *cl)
1832 RatType *rat = (RatType *) b;
1833 struct lo_info *i = (struct lo_info *) cl;
1835 if (!TEST_FLAG (i->flag, rat))
1837 if ((rat->group1 == i->layer)
1838 && IsRatPointOnLineEnd (&rat->Point1, i->line))
1840 if (ADD_RAT_TO_LIST (rat, i->flag))
1841 longjmp (i->env, 1);
1843 else if ((rat->group2 == i->layer)
1844 && IsRatPointOnLineEnd (&rat->Point2, i->line))
1846 if (ADD_RAT_TO_LIST (rat, i->flag))
1847 longjmp (i->env, 1);
1850 return 0;
1853 static int
1854 LOCtoLinePad_callback (const BoxType * b, void *cl)
1856 PadType *pad = (PadType *) b;
1857 struct lo_info *i = (struct lo_info *) cl;
1859 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1860 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE)
1861 && LinePadIntersect (i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
1862 longjmp (i->env, 1);
1863 return 0;
1867 * \brief Searches all LOs that are connected to the given line on the
1868 * given layergroup.
1870 * All found connections are added to the list.
1872 * The notation that is used is:
1873 * Xij means Xj at line i.
1875 static bool
1876 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup,
1877 int flag, bool PolysTo, bool AndRats)
1879 Cardinal entry;
1880 struct lo_info info;
1881 BoxType search_box;
1883 info.flag = flag;
1884 info.layer = LayerGroup;
1885 info.line = Line;
1886 search_box = expand_bounds ((BoxType *)info.line);
1888 if (AndRats)
1890 /* add the new rat lines */
1891 if (setjmp (info.env) == 0)
1892 r_search (PCB->Data->rat_tree, &search_box, NULL,
1893 LOCtoLineRat_callback, &info);
1894 else
1895 return true;
1898 /* loop over all layers of the group */
1899 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
1901 Cardinal layer_no;
1902 LayerType *layer;
1904 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
1905 layer = LAYER_PTR (layer_no);
1907 /* handle normal layers */
1908 if (layer_no < max_copper_layer)
1910 info.layer = layer_no;
1911 /* add lines */
1912 if (setjmp (info.env) == 0)
1913 r_search (layer->line_tree, &search_box,
1914 NULL, LOCtoLineLine_callback, &info);
1915 else
1916 return true;
1917 /* add arcs */
1918 if (setjmp (info.env) == 0)
1919 r_search (layer->arc_tree, &search_box,
1920 NULL, LOCtoLineArc_callback, &info);
1921 else
1922 return true;
1923 /* now check all polygons */
1924 if (PolysTo)
1926 GList *i;
1927 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
1929 PolygonType *polygon = i->data;
1930 if (!TEST_FLAG (flag, polygon) && IsLineInPolygon (Line, polygon)
1931 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
1932 return true;
1936 else
1938 /* handle special 'pad' layers */
1939 info.layer = layer_no - max_copper_layer;
1940 if (setjmp (info.env) == 0)
1941 r_search (PCB->Data->pad_tree, &search_box, NULL,
1942 LOCtoLinePad_callback, &info);
1943 else
1944 return true;
1947 return (false);
1950 struct rat_info
1952 Cardinal layer;
1953 PointType *Point;
1954 int flag;
1955 jmp_buf env;
1958 static int
1959 LOCtoRat_callback (const BoxType * b, void *cl)
1961 LineType *line = (LineType *) b;
1962 struct rat_info *i = (struct rat_info *) cl;
1964 if (!TEST_FLAG (i->flag, line) &&
1965 ((line->Point1.X == i->Point->X &&
1966 line->Point1.Y == i->Point->Y) ||
1967 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y)))
1969 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
1970 longjmp (i->env, 1);
1972 return 0;
1974 static int
1975 PolygonToRat_callback (const BoxType * b, void *cl)
1977 PolygonType *polygon = (PolygonType *) b;
1978 struct rat_info *i = (struct rat_info *) cl;
1980 if (!TEST_FLAG (i->flag, polygon) && polygon->Clipped &&
1981 (i->Point->X == polygon->Clipped->contours->head.point[0]) &&
1982 (i->Point->Y == polygon->Clipped->contours->head.point[1]))
1984 if (ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
1985 longjmp (i->env, 1);
1987 return 0;
1990 static int
1991 LOCtoPad_callback (const BoxType * b, void *cl)
1993 PadType *pad = (PadType *) b;
1994 struct rat_info *i = (struct rat_info *) cl;
1996 if (!TEST_FLAG (i->flag, pad) && i->layer ==
1997 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) &&
1998 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) ||
1999 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) ||
2000 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X &&
2001 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) &&
2002 ADD_PAD_TO_LIST (i->layer, pad, i->flag))
2003 longjmp (i->env, 1);
2004 return 0;
2008 * \brief Searches all LOs that are connected to the given rat-line on
2009 * the given layergroup.
2011 * All found connections are added to the list.
2013 * The notation that is used is:
2014 * Xij means Xj at line i.
2016 static bool
2017 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup, int flag)
2019 Cardinal entry;
2020 struct rat_info info;
2022 info.flag = flag;
2023 info.Point = Point;
2024 /* loop over all layers of this group */
2025 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2027 Cardinal layer_no;
2028 LayerType *layer;
2030 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2031 layer = LAYER_PTR (layer_no);
2032 /* handle normal layers
2033 rats don't ever touch
2034 arcs by definition
2037 if (layer_no < max_copper_layer)
2039 info.layer = layer_no;
2040 if (setjmp (info.env) == 0)
2041 r_search_pt (layer->line_tree, Point, 1, NULL,
2042 LOCtoRat_callback, &info);
2043 else
2044 return true;
2045 if (setjmp (info.env) == 0)
2046 r_search_pt (layer->polygon_tree, Point, 1,
2047 NULL, PolygonToRat_callback, &info);
2049 else
2051 /* handle special 'pad' layers */
2052 info.layer = layer_no - max_copper_layer;
2053 if (setjmp (info.env) == 0)
2054 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL,
2055 LOCtoPad_callback, &info);
2056 else
2057 return true;
2060 return (false);
2063 static int
2064 LOCtoPadLine_callback (const BoxType * b, void *cl)
2066 LineType *line = (LineType *) b;
2067 struct lo_info *i = (struct lo_info *) cl;
2069 if (!TEST_FLAG (i->flag, line) && LinePadIntersect (line, i->pad))
2071 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
2072 longjmp (i->env, 1);
2074 return 0;
2077 static int
2078 LOCtoPadArc_callback (const BoxType * b, void *cl)
2080 ArcType *arc = (ArcType *) b;
2081 struct lo_info *i = (struct lo_info *) cl;
2083 if (!arc->Thickness)
2084 return 0;
2085 if (!TEST_FLAG (i->flag, arc) && ArcPadIntersect (arc, i->pad))
2087 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
2088 longjmp (i->env, 1);
2090 return 0;
2093 static int
2094 LOCtoPadPoly_callback (const BoxType * b, void *cl)
2096 PolygonType *polygon = (PolygonType *) b;
2097 struct lo_info *i = (struct lo_info *) cl;
2100 if (!TEST_FLAG (i->flag, polygon) &&
2101 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad->Clearance))
2103 if (IsPadInPolygon (i->pad, polygon) &&
2104 ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag))
2105 longjmp (i->env, 1);
2107 return 0;
2110 static int
2111 LOCtoPadRat_callback (const BoxType * b, void *cl)
2113 RatType *rat = (RatType *) b;
2114 struct lo_info *i = (struct lo_info *) cl;
2116 if (!TEST_FLAG (i->flag, rat))
2118 if (rat->group1 == i->layer &&
2119 ((rat->Point1.X == i->pad->Point1.X && rat->Point1.Y == i->pad->Point1.Y) ||
2120 (rat->Point1.X == i->pad->Point2.X && rat->Point1.Y == i->pad->Point2.Y) ||
2121 (rat->Point1.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 &&
2122 rat->Point1.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2)))
2124 if (ADD_RAT_TO_LIST (rat, i->flag))
2125 longjmp (i->env, 1);
2127 else if (rat->group2 == i->layer &&
2128 ((rat->Point2.X == i->pad->Point1.X && rat->Point2.Y == i->pad->Point1.Y) ||
2129 (rat->Point2.X == i->pad->Point2.X && rat->Point2.Y == i->pad->Point2.Y) ||
2130 (rat->Point2.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 &&
2131 rat->Point2.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2)))
2133 if (ADD_RAT_TO_LIST (rat, i->flag))
2134 longjmp (i->env, 1);
2137 return 0;
2140 static int
2141 LOCtoPadPad_callback (const BoxType * b, void *cl)
2143 PadType *pad = (PadType *) b;
2144 struct lo_info *i = (struct lo_info *) cl;
2146 if (!TEST_FLAG (i->flag, pad) && i->layer ==
2147 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE)
2148 && PadPadIntersect (pad, i->pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag))
2149 longjmp (i->env, 1);
2150 return 0;
2154 * \brief Searches all LOs that are connected to the given pad on the
2155 * given layergroup.
2157 * All found connections are added to the list.
2159 static bool
2160 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup, int flag, bool AndRats)
2162 Cardinal entry;
2163 struct lo_info info;
2164 BoxType search_box;
2166 if (!TEST_FLAG (SQUAREFLAG, Pad))
2167 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, flag, false, AndRats));
2169 info.flag = flag;
2170 info.pad = Pad;
2171 search_box = expand_bounds ((BoxType *)info.pad);
2173 /* add the new rat lines */
2174 info.layer = LayerGroup;
2176 if (AndRats)
2178 if (setjmp (info.env) == 0)
2179 r_search (PCB->Data->rat_tree, &search_box, NULL,
2180 LOCtoPadRat_callback, &info);
2181 else
2182 return true;
2185 /* loop over all layers of the group */
2186 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2188 Cardinal layer_no;
2189 LayerType *layer;
2191 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2192 layer = LAYER_PTR (layer_no);
2193 /* handle normal layers */
2194 if (layer_no < max_copper_layer)
2196 info.layer = layer_no;
2197 /* add lines */
2198 if (setjmp (info.env) == 0)
2199 r_search (layer->line_tree, &search_box,
2200 NULL, LOCtoPadLine_callback, &info);
2201 else
2202 return true;
2203 /* add arcs */
2204 if (setjmp (info.env) == 0)
2205 r_search (layer->arc_tree, &search_box,
2206 NULL, LOCtoPadArc_callback, &info);
2207 else
2208 return true;
2209 /* add polygons */
2210 if (setjmp (info.env) == 0)
2211 r_search (layer->polygon_tree, &search_box,
2212 NULL, LOCtoPadPoly_callback, &info);
2213 else
2214 return true;
2216 else
2218 /* handle special 'pad' layers */
2219 info.layer = layer_no - max_copper_layer;
2220 if (setjmp (info.env) == 0)
2221 r_search (PCB->Data->pad_tree, &search_box, NULL,
2222 LOCtoPadPad_callback, &info);
2223 else
2224 return true;
2228 return (false);
2231 static int
2232 LOCtoPolyLine_callback (const BoxType * b, void *cl)
2234 LineType *line = (LineType *) b;
2235 struct lo_info *i = (struct lo_info *) cl;
2237 if (!TEST_FLAG (i->flag, line) && IsLineInPolygon (line, i->polygon))
2239 if (ADD_LINE_TO_LIST (i->layer, line, i->flag))
2240 longjmp (i->env, 1);
2242 return 0;
2245 static int
2246 LOCtoPolyArc_callback (const BoxType * b, void *cl)
2248 ArcType *arc = (ArcType *) b;
2249 struct lo_info *i = (struct lo_info *) cl;
2251 if (!arc->Thickness)
2252 return 0;
2253 if (!TEST_FLAG (i->flag, arc) && IsArcInPolygon (arc, i->polygon))
2255 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag))
2256 longjmp (i->env, 1);
2258 return 0;
2261 static int
2262 LOCtoPolyPad_callback (const BoxType * b, void *cl)
2264 PadType *pad = (PadType *) b;
2265 struct lo_info *i = (struct lo_info *) cl;
2267 if (!TEST_FLAG (i->flag, pad) && i->layer ==
2268 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE)
2269 && IsPadInPolygon (pad, i->polygon))
2271 if (ADD_PAD_TO_LIST (i->layer, pad, i->flag))
2272 longjmp (i->env, 1);
2274 return 0;
2277 static int
2278 LOCtoPolyRat_callback (const BoxType * b, void *cl)
2280 RatType *rat = (RatType *) b;
2281 struct lo_info *i = (struct lo_info *) cl;
2283 if (!TEST_FLAG (i->flag, rat))
2285 if ((rat->Point1.X == (i->polygon->Clipped->contours->head.point[0]) &&
2286 rat->Point1.Y == (i->polygon->Clipped->contours->head.point[1]) &&
2287 rat->group1 == i->layer) ||
2288 (rat->Point2.X == (i->polygon->Clipped->contours->head.point[0]) &&
2289 rat->Point2.Y == (i->polygon->Clipped->contours->head.point[1]) &&
2290 rat->group2 == i->layer))
2291 if (ADD_RAT_TO_LIST (rat, i->flag))
2292 longjmp (i->env, 1);
2294 return 0;
2299 * \brief Looks up LOs that are connected to the given polygon on the
2300 * given layergroup.
2302 * All found connections are added to the list.
2304 static bool
2305 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup, int flag, bool AndRats)
2307 Cardinal entry;
2308 struct lo_info info;
2309 BoxType search_box;
2311 if (!Polygon->Clipped)
2312 return false;
2314 info.flag = flag;
2315 info.polygon = Polygon;
2316 search_box = expand_bounds ((BoxType *)info.polygon);
2318 info.layer = LayerGroup;
2320 /* check rats */
2321 if (AndRats)
2323 if (setjmp (info.env) == 0)
2324 r_search (PCB->Data->rat_tree, &search_box, NULL,
2325 LOCtoPolyRat_callback, &info);
2326 else
2327 return true;
2330 /* loop over all layers of the group */
2331 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
2333 Cardinal layer_no;
2334 LayerType *layer;
2336 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry];
2337 layer = LAYER_PTR (layer_no);
2339 /* handle normal layers */
2340 if (layer_no < max_copper_layer)
2342 GList *i;
2344 /* check all polygons */
2345 for (i = layer->Polygon; i != NULL; i = g_list_next (i))
2347 PolygonType *polygon = i->data;
2348 if (!TEST_FLAG (flag, polygon)
2349 && IsPolygonInPolygon (polygon, Polygon)
2350 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag))
2351 return true;
2354 info.layer = layer_no;
2355 /* check all lines */
2356 if (setjmp (info.env) == 0)
2357 r_search (layer->line_tree, &search_box,
2358 NULL, LOCtoPolyLine_callback, &info);
2359 else
2360 return true;
2361 /* check all arcs */
2362 if (setjmp (info.env) == 0)
2363 r_search (layer->arc_tree, &search_box,
2364 NULL, LOCtoPolyArc_callback, &info);
2365 else
2366 return true;
2368 else
2370 info.layer = layer_no - max_copper_layer;
2371 if (setjmp (info.env) == 0)
2372 r_search (PCB->Data->pad_tree, &search_box,
2373 NULL, LOCtoPolyPad_callback, &info);
2374 else
2375 return true;
2378 return (false);
2382 * \brief Checks if an arc has a connection to a polygon.
2384 * - first check if the arc can intersect with the polygon by
2385 * evaluating the bounding boxes.
2386 * - check the two end points of the arc. If none of them matches
2387 * - check all segments of the polygon against the arc.
2389 static bool
2390 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon)
2392 BoxType *Box = (BoxType *) Arc;
2394 /* arcs with clearance never touch polys */
2395 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc))
2396 return false;
2397 if (!Polygon->Clipped)
2398 return false;
2399 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2400 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2401 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2402 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2404 POLYAREA *ap;
2406 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat)))
2407 return false; /* error */
2408 return isects (ap, Polygon, true);
2410 return false;
2414 * \brief Checks if a line has a connection to a polygon.
2416 * - first check if the line can intersect with the polygon by
2417 * evaluating the bounding boxes
2418 * - check the two end points of the line. If none of them matches
2419 * - check all segments of the polygon against the line.
2421 static bool
2422 IsLineInPolygon (LineType *Line, PolygonType *Polygon)
2424 BoxType *Box = (BoxType *) Line;
2425 POLYAREA *lp;
2427 /* lines with clearance never touch polygons */
2428 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line))
2429 return false;
2430 if (!Polygon->Clipped)
2431 return false;
2432 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y))
2434 Coord wid = (Line->Thickness + Bloat + 1) / 2;
2435 Coord x1, x2, y1, y2;
2437 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid;
2438 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid;
2439 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid;
2440 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid;
2441 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon);
2443 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat
2444 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat
2445 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat
2446 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat)
2448 if (!(lp = LinePoly (Line, Line->Thickness + Bloat)))
2449 return FALSE; /* error */
2450 return isects (lp, Polygon, true);
2452 return false;
2456 * \brief Checks if a pad connects to a non-clearing polygon.
2458 * The polygon is assumed to already have been proven non-clearing.
2460 static bool
2461 IsPadInPolygon (PadType *pad, PolygonType *polygon)
2463 return IsLineInPolygon ((LineType *) pad, polygon);
2467 * \brief Checks if a polygon has a connection to a second one.
2469 * First check all points out of P1 against P2 and vice versa.
2470 * If both fail check all lines of P1 against the ones of P2.
2472 static bool
2473 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2)
2475 if (!P1->Clipped || !P2->Clipped)
2476 return false;
2477 assert (P1->Clipped->contours);
2478 assert (P2->Clipped->contours);
2480 /* first check if both bounding boxes intersect. If not, return quickly */
2481 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax ||
2482 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin ||
2483 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax ||
2484 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin)
2485 return false;
2487 /* first check un-bloated case */
2488 if (isects (P1->Clipped, P2, false))
2489 return TRUE;
2491 /* now the difficult case of bloated */
2492 if (Bloat > 0)
2494 PLINE *c;
2495 for (c = P1->Clipped->contours; c; c = c->next)
2497 LineType line;
2498 VNODE *v = &c->head;
2499 if (c->xmin - Bloat <= P2->Clipped->contours->xmax &&
2500 c->xmax + Bloat >= P2->Clipped->contours->xmin &&
2501 c->ymin - Bloat <= P2->Clipped->contours->ymax &&
2502 c->ymax + Bloat >= P2->Clipped->contours->ymin)
2505 line.Point1.X = v->point[0];
2506 line.Point1.Y = v->point[1];
2507 line.Thickness = Bloat;
2508 /* Another Bloat is added by IsLineInPolygon, making the correct
2509 * 2x Bloat. Perhaps we should change it there, but doing so
2510 * breaks some other DRC checks which rely on the behaviour
2511 * in IsLineInPolygon.
2513 line.Clearance = 0;
2514 line.Flags = NoFlags ();
2515 for (v = v->next; v != &c->head; v = v->next)
2517 line.Point2.X = v->point[0];
2518 line.Point2.Y = v->point[1];
2519 SetLineBoundingBox (&line);
2520 if (IsLineInPolygon (&line, P2))
2521 return (true);
2522 line.Point1.X = line.Point2.X;
2523 line.Point1.Y = line.Point2.Y;
2529 return (false);
2533 * \brief Writes the several names of an element to a file.
2535 static void
2536 PrintElementNameList (ElementType *Element, FILE * FP)
2538 static DynamicStringType cname, pname, vname;
2540 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element)));
2541 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element)));
2542 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element)));
2543 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data);
2547 * \brief Writes the several names of an element to a file.
2549 static void
2550 PrintConnectionElementName (ElementType *Element, FILE * FP)
2552 fputs ("Element", FP);
2553 PrintElementNameList (Element, FP);
2554 fputs ("{\n", FP);
2558 * \brief Prints one {pin,pad,via}/element entry of connection lists.
2560 static void
2561 PrintConnectionListEntry (char *ObjName, ElementType *Element,
2562 bool FirstOne, FILE * FP)
2564 static DynamicStringType oname;
2566 CreateQuotedString (&oname, ObjName);
2567 if (FirstOne)
2568 fprintf (FP, "\t%s\n\t{\n", oname.Data);
2569 else
2571 fprintf (FP, "\t\t%s ", oname.Data);
2572 if (Element)
2573 PrintElementNameList (Element, FP);
2574 else
2575 fputs ("(__VIA__)\n", FP);
2580 * \brief Prints all found connections of a pads to file FP
2581 * the connections are stacked in 'PadList'.
2583 static void
2584 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst)
2586 Cardinal i;
2587 PadType *ptr;
2589 if (!PadList[Layer].Number)
2590 return;
2592 /* the starting pad */
2593 if (IsFirst)
2595 ptr = PADLIST_ENTRY (Layer, 0);
2596 if (ptr != NULL)
2597 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP);
2598 else
2599 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n");
2602 /* we maybe have to start with i=1 if we are handling the
2603 * starting-pad itself
2605 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++)
2607 ptr = PADLIST_ENTRY (Layer, i);
2608 if (ptr != NULL)
2609 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP);
2610 else
2611 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n");
2616 * \brief Prints all found connections of a pin to file FP
2617 * the connections are stacked in 'PVList'.
2619 static void
2620 PrintPinConnections (FILE * FP, bool IsFirst)
2622 Cardinal i;
2623 PinType *pv;
2625 if (!PVList.Number)
2626 return;
2628 if (IsFirst)
2630 /* the starting pin */
2631 pv = PVLIST_ENTRY (0);
2632 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP);
2635 /* we maybe have to start with i=1 if we are handling the
2636 * starting-pin itself
2638 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++)
2640 /* get the elements name or assume that its a via */
2641 pv = PVLIST_ENTRY (i);
2642 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP);
2647 * \brief Checks if all lists of new objects are handled.
2649 static bool
2650 ListsEmpty (bool AndRats)
2652 bool empty;
2653 int i;
2655 empty = (PVList.Location >= PVList.Number);
2656 if (AndRats)
2657 empty = empty && (RatList.Location >= RatList.Number);
2658 for (i = 0; i < max_copper_layer && empty; i++)
2659 if (!LAYER_PTR (i)->no_drc)
2660 empty = empty && LineList[i].Location >= LineList[i].Number
2661 && ArcList[i].Location >= ArcList[i].Number
2662 && PolygonList[i].Location >= PolygonList[i].Number;
2663 return (empty);
2666 static void
2667 reassign_no_drc_flags (void)
2669 int layer;
2671 for (layer = 0; layer < max_copper_layer; layer++)
2673 LayerType *l = LAYER_PTR (layer);
2674 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL;
2682 * \brief Loops till no more connections are found.
2684 static bool
2685 DoIt (int flag, bool AndRats, bool AndDraw)
2687 bool newone = false;
2688 reassign_no_drc_flags ();
2691 /* lookup connections; these are the steps (2) to (4)
2692 * from the description
2694 newone = LookupPVConnectionsToPVList (flag) ||
2695 LookupLOConnectionsToPVList (flag, AndRats) ||
2696 LookupLOConnectionsToLOList (flag, AndRats) ||
2697 LookupPVConnectionsToLOList (flag, AndRats);
2698 if (AndDraw)
2699 DrawNewConnections ();
2701 while (!newone && !ListsEmpty (AndRats));
2702 if (AndDraw)
2703 Draw ();
2704 return (newone);
2708 * \brief Prints all unused pins of an element to file FP.
2710 static bool
2711 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP, int flag)
2713 bool first = true;
2714 Cardinal number;
2715 static DynamicStringType oname;
2717 /* check all pins in element */
2719 PIN_LOOP (Element);
2721 if (!TEST_FLAG (HOLEFLAG, pin))
2723 /* pin might have bee checked before, add to list if not */
2724 if (!TEST_FLAG (flag, pin) && FP)
2726 int i;
2727 if (ADD_PV_TO_LIST (pin, flag))
2728 return true;
2729 DoIt (flag, true, true);
2730 number = PadList[TOP_SIDE].Number
2731 + PadList[BOTTOM_SIDE].Number + PVList.Number;
2732 /* the pin has no connection if it's the only
2733 * list entry; don't count vias
2735 for (i = 0; i < PVList.Number; i++)
2736 if (!PVLIST_ENTRY (i)->Element)
2737 number--;
2738 if (number == 1)
2740 /* output of element name if not already done */
2741 if (first)
2743 PrintConnectionElementName (Element, FP);
2744 first = false;
2747 /* write name to list and draw selected object */
2748 CreateQuotedString (&oname, (char *)EMPTY (pin->Name));
2749 fprintf (FP, "\t%s\n", oname.Data);
2750 SET_FLAG (SELECTEDFLAG, pin);
2751 DrawPin (pin);
2754 /* reset found objects for the next pin */
2755 if (PrepareNextLoop (FP))
2756 return (true);
2760 END_LOOP;
2762 /* check all pads in element */
2763 PAD_LOOP (Element);
2765 /* lookup pad in list */
2766 /* pad might has bee checked before, add to list if not */
2767 if (!TEST_FLAG (flag, pad) && FP)
2769 int i;
2770 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad)
2771 ? BOTTOM_SIDE : TOP_SIDE, pad, flag))
2772 return true;
2773 DoIt (flag, true, true);
2774 number = PadList[TOP_SIDE].Number
2775 + PadList[BOTTOM_SIDE].Number + PVList.Number;
2776 /* the pin has no connection if it's the only
2777 * list entry; don't count vias
2779 for (i = 0; i < PVList.Number; i++)
2780 if (!PVLIST_ENTRY (i)->Element)
2781 number--;
2782 if (number == 1)
2784 /* output of element name if not already done */
2785 if (first)
2787 PrintConnectionElementName (Element, FP);
2788 first = false;
2791 /* write name to list and draw selected object */
2792 CreateQuotedString (&oname, (char *)EMPTY (pad->Name));
2793 fprintf (FP, "\t%s\n", oname.Data);
2794 SET_FLAG (SELECTEDFLAG, pad);
2795 DrawPad (pad);
2798 /* reset found objects for the next pin */
2799 if (PrepareNextLoop (FP))
2800 return (true);
2803 END_LOOP;
2805 /* print separator if element has unused pins or pads */
2806 if (!first)
2808 fputs ("}\n\n", FP);
2809 SEPARATE (FP);
2811 return (false);
2815 * \brief Resets some flags for looking up the next pin/pad.
2817 static bool
2818 PrepareNextLoop (FILE * FP)
2820 Cardinal layer;
2822 /* reset found LOs for the next pin */
2823 for (layer = 0; layer < max_copper_layer; layer++)
2825 LineList[layer].Location = LineList[layer].Number = 0;
2826 ArcList[layer].Location = ArcList[layer].Number = 0;
2827 PolygonList[layer].Location = PolygonList[layer].Number = 0;
2830 /* reset found pads */
2831 for (layer = 0; layer < 2; layer++)
2832 PadList[layer].Location = PadList[layer].Number = 0;
2834 /* reset PVs */
2835 PVList.Number = PVList.Location = 0;
2836 RatList.Number = RatList.Location = 0;
2838 return (false);
2842 * \brief Finds all connections to the pins of the passed element.
2844 * The result is written to file FP.
2846 * \return true if operation was aborted.
2848 static bool
2849 PrintElementConnections (ElementType *Element, FILE * FP, int flag, bool AndDraw)
2851 PrintConnectionElementName (Element, FP);
2853 /* check all pins in element */
2854 PIN_LOOP (Element);
2856 /* pin might have been checked before, add to list if not */
2857 if (TEST_FLAG (flag, pin))
2859 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP);
2860 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2861 continue;
2863 if (ADD_PV_TO_LIST (pin, flag))
2864 return true;
2865 DoIt (flag, true, AndDraw);
2866 /* printout all found connections */
2867 PrintPinConnections (FP, true);
2868 PrintPadConnections (TOP_SIDE, FP, false);
2869 PrintPadConnections (BOTTOM_SIDE, FP, false);
2870 fputs ("\t}\n", FP);
2871 if (PrepareNextLoop (FP))
2872 return (true);
2874 END_LOOP;
2876 /* check all pads in element */
2877 PAD_LOOP (Element);
2879 Cardinal layer;
2880 /* pad might have been checked before, add to list if not */
2881 if (TEST_FLAG (flag, pad))
2883 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP);
2884 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP);
2885 continue;
2887 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE;
2888 if (ADD_PAD_TO_LIST (layer, pad, flag))
2889 return true;
2890 DoIt (flag, true, AndDraw);
2891 /* print all found connections */
2892 PrintPadConnections (layer, FP, true);
2893 PrintPadConnections (layer ==
2894 (TOP_SIDE ? BOTTOM_SIDE : TOP_SIDE),
2895 FP, false);
2896 PrintPinConnections (FP, false);
2897 fputs ("\t}\n", FP);
2898 if (PrepareNextLoop (FP))
2899 return (true);
2901 END_LOOP;
2902 fputs ("}\n\n", FP);
2903 return (false);
2907 * \brief Draws all new connections which have been found since the
2908 * routine was called the last time.
2910 static void
2911 DrawNewConnections (void)
2913 int i;
2914 Cardinal position;
2916 /* decrement 'i' to keep layerstack order */
2917 for (i = max_copper_layer - 1; i != -1; i--)
2919 Cardinal layer = LayerStack[i];
2921 if (PCB->Data->Layer[layer].On)
2923 /* draw all new lines */
2924 position = LineList[layer].DrawLocation;
2925 for (; position < LineList[layer].Number; position++)
2926 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position));
2927 LineList[layer].DrawLocation = LineList[layer].Number;
2929 /* draw all new arcs */
2930 position = ArcList[layer].DrawLocation;
2931 for (; position < ArcList[layer].Number; position++)
2932 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position));
2933 ArcList[layer].DrawLocation = ArcList[layer].Number;
2935 /* draw all new polygons */
2936 position = PolygonList[layer].DrawLocation;
2937 for (; position < PolygonList[layer].Number; position++)
2938 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position));
2939 PolygonList[layer].DrawLocation = PolygonList[layer].Number;
2943 /* draw all new pads */
2944 if (PCB->PinOn)
2945 for (i = 0; i < 2; i++)
2947 position = PadList[i].DrawLocation;
2949 for (; position < PadList[i].Number; position++)
2950 DrawPad (PADLIST_ENTRY (i, position));
2951 PadList[i].DrawLocation = PadList[i].Number;
2954 /* draw all new PVs; 'PVList' holds a list of pointers to the
2955 * sorted array pointers to PV data
2957 while (PVList.DrawLocation < PVList.Number)
2959 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation);
2961 if (TEST_FLAG (PINFLAG, pv))
2963 if (PCB->PinOn)
2964 DrawPin (pv);
2966 else if (PCB->ViaOn)
2967 DrawVia (pv);
2968 PVList.DrawLocation++;
2970 /* draw the new rat-lines */
2971 if (PCB->RatOn)
2973 position = RatList.DrawLocation;
2974 for (; position < RatList.Number; position++)
2975 DrawRat (RATLIST_ENTRY (position));
2976 RatList.DrawLocation = RatList.Number;
2981 * \brief Find all connections to pins within one element.
2983 void
2984 LookupElementConnections (ElementType *Element, FILE * FP)
2986 /* reset all currently marked connections */
2987 User = true;
2988 ClearFlagOnAllObjects (true, FOUNDFLAG);
2989 InitConnectionLookup ();
2990 PrintElementConnections (Element, FP, FOUNDFLAG, true);
2991 SetChangedFlag (true);
2992 if (Settings.RingBellWhenFinished)
2993 gui->beep ();
2994 FreeConnectionLookupMemory ();
2995 IncrementUndoSerialNumber ();
2996 User = false;
2997 Draw ();
3001 * \brief Find all connections to pins of all element.
3003 void
3004 LookupConnectionsToAllElements (FILE * FP)
3006 /* reset all currently marked connections */
3007 User = false;
3008 ClearFlagOnAllObjects (false, FOUNDFLAG);
3009 InitConnectionLookup ();
3011 ELEMENT_LOOP (PCB->Data);
3013 /* break if abort dialog returned true */
3014 if (PrintElementConnections (element, FP, FOUNDFLAG, false))
3015 break;
3016 SEPARATE (FP);
3017 if (Settings.ResetAfterElement && n != 1)
3018 ClearFlagOnAllObjects (false, FOUNDFLAG);
3020 END_LOOP;
3021 if (Settings.RingBellWhenFinished)
3022 gui->beep ();
3023 ClearFlagOnAllObjects (false, FOUNDFLAG);
3024 FreeConnectionLookupMemory ();
3025 Redraw ();
3029 * \brief Add the starting object to the list of found objects.
3031 static bool
3032 ListStart (int type, void *ptr1, void *ptr2, void *ptr3, int flag)
3034 DumpList ();
3035 switch (type)
3037 case PIN_TYPE:
3038 case VIA_TYPE:
3040 if (ADD_PV_TO_LIST ((PinType *) ptr2, flag))
3041 return true;
3042 break;
3045 case RATLINE_TYPE:
3047 if (ADD_RAT_TO_LIST ((RatType *) ptr1, flag))
3048 return true;
3049 break;
3052 case LINE_TYPE:
3054 int layer = GetLayerNumber (PCB->Data,
3055 (LayerType *) ptr1);
3057 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2, flag))
3058 return true;
3059 break;
3062 case ARC_TYPE:
3064 int layer = GetLayerNumber (PCB->Data,
3065 (LayerType *) ptr1);
3067 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2, flag))
3068 return true;
3069 break;
3072 case POLYGON_TYPE:
3074 int layer = GetLayerNumber (PCB->Data,
3075 (LayerType *) ptr1);
3077 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2, flag))
3078 return true;
3079 break;
3082 case PAD_TYPE:
3084 PadType *pad = (PadType *) ptr2;
3085 if (ADD_PAD_TO_LIST
3086 (TEST_FLAG
3087 (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE, pad, flag))
3088 return true;
3089 break;
3092 return (false);
3097 * \brief Looks up all connections from the object at the given
3098 * coordinates the TheFlag (normally 'FOUNDFLAG') is set for all objects
3099 * found.
3101 * The objects are re-drawn if AndDraw is true, also the action is
3102 * marked as undoable if AndDraw is true.
3104 void
3105 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int flag,
3106 bool AndRats)
3108 void *ptr1, *ptr2, *ptr3;
3109 char *name;
3110 int type;
3112 /* check if there are any pins or pads at that position */
3114 reassign_no_drc_flags ();
3116 type
3117 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range);
3118 if (type == NO_TYPE)
3120 type = SearchObjectByLocation (
3121 LOOKUP_MORE & ~(AndRats ? 0 : RATLINE_TYPE),
3122 &ptr1, &ptr2, &ptr3, X, Y, Range);
3123 if (type == NO_TYPE)
3124 return;
3125 if (type & SILK_TYPE)
3127 int laynum = GetLayerNumber (PCB->Data,
3128 (LayerType *) ptr1);
3130 /* don't mess with non-conducting objects! */
3131 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc)
3132 return;
3136 name = ConnectionName (type, ptr1, ptr2);
3137 hid_actionl ("NetlistShow", name, NULL);
3139 User = AndDraw;
3140 InitConnectionLookup ();
3142 /* now add the object to the appropriate list and start scanning
3143 * This is step (1) from the description
3145 ListStart (type, ptr1, ptr2, ptr3, flag);
3146 DoIt (flag, AndRats, AndDraw);
3147 if (User)
3148 IncrementUndoSerialNumber ();
3149 User = false;
3151 /* we are done */
3152 if (AndDraw)
3153 Draw ();
3154 if (AndDraw && Settings.RingBellWhenFinished)
3155 gui->beep ();
3156 FreeConnectionLookupMemory ();
3160 * \brief Find connections for rats nesting.
3162 * Assumes InitConnectionLookup() has already been done.
3164 void
3165 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3,
3166 bool undo, int flag, bool AndRats)
3168 User = undo;
3169 DumpList ();
3170 ListStart (type, ptr1, ptr2, ptr3, flag);
3171 DoIt (flag, AndRats, false);
3172 User = false;
3176 * \brief Find all unused pins of all elements.
3178 void
3179 LookupUnusedPins (FILE * FP)
3181 /* reset all currently marked connections */
3182 User = true;
3183 ClearFlagOnAllObjects (true, FOUNDFLAG);
3184 InitConnectionLookup ();
3186 ELEMENT_LOOP (PCB->Data);
3188 /* break if abort dialog returned true;
3189 * passing NULL as filedescriptor discards the normal output
3191 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP, FOUNDFLAG))
3192 break;
3194 END_LOOP;
3196 if (Settings.RingBellWhenFinished)
3197 gui->beep ();
3198 FreeConnectionLookupMemory ();
3199 IncrementUndoSerialNumber ();
3200 User = false;
3201 Draw ();
3205 * \brief Resets all used flags of pins and vias.
3207 bool
3208 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag)
3210 bool change = false;
3212 VIA_LOOP (PCB->Data);
3214 if (TEST_FLAG (flag, via))
3216 if (AndDraw)
3217 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3218 CLEAR_FLAG (flag, via);
3219 if (AndDraw)
3220 DrawVia (via);
3221 change = true;
3224 END_LOOP;
3225 ELEMENT_LOOP (PCB->Data);
3227 PIN_LOOP (element);
3229 if (TEST_FLAG (flag, pin))
3231 if (AndDraw)
3232 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3233 CLEAR_FLAG (flag, pin);
3234 if (AndDraw)
3235 DrawPin (pin);
3236 change = true;
3239 END_LOOP;
3240 PAD_LOOP (element);
3242 if (TEST_FLAG (flag, pad))
3244 if (AndDraw)
3245 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3246 CLEAR_FLAG (flag, pad);
3247 if (AndDraw)
3248 DrawPad (pad);
3249 change = true;
3252 END_LOOP;
3254 END_LOOP;
3255 if (change)
3256 SetChangedFlag (true);
3257 return change;
3261 * \brief Resets all used flags of LOs.
3263 bool
3264 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag)
3266 bool change = false;
3268 RAT_LOOP (PCB->Data);
3270 if (TEST_FLAG (flag, line))
3272 if (AndDraw)
3273 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
3274 CLEAR_FLAG (flag, line);
3275 if (AndDraw)
3276 DrawRat (line);
3277 change = true;
3280 END_LOOP;
3281 COPPERLINE_LOOP (PCB->Data);
3283 if (TEST_FLAG (flag, line))
3285 if (AndDraw)
3286 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3287 CLEAR_FLAG (flag, line);
3288 if (AndDraw)
3289 DrawLine (layer, line);
3290 change = true;
3293 ENDALL_LOOP;
3294 COPPERARC_LOOP (PCB->Data);
3296 if (TEST_FLAG (flag, arc))
3298 if (AndDraw)
3299 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3300 CLEAR_FLAG (flag, arc);
3301 if (AndDraw)
3302 DrawArc (layer, arc);
3303 change = true;
3306 ENDALL_LOOP;
3307 COPPERPOLYGON_LOOP (PCB->Data);
3309 if (TEST_FLAG (flag, polygon))
3311 if (AndDraw)
3312 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3313 CLEAR_FLAG (flag, polygon);
3314 if (AndDraw)
3315 DrawPolygon (layer, polygon);
3316 change = true;
3319 ENDALL_LOOP;
3320 if (change)
3321 SetChangedFlag (true);
3322 return change;
3326 * \brief Resets all found connections.
3328 bool
3329 ClearFlagOnAllObjects (bool AndDraw, int flag)
3331 bool change = false;
3333 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change;
3334 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change;
3336 return change;
3340 * \brief Dumps the list contents.
3342 static void
3343 DumpList (void)
3345 Cardinal i;
3347 for (i = 0; i < 2; i++)
3349 PadList[i].Number = 0;
3350 PadList[i].Location = 0;
3351 PadList[i].DrawLocation = 0;
3354 PVList.Number = 0;
3355 PVList.Location = 0;
3357 for (i = 0; i < max_copper_layer; i++)
3359 LineList[i].Location = 0;
3360 LineList[i].DrawLocation = 0;
3361 LineList[i].Number = 0;
3362 ArcList[i].Location = 0;
3363 ArcList[i].DrawLocation = 0;
3364 ArcList[i].Number = 0;
3365 PolygonList[i].Location = 0;
3366 PolygonList[i].DrawLocation = 0;
3367 PolygonList[i].Number = 0;
3369 RatList.Number = 0;
3370 RatList.Location = 0;
3371 RatList.DrawLocation = 0;
3374 struct drc_info
3376 int flag;
3380 * \brief Check for DRC violations on a single net starting from the pad
3381 * or pin.
3383 * Sees if the connectivity changes when everything is bloated, or
3384 * shrunk.
3386 static bool
3387 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
3389 Coord x, y;
3390 int object_count;
3391 long int *object_id_list;
3392 int *object_type_list;
3393 DrcViolationType *violation;
3394 int flag;
3396 if (PCB->Shrink != 0)
3398 Bloat = -PCB->Shrink;
3399 ListStart (What, ptr1, ptr2, ptr3, DRCFLAG | SELECTEDFLAG);
3400 DoIt (DRCFLAG | SELECTEDFLAG, true, false);
3401 /* ok now the shrunk net has the SELECTEDFLAG set */
3402 DumpList ();
3403 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG);
3404 Bloat = 0;
3405 drc = true; /* abort the search if we find anything not already found */
3406 if (DoIt (FOUNDFLAG, true, false))
3408 DumpList ();
3409 /* make the flag changes undoable */
3410 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
3411 User = true;
3412 drc = false;
3413 Bloat = -PCB->Shrink;
3414 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG);
3415 DoIt (SELECTEDFLAG, true, true);
3416 DumpList ();
3417 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG);
3418 Bloat = 0;
3419 drc = true;
3420 DoIt (FOUNDFLAG, true, true);
3421 DumpList ();
3422 User = false;
3423 drc = false;
3424 drcerr_count++;
3425 LocateError (&x, &y);
3426 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3427 violation = pcb_drc_violation_new (_("Potential for broken trace"),
3428 _("Insufficient overlap between objects can lead to broken tracks\n"
3429 "due to registration errors with old wheel style photo-plotters."),
3430 x, y,
3431 0, /* ANGLE OF ERROR UNKNOWN */
3432 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3433 0, /* MAGNITUDE OF ERROR UNKNOWN */
3434 PCB->Shrink,
3435 object_count,
3436 object_id_list,
3437 object_type_list);
3438 append_drc_violation (violation);
3439 pcb_drc_violation_free (violation);
3440 free (object_id_list);
3441 free (object_type_list);
3443 if (!throw_drc_dialog())
3444 return (true);
3445 IncrementUndoSerialNumber ();
3446 Undo (true);
3448 DumpList ();
3450 /* now check the bloated condition */
3451 drc = false;
3452 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
3453 Bloat = 0;
3454 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG);
3455 DoIt (SELECTEDFLAG, true, false);
3456 DumpList ();
3457 flag = FOUNDFLAG;
3458 ListStart (What, ptr1, ptr2, ptr3, flag);
3459 Bloat = PCB->Bloat;
3460 drc = true;
3461 while (DoIt (flag, true, false))
3463 DumpList ();
3464 /* make the flag changes undoable */
3465 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
3466 User = true;
3467 drc = false;
3468 Bloat = 0;
3469 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG);
3470 DoIt (SELECTEDFLAG, true, true);
3471 DumpList ();
3472 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG);
3473 Bloat = PCB->Bloat;
3474 drc = true;
3475 DoIt (FOUNDFLAG, true, true);
3476 DumpList ();
3477 drcerr_count++;
3478 LocateError (&x, &y);
3479 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3480 violation = pcb_drc_violation_new (_("Copper areas too close"),
3481 _("Circuits that are too close may bridge during imaging, etching,\n"
3482 "plating, or soldering processes resulting in a direct short."),
3483 x, y,
3484 0, /* ANGLE OF ERROR UNKNOWN */
3485 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3486 0, /* MAGNITUDE OF ERROR UNKNOWN */
3487 PCB->Bloat,
3488 object_count,
3489 object_id_list,
3490 object_type_list);
3491 append_drc_violation (violation);
3492 pcb_drc_violation_free (violation);
3493 free (object_id_list);
3494 free (object_type_list);
3495 User = false;
3496 drc = false;
3497 if (!throw_drc_dialog())
3498 return (true);
3499 IncrementUndoSerialNumber ();
3500 Undo (true);
3501 /* highlight the rest of the encroaching net so it's not reported again */
3502 flag = FOUNDFLAG | SELECTEDFLAG;
3503 Bloat = 0;
3504 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3, flag);
3505 DoIt (flag, true, true);
3506 DumpList ();
3507 drc = true;
3508 Bloat = PCB->Bloat;
3509 ListStart (What, ptr1, ptr2, ptr3, flag);
3511 drc = false;
3512 DumpList ();
3513 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
3514 return (false);
3518 * \brief DRC clearance callback.
3520 static int
3521 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon,
3522 int type, void *ptr1, void *ptr2, void *userdata)
3524 struct drc_info *i = (struct drc_info *) userdata;
3525 char *message;
3526 Coord x, y;
3527 int object_count;
3528 long int *object_id_list;
3529 int *object_type_list;
3530 DrcViolationType *violation;
3532 LineType *line = (LineType *) ptr2;
3533 ArcType *arc = (ArcType *) ptr2;
3534 PinType *pin = (PinType *) ptr2;
3535 PadType *pad = (PadType *) ptr2;
3537 SetThing (type, ptr1, ptr2, ptr2);
3539 switch (type)
3541 case LINE_TYPE:
3542 if (line->Clearance < 2 * PCB->Bloat)
3544 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3545 SET_FLAG (i->flag, line);
3546 message = _("Line with insufficient clearance inside polygon\n");
3547 goto doIsBad;
3549 break;
3550 case ARC_TYPE:
3551 if (arc->Clearance < 2 * PCB->Bloat)
3553 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3554 SET_FLAG (i->flag, arc);
3555 message = _("Arc with insufficient clearance inside polygon\n");
3556 goto doIsBad;
3558 break;
3559 case PAD_TYPE:
3560 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat)
3561 if (IsPadInPolygon(pad,polygon))
3563 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3564 SET_FLAG (i->flag, pad);
3565 message = _("Pad with insufficient clearance inside polygon\n");
3566 goto doIsBad;
3568 break;
3569 case PIN_TYPE:
3570 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3572 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3573 SET_FLAG (i->flag, pin);
3574 message = _("Pin with insufficient clearance inside polygon\n");
3575 goto doIsBad;
3577 break;
3578 case VIA_TYPE:
3579 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat)
3581 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
3582 SET_FLAG (i->flag, pin);
3583 message = _("Via with insufficient clearance inside polygon\n");
3584 goto doIsBad;
3586 break;
3587 default:
3588 Message ("hace: Bad Plow object in callback\n");
3590 return 0;
3592 doIsBad:
3593 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
3594 SET_FLAG (FOUNDFLAG, polygon);
3595 DrawPolygon (layer, polygon);
3596 DrawObject (type, ptr1, ptr2);
3597 drcerr_count++;
3598 LocateError (&x, &y);
3599 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3600 violation = pcb_drc_violation_new (message,
3601 _("Circuits that are too close may bridge during imaging, etching,\n"
3602 "plating, or soldering processes resulting in a direct short."),
3603 x, y,
3604 0, /* ANGLE OF ERROR UNKNOWN */
3605 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */
3606 0, /* MAGNITUDE OF ERROR UNKNOWN */
3607 PCB->Bloat,
3608 object_count,
3609 object_id_list,
3610 object_type_list);
3611 append_drc_violation (violation);
3612 pcb_drc_violation_free (violation);
3613 free (object_id_list);
3614 free (object_type_list);
3616 if (!throw_drc_dialog())
3617 return 1;
3619 IncrementUndoSerialNumber ();
3620 Undo (true);
3621 return 0;
3625 * \brief Check for DRC violations.
3627 * See if the connectivity changes when everything is bloated, or shrunk.
3630 DRCAll (void)
3632 Coord x, y;
3633 int object_count;
3634 long int *object_id_list;
3635 int *object_type_list;
3636 DrcViolationType *violation;
3637 int tmpcnt;
3638 int nopastecnt = 0;
3639 bool IsBad;
3640 struct drc_info info;
3642 reset_drc_dialog_message();
3644 IsBad = false;
3645 drcerr_count = 0;
3646 SaveStackAndVisibility ();
3647 ResetStackAndVisibility ();
3648 hid_action ("LayersChanged");
3649 InitConnectionLookup ();
3651 if (ClearFlagOnAllObjects (true, FOUNDFLAG | DRCFLAG | SELECTEDFLAG))
3653 IncrementUndoSerialNumber ();
3654 Draw ();
3657 User = false;
3659 ELEMENT_LOOP (PCB->Data);
3661 PIN_LOOP (element);
3663 if (!TEST_FLAG (DRCFLAG, pin)
3664 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin))
3666 IsBad = true;
3667 break;
3670 END_LOOP;
3671 if (IsBad)
3672 break;
3673 PAD_LOOP (element);
3676 /* count up how many pads have no solderpaste openings */
3677 if (TEST_FLAG (NOPASTEFLAG, pad))
3678 nopastecnt++;
3680 if (!TEST_FLAG (DRCFLAG, pad)
3681 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad))
3683 IsBad = true;
3684 break;
3687 END_LOOP;
3688 if (IsBad)
3689 break;
3691 END_LOOP;
3692 if (!IsBad)
3693 VIA_LOOP (PCB->Data);
3695 if (!TEST_FLAG (DRCFLAG, via)
3696 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via))
3698 IsBad = true;
3699 break;
3702 END_LOOP;
3704 ClearFlagOnAllObjects (false, IsBad ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG));
3705 info.flag = SELECTEDFLAG;
3706 /* check minimum widths and polygon clearances */
3707 if (!IsBad)
3709 COPPERLINE_LOOP (PCB->Data);
3711 /* check line clearances in polygons */
3712 if (PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback, &info))
3714 IsBad = true;
3715 break;
3717 if (line->Thickness < PCB->minWid)
3719 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
3720 SET_FLAG (SELECTEDFLAG, line);
3721 DrawLine (layer, line);
3722 drcerr_count++;
3723 SetThing (LINE_TYPE, layer, line, line);
3724 LocateError (&x, &y);
3725 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3726 violation = pcb_drc_violation_new (_("Line width is too thin"),
3727 _("Process specifications dictate a minimum feature-width\n"
3728 "that can reliably be reproduced"),
3729 x, y,
3730 0, /* ANGLE OF ERROR UNKNOWN */
3731 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3732 line->Thickness,
3733 PCB->minWid,
3734 object_count,
3735 object_id_list,
3736 object_type_list);
3737 append_drc_violation (violation);
3738 pcb_drc_violation_free (violation);
3739 free (object_id_list);
3740 free (object_type_list);
3741 if (!throw_drc_dialog())
3743 IsBad = true;
3744 break;
3746 IncrementUndoSerialNumber ();
3747 Undo (false);
3750 ENDALL_LOOP;
3752 if (!IsBad)
3754 COPPERARC_LOOP (PCB->Data);
3756 if (PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback, &info))
3758 IsBad = true;
3759 break;
3761 if (arc->Thickness < PCB->minWid)
3763 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
3764 SET_FLAG (SELECTEDFLAG, arc);
3765 DrawArc (layer, arc);
3766 drcerr_count++;
3767 SetThing (ARC_TYPE, layer, arc, arc);
3768 LocateError (&x, &y);
3769 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3770 violation = pcb_drc_violation_new (_("Arc width is too thin"),
3771 _("Process specifications dictate a minimum feature-width\n"
3772 "that can reliably be reproduced"),
3773 x, y,
3774 0, /* ANGLE OF ERROR UNKNOWN */
3775 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3776 arc->Thickness,
3777 PCB->minWid,
3778 object_count,
3779 object_id_list,
3780 object_type_list);
3781 append_drc_violation (violation);
3782 pcb_drc_violation_free (violation);
3783 free (object_id_list);
3784 free (object_type_list);
3785 if (!throw_drc_dialog())
3787 IsBad = true;
3788 break;
3790 IncrementUndoSerialNumber ();
3791 Undo (false);
3794 ENDALL_LOOP;
3796 if (!IsBad)
3798 ALLPIN_LOOP (PCB->Data);
3800 if (PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback, &info))
3802 IsBad = true;
3803 break;
3805 if (!TEST_FLAG (HOLEFLAG, pin) &&
3806 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing)
3808 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3809 SET_FLAG (SELECTEDFLAG, pin);
3810 DrawPin (pin);
3811 drcerr_count++;
3812 SetThing (PIN_TYPE, element, pin, pin);
3813 LocateError (&x, &y);
3814 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3815 violation = pcb_drc_violation_new (_("Pin annular ring too small"),
3816 _("Annular rings that are too small may erode during etching,\n"
3817 "resulting in a broken connection"),
3818 x, y,
3819 0, /* ANGLE OF ERROR UNKNOWN */
3820 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3821 (pin->Thickness - pin->DrillingHole) / 2,
3822 PCB->minRing,
3823 object_count,
3824 object_id_list,
3825 object_type_list);
3826 append_drc_violation (violation);
3827 pcb_drc_violation_free (violation);
3828 free (object_id_list);
3829 free (object_type_list);
3830 if (!throw_drc_dialog())
3832 IsBad = true;
3833 break;
3835 IncrementUndoSerialNumber ();
3836 Undo (false);
3838 if (pin->DrillingHole < PCB->minDrill)
3840 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
3841 SET_FLAG (SELECTEDFLAG, pin);
3842 DrawPin (pin);
3843 drcerr_count++;
3844 SetThing (PIN_TYPE, element, pin, pin);
3845 LocateError (&x, &y);
3846 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3847 violation = pcb_drc_violation_new (_("Pin drill size is too small"),
3848 _("Process rules dictate the minimum drill size which can be used"),
3849 x, y,
3850 0, /* ANGLE OF ERROR UNKNOWN */
3851 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3852 pin->DrillingHole,
3853 PCB->minDrill,
3854 object_count,
3855 object_id_list,
3856 object_type_list);
3857 append_drc_violation (violation);
3858 pcb_drc_violation_free (violation);
3859 free (object_id_list);
3860 free (object_type_list);
3861 if (!throw_drc_dialog())
3863 IsBad = true;
3864 break;
3866 IncrementUndoSerialNumber ();
3867 Undo (false);
3870 ENDALL_LOOP;
3872 if (!IsBad)
3874 ALLPAD_LOOP (PCB->Data);
3876 if (PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback, &info))
3878 IsBad = true;
3879 break;
3881 if (pad->Thickness < PCB->minWid)
3883 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
3884 SET_FLAG (SELECTEDFLAG, pad);
3885 DrawPad (pad);
3886 drcerr_count++;
3887 SetThing (PAD_TYPE, element, pad, pad);
3888 LocateError (&x, &y);
3889 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3890 violation = pcb_drc_violation_new (_("Pad is too thin"),
3891 _("Pads which are too thin may erode during etching,\n"
3892 "resulting in a broken or unreliable connection"),
3893 x, y,
3894 0, /* ANGLE OF ERROR UNKNOWN */
3895 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3896 pad->Thickness,
3897 PCB->minWid,
3898 object_count,
3899 object_id_list,
3900 object_type_list);
3901 append_drc_violation (violation);
3902 pcb_drc_violation_free (violation);
3903 free (object_id_list);
3904 free (object_type_list);
3905 if (!throw_drc_dialog())
3907 IsBad = true;
3908 break;
3910 IncrementUndoSerialNumber ();
3911 Undo (false);
3914 ENDALL_LOOP;
3916 if (!IsBad)
3918 VIA_LOOP (PCB->Data);
3920 if (PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback, &info))
3922 IsBad = true;
3923 break;
3925 if (!TEST_FLAG (HOLEFLAG, via) &&
3926 via->Thickness - via->DrillingHole < 2 * PCB->minRing)
3928 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3929 SET_FLAG (SELECTEDFLAG, via);
3930 DrawVia (via);
3931 drcerr_count++;
3932 SetThing (VIA_TYPE, via, via, via);
3933 LocateError (&x, &y);
3934 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3935 violation = pcb_drc_violation_new (_("Via annular ring too small"),
3936 _("Annular rings that are too small may erode during etching,\n"
3937 "resulting in a broken connection"),
3938 x, y,
3939 0, /* ANGLE OF ERROR UNKNOWN */
3940 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3941 (via->Thickness - via->DrillingHole) / 2,
3942 PCB->minRing,
3943 object_count,
3944 object_id_list,
3945 object_type_list);
3946 append_drc_violation (violation);
3947 pcb_drc_violation_free (violation);
3948 free (object_id_list);
3949 free (object_type_list);
3950 if (!throw_drc_dialog())
3952 IsBad = true;
3953 break;
3955 IncrementUndoSerialNumber ();
3956 Undo (false);
3958 if (via->DrillingHole < PCB->minDrill)
3960 AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
3961 SET_FLAG (SELECTEDFLAG, via);
3962 DrawVia (via);
3963 drcerr_count++;
3964 SetThing (VIA_TYPE, via, via, via);
3965 LocateError (&x, &y);
3966 BuildObjectList (&object_count, &object_id_list, &object_type_list);
3967 violation = pcb_drc_violation_new (_("Via drill size is too small"),
3968 _("Process rules dictate the minimum drill size which can be used"),
3969 x, y,
3970 0, /* ANGLE OF ERROR UNKNOWN */
3971 TRUE, /* MEASUREMENT OF ERROR KNOWN */
3972 via->DrillingHole,
3973 PCB->minDrill,
3974 object_count,
3975 object_id_list,
3976 object_type_list);
3977 append_drc_violation (violation);
3978 pcb_drc_violation_free (violation);
3979 free (object_id_list);
3980 free (object_type_list);
3981 if (!throw_drc_dialog())
3983 IsBad = true;
3984 break;
3986 IncrementUndoSerialNumber ();
3987 Undo (false);
3990 END_LOOP;
3993 FreeConnectionLookupMemory ();
3994 Bloat = 0;
3996 /* check silkscreen minimum widths outside of elements */
3997 /* XXX - need to check text and polygons too! */
3998 if (!IsBad)
4000 SILKLINE_LOOP (PCB->Data);
4002 if (line->Thickness < PCB->minSlk)
4004 SET_FLAG (SELECTEDFLAG, line);
4005 DrawLine (layer, line);
4006 drcerr_count++;
4007 SetThing (LINE_TYPE, layer, line, line);
4008 LocateError (&x, &y);
4009 BuildObjectList (&object_count, &object_id_list, &object_type_list);
4010 violation = pcb_drc_violation_new (_("Silk line is too thin"),
4011 _("Process specifications dictate a minimum silkscreen\n"
4012 "feature-width that can reliably be reproduced"),
4013 x, y,
4014 0, /* ANGLE OF ERROR UNKNOWN */
4015 TRUE, /* MEASUREMENT OF ERROR KNOWN */
4016 line->Thickness,
4017 PCB->minSlk,
4018 object_count,
4019 object_id_list,
4020 object_type_list);
4021 append_drc_violation (violation);
4022 pcb_drc_violation_free (violation);
4023 free (object_id_list);
4024 free (object_type_list);
4025 if (!throw_drc_dialog())
4027 IsBad = true;
4028 break;
4032 ENDALL_LOOP;
4035 /* check silkscreen minimum widths inside of elements */
4036 /* XXX - need to check text and polygons too! */
4037 if (!IsBad)
4039 ELEMENT_LOOP (PCB->Data);
4041 tmpcnt = 0;
4042 ELEMENTLINE_LOOP (element);
4044 if (line->Thickness < PCB->minSlk)
4045 tmpcnt++;
4047 END_LOOP;
4048 if (tmpcnt > 0)
4050 char *title;
4051 char *name;
4052 char *buffer;
4053 int buflen;
4055 SET_FLAG (SELECTEDFLAG, element);
4056 DrawElement (element);
4057 drcerr_count++;
4058 SetThing (ELEMENT_TYPE, element, element, element);
4059 LocateError (&x, &y);
4060 BuildObjectList (&object_count, &object_id_list, &object_type_list);
4062 title = _("Element %s has %i silk lines which are too thin");
4063 name = (char *)UNKNOWN (NAMEONPCB_NAME (element));
4065 /* -4 is for the %s and %i place-holders */
4066 /* +11 is the max printed length for a 32 bit integer */
4067 /* +1 is for the \0 termination */
4068 buflen = strlen (title) - 4 + strlen (name) + 11 + 1;
4069 buffer = (char *)malloc (buflen);
4070 snprintf (buffer, buflen, title, name, tmpcnt);
4072 violation = pcb_drc_violation_new (buffer,
4073 _("Process specifications dictate a minimum silkscreen\n"
4074 "feature-width that can reliably be reproduced"),
4075 x, y,
4076 0, /* ANGLE OF ERROR UNKNOWN */
4077 TRUE, /* MEASUREMENT OF ERROR KNOWN */
4078 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
4079 PCB->minSlk,
4080 object_count,
4081 object_id_list,
4082 object_type_list);
4083 free (buffer);
4084 append_drc_violation (violation);
4085 pcb_drc_violation_free (violation);
4086 free (object_id_list);
4087 free (object_type_list);
4088 if (!throw_drc_dialog())
4090 IsBad = true;
4091 break;
4095 END_LOOP;
4099 if (IsBad)
4101 IncrementUndoSerialNumber ();
4105 RestoreStackAndVisibility ();
4106 hid_action ("LayersChanged");
4107 gui->invalidate_all ();
4109 if (nopastecnt > 0)
4111 Message (ngettext ("Warning: %d pad has the nopaste flag set.\n",
4112 "Warning: %d pads have the nopaste flag set.\n",
4113 nopastecnt), nopastecnt);
4115 return IsBad ? -drcerr_count : drcerr_count;
4119 * \brief Locate the coordinatates of offending item (thing).
4121 static void
4122 LocateError (Coord *x, Coord *y)
4124 switch (thing_type)
4126 case LINE_TYPE:
4128 LineType *line = (LineType *) thing_ptr3;
4129 *x = (line->Point1.X + line->Point2.X) / 2;
4130 *y = (line->Point1.Y + line->Point2.Y) / 2;
4131 break;
4133 case ARC_TYPE:
4135 ArcType *arc = (ArcType *) thing_ptr3;
4136 *x = arc->X;
4137 *y = arc->Y;
4138 break;
4140 case POLYGON_TYPE:
4142 PolygonType *polygon = (PolygonType *) thing_ptr3;
4143 *x =
4144 (polygon->Clipped->contours->xmin +
4145 polygon->Clipped->contours->xmax) / 2;
4146 *y =
4147 (polygon->Clipped->contours->ymin +
4148 polygon->Clipped->contours->ymax) / 2;
4149 break;
4151 case PIN_TYPE:
4152 case VIA_TYPE:
4154 PinType *pin = (PinType *) thing_ptr3;
4155 *x = pin->X;
4156 *y = pin->Y;
4157 break;
4159 case PAD_TYPE:
4161 PadType *pad = (PadType *) thing_ptr3;
4162 *x = (pad->Point1.X + pad->Point2.X) / 2;
4163 *y = (pad->Point1.Y + pad->Point2.Y) / 2;
4164 break;
4166 case ELEMENT_TYPE:
4168 ElementType *element = (ElementType *) thing_ptr3;
4169 *x = element->MarkX;
4170 *y = element->MarkY;
4171 break;
4173 default:
4174 return;
4180 * \brief Build a list of the of offending items by ID.
4182 * (Currently just "thing").
4184 static void
4185 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
4187 *object_count = 0;
4188 *object_id_list = NULL;
4189 *object_type_list = NULL;
4191 switch (thing_type)
4193 case LINE_TYPE:
4194 case ARC_TYPE:
4195 case POLYGON_TYPE:
4196 case PIN_TYPE:
4197 case VIA_TYPE:
4198 case PAD_TYPE:
4199 case ELEMENT_TYPE:
4200 case RATLINE_TYPE:
4201 *object_count = 1;
4202 *object_id_list = (long int *)malloc (sizeof (long int));
4203 *object_type_list = (int *)malloc (sizeof (int));
4204 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
4205 **object_type_list = thing_type;
4206 return;
4208 default:
4209 fprintf (stderr,
4210 _("Internal error in BuildObjectList: unknown object type %i\n"),
4211 thing_type);
4217 * \brief Center the display to show the offending item (thing).
4219 static void
4220 GotoError (void)
4222 Coord X, Y;
4224 LocateError (&X, &Y);
4226 switch (thing_type)
4228 case LINE_TYPE:
4229 case ARC_TYPE:
4230 case POLYGON_TYPE:
4231 ChangeGroupVisibility (
4232 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1),
4233 true, true);
4235 CenterDisplay (X, Y, false);
4238 void
4239 InitConnectionLookup (void)
4241 InitComponentLookup ();
4242 InitLayoutLookup ();
4245 void
4246 FreeConnectionLookupMemory (void)
4248 FreeComponentLookupMemory ();
4249 FreeLayoutLookupMemory ();