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
);;
236 drcVia_callback (const BoxType
* b
, void *cl
)
238 PinType
*via
= (PinType
*) b
;
239 struct drc_info
*i
= (struct drc_info
*) cl
;
241 if (!TEST_FLAG (FOUNDFLAG
, via
) && PinLineIntersect (via
, i
->line
))
247 drcPad_callback (const BoxType
* b
, void *cl
)
249 PadType
*pad
= (PadType
*) b
;
250 struct drc_info
*i
= (struct drc_info
*) cl
;
252 if (TEST_FLAG (ONSOLDERFLAG
, pad
) == i
->solder
&&
253 !TEST_FLAG (FOUNDFLAG
, pad
) && LinePadIntersect (i
->line
, pad
))
259 drcLine_callback (const BoxType
* b
, void *cl
)
261 LineType
*line
= (LineType
*) b
;
262 struct drc_info
*i
= (struct drc_info
*) cl
;
264 if (!TEST_FLAG (FOUNDFLAG
, line
) && LineLineIntersect (line
, i
->line
))
270 drcArc_callback (const BoxType
* b
, void *cl
)
272 ArcType
*arc
= (ArcType
*) b
;
273 struct drc_info
*i
= (struct drc_info
*) cl
;
275 if (!TEST_FLAG (FOUNDFLAG
, arc
) && LineArcIntersect (i
->line
, arc
))
280 /* drc_lines() checks for intersectors against two lines and
281 * adjusts the end point until there is no intersection or
282 * it winds up back at the start. If way is false it checks
283 * straight start, 45 end lines, otherwise it checks 45 start,
286 * It returns the straight-line length of the best answer, and
287 * changes the position of the input point to the best answer.
291 drc_lines (PointType
*end
, bool way
)
293 double f
, s
, f2
, s2
, len
, best
;
294 Coord dx
, dy
, temp
, last
, length
;
295 Coord temp2
, last2
, length2
;
296 LineType line1
, line2
;
297 Cardinal group
, comp
;
298 struct drc_info info
;
299 bool two_lines
, x_is_long
, blocker
;
305 line1
.Flags
= line2
.Flags
= NoFlags ();
306 line1
.Thickness
= Settings
.LineThickness
+ 2 * (PCB
->Bloat
+ 1);
307 line2
.Thickness
= line1
.Thickness
;
308 line1
.Clearance
= line2
.Clearance
= 0;
309 line1
.Point1
.X
= Crosshair
.AttachedLine
.Point1
.X
;
310 line1
.Point1
.Y
= Crosshair
.AttachedLine
.Point1
.Y
;
311 dy
= end
->Y
- line1
.Point1
.Y
;
312 dx
= end
->X
- line1
.Point1
.X
;
313 if (abs (dx
) > abs (dy
))
323 group
= GetGroupOfLayer (INDEXOFCURRENT
);
324 comp
= max_group
+ 10; /* this out-of-range group might save a call */
325 if (GetLayerGroupNumberByNumber (solder_silk_layer
) == group
)
330 comp
= GetLayerGroupNumberByNumber (component_silk_layer
);
333 /* assume the worst */
335 ans
.X
= line1
.Point1
.X
;
336 ans
.Y
= line1
.Point1
.Y
;
337 while (length
!= last
)
342 dx
= SGN (dx
) * length
;
343 dy
= end
->Y
- line1
.Point1
.Y
;
348 dy
= SGN (dy
) * length
;
349 dx
= end
->X
- line1
.Point1
.X
;
357 while (length2
!= last2
)
360 dy
= SGN (dy
) * length2
;
362 dx
= SGN (dx
) * length2
;
364 if (abs (dx
) > abs (dy
) && x_is_long
)
366 line1
.Point2
.X
= line1
.Point1
.X
+
367 (way
? SGN (dx
) * abs (dy
) : dx
- SGN (dx
) * abs (dy
));
368 line1
.Point2
.Y
= line1
.Point1
.Y
+ (way
? dy
: 0);
370 else if (abs (dy
) >= abs (dx
) && !x_is_long
)
372 line1
.Point2
.X
= line1
.Point1
.X
+ (way
? dx
: 0);
373 line1
.Point2
.Y
= line1
.Point1
.Y
+
374 (way
? SGN (dy
) * abs (dx
) : dy
- SGN (dy
) * abs (dx
));
378 /* we've changed which axis is long, so only do one line */
379 line1
.Point2
.X
= line1
.Point1
.X
+ dx
;
381 line1
.Point1
.Y
+ (way
? SGN (dy
) * abs (dx
) : 0);
386 /* we've changed which axis is long, so only do one line */
387 line1
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
389 line1
.Point1
.X
+ (way
? SGN (dx
) * abs (dy
) : 0);
392 line2
.Point1
.X
= line1
.Point2
.X
;
393 line2
.Point1
.Y
= line1
.Point2
.Y
;
396 line2
.Point2
.Y
= line1
.Point2
.Y
;
397 line2
.Point2
.X
= line1
.Point2
.X
;
401 line2
.Point2
.X
= line1
.Point1
.X
+ dx
;
402 line2
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
404 SetLineBoundingBox (&line1
);
405 SetLineBoundingBox (&line2
);
407 if (setjmp (info
.env
) == 0)
410 r_search (PCB
->Data
->via_tree
, &line1
.BoundingBox
, NULL
,
411 drcVia_callback
, &info
);
412 r_search (PCB
->Data
->pin_tree
, &line1
.BoundingBox
, NULL
,
413 drcVia_callback
, &info
);
414 if (info
.solder
|| comp
== group
)
415 r_search (PCB
->Data
->pad_tree
, &line1
.BoundingBox
, NULL
,
416 drcPad_callback
, &info
);
420 r_search (PCB
->Data
->via_tree
, &line2
.BoundingBox
, NULL
,
421 drcVia_callback
, &info
);
422 r_search (PCB
->Data
->pin_tree
, &line2
.BoundingBox
, NULL
,
423 drcVia_callback
, &info
);
424 if (info
.solder
|| comp
== group
)
425 r_search (PCB
->Data
->pad_tree
, &line2
.BoundingBox
, NULL
,
426 drcPad_callback
, &info
);
428 GROUP_LOOP (PCB
->Data
, group
);
431 r_search (layer
->line_tree
, &line1
.BoundingBox
, NULL
,
432 drcLine_callback
, &info
);
433 r_search (layer
->arc_tree
, &line1
.BoundingBox
, NULL
,
434 drcArc_callback
, &info
);
438 r_search (layer
->line_tree
, &line2
.BoundingBox
,
439 NULL
, drcLine_callback
, &info
);
440 r_search (layer
->arc_tree
, &line2
.BoundingBox
,
441 NULL
, drcArc_callback
, &info
);
445 /* no intersector! */
448 len
= (line2
.Point2
.X
- line1
.Point1
.X
);
450 len
+= (double) (line2
.Point2
.Y
- line1
.Point1
.Y
) *
451 (line2
.Point2
.Y
- line1
.Point1
.Y
);
455 ans
.X
= line2
.Point2
.X
;
456 ans
.Y
= line2
.Point2
.Y
;
465 /* bumped into something, back off */
469 length2
= MIN (f2
* temp2
, temp2
);
471 if (!blocker
&& ((x_is_long
&& line2
.Point2
.X
- line1
.Point1
.X
== dx
)
473 && line2
.Point2
.Y
- line1
.Point1
.Y
== dy
)))
478 length
= MIN (f
* temp
, temp
);
487 EnforceLineDRC (void)
493 /* Silence a bogus compiler warning by storing this in a variable */
494 int layer_idx
= INDEXOFCURRENT
;
496 if ( gui
->mod1_is_pressed() || gui
->control_is_pressed () || PCB
->RatDraw
497 || layer_idx
>= max_copper_layer
)
500 rs
.X
= r45
.X
= Crosshair
.X
;
501 rs
.Y
= r45
.Y
= Crosshair
.Y
;
502 /* first try starting straight */
503 r1
= drc_lines (&rs
, false);
504 /* then try starting at 45 */
505 r2
= drc_lines (&r45
, true);
506 shift
= gui
->shift_is_pressed ();
507 if (XOR (r1
> r2
, shift
))
510 PCB
->Clipping
= shift
? 2 : 1;
517 PCB
->Clipping
= shift
? 1 : 2;