1 /*!
2 * \file src/djopt.c
3 *
4 * \brief .
5 *
6 * <hr>
7 *
8 * <h1><b>Copyright.</b></h1>\n
9 *
10 * PCB, interactive printed circuit board design
11 *
12 * Copyright (C) 2003 DJ Delorie
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 *
28 * Contact addresses for paper mail and Email:
29 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
30 * dj@delorie.com
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "global.h"
38
39 #include <memory.h>
40 #include <limits.h>
41
42
43 #include "data.h"
44 #include "create.h"
45 #include "remove.h"
46 #include "move.h"
47 #include "draw.h"
48 #include "undo.h"
49 #include "strflags.h"
50 #include "find.h"
51 #include "pcb-printf.h"
52
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
56
57 #ifndef HAVE_RINT
58 #define rint(x) (ceil((x) - 0.5))
59 #endif
60
61 #define dprintf if(0)pcb_printf
62
63 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x))
64 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x))
65
66 #define SB (PCB->Bloat+1)
67
68 /* must be 2^N-1 */
69 #define INC 7
70
71 #define O_HORIZ 0x10
72 #define O_VERT 0x20
73 #define LEFT 0x11
74 #define RIGHT 0x12
75 #define UP 0x24
76 #define DOWN 0x28
77 #define DIAGONAL 0xf0
78 #define ORIENT(x) ((x) & 0xf0)
79 #define DIRECT(x) ((x) & 0x0f)
80
81 #define LONGEST_FRECKLE 2 /*!< Manhattan length of the longest "freckle" */
82
83
84 struct line_s;
85
86 typedef struct corner_s
87 {
88 int layer;
89 struct corner_s *next;
90 int x, y;
91 int net;
92 PinType *via;
93 PadType *pad;
94 PinType *pin;
95 int miter;
96 int n_lines;
97 struct line_s **lines;
98 } corner_s;
99
100 typedef struct line_s
101 {
102 int layer;
103 struct line_s *next;
104 corner_s *s, *e;
105 LineType *line;
106 char is_pad;
107 } line_s;
108
109 typedef struct rect_s
110 {
111 int x1, y1, x2, y2;
112 } rect_s;
113
114 #define DELETE(q) (q)->layer = 0xdeadbeef
115 #define DELETED(q) ((q)->layer == 0xdeadbeef)
116
117 static corner_s *corners, *next_corner = 0;
118 static line_s *lines;
119
120 static int layer_groupings[MAX_LAYER];
121 static char layer_type[MAX_LAYER];
122 #define LT_TOP 1
123 #define LT_BOTTOM 2
124
125 static int autorouted_only = 1;
126
127 static const char djopt_sao_syntax[] = "OptAutoOnly()";
128
129 static const char djopt_sao_help[] =
130 "Toggles the optimize-only-autorouted flag.";
131
132 /* %start-doc actions OptAutoOnly
133
134 The original purpose of the trace optimizer was to clean up the traces
135 created by the various autorouters that have been used with PCB. When
136 a board has a mix of autorouted and carefully hand-routed traces, you
137 don't normally want the optimizer to move your hand-routed traces.
138 But, sometimes you do. By default, the optimizer only optimizes
139 autorouted traces. This action toggles that setting, so that you can
140 optimize hand-routed traces also.
141
142 %end-doc */
143
144 int
djopt_set_auto_only(int argc,char ** argv,Coord x,Coord y)145 djopt_set_auto_only (int argc, char **argv, Coord x, Coord y)
146 {
147 autorouted_only = autorouted_only ? 0 : 1;
148 return 0;
149 }
150
151 static int
djopt_get_auto_only(void * data)152 djopt_get_auto_only (void *data)
153 {
154 return autorouted_only;
155 }
156
157 HID_Flag djopt_flag_list[] = {
158 {"optautoonly", djopt_get_auto_only, NULL}
159 };
160
REGISTER_FLAGS(djopt_flag_list)161 REGISTER_FLAGS (djopt_flag_list)
162
163 static char *
164 element_name_for (corner_s * c)
165 {
166 ELEMENT_LOOP (PCB->Data);
167 {
168 PIN_LOOP (element);
169 {
170 if (pin == c->pin)
171 return element->Name[1].TextString;
172 }
173 END_LOOP;
174 PAD_LOOP (element);
175 {
176 if (pad == c->pad)
177 return element->Name[1].TextString;
178 }
179 END_LOOP;
180 }
181 END_LOOP;
182 return "unknown";
183 }
184
185 static char *
corner_name(corner_s * c)186 corner_name (corner_s * c)
187 {
188 static char buf[4][100];
189 static int bn = 0;
190 char *bp;
191 size_t size_left;
192 bn = (bn + 1) % 4;
193
194 if (c->net == 0xf1eef1ee)
195 {
196 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
197 return buf[bn];
198 }
199
200 sprintf (buf[bn], "\033[%dm[%p ",
201 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
202 bp = buf[bn] + strlen (buf[bn]);
203 size_left = sizeof (buf[bn]) - strlen (buf[bn]);
204
205 if (c->pin)
206 pcb_snprintf (bp, size_left, "pin %s:%s at %#mD",
207 element_name_for (c), c->pin->Number, c->x, c->y);
208 else if (c->via)
209 pcb_snprintf (bp, size_left, "via at %#mD", c->x, c->y);
210 else if (c->pad)
211 {
212 pcb_snprintf (bp, size_left, "pad %s:%s at %#mD %#mD-%#mD",
213 element_name_for (c), c->pad->Number, c->x, c->y,
214 c->pad->Point1.X, c->pad->Point1.Y,
215 c->pad->Point2.X, c->pad->Point2.Y);
216 }
217 else
218 pcb_snprintf (bp, size_left, "at %#mD", c->x, c->y);
219 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
220 return buf[bn];
221 }
222
223 static int solder_layer, component_layer;
224
225 static void
dj_abort(char * msg,...)226 dj_abort (char *msg, ...)
227 {
228 va_list a;
229 va_start (a, msg);
230 vprintf (msg, a);
231 va_end (a);
232 fflush (stdout);
233 abort ();
234 }
235
236 #if 1
237 #define check(c,l)
238 #else
239 #define check(c,l) check2(__LINE__,c,l)
240 static void
check2(int srcline,corner_s * c,line_s * l)241 check2 (int srcline, corner_s * c, line_s * l)
242 {
243 int saw_c = 0, saw_l = 0;
244 corner_s *cc;
245 line_s *ll;
246 int i;
247
248 for (cc = corners; cc; cc = cc->next)
249 {
250 if (DELETED (cc))
251 continue;
252 if (cc == c)
253 saw_c = 1;
254 for (i = 0; i < cc->n_lines; i++)
255 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
256 dj_abort ("check:%d: cc has line without backref\n", srcline);
257 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
258 dj_abort ("check:%d: via not at corner\n", srcline);
259 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
260 dj_abort ("check:%d: pin not at corner\n", srcline);
261 }
262 if (c && !saw_c)
263 dj_abort ("check:%d: corner not in corners list\n", srcline);
264 for (ll = lines; ll; ll = ll->next)
265 {
266 if (DELETED (ll))
267 continue;
268 if (ll == l)
269 saw_l = 1;
270 for (i = 0; i < ll->s->n_lines; i++)
271 if (ll->s->lines[i] == ll)
272 break;
273 if (i == ll->s->n_lines)
274 dj_abort ("check:%d: ll->s has no backref\n", srcline);
275 for (i = 0; i < ll->e->n_lines; i++)
276 if (ll->e->lines[i] == ll)
277 break;
278 if (i == ll->e->n_lines)
279 dj_abort ("check:%d: ll->e has no backref\n", srcline);
280 if (!ll->is_pad
281 && (ll->s->x != ll->line->Point1.X
282 || ll->s->y != ll->line->Point1.Y
283 || ll->e->x != ll->line->Point2.X
284 || ll->e->y != ll->line->Point2.Y))
285 {
286 pcb_printf ("line: %#mD to %#mD pcbline: %#mD to %#mD\n",
287 ll->s->x, ll->s->y,
288 ll->e->x, ll->e->y,
289 ll->line->Point1.X,
290 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
291 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
292 }
293 }
294 if (l && !saw_l)
295 dj_abort ("check:%d: line not in lines list\n", srcline);
296 }
297
298 #endif
299
300 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
301
302 static int
gridsnap(Coord n)303 gridsnap (Coord n)
304 {
305 if (n <= 0)
306 return 0;
307 return n - n % (Settings.Grid);
308 }
309
310 /* Avoid commonly used names. */
311
312 static int
djabs(int x)313 djabs (int x)
314 {
315 return x > 0 ? x : -x;
316 }
317
318 static int
djmax(int x,int y)319 djmax (int x, int y)
320 {
321 return x > y ? x : y;
322 }
323
324 static int
djmin(int x,int y)325 djmin (int x, int y)
326 {
327 return x < y ? x : y;
328 }
329
330 /*!
331 * \brief Find distance between 2 points.
332 *
333 * We use floating point math here because we can fairly easily overflow
334 * a 32 bit integer here.
335 * In fact it only takes 0.46" to do so.
336 */
337 static int
dist(int x1,int y1,int x2,int y2)338 dist (int x1, int y1, int x2, int y2)
339 {
340 double d;
341
342 d = hypot ((double) x1 - (double) x2, (double) y1 - (double) y2);
343 d = rint (d);
344
345 return (int) d;
346 }
347
348 static int
line_length(line_s * l)349 line_length (line_s * l)
350 {
351 if (l->s->x == l->e->x)
352 return djabs (l->s->y - l->e->y);
353 if (l->s->y == l->e->y)
354 return djabs (l->s->x - l->e->x);
355 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
356 }
357
358 static int
dist_ltp2(int dx,int y,int y1,int y2)359 dist_ltp2 (int dx, int y, int y1, int y2)
360 {
361 if (y1 > y2)
362 SWAP (y1, y2);
363 if (y < y1)
364 return dist (dx, y, 0, y1);
365 if (y > y2)
366 return dist (dx, y, 0, y2);
367 return djabs (dx);
368 }
369
370 static int
intersecting_layers(int l1,int l2)371 intersecting_layers (int l1, int l2)
372 {
373 if (l1 == -1 || l2 == -1)
374 return 1;
375 if (l1 == l2)
376 return 1;
377 if (layer_groupings[l1] == layer_groupings[l2])
378 return 1;
379 return 0;
380 }
381
382 static int
dist_line_to_point(line_s * l,corner_s * c)383 dist_line_to_point (line_s * l, corner_s * c)
384 {
385 double len, r, d;
386 /* We can do this quickly if l is vertical or horizontal. */
387 if (l->s->x == l->e->x)
388 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
389 if (l->s->y == l->e->y)
390 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
391
392 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
393 len = hypot (l->s->x - l->e->x, l->s->y - l->e->y);
394 if (len == 0)
395 return dist (l->s->x, l->s->y, c->x, c->y);
396 r =
397 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
398 l->e->x);
399 r /= len * len;
400 if (r < 0)
401 return dist (l->s->x, l->s->y, c->x, c->y);
402 if (r > 1)
403 return dist (l->e->x, l->e->y, c->x, c->y);
404 d =
405 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
406 l->s->y);
407 return (int) (d / len);
408 }
409
410 static int
line_orient(line_s * l,corner_s * c)411 line_orient (line_s * l, corner_s * c)
412 {
413 int x1, y1, x2, y2;
414 if (c == l->s)
415 {
416 x1 = l->s->x;
417 y1 = l->s->y;
418 x2 = l->e->x;
419 y2 = l->e->y;
420 }
421 else
422 {
423 x1 = l->e->x;
424 y1 = l->e->y;
425 x2 = l->s->x;
426 y2 = l->s->y;
427 }
428 if (x1 == x2)
429 {
430 if (y1 < y2)
431 return DOWN;
432 return UP;
433 }
434 else if (y1 == y2)
435 {
436 if (x1 < x2)
437 return RIGHT;
438 return LEFT;
439 }
440 return DIAGONAL;
441 }
442
443 #if 0
444 /* Not used */
445 static corner_s *
446 common_corner (line_s * l1, line_s * l2)
447 {
448 if (l1->s == l2->s || l1->s == l2->e)
449 return l1->s;
450 if (l1->e == l2->s || l1->e == l2->e)
451 return l1->e;
452 dj_abort ("common_corner: no common corner found\n");
453 return NULL;
454 }
455 #endif
456
457 static corner_s *
other_corner(line_s * l,corner_s * c)458 other_corner (line_s * l, corner_s * c)
459 {
460 if (l->s == c)
461 return l->e;
462 if (l->e == c)
463 return l->s;
464 dj_abort ("other_corner: neither corner passed\n");
465 return NULL;
466 }
467
468 static corner_s *
find_corner_if(int x,int y,int l)469 find_corner_if (int x, int y, int l)
470 {
471 corner_s *c;
472 for (c = corners; c; c = c->next)
473 {
474 if (DELETED (c))
475 continue;
476 if (c->x != x || c->y != y)
477 continue;
478 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
479 continue;
480 return c;
481 }
482 return 0;
483 }
484
485 static corner_s *
find_corner(int x,int y,int l)486 find_corner (int x, int y, int l)
487 {
488 corner_s *c;
489 for (c = corners; c; c = c->next)
490 {
491 if (DELETED (c))
492 continue;
493 if (c->x != x || c->y != y)
494 continue;
495 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
496 continue;
497 return c;
498 }
499 c = (corner_s *) malloc (sizeof (corner_s));
500 c->next = corners;
501 corners = c;
502 c->x = x;
503 c->y = y;
504 c->net = 0;
505 c->via = 0;
506 c->pad = 0;
507 c->pin = 0;
508 c->layer = l;
509 c->n_lines = 0;
510 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
511 return c;
512 }
513
514 static void
add_line_to_corner(line_s * l,corner_s * c)515 add_line_to_corner (line_s * l, corner_s * c)
516 {
517 int n;
518 n = (c->n_lines + 1 + INC) & ~INC;
519 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
520 c->lines[c->n_lines] = l;
521 c->n_lines++;
522 dprintf ("add_line_to_corner %#mD\n", c->x, c->y);
523 }
524
525 static LineType *
create_pcb_line(int layer,int x1,int y1,int x2,int y2,int thick,int clear,FlagType flags)526 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
527 int thick, int clear, FlagType flags)
528 {
529 char *from, *to;
530 LineType *nl;
531 LayerType *lyr = LAYER_PTR (layer);
532
533 from = (char *) lyr->Line;
534 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
535 x1, y1, x2, y2, thick, clear, flags);
536 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
537
538 to = (char *) lyr->Line;
539 if (from != to)
540 {
541 line_s *lp;
542 for (lp = lines; lp; lp = lp->next)
543 {
544 if (DELETED (lp))
545 continue;
546 if ((char *) (lp->line) >= from
547 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
548 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
549 }
550 }
551 return nl;
552 }
553
554 static void
new_line(corner_s * s,corner_s * e,int layer,LineType * example)555 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
556 {
557 line_s *ls;
558
559 if (layer >= max_copper_layer)
560 dj_abort ("layer %d\n", layer);
561
562 if (example == NULL)
563 dj_abort ("NULL example passed to new_line()\n", layer);
564
565 if (s->x == e->x && s->y == e->y)
566 return;
567
568 ls = (line_s *) malloc (sizeof (line_s));
569 ls->next = lines;
570 lines = ls;
571 ls->is_pad = 0;
572 ls->s = s;
573 ls->e = e;
574 ls->layer = layer;
575 #if 0
576 if ((example->Point1.X == s->x && example->Point1.Y == s->y
577 && example->Point2.X == e->x && example->Point2.Y == e->y)
578 || (example->Point2.X == s->x && example->Point2.Y == s->y
579 && example->Point1.X == e->x && example->Point1.Y == e->y))
580 {
581 ls->line = example;
582 }
583 else
584 #endif
585 {
586 LineType *nl;
587 dprintf
588 ("New line \033[35m%#mD to %#mD from l%d t%#mS c%#mS f%s\033[0m\n",
589 s->x, s->y, e->x, e->y, layer, example->Thickness,
590 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
591 nl =
592 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
593 example->Clearance, example->Flags);
594
595 if (!nl)
596 dj_abort ("can't create new line!");
597 ls->line = nl;
598 }
599 add_line_to_corner (ls, s);
600 add_line_to_corner (ls, e);
601 check (s, ls);
602 check (e, ls);
603 }
604
605 #if 0
606 /* Not used */
607 static int
608 c_orth_to (corner_s * c, line_s * l, int o)
609 {
610 int i, o2;
611 int rv = 0;
612 for (i = 0; i < c->n_lines; i++)
613 {
614 if (c->lines[i] == l)
615 continue;
616 o2 = line_orient (c->lines[i], c);
617 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
618 return 0;
619 rv++;
620 }
621 return rv;
622 }
623 #endif
624
625 static line_s *
other_line(corner_s * c,line_s * l)626 other_line (corner_s * c, line_s * l)
627 {
628 int i;
629 line_s *rv = 0;
630 if (c->pin || c->pad || c->via)
631 return 0;
632 for (i = 0; i < c->n_lines; i++)
633 {
634 if (c->lines[i] == l)
635 continue;
636 if (rv)
637 return 0;
638 rv = c->lines[i];
639 }
640 return rv;
641 }
642
643 static void
empty_rect(rect_s * rect)644 empty_rect (rect_s * rect)
645 {
646 rect->x1 = rect->y1 = INT_MAX;
647 rect->x2 = rect->y2 = INT_MIN;
648 }
649
650 static void
add_point_to_rect(rect_s * rect,int x,int y,int w)651 add_point_to_rect (rect_s * rect, int x, int y, int w)
652 {
653 if (rect->x1 > x - w)
654 rect->x1 = x - w;
655 if (rect->x2 < x + w)
656 rect->x2 = x + w;
657 if (rect->y1 > y - w)
658 rect->y1 = y - w;
659 if (rect->y2 < y + w)
660 rect->y2 = y + w;
661 }
662
663 static void
add_line_to_rect(rect_s * rect,line_s * l)664 add_line_to_rect (rect_s * rect, line_s * l)
665 {
666 add_point_to_rect (rect, l->s->x, l->s->y, 0);
667 add_point_to_rect (rect, l->e->x, l->e->y, 0);
668 }
669
670 static int
pin_in_rect(rect_s * r,int x,int y,int w)671 pin_in_rect (rect_s * r, int x, int y, int w)
672 {
673 if (x < r->x1 && x + w < r->x1)
674 return 0;
675 if (x > r->x2 && x - w > r->x2)
676 return 0;
677 if (y < r->y1 && y + w < r->y1)
678 return 0;
679 if (y > r->y2 && y - w > r->y2)
680 return 0;
681 return 1;
682 }
683
684 static int
line_in_rect(rect_s * r,line_s * l)685 line_in_rect (rect_s * r, line_s * l)
686 {
687 rect_s lr;
688 empty_rect (&lr);
689 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
690 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
691 dprintf ("line_in_rect %#mD-%#mD vs %#mD-%#mD\n",
692 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
693 /* simple intersection of rectangles */
694 if (lr.x1 < r->x1)
695 lr.x1 = r->x1;
696 if (lr.x2 > r->x2)
697 lr.x2 = r->x2;
698 if (lr.y1 < r->y1)
699 lr.y1 = r->y1;
700 if (lr.y2 > r->y2)
701 lr.y2 = r->y2;
702 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
703 return 1;
704 return 0;
705 }
706
707 static int
corner_radius(corner_s * c)708 corner_radius (corner_s * c)
709 {
710 int diam = 0;
711 int i;
712 if (c->pin)
713 diam = djmax (c->pin->Thickness, diam);
714 if (c->via)
715 diam = djmax (c->via->Thickness, diam);
716 for (i = 0; i < c->n_lines; i++)
717 if (c->lines[i]->line)
718 diam = djmax (c->lines[i]->line->Thickness, diam);
719 diam = (diam + 1) / 2;
720 return diam;
721 }
722
723 #if 0
724 /* Not used */
725 static int
726 corner_layer (corner_s * c)
727 {
728 if (c->pin || c->via)
729 return -1;
730 if (c->n_lines < 1)
731 return -1;
732 return c->lines[0]->layer;
733 }
734 #endif
735
736 static void
add_corner_to_rect_if(rect_s * rect,corner_s * c,rect_s * e)737 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
738 {
739 int diam = corner_radius (c);
740 if (!pin_in_rect (e, c->x, c->y, diam))
741 return;
742 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
743 return;
744 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
745 return;
746 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
747 return;
748 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
749 return;
750
751 /*pcb_printf("add point %#mD diam %#mS\n", c->x, c->y, diam); */
752 add_point_to_rect (rect, c->x, c->y, diam);
753 }
754
755 static void
remove_line(line_s * l)756 remove_line (line_s * l)
757 {
758 int i, j;
759 LayerType *layer = &(PCB->Data->Layer[l->layer]);
760
761 check (0, 0);
762
763 if (l->line)
764 RemoveLine (layer, l->line);
765
766 DELETE (l);
767
768 for (i = 0, j = 0; i < l->s->n_lines; i++)
769 if (l->s->lines[i] != l)
770 l->s->lines[j++] = l->s->lines[i];
771 l->s->n_lines = j;
772
773 for (i = 0, j = 0; i < l->e->n_lines; i++)
774 if (l->e->lines[i] != l)
775 l->e->lines[j++] = l->e->lines[i];
776 l->e->n_lines = j;
777 check (0, 0);
778 }
779
780 static void
move_line_to_layer(line_s * l,int layer)781 move_line_to_layer (line_s * l, int layer)
782 {
783 LayerType *ls, *ld;
784
785 ls = LAYER_PTR (l->layer);
786 ld = LAYER_PTR (layer);
787
788 MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
789 l->layer = layer;
790 }
791
792 static void
remove_via_at(corner_s * c)793 remove_via_at (corner_s * c)
794 {
795 RemoveObject (VIA_TYPE, c->via, 0, 0);
796 c->via = 0;
797 }
798
799 static void
remove_corner(corner_s * c2)800 remove_corner (corner_s * c2)
801 {
802 corner_s *c;
803 dprintf ("remove corner %s\n", corner_name (c2));
804 if (corners == c2)
805 corners = c2->next;
806 for (c = corners; c; c = c->next)
807 {
808 if (DELETED (c))
809 continue;
810 if (c->next == c2)
811 c->next = c2->next;
812 }
813 if (next_corner == c2)
814 next_corner = c2->next;
815 free (c2->lines);
816 c2->lines = 0;
817 DELETE (c2);
818 }
819
820 static void
merge_corners(corner_s * c1,corner_s * c2)821 merge_corners (corner_s * c1, corner_s * c2)
822 {
823 int i;
824 if (c1 == c2)
825 abort ();
826 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
827 for (i = 0; i < c2->n_lines; i++)
828 {
829 add_line_to_corner (c2->lines[i], c1);
830 if (c2->lines[i]->s == c2)
831 c2->lines[i]->s = c1;
832 if (c2->lines[i]->e == c2)
833 c2->lines[i]->e = c1;
834 }
835 if (c1->via && c2->via)
836 remove_via_at (c2);
837 else if (c2->via)
838 c1->via = c2->via;
839 if (c2->pad)
840 c1->pad = c2->pad;
841 if (c2->pin)
842 c1->pin = c2->pin;
843 if (c2->layer != c1->layer)
844 c1->layer = -1;
845
846 remove_corner (c2);
847 }
848
849 static void
move_corner(corner_s * c,int x,int y)850 move_corner (corner_s * c, int x, int y)
851 {
852 PinType *via;
853 int i;
854 corner_s *pad;
855
856 check (c, 0);
857 if (c->pad || c->pin)
858 dj_abort ("move_corner: has pin or pad\n");
859 dprintf ("move_corner %p from %#mD to %#mD\n", (void *) c, c->x, c->y, x, y);
860 pad = find_corner_if (x, y, c->layer);
861 c->x = x;
862 c->y = y;
863 via = c->via;
864 if (via)
865 {
866 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
867 dprintf ("via move %#mD to %#mD\n", via->X, via->Y, x, y);
868 }
869 for (i = 0; i < c->n_lines; i++)
870 {
871 LineType *tl = c->lines[i]->line;
872 if (tl)
873 {
874 if (c->lines[i]->s == c)
875 {
876 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
877 &tl->Point1, x - (tl->Point1.X),
878 y - (tl->Point1.Y));
879 }
880 else
881 {
882 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
883 &tl->Point2, x - (tl->Point2.X),
884 y - (tl->Point2.Y));
885 }
886 dprintf ("Line %p moved to %#mD %#mD\n", (void *) tl,
887 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
888 }
889 }
890 if (pad && pad != c)
891 merge_corners (c, pad);
892 else
893 for (i = 0; i < c->n_lines; i++)
894 {
895 if (c->lines[i]->s->x == c->lines[i]->e->x
896 && c->lines[i]->s->y == c->lines[i]->e->y)
897 {
898 corner_s *c2 = other_corner (c->lines[i], c);
899 dprintf ("move_corner: removing line %#mD %#mD %p %p\n",
900 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
901
902 remove_line (c->lines[i]);
903 if (c != c2)
904 merge_corners (c, c2);
905 check (c, 0);
906 i--;
907 break;
908 }
909 }
910 gui->progress (0, 0, 0);
911 check (c, 0);
912 }
913
914 static int
any_line_selected()915 any_line_selected ()
916 {
917 line_s *l;
918 for (l = lines; l; l = l->next)
919 {
920 if (DELETED (l))
921 continue;
922 if (l->line && selected (l->line))
923 return 1;
924 }
925 return 0;
926 }
927
928 static int
trim_step(int s,int l1,int l2)929 trim_step (int s, int l1, int l2)
930 {
931 dprintf ("trim %d %d %d\n", s, l1, l2);
932 if (s > l1)
933 s = l1;
934 if (s > l2)
935 s = l2;
936 if (s != l1 && s != l2)
937 s = gridsnap (s);
938 return s;
939 }
940
941 static int canonicalize_line (line_s * l);
942
943 static int
split_line(line_s * l,corner_s * c)944 split_line (line_s * l, corner_s * c)
945 {
946 int i;
947 LineType *pcbline;
948 line_s *ls;
949
950 if (!intersecting_layers (l->layer, c->layer))
951 return 0;
952 if (l->is_pad)
953 return 0;
954 if (c->pad)
955 {
956 dprintf ("split on pad!\n");
957 if (l->s->pad == c->pad || l->e->pad == c->pad)
958 return 0;
959 dprintf ("splitting...\n");
960 }
961
962 check (c, l);
963 pcbline = create_pcb_line (l->layer,
964 c->x, c->y, l->e->x, l->e->y,
965 l->line->Thickness, l->line->Clearance,
966 l->line->Flags);
967 if (pcbline == 0)
968 return 0; /* already a line there */
969
970 check (c, l);
971
972 dprintf ("split line from %#mD to %#mD at %#mD\n",
973 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
974 ls = (line_s *) malloc (sizeof (line_s));
975
976 ls->next = lines;
977 lines = ls;
978 ls->is_pad = 0;
979 ls->s = c;
980 ls->e = l->e;
981 ls->line = pcbline;
982 ls->layer = l->layer;
983 for (i = 0; i < l->e->n_lines; i++)
984 if (l->e->lines[i] == l)
985 l->e->lines[i] = ls;
986 l->e = c;
987 add_line_to_corner (l, c);
988 add_line_to_corner (ls, c);
989
990 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
991 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
992
993 return 1;
994 }
995
996 static int
canonicalize_line(line_s * l)997 canonicalize_line (line_s * l)
998 {
999 /* This could be faster */
1000 corner_s *c;
1001 if (l->s->x == l->e->x)
1002 {
1003 int y1 = l->s->y;
1004 int y2 = l->e->y;
1005 int x1 = l->s->x - l->line->Thickness / 2;
1006 int x2 = l->s->x + l->line->Thickness / 2;
1007 if (y1 > y2)
1008 {
1009 int t = y1;
1010 y1 = y2;
1011 y2 = t;
1012 }
1013 for (c = corners; c; c = c->next)
1014 {
1015 if (DELETED (c))
1016 continue;
1017 if ((y1 < c->y && c->y < y2)
1018 && intersecting_layers (l->layer, c->layer))
1019 {
1020 if (c->x != l->s->x
1021 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1022 {
1023 move_corner (c, l->s->x, c->y);
1024 }
1025 if (c->x == l->s->x)
1026 {
1027 /* FIXME: if the line is split, we have to re-canonicalize
1028 both segments. */
1029 return split_line (l, c);
1030 }
1031 }
1032 }
1033 }
1034 else if (l->s->y == l->e->y)
1035 {
1036 int x1 = l->s->x;
1037 int x2 = l->e->x;
1038 int y1 = l->s->y - l->line->Thickness / 2;
1039 int y2 = l->s->y + l->line->Thickness / 2;
1040 if (x1 > x2)
1041 {
1042 int t = x1;
1043 x1 = x2;
1044 x2 = t;
1045 }
1046 for (c = corners; c; c = c->next)
1047 {
1048 if (DELETED (c))
1049 continue;
1050 if ((x1 < c->x && c->x < x2)
1051 && intersecting_layers (l->layer, c->layer))
1052 {
1053 if (c->y != l->s->y
1054 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1055 {
1056 move_corner (c, c->x, l->s->y);
1057 }
1058 if (c->y == l->s->y)
1059 {
1060 /* FIXME: Likewise. */
1061 return split_line (l, c);
1062 }
1063 }
1064 }
1065 }
1066 else
1067 {
1068 /* diagonal lines. Let's try to split them at pins/vias
1069 anyway. */
1070 int x1 = l->s->x;
1071 int x2 = l->e->x;
1072 int y1 = l->s->y;
1073 int y2 = l->e->y;
1074 if (x1 > x2)
1075 {
1076 int t = x1;
1077 x1 = x2;
1078 x2 = t;
1079 }
1080 if (y1 > y2)
1081 {
1082 int t = y1;
1083 y1 = y2;
1084 y2 = t;
1085 }
1086 for (c = corners; c; c = c->next)
1087 {
1088 if (DELETED (c))
1089 continue;
1090 if (!c->via && !c->pin)
1091 continue;
1092 if ((x1 < c->x && c->x < x2)
1093 && (y1 < c->y && c->y < y2)
1094 && intersecting_layers (l->layer, c->layer))
1095 {
1096 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1097 th /= 2;
1098 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1099 && dist (l->e->x, l->e->y, c->x, c->y) > th
1100 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1101 {
1102 return split_line (l, c);
1103 }
1104 }
1105 }
1106 }
1107 return 0;
1108 }
1109
1110 /*!
1111 * \brief Make sure all vias are at line end points.
1112 */
1113 static int
canonicalize_lines()1114 canonicalize_lines ()
1115 {
1116 int changes = 0;
1117 int count;
1118 line_s *l;
1119 while (1)
1120 {
1121 count = 0;
1122 for (l = lines; l; l = l->next)
1123 {
1124 if (DELETED (l))
1125 continue;
1126 count += canonicalize_line (l);
1127 }
1128 changes += count;
1129 if (count == 0)
1130 break;
1131 }
1132 return changes;
1133 }
1134
1135 static int
simple_optimize_corner(corner_s * c)1136 simple_optimize_corner (corner_s * c)
1137 {
1138 int i;
1139 int rv = 0;
1140
1141 check (c, 0);
1142 if (c->via)
1143 {
1144 /* see if no via is needed */
1145 if (selected (c->via))
1146 dprintf ("via check: line[0] layer %d at %#mD nl %d\n",
1147 c->lines[0]->layer, c->x, c->y, c->n_lines);
1148 /* We can't delete vias that connect to power planes, or vias
1149 that aren't tented (assume they're test points). */
1150 if (!TEST_ANY_THERMS (c->via)
1151 && c->via->Mask == 0)
1152 {
1153 for (i = 1; i < c->n_lines; i++)
1154 {
1155 if (selected (c->via))
1156 dprintf (" line[%d] layer %d %#mD to %#mD\n",
1157 i, c->lines[i]->layer,
1158 c->lines[i]->s->x, c->lines[i]->s->y,
1159 c->lines[i]->e->x, c->lines[i]->e->y);
1160 if (c->lines[i]->layer != c->lines[0]->layer)
1161 break;
1162 }
1163 if (i == c->n_lines)
1164 {
1165 if (selected (c->via))
1166 dprintf (" remove it\n");
1167 remove_via_at (c);
1168 rv++;
1169 }
1170 }
1171 }
1172
1173 check (c, 0);
1174 if (c->n_lines == 2 && !c->via)
1175 {
1176 /* see if it is an unneeded corner */
1177 int o = line_orient (c->lines[0], c);
1178 corner_s *c2 = other_corner (c->lines[1], c);
1179 corner_s *c0 = other_corner (c->lines[0], c);
1180 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1181 {
1182 dprintf ("straight %#mD to %#mD to %#mD\n",
1183 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1184 if (selected (c->lines[0]->line))
1185 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1186 if (selected (c->lines[1]->line))
1187 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1188 move_corner (c, c2->x, c2->y);
1189 }
1190 }
1191 check (c, 0);
1192 if (c->n_lines == 1 && !c->via)
1193 {
1194 corner_s *c0 = other_corner (c->lines[0], c);
1195 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE)
1196 {
1197 /*
1198 * Remove this line, as it is a "freckle". A freckle is an extremely
1199 * short line (around 0.01 thou) that is unconnected at one end.
1200 * Freckles are almost insignificantly small, but are annoying as
1201 * they prevent the mitering optimiser from working.
1202 * Freckles sometimes arise because of a bug in the autorouter that
1203 * causes it to create small overshoots (typically 0.01 thou) at the
1204 * intersections of vertical and horizontal lines. These overshoots
1205 * are converted to freckles as a side effect of canonicalize_line().
1206 * Note that canonicalize_line() is not at fault, the bug is in the
1207 * autorouter creating overshoots.
1208 * The autorouter bug arose some time between the 20080202 and 20091103
1209 * releases.
1210 * This code is probably worth keeping even when the autorouter bug is
1211 * fixed, as "freckles" could conceivably arise in other ways.
1212 */
1213 dprintf ("freckle %#mD to %#mD\n", c->x, c->y, c0->x, c0->y);
1214 move_corner (c, c0->x, c0->y);
1215 }
1216 }
1217 check (c, 0);
1218 return rv;
1219 }
1220
1221 /* We always run these */
1222 static int
simple_optimizations()1223 simple_optimizations ()
1224 {
1225 corner_s *c;
1226 int rv = 0;
1227
1228 /* Look for corners that aren't */
1229 for (c = corners; c; c = c->next)
1230 {
1231 if (DELETED (c))
1232 continue;
1233 if (c->pad || c->pin)
1234 continue;
1235 rv += simple_optimize_corner (c);
1236 }
1237 return rv;
1238 }
1239
1240 static int
is_hole(corner_s * c)1241 is_hole (corner_s * c)
1242 {
1243 return c->pin || c->pad || c->via;
1244 }
1245
1246 static int
orthopull_1(corner_s * c,int fdir,int rdir,int any_sel)1247 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1248 {
1249 static corner_s **cs = 0;
1250 static int cm = 0;
1251 static line_s **ls = 0;
1252 static int lm = 0;
1253 int i, li, ln, cn, snap;
1254 line_s *l = 0;
1255 corner_s *c2, *cb;
1256 int adir = 0, sdir = 0, pull;
1257 int saw_sel = 0, saw_auto = 0;
1258 int max, len = 0, r1 = 0, r2;
1259 rect_s rr;
1260 int edir = 0, done;
1261
1262 if (cs == 0)
1263 {
1264 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1265 cm = 10;
1266 ls = (line_s **) malloc (10 * sizeof (line_s));
1267 lm = 10;
1268 }
1269
1270 for (i = 0; i < c->n_lines; i++)
1271 {
1272 int o = line_orient (c->lines[i], c);
1273 if (o == rdir)
1274 return 0;
1275 }
1276
1277 switch (fdir)
1278 {
1279 case RIGHT:
1280 adir = DOWN;
1281 sdir = UP;
1282 break;
1283 case DOWN:
1284 adir = RIGHT;
1285 sdir = LEFT;
1286 break;
1287 default:
1288 dj_abort ("fdir not right or down\n");
1289 }
1290
1291 c2 = c;
1292 cn = 0;
1293 ln = 0;
1294 pull = 0;
1295 while (c2)
1296 {
1297 if (c2->pad || c2->pin || c2->n_lines < 2)
1298 return 0;
1299 if (cn >= cm)
1300 {
1301 cm = cn + 10;
1302 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s *));
1303 }
1304 cs[cn++] = c2;
1305 r2 = corner_radius (c2);
1306 if (r1 < r2)
1307 r1 = r2;
1308 l = 0;
1309 for (i = 0; i < c2->n_lines; i++)
1310 {
1311 int o = line_orient (c2->lines[i], c2);
1312 if (o == DIAGONAL)
1313 return 0;
1314 if (o == fdir)
1315 {
1316 if (l)
1317 return 0; /* we don't support overlapping lines yet */
1318 l = c2->lines[i];
1319 }
1320 if (o == rdir && c2->lines[i] != ls[ln - 1])
1321 return 0; /* likewise */
1322 if (o == adir)
1323 pull++;
1324 if (o == sdir)
1325 pull--;
1326 }
1327 if (!l)
1328 break;
1329 if (selected (l->line))
1330 saw_sel = 1;
1331 if (autorouted (l->line))
1332 saw_auto = 1;
1333 if (ln >= lm)
1334 {
1335 lm = ln + 10;
1336 ls = (line_s **) realloc (ls, lm * sizeof (line_s *));
1337 }
1338 ls[ln++] = l;
1339 c2 = other_corner (l, c2);
1340 }
1341 if (cn < 2 || pull == 0)
1342 return 0;
1343 if (any_sel && !saw_sel)
1344 return 0;
1345 if (!any_sel && autorouted_only && !saw_auto)
1346 return 0;
1347
1348 /* Ok, now look for other blockages. */
1349
1350 empty_rect (&rr);
1351 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1352 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1353
1354 if (fdir == RIGHT && pull < 0)
1355 edir = UP;
1356 else if (fdir == RIGHT && pull > 0)
1357 edir = DOWN;
1358 else if (fdir == DOWN && pull < 0)
1359 edir = LEFT;
1360 else if (fdir == DOWN && pull > 0)
1361 edir = RIGHT;
1362
1363 max = -1;
1364 for (i = 0; i < cn; i++)
1365 for (li = 0; li < cs[i]->n_lines; li++)
1366 {
1367 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1368 continue;
1369 len = line_length (cs[i]->lines[li]);
1370 if (max > len || max == -1)
1371 max = len;
1372 }
1373 dprintf ("c %s %4#mD cn %d pull %3d max %4#mS\n",
1374 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1375
1376 switch (edir)
1377 {
1378 case UP:
1379 rr.y1 = c->y - r1 - max;
1380 break;
1381 case DOWN:
1382 rr.y2 = c->y + r1 + max;
1383 break;
1384 case LEFT:
1385 rr.x1 = c->x - r1 - max;
1386 break;
1387 case RIGHT:
1388 rr.x2 = c->x + r1 + max;
1389 break;
1390 }
1391 rr.x1 -= SB + 1;
1392 rr.x2 += SB + 1;
1393 rr.y1 -= SB + 1;
1394 rr.y2 += SB + 1;
1395
1396 snap = 0;
1397 for (cb = corners; cb; cb = cb->next)
1398 {
1399 int sep;
1400 if (DELETED (cb))
1401 continue;
1402 r1 = corner_radius (cb);
1403 if (cb->net == c->net && !cb->pad)
1404 continue;
1405 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1406 continue;
1407 switch (edir)
1408 {
1409 #define ECHK(X,Y,LT) \
1410 for (i=0; i<cn; i++) \
1411 { \
1412 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1413 continue; \
1414 r2 = corner_radius(cs[i]); \
1415 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1416 continue; \
1417 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1418 continue; \
1419 if (cb->Y LT cs[i]->Y) \
1420 continue; \
1421 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1422 if (max > sep) \
1423 { max = sep; snap = 1; }\
1424 } \
1425 for (i=0; i<ln; i++) \
1426 { \
1427 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1428 continue; \
1429 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1430 continue; \
1431 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1432 - r1 - SB - 1); \
1433 if (max > sep) \
1434 { max = sep; snap = 1; }\
1435 }
1436 case UP:
1437 ECHK (x, y, >=);
1438 break;
1439 case DOWN:
1440 ECHK (x, y, <=);
1441 break;
1442 case LEFT:
1443 ECHK (y, x, >=);
1444 break;
1445 case RIGHT:
1446 ECHK (y, x, <=);
1447 break;
1448 }
1449 }
1450
1451 /* We must now check every line segment against our corners. */
1452 for (l = lines; l; l = l->next)
1453 {
1454 int o, x1, x2, y1, y2;
1455 if (DELETED (l))
1456 continue;
1457 dprintf ("check line %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1458 if (l->s->net == c->net)
1459 {
1460 dprintf (" same net\n");
1461 continue;
1462 }
1463 o = line_orient (l, 0);
1464 /* We don't need to check perpendicular lines, because their
1465 corners already take care of it. */
1466 if ((fdir == RIGHT && (o == UP || o == DOWN))
1467 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1468 {
1469 dprintf (" perpendicular\n");
1470 continue;
1471 }
1472
1473 /* Choose so that x1,y1 is closest to corner C */
1474 if ((fdir == RIGHT && l->s->x < l->e->x)
1475 || (fdir == DOWN && l->s->y < l->e->y))
1476 {
1477 x1 = l->s->x;
1478 y1 = l->s->y;
1479 x2 = l->e->x;
1480 y2 = l->e->y;
1481 }
1482 else
1483 {
1484 x1 = l->e->x;
1485 y1 = l->e->y;
1486 x2 = l->s->x;
1487 y2 = l->s->y;
1488 }
1489
1490 /* Eliminate all lines outside our range */
1491 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1492 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1493 {
1494 dprintf (" outside our range\n");
1495 continue;
1496 }
1497
1498 /* Eliminate all lines on the wrong side of us */
1499 if ((edir == UP && y1 > c->y && y2 > c->y)
1500 || (edir == DOWN && y1 < c->y && y2 < c->y)
1501 || (edir == LEFT && x1 > c->x && x2 > c->x)
1502 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1503 {
1504 dprintf (" wrong side\n");
1505 continue;
1506 }
1507
1508 /* For now, cheat on diagonals */
1509 switch (edir)
1510 {
1511 case RIGHT:
1512 if (x1 > x2)
1513 x1 = x2;
1514 break;
1515 case LEFT:
1516 if (x1 < x2)
1517 x1 = x2;
1518 break;
1519 case DOWN:
1520 if (y1 > y2)
1521 y1 = y2;
1522 break;
1523 case UP:
1524 if (y1 < y2)
1525 y1 = y2;
1526 break;
1527 }
1528
1529 /* Ok, now see how far we can get for each of our corners. */
1530 for (i = 0; i < cn; i++)
1531 {
1532 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1533 int len = 0;
1534 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1535 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1536 continue;
1537 if (!intersecting_layers (cs[i]->layer, l->layer))
1538 continue;
1539 switch (edir)
1540 {
1541 case RIGHT:
1542 len = x1 - c->x;
1543 break;
1544 case LEFT:
1545 len = c->x - x1;
1546 break;
1547 case DOWN:
1548 len = y1 - c->y;
1549 break;
1550 case UP:
1551 len = c->y - y1;
1552 break;
1553 }
1554 len -= r;
1555 dprintf (" len is %#mS vs corner at %#mD\n", len, cs[i]->x, cs[i]->y);
1556 if (len <= 0)
1557 return 0;
1558 if (max > len)
1559 max = len;
1560 }
1561
1562 }
1563
1564 /* We must make sure that if a segment isn't being completely
1565 removed, that any vias and/or pads don't overlap. */
1566 done = 0;
1567 while (!done)
1568 {
1569 done = 1;
1570 for (i = 0; i < cn; i++)
1571 for (li = 0; li < cs[i]->n_lines; li++)
1572 {
1573 line_s *l = cs[i]->lines[li];
1574 corner_s *oc = other_corner (l, cs[i]);
1575 if (line_orient (l, cs[i]) != edir)
1576 continue;
1577 len = line_length (l);
1578 if (!oc->pad || !cs[i]->via)
1579 {
1580 if (!is_hole (l->s) || !is_hole (l->e))
1581 continue;
1582 if (len == max)
1583 continue;
1584 }
1585 len -= corner_radius (l->s);
1586 len -= corner_radius (l->e);
1587 len -= SB + 1;
1588 if (max > len)
1589 {
1590 max = len;
1591 done = 0;
1592 }
1593 }
1594 }
1595
1596 if (max <= 0)
1597 return 0;
1598 switch (edir)
1599 {
1600 case UP:
1601 len = c->y - max;
1602 break;
1603 case DOWN:
1604 len = c->y + max;
1605 break;
1606 case LEFT:
1607 len = c->x - max;
1608 break;
1609 case RIGHT:
1610 len = c->x + max;
1611 break;
1612 }
1613 if (snap && max > Settings.Grid)
1614 {
1615 if (pull < 0)
1616 len += Settings.Grid - 1;
1617 len = gridsnap (len);
1618 }
1619 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1620 return 0;
1621 for (i = 0; i < cn; i++)
1622 {
1623 if (fdir == RIGHT)
1624 {
1625 max = len - cs[i]->y;
1626 move_corner (cs[i], cs[i]->x, len);
1627 }
1628 else
1629 {
1630 max = len - cs[i]->x;
1631 move_corner (cs[i], len, cs[i]->y);
1632 }
1633 }
1634 return max * pull;
1635 }
1636
1637 /*!
1638 * \brief Look for straight runs which could be moved to reduce total
1639 * trace length.
1640 */
1641 static int
orthopull()1642 orthopull ()
1643 {
1644 int any_sel = any_line_selected ();
1645 corner_s *c;
1646 int rv = 0;
1647
1648 for (c = corners; c;)
1649 {
1650 if (DELETED (c))
1651 continue;
1652 if (c->pin || c->pad)
1653 {
1654 c = c->next;
1655 continue;
1656 }
1657 next_corner = c;
1658 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1659 if (c != next_corner)
1660 {
1661 c = next_corner;
1662 continue;
1663 }
1664 rv += orthopull_1 (c, DOWN, UP, any_sel);
1665 if (c != next_corner)
1666 {
1667 c = next_corner;
1668 continue;
1669 }
1670 c = c->next;
1671 }
1672 if (rv)
1673 pcb_printf ("orthopull: %ml mils saved\n", rv);
1674 return rv;
1675 }
1676
1677 /*!
1678 * \brief Look for "U" shaped traces we can shorten (or eliminate).
1679 */
1680 static int
debumpify()1681 debumpify ()
1682 {
1683 int rv = 0;
1684 int any_selected = any_line_selected ();
1685 line_s *l, *l1, *l2;
1686 corner_s *c, *c1, *c2;
1687 rect_s rr, rp;
1688 int o, o1, o2, step, w;
1689 for (l = lines; l; l = l->next)
1690 {
1691 if (DELETED (l))
1692 continue;
1693 if (!l->line)
1694 continue;
1695 if (any_selected && !selected (l->line))
1696 continue;
1697 if (!any_selected && autorouted_only && !autorouted (l->line))
1698 continue;
1699 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1700 continue;
1701 o = line_orient (l, 0);
1702 if (o == DIAGONAL)
1703 continue;
1704 l1 = other_line (l->s, l);
1705 if (!l1)
1706 continue;
1707 o1 = line_orient (l1, l->s);
1708 l2 = other_line (l->e, l);
1709 if (!l2)
1710 continue;
1711 o2 = line_orient (l2, l->e);
1712 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1713 continue;
1714
1715 dprintf ("\nline: %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1716 w = l->line->Thickness / 2 + SB + 1;
1717 empty_rect (&rr);
1718 add_line_to_rect (&rr, l1);
1719 add_line_to_rect (&rr, l2);
1720 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1721 rr.x1 -= w;
1722 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1723 rr.x2 += w;
1724 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1725 rr.y1 -= w;
1726 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1727 rr.y2 += w;
1728 dprintf ("range: x %#mS..%#mS y %#mS..%#mS\n", rr.x1, rr.x2, rr.y1, rr.y2);
1729
1730 c1 = other_corner (l1, l->s);
1731 c2 = other_corner (l2, l->e);
1732
1733 empty_rect (&rp);
1734 for (c = corners; c; c = c->next)
1735 {
1736 if (DELETED (c))
1737 continue;
1738 if (c->net != l->s->net
1739 && intersecting_layers (c->layer, l->s->layer))
1740 add_corner_to_rect_if (&rp, c, &rr);
1741 }
1742 if (rp.x1 == INT_MAX)
1743 {
1744 rp.x1 = rr.x2;
1745 rp.x2 = rr.x1;
1746 rp.y1 = rr.y2;
1747 rp.y2 = rr.y1;
1748 }
1749 dprintf ("pin r: x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1750
1751 switch (o1)
1752 {
1753 case LEFT:
1754 step = l->s->x - rp.x2 - w;
1755 step = gridsnap (step);
1756 if (step > l->s->x - c1->x)
1757 step = l->s->x - c1->x;
1758 if (step > l->s->x - c2->x)
1759 step = l->s->x - c2->x;
1760 if (step > 0)
1761 {
1762 dprintf ("left step %#mS at %#mD\n", step, l->s->x, l->s->y);
1763 move_corner (l->s, l->s->x - step, l->s->y);
1764 move_corner (l->e, l->e->x - step, l->e->y);
1765 rv += step;
1766 }
1767 break;
1768 case RIGHT:
1769 step = rp.x1 - l->s->x - w;
1770 step = gridsnap (step);
1771 if (step > c1->x - l->s->x)
1772 step = c1->x - l->s->x;
1773 if (step > c2->x - l->s->x)
1774 step = c2->x - l->s->x;
1775 if (step > 0)
1776 {
1777 dprintf ("right step %#mS at %#mD\n", step, l->s->x, l->s->y);
1778 move_corner (l->s, l->s->x + step, l->s->y);
1779 move_corner (l->e, l->e->x + step, l->e->y);
1780 rv += step;
1781 }
1782 break;
1783 case UP:
1784 if (rp.y2 == INT_MIN)
1785 rp.y2 = rr.y1;
1786 step = trim_step (l->s->y - rp.y2 - w,
1787 l->s->y - c1->y, l->s->y - c2->y);
1788 if (step > 0)
1789 {
1790 dprintf ("up step %#mS at %#mD\n", step, l->s->x, l->s->y);
1791 move_corner (l->s, l->s->x, l->s->y - step);
1792 move_corner (l->e, l->e->x, l->e->y - step);
1793 rv += step;
1794 }
1795 break;
1796 case DOWN:
1797 step = rp.y1 - l->s->y - w;
1798 step = gridsnap (step);
1799 if (step > c1->y - l->s->y)
1800 step = c1->y - l->s->y;
1801 if (step > c2->y - l->s->y)
1802 step = c2->y - l->s->y;
1803 if (step > 0)
1804 {
1805 dprintf ("down step %#mS at %#mD\n", step, l->s->x, l->s->y);
1806 move_corner (l->s, l->s->x, l->s->y + step);
1807 move_corner (l->e, l->e->x, l->e->y + step);
1808 rv += step;
1809 }
1810 break;
1811 }
1812 check (0, l);
1813 }
1814
1815 rv += simple_optimizations ();
1816 if (rv)
1817 pcb_printf ("debumpify: %ml mils saved\n", rv / 50);
1818 return rv;
1819 }
1820
1821 static int
simple_corner(corner_s * c)1822 simple_corner (corner_s * c)
1823 {
1824 int o1, o2;
1825 if (c->pad || c->pin || c->via)
1826 return 0;
1827 if (c->n_lines != 2)
1828 return 0;
1829 o1 = line_orient (c->lines[0], c);
1830 o2 = line_orient (c->lines[1], c);
1831 if (ORIENT (o1) == ORIENT (o2))
1832 return 0;
1833 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1834 return 0;
1835 return 1;
1836 }
1837
1838 /*!
1839 * \brief Look for sequences of simple corners we can reduce.
1840 */
1841 static int
unjaggy_once()1842 unjaggy_once ()
1843 {
1844 int rv = 0;
1845 corner_s *c, *c0, *c1, *cc;
1846 int l, w, sel = any_line_selected ();
1847 int o0, o1, s0, s1;
1848 rect_s rr, rp;
1849 for (c = corners; c; c = c->next)
1850 {
1851 if (DELETED (c))
1852 continue;
1853 if (!simple_corner (c))
1854 continue;
1855 if (!c->lines[0]->line || !c->lines[1]->line)
1856 continue;
1857 if (sel && !(selected (c->lines[0]->line)
1858 || selected (c->lines[1]->line)))
1859 continue;
1860 if (!sel && autorouted_only
1861 && !(autorouted (c->lines[0]->line)
1862 || autorouted (c->lines[1]->line)))
1863 continue;
1864 dprintf ("simple at %#mD\n", c->x, c->y);
1865
1866 c0 = other_corner (c->lines[0], c);
1867 o0 = line_orient (c->lines[0], c);
1868 s0 = simple_corner (c0);
1869
1870 c1 = other_corner (c->lines[1], c);
1871 o1 = line_orient (c->lines[1], c);
1872 s1 = simple_corner (c1);
1873
1874 if (!s0 && !s1)
1875 continue;
1876 dprintf ("simples at %#mD\n", c->x, c->y);
1877
1878 w = 1;
1879 for (l = 0; l < c0->n_lines; l++)
1880 if (c0->lines[l] != c->lines[0]
1881 && c0->lines[l]->layer == c->lines[0]->layer)
1882 {
1883 int o = line_orient (c0->lines[l], c0);
1884 if (o == o1)
1885 w = 0;
1886 }
1887 for (l = 0; l < c1->n_lines; l++)
1888 if (c1->lines[l] != c->lines[0]
1889 && c1->lines[l]->layer == c->lines[0]->layer)
1890 {
1891 int o = line_orient (c1->lines[l], c1);
1892 if (o == o0)
1893 w = 0;
1894 }
1895 if (!w)
1896 continue;
1897 dprintf ("orient ok\n");
1898
1899 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1900 empty_rect (&rr);
1901 add_line_to_rect (&rr, c->lines[0]);
1902 add_line_to_rect (&rr, c->lines[1]);
1903 if (c->x != rr.x1)
1904 rr.x1 -= w;
1905 else
1906 rr.x2 += w;
1907 if (c->y != rr.y1)
1908 rr.y1 -= w;
1909 else
1910 rr.y2 += w;
1911
1912 empty_rect (&rp);
1913 for (cc = corners; cc; cc = cc->next)
1914 {
1915 if (DELETED (cc))
1916 continue;
1917 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1918 add_corner_to_rect_if (&rp, cc, &rr);
1919 }
1920 dprintf ("rp x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1921 if (rp.x1 <= rp.x2) /* something triggered */
1922 continue;
1923
1924 dprintf ("unjaggy at %#mD layer %d\n", c->x, c->y, c->layer);
1925 if (c->x == c0->x)
1926 move_corner (c, c1->x, c0->y);
1927 else
1928 move_corner (c, c0->x, c1->y);
1929 rv++;
1930 check (c, 0);
1931 }
1932 rv += simple_optimizations ();
1933 check (c, 0);
1934 return rv;
1935 }
1936
1937 static int
unjaggy()1938 unjaggy ()
1939 {
1940 int i, r = 0, j;
1941 for (i = 0; i < 100; i++)
1942 {
1943 j = unjaggy_once ();
1944 if (j == 0)
1945 break;
1946 r += j;
1947 }
1948 if (r)
1949 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1950 return r;
1951 }
1952
1953 /*!
1954 * \brief Look for vias with all lines leaving the same way, try to
1955 * nudge via to eliminate one or more of them.
1956 */
1957 static int
vianudge()1958 vianudge ()
1959 {
1960 int rv = 0;
1961 corner_s *c, *c2, *c3;
1962 line_s *l;
1963 unsigned char directions[MAX_LAYER];
1964 unsigned char counts[MAX_LAYER];
1965
1966 memset (directions, 0, sizeof (directions));
1967 memset (counts, 0, sizeof (counts));
1968
1969 for (c = corners; c; c = c->next)
1970 {
1971 int o, i, vr, cr, oboth;
1972 int len = 0, saved = 0;
1973
1974 if (DELETED (c))
1975 continue;
1976
1977 if (!c->via)
1978 continue;
1979
1980 memset (directions, 0, sizeof (directions));
1981 memset (counts, 0, sizeof (counts));
1982
1983 for (i = 0; i < c->n_lines; i++)
1984 {
1985 o = line_orient (c->lines[i], c);
1986 counts[c->lines[i]->layer]++;
1987 directions[c->lines[i]->layer] |= o;
1988 }
1989 for (o = 0, i = 0; i < max_copper_layer; i++)
1990 if (counts[i] == 1)
1991 {
1992 o = directions[i];
1993 break;
1994 }
1995 switch (o)
1996 {
1997 case LEFT:
1998 case RIGHT:
1999 oboth = LEFT | RIGHT;
2000 break;
2001 case UP:
2002 case DOWN:
2003 oboth = UP | DOWN;
2004 break;
2005 default:
2006 continue;
2007 }
2008 for (i = 0; i < max_copper_layer; i++)
2009 if (counts[i] && directions[i] != o && directions[i] != oboth)
2010 goto vianudge_continue;
2011
2012 c2 = 0;
2013 for (i = 0; i < c->n_lines; i++)
2014 {
2015 int ll = line_length (c->lines[i]);
2016 if (line_orient (c->lines[i], c) != o)
2017 {
2018 saved--;
2019 continue;
2020 }
2021 saved++;
2022 if (c2 == 0 || len > ll)
2023 {
2024 len = ll;
2025 c2 = other_corner (c->lines[i], c);
2026 }
2027 }
2028 if (c2->pad || c2->pin || c2->via)
2029 continue;
2030
2031 /* Now look for clearance in the new position */
2032 vr = c->via->Thickness / 2 + SB + 1;
2033 for (c3 = corners; c3; c3 = c3->next)
2034 {
2035 if (DELETED (c3))
2036 continue;
2037 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2038 {
2039 cr = corner_radius (c3);
2040 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2041 goto vianudge_continue;
2042 }
2043 }
2044 for (l = lines; l; l = l->next)
2045 {
2046 if (DELETED (l))
2047 continue;
2048 if (l->s->net != c->net)
2049 {
2050 int ld = dist_line_to_point (l, c2);
2051 if (ld < l->line->Thickness / 2 + vr)
2052 goto vianudge_continue;
2053 }
2054 }
2055
2056 /* at this point, we know we can move it */
2057
2058 dprintf ("vianudge: nudging via at %#mD by %#mS saving %#mS\n",
2059 c->x, c->y, len, saved);
2060 rv += len * saved;
2061 move_corner (c, c2->x, c2->y);
2062
2063 check (c, 0);
2064
2065 vianudge_continue:
2066 continue;
2067 }
2068
2069 if (rv)
2070 pcb_printf ("vianudge: %ml mils saved\n", rv);
2071 return rv;
2072 }
2073
2074 /*!
2075 * \brief Look for traces that can be moved to the other side of the
2076 * board, to reduce the number of vias needed.
2077 *
2078 * For now, we look for simple lines, not multi-segmented lines.
2079 */
2080 static int
viatrim()2081 viatrim ()
2082 {
2083 line_s *l, *l2;
2084 int i, rv = 0, vrm = 0;
2085 int any_sel = any_line_selected ();
2086
2087 for (l = lines; l; l = l->next)
2088 {
2089 rect_s r;
2090 int my_layer, other_layer;
2091
2092 if (DELETED (l))
2093 continue;
2094 if (!l->s->via)
2095 continue;
2096 if (!l->e->via)
2097 continue;
2098 if (any_sel && !selected (l->line))
2099 continue;
2100 if (!any_sel && autorouted_only && !autorouted (l->line))
2101 continue;
2102
2103 my_layer = l->layer;
2104 other_layer = -1;
2105 dprintf ("line %p on layer %d from %#mD to %#mD\n", (void *) l,
2106 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2107 for (i = 0; i < l->s->n_lines; i++)
2108 if (l->s->lines[i] != l)
2109 {
2110 if (other_layer == -1)
2111 {
2112 other_layer = l->s->lines[i]->layer;
2113 dprintf ("noting other line %p on layer %d\n",
2114 (void *) (l->s->lines[i]), my_layer);
2115 }
2116 else if (l->s->lines[i]->layer != other_layer)
2117 {
2118 dprintf ("saw other line %p on layer %d (not %d)\n",
2119 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2120 my_layer);
2121 other_layer = -1;
2122 goto viatrim_other_corner;
2123 }
2124 }
2125 viatrim_other_corner:
2126 if (other_layer == -1)
2127 for (i = 0; i < l->e->n_lines; i++)
2128 if (l->e->lines[i] != l)
2129 {
2130 if (other_layer == -1)
2131 {
2132 other_layer = l->s->lines[i]->layer;
2133 dprintf ("noting other line %p on layer %d\n",
2134 (void *) (l->s->lines[i]), my_layer);
2135 }
2136 else if (l->e->lines[i]->layer != other_layer)
2137 {
2138 dprintf ("saw end line on layer %d (not %d)\n",
2139 l->e->lines[i]->layer, other_layer);
2140 goto viatrim_continue;
2141 }
2142 }
2143
2144 /* Now see if any other line intersects us. We don't need to
2145 check corners, because they'd either be pins/vias and
2146 already conflict, or pads, which we'll check here anyway. */
2147 empty_rect (&r);
2148 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2149 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2150
2151 for (l2 = lines; l2; l2 = l2->next)
2152 {
2153 if (DELETED (l2))
2154 continue;
2155 if (l2->s->net != l->s->net && l2->layer == other_layer)
2156 {
2157 dprintf ("checking other line %#mD to %#mD\n", l2->s->x,
2158 l2->s->y, l2->e->x, l2->e->y);
2159 if (line_in_rect (&r, l2))
2160 {
2161 dprintf ("line from %#mD to %#mD in the way\n",
2162 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2163 goto viatrim_continue;
2164 }
2165 }
2166 }
2167
2168 if (l->layer == other_layer)
2169 continue;
2170 move_line_to_layer (l, other_layer);
2171 rv++;
2172
2173 viatrim_continue:
2174 continue;
2175 }
2176 vrm = simple_optimizations ();
2177 if (rv > 0)
2178 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2179 return rv + vrm;
2180 }
2181
2182 static int
automagic()2183 automagic ()
2184 {
2185 int more = 1, oldmore = 0;
2186 int toomany = 100;
2187 while (more != oldmore && --toomany)
2188 {
2189 oldmore = more;
2190 more += debumpify ();
2191 more += unjaggy ();
2192 more += orthopull ();
2193 more += vianudge ();
2194 more += viatrim ();
2195 }
2196 return more - 1;
2197 }
2198
2199 static int
miter()2200 miter ()
2201 {
2202 corner_s *c;
2203 int done, progress;
2204 int sel = any_line_selected ();
2205 int saved = 0;
2206
2207 for (c = corners; c; c = c->next)
2208 {
2209 if (DELETED (c))
2210 continue;
2211 c->miter = 0;
2212 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2213 {
2214 int o1 = line_orient (c->lines[0], c);
2215 int o2 = line_orient (c->lines[1], c);
2216 if (ORIENT (o1) != ORIENT (o2)
2217 && o1 != DIAGONAL && o2 != DIAGONAL
2218 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2219 c->miter = -1;
2220 }
2221 }
2222
2223 done = 0;
2224 progress = 1;
2225 while (!done && progress)
2226 {
2227 done = 1;
2228 progress = 0;
2229 for (c = corners; c; c = c->next)
2230 {
2231 if (DELETED (c))
2232 continue;
2233 if (c->miter == -1)
2234 {
2235 int max = line_length (c->lines[0]);
2236 int len = line_length (c->lines[1]);
2237 int bloat;
2238 int ref, dist;
2239 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2240 int mx = 0, my = 0, x, y;
2241 int o1 = line_orient (c->lines[0], c);
2242 int o2 = line_orient (c->lines[1], c);
2243
2244 if (c->pad || c->pin || c->via)
2245 {
2246 c->miter = 0;
2247 progress = 1;
2248 continue;
2249 }
2250
2251 oc1 = other_corner (c->lines[0], c);
2252 oc2 = other_corner (c->lines[1], c);
2253 #if 0
2254 if (oc1->pad)
2255 oc1 = 0;
2256 if (oc2->pad)
2257 oc2 = 0;
2258 #endif
2259
2260 if ((sel && !(selected (c->lines[0]->line)
2261 || selected (c->lines[1]->line)))
2262 || (!sel && autorouted_only
2263 && !(autorouted (c->lines[0]->line)
2264 || autorouted (c->lines[1]->line))))
2265 {
2266 c->miter = 0;
2267 progress = 1;
2268 continue;
2269 }
2270
2271 if (max > len)
2272 max = len;
2273 switch (o1)
2274 {
2275 case LEFT:
2276 mx = -1;
2277 break;
2278 case RIGHT:
2279 mx = 1;
2280 break;
2281 case UP:
2282 my = -1;
2283 break;
2284 case DOWN:
2285 my = 1;
2286 break;
2287 }
2288 switch (o2)
2289 {
2290 case LEFT:
2291 mx = -1;
2292 break;
2293 case RIGHT:
2294 mx = 1;
2295 break;
2296 case UP:
2297 my = -1;
2298 break;
2299 case DOWN:
2300 my = 1;
2301 break;
2302 }
2303 ref = c->x * mx + c->y * my;
2304 dist = max;
2305
2306 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2307
2308 for (c2 = corners; c2; c2 = c2->next)
2309 {
2310 if (DELETED (c2))
2311 continue;
2312 if (c2 != c && c2 != oc1 && c2 != oc2
2313 && c->x * mx <= c2->x * mx
2314 && c->y * my <= c2->y * my
2315 && c->net != c2->net
2316 && intersecting_layers (c->layer, c2->layer))
2317 {
2318 int cr = corner_radius (c2);
2319 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2320 if (c->x != c2->x && c->y != c2->y)
2321 len -= cr;
2322 if (len < dist || (len == dist && c->miter != -1))
2323 {
2324 dist = len;
2325 closest_corner = c2;
2326 }
2327 }
2328 }
2329
2330 if (closest_corner && closest_corner->miter == -1)
2331 {
2332 done = 0;
2333 continue;
2334 }
2335
2336 #if 0
2337 if (dist < Settings.Grid)
2338 {
2339 c->miter = 0;
2340 progress = 1;
2341 continue;
2342 }
2343
2344 dist -= dist % Settings.Grid;
2345 #endif
2346 if (dist <= 0)
2347 {
2348 c->miter = 0;
2349 progress = 1;
2350 continue;
2351 }
2352
2353 x = c->x;
2354 y = c->y;
2355 switch (o1)
2356 {
2357 case LEFT:
2358 x -= dist;
2359 break;
2360 case RIGHT:
2361 x += dist;
2362 break;
2363 case UP:
2364 y -= dist;
2365 break;
2366 case DOWN:
2367 y += dist;
2368 break;
2369 }
2370 c2 = find_corner (x, y, c->layer);
2371 if (c2 != other_corner (c->lines[0], c))
2372 split_line (c->lines[0], c2);
2373 x = c->x;
2374 y = c->y;
2375 switch (o2)
2376 {
2377 case LEFT:
2378 x -= dist;
2379 break;
2380 case RIGHT:
2381 x += dist;
2382 break;
2383 case UP:
2384 y -= dist;
2385 break;
2386 case DOWN:
2387 y += dist;
2388 break;
2389 }
2390 move_corner (c, x, y);
2391 c->miter = 0;
2392 c2->miter = 0;
2393 progress = 1;
2394 saved++;
2395 }
2396 }
2397 }
2398 return saved;
2399 }
2400
2401 static void
classify_corner(corner_s * c,int this_net)2402 classify_corner (corner_s * c, int this_net)
2403 {
2404 int i;
2405 if (c->net == this_net)
2406 return;
2407 c->net = this_net;
2408 for (i = 0; i < c->n_lines; i++)
2409 classify_corner (other_corner (c->lines[i], c), this_net);
2410 }
2411
2412 static void
classify_nets()2413 classify_nets ()
2414 {
2415 static int this_net = 1;
2416 corner_s *c;
2417
2418 for (c = corners; c; c = c->next)
2419 {
2420 if (DELETED (c))
2421 continue;
2422 if (c->net)
2423 continue;
2424 classify_corner (c, this_net);
2425 this_net++;
2426 }
2427 }
2428
2429 #if 0
2430 /* Not used */
2431 static void
2432 dump_all ()
2433 {
2434 corner_s *c;
2435 line_s *l;
2436 for (c = corners; c; c = c->next)
2437 {
2438 if (DELETED (c))
2439 continue;
2440 printf ("%p corner %d,%d layer %d net %d\n",
2441 (void *) c, c->x, c->y, c->layer, c->net);
2442 }
2443 for (l = lines; l; l = l->next)
2444 {
2445 if (DELETED (l))
2446 continue;
2447 printf ("%p line %p to %p layer %d\n",
2448 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2449 }
2450 }
2451 #endif
2452
2453 #if 0
2454 static void
2455 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2456 {
2457 int ox = c->x;
2458 int oy = c->y;
2459 int l;
2460 if (prev_corner && (c->pin || c->pad))
2461 return;
2462 move_corner (c, ox + dx, oy + dy);
2463 for (l = 0; l < c->n_lines; l++)
2464 {
2465 corner_s *oc = other_corner (c->lines[l], c);
2466 if (oc == prev_corner)
2467 continue;
2468 if (dx && oc->x == ox)
2469 nudge_corner (oc, dx, 0, c);
2470 if (dy && oc->y == oy)
2471 nudge_corner (oc, 0, dy, c);
2472 }
2473 }
2474 #endif
2475
2476 static line_s *
choose_example_line(corner_s * c1,corner_s * c2)2477 choose_example_line (corner_s * c1, corner_s * c2)
2478 {
2479 int ci, li;
2480 corner_s *c[2];
2481 c[0] = c1;
2482 c[1] = c2;
2483 dprintf ("choose_example_line\n");
2484 for (ci = 0; ci < 2; ci++)
2485 for (li = 0; li < c[ci]->n_lines; li++)
2486 {
2487 dprintf (" try[%d,%d] \033[36m<%#mD-%#mD t%#mS c%#mS f%s>\033[0m\n",
2488 ci, li,
2489 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2490 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2491 c[ci]->lines[li]->line->Thickness,
2492 c[ci]->lines[li]->line->Clearance,
2493 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2494 /* Pads are disqualified, as we want to mimic a trace line. */
2495 if (c[ci]->lines[li]->line == (LineType *) c[ci]->pad)
2496 {
2497 dprintf (" bad, pad\n");
2498 continue;
2499 }
2500 /* Lines on layers that don't connect to the other pad are bad too. */
2501 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2502 {
2503 dprintf (" bad, layers\n");
2504 continue;
2505 }
2506 dprintf (" good\n");
2507 return c[ci]->lines[li];
2508 }
2509 dprintf ("choose_example_line: none found!\n");
2510 return 0;
2511 }
2512
2513 static int
connect_corners(corner_s * c1,corner_s * c2)2514 connect_corners (corner_s * c1, corner_s * c2)
2515 {
2516 int layer;
2517 line_s *ex = choose_example_line (c1, c2);
2518 LineType *example = ex->line;
2519
2520 dprintf
2521 ("connect_corners \033[32m%#mD to %#mD, example line %#mD to %#mD l%d\033[0m\n",
2522 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2523 ex->layer);
2524
2525 layer = ex->layer;
2526
2527 /* Assume c1 is the moveable one. */
2528 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2529 {
2530 int nx, ny;
2531 /* Extend the line */
2532 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2533 nx = c1->x, ny = c2->y;
2534 else
2535 nx = c2->x, ny = c1->y;
2536 if (nx != c2->x || ny != c2->y)
2537 {
2538 move_corner (c1, nx, ny);
2539 new_line (c1, c2, layer, example);
2540 return 1;
2541 }
2542 else
2543 {
2544 move_corner (c1, nx, ny);
2545 return 1;
2546 }
2547 }
2548 else
2549 {
2550 corner_s *nc = find_corner (c1->x, c2->y, layer);
2551 new_line (c1, nc, layer, example);
2552 new_line (nc, c2, layer, example);
2553 return 0;
2554 }
2555 }
2556
2557 /*!
2558 * \brief Look for pins that have no connections.
2559 *
2560 * See if there's a corner close by that should be connected to it.
2561 * This usually happens when the MUCS router needs to route to an
2562 * off-grid pin.
2563 */
2564 static void
pinsnap()2565 pinsnap ()
2566 {
2567 corner_s *c;
2568 int best_dist[MAX_LAYER + 1];
2569 corner_s *best_c[MAX_LAYER + 1];
2570 int l, got_one;
2571 int left = 0, right = 0, top = 0, bottom = 0;
2572 PinType *pin;
2573 int again = 1;
2574
2575 int close = 0;
2576 corner_s *c2;
2577
2578 while (again)
2579 {
2580 again = 0;
2581 for (c = corners; c; c = c->next)
2582 {
2583 if (DELETED (c))
2584 continue;
2585 if (!(c->pin || c->via || c->pad))
2586 continue;
2587
2588 pin = 0;
2589
2590 dprintf ("\ncorner %s\n", corner_name (c));
2591 if (c->pin || c->via)
2592 {
2593 pin = c->pin ? c->pin : c->via;
2594 close = pin->Thickness / 2;
2595 left = c->x - close;
2596 right = c->x + close;
2597 bottom = c->y - close;
2598 top = c->y + close;
2599 }
2600 else if (c->pad)
2601 {
2602 close = c->pad->Thickness / 2 + 1;
2603 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2604 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2605 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2606 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2607 if (c->pad->Point1.X == c->pad->Point2.X)
2608 {
2609 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2610 dprintf ("pad y %#mS %#mS hy %#mS c %#mS\n", c->pad->Point1.Y,
2611 c->pad->Point2.Y, hy, c->y);
2612 if (c->y < hy)
2613 top = hy;
2614 else
2615 bottom = hy + 1;
2616 }
2617 else
2618 {
2619 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2620 dprintf ("pad x %#mS %#mS hx %#mS c %#mS\n", c->pad->Point1.X,
2621 c->pad->Point2.X, hx, c->x);
2622 if (c->x < hx)
2623 right = hx;
2624 else
2625 left = hx + 1;
2626 }
2627 }
2628
2629 dprintf ("%s x %#mS-%#mS y %#mS-%#mS\n", corner_name (c), left, right, bottom, top);
2630 for (l = 0; l <= max_copper_layer; l++)
2631 {
2632 best_dist[l] = close * 2;
2633 best_c[l] = 0;
2634 }
2635 got_one = 0;
2636 for (c2 = corners; c2; c2 = c2->next)
2637 {
2638 int lt;
2639
2640 if (DELETED (c2))
2641 continue;
2642 lt = corner_radius (c2);
2643 if (c2->n_lines
2644 && c2 != c
2645 && !(c2->pin || c2->pad || c2->via)
2646 && intersecting_layers (c->layer, c2->layer)
2647 && c2->x >= left - lt
2648 && c2->x <= right + lt
2649 && c2->y >= bottom - lt && c2->y <= top + lt)
2650 {
2651 int d = dist (c->x, c->y, c2->x, c2->y);
2652 if (pin && d > pin->Thickness / 2 + lt)
2653 continue;
2654 if (c2->n_lines == 1)
2655 {
2656 got_one++;
2657 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2658 corner_name (c));
2659 connect_corners (c, c2);
2660 again = 1;
2661 continue;
2662 }
2663 if (best_c[c2->layer] == 0
2664 || c2->n_lines < best_c[c2->layer]->n_lines
2665 || (d < best_dist[c2->layer]
2666 && c2->n_lines <= best_c[c2->layer]->n_lines))
2667 {
2668 best_dist[c2->layer] = d;
2669 best_c[c2->layer] = c2;
2670 dprintf ("layer %d best now %s\n", c2->layer,
2671 corner_name (c2));
2672 }
2673 }
2674 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2675 {
2676 for (l = 0; l <= max_copper_layer; l++)
2677 if (best_c[l])
2678 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2679 for (l = 0; l <= max_copper_layer; l++)
2680 if (best_c[l])
2681 {
2682 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2683 corner_name (c));
2684 connect_corners (best_c[l], c);
2685 again = 1;
2686 continue;
2687 }
2688 }
2689 }
2690 }
2691 }
2692
2693 /* Now look for line ends that don't connect, see if they need to be
2694 extended to intersect another line. */
2695 for (c = corners; c; c = c->next)
2696 {
2697 line_s *l, *t;
2698 int lo;
2699
2700 if (DELETED (c))
2701 continue;
2702 if (c->pin || c->via || c->pad)
2703 continue;
2704 if (c->n_lines != 1)
2705 continue;
2706
2707 l = c->lines[0];
2708 lo = line_orient (l, c);
2709 dprintf ("line end %#mD orient %d\n", c->x, c->y, lo);
2710
2711 for (t = lines; t; t = t->next)
2712 {
2713 if (DELETED (t))
2714 continue;
2715 if (t->layer != c->lines[0]->layer)
2716 continue;
2717 switch (lo) /* remember, orient is for the line relative to the corner */
2718 {
2719 case LEFT:
2720 if (t->s->x == t->e->x
2721 && c->x < t->s->x
2722 && t->s->x <
2723 c->x + (l->line->Thickness + t->line->Thickness) / 2
2724 && ((t->s->y < c->y && c->y < t->e->y)
2725 || (t->e->y < c->y && c->y < t->s->y)))
2726 {
2727 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2728 move_corner (c, t->s->x, c->y);
2729 }
2730 break;
2731 case RIGHT:
2732 if (t->s->x == t->e->x
2733 && c->x > t->s->x
2734 && t->s->x >
2735 c->x - (l->line->Thickness + t->line->Thickness) / 2
2736 && ((t->s->y < c->y && c->y < t->e->y)
2737 || (t->e->y < c->y && c->y < t->s->y)))
2738 {
2739 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2740 move_corner (c, t->s->x, c->y);
2741 }
2742 break;
2743 case UP:
2744 if (t->s->y == t->e->y
2745 && c->y < t->s->y
2746 && t->s->y <
2747 c->y + (l->line->Thickness + t->line->Thickness) / 2
2748 && ((t->s->x < c->x && c->x < t->e->x)
2749 || (t->e->x < c->x && c->x < t->s->x)))
2750 {
2751 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2752 move_corner (c, c->x, t->s->y);
2753 }
2754 break;
2755 case DOWN:
2756 if (t->s->y == t->e->y
2757 && c->y > t->s->y
2758 && t->s->y >
2759 c->y - (l->line->Thickness + t->line->Thickness) / 2
2760 && ((t->s->x < c->x && c->x < t->e->x)
2761 || (t->e->x < c->x && c->x < t->s->x)))
2762 {
2763 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2764 move_corner (c, c->x, t->s->y);
2765 }
2766 break;
2767 }
2768 }
2769 }
2770 }
2771
2772 static int
pad_orient(PadType * p)2773 pad_orient (PadType * p)
2774 {
2775 if (p->Point1.X == p->Point2.X)
2776 return O_VERT;
2777 if (p->Point1.Y == p->Point2.Y)
2778 return O_HORIZ;
2779 return DIAGONAL;
2780 }
2781
2782 static void
padcleaner()2783 padcleaner ()
2784 {
2785 line_s *l, *nextl;
2786 int close;
2787 rect_s r;
2788
2789 dprintf ("\ndj: padcleaner\n");
2790 for (l = lines; l; l = nextl)
2791 {
2792 nextl = l->next;
2793
2794 if (l->is_pad)
2795 continue;
2796
2797 if (DELETED (l))
2798 continue;
2799
2800 dprintf ("dj: line %p\n", (void *) l);
2801 check (0, l);
2802
2803 if (l->s->pad && l->s->pad == l->e->pad)
2804 continue;
2805
2806 ALLPAD_LOOP (PCB->Data);
2807 {
2808 int layerflag =
2809 TEST_FLAG (ONSOLDERFLAG, element) ? LT_BOTTOM : LT_TOP;
2810
2811 if (layer_type[l->layer] != layerflag)
2812 continue;
2813
2814 empty_rect (&r);
2815 close = pad->Thickness / 2 + 1;
2816 add_point_to_rect (&r, pad->Point1.X, pad->Point1.Y, close - SB / 2);
2817 add_point_to_rect (&r, pad->Point2.X, pad->Point2.Y, close - SB / 2);
2818 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2819 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2820 && ORIENT (line_orient (l, 0)) == pad_orient (pad))
2821 {
2822 dprintf
2823 ("padcleaner %#mD-%#mD %#mS vs line %#mD-%#mD %#mS\n",
2824 pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y,
2825 pad->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2826 l->line->Thickness);
2827 remove_line (l);
2828 goto next_line;
2829 }
2830 }
2831 ENDALL_LOOP;
2832 next_line:;
2833 }
2834 }
2835
2836 static void
grok_layer_groups()2837 grok_layer_groups ()
2838 {
2839 int i, j, f;
2840 LayerGroupType *l = &(PCB->LayerGroups);
2841
2842 solder_layer = component_layer = -1;
2843 for (i = 0; i < max_copper_layer; i++)
2844 {
2845 layer_type[i] = 0;
2846 layer_groupings[i] = 0;
2847 }
2848 for (i = 0; i < max_group; i++)
2849 {
2850 f = 0;
2851 for (j = 0; j < l->Number[i]; j++)
2852 {
2853 if (l->Entries[i][j] == bottom_silk_layer)
2854 f |= LT_BOTTOM;
2855 if (l->Entries[i][j] == top_silk_layer)
2856 f |= LT_TOP;
2857 }
2858 for (j = 0; j < l->Number[i]; j++)
2859 {
2860 if (l->Entries[i][j] < max_copper_layer)
2861 {
2862 layer_type[l->Entries[i][j]] |= f;
2863 layer_groupings[l->Entries[i][j]] = i;
2864 if (solder_layer == -1 && f == LT_BOTTOM)
2865 solder_layer = l->Entries[i][j];
2866 if (component_layer == -1 && f == LT_TOP)
2867 component_layer = l->Entries[i][j];
2868 }
2869 }
2870 }
2871 }
2872
2873 static const char djopt_syntax[] =
2874 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull|splitlines)\n"
2875 "djopt(auto) - all of the above\n"
2876 "djopt(miter)";
2877
2878 static const char djopt_help[] =
2879 "Perform various optimizations on the current board.";
2880
2881 /* %start-doc actions djopt
2882
2883 The different types of optimizations change your board in order to
2884 reduce the total trace length and via count.
2885
2886 @table @code
2887
2888 @item debumpify
2889 Looks for U-shaped traces that can be shortened or eliminated.
2890
2891 Example:
2892
2893 Before debumpify:
2894
2895 @center @image{debumpify,,,Example pcb before debumpify,png}
2896
2897 After debumpify:
2898
2899 @center @image{debumpify.out,,,Example pcb after debumpify,png}
2900
2901
2902 @item unjaggy
2903 Looks for corners which could be flipped to eliminate one or more
2904 corners (i.e. jaggy lines become simpler).
2905
2906 Example:
2907
2908 Before unjaggy:
2909
2910 @center @image{unjaggy,,,Example pcb before unjaggy,png}
2911
2912 After unjaggy:
2913
2914 @center @image{unjaggy.out,,,Example pcb after unjaggy,png}
2915
2916
2917 @item simple
2918 Removing uneeded vias, replacing two or more trace segments in a row
2919 with a single segment. This is usually performed automatically after
2920 other optimizations.
2921
2922 @item vianudge
2923 Looks for vias where all traces leave in the same direction. Tries to
2924 move via in that direction to eliminate one of the traces (and thus a
2925 corner).
2926
2927 Example:
2928
2929 Before vianudge:
2930
2931 @center @image{vianudge,,,Example pcb before vianudge,png}
2932
2933 After vianudge:
2934
2935 @center @image{vianudge.out,,,Example pcb after vianudge,png}
2936
2937
2938 @item viatrim
2939 Looks for traces that go from via to via, where moving that trace to a
2940 different layer eliminates one or both vias.
2941
2942 Example:
2943
2944 Before viatrim:
2945
2946 @center @image{viatrim,,,Example pcb before viatrim,png}
2947
2948 After viatrim:
2949
2950 @center @image{viatrim.out,,,Example pcb after viatrim,png}
2951
2952
2953 @item orthopull
2954 Looks for chains of traces all going in one direction, with more
2955 traces orthogonal on one side than on the other. Moves the chain in
2956 that direction, causing a net reduction in trace length, possibly
2957 eliminating traces and/or corners.
2958
2959 Example:
2960
2961 Before orthopull:
2962
2963 @center @image{orthopull,,,Example pcb before orthopull,png}
2964
2965 After orthopull:
2966
2967 @center @image{orthopull.out,,,Example pcb after orthopull,png}
2968
2969
2970 @item splitlines
2971 Looks for lines that pass through vias, pins, or pads, and splits them
2972 into separate lines so they can be managed separately.
2973
2974 @item auto
2975 Performs the above options, repeating until no further optimizations
2976 can be made.
2977
2978 @item miter
2979 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2980 RF losses and trace length.
2981
2982 Example:
2983
2984 Before miter:
2985
2986 @center @image{miter,,,Example pcb before miter,png}
2987
2988 After miter:
2989
2990 @center @image{miter.out,,,Example pcb after miter,png}
2991
2992
2993 @end table
2994
2995 %end-doc */
2996
2997 static int
ActionDJopt(int argc,char ** argv,Coord x,Coord y)2998 ActionDJopt (int argc, char **argv, Coord x, Coord y)
2999 {
3000 char *arg = argc > 0 ? argv[0] : 0;
3001 int layn, saved = 0;
3002 corner_s *c;
3003
3004 hid_action("Busy");
3005
3006 lines = 0;
3007 corners = 0;
3008
3009 grok_layer_groups ();
3010
3011 ELEMENT_LOOP (PCB->Data);
3012 PIN_LOOP (element);
3013 {
3014 c = find_corner (pin->X, pin->Y, -1);
3015 c->pin = pin;
3016 }
3017 END_LOOP;
3018 PAD_LOOP (element);
3019 {
3020 int layern =
3021 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
3022 line_s *ls = (line_s *) malloc (sizeof (line_s));
3023 ls->next = lines;
3024 lines = ls;
3025 ls->is_pad = 1;
3026 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
3027 ls->s->pad = pad;
3028 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
3029 ls->e->pad = pad;
3030 ls->layer = layern;
3031 ls->line = (LineType *) pad;
3032 add_line_to_corner (ls, ls->s);
3033 add_line_to_corner (ls, ls->e);
3034
3035 }
3036 END_LOOP;
3037 END_LOOP;
3038 VIA_LOOP (PCB->Data);
3039 /* hace don't mess with vias that have thermals */
3040 /* but then again don't bump into them
3041 if (!TEST_FLAG(ALLTHERMFLAGS, via))
3042 */
3043 {
3044 c = find_corner (via->X, via->Y, -1);
3045 c->via = via;
3046 }
3047 END_LOOP;
3048 check (0, 0);
3049
3050 for (layn = 0; layn < max_copper_layer; layn++)
3051 {
3052 LayerType *layer = LAYER_PTR (layn);
3053 if (layer->Type != LT_COPPER)
3054 continue;
3055
3056 LINE_LOOP (layer);
3057 {
3058 line_s *ls;
3059
3060 if(autorouted_only && !autorouted (line))
3061 continue;
3062
3063 /* don't mess with thermals */
3064 if (TEST_FLAG (USETHERMALFLAG, line))
3065 continue;
3066
3067 if (line->Point1.X == line->Point2.X &&
3068 line->Point1.Y == line->Point2.Y)
3069 {
3070 RemoveLine (layer, line);
3071 continue;
3072 }
3073
3074 ls = (line_s *) malloc (sizeof (line_s));
3075 ls->next = lines;
3076 lines = ls;
3077 ls->is_pad = 0;
3078 ls->s = find_corner (line->Point1.X, line->Point1.Y, layn);
3079 ls->e = find_corner (line->Point2.X, line->Point2.Y, layn);
3080 ls->line = line;
3081 add_line_to_corner (ls, ls->s);
3082 add_line_to_corner (ls, ls->e);
3083 ls->layer = layn;
3084 }
3085 END_LOOP;
3086 }
3087
3088 check (0, 0);
3089 if (NSTRCMP (arg, "splitlines") != 0)
3090 pinsnap ();
3091 saved += canonicalize_lines ();
3092 check (0, 0);
3093 classify_nets ();
3094 /*dump_all(); */
3095 check (0, 0);
3096
3097 if (NSTRCMP (arg, "debumpify") == 0)
3098 saved += debumpify ();
3099 else if (NSTRCMP (arg, "unjaggy") == 0)
3100 saved += unjaggy ();
3101 else if (NSTRCMP (arg, "simple") == 0)
3102 saved += simple_optimizations ();
3103 else if (NSTRCMP (arg, "vianudge") == 0)
3104 saved += vianudge ();
3105 else if (NSTRCMP (arg, "viatrim") == 0)
3106 saved += viatrim ();
3107 else if (NSTRCMP (arg, "orthopull") == 0)
3108 saved += orthopull ();
3109 else if (NSTRCMP (arg, "auto") == 0)
3110 saved += automagic ();
3111 else if (NSTRCMP (arg, "miter") == 0)
3112 saved += miter ();
3113 else if (NSTRCMP (arg, "splitlines") == 0)
3114 /* Just to call canonicalize_lines() above. */ ;
3115 else
3116 {
3117 printf ("unknown command: %s\n", arg);
3118 return 1;
3119 }
3120
3121 padcleaner ();
3122
3123 check (0, 0);
3124 if (saved)
3125 IncrementUndoSerialNumber ();
3126 return 0;
3127 }
3128
3129 HID_Action djopt_action_list[] = {
3130 {"djopt", 0, ActionDJopt,
3131 djopt_help, djopt_syntax}
3132 ,
3133 {"OptAutoOnly", 0, djopt_set_auto_only,
3134 djopt_sao_help, djopt_sao_syntax}
3135 };
3136
3137 REGISTER_ACTIONS (djopt_action_list)
3138