6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2006 DJ Delorie
8 * Copyright (C) 2011 PCB Contributers (See ChangeLog for details)
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 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
30 /* FIXME: Things that need to be fixed before this is "perfect".
31 Add to this list as we find things.
33 - respect the outline layer.
35 - don't consider points that are perpendicular to our start_arc.
36 I.e. when we have busses going around corners, we have a *lot* of
37 arcs and endpoints that are all in the same direction and all
38 equally "good", but rounding the arc angles to integers causes
39 all sorts of tiny differences that result in bumps, reversals,
42 - Store the X,Y values in our shadow struct so we don't fill up the
43 undo buffer with all our line reversals.
45 - at least check the other layers in our layer group.
66 #include "pcb-printf.h"
72 #ifdef HAVE_LIBDMALLOC
78 #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort()
83 /* sine of one degree */
84 #define SIN1D 0.0174524064372835
86 static jmp_buf abort_buf
;
88 #define sqr(x) (1.0*(x)*(x))
90 static int multi
, line_exact
, arc_exact
;
91 static LineTypePtr the_line
;
92 static ArcTypePtr the_arc
;
93 static double arc_dist
;
95 /* We canonicalize the arc and line such that the point to be moved is
96 always Point2 for the line, and at start+delta for the arc. */
98 static int x
, y
; /* the point we're moving */
99 static int cx
, cy
; /* centerpoint of the arc */
100 static int ex
, ey
; /* fixed end of the line */
102 /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */
105 within (int x1
, int y1
, int x2
, int y2
, int r
)
107 return Distance (x1
, y1
, x2
, y2
) <= r
/ 2;
111 arc_endpoint_is (ArcTypePtr a
, int angle
, int x
, int y
)
113 int ax
= a
->X
, ay
= a
->Y
;
117 int ai
= (int) (angle
/ 90) & 3;
136 double rad
= angle
* M_PI
/ 180;
137 ax
-= a
->Width
* cos (rad
);
138 ay
+= a
->Width
* sin (rad
);
141 pcb_printf (" - arc endpoint %#mD\n", ax
, ay
);
143 arc_dist
= Distance (ax
, ay
, x
, y
);
146 return arc_dist
< a
->Thickness
/ 2;
149 /* Cross c->u and c->v, return the magnitute */
151 cross2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
157 return (double)ux
* vy
- (double)uy
* vx
;
160 /* Likewise, for dot product. */
162 dot2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
168 return (double)ux
* vx
+ (double)uy
* vy
;
172 /* angle of c->v, relative to c->u, in radians. Range is -pi..pi */
174 angle2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
177 double magu
, magv
, sintheta
;
179 printf("angle2d %d,%d %d,%d %d,%d\n", cx
, cy
, ux
, uy
, vx
, vy
);
186 printf(" = %d,%d %d,%d\n", ux
, uy
, vx
, vy
);
188 cross
= (double)ux
* vy
- (double)uy
* vx
;
189 magu
= sqrt((double)ux
*ux
+ (double)uy
*uy
);
190 magv
= sqrt((double)vx
*vx
+ (double)vy
*vy
);
191 sintheta
= cross
/ (magu
* magv
);
193 printf(" = %f / (%f * %f) = %f\n", cross
, magu
, magv
, sintheta
);
195 return asin (sintheta
);
200 same_sign (double a
, double b
)
208 return 180.0 * r
/ M_PI
;
214 return M_PI
* d
/ 180.0;
220 det (double a
, double b
, double c
, double d
)
222 return a
* d
- b
* c
;
225 /* The lines are x1y1-x2y2 and x3y3-x4y4. Returns true if they
228 intersection_of_lines (int x1
, int y1
, int x2
, int y2
,
229 int x3
, int y3
, int x4
, int y4
,
233 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
236 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
237 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
238 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
239 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
240 *xr
= (int) (x
+ 0.5);
241 *yr
= (int) (y
+ 0.5);
245 /* Same, for line segments. Returns true if they intersect. For this
246 function, xr and yr may be NULL if you don't need the values. */
248 intersection_of_linesegs (int x1
, int y1
, int x2
, int y2
,
249 int x3
, int y3
, int x4
, int y4
,
253 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
256 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
257 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
258 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
259 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
260 if (MIN (x1
, x2
) > x
|| x
> MAX (x1
, x2
)
261 || MIN (y1
, y2
) > y
|| y
> MAX (y1
, y2
))
263 if (MIN (x3
, x4
) > x
|| x
> MAX (x3
, x4
)
264 || MIN (y3
, y4
) > y
|| y
> MAX (y3
, y4
))
267 *xr
= (int) (x
+ 0.5);
269 *yr
= (int) (y
+ 0.5);
273 /* distance between a line and a point */
275 dist_lp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
277 double den
= Distance (x1
, y1
, x2
, y2
);
278 double rv
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
279 - ((double)x1
- px
) * ((double)y2
- y1
))
282 pcb_printf("dist %#mD-%#mD to %#mD is %f\n",
283 x1
, y1
, x2
, y2
, px
, py
, rv
);
288 /* distance between a line segment and a point */
290 dist_lsp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
293 if (dot2d (x1
, y1
, x2
, y2
, px
, py
) < 0)
294 return Distance (x1
, y1
, px
, py
);
295 if (dot2d (x2
, y2
, x1
, y1
, px
, py
) < 0)
296 return Distance (x2
, y2
, px
, py
);
297 d
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
298 - ((double)x1
- px
) * ((double)y2
- y1
))
299 / Distance (x1
, y1
, x2
, y2
));
303 /*****************************************************************************/
305 /* Single Point Puller */
307 /*****************************************************************************/
310 line_callback (const BoxType
* b
, void *cl
)
312 /* LayerTypePtr layer = (LayerTypePtr)cl; */
313 LineTypePtr l
= (LineTypePtr
) b
;
316 pcb_printf ("line %#mD .. %#mD\n",
317 l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
319 d1
= Distance (l
->Point1
.X
, l
->Point1
.Y
, x
, y
);
320 d2
= Distance (l
->Point2
.X
, l
->Point2
.Y
, x
, y
);
321 if ((d1
< 2 || d2
< 2) && !line_exact
)
326 t
= line_exact
? 2 : l
->Thickness
/ 2;
327 if (d1
< t
|| d2
< t
)
333 printf ("picked, exact %d\n", line_exact
);
340 arc_callback (const BoxType
* b
, void *cl
)
342 /* LayerTypePtr layer = (LayerTypePtr) cl; */
343 ArcTypePtr a
= (ArcTypePtr
) b
;
346 pcb_printf ("arc a %#mD r %#mS sa %ld d %ld\n", a
->X
, a
->Y
, a
->Width
,
347 a
->StartAngle
, a
->Delta
);
349 if (!arc_endpoint_is (a
, a
->StartAngle
, x
, y
)
350 && !arc_endpoint_is (a
, a
->StartAngle
+ a
->Delta
, x
, y
))
363 printf ("picked, exact %d\n", arc_exact
);
372 printf ("picked, exact %d\n", arc_exact
);
379 find_pair (int Px
, int Py
)
384 pcb_printf ("\nPuller find_pair at %#mD\n", Crosshair
.X
, Crosshair
.Y
);
390 line_exact
= arc_exact
= 0;
397 r_search (CURRENT
->line_tree
, &spot
, NULL
, line_callback
, CURRENT
);
398 r_search (CURRENT
->arc_tree
, &spot
, NULL
, arc_callback
, CURRENT
);
399 if (the_line
&& the_arc
&& !multi
)
407 static const char puller_syntax
[] = "Puller()";
409 static const char puller_help
[] = "Pull an arc-line junction tight.";
411 /* %start-doc actions Puller
413 The @code{Puller()} action is a special-purpose optimization. When
414 invoked while the crosshair is over the junction of an arc and a line,
415 it will adjust the arc's angle and the connecting line's endpoint such
416 that the line intersects the arc at a tangent. In the example below,
417 the left side is ``before'' with the black target marking where to put
420 @center @image{puller,,,Example of how puller works,png}
422 The right side is ``after'' with the black target marking where the
423 arc-line intersection was moved to.
428 Puller (int argc
, char **argv
, Coord Ux
, Coord Uy
)
430 double arc_angle
, base_angle
;
432 double line_angle
, rel_angle
;
437 if (!find_pair (Crosshair
.X
, Crosshair
.Y
))
438 if (!find_pair (Ux
, Uy
))
441 if (within (the_line
->Point1
.X
, the_line
->Point1
.Y
,
442 x
, y
, the_line
->Thickness
))
444 ex
= the_line
->Point2
.X
;
445 ey
= the_line
->Point2
.Y
;
446 the_line
->Point2
.X
= the_line
->Point1
.X
;
447 the_line
->Point2
.Y
= the_line
->Point1
.Y
;
448 the_line
->Point1
.X
= ex
;
449 the_line
->Point1
.Y
= ey
;
451 else if (!within (the_line
->Point2
.X
, the_line
->Point2
.Y
,
452 x
, y
, the_line
->Thickness
))
455 printf ("Line endpoint not at cursor\n");
459 ex
= the_line
->Point1
.X
;
460 ey
= the_line
->Point1
.Y
;
464 if (arc_endpoint_is (the_arc
, the_arc
->StartAngle
, x
, y
))
466 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
469 else if (!arc_endpoint_is (the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
473 printf ("arc not endpoints\n");
478 if (within (cx
, cy
, ex
, ey
, the_arc
->Width
* 2))
481 printf ("line ends inside arc\n");
486 if (the_arc
->Delta
> 0)
487 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
+ 90;
489 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
- 90;
490 base_angle
= r2d (atan2 (ey
- cy
, cx
- ex
));
492 tangent
= r2d (acos (the_arc
->Width
/ Distance (cx
, cy
, ex
, ey
)));
495 line_angle
= r2d (atan2 (ey
- y
, x
- ex
));
496 rel_angle
= line_angle
- arc_angle
;
497 printf ("arc %g line %g rel %g base %g\n", arc_angle
, line_angle
, rel_angle
,
499 printf ("tangent %g\n", tangent
);
501 printf ("arc was start %ld end %ld\n", the_arc
->StartAngle
,
502 the_arc
->StartAngle
+ the_arc
->Delta
);
505 if (the_arc
->Delta
> 0)
506 arc_angle
= base_angle
- tangent
;
508 arc_angle
= base_angle
+ tangent
;
510 printf ("new end angle %g\n", arc_angle
);
513 new_delta_angle
= arc_angle
- the_arc
->StartAngle
;
514 if (new_delta_angle
> 180)
515 new_delta_angle
-= 360;
516 if (new_delta_angle
< -180)
517 new_delta_angle
+= 360;
518 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
, new_delta_angle
);
521 printf ("arc now start %ld end %ld\n", the_arc
->StartAngle
,
522 the_arc
->StartAngle
+ new_delta_angle
);
525 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
;
526 x
= the_arc
->X
- the_arc
->Width
* cos (d2r (arc_angle
)) + 0.5;
527 y
= the_arc
->Y
+ the_arc
->Height
* sin (d2r (arc_angle
)) + 0.5;
529 MoveObject (LINEPOINT_TYPE
, CURRENT
, the_line
, &(the_line
->Point2
),
530 x
- the_line
->Point2
.X
, y
- the_line
->Point2
.Y
);
532 gui
->invalidate_all ();
533 IncrementUndoSerialNumber ();
538 /*****************************************************************************/
542 /*****************************************************************************/
544 static const char globalpuller_syntax
[] =
547 static const char globalpuller_help
[] =
548 "Pull all traces tight.";
550 /* %start-doc actions GlobalPuller
554 /* Ok, here's the deal. We look for the intersection of two traces.
555 The triangle formed by those traces is searched for things we need
556 to avoid. From the other two corners of the triangle, we compute
557 the angle to each obstacle, and remember the ones closest to the
558 start angles. If the two traces hit the same obstacle, we put in
559 the arc and we're done. Else, we bring the traces up to the
560 obstacles and start again.
562 Note that we assume each start point is a tangent to an arc. We
563 start with a radius of zero, but future steps use the arcs we
566 For obstacles, we list each round pin, pad, via, and line/arc
567 endpoints as points with a given radius. For each square pin, pad,
568 via, and polygon points, we list each corner with a zero radius.
569 We also list arcs from their centerpoint.
571 We don't currently do anything to move vias, or intersections of
572 three or more traces. In the future, three-way intersections will
573 be handles similarly to two-way - calculate the range of angles
574 valid from each of the three other endpoints, choose the angle
575 closest to making 120 degree angles at the center. For four-way or
576 more intersections, we break them up into multiple three-way
579 For simplicity, we only do the current layer at this time. We will
580 also edit the lines and arcs in place so that the intersection is
581 always on the second point, and the other ends are always at
582 start+delta for arcs.
584 We also defer intersections which are blocked by other
585 intersections yet to be moved; the idea is to wait until those have
586 been moved so we don't end up with arcs that no longer wrap around
587 things. At a later point, we may choose to pull arced corners in
590 You'll see lots of variables of the form "foo_sign" which keep
591 track of which way things are pointing. This is because everything
592 is relative to corners and arcs, not absolute directions.
595 static int nloops
, npulled
;
600 fprintf(stderr
, "%6d loops, %d pulled \r", nloops
, npulled
);
603 /* Extra data we need to temporarily attach to all lines and arcs. */
605 /* These point to "multi_next" if there are more than one. */
608 unsigned char in_pin
:1;
609 unsigned char at_pin
:1;
610 unsigned char is_pad
:1;
611 unsigned char pending
:1; /* set if this may be moved later */
612 int x
, y
; /* arc endpoint */
613 /* If not NULL, points to End with pending==1 we're blocked on. */
614 struct End
*waiting_for
;
617 typedef struct Extra
{
620 unsigned char found
:1;
621 unsigned char deleted
:1;
629 static Extra multi_next
;
630 static GHashTable
*lines
;
631 static GHashTable
*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) ((Extra *)g_hash_table_lookup (lines, l))
644 #define ARC2EXTRA(a) ((Extra *)g_hash_table_lookup (arcs, a))
645 #define EXTRA2LINE(e) (e->parent.line)
646 #define EXTRA2ARC(e) (e->parent.arc)
647 #define EXTRA_IS_LINE(e) (e->type == LINE_TYPE)
648 #define EXTRA_IS_ARC(e) (e->type == ARC_TYPE)
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
));
679 clear_found_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
687 g_hash_table_foreach (lines
, (GHFunc
)clear_found_cb
, NULL
);
688 g_hash_table_foreach (arcs
, (GHFunc
)clear_found_cb
, NULL
);
693 fix_arc_extra (ArcTypePtr a
, Extra
*e
)
696 printf("new arc angles %ld %ld\n", a
->StartAngle
, a
->Delta
);
698 e
->start
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
)) + 0.5);
699 e
->start
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
)) + 0.5);
700 e
->end
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
701 e
->end
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
703 pcb_printf("new X,Y is %#mD to %#mD\n", e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
712 } FindPairCallbackStruct
;
714 #define NEAR(a,b) ((a) <= (b) + 2 && (a) >= (b) - 2)
717 find_pair_line_callback (const BoxType
* b
, void *cl
)
719 LineTypePtr line
= (LineTypePtr
) b
;
721 Extra
*e
= LINE2EXTRA (line
);
723 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
725 if (line
== fpcs
->me
)
727 #ifdef CHECK_LINE_PT_NEG
728 if (line
->Point1
.X
< 0)
732 pcb_printf(" - %p line %#mD or %#mD\n", e
, line
->Point1
.X
, line
->Point1
.Y
,
733 line
->Point2
.X
, line
->Point2
.Y
);
735 if ((NEAR (line
->Point1
.X
, fpcs
->x
) && NEAR (line
->Point1
.Y
, fpcs
->y
))
736 || (NEAR (line
->Point2
.X
, fpcs
->x
) && NEAR (line
->Point2
.Y
, fpcs
->y
)))
738 if (* fpcs
->extra_ptr
)
741 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
743 *fpcs
->extra_ptr
= & multi_next
;
747 *fpcs
->extra_ptr
= LINE2EXTRA (line
);
749 printf(" - next now %p\n", *fpcs
->extra_ptr
);
757 find_pair_arc_callback (const BoxType
* b
, void *cl
)
759 ArcTypePtr arc
= (ArcTypePtr
) b
;
760 Extra
*e
= ARC2EXTRA (arc
);
761 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
766 pcb_printf(" - %p arc %#mD or %#mD\n", e
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
768 if ((NEAR (e
->start
.x
, fpcs
->x
) && NEAR (e
->start
.y
, fpcs
->y
))
769 || (NEAR (e
->end
.x
, fpcs
->x
) && NEAR (e
->end
.y
, fpcs
->y
)))
771 if (* fpcs
->extra_ptr
)
774 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
776 *fpcs
->extra_ptr
= & multi_next
;
779 *fpcs
->extra_ptr
= e
;
785 find_pairs_1 (void *me
, Extra
**e
, int x
, int y
)
787 FindPairCallbackStruct fpcs
;
798 pcb_printf("looking for %#mD\n", x
, y
);
804 r_search(CURRENT
->line_tree
, &b
, NULL
, find_pair_line_callback
, &fpcs
);
805 r_search(CURRENT
->arc_tree
, &b
, NULL
, find_pair_arc_callback
, &fpcs
);
809 check_point_in_pin (PinTypePtr pin
, int x
, int y
, End
*e
)
812 int t
= (pin
->Thickness
+1)/2;
813 if (TEST_FLAG (SQUAREFLAG
, pin
))
814 inside_p
= (x
>= pin
->X
- t
&& x
<= pin
->X
+ t
815 && y
>= pin
->Y
- t
&& y
<= pin
->Y
+ t
);
817 inside_p
= (Distance (pin
->X
, pin
->Y
, x
, y
) <= t
);
822 if (pin
->X
== x
&& pin
->Y
== y
)
831 find_pair_pinline_callback (const BoxType
* b
, void *cl
)
833 LineTypePtr line
= (LineTypePtr
) b
;
834 PinTypePtr pin
= (PinTypePtr
) cl
;
835 Extra
*e
= LINE2EXTRA (line
);
838 #ifdef CHECK_LINE_PT_NEG
839 if (line
->Point1
.X
< 0)
843 hits
= check_point_in_pin (pin
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
844 hits
+= check_point_in_pin (pin
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
849 /* See if the line passes through this pin. */
850 /* FIXME: this assumes round pads, but it's good enough for square
852 if (dist_lsp (line
->Point1
.X
, line
->Point1
.Y
,
853 line
->Point2
.X
, line
->Point2
.Y
,
854 pin
->X
, pin
->Y
) <= pin
->Thickness
/2)
857 pcb_printf("splitting line %#mD-%#mD because it passes through pin %#mD r%d\n",
858 line
->Point1
.X
, line
->Point1
.Y
,
859 line
->Point2
.X
, line
->Point2
.Y
,
860 pin
->X
, pin
->Y
, pin
->Thickness
/2);
862 unlink_end (e
, &e
->start
.next
);
863 unlink_end (e
, &e
->end
.next
);
869 find_pair_pinarc_callback (const BoxType
* b
, void *cl
)
871 ArcTypePtr arc
= (ArcTypePtr
) b
;
872 PinTypePtr pin
= (PinTypePtr
) cl
;
873 Extra
*e
= ARC2EXTRA (arc
);
876 hits
= check_point_in_pin (pin
, e
->start
.x
, e
->start
.y
, &(e
->start
));
877 hits
+= check_point_in_pin (pin
, e
->end
.x
, e
->end
.y
, &(e
->end
));
882 check_point_in_pad (PadTypePtr pad
, int x
, int y
, End
*e
)
887 pcb_printf("pad %#mD - %#mD t %#mS vs %#mD\n", pad
->Point1
.X
, pad
->Point1
.Y
,
888 pad
->Point2
.X
, pad
->Point2
.Y
, pad
->Thickness
, x
, y
);
889 t
= (pad
->Thickness
+1)/2;
890 if (TEST_FLAG (SQUAREFLAG
, pad
))
892 inside_p
= (x
>= MIN (pad
->Point1
.X
- t
, pad
->Point2
.X
- t
)
893 && x
<= MAX (pad
->Point1
.X
+ t
, pad
->Point2
.X
+ t
)
894 && y
>= MIN (pad
->Point1
.Y
- t
, pad
->Point2
.Y
- t
)
895 && y
<= MAX (pad
->Point1
.Y
+ t
, pad
->Point2
.Y
+ t
));
896 printf(" - inside_p = %d\n", inside_p
);
900 if (pad
->Point1
.X
== pad
->Point2
.X
)
902 inside_p
= (x
>= pad
->Point1
.X
- t
903 && x
<= pad
->Point1
.X
+ t
904 && y
>= MIN (pad
->Point1
.Y
, pad
->Point2
.Y
)
905 && y
<= MAX (pad
->Point1
.Y
, pad
->Point2
.Y
));
909 inside_p
= (x
>= MIN (pad
->Point1
.X
, pad
->Point2
.X
)
910 && x
<= MAX (pad
->Point1
.X
, pad
->Point2
.X
)
911 && y
>= pad
->Point1
.Y
- t
912 && y
<= pad
->Point1
.Y
+ t
);
916 if (Distance (pad
->Point1
.X
, pad
->Point1
.Y
, x
, y
) <= t
917 || Distance (pad
->Point2
.X
, pad
->Point2
.Y
, x
, y
) <= t
)
925 if (pad
->Point1
.X
== x
&& pad
->Point1
.Y
== y
)
927 if (pad
->Point2
.X
== x
&& pad
->Point2
.Y
== y
)
937 find_pair_padline_callback (const BoxType
* b
, void *cl
)
939 LineTypePtr line
= (LineTypePtr
) b
;
940 PadTypePtr pad
= (PadTypePtr
) cl
;
941 Extra
*e
= LINE2EXTRA (line
);
947 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
949 if (!current_is_solder
)
954 if (!current_is_component
)
958 #ifdef CHECK_LINE_PT_NEG
959 if (line
->Point1
.X
< 0)
963 hits
= check_point_in_pad (pad
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
964 hits
+= check_point_in_pad (pad
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
969 /* Ok, something strange. The line intersects our space, but
970 doesn't end in our space. See if it just passes through us, and
973 t
= (pad
->Thickness
+ 1)/2;
974 /* FIXME: this is for round pads. Good enough for now, but add
975 square pad support later. */
976 intersect
= intersection_of_linesegs (pad
->Point1
.X
, pad
->Point1
.Y
,
977 pad
->Point2
.X
, pad
->Point2
.Y
,
978 line
->Point1
.X
, line
->Point1
.Y
,
979 line
->Point2
.X
, line
->Point2
.Y
,
981 p1_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
982 line
->Point2
.X
, line
->Point2
.Y
,
983 pad
->Point1
.X
, pad
->Point1
.Y
);
984 p2_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
985 line
->Point2
.X
, line
->Point2
.Y
,
986 pad
->Point2
.X
, pad
->Point2
.Y
);
988 if (intersect
|| p1_d
< t
|| p2_d
< t
)
991 /* FIXME: we should split the line. */
993 pcb_printf("splitting line %#mD-%#mD because it passes through pad %#mD-%#mD r %#mS\n",
994 line
->Point1
.X
, line
->Point1
.Y
,
995 line
->Point2
.X
, line
->Point2
.Y
,
996 pad
->Point1
.X
, pad
->Point1
.Y
,
997 pad
->Point2
.X
, pad
->Point2
.Y
,
1000 unlink_end (e
, &e
->start
.next
);
1001 unlink_end (e
, &e
->end
.next
);
1008 find_pair_padarc_callback (const BoxType
* b
, void *cl
)
1010 ArcTypePtr arc
= (ArcTypePtr
) b
;
1011 PadTypePtr pad
= (PadTypePtr
) cl
;
1012 Extra
*e
= ARC2EXTRA (arc
);
1015 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
1017 if (!current_is_solder
)
1022 if (!current_is_component
)
1026 hits
= check_point_in_pad (pad
, e
->start
.x
, e
->start
.y
, &(e
->start
));
1027 hits
+= check_point_in_pad (pad
, e
->end
.x
, e
->end
.y
, &(e
->end
));
1032 null_multi_next_ends (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1034 if (extra
->start
.next
== &multi_next
)
1035 extra
->start
.next
= NULL
;
1037 if (extra
->end
.next
== &multi_next
)
1038 extra
->end
.next
= NULL
;
1042 new_line_extra (LineType
*line
)
1044 Extra
*extra
= g_slice_new0 (Extra
);
1045 g_hash_table_insert (lines
, line
, extra
);
1046 extra
->parent
.line
= line
;
1047 extra
->type
= LINE_TYPE
;
1052 new_arc_extra (ArcType
*arc
)
1054 Extra
*extra
= g_slice_new0 (Extra
);
1055 g_hash_table_insert (arcs
, arc
, extra
);
1056 extra
->parent
.arc
= arc
;
1057 extra
->type
= ARC_TYPE
;
1064 ARC_LOOP (CURRENT
); {
1065 Extra
*e
= new_arc_extra (arc
);
1066 fix_arc_extra (arc
, e
);
1069 LINE_LOOP (CURRENT
); {
1070 new_line_extra (line
);
1073 LINE_LOOP (CURRENT
); {
1074 Extra
*e
= LINE2EXTRA (line
);
1075 if (line
->Point1
.X
>= 0)
1077 find_pairs_1 (line
, & e
->start
.next
, line
->Point1
.X
, line
->Point1
.Y
);
1078 find_pairs_1 (line
, & e
->end
.next
, line
->Point2
.X
, line
->Point2
.Y
);
1082 ARC_LOOP (CURRENT
); {
1083 Extra
*e
= ARC2EXTRA (arc
);
1086 find_pairs_1 (arc
, & e
->start
.next
, e
->start
.x
, e
->start
.y
);
1087 find_pairs_1 (arc
, & e
->end
.next
, e
->end
.x
, e
->end
.y
);
1091 ALLPIN_LOOP (PCB
->Data
); {
1093 box
.X1
= pin
->X
- pin
->Thickness
/2;
1094 box
.Y1
= pin
->Y
- pin
->Thickness
/2;
1095 box
.X2
= pin
->X
+ pin
->Thickness
/2;
1096 box
.Y2
= pin
->Y
+ pin
->Thickness
/2;
1097 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, pin
);
1098 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, pin
);
1101 VIA_LOOP (PCB
->Data
); {
1103 box
.X1
= via
->X
- via
->Thickness
/2;
1104 box
.Y1
= via
->Y
- via
->Thickness
/2;
1105 box
.X2
= via
->X
+ via
->Thickness
/2;
1106 box
.Y2
= via
->Y
+ via
->Thickness
/2;
1107 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, via
);
1108 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, via
);
1111 ALLPAD_LOOP (PCB
->Data
); {
1113 box
.X1
= MIN(pad
->Point1
.X
, pad
->Point2
.X
) - pad
->Thickness
/2;
1114 box
.Y1
= MIN(pad
->Point1
.Y
, pad
->Point2
.Y
) - pad
->Thickness
/2;
1115 box
.X2
= MAX(pad
->Point1
.X
, pad
->Point2
.X
) + pad
->Thickness
/2;
1116 box
.Y2
= MAX(pad
->Point1
.Y
, pad
->Point2
.Y
) + pad
->Thickness
/2;
1117 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_padline_callback
, pad
);
1118 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_padarc_callback
, pad
);
1122 g_hash_table_foreach (lines
, (GHFunc
)null_multi_next_ends
, NULL
);
1123 g_hash_table_foreach (arcs
, (GHFunc
)null_multi_next_ends
, NULL
);
1126 #define PROP_NEXT(e,n,f) \
1127 if (f->next->start.next == e) { \
1137 propogate_ends_at (Extra
*e
, End
*near
, End
*far
)
1139 while (far
->in_pin
&& far
->pin
== near
->pin
)
1144 PROP_NEXT (e
, near
, far
);
1150 propogate_end_pin (Extra
*e
, End
*near
, End
*far
)
1152 void *pinpad
= near
->pin
;
1153 int ispad
= near
->is_pad
;
1156 PROP_NEXT (e
, near
, far
);
1157 if (near
->pin
== pinpad
)
1160 near
->is_pad
= ispad
;
1165 propogate_end_step1_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1167 if (extra
->start
.next
!= NULL
&&
1168 extra
->start
.next
== extra
->end
.next
)
1170 extra
->end
.next
= NULL
;
1171 mark_line_for_deletion ((LineType
*)ptr
);
1174 if (extra
->start
.at_pin
)
1175 propogate_ends_at (extra
, &extra
->start
, &extra
->end
);
1177 if (extra
->end
.at_pin
)
1178 propogate_ends_at (extra
, &extra
->end
, &extra
->start
);
1182 propogate_end_step2_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1184 if (extra
->start
.in_pin
)
1187 printf("MULTI at %d: was %p\n", __LINE__
, extra
->start
.next
);
1189 extra
->start
.next
= NULL
;
1191 if (extra
->end
.in_pin
)
1194 printf("MULTI at %d: was %p\n", __LINE__
, extra
->end
.next
);
1196 extra
->end
.next
= NULL
;
1201 propogate_end_step3_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1203 if (extra
->start
.next
)
1204 propogate_end_pin (extra
, &extra
->end
, &extra
->start
);
1205 if (extra
->end
.next
)
1206 propogate_end_pin (extra
, &extra
->start
, &extra
->end
);
1212 /* First, shut of "in pin" when we have an "at pin". We also clean
1213 up zero-length lines. */
1214 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step1_cb
, NULL
);
1216 /* Now end all paths at pins/pads. */
1217 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step2_cb
, NULL
);
1219 /* Now, propogate the pin/pad/vias along paths. */
1220 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step3_cb
, NULL
);
1223 static Extra
*last_pextra
= 0;
1226 print_extra (Extra
*e
, Extra
*prev
)
1229 if (e
->start
.next
== last_pextra
)
1231 else if (e
->end
.next
== last_pextra
)
1235 printf("%10p %10p %10p :", e
, e
->start
.next
, e
->end
.next
);
1238 printf("%10p \033[33m%10p\033[0m %10p :", e
, e
->start
.next
, e
->end
.next
);
1241 printf("%10p %10p \033[33m%10p\033[0m :", e
, e
->start
.next
, e
->end
.next
);
1246 e
->deleted
? 'd' : '-',
1247 e
->found
? 'f' : '-');
1248 printf(" s:%s%s%s%s",
1249 e
->start
.in_pin
? "I" : "-",
1250 e
->start
.at_pin
? "A" : "-",
1251 e
->start
.is_pad
? "P" : "-",
1252 e
->start
.pending
? "p" : "-");
1253 printf(" e:%s%s%s%s ",
1254 e
->end
.in_pin
? "I" : "-",
1255 e
->end
.at_pin
? "A" : "-",
1256 e
->end
.is_pad
? "P" : "-",
1257 e
->end
.pending
? "p" : "-");
1259 if (EXTRA_IS_LINE (e
))
1261 LineTypePtr line
= EXTRA2LINE (e
);
1262 pcb_printf(" %p L %#mD-%#mD", line
, line
->Point1
.X
, line
->Point1
.Y
, line
->Point2
.X
, line
->Point2
.Y
);
1263 printf(" %s %p %s %p\n",
1264 e
->start
.is_pad
? "pad" : "pin", e
->start
.pin
,
1265 e
->end
.is_pad
? "pad" : "pin", e
->end
.pin
);
1267 else if (EXTRA_IS_ARC (e
))
1269 ArcTypePtr arc
= EXTRA2ARC (e
);
1270 pcb_printf(" %p A %#mD-%#mD", arc
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
1271 pcb_printf(" at %#mD ang %ld,%ld\n", arc
->X
, arc
->Y
, arc
->StartAngle
, arc
->Delta
);
1273 else if (e
== &multi_next
)
1275 printf("-- Multi-next\n");
1279 printf("-- Unknown extra: %p\n", e
);
1285 trace_path (Extra
*e
)
1288 if ((e
->start
.next
&& e
->end
.next
)
1289 || (!e
->start
.next
&& !e
->end
.next
))
1293 printf("- path -\n");
1298 print_extra (e
, prev
);
1299 if (e
->start
.next
== prev
)
1318 LINE_LOOP (CURRENT
); {
1319 e
= LINE2EXTRA (line
);
1322 ARC_LOOP (CURRENT
); {
1323 e
= ARC2EXTRA (arc
);
1330 reverse_line (LineTypePtr line
)
1332 Extra
*e
= LINE2EXTRA (line
);
1339 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point1
),
1340 line
->Point2
.X
- line
->Point1
.X
,
1341 line
->Point2
.Y
- line
->Point1
.Y
);
1342 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point2
),
1344 y
- line
->Point2
.Y
);
1346 /* In theory, we should be using the above so that undo works. */
1347 line
->Point1
.X
= line
->Point2
.X
;
1348 line
->Point1
.Y
= line
->Point2
.Y
;
1352 memcpy (&etmp
, &e
->start
, sizeof (End
));
1353 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1354 memcpy (&e
->end
, &etmp
, sizeof (End
));
1358 reverse_arc (ArcTypePtr arc
)
1360 Extra
*e
= ARC2EXTRA (arc
);
1364 ChangeArcAngles (CURRENT
, arc
,
1365 arc
->StartAngle
+ arc
->Delta
, -arc
->Delta
);
1367 /* Likewise, see above. */
1368 arc
->StartAngle
+= arc
->Delta
;
1371 memcpy (&etmp
, &e
->start
, sizeof (End
));
1372 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1373 memcpy (&e
->end
, &etmp
, sizeof (End
));
1377 expand_box (BoxTypePtr b
, int x
, int y
, int t
)
1379 b
->X1
= MIN (b
->X1
, x
-t
);
1380 b
->X2
= MAX (b
->X2
, x
+t
);
1381 b
->Y1
= MIN (b
->Y1
, y
-t
);
1382 b
->Y2
= MAX (b
->Y2
, y
+t
);
1385 /* ---------------------------------------------------------------------- */
1386 /* These are the state variables for the intersection we're currently
1389 /* what we're working with */
1390 static ArcTypePtr start_arc
;
1391 static LineTypePtr start_line
;
1392 static LineTypePtr end_line
;
1393 static ArcTypePtr end_arc
;
1394 static Extra
*start_extra
, *end_extra
;
1395 static Extra
*sarc_extra
, *earc_extra
;
1396 static void *start_pinpad
, *end_pinpad
;
1397 static int thickness
;
1399 /* Pre-computed values. Note that all values are computed according
1400 to CARTESIAN coordinates, not PCB coordinates. Do an up-down board
1401 flip before wrapping your brain around the math. */
1403 /* se_sign is positive when you make a right turn going from start to end. */
1404 /* sa_sign is positive when start's arc is on the same side of start as end. */
1405 /* ea_sign is positive when end's arc is on the same side of end as start. */
1406 /* sa_sign and ea_sign may be zero if there's no arc. */
1407 static double se_sign
, sa_sign
, ea_sign
;
1409 static double best_angle
, start_angle
, end_dist
;
1410 /* arc radii are positive when they're on the same side as the things
1411 we're interested in. */
1412 static int sa_r
, ea_r
;
1413 static int sa_x
, sa_y
; /* start "arc" point */
1415 /* what we've found so far */
1416 static int fx
, fy
, fr
, fp
;
1418 static double fa
; /* relative angle */
1420 #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__)
1423 gp_point_force (int x
, int y
, int t
, End
*e
, int esa
, int eda
, int force
, const char *name
)
1427 double base_angle
, rel_angle
, point_angle
;
1430 pcb_printf("\033[34mgp_point_force %#mD %#mS via %s\033[0m\n", x
, y
, t
, name
);
1437 sr
= start_arc
->Width
;
1441 scx
= start_line
->Point1
.X
;
1442 scy
= start_line
->Point1
.Y
;
1448 /* See if the point is inside our start arc. */
1449 d
= Distance (scx
, scy
, x
, y
);
1451 pcb_printf("%f = dist #mD to %#mD\n", d
, scx
, scy
, x
, y
);
1452 pcb_printf("sr %#mS r %f d %f\n", sr
, r
, d
);
1457 printf("inside start arc, %f < %f\n", d
, sr
-r
);
1461 if (sr
== 0 && d
< r
)
1464 printf("start is inside arc, %f < %f\n", d
, r
);
1469 /* Now for the same tricky math we needed for the single puller.
1470 sr and r are the radii for the two points scx,scy and x,y. */
1472 /* angle between points (NOT pcb arc angles) */
1473 base_angle
= atan2 (y
- scy
, x
- scx
);
1475 pcb_printf("%.1f = atan2 (%#mS-%#mS = %#mS, %#mS-%#mS = %#mS)\n",
1476 r2d(base_angle
), y
, scy
, y
-scy
, x
, scx
, x
-scx
);
1479 if ((sa_sign
* sr
- r
) / d
> 1
1480 || (sa_sign
* sr
- r
) / d
< -1)
1483 /* Angle of tangent, relative to the angle between point centers. */
1484 rel_angle
= se_sign
* asin ((sa_sign
* sr
- r
) / d
);
1486 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n",
1487 r2d(rel_angle
), (int)se_sign
, (int)sa_sign
, sr
, r
, d
);
1490 /* Absolute angle of tangent. */
1491 point_angle
= base_angle
+ rel_angle
;
1493 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n",
1501 /* Check arc angles */
1502 double pa
= point_angle
;
1503 double sa
= d2r(180-esa
);
1504 double da
= d2r(-eda
);
1512 pa
-= se_sign
* M_PI
/2;
1520 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n",
1521 r2d(sa
), r2d(da
), r2d(pa
));
1527 a
= point_angle
- start_angle
;
1533 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a
));
1536 if (!force
&& a
* se_sign
< -0.007)
1540 printf("skipping, would increase angle (%f * %f)\n", a
, se_sign
);
1542 new_r
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1543 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1546 pcb_printf("point %#mD dist %#mS vs thickness %#mS\n", x
, y
, new_r
, thickness
);
1549 new_r
= (int)new_r
- 1;
1551 pcb_printf(" - new thickness %f old %#mS\n", new_r
, t
);
1554 gp_point_force (x
, y
, new_r
, e
, esa
, eda
, 1, __FUNCTION__
);
1559 printf("%f * %f < %f * %f ?\n", a
, se_sign
, best_angle
, se_sign
);
1561 if (a
* se_sign
== best_angle
* se_sign
)
1563 double old_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1565 double new_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1574 fp
= e
? e
->pending
: 0;
1578 else if (a
* se_sign
< best_angle
* se_sign
)
1585 fp
= e
? e
->pending
: 0;
1592 gp_point_2 (int x
, int y
, int t
, End
*e
, int esa
, int eda
, const char *func
)
1597 if (x
== sa_x
&& y
==sa_y
)
1601 pcb_printf("\033[34mgp_point %#mD %#mS via %s\033[0m\n", x
, y
, t
, func
);
1604 /* There are two regions we care about. For points inside our
1605 triangle, we check the crosses against start_line and end_line to
1606 make sure the point is "inside" the triangle. For points on the
1607 other side of the s-e line of the triangle, we check the dots to
1608 make sure it's between our endpoints. */
1610 /* See what side of the s-e line we're on */
1611 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1612 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1615 printf("s-e cross = %f\n", sc
);
1619 if (same_sign (sc
, se_sign
))
1621 /* Outside, check dots. */
1623 /* Ok, is it "in front of" our vectors? */
1624 sd
= dot2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1625 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1628 printf("sd = %f\n", sd
);
1633 ed
= dot2d (end_line
->Point2
.X
, end_line
->Point2
.Y
,
1634 start_line
->Point1
.X
, start_line
->Point1
.Y
,
1637 printf("ed = %f\n", ed
);
1642 sd
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1643 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1645 if (sd
> t
+ thickness
)
1650 /* Inside, check crosses. */
1652 /* First off, is it on the correct side of the start line? */
1653 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1654 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1657 printf("sc = %f\n", sc
);
1659 if (! same_sign (sc
, se_sign
))
1662 /* Ok, is it on the correct side of the end line? */
1663 ec
= cross2d (end_line
->Point1
.X
, end_line
->Point1
.Y
,
1664 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1667 printf("ec = %f\n", ec
);
1669 if (! same_sign (ec
, se_sign
))
1675 printf("in range!\n");
1678 return gp_point_force (x
, y
, t
, e
, esa
, eda
, 0, func
);
1682 gp_line_cb (const BoxType
*b
, void *cb
)
1684 const LineTypePtr l
= (LineTypePtr
) b
;
1685 Extra
*e
= LINE2EXTRA(l
);
1686 if (l
== start_line
|| l
== end_line
)
1690 #ifdef CHECK_LINE_PT_NEG
1691 if (l
->Point1
.X
< 0)
1695 || ! EXTRA_IS_ARC (e
->start
.next
))
1696 gp_point (l
->Point1
.X
, l
->Point1
.Y
, l
->Thickness
/2, &e
->start
);
1698 || ! EXTRA_IS_ARC (e
->end
.next
))
1699 gp_point (l
->Point2
.X
, l
->Point2
.Y
, l
->Thickness
/2, &e
->end
);
1704 gp_arc_cb (const BoxType
*b
, void *cb
)
1706 const ArcTypePtr a
= (ArcTypePtr
) b
;
1707 Extra
*e
= ARC2EXTRA(a
);
1708 if (a
== start_arc
|| a
== end_arc
)
1712 gp_point_2 (a
->X
, a
->Y
, a
->Width
+ a
->Thickness
/2, 0, a
->StartAngle
, a
->Delta
, __FUNCTION__
);
1714 && a
->X
== start_arc
->X
1715 && a
->Y
== start_arc
->Y
)
1718 && a
->X
!= end_arc
->X
1719 && a
->Y
!= end_arc
->Y
)
1722 if (e
->start
.next
|| e
->end
.next
)
1725 gp_point (e
->start
.x
, e
->start
.y
, a
->Thickness
/2, 0);
1726 gp_point (e
->end
.x
, e
->end
.y
, a
->Thickness
/2, 0);
1731 gp_text_cb (const BoxType
*b
, void *cb
)
1733 const TextTypePtr t
= (TextTypePtr
) b
;
1734 /* FIXME: drop in the actual text-line endpoints later. */
1735 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y1
, 0, 0);
1736 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y2
, 0, 0);
1737 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y2
, 0, 0);
1738 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y1
, 0, 0);
1743 gp_poly_cb (const BoxType
*b
, void *cb
)
1746 const PolygonTypePtr p
= (PolygonTypePtr
) b
;
1747 for (i
=0; i
<p
->PointN
; i
++)
1748 gp_point (p
->Points
[i
].X
, p
->Points
[i
].Y
, 0, 0);
1753 gp_pin_cb (const BoxType
*b
, void *cb
)
1755 const PinTypePtr p
= (PinTypePtr
) b
;
1756 int t2
= (p
->Thickness
+1)/2;
1758 if (p
== start_pinpad
|| p
== end_pinpad
)
1761 /* FIXME: we lump octagonal pins in with square; safe, but not
1763 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1765 gp_point (p
->X
- t2
, p
->Y
- t2
, 0, 0);
1766 gp_point (p
->X
- t2
, p
->Y
+ t2
, 0, 0);
1767 gp_point (p
->X
+ t2
, p
->Y
+ t2
, 0, 0);
1768 gp_point (p
->X
+ t2
, p
->Y
- t2
, 0, 0);
1772 gp_point (p
->X
, p
->Y
, t2
, 0);
1778 gp_pad_cb (const BoxType
*b
, void *cb
)
1780 const PadTypePtr p
= (PadTypePtr
) b
;
1781 int t2
= (p
->Thickness
+1)/2;
1783 if (p
== start_pinpad
|| p
== end_pinpad
)
1786 if (TEST_FLAG (ONSOLDERFLAG
, p
))
1788 if (!current_is_solder
)
1793 if (!current_is_component
)
1797 /* FIXME: we lump octagonal pads in with square; safe, but not
1798 optimal. I don't think we even support octagonal pads. */
1799 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1801 if (p
->Point1
.X
== p
->Point2
.X
)
1803 int y1
= MIN (p
->Point1
.Y
, p
->Point2
.Y
) - t2
;
1804 int y2
= MAX (p
->Point1
.Y
, p
->Point2
.Y
) + t2
;
1806 gp_point (p
->Point1
.X
- t2
, y1
, 0, 0);
1807 gp_point (p
->Point1
.X
- t2
, y2
, 0, 0);
1808 gp_point (p
->Point1
.X
+ t2
, y1
, 0, 0);
1809 gp_point (p
->Point1
.X
+ t2
, y2
, 0, 0);
1813 int x1
= MIN (p
->Point1
.X
, p
->Point2
.X
) - t2
;
1814 int x2
= MAX (p
->Point1
.X
, p
->Point2
.X
) + t2
;
1816 gp_point (x1
, p
->Point1
.Y
- t2
, 0, 0);
1817 gp_point (x2
, p
->Point1
.Y
- t2
, 0, 0);
1818 gp_point (x1
, p
->Point1
.Y
+ t2
, 0, 0);
1819 gp_point (x2
, p
->Point1
.Y
+ t2
, 0, 0);
1824 gp_point (p
->Point1
.X
, p
->Point1
.Y
, t2
, 0);
1825 gp_point (p
->Point2
.X
, p
->Point2
.Y
, t2
, 0);
1831 create_line (LineTypePtr sample
, int x1
, int y1
, int x2
, int y2
)
1835 pcb_printf("create_line from %#mD to %#mD\n", x1
, y1
, x2
, y2
);
1837 LineTypePtr line
= CreateNewLineOnLayer (CURRENT
, x1
, y1
, x2
, y2
,
1838 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1839 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1844 new_line_extra (line
);
1846 printf(" - line extra is %p\n", e
);
1852 create_arc (LineTypePtr sample
, int x
, int y
, int r
, int sa
, int da
)
1862 pcb_printf("create_arc at %#mD r %#mS sa %d delta %d\n", x
, y
, r
, sa
, da
);
1864 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
,
1865 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1868 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
*2,
1869 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1871 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1874 longjmp (abort_buf
, 1);
1876 e
= new_arc_extra (arc
);
1878 printf(" - arc extra is %p\n", e
);
1880 fix_arc_extra (arc
, e
);
1885 unlink_extras (Extra
*e
)
1888 fprintf(stderr
, "unlink %p\n", e
);
1894 print_extra(e
->start
.next
, 0);
1896 if (e
->start
.next
->start
.next
== e
)
1899 fprintf(stderr
, " - %p->start points to me\n", e
->start
.next
);
1901 e
->start
.next
->start
.next
= e
->end
.next
;
1903 else if (e
->start
.next
->end
.next
== e
)
1906 fprintf(stderr
, " - %p->end points to me\n", e
->start
.next
);
1908 e
->start
.next
->end
.next
= e
->end
.next
;
1912 fprintf(stderr
, " - %p doesn't point to me!\n", e
->start
.next
);
1919 print_extra(e
->end
.next
, 0);
1921 if (e
->end
.next
->start
.next
== e
)
1924 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1926 e
->end
.next
->start
.next
= e
->start
.next
;
1928 else if (e
->end
.next
->end
.next
== e
)
1931 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1933 e
->end
.next
->end
.next
= e
->start
.next
;
1937 fprintf(stderr
, " - %p doesn't point to me!\n", e
->end
.next
);
1941 e
->start
.next
= e
->end
.next
= 0;
1945 mark_line_for_deletion (LineTypePtr l
)
1947 Extra
*e
= LINE2EXTRA(l
);
1950 fprintf(stderr
, "double delete?\n");
1956 pcb_printf("Marked line %p for deletion %#mD to %#mD\n",
1957 e
, l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1960 if (l
->Point1
.X
< 0)
1962 fprintf(stderr
, "double neg move?\n");
1965 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point1
),
1968 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point2
),
1975 mark_arc_for_deletion (ArcTypePtr a
)
1977 Extra
*e
= ARC2EXTRA(a
);
1981 printf("Marked arc %p for deletion %ld < %ld\n",
1982 e
, a
->StartAngle
, a
->Delta
);
1986 /* Given a starting line, which may be attached to an arc, and which
1987 intersects with an ending line, which also may be attached to an
1988 arc, maybe pull them. We assume start_line is attached to the arc
1989 via Point1, and attached to the end line via Point2. Likewise, we
1990 make end_line attach to the start_line via Point1 and the arc via
1991 Point 2. We also make the arcs attach on the Delta end, not the
1992 Start end. Here's a picture:
1994 S S+D P1 P2 P1 P2 S+D S
1995 *--- start_arc ---*--- start_line ---*--- end_line ---*--- end_arc ---*
2000 maybe_pull_1 (LineTypePtr line
)
2003 /* Line half-thicknesses, including line space */
2005 LineTypePtr new_line
;
2012 start_extra
= LINE2EXTRA (start_line
);
2013 end_extra
= start_extra
->end
.next
;
2014 end_line
= EXTRA2LINE (end_extra
);
2015 if (end_extra
->deleted
)
2017 start_extra
->end
.pending
= 0;
2021 if (end_extra
->end
.next
== start_extra
)
2022 reverse_line (end_line
);
2024 if (start_extra
->start
.next
2025 && EXTRA_IS_ARC (start_extra
->start
.next
))
2027 sarc_extra
= start_extra
->start
.next
;
2028 start_arc
= EXTRA2ARC (sarc_extra
);
2029 if (sarc_extra
->start
.next
== start_extra
)
2030 reverse_arc (start_arc
);
2038 if (end_extra
->end
.next
2039 && EXTRA_IS_ARC (end_extra
->end
.next
))
2041 earc_extra
= end_extra
->end
.next
;
2042 end_arc
= EXTRA2ARC (earc_extra
);
2043 if (earc_extra
->start
.next
== end_extra
)
2044 reverse_arc (end_arc
);
2053 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra
, start_extra
, end_extra
, earc_extra
);
2055 print_extra(sarc_extra
,0);
2056 print_extra(start_extra
,0);
2057 print_extra(end_extra
,0);
2059 print_extra(earc_extra
,0);
2061 if (start_extra
->deleted
2062 || end_extra
->deleted
2063 || (sarc_extra
&& sarc_extra
->deleted
)
2064 || (earc_extra
&& earc_extra
->deleted
))
2066 printf(" one is deleted?\n");
2072 if (!start_extra
->end
.pending
)
2075 if (start_extra
->end
.waiting_for
2076 && start_extra
->end
.waiting_for
->pending
)
2080 if (start_line
->Thickness
!= end_line
->Thickness
)
2082 thickness
= (start_line
->Thickness
+ 1)/2 + PCB
->Bloat
;
2084 /* At this point, our expectations are all met. */
2086 box
.X1
= start_line
->Point1
.X
- thickness
;
2087 box
.X2
= start_line
->Point1
.X
+ thickness
;
2088 box
.Y1
= start_line
->Point1
.Y
- thickness
;
2089 box
.Y2
= start_line
->Point1
.Y
+ thickness
;
2090 expand_box (&box
, start_line
->Point2
.X
, start_line
->Point2
.Y
, thickness
);
2091 expand_box (&box
, end_line
->Point2
.X
, end_line
->Point2
.Y
, thickness
);
2093 expand_box (&box
, sarc_extra
->start
.x
, sarc_extra
->start
.y
, start_arc
->Thickness
/2);
2095 expand_box (&box
, earc_extra
->start
.x
, earc_extra
->start
.y
, end_arc
->Thickness
/2);
2098 se_sign
= copysign (1, cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2099 start_line
->Point2
.X
, start_line
->Point2
.Y
,
2100 end_line
->Point2
.X
, end_line
->Point2
.Y
));
2101 best_angle
= se_sign
* M_PI
;
2104 sa_sign
= copysign (1, -start_arc
->Delta
);
2111 ea_sign
= copysign (1, -end_arc
->Delta
);
2112 ea_sign
*= -se_sign
;
2117 start_angle
= atan2 (start_line
->Point2
.Y
- start_line
->Point1
.Y
,
2118 start_line
->Point2
.X
- start_line
->Point1
.X
);
2120 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n",
2121 se_sign
, sa_sign
, ea_sign
, r2d (best_angle
), r2d(start_angle
));
2126 sa_x
= start_arc
->X
;
2127 sa_y
= start_arc
->Y
;
2128 if (same_sign (start_arc
->Delta
, se_sign
))
2129 sa_r
= - start_arc
->Width
;
2131 sa_r
= start_arc
->Width
;
2135 sa_x
= start_line
->Point1
.X
;
2136 sa_y
= start_line
->Point1
.Y
;
2143 ea_r
= end_arc
->Width
;
2145 ea_r
= - end_arc
->Width
;
2151 trace_path (sarc_extra
? sarc_extra
: start_extra
);
2156 gp_point_force (end_arc
->X
, end_arc
->Y
, -ea_r
-thickness
, 0, 0, 0, 1, "end arc");
2162 gp_point_force (end_line
->Point2
.X
, end_line
->Point2
.Y
, -thickness
, 0, 0, 0, 1, "end arc");
2163 ex
= end_line
->Point2
.X
;
2164 ey
= end_line
->Point2
.Y
;
2171 pcb_fprintf(stderr
, "end line corrupt? f is %#mD\n", fx
, fy
);
2172 print_extra (end_extra
, 0);
2174 print_extra(earc_extra
, 0);
2178 end_dist
= Distance (end_line
->Point1
.X
, end_line
->Point1
.Y
,
2179 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2181 start_pinpad
= start_extra
->start
.pin
;
2182 end_pinpad
= start_extra
->end
.pin
;
2185 r_search(CURRENT
->line_tree
, &box
, NULL
, gp_line_cb
, 0);
2186 r_search(CURRENT
->arc_tree
, &box
, NULL
, gp_arc_cb
, 0);
2187 r_search(CURRENT
->text_tree
, &box
, NULL
, gp_text_cb
, 0);
2188 r_search(CURRENT
->polygon_tree
, &box
, NULL
, gp_poly_cb
, 0);
2189 r_search(PCB
->Data
->pin_tree
, &box
, NULL
, gp_pin_cb
, 0);
2190 r_search(PCB
->Data
->via_tree
, &box
, NULL
, gp_pin_cb
, 0);
2191 r_search(PCB
->Data
->pad_tree
, &box
, NULL
, gp_pad_cb
, 0);
2193 /* radians, absolute angle of (at the moment) the start_line */
2194 abs_angle
= fa
+ start_angle
;
2197 pcb_printf("\033[43;30mBest: at %#mD r %#mS, angle %.1f fp %d\033[0m\n", fx
, fy
, fr
, r2d(fa
), fp
);
2201 if (fa
> M_PI
/2 || fa
< -M_PI
/2)
2203 SET_FLAG (FOUNDFLAG
, line
);
2204 longjmp (abort_buf
, 1);
2210 start_extra
->end
.waiting_for
= fp_end
;
2213 start_extra
->end
.pending
= 0;
2215 /* Step 0: check for merged arcs (special case). */
2217 if (fx
== ex
&& fy
== ey
2218 && start_arc
&& end_arc
2219 && start_arc
->X
== end_arc
->X
&& start_arc
->Y
== end_arc
->Y
)
2224 new_delta
= end_arc
->StartAngle
- start_arc
->StartAngle
;
2225 if (start_arc
->Delta
> 0)
2227 while (new_delta
> 360)
2229 while (new_delta
< 0)
2234 while (new_delta
< -360)
2236 while (new_delta
> 0)
2240 pcb_printf("merging arcs at %#mS nd %d\n", start_arc
->X
, start_arc
->Y
, new_delta
);
2241 print_extra(sarc_extra
, 0);
2242 print_extra(earc_extra
, 0);
2244 mark_arc_for_deletion (end_arc
);
2245 mark_line_for_deletion (start_line
);
2246 mark_line_for_deletion (end_line
);
2247 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2248 fix_arc_extra (start_arc
, sarc_extra
);
2253 /* Step 1: adjust start_arc's angles and move start_line's Point1 to
2261 /* We must always round towards "larger arcs", whichever way that is. */
2262 new_delta
= 180 - r2d(abs_angle
);
2264 printf("new_delta starts at %d vs %d < %d\n",
2265 (int)new_delta
, (int)start_arc
->StartAngle
, (int)start_arc
->Delta
);
2267 if (start_arc
->Delta
< 0)
2268 new_delta
= (int)(new_delta
) + 90;
2270 new_delta
= (int)new_delta
- 90;
2271 new_delta
= new_delta
- start_arc
->StartAngle
;
2272 while (new_delta
> start_arc
->Delta
+180)
2274 while (new_delta
< start_arc
->Delta
-180)
2277 printf("new_delta adjusts to %d\n", (int)new_delta
);
2278 printf("fa = %f, new_delta ends at %.1f vs start %d\n",
2279 fa
, new_delta
, (int)start_arc
->StartAngle
);
2282 if (new_delta
* start_arc
->Delta
<= 0)
2285 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2286 fix_arc_extra (start_arc
, sarc_extra
);
2287 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2288 sarc_extra
->end
.x
- start_line
->Point1
.X
,
2289 sarc_extra
->end
.y
- start_line
->Point1
.Y
);
2293 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2294 sarc_extra
->start
.x
- start_line
->Point1
.X
,
2295 sarc_extra
->start
.y
- start_line
->Point1
.Y
);
2296 mark_arc_for_deletion (start_arc
);
2300 /* Step 1.5: If the "obstacle" is right at the end, ignore it. */
2303 double oa
= start_angle
+fa
- M_PI
/2*se_sign
;
2304 double ox
= fx
+ fr
* cos(oa
);
2305 double oy
= fy
+ fr
* sin(oa
);
2307 pcb_printf("obstacle at %#mD angle %d = arc starts at %#mD\n",
2308 fx
, fy
, (int)r2d(oa
), (int)ox
, (int)oy
);
2311 if (Distance (ox
, oy
, end_line
->Point2
.X
, end_line
->Point2
.Y
)
2314 /* Pretend it doesn't exist. */
2320 /* Step 2: If we have no obstacles, connect start and end. */
2323 pcb_printf("fx %#mS ex %#mS fy %#mS ey %#mS\n", fx
, ex
, fy
, ey
);
2325 if (fx
== ex
&& fy
== ey
)
2329 printf("\033[32mno obstacles\033[0m\n");
2334 int new_delta
, end_angle
, pcb_fa
, end_change
;
2336 end_angle
= end_arc
->StartAngle
+ end_arc
->Delta
;
2337 if (end_arc
->Delta
< 0)
2342 /* We must round so as to make the larger arc. */
2343 if (end_arc
->Delta
< 0)
2344 pcb_fa
= - r2d(start_angle
+ fa
);
2346 pcb_fa
= 1 - r2d(start_angle
+ fa
);
2347 end_change
= pcb_fa
- end_angle
;
2349 while (end_change
> 180)
2351 while (end_change
< -180)
2353 new_delta
= end_arc
->Delta
+ end_change
;
2355 if (new_delta
* end_arc
->Delta
<= 0)
2358 ChangeArcAngles (CURRENT
, end_arc
, end_arc
->StartAngle
, new_delta
);
2359 fix_arc_extra (end_arc
, earc_extra
);
2360 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2361 earc_extra
->end
.x
- start_line
->Point2
.X
,
2362 earc_extra
->end
.y
- start_line
->Point2
.Y
);
2366 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2367 earc_extra
->start
.x
- start_line
->Point2
.X
,
2368 earc_extra
->start
.y
- start_line
->Point2
.Y
);
2369 mark_arc_for_deletion (end_arc
);
2374 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2375 end_line
->Point2
.X
- start_line
->Point2
.X
,
2376 end_line
->Point2
.Y
- start_line
->Point2
.Y
);
2378 mark_line_for_deletion (end_line
);
2379 start_extra
->end
.pending
= 1;
2382 printf("\033[35mdid_something: no obstacles\033[0m\n");
2390 /* Step 3: Compute the new intersection of start_line and end_line. */
2392 ex
= start_line
->Point1
.X
+ cos(start_angle
+ fa
) * 10000.0;
2393 ey
= start_line
->Point1
.Y
+ sin(start_angle
+ fa
) * 10000.0;
2395 pcb_printf("temp point %#mS\n", ex
, ey
);
2396 pcb_printf("intersect %#mS-%#mS with %#mS-%#mS\n",
2397 start_line
->Point1
.X
, start_line
->Point1
.Y
,
2399 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2400 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2402 if (! intersection_of_lines (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2404 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2405 end_line
->Point2
.X
, end_line
->Point2
.Y
,
2408 ex
= end_line
->Point2
.X
;
2409 ey
= end_line
->Point2
.Y
;
2412 pcb_printf("new point %#mS\n", ex
, ey
);
2414 MoveObject (LINEPOINT_TYPE
, CURRENT
, end_line
, &(end_line
->Point1
),
2415 ex
- end_line
->Point1
.X
,
2416 ey
- end_line
->Point1
.Y
);
2418 /* Step 4: Split start_line at the obstacle and insert a zero-delta
2421 new_arc
= create_arc (start_line
, fx
, fy
, fr
,
2422 90-(int)(r2d(start_angle
+fa
)+0.5) + 90 + 90*se_sign
, -se_sign
);
2423 new_aextra
= ARC2EXTRA (new_arc
);
2425 if (start_arc
) sarc_extra
= ARC2EXTRA (start_arc
);
2426 if (end_arc
) earc_extra
= ARC2EXTRA (end_arc
);
2428 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2429 new_aextra
->start
.x
- start_line
->Point2
.X
,
2430 new_aextra
->start
.y
- start_line
->Point2
.Y
);
2432 new_line
= create_line (start_line
, new_aextra
->end
.x
, new_aextra
->end
.y
, ex
, ey
);
2433 start_extra
= LINE2EXTRA (start_line
);
2434 new_lextra
= LINE2EXTRA (new_line
);
2435 end_extra
= LINE2EXTRA (end_line
);
2437 new_lextra
->start
.pin
= start_extra
->start
.pin
;
2438 new_lextra
->end
.pin
= start_extra
->end
.pin
;
2439 new_lextra
->start
.pending
= 1;
2440 new_lextra
->end
.pending
= 1;
2442 start_extra
->end
.next
= new_aextra
;
2443 new_aextra
->start
.next
= start_extra
;
2444 new_aextra
->end
.next
= new_lextra
;
2445 new_lextra
->start
.next
= new_aextra
;
2446 new_lextra
->end
.next
= end_extra
;
2447 end_extra
->start
.next
= new_lextra
;
2449 /* Step 5: Recurse. */
2455 printf("\033[35mdid_something: recursing\033[0m\n");
2457 int i
= gui
->confirm_dialog("recurse?", 0);
2458 printf("confirm = %d\n", i
);
2462 printf("\n\033[33mRECURSING\033[0m\n\n");
2463 IncrementUndoSerialNumber();
2465 maybe_pull_1 (new_line
);
2468 /* Given a line with a end_next, attempt to pull both ends. */
2470 maybe_pull (LineTypePtr line
, Extra
*e
)
2473 printf("maybe_pull: ");
2476 if (e
->end
.next
&& EXTRA_IS_LINE (e
->end
.next
))
2478 maybe_pull_1 (line
);
2483 if (e
->start
.next
&& EXTRA_IS_LINE (e
->start
.next
))
2485 reverse_line (line
);
2486 maybe_pull_1 (line
);
2489 e
->start
.pending
= 0;
2494 validate_pair (Extra
*e
, End
*end
)
2498 if (end
->next
->start
.next
== e
)
2500 if (end
->next
->end
.next
== e
)
2502 fprintf(stderr
, "no backlink!\n");
2504 print_extra (end
->next
, 0);
2509 validate_pair_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2511 validate_pair (extra
, &extra
->start
);
2512 validate_pair (extra
, &extra
->end
);
2518 g_hash_table_foreach (lines
, (GHFunc
)validate_pair_cb
, NULL
);
2522 g_hash_table_foreach (arcs
, (GHFunc
)validate_pair_cb
, NULL
);
2526 FreeExtra (Extra
*extra
)
2528 g_slice_free (Extra
, extra
);
2532 mark_ends_pending (LineType
*line
, Extra
*extra
, void *userdata
)
2534 int *select_flags
= userdata
;
2535 if (TEST_FLAGS (*select_flags
, line
))
2537 extra
->start
.pending
= 1;
2538 extra
->end
.pending
= 1;
2544 trace_print_extra (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2546 last_pextra
= (Extra
*)1;
2547 print_extra(extra
, 0);
2551 trace_print_lines_arcs (void)
2553 printf("\nlines\n");
2554 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2557 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2564 GlobalPuller(int argc
, char **argv
, Coord x
, Coord y
)
2566 int select_flags
= 0;
2571 printf("puller! %s\n", argc
> 0 ? argv
[0] : "");
2573 if (argc
> 0 && strcasecmp (argv
[0], "selected") == 0)
2574 select_flags
= SELECTEDFLAG
;
2575 if (argc
> 0 && strcasecmp (argv
[0], "found") == 0)
2576 select_flags
= FOUNDFLAG
;
2578 printf("optimizing...\n");
2579 /* This canonicalizes all the lines, and cleans up near-misses. */
2580 /* hid_actionl ("djopt", "puller", 0); */
2582 current_is_solder
= (GetLayerGroupNumberByPointer(CURRENT
)
2583 == GetLayerGroupNumberByNumber (solder_silk_layer
));
2584 current_is_component
= (GetLayerGroupNumberByPointer(CURRENT
)
2585 == GetLayerGroupNumberByNumber (component_silk_layer
));
2587 lines
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2588 arcs
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2590 printf("pairing...\n");
2594 g_hash_table_foreach (lines
, (GHFunc
)mark_ends_pending
, &select_flags
);
2597 trace_print_lines_arcs ();
2603 trace_print_lines_arcs ();
2607 printf("pulling...\n");
2608 if (setjmp(abort_buf
) == 0)
2611 int old_did_something
= -1;
2614 while (did_something
)
2619 LINE_LOOP (CURRENT
); {
2620 Extra
*e
= LINE2EXTRA (line
);
2623 #ifdef CHECK_LINE_PT_NEG
2624 if (line
->Point1
.X
< 0)
2627 if (e
->start
.next
|| e
->end
.next
)
2628 maybe_pull (line
, e
);
2630 if (did_something
!= old_did_something
)
2632 IncrementUndoSerialNumber();
2633 old_did_something
= did_something
;
2634 if (gui
->confirm_dialog("more?", 0) == 0)
2641 /*gui->progress(0,0,0);*/
2647 printf("\nlines\n");
2648 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2650 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2652 printf("\nlines\n");
2655 LINE_LOOP (CURRENT
);
2657 if (LINE2EXTRA (line
)->deleted
)
2658 RemoveLine (CURRENT
, line
);
2664 if (ARC2EXTRA (arc
)->deleted
)
2665 RemoveArc (CURRENT
, arc
);
2669 g_hash_table_unref (lines
);
2670 g_hash_table_unref (arcs
);
2672 IncrementUndoSerialNumber();
2676 /*****************************************************************************/
2680 /*****************************************************************************/
2682 HID_Action puller_action_list
[] = {
2683 {"Puller", "Click on a line-arc intersection or line segment", Puller
,
2684 puller_help
, puller_syntax
},
2685 {"GlobalPuller", 0, GlobalPuller
,
2686 globalpuller_help
, globalpuller_syntax
}
2689 REGISTER_ACTIONS (puller_action_list
)