6 * \todo Things that need to be fixed before this is "perfect".\n
7 * Add to this list as we find things.
8 * - respect the outline layer.
9 * - don't consider points that are perpendicular to our start_arc.
10 * I.e. when we have busses going around corners, we have a *lot* of
11 * arcs and endpoints that are all in the same direction and all
12 * equally "good", but rounding the arc angles to integers causes
13 * all sorts of tiny differences that result in bumps, reversals,
15 * - Store the X,Y values in our shadow struct so we don't fill up the
16 * undo buffer with all our line reversals.
17 * - at least check the other layers in our layer group.
21 * <h1><b>Copyright.</b></h1>\n
23 * PCB, interactive printed circuit board design
25 * Copyright (C) 2006 DJ Delorie
27 * Copyright (C) 2011 PCB Contributers (See ChangeLog for details)
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 2 of the License, or
32 * (at your option) any later version.
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43 * Contact addresses for paper mail and Email:
44 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
65 #include "pcb-printf.h"
72 #ifdef HAVE_LIBDMALLOC
76 #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort()
81 /*! Sine of one degree. */
82 #define SIN1D 0.0174524064372835
84 static jmp_buf abort_buf
;
85 static int multi
, line_exact
, arc_exact
;
86 static LineType
*the_line
;
87 static ArcType
*the_arc
;
88 static double arc_dist
;
90 /* We canonicalize the arc and line such that the point to be moved is
91 always Point2 for the line, and at start+delta for the arc. */
93 static Coord x
, y
; /* the point we're moving */
94 static Coord cx
, cy
; /* centerpoint of the arc */
95 static Coord ex
, ey
; /* fixed end of the line */
97 /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */
100 within (Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord r
)
102 return Distance (x1
, y1
, x2
, y2
) <= r
/ 2;
106 arc_endpoint_is (ArcType
*a
, int angle
, Coord x
, Coord y
)
108 Coord ax
= a
->X
, ay
= a
->Y
;
112 int ai
= (int) (angle
/ 90) & 3;
131 double rad
= angle
* M_PI
/ 180;
132 ax
-= a
->Width
* cos (rad
);
133 ay
+= a
->Width
* sin (rad
);
136 pcb_printf (" - arc endpoint %#mD\n", ax
, ay
);
138 arc_dist
= Distance (ax
, ay
, x
, y
);
141 return arc_dist
< a
->Thickness
/ 2;
145 * brief Cross c->u and c->v, return the magnitude.
148 cross2d (Coord cx
, Coord cy
, Coord ux
, Coord uy
, Coord vx
, Coord vy
)
154 return (double)ux
* vy
- (double)uy
* vx
;
158 * \brief Likewise, for dot product.
161 dot2d (Coord cx
, Coord cy
, Coord ux
, Coord uy
, Coord vx
, Coord vy
)
167 return (double)ux
* vx
+ (double)uy
* vy
;
174 * angle of c->v, relative to c->u, in radians.
178 angle2d (Coord cx
, Coord cy
, Coord ux
, Coord uy
, Coord vx
, Coord vy
)
181 double magu
, magv
, sintheta
;
183 pcb_printf("angle2d %mD %mD %mD\n", cx
, cy
, ux
, uy
, vx
, vy
);
190 pcb_printf(" = %mD %mD\n", ux
, uy
, vx
, vy
);
192 cross
= (double)ux
* vy
- (double)uy
* vx
;
193 magu
= hypot(ux
, uy
);
194 magv
= hypot(vx
, vy
);
195 sintheta
= cross
/ (magu
* magv
);
197 printf(" = %f / (%f * %f) = %f\n", cross
, magu
, magv
, sintheta
);
199 return asin (sintheta
);
204 same_sign (double a
, double b
)
212 return 180.0 * r
/ M_PI
;
218 return M_PI
* d
/ 180.0;
229 det (double a
, double b
, double c
, double d
)
231 return a
* d
- b
* c
;
237 * The lines are \f$ x_1y_1-x_2y_2 \f$ and \f$ x_3y_3-x_4y_4 \f$.
239 * \return True if they intersect.
242 intersection_of_lines (Coord x1
, Coord y1
, Coord x2
, Coord y2
,
243 Coord x3
, Coord y3
, Coord x4
, Coord y4
,
244 Coord
*xr
, Coord
*yr
)
247 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
250 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
251 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
252 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
253 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
254 *xr
= (Coord
) (x
+ 0.5);
255 *yr
= (Coord
) (y
+ 0.5);
260 * \brief Same, for line segments.
262 * \return True if they intersect.
264 * For this function, \c xr and \c yr may be \c NULL if you don't need
268 intersection_of_linesegs (Coord x1
, Coord y1
, Coord x2
, Coord y2
,
269 Coord x3
, Coord y3
, Coord x4
, Coord y4
,
270 Coord
*xr
, Coord
*yr
)
273 d
= det (x1
- x2
, y1
- y2
, x3
- x4
, y3
- y4
);
276 x
= (det (det (x1
, y1
, x2
, y2
), x1
- x2
,
277 det (x3
, y3
, x4
, y4
), x3
- x4
) / d
);
278 y
= (det (det (x1
, y1
, x2
, y2
), y1
- y2
,
279 det (x3
, y3
, x4
, y4
), y3
- y4
) / d
);
280 if (MIN (x1
, x2
) > x
|| x
> MAX (x1
, x2
)
281 || MIN (y1
, y2
) > y
|| y
> MAX (y1
, y2
))
283 if (MIN (x3
, x4
) > x
|| x
> MAX (x3
, x4
)
284 || MIN (y3
, y4
) > y
|| y
> MAX (y3
, y4
))
287 *xr
= (Coord
) (x
+ 0.5);
289 *yr
= (Coord
) (y
+ 0.5);
294 * \brief Distance between a line and a point.
297 dist_lp (Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord px
, Coord py
)
299 double den
= Distance (x1
, y1
, x2
, y2
);
300 double rv
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
301 - ((double)x1
- px
) * ((double)y2
- y1
))
304 pcb_printf("dist %#mD-%#mD to %#mD is %f\n",
305 x1
, y1
, x2
, y2
, px
, py
, rv
);
311 * \brief Distance between a line segment and a point.
314 dist_lsp (Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord px
, Coord py
)
317 if (dot2d (x1
, y1
, x2
, y2
, px
, py
) < 0)
318 return Distance (x1
, y1
, px
, py
);
319 if (dot2d (x2
, y2
, x1
, y1
, px
, py
) < 0)
320 return Distance (x2
, y2
, px
, py
);
321 d
= (fabs (((double)x2
- x1
) * ((double)y1
- py
)
322 - ((double)x1
- px
) * ((double)y2
- y1
))
323 / Distance (x1
, y1
, x2
, y2
));
327 /* Single Point Puller */
330 line_callback (const BoxType
* b
, void *cl
)
332 /* LayerType *layer = (LayerType *)cl; */
333 LineType
*l
= (LineType
*) b
;
336 pcb_printf ("line %#mD .. %#mD\n",
337 l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
339 d1
= Distance (l
->Point1
.X
, l
->Point1
.Y
, x
, y
);
340 d2
= Distance (l
->Point2
.X
, l
->Point2
.Y
, x
, y
);
341 if ((d1
< 2 || d2
< 2) && !line_exact
)
346 t
= line_exact
? 2 : l
->Thickness
/ 2;
347 if (d1
< t
|| d2
< t
)
353 printf ("picked, exact %d\n", line_exact
);
360 arc_callback (const BoxType
* b
, void *cl
)
362 /* LayerType *layer = (LayerType *) cl; */
363 ArcType
*a
= (ArcType
*) b
;
366 pcb_printf ("arc a %#mD r %#mS sa %ld d %ld\n", a
->X
, a
->Y
, a
->Width
,
367 a
->StartAngle
, a
->Delta
);
369 if (!arc_endpoint_is (a
, a
->StartAngle
, x
, y
)
370 && !arc_endpoint_is (a
, a
->StartAngle
+ a
->Delta
, x
, y
))
383 printf ("picked, exact %d\n", arc_exact
);
392 printf ("picked, exact %d\n", arc_exact
);
399 find_pair (Coord Px
, Coord Py
)
404 pcb_printf ("\nPuller find_pair at %#mD\n", Px
, Py
);
410 line_exact
= arc_exact
= 0;
417 r_search (CURRENT
->line_tree
, &spot
, NULL
, line_callback
, CURRENT
);
418 r_search (CURRENT
->arc_tree
, &spot
, NULL
, arc_callback
, CURRENT
);
419 if (the_line
&& the_arc
&& !multi
)
427 static const char puller_syntax
[] = "Puller()";
429 static const char puller_help
[] = "Pull an arc-line junction tight.";
431 /* %start-doc actions Puller
433 The @code{Puller()} action is a special-purpose optimization. When
434 invoked while the crosshair is over the junction of an arc and a line,
435 it will adjust the arc's angle and the connecting line's endpoint such
436 that the line intersects the arc at a tangent. In the example below,
437 the left side is ``before'' with the black target marking where to put
440 @center @image{puller,,,Example of how puller works,png}
442 The right side is ``after'' with the black target marking where the
443 arc-line intersection was moved to.
448 Puller (int argc
, char **argv
, Coord Ux
, Coord Uy
)
450 double arc_angle
, base_angle
;
452 double line_angle
, rel_angle
;
457 if (!find_pair (Crosshair
.X
, Crosshair
.Y
))
458 if (!find_pair (Ux
, Uy
))
461 if (within (the_line
->Point1
.X
, the_line
->Point1
.Y
,
462 x
, y
, the_line
->Thickness
))
464 ex
= the_line
->Point2
.X
;
465 ey
= the_line
->Point2
.Y
;
466 the_line
->Point2
.X
= the_line
->Point1
.X
;
467 the_line
->Point2
.Y
= the_line
->Point1
.Y
;
468 the_line
->Point1
.X
= ex
;
469 the_line
->Point1
.Y
= ey
;
471 else if (!within (the_line
->Point2
.X
, the_line
->Point2
.Y
,
472 x
, y
, the_line
->Thickness
))
475 printf ("Line endpoint not at cursor\n");
479 ex
= the_line
->Point1
.X
;
480 ey
= the_line
->Point1
.Y
;
484 if (arc_endpoint_is (the_arc
, the_arc
->StartAngle
, x
, y
))
486 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
489 else if (!arc_endpoint_is (the_arc
, the_arc
->StartAngle
+ the_arc
->Delta
,
493 printf ("arc not endpoints\n");
498 if (within (cx
, cy
, ex
, ey
, the_arc
->Width
* 2))
501 printf ("line ends inside arc\n");
506 if (the_arc
->Delta
> 0)
507 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
+ 90;
509 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
- 90;
510 base_angle
= r2d (atan2 (ey
- cy
, cx
- ex
));
512 tangent
= r2d (acos (the_arc
->Width
/ Distance (cx
, cy
, ex
, ey
)));
515 line_angle
= r2d (atan2 (ey
- y
, x
- ex
));
516 rel_angle
= line_angle
- arc_angle
;
517 printf ("arc %g line %g rel %g base %g\n", arc_angle
, line_angle
, rel_angle
,
519 printf ("tangent %g\n", tangent
);
521 printf ("arc was start %ld end %ld\n", the_arc
->StartAngle
,
522 the_arc
->StartAngle
+ the_arc
->Delta
);
525 if (the_arc
->Delta
> 0)
526 arc_angle
= base_angle
- tangent
;
528 arc_angle
= base_angle
+ tangent
;
530 printf ("new end angle %g\n", arc_angle
);
533 new_delta_angle
= arc_angle
- the_arc
->StartAngle
;
534 if (new_delta_angle
> 180)
535 new_delta_angle
-= 360;
536 if (new_delta_angle
< -180)
537 new_delta_angle
+= 360;
538 ChangeArcAngles (CURRENT
, the_arc
, the_arc
->StartAngle
, new_delta_angle
);
541 printf ("arc now start %ld end %ld\n", the_arc
->StartAngle
,
542 the_arc
->StartAngle
+ new_delta_angle
);
545 arc_angle
= the_arc
->StartAngle
+ the_arc
->Delta
;
546 x
= the_arc
->X
- the_arc
->Width
* cos (d2r (arc_angle
)) + 0.5;
547 y
= the_arc
->Y
+ the_arc
->Height
* sin (d2r (arc_angle
)) + 0.5;
549 MoveObject (LINEPOINT_TYPE
, CURRENT
, the_line
, &(the_line
->Point2
),
550 x
- the_line
->Point2
.X
, y
- the_line
->Point2
.Y
);
552 gui
->invalidate_all ();
553 IncrementUndoSerialNumber ();
560 static const char globalpuller_syntax
[] =
563 static const char globalpuller_help
[] =
564 "Pull all traces tight.";
566 /* %start-doc actions GlobalPuller
570 /* Ok, here's the deal. We look for the intersection of two traces.
571 The triangle formed by those traces is searched for things we need
572 to avoid. From the other two corners of the triangle, we compute
573 the angle to each obstacle, and remember the ones closest to the
574 start angles. If the two traces hit the same obstacle, we put in
575 the arc and we're done. Else, we bring the traces up to the
576 obstacles and start again.
578 Note that we assume each start point is a tangent to an arc. We
579 start with a radius of zero, but future steps use the arcs we
582 For obstacles, we list each round pin, pad, via, and line/arc
583 endpoints as points with a given radius. For each square pin, pad,
584 via, and polygon points, we list each corner with a zero radius.
585 We also list arcs from their centerpoint.
587 We don't currently do anything to move vias, or intersections of
588 three or more traces. In the future, three-way intersections will
589 be handles similarly to two-way - calculate the range of angles
590 valid from each of the three other endpoints, choose the angle
591 closest to making 120 degree angles at the center. For four-way or
592 more intersections, we break them up into multiple three-way
595 For simplicity, we only do the current layer at this time. We will
596 also edit the lines and arcs in place so that the intersection is
597 always on the second point, and the other ends are always at
598 start+delta for arcs.
600 We also defer intersections which are blocked by other
601 intersections yet to be moved; the idea is to wait until those have
602 been moved so we don't end up with arcs that no longer wrap around
603 things. At a later point, we may choose to pull arced corners in
606 You'll see lots of variables of the form "foo_sign" which keep
607 track of which way things are pointing. This is because everything
608 is relative to corners and arcs, not absolute directions.
611 static int nloops
, npulled
;
616 Message ("%6d loops, %d pulled \r", nloops
, npulled
);
620 * \brief Extra data we need to temporarily attach to all lines and
624 /* These point to "multi_next" if there are more than one. */
627 unsigned char in_pin
:1;
628 unsigned char at_pin
:1;
629 unsigned char is_pad
:1;
630 unsigned char pending
:1; /* set if this may be moved later */
631 Coord x
, y
; /* arc endpoint */
632 /* If not NULL, points to End with pending==1 we're blocked on. */
633 struct End
*waiting_for
;
636 typedef struct Extra
{
639 unsigned char found
:1;
640 unsigned char deleted
:1;
648 static Extra multi_next
;
649 static GHashTable
*lines
;
650 static GHashTable
*arcs
;
651 static int did_something
;
652 static int current_is_top
, current_is_bottom
;
654 /* If set, these are the pins/pads/vias that this path ends on. */
655 /* static void *start_pin_pad, *end_pin_pad; */
658 static void trace_paths ();
660 static void mark_line_for_deletion (LineType
*);
662 #define LINE2EXTRA(l) ((Extra *)g_hash_table_lookup (lines, l))
663 #define ARC2EXTRA(a) ((Extra *)g_hash_table_lookup (arcs, a))
664 #define EXTRA2LINE(e) (e->parent.line)
665 #define EXTRA2ARC(e) (e->parent.arc)
666 #define EXTRA_IS_LINE(e) (e->type == LINE_TYPE)
667 #define EXTRA_IS_ARC(e) (e->type == ARC_TYPE)
670 unlink_end (Extra
*x
, Extra
**e
)
674 if ((*e
)->start
.next
== x
)
677 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
679 (*e
)->start
.next
= &multi_next
;
681 if ((*e
)->end
.next
== x
)
684 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
)->start
.next
);
686 (*e
)->end
.next
= &multi_next
;
690 printf("%d: unlink_end, was %p\n", __LINE__
, (*e
));
698 clear_found_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
706 g_hash_table_foreach (lines
, (GHFunc
)clear_found_cb
, NULL
);
707 g_hash_table_foreach (arcs
, (GHFunc
)clear_found_cb
, NULL
);
712 fix_arc_extra (ArcType
*a
, Extra
*e
)
715 printf("new arc angles %ld %ld\n", a
->StartAngle
, a
->Delta
);
717 e
->start
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
)) + 0.5);
718 e
->start
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
)) + 0.5);
719 e
->end
.x
= a
->X
- (a
->Width
* cos (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
720 e
->end
.y
= a
->Y
+ (a
->Height
* sin (d2r (a
->StartAngle
+a
->Delta
)) + 0.5);
722 pcb_printf("new X,Y is %#mD to %#mD\n", e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
731 } FindPairCallbackStruct
;
733 #define NEAR(a,b) ((a) <= (b) + 2 && (a) >= (b) - 2)
736 find_pair_line_callback (const BoxType
* b
, void *cl
)
738 LineType
*line
= (LineType
*) b
;
740 Extra
*e
= LINE2EXTRA (line
);
742 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
744 if (line
== fpcs
->me
)
746 #ifdef CHECK_LINE_PT_NEG
747 if (line
->Point1
.X
< 0)
751 pcb_printf(" - %p line %#mD or %#mD\n", e
, line
->Point1
.X
, line
->Point1
.Y
,
752 line
->Point2
.X
, line
->Point2
.Y
);
754 if ((NEAR (line
->Point1
.X
, fpcs
->x
) && NEAR (line
->Point1
.Y
, fpcs
->y
))
755 || (NEAR (line
->Point2
.X
, fpcs
->x
) && NEAR (line
->Point2
.Y
, fpcs
->y
)))
757 if (* fpcs
->extra_ptr
)
760 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
762 *fpcs
->extra_ptr
= & multi_next
;
766 *fpcs
->extra_ptr
= LINE2EXTRA (line
);
768 printf(" - next now %p\n", *fpcs
->extra_ptr
);
776 find_pair_arc_callback (const BoxType
* b
, void *cl
)
778 ArcType
*arc
= (ArcType
*) b
;
779 Extra
*e
= ARC2EXTRA (arc
);
780 FindPairCallbackStruct
*fpcs
= (FindPairCallbackStruct
*) cl
;
785 pcb_printf(" - %p arc %#mD or %#mD\n", e
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
787 if ((NEAR (e
->start
.x
, fpcs
->x
) && NEAR (e
->start
.y
, fpcs
->y
))
788 || (NEAR (e
->end
.x
, fpcs
->x
) && NEAR (e
->end
.y
, fpcs
->y
)))
790 if (* fpcs
->extra_ptr
)
793 printf("multiple, was %p\n", *fpcs
->extra_ptr
);
795 *fpcs
->extra_ptr
= & multi_next
;
798 *fpcs
->extra_ptr
= e
;
804 find_pairs_1 (void *me
, Extra
**e
, Coord x
, Coord y
)
806 FindPairCallbackStruct fpcs
;
817 pcb_printf("looking for %#mD\n", x
, y
);
823 r_search(CURRENT
->line_tree
, &b
, NULL
, find_pair_line_callback
, &fpcs
);
824 r_search(CURRENT
->arc_tree
, &b
, NULL
, find_pair_arc_callback
, &fpcs
);
828 check_point_in_pin (PinType
*pin
, Coord x
, Coord y
, End
*e
)
831 Coord t
= (PIN_SIZE(pin
)+1)/2;
832 if (TEST_FLAG (SQUAREFLAG
, pin
))
833 inside_p
= (x
>= pin
->X
- t
&& x
<= pin
->X
+ t
834 && y
>= pin
->Y
- t
&& y
<= pin
->Y
+ t
);
836 inside_p
= (Distance (pin
->X
, pin
->Y
, x
, y
) <= t
);
841 if (pin
->X
== x
&& pin
->Y
== y
)
850 find_pair_pinline_callback (const BoxType
* b
, void *cl
)
852 LineType
*line
= (LineType
*) b
;
853 PinType
*pin
= (PinType
*) cl
;
854 Extra
*e
= LINE2EXTRA (line
);
857 #ifdef CHECK_LINE_PT_NEG
858 if (line
->Point1
.X
< 0)
862 hits
= check_point_in_pin (pin
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
863 hits
+= check_point_in_pin (pin
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
868 /* See if the line passes through this pin. */
869 /*! \todo This assumes round pads, but it's good enough for square
871 if (dist_lsp (line
->Point1
.X
, line
->Point1
.Y
,
872 line
->Point2
.X
, line
->Point2
.Y
,
873 pin
->X
, pin
->Y
) <= PIN_SIZE(pin
)/2)
876 pcb_printf("splitting line %#mD-%#mD because it passes through pin %#mD r%d\n",
877 line
->Point1
.X
, line
->Point1
.Y
,
878 line
->Point2
.X
, line
->Point2
.Y
,
879 pin
->X
, pin
->Y
, PIN_SIZE(pin
)/2);
881 unlink_end (e
, &e
->start
.next
);
882 unlink_end (e
, &e
->end
.next
);
888 find_pair_pinarc_callback (const BoxType
* b
, void *cl
)
890 ArcType
*arc
= (ArcType
*) b
;
891 PinType
*pin
= (PinType
*) cl
;
892 Extra
*e
= ARC2EXTRA (arc
);
895 hits
= check_point_in_pin (pin
, e
->start
.x
, e
->start
.y
, &(e
->start
));
896 hits
+= check_point_in_pin (pin
, e
->end
.x
, e
->end
.y
, &(e
->end
));
901 check_point_in_pad (PadType
*pad
, Coord x
, Coord y
, End
*e
)
906 pcb_printf("pad %#mD - %#mD t %#mS vs %#mD\n", pad
->Point1
.X
, pad
->Point1
.Y
,
907 pad
->Point2
.X
, pad
->Point2
.Y
, pad
->Thickness
, x
, y
);
908 t
= (pad
->Thickness
+1)/2;
909 if (TEST_FLAG (SQUAREFLAG
, pad
))
911 inside_p
= (x
>= MIN (pad
->Point1
.X
- t
, pad
->Point2
.X
- t
)
912 && x
<= MAX (pad
->Point1
.X
+ t
, pad
->Point2
.X
+ t
)
913 && y
>= MIN (pad
->Point1
.Y
- t
, pad
->Point2
.Y
- t
)
914 && y
<= MAX (pad
->Point1
.Y
+ t
, pad
->Point2
.Y
+ t
));
915 printf(" - inside_p = %d\n", inside_p
);
919 if (pad
->Point1
.X
== pad
->Point2
.X
)
921 inside_p
= (x
>= pad
->Point1
.X
- t
922 && x
<= pad
->Point1
.X
+ t
923 && y
>= MIN (pad
->Point1
.Y
, pad
->Point2
.Y
)
924 && y
<= MAX (pad
->Point1
.Y
, pad
->Point2
.Y
));
928 inside_p
= (x
>= MIN (pad
->Point1
.X
, pad
->Point2
.X
)
929 && x
<= MAX (pad
->Point1
.X
, pad
->Point2
.X
)
930 && y
>= pad
->Point1
.Y
- t
931 && y
<= pad
->Point1
.Y
+ t
);
935 if (Distance (pad
->Point1
.X
, pad
->Point1
.Y
, x
, y
) <= t
936 || Distance (pad
->Point2
.X
, pad
->Point2
.Y
, x
, y
) <= t
)
944 if (pad
->Point1
.X
== x
&& pad
->Point1
.Y
== y
)
946 if (pad
->Point2
.X
== x
&& pad
->Point2
.Y
== y
)
956 find_pair_padline_callback (const BoxType
* b
, void *cl
)
958 LineType
*line
= (LineType
*) b
;
959 PadType
*pad
= (PadType
*) cl
;
960 Extra
*e
= LINE2EXTRA (line
);
966 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
968 if (!current_is_bottom
)
977 #ifdef CHECK_LINE_PT_NEG
978 if (line
->Point1
.X
< 0)
982 hits
= check_point_in_pad (pad
, line
->Point1
.X
, line
->Point1
.Y
, &(e
->start
));
983 hits
+= check_point_in_pad (pad
, line
->Point2
.X
, line
->Point2
.Y
, &(e
->end
));
988 /* Ok, something strange. The line intersects our space, but
989 doesn't end in our space. See if it just passes through us, and
992 t
= (pad
->Thickness
+ 1)/2;
993 /*! \todo This is for round pads. Good enough for now, but add
994 * square pad support later. */
995 intersect
= intersection_of_linesegs (pad
->Point1
.X
, pad
->Point1
.Y
,
996 pad
->Point2
.X
, pad
->Point2
.Y
,
997 line
->Point1
.X
, line
->Point1
.Y
,
998 line
->Point2
.X
, line
->Point2
.Y
,
1000 p1_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
1001 line
->Point2
.X
, line
->Point2
.Y
,
1002 pad
->Point1
.X
, pad
->Point1
.Y
);
1003 p2_d
= dist_lsp(line
->Point1
.X
, line
->Point1
.Y
,
1004 line
->Point2
.X
, line
->Point2
.Y
,
1005 pad
->Point2
.X
, pad
->Point2
.Y
);
1007 if (intersect
|| p1_d
< t
|| p2_d
< t
)
1010 /*! \todo We should split the line. */
1012 pcb_printf("splitting line %#mD-%#mD because it passes through pad %#mD-%#mD r %#mS\n",
1013 line
->Point1
.X
, line
->Point1
.Y
,
1014 line
->Point2
.X
, line
->Point2
.Y
,
1015 pad
->Point1
.X
, pad
->Point1
.Y
,
1016 pad
->Point2
.X
, pad
->Point2
.Y
,
1019 unlink_end (e
, &e
->start
.next
);
1020 unlink_end (e
, &e
->end
.next
);
1027 find_pair_padarc_callback (const BoxType
* b
, void *cl
)
1029 ArcType
*arc
= (ArcType
*) b
;
1030 PadType
*pad
= (PadType
*) cl
;
1031 Extra
*e
= ARC2EXTRA (arc
);
1034 if (TEST_FLAG (ONSOLDERFLAG
, pad
))
1036 if (!current_is_bottom
)
1041 if (!current_is_top
)
1045 hits
= check_point_in_pad (pad
, e
->start
.x
, e
->start
.y
, &(e
->start
));
1046 hits
+= check_point_in_pad (pad
, e
->end
.x
, e
->end
.y
, &(e
->end
));
1051 null_multi_next_ends (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1053 if (extra
->start
.next
== &multi_next
)
1054 extra
->start
.next
= NULL
;
1056 if (extra
->end
.next
== &multi_next
)
1057 extra
->end
.next
= NULL
;
1061 new_line_extra (LineType
*line
)
1063 Extra
*extra
= g_slice_new0 (Extra
);
1064 g_hash_table_insert (lines
, line
, extra
);
1065 extra
->parent
.line
= line
;
1066 extra
->type
= LINE_TYPE
;
1071 new_arc_extra (ArcType
*arc
)
1073 Extra
*extra
= g_slice_new0 (Extra
);
1074 g_hash_table_insert (arcs
, arc
, extra
);
1075 extra
->parent
.arc
= arc
;
1076 extra
->type
= ARC_TYPE
;
1083 ARC_LOOP (CURRENT
); {
1084 Extra
*e
= new_arc_extra (arc
);
1085 fix_arc_extra (arc
, e
);
1088 LINE_LOOP (CURRENT
); {
1089 new_line_extra (line
);
1092 LINE_LOOP (CURRENT
); {
1093 Extra
*e
= LINE2EXTRA (line
);
1094 if (line
->Point1
.X
>= 0)
1096 find_pairs_1 (line
, & e
->start
.next
, line
->Point1
.X
, line
->Point1
.Y
);
1097 find_pairs_1 (line
, & e
->end
.next
, line
->Point2
.X
, line
->Point2
.Y
);
1101 ARC_LOOP (CURRENT
); {
1102 Extra
*e
= ARC2EXTRA (arc
);
1105 find_pairs_1 (arc
, & e
->start
.next
, e
->start
.x
, e
->start
.y
);
1106 find_pairs_1 (arc
, & e
->end
.next
, e
->end
.x
, e
->end
.y
);
1110 ALLPIN_LOOP (PCB
->Data
); {
1112 box
.X1
= pin
->X
- PIN_SIZE(pin
)/2;
1113 box
.Y1
= pin
->Y
- PIN_SIZE(pin
)/2;
1114 box
.X2
= pin
->X
+ PIN_SIZE(pin
)/2;
1115 box
.Y2
= pin
->Y
+ PIN_SIZE(pin
)/2;
1116 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, pin
);
1117 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, pin
);
1120 VIA_LOOP (PCB
->Data
); {
1122 box
.X1
= via
->X
- PIN_SIZE(via
)/2;
1123 box
.Y1
= via
->Y
- PIN_SIZE(via
)/2;
1124 box
.X2
= via
->X
+ PIN_SIZE(via
)/2;
1125 box
.Y2
= via
->Y
+ PIN_SIZE(via
)/2;
1126 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_pinline_callback
, via
);
1127 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_pinarc_callback
, via
);
1130 ALLPAD_LOOP (PCB
->Data
); {
1132 box
.X1
= MIN(pad
->Point1
.X
, pad
->Point2
.X
) - pad
->Thickness
/2;
1133 box
.Y1
= MIN(pad
->Point1
.Y
, pad
->Point2
.Y
) - pad
->Thickness
/2;
1134 box
.X2
= MAX(pad
->Point1
.X
, pad
->Point2
.X
) + pad
->Thickness
/2;
1135 box
.Y2
= MAX(pad
->Point1
.Y
, pad
->Point2
.Y
) + pad
->Thickness
/2;
1136 r_search (CURRENT
->line_tree
, &box
, NULL
, find_pair_padline_callback
, pad
);
1137 r_search (CURRENT
->arc_tree
, &box
, NULL
, find_pair_padarc_callback
, pad
);
1141 g_hash_table_foreach (lines
, (GHFunc
)null_multi_next_ends
, NULL
);
1142 g_hash_table_foreach (arcs
, (GHFunc
)null_multi_next_ends
, NULL
);
1145 #define PROP_NEXT(e,n,f) \
1146 if (f->next->start.next == e) { \
1156 propogate_ends_at (Extra
*e
, End
*near
, End
*far
)
1158 while (far
->in_pin
&& far
->pin
== near
->pin
)
1163 PROP_NEXT (e
, near
, far
);
1169 propogate_end_pin (Extra
*e
, End
*near
, End
*far
)
1171 void *pinpad
= near
->pin
;
1172 int ispad
= near
->is_pad
;
1175 PROP_NEXT (e
, near
, far
);
1176 if (near
->pin
== pinpad
)
1179 near
->is_pad
= ispad
;
1184 propogate_end_step1_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1186 if (extra
->start
.next
!= NULL
&&
1187 extra
->start
.next
== extra
->end
.next
)
1189 extra
->end
.next
= NULL
;
1190 mark_line_for_deletion ((LineType
*)ptr
);
1193 if (extra
->start
.at_pin
)
1194 propogate_ends_at (extra
, &extra
->start
, &extra
->end
);
1196 if (extra
->end
.at_pin
)
1197 propogate_ends_at (extra
, &extra
->end
, &extra
->start
);
1201 propogate_end_step2_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1203 if (extra
->start
.in_pin
)
1206 printf("MULTI at %d: was %p\n", __LINE__
, extra
->start
.next
);
1208 extra
->start
.next
= NULL
;
1210 if (extra
->end
.in_pin
)
1213 printf("MULTI at %d: was %p\n", __LINE__
, extra
->end
.next
);
1215 extra
->end
.next
= NULL
;
1220 propogate_end_step3_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
1222 if (extra
->start
.next
)
1223 propogate_end_pin (extra
, &extra
->end
, &extra
->start
);
1224 if (extra
->end
.next
)
1225 propogate_end_pin (extra
, &extra
->start
, &extra
->end
);
1231 /* First, shut of "in pin" when we have an "at pin". We also clean
1232 up zero-length lines. */
1233 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step1_cb
, NULL
);
1235 /* Now end all paths at pins/pads. */
1236 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step2_cb
, NULL
);
1238 /* Now, propogate the pin/pad/vias along paths. */
1239 g_hash_table_foreach (lines
, (GHFunc
)propogate_end_step3_cb
, NULL
);
1242 static Extra
*last_pextra
= 0;
1245 print_extra (Extra
*e
, Extra
*prev
)
1248 if (e
->start
.next
== last_pextra
)
1250 else if (e
->end
.next
== last_pextra
)
1254 printf("%10p %10p %10p :", e
, e
->start
.next
, e
->end
.next
);
1257 printf("%10p \033[33m%10p\033[0m %10p :", e
, e
->start
.next
, e
->end
.next
);
1260 printf("%10p %10p \033[33m%10p\033[0m :", e
, e
->start
.next
, e
->end
.next
);
1265 e
->deleted
? 'd' : '-',
1266 e
->found
? 'f' : '-');
1267 printf(" s:%s%s%s%s",
1268 e
->start
.in_pin
? "I" : "-",
1269 e
->start
.at_pin
? "A" : "-",
1270 e
->start
.is_pad
? "P" : "-",
1271 e
->start
.pending
? "p" : "-");
1272 printf(" e:%s%s%s%s ",
1273 e
->end
.in_pin
? "I" : "-",
1274 e
->end
.at_pin
? "A" : "-",
1275 e
->end
.is_pad
? "P" : "-",
1276 e
->end
.pending
? "p" : "-");
1278 if (EXTRA_IS_LINE (e
))
1280 LineType
*line
= EXTRA2LINE (e
);
1281 pcb_printf(" %p L %#mD-%#mD", line
, line
->Point1
.X
, line
->Point1
.Y
, line
->Point2
.X
, line
->Point2
.Y
);
1282 printf(" %s %p %s %p\n",
1283 e
->start
.is_pad
? "pad" : "pin", e
->start
.pin
,
1284 e
->end
.is_pad
? "pad" : "pin", e
->end
.pin
);
1286 else if (EXTRA_IS_ARC (e
))
1288 ArcType
*arc
= EXTRA2ARC (e
);
1289 pcb_printf(" %p A %#mD-%#mD", arc
, e
->start
.x
, e
->start
.y
, e
->end
.x
, e
->end
.y
);
1290 pcb_printf(" at %#mD ang %ld,%ld\n", arc
->X
, arc
->Y
, arc
->StartAngle
, arc
->Delta
);
1292 else if (e
== &multi_next
)
1294 printf("-- Multi-next\n");
1298 printf("-- Unknown extra: %p\n", e
);
1304 trace_path (Extra
*e
)
1307 if ((e
->start
.next
&& e
->end
.next
)
1308 || (!e
->start
.next
&& !e
->end
.next
))
1312 printf("- path -\n");
1317 print_extra (e
, prev
);
1318 if (e
->start
.next
== prev
)
1337 LINE_LOOP (CURRENT
); {
1338 e
= LINE2EXTRA (line
);
1341 ARC_LOOP (CURRENT
); {
1342 e
= ARC2EXTRA (arc
);
1349 reverse_line (LineType
*line
)
1351 Extra
*e
= LINE2EXTRA (line
);
1358 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point1
),
1359 line
->Point2
.X
- line
->Point1
.X
,
1360 line
->Point2
.Y
- line
->Point1
.Y
);
1361 MoveObject (LINEPOINT_TYPE
, CURRENT
, line
, &(line
->Point2
),
1363 y
- line
->Point2
.Y
);
1365 /* In theory, we should be using the above so that undo works. */
1366 line
->Point1
.X
= line
->Point2
.X
;
1367 line
->Point1
.Y
= line
->Point2
.Y
;
1371 memcpy (&etmp
, &e
->start
, sizeof (End
));
1372 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1373 memcpy (&e
->end
, &etmp
, sizeof (End
));
1377 reverse_arc (ArcType
*arc
)
1379 Extra
*e
= ARC2EXTRA (arc
);
1383 ChangeArcAngles (CURRENT
, arc
,
1384 arc
->StartAngle
+ arc
->Delta
, -arc
->Delta
);
1386 /* Likewise, see above. */
1387 arc
->StartAngle
+= arc
->Delta
;
1390 memcpy (&etmp
, &e
->start
, sizeof (End
));
1391 memcpy (&e
->start
, &e
->end
, sizeof (End
));
1392 memcpy (&e
->end
, &etmp
, sizeof (End
));
1396 expand_box (BoxType
*b
, Coord x
, Coord y
, Coord t
)
1398 b
->X1
= MIN (b
->X1
, x
-t
);
1399 b
->X2
= MAX (b
->X2
, x
+t
);
1400 b
->Y1
= MIN (b
->Y1
, y
-t
);
1401 b
->Y2
= MAX (b
->Y2
, y
+t
);
1404 /* ---------------------------------------------------------------------- */
1405 /* These are the state variables for the intersection we're currently
1408 /* what we're working with */
1409 static ArcType
*start_arc
;
1410 static LineType
*start_line
;
1411 static LineType
*end_line
;
1412 static ArcType
*end_arc
;
1413 static Extra
*start_extra
, *end_extra
;
1414 static Extra
*sarc_extra
, *earc_extra
;
1415 static void *start_pinpad
, *end_pinpad
;
1416 static Coord thickness
;
1418 /* Pre-computed values. Note that all values are computed according
1419 to CARTESIAN coordinates, not PCB coordinates. Do an up-down board
1420 flip before wrapping your brain around the math. */
1422 /* se_sign is positive when you make a right turn going from start to end. */
1423 /* sa_sign is positive when start's arc is on the same side of start as end. */
1424 /* ea_sign is positive when end's arc is on the same side of end as start. */
1425 /* sa_sign and ea_sign may be zero if there's no arc. */
1426 static double se_sign
, sa_sign
, ea_sign
;
1428 static double best_angle
, start_angle
, end_dist
;
1429 /* arc radii are positive when they're on the same side as the things
1430 we're interested in. */
1431 static Coord sa_r
, ea_r
;
1432 static Coord sa_x
, sa_y
; /* start "arc" point */
1434 /* what we've found so far */
1435 static Coord fx
, fy
, fr
;
1438 static double fa
; /* relative angle */
1440 #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__)
1443 gp_point_force (Coord x
, Coord y
, Coord t
, End
*e
, int esa
, int eda
, int force
, const char *name
)
1447 double base_angle
, rel_angle
, point_angle
;
1450 pcb_printf("\033[34mgp_point_force %#mD %#mS via %s\033[0m\n", x
, y
, t
, name
);
1457 sr
= start_arc
->Width
;
1461 scx
= start_line
->Point1
.X
;
1462 scy
= start_line
->Point1
.Y
;
1468 /* See if the point is inside our start arc. */
1469 d
= Distance (scx
, scy
, x
, y
);
1471 pcb_printf("%f = dist #mD to %#mD\n", d
, scx
, scy
, x
, y
);
1472 pcb_printf("sr %#mS r %f d %f\n", sr
, r
, d
);
1477 printf("inside start arc, %f < %f\n", d
, sr
-r
);
1481 if (sr
== 0 && d
< r
)
1484 printf("start is inside arc, %f < %f\n", d
, r
);
1489 /* Now for the same tricky math we needed for the single puller.
1490 sr and r are the radii for the two points scx,scy and x,y. */
1492 /* angle between points (NOT pcb arc angles) */
1493 base_angle
= atan2 (y
- scy
, x
- scx
);
1495 pcb_printf("%.1f = atan2 (%#mS-%#mS = %#mS, %#mS-%#mS = %#mS)\n",
1496 r2d(base_angle
), y
, scy
, y
-scy
, x
, scx
, x
-scx
);
1499 if ((sa_sign
* sr
- r
) / d
> 1
1500 || (sa_sign
* sr
- r
) / d
< -1)
1503 /* Angle of tangent, relative to the angle between point centers. */
1504 rel_angle
= se_sign
* asin ((sa_sign
* sr
- r
) / d
);
1506 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n",
1507 r2d(rel_angle
), (int)se_sign
, (int)sa_sign
, sr
, r
, d
);
1510 /* Absolute angle of tangent. */
1511 point_angle
= base_angle
+ rel_angle
;
1513 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n",
1521 /* Check arc angles */
1522 double pa
= point_angle
;
1523 double sa
= d2r(180-esa
);
1524 double da
= d2r(-eda
);
1532 pa
-= se_sign
* M_PI
/2;
1540 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n",
1541 r2d(sa
), r2d(da
), r2d(pa
));
1547 a
= point_angle
- start_angle
;
1553 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a
));
1556 if (!force
&& a
* se_sign
< -0.007)
1560 printf("skipping, would increase angle (%f * %f)\n", a
, se_sign
);
1562 new_r
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1563 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1566 pcb_printf("point %#mD dist %#mS vs thickness %#mS\n", x
, y
, new_r
, thickness
);
1569 new_r
= (int)new_r
- 1;
1571 pcb_printf(" - new thickness %f old %#mS\n", new_r
, t
);
1574 gp_point_force (x
, y
, new_r
, e
, esa
, eda
, 1, __FUNCTION__
);
1579 printf("%f * %f < %f * %f ?\n", a
, se_sign
, best_angle
, se_sign
);
1581 if (a
* se_sign
== best_angle
* se_sign
)
1583 double old_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1585 double new_d
= Distance (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1594 fp
= e
? e
->pending
: 0;
1598 else if (a
* se_sign
< best_angle
* se_sign
)
1605 fp
= e
? e
->pending
: 0;
1612 gp_point_2 (Coord x
, Coord y
, Coord t
, End
*e
, int esa
, int eda
, const char *func
)
1617 if (x
== sa_x
&& y
==sa_y
)
1621 pcb_printf("\033[34mgp_point %#mD %#mS via %s\033[0m\n", x
, y
, t
, func
);
1624 /* There are two regions we care about. For points inside our
1625 triangle, we check the crosses against start_line and end_line to
1626 make sure the point is "inside" the triangle. For points on the
1627 other side of the s-e line of the triangle, we check the dots to
1628 make sure it's between our endpoints. */
1630 /* See what side of the s-e line we're on */
1631 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1632 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1635 printf("s-e cross = %f\n", sc
);
1639 if (same_sign (sc
, se_sign
))
1641 /* Outside, check dots. */
1643 /* Ok, is it "in front of" our vectors? */
1644 sd
= dot2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1645 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1648 printf("sd = %f\n", sd
);
1653 ed
= dot2d (end_line
->Point2
.X
, end_line
->Point2
.Y
,
1654 start_line
->Point1
.X
, start_line
->Point1
.Y
,
1657 printf("ed = %f\n", ed
);
1662 sd
= dist_lp (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1663 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1665 if (sd
> t
+ thickness
)
1670 /* Inside, check crosses. */
1672 /* First off, is it on the correct side of the start line? */
1673 sc
= cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
1674 start_line
->Point2
.X
, start_line
->Point2
.Y
,
1677 printf("sc = %f\n", sc
);
1679 if (! same_sign (sc
, se_sign
))
1682 /* Ok, is it on the correct side of the end line? */
1683 ec
= cross2d (end_line
->Point1
.X
, end_line
->Point1
.Y
,
1684 end_line
->Point2
.X
, end_line
->Point2
.Y
,
1687 printf("ec = %f\n", ec
);
1689 if (! same_sign (ec
, se_sign
))
1695 printf("in range!\n");
1698 return gp_point_force (x
, y
, t
, e
, esa
, eda
, 0, func
);
1702 gp_line_cb (const BoxType
*b
, void *cb
)
1704 const LineType
*l
= (LineType
*) b
;
1705 Extra
*e
= LINE2EXTRA(l
);
1706 if (l
== start_line
|| l
== end_line
)
1710 #ifdef CHECK_LINE_PT_NEG
1711 if (l
->Point1
.X
< 0)
1715 || ! EXTRA_IS_ARC (e
->start
.next
))
1716 gp_point (l
->Point1
.X
, l
->Point1
.Y
, l
->Thickness
/2, &e
->start
);
1718 || ! EXTRA_IS_ARC (e
->end
.next
))
1719 gp_point (l
->Point2
.X
, l
->Point2
.Y
, l
->Thickness
/2, &e
->end
);
1724 gp_arc_cb (const BoxType
*b
, void *cb
)
1726 const ArcType
*a
= (ArcType
*) b
;
1727 Extra
*e
= ARC2EXTRA(a
);
1728 if (a
== start_arc
|| a
== end_arc
)
1732 gp_point_2 (a
->X
, a
->Y
, a
->Width
+ a
->Thickness
/2, 0, a
->StartAngle
, a
->Delta
, __FUNCTION__
);
1734 && a
->X
== start_arc
->X
1735 && a
->Y
== start_arc
->Y
)
1738 && a
->X
!= end_arc
->X
1739 && a
->Y
!= end_arc
->Y
)
1742 if (e
->start
.next
|| e
->end
.next
)
1745 gp_point (e
->start
.x
, e
->start
.y
, a
->Thickness
/2, 0);
1746 gp_point (e
->end
.x
, e
->end
.y
, a
->Thickness
/2, 0);
1751 gp_text_cb (const BoxType
*b
, void *cb
)
1753 const TextType
*t
= (TextType
*) b
;
1754 /* FIXME: drop in the actual text-line endpoints later. */
1755 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y1
, 0, 0);
1756 gp_point (t
->BoundingBox
.X1
, t
->BoundingBox
.Y2
, 0, 0);
1757 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y2
, 0, 0);
1758 gp_point (t
->BoundingBox
.X2
, t
->BoundingBox
.Y1
, 0, 0);
1763 gp_poly_cb (const BoxType
*b
, void *cb
)
1766 const PolygonType
*p
= (PolygonType
*) b
;
1767 for (i
=0; i
<p
->PointN
; i
++)
1768 gp_point (p
->Points
[i
].X
, p
->Points
[i
].Y
, 0, 0);
1773 gp_pin_cb (const BoxType
*b
, void *cb
)
1775 const PinType
*p
= (PinType
*) b
;
1776 Coord t2
= (PIN_SIZE(p
)+1)/2;
1778 if (p
== start_pinpad
|| p
== end_pinpad
)
1781 /*! \todo We lump octagonal pins in with square; safe, but not
1783 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1785 gp_point (p
->X
- t2
, p
->Y
- t2
, 0, 0);
1786 gp_point (p
->X
- t2
, p
->Y
+ t2
, 0, 0);
1787 gp_point (p
->X
+ t2
, p
->Y
+ t2
, 0, 0);
1788 gp_point (p
->X
+ t2
, p
->Y
- t2
, 0, 0);
1792 gp_point (p
->X
, p
->Y
, t2
, 0);
1798 gp_pad_cb (const BoxType
*b
, void *cb
)
1800 const PadType
*p
= (PadType
*) b
;
1801 Coord t2
= (p
->Thickness
+1)/2;
1803 if (p
== start_pinpad
|| p
== end_pinpad
)
1806 if (TEST_FLAG (ONSOLDERFLAG
, p
))
1808 if (!current_is_bottom
)
1813 if (!current_is_top
)
1817 /*! \todo We lump octagonal pads in with square; safe, but not
1818 optimal. I don't think we even support octagonal pads. */
1819 if (TEST_FLAG (SQUAREFLAG
, p
) || TEST_FLAG (OCTAGONFLAG
, p
))
1821 if (p
->Point1
.X
== p
->Point2
.X
)
1823 Coord y1
= MIN (p
->Point1
.Y
, p
->Point2
.Y
) - t2
;
1824 Coord y2
= MAX (p
->Point1
.Y
, p
->Point2
.Y
) + t2
;
1826 gp_point (p
->Point1
.X
- t2
, y1
, 0, 0);
1827 gp_point (p
->Point1
.X
- t2
, y2
, 0, 0);
1828 gp_point (p
->Point1
.X
+ t2
, y1
, 0, 0);
1829 gp_point (p
->Point1
.X
+ t2
, y2
, 0, 0);
1833 Coord x1
= MIN (p
->Point1
.X
, p
->Point2
.X
) - t2
;
1834 Coord x2
= MAX (p
->Point1
.X
, p
->Point2
.X
) + t2
;
1836 gp_point (x1
, p
->Point1
.Y
- t2
, 0, 0);
1837 gp_point (x2
, p
->Point1
.Y
- t2
, 0, 0);
1838 gp_point (x1
, p
->Point1
.Y
+ t2
, 0, 0);
1839 gp_point (x2
, p
->Point1
.Y
+ t2
, 0, 0);
1844 gp_point (p
->Point1
.X
, p
->Point1
.Y
, t2
, 0);
1845 gp_point (p
->Point2
.X
, p
->Point2
.Y
, t2
, 0);
1851 create_line (LineType
*sample
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1855 pcb_printf("create_line from %#mD to %#mD\n", x1
, y1
, x2
, y2
);
1857 LineType
*line
= CreateNewLineOnLayer (CURRENT
, x1
, y1
, x2
, y2
,
1858 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1859 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1864 new_line_extra (line
);
1866 printf(" - line extra is %p\n", e
);
1872 create_arc (LineType
*sample
, Coord x
, Coord y
, Coord r
, Coord sa
, Coord da
)
1882 pcb_printf("create_arc at %#mD r %#mS sa %d delta %d\n", x
, y
, r
, sa
, da
);
1884 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
,
1885 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1888 arc
= CreateNewArcOnLayer (CURRENT
, x
, y
, r
, r
, sa
, da
*2,
1889 sample
->Thickness
, sample
->Clearance
, sample
->Flags
);
1891 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1894 longjmp (abort_buf
, 1);
1896 e
= new_arc_extra (arc
);
1898 printf(" - arc extra is %p\n", e
);
1900 fix_arc_extra (arc
, e
);
1905 unlink_extras (Extra
*e
)
1908 fprintf(stderr
, "unlink %p\n", e
);
1914 print_extra(e
->start
.next
, 0);
1916 if (e
->start
.next
->start
.next
== e
)
1919 fprintf(stderr
, " - %p->start points to me\n", e
->start
.next
);
1921 e
->start
.next
->start
.next
= e
->end
.next
;
1923 else if (e
->start
.next
->end
.next
== e
)
1926 fprintf(stderr
, " - %p->end points to me\n", e
->start
.next
);
1928 e
->start
.next
->end
.next
= e
->end
.next
;
1932 fprintf(stderr
, " - %p doesn't point to me!\n", e
->start
.next
);
1939 print_extra(e
->end
.next
, 0);
1941 if (e
->end
.next
->start
.next
== e
)
1944 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1946 e
->end
.next
->start
.next
= e
->start
.next
;
1948 else if (e
->end
.next
->end
.next
== e
)
1951 fprintf(stderr
, " - %p->end points to me\n", e
->end
.next
);
1953 e
->end
.next
->end
.next
= e
->start
.next
;
1957 fprintf(stderr
, " - %p doesn't point to me!\n", e
->end
.next
);
1961 e
->start
.next
= e
->end
.next
= 0;
1965 mark_line_for_deletion (LineType
*l
)
1967 Extra
*e
= LINE2EXTRA(l
);
1970 fprintf(stderr
, "double delete?\n");
1976 pcb_printf("Marked line %p for deletion %#mD to %#mD\n",
1977 e
, l
->Point1
.X
, l
->Point1
.Y
, l
->Point2
.X
, l
->Point2
.Y
);
1980 if (l
->Point1
.X
< 0)
1982 fprintf(stderr
, "double neg move?\n");
1985 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point1
),
1988 MoveObject (LINEPOINT_TYPE
, CURRENT
, l
, &(l
->Point2
),
1995 mark_arc_for_deletion (ArcType
*a
)
1997 Extra
*e
= ARC2EXTRA(a
);
2001 printf("Marked arc %p for deletion %ld < %ld\n",
2002 e
, a
->StartAngle
, a
->Delta
);
2009 * Given a starting line, which may be attached to an arc, and which
2010 * intersects with an ending line, which also may be attached to an
2011 * arc, maybe pull them.\n
2012 * We assume start_line is attached to the arc via Point1, and attached
2013 * to the end line via Point2.\n
2014 * Likewise, we make end_line attach to the start_line via Point1 and
2015 * the arc via Point 2.\n
2016 * We also make the arcs attach on the Delta end, not the Start end.\n
2019 S S+D P1 P2 P1 P2 S+D S
2020 *--- start_arc ---*--- start_line ---*--- end_line ---*--- end_arc ---*
2025 maybe_pull_1 (LineType
*line
)
2028 /* Line half-thicknesses, including line space */
2037 start_extra
= LINE2EXTRA (start_line
);
2038 end_extra
= start_extra
->end
.next
;
2039 end_line
= EXTRA2LINE (end_extra
);
2040 if (end_extra
->deleted
)
2042 start_extra
->end
.pending
= 0;
2046 if (end_extra
->end
.next
== start_extra
)
2047 reverse_line (end_line
);
2049 if (start_extra
->start
.next
2050 && EXTRA_IS_ARC (start_extra
->start
.next
))
2052 sarc_extra
= start_extra
->start
.next
;
2053 start_arc
= EXTRA2ARC (sarc_extra
);
2054 if (sarc_extra
->start
.next
== start_extra
)
2055 reverse_arc (start_arc
);
2063 if (end_extra
->end
.next
2064 && EXTRA_IS_ARC (end_extra
->end
.next
))
2066 earc_extra
= end_extra
->end
.next
;
2067 end_arc
= EXTRA2ARC (earc_extra
);
2068 if (earc_extra
->start
.next
== end_extra
)
2069 reverse_arc (end_arc
);
2078 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra
, start_extra
, end_extra
, earc_extra
);
2080 print_extra(sarc_extra
,0);
2081 print_extra(start_extra
,0);
2082 print_extra(end_extra
,0);
2084 print_extra(earc_extra
,0);
2086 if (start_extra
->deleted
2087 || end_extra
->deleted
2088 || (sarc_extra
&& sarc_extra
->deleted
)
2089 || (earc_extra
&& earc_extra
->deleted
))
2091 printf(" one is deleted?\n");
2097 if (!start_extra
->end
.pending
)
2100 if (start_extra
->end
.waiting_for
2101 && start_extra
->end
.waiting_for
->pending
)
2105 if (start_line
->Thickness
!= end_line
->Thickness
)
2107 thickness
= (start_line
->Thickness
+ 1)/2 + PCB
->Bloat
;
2109 /* At this point, our expectations are all met. */
2111 box
.X1
= start_line
->Point1
.X
- thickness
;
2112 box
.X2
= start_line
->Point1
.X
+ thickness
;
2113 box
.Y1
= start_line
->Point1
.Y
- thickness
;
2114 box
.Y2
= start_line
->Point1
.Y
+ thickness
;
2115 expand_box (&box
, start_line
->Point2
.X
, start_line
->Point2
.Y
, thickness
);
2116 expand_box (&box
, end_line
->Point2
.X
, end_line
->Point2
.Y
, thickness
);
2118 expand_box (&box
, sarc_extra
->start
.x
, sarc_extra
->start
.y
, start_arc
->Thickness
/2);
2120 expand_box (&box
, earc_extra
->start
.x
, earc_extra
->start
.y
, end_arc
->Thickness
/2);
2123 se_sign
= copysign (1, cross2d (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2124 start_line
->Point2
.X
, start_line
->Point2
.Y
,
2125 end_line
->Point2
.X
, end_line
->Point2
.Y
));
2126 best_angle
= se_sign
* M_PI
;
2129 sa_sign
= copysign (1, -start_arc
->Delta
);
2136 ea_sign
= copysign (1, -end_arc
->Delta
);
2137 ea_sign
*= -se_sign
;
2142 start_angle
= atan2 (start_line
->Point2
.Y
- start_line
->Point1
.Y
,
2143 start_line
->Point2
.X
- start_line
->Point1
.X
);
2145 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n",
2146 se_sign
, sa_sign
, ea_sign
, r2d (best_angle
), r2d(start_angle
));
2151 sa_x
= start_arc
->X
;
2152 sa_y
= start_arc
->Y
;
2153 if (same_sign (start_arc
->Delta
, se_sign
))
2154 sa_r
= - start_arc
->Width
;
2156 sa_r
= start_arc
->Width
;
2160 sa_x
= start_line
->Point1
.X
;
2161 sa_y
= start_line
->Point1
.Y
;
2168 ea_r
= end_arc
->Width
;
2170 ea_r
= - end_arc
->Width
;
2176 trace_path (sarc_extra
? sarc_extra
: start_extra
);
2181 gp_point_force (end_arc
->X
, end_arc
->Y
, -ea_r
-thickness
, 0, 0, 0, 1, "end arc");
2187 gp_point_force (end_line
->Point2
.X
, end_line
->Point2
.Y
, -thickness
, 0, 0, 0, 1, "end arc");
2188 ex
= end_line
->Point2
.X
;
2189 ey
= end_line
->Point2
.Y
;
2196 pcb_fprintf(stderr
, "end line corrupt? f is %#mD\n", fx
, fy
);
2197 print_extra (end_extra
, 0);
2199 print_extra(earc_extra
, 0);
2203 end_dist
= Distance (end_line
->Point1
.X
, end_line
->Point1
.Y
,
2204 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2206 start_pinpad
= start_extra
->start
.pin
;
2207 end_pinpad
= start_extra
->end
.pin
;
2210 r_search(CURRENT
->line_tree
, &box
, NULL
, gp_line_cb
, 0);
2211 r_search(CURRENT
->arc_tree
, &box
, NULL
, gp_arc_cb
, 0);
2212 r_search(CURRENT
->text_tree
, &box
, NULL
, gp_text_cb
, 0);
2213 r_search(CURRENT
->polygon_tree
, &box
, NULL
, gp_poly_cb
, 0);
2214 r_search(PCB
->Data
->pin_tree
, &box
, NULL
, gp_pin_cb
, 0);
2215 r_search(PCB
->Data
->via_tree
, &box
, NULL
, gp_pin_cb
, 0);
2216 r_search(PCB
->Data
->pad_tree
, &box
, NULL
, gp_pad_cb
, 0);
2218 /* radians, absolute angle of (at the moment) the start_line */
2219 abs_angle
= fa
+ start_angle
;
2222 pcb_printf("\033[43;30mBest: at %#mD r %#mS, angle %.1f fp %d\033[0m\n", fx
, fy
, fr
, r2d(fa
), fp
);
2226 if (fa
> M_PI
/2 || fa
< -M_PI
/2)
2228 SET_FLAG (FOUNDFLAG
, line
);
2229 longjmp (abort_buf
, 1);
2235 start_extra
->end
.waiting_for
= fp_end
;
2238 start_extra
->end
.pending
= 0;
2240 /* Step 0: check for merged arcs (special case). */
2242 if (fx
== ex
&& fy
== ey
2243 && start_arc
&& end_arc
2244 && start_arc
->X
== end_arc
->X
&& start_arc
->Y
== end_arc
->Y
)
2249 new_delta
= end_arc
->StartAngle
- start_arc
->StartAngle
;
2250 if (start_arc
->Delta
> 0)
2252 while (new_delta
> 360)
2254 while (new_delta
< 0)
2259 while (new_delta
< -360)
2261 while (new_delta
> 0)
2265 pcb_printf("merging arcs at %#mS nd %d\n", start_arc
->X
, start_arc
->Y
, new_delta
);
2266 print_extra(sarc_extra
, 0);
2267 print_extra(earc_extra
, 0);
2269 mark_arc_for_deletion (end_arc
);
2270 mark_line_for_deletion (start_line
);
2271 mark_line_for_deletion (end_line
);
2272 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2273 fix_arc_extra (start_arc
, sarc_extra
);
2278 /* Step 1: adjust start_arc's angles and move start_line's Point1 to
2286 /* We must always round towards "larger arcs", whichever way that is. */
2287 new_delta
= 180 - r2d(abs_angle
);
2289 printf("new_delta starts at %d vs %d < %d\n",
2290 (int)new_delta
, (int)start_arc
->StartAngle
, (int)start_arc
->Delta
);
2292 if (start_arc
->Delta
< 0)
2293 new_delta
= (int)(new_delta
) + 90;
2295 new_delta
= (int)new_delta
- 90;
2296 new_delta
= new_delta
- start_arc
->StartAngle
;
2297 while (new_delta
> start_arc
->Delta
+180)
2299 while (new_delta
< start_arc
->Delta
-180)
2302 printf("new_delta adjusts to %d\n", (int)new_delta
);
2303 printf("fa = %f, new_delta ends at %.1f vs start %d\n",
2304 fa
, new_delta
, (int)start_arc
->StartAngle
);
2307 if (new_delta
* start_arc
->Delta
<= 0)
2310 ChangeArcAngles (CURRENT
, start_arc
, start_arc
->StartAngle
, new_delta
);
2311 fix_arc_extra (start_arc
, sarc_extra
);
2312 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2313 sarc_extra
->end
.x
- start_line
->Point1
.X
,
2314 sarc_extra
->end
.y
- start_line
->Point1
.Y
);
2318 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point1
),
2319 sarc_extra
->start
.x
- start_line
->Point1
.X
,
2320 sarc_extra
->start
.y
- start_line
->Point1
.Y
);
2321 mark_arc_for_deletion (start_arc
);
2325 /* Step 1.5: If the "obstacle" is right at the end, ignore it. */
2328 double oa
= start_angle
+fa
- M_PI
/2*se_sign
;
2329 double ox
= fx
+ fr
* cos(oa
);
2330 double oy
= fy
+ fr
* sin(oa
);
2332 pcb_printf("obstacle at %#mD angle %d = arc starts at %#mD\n",
2333 fx
, fy
, (int)r2d(oa
), (Coord
)ox
, (Coord
)oy
);
2336 if (Distance (ox
, oy
, end_line
->Point2
.X
, end_line
->Point2
.Y
)
2339 /* Pretend it doesn't exist. */
2345 /* Step 2: If we have no obstacles, connect start and end. */
2348 pcb_printf("fx %#mS ex %#mS fy %#mS ey %#mS\n", fx
, ex
, fy
, ey
);
2350 if (fx
== ex
&& fy
== ey
)
2354 printf("\033[32mno obstacles\033[0m\n");
2359 int new_delta
, end_angle
, pcb_fa
, end_change
;
2361 end_angle
= end_arc
->StartAngle
+ end_arc
->Delta
;
2362 if (end_arc
->Delta
< 0)
2367 /* We must round so as to make the larger arc. */
2368 if (end_arc
->Delta
< 0)
2369 pcb_fa
= - r2d(start_angle
+ fa
);
2371 pcb_fa
= 1 - r2d(start_angle
+ fa
);
2372 end_change
= pcb_fa
- end_angle
;
2374 while (end_change
> 180)
2376 while (end_change
< -180)
2378 new_delta
= end_arc
->Delta
+ end_change
;
2380 if (new_delta
* end_arc
->Delta
<= 0)
2383 ChangeArcAngles (CURRENT
, end_arc
, end_arc
->StartAngle
, new_delta
);
2384 fix_arc_extra (end_arc
, earc_extra
);
2385 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2386 earc_extra
->end
.x
- start_line
->Point2
.X
,
2387 earc_extra
->end
.y
- start_line
->Point2
.Y
);
2391 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2392 earc_extra
->start
.x
- start_line
->Point2
.X
,
2393 earc_extra
->start
.y
- start_line
->Point2
.Y
);
2394 mark_arc_for_deletion (end_arc
);
2399 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2400 end_line
->Point2
.X
- start_line
->Point2
.X
,
2401 end_line
->Point2
.Y
- start_line
->Point2
.Y
);
2403 mark_line_for_deletion (end_line
);
2404 start_extra
->end
.pending
= 1;
2407 printf("\033[35mdid_something: no obstacles\033[0m\n");
2415 /* Step 3: Compute the new intersection of start_line and end_line. */
2417 ex
= start_line
->Point1
.X
+ cos(start_angle
+ fa
) * 10000.0;
2418 ey
= start_line
->Point1
.Y
+ sin(start_angle
+ fa
) * 10000.0;
2420 pcb_printf("temp point %#mS\n", ex
, ey
);
2421 pcb_printf("intersect %#mS-%#mS with %#mS-%#mS\n",
2422 start_line
->Point1
.X
, start_line
->Point1
.Y
,
2424 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2425 end_line
->Point2
.X
, end_line
->Point2
.Y
);
2427 if (! intersection_of_lines (start_line
->Point1
.X
, start_line
->Point1
.Y
,
2429 end_line
->Point1
.X
, end_line
->Point1
.Y
,
2430 end_line
->Point2
.X
, end_line
->Point2
.Y
,
2433 ex
= end_line
->Point2
.X
;
2434 ey
= end_line
->Point2
.Y
;
2437 pcb_printf("new point %#mS\n", ex
, ey
);
2439 MoveObject (LINEPOINT_TYPE
, CURRENT
, end_line
, &(end_line
->Point1
),
2440 ex
- end_line
->Point1
.X
,
2441 ey
- end_line
->Point1
.Y
);
2443 /* Step 4: Split start_line at the obstacle and insert a zero-delta
2446 new_arc
= create_arc (start_line
, fx
, fy
, fr
,
2447 90-(int)(r2d(start_angle
+fa
)+0.5) + 90 + 90*se_sign
, -se_sign
);
2448 new_aextra
= ARC2EXTRA (new_arc
);
2450 if (start_arc
) sarc_extra
= ARC2EXTRA (start_arc
);
2451 if (end_arc
) earc_extra
= ARC2EXTRA (end_arc
);
2453 MoveObject (LINEPOINT_TYPE
, CURRENT
, start_line
, &(start_line
->Point2
),
2454 new_aextra
->start
.x
- start_line
->Point2
.X
,
2455 new_aextra
->start
.y
- start_line
->Point2
.Y
);
2457 new_line
= create_line (start_line
, new_aextra
->end
.x
, new_aextra
->end
.y
, ex
, ey
);
2458 start_extra
= LINE2EXTRA (start_line
);
2459 new_lextra
= LINE2EXTRA (new_line
);
2460 end_extra
= LINE2EXTRA (end_line
);
2462 new_lextra
->start
.pin
= start_extra
->start
.pin
;
2463 new_lextra
->end
.pin
= start_extra
->end
.pin
;
2464 new_lextra
->start
.pending
= 1;
2465 new_lextra
->end
.pending
= 1;
2467 start_extra
->end
.next
= new_aextra
;
2468 new_aextra
->start
.next
= start_extra
;
2469 new_aextra
->end
.next
= new_lextra
;
2470 new_lextra
->start
.next
= new_aextra
;
2471 new_lextra
->end
.next
= end_extra
;
2472 end_extra
->start
.next
= new_lextra
;
2474 /* Step 5: Recurse. */
2480 printf("\033[35mdid_something: recursing\033[0m\n");
2482 int i
= gui
->confirm_dialog("recurse?", 0);
2483 printf("confirm = %d\n", i
);
2487 printf("\n\033[33mRECURSING\033[0m\n\n");
2488 IncrementUndoSerialNumber();
2490 maybe_pull_1 (new_line
);
2494 * \brief Given a line with a end_next, attempt to pull both ends.
2497 maybe_pull (LineType
*line
, Extra
*e
)
2500 printf("maybe_pull: ");
2503 if (e
->end
.next
&& EXTRA_IS_LINE (e
->end
.next
))
2505 maybe_pull_1 (line
);
2510 if (e
->start
.next
&& EXTRA_IS_LINE (e
->start
.next
))
2512 reverse_line (line
);
2513 maybe_pull_1 (line
);
2516 e
->start
.pending
= 0;
2521 validate_pair (Extra
*e
, End
*end
)
2525 if (end
->next
->start
.next
== e
)
2527 if (end
->next
->end
.next
== e
)
2529 fprintf(stderr
, "no backlink!\n");
2531 print_extra (end
->next
, 0);
2536 validate_pair_cb (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2538 validate_pair (extra
, &extra
->start
);
2539 validate_pair (extra
, &extra
->end
);
2545 g_hash_table_foreach (lines
, (GHFunc
)validate_pair_cb
, NULL
);
2549 g_hash_table_foreach (arcs
, (GHFunc
)validate_pair_cb
, NULL
);
2553 FreeExtra (Extra
*extra
)
2555 g_slice_free (Extra
, extra
);
2559 mark_ends_pending (LineType
*line
, Extra
*extra
, void *userdata
)
2561 int *select_flags
= userdata
;
2562 if (TEST_FLAGS (*select_flags
, line
))
2564 extra
->start
.pending
= 1;
2565 extra
->end
.pending
= 1;
2571 trace_print_extra (AnyObjectType
*ptr
, Extra
*extra
, void *userdata
)
2573 last_pextra
= (Extra
*)1;
2574 print_extra(extra
, 0);
2578 trace_print_lines_arcs (void)
2580 printf("\nlines\n");
2581 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2584 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2591 GlobalPuller(int argc
, char **argv
, Coord x
, Coord y
)
2593 int select_flags
= 0;
2598 Message ("puller! %s\n", argc
> 0 ? argv
[0] : "");
2600 if (argc
> 0 && strcasecmp (argv
[0], "selected") == 0)
2601 select_flags
= SELECTEDFLAG
;
2602 if (argc
> 0 && strcasecmp (argv
[0], "found") == 0)
2603 select_flags
= FOUNDFLAG
;
2605 Message ("optimizing...\n");
2606 /* This canonicalizes all the lines, and cleans up near-misses. */
2607 /* hid_actionl ("djopt", "puller", 0); */
2609 current_is_bottom
= (GetLayerGroupNumberByPointer(CURRENT
)
2610 == GetLayerGroupNumberBySide (BOTTOM_SIDE
));
2611 current_is_top
= (GetLayerGroupNumberByPointer(CURRENT
)
2612 == GetLayerGroupNumberBySide (TOP_SIDE
));
2614 lines
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2615 arcs
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
)FreeExtra
);
2617 Message ("pairing...\n");
2621 g_hash_table_foreach (lines
, (GHFunc
)mark_ends_pending
, &select_flags
);
2624 trace_print_lines_arcs ();
2630 trace_print_lines_arcs ();
2634 Message ("pulling...\n");
2635 if (setjmp(abort_buf
) == 0)
2638 int old_did_something
= -1;
2641 while (did_something
)
2646 LINE_LOOP (CURRENT
); {
2647 Extra
*e
= LINE2EXTRA (line
);
2650 #ifdef CHECK_LINE_PT_NEG
2651 if (line
->Point1
.X
< 0)
2654 if (e
->start
.next
|| e
->end
.next
)
2655 maybe_pull (line
, e
);
2657 if (did_something
!= old_did_something
)
2659 IncrementUndoSerialNumber();
2660 old_did_something
= did_something
;
2661 if (gui
->confirm_dialog("more?", 0) == 0)
2668 /*gui->progress(0,0,0);*/
2674 printf("\nlines\n");
2675 g_hash_table_foreach (lines
, (GHFunc
)trace_print_extra
, NULL
);
2677 g_hash_table_foreach (arcs
, (GHFunc
)trace_print_extra
, NULL
);
2679 printf("\nlines\n");
2682 LINE_LOOP (CURRENT
);
2684 if (LINE2EXTRA (line
)->deleted
)
2685 RemoveLine (CURRENT
, line
);
2691 if (ARC2EXTRA (arc
)->deleted
)
2692 RemoveArc (CURRENT
, arc
);
2696 g_hash_table_unref (lines
);
2697 g_hash_table_unref (arcs
);
2699 IncrementUndoSerialNumber();
2705 HID_Action puller_action_list
[] = {
2706 {"Puller", "Click on a line-arc intersection or line segment", Puller
,
2707 puller_help
, puller_syntax
},
2708 {"GlobalPuller", 0, GlobalPuller
,
2709 globalpuller_help
, globalpuller_syntax
}
2712 REGISTER_ACTIONS (puller_action_list
)