Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / djopt.c
blob68b3641eab0a52fead61beedb3bba0e7e7497967
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 struct line_s;
80 typedef struct corner_s
82 int layer;
83 struct corner_s *next;
84 int x, y;
85 int net;
86 PinType *via;
87 PadType *pad;
88 PinType *pin;
89 int miter;
90 int n_lines;
91 struct line_s **lines;
92 } corner_s;
94 typedef struct line_s
96 int layer;
97 struct line_s *next;
98 corner_s *s, *e;
99 LineType *line;
100 } line_s;
102 typedef struct rect_s
104 int x1, y1, x2, y2;
105 } rect_s;
107 #define DELETE(q) (q)->layer = 0xdeadbeef
108 #define DELETED(q) ((q)->layer == 0xdeadbeef)
110 static corner_s *corners, *next_corner = 0;
111 static line_s *lines;
113 static int layer_groupings[MAX_LAYER];
114 static char layer_type[MAX_LAYER];
115 #define LT_COMPONENT 1
116 #define LT_SOLDER 2
118 static int autorouted_only = 1;
120 static const char djopt_sao_syntax[] = "OptAutoOnly()";
122 static const char djopt_sao_help[] =
123 "Toggles the optimize-only-autorouted flag.";
125 /* %start-doc actions OptAutoOnly
127 The original purpose of the trace optimizer was to clean up the traces
128 created by the various autorouters that have been used with PCB. When
129 a board has a mix of autorouted and carefully hand-routed traces, you
130 don't normally want the optimizer to move your hand-routed traces.
131 But, sometimes you do. By default, the optimizer only optimizes
132 autorouted traces. This action toggles that setting, so that you can
133 optimize hand-routed traces also.
135 %end-doc */
138 djopt_set_auto_only (int argc, char **argv, int x, int y)
140 autorouted_only = autorouted_only ? 0 : 1;
141 return 0;
144 static int
145 djopt_get_auto_only (int dummy)
147 return autorouted_only;
150 HID_Flag djopt_flag_list[] = {
151 {"optautoonly", djopt_get_auto_only, 0}
154 REGISTER_FLAGS (djopt_flag_list)
155 #define line_is_pad(l) ((l)->line == (LineType *)(l)->s->pad)
156 static char *element_name_for (corner_s * c)
158 int i, p;
159 ElementType *e;
161 for (i = 0; i < PCB->Data->ElementN; i++)
163 e = PCB->Data->Element + i;
164 for (p = 0; p < e->PinN; p++)
165 if (e->Pin + p == c->pin)
166 return e->Name[1].TextString;
167 for (p = 0; p < e->PadN; p++)
168 if (e->Pad + p == c->pad)
169 return e->Name[1].TextString;
171 return "unknown";
174 static char *
175 corner_name (corner_s * c)
177 static char buf[4][100];
178 static int bn = 0;
179 char *bp;
180 bn = (bn + 1) % 4;
182 if (c->net == 0xf1eef1ee)
184 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
185 return buf[bn];
188 sprintf (buf[bn], "\033[%dm[%p ",
189 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
190 bp = buf[bn] + strlen (buf[bn]);
192 if (c->pin)
193 sprintf (bp, "pin %s:%s at %d,%d", element_name_for (c), c->pin->Number,
194 c->x, c->y);
195 else if (c->via)
196 sprintf (bp, "via at %d,%d", c->x, c->y);
197 else if (c->pad)
199 sprintf (bp, "pad %s:%s at %d,%d (%d,%d-%d,%d)",
200 element_name_for (c), c->pad->Number, c->x, c->y,
201 c->pad->Point1.X, c->pad->Point1.Y,
202 c->pad->Point2.X, c->pad->Point2.Y);
204 else
205 sprintf (bp, "at %d,%d", c->x, c->y);
206 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
207 return buf[bn];
210 static int solder_layer, component_layer;
212 static void
213 dj_abort (char *msg, ...)
215 va_list a;
216 va_start (a, msg);
217 vprintf (msg, a);
218 va_end (a);
219 fflush (stdout);
220 abort ();
223 #if 1
224 #define check(c,l)
225 #else
226 #define check(c,l) check2(__LINE__,c,l)
227 static void
228 check2 (int srcline, corner_s * c, line_s * l)
230 int saw_c = 0, saw_l = 0;
231 corner_s *cc;
232 line_s *ll;
233 int i;
235 for (cc = corners; cc; cc = cc->next)
237 if (DELETED (cc))
238 continue;
239 if (cc == c)
240 saw_c = 1;
241 for (i = 0; i < cc->n_lines; i++)
242 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
243 dj_abort ("check:%d: cc has line without backref\n", srcline);
244 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
245 dj_abort ("check:%d: via not at corner\n", srcline);
246 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
247 dj_abort ("check:%d: pin not at corner\n", srcline);
249 if (c && !saw_c)
250 dj_abort ("check:%d: corner not in corners list\n", srcline);
251 for (ll = lines; ll; ll = ll->next)
253 if (DELETED (ll))
254 continue;
255 if (ll == l)
256 saw_l = 1;
257 for (i = 0; i < ll->s->n_lines; i++)
258 if (ll->s->lines[i] == ll)
259 break;
260 if (i == ll->s->n_lines)
261 dj_abort ("check:%d: ll->s has no backref\n", srcline);
262 for (i = 0; i < ll->e->n_lines; i++)
263 if (ll->e->lines[i] == ll)
264 break;
265 if (i == ll->e->n_lines)
266 dj_abort ("check:%d: ll->e has no backref\n", srcline);
267 if (!line_is_pad (ll)
268 && (ll->s->x != ll->line->Point1.X
269 || ll->s->y != ll->line->Point1.Y
270 || ll->e->x != ll->line->Point2.X
271 || ll->e->y != ll->line->Point2.Y))
273 printf ("line: %d,%d to %d,%d pcbline: %d,%d to %d,%d\n",
274 ll->s->x, ll->s->y,
275 ll->e->x, ll->e->y,
276 ll->line->Point1.X,
277 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
278 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
281 if (l && !saw_l)
282 dj_abort ("check:%d: line not in lines list\n", srcline);
285 #endif
287 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
289 static int
290 gridsnap (int n)
292 if (n <= 0)
293 return 0;
294 return n - n % (int) (Settings.Grid);
297 /* Avoid commonly used names. */
299 static int
300 djabs (int x)
302 return x > 0 ? x : -x;
305 static int
306 djmax (int x, int y)
308 return x > y ? x : y;
311 static int
312 djmin (int x, int y)
314 return x < y ? x : y;
318 * Find distance between 2 points. We use floating point math here
319 * because we can fairly easily overflow a 32 bit integer here. In
320 * fact it only takes 0.46" to do so.
322 static int
323 dist (int x1, int y1, int x2, int y2)
325 double dx1, dy1, dx2, dy2, d;
327 dx1 = (double) x1;
328 dy1 = (double) y1;
329 dx2 = (double) x2;
330 dy2 = (double) y2;
332 d = sqrt ((dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2));
333 d = rint (d);
335 return (int) d;
338 static int
339 line_length (line_s * l)
341 if (l->s->x == l->e->x)
342 return djabs (l->s->y - l->e->y);
343 if (l->s->y == l->e->y)
344 return djabs (l->s->x - l->e->x);
345 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
348 static int
349 dist_ltp2 (int dx, int y, int y1, int y2)
351 if (y1 > y2)
352 SWAP (y1, y2);
353 if (y < y1)
354 return dist (dx, y, 0, y1);
355 if (y > y2)
356 return dist (dx, y, 0, y2);
357 return djabs (dx);
361 sqr (int a)
363 return a * a;
366 static int
367 intersecting_layers (int l1, int l2)
369 if (l1 == -1 || l2 == -1)
370 return 1;
371 if (l1 == l2)
372 return 1;
373 if (layer_groupings[l1] == layer_groupings[l2])
374 return 1;
375 return 0;
378 static int
379 dist_line_to_point (line_s * l, corner_s * c)
381 double len, r, d;
382 /* We can do this quickly if l is vertical or horizontal. */
383 if (l->s->x == l->e->x)
384 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
385 if (l->s->y == l->e->y)
386 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
388 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
389 len = sqrt (sqr (l->s->x - l->e->x) + sqr (l->s->y - l->e->y));
390 if (len == 0)
391 return dist (l->s->x, l->s->y, c->x, c->y);
393 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
394 l->e->x);
395 r /= len * len;
396 if (r < 0)
397 return dist (l->s->x, l->s->y, c->x, c->y);
398 if (r > 1)
399 return dist (l->e->x, l->e->y, c->x, c->y);
401 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
402 l->s->y);
403 return (int) (d / len);
406 static int
407 line_orient (line_s * l, corner_s * c)
409 int x1, y1, x2, y2;
410 if (c == l->s)
412 x1 = l->s->x;
413 y1 = l->s->y;
414 x2 = l->e->x;
415 y2 = l->e->y;
417 else
419 x1 = l->e->x;
420 y1 = l->e->y;
421 x2 = l->s->x;
422 y2 = l->s->y;
424 if (x1 == x2)
426 if (y1 < y2)
427 return DOWN;
428 return UP;
430 else if (y1 == y2)
432 if (x1 < x2)
433 return RIGHT;
434 return LEFT;
436 return DIAGONAL;
439 #if 0
440 /* Not used */
441 static corner_s *
442 common_corner (line_s * l1, line_s * l2)
444 if (l1->s == l2->s || l1->s == l2->e)
445 return l1->s;
446 if (l1->e == l2->s || l1->e == l2->e)
447 return l1->e;
448 dj_abort ("common_corner: no common corner found\n");
449 return NULL;
451 #endif
453 static corner_s *
454 other_corner (line_s * l, corner_s * c)
456 if (l->s == c)
457 return l->e;
458 if (l->e == c)
459 return l->s;
460 dj_abort ("other_corner: neither corner passed\n");
461 return NULL;
464 static corner_s *
465 find_corner_if (int x, int y, int l)
467 corner_s *c;
468 for (c = corners; c; c = c->next)
470 if (DELETED (c))
471 continue;
472 if (c->x != x || c->y != y)
473 continue;
474 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
475 continue;
476 return c;
478 return 0;
481 static corner_s *
482 find_corner (int x, int y, int l)
484 corner_s *c;
485 for (c = corners; c; c = c->next)
487 if (DELETED (c))
488 continue;
489 if (c->x != x || c->y != y)
490 continue;
491 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
492 continue;
493 return c;
495 c = (corner_s *) malloc (sizeof (corner_s));
496 c->next = corners;
497 corners = c;
498 c->x = x;
499 c->y = y;
500 c->net = 0;
501 c->via = 0;
502 c->pad = 0;
503 c->pin = 0;
504 c->layer = l;
505 c->n_lines = 0;
506 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
507 return c;
510 static void
511 add_line_to_corner (line_s * l, corner_s * c)
513 int n;
514 n = (c->n_lines + 1 + INC) & ~INC;
515 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
516 c->lines[c->n_lines] = l;
517 c->n_lines++;
518 dprintf ("add_line_to_corner %d %d\n", c->x, c->y);
521 static LineType *
522 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
523 int thick, int clear, FlagType flags)
525 char *from, *to;
526 LineType *nl;
527 LayerType *lyr = LAYER_PTR (layer);
529 from = (char *) lyr->Line;
530 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
531 x1, y1, x2, y2, thick, clear, flags);
532 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
534 to = (char *) lyr->Line;
535 if (from != to)
537 line_s *lp;
538 for (lp = lines; lp; lp = lp->next)
540 if (DELETED (lp))
541 continue;
542 if ((char *) (lp->line) >= from
543 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
544 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
547 return nl;
550 static void
551 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
553 line_s *ls;
555 if (layer >= max_layer)
556 dj_abort ("layer %d\n", layer);
558 if (example == NULL)
559 dj_abort ("NULL example passed to new_line()\n", layer);
561 if (s->x == e->x && s->y == e->y)
562 return;
564 ls = (line_s *) malloc (sizeof (line_s));
565 ls->next = lines;
566 lines = ls;
567 ls->s = s;
568 ls->e = e;
569 ls->layer = layer;
570 #if 0
571 if ((example->Point1.X == s->x && example->Point1.Y == s->y
572 && example->Point2.X == e->x && example->Point2.Y == e->y)
573 || (example->Point2.X == s->x && example->Point2.Y == s->y
574 && example->Point1.X == e->x && example->Point1.Y == e->y))
576 ls->line = example;
578 else
579 #endif
581 LineType *nl;
582 dprintf
583 ("New line \033[35m%d,%d to %d,%d from l%d t%d c%d f%s\033[0m\n",
584 s->x, s->y, e->x, e->y, layer, example->Thickness,
585 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
586 nl =
587 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
588 example->Clearance, example->Flags);
590 if (!nl)
591 dj_abort ("can't create new line!");
592 ls->line = nl;
594 add_line_to_corner (ls, s);
595 add_line_to_corner (ls, e);
596 check (s, ls);
597 check (e, ls);
600 #if 0
601 /* Not used */
602 static int
603 c_orth_to (corner_s * c, line_s * l, int o)
605 int i, o2;
606 int rv = 0;
607 for (i = 0; i < c->n_lines; i++)
609 if (c->lines[i] == l)
610 continue;
611 o2 = line_orient (c->lines[i], c);
612 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
613 return 0;
614 rv++;
616 return rv;
618 #endif
620 static line_s *
621 other_line (corner_s * c, line_s * l)
623 int i;
624 line_s *rv = 0;
625 if (c->pin || c->pad || c->via)
626 return 0;
627 for (i = 0; i < c->n_lines; i++)
629 if (c->lines[i] == l)
630 continue;
631 if (rv)
632 return 0;
633 rv = c->lines[i];
635 return rv;
638 static void
639 empty_rect (rect_s * rect)
641 rect->x1 = rect->y1 = INT_MAX;
642 rect->x2 = rect->y2 = INT_MIN;
645 static void
646 add_point_to_rect (rect_s * rect, int x, int y, int w)
648 if (rect->x1 > x - w)
649 rect->x1 = x - w;
650 if (rect->x2 < x + w)
651 rect->x2 = x + w;
652 if (rect->y1 > y - w)
653 rect->y1 = y - w;
654 if (rect->y2 < y + w)
655 rect->y2 = y + w;
658 static void
659 add_line_to_rect (rect_s * rect, line_s * l)
661 add_point_to_rect (rect, l->s->x, l->s->y, 0);
662 add_point_to_rect (rect, l->e->x, l->e->y, 0);
665 static int
666 pin_in_rect (rect_s * r, int x, int y, int w)
668 if (x < r->x1 && x + w < r->x1)
669 return 0;
670 if (x > r->x2 && x - w > r->x2)
671 return 0;
672 if (y < r->y1 && y + w < r->y1)
673 return 0;
674 if (y > r->y2 && y - w > r->y2)
675 return 0;
676 return 1;
679 static int
680 line_in_rect (rect_s * r, line_s * l)
682 rect_s lr;
683 empty_rect (&lr);
684 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
685 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
686 dprintf ("line_in_rect %d,%d-%d,%d vs %d,%d-%d,%d\n",
687 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
688 /* simple intersection of rectangles */
689 if (lr.x1 < r->x1)
690 lr.x1 = r->x1;
691 if (lr.x2 > r->x2)
692 lr.x2 = r->x2;
693 if (lr.y1 < r->y1)
694 lr.y1 = r->y1;
695 if (lr.y2 > r->y2)
696 lr.y2 = r->y2;
697 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
698 return 1;
699 return 0;
702 static int
703 corner_radius (corner_s * c)
705 int diam = 0;
706 int i;
707 if (c->pin)
708 diam = djmax (c->pin->Thickness, diam);
709 if (c->via)
710 diam = djmax (c->via->Thickness, diam);
711 for (i = 0; i < c->n_lines; i++)
712 if (c->lines[i]->line)
713 diam = djmax (c->lines[i]->line->Thickness, diam);
714 diam = (diam + 1) / 2;
715 return diam;
718 #if 0
719 /* Not used */
720 static int
721 corner_layer (corner_s * c)
723 if (c->pin || c->via)
724 return -1;
725 if (c->n_lines < 1)
726 return -1;
727 return c->lines[0]->layer;
729 #endif
731 static void
732 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
734 int diam = corner_radius (c);
735 if (!pin_in_rect (e, c->x, c->y, diam))
736 return;
737 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
738 return;
739 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
740 return;
741 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
742 return;
743 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
744 return;
746 /*printf("add point %d,%d diam %d\n", c->x, c->y, diam); */
747 add_point_to_rect (rect, c->x, c->y, diam);
750 static void
751 remove_line (line_s * l)
753 int i, j;
754 line_s *l2;
755 LineType *from = 0, *to = 0;
756 LayerType *layer = &(PCB->Data->Layer[l->layer]);
758 check (0, 0);
760 if (l->line)
762 /* compensate for having line pointers rearranged */
763 from = &(layer->Line[layer->LineN - 1]);
764 to = l->line;
765 RemoveLine (layer, l->line);
768 DELETE (l);
769 for (l2 = lines; l2; l2 = l2->next)
771 if (DELETED (l2))
772 continue;
773 if (l2->line == from)
774 l2->line = to;
777 for (i = 0, j = 0; i < l->s->n_lines; i++)
778 if (l->s->lines[i] != l)
779 l->s->lines[j++] = l->s->lines[i];
780 l->s->n_lines = j;
782 for (i = 0, j = 0; i < l->e->n_lines; i++)
783 if (l->e->lines[i] != l)
784 l->e->lines[j++] = l->e->lines[i];
785 l->e->n_lines = j;
786 check (0, 0);
789 static void
790 move_line_to_layer (line_s * l, int layer)
792 line_s *l2;
793 LayerType *ls, *ld;
794 LineType *from = 0, *to = 0;
795 LineType *oldbase = 0, *newbase = 0, *oldend;
796 LineType *newline;
798 ls = LAYER_PTR (l->layer);
799 from = &(ls->Line[ls->LineN - 1]);
800 to = l->line;
802 ld = LAYER_PTR (layer);
803 oldbase = ld->Line;
804 oldend = oldbase + ld->LineN;
806 newline = (LineType *) MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
807 newbase = ld->Line;
809 for (l2 = lines; l2; l2 = l2->next)
811 if (DELETED (l2))
812 continue;
813 if (l2->line == from)
814 l2->line = to;
815 if (l2->line >= oldbase && l2->line < oldend)
816 l2->line += newbase - oldbase;
819 l->line = newline;
820 l->layer = layer;
823 static void
824 remove_via_at (corner_s * c)
826 corner_s *cc;
827 PinType *from = PCB->Data->Via + PCB->Data->ViaN - 1;
828 PinType *to = c->via;
829 RemoveObject (VIA_TYPE, c->via, 0, 0);
830 c->via = 0;
831 for (cc = corners; cc; cc = cc->next)
833 if (DELETED (cc))
834 continue;
835 if (cc->via == from)
836 cc->via = to;
840 static void
841 remove_corner (corner_s * c2)
843 corner_s *c;
844 dprintf ("remove corner %s\n", corner_name (c2));
845 if (corners == c2)
846 corners = c2->next;
847 for (c = corners; c; c = c->next)
849 if (DELETED (c))
850 continue;
851 if (c->next == c2)
852 c->next = c2->next;
854 if (next_corner == c2)
855 next_corner = c2->next;
856 free (c2->lines);
857 c2->lines = 0;
858 DELETE (c2);
861 static void
862 merge_corners (corner_s * c1, corner_s * c2)
864 int i;
865 if (c1 == c2)
866 abort ();
867 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
868 for (i = 0; i < c2->n_lines; i++)
870 add_line_to_corner (c2->lines[i], c1);
871 if (c2->lines[i]->s == c2)
872 c2->lines[i]->s = c1;
873 if (c2->lines[i]->e == c2)
874 c2->lines[i]->e = c1;
876 if (c1->via && c2->via)
877 remove_via_at (c2);
878 else if (c2->via)
879 c1->via = c2->via;
880 if (c2->pad)
881 c1->pad = c2->pad;
882 if (c2->pin)
883 c1->pin = c2->pin;
884 if (c2->layer != c1->layer)
885 c1->layer = -1;
887 remove_corner (c2);
890 static void
891 move_corner (corner_s * c, int x, int y)
893 PinType *via;
894 int i;
895 corner_s *pad;
897 check (c, 0);
898 if (c->pad || c->pin)
899 dj_abort ("move_corner: has pin or pad\n");
900 dprintf ("move_corner %p from %d,%d to %d,%d\n", (void *) c, c->x, c->y, x,
902 pad = find_corner_if (x, y, c->layer);
903 c->x = x;
904 c->y = y;
905 via = c->via;
906 if (via)
908 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
909 dprintf ("via move %d,%d to %d,%d\n", via->X, via->Y, x, y);
911 for (i = 0; i < c->n_lines; i++)
913 LineTypePtr tl = c->lines[i]->line;
914 if (tl)
916 if (c->lines[i]->s == c)
918 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
919 &tl->Point1, x - (tl->Point1.X),
920 y - (tl->Point1.Y));
922 else
924 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
925 &tl->Point2, x - (tl->Point2.X),
926 y - (tl->Point2.Y));
928 dprintf ("Line %p moved to %d,%d %d,%d\n", (void *) tl,
929 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
932 if (pad && pad != c)
933 merge_corners (c, pad);
934 else
935 for (i = 0; i < c->n_lines; i++)
937 if (c->lines[i]->s->x == c->lines[i]->e->x
938 && c->lines[i]->s->y == c->lines[i]->e->y)
940 corner_s *c2 = other_corner (c->lines[i], c);
941 dprintf ("move_corner: removing line %d,%d %d,%d %p %p\n",
942 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
944 remove_line (c->lines[i]);
945 if (c != c2)
946 merge_corners (c, c2);
947 check (c, 0);
948 i--;
949 break;
952 gui->progress (0, 0, 0);
953 check (c, 0);
956 static int
957 any_line_selected ()
959 line_s *l;
960 for (l = lines; l; l = l->next)
962 if (DELETED (l))
963 continue;
964 if (l->line && selected (l->line))
965 return 1;
967 return 0;
970 static int
971 trim_step (int s, int l1, int l2)
973 dprintf ("trim %d %d %d\n", s, l1, l2);
974 if (s > l1)
975 s = l1;
976 if (s > l2)
977 s = l2;
978 if (s != l1 && s != l2)
979 s = gridsnap (s);
980 return s;
983 static int canonicalize_line (line_s * l);
985 static int
986 split_line (line_s * l, corner_s * c)
988 int i;
989 LayerType *layer;
990 LineType *pcbline;
991 line_s *ls;
993 if (!intersecting_layers (l->layer, c->layer))
994 return 0;
995 if (line_is_pad (l))
996 return 0;
997 if (c->pad)
999 dprintf ("split on pad!\n");
1000 if (l->s->pad == c->pad || l->e->pad == c->pad)
1001 return 0;
1002 dprintf ("splitting...\n");
1005 check (c, l);
1006 layer = PCB->Data->Layer + l->layer;
1007 pcbline = create_pcb_line (l->layer,
1008 c->x, c->y, l->e->x, l->e->y,
1009 l->line->Thickness, l->line->Clearance,
1010 l->line->Flags);
1011 if (pcbline == 0)
1012 return 0; /* already a line there */
1014 check (c, l);
1016 dprintf ("split line from %d,%d to %d,%d at %d,%d\n",
1017 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
1018 ls = (line_s *) malloc (sizeof (line_s));
1020 ls->next = lines;
1021 lines = ls;
1022 ls->s = c;
1023 ls->e = l->e;
1024 ls->line = pcbline;
1025 ls->layer = l->layer;
1026 for (i = 0; i < l->e->n_lines; i++)
1027 if (l->e->lines[i] == l)
1028 l->e->lines[i] = ls;
1029 l->e = c;
1030 add_line_to_corner (l, c);
1031 add_line_to_corner (ls, c);
1033 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
1034 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
1036 return 1;
1039 static int
1040 canonicalize_line (line_s * l)
1042 /* This could be faster */
1043 corner_s *c;
1044 if (l->s->x == l->e->x)
1046 int y1 = l->s->y;
1047 int y2 = l->e->y;
1048 int x1 = l->s->x - l->line->Thickness / 2;
1049 int x2 = l->s->x + l->line->Thickness / 2;
1050 if (y1 > y2)
1052 int t = y1;
1053 y1 = y2;
1054 y2 = t;
1056 for (c = corners; c; c = c->next)
1058 if (DELETED (c))
1059 continue;
1060 if ((y1 < c->y && c->y < y2)
1061 && intersecting_layers (l->layer, c->layer))
1063 if (c->x != l->s->x
1064 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1066 move_corner (c, l->s->x, c->y);
1068 if (c->x == l->s->x)
1070 /* FIXME: if the line is split, we have to re-canonicalize
1071 both segments. */
1072 return split_line (l, c);
1077 else if (l->s->y == l->e->y)
1079 int x1 = l->s->x;
1080 int x2 = l->e->x;
1081 int y1 = l->s->y - l->line->Thickness / 2;
1082 int y2 = l->s->y + l->line->Thickness / 2;
1083 if (x1 > x2)
1085 int t = x1;
1086 x1 = x2;
1087 x2 = t;
1089 for (c = corners; c; c = c->next)
1091 if (DELETED (c))
1092 continue;
1093 if ((x1 < c->x && c->x < x2)
1094 && intersecting_layers (l->layer, c->layer))
1096 if (c->y != l->s->y
1097 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1099 move_corner (c, c->x, l->s->y);
1101 if (c->y == l->s->y)
1103 /* FIXME: Likewise. */
1104 return split_line (l, c);
1109 else
1111 /* diagonal lines. Let's try to split them at pins/vias
1112 anyway. */
1113 int x1 = l->s->x;
1114 int x2 = l->e->x;
1115 int y1 = l->s->y;
1116 int y2 = l->e->y;
1117 if (x1 > x2)
1119 int t = x1;
1120 x1 = x2;
1121 x2 = t;
1123 if (y1 > y2)
1125 int t = y1;
1126 y1 = y2;
1127 y2 = t;
1129 for (c = corners; c; c = c->next)
1131 if (DELETED (c))
1132 continue;
1133 if (!c->via && !c->pin)
1134 continue;
1135 if ((x1 < c->x && c->x < x2)
1136 && (y1 < c->y && c->y < y2)
1137 && intersecting_layers (l->layer, c->layer))
1139 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1140 th /= 2;
1141 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1142 && dist (l->e->x, l->e->y, c->x, c->y) > th
1143 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1145 return split_line (l, c);
1150 return 0;
1153 /* Make sure all vias are at line end points */
1154 static int
1155 canonicalize_lines ()
1157 int changes = 0;
1158 int count;
1159 line_s *l;
1160 while (1)
1162 count = 0;
1163 for (l = lines; l; l = l->next)
1165 if (DELETED (l))
1166 continue;
1167 count += canonicalize_line (l);
1169 changes += count;
1170 if (count == 0)
1171 break;
1173 return changes;
1176 static int
1177 simple_optimize_corner (corner_s * c)
1179 int i;
1180 int rv = 0;
1182 check (c, 0);
1183 if (c->via)
1185 /* see if no via is needed */
1186 if (selected (c->via))
1187 dprintf ("via check: line[0] layer %d at %d,%d nl %d\n",
1188 c->lines[0]->layer, c->x, c->y, c->n_lines);
1189 /* We can't delete vias that connect to power planes, or vias
1190 that aren't tented (assume they're test points). */
1191 if (!TEST_ANY_THERMS (c->via)
1192 && c->via->Mask == 0)
1194 for (i = 1; i < c->n_lines; i++)
1196 if (selected (c->via))
1197 dprintf (" line[%d] layer %d %d,%d to %d,%d\n",
1198 i, c->lines[i]->layer,
1199 c->lines[i]->s->x, c->lines[i]->s->y,
1200 c->lines[i]->e->x, c->lines[i]->e->y);
1201 if (c->lines[i]->layer != c->lines[0]->layer)
1202 break;
1204 if (i == c->n_lines)
1206 if (selected (c->via))
1207 dprintf (" remove it\n");
1208 remove_via_at (c);
1209 rv++;
1214 check (c, 0);
1215 if (c->n_lines == 2 && !c->via)
1217 /* see if it is an unneeded corner */
1218 int o = line_orient (c->lines[0], c);
1219 corner_s *c2 = other_corner (c->lines[1], c);
1220 corner_s *c0 = other_corner (c->lines[0], c);
1221 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1223 dprintf ("straight %d,%d to %d,%d to %d,%d\n",
1224 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1225 if (selected (c->lines[0]->line))
1226 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1227 if (selected (c->lines[1]->line))
1228 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1229 move_corner (c, c2->x, c2->y);
1232 check (c, 0);
1233 return rv;
1236 /* We always run these */
1237 static int
1238 simple_optimizations ()
1240 corner_s *c;
1241 int rv = 0;
1243 /* Look for corners that aren't */
1244 for (c = corners; c; c = c->next)
1246 if (DELETED (c))
1247 continue;
1248 if (c->pad || c->pin)
1249 continue;
1250 rv += simple_optimize_corner (c);
1252 return rv;
1255 static int
1256 is_hole (corner_s * c)
1258 return c->pin || c->pad || c->via;
1261 static int
1262 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1264 static corner_s **cs = 0;
1265 static int cm = 0;
1266 static line_s **ls = 0;
1267 static int lm = 0;
1268 int i, li, ln, cn, snap;
1269 line_s *l = 0;
1270 corner_s *c2, *cb;
1271 int adir = 0, sdir = 0, pull;
1272 int saw_sel = 0, saw_auto = 0;
1273 int max, len = 0, r1 = 0, r2;
1274 rect_s rr;
1275 int edir = 0, done;
1277 if (cs == 0)
1279 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1280 cm = 10;
1281 ls = (line_s **) malloc (10 * sizeof (line_s));
1282 lm = 10;
1285 for (i = 0; i < c->n_lines; i++)
1287 int o = line_orient (c->lines[i], c);
1288 if (o == rdir)
1289 return 0;
1292 switch (fdir)
1294 case RIGHT:
1295 adir = DOWN;
1296 sdir = UP;
1297 break;
1298 case DOWN:
1299 adir = RIGHT;
1300 sdir = LEFT;
1301 break;
1302 default:
1303 dj_abort ("fdir not right or down\n");
1306 c2 = c;
1307 cn = 0;
1308 ln = 0;
1309 pull = 0;
1310 while (c2)
1312 if (c2->pad || c2->pin || c2->n_lines < 2)
1313 return 0;
1314 if (cn >= cm)
1316 cm = cn + 10;
1317 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s));
1319 cs[cn++] = c2;
1320 r2 = corner_radius (c2);
1321 if (r1 < r2)
1322 r1 = r2;
1323 l = 0;
1324 for (i = 0; i < c2->n_lines; i++)
1326 int o = line_orient (c2->lines[i], c2);
1327 if (o == DIAGONAL)
1328 return 0;
1329 if (o == fdir)
1331 if (l)
1332 return 0; /* we don't support overlapping lines yet */
1333 l = c2->lines[i];
1335 if (o == rdir && c2->lines[i] != ls[ln - 1])
1336 return 0; /* likewise */
1337 if (o == adir)
1338 pull++;
1339 if (o == sdir)
1340 pull--;
1342 if (!l)
1343 break;
1344 if (selected (l->line))
1345 saw_sel = 1;
1346 if (autorouted (l->line))
1347 saw_auto = 1;
1348 if (ln >= lm)
1350 lm = ln + 10;
1351 ls = (line_s **) realloc (ls, lm * sizeof (line_s));
1353 ls[ln++] = l;
1354 c2 = other_corner (l, c2);
1356 if (cn < 2 || pull == 0)
1357 return 0;
1358 if (any_sel && !saw_sel)
1359 return 0;
1360 if (!any_sel && autorouted_only && !saw_auto)
1361 return 0;
1363 /* Ok, now look for other blockages. */
1365 empty_rect (&rr);
1366 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1367 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1369 if (fdir == RIGHT && pull < 0)
1370 edir = UP;
1371 else if (fdir == RIGHT && pull > 0)
1372 edir = DOWN;
1373 else if (fdir == DOWN && pull < 0)
1374 edir = LEFT;
1375 else if (fdir == DOWN && pull > 0)
1376 edir = RIGHT;
1378 max = -1;
1379 for (i = 0; i < cn; i++)
1380 for (li = 0; li < cs[i]->n_lines; li++)
1382 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1383 continue;
1384 len = line_length (cs[i]->lines[li]);
1385 if (max > len || max == -1)
1386 max = len;
1388 dprintf ("c %s %4d %4d cn %d pull %3d max %4d\n",
1389 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1391 switch (edir)
1393 case UP:
1394 rr.y1 = c->y - r1 - max;
1395 break;
1396 case DOWN:
1397 rr.y2 = c->y + r1 + max;
1398 break;
1399 case LEFT:
1400 rr.x1 = c->x - r1 - max;
1401 break;
1402 case RIGHT:
1403 rr.x2 = c->x + r1 + max;
1404 break;
1406 rr.x1 -= SB + 1;
1407 rr.x2 += SB + 1;
1408 rr.y1 -= SB + 1;
1409 rr.y2 += SB + 1;
1411 snap = 0;
1412 for (cb = corners; cb; cb = cb->next)
1414 int sep;
1415 if (DELETED (cb))
1416 continue;
1417 r1 = corner_radius (cb);
1418 if (cb->net == c->net && !cb->pad)
1419 continue;
1420 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1421 continue;
1422 switch (edir)
1424 #define ECHK(X,Y,LT) \
1425 for (i=0; i<cn; i++) \
1427 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1428 continue; \
1429 r2 = corner_radius(cs[i]); \
1430 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1431 continue; \
1432 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1433 continue; \
1434 if (cb->Y LT cs[i]->Y) \
1435 continue; \
1436 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1437 if (max > sep) \
1438 { max = sep; snap = 1; }\
1440 for (i=0; i<ln; i++) \
1442 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1443 continue; \
1444 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1445 continue; \
1446 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1447 - r1 - SB - 1); \
1448 if (max > sep) \
1449 { max = sep; snap = 1; }\
1451 case UP:
1452 ECHK (x, y, >=);
1453 break;
1454 case DOWN:
1455 ECHK (x, y, <=);
1456 break;
1457 case LEFT:
1458 ECHK (y, x, >=);
1459 break;
1460 case RIGHT:
1461 ECHK (y, x, <=);
1462 break;
1466 /* We must now check every line segment against our corners. */
1467 for (l = lines; l; l = l->next)
1469 int o, x1, x2, y1, y2;
1470 if (DELETED (l))
1471 continue;
1472 dprintf ("check line %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1473 l->e->y);
1474 if (l->s->net == c->net)
1476 dprintf (" same net\n");
1477 continue;
1479 o = line_orient (l, 0);
1480 /* We don't need to check perpendicular lines, because their
1481 corners already take care of it. */
1482 if ((fdir == RIGHT && (o == UP || o == DOWN))
1483 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1485 dprintf (" perpendicular\n");
1486 continue;
1489 /* Choose so that x1,y1 is closest to corner C */
1490 if ((fdir == RIGHT && l->s->x < l->e->x)
1491 || (fdir == DOWN && l->s->y < l->e->y))
1493 x1 = l->s->x;
1494 y1 = l->s->y;
1495 x2 = l->e->x;
1496 y2 = l->e->y;
1498 else
1500 x1 = l->e->x;
1501 y1 = l->e->y;
1502 x2 = l->s->x;
1503 y2 = l->s->y;
1506 /* Eliminate all lines outside our range */
1507 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1508 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1510 dprintf (" outside our range\n");
1511 continue;
1514 /* Eliminate all lines on the wrong side of us */
1515 if ((edir == UP && y1 > c->y && y2 > c->y)
1516 || (edir == DOWN && y1 < c->y && y2 < c->y)
1517 || (edir == LEFT && x1 > c->x && x2 > c->x)
1518 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1520 dprintf (" wrong side\n");
1521 continue;
1524 /* For now, cheat on diagonals */
1525 switch (edir)
1527 case RIGHT:
1528 if (x1 > x2)
1529 x1 = x2;
1530 break;
1531 case LEFT:
1532 if (x1 < x2)
1533 x1 = x2;
1534 break;
1535 case DOWN:
1536 if (y1 > y2)
1537 y1 = y2;
1538 break;
1539 case UP:
1540 if (y1 < y2)
1541 y1 = y2;
1542 break;
1545 /* Ok, now see how far we can get for each of our corners. */
1546 for (i = 0; i < cn; i++)
1548 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1549 int len = 0;
1550 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1551 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1552 continue;
1553 if (!intersecting_layers (cs[i]->layer, l->layer))
1554 continue;
1555 switch (edir)
1557 case RIGHT:
1558 len = x1 - c->x;
1559 break;
1560 case LEFT:
1561 len = c->x - x1;
1562 break;
1563 case DOWN:
1564 len = y1 - c->y;
1565 break;
1566 case UP:
1567 len = c->y - y1;
1568 break;
1570 len -= r;
1571 dprintf (" len is %d vs corner at %d,%d\n", len, cs[i]->x,
1572 cs[i]->y);
1573 if (len <= 0)
1574 return 0;
1575 if (max > len)
1576 max = len;
1581 /* We must make sure that if a segment isn't being completely
1582 removed, that any vias and/or pads don't overlap. */
1583 done = 0;
1584 while (!done)
1586 done = 1;
1587 for (i = 0; i < cn; i++)
1588 for (li = 0; li < cs[i]->n_lines; li++)
1590 line_s *l = cs[i]->lines[li];
1591 corner_s *oc = other_corner (l, cs[i]);
1592 if (line_orient (l, cs[i]) != edir)
1593 continue;
1594 len = line_length (l);
1595 if (!oc->pad || !cs[i]->via)
1597 if (!is_hole (l->s) || !is_hole (l->e))
1598 continue;
1599 if (len == max)
1600 continue;
1602 len -= corner_radius (l->s);
1603 len -= corner_radius (l->e);
1604 len -= SB + 1;
1605 if (max > len)
1607 max = len;
1608 done = 0;
1613 if (max <= 0)
1614 return 0;
1615 switch (edir)
1617 case UP:
1618 len = c->y - max;
1619 break;
1620 case DOWN:
1621 len = c->y + max;
1622 break;
1623 case LEFT:
1624 len = c->x - max;
1625 break;
1626 case RIGHT:
1627 len = c->x + max;
1628 break;
1630 if (snap && max > Settings.Grid)
1632 if (pull < 0)
1633 len += Settings.Grid - 1;
1634 len -= len % (int) (Settings.Grid);
1636 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1637 return 0;
1638 for (i = 0; i < cn; i++)
1640 if (fdir == RIGHT)
1642 max = len - cs[i]->y;
1643 move_corner (cs[i], cs[i]->x, len);
1645 else
1647 max = len - cs[i]->x;
1648 move_corner (cs[i], len, cs[i]->y);
1651 return max * pull;
1654 static int
1655 orthopull ()
1657 /* Look for straight runs which could be moved to reduce total trace
1658 length. */
1659 int any_sel = any_line_selected ();
1660 corner_s *c;
1661 int rv = 0;
1663 for (c = corners; c;)
1665 if (DELETED (c))
1666 continue;
1667 if (c->pin || c->pad)
1669 c = c->next;
1670 continue;
1672 next_corner = c;
1673 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1674 if (c != next_corner)
1676 c = next_corner;
1677 continue;
1679 rv += orthopull_1 (c, DOWN, UP, any_sel);
1680 if (c != next_corner)
1682 c = next_corner;
1683 continue;
1685 c = c->next;
1687 if (rv)
1688 printf ("orthopull: %d mils saved\n", rv / 100);
1689 return rv;
1692 static int
1693 debumpify ()
1695 /* Look for "U" shaped traces we can shorten (or eliminate) */
1696 int rv = 0;
1697 int any_selected = any_line_selected ();
1698 line_s *l, *l1, *l2;
1699 corner_s *c, *c1, *c2;
1700 rect_s rr, rp;
1701 int o, o1, o2, step, w;
1702 for (l = lines; l; l = l->next)
1704 if (DELETED (l))
1705 continue;
1706 if (!l->line)
1707 continue;
1708 if (any_selected && !selected (l->line))
1709 continue;
1710 if (!any_selected && autorouted_only && !autorouted (l->line))
1711 continue;
1712 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1713 continue;
1714 o = line_orient (l, 0);
1715 if (o == DIAGONAL)
1716 continue;
1717 l1 = other_line (l->s, l);
1718 if (!l1)
1719 continue;
1720 o1 = line_orient (l1, l->s);
1721 l2 = other_line (l->e, l);
1722 if (!l2)
1723 continue;
1724 o2 = line_orient (l2, l->e);
1725 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1726 continue;
1728 dprintf ("\nline: %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1729 l->e->y);
1730 w = l->line->Thickness / 2 + SB + 1;
1731 empty_rect (&rr);
1732 add_line_to_rect (&rr, l1);
1733 add_line_to_rect (&rr, l2);
1734 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1735 rr.x1 -= w;
1736 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1737 rr.x2 += w;
1738 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1739 rr.y1 -= w;
1740 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1741 rr.y2 += w;
1742 dprintf ("range: x %d..%d y %d..%d\n", rr.x1, rr.x2, rr.y1, rr.y2);
1744 c1 = other_corner (l1, l->s);
1745 c2 = other_corner (l2, l->e);
1747 empty_rect (&rp);
1748 for (c = corners; c; c = c->next)
1750 if (DELETED (c))
1751 continue;
1752 if (c->net != l->s->net
1753 && intersecting_layers (c->layer, l->s->layer))
1754 add_corner_to_rect_if (&rp, c, &rr);
1756 if (rp.x1 == INT_MAX)
1758 rp.x1 = rr.x2;
1759 rp.x2 = rr.x1;
1760 rp.y1 = rr.y2;
1761 rp.y2 = rr.y1;
1763 dprintf ("pin r: x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1765 switch (o1)
1767 case LEFT:
1768 step = l->s->x - rp.x2 - w;
1769 step = gridsnap (step);
1770 if (step > l->s->x - c1->x)
1771 step = l->s->x - c1->x;
1772 if (step > l->s->x - c2->x)
1773 step = l->s->x - c2->x;
1774 if (step > 0)
1776 dprintf ("left step %d at %d,%d\n", step, l->s->x, l->s->y);
1777 move_corner (l->s, l->s->x - step, l->s->y);
1778 move_corner (l->e, l->e->x - step, l->e->y);
1779 rv += step;
1781 break;
1782 case RIGHT:
1783 step = rp.x1 - l->s->x - w;
1784 step = gridsnap (step);
1785 if (step > c1->x - l->s->x)
1786 step = c1->x - l->s->x;
1787 if (step > c2->x - l->s->x)
1788 step = c2->x - l->s->x;
1789 if (step > 0)
1791 dprintf ("right step %d at %d,%d\n", step, l->s->x, l->s->y);
1792 move_corner (l->s, l->s->x + step, l->s->y);
1793 move_corner (l->e, l->e->x + step, l->e->y);
1794 rv += step;
1796 break;
1797 case UP:
1798 if (rp.y2 == INT_MIN)
1799 rp.y2 = rr.y1;
1800 step = trim_step (l->s->y - rp.y2 - w,
1801 l->s->y - c1->y, l->s->y - c2->y);
1802 if (step > 0)
1804 dprintf ("up step %d at %d,%d\n", step, l->s->x, l->s->y);
1805 move_corner (l->s, l->s->x, l->s->y - step);
1806 move_corner (l->e, l->e->x, l->e->y - step);
1807 rv += step;
1809 break;
1810 case DOWN:
1811 step = rp.y1 - l->s->y - w;
1812 step = gridsnap (step);
1813 if (step > c1->y - l->s->y)
1814 step = c1->y - l->s->y;
1815 if (step > c2->y - l->s->y)
1816 step = c2->y - l->s->y;
1817 if (step > 0)
1819 dprintf ("down step %d at %d,%d\n", step, l->s->x, l->s->y);
1820 move_corner (l->s, l->s->x, l->s->y + step);
1821 move_corner (l->e, l->e->x, l->e->y + step);
1822 rv += step;
1824 break;
1826 check (0, l);
1829 rv += simple_optimizations ();
1830 if (rv)
1831 printf ("debumpify: %d mils saved\n", rv / 50);
1832 return rv;
1835 static int
1836 simple_corner (corner_s * c)
1838 int o1, o2;
1839 if (c->pad || c->pin || c->via)
1840 return 0;
1841 if (c->n_lines != 2)
1842 return 0;
1843 o1 = line_orient (c->lines[0], c);
1844 o2 = line_orient (c->lines[1], c);
1845 if (ORIENT (o1) == ORIENT (o2))
1846 return 0;
1847 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1848 return 0;
1849 return 1;
1852 static int
1853 unjaggy_once ()
1855 /* Look for sequences of simple corners we can reduce. */
1856 int rv = 0;
1857 corner_s *c, *c0, *c1, *cc;
1858 int l, w, sel = any_line_selected ();
1859 int o0, o1, s0, s1;
1860 rect_s rr, rp;
1861 for (c = corners; c; c = c->next)
1863 if (DELETED (c))
1864 continue;
1865 if (!simple_corner (c))
1866 continue;
1867 if (!c->lines[0]->line || !c->lines[1]->line)
1868 continue;
1869 if (sel && !(selected (c->lines[0]->line)
1870 || selected (c->lines[1]->line)))
1871 continue;
1872 if (!sel && autorouted_only
1873 && !(autorouted (c->lines[0]->line)
1874 || autorouted (c->lines[1]->line)))
1875 continue;
1876 dprintf ("simple at %d,%d\n", c->x, c->y);
1878 c0 = other_corner (c->lines[0], c);
1879 o0 = line_orient (c->lines[0], c);
1880 s0 = simple_corner (c0);
1882 c1 = other_corner (c->lines[1], c);
1883 o1 = line_orient (c->lines[1], c);
1884 s1 = simple_corner (c1);
1886 if (!s0 && !s1)
1887 continue;
1888 dprintf ("simples at %d,%d\n", c->x, c->y);
1890 w = 1;
1891 for (l = 0; l < c0->n_lines; l++)
1892 if (c0->lines[l] != c->lines[0]
1893 && c0->lines[l]->layer == c->lines[0]->layer)
1895 int o = line_orient (c0->lines[l], c0);
1896 if (o == o1)
1897 w = 0;
1899 for (l = 0; l < c1->n_lines; l++)
1900 if (c1->lines[l] != c->lines[0]
1901 && c1->lines[l]->layer == c->lines[0]->layer)
1903 int o = line_orient (c1->lines[l], c1);
1904 if (o == o0)
1905 w = 0;
1907 if (!w)
1908 continue;
1909 dprintf ("orient ok\n");
1911 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1912 empty_rect (&rr);
1913 add_line_to_rect (&rr, c->lines[0]);
1914 add_line_to_rect (&rr, c->lines[1]);
1915 if (c->x != rr.x1)
1916 rr.x1 -= w;
1917 else
1918 rr.x2 += w;
1919 if (c->y != rr.y1)
1920 rr.y1 -= w;
1921 else
1922 rr.y2 += w;
1924 empty_rect (&rp);
1925 for (cc = corners; cc; cc = cc->next)
1927 if (DELETED (cc))
1928 continue;
1929 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1930 add_corner_to_rect_if (&rp, cc, &rr);
1932 dprintf ("rp x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1933 if (rp.x1 <= rp.x2) /* something triggered */
1934 continue;
1936 dprintf ("unjaggy at %d,%d layer %d\n", c->x, c->y, c->layer);
1937 if (c->x == c0->x)
1938 move_corner (c, c1->x, c0->y);
1939 else
1940 move_corner (c, c0->x, c1->y);
1941 rv++;
1942 check (c, 0);
1944 rv += simple_optimizations ();
1945 check (c, 0);
1946 return rv;
1949 static int
1950 unjaggy ()
1952 int i, r = 0, j;
1953 for (i = 0; i < 100; i++)
1955 j = unjaggy_once ();
1956 if (j == 0)
1957 break;
1958 r += j;
1960 if (r)
1961 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1962 return r;
1965 static int
1966 vianudge ()
1968 /* Look for vias with all lines leaving the same way, try to nudge
1969 via to eliminate one or more of them. */
1970 int rv = 0;
1971 corner_s *c, *c2, *c3;
1972 line_s *l;
1973 unsigned char directions[MAX_LAYER];
1974 unsigned char counts[MAX_LAYER];
1976 memset (directions, 0, sizeof (directions));
1977 memset (counts, 0, sizeof (counts));
1979 for (c = corners; c; c = c->next)
1981 int o, i, vr, cr, oboth;
1982 int len = 0, saved = 0;
1984 if (DELETED (c))
1985 continue;
1987 if (!c->via)
1988 continue;
1990 memset (directions, 0, sizeof (directions));
1991 memset (counts, 0, sizeof (counts));
1993 for (i = 0; i < c->n_lines; i++)
1995 o = line_orient (c->lines[i], c);
1996 counts[c->lines[i]->layer]++;
1997 directions[c->lines[i]->layer] |= o;
1999 for (o = 0, i = 0; i < max_layer; i++)
2000 if (counts[i] == 1)
2002 o = directions[i];
2003 break;
2005 switch (o)
2007 case LEFT:
2008 case RIGHT:
2009 oboth = LEFT | RIGHT;
2010 break;
2011 case UP:
2012 case DOWN:
2013 oboth = UP | DOWN;
2014 break;
2015 default:
2016 continue;
2018 for (i = 0; i < max_layer; i++)
2019 if (counts[i] && directions[i] != o && directions[i] != oboth)
2020 goto vianudge_continue;
2022 c2 = 0;
2023 for (i = 0; i < c->n_lines; i++)
2025 int ll = line_length (c->lines[i]);
2026 if (line_orient (c->lines[i], c) != o)
2028 saved--;
2029 continue;
2031 saved++;
2032 if (c2 == 0 || len > ll)
2034 len = ll;
2035 c2 = other_corner (c->lines[i], c);
2038 if (c2->pad || c2->pin || c2->via)
2039 continue;
2041 /* Now look for clearance in the new position */
2042 vr = c->via->Thickness / 2 + SB + 1;
2043 for (c3 = corners; c3; c3 = c3->next)
2045 if (DELETED (c3))
2046 continue;
2047 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2049 cr = corner_radius (c3);
2050 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2051 goto vianudge_continue;
2054 for (l = lines; l; l = l->next)
2056 if (DELETED (l))
2057 continue;
2058 if (l->s->net != c->net)
2060 int ld = dist_line_to_point (l, c2);
2061 if (ld < l->line->Thickness / 2 + vr)
2062 goto vianudge_continue;
2066 /* at this point, we know we can move it */
2068 dprintf ("vianudge: nudging via at %d,%d by %d mils saving %d\n",
2069 c->x, c->y, len / 100, saved / 100);
2070 rv += len * saved;
2071 move_corner (c, c2->x, c2->y);
2073 check (c, 0);
2075 vianudge_continue:
2076 continue;
2079 if (rv)
2080 printf ("vianudge: %d mils saved\n", rv / 100);
2081 return rv;
2084 static int
2085 viatrim ()
2087 /* Look for traces that can be moved to the other side of the board,
2088 to reduce the number of vias needed. For now, we look for simple
2089 lines, not multi-segmented lines. */
2090 line_s *l, *l2;
2091 int i, rv = 0, vrm = 0;
2092 int any_sel = any_line_selected ();
2094 for (l = lines; l; l = l->next)
2096 rect_s r;
2097 int my_layer, other_layer;
2099 if (DELETED (l))
2100 continue;
2101 if (!l->s->via)
2102 continue;
2103 if (!l->e->via)
2104 continue;
2105 if (any_sel && !selected (l->line))
2106 continue;
2107 if (!any_sel && autorouted_only && !autorouted (l->line))
2108 continue;
2110 my_layer = l->layer;
2111 other_layer = -1;
2112 dprintf ("line %p on layer %d from %d,%d to %d,%d\n", (void *) l,
2113 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2114 for (i = 0; i < l->s->n_lines; i++)
2115 if (l->s->lines[i] != l)
2117 if (other_layer == -1)
2119 other_layer = l->s->lines[i]->layer;
2120 dprintf ("noting other line %p on layer %d\n",
2121 (void *) (l->s->lines[i]), my_layer);
2123 else if (l->s->lines[i]->layer != other_layer)
2125 dprintf ("saw other line %p on layer %d (not %d)\n",
2126 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2127 my_layer);
2128 other_layer = -1;
2129 goto viatrim_other_corner;
2132 viatrim_other_corner:
2133 if (other_layer == -1)
2134 for (i = 0; i < l->e->n_lines; i++)
2135 if (l->e->lines[i] != l)
2137 if (other_layer == -1)
2139 other_layer = l->s->lines[i]->layer;
2140 dprintf ("noting other line %p on layer %d\n",
2141 (void *) (l->s->lines[i]), my_layer);
2143 else if (l->e->lines[i]->layer != other_layer)
2145 dprintf ("saw end line on layer %d (not %d)\n",
2146 l->e->lines[i]->layer, other_layer);
2147 goto viatrim_continue;
2151 /* Now see if any other line intersects us. We don't need to
2152 check corners, because they'd either be pins/vias and
2153 already conflict, or pads, which we'll check here anyway. */
2154 empty_rect (&r);
2155 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2156 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2158 for (l2 = lines; l2; l2 = l2->next)
2160 if (DELETED (l2))
2161 continue;
2162 if (l2->s->net != l->s->net && l2->layer == other_layer)
2164 dprintf ("checking other line %d,%d to %d,%d\n", l2->s->x,
2165 l2->s->y, l2->e->x, l2->e->y);
2166 if (line_in_rect (&r, l2))
2168 dprintf ("line from %d,%d to %d,%d in the way\n",
2169 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2170 goto viatrim_continue;
2175 if (l->layer == other_layer)
2176 continue;
2177 move_line_to_layer (l, other_layer);
2178 rv++;
2180 viatrim_continue:
2181 continue;
2183 vrm = simple_optimizations ();
2184 if (rv > 0)
2185 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2186 return rv + vrm;
2189 static int
2190 automagic ()
2192 int more = 1, oldmore = 0;
2193 int toomany = 100;
2194 while (more != oldmore && --toomany)
2196 oldmore = more;
2197 more += debumpify ();
2198 more += unjaggy ();
2199 more += orthopull ();
2200 more += vianudge ();
2201 more += viatrim ();
2203 return more - 1;
2206 static int
2207 miter ()
2209 corner_s *c;
2210 int done, progress;
2211 int sel = any_line_selected ();
2212 int saved = 0;
2214 for (c = corners; c; c = c->next)
2216 if (DELETED (c))
2217 continue;
2218 c->miter = 0;
2219 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2221 int o1 = line_orient (c->lines[0], c);
2222 int o2 = line_orient (c->lines[1], c);
2223 if (ORIENT (o1) != ORIENT (o2)
2224 && o1 != DIAGONAL && o2 != DIAGONAL
2225 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2226 c->miter = -1;
2230 done = 0;
2231 progress = 1;
2232 while (!done && progress)
2234 done = 1;
2235 progress = 0;
2236 for (c = corners; c; c = c->next)
2238 if (DELETED (c))
2239 continue;
2240 if (c->miter == -1)
2242 int max = line_length (c->lines[0]);
2243 int len = line_length (c->lines[1]);
2244 int bloat;
2245 int ref, dist;
2246 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2247 int mx = 0, my = 0, x, y;
2248 int o1 = line_orient (c->lines[0], c);
2249 int o2 = line_orient (c->lines[1], c);
2251 if (c->pad || c->pin || c->via)
2253 c->miter = 0;
2254 progress = 1;
2255 continue;
2258 oc1 = other_corner (c->lines[0], c);
2259 oc2 = other_corner (c->lines[1], c);
2260 #if 0
2261 if (oc1->pad)
2262 oc1 = 0;
2263 if (oc2->pad)
2264 oc2 = 0;
2265 #endif
2267 if ((sel && !(selected (c->lines[0]->line)
2268 || selected (c->lines[1]->line)))
2269 || (!sel && autorouted_only
2270 && !(autorouted (c->lines[0]->line)
2271 || autorouted (c->lines[1]->line))))
2273 c->miter = 0;
2274 progress = 1;
2275 continue;
2278 if (max > len)
2279 max = len;
2280 switch (o1)
2282 case LEFT:
2283 mx = -1;
2284 break;
2285 case RIGHT:
2286 mx = 1;
2287 break;
2288 case UP:
2289 my = -1;
2290 break;
2291 case DOWN:
2292 my = 1;
2293 break;
2295 switch (o2)
2297 case LEFT:
2298 mx = -1;
2299 break;
2300 case RIGHT:
2301 mx = 1;
2302 break;
2303 case UP:
2304 my = -1;
2305 break;
2306 case DOWN:
2307 my = 1;
2308 break;
2310 ref = c->x * mx + c->y * my;
2311 dist = max;
2313 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2315 for (c2 = corners; c2; c2 = c2->next)
2317 if (DELETED (c2))
2318 continue;
2319 if (c2 != c && c2 != oc1 && c2 != oc2
2320 && c->x * mx <= c2->x * mx
2321 && c->y * my <= c2->y * my
2322 && c->net != c2->net
2323 && intersecting_layers (c->layer, c2->layer))
2325 int cr = corner_radius (c2);
2326 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2327 if (c->x != c2->x && c->y != c2->y)
2328 len -= cr;
2329 if (len < dist || (len == dist && c->miter != -1))
2331 dist = len;
2332 closest_corner = c2;
2337 if (closest_corner && closest_corner->miter == -1)
2339 done = 0;
2340 continue;
2343 #if 0
2344 if (dist < Settings.Grid)
2346 c->miter = 0;
2347 progress = 1;
2348 continue;
2351 dist -= dist % Settings.Grid;
2352 #endif
2353 if (dist <= 0)
2355 c->miter = 0;
2356 progress = 1;
2357 continue;
2360 x = c->x;
2361 y = c->y;
2362 switch (o1)
2364 case LEFT:
2365 x -= dist;
2366 break;
2367 case RIGHT:
2368 x += dist;
2369 break;
2370 case UP:
2371 y -= dist;
2372 break;
2373 case DOWN:
2374 y += dist;
2375 break;
2377 c2 = find_corner (x, y, c->layer);
2378 if (c2 != other_corner (c->lines[0], c))
2379 split_line (c->lines[0], c2);
2380 x = c->x;
2381 y = c->y;
2382 switch (o2)
2384 case LEFT:
2385 x -= dist;
2386 break;
2387 case RIGHT:
2388 x += dist;
2389 break;
2390 case UP:
2391 y -= dist;
2392 break;
2393 case DOWN:
2394 y += dist;
2395 break;
2397 move_corner (c, x, y);
2398 c->miter = 0;
2399 c2->miter = 0;
2400 progress = 1;
2401 saved++;
2405 return saved;
2408 static void
2409 classify_corner (corner_s * c, int this_net)
2411 int i;
2412 if (c->net == this_net)
2413 return;
2414 c->net = this_net;
2415 for (i = 0; i < c->n_lines; i++)
2416 classify_corner (other_corner (c->lines[i], c), this_net);
2419 static void
2420 classify_nets ()
2422 static int this_net = 1;
2423 corner_s *c;
2425 for (c = corners; c; c = c->next)
2427 if (DELETED (c))
2428 continue;
2429 if (c->net)
2430 continue;
2431 classify_corner (c, this_net);
2432 this_net++;
2436 #if 0
2437 /* Not used */
2438 static void
2439 dump_all ()
2441 corner_s *c;
2442 line_s *l;
2443 for (c = corners; c; c = c->next)
2445 if (DELETED (c))
2446 continue;
2447 printf ("%p corner %d,%d layer %d net %d\n",
2448 (void *) c, c->x, c->y, c->layer, c->net);
2450 for (l = lines; l; l = l->next)
2452 if (DELETED (l))
2453 continue;
2454 printf ("%p line %p to %p layer %d\n",
2455 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2458 #endif
2460 static void
2461 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2463 int ox = c->x;
2464 int oy = c->y;
2465 int l;
2466 if (prev_corner && (c->pin || c->pad))
2467 return;
2468 move_corner (c, ox + dx, oy + dy);
2469 for (l = 0; l < c->n_lines; l++)
2471 corner_s *oc = other_corner (c->lines[l], c);
2472 if (oc == prev_corner)
2473 continue;
2474 if (dx && oc->x == ox)
2475 nudge_corner (oc, dx, 0, c);
2476 if (dy && oc->y == oy)
2477 nudge_corner (oc, 0, dy, c);
2481 static line_s *
2482 choose_example_line (corner_s * c1, corner_s * c2)
2484 int ci, li;
2485 corner_s *c[2];
2486 c[0] = c1;
2487 c[1] = c2;
2488 dprintf ("choose_example_line\n");
2489 for (ci = 0; ci < 2; ci++)
2490 for (li = 0; li < c[ci]->n_lines; li++)
2492 dprintf (" try[%d,%d] \033[36m<%d,%d-%d,%d t%d c%d f%s>\033[0m\n",
2493 ci, li,
2494 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2495 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2496 c[ci]->lines[li]->line->Thickness,
2497 c[ci]->lines[li]->line->Clearance,
2498 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2499 /* Pads are disqualified, as we want to mimic a trace line. */
2500 if (c[ci]->lines[li]->line == (LineTypePtr) c[ci]->pad)
2502 dprintf (" bad, pad\n");
2503 continue;
2505 /* Lines on layers that don't connect to the other pad are bad too. */
2506 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2508 dprintf (" bad, layers\n");
2509 continue;
2511 dprintf (" good\n");
2512 return c[ci]->lines[li];
2514 dprintf ("choose_example_line: none found!\n");
2515 return 0;
2518 static int
2519 connect_corners (corner_s * c1, corner_s * c2)
2521 int layer;
2522 line_s *ex = choose_example_line (c1, c2);
2523 LineType *example = ex->line;
2525 dprintf
2526 ("connect_corners \033[32m%d,%d to %d,%d, example line %d,%d to %d,%d l%d\033[0m\n",
2527 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2528 ex->layer);
2530 layer = ex->layer;
2532 /* Assume c1 is the moveable one. */
2533 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2535 int nx, ny;
2536 /* Extend the line */
2537 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2538 nx = c1->x, ny = c2->y;
2539 else
2540 nx = c2->x, ny = c1->y;
2541 if (nx != c2->x || ny != c2->y)
2543 move_corner (c1, nx, ny);
2544 new_line (c1, c2, layer, example);
2545 return 1;
2547 else
2549 move_corner (c1, nx, ny);
2550 return 1;
2553 else
2555 corner_s *nc = find_corner (c1->x, c2->y, layer);
2556 new_line (c1, nc, layer, example);
2557 new_line (nc, c2, layer, example);
2558 return 0;
2562 static void
2563 pinsnap ()
2565 corner_s *c;
2566 int best_dist[MAX_LAYER + 1];
2567 corner_s *best_c[MAX_LAYER + 1];
2568 int l, got_one;
2569 int left = 0, right = 0, top = 0, bottom = 0;
2570 PinType *pin;
2571 int again = 1;
2573 corner_s *prev_c;
2574 int close = 0;
2575 corner_s *c2;
2577 /* Look for pins that have no connections. See if there's a corner
2578 close by that should be connected to it. This usually happens
2579 when the MUCS router needs to route to an off-grid pin. */
2580 while (again)
2582 again = 0;
2583 for (c = corners; c; c = c->next)
2585 if (DELETED (c))
2586 continue;
2587 if (!(c->pin || c->via || c->pad))
2588 continue;
2590 prev_c = c;
2591 pin = 0;
2593 dprintf ("\ncorner %s\n", corner_name (c));
2594 if (c->pin || c->via)
2596 pin = c->pin ? c->pin : c->via;
2597 close = pin->Thickness / 2;
2598 left = c->x - close;
2599 right = c->x + close;
2600 bottom = c->y - close;
2601 top = c->y + close;
2603 else if (c->pad)
2605 close = c->pad->Thickness / 2 + 1;
2606 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2607 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2608 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2609 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2610 if (c->pad->Point1.X == c->pad->Point2.X)
2612 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2613 dprintf ("pad y %d %d hy %d c %d\n", c->pad->Point1.Y,
2614 c->pad->Point2.Y, hy, c->y);
2615 if (c->y < hy)
2616 top = hy;
2617 else
2618 bottom = hy + 1;
2620 else
2622 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2623 dprintf ("pad x %d %d hx %d c %d\n", c->pad->Point1.X,
2624 c->pad->Point2.X, hx, c->x);
2625 if (c->x < hx)
2626 right = hx;
2627 else
2628 left = hx + 1;
2632 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c), left, right,
2633 bottom, top);
2634 for (l = 0; l <= max_layer; l++)
2636 best_dist[l] = close * 2;
2637 best_c[l] = 0;
2639 got_one = 0;
2640 for (c2 = corners; c2; c2 = c2->next)
2642 int lt;
2644 if (DELETED (c2))
2645 continue;
2646 lt = corner_radius (c2);
2647 if (c2->n_lines
2648 && c2 != c
2649 && !(c2->pin || c2->pad || c2->via)
2650 && intersecting_layers (c->layer, c2->layer)
2651 && c2->x >= left - lt
2652 && c2->x <= right + lt
2653 && c2->y >= bottom - lt && c2->y <= top + lt)
2655 int d = dist (c->x, c->y, c2->x, c2->y);
2656 if (pin && d > pin->Thickness / 2 + lt)
2657 continue;
2658 if (c2->n_lines == 1)
2660 got_one++;
2661 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2662 corner_name (c));
2663 connect_corners (c, c2);
2664 again = 1;
2665 continue;
2667 if (best_c[c2->layer] == 0
2668 || c2->n_lines < best_c[c2->layer]->n_lines
2669 || (d < best_dist[c2->layer]
2670 && c2->n_lines <= best_c[c2->layer]->n_lines))
2672 best_dist[c2->layer] = d;
2673 best_c[c2->layer] = c2;
2674 dprintf ("layer %d best now %s\n", c2->layer,
2675 corner_name (c2));
2678 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2680 for (l = 0; l <= max_layer; l++)
2681 if (best_c[l])
2682 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2683 for (l = 0; l <= max_layer; l++)
2684 if (best_c[l])
2686 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2687 corner_name (c));
2688 connect_corners (best_c[l], c);
2689 again = 1;
2690 continue;
2697 /* Now look for line ends that don't connect, see if they need to be
2698 extended to intersect another line. */
2699 for (c = corners; c; c = c->next)
2701 line_s *l, *t;
2702 int lo;
2704 if (DELETED (c))
2705 continue;
2706 if (c->pin || c->via || c->pad)
2707 continue;
2708 if (c->n_lines != 1)
2709 continue;
2711 l = c->lines[0];
2712 lo = line_orient (l, c);
2713 dprintf ("line end %d,%d orient %d\n", c->x, c->y, lo);
2715 for (t = lines; t; t = t->next)
2717 if (DELETED (t))
2718 continue;
2719 if (t->layer != c->lines[0]->layer)
2720 continue;
2721 switch (lo) /* remember, orient is for the line relative to the corner */
2723 case LEFT:
2724 if (t->s->x == t->e->x
2725 && c->x < t->s->x
2726 && t->s->x <
2727 c->x + (l->line->Thickness + t->line->Thickness) / 2
2728 && ((t->s->y < c->y && c->y < t->e->y)
2729 || (t->e->y < c->y && c->y < t->s->y)))
2731 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2732 t->e->y);
2733 move_corner (c, t->s->x, c->y);
2735 break;
2736 case RIGHT:
2737 if (t->s->x == t->e->x
2738 && c->x > t->s->x
2739 && t->s->x >
2740 c->x - (l->line->Thickness + t->line->Thickness) / 2
2741 && ((t->s->y < c->y && c->y < t->e->y)
2742 || (t->e->y < c->y && c->y < t->s->y)))
2744 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2745 t->e->y);
2746 move_corner (c, t->s->x, c->y);
2748 break;
2749 case UP:
2750 if (t->s->y == t->e->y
2751 && c->y < t->s->y
2752 && t->s->y <
2753 c->y + (l->line->Thickness + t->line->Thickness) / 2
2754 && ((t->s->x < c->x && c->x < t->e->x)
2755 || (t->e->x < c->x && c->x < t->s->x)))
2757 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2758 t->e->y);
2759 move_corner (c, c->x, t->s->y);
2761 break;
2762 case DOWN:
2763 if (t->s->y == t->e->y
2764 && c->y > t->s->y
2765 && t->s->y >
2766 c->y - (l->line->Thickness + t->line->Thickness) / 2
2767 && ((t->s->x < c->x && c->x < t->e->x)
2768 || (t->e->x < c->x && c->x < t->s->x)))
2770 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2771 t->e->y);
2772 move_corner (c, c->x, t->s->y);
2774 break;
2780 static int
2781 pad_orient (PadType * p)
2783 if (p->Point1.X == p->Point2.X)
2784 return O_VERT;
2785 if (p->Point1.Y == p->Point2.Y)
2786 return O_HORIZ;
2787 return DIAGONAL;
2790 static void
2791 padcleaner ()
2793 line_s *l, *nextl;
2794 int close;
2795 rect_s r;
2796 int ei, pi;
2798 dprintf ("\ndj: padcleaner\n");
2799 for (l = lines; l; l = nextl)
2801 nextl = l->next;
2803 if (DELETED (l))
2804 continue;
2806 dprintf ("dj: line %p\n", (void *) l);
2807 check (0, l);
2809 if (l->s->pad && l->s->pad == l->e->pad)
2810 continue;
2812 for (ei = 0; ei < PCB->Data->ElementN; ei++)
2814 ElementType *e = &(PCB->Data->Element[ei]);
2815 for (pi = 0; pi < e->PadN; pi++)
2817 PadType *p = e->Pad + pi;
2818 int layerflag =
2819 TEST_FLAG (ONSOLDERFLAG, e) ? LT_SOLDER : LT_COMPONENT;
2821 if (layer_type[l->layer] != layerflag)
2822 continue;
2824 empty_rect (&r);
2825 close = p->Thickness / 2 + 1;
2826 add_point_to_rect (&r, p->Point1.X, p->Point1.Y,
2827 close - SB / 2);
2828 add_point_to_rect (&r, p->Point2.X, p->Point2.Y,
2829 close - SB / 2);
2830 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2831 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2832 && ORIENT (line_orient (l, 0)) == pad_orient (p))
2834 dprintf
2835 ("padcleaner %d,%d-%d,%d %d vs line %d,%d-%d,%d %d\n",
2836 p->Point1.X, p->Point1.Y, p->Point2.X, p->Point2.Y,
2837 p->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2838 l->line->Thickness);
2839 remove_line (l);
2840 goto next_line;
2844 next_line:;
2848 static void
2849 grok_layer_groups ()
2851 int i, j, f;
2852 LayerGroupType *l = &(PCB->LayerGroups);
2854 solder_layer = component_layer = -1;
2855 for (i = 0; i < max_layer; i++)
2857 layer_type[i] = 0;
2858 layer_groupings[i] = 0;
2860 for (i = 0; i < max_layer; i++)
2862 f = 0;
2863 for (j = 0; j < l->Number[i]; j++)
2865 if (l->Entries[i][j] == max_layer + SOLDER_LAYER)
2866 f |= LT_SOLDER;
2867 if (l->Entries[i][j] == max_layer + COMPONENT_LAYER)
2868 f |= LT_COMPONENT;
2870 for (j = 0; j < l->Number[i]; j++)
2872 if (l->Entries[i][j] >= 0 && l->Entries[i][j] < max_layer)
2874 layer_type[l->Entries[i][j]] |= f;
2875 layer_groupings[l->Entries[i][j]] = i;
2876 if (solder_layer == -1 && f == LT_SOLDER)
2877 solder_layer = l->Entries[i][j];
2878 if (component_layer == -1 && f == LT_COMPONENT)
2879 component_layer = l->Entries[i][j];
2885 static const char djopt_syntax[] =
2886 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull)\n"
2887 "djopt(auto) - all of the above\n" "djopt(miter)";
2889 static const char djopt_help[] =
2890 "Perform various optimizations on the current board";
2892 /* %start-doc actions djopt
2894 The different types of optimizations change your board in order to
2895 reduce the total trace length and via count.
2897 @table @code
2899 @item debumpify
2900 Looks for U-shaped traces that can be shortened or eliminated.
2902 @item unjaggy
2903 Looks for corners which could be flipped to eliminate one or more
2904 corners (i.e. jaggy lines become simpler).
2906 @item simple
2907 Removing uneeded vias, replacing two or more trace segments in a row
2908 with a single segment. This is usually performed automatically after
2909 other optimizations.
2911 @item vianudge
2912 Looks for vias where all traces leave in the same direction. Tries to
2913 move via in that direction to eliminate one of the traces (and thus a
2914 corner).
2916 @item viatrim
2917 Looks for traces that go from via to via, where moving that trace to a
2918 different layer eliminates one or both vias.
2920 @item orthopull
2921 Looks for chains of traces all going in one direction, with more
2922 traces orthogonal on one side than on the other. Moves the chain in
2923 that direction, causing a net reduction in trace length, possibly
2924 eliminating traces and/or corners.
2926 @item splitlines
2927 Looks for lines that pass through vias, pins, or pads, and splits them
2928 into separate lines so they can be managed separately.
2930 @item auto
2931 Performs the above options, repeating until no further optimizations
2932 can be made.
2934 @item miter
2935 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2936 RF losses and trace length.
2938 @end table
2940 %end-doc */
2942 static int
2943 ActionDJopt (int argc, char **argv, int x, int y)
2945 char *arg = argc > 0 ? argv[0] : 0;
2946 int layn, saved = 0;
2947 corner_s *c;
2949 #ifdef ENDIF
2950 SwitchDrawingWindow (PCB->Zoom, Output.drawing_area->window,
2951 Settings.ShowSolderSide, False);
2952 #endif
2954 hid_action("Busy");
2956 lines = 0;
2957 corners = 0;
2959 grok_layer_groups ();
2961 ELEMENT_LOOP (PCB->Data);
2962 PIN_LOOP (element);
2964 c = find_corner (pin->X, pin->Y, -1);
2965 c->pin = pin;
2967 END_LOOP;
2968 PAD_LOOP (element);
2970 int layern =
2971 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
2972 line_s *ls = (line_s *) malloc (sizeof (line_s));
2973 ls->next = lines;
2974 lines = ls;
2975 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
2976 ls->s->pad = pad;
2977 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
2978 ls->e->pad = pad;
2979 ls->layer = layern;
2980 ls->line = (LineTypePtr) pad;
2981 add_line_to_corner (ls, ls->s);
2982 ls->layer = layern;
2983 ls->line = (LineTypePtr) pad;
2984 add_line_to_corner (ls, ls->s);
2985 add_line_to_corner (ls, ls->e);
2988 END_LOOP;
2989 END_LOOP;
2990 VIA_LOOP (PCB->Data);
2991 /* hace don't mess with vias that have thermals */
2992 /* but then again don't bump into them
2993 if (!TEST_FLAG(ALLTHERMFLAGS, via))
2996 c = find_corner (via->X, via->Y, -1);
2997 c->via = via;
2999 END_LOOP;
3000 check (0, 0);
3002 if (NSTRCMP (arg, "splitlines") == 0)
3004 if (canonicalize_lines ())
3005 IncrementUndoSerialNumber ();
3006 return 0;
3009 for (layn = 0; layn < max_layer; layn++)
3011 LayerType *layer = LAYER_PTR (layn);
3012 int ln;
3013 for (ln = 0; ln < layer->LineN; ln++)
3015 LineType *l = &(layer->Line[ln]);
3016 line_s *ls;
3018 /* don't mess with thermals */
3019 if (TEST_FLAG (USETHERMALFLAG, l))
3020 continue;
3022 if (l->Point1.X == l->Point2.X && l->Point1.Y == l->Point2.Y)
3024 RemoveLine (layer, l);
3025 ln--;
3026 continue;
3029 ls = (line_s *) malloc (sizeof (line_s));
3030 ls->next = lines;
3031 lines = ls;
3032 ls->s = find_corner (l->Point1.X, l->Point1.Y, layn);
3033 ls->e = find_corner (l->Point2.X, l->Point2.Y, layn);
3034 ls->line = l;
3035 add_line_to_corner (ls, ls->s);
3036 add_line_to_corner (ls, ls->e);
3037 ls->layer = layn;
3042 check (0, 0);
3043 pinsnap ();
3044 canonicalize_lines ();
3045 check (0, 0);
3046 classify_nets ();
3047 /*dump_all(); */
3048 check (0, 0);
3050 if (NSTRCMP (arg, "debumpify") == 0)
3051 saved += debumpify ();
3052 else if (NSTRCMP (arg, "unjaggy") == 0)
3053 saved += unjaggy ();
3054 else if (NSTRCMP (arg, "simple") == 0)
3055 saved += simple_optimizations ();
3056 else if (NSTRCMP (arg, "vianudge") == 0)
3057 saved += vianudge ();
3058 else if (NSTRCMP (arg, "viatrim") == 0)
3059 saved += viatrim ();
3060 else if (NSTRCMP (arg, "orthopull") == 0)
3061 saved += orthopull ();
3062 else if (NSTRCMP (arg, "auto") == 0)
3063 saved += automagic ();
3064 else if (NSTRCMP (arg, "miter") == 0)
3065 saved += miter ();
3066 else
3068 printf ("unknown command: %s\n", arg);
3069 return 1;
3072 padcleaner ();
3074 check (0, 0);
3075 if (saved)
3076 IncrementUndoSerialNumber ();
3077 return 0;
3080 HID_Action djopt_action_list[] = {
3081 {"djopt", 0, ActionDJopt,
3082 djopt_help, djopt_syntax}
3084 {"OptAutoOnly", 0, djopt_set_auto_only,
3085 djopt_sao_help, djopt_sao_syntax}
3088 REGISTER_ACTIONS (djopt_action_list)