pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00048 #ifdef HAVE_CONFIG_H 00049 #include "config.h" 00050 #endif 00051 00052 #include "global.h" 00053 00054 #include <math.h> 00055 #include <memory.h> 00056 #include <limits.h> 00057 #include <setjmp.h> 00058 00059 00060 #include "create.h" 00061 #include "data.h" 00062 #include "draw.h" 00063 #include "misc.h" 00064 #include "move.h" 00065 #include "pcb-printf.h" 00066 #include "remove.h" 00067 #include "rtree.h" 00068 #include "strflags.h" 00069 #include "undo.h" 00070 #include "error.h" 00071 00072 #ifdef HAVE_LIBDMALLOC 00073 #include <dmalloc.h> 00074 #endif 00075 00076 #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort() 00077 00078 #define TRACE0 0 00079 #define TRACE1 0 00080 00082 #define SIN1D 0.0174524064372835 00083 00084 static jmp_buf abort_buf; 00085 static int multi, line_exact, arc_exact; 00086 static LineType *the_line; 00087 static ArcType *the_arc; 00088 static double arc_dist; 00089 00090 /* We canonicalize the arc and line such that the point to be moved is 00091 always Point2 for the line, and at start+delta for the arc. */ 00092 00093 static Coord x, y; /* the point we're moving */ 00094 static Coord cx, cy; /* centerpoint of the arc */ 00095 static Coord ex, ey; /* fixed end of the line */ 00096 00097 /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */ 00098 00099 static Coord 00100 within (Coord x1, Coord y1, Coord x2, Coord y2, Coord r) 00101 { 00102 return Distance (x1, y1, x2, y2) <= r / 2; 00103 } 00104 00105 static int 00106 arc_endpoint_is (ArcType *a, int angle, Coord x, Coord y) 00107 { 00108 Coord ax = a->X, ay = a->Y; 00109 00110 if (angle % 90 == 0) 00111 { 00112 int ai = (int) (angle / 90) & 3; 00113 switch (ai) 00114 { 00115 case 0: 00116 ax -= a->Width; 00117 break; 00118 case 1: 00119 ay += a->Height; 00120 break; 00121 case 2: 00122 ax += a->Width; 00123 break; 00124 case 3: 00125 ay -= a->Height; 00126 break; 00127 } 00128 } 00129 else 00130 { 00131 double rad = angle * M_PI / 180; 00132 ax -= a->Width * cos (rad); 00133 ay += a->Width * sin (rad); 00134 } 00135 #if TRACE1 00136 pcb_printf (" - arc endpoint %#mD\n", ax, ay); 00137 #endif 00138 arc_dist = Distance (ax, ay, x, y); 00139 if (arc_exact) 00140 return arc_dist < 2; 00141 return arc_dist < a->Thickness / 2; 00142 } 00143 00147 static double 00148 cross2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) 00149 { 00150 ux -= cx; 00151 uy -= cy; 00152 vx -= cx; 00153 vy -= cy; 00154 return (double)ux * vy - (double)uy * vx; 00155 } 00156 00160 static double 00161 dot2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) 00162 { 00163 ux -= cx; 00164 uy -= cy; 00165 vx -= cx; 00166 vy -= cy; 00167 return (double)ux * vx + (double)uy * vy; 00168 } 00169 00170 #if 0 00171 00177 static double 00178 angle2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) 00179 { 00180 double cross; 00181 double magu, magv, sintheta; 00182 #if TRACE1 00183 pcb_printf("angle2d %mD %mD %mD\n", cx, cy, ux, uy, vx, vy); 00184 #endif 00185 ux -= cx; 00186 uy -= cy; 00187 vx -= cx; 00188 vy -= cy; 00189 #if TRACE1 00190 pcb_printf(" = %mD %mD\n", ux, uy, vx, vy); 00191 #endif 00192 cross = (double)ux * vy - (double)uy * vx; 00193 magu = hypot(ux, uy); 00194 magv = hypot(vx, vy); 00195 sintheta = cross / (magu * magv); 00196 #if TRACE1 00197 printf(" = %f / (%f * %f) = %f\n", cross, magu, magv, sintheta); 00198 #endif 00199 return asin (sintheta); 00200 } 00201 #endif 00202 00203 static int 00204 same_sign (double a, double b) 00205 { 00206 return (a * b >= 0); 00207 } 00208 00209 static double 00210 r2d (double r) 00211 { 00212 return 180.0 * r / M_PI; 00213 } 00214 00215 static double 00216 d2r (double d) 00217 { 00218 return M_PI * d / 180.0; 00219 } 00220 00228 static double 00229 det (double a, double b, double c, double d) 00230 { 00231 return a * d - b * c; 00232 } 00233 00241 static int 00242 intersection_of_lines (Coord x1, Coord y1, Coord x2, Coord y2, 00243 Coord x3, Coord y3, Coord x4, Coord y4, 00244 Coord *xr, Coord *yr) 00245 { 00246 double x, y, d; 00247 d = det (x1 - x2, y1 - y2, x3 - x4, y3 - y4); 00248 if (!d) 00249 return 0; 00250 x = (det (det (x1, y1, x2, y2), x1 - x2, 00251 det (x3, y3, x4, y4), x3 - x4) / d); 00252 y = (det (det (x1, y1, x2, y2), y1 - y2, 00253 det (x3, y3, x4, y4), y3 - y4) / d); 00254 *xr = (Coord) (x + 0.5); 00255 *yr = (Coord) (y + 0.5); 00256 return 1; 00257 } 00258 00267 static int 00268 intersection_of_linesegs (Coord x1, Coord y1, Coord x2, Coord y2, 00269 Coord x3, Coord y3, Coord x4, Coord y4, 00270 Coord *xr, Coord *yr) 00271 { 00272 double x, y, d; 00273 d = det (x1 - x2, y1 - y2, x3 - x4, y3 - y4); 00274 if (!d) 00275 return 0; 00276 x = (det (det (x1, y1, x2, y2), x1 - x2, 00277 det (x3, y3, x4, y4), x3 - x4) / d); 00278 y = (det (det (x1, y1, x2, y2), y1 - y2, 00279 det (x3, y3, x4, y4), y3 - y4) / d); 00280 if (MIN (x1, x2) > x || x > MAX (x1, x2) 00281 || MIN (y1, y2) > y || y > MAX (y1, y2)) 00282 return 0; 00283 if (MIN (x3, x4) > x || x > MAX (x3, x4) 00284 || MIN (y3, y4) > y || y > MAX (y3, y4)) 00285 return 0; 00286 if (xr) 00287 *xr = (Coord) (x + 0.5); 00288 if (yr) 00289 *yr = (Coord) (y + 0.5); 00290 return 1; 00291 } 00292 00296 static double 00297 dist_lp (Coord x1, Coord y1, Coord x2, Coord y2, Coord px, Coord py) 00298 { 00299 double den = Distance (x1, y1, x2, y2); 00300 double rv = (fabs (((double)x2 - x1) * ((double)y1 - py) 00301 - ((double)x1 - px) * ((double)y2 - y1)) 00302 / den); 00303 #if TRACE1 00304 pcb_printf("dist %#mD-%#mD to %#mD is %f\n", 00305 x1, y1, x2, y2, px, py, rv); 00306 #endif 00307 return rv; 00308 } 00309 00313 static double 00314 dist_lsp (Coord x1, Coord y1, Coord x2, Coord y2, Coord px, Coord py) 00315 { 00316 double d; 00317 if (dot2d (x1, y1, x2, y2, px, py) < 0) 00318 return Distance (x1, y1, px, py); 00319 if (dot2d (x2, y2, x1, y1, px, py) < 0) 00320 return Distance (x2, y2, px, py); 00321 d = (fabs (((double)x2 - x1) * ((double)y1 - py) 00322 - ((double)x1 - px) * ((double)y2 - y1)) 00323 / Distance (x1, y1, x2, y2)); 00324 return d; 00325 } 00326 00327 /* Single Point Puller */ 00328 00329 static int 00330 line_callback (const BoxType * b, void *cl) 00331 { 00332 /* LayerType *layer = (LayerType *)cl; */ 00333 LineType *l = (LineType *) b; 00334 double d1, d2, t; 00335 #if TRACE1 00336 pcb_printf ("line %#mD .. %#mD\n", 00337 l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y); 00338 #endif 00339 d1 = Distance (l->Point1.X, l->Point1.Y, x, y); 00340 d2 = Distance (l->Point2.X, l->Point2.Y, x, y); 00341 if ((d1 < 2 || d2 < 2) && !line_exact) 00342 { 00343 line_exact = 1; 00344 the_line = 0; 00345 } 00346 t = line_exact ? 2 : l->Thickness / 2; 00347 if (d1 < t || d2 < t) 00348 { 00349 if (the_line) 00350 multi = 1; 00351 the_line = l; 00352 #if TRACE1 00353 printf ("picked, exact %d\n", line_exact); 00354 #endif 00355 } 00356 return 1; 00357 } 00358 00359 static int 00360 arc_callback (const BoxType * b, void *cl) 00361 { 00362 /* LayerType *layer = (LayerType *) cl; */ 00363 ArcType *a = (ArcType *) b; 00364 00365 #if TRACE1 00366 pcb_printf ("arc a %#mD r %#mS sa %ld d %ld\n", a->X, a->Y, a->Width, 00367 a->StartAngle, a->Delta); 00368 #endif 00369 if (!arc_endpoint_is (a, a->StartAngle, x, y) 00370 && !arc_endpoint_is (a, a->StartAngle + a->Delta, x, y)) 00371 return 1; 00372 if (arc_dist < 2) 00373 { 00374 if (!arc_exact) 00375 { 00376 arc_exact = 1; 00377 the_arc = 0; 00378 } 00379 if (the_arc) 00380 multi = 1; 00381 the_arc = a; 00382 #if TRACE1 00383 printf ("picked, exact %d\n", arc_exact); 00384 #endif 00385 } 00386 else if (!arc_exact) 00387 { 00388 if (the_arc) 00389 multi = 1; 00390 the_arc = a; 00391 #if TRACE1 00392 printf ("picked, exact %d\n", arc_exact); 00393 #endif 00394 } 00395 return 1; 00396 } 00397 00398 static int 00399 find_pair (Coord Px, Coord Py) 00400 { 00401 BoxType spot; 00402 00403 #if TRACE1 00404 pcb_printf ("\nPuller find_pair at %#mD\n", Px, Py); 00405 #endif 00406 00407 x = Px; 00408 y = Py; 00409 multi = 0; 00410 line_exact = arc_exact = 0; 00411 the_line = 0; 00412 the_arc = 0; 00413 spot.X1 = x - 1; 00414 spot.Y1 = y - 1; 00415 spot.X2 = x + 1; 00416 spot.Y2 = y + 1; 00417 r_search (CURRENT->line_tree, &spot, NULL, line_callback, CURRENT); 00418 r_search (CURRENT->arc_tree, &spot, NULL, arc_callback, CURRENT); 00419 if (the_line && the_arc && !multi) 00420 return 1; 00421 x = Px; 00422 y = Py; 00423 return 0; 00424 } 00425 00426 00427 static const char puller_syntax[] = "Puller()"; 00428 00429 static const char puller_help[] = "Pull an arc-line junction tight."; 00430 00431 /* %start-doc actions Puller 00432 00433 The @code{Puller()} action is a special-purpose optimization. When 00434 invoked while the crosshair is over the junction of an arc and a line, 00435 it will adjust the arc's angle and the connecting line's endpoint such 00436 that the line intersects the arc at a tangent. In the example below, 00437 the left side is ``before'' with the black target marking where to put 00438 the crosshair: 00439 00440 @center @image{puller,,,Example of how puller works,png} 00441 00442 The right side is ``after'' with the black target marking where the 00443 arc-line intersection was moved to. 00444 00445 %end-doc */ 00446 00447 static int 00448 Puller (int argc, char **argv, Coord Ux, Coord Uy) 00449 { 00450 double arc_angle, base_angle; 00451 #if TRACE1 00452 double line_angle, rel_angle; 00453 #endif 00454 double tangent; 00455 int new_delta_angle; 00456 00457 if (!find_pair (Crosshair.X, Crosshair.Y)) 00458 if (!find_pair (Ux, Uy)) 00459 return 0; 00460 00461 if (within (the_line->Point1.X, the_line->Point1.Y, 00462 x, y, the_line->Thickness)) 00463 { 00464 ex = the_line->Point2.X; 00465 ey = the_line->Point2.Y; 00466 the_line->Point2.X = the_line->Point1.X; 00467 the_line->Point2.Y = the_line->Point1.Y; 00468 the_line->Point1.X = ex; 00469 the_line->Point1.Y = ey; 00470 } 00471 else if (!within (the_line->Point2.X, the_line->Point2.Y, 00472 x, y, the_line->Thickness)) 00473 { 00474 #if TRACE1 00475 printf ("Line endpoint not at cursor\n"); 00476 #endif 00477 return 1; 00478 } 00479 ex = the_line->Point1.X; 00480 ey = the_line->Point1.Y; 00481 00482 cx = the_arc->X; 00483 cy = the_arc->Y; 00484 if (arc_endpoint_is (the_arc, the_arc->StartAngle, x, y)) 00485 { 00486 ChangeArcAngles (CURRENT, the_arc, the_arc->StartAngle + the_arc->Delta, 00487 -the_arc->Delta); 00488 } 00489 else if (!arc_endpoint_is (the_arc, the_arc->StartAngle + the_arc->Delta, 00490 x, y)) 00491 { 00492 #if TRACE1 00493 printf ("arc not endpoints\n"); 00494 #endif 00495 return 1; 00496 } 00497 00498 if (within (cx, cy, ex, ey, the_arc->Width * 2)) 00499 { 00500 #if TRACE1 00501 printf ("line ends inside arc\n"); 00502 #endif 00503 return 1; 00504 } 00505 00506 if (the_arc->Delta > 0) 00507 arc_angle = the_arc->StartAngle + the_arc->Delta + 90; 00508 else 00509 arc_angle = the_arc->StartAngle + the_arc->Delta - 90; 00510 base_angle = r2d (atan2 (ey - cy, cx - ex)); 00511 00512 tangent = r2d (acos (the_arc->Width / Distance (cx, cy, ex, ey))); 00513 00514 #if TRACE1 00515 line_angle = r2d (atan2 (ey - y, x - ex)); 00516 rel_angle = line_angle - arc_angle; 00517 printf ("arc %g line %g rel %g base %g\n", arc_angle, line_angle, rel_angle, 00518 base_angle); 00519 printf ("tangent %g\n", tangent); 00520 00521 printf ("arc was start %ld end %ld\n", the_arc->StartAngle, 00522 the_arc->StartAngle + the_arc->Delta); 00523 #endif 00524 00525 if (the_arc->Delta > 0) 00526 arc_angle = base_angle - tangent; 00527 else 00528 arc_angle = base_angle + tangent; 00529 #if TRACE1 00530 printf ("new end angle %g\n", arc_angle); 00531 #endif 00532 00533 new_delta_angle = arc_angle - the_arc->StartAngle; 00534 if (new_delta_angle > 180) 00535 new_delta_angle -= 360; 00536 if (new_delta_angle < -180) 00537 new_delta_angle += 360; 00538 ChangeArcAngles (CURRENT, the_arc, the_arc->StartAngle, new_delta_angle); 00539 00540 #if TRACE1 00541 printf ("arc now start %ld end %ld\n", the_arc->StartAngle, 00542 the_arc->StartAngle + new_delta_angle); 00543 #endif 00544 00545 arc_angle = the_arc->StartAngle + the_arc->Delta; 00546 x = the_arc->X - the_arc->Width * cos (d2r (arc_angle)) + 0.5; 00547 y = the_arc->Y + the_arc->Height * sin (d2r (arc_angle)) + 0.5; 00548 00549 MoveObject (LINEPOINT_TYPE, CURRENT, the_line, &(the_line->Point2), 00550 x - the_line->Point2.X, y - the_line->Point2.Y); 00551 00552 gui->invalidate_all (); 00553 IncrementUndoSerialNumber (); 00554 00555 return 1; 00556 } 00557 00558 /* Global Puller */ 00559 00560 static const char globalpuller_syntax[] = 00561 "GlobalPuller()"; 00562 00563 static const char globalpuller_help[] = 00564 "Pull all traces tight."; 00565 00566 /* %start-doc actions GlobalPuller 00567 00568 %end-doc */ 00569 00570 /* Ok, here's the deal. We look for the intersection of two traces. 00571 The triangle formed by those traces is searched for things we need 00572 to avoid. From the other two corners of the triangle, we compute 00573 the angle to each obstacle, and remember the ones closest to the 00574 start angles. If the two traces hit the same obstacle, we put in 00575 the arc and we're done. Else, we bring the traces up to the 00576 obstacles and start again. 00577 00578 Note that we assume each start point is a tangent to an arc. We 00579 start with a radius of zero, but future steps use the arcs we 00580 create as we go. 00581 00582 For obstacles, we list each round pin, pad, via, and line/arc 00583 endpoints as points with a given radius. For each square pin, pad, 00584 via, and polygon points, we list each corner with a zero radius. 00585 We also list arcs from their centerpoint. 00586 00587 We don't currently do anything to move vias, or intersections of 00588 three or more traces. In the future, three-way intersections will 00589 be handles similarly to two-way - calculate the range of angles 00590 valid from each of the three other endpoints, choose the angle 00591 closest to making 120 degree angles at the center. For four-way or 00592 more intersections, we break them up into multiple three-way 00593 intersections. 00594 00595 For simplicity, we only do the current layer at this time. We will 00596 also edit the lines and arcs in place so that the intersection is 00597 always on the second point, and the other ends are always at 00598 start+delta for arcs. 00599 00600 We also defer intersections which are blocked by other 00601 intersections yet to be moved; the idea is to wait until those have 00602 been moved so we don't end up with arcs that no longer wrap around 00603 things. At a later point, we may choose to pull arced corners in 00604 also. 00605 00606 You'll see lots of variables of the form "foo_sign" which keep 00607 track of which way things are pointing. This is because everything 00608 is relative to corners and arcs, not absolute directions. 00609 */ 00610 00611 static int nloops, npulled; 00612 00613 static void 00614 status () 00615 { 00616 Message ("%6d loops, %d pulled \r", nloops, npulled); 00617 } 00618 00623 typedef struct End { 00624 /* These point to "multi_next" if there are more than one. */ 00625 struct Extra *next; 00626 void *pin; 00627 unsigned char in_pin:1; 00628 unsigned char at_pin:1; 00629 unsigned char is_pad:1; 00630 unsigned char pending:1; /* set if this may be moved later */ 00631 Coord x, y; /* arc endpoint */ 00632 /* If not NULL, points to End with pending==1 we're blocked on. */ 00633 struct End *waiting_for; 00634 } End; 00635 00636 typedef struct Extra { 00637 End start; 00638 End end; 00639 unsigned char found:1; 00640 unsigned char deleted:1; 00641 int type; 00642 union { 00643 LineType *line; 00644 ArcType *arc; 00645 } parent; 00646 } Extra; 00647 00648 static Extra multi_next; 00649 static GHashTable *lines; 00650 static GHashTable *arcs; 00651 static int did_something; 00652 static int current_is_top, current_is_bottom; 00653 00654 /* If set, these are the pins/pads/vias that this path ends on. */ 00655 /* static void *start_pin_pad, *end_pin_pad; */ 00656 00657 #if TRACE1 00658 static void trace_paths (); 00659 #endif 00660 static void mark_line_for_deletion (LineType *); 00661 00662 #define LINE2EXTRA(l) ((Extra *)g_hash_table_lookup (lines, l)) 00663 #define ARC2EXTRA(a) ((Extra *)g_hash_table_lookup (arcs, a)) 00664 #define EXTRA2LINE(e) (e->parent.line) 00665 #define EXTRA2ARC(e) (e->parent.arc) 00666 #define EXTRA_IS_LINE(e) (e->type == LINE_TYPE) 00667 #define EXTRA_IS_ARC(e) (e->type == ARC_TYPE) 00668 00669 static void 00670 unlink_end (Extra *x, Extra **e) 00671 { 00672 if (*e) 00673 { 00674 if ((*e)->start.next == x) 00675 { 00676 #if TRACE1 00677 printf("%d: unlink_end, was %p\n", __LINE__, (*e)->start.next); 00678 #endif 00679 (*e)->start.next = &multi_next; 00680 } 00681 if ((*e)->end.next == x) 00682 { 00683 #if TRACE1 00684 printf("%d: unlink_end, was %p\n", __LINE__, (*e)->start.next); 00685 #endif 00686 (*e)->end.next = &multi_next; 00687 } 00688 } 00689 #if TRACE1 00690 printf("%d: unlink_end, was %p\n", __LINE__, (*e)); 00691 #endif 00692 (*e) = &multi_next; 00693 } 00694 00695 #if TRACE1 00696 00697 static void 00698 clear_found_cb (AnyObjectType *ptr, Extra *extra, void *userdata) 00699 { 00700 extra->found = 0; 00701 } 00702 00703 static void 00704 clear_found () 00705 { 00706 g_hash_table_foreach (lines, (GHFunc)clear_found_cb, NULL); 00707 g_hash_table_foreach (arcs, (GHFunc)clear_found_cb, NULL); 00708 } 00709 #endif 00710 00711 static void 00712 fix_arc_extra (ArcType *a, Extra *e) 00713 { 00714 #if TRACE1 00715 printf("new arc angles %ld %ld\n", a->StartAngle, a->Delta); 00716 #endif 00717 e->start.x = a->X - (a->Width * cos (d2r (a->StartAngle)) + 0.5); 00718 e->start.y = a->Y + (a->Height * sin (d2r (a->StartAngle)) + 0.5); 00719 e->end.x = a->X - (a->Width * cos (d2r (a->StartAngle+a->Delta)) + 0.5); 00720 e->end.y = a->Y + (a->Height * sin (d2r (a->StartAngle+a->Delta)) + 0.5); 00721 #if TRACE1 00722 pcb_printf("new X,Y is %#mD to %#mD\n", e->start.x, e->start.y, e->end.x, e->end.y); 00723 #endif 00724 } 00725 00726 typedef struct { 00727 void *me; 00728 Coord x, y; 00729 int is_arc; 00730 Extra **extra_ptr; 00731 } FindPairCallbackStruct; 00732 00733 #define NEAR(a,b) ((a) <= (b) + 2 && (a) >= (b) - 2) 00734 00735 static int 00736 find_pair_line_callback (const BoxType * b, void *cl) 00737 { 00738 LineType *line = (LineType *) b; 00739 #if TRACE1 00740 Extra *e = LINE2EXTRA (line); 00741 #endif 00742 FindPairCallbackStruct *fpcs = (FindPairCallbackStruct *) cl; 00743 00744 if (line == fpcs->me) 00745 return 0; 00746 #ifdef CHECK_LINE_PT_NEG 00747 if (line->Point1.X < 0) 00748 abort1(); 00749 #endif 00750 #if TRACE1 00751 pcb_printf(" - %p line %#mD or %#mD\n", e, line->Point1.X, line->Point1.Y, 00752 line->Point2.X, line->Point2.Y); 00753 #endif 00754 if ((NEAR (line->Point1.X, fpcs->x) && NEAR (line->Point1.Y, fpcs->y)) 00755 || (NEAR (line->Point2.X, fpcs->x) && NEAR (line->Point2.Y, fpcs->y))) 00756 { 00757 if (* fpcs->extra_ptr) 00758 { 00759 #if TRACE1 00760 printf("multiple, was %p\n", *fpcs->extra_ptr); 00761 #endif 00762 *fpcs->extra_ptr = & multi_next; 00763 } 00764 else 00765 { 00766 *fpcs->extra_ptr = LINE2EXTRA (line); 00767 #if TRACE1 00768 printf(" - next now %p\n", *fpcs->extra_ptr); 00769 #endif 00770 } 00771 } 00772 return 0; 00773 } 00774 00775 static int 00776 find_pair_arc_callback (const BoxType * b, void *cl) 00777 { 00778 ArcType *arc = (ArcType *) b; 00779 Extra *e = ARC2EXTRA (arc); 00780 FindPairCallbackStruct *fpcs = (FindPairCallbackStruct *) cl; 00781 00782 if (arc == fpcs->me) 00783 return 0; 00784 #if TRACE1 00785 pcb_printf(" - %p arc %#mD or %#mD\n", e, e->start.x, e->start.y, e->end.x, e->end.y); 00786 #endif 00787 if ((NEAR (e->start.x, fpcs->x) && NEAR (e->start.y, fpcs->y)) 00788 || (NEAR (e->end.x, fpcs->x) && NEAR (e->end.y, fpcs->y))) 00789 { 00790 if (* fpcs->extra_ptr) 00791 { 00792 #if TRACE1 00793 printf("multiple, was %p\n", *fpcs->extra_ptr); 00794 #endif 00795 *fpcs->extra_ptr = & multi_next; 00796 } 00797 else 00798 *fpcs->extra_ptr = e; 00799 } 00800 return 0; 00801 } 00802 00803 static void 00804 find_pairs_1 (void *me, Extra **e, Coord x, Coord y) 00805 { 00806 FindPairCallbackStruct fpcs; 00807 BoxType b; 00808 00809 if (*e) 00810 return; 00811 00812 fpcs.me = me; 00813 fpcs.extra_ptr = e; 00814 fpcs.x = x; 00815 fpcs.y = y; 00816 #if TRACE1 00817 pcb_printf("looking for %#mD\n", x, y); 00818 #endif 00819 b.X1 = x - 10; 00820 b.X2 = x + 10; 00821 b.Y1 = y - 10; 00822 b.Y2 = y + 10; 00823 r_search(CURRENT->line_tree, &b, NULL, find_pair_line_callback, &fpcs); 00824 r_search(CURRENT->arc_tree, &b, NULL, find_pair_arc_callback, &fpcs); 00825 } 00826 00827 static int 00828 check_point_in_pin (PinType *pin, Coord x, Coord y, End *e) 00829 { 00830 int inside_p; 00831 Coord t = (PIN_SIZE(pin)+1)/2; 00832 if (TEST_FLAG (SQUAREFLAG, pin)) 00833 inside_p = (x >= pin->X - t && x <= pin->X + t 00834 && y >= pin->Y - t && y <= pin->Y + t); 00835 else 00836 inside_p = (Distance (pin->X, pin->Y, x, y) <= t); 00837 00838 if (inside_p) 00839 { 00840 e->in_pin = 1; 00841 if (pin->X == x && pin->Y == y) 00842 e->at_pin = 1; 00843 e->pin = pin; 00844 return 1; 00845 } 00846 return 0; 00847 } 00848 00849 static int 00850 find_pair_pinline_callback (const BoxType * b, void *cl) 00851 { 00852 LineType *line = (LineType *) b; 00853 PinType *pin = (PinType *) cl; 00854 Extra *e = LINE2EXTRA (line); 00855 int hits; 00856 00857 #ifdef CHECK_LINE_PT_NEG 00858 if (line->Point1.X < 0) 00859 abort1(); 00860 #endif 00861 00862 hits = check_point_in_pin (pin, line->Point1.X, line->Point1.Y, &(e->start)); 00863 hits += check_point_in_pin (pin, line->Point2.X, line->Point2.Y, &(e->end)); 00864 00865 if (hits) 00866 return 0; 00867 00868 /* See if the line passes through this pin. */ 00871 if (dist_lsp (line->Point1.X, line->Point1.Y, 00872 line->Point2.X, line->Point2.Y, 00873 pin->X, pin->Y) <= PIN_SIZE(pin)/2) 00874 { 00875 #if TRACE1 00876 pcb_printf("splitting line %#mD-%#mD because it passes through pin %#mD r%d\n", 00877 line->Point1.X, line->Point1.Y, 00878 line->Point2.X, line->Point2.Y, 00879 pin->X, pin->Y, PIN_SIZE(pin)/2); 00880 #endif 00881 unlink_end (e, &e->start.next); 00882 unlink_end (e, &e->end.next); 00883 } 00884 return 0; 00885 } 00886 00887 static int 00888 find_pair_pinarc_callback (const BoxType * b, void *cl) 00889 { 00890 ArcType *arc = (ArcType *) b; 00891 PinType *pin = (PinType *) cl; 00892 Extra *e = ARC2EXTRA (arc); 00893 int hits; 00894 00895 hits = check_point_in_pin (pin, e->start.x, e->start.y, &(e->start)); 00896 hits += check_point_in_pin (pin, e->end.x, e->end.y, &(e->end)); 00897 return 0; 00898 } 00899 00900 static int 00901 check_point_in_pad (PadType *pad, Coord x, Coord y, End *e) 00902 { 00903 int inside_p; 00904 Coord t; 00905 00906 pcb_printf("pad %#mD - %#mD t %#mS vs %#mD\n", pad->Point1.X, pad->Point1.Y, 00907 pad->Point2.X, pad->Point2.Y, pad->Thickness, x, y); 00908 t = (pad->Thickness+1)/2; 00909 if (TEST_FLAG (SQUAREFLAG, pad)) 00910 { 00911 inside_p = (x >= MIN (pad->Point1.X - t, pad->Point2.X - t) 00912 && x <= MAX (pad->Point1.X + t, pad->Point2.X + t) 00913 && y >= MIN (pad->Point1.Y - t, pad->Point2.Y - t) 00914 && y <= MAX (pad->Point1.Y + t, pad->Point2.Y + t)); 00915 printf(" - inside_p = %d\n", inside_p); 00916 } 00917 else 00918 { 00919 if (pad->Point1.X == pad->Point2.X) 00920 { 00921 inside_p = (x >= pad->Point1.X - t 00922 && x <= pad->Point1.X + t 00923 && y >= MIN (pad->Point1.Y, pad->Point2.Y) 00924 && y <= MAX (pad->Point1.Y, pad->Point2.Y)); 00925 } 00926 else 00927 { 00928 inside_p = (x >= MIN (pad->Point1.X, pad->Point2.X) 00929 && x <= MAX (pad->Point1.X, pad->Point2.X) 00930 && y >= pad->Point1.Y - t 00931 && y <= pad->Point1.Y + t); 00932 } 00933 if (!inside_p) 00934 { 00935 if (Distance (pad->Point1.X, pad->Point1.Y, x, y) <= t 00936 || Distance (pad->Point2.X, pad->Point2.Y, x, y) <= t) 00937 inside_p = 1; 00938 } 00939 } 00940 00941 if (inside_p) 00942 { 00943 e->in_pin = 1; 00944 if (pad->Point1.X == x && pad->Point1.Y == y) 00945 e->at_pin = 1; 00946 if (pad->Point2.X == x && pad->Point2.Y == y) 00947 e->at_pin = 1; 00948 e->pin = pad; 00949 e->is_pad = 1; 00950 return 1; 00951 } 00952 return 0; 00953 } 00954 00955 static int 00956 find_pair_padline_callback (const BoxType * b, void *cl) 00957 { 00958 LineType *line = (LineType *) b; 00959 PadType *pad = (PadType *) cl; 00960 Extra *e = LINE2EXTRA (line); 00961 int hits; 00962 double t; 00963 int intersect; 00964 double p1_d, p2_d; 00965 00966 if (TEST_FLAG (ONSOLDERFLAG, pad)) 00967 { 00968 if (!current_is_bottom) 00969 return 0; 00970 } 00971 else 00972 { 00973 if (!current_is_top) 00974 return 0; 00975 } 00976 00977 #ifdef CHECK_LINE_PT_NEG 00978 if (line->Point1.X < 0) 00979 abort1(); 00980 #endif 00981 00982 hits = check_point_in_pad (pad, line->Point1.X, line->Point1.Y, &(e->start)); 00983 hits += check_point_in_pad (pad, line->Point2.X, line->Point2.Y, &(e->end)); 00984 00985 if (hits) 00986 return 0; 00987 00988 /* Ok, something strange. The line intersects our space, but 00989 doesn't end in our space. See if it just passes through us, and 00990 mark it anyway. */ 00991 00992 t = (pad->Thickness + 1)/2; 00995 intersect = intersection_of_linesegs (pad->Point1.X, pad->Point1.Y, 00996 pad->Point2.X, pad->Point2.Y, 00997 line->Point1.X, line->Point1.Y, 00998 line->Point2.X, line->Point2.Y, 00999 NULL, NULL); 01000 p1_d = dist_lsp(line->Point1.X, line->Point1.Y, 01001 line->Point2.X, line->Point2.Y, 01002 pad->Point1.X, pad->Point1.Y); 01003 p2_d = dist_lsp(line->Point1.X, line->Point1.Y, 01004 line->Point2.X, line->Point2.Y, 01005 pad->Point2.X, pad->Point2.Y); 01006 01007 if (intersect || p1_d < t || p2_d < t) 01008 { 01009 /* It does. */ 01011 #if TRACE1 01012 pcb_printf("splitting line %#mD-%#mD because it passes through pad %#mD-%#mD r %#mS\n", 01013 line->Point1.X, line->Point1.Y, 01014 line->Point2.X, line->Point2.Y, 01015 pad->Point1.X, pad->Point1.Y, 01016 pad->Point2.X, pad->Point2.Y, 01017 pad->Thickness/2); 01018 #endif 01019 unlink_end (e, &e->start.next); 01020 unlink_end (e, &e->end.next); 01021 } 01022 01023 return 0; 01024 } 01025 01026 static int 01027 find_pair_padarc_callback (const BoxType * b, void *cl) 01028 { 01029 ArcType *arc = (ArcType *) b; 01030 PadType *pad = (PadType *) cl; 01031 Extra *e = ARC2EXTRA (arc); 01032 int hits; 01033 01034 if (TEST_FLAG (ONSOLDERFLAG, pad)) 01035 { 01036 if (!current_is_bottom) 01037 return 0; 01038 } 01039 else 01040 { 01041 if (!current_is_top) 01042 return 0; 01043 } 01044 01045 hits = check_point_in_pad (pad, e->start.x, e->start.y, &(e->start)); 01046 hits += check_point_in_pad (pad, e->end.x, e->end.y, &(e->end)); 01047 return 0; 01048 } 01049 01050 static void 01051 null_multi_next_ends (AnyObjectType *ptr, Extra *extra, void *userdata) 01052 { 01053 if (extra->start.next == &multi_next) 01054 extra->start.next = NULL; 01055 01056 if (extra->end.next == &multi_next) 01057 extra->end.next = NULL; 01058 } 01059 01060 static Extra * 01061 new_line_extra (LineType *line) 01062 { 01063 Extra *extra = g_slice_new0 (Extra); 01064 g_hash_table_insert (lines, line, extra); 01065 extra->parent.line = line; 01066 extra->type = LINE_TYPE; 01067 return extra; 01068 } 01069 01070 static Extra * 01071 new_arc_extra (ArcType *arc) 01072 { 01073 Extra *extra = g_slice_new0 (Extra); 01074 g_hash_table_insert (arcs, arc, extra); 01075 extra->parent.arc = arc; 01076 extra->type = ARC_TYPE; 01077 return extra; 01078 } 01079 01080 static void 01081 find_pairs () 01082 { 01083 ARC_LOOP (CURRENT); { 01084 Extra *e = new_arc_extra (arc); 01085 fix_arc_extra (arc, e); 01086 } END_LOOP; 01087 01088 LINE_LOOP (CURRENT); { 01089 new_line_extra (line); 01090 } END_LOOP; 01091 01092 LINE_LOOP (CURRENT); { 01093 Extra *e = LINE2EXTRA (line); 01094 if (line->Point1.X >= 0) 01095 { 01096 find_pairs_1 (line, & e->start.next, line->Point1.X, line->Point1.Y); 01097 find_pairs_1 (line, & e->end.next, line->Point2.X, line->Point2.Y); 01098 } 01099 } END_LOOP; 01100 01101 ARC_LOOP (CURRENT); { 01102 Extra *e = ARC2EXTRA (arc); 01103 if (!e->deleted) 01104 { 01105 find_pairs_1 (arc, & e->start.next, e->start.x, e->start.y); 01106 find_pairs_1 (arc, & e->end.next, e->end.x, e->end.y); 01107 } 01108 } END_LOOP; 01109 01110 ALLPIN_LOOP (PCB->Data); { 01111 BoxType box; 01112 box.X1 = pin->X - PIN_SIZE(pin)/2; 01113 box.Y1 = pin->Y - PIN_SIZE(pin)/2; 01114 box.X2 = pin->X + PIN_SIZE(pin)/2; 01115 box.Y2 = pin->Y + PIN_SIZE(pin)/2; 01116 r_search (CURRENT->line_tree, &box, NULL, find_pair_pinline_callback, pin); 01117 r_search (CURRENT->arc_tree, &box, NULL, find_pair_pinarc_callback, pin); 01118 } ENDALL_LOOP; 01119 01120 VIA_LOOP (PCB->Data); { 01121 BoxType box; 01122 box.X1 = via->X - PIN_SIZE(via)/2; 01123 box.Y1 = via->Y - PIN_SIZE(via)/2; 01124 box.X2 = via->X + PIN_SIZE(via)/2; 01125 box.Y2 = via->Y + PIN_SIZE(via)/2; 01126 r_search (CURRENT->line_tree, &box, NULL, find_pair_pinline_callback, via); 01127 r_search (CURRENT->arc_tree, &box, NULL, find_pair_pinarc_callback, via); 01128 } END_LOOP; 01129 01130 ALLPAD_LOOP (PCB->Data); { 01131 BoxType box; 01132 box.X1 = MIN(pad->Point1.X, pad->Point2.X) - pad->Thickness/2; 01133 box.Y1 = MIN(pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2; 01134 box.X2 = MAX(pad->Point1.X, pad->Point2.X) + pad->Thickness/2; 01135 box.Y2 = MAX(pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2; 01136 r_search (CURRENT->line_tree, &box, NULL, find_pair_padline_callback, pad); 01137 r_search (CURRENT->arc_tree, &box, NULL, find_pair_padarc_callback, pad); 01138 01139 } ENDALL_LOOP; 01140 01141 g_hash_table_foreach (lines, (GHFunc)null_multi_next_ends, NULL); 01142 g_hash_table_foreach (arcs, (GHFunc)null_multi_next_ends, NULL); 01143 } 01144 01145 #define PROP_NEXT(e,n,f) \ 01146 if (f->next->start.next == e) { \ 01147 e = f->next; \ 01148 n = & e->start; \ 01149 f = & e->end; \ 01150 } else { \ 01151 e = f->next; \ 01152 n = & e->end; \ 01153 f = & e->start; } 01154 01155 static void 01156 propogate_ends_at (Extra *e, End *near, End *far) 01157 { 01158 while (far->in_pin && far->pin == near->pin) 01159 { 01160 far->in_pin = 0; 01161 if (!far->next) 01162 return; 01163 PROP_NEXT (e, near, far); 01164 near->in_pin = 0; 01165 } 01166 } 01167 01168 static void 01169 propogate_end_pin (Extra *e, End *near, End *far) 01170 { 01171 void *pinpad = near->pin; 01172 int ispad = near->is_pad; 01173 while (far->next) 01174 { 01175 PROP_NEXT (e, near, far); 01176 if (near->pin == pinpad) 01177 break; 01178 near->pin = pinpad; 01179 near->is_pad = ispad; 01180 } 01181 } 01182 01183 static void 01184 propogate_end_step1_cb (AnyObjectType *ptr, Extra *extra, void *userdata) 01185 { 01186 if (extra->start.next != NULL && 01187 extra->start.next == extra->end.next) 01188 { 01189 extra->end.next = NULL; 01190 mark_line_for_deletion ((LineType *)ptr); 01191 } 01192 01193 if (extra->start.at_pin) 01194 propogate_ends_at (extra, &extra->start, &extra->end); 01195 01196 if (extra->end.at_pin) 01197 propogate_ends_at (extra, &extra->end, &extra->start); 01198 } 01199 01200 static void 01201 propogate_end_step2_cb (AnyObjectType *ptr, Extra *extra, void *userdata) 01202 { 01203 if (extra->start.in_pin) 01204 { 01205 #if TRACE1 01206 printf("MULTI at %d: was %p\n", __LINE__, extra->start.next); 01207 #endif 01208 extra->start.next = NULL; 01209 } 01210 if (extra->end.in_pin) 01211 { 01212 #if TRACE1 01213 printf("MULTI at %d: was %p\n", __LINE__, extra->end.next); 01214 #endif 01215 extra->end.next = NULL; 01216 } 01217 } 01218 01219 static void 01220 propogate_end_step3_cb (AnyObjectType *ptr, Extra *extra, void *userdata) 01221 { 01222 if (extra->start.next) 01223 propogate_end_pin (extra, &extra->end, &extra->start); 01224 if (extra->end.next) 01225 propogate_end_pin (extra, &extra->start, &extra->end); 01226 } 01227 01228 static void 01229 propogate_ends () 01230 { 01231 /* First, shut of "in pin" when we have an "at pin". We also clean 01232 up zero-length lines. */ 01233 g_hash_table_foreach (lines, (GHFunc)propogate_end_step1_cb, NULL); 01234 01235 /* Now end all paths at pins/pads. */ 01236 g_hash_table_foreach (lines, (GHFunc)propogate_end_step2_cb, NULL); 01237 01238 /* Now, propogate the pin/pad/vias along paths. */ 01239 g_hash_table_foreach (lines, (GHFunc)propogate_end_step3_cb, NULL); 01240 } 01241 01242 static Extra *last_pextra = 0; 01243 01244 static void 01245 print_extra (Extra *e, Extra *prev) 01246 { 01247 int which = 0; 01248 if (e->start.next == last_pextra) 01249 which = 1; 01250 else if (e->end.next == last_pextra) 01251 which = 2; 01252 switch (which) { 01253 case 0: 01254 printf("%10p %10p %10p :", e, e->start.next, e->end.next); 01255 break; 01256 case 1: 01257 printf("%10p \033[33m%10p\033[0m %10p :", e, e->start.next, e->end.next); 01258 break; 01259 case 2: 01260 printf("%10p %10p \033[33m%10p\033[0m :", e, e->start.next, e->end.next); 01261 break; 01262 } 01263 last_pextra = e; 01264 printf(" %c%c", 01265 e->deleted ? 'd' : '-', 01266 e->found ? 'f' : '-'); 01267 printf(" s:%s%s%s%s", 01268 e->start.in_pin ? "I" : "-", 01269 e->start.at_pin ? "A" : "-", 01270 e->start.is_pad ? "P" : "-", 01271 e->start.pending ? "p" : "-"); 01272 printf(" e:%s%s%s%s ", 01273 e->end.in_pin ? "I" : "-", 01274 e->end.at_pin ? "A" : "-", 01275 e->end.is_pad ? "P" : "-", 01276 e->end.pending ? "p" : "-"); 01277 01278 if (EXTRA_IS_LINE (e)) 01279 { 01280 LineType *line = EXTRA2LINE (e); 01281 pcb_printf(" %p L %#mD-%#mD", line, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y); 01282 printf(" %s %p %s %p\n", 01283 e->start.is_pad ? "pad" : "pin", e->start.pin, 01284 e->end.is_pad ? "pad" : "pin", e->end.pin); 01285 } 01286 else if (EXTRA_IS_ARC (e)) 01287 { 01288 ArcType *arc = EXTRA2ARC (e); 01289 pcb_printf(" %p A %#mD-%#mD", arc, e->start.x, e->start.y, e->end.x, e->end.y); 01290 pcb_printf(" at %#mD ang %ld,%ld\n", arc->X, arc->Y, arc->StartAngle, arc->Delta); 01291 } 01292 else if (e == &multi_next) 01293 { 01294 printf("-- Multi-next\n"); 01295 } 01296 else 01297 { 01298 printf("-- Unknown extra: %p\n", e); 01299 } 01300 } 01301 01302 #if TRACE1 01303 static void 01304 trace_path (Extra *e) 01305 { 01306 Extra *prev = 0; 01307 if ((e->start.next && e->end.next) 01308 || (!e->start.next && !e->end.next)) 01309 return; 01310 if (e->found) 01311 return; 01312 printf("- path -\n"); 01313 last_pextra = 0; 01314 while (e) 01315 { 01316 e->found = 1; 01317 print_extra (e, prev); 01318 if (e->start.next == prev) 01319 { 01320 prev = e; 01321 e = e->end.next; 01322 } 01323 else 01324 { 01325 prev = e; 01326 e = e->start.next; 01327 } 01328 } 01329 } 01330 01331 static void 01332 trace_paths () 01333 { 01334 Extra *e; 01335 01336 clear_found (); 01337 LINE_LOOP (CURRENT); { 01338 e = LINE2EXTRA (line); 01339 trace_path (e); 01340 } END_LOOP; 01341 ARC_LOOP (CURRENT); { 01342 e = ARC2EXTRA (arc); 01343 trace_path (e); 01344 } END_LOOP; 01345 } 01346 #endif 01347 01348 static void 01349 reverse_line (LineType *line) 01350 { 01351 Extra *e = LINE2EXTRA (line); 01352 Coord x, y; 01353 End etmp; 01354 01355 x = line->Point1.X; 01356 y = line->Point1.Y; 01357 #if 1 01358 MoveObject (LINEPOINT_TYPE, CURRENT, line, &(line->Point1), 01359 line->Point2.X - line->Point1.X, 01360 line->Point2.Y - line->Point1.Y); 01361 MoveObject (LINEPOINT_TYPE, CURRENT, line, &(line->Point2), 01362 x - line->Point2.X, 01363 y - line->Point2.Y); 01364 #else 01365 /* In theory, we should be using the above so that undo works. */ 01366 line->Point1.X = line->Point2.X; 01367 line->Point1.Y = line->Point2.Y; 01368 line->Point2.X = x; 01369 line->Point2.Y = y; 01370 #endif 01371 memcpy (&etmp, &e->start, sizeof (End)); 01372 memcpy (&e->start, &e->end, sizeof (End)); 01373 memcpy (&e->end, &etmp, sizeof (End)); 01374 } 01375 01376 static void 01377 reverse_arc (ArcType *arc) 01378 { 01379 Extra *e = ARC2EXTRA (arc); 01380 End etmp; 01381 01382 #if 1 01383 ChangeArcAngles (CURRENT, arc, 01384 arc->StartAngle + arc->Delta, -arc->Delta); 01385 #else 01386 /* Likewise, see above. */ 01387 arc->StartAngle += arc->Delta; 01388 arc->Delta *= -1; 01389 #endif 01390 memcpy (&etmp, &e->start, sizeof (End)); 01391 memcpy (&e->start, &e->end, sizeof (End)); 01392 memcpy (&e->end, &etmp, sizeof (End)); 01393 } 01394 01395 static void 01396 expand_box (BoxType *b, Coord x, Coord y, Coord t) 01397 { 01398 b->X1 = MIN (b->X1, x-t); 01399 b->X2 = MAX (b->X2, x+t); 01400 b->Y1 = MIN (b->Y1, y-t); 01401 b->Y2 = MAX (b->Y2, y+t); 01402 } 01403 01404 /* ---------------------------------------------------------------------- */ 01405 /* These are the state variables for the intersection we're currently 01406 working on. */ 01407 01408 /* what we're working with */ 01409 static ArcType *start_arc; 01410 static LineType *start_line; 01411 static LineType *end_line; 01412 static ArcType *end_arc; 01413 static Extra *start_extra, *end_extra; 01414 static Extra *sarc_extra, *earc_extra; 01415 static void *start_pinpad, *end_pinpad; 01416 static Coord thickness; 01417 01418 /* Pre-computed values. Note that all values are computed according 01419 to CARTESIAN coordinates, not PCB coordinates. Do an up-down board 01420 flip before wrapping your brain around the math. */ 01421 01422 /* se_sign is positive when you make a right turn going from start to end. */ 01423 /* sa_sign is positive when start's arc is on the same side of start as end. */ 01424 /* ea_sign is positive when end's arc is on the same side of end as start. */ 01425 /* sa_sign and ea_sign may be zero if there's no arc. */ 01426 static double se_sign, sa_sign, ea_sign; 01427 01428 static double best_angle, start_angle, end_dist; 01429 /* arc radii are positive when they're on the same side as the things 01430 we're interested in. */ 01431 static Coord sa_r, ea_r; 01432 static Coord sa_x, sa_y; /* start "arc" point */ 01433 01434 /* what we've found so far */ 01435 static Coord fx, fy, fr; 01436 static int fp; 01437 static End *fp_end; 01438 static double fa; /* relative angle */ 01439 01440 #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__) 01441 01442 static int 01443 gp_point_force (Coord x, Coord y, Coord t, End *e, int esa, int eda, int force, const char *name) 01444 { 01445 double r, a, d; 01446 Coord scx, scy, sr; 01447 double base_angle, rel_angle, point_angle; 01448 01449 #if TRACE1 01450 pcb_printf("\033[34mgp_point_force %#mD %#mS via %s\033[0m\n", x, y, t, name); 01451 #endif 01452 01453 if (start_arc) 01454 { 01455 scx = start_arc->X; 01456 scy = start_arc->Y; 01457 sr = start_arc->Width; 01458 } 01459 else 01460 { 01461 scx = start_line->Point1.X; 01462 scy = start_line->Point1.Y; 01463 sr = 0; 01464 } 01465 01466 r = t + thickness; 01467 01468 /* See if the point is inside our start arc. */ 01469 d = Distance (scx, scy, x, y); 01470 #if TRACE1 01471 pcb_printf("%f = dist #mD to %#mD\n", d, scx, scy, x, y); 01472 pcb_printf("sr %#mS r %f d %f\n", sr, r, d); 01473 #endif 01474 if (d < sr - r) 01475 { 01476 #if TRACE1 01477 printf("inside start arc, %f < %f\n", d, sr-r); 01478 #endif 01479 return 0; 01480 } 01481 if (sr == 0 && d < r) 01482 { 01483 #if TRACE1 01484 printf("start is inside arc, %f < %f\n", d, r); 01485 #endif 01486 return 0; 01487 } 01488 01489 /* Now for the same tricky math we needed for the single puller. 01490 sr and r are the radii for the two points scx,scy and x,y. */ 01491 01492 /* angle between points (NOT pcb arc angles) */ 01493 base_angle = atan2 (y - scy, x - scx); 01494 #if TRACE1 01495 pcb_printf("%.1f = atan2 (%#mS-%#mS = %#mS, %#mS-%#mS = %#mS)\n", 01496 r2d(base_angle), y, scy, y-scy, x, scx, x-scx); 01497 #endif 01498 01499 if ((sa_sign * sr - r) / d > 1 01500 || (sa_sign * sr - r) / d < -1) 01501 return 0; 01502 01503 /* Angle of tangent, relative to the angle between point centers. */ 01504 rel_angle = se_sign * asin ((sa_sign * sr - r) / d); 01505 #if TRACE1 01506 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n", 01507 r2d(rel_angle), (int)se_sign, (int)sa_sign, sr, r, d); 01508 #endif 01509 01510 /* Absolute angle of tangent. */ 01511 point_angle = base_angle + rel_angle; 01512 #if TRACE1 01513 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n", 01514 r2d(base_angle), 01515 r2d(rel_angle), 01516 r2d(point_angle)); 01517 #endif 01518 01519 if (eda) 01520 { 01521 /* Check arc angles */ 01522 double pa = point_angle; 01523 double sa = d2r(180-esa); 01524 double da = d2r(-eda); 01525 01526 if (da < 0) 01527 { 01528 sa = sa + da; 01529 da = -da; 01530 } 01531 01532 pa -= se_sign * M_PI/2; 01533 while (sa+da < pa) 01534 sa += M_PI*2; 01535 while (sa > pa) 01536 sa -= M_PI*2; 01537 if (sa+da < pa) 01538 { 01539 #if TRACE1 01540 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n", 01541 r2d(sa), r2d(da), r2d(pa)); 01542 #endif 01543 return 0; 01544 } 01545 } 01546 01547 a = point_angle - start_angle; 01548 while (a > M_PI) 01549 a -= M_PI*2; 01550 while (a < -M_PI) 01551 a += M_PI*2; 01552 #if TRACE1 01553 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a)); 01554 #endif 01555 01556 if (!force && a * se_sign < -0.007) 01557 { 01558 double new_r; 01559 #if TRACE1 01560 printf("skipping, would increase angle (%f * %f)\n", a, se_sign); 01561 #endif 01562 new_r = dist_lp (start_line->Point1.X, start_line->Point1.Y, 01563 start_line->Point2.X, start_line->Point2.Y, 01564 x, y); 01565 #if TRACE1 01566 pcb_printf("point %#mD dist %#mS vs thickness %#mS\n", x, y, new_r, thickness); 01567 #endif 01568 new_r -= thickness; 01569 new_r = (int)new_r - 1; 01570 #if TRACE1 01571 pcb_printf(" - new thickness %f old %#mS\n", new_r, t); 01572 #endif 01573 if (new_r < t) 01574 gp_point_force (x, y, new_r, e, esa, eda, 1, __FUNCTION__); 01575 return 0; 01576 } 01577 01578 #if TRACE1 01579 printf("%f * %f < %f * %f ?\n", a, se_sign, best_angle, se_sign); 01580 #endif 01581 if (a * se_sign == best_angle * se_sign) 01582 { 01583 double old_d = Distance (start_line->Point1.X, start_line->Point1.Y, 01584 fx, fy); 01585 double new_d = Distance (start_line->Point1.X, start_line->Point1.Y, 01586 x, y); 01587 if (new_d > old_d) 01588 { 01589 best_angle = a; 01590 fx = x; 01591 fy = y; 01592 fr = r; 01593 fa = a; 01594 fp = e ? e->pending : 0; 01595 fp_end = e; 01596 } 01597 } 01598 else if (a * se_sign < best_angle * se_sign) 01599 { 01600 best_angle = a; 01601 fx = x; 01602 fy = y; 01603 fr = r; 01604 fa = a; 01605 fp = e ? e->pending : 0; 01606 fp_end = e; 01607 } 01608 01609 return 1; 01610 } 01611 static int 01612 gp_point_2 (Coord x, Coord y, Coord t, End *e, int esa, int eda, const char *func) 01613 { 01614 double sc, ec; 01615 double sd, ed; 01616 01617 if (x == sa_x && y ==sa_y) 01618 return 0; 01619 01620 #if TRACE1 01621 pcb_printf("\033[34mgp_point %#mD %#mS via %s\033[0m\n", x, y, t, func); 01622 #endif 01623 01624 /* There are two regions we care about. For points inside our 01625 triangle, we check the crosses against start_line and end_line to 01626 make sure the point is "inside" the triangle. For points on the 01627 other side of the s-e line of the triangle, we check the dots to 01628 make sure it's between our endpoints. */ 01629 01630 /* See what side of the s-e line we're on */ 01631 sc = cross2d (start_line->Point1.X, start_line->Point1.Y, 01632 end_line->Point2.X, end_line->Point2.Y, 01633 x, y); 01634 #if TRACE1 01635 printf("s-e cross = %f\n", sc); 01636 #endif 01637 if (t >= 0) 01638 { 01639 if (same_sign (sc, se_sign)) 01640 { 01641 /* Outside, check dots. */ 01642 01643 /* Ok, is it "in front of" our vectors? */ 01644 sd = dot2d (start_line->Point1.X, start_line->Point1.Y, 01645 end_line->Point2.X, end_line->Point2.Y, 01646 x, y); 01647 #if TRACE1 01648 printf("sd = %f\n", sd); 01649 #endif 01650 if (sd <= 0) 01651 return 0; 01652 01653 ed = dot2d (end_line->Point2.X, end_line->Point2.Y, 01654 start_line->Point1.X, start_line->Point1.Y, 01655 x, y); 01656 #if TRACE1 01657 printf("ed = %f\n", ed); 01658 #endif 01659 if (ed <= 0) 01660 return 0; 01661 01662 sd = dist_lp (start_line->Point1.X, start_line->Point1.Y, 01663 end_line->Point2.X, end_line->Point2.Y, 01664 x, y); 01665 if (sd > t + thickness) 01666 return 0; 01667 } 01668 else 01669 { 01670 /* Inside, check crosses. */ 01671 01672 /* First off, is it on the correct side of the start line? */ 01673 sc = cross2d (start_line->Point1.X, start_line->Point1.Y, 01674 start_line->Point2.X, start_line->Point2.Y, 01675 x, y); 01676 #if TRACE1 01677 printf("sc = %f\n", sc); 01678 #endif 01679 if (! same_sign (sc, se_sign)) 01680 return 0; 01681 01682 /* Ok, is it on the correct side of the end line? */ 01683 ec = cross2d (end_line->Point1.X, end_line->Point1.Y, 01684 end_line->Point2.X, end_line->Point2.Y, 01685 x, y); 01686 #if TRACE1 01687 printf("ec = %f\n", ec); 01688 #endif 01689 if (! same_sign (ec, se_sign)) 01690 return 0; 01691 } 01692 } 01693 01694 #if TRACE1 01695 printf("in range!\n"); 01696 #endif 01697 01698 return gp_point_force (x, y, t, e, esa, eda, 0, func); 01699 } 01700 01701 static int 01702 gp_line_cb (const BoxType *b, void *cb) 01703 { 01704 const LineType *l = (LineType *) b; 01705 Extra *e = LINE2EXTRA(l); 01706 if (l == start_line || l == end_line) 01707 return 0; 01708 if (e->deleted) 01709 return 0; 01710 #ifdef CHECK_LINE_PT_NEG 01711 if (l->Point1.X < 0) 01712 abort1(); 01713 #endif 01714 if (! e->start.next 01715 || ! EXTRA_IS_ARC (e->start.next)) 01716 gp_point (l->Point1.X, l->Point1.Y, l->Thickness/2, &e->start); 01717 if (! e->end.next 01718 || ! EXTRA_IS_ARC (e->end.next)) 01719 gp_point (l->Point2.X, l->Point2.Y, l->Thickness/2, &e->end); 01720 return 0; 01721 } 01722 01723 static int 01724 gp_arc_cb (const BoxType *b, void *cb) 01725 { 01726 const ArcType *a = (ArcType *) b; 01727 Extra *e = ARC2EXTRA(a); 01728 if (a == start_arc || a == end_arc) 01729 return 0; 01730 if (e->deleted) 01731 return 0; 01732 gp_point_2 (a->X, a->Y, a->Width + a->Thickness/2, 0, a->StartAngle, a->Delta, __FUNCTION__); 01733 if (start_arc 01734 && a->X == start_arc->X 01735 && a->Y == start_arc->Y) 01736 return 0; 01737 if (end_arc 01738 && a->X != end_arc->X 01739 && a->Y != end_arc->Y) 01740 return 0; 01741 01742 if (e->start.next || e->end.next) 01743 return 0; 01744 01745 gp_point (e->start.x, e->start.y, a->Thickness/2, 0); 01746 gp_point (e->end.x, e->end.y, a->Thickness/2, 0); 01747 return 0; 01748 } 01749 01750 static int 01751 gp_text_cb (const BoxType *b, void *cb) 01752 { 01753 const TextType *t = (TextType *) b; 01754 /* FIXME: drop in the actual text-line endpoints later. */ 01755 gp_point (t->BoundingBox.X1, t->BoundingBox.Y1, 0, 0); 01756 gp_point (t->BoundingBox.X1, t->BoundingBox.Y2, 0, 0); 01757 gp_point (t->BoundingBox.X2, t->BoundingBox.Y2, 0, 0); 01758 gp_point (t->BoundingBox.X2, t->BoundingBox.Y1, 0, 0); 01759 return 0; 01760 } 01761 01762 static int 01763 gp_poly_cb (const BoxType *b, void *cb) 01764 { 01765 int i; 01766 const PolygonType *p = (PolygonType *) b; 01767 for (i=0; i<p->PointN; i++) 01768 gp_point (p->Points[i].X, p->Points[i].Y, 0, 0); 01769 return 0; 01770 } 01771 01772 static int 01773 gp_pin_cb (const BoxType *b, void *cb) 01774 { 01775 const PinType *p = (PinType *) b; 01776 Coord t2 = (PIN_SIZE(p)+1)/2; 01777 01778 if (p == start_pinpad || p == end_pinpad) 01779 return 0; 01780 01783 if (TEST_FLAG (SQUAREFLAG, p) || TEST_FLAG (OCTAGONFLAG, p)) 01784 { 01785 gp_point (p->X - t2, p->Y - t2, 0, 0); 01786 gp_point (p->X - t2, p->Y + t2, 0, 0); 01787 gp_point (p->X + t2, p->Y + t2, 0, 0); 01788 gp_point (p->X + t2, p->Y - t2, 0, 0); 01789 } 01790 else 01791 { 01792 gp_point (p->X, p->Y, t2, 0); 01793 } 01794 return 0; 01795 } 01796 01797 static int 01798 gp_pad_cb (const BoxType *b, void *cb) 01799 { 01800 const PadType *p = (PadType *) b; 01801 Coord t2 = (p->Thickness+1)/2; 01802 01803 if (p == start_pinpad || p == end_pinpad) 01804 return 0; 01805 01806 if (TEST_FLAG (ONSOLDERFLAG, p)) 01807 { 01808 if (!current_is_bottom) 01809 return 0; 01810 } 01811 else 01812 { 01813 if (!current_is_top) 01814 return 0; 01815 } 01816 01819 if (TEST_FLAG (SQUAREFLAG, p) || TEST_FLAG (OCTAGONFLAG, p)) 01820 { 01821 if (p->Point1.X == p->Point2.X) 01822 { 01823 Coord y1 = MIN (p->Point1.Y, p->Point2.Y) - t2; 01824 Coord y2 = MAX (p->Point1.Y, p->Point2.Y) + t2; 01825 01826 gp_point (p->Point1.X - t2, y1, 0, 0); 01827 gp_point (p->Point1.X - t2, y2, 0, 0); 01828 gp_point (p->Point1.X + t2, y1, 0, 0); 01829 gp_point (p->Point1.X + t2, y2, 0, 0); 01830 } 01831 else 01832 { 01833 Coord x1 = MIN (p->Point1.X, p->Point2.X) - t2; 01834 Coord x2 = MAX (p->Point1.X, p->Point2.X) + t2; 01835 01836 gp_point (x1, p->Point1.Y - t2, 0, 0); 01837 gp_point (x2, p->Point1.Y - t2, 0, 0); 01838 gp_point (x1, p->Point1.Y + t2, 0, 0); 01839 gp_point (x2, p->Point1.Y + t2, 0, 0); 01840 } 01841 } 01842 else 01843 { 01844 gp_point (p->Point1.X, p->Point1.Y, t2, 0); 01845 gp_point (p->Point2.X, p->Point2.Y, t2, 0); 01846 } 01847 return 0; 01848 } 01849 01850 static LineType * 01851 create_line (LineType *sample, Coord x1, Coord y1, Coord x2, Coord y2) 01852 { 01853 #if TRACE1 01854 Extra *e; 01855 pcb_printf("create_line from %#mD to %#mD\n", x1, y1, x2, y2); 01856 #endif 01857 LineType *line = CreateNewLineOnLayer (CURRENT, x1, y1, x2, y2, 01858 sample->Thickness, sample->Clearance, sample->Flags); 01859 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); 01860 01861 #if TRACE1 01862 e = 01863 #endif 01864 new_line_extra (line); 01865 #if TRACE1 01866 printf(" - line extra is %p\n", e); 01867 #endif 01868 return line; 01869 } 01870 01871 static ArcType * 01872 create_arc (LineType *sample, Coord x, Coord y, Coord r, Coord sa, Coord da) 01873 { 01874 Extra *e; 01875 ArcType *arc; 01876 01877 if (r % 100 == 1) 01878 r--; 01879 if (r % 100 == 99) 01880 r++; 01881 #if TRACE1 01882 pcb_printf("create_arc at %#mD r %#mS sa %d delta %d\n", x, y, r, sa, da); 01883 #endif 01884 arc = CreateNewArcOnLayer (CURRENT, x, y, r, r, sa, da, 01885 sample->Thickness, sample->Clearance, sample->Flags); 01886 if (arc == 0) 01887 { 01888 arc = CreateNewArcOnLayer (CURRENT, x, y, r, r, sa, da*2, 01889 sample->Thickness, sample->Clearance, sample->Flags); 01890 } 01891 AddObjectToCreateUndoList (ARC_TYPE, CURRENT, arc, arc); 01892 01893 if (!arc) 01894 longjmp (abort_buf, 1); 01895 01896 e = new_arc_extra (arc); 01897 #if TRACE1 01898 printf(" - arc extra is %p\n", e); 01899 #endif 01900 fix_arc_extra (arc, e); 01901 return arc; 01902 } 01903 01904 static void 01905 unlink_extras (Extra *e) 01906 { 01907 #if TRACE1 01908 fprintf(stderr, "unlink %p\n", e); 01909 print_extra(e,0); 01910 #endif 01911 if (e->start.next) 01912 { 01913 #if TRACE1 01914 print_extra(e->start.next, 0); 01915 #endif 01916 if (e->start.next->start.next == e) 01917 { 01918 #if TRACE1 01919 fprintf(stderr, " - %p->start points to me\n", e->start.next); 01920 #endif 01921 e->start.next->start.next = e->end.next; 01922 } 01923 else if (e->start.next->end.next == e) 01924 { 01925 #if TRACE1 01926 fprintf(stderr, " - %p->end points to me\n", e->start.next); 01927 #endif 01928 e->start.next->end.next = e->end.next; 01929 } 01930 else 01931 { 01932 fprintf(stderr, " - %p doesn't point to me!\n", e->start.next); 01933 abort(); 01934 } 01935 } 01936 if (e->end.next) 01937 { 01938 #if TRACE1 01939 print_extra(e->end.next, 0); 01940 #endif 01941 if (e->end.next->start.next == e) 01942 { 01943 #if TRACE1 01944 fprintf(stderr, " - %p->end points to me\n", e->end.next); 01945 #endif 01946 e->end.next->start.next = e->start.next; 01947 } 01948 else if (e->end.next->end.next == e) 01949 { 01950 #if TRACE1 01951 fprintf(stderr, " - %p->end points to me\n", e->end.next); 01952 #endif 01953 e->end.next->end.next = e->start.next; 01954 } 01955 else 01956 { 01957 fprintf(stderr, " - %p doesn't point to me!\n", e->end.next); 01958 abort(); 01959 } 01960 } 01961 e->start.next = e->end.next = 0; 01962 } 01963 01964 static void 01965 mark_line_for_deletion (LineType *l) 01966 { 01967 Extra *e = LINE2EXTRA(l); 01968 if (e->deleted) 01969 { 01970 fprintf(stderr, "double delete?\n"); 01971 abort(); 01972 } 01973 e->deleted = 1; 01974 unlink_extras (e); 01975 #if TRACE1 01976 pcb_printf("Marked line %p for deletion %#mD to %#mD\n", 01977 e, l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y); 01978 #endif 01979 #if 0 01980 if (l->Point1.X < 0) 01981 { 01982 fprintf(stderr, "double neg move?\n"); 01983 abort(); 01984 } 01985 MoveObject (LINEPOINT_TYPE, CURRENT, l, &(l->Point1), 01986 -1 - l->Point1.X, 01987 -1 - l->Point1.Y); 01988 MoveObject (LINEPOINT_TYPE, CURRENT, l, &(l->Point2), 01989 -1 - l->Point2.X, 01990 -1 - l->Point2.Y); 01991 #endif 01992 } 01993 01994 static void 01995 mark_arc_for_deletion (ArcType *a) 01996 { 01997 Extra *e = ARC2EXTRA(a); 01998 e->deleted = 1; 01999 unlink_extras (e); 02000 #if TRACE1 02001 printf("Marked arc %p for deletion %ld < %ld\n", 02002 e, a->StartAngle, a->Delta); 02003 #endif 02004 } 02005 02024 static void 02025 maybe_pull_1 (LineType *line) 02026 { 02027 BoxType box; 02028 /* Line half-thicknesses, including line space */ 02029 Coord ex, ey; 02030 LineType *new_line; 02031 Extra *new_lextra; 02032 ArcType *new_arc; 02033 Extra *new_aextra; 02034 double abs_angle; 02035 02036 start_line = line; 02037 start_extra = LINE2EXTRA (start_line); 02038 end_extra = start_extra->end.next; 02039 end_line = EXTRA2LINE (end_extra); 02040 if (end_extra->deleted) 02041 { 02042 start_extra->end.pending = 0; 02043 return; 02044 } 02045 02046 if (end_extra->end.next == start_extra) 02047 reverse_line (end_line); 02048 02049 if (start_extra->start.next 02050 && EXTRA_IS_ARC (start_extra->start.next)) 02051 { 02052 sarc_extra = start_extra->start.next; 02053 start_arc = EXTRA2ARC (sarc_extra); 02054 if (sarc_extra->start.next == start_extra) 02055 reverse_arc (start_arc); 02056 } 02057 else 02058 { 02059 start_arc = 0; 02060 sarc_extra = 0; 02061 } 02062 02063 if (end_extra->end.next 02064 && EXTRA_IS_ARC (end_extra->end.next)) 02065 { 02066 earc_extra = end_extra->end.next; 02067 end_arc = EXTRA2ARC (earc_extra); 02068 if (earc_extra->start.next == end_extra) 02069 reverse_arc (end_arc); 02070 } 02071 else 02072 { 02073 end_arc = 0; 02074 earc_extra = 0; 02075 } 02076 02077 #if TRACE1 02078 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra, start_extra, end_extra, earc_extra); 02079 if (sarc_extra) 02080 print_extra(sarc_extra,0); 02081 print_extra(start_extra,0); 02082 print_extra(end_extra,0); 02083 if (earc_extra) 02084 print_extra(earc_extra,0); 02085 02086 if (start_extra->deleted 02087 || end_extra->deleted 02088 || (sarc_extra && sarc_extra->deleted) 02089 || (earc_extra && earc_extra->deleted)) 02090 { 02091 printf(" one is deleted?\n"); 02092 fflush(stdout); 02093 abort(); 02094 } 02095 #endif 02096 02097 if (!start_extra->end.pending) 02098 return; 02099 #if 0 02100 if (start_extra->end.waiting_for 02101 && start_extra->end.waiting_for->pending) 02102 return; 02103 #endif 02104 02105 if (start_line->Thickness != end_line->Thickness) 02106 return; 02107 thickness = (start_line->Thickness + 1)/2 + PCB->Bloat; 02108 02109 /* At this point, our expectations are all met. */ 02110 02111 box.X1 = start_line->Point1.X - thickness; 02112 box.X2 = start_line->Point1.X + thickness; 02113 box.Y1 = start_line->Point1.Y - thickness; 02114 box.Y2 = start_line->Point1.Y + thickness; 02115 expand_box (&box, start_line->Point2.X, start_line->Point2.Y, thickness); 02116 expand_box (&box, end_line->Point2.X, end_line->Point2.Y, thickness); 02117 if (start_arc) 02118 expand_box (&box, sarc_extra->start.x, sarc_extra->start.y, start_arc->Thickness/2); 02119 if (end_arc) 02120 expand_box (&box, earc_extra->start.x, earc_extra->start.y, end_arc->Thickness/2); 02121 02122 02123 se_sign = copysign (1, cross2d (start_line->Point1.X, start_line->Point1.Y, 02124 start_line->Point2.X, start_line->Point2.Y, 02125 end_line->Point2.X, end_line->Point2.Y)); 02126 best_angle = se_sign * M_PI; 02127 if (start_arc) 02128 { 02129 sa_sign = copysign (1, -start_arc->Delta); 02130 sa_sign *= se_sign; 02131 } 02132 else 02133 sa_sign = 0; 02134 if (end_arc) 02135 { 02136 ea_sign = copysign (1, -end_arc->Delta); 02137 ea_sign *= -se_sign; 02138 } 02139 else 02140 ea_sign = 0; 02141 02142 start_angle = atan2 (start_line->Point2.Y - start_line->Point1.Y, 02143 start_line->Point2.X - start_line->Point1.X); 02144 #if TRACE1 02145 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n", 02146 se_sign, sa_sign, ea_sign, r2d (best_angle), r2d(start_angle)); 02147 #endif 02148 02149 if (start_arc) 02150 { 02151 sa_x = start_arc->X; 02152 sa_y = start_arc->Y; 02153 if (same_sign (start_arc->Delta, se_sign)) 02154 sa_r = - start_arc->Width; 02155 else 02156 sa_r = start_arc->Width; 02157 } 02158 else 02159 { 02160 sa_x = start_line->Point1.X; 02161 sa_y = start_line->Point1.Y; 02162 sa_r = 0; 02163 } 02164 02165 if (end_arc) 02166 { 02167 if (ea_sign < 0) 02168 ea_r = end_arc->Width; 02169 else 02170 ea_r = - end_arc->Width; 02171 } 02172 else 02173 ea_r = 0; 02174 02175 #if TRACE1 02176 trace_path (sarc_extra ? sarc_extra : start_extra); 02177 #endif 02178 02179 if (end_arc) 02180 { 02181 gp_point_force (end_arc->X, end_arc->Y, -ea_r-thickness, 0, 0, 0, 1, "end arc"); 02182 ex = end_arc->X; 02183 ey = end_arc->Y; 02184 } 02185 else 02186 { 02187 gp_point_force (end_line->Point2.X, end_line->Point2.Y, -thickness, 0, 0, 0, 1, "end arc"); 02188 ex = end_line->Point2.X; 02189 ey = end_line->Point2.Y; 02190 } 02191 02192 fx = ex; 02193 fy = ey; 02194 if (fx < 0) 02195 { 02196 pcb_fprintf(stderr, "end line corrupt? f is %#mD\n", fx, fy); 02197 print_extra (end_extra, 0); 02198 if (earc_extra) 02199 print_extra(earc_extra, 0); 02200 abort(); 02201 } 02202 02203 end_dist = Distance (end_line->Point1.X, end_line->Point1.Y, 02204 end_line->Point2.X, end_line->Point2.Y); 02205 02206 start_pinpad = start_extra->start.pin; 02207 end_pinpad = start_extra->end.pin; 02208 fp = 0; 02209 02210 r_search(CURRENT->line_tree, &box, NULL, gp_line_cb, 0); 02211 r_search(CURRENT->arc_tree, &box, NULL, gp_arc_cb, 0); 02212 r_search(CURRENT->text_tree, &box, NULL, gp_text_cb, 0); 02213 r_search(CURRENT->polygon_tree, &box, NULL, gp_poly_cb, 0); 02214 r_search(PCB->Data->pin_tree, &box, NULL, gp_pin_cb, 0); 02215 r_search(PCB->Data->via_tree, &box, NULL, gp_pin_cb, 0); 02216 r_search(PCB->Data->pad_tree, &box, NULL, gp_pad_cb, 0); 02217 02218 /* radians, absolute angle of (at the moment) the start_line */ 02219 abs_angle = fa + start_angle; 02220 02221 #if TRACE1 02222 pcb_printf("\033[43;30mBest: at %#mD r %#mS, angle %.1f fp %d\033[0m\n", fx, fy, fr, r2d(fa), fp); 02223 #endif 02224 02225 #if 0 02226 if (fa > M_PI/2 || fa < -M_PI/2) 02227 { 02228 SET_FLAG (FOUNDFLAG, line); 02229 longjmp (abort_buf, 1); 02230 } 02231 #endif 02232 02233 if (fp) 02234 { 02235 start_extra->end.waiting_for = fp_end; 02236 return; 02237 } 02238 start_extra->end.pending = 0; 02239 02240 /* Step 0: check for merged arcs (special case). */ 02241 02242 if (fx == ex && fy == ey 02243 && start_arc && end_arc 02244 && start_arc->X == end_arc->X && start_arc->Y == end_arc->Y) 02245 { 02246 /* Merge arcs */ 02247 int new_delta; 02248 02249 new_delta = end_arc->StartAngle - start_arc->StartAngle; 02250 if (start_arc->Delta > 0) 02251 { 02252 while (new_delta > 360) 02253 new_delta -= 360; 02254 while (new_delta < 0) 02255 new_delta += 360; 02256 } 02257 else 02258 { 02259 while (new_delta < -360) 02260 new_delta += 360; 02261 while (new_delta > 0) 02262 new_delta -= 360; 02263 } 02264 #if TRACE1 02265 pcb_printf("merging arcs at %#mS nd %d\n", start_arc->X, start_arc->Y, new_delta); 02266 print_extra(sarc_extra, 0); 02267 print_extra(earc_extra, 0); 02268 #endif 02269 mark_arc_for_deletion (end_arc); 02270 mark_line_for_deletion (start_line); 02271 mark_line_for_deletion (end_line); 02272 ChangeArcAngles (CURRENT, start_arc, start_arc->StartAngle, new_delta); 02273 fix_arc_extra (start_arc, sarc_extra); 02274 did_something ++; 02275 return; 02276 } 02277 02278 /* Step 1: adjust start_arc's angles and move start_line's Point1 to 02279 match it. */ 02280 02281 if (start_arc) 02282 { 02283 double new_delta; 02284 int del_arc = 0; 02285 02286 /* We must always round towards "larger arcs", whichever way that is. */ 02287 new_delta = 180 - r2d(abs_angle); 02288 #if TRACE1 02289 printf("new_delta starts at %d vs %d < %d\n", 02290 (int)new_delta, (int)start_arc->StartAngle, (int)start_arc->Delta); 02291 #endif 02292 if (start_arc->Delta < 0) 02293 new_delta = (int)(new_delta) + 90; 02294 else 02295 new_delta = (int)new_delta - 90; 02296 new_delta = new_delta - start_arc->StartAngle; 02297 while (new_delta > start_arc->Delta+180) 02298 new_delta -= 360; 02299 while (new_delta < start_arc->Delta-180) 02300 new_delta += 360; 02301 #if TRACE1 02302 printf("new_delta adjusts to %d\n", (int)new_delta); 02303 printf("fa = %f, new_delta ends at %.1f vs start %d\n", 02304 fa, new_delta, (int)start_arc->StartAngle); 02305 #endif 02306 02307 if (new_delta * start_arc->Delta <= 0) 02308 del_arc = 1; 02309 02310 ChangeArcAngles (CURRENT, start_arc, start_arc->StartAngle, new_delta); 02311 fix_arc_extra (start_arc, sarc_extra); 02312 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point1), 02313 sarc_extra->end.x - start_line->Point1.X, 02314 sarc_extra->end.y - start_line->Point1.Y); 02315 02316 if (del_arc) 02317 { 02318 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point1), 02319 sarc_extra->start.x - start_line->Point1.X, 02320 sarc_extra->start.y - start_line->Point1.Y); 02321 mark_arc_for_deletion (start_arc); 02322 } 02323 } 02324 02325 /* Step 1.5: If the "obstacle" is right at the end, ignore it. */ 02326 02327 { 02328 double oa = start_angle+fa - M_PI/2*se_sign; 02329 double ox = fx + fr * cos(oa); 02330 double oy = fy + fr * sin(oa); 02331 #if TRACE1 02332 pcb_printf("obstacle at %#mD angle %d = arc starts at %#mD\n", 02333 fx, fy, (int)r2d(oa), (Coord)ox, (Coord)oy); 02334 #endif 02335 02336 if (Distance (ox, oy, end_line->Point2.X, end_line->Point2.Y) 02337 < fr * SIN1D) 02338 { 02339 /* Pretend it doesn't exist. */ 02340 fx = ex; 02341 fy = ey; 02342 } 02343 } 02344 02345 /* Step 2: If we have no obstacles, connect start and end. */ 02346 02347 #if TRACE1 02348 pcb_printf("fx %#mS ex %#mS fy %#mS ey %#mS\n", fx, ex, fy, ey); 02349 #endif 02350 if (fx == ex && fy == ey) 02351 { 02352 /* No obstacles. */ 02353 #if TRACE1 02354 printf("\033[32mno obstacles\033[0m\n"); 02355 #endif 02356 if (end_arc) 02357 { 02358 int del_arc = 0; 02359 int new_delta, end_angle, pcb_fa, end_change; 02360 02361 end_angle = end_arc->StartAngle + end_arc->Delta; 02362 if (end_arc->Delta < 0) 02363 end_angle -= 90; 02364 else 02365 end_angle += 90; 02366 02367 /* We must round so as to make the larger arc. */ 02368 if (end_arc->Delta < 0) 02369 pcb_fa = - r2d(start_angle + fa); 02370 else 02371 pcb_fa = 1 - r2d(start_angle + fa); 02372 end_change = pcb_fa - end_angle; 02373 02374 while (end_change > 180) 02375 end_change -= 360; 02376 while (end_change < -180) 02377 end_change += 360; 02378 new_delta = end_arc->Delta + end_change; 02379 02380 if (new_delta * end_arc->Delta <= 0) 02381 del_arc = 1; 02382 02383 ChangeArcAngles (CURRENT, end_arc, end_arc->StartAngle, new_delta); 02384 fix_arc_extra (end_arc, earc_extra); 02385 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), 02386 earc_extra->end.x - start_line->Point2.X, 02387 earc_extra->end.y - start_line->Point2.Y); 02388 02389 if (del_arc) 02390 { 02391 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), 02392 earc_extra->start.x - start_line->Point2.X, 02393 earc_extra->start.y - start_line->Point2.Y); 02394 mark_arc_for_deletion (end_arc); 02395 } 02396 } 02397 else 02398 { 02399 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), 02400 end_line->Point2.X - start_line->Point2.X, 02401 end_line->Point2.Y - start_line->Point2.Y); 02402 } 02403 mark_line_for_deletion (end_line); 02404 start_extra->end.pending = 1; 02405 02406 #if TRACE1 02407 printf("\033[35mdid_something: no obstacles\033[0m\n"); 02408 #endif 02409 did_something ++; 02410 npulled ++; 02411 status(); 02412 return; 02413 } 02414 02415 /* Step 3: Compute the new intersection of start_line and end_line. */ 02416 02417 ex = start_line->Point1.X + cos(start_angle + fa) * 10000.0; 02418 ey = start_line->Point1.Y + sin(start_angle + fa) * 10000.0; 02419 #if TRACE1 02420 pcb_printf("temp point %#mS\n", ex, ey); 02421 pcb_printf("intersect %#mS-%#mS with %#mS-%#mS\n", 02422 start_line->Point1.X, start_line->Point1.Y, 02423 ex, ey, 02424 end_line->Point1.X, end_line->Point1.Y, 02425 end_line->Point2.X, end_line->Point2.Y); 02426 #endif 02427 if (! intersection_of_lines (start_line->Point1.X, start_line->Point1.Y, 02428 ex, ey, 02429 end_line->Point1.X, end_line->Point1.Y, 02430 end_line->Point2.X, end_line->Point2.Y, 02431 &ex, &ey)) 02432 { 02433 ex = end_line->Point2.X; 02434 ey = end_line->Point2.Y; 02435 } 02436 #if TRACE1 02437 pcb_printf("new point %#mS\n", ex, ey); 02438 #endif 02439 MoveObject (LINEPOINT_TYPE, CURRENT, end_line, &(end_line->Point1), 02440 ex - end_line->Point1.X, 02441 ey - end_line->Point1.Y); 02442 02443 /* Step 4: Split start_line at the obstacle and insert a zero-delta 02444 arc at it. */ 02445 02446 new_arc = create_arc (start_line, fx, fy, fr, 02447 90-(int)(r2d(start_angle+fa)+0.5) + 90 + 90*se_sign, -se_sign); 02448 new_aextra = ARC2EXTRA (new_arc); 02449 02450 if (start_arc) sarc_extra = ARC2EXTRA (start_arc); 02451 if (end_arc) earc_extra = ARC2EXTRA (end_arc); 02452 02453 MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), 02454 new_aextra->start.x - start_line->Point2.X, 02455 new_aextra->start.y - start_line->Point2.Y); 02456 02457 new_line = create_line (start_line, new_aextra->end.x, new_aextra->end.y, ex, ey); 02458 start_extra = LINE2EXTRA (start_line); 02459 new_lextra = LINE2EXTRA (new_line); 02460 end_extra = LINE2EXTRA (end_line); 02461 02462 new_lextra->start.pin = start_extra->start.pin; 02463 new_lextra->end.pin = start_extra->end.pin; 02464 new_lextra->start.pending = 1; 02465 new_lextra->end.pending = 1; 02466 02467 start_extra->end.next = new_aextra; 02468 new_aextra->start.next = start_extra; 02469 new_aextra->end.next = new_lextra; 02470 new_lextra->start.next = new_aextra; 02471 new_lextra->end.next = end_extra; 02472 end_extra->start.next = new_lextra; 02473 02474 /* Step 5: Recurse. */ 02475 02476 did_something ++; 02477 npulled ++; 02478 status(); 02479 #if TRACE0 02480 printf("\033[35mdid_something: recursing\033[0m\n"); 02481 { 02482 int i = gui->confirm_dialog("recurse?", 0); 02483 printf("confirm = %d\n", i); 02484 if (i == 0) 02485 return; 02486 } 02487 printf("\n\033[33mRECURSING\033[0m\n\n"); 02488 IncrementUndoSerialNumber(); 02489 #endif 02490 maybe_pull_1 (new_line); 02491 } 02492 02496 static void 02497 maybe_pull (LineType *line, Extra *e) 02498 { 02499 #if TRACE0 02500 printf("maybe_pull: "); 02501 print_extra (e, 0); 02502 #endif 02503 if (e->end.next && EXTRA_IS_LINE (e->end.next)) 02504 { 02505 maybe_pull_1 (line); 02506 } 02507 else 02508 { 02509 e->end.pending = 0; 02510 if (e->start.next && EXTRA_IS_LINE (e->start.next)) 02511 { 02512 reverse_line (line); 02513 maybe_pull_1 (line); 02514 } 02515 else 02516 e->start.pending = 0; 02517 } 02518 } 02519 02520 static void 02521 validate_pair (Extra *e, End *end) 02522 { 02523 if (!end->next) 02524 return; 02525 if (end->next->start.next == e) 02526 return; 02527 if (end->next->end.next == e) 02528 return; 02529 fprintf(stderr, "no backlink!\n"); 02530 print_extra (e, 0); 02531 print_extra (end->next, 0); 02532 abort(); 02533 } 02534 02535 static void 02536 validate_pair_cb (AnyObjectType *ptr, Extra *extra, void *userdata) 02537 { 02538 validate_pair (extra, &extra->start); 02539 validate_pair (extra, &extra->end); 02540 } 02541 02542 static void 02543 validate_pairs () 02544 { 02545 g_hash_table_foreach (lines, (GHFunc)validate_pair_cb, NULL); 02546 #if TRACE1 02547 printf("\narcs\n"); 02548 #endif 02549 g_hash_table_foreach (arcs, (GHFunc)validate_pair_cb, NULL); 02550 } 02551 02552 static void 02553 FreeExtra (Extra *extra) 02554 { 02555 g_slice_free (Extra, extra); 02556 } 02557 02558 static void 02559 mark_ends_pending (LineType *line, Extra *extra, void *userdata) 02560 { 02561 int *select_flags = userdata; 02562 if (TEST_FLAGS (*select_flags, line)) 02563 { 02564 extra->start.pending = 1; 02565 extra->end.pending = 1; 02566 } 02567 } 02568 02569 #if TRACE1 02570 static void 02571 trace_print_extra (AnyObjectType *ptr, Extra *extra, void *userdata) 02572 { 02573 last_pextra = (Extra *)1; 02574 print_extra(extra, 0); 02575 } 02576 02577 static void 02578 trace_print_lines_arcs (void) 02579 { 02580 printf("\nlines\n"); 02581 g_hash_table_foreach (lines, (GHFunc)trace_print_extra, NULL); 02582 02583 printf("\narcs\n"); 02584 g_hash_table_foreach (arcs, (GHFunc)trace_print_extra, NULL); 02585 02586 printf("\n"); 02587 } 02588 #endif 02589 02590 static int 02591 GlobalPuller(int argc, char **argv, Coord x, Coord y) 02592 { 02593 int select_flags = 0; 02594 02595 setbuf(stdout, 0); 02596 nloops = 0; 02597 npulled = 0; 02598 Message ("puller! %s\n", argc > 0 ? argv[0] : ""); 02599 02600 if (argc > 0 && strcasecmp (argv[0], "selected") == 0) 02601 select_flags = SELECTEDFLAG; 02602 if (argc > 0 && strcasecmp (argv[0], "found") == 0) 02603 select_flags = FOUNDFLAG; 02604 02605 Message ("optimizing...\n"); 02606 /* This canonicalizes all the lines, and cleans up near-misses. */ 02607 /* hid_actionl ("djopt", "puller", 0); */ 02608 02609 current_is_bottom = (GetLayerGroupNumberByPointer(CURRENT) 02610 == GetLayerGroupNumberBySide (BOTTOM_SIDE)); 02611 current_is_top = (GetLayerGroupNumberByPointer(CURRENT) 02612 == GetLayerGroupNumberBySide (TOP_SIDE)); 02613 02614 lines = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)FreeExtra); 02615 arcs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)FreeExtra); 02616 02617 Message ("pairing...\n"); 02618 find_pairs (); 02619 validate_pairs (); 02620 02621 g_hash_table_foreach (lines, (GHFunc)mark_ends_pending, &select_flags); 02622 02623 #if TRACE1 02624 trace_print_lines_arcs (); 02625 #endif 02626 02627 propogate_ends (); 02628 02629 #if TRACE1 02630 trace_print_lines_arcs (); 02631 trace_paths (); 02632 #endif 02633 02634 Message ("pulling...\n"); 02635 if (setjmp(abort_buf) == 0) 02636 { 02637 #if TRACE0 02638 int old_did_something = -1; 02639 #endif 02640 did_something = 1; 02641 while (did_something) 02642 { 02643 nloops ++; 02644 status(); 02645 did_something = 0; 02646 LINE_LOOP (CURRENT); { 02647 Extra *e = LINE2EXTRA (line); 02648 if (e->deleted) 02649 continue; 02650 #ifdef CHECK_LINE_PT_NEG 02651 if (line->Point1.X < 0) 02652 abort1(); 02653 #endif 02654 if (e->start.next || e->end.next) 02655 maybe_pull (line, e); 02656 #if TRACE0 02657 if (did_something != old_did_something) 02658 { 02659 IncrementUndoSerialNumber(); 02660 old_did_something = did_something; 02661 if (gui->confirm_dialog("more?", 0) == 0) 02662 { 02663 did_something = 0; 02664 break; 02665 } 02666 } 02667 #endif 02668 /*gui->progress(0,0,0);*/ 02669 } END_LOOP; 02670 } 02671 } 02672 02673 #if TRACE0 02674 printf("\nlines\n"); 02675 g_hash_table_foreach (lines, (GHFunc)trace_print_extra, NULL); 02676 printf("\narcs\n"); 02677 g_hash_table_foreach (arcs, (GHFunc)trace_print_extra, NULL); 02678 printf("\n"); 02679 printf("\nlines\n"); 02680 #endif 02681 02682 LINE_LOOP (CURRENT); 02683 { 02684 if (LINE2EXTRA (line)->deleted) 02685 RemoveLine (CURRENT, line); 02686 } 02687 END_LOOP; 02688 02689 ARC_LOOP (CURRENT); 02690 { 02691 if (ARC2EXTRA (arc)->deleted) 02692 RemoveArc (CURRENT, arc); 02693 } 02694 END_LOOP; 02695 02696 g_hash_table_unref (lines); 02697 g_hash_table_unref (arcs); 02698 02699 IncrementUndoSerialNumber(); 02700 return 0; 02701 } 02702 02703 /* Actions */ 02704 02705 HID_Action puller_action_list[] = { 02706 {"Puller", "Click on a line-arc intersection or line segment", Puller, 02707 puller_help, puller_syntax}, 02708 {"GlobalPuller", 0, GlobalPuller, 02709 globalpuller_help, globalpuller_syntax} 02710 }; 02711 02712 REGISTER_ACTIONS (puller_action_list)