1 /*!
2 * \file src/search.c
3 *
4 * \brief Search routines.
5 *
6 * Some of the functions use dummy parameters.
7 *
8 * <hr>
9 *
10 * <h1><b>Copyright.</b></h1>\n
11 *
12 * PCB, interactive printed circuit board design
13 *
14 * Copyright (C) 1994,1995,1996 Thomas Nau
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 *
30 * Contact addresses for paper mail and Email:
31 *
32 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
33 *
34 * Thomas.Nau@rz.uni-ulm.de
35 */
36
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <math.h>
43 #include <setjmp.h>
44
45 #include "global.h"
46
47 #include "box.h"
48 #include "data.h"
49 #include "draw.h"
50 #include "error.h"
51 #include "find.h"
52 #include "misc.h"
53 #include "polygon.h"
54 #include "rtree.h"
55 #include "search.h"
56
57 #ifdef HAVE_LIBDMALLOC
58 #include <dmalloc.h>
59 #endif
60
61 /* ---------------------------------------------------------------------------
62 * some local identifiers
63 */
64 static double PosX, PosY; /* search position for subroutines */
65 static Coord SearchRadius;
66 static BoxType SearchBox;
67 static LayerType *SearchLayer;
68
69 /* ---------------------------------------------------------------------------
70 * some local prototypes. The first parameter includes LOCKED_TYPE if we
71 * want to include locked types in the search.
72 */
73 static bool SearchLineByLocation (int, LayerType **, LineType **,
74 LineType **);
75 static bool SearchArcByLocation (int, LayerType **, ArcType **,
76 ArcType **);
77 static bool SearchRatLineByLocation (int, RatType **, RatType **,
78 RatType **);
79 static bool SearchTextByLocation (int, LayerType **, TextType **,
80 TextType **);
81 static bool SearchPolygonByLocation (int, LayerType **, PolygonType **,
82 PolygonType **);
83 static bool SearchPinByLocation (int, ElementType **, PinType **,
84 PinType **);
85 static bool SearchPadByLocation (int, ElementType **, PadType **,
86 PadType **, bool);
87 static bool SearchViaByLocation (int, PinType **, PinType **,
88 PinType **);
89 static bool SearchElementNameByLocation (int, ElementType **,
90 TextType **, TextType **,
91 bool);
92 static bool SearchLinePointByLocation (int, LayerType **, LineType **,
93 PointType **);
94 static bool SearchPointByLocation (int, LayerType **, PolygonType **,
95 PointType **);
96 static bool SearchElementByLocation (int, ElementType **,
97 ElementType **, ElementType **,
98 bool);
99
100 struct ans_info
101 {
102 void **ptr1, **ptr2, **ptr3;
103 bool BackToo;
104 double area;
105 jmp_buf env;
106 int locked; /*!< This will be zero or \c LOCKFLAG. */
107 bool found_anything;
108 double nearest_sq_dist;
109 };
110
111 static int
pinorvia_callback(const BoxType * box,void * cl)112 pinorvia_callback (const BoxType * box, void *cl)
113 {
114 struct ans_info *i = (struct ans_info *) cl;
115 PinType *pin = (PinType *) box;
116 AnyObjectType *ptr1 = pin->Element ? pin->Element : pin;
117
118 if (TEST_FLAG (i->locked, ptr1))
119 return 0;
120
121 if (!IsPointOnPin (PosX, PosY, SearchRadius, pin))
122 return 0;
123 *i->ptr1 = ptr1;
124 *i->ptr2 = *i->ptr3 = pin;
125 longjmp (i->env, 1);
126 return 1; /* never reached */
127 }
128
129 /*!
130 * \brief Searches a via.
131 */
132 static bool
SearchViaByLocation(int locked,PinType ** Via,PinType ** Dummy1,PinType ** Dummy2)133 SearchViaByLocation (int locked, PinType ** Via, PinType ** Dummy1,
134 PinType ** Dummy2)
135 {
136 struct ans_info info;
137
138 /* search only if via-layer is visible */
139 if (!PCB->ViaOn)
140 return false;
141
142 info.ptr1 = (void **) Via;
143 info.ptr2 = (void **) Dummy1;
144 info.ptr3 = (void **) Dummy2;
145 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
146
147 if (setjmp (info.env) == 0)
148 {
149 r_search (PCB->Data->via_tree, &SearchBox, NULL, pinorvia_callback,
150 &info);
151 return false;
152 }
153 return true;
154 }
155
156 /*!
157 * \brief Searches a pin.
158 *
159 * Starts with the newest element.
160 */
161 static bool
SearchPinByLocation(int locked,ElementType ** Element,PinType ** Pin,PinType ** Dummy)162 SearchPinByLocation (int locked, ElementType ** Element, PinType ** Pin,
163 PinType ** Dummy)
164 {
165 struct ans_info info;
166
167 /* search only if pin-layer is visible */
168 if (!PCB->PinOn)
169 return false;
170 info.ptr1 = (void **) Element;
171 info.ptr2 = (void **) Pin;
172 info.ptr3 = (void **) Dummy;
173 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
174
175 if (setjmp (info.env) == 0)
176 r_search (PCB->Data->pin_tree, &SearchBox, NULL, pinorvia_callback,
177 &info);
178 else
179 return true;
180 return false;
181 }
182
183 static int
pad_callback(const BoxType * b,void * cl)184 pad_callback (const BoxType * b, void *cl)
185 {
186 PadType *pad = (PadType *) b;
187 struct ans_info *i = (struct ans_info *) cl;
188 AnyObjectType *ptr1 = pad->Element;
189 double sq_dist;
190
191 /* Reject locked pads, backside pads (if !BackToo), and non-hit pads */
192 if (TEST_FLAG (i->locked, ptr1) ||
193 (!FRONT (pad) && !i->BackToo) ||
194 !IsPointInPad (PosX, PosY, SearchRadius, pad))
195 return 0;
196
197 /* Determine how close our test-position was to the center of the pad */
198 sq_dist = (PosX - (pad->Point1.X + (pad->Point2.X - pad->Point1.X) / 2)) *
199 (PosX - (pad->Point1.X + (pad->Point2.X - pad->Point1.X) / 2)) +
200 (PosY - (pad->Point1.Y + (pad->Point2.Y - pad->Point1.Y) / 2)) *
201 (PosY - (pad->Point1.Y + (pad->Point2.Y - pad->Point1.Y) / 2));
202
203 /* If this was the closest hit so far, record it */
204 if (!i->found_anything || sq_dist < i->nearest_sq_dist)
205 {
206 *i->ptr1 = ptr1;
207 *i->ptr2 = *i->ptr3 = pad;
208 i->found_anything = true;
209 i->nearest_sq_dist = sq_dist;
210 }
211 return 0;
212 }
213
214 /*!
215 * \brief Searches a pad.
216 *
217 * Starts with the newest element.
218 */
219 static bool
SearchPadByLocation(int locked,ElementType ** Element,PadType ** Pad,PadType ** Dummy,bool BackToo)220 SearchPadByLocation (int locked, ElementType ** Element, PadType ** Pad,
221 PadType ** Dummy, bool BackToo)
222 {
223 struct ans_info info;
224
225 /* search only if pin-layer is visible */
226 if (!PCB->PinOn)
227 return (false);
228 info.ptr1 = (void **) Element;
229 info.ptr2 = (void **) Pad;
230 info.ptr3 = (void **) Dummy;
231 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
232 info.BackToo = (BackToo && PCB->InvisibleObjectsOn);
233 info.found_anything = false;
234 r_search (PCB->Data->pad_tree, &SearchBox, NULL, pad_callback, &info);
235 return info.found_anything;
236 }
237
238 struct line_info
239 {
240 LineType **Line;
241 PointType **Point;
242 double least;
243 jmp_buf env;
244 int locked;
245 };
246
247 static int
line_callback(const BoxType * box,void * cl)248 line_callback (const BoxType * box, void *cl)
249 {
250 struct line_info *i = (struct line_info *) cl;
251 LineType *l = (LineType *) box;
252
253 if (TEST_FLAG (i->locked, l))
254 return 0;
255
256 if (!IsPointInPad (PosX, PosY, SearchRadius, (PadType *)l))
257 return 0;
258 *i->Line = l;
259 *i->Point = (PointType *) l;
260 longjmp (i->env, 1);
261 return 1; /* never reached */
262 }
263
264
265 /*!
266 * \brief Searches ordinary line on the SearchLayer.
267 */
268 static bool
SearchLineByLocation(int locked,LayerType ** Layer,LineType ** Line,LineType ** Dummy)269 SearchLineByLocation (int locked, LayerType ** Layer, LineType ** Line,
270 LineType ** Dummy)
271 {
272 struct line_info info;
273
274 info.Line = Line;
275 info.Point = (PointType **) Dummy;
276 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
277
278 *Layer = SearchLayer;
279 if (setjmp (info.env) == 0)
280 {
281 r_search (SearchLayer->line_tree, &SearchBox, NULL, line_callback,
282 &info);
283 return false;
284 }
285 return (true);
286 }
287
288 static int
rat_callback(const BoxType * box,void * cl)289 rat_callback (const BoxType * box, void *cl)
290 {
291 LineType *line = (LineType *) box;
292 struct ans_info *i = (struct ans_info *) cl;
293
294 if (TEST_FLAG (i->locked, line))
295 return 0;
296
297 if (TEST_FLAG (VIAFLAG, line) ?
298 (Distance (line->Point1.X, line->Point1.Y, PosX, PosY) <=
299 line->Thickness * 2 + SearchRadius) :
300 IsPointOnLine (PosX, PosY, SearchRadius, line))
301 {
302 *i->ptr1 = *i->ptr2 = *i->ptr3 = line;
303 longjmp (i->env, 1);
304 }
305 return 0;
306 }
307
308 /*!
309 * \brief Searches rat lines if they are visible.
310 */
311 static bool
SearchRatLineByLocation(int locked,RatType ** Line,RatType ** Dummy1,RatType ** Dummy2)312 SearchRatLineByLocation (int locked, RatType ** Line, RatType ** Dummy1,
313 RatType ** Dummy2)
314 {
315 struct ans_info info;
316
317 info.ptr1 = (void **) Line;
318 info.ptr2 = (void **) Dummy1;
319 info.ptr3 = (void **) Dummy2;
320 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
321
322 if (setjmp (info.env) == 0)
323 {
324 r_search (PCB->Data->rat_tree, &SearchBox, NULL, rat_callback, &info);
325 return false;
326 }
327 return (true);
328 }
329
330 struct arc_info
331 {
332 ArcType **Arc, **Dummy;
333 PointType **Point;
334 double least;
335 jmp_buf env;
336 int locked;
337 };
338
339 static int
arc_callback(const BoxType * box,void * cl)340 arc_callback (const BoxType * box, void *cl)
341 {
342 struct arc_info *i = (struct arc_info *) cl;
343 ArcType *a = (ArcType *) box;
344
345 if (TEST_FLAG (i->locked, a))
346 return 0;
347
348 if (!IsPointOnArc (PosX, PosY, SearchRadius, a))
349 return 0;
350 *i->Arc = a;
351 *i->Dummy = a;
352 longjmp (i->env, 1);
353 return 1; /* never reached */
354 }
355
356
357 /*!
358 * \brief Searches arc on the SearchLayer.
359 */
360 static bool
SearchArcByLocation(int locked,LayerType ** Layer,ArcType ** Arc,ArcType ** Dummy)361 SearchArcByLocation (int locked, LayerType ** Layer, ArcType ** Arc,
362 ArcType ** Dummy)
363 {
364 struct arc_info info;
365
366 info.Arc = Arc;
367 info.Dummy = Dummy;
368 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
369
370 *Layer = SearchLayer;
371 if (setjmp (info.env) == 0)
372 {
373 r_search (SearchLayer->arc_tree, &SearchBox, NULL, arc_callback, &info);
374 return false;
375 }
376 return (true);
377 }
378
379 static int
text_callback(const BoxType * box,void * cl)380 text_callback (const BoxType * box, void *cl)
381 {
382 TextType *text = (TextType *) box;
383 struct ans_info *i = (struct ans_info *) cl;
384
385 if (TEST_FLAG (i->locked, text))
386 return 0;
387
388 if (POINT_IN_BOX (PosX, PosY, &text->BoundingBox))
389 {
390 *i->ptr2 = *i->ptr3 = text;
391 longjmp (i->env, 1);
392 }
393 return 0;
394 }
395
396 /*!
397 * \brief Searches text on the SearchLayer.
398 */
399 static bool
SearchTextByLocation(int locked,LayerType ** Layer,TextType ** Text,TextType ** Dummy)400 SearchTextByLocation (int locked, LayerType ** Layer, TextType ** Text,
401 TextType ** Dummy)
402 {
403 struct ans_info info;
404
405 *Layer = SearchLayer;
406 info.ptr2 = (void **) Text;
407 info.ptr3 = (void **) Dummy;
408 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
409
410 if (setjmp (info.env) == 0)
411 {
412 r_search (SearchLayer->text_tree, &SearchBox, NULL, text_callback,
413 &info);
414 return false;
415 }
416 return (true);
417 }
418
419 static int
polygon_callback(const BoxType * box,void * cl)420 polygon_callback (const BoxType * box, void *cl)
421 {
422 PolygonType *polygon = (PolygonType *) box;
423 struct ans_info *i = (struct ans_info *) cl;
424
425 if (TEST_FLAG (i->locked, polygon))
426 return 0;
427
428 if (IsPointInPolygon (PosX, PosY, SearchRadius, polygon))
429 {
430 *i->ptr2 = *i->ptr3 = polygon;
431 longjmp (i->env, 1);
432 }
433 return 0;
434 }
435
436
437 /*!
438 * \brief Searches a polygon on the SearchLayer.
439 */
440 static bool
SearchPolygonByLocation(int locked,LayerType ** Layer,PolygonType ** Polygon,PolygonType ** Dummy)441 SearchPolygonByLocation (int locked, LayerType ** Layer,
442 PolygonType ** Polygon, PolygonType ** Dummy)
443 {
444 struct ans_info info;
445
446 *Layer = SearchLayer;
447 info.ptr2 = (void **) Polygon;
448 info.ptr3 = (void **) Dummy;
449 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
450
451 if (setjmp (info.env) == 0)
452 {
453 r_search (SearchLayer->polygon_tree, &SearchBox, NULL, polygon_callback,
454 &info);
455 return false;
456 }
457 return (true);
458 }
459
460 static int
linepoint_callback(const BoxType * b,void * cl)461 linepoint_callback (const BoxType * b, void *cl)
462 {
463 LineType *line = (LineType *) b;
464 struct line_info *i = (struct line_info *) cl;
465 int ret_val = 0;
466 double d;
467
468 if (TEST_FLAG (i->locked, line))
469 return 0;
470
471 /* some stupid code to check both points */
472 d = Distance (PosX, PosY, line->Point1.X, line->Point1.Y);
473 if (d < i->least)
474 {
475 i->least = d;
476 *i->Line = line;
477 *i->Point = &line->Point1;
478 ret_val = 1;
479 }
480
481 d = Distance (PosX, PosY, line->Point2.X, line->Point2.Y);
482 if (d < i->least)
483 {
484 i->least = d;
485 *i->Line = line;
486 *i->Point = &line->Point2;
487 ret_val = 1;
488 }
489 return ret_val;
490 }
491
492 /*!
493 * \brief Searches a line-point on all the search layer.
494 */
495 static bool
SearchLinePointByLocation(int locked,LayerType ** Layer,LineType ** Line,PointType ** Point)496 SearchLinePointByLocation (int locked, LayerType ** Layer,
497 LineType ** Line, PointType ** Point)
498 {
499 struct line_info info;
500 *Layer = SearchLayer;
501 info.Line = Line;
502 info.Point = Point;
503 *Point = NULL;
504 info.least = MAX_LINE_POINT_DISTANCE + SearchRadius;
505 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
506 if (r_search
507 (SearchLayer->line_tree, &SearchBox, NULL, linepoint_callback, &info))
508 return true;
509 return false;
510 }
511
512 static int
arcpoint_callback(const BoxType * b,void * cl)513 arcpoint_callback (const BoxType * b, void *cl)
514 {
515 ArcType *arc = (ArcType *) b;
516 struct arc_info *i = (struct arc_info *) cl;
517 int ret_val = 0;
518 double d;
519
520 if (TEST_FLAG (i->locked, arc))
521 return 0;
522
523 d = Distance (PosX, PosY, arc->Point1.X, arc->Point1.Y);
524 if (d < i->least)
525 {
526 i->least = d;
527 *i->Arc = arc;
528 *i->Point = &arc->Point1;
529 ret_val = 1;
530 }
531
532 d = Distance (PosX, PosY, arc->Point2.X, arc->Point2.Y);
533 if (d < i->least)
534 {
535 i->least = d;
536 *i->Arc = arc;
537 *i->Point = &arc->Point2;
538 ret_val = 1;
539 }
540 return ret_val;
541 }
542
543 /*!
544 * \brief Searches an arc-point on all the search layer.
545 */
546 static bool
SearchArcPointByLocation(int locked,LayerType ** Layer,ArcType ** arc,PointType ** Point)547 SearchArcPointByLocation (int locked, LayerType **Layer,
548 ArcType **arc, PointType **Point)
549 {
550 struct arc_info info;
551 *Layer = SearchLayer;
552 info.Arc = arc;
553 info.Point = Point;
554 *Point = NULL;
555 info.least = MAX_ARC_POINT_DISTANCE + SearchRadius;
556 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
557 if (r_search
558 (SearchLayer->arc_tree, &SearchBox, NULL, arcpoint_callback, &info))
559 return true;
560 return false;
561 }
562 /*!
563 * \brief Searches a polygon-point on all layers that are switched on
564 * in layerstack order.
565 */
566 static bool
SearchPointByLocation(int locked,LayerType ** Layer,PolygonType ** Polygon,PointType ** Point)567 SearchPointByLocation (int locked, LayerType ** Layer,
568 PolygonType ** Polygon, PointType ** Point)
569 {
570 double d, least;
571 bool found = false;
572
573 least = SearchRadius + MAX_POLYGON_POINT_DISTANCE;
574 *Layer = SearchLayer;
575 POLYGON_LOOP (*Layer);
576 {
577 POLYGONPOINT_LOOP (polygon);
578 {
579 d = Distance (point->X, point->Y, PosX, PosY);
580 if (d < least)
581 {
582 least = d;
583 *Polygon = polygon;
584 *Point = point;
585 found = true;
586 }
587 }
588 END_LOOP;
589 }
590 END_LOOP;
591 if (found)
592 return (true);
593 return (false);
594 }
595
596 static int
name_callback(const BoxType * box,void * cl)597 name_callback (const BoxType * box, void *cl)
598 {
599 TextType *text = (TextType *) box;
600 struct ans_info *i = (struct ans_info *) cl;
601 ElementType *element = (ElementType *) text->Element;
602 double newarea;
603
604 if (TEST_FLAG (i->locked, text))
605 return 0;
606
607 if ((FRONT (element) || i->BackToo) && !TEST_FLAG (HIDENAMEFLAG, element) &&
608 POINT_IN_BOX (PosX, PosY, &text->BoundingBox))
609 {
610 /* use the text with the smallest bounding box */
611 newarea = (text->BoundingBox.X2 - text->BoundingBox.X1) *
612 (double) (text->BoundingBox.Y2 - text->BoundingBox.Y1);
613 if (newarea < i->area)
614 {
615 i->area = newarea;
616 *i->ptr1 = element;
617 *i->ptr2 = *i->ptr3 = text;
618 }
619 return 1;
620 }
621 return 0;
622 }
623
624 /*!
625 * \brief Searches the name of an element.
626 *
627 * The search starts with the last element and goes back to the
628 * beginning.
629 */
630 static bool
SearchElementNameByLocation(int locked,ElementType ** Element,TextType ** Text,TextType ** Dummy,bool BackToo)631 SearchElementNameByLocation (int locked, ElementType ** Element,
632 TextType ** Text, TextType ** Dummy,
633 bool BackToo)
634 {
635 struct ans_info info;
636
637 /* package layer have to be switched on */
638 if (PCB->ElementOn)
639 {
640 info.ptr1 = (void **) Element;
641 info.ptr2 = (void **) Text;
642 info.ptr3 = (void **) Dummy;
643 info.area = SQUARE (MAX_COORD);
644 info.BackToo = (BackToo && PCB->InvisibleObjectsOn);
645 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
646 if (r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], &SearchBox, NULL,
647 name_callback, &info))
648 return true;
649 }
650 return (false);
651 }
652
653 static int
element_callback(const BoxType * box,void * cl)654 element_callback (const BoxType * box, void *cl)
655 {
656 ElementType *element = (ElementType *) box;
657 struct ans_info *i = (struct ans_info *) cl;
658 double newarea;
659
660 if (TEST_FLAG (i->locked, element))
661 return 0;
662
663 if ((FRONT (element) || i->BackToo) &&
664 POINT_IN_BOX (PosX, PosY, &element->VBox))
665 {
666 /* use the element with the smallest bounding box */
667 newarea = (element->VBox.X2 - element->VBox.X1) *
668 (double) (element->VBox.Y2 - element->VBox.Y1);
669 if (newarea < i->area)
670 {
671 i->area = newarea;
672 *i->ptr1 = *i->ptr2 = *i->ptr3 = element;
673 return 1;
674 }
675 }
676 return 0;
677 }
678
679 /*!
680 * \brief Searches an element.
681 *
682 * The search starts with the last element and goes back to the
683 * beginning.
684 *
685 * If more than one element matches, the smallest one is taken.
686 */
687 static bool
SearchElementByLocation(int locked,ElementType ** Element,ElementType ** Dummy1,ElementType ** Dummy2,bool BackToo)688 SearchElementByLocation (int locked,
689 ElementType ** Element,
690 ElementType ** Dummy1, ElementType ** Dummy2,
691 bool BackToo)
692 {
693 struct ans_info info;
694
695 /* Both package layers have to be switched on */
696 if (PCB->ElementOn && PCB->PinOn)
697 {
698 info.ptr1 = (void **) Element;
699 info.ptr2 = (void **) Dummy1;
700 info.ptr3 = (void **) Dummy2;
701 info.area = SQUARE (MAX_COORD);
702 info.BackToo = (BackToo && PCB->InvisibleObjectsOn);
703 info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
704 if (r_search
705 (PCB->Data->element_tree, &SearchBox, NULL, element_callback,
706 &info))
707 return true;
708 }
709 return false;
710 }
711
712 /*!
713 * \brief Checks if a point is on a pin.
714 */
715 bool
IsPointOnPin(Coord X,Coord Y,Coord Radius,PinType * pin)716 IsPointOnPin (Coord X, Coord Y, Coord Radius, PinType *pin)
717 {
718 Coord t = PIN_SIZE (pin) / 2;
719 if (TEST_FLAG (SQUAREFLAG, pin))
720 {
721 BoxType b;
722
723 b.X1 = pin->X - t;
724 b.X2 = pin->X + t;
725 b.Y1 = pin->Y - t;
726 b.Y2 = pin->Y + t;
727 if (IsPointInBox (X, Y, &b, Radius))
728 return true;
729 }
730 else if (Distance (pin->X, pin->Y, X, Y) <= Radius + t)
731 return true;
732 return false;
733 }
734
735 /*!
736 * \brief Checks if a rat-line end is on a PV.
737 */
738 bool
IsPointOnLineEnd(Coord X,Coord Y,RatType * Line)739 IsPointOnLineEnd (Coord X, Coord Y, RatType *Line)
740 {
741 if (((X == Line->Point1.X) && (Y == Line->Point1.Y)) ||
742 ((X == Line->Point2.X) && (Y == Line->Point2.Y)))
743 return (true);
744 return (false);
745 }
746
747 /*!
748 * \brief Checks if a line intersects with a PV.
749 *
750 * <pre>
751 * let the point be (X,Y) and the line (X1,Y1)(X2,Y2).
752 * Let L be a vector along the line:
753 *
754 * vec(L) = (X2-X1, Y2-Y1)
755 * L = ((X2-X1)^2 + (Y2-Y1)^2)^0.5
756 *
757 * Let P be a vector from the endpoint of the line to the point in question:
758 * The vector P is:
759 *
760 * vec(P) = (X-X1, Y-Y1)
761 *
762 * let Q be the point of perpendicular projection of (X,Y) onto the line
763 *
764 * QX = X1 + D1*(X2-X1) / L
765 * QY = Y1 + D1*(Y2-Y1) / L
766 *
767 * where D1 is the distance from (X1, Y1) to (QX, QY). The magnitude of D1
768 * can be written as:
769 *
770 * D1 = vec(L) . vec(P) / abs(L) (dot product)
771 *
772 * or (from vector geometry):
773 *
774 * (Y1-Y)(Y1-Y2)+(X1-X)(X1-X2)
775 * D1 = ---------------------------
776 * L
777 *
778 * D1 < 0 Q is on backward extension of the line
779 * D1 > L Q is on forward extension of the line
780 * else Q is on the line
781 *
782 * With some coordinate switcheroos, we can get a vector perpendicular to L
783 *
784 * Lp_x Lp_y
785 * vec (Lp) = (Y2-Y1, -(X2-X1))
786 *
787 * The distance from the line to the point, D2, can be computed with a
788 * similar dot product. The signed distance from (X,Y) to Q is
789 *
790 * (Y2-Y1)(X-X1)-(X2-X1)(Y-Y1)
791 * D2 = ----------------------------
792 * L
793 *
794 * Finally, D1 and D2 are orthogonal, so we can sum them easily
795 * by pythagorean theorem.
796 * </pre>
797 */
798 bool
IsPointOnLine(Coord X,Coord Y,Coord Radius,LineType * Line)799 IsPointOnLine (Coord X, Coord Y, Coord Radius, LineType *Line)
800 {
801 double D1, D2, L;
802
803 /* Get length of segment */
804 L = Distance (Line->Point1.X, Line->Point1.Y, Line->Point2.X, Line->Point2.Y);
805 if (L < 0.1)
806 return Distance (X, Y, Line->Point1.X, Line->Point1.Y) < Radius + Line->Thickness / 2;
807
808 /* Get distance from (X1, Y1) to Q (on the line) */
809 D1 = ((double) (Y - Line->Point1.Y) * (Line->Point2.Y - Line->Point1.Y)
810 + (double) (X - Line->Point1.X) * (Line->Point2.X - Line->Point1.X)) / L;
811 /* Translate this into distance to Q from segment */
812 if (D1 < 0) D1 = -D1;
813 else if (D1 > L) D1 -= L;
814 else D1 = 0;
815 /* Get distance from (X, Y) to Q */
816 D2 = ((double) (X - Line->Point1.X) * (Line->Point2.Y - Line->Point1.Y)
817 - (double) (Y - Line->Point1.Y) * (Line->Point2.X - Line->Point1.X)) / L;
818 /* Total distance is then the pythagorean sum of these */
819 return hypot (D1, D2) <= Radius + Line->Thickness / 2;
820 }
821
822 /*!
823 * \brief Checks if a line crosses a rectangle.
824 */
825 bool
IsLineInRectangle(Coord X1,Coord Y1,Coord X2,Coord Y2,LineType * Line)826 IsLineInRectangle (Coord X1, Coord Y1, Coord X2, Coord Y2, LineType *Line)
827 {
828 LineType line;
829
830 /* first, see if point 1 is inside the rectangle */
831 /* in case the whole line is inside the rectangle */
832 if (X1 < Line->Point1.X && X2 > Line->Point1.X &&
833 Y1 < Line->Point1.Y && Y2 > Line->Point1.Y)
834 return (true);
835 /* construct a set of dummy lines and check each of them */
836 line.Thickness = 0;
837 line.Flags = NoFlags ();
838
839 /* upper-left to upper-right corner */
840 line.Point1.Y = line.Point2.Y = Y1;
841 line.Point1.X = X1;
842 line.Point2.X = X2;
843 if (LineLineIntersect (&line, Line))
844 return (true);
845
846 /* upper-right to lower-right corner */
847 line.Point1.X = X2;
848 line.Point1.Y = Y1;
849 line.Point2.Y = Y2;
850 if (LineLineIntersect (&line, Line))
851 return (true);
852
853 /* lower-right to lower-left corner */
854 line.Point1.Y = Y2;
855 line.Point1.X = X1;
856 line.Point2.X = X2;
857 if (LineLineIntersect (&line, Line))
858 return (true);
859
860 /* lower-left to upper-left corner */
861 line.Point2.X = X1;
862 line.Point1.Y = Y1;
863 line.Point2.Y = Y2;
864 if (LineLineIntersect (&line, Line))
865 return (true);
866
867 return (false);
868 }
869
870 /*!
871 * \brief Checks if a point (of null radius) is in a slanted rectangle.
872 */
873 static int
IsPointInQuadrangle(PointType p[4],PointType * l)874 IsPointInQuadrangle(PointType p[4], PointType *l)
875 {
876 Coord dx, dy, x, y;
877 double prod0, prod1;
878
879 dx = p[1].X - p[0].X;
880 dy = p[1].Y - p[0].Y;
881 x = l->X - p[0].X;
882 y = l->Y - p[0].Y;
883 prod0 = (double) x * dx + (double) y * dy;
884 x = l->X - p[1].X;
885 y = l->Y - p[1].Y;
886 prod1 = (double) x * dx + (double) y * dy;
887 if (prod0 * prod1 <= 0)
888 {
889 dx = p[1].X - p[2].X;
890 dy = p[1].Y - p[2].Y;
891 prod0 = (double) x * dx + (double) y * dy;
892 x = l->X - p[2].X;
893 y = l->Y - p[2].Y;
894 prod1 = (double) x * dx + (double) y * dy;
895 if (prod0 * prod1 <= 0)
896 return true;
897 }
898 return false;
899 }
900
901 /*!
902 * \brief Checks if a line crosses a quadrangle: almost copied from
903 * IsLineInRectangle().
904 *
905 * \note Actually this quadrangle is a slanted rectangle.
906 */
907 bool
IsLineInQuadrangle(PointType p[4],LineType * Line)908 IsLineInQuadrangle (PointType p[4], LineType *Line)
909 {
910 LineType line;
911
912 /* first, see if point 1 is inside the rectangle */
913 /* in case the whole line is inside the rectangle */
914 if (IsPointInQuadrangle(p,&(Line->Point1)))
915 return true;
916 if (IsPointInQuadrangle(p,&(Line->Point2)))
917 return true;
918 /* construct a set of dummy lines and check each of them */
919 line.Thickness = 0;
920 line.Flags = NoFlags ();
921
922 /* upper-left to upper-right corner */
923 line.Point1.X = p[0].X; line.Point1.Y = p[0].Y;
924 line.Point2.X = p[1].X; line.Point2.Y = p[1].Y;
925 if (LineLineIntersect (&line, Line))
926 return (true);
927
928 /* upper-right to lower-right corner */
929 line.Point1.X = p[2].X; line.Point1.Y = p[2].Y;
930 if (LineLineIntersect (&line, Line))
931 return (true);
932
933 /* lower-right to lower-left corner */
934 line.Point2.X = p[3].X; line.Point2.Y = p[3].Y;
935 if (LineLineIntersect (&line, Line))
936 return (true);
937
938 /* lower-left to upper-left corner */
939 line.Point1.X = p[0].X; line.Point1.Y = p[0].Y;
940 if (LineLineIntersect (&line, Line))
941 return (true);
942
943 return (false);
944 }
945 /*!
946 * \brief Checks if an arc crosses a square.
947 */
948 bool
IsArcInRectangle(Coord X1,Coord Y1,Coord X2,Coord Y2,ArcType * Arc)949 IsArcInRectangle (Coord X1, Coord Y1, Coord X2, Coord Y2, ArcType *Arc)
950 {
951 LineType line;
952
953 /* construct a set of dummy lines and check each of them */
954 line.Thickness = 0;
955 line.Flags = NoFlags ();
956
957 /* upper-left to upper-right corner */
958 line.Point1.Y = line.Point2.Y = Y1;
959 line.Point1.X = X1;
960 line.Point2.X = X2;
961 if (LineArcIntersect (&line, Arc))
962 return (true);
963
964 /* upper-right to lower-right corner */
965 line.Point1.X = line.Point2.X = X2;
966 line.Point1.Y = Y1;
967 line.Point2.Y = Y2;
968 if (LineArcIntersect (&line, Arc))
969 return (true);
970
971 /* lower-right to lower-left corner */
972 line.Point1.Y = line.Point2.Y = Y2;
973 line.Point1.X = X1;
974 line.Point2.X = X2;
975 if (LineArcIntersect (&line, Arc))
976 return (true);
977
978 /* lower-left to upper-left corner */
979 line.Point1.X = line.Point2.X = X1;
980 line.Point1.Y = Y1;
981 line.Point2.Y = Y2;
982 if (LineArcIntersect (&line, Arc))
983 return (true);
984
985 return (false);
986 }
987
988 /*!
989 * \brief Check if a circle of Radius with center at (X, Y) intersects
990 * a Pad.
991 *
992 * Written to enable arbitrary pad directions; for rounded pads, too.
993 */
994 bool
IsPointInPad(Coord X,Coord Y,Coord Radius,PadType * Pad)995 IsPointInPad (Coord X, Coord Y, Coord Radius, PadType *Pad)
996 {
997 double r, Sin, Cos;
998 Coord x;
999 Coord t2 = (Pad->Thickness + 1) / 2, range;
1000 PadType pad = *Pad;
1001
1002 /* series of transforms saving range */
1003 /* move Point1 to the origin */
1004 X -= pad.Point1.X;
1005 Y -= pad.Point1.Y;
1006
1007 pad.Point2.X -= pad.Point1.X;
1008 pad.Point2.Y -= pad.Point1.Y;
1009 /* so, pad.Point1.X = pad.Point1.Y = 0; */
1010
1011 /* rotate round (0, 0) so that Point2 coordinates be (r, 0) */
1012 r = Distance (0, 0, pad.Point2.X, pad.Point2.Y);
1013 if (r < .1)
1014 {
1015 Cos = 1;
1016 Sin = 0;
1017 }
1018 else
1019 {
1020 Sin = pad.Point2.Y / r;
1021 Cos = pad.Point2.X / r;
1022 }
1023 x = X;
1024 X = X * Cos + Y * Sin;
1025 Y = Y * Cos - x * Sin;
1026 /* now pad.Point2.X = r; pad.Point2.Y = 0; */
1027
1028 /* take into account the ends */
1029 if (TEST_FLAG (SQUAREFLAG, Pad))
1030 {
1031 r += Pad->Thickness;
1032 X += t2;
1033 }
1034 if (Y < 0)
1035 Y = -Y; /* range value is evident now*/
1036
1037 if (TEST_FLAG (SQUAREFLAG, Pad))
1038 {
1039 if (X <= 0)
1040 {
1041 if (Y <= t2)
1042 range = -X;
1043 else
1044 return Radius > Distance (0, t2, X, Y);
1045 }
1046 else if (X >= r)
1047 {
1048 if (Y <= t2)
1049 range = X - r;
1050 else
1051 return Radius > Distance (r, t2, X, Y);
1052 }
1053 else
1054 range = Y - t2;
1055 }
1056 else/*Rounded pad: even more simple*/
1057 {
1058 if (X <= 0)
1059 return (Radius + t2) > Distance (0, 0, X, Y);
1060 else if (X >= r)
1061 return (Radius + t2) > Distance (r, 0, X, Y);
1062 else
1063 range = Y - t2;
1064 }
1065 return range < Radius;
1066 }
1067
1068 /*!
1069 * \brief .
1070 *
1071 * \note Assumes box has point1 with numerically lower X and Y
1072 * coordinates.
1073 */
1074 bool
IsPointInBox(Coord X,Coord Y,BoxType * box,Coord Radius)1075 IsPointInBox (Coord X, Coord Y, BoxType *box, Coord Radius)
1076 {
1077 Coord width, height, range;
1078
1079 /* Compute coordinates relative to Point1 */
1080 X -= box->X1;
1081 Y -= box->Y1;
1082
1083 width = box->X2 - box->X1;
1084 height = box->Y2 - box->Y1;
1085
1086 if (X <= 0)
1087 {
1088 if (Y < 0)
1089 return Radius > Distance (0, 0, X, Y);
1090 else if (Y > height)
1091 return Radius > Distance (0, height, X, Y);
1092 else
1093 range = -X;
1094 }
1095 else if (X >= width)
1096 {
1097 if (Y < 0)
1098 return Radius > Distance (width, 0, X, Y);
1099 else if (Y > height)
1100 return Radius > Distance (width, height, X, Y);
1101 else
1102 range = X - width;
1103 }
1104 else
1105 {
1106 if (Y < 0)
1107 range = -Y;
1108 else if (Y > height)
1109 range = Y - height;
1110 else
1111 return true;
1112 }
1113
1114 return range < Radius;
1115 }
1116
1117 /*!
1118 * \brief .
1119 *
1120 * \todo This code is BROKEN in the case of non-circular arcs, and in
1121 * the case that the arc thickness is greater than the radius.
1122 */
1123 bool
IsPointOnArc(Coord X,Coord Y,Coord Radius,ArcType * Arc)1124 IsPointOnArc (Coord X, Coord Y, Coord Radius, ArcType *Arc)
1125 {
1126 /* Calculate angle of point from arc center */
1127 double p_dist = Distance (X, Y, Arc->X, Arc->Y);
1128 double p_cos = (X - Arc->X) / p_dist;
1129 Angle p_ang = acos (p_cos) * RAD_TO_DEG;
1130 Angle ang1, ang2;
1131
1132 /* Convert StartAngle, Delta into bounding angles in [0, 720) */
1133 if (Arc->Delta > 0)
1134 {
1135 ang1 = NormalizeAngle (Arc->StartAngle);
1136 ang2 = NormalizeAngle (Arc->StartAngle + Arc->Delta);
1137 }
1138 else
1139 {
1140 ang1 = NormalizeAngle (Arc->StartAngle + Arc->Delta);
1141 ang2 = NormalizeAngle (Arc->StartAngle);
1142 }
1143 /* This could be the case if one of the angles was negative or > 360
1144 * degrees before the call to NormalizeAngles
1145 * */
1146 if (ang1 > ang2)
1147 ang2 += 360;
1148 /* Make sure full circles aren't treated as zero-length arcs */
1149 if (Arc->Delta == 360 || Arc->Delta == -360)
1150 ang2 = ang1 + 360;
1151
1152 if (Y > Arc->Y)
1153 p_ang = -p_ang;
1154 /* In pcb, theta = 0 points to the left (-x) */
1155 p_ang += 180;
1156
1157 /*If either angle is greater than 360, then we're into the second time
1158 * around the circle, so, we need to make sure our target is also.
1159 * */
1160 if ((ang2 > 360) && p_ang < ang1) p_ang += 360;
1161
1162 /* Check point is outside arc range, check distance from endpoints */
1163 if (ang1 >= p_ang || ang2 <= p_ang)
1164 {
1165 Coord ArcX, ArcY;
1166
1167 ArcX = Arc->X + Arc->Width *
1168 cos ((Arc->StartAngle + 180) / RAD_TO_DEG);
1169 ArcY = Arc->Y - Arc->Width *
1170 sin ((Arc->StartAngle + 180) / RAD_TO_DEG);
1171 if (Distance (X, Y, ArcX, ArcY) < Radius + Arc->Thickness / 2)
1172 return true;
1173
1174 ArcX = Arc->X + Arc->Width *
1175 cos ((Arc->StartAngle + Arc->Delta + 180) / RAD_TO_DEG);
1176 ArcY = Arc->Y - Arc->Width *
1177 sin ((Arc->StartAngle + Arc->Delta + 180) / RAD_TO_DEG);
1178 if (Distance (X, Y, ArcX, ArcY) < Radius + Arc->Thickness / 2)
1179 return true;
1180 return false;
1181 }
1182 /* If point is inside the arc range, just compare it to the arc */
1183 return fabs (Distance (X, Y, Arc->X, Arc->Y) - Arc->Width) < Radius + Arc->Thickness / 2;
1184 }
1185
1186 static unsigned int
SearchLayerObjectInternal(LayerType * layer,unsigned int Type,unsigned int HigherAvail,double HigherBound,void ** Result1,void ** Result2,void ** Result3)1187 SearchLayerObjectInternal (LayerType *layer,
1188 unsigned int Type,
1189 unsigned int HigherAvail,
1190 double HigherBound,
1191 void **Result1,
1192 void **Result2,
1193 void **Result3)
1194 {
1195 int locked = Type & LOCKED_TYPE;
1196
1197 if (!layer->On)
1198 return NO_TYPE;
1199
1200 SearchLayer = layer;
1201
1202 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 &&
1203 Type & POLYGONPOINT_TYPE &&
1204 SearchPointByLocation (locked, (LayerType **)Result1, (PolygonType **) Result2, (PointType **) Result3))
1205 return POLYGONPOINT_TYPE;
1206
1207 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 &&
1208 Type & LINEPOINT_TYPE &&
1209 SearchLinePointByLocation (locked, (LayerType **)Result1, (LineType **) Result2, (PointType **) Result3))
1210 return LINEPOINT_TYPE;
1211
1212 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 && Type & LINE_TYPE
1213 && SearchLineByLocation (locked, (LayerType **)Result1, (LineType **) Result2, (LineType **) Result3))
1214 return LINE_TYPE;
1215
1216 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 &&
1217 Type & ARCPOINT_TYPE &&
1218 SearchArcPointByLocation (locked, (LayerType **)Result1, (ArcType **) Result2, (PointType **) Result3))
1219 return ARCPOINT_TYPE;
1220
1221 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 && Type & ARC_TYPE &&
1222 SearchArcByLocation (locked, (LayerType **)Result1, (ArcType **) Result2, (ArcType **) Result3))
1223 return ARC_TYPE;
1224
1225 if ((HigherAvail & (PIN_TYPE | PAD_TYPE)) == 0 && Type & TEXT_TYPE
1226 && SearchTextByLocation (locked, (LayerType **)Result1, (TextType **) Result2, (TextType **) Result3))
1227 return TEXT_TYPE;
1228
1229 if (Type & POLYGON_TYPE &&
1230 SearchPolygonByLocation (locked, (LayerType **)Result1, (PolygonType **) Result2, (PolygonType **) Result3))
1231 {
1232 if (HigherAvail)
1233 {
1234 BoxType *box =
1235 &(*(PolygonType **) Result2)->BoundingBox;
1236 double area =
1237 (double) (box->X2 - box->X1) * (double) (box->X2 - box->X1);
1238 /* XXX: BEHAVIOURAL CHANGE */
1239 if (HigherBound < area)
1240 // break;
1241 return NO_TYPE;
1242 else
1243 return POLYGON_TYPE;
1244 }
1245 else
1246 {
1247 return POLYGON_TYPE;
1248 }
1249 }
1250
1251 return NO_TYPE;
1252 }
1253
1254 /*!
1255 * \brief Searches for any kind of object or for a set of object types
1256 * the calling routine passes two pointers to allocated memory for
1257 * storing the results.
1258 *
1259 * A type value is returned too which is NO_TYPE if no objects has been
1260 * found.
1261 *
1262 * A set of object types is passed in.
1263 *
1264 * The object is located by it's position.
1265 *
1266 * The layout is checked in the following order:
1267 * polygon-point, pin, via, line, text, elementname, polygon, element
1268 *
1269 * \note That if Type includes LOCKED_TYPE, then the search includes
1270 * locked items. Otherwise, locked items are ignored.
1271 */
1272 int
SearchObjectByLocation(unsigned Type,void ** Result1,void ** Result2,void ** Result3,Coord X,Coord Y,Coord Radius)1273 SearchObjectByLocation (unsigned Type,
1274 void **Result1, void **Result2, void **Result3,
1275 Coord X, Coord Y, Coord Radius)
1276 {
1277 void *r1, *r2, *r3;
1278 void **pr1 = &r1, **pr2 = &r2, **pr3 = &r3;
1279 int i;
1280 double HigherBound = 0;
1281 unsigned int HigherAvail = NO_TYPE;
1282 int locked = Type & LOCKED_TYPE;
1283 unsigned int type;
1284 /* setup variables used by local functions */
1285 PosX = X;
1286 PosY = Y;
1287 SearchRadius = Radius;
1288 if (Radius)
1289 {
1290 SearchBox.X1 = X - Radius;
1291 SearchBox.Y1 = Y - Radius;
1292 SearchBox.X2 = X + Radius;
1293 SearchBox.Y2 = Y + Radius;
1294 }
1295 else
1296 {
1297 SearchBox = point_box (X, Y);
1298 }
1299
1300 if (TEST_FLAG (LOCKNAMESFLAG, PCB))
1301 {
1302 Type &= ~ (ELEMENTNAME_TYPE | TEXT_TYPE);
1303 }
1304 if (TEST_FLAG (HIDENAMESFLAG, PCB))
1305 {
1306 Type &= ~ELEMENTNAME_TYPE;
1307 }
1308 if (TEST_FLAG (ONLYNAMESFLAG, PCB))
1309 {
1310 Type &= (ELEMENTNAME_TYPE | TEXT_TYPE);
1311 }
1312 if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
1313 {
1314 Type &= ~POLYGON_TYPE;
1315 }
1316
1317 if (Type & RATLINE_TYPE && PCB->RatOn &&
1318 SearchRatLineByLocation (locked,
1319 (RatType **) Result1,
1320 (RatType **) Result2,
1321 (RatType **) Result3))
1322 return (RATLINE_TYPE);
1323
1324 if (Type & VIA_TYPE &&
1325 SearchViaByLocation (locked,
1326 (PinType **) Result1,
1327 (PinType **) Result2, (PinType **) Result3))
1328 return (VIA_TYPE);
1329
1330 if (Type & PIN_TYPE &&
1331 SearchPinByLocation (locked,
1332 (ElementType **) pr1,
1333 (PinType **) pr2, (PinType **) pr3))
1334 HigherAvail = PIN_TYPE;
1335
1336 if (!HigherAvail && Type & PAD_TYPE &&
1337 SearchPadByLocation (locked,
1338 (ElementType **) pr1,
1339 (PadType **) pr2, (PadType **) pr3, false))
1340 HigherAvail = PAD_TYPE;
1341
1342 if (!HigherAvail && Type & ELEMENTNAME_TYPE &&
1343 SearchElementNameByLocation (locked,
1344 (ElementType **) pr1,
1345 (TextType **) pr2, (TextType **) pr3,
1346 false))
1347 {
1348 BoxType *box = &((TextType *) r2)->BoundingBox;
1349 HigherBound = (double) (box->X2 - box->X1) * (double) (box->Y2 - box->Y1);
1350 HigherAvail = ELEMENTNAME_TYPE;
1351 }
1352
1353 if (!HigherAvail && Type & ELEMENT_TYPE &&
1354 SearchElementByLocation (locked,
1355 (ElementType **) pr1,
1356 (ElementType **) pr2,
1357 (ElementType **) pr3, false))
1358 {
1359 BoxType *box = &((ElementType *) r1)->BoundingBox;
1360 HigherBound = (double) (box->X2 - box->X1) * (double) (box->Y2 - box->Y1);
1361 HigherAvail = ELEMENT_TYPE;
1362 }
1363 /* uncomment if merged with peterc_layers
1364 type = SearchLayerObjectInternal (&PCB->Data->SOLDERMASKLAYER, Type, HigherAvail, HigherBound, Result1, Result2, Result3);
1365 if (type != NO_TYPE)
1366 return type;
1367 */
1368 type = SearchLayerObjectInternal (&PCB->Data->SILKLAYER, Type, HigherAvail, HigherBound, Result1, Result2, Result3);
1369 if (type != NO_TYPE)
1370 return type;
1371
1372 for (i = 0; i < max_copper_layer; i++)
1373 {
1374 type = SearchLayerObjectInternal (LAYER_ON_STACK (i), Type, HigherAvail, HigherBound, Result1, Result2, Result3);
1375 if (type != NO_TYPE)
1376 return type;
1377 }
1378
1379 if (PCB->InvisibleObjectsOn)
1380 {
1381 type = SearchLayerObjectInternal (&PCB->Data->BACKSILKLAYER, Type, HigherAvail, HigherBound, Result1, Result2, Result3);
1382 if (type != NO_TYPE)
1383 return type;
1384
1385 /* uncomment if merged with peterc_layers
1386 type = SearchLayerObjectInternal (&PCB->Data->BACKSOLDERMASKLAYER, Type, HigherAvail, HigherBound, Result1, Result2, Result3);
1387 if (type != NO_TYPE)
1388 return type;
1389 */
1390 }
1391
1392 /* return any previously found objects */
1393 if (HigherAvail & PIN_TYPE)
1394 {
1395 *Result1 = r1;
1396 *Result2 = r2;
1397 *Result3 = r3;
1398 return (PIN_TYPE);
1399 }
1400
1401 if (HigherAvail & PAD_TYPE)
1402 {
1403 *Result1 = r1;
1404 *Result2 = r2;
1405 *Result3 = r3;
1406 return (PAD_TYPE);
1407 }
1408
1409 if (HigherAvail & ELEMENTNAME_TYPE)
1410 {
1411 *Result1 = r1;
1412 *Result2 = r2;
1413 *Result3 = r3;
1414 return (ELEMENTNAME_TYPE);
1415 }
1416
1417 if (HigherAvail & ELEMENT_TYPE)
1418 {
1419 *Result1 = r1;
1420 *Result2 = r2;
1421 *Result3 = r3;
1422 return (ELEMENT_TYPE);
1423 }
1424
1425 /* search the 'invisible objects' last */
1426 if (!PCB->InvisibleObjectsOn)
1427 return (NO_TYPE);
1428
1429 if (Type & PAD_TYPE &&
1430 SearchPadByLocation (locked,
1431 (ElementType **) Result1,
1432 (PadType **) Result2, (PadType **) Result3,
1433 true))
1434 return (PAD_TYPE);
1435
1436 if (Type & ELEMENTNAME_TYPE &&
1437 SearchElementNameByLocation (locked,
1438 (ElementType **) Result1,
1439 (TextType **) Result2,
1440 (TextType **) Result3, true))
1441 return (ELEMENTNAME_TYPE);
1442
1443 if (Type & ELEMENT_TYPE &&
1444 SearchElementByLocation (locked,
1445 (ElementType **) Result1,
1446 (ElementType **) Result2,
1447 (ElementType **) Result3, true))
1448 return (ELEMENT_TYPE);
1449
1450 return (NO_TYPE);
1451 }
1452
1453 /*!
1454 * \brief Searches for a object by it's unique ID.
1455 *
1456 * It doesn't matter if the object is visible or not.
1457 *
1458 * The search is performed on a PCB, a buffer or on the remove list.
1459 *
1460 * The calling routine passes two pointers to allocated memory for
1461 * storing the results.
1462 *
1463 * \return A type value is returned too which is NO_TYPE if no objects
1464 * has been found.
1465 */
1466 int
SearchObjectByID(DataType * Base,void ** Result1,void ** Result2,void ** Result3,int ID,int type)1467 SearchObjectByID (DataType *Base,
1468 void **Result1, void **Result2, void **Result3, int ID,
1469 int type)
1470 {
1471 if (type & (LINE_TYPE | LINEPOINT_TYPE))
1472 {
1473 ALLLINE_LOOP (Base);
1474 {
1475 if (line->ID == ID)
1476 {
1477 *Result1 = (void *) layer;
1478 *Result2 = *Result3 = (void *) line;
1479 return (LINE_TYPE);
1480 }
1481 if (line->Point1.ID == ID)
1482 {
1483 *Result1 = (void *) layer;
1484 *Result2 = (void *) line;
1485 *Result3 = (void *) &line->Point1;
1486 return (LINEPOINT_TYPE);
1487 }
1488 if (line->Point2.ID == ID)
1489 {
1490 *Result1 = (void *) layer;
1491 *Result2 = (void *) line;
1492 *Result3 = (void *) &line->Point2;
1493 return (LINEPOINT_TYPE);
1494 }
1495 }
1496 ENDALL_LOOP;
1497 }
1498 if (type & ARC_TYPE)
1499 {
1500 ALLARC_LOOP (Base);
1501 {
1502 if (arc->ID == ID)
1503 {
1504 *Result1 = (void *) layer;
1505 *Result2 = *Result3 = (void *) arc;
1506 return (ARC_TYPE);
1507 }
1508 }
1509 ENDALL_LOOP;
1510 }
1511
1512 if (type & TEXT_TYPE)
1513 {
1514 ALLTEXT_LOOP (Base);
1515 {
1516 if (text->ID == ID)
1517 {
1518 *Result1 = (void *) layer;
1519 *Result2 = *Result3 = (void *) text;
1520 return (TEXT_TYPE);
1521 }
1522 }
1523 ENDALL_LOOP;
1524 }
1525
1526 if (type & (POLYGON_TYPE | POLYGONPOINT_TYPE))
1527 {
1528 ALLPOLYGON_LOOP (Base);
1529 {
1530 if (polygon->ID == ID)
1531 {
1532 *Result1 = (void *) layer;
1533 *Result2 = *Result3 = (void *) polygon;
1534 return (POLYGON_TYPE);
1535 }
1536 if (type & POLYGONPOINT_TYPE)
1537 POLYGONPOINT_LOOP (polygon);
1538 {
1539 if (point->ID == ID)
1540 {
1541 *Result1 = (void *) layer;
1542 *Result2 = (void *) polygon;
1543 *Result3 = (void *) point;
1544 return (POLYGONPOINT_TYPE);
1545 }
1546 }
1547 END_LOOP;
1548 }
1549 ENDALL_LOOP;
1550 }
1551 if (type & VIA_TYPE)
1552 {
1553 VIA_LOOP (Base);
1554 {
1555 if (via->ID == ID)
1556 {
1557 *Result1 = *Result2 = *Result3 = (void *) via;
1558 return (VIA_TYPE);
1559 }
1560 }
1561 END_LOOP;
1562 }
1563
1564 if (type & (RATLINE_TYPE | LINEPOINT_TYPE))
1565 {
1566 RAT_LOOP (Base);
1567 {
1568 if (line->ID == ID)
1569 {
1570 *Result1 = *Result2 = *Result3 = (void *) line;
1571 return (RATLINE_TYPE);
1572 }
1573 if (line->Point1.ID == ID)
1574 {
1575 *Result1 = (void *) NULL;
1576 *Result2 = (void *) line;
1577 *Result3 = (void *) &line->Point1;
1578 return (LINEPOINT_TYPE);
1579 }
1580 if (line->Point2.ID == ID)
1581 {
1582 *Result1 = (void *) NULL;
1583 *Result2 = (void *) line;
1584 *Result3 = (void *) &line->Point2;
1585 return (LINEPOINT_TYPE);
1586 }
1587 }
1588 END_LOOP;
1589 }
1590
1591 if (type & (ELEMENT_TYPE | PAD_TYPE | PIN_TYPE
1592 | ELEMENTLINE_TYPE | ELEMENTNAME_TYPE
1593 | ELEMENTARC_TYPE))
1594 /* check pins and elementnames too */
1595 ELEMENT_LOOP (Base);
1596 {
1597 if (element->ID == ID)
1598 {
1599 *Result1 = *Result2 = *Result3 = (void *) element;
1600 return (ELEMENT_TYPE);
1601 }
1602 if (type & ELEMENTLINE_TYPE)
1603 ELEMENTLINE_LOOP (element);
1604 {
1605 if (line->ID == ID)
1606 {
1607 *Result1 = (void *) element;
1608 *Result2 = *Result3 = (void *) line;
1609 return (ELEMENTLINE_TYPE);
1610 }
1611 }
1612 END_LOOP;
1613 if (type & ELEMENTARC_TYPE)
1614 ARC_LOOP (element);
1615 {
1616 if (arc->ID == ID)
1617 {
1618 *Result1 = (void *) element;
1619 *Result2 = *Result3 = (void *) arc;
1620 return (ELEMENTARC_TYPE);
1621 }
1622 }
1623 END_LOOP;
1624 if (type & ELEMENTNAME_TYPE)
1625 ELEMENTTEXT_LOOP (element);
1626 {
1627 if (text->ID == ID)
1628 {
1629 *Result1 = (void *) element;
1630 *Result2 = *Result3 = (void *) text;
1631 return (ELEMENTNAME_TYPE);
1632 }
1633 }
1634 END_LOOP;
1635 if (type & PIN_TYPE)
1636 PIN_LOOP (element);
1637 {
1638 if (pin->ID == ID)
1639 {
1640 *Result1 = (void *) element;
1641 *Result2 = *Result3 = (void *) pin;
1642 return (PIN_TYPE);
1643 }
1644 }
1645 END_LOOP;
1646 if (type & PAD_TYPE)
1647 PAD_LOOP (element);
1648 {
1649 if (pad->ID == ID)
1650 {
1651 *Result1 = (void *) element;
1652 *Result2 = *Result3 = (void *) pad;
1653 return (PAD_TYPE);
1654 }
1655 }
1656 END_LOOP;
1657 }
1658 END_LOOP;
1659
1660 #ifdef DEBUG
1661 Message ("hace: Internal error, search for ID %d failed\n", ID);
1662 #endif /* DEBUG */
1663 return (NO_TYPE);
1664 }
1665
1666 /*!
1667 * \brief Searches for an element by its board name.
1668 *
1669 * \return The function returns a pointer to the element, NULL if not
1670 * found.
1671 */
1672 ElementType *
SearchElementByName(DataType * Base,char * Name)1673 SearchElementByName (DataType *Base, char *Name)
1674 {
1675 ElementType *result = NULL;
1676
1677 ELEMENT_LOOP (Base);
1678 {
1679 if (element->Name[1].TextString &&
1680 NSTRCMP (element->Name[1].TextString, Name) == 0)
1681 {
1682 result = element;
1683 return (result);
1684 }
1685 }
1686 END_LOOP;
1687 return result;
1688 }
1689
1690 /*!
1691 * \brief Searches for an layer by its board name.
1692 *
1693 * \return The function returns an index of the layer, -1 if not
1694 * found.
1695 */
1696 int
SearchLayerByName(DataType * Base,char * Name)1697 SearchLayerByName (DataType *Base, char *Name)
1698 {
1699 int result = 0;
1700
1701 LAYER_LOOP (Base, max_copper_layer);
1702 {
1703 if (layer->Name &&
1704 NSTRCMP (layer->Name, Name) == 0)
1705 {
1706 return result;
1707 }
1708 else
1709 result++;
1710 }
1711 END_LOOP;
1712 return -1;
1713 }
1714
1715 /*!
1716 * \brief Searches the cursor position for the type.
1717 */
1718 int
SearchScreen(Coord X,Coord Y,int Type,void ** Result1,void ** Result2,void ** Result3)1719 SearchScreen (Coord X, Coord Y, int Type, void **Result1,
1720 void **Result2, void **Result3)
1721 {
1722 int ans;
1723
1724 ans = SearchObjectByLocation (Type, Result1, Result2, Result3,
1725 X, Y, SLOP * pixel_slop);
1726 return (ans);
1727 }
1728