6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 * Copyright (C) 2004 harry eaton
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Contact addresses for paper mail and Email:
25 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
26 * Thomas.Nau@rz.uni-ulm.de
41 #include "crosshair.h"
47 #ifdef HAVE_LIBDMALLOC
53 static double drc_lines (PointTypePtr end
, bool way
);
55 /* ---------------------------------------------------------------------------
56 * Adjust the attached line to 45 degrees if necessary
59 AdjustAttachedLine (void)
61 AttachedLineTypePtr line
= &Crosshair
.AttachedLine
;
63 /* I need at least one point */
64 if (line
->State
== STATE_FIRST
)
66 /* don't draw outline when ctrl key is pressed */
67 if (Settings
.Mode
== LINE_MODE
&& gui
->control_is_pressed ())
74 /* no 45 degree lines required */
75 if (PCB
->RatDraw
|| TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
77 line
->Point2
.X
= Crosshair
.X
;
78 line
->Point2
.Y
= Crosshair
.Y
;
84 /* ---------------------------------------------------------------------------
85 * makes the attached line fit into a 45 degree direction
96 FortyFiveLine (AttachedLineTypePtr Line
)
99 unsigned direction
= 0;
102 /* first calculate direction of line */
103 dx
= Crosshair
.X
- Line
->Point1
.X
;
104 dy
= Crosshair
.Y
- Line
->Point1
.Y
;
109 /* zero length line, don't draw anything */
112 direction
= dy
> 0 ? 0 : 4;
116 m
= (double) dy
/ dx
;
118 if (m
> TAN_30_DEGREE
)
119 direction
= m
> TAN_60_DEGREE
? 0 : 1;
120 else if (m
< -TAN_30_DEGREE
)
121 direction
= m
< -TAN_60_DEGREE
? 0 : 3;
130 /* now set up the second pair of coordinates */
135 Line
->Point2
.X
= Line
->Point1
.X
;
136 Line
->Point2
.Y
= Crosshair
.Y
;
141 Line
->Point2
.X
= Crosshair
.X
;
142 Line
->Point2
.Y
= Line
->Point1
.Y
;
146 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
147 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
151 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
152 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
156 Line
->Point2
.X
= Line
->Point1
.X
- min
;
157 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
161 Line
->Point2
.X
= Line
->Point1
.X
- min
;
162 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
167 /* ---------------------------------------------------------------------------
168 * adjusts the insert lines to make them 45 degrees as necessary
171 AdjustTwoLine (bool way
)
174 AttachedLineTypePtr line
= &Crosshair
.AttachedLine
;
176 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
178 /* don't draw outline when ctrl key is pressed */
179 if (gui
->control_is_pressed ())
186 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
188 line
->Point2
.X
= Crosshair
.X
;
189 line
->Point2
.Y
= Crosshair
.Y
;
192 /* swap the modes if shift is held down */
193 if (gui
->shift_is_pressed ())
195 dx
= Crosshair
.X
- line
->Point1
.X
;
196 dy
= Crosshair
.Y
- line
->Point1
.Y
;
199 if (abs (dx
) > abs (dy
))
201 line
->Point2
.X
= Crosshair
.X
- SGN (dx
) * abs (dy
);
202 line
->Point2
.Y
= line
->Point1
.Y
;
206 line
->Point2
.X
= line
->Point1
.X
;
207 line
->Point2
.Y
= Crosshair
.Y
- SGN (dy
) * abs (dx
);
212 if (abs (dx
) > abs (dy
))
214 line
->Point2
.X
= line
->Point1
.X
+ SGN (dx
) * abs (dy
);
215 line
->Point2
.Y
= Crosshair
.Y
;
219 line
->Point2
.X
= Crosshair
.X
;
220 line
->Point2
.Y
= line
->Point1
.Y
+ SGN (dy
) * abs (dx
);;
233 drcVia_callback (const BoxType
* b
, void *cl
)
235 PinTypePtr via
= (PinTypePtr
) b
;
236 struct drc_info
*i
= (struct drc_info
*) cl
;
238 if (!TEST_FLAG (FOUNDFLAG
, via
) && PinLineIntersect (via
, i
->line
))
244 drcPad_callback (const BoxType
* b
, void *cl
)
246 PadTypePtr pad
= (PadTypePtr
) b
;
247 struct drc_info
*i
= (struct drc_info
*) cl
;
249 if (TEST_FLAG (ONSOLDERFLAG
, pad
) == i
->solder
&&
250 !TEST_FLAG (FOUNDFLAG
, pad
) && LinePadIntersect (i
->line
, pad
))
256 drcLine_callback (const BoxType
* b
, void *cl
)
258 LineTypePtr line
= (LineTypePtr
) b
;
259 struct drc_info
*i
= (struct drc_info
*) cl
;
261 if (!TEST_FLAG (FOUNDFLAG
, line
) && LineLineIntersect (line
, i
->line
))
267 drcArc_callback (const BoxType
* b
, void *cl
)
269 ArcTypePtr arc
= (ArcTypePtr
) b
;
270 struct drc_info
*i
= (struct drc_info
*) cl
;
272 if (!TEST_FLAG (FOUNDFLAG
, arc
) && LineArcIntersect (i
->line
, arc
))
277 /* drc_lines() checks for intersectors against two lines and
278 * adjusts the end point until there is no intersection or
279 * it winds up back at the start. If way is false it checks
280 * straight start, 45 end lines, otherwise it checks 45 start,
283 * It returns the straight-line length of the best answer, and
284 * changes the position of the input point to the best answer.
288 drc_lines (PointTypePtr end
, bool way
)
290 double f
, s
, f2
, s2
, len
, best
;
291 Coord dx
, dy
, temp
, last
, length
;
292 Coord temp2
, last2
, length2
;
293 LineType line1
, line2
;
294 Cardinal group
, comp
;
295 struct drc_info info
;
296 bool two_lines
, x_is_long
, blocker
;
302 line1
.Flags
= line2
.Flags
= NoFlags ();
303 line1
.Thickness
= Settings
.LineThickness
+ 2 * (PCB
->Bloat
+ 1);
304 line2
.Thickness
= line1
.Thickness
;
305 line1
.Clearance
= line2
.Clearance
= 0;
306 line1
.Point1
.X
= Crosshair
.AttachedLine
.Point1
.X
;
307 line1
.Point1
.Y
= Crosshair
.AttachedLine
.Point1
.Y
;
308 dy
= end
->Y
- line1
.Point1
.Y
;
309 dx
= end
->X
- line1
.Point1
.X
;
310 if (abs (dx
) > abs (dy
))
320 group
= GetGroupOfLayer (INDEXOFCURRENT
);
321 comp
= max_group
+ 10; /* this out-of-range group might save a call */
322 if (GetLayerGroupNumberByNumber (solder_silk_layer
) == group
)
327 comp
= GetLayerGroupNumberByNumber (component_silk_layer
);
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
.solder
|| comp
== group
)
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
.solder
|| comp
== group
)
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
))