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
28 /* functions used by 'rubberband moves'
52 #include "rubberband.h"
56 #ifdef HAVE_LIBDMALLOC
60 /* ---------------------------------------------------------------------------
61 * some local prototypes
63 static void CheckPadForRubberbandConnection (PadType
*);
64 static void CheckPinForRubberbandConnection (PinType
*);
65 static void CheckLinePointForRubberbandConnection (LayerType
*,
69 static void CheckPolygonForRubberbandConnection (LayerType
*,
71 static void CheckLinePointForRat (LayerType
*, PointType
*);
72 static int rubber_callback (const BoxType
* b
, void *cl
);
84 rubber_callback (const BoxType
* b
, void *cl
)
86 LineType
*line
= (LineType
*) b
;
87 struct rubber_info
*i
= (struct rubber_info
*) cl
;
88 double x
, y
, rad
, dist1
, dist2
;
92 t
= line
->Thickness
/ 2;
94 if (TEST_FLAG (LOCKFLAG
, line
))
99 * Check to see if the line touches a rectangular region.
100 * To do this we need to look for the intersection of a circular
101 * region and a rectangular region.
107 if (line
->Point1
.X
+ t
>= i
->box
.X1
&& line
->Point1
.X
- t
<= i
->box
.X2
108 && line
->Point1
.Y
+ t
>= i
->box
.Y1
109 && line
->Point1
.Y
- t
<= i
->box
.Y2
)
111 if (((i
->box
.X1
<= line
->Point1
.X
) &&
112 (line
->Point1
.X
<= i
->box
.X2
)) ||
113 ((i
->box
.Y1
<= line
->Point1
.Y
) &&
114 (line
->Point1
.Y
<= i
->box
.Y2
)))
117 * The circle is positioned such that the closest point
118 * on the rectangular region boundary is not at a corner
119 * of the rectangle. i.e. the shortest line from circle
120 * center to rectangle intersects the rectangle at 90
121 * degrees. In this case our first test is sufficient
128 * Now we must check the distance from the center of the
129 * circle to the corners of the rectangle since the
130 * closest part of the rectangular region is the corner.
132 x
= MIN (abs (i
->box
.X1
- line
->Point1
.X
),
133 abs (i
->box
.X2
- line
->Point1
.X
));
135 y
= MIN (abs (i
->box
.Y1
- line
->Point1
.Y
),
136 abs (i
->box
.Y2
- line
->Point1
.Y
));
145 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
149 if (line
->Point2
.X
+ t
>= i
->box
.X1
&& line
->Point2
.X
- t
<= i
->box
.X2
150 && line
->Point2
.Y
+ t
>= i
->box
.Y1
151 && line
->Point2
.Y
- t
<= i
->box
.Y2
)
153 if (((i
->box
.X1
<= line
->Point2
.X
) &&
154 (line
->Point2
.X
<= i
->box
.X2
)) ||
155 ((i
->box
.Y1
<= line
->Point2
.Y
) &&
156 (line
->Point2
.Y
<= i
->box
.Y2
)))
162 x
= MIN (abs (i
->box
.X1
- line
->Point2
.X
),
163 abs (i
->box
.X2
- line
->Point2
.X
));
165 y
= MIN (abs (i
->box
.Y1
- line
->Point2
.Y
),
166 abs (i
->box
.Y2
- line
->Point2
.Y
));
175 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
181 /* circular search region */
183 rad
= 0; /* require exact match */
185 rad
= SQUARE(i
->radius
+ t
);
187 x
= (i
->X
- line
->Point1
.X
);
189 y
= (i
->Y
- line
->Point1
.Y
);
193 x
= (i
->X
- line
->Point2
.X
);
195 y
= (i
->Y
- line
->Point2
.Y
);
199 if (dist1
> 0 && dist2
> 0)
202 #ifdef CLOSEST_ONLY /* keep this to remind me */
204 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
206 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
209 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
211 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
216 /* ---------------------------------------------------------------------------
217 * checks all visible lines which belong to the same layergroup as the
218 * passed pad. If one of the endpoints of the line lays inside the pad,
219 * the line is added to the 'rubberband' list
222 CheckPadForRubberbandConnection (PadType
*Pad
)
224 Coord half
= Pad
->Thickness
/ 2;
226 struct rubber_info info
;
228 info
.box
.X1
= MIN (Pad
->Point1
.X
, Pad
->Point2
.X
) - half
;
229 info
.box
.Y1
= MIN (Pad
->Point1
.Y
, Pad
->Point2
.Y
) - half
;
230 info
.box
.X2
= MAX (Pad
->Point1
.X
, Pad
->Point2
.X
) + half
;
231 info
.box
.Y2
= MAX (Pad
->Point1
.Y
, Pad
->Point2
.Y
) + half
;
234 i
= TEST_FLAG (ONSOLDERFLAG
, Pad
) ? solder_silk_layer
: component_silk_layer
;
235 group
= GetLayerGroupNumberByNumber (i
);
237 /* check all visible layers in the same group */
238 GROUP_LOOP (PCB
->Data
, group
);
240 /* check all visible lines of the group member */
244 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
261 rat_callback (const BoxType
* box
, void *cl
)
263 RatType
*rat
= (RatType
*) box
;
264 struct rinfo
*i
= (struct rinfo
*) cl
;
269 if (rat
->Point1
.X
== i
->pin
->X
&& rat
->Point1
.Y
== i
->pin
->Y
)
270 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point1
);
271 else if (rat
->Point2
.X
== i
->pin
->X
&& rat
->Point2
.Y
== i
->pin
->Y
)
272 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point2
);
275 if (rat
->Point1
.X
== i
->pad
->Point1
.X
&&
276 rat
->Point1
.Y
== i
->pad
->Point1
.Y
&& rat
->group1
== i
->group
)
277 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point1
);
279 if (rat
->Point2
.X
== i
->pad
->Point1
.X
&&
280 rat
->Point2
.Y
== i
->pad
->Point1
.Y
&& rat
->group2
== i
->group
)
281 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point2
);
283 if (rat
->Point1
.X
== i
->pad
->Point2
.X
&&
284 rat
->Point1
.Y
== i
->pad
->Point2
.Y
&& rat
->group1
== i
->group
)
285 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point1
);
287 if (rat
->Point2
.X
== i
->pad
->Point2
.X
&&
288 rat
->Point2
.Y
== i
->pad
->Point2
.Y
&& rat
->group2
== i
->group
)
289 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point2
);
291 if (rat
->Point1
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
292 rat
->Point1
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
293 rat
->group1
== i
->group
)
294 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point1
);
296 if (rat
->Point2
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
297 rat
->Point2
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
298 rat
->group2
== i
->group
)
299 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point2
);
302 if (rat
->group1
== i
->group
&&
303 rat
->Point1
.X
== i
->point
->X
&& rat
->Point1
.Y
== i
->point
->Y
)
304 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point1
);
306 if (rat
->group2
== i
->group
&&
307 rat
->Point2
.X
== i
->point
->X
&& rat
->Point2
.Y
== i
->point
->Y
)
308 CreateNewRubberbandEntry (NULL
, (LineType
*) rat
, &rat
->Point2
);
311 Message ("hace: bad rubber-rat lookup callback\n");
317 CheckPadForRat (PadType
*Pad
)
322 i
= TEST_FLAG (ONSOLDERFLAG
, Pad
) ? solder_silk_layer
: component_silk_layer
;
323 info
.group
= GetLayerGroupNumberByNumber (i
);
325 info
.type
= PAD_TYPE
;
327 r_search (PCB
->Data
->rat_tree
, &Pad
->BoundingBox
, NULL
, rat_callback
,
332 CheckPinForRat (PinType
*Pin
)
336 info
.type
= PIN_TYPE
;
338 r_search (PCB
->Data
->rat_tree
, &Pin
->BoundingBox
, NULL
, rat_callback
,
343 CheckLinePointForRat (LayerType
*Layer
, PointType
*Point
)
346 info
.group
= GetLayerGroupNumberByPointer (Layer
);
348 info
.type
= LINEPOINT_TYPE
;
350 r_search (PCB
->Data
->rat_tree
, (BoxType
*) Point
, NULL
, rat_callback
,
354 /* ---------------------------------------------------------------------------
355 * checks all visible lines. If one of the endpoints of the line lays
356 * inside the pin, the line is added to the 'rubberband' list
358 * Square pins are handled as if they were round. Speed
359 * and readability is more important then the few %
360 * of failures that are immediately recognized
363 CheckPinForRubberbandConnection (PinType
*Pin
)
365 struct rubber_info info
;
367 Coord t
= Pin
->Thickness
/ 2;
369 info
.box
.X1
= Pin
->X
- t
;
370 info
.box
.X2
= Pin
->X
+ t
;
371 info
.box
.Y1
= Pin
->Y
- t
;
372 info
.box
.Y2
= Pin
->Y
+ t
;
374 if (TEST_FLAG (SQUAREFLAG
, Pin
))
383 for (n
= 0; n
< max_copper_layer
; n
++)
385 info
.layer
= LAYER_PTR (n
);
386 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
391 /* ---------------------------------------------------------------------------
392 * checks all visible lines which belong to the same group as the passed line.
393 * If one of the endpoints of the line lays * inside the passed line,
394 * the scanned line is added to the 'rubberband' list
397 CheckLinePointForRubberbandConnection (LayerType
*Layer
,
399 PointType
*LinePoint
,
403 struct rubber_info info
;
404 Coord t
= Line
->Thickness
/ 2;
406 /* lookup layergroup and check all visible lines in this group */
407 info
.radius
= Exact
? -1 : MAX(Line
->Thickness
/ 2, 1);
408 info
.box
.X1
= LinePoint
->X
- t
;
409 info
.box
.X2
= LinePoint
->X
+ t
;
410 info
.box
.Y1
= LinePoint
->Y
- t
;
411 info
.box
.Y2
= LinePoint
->Y
+ t
;
413 info
.X
= LinePoint
->X
;
414 info
.Y
= LinePoint
->Y
;
415 group
= GetLayerGroupNumberByPointer (Layer
);
416 GROUP_LOOP (PCB
->Data
, group
);
418 /* check all visible lines of the group member */
422 r_search (layer
->line_tree
, &info
.box
, NULL
, rubber_callback
, &info
);
428 /* ---------------------------------------------------------------------------
429 * checks all visible lines which belong to the same group as the passed polygon.
430 * If one of the endpoints of the line lays inside the passed polygon,
431 * the scanned line is added to the 'rubberband' list
434 CheckPolygonForRubberbandConnection (LayerType
*Layer
,
435 PolygonType
*Polygon
)
439 /* lookup layergroup and check all visible lines in this group */
440 group
= GetLayerGroupNumberByPointer (Layer
);
441 GROUP_LOOP (PCB
->Data
, group
);
447 /* the following code just stupidly compares the endpoints
452 if (TEST_FLAG (LOCKFLAG
, line
))
454 if (TEST_FLAG (CLEARLINEFLAG
, line
))
456 thick
= (line
->Thickness
+ 1) / 2;
457 if (IsPointInPolygon (line
->Point1
.X
, line
->Point1
.Y
,
459 CreateNewRubberbandEntry (layer
, line
, &line
->Point1
);
460 if (IsPointInPolygon (line
->Point2
.X
, line
->Point2
.Y
,
462 CreateNewRubberbandEntry (layer
, line
, &line
->Point2
);
470 /* ---------------------------------------------------------------------------
471 * lookup all lines that are connected to an object and save the
472 * data to 'Crosshair.AttachedObject.Rubberband'
473 * lookup is only done for visible layers
476 LookupRubberbandLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
479 /* the function is only supported for some types
480 * check all visible lines;
481 * it is only necessary to check if one of the endpoints
488 ElementType
*element
= (ElementType
*) Ptr1
;
490 /* square pins are handled as if they are round. Speed
491 * and readability is more important then the few %
492 * of failures that are immediately recognized
496 CheckPinForRubberbandConnection (pin
);
501 CheckPadForRubberbandConnection (pad
);
509 LayerType
*layer
= (LayerType
*) Ptr1
;
510 LineType
*line
= (LineType
*) Ptr2
;
511 if (GetLayerNumber (PCB
->Data
, layer
) < max_copper_layer
)
513 CheckLinePointForRubberbandConnection (layer
, line
,
514 &line
->Point1
, false);
515 CheckLinePointForRubberbandConnection (layer
, line
,
516 &line
->Point2
, false);
522 if (GetLayerNumber (PCB
->Data
, (LayerType
*) Ptr1
) < max_copper_layer
)
523 CheckLinePointForRubberbandConnection ((LayerType
*) Ptr1
,
525 (PointType
*) Ptr3
, true);
529 CheckPinForRubberbandConnection ((PinType
*) Ptr1
);
533 if (GetLayerNumber (PCB
->Data
, (LayerType
*) Ptr1
) < max_copper_layer
)
534 CheckPolygonForRubberbandConnection ((LayerType
*) Ptr1
,
535 (PolygonType
*) Ptr2
);
541 LookupRatLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
547 ElementType
*element
= (ElementType
*) Ptr1
;
551 CheckPinForRat (pin
);
556 CheckPadForRat (pad
);
564 LayerType
*layer
= (LayerType
*) Ptr1
;
565 LineType
*line
= (LineType
*) Ptr2
;
567 CheckLinePointForRat (layer
, &line
->Point1
);
568 CheckLinePointForRat (layer
, &line
->Point2
);
573 CheckLinePointForRat ((LayerType
*) Ptr1
, (PointType
*) Ptr3
);
577 CheckPinForRat ((PinType
*) Ptr1
);