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
34 #define NUDGE (TO_PCB (6))
43 #include "crosshair.h"
49 #ifdef HAVE_LIBDMALLOC
55 static float drc_lines (PointTypePtr end
, Boolean way
);
57 /* ---------------------------------------------------------------------------
58 * Adjust the attached line to 45 degrees if necessary
61 AdjustAttachedLine (void)
63 AttachedLineTypePtr line
= &Crosshair
.AttachedLine
;
65 /* I need at least one point */
66 if (line
->State
== STATE_FIRST
)
68 /* don't draw outline when ctrl key is pressed */
69 if (Settings
.Mode
== LINE_MODE
&& gui
->control_is_pressed ())
76 /* no 45 degree lines required */
77 if (PCB
->RatDraw
|| TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
79 line
->Point2
.X
= Crosshair
.X
;
80 line
->Point2
.Y
= Crosshair
.Y
;
86 /* ---------------------------------------------------------------------------
87 * makes the attached line fit into a 45 degree direction
98 FortyFiveLine (AttachedLineTypePtr Line
)
100 LocationType dx
, dy
, min
;
104 /* first calculate direction of line */
105 dx
= Crosshair
.X
- Line
->Point1
.X
;
106 dy
= Crosshair
.Y
- Line
->Point1
.Y
;
111 /* zero length line, don't draw anything */
114 direction
= dy
> 0 ? 0 : 4;
118 m
= (float) dy
/ (float) dx
;
120 if (m
> TAN_30_DEGREE
)
121 direction
= m
> TAN_60_DEGREE
? 0 : 1;
122 else if (m
< -TAN_30_DEGREE
)
123 direction
= m
< -TAN_60_DEGREE
? 0 : 3;
132 /* now set up the second pair of coordinates */
137 Line
->Point2
.X
= Line
->Point1
.X
;
138 Line
->Point2
.Y
= Crosshair
.Y
;
143 Line
->Point2
.X
= Crosshair
.X
;
144 Line
->Point2
.Y
= Line
->Point1
.Y
;
148 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
149 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
153 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
154 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
158 Line
->Point2
.X
= Line
->Point1
.X
- min
;
159 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
163 Line
->Point2
.X
= Line
->Point1
.X
- min
;
164 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
169 /* ---------------------------------------------------------------------------
170 * adjusts the insert lines to make them 45 degrees as necessary
173 AdjustTwoLine (int way
)
176 AttachedLineTypePtr line
= &Crosshair
.AttachedLine
;
178 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
180 /* don't draw outline when ctrl key is pressed */
181 if (gui
->control_is_pressed ())
188 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
190 line
->Point2
.X
= Crosshair
.X
;
191 line
->Point2
.Y
= Crosshair
.Y
;
194 /* swap the modes if shift is held down */
195 if (gui
->shift_is_pressed ())
197 dx
= Crosshair
.X
- line
->Point1
.X
;
198 dy
= Crosshair
.Y
- line
->Point1
.Y
;
201 if (abs (dx
) > abs (dy
))
203 line
->Point2
.X
= Crosshair
.X
- SGN (dx
) * abs (dy
);
204 line
->Point2
.Y
= line
->Point1
.Y
;
208 line
->Point2
.X
= line
->Point1
.X
;
209 line
->Point2
.Y
= Crosshair
.Y
- SGN (dy
) * abs (dx
);
214 if (abs (dx
) > abs (dy
))
216 line
->Point2
.X
= line
->Point1
.X
+ SGN (dx
) * abs (dy
);
217 line
->Point2
.Y
= Crosshair
.Y
;
221 line
->Point2
.X
= Crosshair
.X
;
222 line
->Point2
.Y
= line
->Point1
.Y
+ SGN (dy
) * abs (dx
);;
235 drcVia_callback (const BoxType
* b
, void *cl
)
237 PinTypePtr via
= (PinTypePtr
) b
;
238 struct drc_info
*i
= (struct drc_info
*) cl
;
240 if (!TEST_FLAG (FOUNDFLAG
, via
) && PinLineIntersect (via
, i
->line
))
246 drcPad_callback (const BoxType
* b
, void *cl
)
248 PadTypePtr pad
= (PadTypePtr
) b
;
249 struct drc_info
*i
= (struct drc_info
*) cl
;
251 if (TEST_FLAG (ONSOLDERFLAG
, pad
) == i
->solder
&&
252 !TEST_FLAG (FOUNDFLAG
, pad
) && LinePadIntersect (i
->line
, pad
))
258 drcLine_callback (const BoxType
* b
, void *cl
)
260 LineTypePtr line
= (LineTypePtr
) b
;
261 struct drc_info
*i
= (struct drc_info
*) cl
;
263 if (!TEST_FLAG (FOUNDFLAG
, line
) && LineLineIntersect (line
, i
->line
))
269 drcArc_callback (const BoxType
* b
, void *cl
)
271 ArcTypePtr arc
= (ArcTypePtr
) b
;
272 struct drc_info
*i
= (struct drc_info
*) cl
;
274 if (!TEST_FLAG (FOUNDFLAG
, arc
) && LineArcIntersect (i
->line
, arc
))
279 /* drc_lines() checks for intersectors against two lines and
280 * adjusts the end point until there is no intersection or
281 * it winds up back at the start. If way is false it checks
282 * straight start, 45 end lines, otherwise it checks 45 start,
285 * It returns the straight-line length of the best answer, and
286 * changes the position of the input point to the best answer.
290 drc_lines (PointTypePtr end
, Boolean way
)
292 float f
, s
, f2
, s2
, len
, best
;
293 LocationType dx
, dy
, temp
, last
, length
;
294 LocationType temp2
, last2
, length2
;
295 LineType line1
, line2
;
296 Cardinal group
, comp
;
297 struct drc_info info
;
298 Boolean two_lines
, x_is_long
, blocker
;
304 line1
.Flags
= line2
.Flags
= NoFlags ();
305 line1
.Thickness
= Settings
.LineThickness
+ 2 * (PCB
->Bloat
+ 1);
306 line2
.Thickness
= line1
.Thickness
;
307 line1
.Clearance
= line2
.Clearance
= 0;
308 line1
.Point1
.X
= Crosshair
.AttachedLine
.Point1
.X
;
309 line1
.Point1
.Y
= Crosshair
.AttachedLine
.Point1
.Y
;
310 dy
= end
->Y
- line1
.Point1
.Y
;
311 dx
= end
->X
- line1
.Point1
.X
;
312 if (abs (dx
) > abs (dy
))
322 group
= GetGroupOfLayer (INDEXOFCURRENT
);
323 comp
= max_layer
+ 10; /* this out-of-range group might save a call */
324 if (GetLayerGroupNumberByNumber (max_layer
+ SOLDER_LAYER
) == group
)
329 comp
= GetLayerGroupNumberByNumber (max_layer
+ COMPONENT_LAYER
);
332 /* assume the worst */
334 ans
.X
= line1
.Point1
.X
;
335 ans
.Y
= line1
.Point1
.Y
;
336 while (length
!= last
)
341 dx
= SGN (dx
) * length
;
342 dy
= end
->Y
- line1
.Point1
.Y
;
347 dy
= SGN (dy
) * length
;
348 dx
= end
->X
- line1
.Point1
.X
;
356 while (length2
!= last2
)
359 dy
= SGN (dy
) * length2
;
361 dx
= SGN (dx
) * length2
;
363 if (abs (dx
) > abs (dy
) && x_is_long
)
365 line1
.Point2
.X
= line1
.Point1
.X
+
366 (way
? SGN (dx
) * abs (dy
) : dx
- SGN (dx
) * abs (dy
));
367 line1
.Point2
.Y
= line1
.Point1
.Y
+ (way
? dy
: 0);
369 else if (abs (dy
) >= abs (dx
) && !x_is_long
)
371 line1
.Point2
.X
= line1
.Point1
.X
+ (way
? dx
: 0);
372 line1
.Point2
.Y
= line1
.Point1
.Y
+
373 (way
? SGN (dy
) * abs (dx
) : dy
- SGN (dy
) * abs (dx
));
377 /* we've changed which axis is long, so only do one line */
378 line1
.Point2
.X
= line1
.Point1
.X
+ dx
;
380 line1
.Point1
.Y
+ (way
? SGN (dy
) * abs (dx
) : 0);
385 /* we've changed which axis is long, so only do one line */
386 line1
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
388 line1
.Point1
.X
+ (way
? SGN (dx
) * abs (dy
) : 0);
391 line2
.Point1
.X
= line1
.Point2
.X
;
392 line2
.Point1
.Y
= line1
.Point2
.Y
;
395 line2
.Point2
.Y
= line1
.Point2
.Y
;
396 line2
.Point2
.X
= line1
.Point2
.X
;
400 line2
.Point2
.X
= line1
.Point1
.X
+ dx
;
401 line2
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
403 SetLineBoundingBox (&line1
);
404 SetLineBoundingBox (&line2
);
406 if (setjmp (info
.env
) == 0)
409 r_search (PCB
->Data
->via_tree
, &line1
.BoundingBox
, NULL
,
410 drcVia_callback
, &info
);
411 r_search (PCB
->Data
->pin_tree
, &line1
.BoundingBox
, NULL
,
412 drcVia_callback
, &info
);
413 if (info
.solder
|| comp
== group
)
414 r_search (PCB
->Data
->pad_tree
, &line1
.BoundingBox
, NULL
,
415 drcPad_callback
, &info
);
419 r_search (PCB
->Data
->via_tree
, &line2
.BoundingBox
, NULL
,
420 drcVia_callback
, &info
);
421 r_search (PCB
->Data
->pin_tree
, &line2
.BoundingBox
, NULL
,
422 drcVia_callback
, &info
);
423 if (info
.solder
|| comp
== group
)
424 r_search (PCB
->Data
->pad_tree
, &line2
.BoundingBox
, NULL
,
425 drcPad_callback
, &info
);
427 GROUP_LOOP (PCB
->Data
, group
);
430 r_search (layer
->line_tree
, &line1
.BoundingBox
, NULL
,
431 drcLine_callback
, &info
);
432 r_search (layer
->arc_tree
, &line1
.BoundingBox
, NULL
,
433 drcArc_callback
, &info
);
437 r_search (layer
->line_tree
, &line2
.BoundingBox
,
438 NULL
, drcLine_callback
, &info
);
439 r_search (layer
->arc_tree
, &line2
.BoundingBox
,
440 NULL
, drcArc_callback
, &info
);
444 /* no intersector! */
447 len
= (line2
.Point2
.X
- line1
.Point1
.X
);
449 len
+= (float) (line2
.Point2
.Y
- line1
.Point1
.Y
) *
450 (line2
.Point2
.Y
- line1
.Point1
.Y
);
454 ans
.X
= line2
.Point2
.X
;
455 ans
.Y
= line2
.Point2
.Y
;
464 /* bumped into something, back off */
468 length2
= MIN (f2
* temp2
, temp2
);
470 if (!blocker
&& ((x_is_long
&& line2
.Point2
.X
- line1
.Point1
.X
== dx
)
472 && line2
.Point2
.Y
- line1
.Point1
.Y
== dy
)))
477 length
= MIN (f
* temp
, temp
);
486 EnforceLineDRC (void)
492 if ( gui
->mod1_is_pressed() || gui
->control_is_pressed () || PCB
->RatDraw
493 || INDEXOFCURRENT
>= max_layer
)
495 rs
.X
= r45
.X
= Crosshair
.X
;
496 rs
.Y
= r45
.Y
= Crosshair
.Y
;
497 /* first try starting straight */
498 r1
= drc_lines (&rs
, False
);
499 /* then try starting at 45 */
500 r2
= drc_lines (&r45
, True
);
501 shift
= gui
->shift_is_pressed ();
502 if (XOR (r1
> r2
, shift
))