4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2006 DJ Delorie
6 * Copyright (C) 2011 PCB Contributers (See ChangeLog for details)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Contact addresses for paper mail and Email:
23 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
28 /* FIXME: Things that need to be fixed before this is "perfect".
29 Add to this list as we find things.
31 - respect the outline layer.
33 - don't consider points that are perpendicular to our start_arc.
34 I.e. when we have busses going around corners, we have a *lot* of
35 arcs and endpoints that are all in the same direction and all
36 equally "good", but rounding the arc angles to integers causes
37 all sorts of tiny differences that result in bumps, reversals,
40 - Store the X,Y values in our shadow struct so we don't fill up the
41 undo buffer with all our line reversals.
43 - at least check the other layers in our layer group.
64 #include "pcb-printf.h"
70 #ifdef HAVE_LIBDMALLOC
74 #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort()
79 /* sine of one degree */
80 #define SIN1D 0.0174524064372835
82 static jmp_buf abort_buf
;
84 #define sqr(x) (1.0*(x)*(x))
86 static int multi
, line_exact
, arc_exact
;
87 static LineType
*the_line
;
88 static ArcType
*the_arc
;
89 static double arc_dist
;
91 /* We canonicalize the arc and line such that the point to be moved is
92 always Point2 for the line, and at start+delta for the arc. */
94 static int x
, y
; /* the point we're moving */
95 static int cx
, cy
; /* centerpoint of the arc */
96 static int ex
, ey
; /* fixed end of the line */
98 /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */
101 within (int x1
, int y1
, int x2
, int y2
, int r
)
103 return Distance (x1
, y1
, x2
, y2
) <= r
/ 2;
107 arc_endpoint_is (ArcType
*a
, int angle
, int x
, int y
)
109 int ax
= a
->X
, ay
= a
->Y
;
113 int ai
= (int) (angle
/ 90) & 3;
132 double rad
= angle
* M_PI
/ 180;
133 ax
-= a
->Width
* cos (rad
);
134 ay
+= a
->Width
* sin (rad
);
137 pcb_printf (" - arc endpoint %#mD\n", ax
, ay
);
139 arc_dist
= Distance (ax
, ay
, x
, y
);
142 return arc_dist
< a
->Thickness
/ 2;
145 /* Cross c->u and c->v, return the magnitute */
147 cross2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
153 return (double)ux
* vy
- (double)uy
* vx
;
156 /* Likewise, for dot product. */
158 dot2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
164 return (double)ux
* vx
+ (double)uy
* vy
;
168 /* angle of c->v, relative to c->u, in radians. Range is -pi..pi */
170 angle2d (int cx
, int cy
, int ux
, int uy
, int vx
, int vy
)
173 double magu
, magv
, sintheta
;
175 printf("angle2d %d,%d %d,%d %d,%d\n", cx
, cy
, ux
, uy
, vx
, vy
);
182 printf(" = %d,%d %d,%d\n", ux
, uy
, vx
, vy
);
184 cross
= (double)ux
* vy
- (double)uy
* vx
;
185 magu
= sqrt((double)ux
*ux
+ (double)uy
*uy
);
186 magv
= sqrt((double)vx
*vx
+ (double)vy
*vy
);
187 sintheta
= cross
/ (magu
* magv
);
189 printf(" = %f / (%f * %f) = %f\n", cross
, magu
, magv
, sintheta
);
191 return asin (sintheta
);
196 same_sign (double a
, double b
)
204 return 180.0 * r
/ M_PI
;
210 return M_PI
* d
/ 180.0;
216 det (double a
, double b
, double c
, double d
)
218 return a
* d
- b
* c
;
221 /* The lines are x1y1-x2y2 and x3y3-x4y4. Returns true if they
224 intersection_of_lines (int x1
, int y1
, int x2
, int y2
,
225 int x3
, int y3
, int x4
, int y4
,
229 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
232 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
233 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
234 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
235 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
236 *xr
= (int) (x
+ 0.5);
237 *yr
= (int) (y
+ 0.5);
241 /* Same, for line segments. Returns true if they intersect. For this
242 function, xr and yr may be NULL if you don't need the values. */
244 intersection_of_linesegs (int x1
, int y1
, int x2
, int y2
,
245 int x3
, int y3
, int x4
, int y4
,
249 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
252 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
253 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
254 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
255 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
256 if (MIN (x1
, x2
) > x
|| x
> MAX (x1
, x2
)
257 || MIN (y1
, y2
) > y
|| y
> MAX (y1
, y2
))
259 if (MIN (x3
, x4
) > x
|| x
> MAX (x3
, x4
)
260 || MIN (y3
, y4
) > y
|| y
> MAX (y3
, y4
))
263 *xr
= (int) (x
+ 0.5);
265 *yr
= (int) (y
+ 0.5);
269 /* distance between a line and a point */
271 dist_lp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
273 double den
= Distance (x1
, y1
, x2
, y2
);
274 double rv
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
275 - ((double)x1
- px
) * ((double)y2
- y1
))
278 pcb_printf("dist %#mD-%#mD to %#mD is %f\n",
279 x1
, y1
, x2
, y2
, px
, py
, rv
);
284 /* distance between a line segment and a point */
286 dist_lsp (int x1
, int y1
, int x2
, int y2
, int px
, int py
)
289 if (dot2d (x1
, y1
, x2
, y2
, px
, py
) < 0)
290 return Distance (x1
, y1
, px
, py
);
291 if (dot2d (x2
, y2
, x1
, y1
, px
, py
) < 0)
292 return Distance (x2
, y2
, px
, py
);
293 d
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
294 - ((double)x1
- px
) * ((double)y2
- y1
))
295 / Distance (x1
, y1
, x2
, y2
));
299 /*****************************************************************************/
301 /* Single Point Puller */
303 /*****************************************************************************/
306 line_callback (const BoxType
* b
, void *cl
)
308 /* LayerType *layer = (LayerType *)cl; */
309 LineType
*l
= (LineType
*) b
;
312 pcb_printf ("line %#mD .. %#mD\n",
313 l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
315 d1
= Distance (l
->Point1
.X
, l
->Point1
.Y
, x
, y
);
316 d2
= Distance (l
->Point2
.X
, l
->Point2
.Y
, x
, y
);
317 if ((d1
< 2 || d2
< 2) && !line_exact
)
322 t
= line_exact
? 2 : l
->Thickness
/ 2;
323 if (d1
< t
|| d2
< t
)
329 printf ("picked, exact %d\n", line_exact
);
336 arc_callback (const BoxType
* b
, void *cl
)
338 /* LayerType *layer = (LayerType *) cl; */
339 ArcType
*a
= (ArcType
*) b
;
342 pcb_printf ("arc a %#mD r %#mS sa %ld d %ld\n", a
->X
, a
->Y
, a
->Width
,
343 a
->StartAngle
, a
->Delta
);
345 if (!arc_endpoint_is (a
, a
->StartAngle
, x
, y
)
346 && !arc_endpoint_is (a
, a
->StartAngle
+ a
->Delta
, x
, y
))
359 printf ("picked, exact %d\n", arc_exact
);
368 printf ("picked, exact %d\n", arc_exact
);
375 find_pair (int Px
, int Py
)
380 pcb_printf ("\nPuller find_pair at %#mD\n", Crosshair
.X
, Crosshair
.Y
);
386 line_exact
= arc_exact
= 0;
393 r_search (CURRENT
->line_tree
, &spot
, NULL
, line_callback
, CURRENT
);
394 r_search (CURRENT
->arc_tree
, &spot
, NULL
, arc_callback
, CURRENT
);
395 if (the_line
&& the_arc
&& !multi
)
403 static const char puller_syntax
[] = "Puller()";
405 static const char puller_help
[] = "Pull an arc-line junction tight.";
407 /* %start-doc actions Puller
409 The @code{Puller()} action is a special-purpose optimization. When
410 invoked while the crosshair is over the junction of an arc and a line,
411 it will adjust the arc's angle and the connecting line's endpoint such
412 that the line intersects the arc at a tangent. In the example below,
413 the left side is ``before'' with the black target marking where to put
416 @center @image{puller,,,Example of how puller works,png}
418 The right side is ``after'' with the black target marking where the
419 arc-line intersection was moved to.
424 Puller (int argc
, char **argv
, Coord Ux
, Coord Uy
)
426 double arc_angle
, base_angle
;
428 double line_angle
, rel_angle
;
433 if (!find_pair (Crosshair
.X
, Crosshair
.Y
))
434 if (!find_pair (Ux
, Uy
))
437 if (within (the_line
->Point1
.X
, the_line
->Point1
.Y
,
438 x
, y
, the_line
->Thickness
))
440 ex
= the_line
->Point2
.X
;
441 ey
= the_line
->Point2
.Y
;
442 the_line
->Point2
.X
= the_line
->Point1
.X
;
443 the_line
->Point2
.Y
= the_line
->Point1
.Y
;
444 the_line
->Point1
.X
= ex
;
445 the_line
->Point1
.Y
= ey
;
447 else if (!within (the_line
->Point2
.X
, the_line
->Point2
.Y
,
448 x
, y
, the_line
->Thickness
))
451 printf ("Line endpoint not at cursor\n");
455 ex
= the_line
->Point1
.X
;
456 ey
= the_line
->Point1
.Y
;
460 if (arc_endpoint_is (the_arc
, the_arc
->StartAngle
, x
, y
))
462 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
465 else if (!arc_endpoint_is (the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
469 printf ("arc not endpoints\n");
474 if (within (cx
, cy
, ex
, ey
, the_arc
->Width
* 2))
477 printf ("line ends inside arc\n");
482 if (the_arc
->Delta
> 0)
483 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
+ 90;
485 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
- 90;
486 base_angle
= r2d (atan2 (ey
- cy
, cx
- ex
));
488 tangent
= r2d (acos (the_arc
->Width
/ Distance (cx
, cy
, ex
, ey
)));
491 line_angle
= r2d (atan2 (ey
- y
, x
- ex
));
492 rel_angle
= line_angle
- arc_angle
;
493 printf ("arc %g line %g rel %g base %g\n", arc_angle
, line_angle
, rel_angle
,
495 printf ("tangent %g\n", tangent
);
497 printf ("arc was start %ld end %ld\n", the_arc
->StartAngle
,
498 the_arc
->StartAngle
+ the_arc
->Delta
);
501 if (the_arc
->Delta
> 0)
502 arc_angle
= base_angle
- tangent
;
504 arc_angle
= base_angle
+ tangent
;
506 printf ("new end angle %g\n", arc_angle
);
509 new_delta_angle
= arc_angle
- the_arc
->StartAngle
;
510 if (new_delta_angle
> 180)
511 new_delta_angle
-= 360;
512 if (new_delta_angle
< -180)
513 new_delta_angle
+= 360;
514 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
, new_delta_angle
);
517 printf ("arc now start %ld end %ld\n", the_arc
->StartAngle
,
518 the_arc
->StartAngle
+ new_delta_angle
);
521 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
;
522 x
= the_arc
->X
- the_arc
->Width
* cos (d2r (arc_angle
)) + 0.5;
523 y
= the_arc
->Y
+ the_arc
->Height
* sin (d2r (arc_angle
)) + 0.5;
525 MoveObject (LINEPOINT_TYPE
, CURRENT
, the_line
, &(the_line
->Point2
),
526 x
- the_line
->Point2
.X
, y
- the_line
->Point2
.Y
);
528 gui
->invalidate_all ();
529 IncrementUndoSerialNumber ();
534 /*****************************************************************************/
538 /*****************************************************************************/
540 static const char globalpuller_syntax
[] =
543 static const char globalpuller_help
[] =
544 "Pull all traces tight.";
546 /* %start-doc actions GlobalPuller
550 /* Ok, here's the deal. We look for the intersection of two traces.
551 The triangle formed by those traces is searched for things we need
552 to avoid. From the other two corners of the triangle, we compute
553 the angle to each obstacle, and remember the ones closest to the
554 start angles. If the two traces hit the same obstacle, we put in
555 the arc and we're done. Else, we bring the traces up to the
556 obstacles and start again.
558 Note that we assume each start point is a tangent to an arc. We
559 start with a radius of zero, but future steps use the arcs we
562 For obstacles, we list each round pin, pad, via, and line/arc
563 endpoints as points with a given radius. For each square pin, pad,
564 via, and polygon points, we list each corner with a zero radius.
565 We also list arcs from their centerpoint.
567 We don't currently do anything to move vias, or intersections of
568 three or more traces. In the future, three-way intersections will
569 be handles similarly to two-way - calculate the range of angles
570 valid from each of the three other endpoints, choose the angle
571 closest to making 120 degree angles at the center. For four-way or
572 more intersections, we break them up into multiple three-way
575 For simplicity, we only do the current layer at this time. We will
576 also edit the lines and arcs in place so that the intersection is
577 always on the second point, and the other ends are always at
578 start+delta for arcs.
580 We also defer intersections which are blocked by other
581 intersections yet to be moved; the idea is to wait until those have
582 been moved so we don't end up with arcs that no longer wrap around
583 things. At a later point, we may choose to pull arced corners in
586 You'll see lots of variables of the form "foo_sign" which keep
587 track of which way things are pointing. This is because everything
588 is relative to corners and arcs, not absolute directions.
591 static int nloops
, npulled
;
596 fprintf(stderr
, "%6d loops, %d pulled \r", nloops
, npulled
);
599 /* Extra data we need to temporarily attach to all lines and arcs. */
601 /* These point to "multi_next" if there are more than one. */
604 unsigned char in_pin
:1;
605 unsigned char at_pin
:1;
606 unsigned char is_pad
:1;
607 unsigned char pending
:1; /* set if this may be moved later */
608 int x
, y
; /* arc endpoint */
609 /* If not NULL, points to End with pending==1 we're blocked on. */
610 struct End
*waiting_for
;
613 typedef struct Extra
{
616 unsigned char found
:1;
617 unsigned char deleted
:1;
625 static Extra multi_next
;
626 static GHashTable
*lines
;
627 static GHashTable
*arcs
;
628 static int did_something
;
629 static int current_is_component
, current_is_solder
;
631 /* If set, these are the pins/pads/vias that this path ends on. */
632 /* static void *start_pin_pad, *end_pin_pad; */
635 static void trace_paths ();
637 static void mark_line_for_deletion (LineType
*);
639 #define LINE2EXTRA(l) ((Extra *)g_hash_table_lookup (lines, l))
640 #define ARC2EXTRA(a) ((Extra *)g_hash_table_lookup (arcs, a))
641 #define EXTRA2LINE(e) (e->parent.line)
642 #define EXTRA2ARC(e) (e->parent.arc)
643 #define EXTRA_IS_LINE(e) (e->type == LINE_TYPE)
644 #define EXTRA_IS_ARC(e) (e->type == ARC_TYPE)
647 unlink_end (Extra
*x
, Extra
**e
)
651 if ((*e
)->start
.next
== x
)
654 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
656 (*e
)->start
.next
= &multi_next
;
658 if ((*e
)->end
.next
== x
)
661 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
663 (*e
)->end
.next
= &multi_next
;
667 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
));
675 clear_found_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
683 g_hash_table_foreach (lines
, (GHFunc
)clear_found_cb
, NULL
);
684 g_hash_table_foreach (arcs
, (GHFunc
)clear_found_cb
, NULL
);
689 fix_arc_extra (ArcType
*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 pcb_printf("new X,Y is %#mD to %#mD\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 LineType
*line
= (LineType
*) 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 pcb_printf(" - %p line %#mD or %#mD\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 ArcType
*arc
= (ArcType
*) b
;
756 Extra
*e
= ARC2EXTRA (arc
);
757 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
762 pcb_printf(" - %p arc %#mD or %#mD\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 pcb_printf("looking for %#mD\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 (PinType
*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
= (Distance (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 LineType
*line
= (LineType
*) b
;
830 PinType
*pin
= (PinType
*) 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 pcb_printf("splitting line %#mD-%#mD because it passes through pin %#mD 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 ArcType
*arc
= (ArcType
*) b
;
868 PinType
*pin
= (PinType
*) 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 (PadType
*pad
, int x
, int y
, End
*e
)
883 pcb_printf("pad %#mD - %#mD t %#mS vs %#mD\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 (Distance (pad
->Point1
.X
, pad
->Point1
.Y
, x
, y
) <= t
913 || Distance (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 LineType
*line
= (LineType
*) b
;
936 PadType
*pad
= (PadType
*) 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 pcb_printf("splitting line %#mD-%#mD because it passes through pad %#mD-%#mD r %#mS\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 ArcType
*arc
= (ArcType
*) b
;
1007 PadType
*pad
= (PadType
*) 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
));
1028 null_multi_next_ends (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1030 if (extra
->start
.next
== &multi_next
)
1031 extra
->start
.next
= NULL
;
1033 if (extra
->end
.next
== &multi_next
)
1034 extra
->end
.next
= NULL
;
1038 new_line_extra (LineType
*line
)
1040 Extra
*extra
= g_slice_new0 (Extra
);
1041 g_hash_table_insert (lines
, line
, extra
);
1042 extra
->parent
.line
= line
;
1043 extra
->type
= LINE_TYPE
;
1048 new_arc_extra (ArcType
*arc
)
1050 Extra
*extra
= g_slice_new0 (Extra
);
1051 g_hash_table_insert (arcs
, arc
, extra
);
1052 extra
->parent
.arc
= arc
;
1053 extra
->type
= ARC_TYPE
;
1060 ARC_LOOP (CURRENT
); {
1061 Extra
*e
= new_arc_extra (arc
);
1062 fix_arc_extra (arc
, e
);
1065 LINE_LOOP (CURRENT
); {
1066 new_line_extra (line
);
1069 LINE_LOOP (CURRENT
); {
1070 Extra
*e
= LINE2EXTRA (line
);
1071 if (line
->Point1
.X
>= 0)
1073 find_pairs_1 (line
, & e
->start
.next
, line
->Point1
.X
, line
->Point1
.Y
);
1074 find_pairs_1 (line
, & e
->end
.next
, line
->Point2
.X
, line
->Point2
.Y
);
1078 ARC_LOOP (CURRENT
); {
1079 Extra
*e
= ARC2EXTRA (arc
);
1082 find_pairs_1 (arc
, & e
->start
.next
, e
->start
.x
, e
->start
.y
);
1083 find_pairs_1 (arc
, & e
->end
.next
, e
->end
.x
, e
->end
.y
);
1087 ALLPIN_LOOP (PCB
->Data
); {
1089 box
.X1
= pin
->X
- pin
->Thickness
/2;
1090 box
.Y1
= pin
->Y
- pin
->Thickness
/2;
1091 box
.X2
= pin
->X
+ pin
->Thickness
/2;
1092 box
.Y2
= pin
->Y
+ pin
->Thickness
/2;
1093 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, pin
);
1094 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, pin
);
1097 VIA_LOOP (PCB
->Data
); {
1099 box
.X1
= via
->X
- via
->Thickness
/2;
1100 box
.Y1
= via
->Y
- via
->Thickness
/2;
1101 box
.X2
= via
->X
+ via
->Thickness
/2;
1102 box
.Y2
= via
->Y
+ via
->Thickness
/2;
1103 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, via
);
1104 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, via
);
1107 ALLPAD_LOOP (PCB
->Data
); {
1109 box
.X1
= MIN(pad
->Point1
.X
, pad
->Point2
.X
) - pad
->Thickness
/2;
1110 box
.Y1
= MIN(pad
->Point1
.Y
, pad
->Point2
.Y
) - pad
->Thickness
/2;
1111 box
.X2
= MAX(pad
->Point1
.X
, pad
->Point2
.X
) + pad
->Thickness
/2;
1112 box
.Y2
= MAX(pad
->Point1
.Y
, pad
->Point2
.Y
) + pad
->Thickness
/2;
1113 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_padline_callback
, pad
);
1114 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_padarc_callback
, pad
);
1118 g_hash_table_foreach (lines
, (GHFunc
)null_multi_next_ends
, NULL
);
1119 g_hash_table_foreach (arcs
, (GHFunc
)null_multi_next_ends
, NULL
);
1122 #define PROP_NEXT(e,n,f) \
1123 if (f->next->start.next == e) { \
1133 propogate_ends_at (Extra
*e
, End
*near
, End
*far
)
1135 while (far
->in_pin
&& far
->pin
== near
->pin
)
1140 PROP_NEXT (e
, near
, far
);
1146 propogate_end_pin (Extra
*e
, End
*near
, End
*far
)
1148 void *pinpad
= near
->pin
;
1149 int ispad
= near
->is_pad
;
1152 PROP_NEXT (e
, near
, far
);
1153 if (near
->pin
== pinpad
)
1156 near
->is_pad
= ispad
;
1161 propogate_end_step1_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1163 if (extra
->start
.next
!= NULL
&&
1164 extra
->start
.next
== extra
->end
.next
)
1166 extra
->end
.next
= NULL
;
1167 mark_line_for_deletion ((LineType
*)ptr
);
1170 if (extra
->start
.at_pin
)
1171 propogate_ends_at (extra
, &extra
->start
, &extra
->end
);
1173 if (extra
->end
.at_pin
)
1174 propogate_ends_at (extra
, &extra
->end
, &extra
->start
);
1178 propogate_end_step2_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1180 if (extra
->start
.in_pin
)
1183 printf("MULTI at %d: was %p\n", __LINE__
, extra
->start
.next
);
1185 extra
->start
.next
= NULL
;
1187 if (extra
->end
.in_pin
)
1190 printf("MULTI at %d: was %p\n", __LINE__
, extra
->end
.next
);
1192 extra
->end
.next
= NULL
;
1197 propogate_end_step3_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1199 if (extra
->start
.next
)
1200 propogate_end_pin (extra
, &extra
->end
, &extra
->start
);
1201 if (extra
->end
.next
)
1202 propogate_end_pin (extra
, &extra
->start
, &extra
->end
);
1208 /* First, shut of "in pin" when we have an "at pin". We also clean
1209 up zero-length lines. */
1210 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step1_cb
, NULL
);
1212 /* Now end all paths at pins/pads. */
1213 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step2_cb
, NULL
);
1215 /* Now, propogate the pin/pad/vias along paths. */
1216 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step3_cb
, NULL
);
1219 static Extra
*last_pextra
= 0;
1222 print_extra (Extra
*e
, Extra
*prev
)
1225 if (e
->start
.next
== last_pextra
)
1227 else if (e
->end
.next
== last_pextra
)
1231 printf("%10p %10p %10p :", e
, e
->start
.next
, e
->end
.next
);
1234 printf("%10p \033[33m%10p\033[0m %10p :", e
, e
->start
.next
, e
->end
.next
);
1237 printf("%10p %10p \033[33m%10p\033[0m :", e
, e
->start
.next
, e
->end
.next
);
1242 e
->deleted
? 'd' : '-',
1243 e
->found
? 'f' : '-');
1244 printf(" s:%s%s%s%s",
1245 e
->start
.in_pin
? "I" : "-",
1246 e
->start
.at_pin
? "A" : "-",
1247 e
->start
.is_pad
? "P" : "-",
1248 e
->start
.pending
? "p" : "-");
1249 printf(" e:%s%s%s%s ",
1250 e
->end
.in_pin
? "I" : "-",
1251 e
->end
.at_pin
? "A" : "-",
1252 e
->end
.is_pad
? "P" : "-",
1253 e
->end
.pending
? "p" : "-");
1255 if (EXTRA_IS_LINE (e
))
1257 LineType
*line
= EXTRA2LINE (e
);
1258 pcb_printf(" %p L %#mD-%#mD", line
, line
->Point1
.X
, line
->Point1
.Y
, line
->Point2
.X
, line
->Point2
.Y
);
1259 printf(" %s %p %s %p\n",
1260 e
->start
.is_pad
? "pad" : "pin", e
->start
.pin
,
1261 e
->end
.is_pad
? "pad" : "pin", e
->end
.pin
);
1263 else if (EXTRA_IS_ARC (e
))
1265 ArcType
*arc
= EXTRA2ARC (e
);
1266 pcb_printf(" %p A %#mD-%#mD", arc
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
1267 pcb_printf(" at %#mD ang %ld,%ld\n", arc
->X
, arc
->Y
, arc
->StartAngle
, arc
->Delta
);
1269 else if (e
== &multi_next
)
1271 printf("-- Multi-next\n");
1275 printf("-- Unknown extra: %p\n", e
);
1281 trace_path (Extra
*e
)
1284 if ((e
->start
.next
&& e
->end
.next
)
1285 || (!e
->start
.next
&& !e
->end
.next
))
1289 printf("- path -\n");
1294 print_extra (e
, prev
);
1295 if (e
->start
.next
== prev
)
1314 LINE_LOOP (CURRENT
); {
1315 e
= LINE2EXTRA (line
);
1318 ARC_LOOP (CURRENT
); {
1319 e
= ARC2EXTRA (arc
);
1326 reverse_line (LineType
*line
)
1328 Extra
*e
= LINE2EXTRA (line
);
1335 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point1
),
1336 line
->Point2
.X
- line
->Point1
.X
,
1337 line
->Point2
.Y
- line
->Point1
.Y
);
1338 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point2
),
1340 y
- line
->Point2
.Y
);
1342 /* In theory, we should be using the above so that undo works. */
1343 line
->Point1
.X
= line
->Point2
.X
;
1344 line
->Point1
.Y
= line
->Point2
.Y
;
1348 memcpy (&etmp
, &e
->start
, sizeof (End
));
1349 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1350 memcpy (&e
->end
, &etmp
, sizeof (End
));
1354 reverse_arc (ArcType
*arc
)
1356 Extra
*e
= ARC2EXTRA (arc
);
1360 ChangeArcAngles (CURRENT
, arc
,
1361 arc
->StartAngle
+ arc
->Delta
, -arc
->Delta
);
1363 /* Likewise, see above. */
1364 arc
->StartAngle
+= arc
->Delta
;
1367 memcpy (&etmp
, &e
->start
, sizeof (End
));
1368 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1369 memcpy (&e
->end
, &etmp
, sizeof (End
));
1373 expand_box (BoxType
*b
, int x
, int y
, int t
)
1375 b
->X1
= MIN (b
->X1
, x
-t
);
1376 b
->X2
= MAX (b
->X2
, x
+t
);
1377 b
->Y1
= MIN (b
->Y1
, y
-t
);
1378 b
->Y2
= MAX (b
->Y2
, y
+t
);
1381 /* ---------------------------------------------------------------------- */
1382 /* These are the state variables for the intersection we're currently
1385 /* what we're working with */
1386 static ArcType
*start_arc
;
1387 static LineType
*start_line
;
1388 static LineType
*end_line
;
1389 static ArcType
*end_arc
;
1390 static Extra
*start_extra
, *end_extra
;
1391 static Extra
*sarc_extra
, *earc_extra
;
1392 static void *start_pinpad
, *end_pinpad
;
1393 static int thickness
;
1395 /* Pre-computed values. Note that all values are computed according
1396 to CARTESIAN coordinates, not PCB coordinates. Do an up-down board
1397 flip before wrapping your brain around the math. */
1399 /* se_sign is positive when you make a right turn going from start to end. */
1400 /* sa_sign is positive when start's arc is on the same side of start as end. */
1401 /* ea_sign is positive when end's arc is on the same side of end as start. */
1402 /* sa_sign and ea_sign may be zero if there's no arc. */
1403 static double se_sign
, sa_sign
, ea_sign
;
1405 static double best_angle
, start_angle
, end_dist
;
1406 /* arc radii are positive when they're on the same side as the things
1407 we're interested in. */
1408 static int sa_r
, ea_r
;
1409 static int sa_x
, sa_y
; /* start "arc" point */
1411 /* what we've found so far */
1412 static int fx
, fy
, fr
, fp
;
1414 static double fa
; /* relative angle */
1416 #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__)
1419 gp_point_force (int x
, int y
, int t
, End
*e
, int esa
, int eda
, int force
, const char *name
)
1423 double base_angle
, rel_angle
, point_angle
;
1426 pcb_printf("\033[34mgp_point_force %#mD %#mS via %s\033[0m\n", x
, y
, t
, name
);
1433 sr
= start_arc
->Width
;
1437 scx
= start_line
->Point1
.X
;
1438 scy
= start_line
->Point1
.Y
;
1444 /* See if the point is inside our start arc. */
1445 d
= Distance (scx
, scy
, x
, y
);
1447 pcb_printf("%f = dist #mD to %#mD\n", d
, scx
, scy
, x
, y
);
1448 pcb_printf("sr %#mS r %f d %f\n", sr
, r
, d
);
1453 printf("inside start arc, %f < %f\n", d
, sr
-r
);
1457 if (sr
== 0 && d
< r
)
1460 printf("start is inside arc, %f < %f\n", d
, r
);
1465 /* Now for the same tricky math we needed for the single puller.
1466 sr and r are the radii for the two points scx,scy and x,y. */
1468 /* angle between points (NOT pcb arc angles) */
1469 base_angle
= atan2 (y
- scy
, x
- scx
);
1471 pcb_printf("%.1f = atan2 (%#mS-%#mS = %#mS, %#mS-%#mS = %#mS)\n",
1472 r2d(base_angle
), y
, scy
, y
-scy
, x
, scx
, x
-scx
);
1475 if ((sa_sign
* sr
- r
) / d
> 1
1476 || (sa_sign
* sr
- r
) / d
< -1)
1479 /* Angle of tangent, relative to the angle between point centers. */
1480 rel_angle
= se_sign
* asin ((sa_sign
* sr
- r
) / d
);
1482 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n",
1483 r2d(rel_angle
), (int)se_sign
, (int)sa_sign
, sr
, r
, d
);
1486 /* Absolute angle of tangent. */
1487 point_angle
= base_angle
+ rel_angle
;
1489 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n",
1497 /* Check arc angles */
1498 double pa
= point_angle
;
1499 double sa
= d2r(180-esa
);
1500 double da
= d2r(-eda
);
1508 pa
-= se_sign
* M_PI
/2;
1516 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n",
1517 r2d(sa
), r2d(da
), r2d(pa
));
1523 a
= point_angle
- start_angle
;
1529 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a
));
1532 if (!force
&& a
* se_sign
< -0.007)
1536 printf("skipping, would increase angle (%f * %f)\n", a
, se_sign
);
1538 new_r
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1539 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1542 pcb_printf("point %#mD dist %#mS vs thickness %#mS\n", x
, y
, new_r
, thickness
);
1545 new_r
= (int)new_r
- 1;
1547 pcb_printf(" - new thickness %f old %#mS\n", new_r
, t
);
1550 gp_point_force (x
, y
, new_r
, e
, esa
, eda
, 1, __FUNCTION__
);
1555 printf("%f * %f < %f * %f ?\n", a
, se_sign
, best_angle
, se_sign
);
1557 if (a
* se_sign
== best_angle
* se_sign
)
1559 double old_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1561 double new_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1570 fp
= e
? e
->pending
: 0;
1574 else if (a
* se_sign
< best_angle
* se_sign
)
1581 fp
= e
? e
->pending
: 0;
1588 gp_point_2 (int x
, int y
, int t
, End
*e
, int esa
, int eda
, const char *func
)
1593 if (x
== sa_x
&& y
==sa_y
)
1597 pcb_printf("\033[34mgp_point %#mD %#mS via %s\033[0m\n", x
, y
, t
, func
);
1600 /* There are two regions we care about. For points inside our
1601 triangle, we check the crosses against start_line and end_line to
1602 make sure the point is "inside" the triangle. For points on the
1603 other side of the s-e line of the triangle, we check the dots to
1604 make sure it's between our endpoints. */
1606 /* See what side of the s-e line we're on */
1607 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1608 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1611 printf("s-e cross = %f\n", sc
);
1615 if (same_sign (sc
, se_sign
))
1617 /* Outside, check dots. */
1619 /* Ok, is it "in front of" our vectors? */
1620 sd
= dot2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1621 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1624 printf("sd = %f\n", sd
);
1629 ed
= dot2d (end_line
->Point2
.X
, end_line
->Point2
.Y
,
1630 start_line
->Point1
.X
, start_line
->Point1
.Y
,
1633 printf("ed = %f\n", ed
);
1638 sd
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1639 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1641 if (sd
> t
+ thickness
)
1646 /* Inside, check crosses. */
1648 /* First off, is it on the correct side of the start line? */
1649 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1650 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1653 printf("sc = %f\n", sc
);
1655 if (! same_sign (sc
, se_sign
))
1658 /* Ok, is it on the correct side of the end line? */
1659 ec
= cross2d (end_line
->Point1
.X
, end_line
->Point1
.Y
,
1660 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1663 printf("ec = %f\n", ec
);
1665 if (! same_sign (ec
, se_sign
))
1671 printf("in range!\n");
1674 return gp_point_force (x
, y
, t
, e
, esa
, eda
, 0, func
);
1678 gp_line_cb (const BoxType
*b
, void *cb
)
1680 const LineType
*l
= (LineType
*) b
;
1681 Extra
*e
= LINE2EXTRA(l
);
1682 if (l
== start_line
|| l
== end_line
)
1686 #ifdef CHECK_LINE_PT_NEG
1687 if (l
->Point1
.X
< 0)
1691 || ! EXTRA_IS_ARC (e
->start
.next
))
1692 gp_point (l
->Point1
.X
, l
->Point1
.Y
, l
->Thickness
/2, &e
->start
);
1694 || ! EXTRA_IS_ARC (e
->end
.next
))
1695 gp_point (l
->Point2
.X
, l
->Point2
.Y
, l
->Thickness
/2, &e
->end
);
1700 gp_arc_cb (const BoxType
*b
, void *cb
)
1702 const ArcType
*a
= (ArcType
*) b
;
1703 Extra
*e
= ARC2EXTRA(a
);
1704 if (a
== start_arc
|| a
== end_arc
)
1708 gp_point_2 (a
->X
, a
->Y
, a
->Width
+ a
->Thickness
/2, 0, a
->StartAngle
, a
->Delta
, __FUNCTION__
);
1710 && a
->X
== start_arc
->X
1711 && a
->Y
== start_arc
->Y
)
1714 && a
->X
!= end_arc
->X
1715 && a
->Y
!= end_arc
->Y
)
1718 if (e
->start
.next
|| e
->end
.next
)
1721 gp_point (e
->start
.x
, e
->start
.y
, a
->Thickness
/2, 0);
1722 gp_point (e
->end
.x
, e
->end
.y
, a
->Thickness
/2, 0);
1727 gp_text_cb (const BoxType
*b
, void *cb
)
1729 const TextType
*t
= (TextType
*) b
;
1730 /* FIXME: drop in the actual text-line endpoints later. */
1731 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y1
, 0, 0);
1732 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y2
, 0, 0);
1733 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y2
, 0, 0);
1734 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y1
, 0, 0);
1739 gp_poly_cb (const BoxType
*b
, void *cb
)
1742 const PolygonType
*p
= (PolygonType
*) b
;
1743 for (i
=0; i
<p
->PointN
; i
++)
1744 gp_point (p
->Points
[i
].X
, p
->Points
[i
].Y
, 0, 0);
1749 gp_pin_cb (const BoxType
*b
, void *cb
)
1751 const PinType
*p
= (PinType
*) b
;
1752 int t2
= (p
->Thickness
+1)/2;
1754 if (p
== start_pinpad
|| p
== end_pinpad
)
1757 /* FIXME: we lump octagonal pins in with square; safe, but not
1759 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1761 gp_point (p
->X
- t2
, p
->Y
- t2
, 0, 0);
1762 gp_point (p
->X
- t2
, p
->Y
+ t2
, 0, 0);
1763 gp_point (p
->X
+ t2
, p
->Y
+ t2
, 0, 0);
1764 gp_point (p
->X
+ t2
, p
->Y
- t2
, 0, 0);
1768 gp_point (p
->X
, p
->Y
, t2
, 0);
1774 gp_pad_cb (const BoxType
*b
, void *cb
)
1776 const PadType
*p
= (PadType
*) b
;
1777 int t2
= (p
->Thickness
+1)/2;
1779 if (p
== start_pinpad
|| p
== end_pinpad
)
1782 if (TEST_FLAG (ONSOLDERFLAG
, p
))
1784 if (!current_is_solder
)
1789 if (!current_is_component
)
1793 /* FIXME: we lump octagonal pads in with square; safe, but not
1794 optimal. I don't think we even support octagonal pads. */
1795 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1797 if (p
->Point1
.X
== p
->Point2
.X
)
1799 int y1
= MIN (p
->Point1
.Y
, p
->Point2
.Y
) - t2
;
1800 int y2
= MAX (p
->Point1
.Y
, p
->Point2
.Y
) + t2
;
1802 gp_point (p
->Point1
.X
- t2
, y1
, 0, 0);
1803 gp_point (p
->Point1
.X
- t2
, y2
, 0, 0);
1804 gp_point (p
->Point1
.X
+ t2
, y1
, 0, 0);
1805 gp_point (p
->Point1
.X
+ t2
, y2
, 0, 0);
1809 int x1
= MIN (p
->Point1
.X
, p
->Point2
.X
) - t2
;
1810 int x2
= MAX (p
->Point1
.X
, p
->Point2
.X
) + t2
;
1812 gp_point (x1
, p
->Point1
.Y
- t2
, 0, 0);
1813 gp_point (x2
, p
->Point1
.Y
- t2
, 0, 0);
1814 gp_point (x1
, p
->Point1
.Y
+ t2
, 0, 0);
1815 gp_point (x2
, p
->Point1
.Y
+ t2
, 0, 0);
1820 gp_point (p
->Point1
.X
, p
->Point1
.Y
, t2
, 0);
1821 gp_point (p
->Point2
.X
, p
->Point2
.Y
, t2
, 0);
1827 create_line (LineType
*sample
, int x1
, int y1
, int x2
, int y2
)
1831 pcb_printf("create_line from %#mD to %#mD\n", x1
, y1
, x2
, y2
);
1833 LineType
*line
= CreateNewLineOnLayer (CURRENT
, x1
, y1
, x2
, y2
,
1834 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1835 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1840 new_line_extra (line
);
1842 printf(" - line extra is %p\n", e
);
1848 create_arc (LineType
*sample
, int x
, int y
, int r
, int sa
, int da
)
1858 pcb_printf("create_arc at %#mD r %#mS sa %d delta %d\n", x
, y
, r
, sa
, da
);
1860 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
,
1861 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1864 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
*2,
1865 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1867 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1870 longjmp (abort_buf
, 1);
1872 e
= new_arc_extra (arc
);
1874 printf(" - arc extra is %p\n", e
);
1876 fix_arc_extra (arc
, e
);
1881 unlink_extras (Extra
*e
)
1884 fprintf(stderr
, "unlink %p\n", e
);
1890 print_extra(e
->start
.next
, 0);
1892 if (e
->start
.next
->start
.next
== e
)
1895 fprintf(stderr
, " - %p->start points to me\n", e
->start
.next
);
1897 e
->start
.next
->start
.next
= e
->end
.next
;
1899 else if (e
->start
.next
->end
.next
== e
)
1902 fprintf(stderr
, " - %p->end points to me\n", e
->start
.next
);
1904 e
->start
.next
->end
.next
= e
->end
.next
;
1908 fprintf(stderr
, " - %p doesn't point to me!\n", e
->start
.next
);
1915 print_extra(e
->end
.next
, 0);
1917 if (e
->end
.next
->start
.next
== e
)
1920 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1922 e
->end
.next
->start
.next
= e
->start
.next
;
1924 else if (e
->end
.next
->end
.next
== e
)
1927 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1929 e
->end
.next
->end
.next
= e
->start
.next
;
1933 fprintf(stderr
, " - %p doesn't point to me!\n", e
->end
.next
);
1937 e
->start
.next
= e
->end
.next
= 0;
1941 mark_line_for_deletion (LineType
*l
)
1943 Extra
*e
= LINE2EXTRA(l
);
1946 fprintf(stderr
, "double delete?\n");
1952 pcb_printf("Marked line %p for deletion %#mD to %#mD\n",
1953 e
, l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1956 if (l
->Point1
.X
< 0)
1958 fprintf(stderr
, "double neg move?\n");
1961 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point1
),
1964 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point2
),
1971 mark_arc_for_deletion (ArcType
*a
)
1973 Extra
*e
= ARC2EXTRA(a
);
1977 printf("Marked arc %p for deletion %ld < %ld\n",
1978 e
, a
->StartAngle
, a
->Delta
);
1982 /* Given a starting line, which may be attached to an arc, and which
1983 intersects with an ending line, which also may be attached to an
1984 arc, maybe pull them. We assume start_line is attached to the arc
1985 via Point1, and attached to the end line via Point2. Likewise, we
1986 make end_line attach to the start_line via Point1 and the arc via
1987 Point 2. We also make the arcs attach on the Delta end, not the
1988 Start end. Here's a picture:
1990 S S+D P1 P2 P1 P2 S+D S
1991 *--- start_arc ---*--- start_line ---*--- end_line ---*--- end_arc ---*
1996 maybe_pull_1 (LineType
*line
)
1999 /* Line half-thicknesses, including line space */
2008 start_extra
= LINE2EXTRA (start_line
);
2009 end_extra
= start_extra
->end
.next
;
2010 end_line
= EXTRA2LINE (end_extra
);
2011 if (end_extra
->deleted
)
2013 start_extra
->end
.pending
= 0;
2017 if (end_extra
->end
.next
== start_extra
)
2018 reverse_line (end_line
);
2020 if (start_extra
->start
.next
2021 && EXTRA_IS_ARC (start_extra
->start
.next
))
2023 sarc_extra
= start_extra
->start
.next
;
2024 start_arc
= EXTRA2ARC (sarc_extra
);
2025 if (sarc_extra
->start
.next
== start_extra
)
2026 reverse_arc (start_arc
);
2034 if (end_extra
->end
.next
2035 && EXTRA_IS_ARC (end_extra
->end
.next
))
2037 earc_extra
= end_extra
->end
.next
;
2038 end_arc
= EXTRA2ARC (earc_extra
);
2039 if (earc_extra
->start
.next
== end_extra
)
2040 reverse_arc (end_arc
);
2049 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra
, start_extra
, end_extra
, earc_extra
);
2051 print_extra(sarc_extra
,0);
2052 print_extra(start_extra
,0);
2053 print_extra(end_extra
,0);
2055 print_extra(earc_extra
,0);
2057 if (start_extra
->deleted
2058 || end_extra
->deleted
2059 || (sarc_extra
&& sarc_extra
->deleted
)
2060 || (earc_extra
&& earc_extra
->deleted
))
2062 printf(" one is deleted?\n");
2068 if (!start_extra
->end
.pending
)
2071 if (start_extra
->end
.waiting_for
2072 && start_extra
->end
.waiting_for
->pending
)
2076 if (start_line
->Thickness
!= end_line
->Thickness
)
2078 thickness
= (start_line
->Thickness
+ 1)/2 + PCB
->Bloat
;
2080 /* At this point, our expectations are all met. */
2082 box
.X1
= start_line
->Point1
.X
- thickness
;
2083 box
.X2
= start_line
->Point1
.X
+ thickness
;
2084 box
.Y1
= start_line
->Point1
.Y
- thickness
;
2085 box
.Y2
= start_line
->Point1
.Y
+ thickness
;
2086 expand_box (&box
, start_line
->Point2
.X
, start_line
->Point2
.Y
, thickness
);
2087 expand_box (&box
, end_line
->Point2
.X
, end_line
->Point2
.Y
, thickness
);
2089 expand_box (&box
, sarc_extra
->start
.x
, sarc_extra
->start
.y
, start_arc
->Thickness
/2);
2091 expand_box (&box
, earc_extra
->start
.x
, earc_extra
->start
.y
, end_arc
->Thickness
/2);
2094 se_sign
= copysign (1, cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2095 start_line
->Point2
.X
, start_line
->Point2
.Y
,
2096 end_line
->Point2
.X
, end_line
->Point2
.Y
));
2097 best_angle
= se_sign
* M_PI
;
2100 sa_sign
= copysign (1, -start_arc
->Delta
);
2107 ea_sign
= copysign (1, -end_arc
->Delta
);
2108 ea_sign
*= -se_sign
;
2113 start_angle
= atan2 (start_line
->Point2
.Y
- start_line
->Point1
.Y
,
2114 start_line
->Point2
.X
- start_line
->Point1
.X
);
2116 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n",
2117 se_sign
, sa_sign
, ea_sign
, r2d (best_angle
), r2d(start_angle
));
2122 sa_x
= start_arc
->X
;
2123 sa_y
= start_arc
->Y
;
2124 if (same_sign (start_arc
->Delta
, se_sign
))
2125 sa_r
= - start_arc
->Width
;
2127 sa_r
= start_arc
->Width
;
2131 sa_x
= start_line
->Point1
.X
;
2132 sa_y
= start_line
->Point1
.Y
;
2139 ea_r
= end_arc
->Width
;
2141 ea_r
= - end_arc
->Width
;
2147 trace_path (sarc_extra
? sarc_extra
: start_extra
);
2152 gp_point_force (end_arc
->X
, end_arc
->Y
, -ea_r
-thickness
, 0, 0, 0, 1, "end arc");
2158 gp_point_force (end_line
->Point2
.X
, end_line
->Point2
.Y
, -thickness
, 0, 0, 0, 1, "end arc");
2159 ex
= end_line
->Point2
.X
;
2160 ey
= end_line
->Point2
.Y
;
2167 pcb_fprintf(stderr
, "end line corrupt? f is %#mD\n", fx
, fy
);
2168 print_extra (end_extra
, 0);
2170 print_extra(earc_extra
, 0);
2174 end_dist
= Distance (end_line
->Point1
.X
, end_line
->Point1
.Y
,
2175 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2177 start_pinpad
= start_extra
->start
.pin
;
2178 end_pinpad
= start_extra
->end
.pin
;
2181 r_search(CURRENT
->line_tree
, &box
, NULL
, gp_line_cb
, 0);
2182 r_search(CURRENT
->arc_tree
, &box
, NULL
, gp_arc_cb
, 0);
2183 r_search(CURRENT
->text_tree
, &box
, NULL
, gp_text_cb
, 0);
2184 r_search(CURRENT
->polygon_tree
, &box
, NULL
, gp_poly_cb
, 0);
2185 r_search(PCB
->Data
->pin_tree
, &box
, NULL
, gp_pin_cb
, 0);
2186 r_search(PCB
->Data
->via_tree
, &box
, NULL
, gp_pin_cb
, 0);
2187 r_search(PCB
->Data
->pad_tree
, &box
, NULL
, gp_pad_cb
, 0);
2189 /* radians, absolute angle of (at the moment) the start_line */
2190 abs_angle
= fa
+ start_angle
;
2193 pcb_printf("\033[43;30mBest: at %#mD r %#mS, angle %.1f fp %d\033[0m\n", fx
, fy
, fr
, r2d(fa
), fp
);
2197 if (fa
> M_PI
/2 || fa
< -M_PI
/2)
2199 SET_FLAG (FOUNDFLAG
, line
);
2200 longjmp (abort_buf
, 1);
2206 start_extra
->end
.waiting_for
= fp_end
;
2209 start_extra
->end
.pending
= 0;
2211 /* Step 0: check for merged arcs (special case). */
2213 if (fx
== ex
&& fy
== ey
2214 && start_arc
&& end_arc
2215 && start_arc
->X
== end_arc
->X
&& start_arc
->Y
== end_arc
->Y
)
2220 new_delta
= end_arc
->StartAngle
- start_arc
->StartAngle
;
2221 if (start_arc
->Delta
> 0)
2223 while (new_delta
> 360)
2225 while (new_delta
< 0)
2230 while (new_delta
< -360)
2232 while (new_delta
> 0)
2236 pcb_printf("merging arcs at %#mS nd %d\n", start_arc
->X
, start_arc
->Y
, new_delta
);
2237 print_extra(sarc_extra
, 0);
2238 print_extra(earc_extra
, 0);
2240 mark_arc_for_deletion (end_arc
);
2241 mark_line_for_deletion (start_line
);
2242 mark_line_for_deletion (end_line
);
2243 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2244 fix_arc_extra (start_arc
, sarc_extra
);
2249 /* Step 1: adjust start_arc's angles and move start_line's Point1 to
2257 /* We must always round towards "larger arcs", whichever way that is. */
2258 new_delta
= 180 - r2d(abs_angle
);
2260 printf("new_delta starts at %d vs %d < %d\n",
2261 (int)new_delta
, (int)start_arc
->StartAngle
, (int)start_arc
->Delta
);
2263 if (start_arc
->Delta
< 0)
2264 new_delta
= (int)(new_delta
) + 90;
2266 new_delta
= (int)new_delta
- 90;
2267 new_delta
= new_delta
- start_arc
->StartAngle
;
2268 while (new_delta
> start_arc
->Delta
+180)
2270 while (new_delta
< start_arc
->Delta
-180)
2273 printf("new_delta adjusts to %d\n", (int)new_delta
);
2274 printf("fa = %f, new_delta ends at %.1f vs start %d\n",
2275 fa
, new_delta
, (int)start_arc
->StartAngle
);
2278 if (new_delta
* start_arc
->Delta
<= 0)
2281 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2282 fix_arc_extra (start_arc
, sarc_extra
);
2283 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2284 sarc_extra
->end
.x
- start_line
->Point1
.X
,
2285 sarc_extra
->end
.y
- start_line
->Point1
.Y
);
2289 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2290 sarc_extra
->start
.x
- start_line
->Point1
.X
,
2291 sarc_extra
->start
.y
- start_line
->Point1
.Y
);
2292 mark_arc_for_deletion (start_arc
);
2296 /* Step 1.5: If the "obstacle" is right at the end, ignore it. */
2299 double oa
= start_angle
+fa
- M_PI
/2*se_sign
;
2300 double ox
= fx
+ fr
* cos(oa
);
2301 double oy
= fy
+ fr
* sin(oa
);
2303 pcb_printf("obstacle at %#mD angle %d = arc starts at %#mD\n",
2304 fx
, fy
, (int)r2d(oa
), (int)ox
, (int)oy
);
2307 if (Distance (ox
, oy
, end_line
->Point2
.X
, end_line
->Point2
.Y
)
2310 /* Pretend it doesn't exist. */
2316 /* Step 2: If we have no obstacles, connect start and end. */
2319 pcb_printf("fx %#mS ex %#mS fy %#mS ey %#mS\n", fx
, ex
, fy
, ey
);
2321 if (fx
== ex
&& fy
== ey
)
2325 printf("\033[32mno obstacles\033[0m\n");
2330 int new_delta
, end_angle
, pcb_fa
, end_change
;
2332 end_angle
= end_arc
->StartAngle
+ end_arc
->Delta
;
2333 if (end_arc
->Delta
< 0)
2338 /* We must round so as to make the larger arc. */
2339 if (end_arc
->Delta
< 0)
2340 pcb_fa
= - r2d(start_angle
+ fa
);
2342 pcb_fa
= 1 - r2d(start_angle
+ fa
);
2343 end_change
= pcb_fa
- end_angle
;
2345 while (end_change
> 180)
2347 while (end_change
< -180)
2349 new_delta
= end_arc
->Delta
+ end_change
;
2351 if (new_delta
* end_arc
->Delta
<= 0)
2354 ChangeArcAngles (CURRENT
, end_arc
, end_arc
->StartAngle
, new_delta
);
2355 fix_arc_extra (end_arc
, earc_extra
);
2356 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2357 earc_extra
->end
.x
- start_line
->Point2
.X
,
2358 earc_extra
->end
.y
- start_line
->Point2
.Y
);
2362 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2363 earc_extra
->start
.x
- start_line
->Point2
.X
,
2364 earc_extra
->start
.y
- start_line
->Point2
.Y
);
2365 mark_arc_for_deletion (end_arc
);
2370 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2371 end_line
->Point2
.X
- start_line
->Point2
.X
,
2372 end_line
->Point2
.Y
- start_line
->Point2
.Y
);
2374 mark_line_for_deletion (end_line
);
2375 start_extra
->end
.pending
= 1;
2378 printf("\033[35mdid_something: no obstacles\033[0m\n");
2386 /* Step 3: Compute the new intersection of start_line and end_line. */
2388 ex
= start_line
->Point1
.X
+ cos(start_angle
+ fa
) * 10000.0;
2389 ey
= start_line
->Point1
.Y
+ sin(start_angle
+ fa
) * 10000.0;
2391 pcb_printf("temp point %#mS\n", ex
, ey
);
2392 pcb_printf("intersect %#mS-%#mS with %#mS-%#mS\n",
2393 start_line
->Point1
.X
, start_line
->Point1
.Y
,
2395 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2396 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2398 if (! intersection_of_lines (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2400 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2401 end_line
->Point2
.X
, end_line
->Point2
.Y
,
2404 ex
= end_line
->Point2
.X
;
2405 ey
= end_line
->Point2
.Y
;
2408 pcb_printf("new point %#mS\n", ex
, ey
);
2410 MoveObject (LINEPOINT_TYPE
, CURRENT
, end_line
, &(end_line
->Point1
),
2411 ex
- end_line
->Point1
.X
,
2412 ey
- end_line
->Point1
.Y
);
2414 /* Step 4: Split start_line at the obstacle and insert a zero-delta
2417 new_arc
= create_arc (start_line
, fx
, fy
, fr
,
2418 90-(int)(r2d(start_angle
+fa
)+0.5) + 90 + 90*se_sign
, -se_sign
);
2419 new_aextra
= ARC2EXTRA (new_arc
);
2421 if (start_arc
) sarc_extra
= ARC2EXTRA (start_arc
);
2422 if (end_arc
) earc_extra
= ARC2EXTRA (end_arc
);
2424 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2425 new_aextra
->start
.x
- start_line
->Point2
.X
,
2426 new_aextra
->start
.y
- start_line
->Point2
.Y
);
2428 new_line
= create_line (start_line
, new_aextra
->end
.x
, new_aextra
->end
.y
, ex
, ey
);
2429 start_extra
= LINE2EXTRA (start_line
);
2430 new_lextra
= LINE2EXTRA (new_line
);
2431 end_extra
= LINE2EXTRA (end_line
);
2433 new_lextra
->start
.pin
= start_extra
->start
.pin
;
2434 new_lextra
->end
.pin
= start_extra
->end
.pin
;
2435 new_lextra
->start
.pending
= 1;
2436 new_lextra
->end
.pending
= 1;
2438 start_extra
->end
.next
= new_aextra
;
2439 new_aextra
->start
.next
= start_extra
;
2440 new_aextra
->end
.next
= new_lextra
;
2441 new_lextra
->start
.next
= new_aextra
;
2442 new_lextra
->end
.next
= end_extra
;
2443 end_extra
->start
.next
= new_lextra
;
2445 /* Step 5: Recurse. */
2451 printf("\033[35mdid_something: recursing\033[0m\n");
2453 int i
= gui
->confirm_dialog("recurse?", 0);
2454 printf("confirm = %d\n", i
);
2458 printf("\n\033[33mRECURSING\033[0m\n\n");
2459 IncrementUndoSerialNumber();
2461 maybe_pull_1 (new_line
);
2464 /* Given a line with a end_next, attempt to pull both ends. */
2466 maybe_pull (LineType
*line
, Extra
*e
)
2469 printf("maybe_pull: ");
2472 if (e
->end
.next
&& EXTRA_IS_LINE (e
->end
.next
))
2474 maybe_pull_1 (line
);
2479 if (e
->start
.next
&& EXTRA_IS_LINE (e
->start
.next
))
2481 reverse_line (line
);
2482 maybe_pull_1 (line
);
2485 e
->start
.pending
= 0;
2490 validate_pair (Extra
*e
, End
*end
)
2494 if (end
->next
->start
.next
== e
)
2496 if (end
->next
->end
.next
== e
)
2498 fprintf(stderr
, "no backlink!\n");
2500 print_extra (end
->next
, 0);
2505 validate_pair_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2507 validate_pair (extra
, &extra
->start
);
2508 validate_pair (extra
, &extra
->end
);
2514 g_hash_table_foreach (lines
, (GHFunc
)validate_pair_cb
, NULL
);
2518 g_hash_table_foreach (arcs
, (GHFunc
)validate_pair_cb
, NULL
);
2522 FreeExtra (Extra
*extra
)
2524 g_slice_free (Extra
, extra
);
2528 mark_ends_pending (LineType
*line
, Extra
*extra
, void *userdata
)
2530 int *select_flags
= userdata
;
2531 if (TEST_FLAGS (*select_flags
, line
))
2533 extra
->start
.pending
= 1;
2534 extra
->end
.pending
= 1;
2540 trace_print_extra (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2542 last_pextra
= (Extra
*)1;
2543 print_extra(extra
, 0);
2547 trace_print_lines_arcs (void)
2549 printf("\nlines\n");
2550 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2553 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2560 GlobalPuller(int argc
, char **argv
, Coord x
, Coord y
)
2562 int select_flags
= 0;
2567 printf("puller! %s\n", argc
> 0 ? argv
[0] : "");
2569 if (argc
> 0 && strcasecmp (argv
[0], "selected") == 0)
2570 select_flags
= SELECTEDFLAG
;
2571 if (argc
> 0 && strcasecmp (argv
[0], "found") == 0)
2572 select_flags
= FOUNDFLAG
;
2574 printf("optimizing...\n");
2575 /* This canonicalizes all the lines, and cleans up near-misses. */
2576 /* hid_actionl ("djopt", "puller", 0); */
2578 current_is_solder
= (GetLayerGroupNumberByPointer(CURRENT
)
2579 == GetLayerGroupNumberByNumber (solder_silk_layer
));
2580 current_is_component
= (GetLayerGroupNumberByPointer(CURRENT
)
2581 == GetLayerGroupNumberByNumber (component_silk_layer
));
2583 lines
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2584 arcs
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2586 printf("pairing...\n");
2590 g_hash_table_foreach (lines
, (GHFunc
)mark_ends_pending
, &select_flags
);
2593 trace_print_lines_arcs ();
2599 trace_print_lines_arcs ();
2603 printf("pulling...\n");
2604 if (setjmp(abort_buf
) == 0)
2607 int old_did_something
= -1;
2610 while (did_something
)
2615 LINE_LOOP (CURRENT
); {
2616 Extra
*e
= LINE2EXTRA (line
);
2619 #ifdef CHECK_LINE_PT_NEG
2620 if (line
->Point1
.X
< 0)
2623 if (e
->start
.next
|| e
->end
.next
)
2624 maybe_pull (line
, e
);
2626 if (did_something
!= old_did_something
)
2628 IncrementUndoSerialNumber();
2629 old_did_something
= did_something
;
2630 if (gui
->confirm_dialog("more?", 0) == 0)
2637 /*gui->progress(0,0,0);*/
2643 printf("\nlines\n");
2644 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2646 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2648 printf("\nlines\n");
2651 LINE_LOOP (CURRENT
);
2653 if (LINE2EXTRA (line
)->deleted
)
2654 RemoveLine (CURRENT
, line
);
2660 if (ARC2EXTRA (arc
)->deleted
)
2661 RemoveArc (CURRENT
, arc
);
2665 g_hash_table_unref (lines
);
2666 g_hash_table_unref (arcs
);
2668 IncrementUndoSerialNumber();
2672 /*****************************************************************************/
2676 /*****************************************************************************/
2678 HID_Action puller_action_list
[] = {
2679 {"Puller", "Click on a line-arc intersection or line segment", Puller
,
2680 puller_help
, puller_syntax
},
2681 {"GlobalPuller", 0, GlobalPuller
,
2682 globalpuller_help
, globalpuller_syntax
}
2685 REGISTER_ACTIONS (puller_action_list
)