4 * \brief Routines for inserting points into objects.
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996 Thomas Nau
14 * Copyright (C) 2004 harry eaton
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 * Contact addresses for paper mail and Email:
31 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
32 * Thomas.Nau@rz.uni-ulm.de
46 #include "crosshair.h"
52 #ifdef HAVE_LIBDMALLOC
56 static double drc_lines (PointType
*end
, bool way
);
59 * \brief Adjust the attached line to 45 degrees if necessary.
62 AdjustAttachedLine (void)
64 AttachedLineType
*line
= &Crosshair
.AttachedLine
;
66 /* I need at least one point */
67 if (line
->State
== STATE_FIRST
)
69 /* don't draw outline when ctrl key is pressed */
70 if (Settings
.Mode
== LINE_MODE
&& gui
->control_is_pressed ())
77 /* no 45 degree lines required */
78 if (PCB
->RatDraw
|| TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
80 line
->Point2
.X
= Crosshair
.X
;
81 line
->Point2
.Y
= Crosshair
.Y
;
88 * \brief Makes the attached line fit into a 45 degree direction.
100 FortyFiveLine (AttachedLineType
*Line
)
102 Coord dx
, dy
, min
, max
;
103 unsigned direction
= 0;
106 /* first calculate direction of line */
107 dx
= Crosshair
.X
- Line
->Point1
.X
;
108 dy
= Crosshair
.Y
- Line
->Point1
.Y
;
110 /* zero length line, don't draw anything */
111 if (dx
== 0 && dy
== 0)
115 direction
= dy
> 0 ? 0 : 4;
118 m
= (double)dy
/ (double)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
? 4 : 3;
133 /* now set up the second pair of coordinates */
137 Line
->Point2
.X
= Line
->Point1
.X
;
138 Line
->Point2
.Y
= Line
->Point1
.Y
+ max
;
142 Line
->Point2
.X
= Line
->Point1
.X
;
143 Line
->Point2
.Y
= Line
->Point1
.Y
- max
;
147 Line
->Point2
.X
= Line
->Point1
.X
+ max
;
148 Line
->Point2
.Y
= Line
->Point1
.Y
;
152 Line
->Point2
.X
= Line
->Point1
.X
- max
;
153 Line
->Point2
.Y
= Line
->Point1
.Y
;
157 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
158 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
162 Line
->Point2
.X
= Line
->Point1
.X
+ min
;
163 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
167 Line
->Point2
.X
= Line
->Point1
.X
- min
;
168 Line
->Point2
.Y
= Line
->Point1
.Y
- min
;
172 Line
->Point2
.X
= Line
->Point1
.X
- min
;
173 Line
->Point2
.Y
= Line
->Point1
.Y
+ min
;
179 * \brief Adjusts the insert lines to make them 45 degrees as necessary.
182 AdjustTwoLine (bool way
)
185 AttachedLineType
*line
= &Crosshair
.AttachedLine
;
187 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
189 /* don't draw outline when ctrl key is pressed */
190 if (gui
->control_is_pressed ())
197 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
199 line
->Point2
.X
= Crosshair
.X
;
200 line
->Point2
.Y
= Crosshair
.Y
;
203 /* swap the modes if shift is held down */
204 if (gui
->shift_is_pressed ())
206 dx
= Crosshair
.X
- line
->Point1
.X
;
207 dy
= Crosshair
.Y
- line
->Point1
.Y
;
210 if (abs (dx
) > abs (dy
))
212 line
->Point2
.X
= Crosshair
.X
- SGN (dx
) * abs (dy
);
213 line
->Point2
.Y
= line
->Point1
.Y
;
217 line
->Point2
.X
= line
->Point1
.X
;
218 line
->Point2
.Y
= Crosshair
.Y
- SGN (dy
) * abs (dx
);
223 if (abs (dx
) > abs (dy
))
225 line
->Point2
.X
= line
->Point1
.X
+ SGN (dx
) * abs (dy
);
226 line
->Point2
.Y
= Crosshair
.Y
;
230 line
->Point2
.X
= Crosshair
.X
;
231 line
->Point2
.Y
= line
->Point1
.Y
+ SGN (dy
) * abs (dx
);;
245 drcVia_callback (const BoxType
* b
, void *cl
)
247 PinType
*via
= (PinType
*) b
;
248 struct drc_info
*i
= (struct drc_info
*) cl
;
250 if (!TEST_FLAG (FOUNDFLAG
, via
) && PinLineIntersect (via
, i
->line
))
256 drcPad_callback (const BoxType
* b
, void *cl
)
258 PadType
*pad
= (PadType
*) b
;
259 struct drc_info
*i
= (struct drc_info
*) cl
;
261 if (TEST_FLAG (ONSOLDERFLAG
, pad
) == i
->bottom_side
&&
262 !TEST_FLAG (FOUNDFLAG
, pad
) && LinePadIntersect (i
->line
, pad
))
268 drcLine_callback (const BoxType
* b
, void *cl
)
270 LineType
*line
= (LineType
*) b
;
271 struct drc_info
*i
= (struct drc_info
*) cl
;
273 if (!TEST_FLAG (FOUNDFLAG
, line
) && LineLineIntersect (line
, i
->line
))
279 drcArc_callback (const BoxType
* b
, void *cl
)
281 ArcType
*arc
= (ArcType
*) b
;
282 struct drc_info
*i
= (struct drc_info
*) cl
;
284 if (!TEST_FLAG (FOUNDFLAG
, arc
) && LineArcIntersect (i
->line
, arc
))
290 * \brief drc_lines() checks for intersectors against two lines and
291 * adjusts the end point until there is no intersection or
292 * it winds up back at the start.
294 * If way is false it checks straight start, 45 end lines, otherwise it
295 * checks 45 start, straight end.
297 * It returns the straight-line length of the best answer, and
298 * changes the position of the input point to the best answer.
301 drc_lines (PointType
*end
, bool way
)
303 double f
, s
, f2
, s2
, len
, best
;
304 Coord dx
, dy
, temp
, last
, length
;
305 Coord temp2
, last2
, length2
;
306 LineType line1
, line2
;
308 struct drc_info info
;
309 bool two_lines
, x_is_long
, blocker
;
315 line1
.Flags
= line2
.Flags
= NoFlags ();
316 line1
.Thickness
= Settings
.LineThickness
+ 2 * PCB
->Bloat
;
317 line2
.Thickness
= line1
.Thickness
;
318 line1
.Clearance
= line2
.Clearance
= 0;
319 line1
.Point1
.X
= Crosshair
.AttachedLine
.Point1
.X
;
320 line1
.Point1
.Y
= Crosshair
.AttachedLine
.Point1
.Y
;
321 dy
= end
->Y
- line1
.Point1
.Y
;
322 dx
= end
->X
- line1
.Point1
.X
;
323 if (abs (dx
) > abs (dy
))
334 group
= GetLayerGroupNumberByNumber (INDEXOFCURRENT
);
335 info
.bottom_side
= (GetLayerGroupNumberBySide (BOTTOM_SIDE
) == group
);
336 info
.top_side
= (GetLayerGroupNumberBySide (TOP_SIDE
) == group
);
339 /* assume the worst */
341 ans
.X
= line1
.Point1
.X
;
342 ans
.Y
= line1
.Point1
.Y
;
343 while (length
!= last
)
348 dx
= SGN (dx
) * length
;
349 dy
= end
->Y
- line1
.Point1
.Y
;
354 dy
= SGN (dy
) * length
;
355 dx
= end
->X
- line1
.Point1
.X
;
363 while (length2
!= last2
)
366 dy
= SGN (dy
) * length2
;
368 dx
= SGN (dx
) * length2
;
370 if (abs (dx
) > abs (dy
) && x_is_long
)
372 line1
.Point2
.X
= line1
.Point1
.X
+
373 (way
? SGN (dx
) * abs (dy
) : dx
- SGN (dx
) * abs (dy
));
374 line1
.Point2
.Y
= line1
.Point1
.Y
+ (way
? dy
: 0);
376 else if (abs (dy
) >= abs (dx
) && !x_is_long
)
378 line1
.Point2
.X
= line1
.Point1
.X
+ (way
? dx
: 0);
379 line1
.Point2
.Y
= line1
.Point1
.Y
+
380 (way
? SGN (dy
) * abs (dx
) : dy
- SGN (dy
) * abs (dx
));
384 /* we've changed which axis is long, so only do one line */
385 line1
.Point2
.X
= line1
.Point1
.X
+ dx
;
387 line1
.Point1
.Y
+ (way
? SGN (dy
) * abs (dx
) : 0);
392 /* we've changed which axis is long, so only do one line */
393 line1
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
395 line1
.Point1
.X
+ (way
? SGN (dx
) * abs (dy
) : 0);
398 line2
.Point1
.X
= line1
.Point2
.X
;
399 line2
.Point1
.Y
= line1
.Point2
.Y
;
402 line2
.Point2
.Y
= line1
.Point2
.Y
;
403 line2
.Point2
.X
= line1
.Point2
.X
;
407 line2
.Point2
.X
= line1
.Point1
.X
+ dx
;
408 line2
.Point2
.Y
= line1
.Point1
.Y
+ dy
;
410 SetLineBoundingBox (&line1
);
411 SetLineBoundingBox (&line2
);
413 if (setjmp (info
.env
) == 0)
416 r_search (PCB
->Data
->via_tree
, &line1
.BoundingBox
, NULL
,
417 drcVia_callback
, &info
);
418 r_search (PCB
->Data
->pin_tree
, &line1
.BoundingBox
, NULL
,
419 drcVia_callback
, &info
);
420 if (info
.bottom_side
|| info
.top_side
)
421 r_search (PCB
->Data
->pad_tree
, &line1
.BoundingBox
, NULL
,
422 drcPad_callback
, &info
);
426 r_search (PCB
->Data
->via_tree
, &line2
.BoundingBox
, NULL
,
427 drcVia_callback
, &info
);
428 r_search (PCB
->Data
->pin_tree
, &line2
.BoundingBox
, NULL
,
429 drcVia_callback
, &info
);
430 if (info
.bottom_side
|| info
.top_side
)
431 r_search (PCB
->Data
->pad_tree
, &line2
.BoundingBox
, NULL
,
432 drcPad_callback
, &info
);
434 GROUP_LOOP (PCB
->Data
, group
);
437 r_search (layer
->line_tree
, &line1
.BoundingBox
, NULL
,
438 drcLine_callback
, &info
);
439 r_search (layer
->arc_tree
, &line1
.BoundingBox
, NULL
,
440 drcArc_callback
, &info
);
444 r_search (layer
->line_tree
, &line2
.BoundingBox
,
445 NULL
, drcLine_callback
, &info
);
446 r_search (layer
->arc_tree
, &line2
.BoundingBox
,
447 NULL
, drcArc_callback
, &info
);
451 /* no intersector! */
454 len
= (line2
.Point2
.X
- line1
.Point1
.X
);
456 len
+= (double) (line2
.Point2
.Y
- line1
.Point1
.Y
) *
457 (line2
.Point2
.Y
- line1
.Point1
.Y
);
461 ans
.X
= line2
.Point2
.X
;
462 ans
.Y
= line2
.Point2
.Y
;
471 /* bumped into something, back off */
475 length2
= MIN (f2
* temp2
, temp2
);
477 if (!blocker
&& ((x_is_long
&& line2
.Point2
.X
- line1
.Point1
.X
== dx
)
479 && line2
.Point2
.Y
- line1
.Point1
.Y
== dy
)))
484 length
= MIN (f
* temp
, temp
);
493 EnforceLineDRC (void)
499 /* Silence a bogus compiler warning by storing this in a variable */
500 int layer_idx
= INDEXOFCURRENT
;
502 if ( gui
->mod1_is_pressed() || gui
->control_is_pressed () || PCB
->RatDraw
503 || layer_idx
>= max_copper_layer
)
506 rs
.X
= r45
.X
= Crosshair
.X
;
507 rs
.Y
= r45
.Y
= Crosshair
.Y
;
508 /* first try starting straight */
509 r1
= drc_lines (&rs
, false);
510 /* then try starting at 45 */
511 r2
= drc_lines (&r45
, true);
512 shift
= gui
->shift_is_pressed ();
513 if (XOR (r1
> r2
, shift
))
516 PCB
->Clipping
= shift
? 2 : 1;
523 PCB
->Clipping
= shift
? 1 : 2;