6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
31 * some of the functions use dummy parameters
53 #ifdef HAVE_LIBDMALLOC
60 /* ---------------------------------------------------------------------------
61 * some local identifiers
63 static double PosX
, PosY
; /* search position for subroutines */
64 static Coord SearchRadius
;
65 static BoxType SearchBox
;
66 static LayerTypePtr SearchLayer
;
68 /* ---------------------------------------------------------------------------
69 * some local prototypes. The first parameter includes LOCKED_TYPE if we
70 * want to include locked types in the search.
72 static bool SearchLineByLocation (int, LayerTypePtr
*, LineTypePtr
*,
74 static bool SearchArcByLocation (int, LayerTypePtr
*, ArcTypePtr
*,
76 static bool SearchRatLineByLocation (int, RatTypePtr
*, RatTypePtr
*,
78 static bool SearchTextByLocation (int, LayerTypePtr
*, TextTypePtr
*,
80 static bool SearchPolygonByLocation (int, LayerTypePtr
*, PolygonTypePtr
*,
82 static bool SearchPinByLocation (int, ElementTypePtr
*, PinTypePtr
*,
84 static bool SearchPadByLocation (int, ElementTypePtr
*, PadTypePtr
*,
86 static bool SearchViaByLocation (int, PinTypePtr
*, PinTypePtr
*,
88 static bool SearchElementNameByLocation (int, ElementTypePtr
*,
89 TextTypePtr
*, TextTypePtr
*,
91 static bool SearchLinePointByLocation (int, LayerTypePtr
*, LineTypePtr
*,
93 static bool SearchPointByLocation (int, LayerTypePtr
*, PolygonTypePtr
*,
95 static bool SearchElementByLocation (int, ElementTypePtr
*,
96 ElementTypePtr
*, ElementTypePtr
*,
99 /* ---------------------------------------------------------------------------
104 void **ptr1
, **ptr2
, **ptr3
;
108 int locked
; /* This will be zero or LOCKFLAG */
112 pinorvia_callback (const BoxType
* box
, void *cl
)
114 struct ans_info
*i
= (struct ans_info
*) cl
;
115 PinTypePtr pin
= (PinTypePtr
) box
;
116 AnyObjectType
*ptr1
= pin
->Element
? pin
->Element
: pin
;
118 if (TEST_FLAG (i
->locked
, ptr1
))
121 if (!IsPointOnPin (PosX
, PosY
, SearchRadius
, pin
))
124 *i
->ptr2
= *i
->ptr3
= pin
;
126 return 1; /* never reached */
130 SearchViaByLocation (int locked
, PinTypePtr
* Via
, PinTypePtr
* Dummy1
,
133 struct ans_info info
;
135 /* search only if via-layer is visible */
139 info
.ptr1
= (void **) Via
;
140 info
.ptr2
= (void **) Dummy1
;
141 info
.ptr3
= (void **) Dummy2
;
142 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
144 if (setjmp (info
.env
) == 0)
146 r_search (PCB
->Data
->via_tree
, &SearchBox
, NULL
, pinorvia_callback
,
153 /* ---------------------------------------------------------------------------
155 * starts with the newest element
158 SearchPinByLocation (int locked
, ElementTypePtr
* Element
, PinTypePtr
* Pin
,
161 struct ans_info info
;
163 /* search only if pin-layer is visible */
166 info
.ptr1
= (void **) Element
;
167 info
.ptr2
= (void **) Pin
;
168 info
.ptr3
= (void **) Dummy
;
169 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
171 if (setjmp (info
.env
) == 0)
172 r_search (PCB
->Data
->pin_tree
, &SearchBox
, NULL
, pinorvia_callback
,
180 pad_callback (const BoxType
* b
, void *cl
)
182 PadTypePtr pad
= (PadTypePtr
) b
;
183 struct ans_info
*i
= (struct ans_info
*) cl
;
184 AnyObjectType
*ptr1
= pad
->Element
;
186 if (TEST_FLAG (i
->locked
, ptr1
))
189 if (FRONT (pad
) || i
->BackToo
)
191 if (IsPointInPad (PosX
, PosY
, SearchRadius
, pad
))
194 *i
->ptr2
= *i
->ptr3
= pad
;
201 /* ---------------------------------------------------------------------------
203 * starts with the newest element
206 SearchPadByLocation (int locked
, ElementTypePtr
* Element
, PadTypePtr
* Pad
,
207 PadTypePtr
* Dummy
, bool BackToo
)
209 struct ans_info info
;
211 /* search only if pin-layer is visible */
214 info
.ptr1
= (void **) Element
;
215 info
.ptr2
= (void **) Pad
;
216 info
.ptr3
= (void **) Dummy
;
217 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
218 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
219 if (setjmp (info
.env
) == 0)
220 r_search (PCB
->Data
->pad_tree
, &SearchBox
, NULL
, pad_callback
, &info
);
226 /* ---------------------------------------------------------------------------
227 * searches ordinary line on the SearchLayer
240 line_callback (const BoxType
* box
, void *cl
)
242 struct line_info
*i
= (struct line_info
*) cl
;
243 LineTypePtr l
= (LineTypePtr
) box
;
245 if (TEST_FLAG (i
->locked
, l
))
248 if (!IsPointInPad (PosX
, PosY
, SearchRadius
, (PadTypePtr
)l
))
251 *i
->Point
= (PointTypePtr
) l
;
253 return 1; /* never reached */
258 SearchLineByLocation (int locked
, LayerTypePtr
* Layer
, LineTypePtr
* Line
,
261 struct line_info info
;
264 info
.Point
= (PointTypePtr
*) Dummy
;
265 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
267 *Layer
= SearchLayer
;
268 if (setjmp (info
.env
) == 0)
270 r_search (SearchLayer
->line_tree
, &SearchBox
, NULL
, line_callback
,
278 rat_callback (const BoxType
* box
, void *cl
)
280 LineTypePtr line
= (LineTypePtr
) box
;
281 struct ans_info
*i
= (struct ans_info
*) cl
;
283 if (TEST_FLAG (i
->locked
, line
))
286 if (TEST_FLAG (VIAFLAG
, line
) ?
287 (Distance (line
->Point1
.X
, line
->Point1
.Y
, PosX
, PosY
) <=
288 line
->Thickness
* 2 + SearchRadius
) :
289 IsPointOnLine (PosX
, PosY
, SearchRadius
, line
))
291 *i
->ptr1
= *i
->ptr2
= *i
->ptr3
= line
;
297 /* ---------------------------------------------------------------------------
298 * searches rat lines if they are visible
301 SearchRatLineByLocation (int locked
, RatTypePtr
* Line
, RatTypePtr
* Dummy1
,
304 struct ans_info info
;
306 info
.ptr1
= (void **) Line
;
307 info
.ptr2
= (void **) Dummy1
;
308 info
.ptr3
= (void **) Dummy2
;
309 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
311 if (setjmp (info
.env
) == 0)
313 r_search (PCB
->Data
->rat_tree
, &SearchBox
, NULL
, rat_callback
, &info
);
319 /* ---------------------------------------------------------------------------
320 * searches arc on the SearchLayer
324 ArcTypePtr
*Arc
, *Dummy
;
330 arc_callback (const BoxType
* box
, void *cl
)
332 struct arc_info
*i
= (struct arc_info
*) cl
;
333 ArcTypePtr a
= (ArcTypePtr
) box
;
335 if (TEST_FLAG (i
->locked
, a
))
338 if (!IsPointOnArc (PosX
, PosY
, SearchRadius
, a
))
343 return 1; /* never reached */
348 SearchArcByLocation (int locked
, LayerTypePtr
* Layer
, ArcTypePtr
* Arc
,
351 struct arc_info info
;
355 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
357 *Layer
= SearchLayer
;
358 if (setjmp (info
.env
) == 0)
360 r_search (SearchLayer
->arc_tree
, &SearchBox
, NULL
, arc_callback
, &info
);
367 text_callback (const BoxType
* box
, void *cl
)
369 TextTypePtr text
= (TextTypePtr
) box
;
370 struct ans_info
*i
= (struct ans_info
*) cl
;
372 if (TEST_FLAG (i
->locked
, text
))
375 if (POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
377 *i
->ptr2
= *i
->ptr3
= text
;
383 /* ---------------------------------------------------------------------------
384 * searches text on the SearchLayer
387 SearchTextByLocation (int locked
, LayerTypePtr
* Layer
, TextTypePtr
* Text
,
390 struct ans_info info
;
392 *Layer
= SearchLayer
;
393 info
.ptr2
= (void **) Text
;
394 info
.ptr3
= (void **) Dummy
;
395 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
397 if (setjmp (info
.env
) == 0)
399 r_search (SearchLayer
->text_tree
, &SearchBox
, NULL
, text_callback
,
407 polygon_callback (const BoxType
* box
, void *cl
)
409 PolygonTypePtr polygon
= (PolygonTypePtr
) box
;
410 struct ans_info
*i
= (struct ans_info
*) cl
;
412 if (TEST_FLAG (i
->locked
, polygon
))
415 if (IsPointInPolygon (PosX
, PosY
, SearchRadius
, polygon
))
417 *i
->ptr2
= *i
->ptr3
= polygon
;
424 /* ---------------------------------------------------------------------------
425 * searches a polygon on the SearchLayer
428 SearchPolygonByLocation (int locked
, LayerTypePtr
* Layer
,
429 PolygonTypePtr
* Polygon
, PolygonTypePtr
* Dummy
)
431 struct ans_info info
;
433 *Layer
= SearchLayer
;
434 info
.ptr2
= (void **) Polygon
;
435 info
.ptr3
= (void **) Dummy
;
436 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
438 if (setjmp (info
.env
) == 0)
440 r_search (SearchLayer
->polygon_tree
, &SearchBox
, NULL
, polygon_callback
,
448 linepoint_callback (const BoxType
* b
, void *cl
)
450 LineTypePtr line
= (LineTypePtr
) b
;
451 struct line_info
*i
= (struct line_info
*) cl
;
455 if (TEST_FLAG (i
->locked
, line
))
458 /* some stupid code to check both points */
459 d
= Distance (PosX
, PosY
, line
->Point1
.X
, line
->Point1
.Y
);
464 *i
->Point
= &line
->Point1
;
468 d
= Distance (PosX
, PosY
, line
->Point2
.X
, line
->Point2
.Y
);
473 *i
->Point
= &line
->Point2
;
479 /* ---------------------------------------------------------------------------
480 * searches a line-point on all the search layer
483 SearchLinePointByLocation (int locked
, LayerTypePtr
* Layer
,
484 LineTypePtr
* Line
, PointTypePtr
* Point
)
486 struct line_info info
;
487 *Layer
= SearchLayer
;
491 info
.least
= MAX_LINE_POINT_DISTANCE
+ SearchRadius
;
492 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
494 (SearchLayer
->line_tree
, &SearchBox
, NULL
, linepoint_callback
, &info
))
499 /* ---------------------------------------------------------------------------
500 * searches a polygon-point on all layers that are switched on
501 * in layerstack order
504 SearchPointByLocation (int locked
, LayerTypePtr
* Layer
,
505 PolygonTypePtr
* Polygon
, PointTypePtr
* Point
)
510 least
= SearchRadius
+ MAX_POLYGON_POINT_DISTANCE
;
511 *Layer
= SearchLayer
;
512 POLYGON_LOOP (*Layer
);
514 POLYGONPOINT_LOOP (polygon
);
516 d
= Distance (point
->X
, point
->Y
, PosX
, PosY
);
534 name_callback (const BoxType
* box
, void *cl
)
536 TextTypePtr text
= (TextTypePtr
) box
;
537 struct ans_info
*i
= (struct ans_info
*) cl
;
538 ElementTypePtr element
= (ElementTypePtr
) text
->Element
;
541 if (TEST_FLAG (i
->locked
, text
))
544 if ((FRONT (element
) || i
->BackToo
) && !TEST_FLAG (HIDENAMEFLAG
, element
) &&
545 POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
547 /* use the text with the smallest bounding box */
548 newarea
= (text
->BoundingBox
.X2
- text
->BoundingBox
.X1
) *
549 (double) (text
->BoundingBox
.Y2
- text
->BoundingBox
.Y1
);
550 if (newarea
< i
->area
)
554 *i
->ptr2
= *i
->ptr3
= text
;
561 /* ---------------------------------------------------------------------------
562 * searches the name of an element
563 * the search starts with the last element and goes back to the beginning
566 SearchElementNameByLocation (int locked
, ElementTypePtr
* Element
,
567 TextTypePtr
* Text
, TextTypePtr
* Dummy
,
570 struct ans_info info
;
572 /* package layer have to be switched on */
575 info
.ptr1
= (void **) Element
;
576 info
.ptr2
= (void **) Text
;
577 info
.ptr3
= (void **) Dummy
;
578 info
.area
= SQUARE (MAX_COORD
);
579 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
580 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
581 if (r_search (PCB
->Data
->name_tree
[NAME_INDEX (PCB
)], &SearchBox
, NULL
,
582 name_callback
, &info
))
589 element_callback (const BoxType
* box
, void *cl
)
591 ElementTypePtr element
= (ElementTypePtr
) box
;
592 struct ans_info
*i
= (struct ans_info
*) cl
;
595 if (TEST_FLAG (i
->locked
, element
))
598 if ((FRONT (element
) || i
->BackToo
) &&
599 POINT_IN_BOX (PosX
, PosY
, &element
->VBox
))
601 /* use the element with the smallest bounding box */
602 newarea
= (element
->VBox
.X2
- element
->VBox
.X1
) *
603 (double) (element
->VBox
.Y2
- element
->VBox
.Y1
);
604 if (newarea
< i
->area
)
607 *i
->ptr1
= *i
->ptr2
= *i
->ptr3
= element
;
614 /* ---------------------------------------------------------------------------
615 * searches an element
616 * the search starts with the last element and goes back to the beginning
617 * if more than one element matches, the smallest one is taken
620 SearchElementByLocation (int locked
,
621 ElementTypePtr
* Element
,
622 ElementTypePtr
* Dummy1
, ElementTypePtr
* Dummy2
,
625 struct ans_info info
;
627 /* Both package layers have to be switched on */
628 if (PCB
->ElementOn
&& PCB
->PinOn
)
630 info
.ptr1
= (void **) Element
;
631 info
.ptr2
= (void **) Dummy1
;
632 info
.ptr3
= (void **) Dummy2
;
633 info
.area
= SQUARE (MAX_COORD
);
634 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
635 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
637 (PCB
->Data
->element_tree
, &SearchBox
, NULL
, element_callback
,
644 /* ---------------------------------------------------------------------------
645 * checks if a point is on a pin
648 IsPointOnPin (Coord X
, Coord Y
, Coord Radius
, PinTypePtr pin
)
650 Coord t
= PIN_SIZE (pin
) / 2;
651 if (TEST_FLAG (SQUAREFLAG
, pin
))
659 if (IsPointInBox (X
, Y
, &b
, Radius
))
662 else if (Distance (pin
->X
, pin
->Y
, X
, Y
) <= Radius
+ t
)
667 /* ---------------------------------------------------------------------------
668 * checks if a rat-line end is on a PV
671 IsPointOnLineEnd (Coord X
, Coord Y
, RatTypePtr Line
)
673 if (((X
== Line
->Point1
.X
) && (Y
== Line
->Point1
.Y
)) ||
674 ((X
== Line
->Point2
.X
) && (Y
== Line
->Point2
.Y
)))
679 /* ---------------------------------------------------------------------------
680 * checks if a line intersects with a PV
682 * let the point be (X,Y) and the line (X1,Y1)(X2,Y2)
683 * the length of the line is
685 * L = ((X2-X1)^2 + (Y2-Y1)^2)^0.5
687 * let Q be the point of perpendicular projection of (X,Y) onto the line
689 * QX = X1 + D1*(X2-X1) / L
690 * QY = Y1 + D1*(Y2-Y1) / L
692 * with (from vector geometry)
694 * (Y1-Y)(Y1-Y2)+(X1-X)(X1-X2)
695 * D1 = ---------------------------
698 * D1 < 0 Q is on backward extension of the line
699 * D1 > L Q is on forward extension of the line
700 * else Q is on the line
702 * the signed distance from (X,Y) to Q is
704 * (Y2-Y1)(X-X1)-(X2-X1)(Y-Y1)
705 * D2 = ----------------------------
708 * Finally, D1 and D2 are orthogonal, so we can sum them easily
709 * by pythagorean theorem.
712 IsPointOnLine (Coord X
, Coord Y
, Coord Radius
, LineTypePtr Line
)
716 /* Get length of segment */
717 L
= Distance (Line
->Point1
.X
, Line
->Point1
.Y
, Line
->Point2
.X
, Line
->Point2
.Y
);
719 return Distance (X
, Y
, Line
->Point1
.X
, Line
->Point1
.Y
) < Radius
+ Line
->Thickness
/ 2;
721 /* Get distance from (X1, Y1) to Q (on the line) */
722 D1
= ((double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
723 + (double) (X
- Line
->Point1
.X
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
724 /* Translate this into distance to Q from segment */
725 if (D1
< 0) D1
= -D1
;
726 else if (D1
> L
) D1
-= L
;
728 /* Get distance from (X, Y) to Q */
729 D2
= ((double) (X
- Line
->Point1
.X
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
730 - (double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
731 /* Total distance is then the pythagorean sum of these */
732 return sqrt (D1
*D1
+ D2
*D2
) <= Radius
+ Line
->Thickness
/ 2;
735 /* ---------------------------------------------------------------------------
736 * checks if a line crosses a rectangle
739 IsLineInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, LineTypePtr Line
)
743 /* first, see if point 1 is inside the rectangle */
744 /* in case the whole line is inside the rectangle */
745 if (X1
< Line
->Point1
.X
&& X2
> Line
->Point1
.X
&&
746 Y1
< Line
->Point1
.Y
&& Y2
> Line
->Point1
.Y
)
748 /* construct a set of dummy lines and check each of them */
750 line
.Flags
= NoFlags ();
752 /* upper-left to upper-right corner */
753 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
756 if (LineLineIntersect (&line
, Line
))
759 /* upper-right to lower-right corner */
763 if (LineLineIntersect (&line
, Line
))
766 /* lower-right to lower-left corner */
770 if (LineLineIntersect (&line
, Line
))
773 /* lower-left to upper-left corner */
777 if (LineLineIntersect (&line
, Line
))
783 static int /*checks if a point (of null radius) is in a slanted rectangle*/
784 IsPointInQuadrangle(PointType p
[4], PointTypePtr l
)
789 dx
= p
[1].X
- p
[0].X
;
790 dy
= p
[1].Y
- p
[0].Y
;
793 prod0
= (double) x
* dx
+ (double) y
* dy
;
796 prod1
= (double) x
* dx
+ (double) y
* dy
;
797 if (prod0
* prod1
<= 0)
799 dx
= p
[1].X
- p
[2].X
;
800 dy
= p
[1].Y
- p
[2].Y
;
801 prod0
= (double) x
* dx
+ (double) y
* dy
;
804 prod1
= (double) x
* dx
+ (double) y
* dy
;
805 if (prod0
* prod1
<= 0)
810 /* ---------------------------------------------------------------------------
811 * checks if a line crosses a quadrangle: almost copied from IsLineInRectangle()
812 * Note: actually this quadrangle is a slanted rectangle
815 IsLineInQuadrangle (PointType p
[4], LineTypePtr Line
)
819 /* first, see if point 1 is inside the rectangle */
820 /* in case the whole line is inside the rectangle */
821 if (IsPointInQuadrangle(p
,&(Line
->Point1
)))
823 if (IsPointInQuadrangle(p
,&(Line
->Point2
)))
825 /* construct a set of dummy lines and check each of them */
827 line
.Flags
= NoFlags ();
829 /* upper-left to upper-right corner */
830 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
831 line
.Point2
.X
= p
[1].X
; line
.Point2
.Y
= p
[1].Y
;
832 if (LineLineIntersect (&line
, Line
))
835 /* upper-right to lower-right corner */
836 line
.Point1
.X
= p
[2].X
; line
.Point1
.Y
= p
[2].Y
;
837 if (LineLineIntersect (&line
, Line
))
840 /* lower-right to lower-left corner */
841 line
.Point2
.X
= p
[3].X
; line
.Point2
.Y
= p
[3].Y
;
842 if (LineLineIntersect (&line
, Line
))
845 /* lower-left to upper-left corner */
846 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
847 if (LineLineIntersect (&line
, Line
))
852 /* ---------------------------------------------------------------------------
853 * checks if an arc crosses a square
856 IsArcInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, ArcTypePtr Arc
)
860 /* construct a set of dummy lines and check each of them */
862 line
.Flags
= NoFlags ();
864 /* upper-left to upper-right corner */
865 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
868 if (LineArcIntersect (&line
, Arc
))
871 /* upper-right to lower-right corner */
872 line
.Point1
.X
= line
.Point2
.X
= X2
;
875 if (LineArcIntersect (&line
, Arc
))
878 /* lower-right to lower-left corner */
879 line
.Point1
.Y
= line
.Point2
.Y
= Y2
;
882 if (LineArcIntersect (&line
, Arc
))
885 /* lower-left to upper-left corner */
886 line
.Point1
.X
= line
.Point2
.X
= X1
;
889 if (LineArcIntersect (&line
, Arc
))
895 /* ---------------------------------------------------------------------------
896 * Check if a circle of Radius with center at (X, Y) intersects a Pad.
897 * Written to enable arbitrary pad directions; for rounded pads, too.
900 IsPointInPad (Coord X
, Coord Y
, Coord Radius
, PadTypePtr Pad
)
904 Coord t2
= (Pad
->Thickness
+ 1) / 2, range
;
907 /* series of transforms saving range */
908 /* move Point1 to the origin */
912 pad
.Point2
.X
-= pad
.Point1
.X
;
913 pad
.Point2
.Y
-= pad
.Point1
.Y
;
914 /* so, pad.Point1.X = pad.Point1.Y = 0; */
916 /* rotate round (0, 0) so that Point2 coordinates be (r, 0) */
917 r
= Distance (0, 0, pad
.Point2
.X
, pad
.Point2
.Y
);
925 Sin
= pad
.Point2
.Y
/ r
;
926 Cos
= pad
.Point2
.X
/ r
;
929 X
= X
* Cos
+ Y
* Sin
;
930 Y
= Y
* Cos
- x
* Sin
;
931 /* now pad.Point2.X = r; pad.Point2.Y = 0; */
933 /* take into account the ends */
934 if (TEST_FLAG (SQUAREFLAG
, Pad
))
940 Y
= -Y
; /* range value is evident now*/
942 if (TEST_FLAG (SQUAREFLAG
, Pad
))
949 return Radius
> Distance (0, t2
, X
, Y
);
956 return Radius
> Distance (r
, t2
, X
, Y
);
961 else/*Rounded pad: even more simple*/
964 return (Radius
+ t2
) > Distance (0, 0, X
, Y
);
966 return (Radius
+ t2
) > Distance (r
, 0, X
, Y
);
970 return range
< Radius
;
974 IsPointInBox (Coord X
, Coord Y
, BoxTypePtr box
, Coord Radius
)
976 Coord width
, height
, range
;
978 /* NB: Assumes box has point1 with numerically lower X and Y coordinates */
980 /* Compute coordinates relative to Point1 */
984 width
= box
->X2
- box
->X1
;
985 height
= box
->Y2
- box
->Y1
;
990 return Radius
> Distance (0, 0, X
, Y
);
992 return Radius
> Distance (0, height
, X
, Y
);
999 return Radius
> Distance (width
, 0, X
, Y
);
1000 else if (Y
> height
)
1001 return Radius
> Distance (width
, height
, X
, Y
);
1009 else if (Y
> height
)
1015 return range
< Radius
;
1018 /* TODO: this code is BROKEN in the case of non-circular arcs,
1019 * and in the case that the arc thickness is greater than
1023 IsPointOnArc (Coord X
, Coord Y
, Coord Radius
, ArcTypePtr Arc
)
1025 /* Calculate angle of point from arc center */
1026 double p_dist
= Distance (X
, Y
, Arc
->X
, Arc
->Y
);
1027 double p_cos
= (X
- Arc
->X
) / p_dist
;
1028 Angle p_ang
= acos (p_cos
) * RAD_TO_DEG
;
1031 /* Convert StartAngle, Delta into bounding angles in [0, 720) */
1034 ang1
= NormalizeAngle (Arc
->StartAngle
);
1035 ang2
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1039 ang1
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1040 ang2
= NormalizeAngle (Arc
->StartAngle
);
1044 /* Make sure full circles aren't treated as zero-length arcs */
1045 if (Arc
->Delta
== 360 || Arc
->Delta
== -360)
1052 /* Check point is outside arc range, check distance from endpoints */
1053 if (ang1
>= p_ang
|| ang2
<= p_ang
)
1057 ArcX
= Arc
->X
+ Arc
->Width
*
1058 cos ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1059 ArcY
= Arc
->Y
- Arc
->Width
*
1060 sin ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1061 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1064 ArcX
= Arc
->X
+ Arc
->Width
*
1065 cos ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1066 ArcY
= Arc
->Y
- Arc
->Width
*
1067 sin ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1068 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1072 /* If point is inside the arc range, just compare it to the arc */
1073 return fabs (Distance (X
, Y
, Arc
->X
, Arc
->Y
) - Arc
->Width
) < Radius
+ Arc
->Thickness
/ 2;
1076 /* ---------------------------------------------------------------------------
1077 * searches for any kind of object or for a set of object types
1078 * the calling routine passes two pointers to allocated memory for storing
1080 * A type value is returned too which is NO_TYPE if no objects has been found.
1081 * A set of object types is passed in.
1082 * The object is located by it's position.
1084 * The layout is checked in the following order:
1085 * polygon-point, pin, via, line, text, elementname, polygon, element
1087 * Note that if Type includes LOCKED_TYPE, then the search includes
1088 * locked items. Otherwise, locked items are ignored.
1091 SearchObjectByLocation (unsigned Type
,
1092 void **Result1
, void **Result2
, void **Result3
,
1093 Coord X
, Coord Y
, Coord Radius
)
1096 void **pr1
= &r1
, **pr2
= &r2
, **pr3
= &r3
;
1098 double HigherBound
= 0;
1099 int HigherAvail
= NO_TYPE
;
1100 int locked
= Type
& LOCKED_TYPE
;
1101 /* setup variables used by local functions */
1104 SearchRadius
= Radius
;
1107 SearchBox
.X1
= X
- Radius
;
1108 SearchBox
.Y1
= Y
- Radius
;
1109 SearchBox
.X2
= X
+ Radius
;
1110 SearchBox
.Y2
= Y
+ Radius
;
1114 SearchBox
= point_box (X
, Y
);
1117 if (TEST_FLAG (LOCKNAMESFLAG
, PCB
))
1119 Type
&= ~ (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1121 if (TEST_FLAG (HIDENAMESFLAG
, PCB
))
1123 Type
&= ~ELEMENTNAME_TYPE
;
1125 if (TEST_FLAG (ONLYNAMESFLAG
, PCB
))
1127 Type
&= (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1129 if (TEST_FLAG (THINDRAWFLAG
, PCB
) || TEST_FLAG (THINDRAWPOLYFLAG
, PCB
))
1131 Type
&= ~POLYGON_TYPE
;
1134 if (Type
& RATLINE_TYPE
&& PCB
->RatOn
&&
1135 SearchRatLineByLocation (locked
,
1136 (RatTypePtr
*) Result1
,
1137 (RatTypePtr
*) Result2
,
1138 (RatTypePtr
*) Result3
))
1139 return (RATLINE_TYPE
);
1141 if (Type
& VIA_TYPE
&&
1142 SearchViaByLocation (locked
,
1143 (PinTypePtr
*) Result1
,
1144 (PinTypePtr
*) Result2
, (PinTypePtr
*) Result3
))
1147 if (Type
& PIN_TYPE
&&
1148 SearchPinByLocation (locked
,
1149 (ElementTypePtr
*) pr1
,
1150 (PinTypePtr
*) pr2
, (PinTypePtr
*) pr3
))
1151 HigherAvail
= PIN_TYPE
;
1153 if (!HigherAvail
&& Type
& PAD_TYPE
&&
1154 SearchPadByLocation (locked
,
1155 (ElementTypePtr
*) pr1
,
1156 (PadTypePtr
*) pr2
, (PadTypePtr
*) pr3
, false))
1157 HigherAvail
= PAD_TYPE
;
1159 if (!HigherAvail
&& Type
& ELEMENTNAME_TYPE
&&
1160 SearchElementNameByLocation (locked
,
1161 (ElementTypePtr
*) pr1
,
1162 (TextTypePtr
*) pr2
, (TextTypePtr
*) pr3
,
1165 BoxTypePtr box
= &((TextTypePtr
) r2
)->BoundingBox
;
1166 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1167 HigherAvail
= ELEMENTNAME_TYPE
;
1170 if (!HigherAvail
&& Type
& ELEMENT_TYPE
&&
1171 SearchElementByLocation (locked
,
1172 (ElementTypePtr
*) pr1
,
1173 (ElementTypePtr
*) pr2
,
1174 (ElementTypePtr
*) pr3
, false))
1176 BoxTypePtr box
= &((ElementTypePtr
) r1
)->BoundingBox
;
1177 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1178 HigherAvail
= ELEMENT_TYPE
;
1181 for (i
= -1; i
< max_copper_layer
+ 1; i
++)
1184 SearchLayer
= &PCB
->Data
->SILKLAYER
;
1185 else if (i
< max_copper_layer
)
1186 SearchLayer
= LAYER_ON_STACK (i
);
1189 SearchLayer
= &PCB
->Data
->BACKSILKLAYER
;
1190 if (!PCB
->InvisibleObjectsOn
)
1193 if (SearchLayer
->On
)
1195 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1196 Type
& POLYGONPOINT_TYPE
&&
1197 SearchPointByLocation (locked
,
1198 (LayerTypePtr
*) Result1
,
1199 (PolygonTypePtr
*) Result2
,
1200 (PointTypePtr
*) Result3
))
1201 return (POLYGONPOINT_TYPE
);
1203 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1204 Type
& LINEPOINT_TYPE
&&
1205 SearchLinePointByLocation (locked
,
1206 (LayerTypePtr
*) Result1
,
1207 (LineTypePtr
*) Result2
,
1208 (PointTypePtr
*) Result3
))
1209 return (LINEPOINT_TYPE
);
1211 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& LINE_TYPE
1212 && SearchLineByLocation (locked
,
1213 (LayerTypePtr
*) Result1
,
1214 (LineTypePtr
*) Result2
,
1215 (LineTypePtr
*) Result3
))
1218 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& ARC_TYPE
&&
1219 SearchArcByLocation (locked
,
1220 (LayerTypePtr
*) Result1
,
1221 (ArcTypePtr
*) Result2
,
1222 (ArcTypePtr
*) Result3
))
1225 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& TEXT_TYPE
1226 && SearchTextByLocation (locked
,
1227 (LayerTypePtr
*) Result1
,
1228 (TextTypePtr
*) Result2
,
1229 (TextTypePtr
*) Result3
))
1232 if (Type
& POLYGON_TYPE
&&
1233 SearchPolygonByLocation (locked
,
1234 (LayerTypePtr
*) Result1
,
1235 (PolygonTypePtr
*) Result2
,
1236 (PolygonTypePtr
*) Result3
))
1241 &(*(PolygonTypePtr
*) Result2
)->BoundingBox
;
1243 (double) (box
->X2
- box
->X1
) * (double) (box
->X2
- box
->X1
);
1244 if (HigherBound
< area
)
1247 return (POLYGON_TYPE
);
1250 return (POLYGON_TYPE
);
1254 /* return any previously found objects */
1255 if (HigherAvail
& PIN_TYPE
)
1263 if (HigherAvail
& PAD_TYPE
)
1271 if (HigherAvail
& ELEMENTNAME_TYPE
)
1276 return (ELEMENTNAME_TYPE
);
1279 if (HigherAvail
& ELEMENT_TYPE
)
1284 return (ELEMENT_TYPE
);
1287 /* search the 'invisible objects' last */
1288 if (!PCB
->InvisibleObjectsOn
)
1291 if (Type
& PAD_TYPE
&&
1292 SearchPadByLocation (locked
,
1293 (ElementTypePtr
*) Result1
,
1294 (PadTypePtr
*) Result2
, (PadTypePtr
*) Result3
,
1298 if (Type
& ELEMENTNAME_TYPE
&&
1299 SearchElementNameByLocation (locked
,
1300 (ElementTypePtr
*) Result1
,
1301 (TextTypePtr
*) Result2
,
1302 (TextTypePtr
*) Result3
, true))
1303 return (ELEMENTNAME_TYPE
);
1305 if (Type
& ELEMENT_TYPE
&&
1306 SearchElementByLocation (locked
,
1307 (ElementTypePtr
*) Result1
,
1308 (ElementTypePtr
*) Result2
,
1309 (ElementTypePtr
*) Result3
, true))
1310 return (ELEMENT_TYPE
);
1315 /* ---------------------------------------------------------------------------
1316 * searches for a object by it's unique ID. It doesn't matter if
1317 * the object is visible or not. The search is performed on a PCB, a
1318 * buffer or on the remove list.
1319 * The calling routine passes two pointers to allocated memory for storing
1321 * A type value is returned too which is NO_TYPE if no objects has been found.
1324 SearchObjectByID (DataTypePtr Base
,
1325 void **Result1
, void **Result2
, void **Result3
, int ID
,
1328 if (type
== LINE_TYPE
|| type
== LINEPOINT_TYPE
)
1330 ALLLINE_LOOP (Base
);
1334 *Result1
= (void *) layer
;
1335 *Result2
= *Result3
= (void *) line
;
1338 if (line
->Point1
.ID
== ID
)
1340 *Result1
= (void *) layer
;
1341 *Result2
= (void *) line
;
1342 *Result3
= (void *) &line
->Point1
;
1343 return (LINEPOINT_TYPE
);
1345 if (line
->Point2
.ID
== ID
)
1347 *Result1
= (void *) layer
;
1348 *Result2
= (void *) line
;
1349 *Result3
= (void *) &line
->Point2
;
1350 return (LINEPOINT_TYPE
);
1355 if (type
== ARC_TYPE
)
1361 *Result1
= (void *) layer
;
1362 *Result2
= *Result3
= (void *) arc
;
1369 if (type
== TEXT_TYPE
)
1371 ALLTEXT_LOOP (Base
);
1375 *Result1
= (void *) layer
;
1376 *Result2
= *Result3
= (void *) text
;
1383 if (type
== POLYGON_TYPE
|| type
== POLYGONPOINT_TYPE
)
1385 ALLPOLYGON_LOOP (Base
);
1387 if (polygon
->ID
== ID
)
1389 *Result1
= (void *) layer
;
1390 *Result2
= *Result3
= (void *) polygon
;
1391 return (POLYGON_TYPE
);
1393 if (type
== POLYGONPOINT_TYPE
)
1394 POLYGONPOINT_LOOP (polygon
);
1396 if (point
->ID
== ID
)
1398 *Result1
= (void *) layer
;
1399 *Result2
= (void *) polygon
;
1400 *Result3
= (void *) point
;
1401 return (POLYGONPOINT_TYPE
);
1408 if (type
== VIA_TYPE
)
1414 *Result1
= *Result2
= *Result3
= (void *) via
;
1421 if (type
== RATLINE_TYPE
|| type
== LINEPOINT_TYPE
)
1427 *Result1
= *Result2
= *Result3
= (void *) line
;
1428 return (RATLINE_TYPE
);
1430 if (line
->Point1
.ID
== ID
)
1432 *Result1
= (void *) NULL
;
1433 *Result2
= (void *) line
;
1434 *Result3
= (void *) &line
->Point1
;
1435 return (LINEPOINT_TYPE
);
1437 if (line
->Point2
.ID
== ID
)
1439 *Result1
= (void *) NULL
;
1440 *Result2
= (void *) line
;
1441 *Result3
= (void *) &line
->Point2
;
1442 return (LINEPOINT_TYPE
);
1448 if (type
== ELEMENT_TYPE
|| type
== PAD_TYPE
|| type
== PIN_TYPE
1449 || type
== ELEMENTLINE_TYPE
|| type
== ELEMENTNAME_TYPE
1450 || type
== ELEMENTARC_TYPE
)
1451 /* check pins and elementnames too */
1452 ELEMENT_LOOP (Base
);
1454 if (element
->ID
== ID
)
1456 *Result1
= *Result2
= *Result3
= (void *) element
;
1457 return (ELEMENT_TYPE
);
1459 if (type
== ELEMENTLINE_TYPE
)
1460 ELEMENTLINE_LOOP (element
);
1464 *Result1
= (void *) element
;
1465 *Result2
= *Result3
= (void *) line
;
1466 return (ELEMENTLINE_TYPE
);
1470 if (type
== ELEMENTARC_TYPE
)
1475 *Result1
= (void *) element
;
1476 *Result2
= *Result3
= (void *) arc
;
1477 return (ELEMENTARC_TYPE
);
1481 if (type
== ELEMENTNAME_TYPE
)
1482 ELEMENTTEXT_LOOP (element
);
1486 *Result1
= (void *) element
;
1487 *Result2
= *Result3
= (void *) text
;
1488 return (ELEMENTNAME_TYPE
);
1492 if (type
== PIN_TYPE
)
1497 *Result1
= (void *) element
;
1498 *Result2
= *Result3
= (void *) pin
;
1503 if (type
== PAD_TYPE
)
1508 *Result1
= (void *) element
;
1509 *Result2
= *Result3
= (void *) pad
;
1517 Message ("hace: Internal error, search for ID %d failed\n", ID
);
1521 /* ---------------------------------------------------------------------------
1522 * searches for an element by its board name.
1523 * The function returns a pointer to the element, NULL if not found
1526 SearchElementByName (DataTypePtr Base
, char *Name
)
1528 ElementTypePtr result
= NULL
;
1530 ELEMENT_LOOP (Base
);
1532 if (element
->Name
[1].TextString
&&
1533 NSTRCMP (element
->Name
[1].TextString
, Name
) == 0)
1543 /* ---------------------------------------------------------------------------
1544 * searches the cursor position for the type
1547 SearchScreen (Coord X
, Coord Y
, int Type
, void **Result1
,
1548 void **Result2
, void **Result3
)
1552 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1553 X
, Y
, SLOP
* pixel_slop
);
1557 /* ---------------------------------------------------------------------------
1558 * searches the cursor position for the type
1561 SearchScreenGridSlop (Coord X
, Coord Y
, int Type
, void **Result1
,
1562 void **Result2
, void **Result3
)
1566 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1567 X
, Y
, PCB
->Grid
/ 2);