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 double 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 Coord 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
;
239 i
= TEST_FLAG (ONSOLDERFLAG
, Pad
) ? solder_silk_layer
: component_silk_layer
;
240 group
= GetLayerGroupNumberByNumber (i
);
242 /* check all visible layers in the same group */
243 GROUP_LOOP (PCB
->Data
, group
);
245 /* check all visible lines of the group member */
249 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
266 rat_callback (const BoxType
* box
, void *cl
)
268 RatTypePtr rat
= (RatTypePtr
) box
;
269 struct rinfo
*i
= (struct rinfo
*) cl
;
274 if (rat
->Point1
.X
== i
->pin
->X
&& rat
->Point1
.Y
== i
->pin
->Y
)
275 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
276 else if (rat
->Point2
.X
== i
->pin
->X
&& rat
->Point2
.Y
== i
->pin
->Y
)
277 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
280 if (rat
->Point1
.X
== i
->pad
->Point1
.X
&&
281 rat
->Point1
.Y
== i
->pad
->Point1
.Y
&& rat
->group1
== i
->group
)
282 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
284 if (rat
->Point2
.X
== i
->pad
->Point1
.X
&&
285 rat
->Point2
.Y
== i
->pad
->Point1
.Y
&& rat
->group2
== i
->group
)
286 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
288 if (rat
->Point1
.X
== i
->pad
->Point2
.X
&&
289 rat
->Point1
.Y
== i
->pad
->Point2
.Y
&& rat
->group1
== i
->group
)
290 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
292 if (rat
->Point2
.X
== i
->pad
->Point2
.X
&&
293 rat
->Point2
.Y
== i
->pad
->Point2
.Y
&& rat
->group2
== i
->group
)
294 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
296 if (rat
->Point1
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
297 rat
->Point1
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
298 rat
->group1
== i
->group
)
299 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
301 if (rat
->Point2
.X
== (i
->pad
->Point1
.X
+ i
->pad
->Point2
.X
) / 2 &&
302 rat
->Point2
.Y
== (i
->pad
->Point1
.Y
+ i
->pad
->Point2
.Y
) / 2 &&
303 rat
->group2
== i
->group
)
304 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
307 if (rat
->group1
== i
->group
&&
308 rat
->Point1
.X
== i
->point
->X
&& rat
->Point1
.Y
== i
->point
->Y
)
309 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point1
);
311 if (rat
->group2
== i
->group
&&
312 rat
->Point2
.X
== i
->point
->X
&& rat
->Point2
.Y
== i
->point
->Y
)
313 CreateNewRubberbandEntry (NULL
, (LineTypePtr
) rat
, &rat
->Point2
);
316 Message ("hace: bad rubber-rat lookup callback\n");
322 CheckPadForRat (PadTypePtr Pad
)
327 i
= TEST_FLAG (ONSOLDERFLAG
, Pad
) ? solder_silk_layer
: component_silk_layer
;
328 info
.group
= GetLayerGroupNumberByNumber (i
);
330 info
.type
= PAD_TYPE
;
332 r_search (PCB
->Data
->rat_tree
, &Pad
->BoundingBox
, NULL
, rat_callback
,
337 CheckPinForRat (PinTypePtr Pin
)
341 info
.type
= PIN_TYPE
;
343 r_search (PCB
->Data
->rat_tree
, &Pin
->BoundingBox
, NULL
, rat_callback
,
348 CheckLinePointForRat (LayerTypePtr Layer
, PointTypePtr Point
)
351 info
.group
= GetLayerGroupNumberByPointer (Layer
);
353 info
.type
= LINEPOINT_TYPE
;
355 r_search (PCB
->Data
->rat_tree
, (BoxType
*) Point
, NULL
, rat_callback
,
359 /* ---------------------------------------------------------------------------
360 * checks all visible lines. If one of the endpoints of the line lays
361 * inside the pin, the line is added to the 'rubberband' list
363 * Square pins are handled as if they were round. Speed
364 * and readability is more important then the few %
365 * of failures that are immediately recognized
368 CheckPinForRubberbandConnection (PinTypePtr Pin
)
370 struct rubber_info info
;
372 Coord t
= Pin
->Thickness
/ 2;
374 info
.box
.X1
= Pin
->X
- t
;
375 info
.box
.X2
= Pin
->X
+ t
;
376 info
.box
.Y1
= Pin
->Y
- t
;
377 info
.box
.Y2
= Pin
->Y
+ t
;
379 if (TEST_FLAG (SQUAREFLAG
, Pin
))
388 for (n
= 0; n
< max_copper_layer
; n
++)
390 info
.layer
= LAYER_PTR (n
);
391 r_search (info
.layer
->line_tree
, &info
.box
, NULL
, rubber_callback
,
396 /* ---------------------------------------------------------------------------
397 * checks all visible lines which belong to the same group as the passed line.
398 * If one of the endpoints of the line lays * inside the passed line,
399 * the scanned line is added to the 'rubberband' list
402 CheckLinePointForRubberbandConnection (LayerTypePtr Layer
,
404 PointTypePtr LinePoint
,
408 struct rubber_info info
;
409 Coord t
= Line
->Thickness
/ 2;
411 /* lookup layergroup and check all visible lines in this group */
412 info
.radius
= Exact
? -1 : MAX(Line
->Thickness
/ 2, 1);
413 info
.box
.X1
= LinePoint
->X
- t
;
414 info
.box
.X2
= LinePoint
->X
+ t
;
415 info
.box
.Y1
= LinePoint
->Y
- t
;
416 info
.box
.Y2
= LinePoint
->Y
+ t
;
418 info
.X
= LinePoint
->X
;
419 info
.Y
= LinePoint
->Y
;
420 group
= GetLayerGroupNumberByPointer (Layer
);
421 GROUP_LOOP (PCB
->Data
, group
);
423 /* check all visible lines of the group member */
427 r_search (layer
->line_tree
, &info
.box
, NULL
, rubber_callback
, &info
);
433 /* ---------------------------------------------------------------------------
434 * checks all visible lines which belong to the same group as the passed polygon.
435 * If one of the endpoints of the line lays inside the passed polygon,
436 * the scanned line is added to the 'rubberband' list
439 CheckPolygonForRubberbandConnection (LayerTypePtr Layer
,
440 PolygonTypePtr Polygon
)
444 /* lookup layergroup and check all visible lines in this group */
445 group
= GetLayerGroupNumberByPointer (Layer
);
446 GROUP_LOOP (PCB
->Data
, group
);
452 /* the following code just stupidly compares the endpoints
457 if (TEST_FLAG (LOCKFLAG
, line
))
459 if (TEST_FLAG (CLEARLINEFLAG
, line
))
461 thick
= (line
->Thickness
+ 1) / 2;
462 if (IsPointInPolygon (line
->Point1
.X
, line
->Point1
.Y
,
464 CreateNewRubberbandEntry (layer
, line
, &line
->Point1
);
465 if (IsPointInPolygon (line
->Point2
.X
, line
->Point2
.Y
,
467 CreateNewRubberbandEntry (layer
, line
, &line
->Point2
);
475 /* ---------------------------------------------------------------------------
476 * lookup all lines that are connected to an object and save the
477 * data to 'Crosshair.AttachedObject.Rubberband'
478 * lookup is only done for visible layers
481 LookupRubberbandLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
484 /* the function is only supported for some types
485 * check all visible lines;
486 * it is only necessary to check if one of the endpoints
493 ElementTypePtr element
= (ElementTypePtr
) Ptr1
;
495 /* square pins are handled as if they are round. Speed
496 * and readability is more important then the few %
497 * of failures that are immediately recognized
501 CheckPinForRubberbandConnection (pin
);
506 CheckPadForRubberbandConnection (pad
);
514 LayerTypePtr layer
= (LayerTypePtr
) Ptr1
;
515 LineTypePtr line
= (LineTypePtr
) Ptr2
;
516 if (GetLayerNumber (PCB
->Data
, layer
) < max_copper_layer
)
518 CheckLinePointForRubberbandConnection (layer
, line
,
519 &line
->Point1
, false);
520 CheckLinePointForRubberbandConnection (layer
, line
,
521 &line
->Point2
, false);
527 if (GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
) < max_copper_layer
)
528 CheckLinePointForRubberbandConnection ((LayerTypePtr
) Ptr1
,
530 (PointTypePtr
) Ptr3
, true);
534 CheckPinForRubberbandConnection ((PinTypePtr
) Ptr1
);
538 if (GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
) < max_copper_layer
)
539 CheckPolygonForRubberbandConnection ((LayerTypePtr
) Ptr1
,
540 (PolygonTypePtr
) Ptr2
);
546 LookupRatLines (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
552 ElementTypePtr element
= (ElementTypePtr
) Ptr1
;
556 CheckPinForRat (pin
);
561 CheckPadForRat (pad
);
569 LayerTypePtr layer
= (LayerTypePtr
) Ptr1
;
570 LineTypePtr line
= (LineTypePtr
) Ptr2
;
572 CheckLinePointForRat (layer
, &line
->Point1
);
573 CheckLinePointForRat (layer
, &line
->Point2
);
578 CheckLinePointForRat ((LayerTypePtr
) Ptr1
, (PointTypePtr
) Ptr3
);
582 CheckPinForRat ((PinTypePtr
) Ptr1
);