6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2006 DJ Delorie
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
29 /* FIXME: Things that need to be fixed before this is "perfect".
30 Add to this list as we find things.
32 - respect the outline layer.
34 - don't consider points that are perpendicular to our start_arc.
35 I.e. when we have busses going around corners, we have a *lot* of
36 arcs and endpoints that are all in the same direction and all
37 equally "good", but rounding the arc angles to integers causes
38 all sorts of tiny differences that result in bumps, reversals,
41 - Store the X,Y values in our shadow struct so we don't fill up the
42 undo buffer with all our line reversals.
44 - at least check the other layers in our layer group.
70 #ifdef HAVE_LIBDMALLOC
76 #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort()
81 /* sine of one degree */
82 #define SIN1D 0.0174524064372835
84 static jmp_buf abort_buf
;
86 #define sqr(x) (1.0*(x)*(x))
88 static int multi
, line_exact
, arc_exact
;
89 static LineTypePtr the_line
;
90 static ArcTypePtr the_arc
;
91 static double arc_dist
;
93 /* We canonicalize the arc and line such that the point to be moved is
94 always Point2 for the line, and at start+delta for the arc. */
96 static int x
, y
; /* the point we're moving */
97 static int cx
, cy
; /* centerpoint of the arc */
98 static int ex
, ey
; /* fixed end of the line */
100 /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */
103 dist (int x1
, int y1
, int x2
, int y2
)
107 double dist
= sqrt (dx
* dx
+ dy
* dy
);
112 within (int x1
, int y1
, int x2
, int y2
, int r
)
114 return dist (x1
, y1
, x2
, y2
) <= r
/ 2;
118 arc_endpoint_is (ArcTypePtr a
, int angle
, int x
, int y
)
120 int ax
= a
->X
, ay
= a
->Y
;
124 int ai
= (int) (angle
/ 90) & 3;
143 double rad
= angle
* M_PI
/ 180;
144 ax
-= a
->Width
* cos (rad
);
145 ay
+= a
->Width
* sin (rad
);
148 printf (" - arc endpoint %d,%d\n", ax
, ay
);
150 arc_dist
= dist (ax
, ay
, x
, y
);
153 return arc_dist
< a
->Thickness
/ 2;
156 /* Cross c->u and c->v, return the magnitute */
158 cross2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
164 return (double)ux
* vy
- (double)uy
* vx
;
167 /* Likewise, for dot product. */
169 dot2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
175 return (double)ux
* vx
+ (double)uy
* vy
;
179 /* angle of c->v, relative to c->u, in radians. Range is -pi..pi */
181 angle2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
184 double magu
, magv
, sintheta
;
186 printf("angle2d %d,%d %d,%d %d,%d\n", cx
, cy
, ux
, uy
, vx
, vy
);
193 printf(" = %d,%d %d,%d\n", ux
, uy
, vx
, vy
);
195 cross
= (double)ux
* vy
- (double)uy
* vx
;
196 magu
= sqrt((double)ux
*ux
+ (double)uy
*uy
);
197 magv
= sqrt((double)vx
*vx
+ (double)vy
*vy
);
198 sintheta
= cross
/ (magu
* magv
);
200 printf(" = %f / (%f * %f) = %f\n", cross
, magu
, magv
, sintheta
);
202 return asin (sintheta
);
207 same_sign (double a
, double b
)
215 return 180.0 * r
/ M_PI
;
221 return M_PI
* d
/ 180.0;
227 det (double a
, double b
, double c
, double d
)
229 return a
* d
- b
* c
;
232 /* The lines are x1y1-x2y2 and x3y3-x4y4. Returns true if they
235 intersection_of_lines (int x1
, int y1
, int x2
, int y2
,
236 int x3
, int y3
, int x4
, int y4
,
240 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
243 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
244 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
245 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
246 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
247 *xr
= (int) (x
+ 0.5);
248 *yr
= (int) (y
+ 0.5);
252 /* Same, for line segments. Returns true if they intersect. For this
253 function, xr and yr may be NULL if you don't need the values. */
255 intersection_of_linesegs (int x1
, int y1
, int x2
, int y2
,
256 int x3
, int y3
, int x4
, int y4
,
260 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
263 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
264 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
265 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
266 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
267 if (MIN (x1
, x2
) > x
|| x
> MAX (x1
, x2
)
268 || MIN (y1
, y2
) > y
|| y
> MAX (y1
, y2
))
270 if (MIN (x3
, x4
) > x
|| x
> MAX (x3
, x4
)
271 || MIN (y3
, y4
) > y
|| y
> MAX (y3
, y4
))
274 *xr
= (int) (x
+ 0.5);
276 *yr
= (int) (y
+ 0.5);
280 /* distance between a line and a point */
282 dist_lp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
284 double den
= dist (x1
, y1
, x2
, y2
);
285 double rv
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
286 - ((double)x1
- px
) * ((double)y2
- y1
))
289 printf("dist (%d,%d-%d,%d) to %d,%d is %f\n",
290 x1
, y1
, x2
, y2
, px
, py
, rv
);
295 /* distance between a line segment and a point */
297 dist_lsp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
300 if (dot2d (x1
, y1
, x2
, y2
, px
, py
) < 0)
301 return dist (x1
, y1
, px
, py
);
302 if (dot2d (x2
, y2
, x1
, y1
, px
, py
) < 0)
303 return dist (x2
, y2
, px
, py
);
304 d
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
305 - ((double)x1
- px
) * ((double)y2
- y1
))
306 / dist (x1
, y1
, x2
, y2
));
310 /*****************************************************************************/
312 /* Single Point Puller */
314 /*****************************************************************************/
317 line_callback (const BoxType
* b
, void *cl
)
319 /* LayerTypePtr layer = (LayerTypePtr)cl; */
320 LineTypePtr l
= (LineTypePtr
) b
;
323 printf ("line %d,%d .. %d,%d\n",
324 l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
326 d1
= dist (l
->Point1
.X
, l
->Point1
.Y
, x
, y
);
327 d2
= dist (l
->Point2
.X
, l
->Point2
.Y
, x
, y
);
328 if ((d1
< 2 || d2
< 2) && !line_exact
)
333 t
= line_exact
? 2 : l
->Thickness
/ 2;
334 if (d1
< t
|| d2
< t
)
340 printf ("picked, exact %d\n", line_exact
);
347 arc_callback (const BoxType
* b
, void *cl
)
349 /* LayerTypePtr layer = (LayerTypePtr) cl; */
350 ArcTypePtr a
= (ArcTypePtr
) b
;
353 printf ("arc a %d,%d r %d sa %ld d %ld\n", a
->X
, a
->Y
, a
->Width
,
354 a
->StartAngle
, a
->Delta
);
356 if (!arc_endpoint_is (a
, a
->StartAngle
, x
, y
)
357 && !arc_endpoint_is (a
, a
->StartAngle
+ a
->Delta
, x
, y
))
370 printf ("picked, exact %d\n", arc_exact
);
379 printf ("picked, exact %d\n", arc_exact
);
386 find_pair (int Px
, int Py
)
391 printf ("\nPuller find_pair at %d,%d\n", Crosshair
.X
, Crosshair
.Y
);
397 line_exact
= arc_exact
= 0;
404 r_search (CURRENT
->line_tree
, &spot
, NULL
, line_callback
, CURRENT
);
405 r_search (CURRENT
->arc_tree
, &spot
, NULL
, arc_callback
, CURRENT
);
406 if (the_line
&& the_arc
&& !multi
)
414 static const char puller_syntax
[] = "Puller()";
416 static const char puller_help
[] = "Pull an arc-line junction tight.";
418 /* %start-doc actions Puller
420 The @code{Puller()} action is a special-purpose optimization. When
421 invoked while the crosshair is over the junction of an arc and a line,
422 it will adjust the arc's angle and the connecting line's endpoint such
423 that the line intersects the arc at a tangent. In the example below,
424 the left side is ``before'' with the black target marking where to put
427 @center @image{puller,,,Example of how puller works,png}
429 The right side is ``after'' with the black target marking where the
430 arc-line intersection was moved to.
435 Puller (int argc
, char **argv
, int Ux
, int Uy
)
437 double arc_angle
, line_angle
, rel_angle
, base_angle
;
441 if (!find_pair (Crosshair
.X
, Crosshair
.Y
))
442 if (!find_pair (Ux
, Uy
))
445 if (within (the_line
->Point1
.X
, the_line
->Point1
.Y
,
446 x
, y
, the_line
->Thickness
))
448 ex
= the_line
->Point2
.X
;
449 ey
= the_line
->Point2
.Y
;
450 the_line
->Point2
.X
= the_line
->Point1
.X
;
451 the_line
->Point2
.Y
= the_line
->Point1
.Y
;
452 the_line
->Point1
.X
= ex
;
453 the_line
->Point1
.Y
= ey
;
455 else if (!within (the_line
->Point2
.X
, the_line
->Point2
.Y
,
456 x
, y
, the_line
->Thickness
))
459 printf ("Line endpoint not at cursor\n");
463 ex
= the_line
->Point1
.X
;
464 ey
= the_line
->Point1
.Y
;
468 if (arc_endpoint_is (the_arc
, the_arc
->StartAngle
, x
, y
))
470 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
473 else if (!arc_endpoint_is (the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
477 printf ("arc not endpoints\n");
482 if (within (cx
, cy
, ex
, ey
, the_arc
->Width
* 2))
485 printf ("line ends inside arc\n");
490 if (the_arc
->Delta
> 0)
491 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
+ 90;
493 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
- 90;
494 line_angle
= r2d (atan2 (ey
- y
, x
- ex
));
495 rel_angle
= line_angle
- arc_angle
;
496 base_angle
= r2d (atan2 (ey
- cy
, cx
- ex
));
498 tangent
= r2d (acos (the_arc
->Width
/ dist (cx
, cy
, ex
, ey
)));
501 printf ("arc %g line %g rel %g base %g\n", arc_angle
, line_angle
, rel_angle
,
503 printf ("tangent %g\n", tangent
);
505 printf ("arc was start %ld end %ld\n", the_arc
->StartAngle
,
506 the_arc
->StartAngle
+ the_arc
->Delta
);
509 if (the_arc
->Delta
> 0)
510 arc_angle
= base_angle
- tangent
;
512 arc_angle
= base_angle
+ tangent
;
514 printf ("new end angle %g\n", arc_angle
);
517 new_delta_angle
= arc_angle
- the_arc
->StartAngle
;
518 if (new_delta_angle
> 180)
519 new_delta_angle
-= 360;
520 if (new_delta_angle
< -180)
521 new_delta_angle
+= 360;
522 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
, new_delta_angle
);
525 printf ("arc now start %ld end %ld\n", the_arc
->StartAngle
,
526 the_arc
->StartAngle
+ new_delta_angle
);
529 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
;
530 x
= the_arc
->X
- the_arc
->Width
* cos (d2r (arc_angle
)) + 0.5;
531 y
= the_arc
->Y
+ the_arc
->Height
* sin (d2r (arc_angle
)) + 0.5;
533 MoveObject (LINEPOINT_TYPE
, CURRENT
, the_line
, &(the_line
->Point2
),
534 x
- the_line
->Point2
.X
, y
- the_line
->Point2
.Y
);
536 gui
->invalidate_all ();
537 IncrementUndoSerialNumber ();
542 /*****************************************************************************/
546 /*****************************************************************************/
548 static const char globalpuller_syntax
[] =
551 static const char globalpuller_help
[] =
552 "Pull all traces tight.";
554 /* %start-doc actions GlobalPuller
558 /* Ok, here's the deal. We look for the intersection of two traces.
559 The triangle formed by those traces is searched for things we need
560 to avoid. From the other two corners of the triangle, we compute
561 the angle to each obstacle, and remember the ones closest to the
562 start angles. If the two traces hit the same obstacle, we put in
563 the arc and we're done. Else, we bring the traces up to the
564 obstacles and start again.
566 Note that we assume each start point is a tangent to an arc. We
567 start with a radius of zero, but future steps use the arcs we
570 For obstacles, we list each round pin, pad, via, and line/arc
571 endpoints as points with a given radius. For each square pin, pad,
572 via, and polygon points, we list each corner with a zero radius.
573 We also list arcs from their centerpoint.
575 We don't currently do anything to move vias, or intersections of
576 three or more traces. In the future, three-way intersections will
577 be handles similarly to two-way - calculate the range of angles
578 valid from each of the three other endpoints, choose the angle
579 closest to making 120 degree angles at the center. For four-way or
580 more intersections, we break them up into multiple three-way
583 For simplicity, we only do the current layer at this time. We will
584 also edit the lines and arcs in place so that the intersection is
585 always on the second point, and the other ends are always at
586 start+delta for arcs.
588 We also defer intersections which are blocked by other
589 intersections yet to be moved; the idea is to wait until those have
590 been moved so we don't end up with arcs that no longer wrap around
591 things. At a later point, we may choose to pull arced corners in
594 You'll see lots of variables of the form "foo_sign" which keep
595 track of which way things are pointing. This is because everything
596 is relative to corners and arcs, not absolute directions.
599 static int nloops
, npulled
;
604 fprintf(stderr
, "%6d loops, %d pulled \r", nloops
, npulled
);
607 /* Extra data we need to temporarily attach to all lines and arcs. */
609 /* These point to "multi_next" if there are more than one. */
612 unsigned char in_pin
:1;
613 unsigned char at_pin
:1;
614 unsigned char is_pad
:1;
615 unsigned char pending
:1; /* set if this may be moved later */
616 int x
, y
; /* arc endpoint */
617 /* If not NULL, points to End with pending==1 we're blocked on. */
618 struct End
*waiting_for
;
621 typedef struct Extra
{
624 unsigned char found
:1;
625 unsigned char deleted
:1;
628 static Extra multi_next
;
631 static int nlines
, narcs
, max_lines
, max_arcs
;
632 static int did_something
;
633 static int current_is_component
, current_is_solder
;
635 /* If set, these are the pins/pads/vias that this path ends on. */
636 /* static void *start_pin_pad, *end_pin_pad; */
639 static void trace_paths ();
641 static void mark_line_for_deletion (LineTypePtr
);
643 #define LINE2EXTRA(l) (lines[(l)-CURRENT->Line])
644 #define ARC2EXTRA(a) (arcs[(a)-CURRENT->Arc])
645 #define EXTRA2LINE(e) (CURRENT->Line[(e)-lines])
646 #define EXTRA2ARC(e) (CURRENT->Arc[(e)-arcs])
647 #define EXTRA_IS_LINE(e) ((unsigned)(e-lines) < nlines)
648 #define EXTRA_IS_ARC(e) ((unsigned)(e-arcs) < narcs)
651 unlink_end (Extra
*x
, Extra
**e
)
655 if ((*e
)->start
.next
== x
)
658 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
660 (*e
)->start
.next
= &multi_next
;
662 if ((*e
)->end
.next
== x
)
665 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
667 (*e
)->end
.next
= &multi_next
;
671 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
));
681 for (i
=0; i
<nlines
; i
++)
683 for (i
=0; i
<narcs
; i
++)
689 fix_arc_extra (ArcTypePtr a
, Extra
*e
)
692 printf("new arc angles %ld %ld\n", a
->StartAngle
, a
->Delta
);
694 e
->start
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
)) + 0.5);
695 e
->start
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
)) + 0.5);
696 e
->end
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
697 e
->end
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
699 printf("new X,Y is %d,%d to %d,%d\n", e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
708 } FindPairCallbackStruct
;
710 #define NEAR(a,b) ((a) <= (b) + 2 && (a) >= (b) - 2)
713 find_pair_line_callback (const BoxType
* b
, void *cl
)
715 LineTypePtr line
= (LineTypePtr
) b
;
717 Extra
*e
= & LINE2EXTRA (line
);
719 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
721 if (line
== fpcs
->me
)
723 #ifdef CHECK_LINE_PT_NEG
724 if (line
->Point1
.X
< 0)
728 printf(" - %p line %d,%d or %d,%d\n", e
, line
->Point1
.X
, line
->Point1
.Y
,
729 line
->Point2
.X
, line
->Point2
.Y
);
731 if ((NEAR (line
->Point1
.X
, fpcs
->x
) && NEAR (line
->Point1
.Y
, fpcs
->y
))
732 || (NEAR (line
->Point2
.X
, fpcs
->x
) && NEAR (line
->Point2
.Y
, fpcs
->y
)))
734 if (* fpcs
->extra_ptr
)
737 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
739 *fpcs
->extra_ptr
= & multi_next
;
743 *fpcs
->extra_ptr
= & LINE2EXTRA (line
);
745 printf(" - next now %p\n", *fpcs
->extra_ptr
);
753 find_pair_arc_callback (const BoxType
* b
, void *cl
)
755 ArcTypePtr arc
= (ArcTypePtr
) b
;
756 Extra
*e
= & ARC2EXTRA (arc
);
757 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
762 printf(" - %p arc %d,%d or %d,%d\n", e
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
764 if ((NEAR (e
->start
.x
, fpcs
->x
) && NEAR (e
->start
.y
, fpcs
->y
))
765 || (NEAR (e
->end
.x
, fpcs
->x
) && NEAR (e
->end
.y
, fpcs
->y
)))
767 if (* fpcs
->extra_ptr
)
770 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
772 *fpcs
->extra_ptr
= & multi_next
;
775 *fpcs
->extra_ptr
= e
;
781 find_pairs_1 (void *me
, Extra
**e
, int x
, int y
)
783 FindPairCallbackStruct fpcs
;
794 printf("looking for %d,%d\n", x
, y
);
800 r_search(CURRENT
->line_tree
, &b
, NULL
, find_pair_line_callback
, &fpcs
);
801 r_search(CURRENT
->arc_tree
, &b
, NULL
, find_pair_arc_callback
, &fpcs
);
805 check_point_in_pin (PinTypePtr pin
, int x
, int y
, End
*e
)
808 int t
= (pin
->Thickness
+1)/2;
809 if (TEST_FLAG (SQUAREFLAG
, pin
))
810 inside_p
= (x
>= pin
->X
- t
&& x
<= pin
->X
+ t
811 && y
>= pin
->Y
- t
&& y
<= pin
->Y
+ t
);
813 inside_p
= (dist (pin
->X
, pin
->Y
, x
, y
) <= t
);
818 if (pin
->X
== x
&& pin
->Y
== y
)
827 find_pair_pinline_callback (const BoxType
* b
, void *cl
)
829 LineTypePtr line
= (LineTypePtr
) b
;
830 PinTypePtr pin
= (PinTypePtr
) cl
;
831 Extra
*e
= & LINE2EXTRA (line
);
834 #ifdef CHECK_LINE_PT_NEG
835 if (line
->Point1
.X
< 0)
839 hits
= check_point_in_pin (pin
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
840 hits
+= check_point_in_pin (pin
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
845 /* See if the line passes through this pin. */
846 /* FIXME: this assumes round pads, but it's good enough for square
848 if (dist_lsp (line
->Point1
.X
, line
->Point1
.Y
,
849 line
->Point2
.X
, line
->Point2
.Y
,
850 pin
->X
, pin
->Y
) <= pin
->Thickness
/2)
853 printf("splitting line %d,%d-%d,%d because it passes through pin %d,%d r%d\n",
854 line
->Point1
.X
, line
->Point1
.Y
,
855 line
->Point2
.X
, line
->Point2
.Y
,
856 pin
->X
, pin
->Y
, pin
->Thickness
/2);
858 unlink_end (e
, &e
->start
.next
);
859 unlink_end (e
, &e
->end
.next
);
865 find_pair_pinarc_callback (const BoxType
* b
, void *cl
)
867 ArcTypePtr arc
= (ArcTypePtr
) b
;
868 PinTypePtr pin
= (PinTypePtr
) cl
;
869 Extra
*e
= & ARC2EXTRA (arc
);
872 hits
= check_point_in_pin (pin
, e
->start
.x
, e
->start
.y
, &(e
->start
));
873 hits
+= check_point_in_pin (pin
, e
->end
.x
, e
->end
.y
, &(e
->end
));
878 check_point_in_pad (PadTypePtr pad
, int x
, int y
, End
*e
)
883 printf("pad %d,%d - %d,%d t %d vs %d,%d\n", pad
->Point1
.X
, pad
->Point1
.Y
,
884 pad
->Point2
.X
, pad
->Point2
.Y
, pad
->Thickness
, x
, y
);
885 t
= (pad
->Thickness
+1)/2;
886 if (TEST_FLAG (SQUAREFLAG
, pad
))
888 inside_p
= (x
>= MIN (pad
->Point1
.X
- t
, pad
->Point2
.X
- t
)
889 && x
<= MAX (pad
->Point1
.X
+ t
, pad
->Point2
.X
+ t
)
890 && y
>= MIN (pad
->Point1
.Y
- t
, pad
->Point2
.Y
- t
)
891 && y
<= MAX (pad
->Point1
.Y
+ t
, pad
->Point2
.Y
+ t
));
892 printf(" - inside_p = %d\n", inside_p
);
896 if (pad
->Point1
.X
== pad
->Point2
.X
)
898 inside_p
= (x
>= pad
->Point1
.X
- t
899 && x
<= pad
->Point1
.X
+ t
900 && y
>= MIN (pad
->Point1
.Y
, pad
->Point2
.Y
)
901 && y
<= MAX (pad
->Point1
.Y
, pad
->Point2
.Y
));
905 inside_p
= (x
>= MIN (pad
->Point1
.X
, pad
->Point2
.X
)
906 && x
<= MAX (pad
->Point1
.X
, pad
->Point2
.X
)
907 && y
>= pad
->Point1
.Y
- t
908 && y
<= pad
->Point1
.Y
+ t
);
912 if (dist (pad
->Point1
.X
, pad
->Point1
.Y
, x
, y
) <= t
913 || dist (pad
->Point2
.X
, pad
->Point2
.Y
, x
, y
) <= t
)
921 if (pad
->Point1
.X
== x
&& pad
->Point1
.Y
== y
)
923 if (pad
->Point2
.X
== x
&& pad
->Point2
.Y
== y
)
933 find_pair_padline_callback (const BoxType
* b
, void *cl
)
935 LineTypePtr line
= (LineTypePtr
) b
;
936 PadTypePtr pad
= (PadTypePtr
) cl
;
937 Extra
*e
= & LINE2EXTRA (line
);
943 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
945 if (!current_is_solder
)
950 if (!current_is_component
)
954 #ifdef CHECK_LINE_PT_NEG
955 if (line
->Point1
.X
< 0)
959 hits
= check_point_in_pad (pad
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
960 hits
+= check_point_in_pad (pad
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
965 /* Ok, something strange. The line intersects our space, but
966 doesn't end in our space. See if it just passes through us, and
969 t
= (pad
->Thickness
+ 1)/2;
970 /* FIXME: this is for round pads. Good enough for now, but add
971 square pad support later. */
972 intersect
= intersection_of_linesegs (pad
->Point1
.X
, pad
->Point1
.Y
,
973 pad
->Point2
.X
, pad
->Point2
.Y
,
974 line
->Point1
.X
, line
->Point1
.Y
,
975 line
->Point2
.X
, line
->Point2
.Y
,
977 p1_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
978 line
->Point2
.X
, line
->Point2
.Y
,
979 pad
->Point1
.X
, pad
->Point1
.Y
);
980 p2_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
981 line
->Point2
.X
, line
->Point2
.Y
,
982 pad
->Point2
.X
, pad
->Point2
.Y
);
984 if (intersect
|| p1_d
< t
|| p2_d
< t
)
987 /* FIXME: we should split the line. */
989 printf("splitting line %d,%d-%d,%d because it passes through pad %d,%d-%d,%d r%d\n",
990 line
->Point1
.X
, line
->Point1
.Y
,
991 line
->Point2
.X
, line
->Point2
.Y
,
992 pad
->Point1
.X
, pad
->Point1
.Y
,
993 pad
->Point2
.X
, pad
->Point2
.Y
,
996 unlink_end (e
, &e
->start
.next
);
997 unlink_end (e
, &e
->end
.next
);
1004 find_pair_padarc_callback (const BoxType
* b
, void *cl
)
1006 ArcTypePtr arc
= (ArcTypePtr
) b
;
1007 PadTypePtr pad
= (PadTypePtr
) cl
;
1008 Extra
*e
= & ARC2EXTRA (arc
);
1011 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
1013 if (!current_is_solder
)
1018 if (!current_is_component
)
1022 hits
= check_point_in_pad (pad
, e
->start
.x
, e
->start
.y
, &(e
->start
));
1023 hits
+= check_point_in_pad (pad
, e
->end
.x
, e
->end
.y
, &(e
->end
));
1031 ARC_LOOP (CURRENT
); {
1032 Extra
*e
= & ARC2EXTRA (arc
);
1033 fix_arc_extra (arc
, e
);
1036 LINE_LOOP (CURRENT
); {
1037 Extra
*e
= & LINE2EXTRA (line
);
1038 if (line
->Point1
.X
>= 0)
1040 find_pairs_1 (line
, & e
->start
.next
, line
->Point1
.X
, line
->Point1
.Y
);
1041 find_pairs_1 (line
, & e
->end
.next
, line
->Point2
.X
, line
->Point2
.Y
);
1045 ARC_LOOP (CURRENT
); {
1046 Extra
*e
= & ARC2EXTRA (arc
);
1049 find_pairs_1 (arc
, & e
->start
.next
, e
->start
.x
, e
->start
.y
);
1050 find_pairs_1 (arc
, & e
->end
.next
, e
->end
.x
, e
->end
.y
);
1054 ALLPIN_LOOP (PCB
->Data
); {
1056 box
.X1
= pin
->X
- pin
->Thickness
/2;
1057 box
.Y1
= pin
->Y
- pin
->Thickness
/2;
1058 box
.X2
= pin
->X
+ pin
->Thickness
/2;
1059 box
.Y2
= pin
->Y
+ pin
->Thickness
/2;
1060 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, pin
);
1061 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, pin
);
1064 VIA_LOOP (PCB
->Data
); {
1066 box
.X1
= via
->X
- via
->Thickness
/2;
1067 box
.Y1
= via
->Y
- via
->Thickness
/2;
1068 box
.X2
= via
->X
+ via
->Thickness
/2;
1069 box
.Y2
= via
->Y
+ via
->Thickness
/2;
1070 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, via
);
1071 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, via
);
1074 ALLPAD_LOOP (PCB
->Data
); {
1076 box
.X1
= MIN(pad
->Point1
.X
, pad
->Point2
.X
) - pad
->Thickness
/2;
1077 box
.Y1
= MIN(pad
->Point1
.Y
, pad
->Point2
.Y
) - pad
->Thickness
/2;
1078 box
.X2
= MAX(pad
->Point1
.X
, pad
->Point2
.X
) + pad
->Thickness
/2;
1079 box
.Y2
= MAX(pad
->Point1
.Y
, pad
->Point2
.Y
) + pad
->Thickness
/2;
1080 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_padline_callback
, pad
);
1081 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_padarc_callback
, pad
);
1085 for (i
=0; i
<nlines
; i
++)
1087 if (lines
[i
].start
.next
== &multi_next
)
1088 lines
[i
].start
.next
= 0;
1089 if (lines
[i
].end
.next
== &multi_next
)
1090 lines
[i
].end
.next
= 0;
1092 for (i
=0; i
<narcs
; i
++)
1094 if (arcs
[i
].start
.next
== &multi_next
)
1095 arcs
[i
].start
.next
= 0;
1096 if (arcs
[i
].end
.next
== &multi_next
)
1097 arcs
[i
].end
.next
= 0;
1101 #define PROP_NEXT(e,n,f) \
1102 if (f->next->start.next == e) { \
1112 propogate_ends_at (Extra
*e
, End
*near
, End
*far
)
1114 while (far
->in_pin
&& far
->pin
== near
->pin
)
1119 PROP_NEXT (e
, near
, far
);
1125 propogate_end_pin (Extra
*e
, End
*near
, End
*far
)
1127 void *pinpad
= near
->pin
;
1128 int ispad
= near
->is_pad
;
1131 PROP_NEXT (e
, near
, far
);
1132 if (near
->pin
== pinpad
)
1135 near
->is_pad
= ispad
;
1144 /* First, shut of "in pin" when we have an "at pin". We also clean
1145 up zero-length lines. */
1146 for (i
=0; i
<nlines
; i
++)
1148 if (lines
[i
].start
.next
&& lines
[i
].start
.next
== lines
[i
].end
.next
)
1150 lines
[i
].end
.next
= 0;
1151 mark_line_for_deletion (CURRENT
->Line
+ i
);
1153 if (lines
[i
].start
.at_pin
)
1154 propogate_ends_at (&lines
[i
], &lines
[i
].start
, &lines
[i
].end
);
1155 if (lines
[i
].end
.at_pin
)
1156 propogate_ends_at (&lines
[i
], &lines
[i
].end
, &lines
[i
].start
);
1159 /* Now end all paths at pins/pads. */
1160 for (i
=0; i
<nlines
; i
++)
1162 if (lines
[i
].start
.in_pin
)
1165 printf("MULTI at %d: %d was %p\n", __LINE__
, i
, lines
[i
].start
.next
);
1167 lines
[i
].start
.next
= 0;
1169 if (lines
[i
].end
.in_pin
)
1172 printf("MULTI at %d: %d was %p\n", __LINE__
, i
, lines
[i
].end
.next
);
1174 lines
[i
].end
.next
= 0;
1178 /* Now, propogate the pin/pad/vias along paths. */
1179 for (i
=0; i
<nlines
; i
++)
1181 if (lines
[i
].start
.next
)
1182 propogate_end_pin (&lines
[i
], &lines
[i
].end
, &lines
[i
].start
);
1183 if (lines
[i
].end
.next
)
1184 propogate_end_pin (&lines
[i
], &lines
[i
].start
, &lines
[i
].end
);
1188 static Extra
*last_pextra
= 0;
1191 print_extra (Extra
*e
, Extra
*prev
)
1194 if (e
->start
.next
== last_pextra
)
1196 else if (e
->end
.next
== last_pextra
)
1200 printf("%10p %10p %10p :", e
, e
->start
.next
, e
->end
.next
);
1203 printf("%10p \033[33m%10p\033[0m %10p :", e
, e
->start
.next
, e
->end
.next
);
1206 printf("%10p %10p \033[33m%10p\033[0m :", e
, e
->start
.next
, e
->end
.next
);
1211 e
->deleted
? 'd' : '-',
1212 e
->found
? 'f' : '-');
1213 printf(" s:%s%s%s%s",
1214 e
->start
.in_pin
? "I" : "-",
1215 e
->start
.at_pin
? "A" : "-",
1216 e
->start
.is_pad
? "P" : "-",
1217 e
->start
.pending
? "p" : "-");
1218 printf(" e:%s%s%s%s ",
1219 e
->end
.in_pin
? "I" : "-",
1220 e
->end
.at_pin
? "A" : "-",
1221 e
->end
.is_pad
? "P" : "-",
1222 e
->end
.pending
? "p" : "-");
1224 if (EXTRA_IS_LINE (e
))
1226 LineTypePtr line
= & EXTRA2LINE (e
);
1227 printf(" %4d L %d,%d-%d,%d", (int)(line
-CURRENT
->Line
), line
->Point1
.X
, line
->Point1
.Y
, line
->Point2
.X
, line
->Point2
.Y
);
1228 printf(" %s %p %s %p\n",
1229 e
->start
.is_pad
? "pad" : "pin", e
->start
.pin
,
1230 e
->end
.is_pad
? "pad" : "pin", e
->end
.pin
);
1232 else if (EXTRA_IS_ARC (e
))
1234 ArcTypePtr arc
= & EXTRA2ARC (e
);
1235 printf(" %4d A %d,%d-%d,%d", (int) (arc
-CURRENT
->Arc
), e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
1236 printf(" at %d,%d ang %ld,%ld\n", arc
->X
, arc
->Y
, arc
->StartAngle
, arc
->Delta
);
1238 else if (e
== &multi_next
)
1240 printf("-- Multi-next\n");
1244 printf("-- Unknown extra: %p\n", e
);
1250 trace_path (Extra
*e
)
1253 if ((e
->start
.next
&& e
->end
.next
)
1254 || (!e
->start
.next
&& !e
->end
.next
))
1258 printf("- path -\n");
1263 print_extra (e
, prev
);
1264 if (e
->start
.next
== prev
)
1283 LINE_LOOP (CURRENT
); {
1284 e
= & LINE2EXTRA (line
);
1287 ARC_LOOP (CURRENT
); {
1288 e
= & ARC2EXTRA (arc
);
1295 reverse_line (LineTypePtr line
)
1297 Extra
*e
= & LINE2EXTRA (line
);
1304 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point1
),
1305 line
->Point2
.X
- line
->Point1
.X
,
1306 line
->Point2
.Y
- line
->Point1
.Y
);
1307 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point2
),
1309 y
- line
->Point2
.Y
);
1311 /* In theory, we should be using the above so that undo works. */
1312 line
->Point1
.X
= line
->Point2
.X
;
1313 line
->Point1
.Y
= line
->Point2
.Y
;
1317 memcpy (&etmp
, &e
->start
, sizeof (End
));
1318 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1319 memcpy (&e
->end
, &etmp
, sizeof (End
));
1323 reverse_arc (ArcTypePtr arc
)
1325 Extra
*e
= & ARC2EXTRA (arc
);
1329 ChangeArcAngles (CURRENT
, arc
,
1330 arc
->StartAngle
+ arc
->Delta
, -arc
->Delta
);
1332 /* Likewise, see above. */
1333 arc
->StartAngle
+= arc
->Delta
;
1336 memcpy (&etmp
, &e
->start
, sizeof (End
));
1337 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1338 memcpy (&e
->end
, &etmp
, sizeof (End
));
1342 expand_box (BoxTypePtr b
, int x
, int y
, int t
)
1344 b
->X1
= MIN (b
->X1
, x
-t
);
1345 b
->X2
= MAX (b
->X2
, x
+t
);
1346 b
->Y1
= MIN (b
->Y1
, y
-t
);
1347 b
->Y2
= MAX (b
->Y2
, y
+t
);
1350 /* ---------------------------------------------------------------------- */
1351 /* These are the state variables for the intersection we're currently
1354 /* what we're working with */
1355 static ArcTypePtr start_arc
;
1356 static LineTypePtr start_line
;
1357 static LineTypePtr end_line
;
1358 static ArcTypePtr end_arc
;
1359 static Extra
*start_extra
, *end_extra
;
1360 static Extra
*sarc_extra
, *earc_extra
;
1361 static void *start_pinpad
, *end_pinpad
;
1362 static int thickness
;
1364 /* Pre-computed values. Note that all values are computed according
1365 to CARTESIAN coordinates, not PCB coordinates. Do an up-down board
1366 flip before wrapping your brain around the math. */
1368 /* se_sign is positive when you make a right turn going from start to end. */
1369 /* sa_sign is positive when start's arc is on the same side of start as end. */
1370 /* ea_sign is positive when end's arc is on the same side of end as start. */
1371 /* sa_sign and ea_sign may be zero if there's no arc. */
1372 static double se_sign
, sa_sign
, ea_sign
;
1374 static double best_angle
, start_angle
, end_dist
;
1375 /* arc radii are positive when they're on the same side as the things
1376 we're interested in. */
1377 static int sa_r
, ea_r
;
1378 static int sa_x
, sa_y
; /* start "arc" point */
1380 /* what we've found so far */
1381 static int fx
, fy
, fr
, fp
;
1383 static double fa
; /* relative angle */
1385 #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__)
1388 gp_point_force (int x
, int y
, int t
, End
*e
, int esa
, int eda
, int force
, const char *name
)
1392 double base_angle
, rel_angle
, point_angle
;
1395 printf("\033[34mgp_point_force %d,%d %d via %s\033[0m\n", x
, y
, t
, name
);
1402 sr
= start_arc
->Width
;
1406 scx
= start_line
->Point1
.X
;
1407 scy
= start_line
->Point1
.Y
;
1413 /* See if the point is inside our start arc. */
1414 d
= dist (scx
, scy
, x
, y
);
1416 printf("%f = dist (%d,%d to %d,%d)\n", d
, scx
, scy
, x
, y
);
1417 printf("sr %d r %f d %f\n", sr
, r
, d
);
1422 printf("inside start arc, %f < %f\n", d
, sr
-r
);
1426 if (sr
== 0 && d
< r
)
1429 printf("start is inside arc, %f < %f\n", d
, r
);
1434 /* Now for the same tricky math we needed for the single puller.
1435 sr and r are the radii for the two points scx,scy and x,y. */
1437 /* angle between points (NOT pcb arc angles) */
1438 base_angle
= atan2 (y
- scy
, x
- scx
);
1440 printf("%.1f = atan2 (%d-%d = %d, %d-%d = %d)\n",
1441 r2d(base_angle
), y
, scy
, y
-scy
, x
, scx
, x
-scx
);
1444 if ((sa_sign
* sr
- r
) / d
> 1
1445 || (sa_sign
* sr
- r
) / d
< -1)
1448 /* Angle of tangent, relative to the angle between point centers. */
1449 rel_angle
= se_sign
* asin ((sa_sign
* sr
- r
) / d
);
1451 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n",
1452 r2d(rel_angle
), (int)se_sign
, (int)sa_sign
, sr
, r
, d
);
1455 /* Absolute angle of tangent. */
1456 point_angle
= base_angle
+ rel_angle
;
1458 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n",
1466 /* Check arc angles */
1467 double pa
= point_angle
;
1468 double sa
= d2r(180-esa
);
1469 double da
= d2r(-eda
);
1477 pa
-= se_sign
* M_PI
/2;
1485 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n",
1486 r2d(sa
), r2d(da
), r2d(pa
));
1492 a
= point_angle
- start_angle
;
1498 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a
));
1501 if (!force
&& a
* se_sign
< -0.007)
1505 printf("skipping, would increase angle (%f * %f)\n", a
, se_sign
);
1507 new_r
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1508 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1511 printf("point %d,%d dist %f vs thickness %d\n", x
, y
, new_r
, thickness
);
1514 new_r
= (int)new_r
- 1;
1516 printf(" - new thickness %f old %d\n", new_r
, t
);
1519 gp_point_force (x
, y
, new_r
, e
, esa
, eda
, 1, __FUNCTION__
);
1524 printf("%f * %f < %f * %f ?\n", a
, se_sign
, best_angle
, se_sign
);
1526 if (a
* se_sign
== best_angle
* se_sign
)
1528 double old_d
= dist (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1530 double new_d
= dist (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1539 fp
= e
? e
->pending
: 0;
1543 else if (a
* se_sign
< best_angle
* se_sign
)
1550 fp
= e
? e
->pending
: 0;
1557 gp_point_2 (int x
, int y
, int t
, End
*e
, int esa
, int eda
, const char *func
)
1562 if (x
== sa_x
&& y
==sa_y
)
1566 printf("\033[34mgp_point %d,%d %d via %s\033[0m\n", x
, y
, t
, func
);
1569 /* There are two regions we care about. For points inside our
1570 triangle, we check the crosses against start_line and end_line to
1571 make sure the point is "inside" the triangle. For points on the
1572 other side of the s-e line of the triangle, we check the dots to
1573 make sure it's between our endpoints. */
1575 /* See what side of the s-e line we're on */
1576 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1577 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1580 printf("s-e cross = %f\n", sc
);
1584 if (same_sign (sc
, se_sign
))
1586 /* Outside, check dots. */
1588 /* Ok, is it "in front of" our vectors? */
1589 sd
= dot2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1590 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1593 printf("sd = %f\n", sd
);
1598 ed
= dot2d (end_line
->Point2
.X
, end_line
->Point2
.Y
,
1599 start_line
->Point1
.X
, start_line
->Point1
.Y
,
1602 printf("ed = %f\n", ed
);
1607 sd
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1608 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1610 if (sd
> t
+ thickness
)
1615 /* Inside, check crosses. */
1617 /* First off, is it on the correct side of the start line? */
1618 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1619 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1622 printf("sc = %f\n", sc
);
1624 if (! same_sign (sc
, se_sign
))
1627 /* Ok, is it on the correct side of the end line? */
1628 ec
= cross2d (end_line
->Point1
.X
, end_line
->Point1
.Y
,
1629 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1632 printf("ec = %f\n", ec
);
1634 if (! same_sign (ec
, se_sign
))
1640 printf("in range!\n");
1643 return gp_point_force (x
, y
, t
, e
, esa
, eda
, 0, func
);
1647 gp_line_cb (const BoxType
*b
, void *cb
)
1649 const LineTypePtr l
= (LineTypePtr
) b
;
1650 Extra
*e
= &LINE2EXTRA(l
);
1651 if (l
== start_line
|| l
== end_line
)
1655 #ifdef CHECK_LINE_PT_NEG
1656 if (l
->Point1
.X
< 0)
1660 || ! EXTRA_IS_ARC (e
->start
.next
))
1661 gp_point (l
->Point1
.X
, l
->Point1
.Y
, l
->Thickness
/2, &e
->start
);
1663 || ! EXTRA_IS_ARC (e
->end
.next
))
1664 gp_point (l
->Point2
.X
, l
->Point2
.Y
, l
->Thickness
/2, &e
->end
);
1669 gp_arc_cb (const BoxType
*b
, void *cb
)
1671 const ArcTypePtr a
= (ArcTypePtr
) b
;
1672 Extra
*e
= & ARC2EXTRA(a
);
1673 if (a
== start_arc
|| a
== end_arc
)
1677 gp_point_2 (a
->X
, a
->Y
, a
->Width
+ a
->Thickness
/2, 0, a
->StartAngle
, a
->Delta
, __FUNCTION__
);
1679 && a
->X
== start_arc
->X
1680 && a
->Y
== start_arc
->Y
)
1683 && a
->X
!= end_arc
->X
1684 && a
->Y
!= end_arc
->Y
)
1687 if (e
->start
.next
|| e
->end
.next
)
1690 gp_point (e
->start
.x
, e
->start
.y
, a
->Thickness
/2, 0);
1691 gp_point (e
->end
.x
, e
->end
.y
, a
->Thickness
/2, 0);
1696 gp_text_cb (const BoxType
*b
, void *cb
)
1698 const TextTypePtr t
= (TextTypePtr
) b
;
1699 /* FIXME: drop in the actual text-line endpoints later. */
1700 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y1
, 0, 0);
1701 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y2
, 0, 0);
1702 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y2
, 0, 0);
1703 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y1
, 0, 0);
1708 gp_poly_cb (const BoxType
*b
, void *cb
)
1711 const PolygonTypePtr p
= (PolygonTypePtr
) b
;
1712 for (i
=0; i
<p
->PointN
; i
++)
1713 gp_point (p
->Points
[i
].X
, p
->Points
[i
].Y
, 0, 0);
1718 gp_pin_cb (const BoxType
*b
, void *cb
)
1720 const PinTypePtr p
= (PinTypePtr
) b
;
1721 int t2
= (p
->Thickness
+1)/2;
1723 if (p
== start_pinpad
|| p
== end_pinpad
)
1726 /* FIXME: we lump octagonal pins in with square; safe, but not
1728 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1730 gp_point (p
->X
- t2
, p
->Y
- t2
, 0, 0);
1731 gp_point (p
->X
- t2
, p
->Y
+ t2
, 0, 0);
1732 gp_point (p
->X
+ t2
, p
->Y
+ t2
, 0, 0);
1733 gp_point (p
->X
+ t2
, p
->Y
- t2
, 0, 0);
1737 gp_point (p
->X
, p
->Y
, t2
, 0);
1743 gp_pad_cb (const BoxType
*b
, void *cb
)
1745 const PadTypePtr p
= (PadTypePtr
) b
;
1746 int t2
= (p
->Thickness
+1)/2;
1748 if (p
== start_pinpad
|| p
== end_pinpad
)
1751 if (TEST_FLAG (ONSOLDERFLAG
, p
))
1753 if (!current_is_solder
)
1758 if (!current_is_component
)
1762 /* FIXME: we lump octagonal pads in with square; safe, but not
1763 optimal. I don't think we even support octagonal pads. */
1764 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1766 if (p
->Point1
.X
== p
->Point2
.X
)
1768 int y1
= MIN (p
->Point1
.Y
, p
->Point2
.Y
) - t2
;
1769 int y2
= MAX (p
->Point1
.Y
, p
->Point2
.Y
) + t2
;
1771 gp_point (p
->Point1
.X
- t2
, y1
, 0, 0);
1772 gp_point (p
->Point1
.X
- t2
, y2
, 0, 0);
1773 gp_point (p
->Point1
.X
+ t2
, y1
, 0, 0);
1774 gp_point (p
->Point1
.X
+ t2
, y2
, 0, 0);
1778 int x1
= MIN (p
->Point1
.X
, p
->Point2
.X
) - t2
;
1779 int x2
= MAX (p
->Point1
.X
, p
->Point2
.X
) + t2
;
1781 gp_point (x1
, p
->Point1
.Y
- t2
, 0, 0);
1782 gp_point (x2
, p
->Point1
.Y
- t2
, 0, 0);
1783 gp_point (x1
, p
->Point1
.Y
+ t2
, 0, 0);
1784 gp_point (x2
, p
->Point1
.Y
+ t2
, 0, 0);
1789 gp_point (p
->Point1
.X
, p
->Point1
.Y
, t2
, 0);
1790 gp_point (p
->Point2
.X
, p
->Point2
.Y
, t2
, 0);
1796 adjust_pointers_1 (Extra
*old
, Extra
*new, int num
, Extra
*l
, int n
)
1798 int delta
= new - old
;
1799 long cdelta
= (char *)new - (char *)old
;
1800 Extra
*last
= old
+ num
;
1805 if (l
[i
].start
.waiting_for
1806 && (Extra
*) l
[i
].start
.waiting_for
> old
1807 && (Extra
*) l
[i
].start
.waiting_for
< last
+1)
1809 l
[i
].start
.waiting_for
1810 = (End
*)((char *)l
[i
].start
.waiting_for
1813 if (l
[i
].end
.waiting_for
1814 && (Extra
*) l
[i
].end
.waiting_for
> old
1815 && (Extra
*) l
[i
].end
.waiting_for
< last
+1)
1817 l
[i
].end
.waiting_for
1818 = (End
*)((char *)l
[i
].end
.waiting_for
1821 if (l
[i
].start
.next
>= old
1822 && l
[i
].start
.next
< last
)
1825 printf(" - lstart %p to ", l
[i
].start
.next
);
1827 l
[i
].start
.next
+= delta
;
1829 printf(" %p\n", l
[i
].start
.next
);
1832 if (l
[i
].end
.next
>= old
1833 && l
[i
].end
.next
< last
)
1836 printf(" - lend %p to ", l
[i
].end
.next
);
1838 l
[i
].end
.next
+= delta
;
1840 printf(" %p\n", l
[i
].end
.next
);
1847 adjust_pointers (Extra
*old
, Extra
*new, int num
)
1849 adjust_pointers_1 (old
, new, num
, lines
, nlines
);
1850 adjust_pointers_1 (old
, new, num
, arcs
, narcs
);
1854 create_line (LineTypePtr sample
, int x1
, int y1
, int x2
, int y2
)
1856 Extra
*e
, *new_lines
;
1858 printf("create_line from %d,%d to %d,%d\n", x1
, y1
, x2
, y2
);
1860 LineTypePtr line
= CreateNewLineOnLayer (CURRENT
, x1
, y1
, x2
, y2
,
1861 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1862 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1863 if (CURRENT
->LineN
>= max_lines
)
1866 new_lines
= (Extra
*) realloc (lines
, max_lines
* sizeof(Extra
));
1867 if (new_lines
!= lines
)
1871 printf("\033[32mMoving lines from %p to %p\033[0m\n", lines
, new_lines
);
1874 adjust_pointers (old
, lines
, nlines
);
1876 memset (lines
+nlines
, 0, (max_lines
-nlines
)*sizeof(Extra
));
1878 nlines
= CURRENT
->LineN
;
1879 e
= & LINE2EXTRA (line
);
1881 printf(" - line extra is %p\n", e
);
1883 memset (e
, 0, sizeof(Extra
));
1888 create_arc (LineTypePtr sample
, int x
, int y
, int r
, int sa
, int da
)
1890 Extra
*e
, *new_arcs
;
1898 printf("create_arc at %d,%d r %d sa %d delta %d\n", x
, y
, r
, sa
, da
);
1900 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
,
1901 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1904 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
*2,
1905 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1907 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1910 longjmp (abort_buf
, 1);
1912 if (CURRENT
->ArcN
>= max_arcs
)
1915 new_arcs
= (Extra
*) realloc (arcs
, max_arcs
* sizeof(Extra
));
1916 if (new_arcs
!= arcs
)
1920 printf("\033[32mMoving arcs from %p to %p\033[0m\n", arcs
, new_arcs
);
1923 adjust_pointers (old
, arcs
, narcs
);
1925 memset (arcs
+narcs
, 0, (max_arcs
-narcs
)*sizeof(Extra
));
1927 narcs
= CURRENT
->ArcN
;
1928 e
= & ARC2EXTRA (arc
);
1930 printf(" - arc extra is %p\n", e
);
1932 memset (e
, 0, sizeof(Extra
));
1933 fix_arc_extra (arc
, e
);
1938 unlink_extras (Extra
*e
)
1941 fprintf(stderr
, "unlink %p\n", e
);
1947 print_extra(e
->start
.next
, 0);
1949 if (e
->start
.next
->start
.next
== e
)
1952 fprintf(stderr
, " - %p->start points to me\n", e
->start
.next
);
1954 e
->start
.next
->start
.next
= e
->end
.next
;
1956 else if (e
->start
.next
->end
.next
== e
)
1959 fprintf(stderr
, " - %p->end points to me\n", e
->start
.next
);
1961 e
->start
.next
->end
.next
= e
->end
.next
;
1965 fprintf(stderr
, " - %p doesn't point to me!\n", e
->start
.next
);
1972 print_extra(e
->end
.next
, 0);
1974 if (e
->end
.next
->start
.next
== e
)
1977 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1979 e
->end
.next
->start
.next
= e
->start
.next
;
1981 else if (e
->end
.next
->end
.next
== e
)
1984 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1986 e
->end
.next
->end
.next
= e
->start
.next
;
1990 fprintf(stderr
, " - %p doesn't point to me!\n", e
->end
.next
);
1994 e
->start
.next
= e
->end
.next
= 0;
1998 mark_line_for_deletion (LineTypePtr l
)
2000 Extra
*e
= & LINE2EXTRA(l
);
2003 fprintf(stderr
, "double delete?\n");
2009 printf("Marked line %p for deletion %d,%d to %d,%d\n",
2010 e
, l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
2013 if (l
->Point1
.X
< 0)
2015 fprintf(stderr
, "double neg move?\n");
2018 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point1
),
2021 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point2
),
2028 mark_arc_for_deletion (ArcTypePtr a
)
2030 Extra
*e
= & ARC2EXTRA(a
);
2034 printf("Marked arc %p for deletion %ld < %ld\n",
2035 e
, a
->StartAngle
, a
->Delta
);
2039 /* Given a starting line, which may be attached to an arc, and which
2040 intersects with an ending line, which also may be attached to an
2041 arc, maybe pull them. We assume start_line is attached to the arc
2042 via Point1, and attached to the end line via Point2. Likewise, we
2043 make end_line attach to the start_line via Point1 and the arc via
2044 Point 2. We also make the arcs attach on the Delta end, not the
2045 Start end. Here's a picture:
2047 S S+D P1 P2 P1 P2 S+D S
2048 *--- start_arc ---*--- start_line ---*--- end_line ---*--- end_arc ---*
2053 maybe_pull_1 (LineTypePtr line
)
2056 /* Line half-thicknesses, including line space */
2058 LineTypePtr new_line
;
2065 start_extra
= & LINE2EXTRA (start_line
);
2066 end_extra
= start_extra
->end
.next
;
2067 end_line
= & EXTRA2LINE (end_extra
);
2068 if (end_extra
->deleted
)
2070 start_extra
->end
.pending
= 0;
2074 if (end_extra
->end
.next
== start_extra
)
2075 reverse_line (end_line
);
2077 if (start_extra
->start
.next
2078 && EXTRA_IS_ARC (start_extra
->start
.next
))
2080 sarc_extra
= start_extra
->start
.next
;
2081 start_arc
= & EXTRA2ARC (sarc_extra
);
2082 if (sarc_extra
->start
.next
== start_extra
)
2083 reverse_arc (start_arc
);
2091 if (end_extra
->end
.next
2092 && EXTRA_IS_ARC (end_extra
->end
.next
))
2094 earc_extra
= end_extra
->end
.next
;
2095 end_arc
= & EXTRA2ARC (earc_extra
);
2096 if (earc_extra
->start
.next
== end_extra
)
2097 reverse_arc (end_arc
);
2106 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra
, start_extra
, end_extra
, earc_extra
);
2108 print_extra(sarc_extra
,0);
2109 print_extra(start_extra
,0);
2110 print_extra(end_extra
,0);
2112 print_extra(earc_extra
,0);
2114 if (start_extra
->deleted
2115 || end_extra
->deleted
2116 || (sarc_extra
&& sarc_extra
->deleted
)
2117 || (earc_extra
&& earc_extra
->deleted
))
2119 printf(" one is deleted?\n");
2125 if (!start_extra
->end
.pending
)
2128 if (start_extra
->end
.waiting_for
2129 && start_extra
->end
.waiting_for
->pending
)
2133 if (start_line
->Thickness
!= end_line
->Thickness
)
2135 thickness
= (start_line
->Thickness
+ 1)/2 + PCB
->Bloat
;
2137 /* At this point, our expectations are all met. */
2139 box
.X1
= start_line
->Point1
.X
- thickness
;
2140 box
.X2
= start_line
->Point1
.X
+ thickness
;
2141 box
.Y1
= start_line
->Point1
.Y
- thickness
;
2142 box
.Y2
= start_line
->Point1
.Y
+ thickness
;
2143 expand_box (&box
, start_line
->Point2
.X
, start_line
->Point2
.Y
, thickness
);
2144 expand_box (&box
, end_line
->Point2
.X
, end_line
->Point2
.Y
, thickness
);
2146 expand_box (&box
, sarc_extra
->start
.x
, sarc_extra
->start
.y
, start_arc
->Thickness
/2);
2148 expand_box (&box
, earc_extra
->start
.x
, earc_extra
->start
.y
, end_arc
->Thickness
/2);
2151 se_sign
= copysign (1, cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2152 start_line
->Point2
.X
, start_line
->Point2
.Y
,
2153 end_line
->Point2
.X
, end_line
->Point2
.Y
));
2154 best_angle
= se_sign
* M_PI
;
2157 sa_sign
= copysign (1, -start_arc
->Delta
);
2164 ea_sign
= copysign (1, -end_arc
->Delta
);
2165 ea_sign
*= -se_sign
;
2170 start_angle
= atan2 (start_line
->Point2
.Y
- start_line
->Point1
.Y
,
2171 start_line
->Point2
.X
- start_line
->Point1
.X
);
2173 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n",
2174 se_sign
, sa_sign
, ea_sign
, r2d (best_angle
), r2d(start_angle
));
2179 sa_x
= start_arc
->X
;
2180 sa_y
= start_arc
->Y
;
2181 if (same_sign (start_arc
->Delta
, se_sign
))
2182 sa_r
= - start_arc
->Width
;
2184 sa_r
= start_arc
->Width
;
2188 sa_x
= start_line
->Point1
.X
;
2189 sa_y
= start_line
->Point1
.Y
;
2196 ea_r
= end_arc
->Width
;
2198 ea_r
= - end_arc
->Width
;
2204 trace_path (sarc_extra
? sarc_extra
: start_extra
);
2209 gp_point_force (end_arc
->X
, end_arc
->Y
, -ea_r
-thickness
, 0, 0, 0, 1, "end arc");
2215 gp_point_force (end_line
->Point2
.X
, end_line
->Point2
.Y
, -thickness
, 0, 0, 0, 1, "end arc");
2216 ex
= end_line
->Point2
.X
;
2217 ey
= end_line
->Point2
.Y
;
2224 fprintf(stderr
, "end line corrupt? f is %d,%d\n", fx
, fy
);
2225 print_extra (end_extra
, 0);
2227 print_extra(earc_extra
, 0);
2231 end_dist
= dist (end_line
->Point1
.X
, end_line
->Point1
.Y
,
2232 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2234 start_pinpad
= start_extra
->start
.pin
;
2235 end_pinpad
= start_extra
->end
.pin
;
2238 r_search(CURRENT
->line_tree
, &box
, NULL
, gp_line_cb
, 0);
2239 r_search(CURRENT
->arc_tree
, &box
, NULL
, gp_arc_cb
, 0);
2240 r_search(CURRENT
->text_tree
, &box
, NULL
, gp_text_cb
, 0);
2241 r_search(CURRENT
->polygon_tree
, &box
, NULL
, gp_poly_cb
, 0);
2242 r_search(PCB
->Data
->pin_tree
, &box
, NULL
, gp_pin_cb
, 0);
2243 r_search(PCB
->Data
->via_tree
, &box
, NULL
, gp_pin_cb
, 0);
2244 r_search(PCB
->Data
->pad_tree
, &box
, NULL
, gp_pad_cb
, 0);
2246 /* radians, absolute angle of (at the moment) the start_line */
2247 abs_angle
= fa
+ start_angle
;
2250 printf("\033[43;30mBest: at %d,%d r %d, angle %.1f fp %d\033[0m\n", fx
, fy
, fr
, r2d(fa
), fp
);
2254 if (fa
> M_PI
/2 || fa
< -M_PI
/2)
2256 SET_FLAG (FOUNDFLAG
, line
);
2257 longjmp (abort_buf
, 1);
2263 start_extra
->end
.waiting_for
= fp_end
;
2266 start_extra
->end
.pending
= 0;
2268 /* Step 0: check for merged arcs (special case). */
2270 if (fx
== ex
&& fy
== ey
2271 && start_arc
&& end_arc
2272 && start_arc
->X
== end_arc
->X
&& start_arc
->Y
== end_arc
->Y
)
2277 new_delta
= end_arc
->StartAngle
- start_arc
->StartAngle
;
2278 if (start_arc
->Delta
> 0)
2280 while (new_delta
> 360)
2282 while (new_delta
< 0)
2287 while (new_delta
< -360)
2289 while (new_delta
> 0)
2293 printf("merging arcs at %d,%d nd %d\n", start_arc
->X
, start_arc
->Y
, new_delta
);
2294 print_extra(sarc_extra
, 0);
2295 print_extra(earc_extra
, 0);
2297 mark_arc_for_deletion (end_arc
);
2298 mark_line_for_deletion (start_line
);
2299 mark_line_for_deletion (end_line
);
2300 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2301 fix_arc_extra (start_arc
, sarc_extra
);
2306 /* Step 1: adjust start_arc's angles and move start_line's Point1 to
2314 /* We must always round towards "larger arcs", whichever way that is. */
2315 new_delta
= 180 - r2d(abs_angle
);
2317 printf("new_delta starts at %d vs %d < %d\n",
2318 (int)new_delta
, start_arc
->StartAngle
, start_arc
->Delta
);
2320 if (start_arc
->Delta
< 0)
2321 new_delta
= (int)(new_delta
) + 90;
2323 new_delta
= (int)new_delta
- 90;
2324 new_delta
= new_delta
- start_arc
->StartAngle
;
2325 while (new_delta
> start_arc
->Delta
+180)
2327 while (new_delta
< start_arc
->Delta
-180)
2330 printf("new_delta adjusts to %d\n", (int)new_delta
);
2331 printf("fa = %f, new_delta ends at %.1f vs start %d\n",
2332 fa
, new_delta
, start_arc
->StartAngle
);
2335 if (new_delta
* start_arc
->Delta
<= 0)
2338 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2339 fix_arc_extra (start_arc
, sarc_extra
);
2340 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2341 sarc_extra
->end
.x
- start_line
->Point1
.X
,
2342 sarc_extra
->end
.y
- start_line
->Point1
.Y
);
2346 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2347 sarc_extra
->start
.x
- start_line
->Point1
.X
,
2348 sarc_extra
->start
.y
- start_line
->Point1
.Y
);
2349 mark_arc_for_deletion (start_arc
);
2353 /* Step 1.5: If the "obstacle" is right at the end, ignore it. */
2356 double oa
= start_angle
+fa
- M_PI
/2*se_sign
;
2357 double ox
= fx
+ fr
* cos(oa
);
2358 double oy
= fy
+ fr
* sin(oa
);
2360 printf("obstacle at %d,%d angle %d = arc starts at %d,%d\n",
2361 fx
, fy
, (int)r2d(oa
), (int)ox
, (int)oy
);
2364 if (dist (ox
, oy
, end_line
->Point2
.X
, end_line
->Point2
.Y
)
2367 /* Pretend it doesn't exist. */
2373 /* Step 2: If we have no obstacles, connect start and end. */
2376 printf("fx %d ex %d fy %d ey %d\n", fx
, ex
, fy
, ey
);
2378 if (fx
== ex
&& fy
== ey
)
2382 printf("\033[32mno obstacles\033[0m\n");
2387 int new_delta
, end_angle
, pcb_fa
, end_change
;
2389 end_angle
= end_arc
->StartAngle
+ end_arc
->Delta
;
2390 if (end_arc
->Delta
< 0)
2395 /* We must round so as to make the larger arc. */
2396 if (end_arc
->Delta
< 0)
2397 pcb_fa
= - r2d(start_angle
+ fa
);
2399 pcb_fa
= 1 - r2d(start_angle
+ fa
);
2400 end_change
= pcb_fa
- end_angle
;
2402 while (end_change
> 180)
2404 while (end_change
< -180)
2406 new_delta
= end_arc
->Delta
+ end_change
;
2408 if (new_delta
* end_arc
->Delta
<= 0)
2411 ChangeArcAngles (CURRENT
, end_arc
, end_arc
->StartAngle
, new_delta
);
2412 fix_arc_extra (end_arc
, earc_extra
);
2413 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2414 earc_extra
->end
.x
- start_line
->Point2
.X
,
2415 earc_extra
->end
.y
- start_line
->Point2
.Y
);
2419 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2420 earc_extra
->start
.x
- start_line
->Point2
.X
,
2421 earc_extra
->start
.y
- start_line
->Point2
.Y
);
2422 mark_arc_for_deletion (end_arc
);
2427 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2428 end_line
->Point2
.X
- start_line
->Point2
.X
,
2429 end_line
->Point2
.Y
- start_line
->Point2
.Y
);
2431 mark_line_for_deletion (end_line
);
2432 start_extra
->end
.pending
= 1;
2435 printf("\033[35mdid_something: no obstacles\033[0m\n");
2443 /* Step 3: Compute the new intersection of start_line and end_line. */
2445 ex
= start_line
->Point1
.X
+ cos(start_angle
+ fa
) * 10000.0;
2446 ey
= start_line
->Point1
.Y
+ sin(start_angle
+ fa
) * 10000.0;
2448 printf("temp point %d,%d\n", ex
, ey
);
2449 printf("intersect %d,%d-%d,%d with %d,%d-%d,%d\n",
2450 start_line
->Point1
.X
, start_line
->Point1
.Y
,
2452 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2453 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2455 if (! intersection_of_lines (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2457 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2458 end_line
->Point2
.X
, end_line
->Point2
.Y
,
2461 ex
= end_line
->Point2
.X
;
2462 ey
= end_line
->Point2
.Y
;
2465 printf("new point %d,%d\n", ex
, ey
);
2467 MoveObject (LINEPOINT_TYPE
, CURRENT
, end_line
, &(end_line
->Point1
),
2468 ex
- end_line
->Point1
.X
,
2469 ey
- end_line
->Point1
.Y
);
2471 /* Step 4: Split start_line at the obstacle and insert a zero-delta
2474 new_arc
= create_arc (start_line
, fx
, fy
, fr
,
2475 90-(int)(r2d(start_angle
+fa
)+0.5) + 90 + 90*se_sign
, -se_sign
);
2476 new_aextra
= & ARC2EXTRA (new_arc
);
2478 if (start_arc
) sarc_extra
= & ARC2EXTRA (start_arc
);
2479 if (end_arc
) earc_extra
= & ARC2EXTRA (end_arc
);
2481 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2482 new_aextra
->start
.x
- start_line
->Point2
.X
,
2483 new_aextra
->start
.y
- start_line
->Point2
.Y
);
2485 new_line
= create_line (start_line
, new_aextra
->end
.x
, new_aextra
->end
.y
, ex
, ey
);
2486 start_extra
= & LINE2EXTRA (start_line
);
2487 new_lextra
= & LINE2EXTRA (new_line
);
2488 end_extra
= & LINE2EXTRA (end_line
);
2490 new_lextra
->start
.pin
= start_extra
->start
.pin
;
2491 new_lextra
->end
.pin
= start_extra
->end
.pin
;
2492 new_lextra
->start
.pending
= 1;
2493 new_lextra
->end
.pending
= 1;
2495 start_extra
->end
.next
= new_aextra
;
2496 new_aextra
->start
.next
= start_extra
;
2497 new_aextra
->end
.next
= new_lextra
;
2498 new_lextra
->start
.next
= new_aextra
;
2499 new_lextra
->end
.next
= end_extra
;
2500 end_extra
->start
.next
= new_lextra
;
2502 /* Step 5: Recurse. */
2508 printf("\033[35mdid_something: recursing\033[0m\n");
2510 int i
= gui
->confirm_dialog("recurse?", 0);
2511 printf("confirm = %d\n", i
);
2515 printf("\n\033[33mRECURSING\033[0m\n\n");
2516 IncrementUndoSerialNumber();
2518 maybe_pull_1 (new_line
);
2521 /* Given a line with a end_next, attempt to pull both ends. */
2523 maybe_pull (LineTypePtr line
, Extra
*e
)
2526 printf("maybe_pull: ");
2529 if (e
->end
.next
&& EXTRA_IS_LINE (e
->end
.next
))
2531 maybe_pull_1 (line
);
2536 if (e
->start
.next
&& EXTRA_IS_LINE (e
->start
.next
))
2538 reverse_line (line
);
2539 maybe_pull_1 (line
);
2542 e
->start
.pending
= 0;
2547 validate_pair (Extra
*e
, End
*end
)
2551 if (end
->next
->start
.next
== e
)
2553 if (end
->next
->end
.next
== e
)
2555 fprintf(stderr
, "no backlink!\n");
2557 print_extra (end
->next
, 0);
2565 for (i
=0; i
<nlines
; i
++)
2567 validate_pair (&lines
[i
], &lines
[i
].start
);
2568 validate_pair (&lines
[i
], &lines
[i
].end
);
2573 for (i
=0; i
<narcs
; i
++)
2575 validate_pair (&arcs
[i
], &arcs
[i
].start
);
2576 validate_pair (&arcs
[i
], &arcs
[i
].end
);
2581 GlobalPuller(int argc
, char **argv
, int x
, int y
)
2584 int select_flags
= 0;
2589 printf("puller! %s\n", argc
> 0 ? argv
[0] : "");
2591 if (argc
> 0 && strcasecmp (argv
[0], "selected") == 0)
2592 select_flags
= SELECTEDFLAG
;
2593 if (argc
> 0 && strcasecmp (argv
[0], "found") == 0)
2594 select_flags
= FOUNDFLAG
;
2596 printf("optimizing...\n");
2597 /* This canonicalizes all the lines, and cleans up near-misses. */
2598 /* hid_actionl ("djopt", "puller", 0); */
2600 current_is_solder
= (GetLayerGroupNumberByPointer(CURRENT
)
2601 == GetLayerGroupNumberByNumber (max_layer
+ SOLDER_LAYER
));
2602 current_is_component
= (GetLayerGroupNumberByPointer(CURRENT
)
2603 == GetLayerGroupNumberByNumber (max_layer
+ COMPONENT_LAYER
));
2605 max_lines
= nlines
= CURRENT
->LineN
;
2606 lines
= (Extra
*) calloc (nlines
, sizeof (Extra
));
2607 max_arcs
= narcs
= CURRENT
->ArcN
;
2608 arcs
= (Extra
*) calloc (narcs
, sizeof (Extra
));
2610 printf("pairing...\n");
2614 for (i
=0; i
<nlines
; i
++)
2615 if (TEST_FLAGS (select_flags
, &CURRENT
->Line
[i
]))
2617 lines
[i
].start
.pending
= 1;
2618 lines
[i
].end
.pending
= 1;
2622 printf("\nlines\n");
2623 for (i
=0; i
<nlines
; i
++)
2625 last_pextra
= (Extra
*)1;
2626 print_extra(&lines
[i
], 0);
2629 for (i
=0; i
<narcs
; i
++)
2631 last_pextra
= (Extra
*)1;
2632 print_extra(&arcs
[i
], 0);
2640 printf("\nlines\n");
2641 for (i
=0; i
<nlines
; i
++)
2643 last_pextra
= (Extra
*)1;
2644 print_extra(&lines
[i
], 0);
2647 for (i
=0; i
<narcs
; i
++)
2649 last_pextra
= (Extra
*)1;
2650 print_extra(&arcs
[i
], 0);
2656 printf("pulling...\n");
2657 if (setjmp(abort_buf
) == 0)
2660 int old_did_something
= -1;
2663 while (did_something
)
2668 LINE_LOOP (CURRENT
); {
2669 Extra
*e
= & LINE2EXTRA (line
);
2672 #ifdef CHECK_LINE_PT_NEG
2673 if (line
->Point1
.X
< 0)
2676 if (e
->start
.next
|| e
->end
.next
)
2677 maybe_pull (line
, e
);
2679 if (did_something
!= old_did_something
)
2681 IncrementUndoSerialNumber();
2682 old_did_something
= did_something
;
2683 if (gui
->confirm_dialog("more?", 0) == 0)
2690 /*gui->progress(0,0,0);*/
2696 printf("\nlines\n");
2697 for (i
=0; i
<nlines
; i
++)
2699 last_pextra
= (Extra
*)1;
2700 print_extra(&lines
[i
], 0);
2703 for (i
=0; i
<narcs
; i
++)
2705 last_pextra
= (Extra
*)1;
2706 print_extra(&arcs
[i
], 0);
2711 /* We do this backwards so we don't have to edit the extras. */
2712 for (i
=CURRENT
->LineN
-1; i
>=0; i
--)
2714 LineTypePtr line
= & CURRENT
->Line
[i
];
2715 if (LINE2EXTRA (line
).deleted
)
2716 RemoveLine (CURRENT
, line
);
2719 /* We do this backwards so we don't have to edit the extras. */
2720 for (i
=CURRENT
->ArcN
-1; i
>=0; i
--)
2722 ArcTypePtr arc
= & CURRENT
->Arc
[i
];
2723 if (ARC2EXTRA (arc
).deleted
)
2724 RemoveArc (CURRENT
, arc
);
2730 nlines
= narcs
= max_lines
= max_arcs
= 0;
2732 IncrementUndoSerialNumber();
2736 /*****************************************************************************/
2740 /*****************************************************************************/
2742 HID_Action puller_action_list
[] = {
2743 {"Puller", "Click on a line-arc intersection or line segment", Puller
,
2744 puller_help
, puller_syntax
},
2745 {"GlobalPuller", 0, GlobalPuller
,
2746 globalpuller_help
, globalpuller_syntax
}
2749 REGISTER_ACTIONS (puller_action_list
)