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
30 /* functions used by 'rubberband moves'
54 #include "rubberband.h"
58 #ifdef HAVE_LIBDMALLOC
65 /* ---------------------------------------------------------------------------
66 * some local prototypes
68 static void CheckPadForRubberbandConnection (PadTypePtr
);
69 static void CheckPinForRubberbandConnection (PinTypePtr
);
70 static void CheckLinePointForRubberbandConnection (LayerTypePtr
,
74 static void CheckPolygonForRubberbandConnection (LayerTypePtr
,
76 static void CheckLinePointForRat (LayerTypePtr
, PointTypePtr
);
77 static int rubber_callback (const BoxType
* b
, void *cl
);
89 rubber_callback (const BoxType
* b
, void *cl
)
91 LineTypePtr line
= (LineTypePtr
) b
;
92 struct rubber_info
*i
= (struct rubber_info
*) cl
;
93 float x
, y
, rad
, dist1
, dist2
;
97 t
= line
->Thickness
/ 2;
99 if (TEST_FLAG (LOCKFLAG
, line
))
104 * Check to see if the line touches a rectangular region.
105 * To do this we need to look for the intersection of a circular
106 * region and a rectangular region.
112 if (line
->Point1
.X
+ t
>= i
->box
.X1
&& line
->Point1
.X
- t
<= i
->box
.X2
113 && line
->Point1
.Y
+ t
>= i
->box
.Y1
114 && line
->Point1
.Y
- t
<= i
->box
.Y2
)
116 if (((i
->box
.X1
<= line
->Point1
.X
) &&
117 (line
->Point1
.X
<= i
->box
.X2
)) ||
118 ((i
->box
.Y1
<= line
->Point1
.Y
) &&
119 (line
->Point1
.Y
<= i
->box
.Y2
)))
122 * The circle is positioned such that the closest point
123 * on the rectangular region boundary is not at a corner
124 * of the rectangle. i.e. the shortest line from circle
125 * center to rectangle intersects the rectangle at 90
126 * degrees. In this case our first test is sufficient
133 * Now we must check the distance from the center of the
134 * circle to the corners of the rectangle since the
135 * closest part of the rectangular region is the corner.
137 x
= MIN (abs (i
->box
.X1
- line
->Point1
.X
),
138 abs (i
->box
.X2
- line
->Point1
.X
));
140 y
= MIN (abs (i
->box
.Y1
- line
->Point1
.Y
),
141 abs (i
->box
.Y2
- line
->Point1
.Y
));
150 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
154 if (line
->Point2
.X
+ t
>= i
->box
.X1
&& line
->Point2
.X
- t
<= i
->box
.X2
155 && line
->Point2
.Y
+ t
>= i
->box
.Y1
156 && line
->Point2
.Y
- t
<= i
->box
.Y2
)
158 if (((i
->box
.X1
<= line
->Point2
.X
) &&
159 (line
->Point2
.X
<= i
->box
.X2
)) ||
160 ((i
->box
.Y1
<= line
->Point2
.Y
) &&
161 (line
->Point2
.Y
<= i
->box
.Y2
)))
167 x
= MIN (abs (i
->box
.X1
- line
->Point2
.X
),
168 abs (i
->box
.X2
- line
->Point2
.X
));
170 y
= MIN (abs (i
->box
.Y1
- line
->Point2
.Y
),
171 abs (i
->box
.Y2
- line
->Point2
.Y
));
180 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
186 /* circular search region */
188 rad
= 0; /* require exact match */
190 rad
= SQUARE(i
->radius
+ t
);
192 x
= (i
->X
- line
->Point1
.X
);
194 y
= (i
->Y
- line
->Point1
.Y
);
198 x
= (i
->X
- line
->Point2
.X
);
200 y
= (i
->Y
- line
->Point2
.Y
);
204 if (dist1
> 0 && dist2
> 0)
207 #ifdef CLOSEST_ONLY /* keep this to remind me */
209 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
211 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
214 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point1
);
216 CreateNewRubberbandEntry (i
->layer
, line
, &line
->Point2
);
221 /* ---------------------------------------------------------------------------
222 * checks all visible lines which belong to the same layergroup as the
223 * passed pad. If one of the endpoints of the line lays inside the pad,
224 * the line is added to the 'rubberband' list
227 CheckPadForRubberbandConnection (PadTypePtr Pad
)
229 BDimension half
= Pad
->Thickness
/ 2;
231 struct rubber_info info
;
233 info
.box
.X1
= MIN (Pad
->Point1
.X
, Pad
->Point2
.X
) - half
;
234 info
.box
.Y1
= MIN (Pad
->Point1
.Y
, Pad
->Point2
.Y
) - half
;
235 info
.box
.X2
= MAX (Pad
->Point1
.X
, Pad
->Point2
.X
) + half
;
236 info
.box
.Y2
= MAX (Pad
->Point1
.Y
, Pad
->Point2
.Y
) + half
;
240 (TEST_FLAG (ONSOLDERFLAG
, Pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
);
241 group
= GetLayerGroupNumberByNumber (i
);
243 /* check all visible layers in the same group */
244 GROUP_LOOP (PCB
->Data
, group
);
246 /* check all visible lines of the group member */
250 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
267 rat_callback (const BoxType
* box
, void *cl
)
269 RatTypePtr rat
= (RatTypePtr
) box
;
270 struct rinfo
*i
= (struct rinfo
*) cl
;
275 if (rat
->Point1
.X
== i
->pin
->X
&& rat
->Point1
.Y
== i
->pin
->Y
)
276 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
277 else if (rat
->Point2
.X
== i
->pin
->X
&& rat
->Point2
.Y
== i
->pin
->Y
)
278 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
281 if (rat
->Point1
.X
== i
->pad
->Point1
.X
&&
282 rat
->Point1
.Y
== i
->pad
->Point1
.Y
&& rat
->group1
== i
->group
)
283 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
285 if (rat
->Point2
.X
== i
->pad
->Point1
.X
&&
286 rat
->Point2
.Y
== i
->pad
->Point1
.Y
&& rat
->group2
== i
->group
)
287 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
289 if (rat
->Point1
.X
== i
->pad
->Point2
.X
&&
290 rat
->Point1
.Y
== i
->pad
->Point2
.Y
&& rat
->group1
== i
->group
)
291 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
293 if (rat
->Point2
.X
== i
->pad
->Point2
.X
&&
294 rat
->Point2
.Y
== i
->pad
->Point2
.Y
&& rat
->group2
== i
->group
)
295 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
297 if (rat
->Point1
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
298 rat
->Point1
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
299 rat
->group1
== i
->group
)
300 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
302 if (rat
->Point2
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
303 rat
->Point2
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
304 rat
->group2
== i
->group
)
305 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
308 if (rat
->group1
== i
->group
&&
309 rat
->Point1
.X
== i
->point
->X
&& rat
->Point1
.Y
== i
->point
->Y
)
310 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
312 if (rat
->group2
== i
->group
&&
313 rat
->Point2
.X
== i
->point
->X
&& rat
->Point2
.Y
== i
->point
->Y
)
314 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
317 Message ("hace: bad rubber-rat lookup callback\n");
323 CheckPadForRat (PadTypePtr Pad
)
329 (TEST_FLAG (ONSOLDERFLAG
, Pad
) ? SOLDER_LAYER
: COMPONENT_LAYER
);
330 info
.group
= GetLayerGroupNumberByNumber (i
);
332 info
.type
= PAD_TYPE
;
334 r_search (PCB
->Data
->rat_tree
, &Pad
->BoundingBox
, NULL
, rat_callback
,
339 CheckPinForRat (PinTypePtr Pin
)
343 info
.type
= PIN_TYPE
;
345 r_search (PCB
->Data
->rat_tree
, &Pin
->BoundingBox
, NULL
, rat_callback
,
350 CheckLinePointForRat (LayerTypePtr Layer
, PointTypePtr Point
)
353 info
.group
= GetLayerGroupNumberByPointer (Layer
);
355 info
.type
= LINEPOINT_TYPE
;
357 r_search (PCB
->Data
->rat_tree
, (BoxType
*) Point
, NULL
, rat_callback
,
361 /* ---------------------------------------------------------------------------
362 * checks all visible lines. If one of the endpoints of the line lays
363 * inside the pin, the line is added to the 'rubberband' list
365 * Square pins are handled as if they were round. Speed
366 * and readability is more important then the few %
367 * of failures that are immediately recognized
370 CheckPinForRubberbandConnection (PinTypePtr Pin
)
372 struct rubber_info info
;
374 BDimension t
= Pin
->Thickness
/ 2;
376 info
.box
.X1
= Pin
->X
- t
;
377 info
.box
.X2
= Pin
->X
+ t
;
378 info
.box
.Y1
= Pin
->Y
- t
;
379 info
.box
.Y2
= Pin
->Y
+ t
;
381 if (TEST_FLAG (SQUAREFLAG
, Pin
))
390 for (n
= 0; n
< max_layer
; n
++)
392 info
.layer
= LAYER_PTR (n
);
393 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
398 /* ---------------------------------------------------------------------------
399 * checks all visible lines which belong to the same group as the passed line.
400 * If one of the endpoints of the line lays * inside the passed line,
401 * the scanned line is added to the 'rubberband' list
404 CheckLinePointForRubberbandConnection (LayerTypePtr Layer
,
406 PointTypePtr LinePoint
,
410 struct rubber_info info
;
411 BDimension t
= Line
->Thickness
/ 2;
413 /* lookup layergroup and check all visible lines in this group */
414 info
.radius
= Exact
? -1 : MAX(Line
->Thickness
/ 2, 1);
415 info
.box
.X1
= LinePoint
->X
- t
;
416 info
.box
.X2
= LinePoint
->X
+ t
;
417 info
.box
.Y1
= LinePoint
->Y
- t
;
418 info
.box
.Y2
= LinePoint
->Y
+ t
;
420 info
.X
= LinePoint
->X
;
421 info
.Y
= LinePoint
->Y
;
422 group
= GetLayerGroupNumberByPointer (Layer
);
423 GROUP_LOOP (PCB
->Data
, group
);
425 /* check all visible lines of the group member */
429 r_search (layer
->line_tree
, &info
.box
, NULL
, rubber_callback
, &info
);
435 /* ---------------------------------------------------------------------------
436 * checks all visible lines which belong to the same group as the passed polygon.
437 * If one of the endpoints of the line lays inside the passed polygon,
438 * the scanned line is added to the 'rubberband' list
441 CheckPolygonForRubberbandConnection (LayerTypePtr Layer
,
442 PolygonTypePtr Polygon
)
446 /* lookup layergroup and check all visible lines in this group */
447 group
= GetLayerGroupNumberByPointer (Layer
);
448 GROUP_LOOP (PCB
->Data
, group
);
454 /* the following code just stupidly compares the endpoints
459 if (TEST_FLAG (LOCKFLAG
, line
))
461 if (TEST_FLAG (CLEARLINEFLAG
, line
))
463 thick
= (line
->Thickness
+ 1) / 2;
464 if (IsPointInPolygon (line
->Point1
.X
, line
->Point1
.Y
,
466 CreateNewRubberbandEntry (layer
, line
, &line
->Point1
);
467 if (IsPointInPolygon (line
->Point2
.X
, line
->Point2
.Y
,
469 CreateNewRubberbandEntry (layer
, line
, &line
->Point2
);
477 /* ---------------------------------------------------------------------------
478 * lookup all lines that are connected to an object and save the
479 * data to 'Crosshair.AttachedObject.Rubberband'
480 * lookup is only done for visible layers
483 LookupRubberbandLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
486 /* the function is only supported for some types
487 * check all visible lines;
488 * it is only necessary to check if one of the endpoints
495 ElementTypePtr element
= (ElementTypePtr
) Ptr1
;
497 /* square pins are handled as if they are round. Speed
498 * and readability is more important then the few %
499 * of failures that are immediately recognized
503 CheckPinForRubberbandConnection (pin
);
508 CheckPadForRubberbandConnection (pad
);
516 LayerTypePtr layer
= (LayerTypePtr
) Ptr1
;
517 LineTypePtr line
= (LineTypePtr
) Ptr2
;
518 if (GetLayerNumber (PCB
->Data
, layer
) < max_layer
)
520 CheckLinePointForRubberbandConnection (layer
, line
,
521 &line
->Point1
, false);
522 CheckLinePointForRubberbandConnection (layer
, line
,
523 &line
->Point2
, false);
529 if (GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
) < max_layer
)
530 CheckLinePointForRubberbandConnection ((LayerTypePtr
) Ptr1
,
532 (PointTypePtr
) Ptr3
, true);
536 CheckPinForRubberbandConnection ((PinTypePtr
) Ptr1
);
540 if (GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
) < max_layer
)
541 CheckPolygonForRubberbandConnection ((LayerTypePtr
) Ptr1
,
542 (PolygonTypePtr
) Ptr2
);
548 LookupRatLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
554 ElementTypePtr element
= (ElementTypePtr
) Ptr1
;
558 CheckPinForRat (pin
);
563 CheckPadForRat (pad
);
571 LayerTypePtr layer
= (LayerTypePtr
) Ptr1
;
572 LineTypePtr line
= (LineTypePtr
) Ptr2
;
574 CheckLinePointForRat (layer
, &line
->Point1
);
575 CheckLinePointForRat (layer
, &line
->Point2
);
580 CheckLinePointForRat ((LayerTypePtr
) Ptr1
, (PointTypePtr
) Ptr3
);
584 CheckPinForRat ((PinTypePtr
) Ptr1
);