pcb 4.1.1
An interactive printed circuit board layout editor.

djopt.c

Go to the documentation of this file.
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)