4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
29 * some of the functions use dummy parameters
51 #ifdef HAVE_LIBDMALLOC
55 /* ---------------------------------------------------------------------------
56 * some local identifiers
58 static double PosX
, PosY
; /* search position for subroutines */
59 static Coord SearchRadius
;
60 static BoxType SearchBox
;
61 static LayerType
*SearchLayer
;
63 /* ---------------------------------------------------------------------------
64 * some local prototypes. The first parameter includes LOCKED_TYPE if we
65 * want to include locked types in the search.
67 static bool SearchLineByLocation (int, LayerType
**, LineType
**,
69 static bool SearchArcByLocation (int, LayerType
**, ArcType
**,
71 static bool SearchRatLineByLocation (int, RatType
**, RatType
**,
73 static bool SearchTextByLocation (int, LayerType
**, TextType
**,
75 static bool SearchPolygonByLocation (int, LayerType
**, PolygonType
**,
77 static bool SearchPinByLocation (int, ElementType
**, PinType
**,
79 static bool SearchPadByLocation (int, ElementType
**, PadType
**,
81 static bool SearchViaByLocation (int, PinType
**, PinType
**,
83 static bool SearchElementNameByLocation (int, ElementType
**,
84 TextType
**, TextType
**,
86 static bool SearchLinePointByLocation (int, LayerType
**, LineType
**,
88 static bool SearchPointByLocation (int, LayerType
**, PolygonType
**,
90 static bool SearchElementByLocation (int, ElementType
**,
91 ElementType
**, ElementType
**,
94 /* ---------------------------------------------------------------------------
99 void **ptr1
, **ptr2
, **ptr3
;
103 int locked
; /* This will be zero or LOCKFLAG */
105 double nearest_sq_dist
;
109 pinorvia_callback (const BoxType
* box
, void *cl
)
111 struct ans_info
*i
= (struct ans_info
*) cl
;
112 PinType
*pin
= (PinType
*) box
;
113 AnyObjectType
*ptr1
= pin
->Element
? pin
->Element
: pin
;
115 if (TEST_FLAG (i
->locked
, ptr1
))
118 if (!IsPointOnPin (PosX
, PosY
, SearchRadius
, pin
))
121 *i
->ptr2
= *i
->ptr3
= pin
;
123 return 1; /* never reached */
127 SearchViaByLocation (int locked
, PinType
** Via
, PinType
** Dummy1
,
130 struct ans_info info
;
132 /* search only if via-layer is visible */
136 info
.ptr1
= (void **) Via
;
137 info
.ptr2
= (void **) Dummy1
;
138 info
.ptr3
= (void **) Dummy2
;
139 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
141 if (setjmp (info
.env
) == 0)
143 r_search (PCB
->Data
->via_tree
, &SearchBox
, NULL
, pinorvia_callback
,
150 /* ---------------------------------------------------------------------------
152 * starts with the newest element
155 SearchPinByLocation (int locked
, ElementType
** Element
, PinType
** Pin
,
158 struct ans_info info
;
160 /* search only if pin-layer is visible */
163 info
.ptr1
= (void **) Element
;
164 info
.ptr2
= (void **) Pin
;
165 info
.ptr3
= (void **) Dummy
;
166 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
168 if (setjmp (info
.env
) == 0)
169 r_search (PCB
->Data
->pin_tree
, &SearchBox
, NULL
, pinorvia_callback
,
177 pad_callback (const BoxType
* b
, void *cl
)
179 PadType
*pad
= (PadType
*) b
;
180 struct ans_info
*i
= (struct ans_info
*) cl
;
181 AnyObjectType
*ptr1
= pad
->Element
;
184 /* Reject locked pads, backside pads (if !BackToo), and non-hit pads */
185 if (TEST_FLAG (i
->locked
, ptr1
) ||
186 (!FRONT (pad
) && !i
->BackToo
) ||
187 !IsPointInPad (PosX
, PosY
, SearchRadius
, pad
))
190 /* Determine how close our test-position was to the center of the pad */
191 sq_dist
= (PosX
- (pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2)) *
192 (PosX
- (pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2)) +
193 (PosY
- (pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2)) *
194 (PosY
- (pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2));
196 /* If this was the closest hit so far, record it */
197 if (!i
->found_anything
|| sq_dist
< i
->nearest_sq_dist
)
200 *i
->ptr2
= *i
->ptr3
= pad
;
201 i
->found_anything
= true;
202 i
->nearest_sq_dist
= sq_dist
;
207 /* ---------------------------------------------------------------------------
209 * starts with the newest element
212 SearchPadByLocation (int locked
, ElementType
** Element
, PadType
** Pad
,
213 PadType
** Dummy
, bool BackToo
)
215 struct ans_info info
;
217 /* search only if pin-layer is visible */
220 info
.ptr1
= (void **) Element
;
221 info
.ptr2
= (void **) Pad
;
222 info
.ptr3
= (void **) Dummy
;
223 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
224 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
225 info
.found_anything
= false;
226 r_search (PCB
->Data
->pad_tree
, &SearchBox
, NULL
, pad_callback
, &info
);
227 return info
.found_anything
;
230 /* ---------------------------------------------------------------------------
231 * searches ordinary line on the SearchLayer
244 line_callback (const BoxType
* box
, void *cl
)
246 struct line_info
*i
= (struct line_info
*) cl
;
247 LineType
*l
= (LineType
*) box
;
249 if (TEST_FLAG (i
->locked
, l
))
252 if (!IsPointInPad (PosX
, PosY
, SearchRadius
, (PadType
*)l
))
255 *i
->Point
= (PointType
*) l
;
257 return 1; /* never reached */
262 SearchLineByLocation (int locked
, LayerType
** Layer
, LineType
** Line
,
265 struct line_info info
;
268 info
.Point
= (PointType
**) Dummy
;
269 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
271 *Layer
= SearchLayer
;
272 if (setjmp (info
.env
) == 0)
274 r_search (SearchLayer
->line_tree
, &SearchBox
, NULL
, line_callback
,
282 rat_callback (const BoxType
* box
, void *cl
)
284 LineType
*line
= (LineType
*) box
;
285 struct ans_info
*i
= (struct ans_info
*) cl
;
287 if (TEST_FLAG (i
->locked
, line
))
290 if (TEST_FLAG (VIAFLAG
, line
) ?
291 (Distance (line
->Point1
.X
, line
->Point1
.Y
, PosX
, PosY
) <=
292 line
->Thickness
* 2 + SearchRadius
) :
293 IsPointOnLine (PosX
, PosY
, SearchRadius
, line
))
295 *i
->ptr1
= *i
->ptr2
= *i
->ptr3
= line
;
301 /* ---------------------------------------------------------------------------
302 * searches rat lines if they are visible
305 SearchRatLineByLocation (int locked
, RatType
** Line
, RatType
** Dummy1
,
308 struct ans_info info
;
310 info
.ptr1
= (void **) Line
;
311 info
.ptr2
= (void **) Dummy1
;
312 info
.ptr3
= (void **) Dummy2
;
313 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
315 if (setjmp (info
.env
) == 0)
317 r_search (PCB
->Data
->rat_tree
, &SearchBox
, NULL
, rat_callback
, &info
);
323 /* ---------------------------------------------------------------------------
324 * searches arc on the SearchLayer
328 ArcType
**Arc
, **Dummy
;
336 arc_callback (const BoxType
* box
, void *cl
)
338 struct arc_info
*i
= (struct arc_info
*) cl
;
339 ArcType
*a
= (ArcType
*) box
;
341 if (TEST_FLAG (i
->locked
, a
))
344 if (!IsPointOnArc (PosX
, PosY
, SearchRadius
, a
))
349 return 1; /* never reached */
354 SearchArcByLocation (int locked
, LayerType
** Layer
, ArcType
** Arc
,
357 struct arc_info info
;
361 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
363 *Layer
= SearchLayer
;
364 if (setjmp (info
.env
) == 0)
366 r_search (SearchLayer
->arc_tree
, &SearchBox
, NULL
, arc_callback
, &info
);
373 text_callback (const BoxType
* box
, void *cl
)
375 TextType
*text
= (TextType
*) box
;
376 struct ans_info
*i
= (struct ans_info
*) cl
;
378 if (TEST_FLAG (i
->locked
, text
))
381 if (POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
383 *i
->ptr2
= *i
->ptr3
= text
;
389 /* ---------------------------------------------------------------------------
390 * searches text on the SearchLayer
393 SearchTextByLocation (int locked
, LayerType
** Layer
, TextType
** Text
,
396 struct ans_info info
;
398 *Layer
= SearchLayer
;
399 info
.ptr2
= (void **) Text
;
400 info
.ptr3
= (void **) Dummy
;
401 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
403 if (setjmp (info
.env
) == 0)
405 r_search (SearchLayer
->text_tree
, &SearchBox
, NULL
, text_callback
,
413 polygon_callback (const BoxType
* box
, void *cl
)
415 PolygonType
*polygon
= (PolygonType
*) box
;
416 struct ans_info
*i
= (struct ans_info
*) cl
;
418 if (TEST_FLAG (i
->locked
, polygon
))
421 if (IsPointInPolygon (PosX
, PosY
, SearchRadius
, polygon
))
423 *i
->ptr2
= *i
->ptr3
= polygon
;
430 /* ---------------------------------------------------------------------------
431 * searches a polygon on the SearchLayer
434 SearchPolygonByLocation (int locked
, LayerType
** Layer
,
435 PolygonType
** Polygon
, PolygonType
** Dummy
)
437 struct ans_info info
;
439 *Layer
= SearchLayer
;
440 info
.ptr2
= (void **) Polygon
;
441 info
.ptr3
= (void **) Dummy
;
442 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
444 if (setjmp (info
.env
) == 0)
446 r_search (SearchLayer
->polygon_tree
, &SearchBox
, NULL
, polygon_callback
,
454 linepoint_callback (const BoxType
* b
, void *cl
)
456 LineType
*line
= (LineType
*) b
;
457 struct line_info
*i
= (struct line_info
*) cl
;
461 if (TEST_FLAG (i
->locked
, line
))
464 /* some stupid code to check both points */
465 d
= Distance (PosX
, PosY
, line
->Point1
.X
, line
->Point1
.Y
);
470 *i
->Point
= &line
->Point1
;
474 d
= Distance (PosX
, PosY
, line
->Point2
.X
, line
->Point2
.Y
);
479 *i
->Point
= &line
->Point2
;
485 /* ---------------------------------------------------------------------------
486 * searches a line-point on all the search layer
489 SearchLinePointByLocation (int locked
, LayerType
** Layer
,
490 LineType
** Line
, PointType
** Point
)
492 struct line_info info
;
493 *Layer
= SearchLayer
;
497 info
.least
= MAX_LINE_POINT_DISTANCE
+ SearchRadius
;
498 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
500 (SearchLayer
->line_tree
, &SearchBox
, NULL
, linepoint_callback
, &info
))
506 arcpoint_callback (const BoxType
* b
, void *cl
)
508 ArcType
*arc
= (ArcType
*) b
;
509 struct arc_info
*i
= (struct arc_info
*) cl
;
513 if (TEST_FLAG (i
->locked
, arc
))
516 d
= Distance (PosX
, PosY
, arc
->Point1
.X
, arc
->Point1
.Y
);
521 *i
->Point
= &arc
->Point1
;
525 d
= Distance (PosX
, PosY
, arc
->Point2
.X
, arc
->Point2
.Y
);
530 *i
->Point
= &arc
->Point2
;
536 /* ---------------------------------------------------------------------------
537 * searches an arc-point on all the search layer
540 SearchArcPointByLocation (int locked
, LayerType
**Layer
,
541 ArcType
**arc
, PointType
**Point
)
543 struct arc_info info
;
544 *Layer
= SearchLayer
;
548 info
.least
= MAX_ARC_POINT_DISTANCE
+ SearchRadius
;
549 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
551 (SearchLayer
->arc_tree
, &SearchBox
, NULL
, arcpoint_callback
, &info
))
555 /* ---------------------------------------------------------------------------
556 * searches a polygon-point on all layers that are switched on
557 * in layerstack order
560 SearchPointByLocation (int locked
, LayerType
** Layer
,
561 PolygonType
** Polygon
, PointType
** Point
)
566 least
= SearchRadius
+ MAX_POLYGON_POINT_DISTANCE
;
567 *Layer
= SearchLayer
;
568 POLYGON_LOOP (*Layer
);
570 POLYGONPOINT_LOOP (polygon
);
572 d
= Distance (point
->X
, point
->Y
, PosX
, PosY
);
590 name_callback (const BoxType
* box
, void *cl
)
592 TextType
*text
= (TextType
*) box
;
593 struct ans_info
*i
= (struct ans_info
*) cl
;
594 ElementType
*element
= (ElementType
*) text
->Element
;
597 if (TEST_FLAG (i
->locked
, text
))
600 if ((FRONT (element
) || i
->BackToo
) && !TEST_FLAG (HIDENAMEFLAG
, element
) &&
601 POINT_IN_BOX (PosX
, PosY
, &text
->BoundingBox
))
603 /* use the text with the smallest bounding box */
604 newarea
= (text
->BoundingBox
.X2
- text
->BoundingBox
.X1
) *
605 (double) (text
->BoundingBox
.Y2
- text
->BoundingBox
.Y1
);
606 if (newarea
< i
->area
)
610 *i
->ptr2
= *i
->ptr3
= text
;
617 /* ---------------------------------------------------------------------------
618 * searches the name of an element
619 * the search starts with the last element and goes back to the beginning
622 SearchElementNameByLocation (int locked
, ElementType
** Element
,
623 TextType
** Text
, TextType
** Dummy
,
626 struct ans_info info
;
628 /* package layer have to be switched on */
631 info
.ptr1
= (void **) Element
;
632 info
.ptr2
= (void **) Text
;
633 info
.ptr3
= (void **) Dummy
;
634 info
.area
= SQUARE (MAX_COORD
);
635 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
636 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
637 if (r_search (PCB
->Data
->name_tree
[NAME_INDEX (PCB
)], &SearchBox
, NULL
,
638 name_callback
, &info
))
645 element_callback (const BoxType
* box
, void *cl
)
647 ElementType
*element
= (ElementType
*) box
;
648 struct ans_info
*i
= (struct ans_info
*) cl
;
651 if (TEST_FLAG (i
->locked
, element
))
654 if ((FRONT (element
) || i
->BackToo
) &&
655 POINT_IN_BOX (PosX
, PosY
, &element
->VBox
))
657 /* use the element with the smallest bounding box */
658 newarea
= (element
->VBox
.X2
- element
->VBox
.X1
) *
659 (double) (element
->VBox
.Y2
- element
->VBox
.Y1
);
660 if (newarea
< i
->area
)
663 *i
->ptr1
= *i
->ptr2
= *i
->ptr3
= element
;
670 /* ---------------------------------------------------------------------------
671 * searches an element
672 * the search starts with the last element and goes back to the beginning
673 * if more than one element matches, the smallest one is taken
676 SearchElementByLocation (int locked
,
677 ElementType
** Element
,
678 ElementType
** Dummy1
, ElementType
** Dummy2
,
681 struct ans_info info
;
683 /* Both package layers have to be switched on */
684 if (PCB
->ElementOn
&& PCB
->PinOn
)
686 info
.ptr1
= (void **) Element
;
687 info
.ptr2
= (void **) Dummy1
;
688 info
.ptr3
= (void **) Dummy2
;
689 info
.area
= SQUARE (MAX_COORD
);
690 info
.BackToo
= (BackToo
&& PCB
->InvisibleObjectsOn
);
691 info
.locked
= (locked
& LOCKED_TYPE
) ? 0 : LOCKFLAG
;
693 (PCB
->Data
->element_tree
, &SearchBox
, NULL
, element_callback
,
700 /* ---------------------------------------------------------------------------
701 * checks if a point is on a pin
704 IsPointOnPin (Coord X
, Coord Y
, Coord Radius
, PinType
*pin
)
706 Coord t
= PIN_SIZE (pin
) / 2;
707 if (TEST_FLAG (SQUAREFLAG
, pin
))
715 if (IsPointInBox (X
, Y
, &b
, Radius
))
718 else if (Distance (pin
->X
, pin
->Y
, X
, Y
) <= Radius
+ t
)
723 /* ---------------------------------------------------------------------------
724 * checks if a rat-line end is on a PV
727 IsPointOnLineEnd (Coord X
, Coord Y
, RatType
*Line
)
729 if (((X
== Line
->Point1
.X
) && (Y
== Line
->Point1
.Y
)) ||
730 ((X
== Line
->Point2
.X
) && (Y
== Line
->Point2
.Y
)))
735 /* ---------------------------------------------------------------------------
736 * checks if a line intersects with a PV
738 * let the point be (X,Y) and the line (X1,Y1)(X2,Y2)
739 * the length of the line is
741 * L = ((X2-X1)^2 + (Y2-Y1)^2)^0.5
743 * let Q be the point of perpendicular projection of (X,Y) onto the line
745 * QX = X1 + D1*(X2-X1) / L
746 * QY = Y1 + D1*(Y2-Y1) / L
748 * with (from vector geometry)
750 * (Y1-Y)(Y1-Y2)+(X1-X)(X1-X2)
751 * D1 = ---------------------------
754 * D1 < 0 Q is on backward extension of the line
755 * D1 > L Q is on forward extension of the line
756 * else Q is on the line
758 * the signed distance from (X,Y) to Q is
760 * (Y2-Y1)(X-X1)-(X2-X1)(Y-Y1)
761 * D2 = ----------------------------
764 * Finally, D1 and D2 are orthogonal, so we can sum them easily
765 * by pythagorean theorem.
768 IsPointOnLine (Coord X
, Coord Y
, Coord Radius
, LineType
*Line
)
772 /* Get length of segment */
773 L
= Distance (Line
->Point1
.X
, Line
->Point1
.Y
, Line
->Point2
.X
, Line
->Point2
.Y
);
775 return Distance (X
, Y
, Line
->Point1
.X
, Line
->Point1
.Y
) < Radius
+ Line
->Thickness
/ 2;
777 /* Get distance from (X1, Y1) to Q (on the line) */
778 D1
= ((double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
779 + (double) (X
- Line
->Point1
.X
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
780 /* Translate this into distance to Q from segment */
781 if (D1
< 0) D1
= -D1
;
782 else if (D1
> L
) D1
-= L
;
784 /* Get distance from (X, Y) to Q */
785 D2
= ((double) (X
- Line
->Point1
.X
) * (Line
->Point2
.Y
- Line
->Point1
.Y
)
786 - (double) (Y
- Line
->Point1
.Y
) * (Line
->Point2
.X
- Line
->Point1
.X
)) / L
;
787 /* Total distance is then the pythagorean sum of these */
788 return sqrt (D1
*D1
+ D2
*D2
) <= Radius
+ Line
->Thickness
/ 2;
791 /* ---------------------------------------------------------------------------
792 * checks if a line crosses a rectangle
795 IsLineInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, LineType
*Line
)
799 /* first, see if point 1 is inside the rectangle */
800 /* in case the whole line is inside the rectangle */
801 if (X1
< Line
->Point1
.X
&& X2
> Line
->Point1
.X
&&
802 Y1
< Line
->Point1
.Y
&& Y2
> Line
->Point1
.Y
)
804 /* construct a set of dummy lines and check each of them */
806 line
.Flags
= NoFlags ();
808 /* upper-left to upper-right corner */
809 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
812 if (LineLineIntersect (&line
, Line
))
815 /* upper-right to lower-right corner */
819 if (LineLineIntersect (&line
, Line
))
822 /* lower-right to lower-left corner */
826 if (LineLineIntersect (&line
, Line
))
829 /* lower-left to upper-left corner */
833 if (LineLineIntersect (&line
, Line
))
839 static int /*checks if a point (of null radius) is in a slanted rectangle*/
840 IsPointInQuadrangle(PointType p
[4], PointType
*l
)
845 dx
= p
[1].X
- p
[0].X
;
846 dy
= p
[1].Y
- p
[0].Y
;
849 prod0
= (double) x
* dx
+ (double) y
* dy
;
852 prod1
= (double) x
* dx
+ (double) y
* dy
;
853 if (prod0
* prod1
<= 0)
855 dx
= p
[1].X
- p
[2].X
;
856 dy
= p
[1].Y
- p
[2].Y
;
857 prod0
= (double) x
* dx
+ (double) y
* dy
;
860 prod1
= (double) x
* dx
+ (double) y
* dy
;
861 if (prod0
* prod1
<= 0)
866 /* ---------------------------------------------------------------------------
867 * checks if a line crosses a quadrangle: almost copied from IsLineInRectangle()
868 * Note: actually this quadrangle is a slanted rectangle
871 IsLineInQuadrangle (PointType p
[4], LineType
*Line
)
875 /* first, see if point 1 is inside the rectangle */
876 /* in case the whole line is inside the rectangle */
877 if (IsPointInQuadrangle(p
,&(Line
->Point1
)))
879 if (IsPointInQuadrangle(p
,&(Line
->Point2
)))
881 /* construct a set of dummy lines and check each of them */
883 line
.Flags
= NoFlags ();
885 /* upper-left to upper-right corner */
886 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
887 line
.Point2
.X
= p
[1].X
; line
.Point2
.Y
= p
[1].Y
;
888 if (LineLineIntersect (&line
, Line
))
891 /* upper-right to lower-right corner */
892 line
.Point1
.X
= p
[2].X
; line
.Point1
.Y
= p
[2].Y
;
893 if (LineLineIntersect (&line
, Line
))
896 /* lower-right to lower-left corner */
897 line
.Point2
.X
= p
[3].X
; line
.Point2
.Y
= p
[3].Y
;
898 if (LineLineIntersect (&line
, Line
))
901 /* lower-left to upper-left corner */
902 line
.Point1
.X
= p
[0].X
; line
.Point1
.Y
= p
[0].Y
;
903 if (LineLineIntersect (&line
, Line
))
908 /* ---------------------------------------------------------------------------
909 * checks if an arc crosses a square
912 IsArcInRectangle (Coord X1
, Coord Y1
, Coord X2
, Coord Y2
, ArcType
*Arc
)
916 /* construct a set of dummy lines and check each of them */
918 line
.Flags
= NoFlags ();
920 /* upper-left to upper-right corner */
921 line
.Point1
.Y
= line
.Point2
.Y
= Y1
;
924 if (LineArcIntersect (&line
, Arc
))
927 /* upper-right to lower-right corner */
928 line
.Point1
.X
= line
.Point2
.X
= X2
;
931 if (LineArcIntersect (&line
, Arc
))
934 /* lower-right to lower-left corner */
935 line
.Point1
.Y
= line
.Point2
.Y
= Y2
;
938 if (LineArcIntersect (&line
, Arc
))
941 /* lower-left to upper-left corner */
942 line
.Point1
.X
= line
.Point2
.X
= X1
;
945 if (LineArcIntersect (&line
, Arc
))
951 /* ---------------------------------------------------------------------------
952 * Check if a circle of Radius with center at (X, Y) intersects a Pad.
953 * Written to enable arbitrary pad directions; for rounded pads, too.
956 IsPointInPad (Coord X
, Coord Y
, Coord Radius
, PadType
*Pad
)
960 Coord t2
= (Pad
->Thickness
+ 1) / 2, range
;
963 /* series of transforms saving range */
964 /* move Point1 to the origin */
968 pad
.Point2
.X
-= pad
.Point1
.X
;
969 pad
.Point2
.Y
-= pad
.Point1
.Y
;
970 /* so, pad.Point1.X = pad.Point1.Y = 0; */
972 /* rotate round (0, 0) so that Point2 coordinates be (r, 0) */
973 r
= Distance (0, 0, pad
.Point2
.X
, pad
.Point2
.Y
);
981 Sin
= pad
.Point2
.Y
/ r
;
982 Cos
= pad
.Point2
.X
/ r
;
985 X
= X
* Cos
+ Y
* Sin
;
986 Y
= Y
* Cos
- x
* Sin
;
987 /* now pad.Point2.X = r; pad.Point2.Y = 0; */
989 /* take into account the ends */
990 if (TEST_FLAG (SQUAREFLAG
, Pad
))
996 Y
= -Y
; /* range value is evident now*/
998 if (TEST_FLAG (SQUAREFLAG
, Pad
))
1005 return Radius
> Distance (0, t2
, X
, Y
);
1012 return Radius
> Distance (r
, t2
, X
, Y
);
1017 else/*Rounded pad: even more simple*/
1020 return (Radius
+ t2
) > Distance (0, 0, X
, Y
);
1022 return (Radius
+ t2
) > Distance (r
, 0, X
, Y
);
1026 return range
< Radius
;
1030 IsPointInBox (Coord X
, Coord Y
, BoxType
*box
, Coord Radius
)
1032 Coord width
, height
, range
;
1034 /* NB: Assumes box has point1 with numerically lower X and Y coordinates */
1036 /* Compute coordinates relative to Point1 */
1040 width
= box
->X2
- box
->X1
;
1041 height
= box
->Y2
- box
->Y1
;
1046 return Radius
> Distance (0, 0, X
, Y
);
1047 else if (Y
> height
)
1048 return Radius
> Distance (0, height
, X
, Y
);
1052 else if (X
>= width
)
1055 return Radius
> Distance (width
, 0, X
, Y
);
1056 else if (Y
> height
)
1057 return Radius
> Distance (width
, height
, X
, Y
);
1065 else if (Y
> height
)
1071 return range
< Radius
;
1074 /* TODO: this code is BROKEN in the case of non-circular arcs,
1075 * and in the case that the arc thickness is greater than
1079 IsPointOnArc (Coord X
, Coord Y
, Coord Radius
, ArcType
*Arc
)
1081 /* Calculate angle of point from arc center */
1082 double p_dist
= Distance (X
, Y
, Arc
->X
, Arc
->Y
);
1083 double p_cos
= (X
- Arc
->X
) / p_dist
;
1084 Angle p_ang
= acos (p_cos
) * RAD_TO_DEG
;
1087 /* Convert StartAngle, Delta into bounding angles in [0, 720) */
1090 ang1
= NormalizeAngle (Arc
->StartAngle
);
1091 ang2
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1095 ang1
= NormalizeAngle (Arc
->StartAngle
+ Arc
->Delta
);
1096 ang2
= NormalizeAngle (Arc
->StartAngle
);
1100 /* Make sure full circles aren't treated as zero-length arcs */
1101 if (Arc
->Delta
== 360 || Arc
->Delta
== -360)
1108 /* Check point is outside arc range, check distance from endpoints */
1109 if (ang1
>= p_ang
|| ang2
<= p_ang
)
1113 ArcX
= Arc
->X
+ Arc
->Width
*
1114 cos ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1115 ArcY
= Arc
->Y
- Arc
->Width
*
1116 sin ((Arc
->StartAngle
+ 180) / RAD_TO_DEG
);
1117 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1120 ArcX
= Arc
->X
+ Arc
->Width
*
1121 cos ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1122 ArcY
= Arc
->Y
- Arc
->Width
*
1123 sin ((Arc
->StartAngle
+ Arc
->Delta
+ 180) / RAD_TO_DEG
);
1124 if (Distance (X
, Y
, ArcX
, ArcY
) < Radius
+ Arc
->Thickness
/ 2)
1128 /* If point is inside the arc range, just compare it to the arc */
1129 return fabs (Distance (X
, Y
, Arc
->X
, Arc
->Y
) - Arc
->Width
) < Radius
+ Arc
->Thickness
/ 2;
1132 /* ---------------------------------------------------------------------------
1133 * searches for any kind of object or for a set of object types
1134 * the calling routine passes two pointers to allocated memory for storing
1136 * A type value is returned too which is NO_TYPE if no objects has been found.
1137 * A set of object types is passed in.
1138 * The object is located by it's position.
1140 * The layout is checked in the following order:
1141 * polygon-point, pin, via, line, text, elementname, polygon, element
1143 * Note that if Type includes LOCKED_TYPE, then the search includes
1144 * locked items. Otherwise, locked items are ignored.
1147 SearchObjectByLocation (unsigned Type
,
1148 void **Result1
, void **Result2
, void **Result3
,
1149 Coord X
, Coord Y
, Coord Radius
)
1152 void **pr1
= &r1
, **pr2
= &r2
, **pr3
= &r3
;
1154 double HigherBound
= 0;
1155 int HigherAvail
= NO_TYPE
;
1156 int locked
= Type
& LOCKED_TYPE
;
1157 /* setup variables used by local functions */
1160 SearchRadius
= Radius
;
1163 SearchBox
.X1
= X
- Radius
;
1164 SearchBox
.Y1
= Y
- Radius
;
1165 SearchBox
.X2
= X
+ Radius
;
1166 SearchBox
.Y2
= Y
+ Radius
;
1170 SearchBox
= point_box (X
, Y
);
1173 if (TEST_FLAG (LOCKNAMESFLAG
, PCB
))
1175 Type
&= ~ (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1177 if (TEST_FLAG (HIDENAMESFLAG
, PCB
))
1179 Type
&= ~ELEMENTNAME_TYPE
;
1181 if (TEST_FLAG (ONLYNAMESFLAG
, PCB
))
1183 Type
&= (ELEMENTNAME_TYPE
| TEXT_TYPE
);
1185 if (TEST_FLAG (THINDRAWFLAG
, PCB
) || TEST_FLAG (THINDRAWPOLYFLAG
, PCB
))
1187 Type
&= ~POLYGON_TYPE
;
1190 if (Type
& RATLINE_TYPE
&& PCB
->RatOn
&&
1191 SearchRatLineByLocation (locked
,
1192 (RatType
**) Result1
,
1193 (RatType
**) Result2
,
1194 (RatType
**) Result3
))
1195 return (RATLINE_TYPE
);
1197 if (Type
& VIA_TYPE
&&
1198 SearchViaByLocation (locked
,
1199 (PinType
**) Result1
,
1200 (PinType
**) Result2
, (PinType
**) Result3
))
1203 if (Type
& PIN_TYPE
&&
1204 SearchPinByLocation (locked
,
1205 (ElementType
**) pr1
,
1206 (PinType
**) pr2
, (PinType
**) pr3
))
1207 HigherAvail
= PIN_TYPE
;
1209 if (!HigherAvail
&& Type
& PAD_TYPE
&&
1210 SearchPadByLocation (locked
,
1211 (ElementType
**) pr1
,
1212 (PadType
**) pr2
, (PadType
**) pr3
, false))
1213 HigherAvail
= PAD_TYPE
;
1215 if (!HigherAvail
&& Type
& ELEMENTNAME_TYPE
&&
1216 SearchElementNameByLocation (locked
,
1217 (ElementType
**) pr1
,
1218 (TextType
**) pr2
, (TextType
**) pr3
,
1221 BoxType
*box
= &((TextType
*) r2
)->BoundingBox
;
1222 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1223 HigherAvail
= ELEMENTNAME_TYPE
;
1226 if (!HigherAvail
&& Type
& ELEMENT_TYPE
&&
1227 SearchElementByLocation (locked
,
1228 (ElementType
**) pr1
,
1229 (ElementType
**) pr2
,
1230 (ElementType
**) pr3
, false))
1232 BoxType
*box
= &((ElementType
*) r1
)->BoundingBox
;
1233 HigherBound
= (double) (box
->X2
- box
->X1
) * (double) (box
->Y2
- box
->Y1
);
1234 HigherAvail
= ELEMENT_TYPE
;
1237 for (i
= -1; i
< max_copper_layer
+ 1; i
++)
1240 SearchLayer
= &PCB
->Data
->SILKLAYER
;
1241 else if (i
< max_copper_layer
)
1242 SearchLayer
= LAYER_ON_STACK (i
);
1245 SearchLayer
= &PCB
->Data
->BACKSILKLAYER
;
1246 if (!PCB
->InvisibleObjectsOn
)
1249 if (SearchLayer
->On
)
1251 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1252 Type
& POLYGONPOINT_TYPE
&&
1253 SearchPointByLocation (locked
,
1254 (LayerType
**) Result1
,
1255 (PolygonType
**) Result2
,
1256 (PointType
**) Result3
))
1257 return (POLYGONPOINT_TYPE
);
1259 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1260 Type
& LINEPOINT_TYPE
&&
1261 SearchLinePointByLocation (locked
,
1262 (LayerType
**) Result1
,
1263 (LineType
**) Result2
,
1264 (PointType
**) Result3
))
1265 return (LINEPOINT_TYPE
);
1267 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& LINE_TYPE
1268 && SearchLineByLocation (locked
,
1269 (LayerType
**) Result1
,
1270 (LineType
**) Result2
,
1271 (LineType
**) Result3
))
1274 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 &&
1275 Type
& ARCPOINT_TYPE
&&
1276 SearchArcPointByLocation (locked
,
1277 (LayerType
**) Result1
,
1278 (ArcType
**) Result2
,
1279 (PointType
**) Result3
))
1280 return (ARCPOINT_TYPE
);
1282 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& ARC_TYPE
&&
1283 SearchArcByLocation (locked
,
1284 (LayerType
**) Result1
,
1285 (ArcType
**) Result2
,
1286 (ArcType
**) Result3
))
1289 if ((HigherAvail
& (PIN_TYPE
| PAD_TYPE
)) == 0 && Type
& TEXT_TYPE
1290 && SearchTextByLocation (locked
,
1291 (LayerType
**) Result1
,
1292 (TextType
**) Result2
,
1293 (TextType
**) Result3
))
1296 if (Type
& POLYGON_TYPE
&&
1297 SearchPolygonByLocation (locked
,
1298 (LayerType
**) Result1
,
1299 (PolygonType
**) Result2
,
1300 (PolygonType
**) Result3
))
1305 &(*(PolygonType
**) Result2
)->BoundingBox
;
1307 (double) (box
->X2
- box
->X1
) * (double) (box
->X2
- box
->X1
);
1308 if (HigherBound
< area
)
1311 return (POLYGON_TYPE
);
1314 return (POLYGON_TYPE
);
1318 /* return any previously found objects */
1319 if (HigherAvail
& PIN_TYPE
)
1327 if (HigherAvail
& PAD_TYPE
)
1335 if (HigherAvail
& ELEMENTNAME_TYPE
)
1340 return (ELEMENTNAME_TYPE
);
1343 if (HigherAvail
& ELEMENT_TYPE
)
1348 return (ELEMENT_TYPE
);
1351 /* search the 'invisible objects' last */
1352 if (!PCB
->InvisibleObjectsOn
)
1355 if (Type
& PAD_TYPE
&&
1356 SearchPadByLocation (locked
,
1357 (ElementType
**) Result1
,
1358 (PadType
**) Result2
, (PadType
**) Result3
,
1362 if (Type
& ELEMENTNAME_TYPE
&&
1363 SearchElementNameByLocation (locked
,
1364 (ElementType
**) Result1
,
1365 (TextType
**) Result2
,
1366 (TextType
**) Result3
, true))
1367 return (ELEMENTNAME_TYPE
);
1369 if (Type
& ELEMENT_TYPE
&&
1370 SearchElementByLocation (locked
,
1371 (ElementType
**) Result1
,
1372 (ElementType
**) Result2
,
1373 (ElementType
**) Result3
, true))
1374 return (ELEMENT_TYPE
);
1379 /* ---------------------------------------------------------------------------
1380 * searches for a object by it's unique ID. It doesn't matter if
1381 * the object is visible or not. The search is performed on a PCB, a
1382 * buffer or on the remove list.
1383 * The calling routine passes two pointers to allocated memory for storing
1385 * A type value is returned too which is NO_TYPE if no objects has been found.
1388 SearchObjectByID (DataType
*Base
,
1389 void **Result1
, void **Result2
, void **Result3
, int ID
,
1392 if (type
== LINE_TYPE
|| type
== LINEPOINT_TYPE
)
1394 ALLLINE_LOOP (Base
);
1398 *Result1
= (void *) layer
;
1399 *Result2
= *Result3
= (void *) line
;
1402 if (line
->Point1
.ID
== ID
)
1404 *Result1
= (void *) layer
;
1405 *Result2
= (void *) line
;
1406 *Result3
= (void *) &line
->Point1
;
1407 return (LINEPOINT_TYPE
);
1409 if (line
->Point2
.ID
== ID
)
1411 *Result1
= (void *) layer
;
1412 *Result2
= (void *) line
;
1413 *Result3
= (void *) &line
->Point2
;
1414 return (LINEPOINT_TYPE
);
1419 if (type
== ARC_TYPE
)
1425 *Result1
= (void *) layer
;
1426 *Result2
= *Result3
= (void *) arc
;
1433 if (type
== TEXT_TYPE
)
1435 ALLTEXT_LOOP (Base
);
1439 *Result1
= (void *) layer
;
1440 *Result2
= *Result3
= (void *) text
;
1447 if (type
== POLYGON_TYPE
|| type
== POLYGONPOINT_TYPE
)
1449 ALLPOLYGON_LOOP (Base
);
1451 if (polygon
->ID
== ID
)
1453 *Result1
= (void *) layer
;
1454 *Result2
= *Result3
= (void *) polygon
;
1455 return (POLYGON_TYPE
);
1457 if (type
== POLYGONPOINT_TYPE
)
1458 POLYGONPOINT_LOOP (polygon
);
1460 if (point
->ID
== ID
)
1462 *Result1
= (void *) layer
;
1463 *Result2
= (void *) polygon
;
1464 *Result3
= (void *) point
;
1465 return (POLYGONPOINT_TYPE
);
1472 if (type
== VIA_TYPE
)
1478 *Result1
= *Result2
= *Result3
= (void *) via
;
1485 if (type
== RATLINE_TYPE
|| type
== LINEPOINT_TYPE
)
1491 *Result1
= *Result2
= *Result3
= (void *) line
;
1492 return (RATLINE_TYPE
);
1494 if (line
->Point1
.ID
== ID
)
1496 *Result1
= (void *) NULL
;
1497 *Result2
= (void *) line
;
1498 *Result3
= (void *) &line
->Point1
;
1499 return (LINEPOINT_TYPE
);
1501 if (line
->Point2
.ID
== ID
)
1503 *Result1
= (void *) NULL
;
1504 *Result2
= (void *) line
;
1505 *Result3
= (void *) &line
->Point2
;
1506 return (LINEPOINT_TYPE
);
1512 if (type
== ELEMENT_TYPE
|| type
== PAD_TYPE
|| type
== PIN_TYPE
1513 || type
== ELEMENTLINE_TYPE
|| type
== ELEMENTNAME_TYPE
1514 || type
== ELEMENTARC_TYPE
)
1515 /* check pins and elementnames too */
1516 ELEMENT_LOOP (Base
);
1518 if (element
->ID
== ID
)
1520 *Result1
= *Result2
= *Result3
= (void *) element
;
1521 return (ELEMENT_TYPE
);
1523 if (type
== ELEMENTLINE_TYPE
)
1524 ELEMENTLINE_LOOP (element
);
1528 *Result1
= (void *) element
;
1529 *Result2
= *Result3
= (void *) line
;
1530 return (ELEMENTLINE_TYPE
);
1534 if (type
== ELEMENTARC_TYPE
)
1539 *Result1
= (void *) element
;
1540 *Result2
= *Result3
= (void *) arc
;
1541 return (ELEMENTARC_TYPE
);
1545 if (type
== ELEMENTNAME_TYPE
)
1546 ELEMENTTEXT_LOOP (element
);
1550 *Result1
= (void *) element
;
1551 *Result2
= *Result3
= (void *) text
;
1552 return (ELEMENTNAME_TYPE
);
1556 if (type
== PIN_TYPE
)
1561 *Result1
= (void *) element
;
1562 *Result2
= *Result3
= (void *) pin
;
1567 if (type
== PAD_TYPE
)
1572 *Result1
= (void *) element
;
1573 *Result2
= *Result3
= (void *) pad
;
1581 Message ("hace: Internal error, search for ID %d failed\n", ID
);
1585 /* ---------------------------------------------------------------------------
1586 * searches for an element by its board name.
1587 * The function returns a pointer to the element, NULL if not found
1590 SearchElementByName (DataType
*Base
, char *Name
)
1592 ElementType
*result
= NULL
;
1594 ELEMENT_LOOP (Base
);
1596 if (element
->Name
[1].TextString
&&
1597 NSTRCMP (element
->Name
[1].TextString
, Name
) == 0)
1607 /* ---------------------------------------------------------------------------
1608 * searches the cursor position for the type
1611 SearchScreen (Coord X
, Coord Y
, int Type
, void **Result1
,
1612 void **Result2
, void **Result3
)
1616 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1617 X
, Y
, SLOP
* pixel_slop
);
1621 /* ---------------------------------------------------------------------------
1622 * searches the cursor position for the type
1625 SearchScreenGridSlop (Coord X
, Coord Y
, int Type
, void **Result1
,
1626 void **Result2
, void **Result3
)
1630 ans
= SearchObjectByLocation (Type
, Result1
, Result2
, Result3
,
1631 X
, Y
, PCB
->Grid
/ 2);