4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 2004 harry eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Contact addresses for paper mail and Email:
23 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
24 * Thomas.Nau@rz.uni-ulm.de
39 #include "crosshair.h"
45 #ifdef HAVE_LIBDMALLOC
49 static double drc_lines (PointType
*end
, bool way
);
51 /* ---------------------------------------------------------------------------
52 * Adjust the attached line to 45 degrees if necessary
55 AdjustAttachedLine (void)
57 AttachedLineType
*line
= &Crosshair
.AttachedLine
;
59 /* I need at least one point */
60 if (line
->State
== STATE_FIRST
)
62 /* don't draw outline when ctrl key is pressed */
63 if (Settings
.Mode
== LINE_MODE
&& gui
->control_is_pressed ())
70 /* no 45 degree lines required */
71 if (PCB
->RatDraw
|| TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
73 line
->Point2
.X
= Crosshair
.X
;
74 line
->Point2
.Y
= Crosshair
.Y
;
80 /* ---------------------------------------------------------------------------
81 * makes the attached line fit into a 45 degree direction
92 FortyFiveLine (AttachedLineType
*Line
)
94 Coord dx
, dy
, min
, max
;
95 unsigned direction
= 0;
98 /* first calculate direction of line */
99 dx
= Crosshair
.X
- Line
->Point1
.X
;
100 dy
= Crosshair
.Y
- Line
->Point1
.Y
;
102 /* zero length line, don't draw anything */
103 if (dx
== 0 && dy
== 0)
107 direction
= dy
> 0 ? 0 : 4;
110 m
= (double)dy
/ (double)dx
;
112 if (m
> TAN_30_DEGREE
)
113 direction
= m
> TAN_60_DEGREE
? 0 : 1;
114 else if (m
< -TAN_30_DEGREE
)
115 direction
= m
< -TAN_60_DEGREE
? 4 : 3;
125 /* now set up the second pair of coordinates */
129 Line
->Point2
.X
= Line
->Point1
.X
;
130 Line
->Point2
.Y
= Line
->Point1
.Y
+ max
;
134 Line
->Point2
.X
= Line
->Point1
.X
;
135 Line
->Point2
.Y
= Line
->Point1
.Y
- max
;
139 Line
->Point2
.X
= Line
->Point1
.X
+ max
;
140 Line
->Point2
.Y
= Line
->Point1
.Y
;
144 Line
->Point2
.X
= Line
->Point1
.X
- max
;
145 Line
->Point2
.Y
= Line
->Point1
.Y
;
149 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
150 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
154 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
155 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
159 Line
->Point2
.X
= Line
->Point1
.X
- min
;
160 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
164 Line
->Point2
.X
= Line
->Point1
.X
- min
;
165 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
170 /* ---------------------------------------------------------------------------
171 * adjusts the insert lines to make them 45 degrees as necessary
174 AdjustTwoLine (bool way
)
177 AttachedLineType
*line
= &Crosshair
.AttachedLine
;
179 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
181 /* don't draw outline when ctrl key is pressed */
182 if (gui
->control_is_pressed ())
189 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
191 line
->Point2
.X
= Crosshair
.X
;
192 line
->Point2
.Y
= Crosshair
.Y
;
195 /* swap the modes if shift is held down */
196 if (gui
->shift_is_pressed ())
198 dx
= Crosshair
.X
- line
->Point1
.X
;
199 dy
= Crosshair
.Y
- line
->Point1
.Y
;
202 if (abs (dx
) > abs (dy
))
204 line
->Point2
.X
= Crosshair
.X
- SGN (dx
) * abs (dy
);
205 line
->Point2
.Y
= line
->Point1
.Y
;
209 line
->Point2
.X
= line
->Point1
.X
;
210 line
->Point2
.Y
= Crosshair
.Y
- SGN (dy
) * abs (dx
);
215 if (abs (dx
) > abs (dy
))
217 line
->Point2
.X
= line
->Point1
.X
+ SGN (dx
) * abs (dy
);
218 line
->Point2
.Y
= Crosshair
.Y
;
222 line
->Point2
.X
= Crosshair
.X
;
223 line
->Point2
.Y
= line
->Point1
.Y
+ SGN (dy
) * abs (dx
);;
237 drcVia_callback (const BoxType
* b
, void *cl
)
239 PinType
*via
= (PinType
*) b
;
240 struct drc_info
*i
= (struct drc_info
*) cl
;
242 if (!TEST_FLAG (FOUNDFLAG
, via
) && PinLineIntersect (via
, i
->line
))
248 drcPad_callback (const BoxType
* b
, void *cl
)
250 PadType
*pad
= (PadType
*) b
;
251 struct drc_info
*i
= (struct drc_info
*) cl
;
253 if (TEST_FLAG (ONSOLDERFLAG
, pad
) == i
->bottom_side
&&
254 !TEST_FLAG (FOUNDFLAG
, pad
) && LinePadIntersect (i
->line
, pad
))
260 drcLine_callback (const BoxType
* b
, void *cl
)
262 LineType
*line
= (LineType
*) b
;
263 struct drc_info
*i
= (struct drc_info
*) cl
;
265 if (!TEST_FLAG (FOUNDFLAG
, line
) && LineLineIntersect (line
, i
->line
))
271 drcArc_callback (const BoxType
* b
, void *cl
)
273 ArcType
*arc
= (ArcType
*) b
;
274 struct drc_info
*i
= (struct drc_info
*) cl
;
276 if (!TEST_FLAG (FOUNDFLAG
, arc
) && LineArcIntersect (i
->line
, arc
))
281 /* drc_lines() checks for intersectors against two lines and
282 * adjusts the end point until there is no intersection or
283 * it winds up back at the start. If way is false it checks
284 * straight start, 45 end lines, otherwise it checks 45 start,
287 * It returns the straight-line length of the best answer, and
288 * changes the position of the input point to the best answer.
292 drc_lines (PointType
*end
, bool way
)
294 double f
, s
, f2
, s2
, len
, best
;
295 Coord dx
, dy
, temp
, last
, length
;
296 Coord temp2
, last2
, length2
;
297 LineType line1
, line2
;
299 struct drc_info info
;
300 bool two_lines
, x_is_long
, blocker
;
306 line1
.Flags
= line2
.Flags
= NoFlags ();
307 line1
.Thickness
= Settings
.LineThickness
+ 2 * (PCB
->Bloat
+ 1);
308 line2
.Thickness
= line1
.Thickness
;
309 line1
.Clearance
= line2
.Clearance
= 0;
310 line1
.Point1
.X
= Crosshair
.AttachedLine
.Point1
.X
;
311 line1
.Point1
.Y
= Crosshair
.AttachedLine
.Point1
.Y
;
312 dy
= end
->Y
- line1
.Point1
.Y
;
313 dx
= end
->X
- line1
.Point1
.X
;
314 if (abs (dx
) > abs (dy
))
325 group
= GetLayerGroupNumberByNumber (INDEXOFCURRENT
);
326 info
.bottom_side
= (GetLayerGroupNumberBySide (BOTTOM_SIDE
) == group
);
327 info
.top_side
= (GetLayerGroupNumberBySide (TOP_SIDE
) == group
);
330 /* assume the worst */
332 ans
.X
= line1
.Point1
.X
;
333 ans
.Y
= line1
.Point1
.Y
;
334 while (length
!= last
)
339 dx
= SGN (dx
) * length
;
340 dy
= end
->Y
- line1
.Point1
.Y
;
345 dy
= SGN (dy
) * length
;
346 dx
= end
->X
- line1
.Point1
.X
;
354 while (length2
!= last2
)
357 dy
= SGN (dy
) * length2
;
359 dx
= SGN (dx
) * length2
;
361 if (abs (dx
) > abs (dy
) && x_is_long
)
363 line1
.Point2
.X
= line1
.Point1
.X
+
364 (way
? SGN (dx
) * abs (dy
) : dx
- SGN (dx
) * abs (dy
));
365 line1
.Point2
.Y
= line1
.Point1
.Y
+ (way
? dy
: 0);
367 else if (abs (dy
) >= abs (dx
) && !x_is_long
)
369 line1
.Point2
.X
= line1
.Point1
.X
+ (way
? dx
: 0);
370 line1
.Point2
.Y
= line1
.Point1
.Y
+
371 (way
? SGN (dy
) * abs (dx
) : dy
- SGN (dy
) * abs (dx
));
375 /* we've changed which axis is long, so only do one line */
376 line1
.Point2
.X
= line1
.Point1
.X
+ dx
;
378 line1
.Point1
.Y
+ (way
? SGN (dy
) * abs (dx
) : 0);
383 /* we've changed which axis is long, so only do one line */
384 line1
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
386 line1
.Point1
.X
+ (way
? SGN (dx
) * abs (dy
) : 0);
389 line2
.Point1
.X
= line1
.Point2
.X
;
390 line2
.Point1
.Y
= line1
.Point2
.Y
;
393 line2
.Point2
.Y
= line1
.Point2
.Y
;
394 line2
.Point2
.X
= line1
.Point2
.X
;
398 line2
.Point2
.X
= line1
.Point1
.X
+ dx
;
399 line2
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
401 SetLineBoundingBox (&line1
);
402 SetLineBoundingBox (&line2
);
404 if (setjmp (info
.env
) == 0)
407 r_search (PCB
->Data
->via_tree
, &line1
.BoundingBox
, NULL
,
408 drcVia_callback
, &info
);
409 r_search (PCB
->Data
->pin_tree
, &line1
.BoundingBox
, NULL
,
410 drcVia_callback
, &info
);
411 if (info
.bottom_side
|| info
.top_side
)
412 r_search (PCB
->Data
->pad_tree
, &line1
.BoundingBox
, NULL
,
413 drcPad_callback
, &info
);
417 r_search (PCB
->Data
->via_tree
, &line2
.BoundingBox
, NULL
,
418 drcVia_callback
, &info
);
419 r_search (PCB
->Data
->pin_tree
, &line2
.BoundingBox
, NULL
,
420 drcVia_callback
, &info
);
421 if (info
.bottom_side
|| info
.top_side
)
422 r_search (PCB
->Data
->pad_tree
, &line2
.BoundingBox
, NULL
,
423 drcPad_callback
, &info
);
425 GROUP_LOOP (PCB
->Data
, group
);
428 r_search (layer
->line_tree
, &line1
.BoundingBox
, NULL
,
429 drcLine_callback
, &info
);
430 r_search (layer
->arc_tree
, &line1
.BoundingBox
, NULL
,
431 drcArc_callback
, &info
);
435 r_search (layer
->line_tree
, &line2
.BoundingBox
,
436 NULL
, drcLine_callback
, &info
);
437 r_search (layer
->arc_tree
, &line2
.BoundingBox
,
438 NULL
, drcArc_callback
, &info
);
442 /* no intersector! */
445 len
= (line2
.Point2
.X
- line1
.Point1
.X
);
447 len
+= (double) (line2
.Point2
.Y
- line1
.Point1
.Y
) *
448 (line2
.Point2
.Y
- line1
.Point1
.Y
);
452 ans
.X
= line2
.Point2
.X
;
453 ans
.Y
= line2
.Point2
.Y
;
462 /* bumped into something, back off */
466 length2
= MIN (f2
* temp2
, temp2
);
468 if (!blocker
&& ((x_is_long
&& line2
.Point2
.X
- line1
.Point1
.X
== dx
)
470 && line2
.Point2
.Y
- line1
.Point1
.Y
== dy
)))
475 length
= MIN (f
* temp
, temp
);
484 EnforceLineDRC (void)
490 /* Silence a bogus compiler warning by storing this in a variable */
491 int layer_idx
= INDEXOFCURRENT
;
493 if ( gui
->mod1_is_pressed() || gui
->control_is_pressed () || PCB
->RatDraw
494 || layer_idx
>= max_copper_layer
)
497 rs
.X
= r45
.X
= Crosshair
.X
;
498 rs
.Y
= r45
.Y
= Crosshair
.Y
;
499 /* first try starting straight */
500 r1
= drc_lines (&rs
, false);
501 /* then try starting at 45 */
502 r2
= drc_lines (&r45
, true);
503 shift
= gui
->shift_is_pressed ();
504 if (XOR (r1
> r2
, shift
))
507 PCB
->Clipping
= shift
? 2 : 1;
514 PCB
->Clipping
= shift
? 1 : 2;