Merge branch 'master' of git://git.gpleda.org/pcb
[geda-pcb/see.git] / src / djopt.c
blob8b01641eb468c4b59bd47289560998d54e39621c
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2003 DJ Delorie
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
25 * dj@delorie.com
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include "global.h"
35 #include <memory.h>
36 #include <limits.h>
39 #include "data.h"
40 #include "create.h"
41 #include "remove.h"
42 #include "move.h"
43 #include "draw.h"
44 #include "undo.h"
45 #include "strflags.h"
46 #include "find.h"
48 #ifdef HAVE_LIBDMALLOC
49 #include <dmalloc.h>
50 #endif
52 RCSID ("$Id$");
54 #ifndef HAVE_RINT
55 #define rint(x) (ceil((x) - 0.5))
56 #endif
58 #define dprintf if(0)printf
60 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x))
61 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x))
63 #define SB (PCB->Bloat+1)
65 /* must be 2^N-1 */
66 #define INC 7
68 #define O_HORIZ 0x10
69 #define O_VERT 0x20
70 #define LEFT 0x11
71 #define RIGHT 0x12
72 #define UP 0x24
73 #define DOWN 0x28
74 #define DIAGONAL 0xf0
75 #define ORIENT(x) ((x) & 0xf0)
76 #define DIRECT(x) ((x) & 0x0f)
78 /* Manhattan length of the longest "freckle" */
79 #define LONGEST_FRECKLE 2
81 struct line_s;
83 typedef struct corner_s
85 int layer;
86 struct corner_s *next;
87 int x, y;
88 int net;
89 PinType *via;
90 PadType *pad;
91 PinType *pin;
92 int miter;
93 int n_lines;
94 struct line_s **lines;
95 } corner_s;
97 typedef struct line_s
99 int layer;
100 struct line_s *next;
101 corner_s *s, *e;
102 LineType *line;
103 char is_pad;
104 } line_s;
106 typedef struct rect_s
108 int x1, y1, x2, y2;
109 } rect_s;
111 #define DELETE(q) (q)->layer = 0xdeadbeef
112 #define DELETED(q) ((q)->layer == 0xdeadbeef)
114 static corner_s *corners, *next_corner = 0;
115 static line_s *lines;
117 static int layer_groupings[MAX_LAYER];
118 static char layer_type[MAX_LAYER];
119 #define LT_COMPONENT 1
120 #define LT_SOLDER 2
122 static int autorouted_only = 1;
124 static const char djopt_sao_syntax[] = "OptAutoOnly()";
126 static const char djopt_sao_help[] =
127 "Toggles the optimize-only-autorouted flag.";
129 /* %start-doc actions OptAutoOnly
131 The original purpose of the trace optimizer was to clean up the traces
132 created by the various autorouters that have been used with PCB. When
133 a board has a mix of autorouted and carefully hand-routed traces, you
134 don't normally want the optimizer to move your hand-routed traces.
135 But, sometimes you do. By default, the optimizer only optimizes
136 autorouted traces. This action toggles that setting, so that you can
137 optimize hand-routed traces also.
139 %end-doc */
142 djopt_set_auto_only (int argc, char **argv, int x, int y)
144 autorouted_only = autorouted_only ? 0 : 1;
145 return 0;
148 static int
149 djopt_get_auto_only (int dummy)
151 return autorouted_only;
154 HID_Flag djopt_flag_list[] = {
155 {"optautoonly", djopt_get_auto_only, 0}
158 REGISTER_FLAGS (djopt_flag_list)
160 static char *
161 element_name_for (corner_s * c)
163 int i, p;
164 ElementType *e;
166 for (i = 0; i < PCB->Data->ElementN; i++)
168 e = PCB->Data->Element + i;
169 for (p = 0; p < e->PinN; p++)
170 if (e->Pin + p == c->pin)
171 return e->Name[1].TextString;
172 for (p = 0; p < e->PadN; p++)
173 if (e->Pad + p == c->pad)
174 return e->Name[1].TextString;
176 return "unknown";
179 static char *
180 corner_name (corner_s * c)
182 static char buf[4][100];
183 static int bn = 0;
184 char *bp;
185 bn = (bn + 1) % 4;
187 if (c->net == 0xf1eef1ee)
189 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
190 return buf[bn];
193 sprintf (buf[bn], "\033[%dm[%p ",
194 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
195 bp = buf[bn] + strlen (buf[bn]);
197 if (c->pin)
198 sprintf (bp, "pin %s:%s at %d,%d", element_name_for (c), c->pin->Number,
199 c->x, c->y);
200 else if (c->via)
201 sprintf (bp, "via at %d,%d", c->x, c->y);
202 else if (c->pad)
204 sprintf (bp, "pad %s:%s at %d,%d (%d,%d-%d,%d)",
205 element_name_for (c), c->pad->Number, c->x, c->y,
206 c->pad->Point1.X, c->pad->Point1.Y,
207 c->pad->Point2.X, c->pad->Point2.Y);
209 else
210 sprintf (bp, "at %d,%d", c->x, c->y);
211 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
212 return buf[bn];
215 static int solder_layer, component_layer;
217 static void
218 dj_abort (char *msg, ...)
220 va_list a;
221 va_start (a, msg);
222 vprintf (msg, a);
223 va_end (a);
224 fflush (stdout);
225 abort ();
228 #if 1
229 #define check(c,l)
230 #else
231 #define check(c,l) check2(__LINE__,c,l)
232 static void
233 check2 (int srcline, corner_s * c, line_s * l)
235 int saw_c = 0, saw_l = 0;
236 corner_s *cc;
237 line_s *ll;
238 int i;
240 for (cc = corners; cc; cc = cc->next)
242 if (DELETED (cc))
243 continue;
244 if (cc == c)
245 saw_c = 1;
246 for (i = 0; i < cc->n_lines; i++)
247 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
248 dj_abort ("check:%d: cc has line without backref\n", srcline);
249 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
250 dj_abort ("check:%d: via not at corner\n", srcline);
251 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
252 dj_abort ("check:%d: pin not at corner\n", srcline);
254 if (c && !saw_c)
255 dj_abort ("check:%d: corner not in corners list\n", srcline);
256 for (ll = lines; ll; ll = ll->next)
258 if (DELETED (ll))
259 continue;
260 if (ll == l)
261 saw_l = 1;
262 for (i = 0; i < ll->s->n_lines; i++)
263 if (ll->s->lines[i] == ll)
264 break;
265 if (i == ll->s->n_lines)
266 dj_abort ("check:%d: ll->s has no backref\n", srcline);
267 for (i = 0; i < ll->e->n_lines; i++)
268 if (ll->e->lines[i] == ll)
269 break;
270 if (i == ll->e->n_lines)
271 dj_abort ("check:%d: ll->e has no backref\n", srcline);
272 if (!ll->is_pad
273 && (ll->s->x != ll->line->Point1.X
274 || ll->s->y != ll->line->Point1.Y
275 || ll->e->x != ll->line->Point2.X
276 || ll->e->y != ll->line->Point2.Y))
278 printf ("line: %d,%d to %d,%d pcbline: %d,%d to %d,%d\n",
279 ll->s->x, ll->s->y,
280 ll->e->x, ll->e->y,
281 ll->line->Point1.X,
282 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
283 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
286 if (l && !saw_l)
287 dj_abort ("check:%d: line not in lines list\n", srcline);
290 #endif
292 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
294 static int
295 gridsnap (int n)
297 if (n <= 0)
298 return 0;
299 return n - n % (int) (Settings.Grid);
302 /* Avoid commonly used names. */
304 static int
305 djabs (int x)
307 return x > 0 ? x : -x;
310 static int
311 djmax (int x, int y)
313 return x > y ? x : y;
316 static int
317 djmin (int x, int y)
319 return x < y ? x : y;
323 * Find distance between 2 points. We use floating point math here
324 * because we can fairly easily overflow a 32 bit integer here. In
325 * fact it only takes 0.46" to do so.
327 static int
328 dist (int x1, int y1, int x2, int y2)
330 double dx1, dy1, dx2, dy2, d;
332 dx1 = (double) x1;
333 dy1 = (double) y1;
334 dx2 = (double) x2;
335 dy2 = (double) y2;
337 d = sqrt ((dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2));
338 d = rint (d);
340 return (int) d;
343 static int
344 line_length (line_s * l)
346 if (l->s->x == l->e->x)
347 return djabs (l->s->y - l->e->y);
348 if (l->s->y == l->e->y)
349 return djabs (l->s->x - l->e->x);
350 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
353 static int
354 dist_ltp2 (int dx, int y, int y1, int y2)
356 if (y1 > y2)
357 SWAP (y1, y2);
358 if (y < y1)
359 return dist (dx, y, 0, y1);
360 if (y > y2)
361 return dist (dx, y, 0, y2);
362 return djabs (dx);
366 sqr (int a)
368 return a * a;
371 static int
372 intersecting_layers (int l1, int l2)
374 if (l1 == -1 || l2 == -1)
375 return 1;
376 if (l1 == l2)
377 return 1;
378 if (layer_groupings[l1] == layer_groupings[l2])
379 return 1;
380 return 0;
383 static int
384 dist_line_to_point (line_s * l, corner_s * c)
386 double len, r, d;
387 /* We can do this quickly if l is vertical or horizontal. */
388 if (l->s->x == l->e->x)
389 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
390 if (l->s->y == l->e->y)
391 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
393 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
394 len = sqrt (sqr (l->s->x - l->e->x) + sqr (l->s->y - l->e->y));
395 if (len == 0)
396 return dist (l->s->x, l->s->y, c->x, c->y);
398 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
399 l->e->x);
400 r /= len * len;
401 if (r < 0)
402 return dist (l->s->x, l->s->y, c->x, c->y);
403 if (r > 1)
404 return dist (l->e->x, l->e->y, c->x, c->y);
406 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
407 l->s->y);
408 return (int) (d / len);
411 static int
412 line_orient (line_s * l, corner_s * c)
414 int x1, y1, x2, y2;
415 if (c == l->s)
417 x1 = l->s->x;
418 y1 = l->s->y;
419 x2 = l->e->x;
420 y2 = l->e->y;
422 else
424 x1 = l->e->x;
425 y1 = l->e->y;
426 x2 = l->s->x;
427 y2 = l->s->y;
429 if (x1 == x2)
431 if (y1 < y2)
432 return DOWN;
433 return UP;
435 else if (y1 == y2)
437 if (x1 < x2)
438 return RIGHT;
439 return LEFT;
441 return DIAGONAL;
444 #if 0
445 /* Not used */
446 static corner_s *
447 common_corner (line_s * l1, line_s * l2)
449 if (l1->s == l2->s || l1->s == l2->e)
450 return l1->s;
451 if (l1->e == l2->s || l1->e == l2->e)
452 return l1->e;
453 dj_abort ("common_corner: no common corner found\n");
454 return NULL;
456 #endif
458 static corner_s *
459 other_corner (line_s * l, corner_s * c)
461 if (l->s == c)
462 return l->e;
463 if (l->e == c)
464 return l->s;
465 dj_abort ("other_corner: neither corner passed\n");
466 return NULL;
469 static corner_s *
470 find_corner_if (int x, int y, int l)
472 corner_s *c;
473 for (c = corners; c; c = c->next)
475 if (DELETED (c))
476 continue;
477 if (c->x != x || c->y != y)
478 continue;
479 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
480 continue;
481 return c;
483 return 0;
486 static corner_s *
487 find_corner (int x, int y, int l)
489 corner_s *c;
490 for (c = corners; c; c = c->next)
492 if (DELETED (c))
493 continue;
494 if (c->x != x || c->y != y)
495 continue;
496 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
497 continue;
498 return c;
500 c = (corner_s *) malloc (sizeof (corner_s));
501 c->next = corners;
502 corners = c;
503 c->x = x;
504 c->y = y;
505 c->net = 0;
506 c->via = 0;
507 c->pad = 0;
508 c->pin = 0;
509 c->layer = l;
510 c->n_lines = 0;
511 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
512 return c;
515 static void
516 add_line_to_corner (line_s * l, corner_s * c)
518 int n;
519 n = (c->n_lines + 1 + INC) & ~INC;
520 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
521 c->lines[c->n_lines] = l;
522 c->n_lines++;
523 dprintf ("add_line_to_corner %d %d\n", c->x, c->y);
526 static LineType *
527 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
528 int thick, int clear, FlagType flags)
530 char *from, *to;
531 LineType *nl;
532 LayerType *lyr = LAYER_PTR (layer);
534 from = (char *) lyr->Line;
535 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
536 x1, y1, x2, y2, thick, clear, flags);
537 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
539 to = (char *) lyr->Line;
540 if (from != to)
542 line_s *lp;
543 for (lp = lines; lp; lp = lp->next)
545 if (DELETED (lp))
546 continue;
547 if ((char *) (lp->line) >= from
548 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
549 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
552 return nl;
555 static void
556 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
558 line_s *ls;
560 if (layer >= max_copper_layer)
561 dj_abort ("layer %d\n", layer);
563 if (example == NULL)
564 dj_abort ("NULL example passed to new_line()\n", layer);
566 if (s->x == e->x && s->y == e->y)
567 return;
569 ls = (line_s *) malloc (sizeof (line_s));
570 ls->next = lines;
571 lines = ls;
572 ls->is_pad = 0;
573 ls->s = s;
574 ls->e = e;
575 ls->layer = layer;
576 #if 0
577 if ((example->Point1.X == s->x && example->Point1.Y == s->y
578 && example->Point2.X == e->x && example->Point2.Y == e->y)
579 || (example->Point2.X == s->x && example->Point2.Y == s->y
580 && example->Point1.X == e->x && example->Point1.Y == e->y))
582 ls->line = example;
584 else
585 #endif
587 LineType *nl;
588 dprintf
589 ("New line \033[35m%d,%d to %d,%d from l%d t%d c%d f%s\033[0m\n",
590 s->x, s->y, e->x, e->y, layer, example->Thickness,
591 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
592 nl =
593 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
594 example->Clearance, example->Flags);
596 if (!nl)
597 dj_abort ("can't create new line!");
598 ls->line = nl;
600 add_line_to_corner (ls, s);
601 add_line_to_corner (ls, e);
602 check (s, ls);
603 check (e, ls);
606 #if 0
607 /* Not used */
608 static int
609 c_orth_to (corner_s * c, line_s * l, int o)
611 int i, o2;
612 int rv = 0;
613 for (i = 0; i < c->n_lines; i++)
615 if (c->lines[i] == l)
616 continue;
617 o2 = line_orient (c->lines[i], c);
618 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
619 return 0;
620 rv++;
622 return rv;
624 #endif
626 static line_s *
627 other_line (corner_s * c, line_s * l)
629 int i;
630 line_s *rv = 0;
631 if (c->pin || c->pad || c->via)
632 return 0;
633 for (i = 0; i < c->n_lines; i++)
635 if (c->lines[i] == l)
636 continue;
637 if (rv)
638 return 0;
639 rv = c->lines[i];
641 return rv;
644 static void
645 empty_rect (rect_s * rect)
647 rect->x1 = rect->y1 = INT_MAX;
648 rect->x2 = rect->y2 = INT_MIN;
651 static void
652 add_point_to_rect (rect_s * rect, int x, int y, int w)
654 if (rect->x1 > x - w)
655 rect->x1 = x - w;
656 if (rect->x2 < x + w)
657 rect->x2 = x + w;
658 if (rect->y1 > y - w)
659 rect->y1 = y - w;
660 if (rect->y2 < y + w)
661 rect->y2 = y + w;
664 static void
665 add_line_to_rect (rect_s * rect, line_s * l)
667 add_point_to_rect (rect, l->s->x, l->s->y, 0);
668 add_point_to_rect (rect, l->e->x, l->e->y, 0);
671 static int
672 pin_in_rect (rect_s * r, int x, int y, int w)
674 if (x < r->x1 && x + w < r->x1)
675 return 0;
676 if (x > r->x2 && x - w > r->x2)
677 return 0;
678 if (y < r->y1 && y + w < r->y1)
679 return 0;
680 if (y > r->y2 && y - w > r->y2)
681 return 0;
682 return 1;
685 static int
686 line_in_rect (rect_s * r, line_s * l)
688 rect_s lr;
689 empty_rect (&lr);
690 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
691 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
692 dprintf ("line_in_rect %d,%d-%d,%d vs %d,%d-%d,%d\n",
693 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
694 /* simple intersection of rectangles */
695 if (lr.x1 < r->x1)
696 lr.x1 = r->x1;
697 if (lr.x2 > r->x2)
698 lr.x2 = r->x2;
699 if (lr.y1 < r->y1)
700 lr.y1 = r->y1;
701 if (lr.y2 > r->y2)
702 lr.y2 = r->y2;
703 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
704 return 1;
705 return 0;
708 static int
709 corner_radius (corner_s * c)
711 int diam = 0;
712 int i;
713 if (c->pin)
714 diam = djmax (c->pin->Thickness, diam);
715 if (c->via)
716 diam = djmax (c->via->Thickness, diam);
717 for (i = 0; i < c->n_lines; i++)
718 if (c->lines[i]->line)
719 diam = djmax (c->lines[i]->line->Thickness, diam);
720 diam = (diam + 1) / 2;
721 return diam;
724 #if 0
725 /* Not used */
726 static int
727 corner_layer (corner_s * c)
729 if (c->pin || c->via)
730 return -1;
731 if (c->n_lines < 1)
732 return -1;
733 return c->lines[0]->layer;
735 #endif
737 static void
738 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
740 int diam = corner_radius (c);
741 if (!pin_in_rect (e, c->x, c->y, diam))
742 return;
743 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
744 return;
745 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
746 return;
747 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
748 return;
749 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
750 return;
752 /*printf("add point %d,%d diam %d\n", c->x, c->y, diam); */
753 add_point_to_rect (rect, c->x, c->y, diam);
756 static void
757 remove_line (line_s * l)
759 int i, j;
760 line_s *l2;
761 LineType *from = 0, *to = 0;
762 LayerType *layer = &(PCB->Data->Layer[l->layer]);
764 check (0, 0);
766 if (l->line)
768 /* compensate for having line pointers rearranged */
769 from = &(layer->Line[layer->LineN - 1]);
770 to = l->line;
771 RemoveLine (layer, l->line);
774 DELETE (l);
775 for (l2 = lines; l2; l2 = l2->next)
777 if (DELETED (l2))
778 continue;
779 if (l2->line == from)
780 l2->line = to;
783 for (i = 0, j = 0; i < l->s->n_lines; i++)
784 if (l->s->lines[i] != l)
785 l->s->lines[j++] = l->s->lines[i];
786 l->s->n_lines = j;
788 for (i = 0, j = 0; i < l->e->n_lines; i++)
789 if (l->e->lines[i] != l)
790 l->e->lines[j++] = l->e->lines[i];
791 l->e->n_lines = j;
792 check (0, 0);
795 static void
796 move_line_to_layer (line_s * l, int layer)
798 line_s *l2;
799 LayerType *ls, *ld;
800 LineType *from = 0, *to = 0;
801 LineType *oldbase = 0, *newbase = 0, *oldend;
802 LineType *newline;
804 ls = LAYER_PTR (l->layer);
805 from = &(ls->Line[ls->LineN - 1]);
806 to = l->line;
808 ld = LAYER_PTR (layer);
809 oldbase = ld->Line;
810 oldend = oldbase + ld->LineN;
812 newline = (LineType *) MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
813 newbase = ld->Line;
815 for (l2 = lines; l2; l2 = l2->next)
817 if (DELETED (l2))
818 continue;
819 if (l2->line == from)
820 l2->line = to;
821 if (l2->line >= oldbase && l2->line < oldend)
822 l2->line += newbase - oldbase;
825 l->line = newline;
826 l->layer = layer;
829 static void
830 remove_via_at (corner_s * c)
832 corner_s *cc;
833 PinType *from = PCB->Data->Via + PCB->Data->ViaN - 1;
834 PinType *to = c->via;
835 RemoveObject (VIA_TYPE, c->via, 0, 0);
836 c->via = 0;
837 for (cc = corners; cc; cc = cc->next)
839 if (DELETED (cc))
840 continue;
841 if (cc->via == from)
842 cc->via = to;
846 static void
847 remove_corner (corner_s * c2)
849 corner_s *c;
850 dprintf ("remove corner %s\n", corner_name (c2));
851 if (corners == c2)
852 corners = c2->next;
853 for (c = corners; c; c = c->next)
855 if (DELETED (c))
856 continue;
857 if (c->next == c2)
858 c->next = c2->next;
860 if (next_corner == c2)
861 next_corner = c2->next;
862 free (c2->lines);
863 c2->lines = 0;
864 DELETE (c2);
867 static void
868 merge_corners (corner_s * c1, corner_s * c2)
870 int i;
871 if (c1 == c2)
872 abort ();
873 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
874 for (i = 0; i < c2->n_lines; i++)
876 add_line_to_corner (c2->lines[i], c1);
877 if (c2->lines[i]->s == c2)
878 c2->lines[i]->s = c1;
879 if (c2->lines[i]->e == c2)
880 c2->lines[i]->e = c1;
882 if (c1->via && c2->via)
883 remove_via_at (c2);
884 else if (c2->via)
885 c1->via = c2->via;
886 if (c2->pad)
887 c1->pad = c2->pad;
888 if (c2->pin)
889 c1->pin = c2->pin;
890 if (c2->layer != c1->layer)
891 c1->layer = -1;
893 remove_corner (c2);
896 static void
897 move_corner (corner_s * c, int x, int y)
899 PinType *via;
900 int i;
901 corner_s *pad;
903 check (c, 0);
904 if (c->pad || c->pin)
905 dj_abort ("move_corner: has pin or pad\n");
906 dprintf ("move_corner %p from %d,%d to %d,%d\n", (void *) c, c->x, c->y, x,
908 pad = find_corner_if (x, y, c->layer);
909 c->x = x;
910 c->y = y;
911 via = c->via;
912 if (via)
914 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
915 dprintf ("via move %d,%d to %d,%d\n", via->X, via->Y, x, y);
917 for (i = 0; i < c->n_lines; i++)
919 LineTypePtr tl = c->lines[i]->line;
920 if (tl)
922 if (c->lines[i]->s == c)
924 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
925 &tl->Point1, x - (tl->Point1.X),
926 y - (tl->Point1.Y));
928 else
930 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
931 &tl->Point2, x - (tl->Point2.X),
932 y - (tl->Point2.Y));
934 dprintf ("Line %p moved to %d,%d %d,%d\n", (void *) tl,
935 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
938 if (pad && pad != c)
939 merge_corners (c, pad);
940 else
941 for (i = 0; i < c->n_lines; i++)
943 if (c->lines[i]->s->x == c->lines[i]->e->x
944 && c->lines[i]->s->y == c->lines[i]->e->y)
946 corner_s *c2 = other_corner (c->lines[i], c);
947 dprintf ("move_corner: removing line %d,%d %d,%d %p %p\n",
948 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
950 remove_line (c->lines[i]);
951 if (c != c2)
952 merge_corners (c, c2);
953 check (c, 0);
954 i--;
955 break;
958 gui->progress (0, 0, 0);
959 check (c, 0);
962 static int
963 any_line_selected ()
965 line_s *l;
966 for (l = lines; l; l = l->next)
968 if (DELETED (l))
969 continue;
970 if (l->line && selected (l->line))
971 return 1;
973 return 0;
976 static int
977 trim_step (int s, int l1, int l2)
979 dprintf ("trim %d %d %d\n", s, l1, l2);
980 if (s > l1)
981 s = l1;
982 if (s > l2)
983 s = l2;
984 if (s != l1 && s != l2)
985 s = gridsnap (s);
986 return s;
989 static int canonicalize_line (line_s * l);
991 static int
992 split_line (line_s * l, corner_s * c)
994 int i;
995 LayerType *layer;
996 LineType *pcbline;
997 line_s *ls;
999 if (!intersecting_layers (l->layer, c->layer))
1000 return 0;
1001 if (l->is_pad)
1002 return 0;
1003 if (c->pad)
1005 dprintf ("split on pad!\n");
1006 if (l->s->pad == c->pad || l->e->pad == c->pad)
1007 return 0;
1008 dprintf ("splitting...\n");
1011 check (c, l);
1012 layer = PCB->Data->Layer + l->layer;
1013 pcbline = create_pcb_line (l->layer,
1014 c->x, c->y, l->e->x, l->e->y,
1015 l->line->Thickness, l->line->Clearance,
1016 l->line->Flags);
1017 if (pcbline == 0)
1018 return 0; /* already a line there */
1020 check (c, l);
1022 dprintf ("split line from %d,%d to %d,%d at %d,%d\n",
1023 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
1024 ls = (line_s *) malloc (sizeof (line_s));
1026 ls->next = lines;
1027 lines = ls;
1028 ls->is_pad = 0;
1029 ls->s = c;
1030 ls->e = l->e;
1031 ls->line = pcbline;
1032 ls->layer = l->layer;
1033 for (i = 0; i < l->e->n_lines; i++)
1034 if (l->e->lines[i] == l)
1035 l->e->lines[i] = ls;
1036 l->e = c;
1037 add_line_to_corner (l, c);
1038 add_line_to_corner (ls, c);
1040 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
1041 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
1043 return 1;
1046 static int
1047 canonicalize_line (line_s * l)
1049 /* This could be faster */
1050 corner_s *c;
1051 if (l->s->x == l->e->x)
1053 int y1 = l->s->y;
1054 int y2 = l->e->y;
1055 int x1 = l->s->x - l->line->Thickness / 2;
1056 int x2 = l->s->x + l->line->Thickness / 2;
1057 if (y1 > y2)
1059 int t = y1;
1060 y1 = y2;
1061 y2 = t;
1063 for (c = corners; c; c = c->next)
1065 if (DELETED (c))
1066 continue;
1067 if ((y1 < c->y && c->y < y2)
1068 && intersecting_layers (l->layer, c->layer))
1070 if (c->x != l->s->x
1071 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1073 move_corner (c, l->s->x, c->y);
1075 if (c->x == l->s->x)
1077 /* FIXME: if the line is split, we have to re-canonicalize
1078 both segments. */
1079 return split_line (l, c);
1084 else if (l->s->y == l->e->y)
1086 int x1 = l->s->x;
1087 int x2 = l->e->x;
1088 int y1 = l->s->y - l->line->Thickness / 2;
1089 int y2 = l->s->y + l->line->Thickness / 2;
1090 if (x1 > x2)
1092 int t = x1;
1093 x1 = x2;
1094 x2 = t;
1096 for (c = corners; c; c = c->next)
1098 if (DELETED (c))
1099 continue;
1100 if ((x1 < c->x && c->x < x2)
1101 && intersecting_layers (l->layer, c->layer))
1103 if (c->y != l->s->y
1104 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1106 move_corner (c, c->x, l->s->y);
1108 if (c->y == l->s->y)
1110 /* FIXME: Likewise. */
1111 return split_line (l, c);
1116 else
1118 /* diagonal lines. Let's try to split them at pins/vias
1119 anyway. */
1120 int x1 = l->s->x;
1121 int x2 = l->e->x;
1122 int y1 = l->s->y;
1123 int y2 = l->e->y;
1124 if (x1 > x2)
1126 int t = x1;
1127 x1 = x2;
1128 x2 = t;
1130 if (y1 > y2)
1132 int t = y1;
1133 y1 = y2;
1134 y2 = t;
1136 for (c = corners; c; c = c->next)
1138 if (DELETED (c))
1139 continue;
1140 if (!c->via && !c->pin)
1141 continue;
1142 if ((x1 < c->x && c->x < x2)
1143 && (y1 < c->y && c->y < y2)
1144 && intersecting_layers (l->layer, c->layer))
1146 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1147 th /= 2;
1148 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1149 && dist (l->e->x, l->e->y, c->x, c->y) > th
1150 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1152 return split_line (l, c);
1157 return 0;
1160 /* Make sure all vias are at line end points */
1161 static int
1162 canonicalize_lines ()
1164 int changes = 0;
1165 int count;
1166 line_s *l;
1167 while (1)
1169 count = 0;
1170 for (l = lines; l; l = l->next)
1172 if (DELETED (l))
1173 continue;
1174 count += canonicalize_line (l);
1176 changes += count;
1177 if (count == 0)
1178 break;
1180 return changes;
1183 static int
1184 simple_optimize_corner (corner_s * c)
1186 int i;
1187 int rv = 0;
1189 check (c, 0);
1190 if (c->via)
1192 /* see if no via is needed */
1193 if (selected (c->via))
1194 dprintf ("via check: line[0] layer %d at %d,%d nl %d\n",
1195 c->lines[0]->layer, c->x, c->y, c->n_lines);
1196 /* We can't delete vias that connect to power planes, or vias
1197 that aren't tented (assume they're test points). */
1198 if (!TEST_ANY_THERMS (c->via)
1199 && c->via->Mask == 0)
1201 for (i = 1; i < c->n_lines; i++)
1203 if (selected (c->via))
1204 dprintf (" line[%d] layer %d %d,%d to %d,%d\n",
1205 i, c->lines[i]->layer,
1206 c->lines[i]->s->x, c->lines[i]->s->y,
1207 c->lines[i]->e->x, c->lines[i]->e->y);
1208 if (c->lines[i]->layer != c->lines[0]->layer)
1209 break;
1211 if (i == c->n_lines)
1213 if (selected (c->via))
1214 dprintf (" remove it\n");
1215 remove_via_at (c);
1216 rv++;
1221 check (c, 0);
1222 if (c->n_lines == 2 && !c->via)
1224 /* see if it is an unneeded corner */
1225 int o = line_orient (c->lines[0], c);
1226 corner_s *c2 = other_corner (c->lines[1], c);
1227 corner_s *c0 = other_corner (c->lines[0], c);
1228 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1230 dprintf ("straight %d,%d to %d,%d to %d,%d\n",
1231 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1232 if (selected (c->lines[0]->line))
1233 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1234 if (selected (c->lines[1]->line))
1235 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1236 move_corner (c, c2->x, c2->y);
1239 check (c, 0);
1240 if (c->n_lines == 1 && !c->via)
1242 corner_s *c0 = other_corner (c->lines[0], c);
1243 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE)
1246 * Remove this line, as it is a "freckle". A freckle is an extremely
1247 * short line (around 0.01 thou) that is unconnected at one end.
1248 * Freckles are almost insignificantly small, but are annoying as
1249 * they prevent the mitering optimiser from working.
1250 * Freckles sometimes arise because of a bug in the autorouter that
1251 * causes it to create small overshoots (typically 0.01 thou) at the
1252 * intersections of vertical and horizontal lines. These overshoots
1253 * are converted to freckles as a side effect of canonicalize_line().
1254 * Note that canonicalize_line() is not at fault, the bug is in the
1255 * autorouter creating overshoots.
1256 * The autorouter bug arose some time between the 20080202 and 20091103
1257 * releases.
1258 * This code is probably worth keeping even when the autorouter bug is
1259 * fixed, as "freckles" could conceivably arise in other ways.
1261 dprintf ("freckle %d,%d to %d,%d\n",
1262 c->x, c->y, c0->x, c0->y);
1263 move_corner (c, c0->x, c0->y);
1266 check (c, 0);
1267 return rv;
1270 /* We always run these */
1271 static int
1272 simple_optimizations ()
1274 corner_s *c;
1275 int rv = 0;
1277 /* Look for corners that aren't */
1278 for (c = corners; c; c = c->next)
1280 if (DELETED (c))
1281 continue;
1282 if (c->pad || c->pin)
1283 continue;
1284 rv += simple_optimize_corner (c);
1286 return rv;
1289 static int
1290 is_hole (corner_s * c)
1292 return c->pin || c->pad || c->via;
1295 static int
1296 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1298 static corner_s **cs = 0;
1299 static int cm = 0;
1300 static line_s **ls = 0;
1301 static int lm = 0;
1302 int i, li, ln, cn, snap;
1303 line_s *l = 0;
1304 corner_s *c2, *cb;
1305 int adir = 0, sdir = 0, pull;
1306 int saw_sel = 0, saw_auto = 0;
1307 int max, len = 0, r1 = 0, r2;
1308 rect_s rr;
1309 int edir = 0, done;
1311 if (cs == 0)
1313 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1314 cm = 10;
1315 ls = (line_s **) malloc (10 * sizeof (line_s));
1316 lm = 10;
1319 for (i = 0; i < c->n_lines; i++)
1321 int o = line_orient (c->lines[i], c);
1322 if (o == rdir)
1323 return 0;
1326 switch (fdir)
1328 case RIGHT:
1329 adir = DOWN;
1330 sdir = UP;
1331 break;
1332 case DOWN:
1333 adir = RIGHT;
1334 sdir = LEFT;
1335 break;
1336 default:
1337 dj_abort ("fdir not right or down\n");
1340 c2 = c;
1341 cn = 0;
1342 ln = 0;
1343 pull = 0;
1344 while (c2)
1346 if (c2->pad || c2->pin || c2->n_lines < 2)
1347 return 0;
1348 if (cn >= cm)
1350 cm = cn + 10;
1351 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s));
1353 cs[cn++] = c2;
1354 r2 = corner_radius (c2);
1355 if (r1 < r2)
1356 r1 = r2;
1357 l = 0;
1358 for (i = 0; i < c2->n_lines; i++)
1360 int o = line_orient (c2->lines[i], c2);
1361 if (o == DIAGONAL)
1362 return 0;
1363 if (o == fdir)
1365 if (l)
1366 return 0; /* we don't support overlapping lines yet */
1367 l = c2->lines[i];
1369 if (o == rdir && c2->lines[i] != ls[ln - 1])
1370 return 0; /* likewise */
1371 if (o == adir)
1372 pull++;
1373 if (o == sdir)
1374 pull--;
1376 if (!l)
1377 break;
1378 if (selected (l->line))
1379 saw_sel = 1;
1380 if (autorouted (l->line))
1381 saw_auto = 1;
1382 if (ln >= lm)
1384 lm = ln + 10;
1385 ls = (line_s **) realloc (ls, lm * sizeof (line_s));
1387 ls[ln++] = l;
1388 c2 = other_corner (l, c2);
1390 if (cn < 2 || pull == 0)
1391 return 0;
1392 if (any_sel && !saw_sel)
1393 return 0;
1394 if (!any_sel && autorouted_only && !saw_auto)
1395 return 0;
1397 /* Ok, now look for other blockages. */
1399 empty_rect (&rr);
1400 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1401 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1403 if (fdir == RIGHT && pull < 0)
1404 edir = UP;
1405 else if (fdir == RIGHT && pull > 0)
1406 edir = DOWN;
1407 else if (fdir == DOWN && pull < 0)
1408 edir = LEFT;
1409 else if (fdir == DOWN && pull > 0)
1410 edir = RIGHT;
1412 max = -1;
1413 for (i = 0; i < cn; i++)
1414 for (li = 0; li < cs[i]->n_lines; li++)
1416 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1417 continue;
1418 len = line_length (cs[i]->lines[li]);
1419 if (max > len || max == -1)
1420 max = len;
1422 dprintf ("c %s %4d %4d cn %d pull %3d max %4d\n",
1423 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1425 switch (edir)
1427 case UP:
1428 rr.y1 = c->y - r1 - max;
1429 break;
1430 case DOWN:
1431 rr.y2 = c->y + r1 + max;
1432 break;
1433 case LEFT:
1434 rr.x1 = c->x - r1 - max;
1435 break;
1436 case RIGHT:
1437 rr.x2 = c->x + r1 + max;
1438 break;
1440 rr.x1 -= SB + 1;
1441 rr.x2 += SB + 1;
1442 rr.y1 -= SB + 1;
1443 rr.y2 += SB + 1;
1445 snap = 0;
1446 for (cb = corners; cb; cb = cb->next)
1448 int sep;
1449 if (DELETED (cb))
1450 continue;
1451 r1 = corner_radius (cb);
1452 if (cb->net == c->net && !cb->pad)
1453 continue;
1454 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1455 continue;
1456 switch (edir)
1458 #define ECHK(X,Y,LT) \
1459 for (i=0; i<cn; i++) \
1461 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1462 continue; \
1463 r2 = corner_radius(cs[i]); \
1464 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1465 continue; \
1466 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1467 continue; \
1468 if (cb->Y LT cs[i]->Y) \
1469 continue; \
1470 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1471 if (max > sep) \
1472 { max = sep; snap = 1; }\
1474 for (i=0; i<ln; i++) \
1476 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1477 continue; \
1478 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1479 continue; \
1480 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1481 - r1 - SB - 1); \
1482 if (max > sep) \
1483 { max = sep; snap = 1; }\
1485 case UP:
1486 ECHK (x, y, >=);
1487 break;
1488 case DOWN:
1489 ECHK (x, y, <=);
1490 break;
1491 case LEFT:
1492 ECHK (y, x, >=);
1493 break;
1494 case RIGHT:
1495 ECHK (y, x, <=);
1496 break;
1500 /* We must now check every line segment against our corners. */
1501 for (l = lines; l; l = l->next)
1503 int o, x1, x2, y1, y2;
1504 if (DELETED (l))
1505 continue;
1506 dprintf ("check line %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1507 l->e->y);
1508 if (l->s->net == c->net)
1510 dprintf (" same net\n");
1511 continue;
1513 o = line_orient (l, 0);
1514 /* We don't need to check perpendicular lines, because their
1515 corners already take care of it. */
1516 if ((fdir == RIGHT && (o == UP || o == DOWN))
1517 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1519 dprintf (" perpendicular\n");
1520 continue;
1523 /* Choose so that x1,y1 is closest to corner C */
1524 if ((fdir == RIGHT && l->s->x < l->e->x)
1525 || (fdir == DOWN && l->s->y < l->e->y))
1527 x1 = l->s->x;
1528 y1 = l->s->y;
1529 x2 = l->e->x;
1530 y2 = l->e->y;
1532 else
1534 x1 = l->e->x;
1535 y1 = l->e->y;
1536 x2 = l->s->x;
1537 y2 = l->s->y;
1540 /* Eliminate all lines outside our range */
1541 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1542 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1544 dprintf (" outside our range\n");
1545 continue;
1548 /* Eliminate all lines on the wrong side of us */
1549 if ((edir == UP && y1 > c->y && y2 > c->y)
1550 || (edir == DOWN && y1 < c->y && y2 < c->y)
1551 || (edir == LEFT && x1 > c->x && x2 > c->x)
1552 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1554 dprintf (" wrong side\n");
1555 continue;
1558 /* For now, cheat on diagonals */
1559 switch (edir)
1561 case RIGHT:
1562 if (x1 > x2)
1563 x1 = x2;
1564 break;
1565 case LEFT:
1566 if (x1 < x2)
1567 x1 = x2;
1568 break;
1569 case DOWN:
1570 if (y1 > y2)
1571 y1 = y2;
1572 break;
1573 case UP:
1574 if (y1 < y2)
1575 y1 = y2;
1576 break;
1579 /* Ok, now see how far we can get for each of our corners. */
1580 for (i = 0; i < cn; i++)
1582 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1583 int len = 0;
1584 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1585 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1586 continue;
1587 if (!intersecting_layers (cs[i]->layer, l->layer))
1588 continue;
1589 switch (edir)
1591 case RIGHT:
1592 len = x1 - c->x;
1593 break;
1594 case LEFT:
1595 len = c->x - x1;
1596 break;
1597 case DOWN:
1598 len = y1 - c->y;
1599 break;
1600 case UP:
1601 len = c->y - y1;
1602 break;
1604 len -= r;
1605 dprintf (" len is %d vs corner at %d,%d\n", len, cs[i]->x,
1606 cs[i]->y);
1607 if (len <= 0)
1608 return 0;
1609 if (max > len)
1610 max = len;
1615 /* We must make sure that if a segment isn't being completely
1616 removed, that any vias and/or pads don't overlap. */
1617 done = 0;
1618 while (!done)
1620 done = 1;
1621 for (i = 0; i < cn; i++)
1622 for (li = 0; li < cs[i]->n_lines; li++)
1624 line_s *l = cs[i]->lines[li];
1625 corner_s *oc = other_corner (l, cs[i]);
1626 if (line_orient (l, cs[i]) != edir)
1627 continue;
1628 len = line_length (l);
1629 if (!oc->pad || !cs[i]->via)
1631 if (!is_hole (l->s) || !is_hole (l->e))
1632 continue;
1633 if (len == max)
1634 continue;
1636 len -= corner_radius (l->s);
1637 len -= corner_radius (l->e);
1638 len -= SB + 1;
1639 if (max > len)
1641 max = len;
1642 done = 0;
1647 if (max <= 0)
1648 return 0;
1649 switch (edir)
1651 case UP:
1652 len = c->y - max;
1653 break;
1654 case DOWN:
1655 len = c->y + max;
1656 break;
1657 case LEFT:
1658 len = c->x - max;
1659 break;
1660 case RIGHT:
1661 len = c->x + max;
1662 break;
1664 if (snap && max > Settings.Grid)
1666 if (pull < 0)
1667 len += Settings.Grid - 1;
1668 len -= len % (int) (Settings.Grid);
1670 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1671 return 0;
1672 for (i = 0; i < cn; i++)
1674 if (fdir == RIGHT)
1676 max = len - cs[i]->y;
1677 move_corner (cs[i], cs[i]->x, len);
1679 else
1681 max = len - cs[i]->x;
1682 move_corner (cs[i], len, cs[i]->y);
1685 return max * pull;
1688 static int
1689 orthopull ()
1691 /* Look for straight runs which could be moved to reduce total trace
1692 length. */
1693 int any_sel = any_line_selected ();
1694 corner_s *c;
1695 int rv = 0;
1697 for (c = corners; c;)
1699 if (DELETED (c))
1700 continue;
1701 if (c->pin || c->pad)
1703 c = c->next;
1704 continue;
1706 next_corner = c;
1707 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1708 if (c != next_corner)
1710 c = next_corner;
1711 continue;
1713 rv += orthopull_1 (c, DOWN, UP, any_sel);
1714 if (c != next_corner)
1716 c = next_corner;
1717 continue;
1719 c = c->next;
1721 if (rv)
1722 printf ("orthopull: %d mils saved\n", rv / 100);
1723 return rv;
1726 static int
1727 debumpify ()
1729 /* Look for "U" shaped traces we can shorten (or eliminate) */
1730 int rv = 0;
1731 int any_selected = any_line_selected ();
1732 line_s *l, *l1, *l2;
1733 corner_s *c, *c1, *c2;
1734 rect_s rr, rp;
1735 int o, o1, o2, step, w;
1736 for (l = lines; l; l = l->next)
1738 if (DELETED (l))
1739 continue;
1740 if (!l->line)
1741 continue;
1742 if (any_selected && !selected (l->line))
1743 continue;
1744 if (!any_selected && autorouted_only && !autorouted (l->line))
1745 continue;
1746 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1747 continue;
1748 o = line_orient (l, 0);
1749 if (o == DIAGONAL)
1750 continue;
1751 l1 = other_line (l->s, l);
1752 if (!l1)
1753 continue;
1754 o1 = line_orient (l1, l->s);
1755 l2 = other_line (l->e, l);
1756 if (!l2)
1757 continue;
1758 o2 = line_orient (l2, l->e);
1759 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1760 continue;
1762 dprintf ("\nline: %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1763 l->e->y);
1764 w = l->line->Thickness / 2 + SB + 1;
1765 empty_rect (&rr);
1766 add_line_to_rect (&rr, l1);
1767 add_line_to_rect (&rr, l2);
1768 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1769 rr.x1 -= w;
1770 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1771 rr.x2 += w;
1772 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1773 rr.y1 -= w;
1774 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1775 rr.y2 += w;
1776 dprintf ("range: x %d..%d y %d..%d\n", rr.x1, rr.x2, rr.y1, rr.y2);
1778 c1 = other_corner (l1, l->s);
1779 c2 = other_corner (l2, l->e);
1781 empty_rect (&rp);
1782 for (c = corners; c; c = c->next)
1784 if (DELETED (c))
1785 continue;
1786 if (c->net != l->s->net
1787 && intersecting_layers (c->layer, l->s->layer))
1788 add_corner_to_rect_if (&rp, c, &rr);
1790 if (rp.x1 == INT_MAX)
1792 rp.x1 = rr.x2;
1793 rp.x2 = rr.x1;
1794 rp.y1 = rr.y2;
1795 rp.y2 = rr.y1;
1797 dprintf ("pin r: x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1799 switch (o1)
1801 case LEFT:
1802 step = l->s->x - rp.x2 - w;
1803 step = gridsnap (step);
1804 if (step > l->s->x - c1->x)
1805 step = l->s->x - c1->x;
1806 if (step > l->s->x - c2->x)
1807 step = l->s->x - c2->x;
1808 if (step > 0)
1810 dprintf ("left step %d at %d,%d\n", step, l->s->x, l->s->y);
1811 move_corner (l->s, l->s->x - step, l->s->y);
1812 move_corner (l->e, l->e->x - step, l->e->y);
1813 rv += step;
1815 break;
1816 case RIGHT:
1817 step = rp.x1 - l->s->x - w;
1818 step = gridsnap (step);
1819 if (step > c1->x - l->s->x)
1820 step = c1->x - l->s->x;
1821 if (step > c2->x - l->s->x)
1822 step = c2->x - l->s->x;
1823 if (step > 0)
1825 dprintf ("right step %d at %d,%d\n", step, l->s->x, l->s->y);
1826 move_corner (l->s, l->s->x + step, l->s->y);
1827 move_corner (l->e, l->e->x + step, l->e->y);
1828 rv += step;
1830 break;
1831 case UP:
1832 if (rp.y2 == INT_MIN)
1833 rp.y2 = rr.y1;
1834 step = trim_step (l->s->y - rp.y2 - w,
1835 l->s->y - c1->y, l->s->y - c2->y);
1836 if (step > 0)
1838 dprintf ("up step %d at %d,%d\n", step, l->s->x, l->s->y);
1839 move_corner (l->s, l->s->x, l->s->y - step);
1840 move_corner (l->e, l->e->x, l->e->y - step);
1841 rv += step;
1843 break;
1844 case DOWN:
1845 step = rp.y1 - l->s->y - w;
1846 step = gridsnap (step);
1847 if (step > c1->y - l->s->y)
1848 step = c1->y - l->s->y;
1849 if (step > c2->y - l->s->y)
1850 step = c2->y - l->s->y;
1851 if (step > 0)
1853 dprintf ("down step %d at %d,%d\n", step, l->s->x, l->s->y);
1854 move_corner (l->s, l->s->x, l->s->y + step);
1855 move_corner (l->e, l->e->x, l->e->y + step);
1856 rv += step;
1858 break;
1860 check (0, l);
1863 rv += simple_optimizations ();
1864 if (rv)
1865 printf ("debumpify: %d mils saved\n", rv / 50);
1866 return rv;
1869 static int
1870 simple_corner (corner_s * c)
1872 int o1, o2;
1873 if (c->pad || c->pin || c->via)
1874 return 0;
1875 if (c->n_lines != 2)
1876 return 0;
1877 o1 = line_orient (c->lines[0], c);
1878 o2 = line_orient (c->lines[1], c);
1879 if (ORIENT (o1) == ORIENT (o2))
1880 return 0;
1881 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1882 return 0;
1883 return 1;
1886 static int
1887 unjaggy_once ()
1889 /* Look for sequences of simple corners we can reduce. */
1890 int rv = 0;
1891 corner_s *c, *c0, *c1, *cc;
1892 int l, w, sel = any_line_selected ();
1893 int o0, o1, s0, s1;
1894 rect_s rr, rp;
1895 for (c = corners; c; c = c->next)
1897 if (DELETED (c))
1898 continue;
1899 if (!simple_corner (c))
1900 continue;
1901 if (!c->lines[0]->line || !c->lines[1]->line)
1902 continue;
1903 if (sel && !(selected (c->lines[0]->line)
1904 || selected (c->lines[1]->line)))
1905 continue;
1906 if (!sel && autorouted_only
1907 && !(autorouted (c->lines[0]->line)
1908 || autorouted (c->lines[1]->line)))
1909 continue;
1910 dprintf ("simple at %d,%d\n", c->x, c->y);
1912 c0 = other_corner (c->lines[0], c);
1913 o0 = line_orient (c->lines[0], c);
1914 s0 = simple_corner (c0);
1916 c1 = other_corner (c->lines[1], c);
1917 o1 = line_orient (c->lines[1], c);
1918 s1 = simple_corner (c1);
1920 if (!s0 && !s1)
1921 continue;
1922 dprintf ("simples at %d,%d\n", c->x, c->y);
1924 w = 1;
1925 for (l = 0; l < c0->n_lines; l++)
1926 if (c0->lines[l] != c->lines[0]
1927 && c0->lines[l]->layer == c->lines[0]->layer)
1929 int o = line_orient (c0->lines[l], c0);
1930 if (o == o1)
1931 w = 0;
1933 for (l = 0; l < c1->n_lines; l++)
1934 if (c1->lines[l] != c->lines[0]
1935 && c1->lines[l]->layer == c->lines[0]->layer)
1937 int o = line_orient (c1->lines[l], c1);
1938 if (o == o0)
1939 w = 0;
1941 if (!w)
1942 continue;
1943 dprintf ("orient ok\n");
1945 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1946 empty_rect (&rr);
1947 add_line_to_rect (&rr, c->lines[0]);
1948 add_line_to_rect (&rr, c->lines[1]);
1949 if (c->x != rr.x1)
1950 rr.x1 -= w;
1951 else
1952 rr.x2 += w;
1953 if (c->y != rr.y1)
1954 rr.y1 -= w;
1955 else
1956 rr.y2 += w;
1958 empty_rect (&rp);
1959 for (cc = corners; cc; cc = cc->next)
1961 if (DELETED (cc))
1962 continue;
1963 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1964 add_corner_to_rect_if (&rp, cc, &rr);
1966 dprintf ("rp x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1967 if (rp.x1 <= rp.x2) /* something triggered */
1968 continue;
1970 dprintf ("unjaggy at %d,%d layer %d\n", c->x, c->y, c->layer);
1971 if (c->x == c0->x)
1972 move_corner (c, c1->x, c0->y);
1973 else
1974 move_corner (c, c0->x, c1->y);
1975 rv++;
1976 check (c, 0);
1978 rv += simple_optimizations ();
1979 check (c, 0);
1980 return rv;
1983 static int
1984 unjaggy ()
1986 int i, r = 0, j;
1987 for (i = 0; i < 100; i++)
1989 j = unjaggy_once ();
1990 if (j == 0)
1991 break;
1992 r += j;
1994 if (r)
1995 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1996 return r;
1999 static int
2000 vianudge ()
2002 /* Look for vias with all lines leaving the same way, try to nudge
2003 via to eliminate one or more of them. */
2004 int rv = 0;
2005 corner_s *c, *c2, *c3;
2006 line_s *l;
2007 unsigned char directions[MAX_LAYER];
2008 unsigned char counts[MAX_LAYER];
2010 memset (directions, 0, sizeof (directions));
2011 memset (counts, 0, sizeof (counts));
2013 for (c = corners; c; c = c->next)
2015 int o, i, vr, cr, oboth;
2016 int len = 0, saved = 0;
2018 if (DELETED (c))
2019 continue;
2021 if (!c->via)
2022 continue;
2024 memset (directions, 0, sizeof (directions));
2025 memset (counts, 0, sizeof (counts));
2027 for (i = 0; i < c->n_lines; i++)
2029 o = line_orient (c->lines[i], c);
2030 counts[c->lines[i]->layer]++;
2031 directions[c->lines[i]->layer] |= o;
2033 for (o = 0, i = 0; i < max_copper_layer; i++)
2034 if (counts[i] == 1)
2036 o = directions[i];
2037 break;
2039 switch (o)
2041 case LEFT:
2042 case RIGHT:
2043 oboth = LEFT | RIGHT;
2044 break;
2045 case UP:
2046 case DOWN:
2047 oboth = UP | DOWN;
2048 break;
2049 default:
2050 continue;
2052 for (i = 0; i < max_copper_layer; i++)
2053 if (counts[i] && directions[i] != o && directions[i] != oboth)
2054 goto vianudge_continue;
2056 c2 = 0;
2057 for (i = 0; i < c->n_lines; i++)
2059 int ll = line_length (c->lines[i]);
2060 if (line_orient (c->lines[i], c) != o)
2062 saved--;
2063 continue;
2065 saved++;
2066 if (c2 == 0 || len > ll)
2068 len = ll;
2069 c2 = other_corner (c->lines[i], c);
2072 if (c2->pad || c2->pin || c2->via)
2073 continue;
2075 /* Now look for clearance in the new position */
2076 vr = c->via->Thickness / 2 + SB + 1;
2077 for (c3 = corners; c3; c3 = c3->next)
2079 if (DELETED (c3))
2080 continue;
2081 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2083 cr = corner_radius (c3);
2084 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2085 goto vianudge_continue;
2088 for (l = lines; l; l = l->next)
2090 if (DELETED (l))
2091 continue;
2092 if (l->s->net != c->net)
2094 int ld = dist_line_to_point (l, c2);
2095 if (ld < l->line->Thickness / 2 + vr)
2096 goto vianudge_continue;
2100 /* at this point, we know we can move it */
2102 dprintf ("vianudge: nudging via at %d,%d by %d mils saving %d\n",
2103 c->x, c->y, len / 100, saved / 100);
2104 rv += len * saved;
2105 move_corner (c, c2->x, c2->y);
2107 check (c, 0);
2109 vianudge_continue:
2110 continue;
2113 if (rv)
2114 printf ("vianudge: %d mils saved\n", rv / 100);
2115 return rv;
2118 static int
2119 viatrim ()
2121 /* Look for traces that can be moved to the other side of the board,
2122 to reduce the number of vias needed. For now, we look for simple
2123 lines, not multi-segmented lines. */
2124 line_s *l, *l2;
2125 int i, rv = 0, vrm = 0;
2126 int any_sel = any_line_selected ();
2128 for (l = lines; l; l = l->next)
2130 rect_s r;
2131 int my_layer, other_layer;
2133 if (DELETED (l))
2134 continue;
2135 if (!l->s->via)
2136 continue;
2137 if (!l->e->via)
2138 continue;
2139 if (any_sel && !selected (l->line))
2140 continue;
2141 if (!any_sel && autorouted_only && !autorouted (l->line))
2142 continue;
2144 my_layer = l->layer;
2145 other_layer = -1;
2146 dprintf ("line %p on layer %d from %d,%d to %d,%d\n", (void *) l,
2147 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2148 for (i = 0; i < l->s->n_lines; i++)
2149 if (l->s->lines[i] != l)
2151 if (other_layer == -1)
2153 other_layer = l->s->lines[i]->layer;
2154 dprintf ("noting other line %p on layer %d\n",
2155 (void *) (l->s->lines[i]), my_layer);
2157 else if (l->s->lines[i]->layer != other_layer)
2159 dprintf ("saw other line %p on layer %d (not %d)\n",
2160 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2161 my_layer);
2162 other_layer = -1;
2163 goto viatrim_other_corner;
2166 viatrim_other_corner:
2167 if (other_layer == -1)
2168 for (i = 0; i < l->e->n_lines; i++)
2169 if (l->e->lines[i] != l)
2171 if (other_layer == -1)
2173 other_layer = l->s->lines[i]->layer;
2174 dprintf ("noting other line %p on layer %d\n",
2175 (void *) (l->s->lines[i]), my_layer);
2177 else if (l->e->lines[i]->layer != other_layer)
2179 dprintf ("saw end line on layer %d (not %d)\n",
2180 l->e->lines[i]->layer, other_layer);
2181 goto viatrim_continue;
2185 /* Now see if any other line intersects us. We don't need to
2186 check corners, because they'd either be pins/vias and
2187 already conflict, or pads, which we'll check here anyway. */
2188 empty_rect (&r);
2189 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2190 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2192 for (l2 = lines; l2; l2 = l2->next)
2194 if (DELETED (l2))
2195 continue;
2196 if (l2->s->net != l->s->net && l2->layer == other_layer)
2198 dprintf ("checking other line %d,%d to %d,%d\n", l2->s->x,
2199 l2->s->y, l2->e->x, l2->e->y);
2200 if (line_in_rect (&r, l2))
2202 dprintf ("line from %d,%d to %d,%d in the way\n",
2203 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2204 goto viatrim_continue;
2209 if (l->layer == other_layer)
2210 continue;
2211 move_line_to_layer (l, other_layer);
2212 rv++;
2214 viatrim_continue:
2215 continue;
2217 vrm = simple_optimizations ();
2218 if (rv > 0)
2219 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2220 return rv + vrm;
2223 static int
2224 automagic ()
2226 int more = 1, oldmore = 0;
2227 int toomany = 100;
2228 while (more != oldmore && --toomany)
2230 oldmore = more;
2231 more += debumpify ();
2232 more += unjaggy ();
2233 more += orthopull ();
2234 more += vianudge ();
2235 more += viatrim ();
2237 return more - 1;
2240 static int
2241 miter ()
2243 corner_s *c;
2244 int done, progress;
2245 int sel = any_line_selected ();
2246 int saved = 0;
2248 for (c = corners; c; c = c->next)
2250 if (DELETED (c))
2251 continue;
2252 c->miter = 0;
2253 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2255 int o1 = line_orient (c->lines[0], c);
2256 int o2 = line_orient (c->lines[1], c);
2257 if (ORIENT (o1) != ORIENT (o2)
2258 && o1 != DIAGONAL && o2 != DIAGONAL
2259 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2260 c->miter = -1;
2264 done = 0;
2265 progress = 1;
2266 while (!done && progress)
2268 done = 1;
2269 progress = 0;
2270 for (c = corners; c; c = c->next)
2272 if (DELETED (c))
2273 continue;
2274 if (c->miter == -1)
2276 int max = line_length (c->lines[0]);
2277 int len = line_length (c->lines[1]);
2278 int bloat;
2279 int ref, dist;
2280 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2281 int mx = 0, my = 0, x, y;
2282 int o1 = line_orient (c->lines[0], c);
2283 int o2 = line_orient (c->lines[1], c);
2285 if (c->pad || c->pin || c->via)
2287 c->miter = 0;
2288 progress = 1;
2289 continue;
2292 oc1 = other_corner (c->lines[0], c);
2293 oc2 = other_corner (c->lines[1], c);
2294 #if 0
2295 if (oc1->pad)
2296 oc1 = 0;
2297 if (oc2->pad)
2298 oc2 = 0;
2299 #endif
2301 if ((sel && !(selected (c->lines[0]->line)
2302 || selected (c->lines[1]->line)))
2303 || (!sel && autorouted_only
2304 && !(autorouted (c->lines[0]->line)
2305 || autorouted (c->lines[1]->line))))
2307 c->miter = 0;
2308 progress = 1;
2309 continue;
2312 if (max > len)
2313 max = len;
2314 switch (o1)
2316 case LEFT:
2317 mx = -1;
2318 break;
2319 case RIGHT:
2320 mx = 1;
2321 break;
2322 case UP:
2323 my = -1;
2324 break;
2325 case DOWN:
2326 my = 1;
2327 break;
2329 switch (o2)
2331 case LEFT:
2332 mx = -1;
2333 break;
2334 case RIGHT:
2335 mx = 1;
2336 break;
2337 case UP:
2338 my = -1;
2339 break;
2340 case DOWN:
2341 my = 1;
2342 break;
2344 ref = c->x * mx + c->y * my;
2345 dist = max;
2347 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2349 for (c2 = corners; c2; c2 = c2->next)
2351 if (DELETED (c2))
2352 continue;
2353 if (c2 != c && c2 != oc1 && c2 != oc2
2354 && c->x * mx <= c2->x * mx
2355 && c->y * my <= c2->y * my
2356 && c->net != c2->net
2357 && intersecting_layers (c->layer, c2->layer))
2359 int cr = corner_radius (c2);
2360 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2361 if (c->x != c2->x && c->y != c2->y)
2362 len -= cr;
2363 if (len < dist || (len == dist && c->miter != -1))
2365 dist = len;
2366 closest_corner = c2;
2371 if (closest_corner && closest_corner->miter == -1)
2373 done = 0;
2374 continue;
2377 #if 0
2378 if (dist < Settings.Grid)
2380 c->miter = 0;
2381 progress = 1;
2382 continue;
2385 dist -= dist % Settings.Grid;
2386 #endif
2387 if (dist <= 0)
2389 c->miter = 0;
2390 progress = 1;
2391 continue;
2394 x = c->x;
2395 y = c->y;
2396 switch (o1)
2398 case LEFT:
2399 x -= dist;
2400 break;
2401 case RIGHT:
2402 x += dist;
2403 break;
2404 case UP:
2405 y -= dist;
2406 break;
2407 case DOWN:
2408 y += dist;
2409 break;
2411 c2 = find_corner (x, y, c->layer);
2412 if (c2 != other_corner (c->lines[0], c))
2413 split_line (c->lines[0], c2);
2414 x = c->x;
2415 y = c->y;
2416 switch (o2)
2418 case LEFT:
2419 x -= dist;
2420 break;
2421 case RIGHT:
2422 x += dist;
2423 break;
2424 case UP:
2425 y -= dist;
2426 break;
2427 case DOWN:
2428 y += dist;
2429 break;
2431 move_corner (c, x, y);
2432 c->miter = 0;
2433 c2->miter = 0;
2434 progress = 1;
2435 saved++;
2439 return saved;
2442 static void
2443 classify_corner (corner_s * c, int this_net)
2445 int i;
2446 if (c->net == this_net)
2447 return;
2448 c->net = this_net;
2449 for (i = 0; i < c->n_lines; i++)
2450 classify_corner (other_corner (c->lines[i], c), this_net);
2453 static void
2454 classify_nets ()
2456 static int this_net = 1;
2457 corner_s *c;
2459 for (c = corners; c; c = c->next)
2461 if (DELETED (c))
2462 continue;
2463 if (c->net)
2464 continue;
2465 classify_corner (c, this_net);
2466 this_net++;
2470 #if 0
2471 /* Not used */
2472 static void
2473 dump_all ()
2475 corner_s *c;
2476 line_s *l;
2477 for (c = corners; c; c = c->next)
2479 if (DELETED (c))
2480 continue;
2481 printf ("%p corner %d,%d layer %d net %d\n",
2482 (void *) c, c->x, c->y, c->layer, c->net);
2484 for (l = lines; l; l = l->next)
2486 if (DELETED (l))
2487 continue;
2488 printf ("%p line %p to %p layer %d\n",
2489 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2492 #endif
2494 static void
2495 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2497 int ox = c->x;
2498 int oy = c->y;
2499 int l;
2500 if (prev_corner && (c->pin || c->pad))
2501 return;
2502 move_corner (c, ox + dx, oy + dy);
2503 for (l = 0; l < c->n_lines; l++)
2505 corner_s *oc = other_corner (c->lines[l], c);
2506 if (oc == prev_corner)
2507 continue;
2508 if (dx && oc->x == ox)
2509 nudge_corner (oc, dx, 0, c);
2510 if (dy && oc->y == oy)
2511 nudge_corner (oc, 0, dy, c);
2515 static line_s *
2516 choose_example_line (corner_s * c1, corner_s * c2)
2518 int ci, li;
2519 corner_s *c[2];
2520 c[0] = c1;
2521 c[1] = c2;
2522 dprintf ("choose_example_line\n");
2523 for (ci = 0; ci < 2; ci++)
2524 for (li = 0; li < c[ci]->n_lines; li++)
2526 dprintf (" try[%d,%d] \033[36m<%d,%d-%d,%d t%d c%d f%s>\033[0m\n",
2527 ci, li,
2528 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2529 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2530 c[ci]->lines[li]->line->Thickness,
2531 c[ci]->lines[li]->line->Clearance,
2532 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2533 /* Pads are disqualified, as we want to mimic a trace line. */
2534 if (c[ci]->lines[li]->line == (LineTypePtr) c[ci]->pad)
2536 dprintf (" bad, pad\n");
2537 continue;
2539 /* Lines on layers that don't connect to the other pad are bad too. */
2540 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2542 dprintf (" bad, layers\n");
2543 continue;
2545 dprintf (" good\n");
2546 return c[ci]->lines[li];
2548 dprintf ("choose_example_line: none found!\n");
2549 return 0;
2552 static int
2553 connect_corners (corner_s * c1, corner_s * c2)
2555 int layer;
2556 line_s *ex = choose_example_line (c1, c2);
2557 LineType *example = ex->line;
2559 dprintf
2560 ("connect_corners \033[32m%d,%d to %d,%d, example line %d,%d to %d,%d l%d\033[0m\n",
2561 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2562 ex->layer);
2564 layer = ex->layer;
2566 /* Assume c1 is the moveable one. */
2567 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2569 int nx, ny;
2570 /* Extend the line */
2571 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2572 nx = c1->x, ny = c2->y;
2573 else
2574 nx = c2->x, ny = c1->y;
2575 if (nx != c2->x || ny != c2->y)
2577 move_corner (c1, nx, ny);
2578 new_line (c1, c2, layer, example);
2579 return 1;
2581 else
2583 move_corner (c1, nx, ny);
2584 return 1;
2587 else
2589 corner_s *nc = find_corner (c1->x, c2->y, layer);
2590 new_line (c1, nc, layer, example);
2591 new_line (nc, c2, layer, example);
2592 return 0;
2596 static void
2597 pinsnap ()
2599 corner_s *c;
2600 int best_dist[MAX_LAYER + 1];
2601 corner_s *best_c[MAX_LAYER + 1];
2602 int l, got_one;
2603 int left = 0, right = 0, top = 0, bottom = 0;
2604 PinType *pin;
2605 int again = 1;
2607 corner_s *prev_c;
2608 int close = 0;
2609 corner_s *c2;
2611 /* Look for pins that have no connections. See if there's a corner
2612 close by that should be connected to it. This usually happens
2613 when the MUCS router needs to route to an off-grid pin. */
2614 while (again)
2616 again = 0;
2617 for (c = corners; c; c = c->next)
2619 if (DELETED (c))
2620 continue;
2621 if (!(c->pin || c->via || c->pad))
2622 continue;
2624 prev_c = c;
2625 pin = 0;
2627 dprintf ("\ncorner %s\n", corner_name (c));
2628 if (c->pin || c->via)
2630 pin = c->pin ? c->pin : c->via;
2631 close = pin->Thickness / 2;
2632 left = c->x - close;
2633 right = c->x + close;
2634 bottom = c->y - close;
2635 top = c->y + close;
2637 else if (c->pad)
2639 close = c->pad->Thickness / 2 + 1;
2640 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2641 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2642 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2643 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2644 if (c->pad->Point1.X == c->pad->Point2.X)
2646 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2647 dprintf ("pad y %d %d hy %d c %d\n", c->pad->Point1.Y,
2648 c->pad->Point2.Y, hy, c->y);
2649 if (c->y < hy)
2650 top = hy;
2651 else
2652 bottom = hy + 1;
2654 else
2656 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2657 dprintf ("pad x %d %d hx %d c %d\n", c->pad->Point1.X,
2658 c->pad->Point2.X, hx, c->x);
2659 if (c->x < hx)
2660 right = hx;
2661 else
2662 left = hx + 1;
2666 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c), left, right,
2667 bottom, top);
2668 for (l = 0; l <= max_copper_layer; l++)
2670 best_dist[l] = close * 2;
2671 best_c[l] = 0;
2673 got_one = 0;
2674 for (c2 = corners; c2; c2 = c2->next)
2676 int lt;
2678 if (DELETED (c2))
2679 continue;
2680 lt = corner_radius (c2);
2681 if (c2->n_lines
2682 && c2 != c
2683 && !(c2->pin || c2->pad || c2->via)
2684 && intersecting_layers (c->layer, c2->layer)
2685 && c2->x >= left - lt
2686 && c2->x <= right + lt
2687 && c2->y >= bottom - lt && c2->y <= top + lt)
2689 int d = dist (c->x, c->y, c2->x, c2->y);
2690 if (pin && d > pin->Thickness / 2 + lt)
2691 continue;
2692 if (c2->n_lines == 1)
2694 got_one++;
2695 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2696 corner_name (c));
2697 connect_corners (c, c2);
2698 again = 1;
2699 continue;
2701 if (best_c[c2->layer] == 0
2702 || c2->n_lines < best_c[c2->layer]->n_lines
2703 || (d < best_dist[c2->layer]
2704 && c2->n_lines <= best_c[c2->layer]->n_lines))
2706 best_dist[c2->layer] = d;
2707 best_c[c2->layer] = c2;
2708 dprintf ("layer %d best now %s\n", c2->layer,
2709 corner_name (c2));
2712 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2714 for (l = 0; l <= max_copper_layer; l++)
2715 if (best_c[l])
2716 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2717 for (l = 0; l <= max_copper_layer; l++)
2718 if (best_c[l])
2720 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2721 corner_name (c));
2722 connect_corners (best_c[l], c);
2723 again = 1;
2724 continue;
2731 /* Now look for line ends that don't connect, see if they need to be
2732 extended to intersect another line. */
2733 for (c = corners; c; c = c->next)
2735 line_s *l, *t;
2736 int lo;
2738 if (DELETED (c))
2739 continue;
2740 if (c->pin || c->via || c->pad)
2741 continue;
2742 if (c->n_lines != 1)
2743 continue;
2745 l = c->lines[0];
2746 lo = line_orient (l, c);
2747 dprintf ("line end %d,%d orient %d\n", c->x, c->y, lo);
2749 for (t = lines; t; t = t->next)
2751 if (DELETED (t))
2752 continue;
2753 if (t->layer != c->lines[0]->layer)
2754 continue;
2755 switch (lo) /* remember, orient is for the line relative to the corner */
2757 case LEFT:
2758 if (t->s->x == t->e->x
2759 && c->x < t->s->x
2760 && t->s->x <
2761 c->x + (l->line->Thickness + t->line->Thickness) / 2
2762 && ((t->s->y < c->y && c->y < t->e->y)
2763 || (t->e->y < c->y && c->y < t->s->y)))
2765 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2766 t->e->y);
2767 move_corner (c, t->s->x, c->y);
2769 break;
2770 case RIGHT:
2771 if (t->s->x == t->e->x
2772 && c->x > t->s->x
2773 && t->s->x >
2774 c->x - (l->line->Thickness + t->line->Thickness) / 2
2775 && ((t->s->y < c->y && c->y < t->e->y)
2776 || (t->e->y < c->y && c->y < t->s->y)))
2778 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2779 t->e->y);
2780 move_corner (c, t->s->x, c->y);
2782 break;
2783 case UP:
2784 if (t->s->y == t->e->y
2785 && c->y < t->s->y
2786 && t->s->y <
2787 c->y + (l->line->Thickness + t->line->Thickness) / 2
2788 && ((t->s->x < c->x && c->x < t->e->x)
2789 || (t->e->x < c->x && c->x < t->s->x)))
2791 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2792 t->e->y);
2793 move_corner (c, c->x, t->s->y);
2795 break;
2796 case DOWN:
2797 if (t->s->y == t->e->y
2798 && c->y > t->s->y
2799 && t->s->y >
2800 c->y - (l->line->Thickness + t->line->Thickness) / 2
2801 && ((t->s->x < c->x && c->x < t->e->x)
2802 || (t->e->x < c->x && c->x < t->s->x)))
2804 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2805 t->e->y);
2806 move_corner (c, c->x, t->s->y);
2808 break;
2814 static int
2815 pad_orient (PadType * p)
2817 if (p->Point1.X == p->Point2.X)
2818 return O_VERT;
2819 if (p->Point1.Y == p->Point2.Y)
2820 return O_HORIZ;
2821 return DIAGONAL;
2824 static void
2825 padcleaner ()
2827 line_s *l, *nextl;
2828 int close;
2829 rect_s r;
2830 int ei, pi;
2832 dprintf ("\ndj: padcleaner\n");
2833 for (l = lines; l; l = nextl)
2835 nextl = l->next;
2837 if (l->is_pad)
2838 continue;
2840 if (DELETED (l))
2841 continue;
2843 dprintf ("dj: line %p\n", (void *) l);
2844 check (0, l);
2846 if (l->s->pad && l->s->pad == l->e->pad)
2847 continue;
2849 for (ei = 0; ei < PCB->Data->ElementN; ei++)
2851 ElementType *e = &(PCB->Data->Element[ei]);
2852 for (pi = 0; pi < e->PadN; pi++)
2854 PadType *p = e->Pad + pi;
2855 int layerflag =
2856 TEST_FLAG (ONSOLDERFLAG, e) ? LT_SOLDER : LT_COMPONENT;
2858 if (layer_type[l->layer] != layerflag)
2859 continue;
2861 if (p == l->line)
2862 continue;
2864 empty_rect (&r);
2865 close = p->Thickness / 2 + 1;
2866 add_point_to_rect (&r, p->Point1.X, p->Point1.Y,
2867 close - SB / 2);
2868 add_point_to_rect (&r, p->Point2.X, p->Point2.Y,
2869 close - SB / 2);
2870 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2871 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2872 && ORIENT (line_orient (l, 0)) == pad_orient (p))
2874 dprintf
2875 ("padcleaner %d,%d-%d,%d %d vs line %d,%d-%d,%d %d\n",
2876 p->Point1.X, p->Point1.Y, p->Point2.X, p->Point2.Y,
2877 p->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2878 l->line->Thickness);
2879 remove_line (l);
2880 goto next_line;
2884 next_line:;
2888 static void
2889 grok_layer_groups ()
2891 int i, j, f;
2892 LayerGroupType *l = &(PCB->LayerGroups);
2894 solder_layer = component_layer = -1;
2895 for (i = 0; i < max_copper_layer; i++)
2897 layer_type[i] = 0;
2898 layer_groupings[i] = 0;
2900 for (i = 0; i < max_group; i++)
2902 f = 0;
2903 for (j = 0; j < l->Number[i]; j++)
2905 if (l->Entries[i][j] == solder_silk_layer)
2906 f |= LT_SOLDER;
2907 if (l->Entries[i][j] == component_silk_layer)
2908 f |= LT_COMPONENT;
2910 for (j = 0; j < l->Number[i]; j++)
2912 if (l->Entries[i][j] >= 0 && l->Entries[i][j] < max_copper_layer)
2914 layer_type[l->Entries[i][j]] |= f;
2915 layer_groupings[l->Entries[i][j]] = i;
2916 if (solder_layer == -1 && f == LT_SOLDER)
2917 solder_layer = l->Entries[i][j];
2918 if (component_layer == -1 && f == LT_COMPONENT)
2919 component_layer = l->Entries[i][j];
2925 static const char djopt_syntax[] =
2926 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull)\n"
2927 "djopt(auto) - all of the above\n" "djopt(miter)";
2929 static const char djopt_help[] =
2930 "Perform various optimizations on the current board";
2932 /* %start-doc actions djopt
2934 The different types of optimizations change your board in order to
2935 reduce the total trace length and via count.
2937 @table @code
2939 @item debumpify
2940 Looks for U-shaped traces that can be shortened or eliminated.
2942 @item unjaggy
2943 Looks for corners which could be flipped to eliminate one or more
2944 corners (i.e. jaggy lines become simpler).
2946 @item simple
2947 Removing uneeded vias, replacing two or more trace segments in a row
2948 with a single segment. This is usually performed automatically after
2949 other optimizations.
2951 @item vianudge
2952 Looks for vias where all traces leave in the same direction. Tries to
2953 move via in that direction to eliminate one of the traces (and thus a
2954 corner).
2956 @item viatrim
2957 Looks for traces that go from via to via, where moving that trace to a
2958 different layer eliminates one or both vias.
2960 @item orthopull
2961 Looks for chains of traces all going in one direction, with more
2962 traces orthogonal on one side than on the other. Moves the chain in
2963 that direction, causing a net reduction in trace length, possibly
2964 eliminating traces and/or corners.
2966 @item splitlines
2967 Looks for lines that pass through vias, pins, or pads, and splits them
2968 into separate lines so they can be managed separately.
2970 @item auto
2971 Performs the above options, repeating until no further optimizations
2972 can be made.
2974 @item miter
2975 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2976 RF losses and trace length.
2978 @end table
2980 %end-doc */
2982 static int
2983 ActionDJopt (int argc, char **argv, int x, int y)
2985 char *arg = argc > 0 ? argv[0] : 0;
2986 int layn, saved = 0;
2987 corner_s *c;
2989 #ifdef ENDIF
2990 SwitchDrawingWindow (PCB->Zoom, Output.drawing_area->window,
2991 Settings.ShowSolderSide, false);
2992 #endif
2994 hid_action("Busy");
2996 lines = 0;
2997 corners = 0;
2999 grok_layer_groups ();
3001 ELEMENT_LOOP (PCB->Data);
3002 PIN_LOOP (element);
3004 c = find_corner (pin->X, pin->Y, -1);
3005 c->pin = pin;
3007 END_LOOP;
3008 PAD_LOOP (element);
3010 int layern =
3011 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
3012 line_s *ls = (line_s *) malloc (sizeof (line_s));
3013 ls->next = lines;
3014 lines = ls;
3015 ls->is_pad = 1;
3016 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
3017 ls->s->pad = pad;
3018 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
3019 ls->e->pad = pad;
3020 ls->layer = layern;
3021 ls->line = (LineTypePtr) pad;
3022 add_line_to_corner (ls, ls->s);
3023 add_line_to_corner (ls, ls->e);
3026 END_LOOP;
3027 END_LOOP;
3028 VIA_LOOP (PCB->Data);
3029 /* hace don't mess with vias that have thermals */
3030 /* but then again don't bump into them
3031 if (!TEST_FLAG(ALLTHERMFLAGS, via))
3034 c = find_corner (via->X, via->Y, -1);
3035 c->via = via;
3037 END_LOOP;
3038 check (0, 0);
3040 if (NSTRCMP (arg, "splitlines") == 0)
3042 if (canonicalize_lines ())
3043 IncrementUndoSerialNumber ();
3044 return 0;
3047 for (layn = 0; layn < max_copper_layer; layn++)
3049 LayerType *layer = LAYER_PTR (layn);
3050 int ln;
3051 for (ln = 0; ln < layer->LineN; ln++)
3053 LineType *l = &(layer->Line[ln]);
3054 line_s *ls;
3056 /* don't mess with thermals */
3057 if (TEST_FLAG (USETHERMALFLAG, l))
3058 continue;
3060 if (l->Point1.X == l->Point2.X && l->Point1.Y == l->Point2.Y)
3062 RemoveLine (layer, l);
3063 ln--;
3064 continue;
3067 ls = (line_s *) malloc (sizeof (line_s));
3068 ls->next = lines;
3069 lines = ls;
3070 ls->is_pad = 0;
3071 ls->s = find_corner (l->Point1.X, l->Point1.Y, layn);
3072 ls->e = find_corner (l->Point2.X, l->Point2.Y, layn);
3073 ls->line = l;
3074 add_line_to_corner (ls, ls->s);
3075 add_line_to_corner (ls, ls->e);
3076 ls->layer = layn;
3081 check (0, 0);
3082 pinsnap ();
3083 canonicalize_lines ();
3084 check (0, 0);
3085 classify_nets ();
3086 /*dump_all(); */
3087 check (0, 0);
3089 if (NSTRCMP (arg, "debumpify") == 0)
3090 saved += debumpify ();
3091 else if (NSTRCMP (arg, "unjaggy") == 0)
3092 saved += unjaggy ();
3093 else if (NSTRCMP (arg, "simple") == 0)
3094 saved += simple_optimizations ();
3095 else if (NSTRCMP (arg, "vianudge") == 0)
3096 saved += vianudge ();
3097 else if (NSTRCMP (arg, "viatrim") == 0)
3098 saved += viatrim ();
3099 else if (NSTRCMP (arg, "orthopull") == 0)
3100 saved += orthopull ();
3101 else if (NSTRCMP (arg, "auto") == 0)
3102 saved += automagic ();
3103 else if (NSTRCMP (arg, "miter") == 0)
3104 saved += miter ();
3105 else
3107 printf ("unknown command: %s\n", arg);
3108 return 1;
3111 padcleaner ();
3113 check (0, 0);
3114 if (saved)
3115 IncrementUndoSerialNumber ();
3116 return 0;
3119 HID_Action djopt_action_list[] = {
3120 {"djopt", 0, ActionDJopt,
3121 djopt_help, djopt_syntax}
3123 {"OptAutoOnly", 0, djopt_set_auto_only,
3124 djopt_sao_help, djopt_sao_syntax}
3127 REGISTER_ACTIONS (djopt_action_list)