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
;
332 arc_callback (const BoxType
* box
, void *cl
)
334 struct arc_info
*i
= (struct arc_info
*) cl
;
335 ArcTypePtr a
= (ArcTypePtr
) box
;
337 if (TEST_FLAG (i
->locked
, a
))
340 if (!IsPointOnArc (PosX
, PosY
, SearchRadius
, a
))
345 return 1; /* never reached */
350 SearchArcByLocation (int locked
, LayerTypePtr
* Layer
, ArcTypePtr
* Arc
,
353 struct arc_info info
;
357 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
359 *Layer
= SearchLayer
;
360 if (setjmp (info
.env
) == 0)
362 r_search (SearchLayer
->arc_tree
, &SearchBox
, NULL
, arc_callback
, &info
);
369 text_callback (const BoxType
* box
, void *cl
)
371 TextTypePtr text
= (TextTypePtr
) box
;
372 struct ans_info
*i
= (struct ans_info
*) cl
;
374 if (TEST_FLAG (i
->locked
, text
))
377 if (POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
379 *i
->ptr2
= *i
->ptr3
= text
;
385 /* ---------------------------------------------------------------------------
386 * searches text on the SearchLayer
389 SearchTextByLocation (int locked
, LayerTypePtr
* Layer
, TextTypePtr
* Text
,
392 struct ans_info info
;
394 *Layer
= SearchLayer
;
395 info
.ptr2
= (void **) Text
;
396 info
.ptr3
= (void **) Dummy
;
397 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
399 if (setjmp (info
.env
) == 0)
401 r_search (SearchLayer
->text_tree
, &SearchBox
, NULL
, text_callback
,
409 polygon_callback (const BoxType
* box
, void *cl
)
411 PolygonTypePtr polygon
= (PolygonTypePtr
) box
;
412 struct ans_info
*i
= (struct ans_info
*) cl
;
414 if (TEST_FLAG (i
->locked
, polygon
))
417 if (IsPointInPolygon (PosX
, PosY
, SearchRadius
, polygon
))
419 *i
->ptr2
= *i
->ptr3
= polygon
;
426 /* ---------------------------------------------------------------------------
427 * searches a polygon on the SearchLayer
430 SearchPolygonByLocation (int locked
, LayerTypePtr
* Layer
,
431 PolygonTypePtr
* Polygon
, PolygonTypePtr
* Dummy
)
433 struct ans_info info
;
435 *Layer
= SearchLayer
;
436 info
.ptr2
= (void **) Polygon
;
437 info
.ptr3
= (void **) Dummy
;
438 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
440 if (setjmp (info
.env
) == 0)
442 r_search (SearchLayer
->polygon_tree
, &SearchBox
, NULL
, polygon_callback
,
450 linepoint_callback (const BoxType
* b
, void *cl
)
452 LineTypePtr line
= (LineTypePtr
) b
;
453 struct line_info
*i
= (struct line_info
*) cl
;
457 if (TEST_FLAG (i
->locked
, line
))
460 /* some stupid code to check both points */
461 d
= Distance (PosX
, PosY
, line
->Point1
.X
, line
->Point1
.Y
);
466 *i
->Point
= &line
->Point1
;
470 d
= Distance (PosX
, PosY
, line
->Point2
.X
, line
->Point2
.Y
);
475 *i
->Point
= &line
->Point2
;
481 /* ---------------------------------------------------------------------------
482 * searches a line-point on all the search layer
485 SearchLinePointByLocation (int locked
, LayerTypePtr
* Layer
,
486 LineTypePtr
* Line
, PointTypePtr
* Point
)
488 struct line_info info
;
489 *Layer
= SearchLayer
;
493 info
.least
= MAX_LINE_POINT_DISTANCE
+ SearchRadius
;
494 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
496 (SearchLayer
->line_tree
, &SearchBox
, NULL
, linepoint_callback
, &info
))
502 arcpoint_callback (const BoxType
* b
, void *cl
)
504 ArcTypePtr arc
= (ArcTypePtr
) b
;
505 struct arc_info
*i
= (struct arc_info
*) cl
;
509 if (TEST_FLAG (i
->locked
, arc
))
512 d
= Distance (PosX
, PosY
, arc
->Point1
.X
, arc
->Point1
.Y
);
517 *i
->Point
= &arc
->Point1
;
521 d
= Distance (PosX
, PosY
, arc
->Point2
.X
, arc
->Point2
.Y
);
526 *i
->Point
= &arc
->Point2
;
532 /* ---------------------------------------------------------------------------
533 * searches an arc-point on all the search layer
536 SearchArcPointByLocation (int locked
, LayerType
**Layer
,
537 ArcType
**arc
, PointType
**Point
)
539 struct arc_info info
;
540 *Layer
= SearchLayer
;
544 info
.least
= MAX_ARC_POINT_DISTANCE
+ SearchRadius
;
545 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
547 (SearchLayer
->arc_tree
, &SearchBox
, NULL
, arcpoint_callback
, &info
))
551 /* ---------------------------------------------------------------------------
552 * searches a polygon-point on all layers that are switched on
553 * in layerstack order
556 SearchPointByLocation (int locked
, LayerTypePtr
* Layer
,
557 PolygonTypePtr
* Polygon
, PointTypePtr
* Point
)
562 least
= SearchRadius
+ MAX_POLYGON_POINT_DISTANCE
;
563 *Layer
= SearchLayer
;
564 POLYGON_LOOP (*Layer
);
566 POLYGONPOINT_LOOP (polygon
);
568 d
= Distance (point
->X
, point
->Y
, PosX
, PosY
);
586 name_callback (const BoxType
* box
, void *cl
)
588 TextTypePtr text
= (TextTypePtr
) box
;
589 struct ans_info
*i
= (struct ans_info
*) cl
;
590 ElementTypePtr element
= (ElementTypePtr
) text
->Element
;
593 if (TEST_FLAG (i
->locked
, text
))
596 if ((FRONT (element
) || i
->BackToo
) && !TEST_FLAG (HIDENAMEFLAG
, element
) &&
597 POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
599 /* use the text with the smallest bounding box */
600 newarea
= (text
->BoundingBox
.X2
- text
->BoundingBox
.X1
) *
601 (double) (text
->BoundingBox
.Y2
- text
->BoundingBox
.Y1
);
602 if (newarea
< i
->area
)
606 *i
->ptr2
= *i
->ptr3
= text
;
613 /* ---------------------------------------------------------------------------
614 * searches the name of an element
615 * the search starts with the last element and goes back to the beginning
618 SearchElementNameByLocation (int locked
, ElementTypePtr
* Element
,
619 TextTypePtr
* Text
, TextTypePtr
* Dummy
,
622 struct ans_info info
;
624 /* package layer have to be switched on */
627 info
.ptr1
= (void **) Element
;
628 info
.ptr2
= (void **) Text
;
629 info
.ptr3
= (void **) Dummy
;
630 info
.area
= SQUARE (MAX_COORD
);
631 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
632 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
633 if (r_search (PCB
->Data
->name_tree
[NAME_INDEX (PCB
)], &SearchBox
, NULL
,
634 name_callback
, &info
))
641 element_callback (const BoxType
* box
, void *cl
)
643 ElementTypePtr element
= (ElementTypePtr
) box
;
644 struct ans_info
*i
= (struct ans_info
*) cl
;
647 if (TEST_FLAG (i
->locked
, element
))
650 if ((FRONT (element
) || i
->BackToo
) &&
651 POINT_IN_BOX (PosX
, PosY
, &element
->VBox
))
653 /* use the element with the smallest bounding box */
654 newarea
= (element
->VBox
.X2
- element
->VBox
.X1
) *
655 (double) (element
->VBox
.Y2
- element
->VBox
.Y1
);
656 if (newarea
< i
->area
)
659 *i
->ptr1
= *i
->ptr2
= *i
->ptr3
= element
;
666 /* ---------------------------------------------------------------------------
667 * searches an element
668 * the search starts with the last element and goes back to the beginning
669 * if more than one element matches, the smallest one is taken
672 SearchElementByLocation (int locked
,
673 ElementTypePtr
* Element
,
674 ElementTypePtr
* Dummy1
, ElementTypePtr
* Dummy2
,
677 struct ans_info info
;
679 /* Both package layers have to be switched on */
680 if (PCB
->ElementOn
&& PCB
->PinOn
)
682 info
.ptr1
= (void **) Element
;
683 info
.ptr2
= (void **) Dummy1
;
684 info
.ptr3
= (void **) Dummy2
;
685 info
.area
= SQUARE (MAX_COORD
);
686 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
687 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
689 (PCB
->Data
->element_tree
, &SearchBox
, NULL
, element_callback
,
696 /* ---------------------------------------------------------------------------
697 * checks if a point is on a pin
700 IsPointOnPin (Coord X
, Coord Y
, Coord Radius
, PinTypePtr pin
)
702 Coord t
= PIN_SIZE (pin
) / 2;
703 if (TEST_FLAG (SQUAREFLAG
, pin
))
711 if (IsPointInBox (X
, Y
, &b
, Radius
))
714 else if (Distance (pin
->X
, pin
->Y
, X
, Y
) <= Radius
+ t
)
719 /* ---------------------------------------------------------------------------
720 * checks if a rat-line end is on a PV
723 IsPointOnLineEnd (Coord X
, Coord Y
, RatTypePtr Line
)
725 if (((X
== Line
->Point1
.X
) && (Y
== Line
->Point1
.Y
)) ||
726 ((X
== Line
->Point2
.X
) && (Y
== Line
->Point2
.Y
)))
731 /* ---------------------------------------------------------------------------
732 * checks if a line intersects with a PV
734 * let the point be (X,Y) and the line (X1,Y1)(X2,Y2)
735 * the length of the line is
737 * L = ((X2-X1)^2 + (Y2-Y1)^2)^0.5
739 * let Q be the point of perpendicular projection of (X,Y) onto the line
741 * QX = X1 + D1*(X2-X1) / L
742 * QY = Y1 + D1*(Y2-Y1) / L
744 * with (from vector geometry)
746 * (Y1-Y)(Y1-Y2)+(X1-X)(X1-X2)
747 * D1 = ---------------------------
750 * D1 < 0 Q is on backward extension of the line
751 * D1 > L Q is on forward extension of the line
752 * else Q is on the line
754 * the signed distance from (X,Y) to Q is
756 * (Y2-Y1)(X-X1)-(X2-X1)(Y-Y1)
757 * D2 = ----------------------------
760 * Finally, D1 and D2 are orthogonal, so we can sum them easily
761 * by pythagorean theorem.
764 IsPointOnLine (Coord X
, Coord Y
, Coord Radius
, LineTypePtr Line
)
768 /* Get length of segment */
769 L
= Distance (Line
->Point1
.X
, Line
->Point1
.Y
, Line
->Point2
.X
, Line
->Point2
.Y
);
771 return Distance (X
, Y
, Line
->Point1
.X
, Line
->Point1
.Y
) < Radius
+ Line
->Thickness
/ 2;
773 /* Get distance from (X1, Y1) to Q (on the line) */
774 D1
= ((double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
775 + (double) (X
- Line
->Point1
.X
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
776 /* Translate this into distance to Q from segment */
777 if (D1
< 0) D1
= -D1
;
778 else if (D1
> L
) D1
-= L
;
780 /* Get distance from (X, Y) to Q */
781 D2
= ((double) (X
- Line
->Point1
.X
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
782 - (double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
783 /* Total distance is then the pythagorean sum of these */
784 return sqrt (D1
*D1
+ D2
*D2
) <= Radius
+ Line
->Thickness
/ 2;
787 /* ---------------------------------------------------------------------------
788 * checks if a line crosses a rectangle
791 IsLineInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, LineTypePtr Line
)
795 /* first, see if point 1 is inside the rectangle */
796 /* in case the whole line is inside the rectangle */
797 if (X1
< Line
->Point1
.X
&& X2
> Line
->Point1
.X
&&
798 Y1
< Line
->Point1
.Y
&& Y2
> Line
->Point1
.Y
)
800 /* construct a set of dummy lines and check each of them */
802 line
.Flags
= NoFlags ();
804 /* upper-left to upper-right corner */
805 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
808 if (LineLineIntersect (&line
, Line
))
811 /* upper-right to lower-right corner */
815 if (LineLineIntersect (&line
, Line
))
818 /* lower-right to lower-left corner */
822 if (LineLineIntersect (&line
, Line
))
825 /* lower-left to upper-left corner */
829 if (LineLineIntersect (&line
, Line
))
835 static int /*checks if a point (of null radius) is in a slanted rectangle*/
836 IsPointInQuadrangle(PointType p
[4], PointTypePtr l
)
841 dx
= p
[1].X
- p
[0].X
;
842 dy
= p
[1].Y
- p
[0].Y
;
845 prod0
= (double) x
* dx
+ (double) y
* dy
;
848 prod1
= (double) x
* dx
+ (double) y
* dy
;
849 if (prod0
* prod1
<= 0)
851 dx
= p
[1].X
- p
[2].X
;
852 dy
= p
[1].Y
- p
[2].Y
;
853 prod0
= (double) x
* dx
+ (double) y
* dy
;
856 prod1
= (double) x
* dx
+ (double) y
* dy
;
857 if (prod0
* prod1
<= 0)
862 /* ---------------------------------------------------------------------------
863 * checks if a line crosses a quadrangle: almost copied from IsLineInRectangle()
864 * Note: actually this quadrangle is a slanted rectangle
867 IsLineInQuadrangle (PointType p
[4], LineTypePtr Line
)
871 /* first, see if point 1 is inside the rectangle */
872 /* in case the whole line is inside the rectangle */
873 if (IsPointInQuadrangle(p
,&(Line
->Point1
)))
875 if (IsPointInQuadrangle(p
,&(Line
->Point2
)))
877 /* construct a set of dummy lines and check each of them */
879 line
.Flags
= NoFlags ();
881 /* upper-left to upper-right corner */
882 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
883 line
.Point2
.X
= p
[1].X
; line
.Point2
.Y
= p
[1].Y
;
884 if (LineLineIntersect (&line
, Line
))
887 /* upper-right to lower-right corner */
888 line
.Point1
.X
= p
[2].X
; line
.Point1
.Y
= p
[2].Y
;
889 if (LineLineIntersect (&line
, Line
))
892 /* lower-right to lower-left corner */
893 line
.Point2
.X
= p
[3].X
; line
.Point2
.Y
= p
[3].Y
;
894 if (LineLineIntersect (&line
, Line
))
897 /* lower-left to upper-left corner */
898 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
899 if (LineLineIntersect (&line
, Line
))
904 /* ---------------------------------------------------------------------------
905 * checks if an arc crosses a square
908 IsArcInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, ArcTypePtr Arc
)
912 /* construct a set of dummy lines and check each of them */
914 line
.Flags
= NoFlags ();
916 /* upper-left to upper-right corner */
917 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
920 if (LineArcIntersect (&line
, Arc
))
923 /* upper-right to lower-right corner */
924 line
.Point1
.X
= line
.Point2
.X
= X2
;
927 if (LineArcIntersect (&line
, Arc
))
930 /* lower-right to lower-left corner */
931 line
.Point1
.Y
= line
.Point2
.Y
= Y2
;
934 if (LineArcIntersect (&line
, Arc
))
937 /* lower-left to upper-left corner */
938 line
.Point1
.X
= line
.Point2
.X
= X1
;
941 if (LineArcIntersect (&line
, Arc
))
947 /* ---------------------------------------------------------------------------
948 * Check if a circle of Radius with center at (X, Y) intersects a Pad.
949 * Written to enable arbitrary pad directions; for rounded pads, too.
952 IsPointInPad (Coord X
, Coord Y
, Coord Radius
, PadTypePtr Pad
)
956 Coord t2
= (Pad
->Thickness
+ 1) / 2, range
;
959 /* series of transforms saving range */
960 /* move Point1 to the origin */
964 pad
.Point2
.X
-= pad
.Point1
.X
;
965 pad
.Point2
.Y
-= pad
.Point1
.Y
;
966 /* so, pad.Point1.X = pad.Point1.Y = 0; */
968 /* rotate round (0, 0) so that Point2 coordinates be (r, 0) */
969 r
= Distance (0, 0, pad
.Point2
.X
, pad
.Point2
.Y
);
977 Sin
= pad
.Point2
.Y
/ r
;
978 Cos
= pad
.Point2
.X
/ r
;
981 X
= X
* Cos
+ Y
* Sin
;
982 Y
= Y
* Cos
- x
* Sin
;
983 /* now pad.Point2.X = r; pad.Point2.Y = 0; */
985 /* take into account the ends */
986 if (TEST_FLAG (SQUAREFLAG
, Pad
))
992 Y
= -Y
; /* range value is evident now*/
994 if (TEST_FLAG (SQUAREFLAG
, Pad
))
1001 return Radius
> Distance (0, t2
, X
, Y
);
1008 return Radius
> Distance (r
, t2
, X
, Y
);
1013 else/*Rounded pad: even more simple*/
1016 return (Radius
+ t2
) > Distance (0, 0, X
, Y
);
1018 return (Radius
+ t2
) > Distance (r
, 0, X
, Y
);
1022 return range
< Radius
;
1026 IsPointInBox (Coord X
, Coord Y
, BoxTypePtr box
, Coord Radius
)
1028 Coord width
, height
, range
;
1030 /* NB: Assumes box has point1 with numerically lower X and Y coordinates */
1032 /* Compute coordinates relative to Point1 */
1036 width
= box
->X2
- box
->X1
;
1037 height
= box
->Y2
- box
->Y1
;
1042 return Radius
> Distance (0, 0, X
, Y
);
1043 else if (Y
> height
)
1044 return Radius
> Distance (0, height
, X
, Y
);
1048 else if (X
>= width
)
1051 return Radius
> Distance (width
, 0, X
, Y
);
1052 else if (Y
> height
)
1053 return Radius
> Distance (width
, height
, X
, Y
);
1061 else if (Y
> height
)
1067 return range
< Radius
;
1070 /* TODO: this code is BROKEN in the case of non-circular arcs,
1071 * and in the case that the arc thickness is greater than
1075 IsPointOnArc (Coord X
, Coord Y
, Coord Radius
, ArcTypePtr Arc
)
1077 /* Calculate angle of point from arc center */
1078 double p_dist
= Distance (X
, Y
, Arc
->X
, Arc
->Y
);
1079 double p_cos
= (X
- Arc
->X
) / p_dist
;
1080 Angle p_ang
= acos (p_cos
) * RAD_TO_DEG
;
1083 /* Convert StartAngle, Delta into bounding angles in [0, 720) */
1086 ang1
= NormalizeAngle (Arc
->StartAngle
);
1087 ang2
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1091 ang1
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1092 ang2
= NormalizeAngle (Arc
->StartAngle
);
1096 /* Make sure full circles aren't treated as zero-length arcs */
1097 if (Arc
->Delta
== 360 || Arc
->Delta
== -360)
1104 /* Check point is outside arc range, check distance from endpoints */
1105 if (ang1
>= p_ang
|| ang2
<= p_ang
)
1109 ArcX
= Arc
->X
+ Arc
->Width
*
1110 cos ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1111 ArcY
= Arc
->Y
- Arc
->Width
*
1112 sin ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1113 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1116 ArcX
= Arc
->X
+ Arc
->Width
*
1117 cos ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1118 ArcY
= Arc
->Y
- Arc
->Width
*
1119 sin ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1120 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1124 /* If point is inside the arc range, just compare it to the arc */
1125 return fabs (Distance (X
, Y
, Arc
->X
, Arc
->Y
) - Arc
->Width
) < Radius
+ Arc
->Thickness
/ 2;
1128 /* ---------------------------------------------------------------------------
1129 * searches for any kind of object or for a set of object types
1130 * the calling routine passes two pointers to allocated memory for storing
1132 * A type value is returned too which is NO_TYPE if no objects has been found.
1133 * A set of object types is passed in.
1134 * The object is located by it's position.
1136 * The layout is checked in the following order:
1137 * polygon-point, pin, via, line, text, elementname, polygon, element
1139 * Note that if Type includes LOCKED_TYPE, then the search includes
1140 * locked items. Otherwise, locked items are ignored.
1143 SearchObjectByLocation (unsigned Type
,
1144 void **Result1
, void **Result2
, void **Result3
,
1145 Coord X
, Coord Y
, Coord Radius
)
1148 void **pr1
= &r1
, **pr2
= &r2
, **pr3
= &r3
;
1150 double HigherBound
= 0;
1151 int HigherAvail
= NO_TYPE
;
1152 int locked
= Type
& LOCKED_TYPE
;
1153 /* setup variables used by local functions */
1156 SearchRadius
= Radius
;
1159 SearchBox
.X1
= X
- Radius
;
1160 SearchBox
.Y1
= Y
- Radius
;
1161 SearchBox
.X2
= X
+ Radius
;
1162 SearchBox
.Y2
= Y
+ Radius
;
1166 SearchBox
= point_box (X
, Y
);
1169 if (TEST_FLAG (LOCKNAMESFLAG
, PCB
))
1171 Type
&= ~ (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1173 if (TEST_FLAG (HIDENAMESFLAG
, PCB
))
1175 Type
&= ~ELEMENTNAME_TYPE
;
1177 if (TEST_FLAG (ONLYNAMESFLAG
, PCB
))
1179 Type
&= (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1181 if (TEST_FLAG (THINDRAWFLAG
, PCB
) || TEST_FLAG (THINDRAWPOLYFLAG
, PCB
))
1183 Type
&= ~POLYGON_TYPE
;
1186 if (Type
& RATLINE_TYPE
&& PCB
->RatOn
&&
1187 SearchRatLineByLocation (locked
,
1188 (RatTypePtr
*) Result1
,
1189 (RatTypePtr
*) Result2
,
1190 (RatTypePtr
*) Result3
))
1191 return (RATLINE_TYPE
);
1193 if (Type
& VIA_TYPE
&&
1194 SearchViaByLocation (locked
,
1195 (PinTypePtr
*) Result1
,
1196 (PinTypePtr
*) Result2
, (PinTypePtr
*) Result3
))
1199 if (Type
& PIN_TYPE
&&
1200 SearchPinByLocation (locked
,
1201 (ElementTypePtr
*) pr1
,
1202 (PinTypePtr
*) pr2
, (PinTypePtr
*) pr3
))
1203 HigherAvail
= PIN_TYPE
;
1205 if (!HigherAvail
&& Type
& PAD_TYPE
&&
1206 SearchPadByLocation (locked
,
1207 (ElementTypePtr
*) pr1
,
1208 (PadTypePtr
*) pr2
, (PadTypePtr
*) pr3
, false))
1209 HigherAvail
= PAD_TYPE
;
1211 if (!HigherAvail
&& Type
& ELEMENTNAME_TYPE
&&
1212 SearchElementNameByLocation (locked
,
1213 (ElementTypePtr
*) pr1
,
1214 (TextTypePtr
*) pr2
, (TextTypePtr
*) pr3
,
1217 BoxTypePtr box
= &((TextTypePtr
) r2
)->BoundingBox
;
1218 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1219 HigherAvail
= ELEMENTNAME_TYPE
;
1222 if (!HigherAvail
&& Type
& ELEMENT_TYPE
&&
1223 SearchElementByLocation (locked
,
1224 (ElementTypePtr
*) pr1
,
1225 (ElementTypePtr
*) pr2
,
1226 (ElementTypePtr
*) pr3
, false))
1228 BoxTypePtr box
= &((ElementTypePtr
) r1
)->BoundingBox
;
1229 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1230 HigherAvail
= ELEMENT_TYPE
;
1233 for (i
= -1; i
< max_copper_layer
+ 1; i
++)
1236 SearchLayer
= &PCB
->Data
->SILKLAYER
;
1237 else if (i
< max_copper_layer
)
1238 SearchLayer
= LAYER_ON_STACK (i
);
1241 SearchLayer
= &PCB
->Data
->BACKSILKLAYER
;
1242 if (!PCB
->InvisibleObjectsOn
)
1245 if (SearchLayer
->On
)
1247 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1248 Type
& POLYGONPOINT_TYPE
&&
1249 SearchPointByLocation (locked
,
1250 (LayerTypePtr
*) Result1
,
1251 (PolygonTypePtr
*) Result2
,
1252 (PointTypePtr
*) Result3
))
1253 return (POLYGONPOINT_TYPE
);
1255 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1256 Type
& LINEPOINT_TYPE
&&
1257 SearchLinePointByLocation (locked
,
1258 (LayerTypePtr
*) Result1
,
1259 (LineTypePtr
*) Result2
,
1260 (PointTypePtr
*) Result3
))
1261 return (LINEPOINT_TYPE
);
1263 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& LINE_TYPE
1264 && SearchLineByLocation (locked
,
1265 (LayerTypePtr
*) Result1
,
1266 (LineTypePtr
*) Result2
,
1267 (LineTypePtr
*) Result3
))
1270 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1271 Type
& ARCPOINT_TYPE
&&
1272 SearchArcPointByLocation (locked
,
1273 (LayerTypePtr
*) Result1
,
1274 (ArcTypePtr
*) Result2
,
1275 (PointTypePtr
*) Result3
))
1276 return (ARCPOINT_TYPE
);
1278 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& ARC_TYPE
&&
1279 SearchArcByLocation (locked
,
1280 (LayerTypePtr
*) Result1
,
1281 (ArcTypePtr
*) Result2
,
1282 (ArcTypePtr
*) Result3
))
1285 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& TEXT_TYPE
1286 && SearchTextByLocation (locked
,
1287 (LayerTypePtr
*) Result1
,
1288 (TextTypePtr
*) Result2
,
1289 (TextTypePtr
*) Result3
))
1292 if (Type
& POLYGON_TYPE
&&
1293 SearchPolygonByLocation (locked
,
1294 (LayerTypePtr
*) Result1
,
1295 (PolygonTypePtr
*) Result2
,
1296 (PolygonTypePtr
*) Result3
))
1301 &(*(PolygonTypePtr
*) Result2
)->BoundingBox
;
1303 (double) (box
->X2
- box
->X1
) * (double) (box
->X2
- box
->X1
);
1304 if (HigherBound
< area
)
1307 return (POLYGON_TYPE
);
1310 return (POLYGON_TYPE
);
1314 /* return any previously found objects */
1315 if (HigherAvail
& PIN_TYPE
)
1323 if (HigherAvail
& PAD_TYPE
)
1331 if (HigherAvail
& ELEMENTNAME_TYPE
)
1336 return (ELEMENTNAME_TYPE
);
1339 if (HigherAvail
& ELEMENT_TYPE
)
1344 return (ELEMENT_TYPE
);
1347 /* search the 'invisible objects' last */
1348 if (!PCB
->InvisibleObjectsOn
)
1351 if (Type
& PAD_TYPE
&&
1352 SearchPadByLocation (locked
,
1353 (ElementTypePtr
*) Result1
,
1354 (PadTypePtr
*) Result2
, (PadTypePtr
*) Result3
,
1358 if (Type
& ELEMENTNAME_TYPE
&&
1359 SearchElementNameByLocation (locked
,
1360 (ElementTypePtr
*) Result1
,
1361 (TextTypePtr
*) Result2
,
1362 (TextTypePtr
*) Result3
, true))
1363 return (ELEMENTNAME_TYPE
);
1365 if (Type
& ELEMENT_TYPE
&&
1366 SearchElementByLocation (locked
,
1367 (ElementTypePtr
*) Result1
,
1368 (ElementTypePtr
*) Result2
,
1369 (ElementTypePtr
*) Result3
, true))
1370 return (ELEMENT_TYPE
);
1375 /* ---------------------------------------------------------------------------
1376 * searches for a object by it's unique ID. It doesn't matter if
1377 * the object is visible or not. The search is performed on a PCB, a
1378 * buffer or on the remove list.
1379 * The calling routine passes two pointers to allocated memory for storing
1381 * A type value is returned too which is NO_TYPE if no objects has been found.
1384 SearchObjectByID (DataTypePtr Base
,
1385 void **Result1
, void **Result2
, void **Result3
, int ID
,
1388 if (type
== LINE_TYPE
|| type
== LINEPOINT_TYPE
)
1390 ALLLINE_LOOP (Base
);
1394 *Result1
= (void *) layer
;
1395 *Result2
= *Result3
= (void *) line
;
1398 if (line
->Point1
.ID
== ID
)
1400 *Result1
= (void *) layer
;
1401 *Result2
= (void *) line
;
1402 *Result3
= (void *) &line
->Point1
;
1403 return (LINEPOINT_TYPE
);
1405 if (line
->Point2
.ID
== ID
)
1407 *Result1
= (void *) layer
;
1408 *Result2
= (void *) line
;
1409 *Result3
= (void *) &line
->Point2
;
1410 return (LINEPOINT_TYPE
);
1415 if (type
== ARC_TYPE
)
1421 *Result1
= (void *) layer
;
1422 *Result2
= *Result3
= (void *) arc
;
1429 if (type
== TEXT_TYPE
)
1431 ALLTEXT_LOOP (Base
);
1435 *Result1
= (void *) layer
;
1436 *Result2
= *Result3
= (void *) text
;
1443 if (type
== POLYGON_TYPE
|| type
== POLYGONPOINT_TYPE
)
1445 ALLPOLYGON_LOOP (Base
);
1447 if (polygon
->ID
== ID
)
1449 *Result1
= (void *) layer
;
1450 *Result2
= *Result3
= (void *) polygon
;
1451 return (POLYGON_TYPE
);
1453 if (type
== POLYGONPOINT_TYPE
)
1454 POLYGONPOINT_LOOP (polygon
);
1456 if (point
->ID
== ID
)
1458 *Result1
= (void *) layer
;
1459 *Result2
= (void *) polygon
;
1460 *Result3
= (void *) point
;
1461 return (POLYGONPOINT_TYPE
);
1468 if (type
== VIA_TYPE
)
1474 *Result1
= *Result2
= *Result3
= (void *) via
;
1481 if (type
== RATLINE_TYPE
|| type
== LINEPOINT_TYPE
)
1487 *Result1
= *Result2
= *Result3
= (void *) line
;
1488 return (RATLINE_TYPE
);
1490 if (line
->Point1
.ID
== ID
)
1492 *Result1
= (void *) NULL
;
1493 *Result2
= (void *) line
;
1494 *Result3
= (void *) &line
->Point1
;
1495 return (LINEPOINT_TYPE
);
1497 if (line
->Point2
.ID
== ID
)
1499 *Result1
= (void *) NULL
;
1500 *Result2
= (void *) line
;
1501 *Result3
= (void *) &line
->Point2
;
1502 return (LINEPOINT_TYPE
);
1508 if (type
== ELEMENT_TYPE
|| type
== PAD_TYPE
|| type
== PIN_TYPE
1509 || type
== ELEMENTLINE_TYPE
|| type
== ELEMENTNAME_TYPE
1510 || type
== ELEMENTARC_TYPE
)
1511 /* check pins and elementnames too */
1512 ELEMENT_LOOP (Base
);
1514 if (element
->ID
== ID
)
1516 *Result1
= *Result2
= *Result3
= (void *) element
;
1517 return (ELEMENT_TYPE
);
1519 if (type
== ELEMENTLINE_TYPE
)
1520 ELEMENTLINE_LOOP (element
);
1524 *Result1
= (void *) element
;
1525 *Result2
= *Result3
= (void *) line
;
1526 return (ELEMENTLINE_TYPE
);
1530 if (type
== ELEMENTARC_TYPE
)
1535 *Result1
= (void *) element
;
1536 *Result2
= *Result3
= (void *) arc
;
1537 return (ELEMENTARC_TYPE
);
1541 if (type
== ELEMENTNAME_TYPE
)
1542 ELEMENTTEXT_LOOP (element
);
1546 *Result1
= (void *) element
;
1547 *Result2
= *Result3
= (void *) text
;
1548 return (ELEMENTNAME_TYPE
);
1552 if (type
== PIN_TYPE
)
1557 *Result1
= (void *) element
;
1558 *Result2
= *Result3
= (void *) pin
;
1563 if (type
== PAD_TYPE
)
1568 *Result1
= (void *) element
;
1569 *Result2
= *Result3
= (void *) pad
;
1577 Message ("hace: Internal error, search for ID %d failed\n", ID
);
1581 /* ---------------------------------------------------------------------------
1582 * searches for an element by its board name.
1583 * The function returns a pointer to the element, NULL if not found
1586 SearchElementByName (DataTypePtr Base
, char *Name
)
1588 ElementTypePtr result
= NULL
;
1590 ELEMENT_LOOP (Base
);
1592 if (element
->Name
[1].TextString
&&
1593 NSTRCMP (element
->Name
[1].TextString
, Name
) == 0)
1603 /* ---------------------------------------------------------------------------
1604 * searches the cursor position for the type
1607 SearchScreen (Coord X
, Coord Y
, int Type
, void **Result1
,
1608 void **Result2
, void **Result3
)
1612 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1613 X
, Y
, SLOP
* pixel_slop
);
1617 /* ---------------------------------------------------------------------------
1618 * searches the cursor position for the type
1621 SearchScreenGridSlop (Coord X
, Coord Y
, int Type
, void **Result1
,
1622 void **Result2
, void **Result3
)
1626 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1627 X
, Y
, PCB
->Grid
/ 2);