pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00033 #ifdef HAVE_CONFIG_H 00034 #include "config.h" 00035 #endif 00036 00037 #include "global.h" 00038 00039 #include <memory.h> 00040 #include <limits.h> 00041 00042 00043 #include "data.h" 00044 #include "create.h" 00045 #include "remove.h" 00046 #include "move.h" 00047 #include "draw.h" 00048 #include "undo.h" 00049 #include "strflags.h" 00050 #include "find.h" 00051 #include "pcb-printf.h" 00052 00053 #ifdef HAVE_LIBDMALLOC 00054 #include <dmalloc.h> 00055 #endif 00056 00057 #ifndef HAVE_RINT 00058 #define rint(x) (ceil((x) - 0.5)) 00059 #endif 00060 00061 #define dprintf if(0)pcb_printf 00062 00063 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x)) 00064 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x)) 00065 00066 #define SB (PCB->Bloat+1) 00067 00068 /* must be 2^N-1 */ 00069 #define INC 7 00070 00071 #define O_HORIZ 0x10 00072 #define O_VERT 0x20 00073 #define LEFT 0x11 00074 #define RIGHT 0x12 00075 #define UP 0x24 00076 #define DOWN 0x28 00077 #define DIAGONAL 0xf0 00078 #define ORIENT(x) ((x) & 0xf0) 00079 #define DIRECT(x) ((x) & 0x0f) 00080 00081 #define LONGEST_FRECKLE 2 00084 struct line_s; 00085 00086 typedef struct corner_s 00087 { 00088 int layer; 00089 struct corner_s *next; 00090 int x, y; 00091 int net; 00092 PinType *via; 00093 PadType *pad; 00094 PinType *pin; 00095 int miter; 00096 int n_lines; 00097 struct line_s **lines; 00098 } corner_s; 00099 00100 typedef struct line_s 00101 { 00102 int layer; 00103 struct line_s *next; 00104 corner_s *s, *e; 00105 LineType *line; 00106 char is_pad; 00107 } line_s; 00108 00109 typedef struct rect_s 00110 { 00111 int x1, y1, x2, y2; 00112 } rect_s; 00113 00114 #define DELETE(q) (q)->layer = 0xdeadbeef 00115 #define DELETED(q) ((q)->layer == 0xdeadbeef) 00116 00117 static corner_s *corners, *next_corner = 0; 00118 static line_s *lines; 00119 00120 static int layer_groupings[MAX_LAYER]; 00121 static char layer_type[MAX_LAYER]; 00122 #define LT_TOP 1 00123 #define LT_BOTTOM 2 00124 00125 static int autorouted_only = 1; 00126 00127 static const char djopt_sao_syntax[] = "OptAutoOnly()"; 00128 00129 static const char djopt_sao_help[] = 00130 "Toggles the optimize-only-autorouted flag."; 00131 00132 /* %start-doc actions OptAutoOnly 00133 00134 The original purpose of the trace optimizer was to clean up the traces 00135 created by the various autorouters that have been used with PCB. When 00136 a board has a mix of autorouted and carefully hand-routed traces, you 00137 don't normally want the optimizer to move your hand-routed traces. 00138 But, sometimes you do. By default, the optimizer only optimizes 00139 autorouted traces. This action toggles that setting, so that you can 00140 optimize hand-routed traces also. 00141 00142 %end-doc */ 00143 00144 int 00145 djopt_set_auto_only (int argc, char **argv, Coord x, Coord y) 00146 { 00147 autorouted_only = autorouted_only ? 0 : 1; 00148 return 0; 00149 } 00150 00151 static int 00152 djopt_get_auto_only (void *data) 00153 { 00154 return autorouted_only; 00155 } 00156 00157 HID_Flag djopt_flag_list[] = { 00158 {"optautoonly", djopt_get_auto_only, NULL} 00159 }; 00160 00161 REGISTER_FLAGS (djopt_flag_list) 00162 00163 static char * 00164 element_name_for (corner_s * c) 00165 { 00166 ELEMENT_LOOP (PCB->Data); 00167 { 00168 PIN_LOOP (element); 00169 { 00170 if (pin == c->pin) 00171 return element->Name[1].TextString; 00172 } 00173 END_LOOP; 00174 PAD_LOOP (element); 00175 { 00176 if (pad == c->pad) 00177 return element->Name[1].TextString; 00178 } 00179 END_LOOP; 00180 } 00181 END_LOOP; 00182 return "unknown"; 00183 } 00184 00185 static char * 00186 corner_name (corner_s * c) 00187 { 00188 static char buf[4][100]; 00189 static int bn = 0; 00190 char *bp; 00191 size_t size_left; 00192 bn = (bn + 1) % 4; 00193 00194 if (c->net == 0xf1eef1ee) 00195 { 00196 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c); 00197 return buf[bn]; 00198 } 00199 00200 sprintf (buf[bn], "\033[%dm[%p ", 00201 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c); 00202 bp = buf[bn] + strlen (buf[bn]); 00203 size_left = sizeof (buf[bn]) - strlen (buf[bn]); 00204 00205 if (c->pin) 00206 pcb_snprintf (bp, size_left, "pin %s:%s at %#mD", 00207 element_name_for (c), c->pin->Number, c->x, c->y); 00208 else if (c->via) 00209 pcb_snprintf (bp, size_left, "via at %#mD", c->x, c->y); 00210 else if (c->pad) 00211 { 00212 pcb_snprintf (bp, size_left, "pad %s:%s at %#mD %#mD-%#mD", 00213 element_name_for (c), c->pad->Number, c->x, c->y, 00214 c->pad->Point1.X, c->pad->Point1.Y, 00215 c->pad->Point2.X, c->pad->Point2.Y); 00216 } 00217 else 00218 pcb_snprintf (bp, size_left, "at %#mD", c->x, c->y); 00219 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer); 00220 return buf[bn]; 00221 } 00222 00223 static int solder_layer, component_layer; 00224 00225 static void 00226 dj_abort (char *msg, ...) 00227 { 00228 va_list a; 00229 va_start (a, msg); 00230 vprintf (msg, a); 00231 va_end (a); 00232 fflush (stdout); 00233 abort (); 00234 } 00235 00236 #if 1 00237 #define check(c,l) 00238 #else 00239 #define check(c,l) check2(__LINE__,c,l) 00240 static void 00241 check2 (int srcline, corner_s * c, line_s * l) 00242 { 00243 int saw_c = 0, saw_l = 0; 00244 corner_s *cc; 00245 line_s *ll; 00246 int i; 00247 00248 for (cc = corners; cc; cc = cc->next) 00249 { 00250 if (DELETED (cc)) 00251 continue; 00252 if (cc == c) 00253 saw_c = 1; 00254 for (i = 0; i < cc->n_lines; i++) 00255 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc) 00256 dj_abort ("check:%d: cc has line without backref\n", srcline); 00257 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y)) 00258 dj_abort ("check:%d: via not at corner\n", srcline); 00259 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y)) 00260 dj_abort ("check:%d: pin not at corner\n", srcline); 00261 } 00262 if (c && !saw_c) 00263 dj_abort ("check:%d: corner not in corners list\n", srcline); 00264 for (ll = lines; ll; ll = ll->next) 00265 { 00266 if (DELETED (ll)) 00267 continue; 00268 if (ll == l) 00269 saw_l = 1; 00270 for (i = 0; i < ll->s->n_lines; i++) 00271 if (ll->s->lines[i] == ll) 00272 break; 00273 if (i == ll->s->n_lines) 00274 dj_abort ("check:%d: ll->s has no backref\n", srcline); 00275 for (i = 0; i < ll->e->n_lines; i++) 00276 if (ll->e->lines[i] == ll) 00277 break; 00278 if (i == ll->e->n_lines) 00279 dj_abort ("check:%d: ll->e has no backref\n", srcline); 00280 if (!ll->is_pad 00281 && (ll->s->x != ll->line->Point1.X 00282 || ll->s->y != ll->line->Point1.Y 00283 || ll->e->x != ll->line->Point2.X 00284 || ll->e->y != ll->line->Point2.Y)) 00285 { 00286 pcb_printf ("line: %#mD to %#mD pcbline: %#mD to %#mD\n", 00287 ll->s->x, ll->s->y, 00288 ll->e->x, ll->e->y, 00289 ll->line->Point1.X, 00290 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y); 00291 dj_abort ("check:%d: line doesn't match pcbline\n", srcline); 00292 } 00293 } 00294 if (l && !saw_l) 00295 dj_abort ("check:%d: line not in lines list\n", srcline); 00296 } 00297 00298 #endif 00299 00300 #define SWAP(a,b) { a^=b; b^=a; a^=b; } 00301 00302 static int 00303 gridsnap (Coord n) 00304 { 00305 if (n <= 0) 00306 return 0; 00307 return n - n % (Settings.Grid); 00308 } 00309 00310 /* Avoid commonly used names. */ 00311 00312 static int 00313 djabs (int x) 00314 { 00315 return x > 0 ? x : -x; 00316 } 00317 00318 static int 00319 djmax (int x, int y) 00320 { 00321 return x > y ? x : y; 00322 } 00323 00324 static int 00325 djmin (int x, int y) 00326 { 00327 return x < y ? x : y; 00328 } 00329 00337 static int 00338 dist (int x1, int y1, int x2, int y2) 00339 { 00340 double d; 00341 00342 d = hypot ((double) x1 - (double) x2, (double) y1 - (double) y2); 00343 d = rint (d); 00344 00345 return (int) d; 00346 } 00347 00348 static int 00349 line_length (line_s * l) 00350 { 00351 if (l->s->x == l->e->x) 00352 return djabs (l->s->y - l->e->y); 00353 if (l->s->y == l->e->y) 00354 return djabs (l->s->x - l->e->x); 00355 return dist (l->s->x, l->s->y, l->e->x, l->e->y); 00356 } 00357 00358 static int 00359 dist_ltp2 (int dx, int y, int y1, int y2) 00360 { 00361 if (y1 > y2) 00362 SWAP (y1, y2); 00363 if (y < y1) 00364 return dist (dx, y, 0, y1); 00365 if (y > y2) 00366 return dist (dx, y, 0, y2); 00367 return djabs (dx); 00368 } 00369 00370 static int 00371 intersecting_layers (int l1, int l2) 00372 { 00373 if (l1 == -1 || l2 == -1) 00374 return 1; 00375 if (l1 == l2) 00376 return 1; 00377 if (layer_groupings[l1] == layer_groupings[l2]) 00378 return 1; 00379 return 0; 00380 } 00381 00382 static int 00383 dist_line_to_point (line_s * l, corner_s * c) 00384 { 00385 double len, r, d; 00386 /* We can do this quickly if l is vertical or horizontal. */ 00387 if (l->s->x == l->e->x) 00388 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y); 00389 if (l->s->y == l->e->y) 00390 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x); 00391 00392 /* Do it the hard way. See comments for IsPointOnLine() in search.c */ 00393 len = hypot (l->s->x - l->e->x, l->s->y - l->e->y); 00394 if (len == 0) 00395 return dist (l->s->x, l->s->y, c->x, c->y); 00396 r = 00397 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x - 00398 l->e->x); 00399 r /= len * len; 00400 if (r < 0) 00401 return dist (l->s->x, l->s->y, c->x, c->y); 00402 if (r > 1) 00403 return dist (l->e->x, l->e->y, c->x, c->y); 00404 d = 00405 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y - 00406 l->s->y); 00407 return (int) (d / len); 00408 } 00409 00410 static int 00411 line_orient (line_s * l, corner_s * c) 00412 { 00413 int x1, y1, x2, y2; 00414 if (c == l->s) 00415 { 00416 x1 = l->s->x; 00417 y1 = l->s->y; 00418 x2 = l->e->x; 00419 y2 = l->e->y; 00420 } 00421 else 00422 { 00423 x1 = l->e->x; 00424 y1 = l->e->y; 00425 x2 = l->s->x; 00426 y2 = l->s->y; 00427 } 00428 if (x1 == x2) 00429 { 00430 if (y1 < y2) 00431 return DOWN; 00432 return UP; 00433 } 00434 else if (y1 == y2) 00435 { 00436 if (x1 < x2) 00437 return RIGHT; 00438 return LEFT; 00439 } 00440 return DIAGONAL; 00441 } 00442 00443 #if 0 00444 /* Not used */ 00445 static corner_s * 00446 common_corner (line_s * l1, line_s * l2) 00447 { 00448 if (l1->s == l2->s || l1->s == l2->e) 00449 return l1->s; 00450 if (l1->e == l2->s || l1->e == l2->e) 00451 return l1->e; 00452 dj_abort ("common_corner: no common corner found\n"); 00453 return NULL; 00454 } 00455 #endif 00456 00457 static corner_s * 00458 other_corner (line_s * l, corner_s * c) 00459 { 00460 if (l->s == c) 00461 return l->e; 00462 if (l->e == c) 00463 return l->s; 00464 dj_abort ("other_corner: neither corner passed\n"); 00465 return NULL; 00466 } 00467 00468 static corner_s * 00469 find_corner_if (int x, int y, int l) 00470 { 00471 corner_s *c; 00472 for (c = corners; c; c = c->next) 00473 { 00474 if (DELETED (c)) 00475 continue; 00476 if (c->x != x || c->y != y) 00477 continue; 00478 if (!(c->layer == -1 || intersecting_layers (c->layer, l))) 00479 continue; 00480 return c; 00481 } 00482 return 0; 00483 } 00484 00485 static corner_s * 00486 find_corner (int x, int y, int l) 00487 { 00488 corner_s *c; 00489 for (c = corners; c; c = c->next) 00490 { 00491 if (DELETED (c)) 00492 continue; 00493 if (c->x != x || c->y != y) 00494 continue; 00495 if (!(c->layer == -1 || intersecting_layers (c->layer, l))) 00496 continue; 00497 return c; 00498 } 00499 c = (corner_s *) malloc (sizeof (corner_s)); 00500 c->next = corners; 00501 corners = c; 00502 c->x = x; 00503 c->y = y; 00504 c->net = 0; 00505 c->via = 0; 00506 c->pad = 0; 00507 c->pin = 0; 00508 c->layer = l; 00509 c->n_lines = 0; 00510 c->lines = (line_s **) malloc (INC * sizeof (line_s *)); 00511 return c; 00512 } 00513 00514 static void 00515 add_line_to_corner (line_s * l, corner_s * c) 00516 { 00517 int n; 00518 n = (c->n_lines + 1 + INC) & ~INC; 00519 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *)); 00520 c->lines[c->n_lines] = l; 00521 c->n_lines++; 00522 dprintf ("add_line_to_corner %#mD\n", c->x, c->y); 00523 } 00524 00525 static LineType * 00526 create_pcb_line (int layer, int x1, int y1, int x2, int y2, 00527 int thick, int clear, FlagType flags) 00528 { 00529 char *from, *to; 00530 LineType *nl; 00531 LayerType *lyr = LAYER_PTR (layer); 00532 00533 from = (char *) lyr->Line; 00534 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer, 00535 x1, y1, x2, y2, thick, clear, flags); 00536 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl); 00537 00538 to = (char *) lyr->Line; 00539 if (from != to) 00540 { 00541 line_s *lp; 00542 for (lp = lines; lp; lp = lp->next) 00543 { 00544 if (DELETED (lp)) 00545 continue; 00546 if ((char *) (lp->line) >= from 00547 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType)) 00548 lp->line = (LineType *) ((char *) (lp->line) + (to - from)); 00549 } 00550 } 00551 return nl; 00552 } 00553 00554 static void 00555 new_line (corner_s * s, corner_s * e, int layer, LineType * example) 00556 { 00557 line_s *ls; 00558 00559 if (layer >= max_copper_layer) 00560 dj_abort ("layer %d\n", layer); 00561 00562 if (example == NULL) 00563 dj_abort ("NULL example passed to new_line()\n", layer); 00564 00565 if (s->x == e->x && s->y == e->y) 00566 return; 00567 00568 ls = (line_s *) malloc (sizeof (line_s)); 00569 ls->next = lines; 00570 lines = ls; 00571 ls->is_pad = 0; 00572 ls->s = s; 00573 ls->e = e; 00574 ls->layer = layer; 00575 #if 0 00576 if ((example->Point1.X == s->x && example->Point1.Y == s->y 00577 && example->Point2.X == e->x && example->Point2.Y == e->y) 00578 || (example->Point2.X == s->x && example->Point2.Y == s->y 00579 && example->Point1.X == e->x && example->Point1.Y == e->y)) 00580 { 00581 ls->line = example; 00582 } 00583 else 00584 #endif 00585 { 00586 LineType *nl; 00587 dprintf 00588 ("New line \033[35m%#mD to %#mD from l%d t%#mS c%#mS f%s\033[0m\n", 00589 s->x, s->y, e->x, e->y, layer, example->Thickness, 00590 example->Clearance, flags_to_string (example->Flags, LINE_TYPE)); 00591 nl = 00592 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness, 00593 example->Clearance, example->Flags); 00594 00595 if (!nl) 00596 dj_abort ("can't create new line!"); 00597 ls->line = nl; 00598 } 00599 add_line_to_corner (ls, s); 00600 add_line_to_corner (ls, e); 00601 check (s, ls); 00602 check (e, ls); 00603 } 00604 00605 #if 0 00606 /* Not used */ 00607 static int 00608 c_orth_to (corner_s * c, line_s * l, int o) 00609 { 00610 int i, o2; 00611 int rv = 0; 00612 for (i = 0; i < c->n_lines; i++) 00613 { 00614 if (c->lines[i] == l) 00615 continue; 00616 o2 = line_orient (c->lines[i], c); 00617 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL) 00618 return 0; 00619 rv++; 00620 } 00621 return rv; 00622 } 00623 #endif 00624 00625 static line_s * 00626 other_line (corner_s * c, line_s * l) 00627 { 00628 int i; 00629 line_s *rv = 0; 00630 if (c->pin || c->pad || c->via) 00631 return 0; 00632 for (i = 0; i < c->n_lines; i++) 00633 { 00634 if (c->lines[i] == l) 00635 continue; 00636 if (rv) 00637 return 0; 00638 rv = c->lines[i]; 00639 } 00640 return rv; 00641 } 00642 00643 static void 00644 empty_rect (rect_s * rect) 00645 { 00646 rect->x1 = rect->y1 = INT_MAX; 00647 rect->x2 = rect->y2 = INT_MIN; 00648 } 00649 00650 static void 00651 add_point_to_rect (rect_s * rect, int x, int y, int w) 00652 { 00653 if (rect->x1 > x - w) 00654 rect->x1 = x - w; 00655 if (rect->x2 < x + w) 00656 rect->x2 = x + w; 00657 if (rect->y1 > y - w) 00658 rect->y1 = y - w; 00659 if (rect->y2 < y + w) 00660 rect->y2 = y + w; 00661 } 00662 00663 static void 00664 add_line_to_rect (rect_s * rect, line_s * l) 00665 { 00666 add_point_to_rect (rect, l->s->x, l->s->y, 0); 00667 add_point_to_rect (rect, l->e->x, l->e->y, 0); 00668 } 00669 00670 static int 00671 pin_in_rect (rect_s * r, int x, int y, int w) 00672 { 00673 if (x < r->x1 && x + w < r->x1) 00674 return 0; 00675 if (x > r->x2 && x - w > r->x2) 00676 return 0; 00677 if (y < r->y1 && y + w < r->y1) 00678 return 0; 00679 if (y > r->y2 && y - w > r->y2) 00680 return 0; 00681 return 1; 00682 } 00683 00684 static int 00685 line_in_rect (rect_s * r, line_s * l) 00686 { 00687 rect_s lr; 00688 empty_rect (&lr); 00689 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2); 00690 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2); 00691 dprintf ("line_in_rect %#mD-%#mD vs %#mD-%#mD\n", 00692 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2); 00693 /* simple intersection of rectangles */ 00694 if (lr.x1 < r->x1) 00695 lr.x1 = r->x1; 00696 if (lr.x2 > r->x2) 00697 lr.x2 = r->x2; 00698 if (lr.y1 < r->y1) 00699 lr.y1 = r->y1; 00700 if (lr.y2 > r->y2) 00701 lr.y2 = r->y2; 00702 if (lr.x1 < lr.x2 && lr.y1 < lr.y2) 00703 return 1; 00704 return 0; 00705 } 00706 00707 static int 00708 corner_radius (corner_s * c) 00709 { 00710 int diam = 0; 00711 int i; 00712 if (c->pin) 00713 diam = djmax (c->pin->Thickness, diam); 00714 if (c->via) 00715 diam = djmax (c->via->Thickness, diam); 00716 for (i = 0; i < c->n_lines; i++) 00717 if (c->lines[i]->line) 00718 diam = djmax (c->lines[i]->line->Thickness, diam); 00719 diam = (diam + 1) / 2; 00720 return diam; 00721 } 00722 00723 #if 0 00724 /* Not used */ 00725 static int 00726 corner_layer (corner_s * c) 00727 { 00728 if (c->pin || c->via) 00729 return -1; 00730 if (c->n_lines < 1) 00731 return -1; 00732 return c->lines[0]->layer; 00733 } 00734 #endif 00735 00736 static void 00737 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e) 00738 { 00739 int diam = corner_radius (c); 00740 if (!pin_in_rect (e, c->x, c->y, diam)) 00741 return; 00742 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam) 00743 return; 00744 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam) 00745 return; 00746 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam) 00747 return; 00748 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam) 00749 return; 00750 00751 /*pcb_printf("add point %#mD diam %#mS\n", c->x, c->y, diam); */ 00752 add_point_to_rect (rect, c->x, c->y, diam); 00753 } 00754 00755 static void 00756 remove_line (line_s * l) 00757 { 00758 int i, j; 00759 LayerType *layer = &(PCB->Data->Layer[l->layer]); 00760 00761 check (0, 0); 00762 00763 if (l->line) 00764 RemoveLine (layer, l->line); 00765 00766 DELETE (l); 00767 00768 for (i = 0, j = 0; i < l->s->n_lines; i++) 00769 if (l->s->lines[i] != l) 00770 l->s->lines[j++] = l->s->lines[i]; 00771 l->s->n_lines = j; 00772 00773 for (i = 0, j = 0; i < l->e->n_lines; i++) 00774 if (l->e->lines[i] != l) 00775 l->e->lines[j++] = l->e->lines[i]; 00776 l->e->n_lines = j; 00777 check (0, 0); 00778 } 00779 00780 static void 00781 move_line_to_layer (line_s * l, int layer) 00782 { 00783 LayerType *ls, *ld; 00784 00785 ls = LAYER_PTR (l->layer); 00786 ld = LAYER_PTR (layer); 00787 00788 MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0); 00789 l->layer = layer; 00790 } 00791 00792 static void 00793 remove_via_at (corner_s * c) 00794 { 00795 RemoveObject (VIA_TYPE, c->via, 0, 0); 00796 c->via = 0; 00797 } 00798 00799 static void 00800 remove_corner (corner_s * c2) 00801 { 00802 corner_s *c; 00803 dprintf ("remove corner %s\n", corner_name (c2)); 00804 if (corners == c2) 00805 corners = c2->next; 00806 for (c = corners; c; c = c->next) 00807 { 00808 if (DELETED (c)) 00809 continue; 00810 if (c->next == c2) 00811 c->next = c2->next; 00812 } 00813 if (next_corner == c2) 00814 next_corner = c2->next; 00815 free (c2->lines); 00816 c2->lines = 0; 00817 DELETE (c2); 00818 } 00819 00820 static void 00821 merge_corners (corner_s * c1, corner_s * c2) 00822 { 00823 int i; 00824 if (c1 == c2) 00825 abort (); 00826 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2)); 00827 for (i = 0; i < c2->n_lines; i++) 00828 { 00829 add_line_to_corner (c2->lines[i], c1); 00830 if (c2->lines[i]->s == c2) 00831 c2->lines[i]->s = c1; 00832 if (c2->lines[i]->e == c2) 00833 c2->lines[i]->e = c1; 00834 } 00835 if (c1->via && c2->via) 00836 remove_via_at (c2); 00837 else if (c2->via) 00838 c1->via = c2->via; 00839 if (c2->pad) 00840 c1->pad = c2->pad; 00841 if (c2->pin) 00842 c1->pin = c2->pin; 00843 if (c2->layer != c1->layer) 00844 c1->layer = -1; 00845 00846 remove_corner (c2); 00847 } 00848 00849 static void 00850 move_corner (corner_s * c, int x, int y) 00851 { 00852 PinType *via; 00853 int i; 00854 corner_s *pad; 00855 00856 check (c, 0); 00857 if (c->pad || c->pin) 00858 dj_abort ("move_corner: has pin or pad\n"); 00859 dprintf ("move_corner %p from %#mD to %#mD\n", (void *) c, c->x, c->y, x, y); 00860 pad = find_corner_if (x, y, c->layer); 00861 c->x = x; 00862 c->y = y; 00863 via = c->via; 00864 if (via) 00865 { 00866 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y); 00867 dprintf ("via move %#mD to %#mD\n", via->X, via->Y, x, y); 00868 } 00869 for (i = 0; i < c->n_lines; i++) 00870 { 00871 LineType *tl = c->lines[i]->line; 00872 if (tl) 00873 { 00874 if (c->lines[i]->s == c) 00875 { 00876 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl, 00877 &tl->Point1, x - (tl->Point1.X), 00878 y - (tl->Point1.Y)); 00879 } 00880 else 00881 { 00882 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl, 00883 &tl->Point2, x - (tl->Point2.X), 00884 y - (tl->Point2.Y)); 00885 } 00886 dprintf ("Line %p moved to %#mD %#mD\n", (void *) tl, 00887 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y); 00888 } 00889 } 00890 if (pad && pad != c) 00891 merge_corners (c, pad); 00892 else 00893 for (i = 0; i < c->n_lines; i++) 00894 { 00895 if (c->lines[i]->s->x == c->lines[i]->e->x 00896 && c->lines[i]->s->y == c->lines[i]->e->y) 00897 { 00898 corner_s *c2 = other_corner (c->lines[i], c); 00899 dprintf ("move_corner: removing line %#mD %#mD %p %p\n", 00900 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2); 00901 00902 remove_line (c->lines[i]); 00903 if (c != c2) 00904 merge_corners (c, c2); 00905 check (c, 0); 00906 i--; 00907 break; 00908 } 00909 } 00910 gui->progress (0, 0, 0); 00911 check (c, 0); 00912 } 00913 00914 static int 00915 any_line_selected () 00916 { 00917 line_s *l; 00918 for (l = lines; l; l = l->next) 00919 { 00920 if (DELETED (l)) 00921 continue; 00922 if (l->line && selected (l->line)) 00923 return 1; 00924 } 00925 return 0; 00926 } 00927 00928 static int 00929 trim_step (int s, int l1, int l2) 00930 { 00931 dprintf ("trim %d %d %d\n", s, l1, l2); 00932 if (s > l1) 00933 s = l1; 00934 if (s > l2) 00935 s = l2; 00936 if (s != l1 && s != l2) 00937 s = gridsnap (s); 00938 return s; 00939 } 00940 00941 static int canonicalize_line (line_s * l); 00942 00943 static int 00944 split_line (line_s * l, corner_s * c) 00945 { 00946 int i; 00947 LineType *pcbline; 00948 line_s *ls; 00949 00950 if (!intersecting_layers (l->layer, c->layer)) 00951 return 0; 00952 if (l->is_pad) 00953 return 0; 00954 if (c->pad) 00955 { 00956 dprintf ("split on pad!\n"); 00957 if (l->s->pad == c->pad || l->e->pad == c->pad) 00958 return 0; 00959 dprintf ("splitting...\n"); 00960 } 00961 00962 check (c, l); 00963 pcbline = create_pcb_line (l->layer, 00964 c->x, c->y, l->e->x, l->e->y, 00965 l->line->Thickness, l->line->Clearance, 00966 l->line->Flags); 00967 if (pcbline == 0) 00968 return 0; /* already a line there */ 00969 00970 check (c, l); 00971 00972 dprintf ("split line from %#mD to %#mD at %#mD\n", 00973 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y); 00974 ls = (line_s *) malloc (sizeof (line_s)); 00975 00976 ls->next = lines; 00977 lines = ls; 00978 ls->is_pad = 0; 00979 ls->s = c; 00980 ls->e = l->e; 00981 ls->line = pcbline; 00982 ls->layer = l->layer; 00983 for (i = 0; i < l->e->n_lines; i++) 00984 if (l->e->lines[i] == l) 00985 l->e->lines[i] = ls; 00986 l->e = c; 00987 add_line_to_corner (l, c); 00988 add_line_to_corner (ls, c); 00989 00990 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2, 00991 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y)); 00992 00993 return 1; 00994 } 00995 00996 static int 00997 canonicalize_line (line_s * l) 00998 { 00999 /* This could be faster */ 01000 corner_s *c; 01001 if (l->s->x == l->e->x) 01002 { 01003 int y1 = l->s->y; 01004 int y2 = l->e->y; 01005 int x1 = l->s->x - l->line->Thickness / 2; 01006 int x2 = l->s->x + l->line->Thickness / 2; 01007 if (y1 > y2) 01008 { 01009 int t = y1; 01010 y1 = y2; 01011 y2 = t; 01012 } 01013 for (c = corners; c; c = c->next) 01014 { 01015 if (DELETED (c)) 01016 continue; 01017 if ((y1 < c->y && c->y < y2) 01018 && intersecting_layers (l->layer, c->layer)) 01019 { 01020 if (c->x != l->s->x 01021 && c->x < x2 && c->x > x1 && !(c->pad || c->pin)) 01022 { 01023 move_corner (c, l->s->x, c->y); 01024 } 01025 if (c->x == l->s->x) 01026 { 01027 /* FIXME: if the line is split, we have to re-canonicalize 01028 both segments. */ 01029 return split_line (l, c); 01030 } 01031 } 01032 } 01033 } 01034 else if (l->s->y == l->e->y) 01035 { 01036 int x1 = l->s->x; 01037 int x2 = l->e->x; 01038 int y1 = l->s->y - l->line->Thickness / 2; 01039 int y2 = l->s->y + l->line->Thickness / 2; 01040 if (x1 > x2) 01041 { 01042 int t = x1; 01043 x1 = x2; 01044 x2 = t; 01045 } 01046 for (c = corners; c; c = c->next) 01047 { 01048 if (DELETED (c)) 01049 continue; 01050 if ((x1 < c->x && c->x < x2) 01051 && intersecting_layers (l->layer, c->layer)) 01052 { 01053 if (c->y != l->s->y 01054 && c->y < y2 && c->y > y1 && !(c->pad || c->pin)) 01055 { 01056 move_corner (c, c->x, l->s->y); 01057 } 01058 if (c->y == l->s->y) 01059 { 01060 /* FIXME: Likewise. */ 01061 return split_line (l, c); 01062 } 01063 } 01064 } 01065 } 01066 else 01067 { 01068 /* diagonal lines. Let's try to split them at pins/vias 01069 anyway. */ 01070 int x1 = l->s->x; 01071 int x2 = l->e->x; 01072 int y1 = l->s->y; 01073 int y2 = l->e->y; 01074 if (x1 > x2) 01075 { 01076 int t = x1; 01077 x1 = x2; 01078 x2 = t; 01079 } 01080 if (y1 > y2) 01081 { 01082 int t = y1; 01083 y1 = y2; 01084 y2 = t; 01085 } 01086 for (c = corners; c; c = c->next) 01087 { 01088 if (DELETED (c)) 01089 continue; 01090 if (!c->via && !c->pin) 01091 continue; 01092 if ((x1 < c->x && c->x < x2) 01093 && (y1 < c->y && c->y < y2) 01094 && intersecting_layers (l->layer, c->layer)) 01095 { 01096 int th = c->pin ? c->pin->Thickness : c->via->Thickness; 01097 th /= 2; 01098 if (dist (l->s->x, l->s->y, c->x, c->y) > th 01099 && dist (l->e->x, l->e->y, c->x, c->y) > th 01100 && PinLineIntersect (c->pin ? c->pin : c->via, l->line)) 01101 { 01102 return split_line (l, c); 01103 } 01104 } 01105 } 01106 } 01107 return 0; 01108 } 01109 01113 static int 01114 canonicalize_lines () 01115 { 01116 int changes = 0; 01117 int count; 01118 line_s *l; 01119 while (1) 01120 { 01121 count = 0; 01122 for (l = lines; l; l = l->next) 01123 { 01124 if (DELETED (l)) 01125 continue; 01126 count += canonicalize_line (l); 01127 } 01128 changes += count; 01129 if (count == 0) 01130 break; 01131 } 01132 return changes; 01133 } 01134 01135 static int 01136 simple_optimize_corner (corner_s * c) 01137 { 01138 int i; 01139 int rv = 0; 01140 01141 check (c, 0); 01142 if (c->via) 01143 { 01144 /* see if no via is needed */ 01145 if (selected (c->via)) 01146 dprintf ("via check: line[0] layer %d at %#mD nl %d\n", 01147 c->lines[0]->layer, c->x, c->y, c->n_lines); 01148 /* We can't delete vias that connect to power planes, or vias 01149 that aren't tented (assume they're test points). */ 01150 if (!TEST_ANY_THERMS (c->via) 01151 && c->via->Mask == 0) 01152 { 01153 for (i = 1; i < c->n_lines; i++) 01154 { 01155 if (selected (c->via)) 01156 dprintf (" line[%d] layer %d %#mD to %#mD\n", 01157 i, c->lines[i]->layer, 01158 c->lines[i]->s->x, c->lines[i]->s->y, 01159 c->lines[i]->e->x, c->lines[i]->e->y); 01160 if (c->lines[i]->layer != c->lines[0]->layer) 01161 break; 01162 } 01163 if (i == c->n_lines) 01164 { 01165 if (selected (c->via)) 01166 dprintf (" remove it\n"); 01167 remove_via_at (c); 01168 rv++; 01169 } 01170 } 01171 } 01172 01173 check (c, 0); 01174 if (c->n_lines == 2 && !c->via) 01175 { 01176 /* see if it is an unneeded corner */ 01177 int o = line_orient (c->lines[0], c); 01178 corner_s *c2 = other_corner (c->lines[1], c); 01179 corner_s *c0 = other_corner (c->lines[0], c); 01180 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL) 01181 { 01182 dprintf ("straight %#mD to %#mD to %#mD\n", 01183 c0->x, c0->y, c->x, c->y, c2->x, c2->y); 01184 if (selected (c->lines[0]->line)) 01185 SET_FLAG (SELECTEDFLAG, c->lines[1]->line); 01186 if (selected (c->lines[1]->line)) 01187 SET_FLAG (SELECTEDFLAG, c->lines[0]->line); 01188 move_corner (c, c2->x, c2->y); 01189 } 01190 } 01191 check (c, 0); 01192 if (c->n_lines == 1 && !c->via) 01193 { 01194 corner_s *c0 = other_corner (c->lines[0], c); 01195 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE) 01196 { 01197 /* 01198 * Remove this line, as it is a "freckle". A freckle is an extremely 01199 * short line (around 0.01 thou) that is unconnected at one end. 01200 * Freckles are almost insignificantly small, but are annoying as 01201 * they prevent the mitering optimiser from working. 01202 * Freckles sometimes arise because of a bug in the autorouter that 01203 * causes it to create small overshoots (typically 0.01 thou) at the 01204 * intersections of vertical and horizontal lines. These overshoots 01205 * are converted to freckles as a side effect of canonicalize_line(). 01206 * Note that canonicalize_line() is not at fault, the bug is in the 01207 * autorouter creating overshoots. 01208 * The autorouter bug arose some time between the 20080202 and 20091103 01209 * releases. 01210 * This code is probably worth keeping even when the autorouter bug is 01211 * fixed, as "freckles" could conceivably arise in other ways. 01212 */ 01213 dprintf ("freckle %#mD to %#mD\n", c->x, c->y, c0->x, c0->y); 01214 move_corner (c, c0->x, c0->y); 01215 } 01216 } 01217 check (c, 0); 01218 return rv; 01219 } 01220 01221 /* We always run these */ 01222 static int 01223 simple_optimizations () 01224 { 01225 corner_s *c; 01226 int rv = 0; 01227 01228 /* Look for corners that aren't */ 01229 for (c = corners; c; c = c->next) 01230 { 01231 if (DELETED (c)) 01232 continue; 01233 if (c->pad || c->pin) 01234 continue; 01235 rv += simple_optimize_corner (c); 01236 } 01237 return rv; 01238 } 01239 01240 static int 01241 is_hole (corner_s * c) 01242 { 01243 return c->pin || c->pad || c->via; 01244 } 01245 01246 static int 01247 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel) 01248 { 01249 static corner_s **cs = 0; 01250 static int cm = 0; 01251 static line_s **ls = 0; 01252 static int lm = 0; 01253 int i, li, ln, cn, snap; 01254 line_s *l = 0; 01255 corner_s *c2, *cb; 01256 int adir = 0, sdir = 0, pull; 01257 int saw_sel = 0, saw_auto = 0; 01258 int max, len = 0, r1 = 0, r2; 01259 rect_s rr; 01260 int edir = 0, done; 01261 01262 if (cs == 0) 01263 { 01264 cs = (corner_s **) malloc (10 * sizeof (corner_s)); 01265 cm = 10; 01266 ls = (line_s **) malloc (10 * sizeof (line_s)); 01267 lm = 10; 01268 } 01269 01270 for (i = 0; i < c->n_lines; i++) 01271 { 01272 int o = line_orient (c->lines[i], c); 01273 if (o == rdir) 01274 return 0; 01275 } 01276 01277 switch (fdir) 01278 { 01279 case RIGHT: 01280 adir = DOWN; 01281 sdir = UP; 01282 break; 01283 case DOWN: 01284 adir = RIGHT; 01285 sdir = LEFT; 01286 break; 01287 default: 01288 dj_abort ("fdir not right or down\n"); 01289 } 01290 01291 c2 = c; 01292 cn = 0; 01293 ln = 0; 01294 pull = 0; 01295 while (c2) 01296 { 01297 if (c2->pad || c2->pin || c2->n_lines < 2) 01298 return 0; 01299 if (cn >= cm) 01300 { 01301 cm = cn + 10; 01302 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s *)); 01303 } 01304 cs[cn++] = c2; 01305 r2 = corner_radius (c2); 01306 if (r1 < r2) 01307 r1 = r2; 01308 l = 0; 01309 for (i = 0; i < c2->n_lines; i++) 01310 { 01311 int o = line_orient (c2->lines[i], c2); 01312 if (o == DIAGONAL) 01313 return 0; 01314 if (o == fdir) 01315 { 01316 if (l) 01317 return 0; /* we don't support overlapping lines yet */ 01318 l = c2->lines[i]; 01319 } 01320 if (o == rdir && c2->lines[i] != ls[ln - 1]) 01321 return 0; /* likewise */ 01322 if (o == adir) 01323 pull++; 01324 if (o == sdir) 01325 pull--; 01326 } 01327 if (!l) 01328 break; 01329 if (selected (l->line)) 01330 saw_sel = 1; 01331 if (autorouted (l->line)) 01332 saw_auto = 1; 01333 if (ln >= lm) 01334 { 01335 lm = ln + 10; 01336 ls = (line_s **) realloc (ls, lm * sizeof (line_s *)); 01337 } 01338 ls[ln++] = l; 01339 c2 = other_corner (l, c2); 01340 } 01341 if (cn < 2 || pull == 0) 01342 return 0; 01343 if (any_sel && !saw_sel) 01344 return 0; 01345 if (!any_sel && autorouted_only && !saw_auto) 01346 return 0; 01347 01348 /* Ok, now look for other blockages. */ 01349 01350 empty_rect (&rr); 01351 add_point_to_rect (&rr, c->x, c->y, corner_radius (c)); 01352 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2)); 01353 01354 if (fdir == RIGHT && pull < 0) 01355 edir = UP; 01356 else if (fdir == RIGHT && pull > 0) 01357 edir = DOWN; 01358 else if (fdir == DOWN && pull < 0) 01359 edir = LEFT; 01360 else if (fdir == DOWN && pull > 0) 01361 edir = RIGHT; 01362 01363 max = -1; 01364 for (i = 0; i < cn; i++) 01365 for (li = 0; li < cs[i]->n_lines; li++) 01366 { 01367 if (line_orient (cs[i]->lines[li], cs[i]) != edir) 01368 continue; 01369 len = line_length (cs[i]->lines[li]); 01370 if (max > len || max == -1) 01371 max = len; 01372 } 01373 dprintf ("c %s %4#mD cn %d pull %3d max %4#mS\n", 01374 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max); 01375 01376 switch (edir) 01377 { 01378 case UP: 01379 rr.y1 = c->y - r1 - max; 01380 break; 01381 case DOWN: 01382 rr.y2 = c->y + r1 + max; 01383 break; 01384 case LEFT: 01385 rr.x1 = c->x - r1 - max; 01386 break; 01387 case RIGHT: 01388 rr.x2 = c->x + r1 + max; 01389 break; 01390 } 01391 rr.x1 -= SB + 1; 01392 rr.x2 += SB + 1; 01393 rr.y1 -= SB + 1; 01394 rr.y2 += SB + 1; 01395 01396 snap = 0; 01397 for (cb = corners; cb; cb = cb->next) 01398 { 01399 int sep; 01400 if (DELETED (cb)) 01401 continue; 01402 r1 = corner_radius (cb); 01403 if (cb->net == c->net && !cb->pad) 01404 continue; 01405 if (!pin_in_rect (&rr, cb->x, cb->y, r1)) 01406 continue; 01407 switch (edir) 01408 { 01409 #define ECHK(X,Y,LT) \ 01410 for (i=0; i<cn; i++) \ 01411 { \ 01412 if (!intersecting_layers(cs[i]->layer, cb->layer)) \ 01413 continue; \ 01414 r2 = corner_radius(cs[i]); \ 01415 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \ 01416 continue; \ 01417 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \ 01418 continue; \ 01419 if (cb->Y LT cs[i]->Y) \ 01420 continue; \ 01421 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \ 01422 if (max > sep) \ 01423 { max = sep; snap = 1; }\ 01424 } \ 01425 for (i=0; i<ln; i++) \ 01426 { \ 01427 if (!intersecting_layers(ls[i]->layer, cb->layer)) \ 01428 continue; \ 01429 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \ 01430 continue; \ 01431 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \ 01432 - r1 - SB - 1); \ 01433 if (max > sep) \ 01434 { max = sep; snap = 1; }\ 01435 } 01436 case UP: 01437 ECHK (x, y, >=); 01438 break; 01439 case DOWN: 01440 ECHK (x, y, <=); 01441 break; 01442 case LEFT: 01443 ECHK (y, x, >=); 01444 break; 01445 case RIGHT: 01446 ECHK (y, x, <=); 01447 break; 01448 } 01449 } 01450 01451 /* We must now check every line segment against our corners. */ 01452 for (l = lines; l; l = l->next) 01453 { 01454 int o, x1, x2, y1, y2; 01455 if (DELETED (l)) 01456 continue; 01457 dprintf ("check line %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y); 01458 if (l->s->net == c->net) 01459 { 01460 dprintf (" same net\n"); 01461 continue; 01462 } 01463 o = line_orient (l, 0); 01464 /* We don't need to check perpendicular lines, because their 01465 corners already take care of it. */ 01466 if ((fdir == RIGHT && (o == UP || o == DOWN)) 01467 || (fdir == DOWN && (o == RIGHT || o == LEFT))) 01468 { 01469 dprintf (" perpendicular\n"); 01470 continue; 01471 } 01472 01473 /* Choose so that x1,y1 is closest to corner C */ 01474 if ((fdir == RIGHT && l->s->x < l->e->x) 01475 || (fdir == DOWN && l->s->y < l->e->y)) 01476 { 01477 x1 = l->s->x; 01478 y1 = l->s->y; 01479 x2 = l->e->x; 01480 y2 = l->e->y; 01481 } 01482 else 01483 { 01484 x1 = l->e->x; 01485 y1 = l->e->y; 01486 x2 = l->s->x; 01487 y2 = l->s->y; 01488 } 01489 01490 /* Eliminate all lines outside our range */ 01491 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x)) 01492 || (fdir == DOWN && (y2 < c->y || y1 > c2->y))) 01493 { 01494 dprintf (" outside our range\n"); 01495 continue; 01496 } 01497 01498 /* Eliminate all lines on the wrong side of us */ 01499 if ((edir == UP && y1 > c->y && y2 > c->y) 01500 || (edir == DOWN && y1 < c->y && y2 < c->y) 01501 || (edir == LEFT && x1 > c->x && x2 > c->x) 01502 || (edir == RIGHT && x1 < c->x && x2 < c->x)) 01503 { 01504 dprintf (" wrong side\n"); 01505 continue; 01506 } 01507 01508 /* For now, cheat on diagonals */ 01509 switch (edir) 01510 { 01511 case RIGHT: 01512 if (x1 > x2) 01513 x1 = x2; 01514 break; 01515 case LEFT: 01516 if (x1 < x2) 01517 x1 = x2; 01518 break; 01519 case DOWN: 01520 if (y1 > y2) 01521 y1 = y2; 01522 break; 01523 case UP: 01524 if (y1 < y2) 01525 y1 = y2; 01526 break; 01527 } 01528 01529 /* Ok, now see how far we can get for each of our corners. */ 01530 for (i = 0; i < cn; i++) 01531 { 01532 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1; 01533 int len = 0; 01534 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x)) 01535 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y))) 01536 continue; 01537 if (!intersecting_layers (cs[i]->layer, l->layer)) 01538 continue; 01539 switch (edir) 01540 { 01541 case RIGHT: 01542 len = x1 - c->x; 01543 break; 01544 case LEFT: 01545 len = c->x - x1; 01546 break; 01547 case DOWN: 01548 len = y1 - c->y; 01549 break; 01550 case UP: 01551 len = c->y - y1; 01552 break; 01553 } 01554 len -= r; 01555 dprintf (" len is %#mS vs corner at %#mD\n", len, cs[i]->x, cs[i]->y); 01556 if (len <= 0) 01557 return 0; 01558 if (max > len) 01559 max = len; 01560 } 01561 01562 } 01563 01564 /* We must make sure that if a segment isn't being completely 01565 removed, that any vias and/or pads don't overlap. */ 01566 done = 0; 01567 while (!done) 01568 { 01569 done = 1; 01570 for (i = 0; i < cn; i++) 01571 for (li = 0; li < cs[i]->n_lines; li++) 01572 { 01573 line_s *l = cs[i]->lines[li]; 01574 corner_s *oc = other_corner (l, cs[i]); 01575 if (line_orient (l, cs[i]) != edir) 01576 continue; 01577 len = line_length (l); 01578 if (!oc->pad || !cs[i]->via) 01579 { 01580 if (!is_hole (l->s) || !is_hole (l->e)) 01581 continue; 01582 if (len == max) 01583 continue; 01584 } 01585 len -= corner_radius (l->s); 01586 len -= corner_radius (l->e); 01587 len -= SB + 1; 01588 if (max > len) 01589 { 01590 max = len; 01591 done = 0; 01592 } 01593 } 01594 } 01595 01596 if (max <= 0) 01597 return 0; 01598 switch (edir) 01599 { 01600 case UP: 01601 len = c->y - max; 01602 break; 01603 case DOWN: 01604 len = c->y + max; 01605 break; 01606 case LEFT: 01607 len = c->x - max; 01608 break; 01609 case RIGHT: 01610 len = c->x + max; 01611 break; 01612 } 01613 if (snap && max > Settings.Grid) 01614 { 01615 if (pull < 0) 01616 len += Settings.Grid - 1; 01617 len = gridsnap (len); 01618 } 01619 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x)) 01620 return 0; 01621 for (i = 0; i < cn; i++) 01622 { 01623 if (fdir == RIGHT) 01624 { 01625 max = len - cs[i]->y; 01626 move_corner (cs[i], cs[i]->x, len); 01627 } 01628 else 01629 { 01630 max = len - cs[i]->x; 01631 move_corner (cs[i], len, cs[i]->y); 01632 } 01633 } 01634 return max * pull; 01635 } 01636 01641 static int 01642 orthopull () 01643 { 01644 int any_sel = any_line_selected (); 01645 corner_s *c; 01646 int rv = 0; 01647 01648 for (c = corners; c;) 01649 { 01650 if (DELETED (c)) 01651 continue; 01652 if (c->pin || c->pad) 01653 { 01654 c = c->next; 01655 continue; 01656 } 01657 next_corner = c; 01658 rv += orthopull_1 (c, RIGHT, LEFT, any_sel); 01659 if (c != next_corner) 01660 { 01661 c = next_corner; 01662 continue; 01663 } 01664 rv += orthopull_1 (c, DOWN, UP, any_sel); 01665 if (c != next_corner) 01666 { 01667 c = next_corner; 01668 continue; 01669 } 01670 c = c->next; 01671 } 01672 if (rv) 01673 pcb_printf ("orthopull: %ml mils saved\n", rv); 01674 return rv; 01675 } 01676 01680 static int 01681 debumpify () 01682 { 01683 int rv = 0; 01684 int any_selected = any_line_selected (); 01685 line_s *l, *l1, *l2; 01686 corner_s *c, *c1, *c2; 01687 rect_s rr, rp; 01688 int o, o1, o2, step, w; 01689 for (l = lines; l; l = l->next) 01690 { 01691 if (DELETED (l)) 01692 continue; 01693 if (!l->line) 01694 continue; 01695 if (any_selected && !selected (l->line)) 01696 continue; 01697 if (!any_selected && autorouted_only && !autorouted (l->line)) 01698 continue; 01699 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad) 01700 continue; 01701 o = line_orient (l, 0); 01702 if (o == DIAGONAL) 01703 continue; 01704 l1 = other_line (l->s, l); 01705 if (!l1) 01706 continue; 01707 o1 = line_orient (l1, l->s); 01708 l2 = other_line (l->e, l); 01709 if (!l2) 01710 continue; 01711 o2 = line_orient (l2, l->e); 01712 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL) 01713 continue; 01714 01715 dprintf ("\nline: %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y); 01716 w = l->line->Thickness / 2 + SB + 1; 01717 empty_rect (&rr); 01718 add_line_to_rect (&rr, l1); 01719 add_line_to_rect (&rr, l2); 01720 if (rr.x1 != l->s->x && rr.x1 != l->e->x) 01721 rr.x1 -= w; 01722 if (rr.x2 != l->s->x && rr.x2 != l->e->x) 01723 rr.x2 += w; 01724 if (rr.y1 != l->s->y && rr.y1 != l->e->y) 01725 rr.y1 -= w; 01726 if (rr.y2 != l->s->y && rr.y2 != l->e->y) 01727 rr.y2 += w; 01728 dprintf ("range: x %#mS..%#mS y %#mS..%#mS\n", rr.x1, rr.x2, rr.y1, rr.y2); 01729 01730 c1 = other_corner (l1, l->s); 01731 c2 = other_corner (l2, l->e); 01732 01733 empty_rect (&rp); 01734 for (c = corners; c; c = c->next) 01735 { 01736 if (DELETED (c)) 01737 continue; 01738 if (c->net != l->s->net 01739 && intersecting_layers (c->layer, l->s->layer)) 01740 add_corner_to_rect_if (&rp, c, &rr); 01741 } 01742 if (rp.x1 == INT_MAX) 01743 { 01744 rp.x1 = rr.x2; 01745 rp.x2 = rr.x1; 01746 rp.y1 = rr.y2; 01747 rp.y2 = rr.y1; 01748 } 01749 dprintf ("pin r: x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2); 01750 01751 switch (o1) 01752 { 01753 case LEFT: 01754 step = l->s->x - rp.x2 - w; 01755 step = gridsnap (step); 01756 if (step > l->s->x - c1->x) 01757 step = l->s->x - c1->x; 01758 if (step > l->s->x - c2->x) 01759 step = l->s->x - c2->x; 01760 if (step > 0) 01761 { 01762 dprintf ("left step %#mS at %#mD\n", step, l->s->x, l->s->y); 01763 move_corner (l->s, l->s->x - step, l->s->y); 01764 move_corner (l->e, l->e->x - step, l->e->y); 01765 rv += step; 01766 } 01767 break; 01768 case RIGHT: 01769 step = rp.x1 - l->s->x - w; 01770 step = gridsnap (step); 01771 if (step > c1->x - l->s->x) 01772 step = c1->x - l->s->x; 01773 if (step > c2->x - l->s->x) 01774 step = c2->x - l->s->x; 01775 if (step > 0) 01776 { 01777 dprintf ("right step %#mS at %#mD\n", step, l->s->x, l->s->y); 01778 move_corner (l->s, l->s->x + step, l->s->y); 01779 move_corner (l->e, l->e->x + step, l->e->y); 01780 rv += step; 01781 } 01782 break; 01783 case UP: 01784 if (rp.y2 == INT_MIN) 01785 rp.y2 = rr.y1; 01786 step = trim_step (l->s->y - rp.y2 - w, 01787 l->s->y - c1->y, l->s->y - c2->y); 01788 if (step > 0) 01789 { 01790 dprintf ("up step %#mS at %#mD\n", step, l->s->x, l->s->y); 01791 move_corner (l->s, l->s->x, l->s->y - step); 01792 move_corner (l->e, l->e->x, l->e->y - step); 01793 rv += step; 01794 } 01795 break; 01796 case DOWN: 01797 step = rp.y1 - l->s->y - w; 01798 step = gridsnap (step); 01799 if (step > c1->y - l->s->y) 01800 step = c1->y - l->s->y; 01801 if (step > c2->y - l->s->y) 01802 step = c2->y - l->s->y; 01803 if (step > 0) 01804 { 01805 dprintf ("down step %#mS at %#mD\n", step, l->s->x, l->s->y); 01806 move_corner (l->s, l->s->x, l->s->y + step); 01807 move_corner (l->e, l->e->x, l->e->y + step); 01808 rv += step; 01809 } 01810 break; 01811 } 01812 check (0, l); 01813 } 01814 01815 rv += simple_optimizations (); 01816 if (rv) 01817 pcb_printf ("debumpify: %ml mils saved\n", rv / 50); 01818 return rv; 01819 } 01820 01821 static int 01822 simple_corner (corner_s * c) 01823 { 01824 int o1, o2; 01825 if (c->pad || c->pin || c->via) 01826 return 0; 01827 if (c->n_lines != 2) 01828 return 0; 01829 o1 = line_orient (c->lines[0], c); 01830 o2 = line_orient (c->lines[1], c); 01831 if (ORIENT (o1) == ORIENT (o2)) 01832 return 0; 01833 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL) 01834 return 0; 01835 return 1; 01836 } 01837 01841 static int 01842 unjaggy_once () 01843 { 01844 int rv = 0; 01845 corner_s *c, *c0, *c1, *cc; 01846 int l, w, sel = any_line_selected (); 01847 int o0, o1, s0, s1; 01848 rect_s rr, rp; 01849 for (c = corners; c; c = c->next) 01850 { 01851 if (DELETED (c)) 01852 continue; 01853 if (!simple_corner (c)) 01854 continue; 01855 if (!c->lines[0]->line || !c->lines[1]->line) 01856 continue; 01857 if (sel && !(selected (c->lines[0]->line) 01858 || selected (c->lines[1]->line))) 01859 continue; 01860 if (!sel && autorouted_only 01861 && !(autorouted (c->lines[0]->line) 01862 || autorouted (c->lines[1]->line))) 01863 continue; 01864 dprintf ("simple at %#mD\n", c->x, c->y); 01865 01866 c0 = other_corner (c->lines[0], c); 01867 o0 = line_orient (c->lines[0], c); 01868 s0 = simple_corner (c0); 01869 01870 c1 = other_corner (c->lines[1], c); 01871 o1 = line_orient (c->lines[1], c); 01872 s1 = simple_corner (c1); 01873 01874 if (!s0 && !s1) 01875 continue; 01876 dprintf ("simples at %#mD\n", c->x, c->y); 01877 01878 w = 1; 01879 for (l = 0; l < c0->n_lines; l++) 01880 if (c0->lines[l] != c->lines[0] 01881 && c0->lines[l]->layer == c->lines[0]->layer) 01882 { 01883 int o = line_orient (c0->lines[l], c0); 01884 if (o == o1) 01885 w = 0; 01886 } 01887 for (l = 0; l < c1->n_lines; l++) 01888 if (c1->lines[l] != c->lines[0] 01889 && c1->lines[l]->layer == c->lines[0]->layer) 01890 { 01891 int o = line_orient (c1->lines[l], c1); 01892 if (o == o0) 01893 w = 0; 01894 } 01895 if (!w) 01896 continue; 01897 dprintf ("orient ok\n"); 01898 01899 w = c->lines[0]->line->Thickness / 2 + SB + 1; 01900 empty_rect (&rr); 01901 add_line_to_rect (&rr, c->lines[0]); 01902 add_line_to_rect (&rr, c->lines[1]); 01903 if (c->x != rr.x1) 01904 rr.x1 -= w; 01905 else 01906 rr.x2 += w; 01907 if (c->y != rr.y1) 01908 rr.y1 -= w; 01909 else 01910 rr.y2 += w; 01911 01912 empty_rect (&rp); 01913 for (cc = corners; cc; cc = cc->next) 01914 { 01915 if (DELETED (cc)) 01916 continue; 01917 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer)) 01918 add_corner_to_rect_if (&rp, cc, &rr); 01919 } 01920 dprintf ("rp x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2); 01921 if (rp.x1 <= rp.x2) /* something triggered */ 01922 continue; 01923 01924 dprintf ("unjaggy at %#mD layer %d\n", c->x, c->y, c->layer); 01925 if (c->x == c0->x) 01926 move_corner (c, c1->x, c0->y); 01927 else 01928 move_corner (c, c0->x, c1->y); 01929 rv++; 01930 check (c, 0); 01931 } 01932 rv += simple_optimizations (); 01933 check (c, 0); 01934 return rv; 01935 } 01936 01937 static int 01938 unjaggy () 01939 { 01940 int i, r = 0, j; 01941 for (i = 0; i < 100; i++) 01942 { 01943 j = unjaggy_once (); 01944 if (j == 0) 01945 break; 01946 r += j; 01947 } 01948 if (r) 01949 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies"); 01950 return r; 01951 } 01952 01957 static int 01958 vianudge () 01959 { 01960 int rv = 0; 01961 corner_s *c, *c2, *c3; 01962 line_s *l; 01963 unsigned char directions[MAX_LAYER]; 01964 unsigned char counts[MAX_LAYER]; 01965 01966 memset (directions, 0, sizeof (directions)); 01967 memset (counts, 0, sizeof (counts)); 01968 01969 for (c = corners; c; c = c->next) 01970 { 01971 int o, i, vr, cr, oboth; 01972 int len = 0, saved = 0; 01973 01974 if (DELETED (c)) 01975 continue; 01976 01977 if (!c->via) 01978 continue; 01979 01980 memset (directions, 0, sizeof (directions)); 01981 memset (counts, 0, sizeof (counts)); 01982 01983 for (i = 0; i < c->n_lines; i++) 01984 { 01985 o = line_orient (c->lines[i], c); 01986 counts[c->lines[i]->layer]++; 01987 directions[c->lines[i]->layer] |= o; 01988 } 01989 for (o = 0, i = 0; i < max_copper_layer; i++) 01990 if (counts[i] == 1) 01991 { 01992 o = directions[i]; 01993 break; 01994 } 01995 switch (o) 01996 { 01997 case LEFT: 01998 case RIGHT: 01999 oboth = LEFT | RIGHT; 02000 break; 02001 case UP: 02002 case DOWN: 02003 oboth = UP | DOWN; 02004 break; 02005 default: 02006 continue; 02007 } 02008 for (i = 0; i < max_copper_layer; i++) 02009 if (counts[i] && directions[i] != o && directions[i] != oboth) 02010 goto vianudge_continue; 02011 02012 c2 = 0; 02013 for (i = 0; i < c->n_lines; i++) 02014 { 02015 int ll = line_length (c->lines[i]); 02016 if (line_orient (c->lines[i], c) != o) 02017 { 02018 saved--; 02019 continue; 02020 } 02021 saved++; 02022 if (c2 == 0 || len > ll) 02023 { 02024 len = ll; 02025 c2 = other_corner (c->lines[i], c); 02026 } 02027 } 02028 if (c2->pad || c2->pin || c2->via) 02029 continue; 02030 02031 /* Now look for clearance in the new position */ 02032 vr = c->via->Thickness / 2 + SB + 1; 02033 for (c3 = corners; c3; c3 = c3->next) 02034 { 02035 if (DELETED (c3)) 02036 continue; 02037 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad) 02038 { 02039 cr = corner_radius (c3); 02040 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr) 02041 goto vianudge_continue; 02042 } 02043 } 02044 for (l = lines; l; l = l->next) 02045 { 02046 if (DELETED (l)) 02047 continue; 02048 if (l->s->net != c->net) 02049 { 02050 int ld = dist_line_to_point (l, c2); 02051 if (ld < l->line->Thickness / 2 + vr) 02052 goto vianudge_continue; 02053 } 02054 } 02055 02056 /* at this point, we know we can move it */ 02057 02058 dprintf ("vianudge: nudging via at %#mD by %#mS saving %#mS\n", 02059 c->x, c->y, len, saved); 02060 rv += len * saved; 02061 move_corner (c, c2->x, c2->y); 02062 02063 check (c, 0); 02064 02065 vianudge_continue: 02066 continue; 02067 } 02068 02069 if (rv) 02070 pcb_printf ("vianudge: %ml mils saved\n", rv); 02071 return rv; 02072 } 02073 02080 static int 02081 viatrim () 02082 { 02083 line_s *l, *l2; 02084 int i, rv = 0, vrm = 0; 02085 int any_sel = any_line_selected (); 02086 02087 for (l = lines; l; l = l->next) 02088 { 02089 rect_s r; 02090 int my_layer, other_layer; 02091 02092 if (DELETED (l)) 02093 continue; 02094 if (!l->s->via) 02095 continue; 02096 if (!l->e->via) 02097 continue; 02098 if (any_sel && !selected (l->line)) 02099 continue; 02100 if (!any_sel && autorouted_only && !autorouted (l->line)) 02101 continue; 02102 02103 my_layer = l->layer; 02104 other_layer = -1; 02105 dprintf ("line %p on layer %d from %#mD to %#mD\n", (void *) l, 02106 l->layer, l->s->x, l->s->y, l->e->x, l->e->y); 02107 for (i = 0; i < l->s->n_lines; i++) 02108 if (l->s->lines[i] != l) 02109 { 02110 if (other_layer == -1) 02111 { 02112 other_layer = l->s->lines[i]->layer; 02113 dprintf ("noting other line %p on layer %d\n", 02114 (void *) (l->s->lines[i]), my_layer); 02115 } 02116 else if (l->s->lines[i]->layer != other_layer) 02117 { 02118 dprintf ("saw other line %p on layer %d (not %d)\n", 02119 (void *) (l->s->lines[i]), l->s->lines[i]->layer, 02120 my_layer); 02121 other_layer = -1; 02122 goto viatrim_other_corner; 02123 } 02124 } 02125 viatrim_other_corner: 02126 if (other_layer == -1) 02127 for (i = 0; i < l->e->n_lines; i++) 02128 if (l->e->lines[i] != l) 02129 { 02130 if (other_layer == -1) 02131 { 02132 other_layer = l->s->lines[i]->layer; 02133 dprintf ("noting other line %p on layer %d\n", 02134 (void *) (l->s->lines[i]), my_layer); 02135 } 02136 else if (l->e->lines[i]->layer != other_layer) 02137 { 02138 dprintf ("saw end line on layer %d (not %d)\n", 02139 l->e->lines[i]->layer, other_layer); 02140 goto viatrim_continue; 02141 } 02142 } 02143 02144 /* Now see if any other line intersects us. We don't need to 02145 check corners, because they'd either be pins/vias and 02146 already conflict, or pads, which we'll check here anyway. */ 02147 empty_rect (&r); 02148 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness); 02149 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness); 02150 02151 for (l2 = lines; l2; l2 = l2->next) 02152 { 02153 if (DELETED (l2)) 02154 continue; 02155 if (l2->s->net != l->s->net && l2->layer == other_layer) 02156 { 02157 dprintf ("checking other line %#mD to %#mD\n", l2->s->x, 02158 l2->s->y, l2->e->x, l2->e->y); 02159 if (line_in_rect (&r, l2)) 02160 { 02161 dprintf ("line from %#mD to %#mD in the way\n", 02162 l2->s->x, l2->s->y, l2->e->x, l2->e->y); 02163 goto viatrim_continue; 02164 } 02165 } 02166 } 02167 02168 if (l->layer == other_layer) 02169 continue; 02170 move_line_to_layer (l, other_layer); 02171 rv++; 02172 02173 viatrim_continue: 02174 continue; 02175 } 02176 vrm = simple_optimizations (); 02177 if (rv > 0) 02178 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm); 02179 return rv + vrm; 02180 } 02181 02182 static int 02183 automagic () 02184 { 02185 int more = 1, oldmore = 0; 02186 int toomany = 100; 02187 while (more != oldmore && --toomany) 02188 { 02189 oldmore = more; 02190 more += debumpify (); 02191 more += unjaggy (); 02192 more += orthopull (); 02193 more += vianudge (); 02194 more += viatrim (); 02195 } 02196 return more - 1; 02197 } 02198 02199 static int 02200 miter () 02201 { 02202 corner_s *c; 02203 int done, progress; 02204 int sel = any_line_selected (); 02205 int saved = 0; 02206 02207 for (c = corners; c; c = c->next) 02208 { 02209 if (DELETED (c)) 02210 continue; 02211 c->miter = 0; 02212 if (c->n_lines == 2 && !c->via && !c->pin && !c->via) 02213 { 02214 int o1 = line_orient (c->lines[0], c); 02215 int o2 = line_orient (c->lines[1], c); 02216 if (ORIENT (o1) != ORIENT (o2) 02217 && o1 != DIAGONAL && o2 != DIAGONAL 02218 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness) 02219 c->miter = -1; 02220 } 02221 } 02222 02223 done = 0; 02224 progress = 1; 02225 while (!done && progress) 02226 { 02227 done = 1; 02228 progress = 0; 02229 for (c = corners; c; c = c->next) 02230 { 02231 if (DELETED (c)) 02232 continue; 02233 if (c->miter == -1) 02234 { 02235 int max = line_length (c->lines[0]); 02236 int len = line_length (c->lines[1]); 02237 int bloat; 02238 int ref, dist; 02239 corner_s *closest_corner = 0, *c2, *oc1, *oc2; 02240 int mx = 0, my = 0, x, y; 02241 int o1 = line_orient (c->lines[0], c); 02242 int o2 = line_orient (c->lines[1], c); 02243 02244 if (c->pad || c->pin || c->via) 02245 { 02246 c->miter = 0; 02247 progress = 1; 02248 continue; 02249 } 02250 02251 oc1 = other_corner (c->lines[0], c); 02252 oc2 = other_corner (c->lines[1], c); 02253 #if 0 02254 if (oc1->pad) 02255 oc1 = 0; 02256 if (oc2->pad) 02257 oc2 = 0; 02258 #endif 02259 02260 if ((sel && !(selected (c->lines[0]->line) 02261 || selected (c->lines[1]->line))) 02262 || (!sel && autorouted_only 02263 && !(autorouted (c->lines[0]->line) 02264 || autorouted (c->lines[1]->line)))) 02265 { 02266 c->miter = 0; 02267 progress = 1; 02268 continue; 02269 } 02270 02271 if (max > len) 02272 max = len; 02273 switch (o1) 02274 { 02275 case LEFT: 02276 mx = -1; 02277 break; 02278 case RIGHT: 02279 mx = 1; 02280 break; 02281 case UP: 02282 my = -1; 02283 break; 02284 case DOWN: 02285 my = 1; 02286 break; 02287 } 02288 switch (o2) 02289 { 02290 case LEFT: 02291 mx = -1; 02292 break; 02293 case RIGHT: 02294 mx = 1; 02295 break; 02296 case UP: 02297 my = -1; 02298 break; 02299 case DOWN: 02300 my = 1; 02301 break; 02302 } 02303 ref = c->x * mx + c->y * my; 02304 dist = max; 02305 02306 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2; 02307 02308 for (c2 = corners; c2; c2 = c2->next) 02309 { 02310 if (DELETED (c2)) 02311 continue; 02312 if (c2 != c && c2 != oc1 && c2 != oc2 02313 && c->x * mx <= c2->x * mx 02314 && c->y * my <= c2->y * my 02315 && c->net != c2->net 02316 && intersecting_layers (c->layer, c2->layer)) 02317 { 02318 int cr = corner_radius (c2); 02319 len = c2->x * mx + c2->y * my - ref - cr - bloat; 02320 if (c->x != c2->x && c->y != c2->y) 02321 len -= cr; 02322 if (len < dist || (len == dist && c->miter != -1)) 02323 { 02324 dist = len; 02325 closest_corner = c2; 02326 } 02327 } 02328 } 02329 02330 if (closest_corner && closest_corner->miter == -1) 02331 { 02332 done = 0; 02333 continue; 02334 } 02335 02336 #if 0 02337 if (dist < Settings.Grid) 02338 { 02339 c->miter = 0; 02340 progress = 1; 02341 continue; 02342 } 02343 02344 dist -= dist % Settings.Grid; 02345 #endif 02346 if (dist <= 0) 02347 { 02348 c->miter = 0; 02349 progress = 1; 02350 continue; 02351 } 02352 02353 x = c->x; 02354 y = c->y; 02355 switch (o1) 02356 { 02357 case LEFT: 02358 x -= dist; 02359 break; 02360 case RIGHT: 02361 x += dist; 02362 break; 02363 case UP: 02364 y -= dist; 02365 break; 02366 case DOWN: 02367 y += dist; 02368 break; 02369 } 02370 c2 = find_corner (x, y, c->layer); 02371 if (c2 != other_corner (c->lines[0], c)) 02372 split_line (c->lines[0], c2); 02373 x = c->x; 02374 y = c->y; 02375 switch (o2) 02376 { 02377 case LEFT: 02378 x -= dist; 02379 break; 02380 case RIGHT: 02381 x += dist; 02382 break; 02383 case UP: 02384 y -= dist; 02385 break; 02386 case DOWN: 02387 y += dist; 02388 break; 02389 } 02390 move_corner (c, x, y); 02391 c->miter = 0; 02392 c2->miter = 0; 02393 progress = 1; 02394 saved++; 02395 } 02396 } 02397 } 02398 return saved; 02399 } 02400 02401 static void 02402 classify_corner (corner_s * c, int this_net) 02403 { 02404 int i; 02405 if (c->net == this_net) 02406 return; 02407 c->net = this_net; 02408 for (i = 0; i < c->n_lines; i++) 02409 classify_corner (other_corner (c->lines[i], c), this_net); 02410 } 02411 02412 static void 02413 classify_nets () 02414 { 02415 static int this_net = 1; 02416 corner_s *c; 02417 02418 for (c = corners; c; c = c->next) 02419 { 02420 if (DELETED (c)) 02421 continue; 02422 if (c->net) 02423 continue; 02424 classify_corner (c, this_net); 02425 this_net++; 02426 } 02427 } 02428 02429 #if 0 02430 /* Not used */ 02431 static void 02432 dump_all () 02433 { 02434 corner_s *c; 02435 line_s *l; 02436 for (c = corners; c; c = c->next) 02437 { 02438 if (DELETED (c)) 02439 continue; 02440 printf ("%p corner %d,%d layer %d net %d\n", 02441 (void *) c, c->x, c->y, c->layer, c->net); 02442 } 02443 for (l = lines; l; l = l->next) 02444 { 02445 if (DELETED (l)) 02446 continue; 02447 printf ("%p line %p to %p layer %d\n", 02448 (void *) l, (void *) (l->s), (void *) (l->e), l->layer); 02449 } 02450 } 02451 #endif 02452 02453 #if 0 02454 static void 02455 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner) 02456 { 02457 int ox = c->x; 02458 int oy = c->y; 02459 int l; 02460 if (prev_corner && (c->pin || c->pad)) 02461 return; 02462 move_corner (c, ox + dx, oy + dy); 02463 for (l = 0; l < c->n_lines; l++) 02464 { 02465 corner_s *oc = other_corner (c->lines[l], c); 02466 if (oc == prev_corner) 02467 continue; 02468 if (dx && oc->x == ox) 02469 nudge_corner (oc, dx, 0, c); 02470 if (dy && oc->y == oy) 02471 nudge_corner (oc, 0, dy, c); 02472 } 02473 } 02474 #endif 02475 02476 static line_s * 02477 choose_example_line (corner_s * c1, corner_s * c2) 02478 { 02479 int ci, li; 02480 corner_s *c[2]; 02481 c[0] = c1; 02482 c[1] = c2; 02483 dprintf ("choose_example_line\n"); 02484 for (ci = 0; ci < 2; ci++) 02485 for (li = 0; li < c[ci]->n_lines; li++) 02486 { 02487 dprintf (" try[%d,%d] \033[36m<%#mD-%#mD t%#mS c%#mS f%s>\033[0m\n", 02488 ci, li, 02489 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y, 02490 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y, 02491 c[ci]->lines[li]->line->Thickness, 02492 c[ci]->lines[li]->line->Clearance, 02493 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE)); 02494 /* Pads are disqualified, as we want to mimic a trace line. */ 02495 if (c[ci]->lines[li]->line == (LineType *) c[ci]->pad) 02496 { 02497 dprintf (" bad, pad\n"); 02498 continue; 02499 } 02500 /* Lines on layers that don't connect to the other pad are bad too. */ 02501 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer)) 02502 { 02503 dprintf (" bad, layers\n"); 02504 continue; 02505 } 02506 dprintf (" good\n"); 02507 return c[ci]->lines[li]; 02508 } 02509 dprintf ("choose_example_line: none found!\n"); 02510 return 0; 02511 } 02512 02513 static int 02514 connect_corners (corner_s * c1, corner_s * c2) 02515 { 02516 int layer; 02517 line_s *ex = choose_example_line (c1, c2); 02518 LineType *example = ex->line; 02519 02520 dprintf 02521 ("connect_corners \033[32m%#mD to %#mD, example line %#mD to %#mD l%d\033[0m\n", 02522 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y, 02523 ex->layer); 02524 02525 layer = ex->layer; 02526 02527 /* Assume c1 is the moveable one. */ 02528 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1) 02529 { 02530 int nx, ny; 02531 /* Extend the line */ 02532 if (c1->lines[0]->s->x == c1->lines[0]->e->x) 02533 nx = c1->x, ny = c2->y; 02534 else 02535 nx = c2->x, ny = c1->y; 02536 if (nx != c2->x || ny != c2->y) 02537 { 02538 move_corner (c1, nx, ny); 02539 new_line (c1, c2, layer, example); 02540 return 1; 02541 } 02542 else 02543 { 02544 move_corner (c1, nx, ny); 02545 return 1; 02546 } 02547 } 02548 else 02549 { 02550 corner_s *nc = find_corner (c1->x, c2->y, layer); 02551 new_line (c1, nc, layer, example); 02552 new_line (nc, c2, layer, example); 02553 return 0; 02554 } 02555 } 02556 02564 static void 02565 pinsnap () 02566 { 02567 corner_s *c; 02568 int best_dist[MAX_LAYER + 1]; 02569 corner_s *best_c[MAX_LAYER + 1]; 02570 int l, got_one; 02571 int left = 0, right = 0, top = 0, bottom = 0; 02572 PinType *pin; 02573 int again = 1; 02574 02575 int close = 0; 02576 corner_s *c2; 02577 02578 while (again) 02579 { 02580 again = 0; 02581 for (c = corners; c; c = c->next) 02582 { 02583 if (DELETED (c)) 02584 continue; 02585 if (!(c->pin || c->via || c->pad)) 02586 continue; 02587 02588 pin = 0; 02589 02590 dprintf ("\ncorner %s\n", corner_name (c)); 02591 if (c->pin || c->via) 02592 { 02593 pin = c->pin ? c->pin : c->via; 02594 close = pin->Thickness / 2; 02595 left = c->x - close; 02596 right = c->x + close; 02597 bottom = c->y - close; 02598 top = c->y + close; 02599 } 02600 else if (c->pad) 02601 { 02602 close = c->pad->Thickness / 2 + 1; 02603 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close; 02604 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close; 02605 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close; 02606 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close; 02607 if (c->pad->Point1.X == c->pad->Point2.X) 02608 { 02609 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2; 02610 dprintf ("pad y %#mS %#mS hy %#mS c %#mS\n", c->pad->Point1.Y, 02611 c->pad->Point2.Y, hy, c->y); 02612 if (c->y < hy) 02613 top = hy; 02614 else 02615 bottom = hy + 1; 02616 } 02617 else 02618 { 02619 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2; 02620 dprintf ("pad x %#mS %#mS hx %#mS c %#mS\n", c->pad->Point1.X, 02621 c->pad->Point2.X, hx, c->x); 02622 if (c->x < hx) 02623 right = hx; 02624 else 02625 left = hx + 1; 02626 } 02627 } 02628 02629 dprintf ("%s x %#mS-%#mS y %#mS-%#mS\n", corner_name (c), left, right, bottom, top); 02630 for (l = 0; l <= max_copper_layer; l++) 02631 { 02632 best_dist[l] = close * 2; 02633 best_c[l] = 0; 02634 } 02635 got_one = 0; 02636 for (c2 = corners; c2; c2 = c2->next) 02637 { 02638 int lt; 02639 02640 if (DELETED (c2)) 02641 continue; 02642 lt = corner_radius (c2); 02643 if (c2->n_lines 02644 && c2 != c 02645 && !(c2->pin || c2->pad || c2->via) 02646 && intersecting_layers (c->layer, c2->layer) 02647 && c2->x >= left - lt 02648 && c2->x <= right + lt 02649 && c2->y >= bottom - lt && c2->y <= top + lt) 02650 { 02651 int d = dist (c->x, c->y, c2->x, c2->y); 02652 if (pin && d > pin->Thickness / 2 + lt) 02653 continue; 02654 if (c2->n_lines == 1) 02655 { 02656 got_one++; 02657 dprintf ("found orphan %s vs %s\n", corner_name (c2), 02658 corner_name (c)); 02659 connect_corners (c, c2); 02660 again = 1; 02661 continue; 02662 } 02663 if (best_c[c2->layer] == 0 02664 || c2->n_lines < best_c[c2->layer]->n_lines 02665 || (d < best_dist[c2->layer] 02666 && c2->n_lines <= best_c[c2->layer]->n_lines)) 02667 { 02668 best_dist[c2->layer] = d; 02669 best_c[c2->layer] = c2; 02670 dprintf ("layer %d best now %s\n", c2->layer, 02671 corner_name (c2)); 02672 } 02673 } 02674 if (!got_one && c->n_lines == (c->pad ? 1 : 0)) 02675 { 02676 for (l = 0; l <= max_copper_layer; l++) 02677 if (best_c[l]) 02678 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l])); 02679 for (l = 0; l <= max_copper_layer; l++) 02680 if (best_c[l]) 02681 { 02682 dprintf ("move %s to %s\n", corner_name (best_c[l]), 02683 corner_name (c)); 02684 connect_corners (best_c[l], c); 02685 again = 1; 02686 continue; 02687 } 02688 } 02689 } 02690 } 02691 } 02692 02693 /* Now look for line ends that don't connect, see if they need to be 02694 extended to intersect another line. */ 02695 for (c = corners; c; c = c->next) 02696 { 02697 line_s *l, *t; 02698 int lo; 02699 02700 if (DELETED (c)) 02701 continue; 02702 if (c->pin || c->via || c->pad) 02703 continue; 02704 if (c->n_lines != 1) 02705 continue; 02706 02707 l = c->lines[0]; 02708 lo = line_orient (l, c); 02709 dprintf ("line end %#mD orient %d\n", c->x, c->y, lo); 02710 02711 for (t = lines; t; t = t->next) 02712 { 02713 if (DELETED (t)) 02714 continue; 02715 if (t->layer != c->lines[0]->layer) 02716 continue; 02717 switch (lo) /* remember, orient is for the line relative to the corner */ 02718 { 02719 case LEFT: 02720 if (t->s->x == t->e->x 02721 && c->x < t->s->x 02722 && t->s->x < 02723 c->x + (l->line->Thickness + t->line->Thickness) / 2 02724 && ((t->s->y < c->y && c->y < t->e->y) 02725 || (t->e->y < c->y && c->y < t->s->y))) 02726 { 02727 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y); 02728 move_corner (c, t->s->x, c->y); 02729 } 02730 break; 02731 case RIGHT: 02732 if (t->s->x == t->e->x 02733 && c->x > t->s->x 02734 && t->s->x > 02735 c->x - (l->line->Thickness + t->line->Thickness) / 2 02736 && ((t->s->y < c->y && c->y < t->e->y) 02737 || (t->e->y < c->y && c->y < t->s->y))) 02738 { 02739 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y); 02740 move_corner (c, t->s->x, c->y); 02741 } 02742 break; 02743 case UP: 02744 if (t->s->y == t->e->y 02745 && c->y < t->s->y 02746 && t->s->y < 02747 c->y + (l->line->Thickness + t->line->Thickness) / 2 02748 && ((t->s->x < c->x && c->x < t->e->x) 02749 || (t->e->x < c->x && c->x < t->s->x))) 02750 { 02751 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y); 02752 move_corner (c, c->x, t->s->y); 02753 } 02754 break; 02755 case DOWN: 02756 if (t->s->y == t->e->y 02757 && c->y > t->s->y 02758 && t->s->y > 02759 c->y - (l->line->Thickness + t->line->Thickness) / 2 02760 && ((t->s->x < c->x && c->x < t->e->x) 02761 || (t->e->x < c->x && c->x < t->s->x))) 02762 { 02763 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y); 02764 move_corner (c, c->x, t->s->y); 02765 } 02766 break; 02767 } 02768 } 02769 } 02770 } 02771 02772 static int 02773 pad_orient (PadType * p) 02774 { 02775 if (p->Point1.X == p->Point2.X) 02776 return O_VERT; 02777 if (p->Point1.Y == p->Point2.Y) 02778 return O_HORIZ; 02779 return DIAGONAL; 02780 } 02781 02782 static void 02783 padcleaner () 02784 { 02785 line_s *l, *nextl; 02786 int close; 02787 rect_s r; 02788 02789 dprintf ("\ndj: padcleaner\n"); 02790 for (l = lines; l; l = nextl) 02791 { 02792 nextl = l->next; 02793 02794 if (l->is_pad) 02795 continue; 02796 02797 if (DELETED (l)) 02798 continue; 02799 02800 dprintf ("dj: line %p\n", (void *) l); 02801 check (0, l); 02802 02803 if (l->s->pad && l->s->pad == l->e->pad) 02804 continue; 02805 02806 ALLPAD_LOOP (PCB->Data); 02807 { 02808 int layerflag = 02809 TEST_FLAG (ONSOLDERFLAG, element) ? LT_BOTTOM : LT_TOP; 02810 02811 if (layer_type[l->layer] != layerflag) 02812 continue; 02813 02814 empty_rect (&r); 02815 close = pad->Thickness / 2 + 1; 02816 add_point_to_rect (&r, pad->Point1.X, pad->Point1.Y, close - SB / 2); 02817 add_point_to_rect (&r, pad->Point2.X, pad->Point2.Y, close - SB / 2); 02818 if (pin_in_rect (&r, l->s->x, l->s->y, 0) 02819 && pin_in_rect (&r, l->e->x, l->e->y, 0) 02820 && ORIENT (line_orient (l, 0)) == pad_orient (pad)) 02821 { 02822 dprintf 02823 ("padcleaner %#mD-%#mD %#mS vs line %#mD-%#mD %#mS\n", 02824 pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, 02825 pad->Thickness, l->s->x, l->s->y, l->e->x, l->e->y, 02826 l->line->Thickness); 02827 remove_line (l); 02828 goto next_line; 02829 } 02830 } 02831 ENDALL_LOOP; 02832 next_line:; 02833 } 02834 } 02835 02836 static void 02837 grok_layer_groups () 02838 { 02839 int i, j, f; 02840 LayerGroupType *l = &(PCB->LayerGroups); 02841 02842 solder_layer = component_layer = -1; 02843 for (i = 0; i < max_copper_layer; i++) 02844 { 02845 layer_type[i] = 0; 02846 layer_groupings[i] = 0; 02847 } 02848 for (i = 0; i < max_group; i++) 02849 { 02850 f = 0; 02851 for (j = 0; j < l->Number[i]; j++) 02852 { 02853 if (l->Entries[i][j] == bottom_silk_layer) 02854 f |= LT_BOTTOM; 02855 if (l->Entries[i][j] == top_silk_layer) 02856 f |= LT_TOP; 02857 } 02858 for (j = 0; j < l->Number[i]; j++) 02859 { 02860 if (l->Entries[i][j] < max_copper_layer) 02861 { 02862 layer_type[l->Entries[i][j]] |= f; 02863 layer_groupings[l->Entries[i][j]] = i; 02864 if (solder_layer == -1 && f == LT_BOTTOM) 02865 solder_layer = l->Entries[i][j]; 02866 if (component_layer == -1 && f == LT_TOP) 02867 component_layer = l->Entries[i][j]; 02868 } 02869 } 02870 } 02871 } 02872 02873 static const char djopt_syntax[] = 02874 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull|splitlines)\n" 02875 "djopt(auto) - all of the above\n" 02876 "djopt(miter)"; 02877 02878 static const char djopt_help[] = 02879 "Perform various optimizations on the current board."; 02880 02881 /* %start-doc actions djopt 02882 02883 The different types of optimizations change your board in order to 02884 reduce the total trace length and via count. 02885 02886 @table @code 02887 02888 @item debumpify 02889 Looks for U-shaped traces that can be shortened or eliminated. 02890 02891 Example: 02892 02893 Before debumpify: 02894 02895 @center @image{debumpify,,,Example pcb before debumpify,png} 02896 02897 After debumpify: 02898 02899 @center @image{debumpify.out,,,Example pcb after debumpify,png} 02900 02901 02902 @item unjaggy 02903 Looks for corners which could be flipped to eliminate one or more 02904 corners (i.e. jaggy lines become simpler). 02905 02906 Example: 02907 02908 Before unjaggy: 02909 02910 @center @image{unjaggy,,,Example pcb before unjaggy,png} 02911 02912 After unjaggy: 02913 02914 @center @image{unjaggy.out,,,Example pcb after unjaggy,png} 02915 02916 02917 @item simple 02918 Removing uneeded vias, replacing two or more trace segments in a row 02919 with a single segment. This is usually performed automatically after 02920 other optimizations. 02921 02922 @item vianudge 02923 Looks for vias where all traces leave in the same direction. Tries to 02924 move via in that direction to eliminate one of the traces (and thus a 02925 corner). 02926 02927 Example: 02928 02929 Before vianudge: 02930 02931 @center @image{vianudge,,,Example pcb before vianudge,png} 02932 02933 After vianudge: 02934 02935 @center @image{vianudge.out,,,Example pcb after vianudge,png} 02936 02937 02938 @item viatrim 02939 Looks for traces that go from via to via, where moving that trace to a 02940 different layer eliminates one or both vias. 02941 02942 Example: 02943 02944 Before viatrim: 02945 02946 @center @image{viatrim,,,Example pcb before viatrim,png} 02947 02948 After viatrim: 02949 02950 @center @image{viatrim.out,,,Example pcb after viatrim,png} 02951 02952 02953 @item orthopull 02954 Looks for chains of traces all going in one direction, with more 02955 traces orthogonal on one side than on the other. Moves the chain in 02956 that direction, causing a net reduction in trace length, possibly 02957 eliminating traces and/or corners. 02958 02959 Example: 02960 02961 Before orthopull: 02962 02963 @center @image{orthopull,,,Example pcb before orthopull,png} 02964 02965 After orthopull: 02966 02967 @center @image{orthopull.out,,,Example pcb after orthopull,png} 02968 02969 02970 @item splitlines 02971 Looks for lines that pass through vias, pins, or pads, and splits them 02972 into separate lines so they can be managed separately. 02973 02974 @item auto 02975 Performs the above options, repeating until no further optimizations 02976 can be made. 02977 02978 @item miter 02979 Replaces 90 degree corners with a pair of 45 degree corners, to reduce 02980 RF losses and trace length. 02981 02982 Example: 02983 02984 Before miter: 02985 02986 @center @image{miter,,,Example pcb before miter,png} 02987 02988 After miter: 02989 02990 @center @image{miter.out,,,Example pcb after miter,png} 02991 02992 02993 @end table 02994 02995 %end-doc */ 02996 02997 static int 02998 ActionDJopt (int argc, char **argv, Coord x, Coord y) 02999 { 03000 char *arg = argc > 0 ? argv[0] : 0; 03001 int layn, saved = 0; 03002 corner_s *c; 03003 03004 hid_action("Busy"); 03005 03006 lines = 0; 03007 corners = 0; 03008 03009 grok_layer_groups (); 03010 03011 ELEMENT_LOOP (PCB->Data); 03012 PIN_LOOP (element); 03013 { 03014 c = find_corner (pin->X, pin->Y, -1); 03015 c->pin = pin; 03016 } 03017 END_LOOP; 03018 PAD_LOOP (element); 03019 { 03020 int layern = 03021 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer; 03022 line_s *ls = (line_s *) malloc (sizeof (line_s)); 03023 ls->next = lines; 03024 lines = ls; 03025 ls->is_pad = 1; 03026 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern); 03027 ls->s->pad = pad; 03028 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern); 03029 ls->e->pad = pad; 03030 ls->layer = layern; 03031 ls->line = (LineType *) pad; 03032 add_line_to_corner (ls, ls->s); 03033 add_line_to_corner (ls, ls->e); 03034 03035 } 03036 END_LOOP; 03037 END_LOOP; 03038 VIA_LOOP (PCB->Data); 03039 /* hace don't mess with vias that have thermals */ 03040 /* but then again don't bump into them 03041 if (!TEST_FLAG(ALLTHERMFLAGS, via)) 03042 */ 03043 { 03044 c = find_corner (via->X, via->Y, -1); 03045 c->via = via; 03046 } 03047 END_LOOP; 03048 check (0, 0); 03049 03050 for (layn = 0; layn < max_copper_layer; layn++) 03051 { 03052 LayerType *layer = LAYER_PTR (layn); 03053 if (layer->Type != LT_COPPER) 03054 continue; 03055 03056 LINE_LOOP (layer); 03057 { 03058 line_s *ls; 03059 03060 if(autorouted_only && !autorouted (line)) 03061 continue; 03062 03063 /* don't mess with thermals */ 03064 if (TEST_FLAG (USETHERMALFLAG, line)) 03065 continue; 03066 03067 if (line->Point1.X == line->Point2.X && 03068 line->Point1.Y == line->Point2.Y) 03069 { 03070 RemoveLine (layer, line); 03071 continue; 03072 } 03073 03074 ls = (line_s *) malloc (sizeof (line_s)); 03075 ls->next = lines; 03076 lines = ls; 03077 ls->is_pad = 0; 03078 ls->s = find_corner (line->Point1.X, line->Point1.Y, layn); 03079 ls->e = find_corner (line->Point2.X, line->Point2.Y, layn); 03080 ls->line = line; 03081 add_line_to_corner (ls, ls->s); 03082 add_line_to_corner (ls, ls->e); 03083 ls->layer = layn; 03084 } 03085 END_LOOP; 03086 } 03087 03088 check (0, 0); 03089 if (NSTRCMP (arg, "splitlines") != 0) 03090 pinsnap (); 03091 saved += canonicalize_lines (); 03092 check (0, 0); 03093 classify_nets (); 03094 /*dump_all(); */ 03095 check (0, 0); 03096 03097 if (NSTRCMP (arg, "debumpify") == 0) 03098 saved += debumpify (); 03099 else if (NSTRCMP (arg, "unjaggy") == 0) 03100 saved += unjaggy (); 03101 else if (NSTRCMP (arg, "simple") == 0) 03102 saved += simple_optimizations (); 03103 else if (NSTRCMP (arg, "vianudge") == 0) 03104 saved += vianudge (); 03105 else if (NSTRCMP (arg, "viatrim") == 0) 03106 saved += viatrim (); 03107 else if (NSTRCMP (arg, "orthopull") == 0) 03108 saved += orthopull (); 03109 else if (NSTRCMP (arg, "auto") == 0) 03110 saved += automagic (); 03111 else if (NSTRCMP (arg, "miter") == 0) 03112 saved += miter (); 03113 else if (NSTRCMP (arg, "splitlines") == 0) 03114 /* Just to call canonicalize_lines() above. */ ; 03115 else 03116 { 03117 printf ("unknown command: %s\n", arg); 03118 return 1; 03119 } 03120 03121 padcleaner (); 03122 03123 check (0, 0); 03124 if (saved) 03125 IncrementUndoSerialNumber (); 03126 return 0; 03127 } 03128 03129 HID_Action djopt_action_list[] = { 03130 {"djopt", 0, ActionDJopt, 03131 djopt_help, djopt_syntax} 03132 , 03133 {"OptAutoOnly", 0, djopt_set_auto_only, 03134 djopt_sao_help, djopt_sao_syntax} 03135 }; 03136 03137 REGISTER_ACTIONS (djopt_action_list)