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