Added a description of djopt(debumpify) in the user docs.
[geda-pcb/pcjc2.git] / src / djopt.c
blob9d0cc57daf68aa28178d457b822239739f7fd085
1 /*!
2 * \file src/djopt.c
4 * \brief .
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 2003 DJ Delorie
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Contact addresses for paper mail and Email:
29 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
30 * dj@delorie.com
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include "global.h"
39 #include <memory.h>
40 #include <limits.h>
43 #include "data.h"
44 #include "create.h"
45 #include "remove.h"
46 #include "move.h"
47 #include "draw.h"
48 #include "undo.h"
49 #include "strflags.h"
50 #include "find.h"
51 #include "pcb-printf.h"
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
57 #ifndef HAVE_RINT
58 #define rint(x) (ceil((x) - 0.5))
59 #endif
61 #define dprintf if(0)pcb_printf
63 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x))
64 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x))
66 #define SB (PCB->Bloat+1)
68 /* must be 2^N-1 */
69 #define INC 7
71 #define O_HORIZ 0x10
72 #define O_VERT 0x20
73 #define LEFT 0x11
74 #define RIGHT 0x12
75 #define UP 0x24
76 #define DOWN 0x28
77 #define DIAGONAL 0xf0
78 #define ORIENT(x) ((x) & 0xf0)
79 #define DIRECT(x) ((x) & 0x0f)
81 #define LONGEST_FRECKLE 2 /*!< Manhattan length of the longest "freckle" */
84 struct line_s;
86 typedef struct corner_s
88 int layer;
89 struct corner_s *next;
90 int x, y;
91 int net;
92 PinType *via;
93 PadType *pad;
94 PinType *pin;
95 int miter;
96 int n_lines;
97 struct line_s **lines;
98 } corner_s;
100 typedef struct line_s
102 int layer;
103 struct line_s *next;
104 corner_s *s, *e;
105 LineType *line;
106 char is_pad;
107 } line_s;
109 typedef struct rect_s
111 int x1, y1, x2, y2;
112 } rect_s;
114 #define DELETE(q) (q)->layer = 0xdeadbeef
115 #define DELETED(q) ((q)->layer == 0xdeadbeef)
117 static corner_s *corners, *next_corner = 0;
118 static line_s *lines;
120 static int layer_groupings[MAX_LAYER];
121 static char layer_type[MAX_LAYER];
122 #define LT_TOP 1
123 #define LT_BOTTOM 2
125 static int autorouted_only = 1;
127 static const char djopt_sao_syntax[] = "OptAutoOnly()";
129 static const char djopt_sao_help[] =
130 "Toggles the optimize-only-autorouted flag.";
132 /* %start-doc actions OptAutoOnly
134 The original purpose of the trace optimizer was to clean up the traces
135 created by the various autorouters that have been used with PCB. When
136 a board has a mix of autorouted and carefully hand-routed traces, you
137 don't normally want the optimizer to move your hand-routed traces.
138 But, sometimes you do. By default, the optimizer only optimizes
139 autorouted traces. This action toggles that setting, so that you can
140 optimize hand-routed traces also.
142 %end-doc */
145 djopt_set_auto_only (int argc, char **argv, Coord x, Coord y)
147 autorouted_only = autorouted_only ? 0 : 1;
148 return 0;
151 static int
152 djopt_get_auto_only (void *data)
154 return autorouted_only;
157 HID_Flag djopt_flag_list[] = {
158 {"optautoonly", djopt_get_auto_only, NULL}
161 REGISTER_FLAGS (djopt_flag_list)
163 static char *
164 element_name_for (corner_s * c)
166 ELEMENT_LOOP (PCB->Data);
168 PIN_LOOP (element);
170 if (pin == c->pin)
171 return element->Name[1].TextString;
173 END_LOOP;
174 PAD_LOOP (element);
176 if (pad == c->pad)
177 return element->Name[1].TextString;
179 END_LOOP;
181 END_LOOP;
182 return "unknown";
185 static char *
186 corner_name (corner_s * c)
188 static char buf[4][100];
189 static int bn = 0;
190 char *bp;
191 size_t size_left;
192 bn = (bn + 1) % 4;
194 if (c->net == 0xf1eef1ee)
196 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
197 return buf[bn];
200 sprintf (buf[bn], "\033[%dm[%p ",
201 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
202 bp = buf[bn] + strlen (buf[bn]);
203 size_left = sizeof (buf[bn]) - strlen (buf[bn]);
205 if (c->pin)
206 pcb_snprintf (bp, size_left, "pin %s:%s at %#mD",
207 element_name_for (c), c->pin->Number, c->x, c->y);
208 else if (c->via)
209 pcb_snprintf (bp, size_left, "via at %#mD", c->x, c->y);
210 else if (c->pad)
212 pcb_snprintf (bp, size_left, "pad %s:%s at %#mD %#mD-%#mD",
213 element_name_for (c), c->pad->Number, c->x, c->y,
214 c->pad->Point1.X, c->pad->Point1.Y,
215 c->pad->Point2.X, c->pad->Point2.Y);
217 else
218 pcb_snprintf (bp, size_left, "at %#mD", c->x, c->y);
219 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
220 return buf[bn];
223 static int solder_layer, component_layer;
225 static void
226 dj_abort (char *msg, ...)
228 va_list a;
229 va_start (a, msg);
230 vprintf (msg, a);
231 va_end (a);
232 fflush (stdout);
233 abort ();
236 #if 1
237 #define check(c,l)
238 #else
239 #define check(c,l) check2(__LINE__,c,l)
240 static void
241 check2 (int srcline, corner_s * c, line_s * l)
243 int saw_c = 0, saw_l = 0;
244 corner_s *cc;
245 line_s *ll;
246 int i;
248 for (cc = corners; cc; cc = cc->next)
250 if (DELETED (cc))
251 continue;
252 if (cc == c)
253 saw_c = 1;
254 for (i = 0; i < cc->n_lines; i++)
255 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
256 dj_abort ("check:%d: cc has line without backref\n", srcline);
257 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
258 dj_abort ("check:%d: via not at corner\n", srcline);
259 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
260 dj_abort ("check:%d: pin not at corner\n", srcline);
262 if (c && !saw_c)
263 dj_abort ("check:%d: corner not in corners list\n", srcline);
264 for (ll = lines; ll; ll = ll->next)
266 if (DELETED (ll))
267 continue;
268 if (ll == l)
269 saw_l = 1;
270 for (i = 0; i < ll->s->n_lines; i++)
271 if (ll->s->lines[i] == ll)
272 break;
273 if (i == ll->s->n_lines)
274 dj_abort ("check:%d: ll->s has no backref\n", srcline);
275 for (i = 0; i < ll->e->n_lines; i++)
276 if (ll->e->lines[i] == ll)
277 break;
278 if (i == ll->e->n_lines)
279 dj_abort ("check:%d: ll->e has no backref\n", srcline);
280 if (!ll->is_pad
281 && (ll->s->x != ll->line->Point1.X
282 || ll->s->y != ll->line->Point1.Y
283 || ll->e->x != ll->line->Point2.X
284 || ll->e->y != ll->line->Point2.Y))
286 pcb_printf ("line: %#mD to %#mD pcbline: %#mD to %#mD\n",
287 ll->s->x, ll->s->y,
288 ll->e->x, ll->e->y,
289 ll->line->Point1.X,
290 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
291 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
294 if (l && !saw_l)
295 dj_abort ("check:%d: line not in lines list\n", srcline);
298 #endif
300 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
302 static int
303 gridsnap (Coord n)
305 if (n <= 0)
306 return 0;
307 return n - n % (Settings.Grid);
310 /* Avoid commonly used names. */
312 static int
313 djabs (int x)
315 return x > 0 ? x : -x;
318 static int
319 djmax (int x, int y)
321 return x > y ? x : y;
324 static int
325 djmin (int x, int y)
327 return x < y ? x : y;
331 * \brief Find distance between 2 points.
333 * We use floating point math here because we can fairly easily overflow
334 * a 32 bit integer here.
335 * In fact it only takes 0.46" to do so.
337 static int
338 dist (int x1, int y1, int x2, int y2)
340 double dx1, dy1, dx2, dy2, d;
342 dx1 = (double) x1;
343 dy1 = (double) y1;
344 dx2 = (double) x2;
345 dy2 = (double) y2;
347 d = sqrt ((dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2));
348 d = rint (d);
350 return (int) d;
353 static int
354 line_length (line_s * l)
356 if (l->s->x == l->e->x)
357 return djabs (l->s->y - l->e->y);
358 if (l->s->y == l->e->y)
359 return djabs (l->s->x - l->e->x);
360 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
363 static int
364 dist_ltp2 (int dx, int y, int y1, int y2)
366 if (y1 > y2)
367 SWAP (y1, y2);
368 if (y < y1)
369 return dist (dx, y, 0, y1);
370 if (y > y2)
371 return dist (dx, y, 0, y2);
372 return djabs (dx);
376 sqr (int a)
378 return a * a;
381 static int
382 intersecting_layers (int l1, int l2)
384 if (l1 == -1 || l2 == -1)
385 return 1;
386 if (l1 == l2)
387 return 1;
388 if (layer_groupings[l1] == layer_groupings[l2])
389 return 1;
390 return 0;
393 static int
394 dist_line_to_point (line_s * l, corner_s * c)
396 double len, r, d;
397 /* We can do this quickly if l is vertical or horizontal. */
398 if (l->s->x == l->e->x)
399 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
400 if (l->s->y == l->e->y)
401 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
403 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
404 len = sqrt (sqr (l->s->x - l->e->x) + sqr (l->s->y - l->e->y));
405 if (len == 0)
406 return dist (l->s->x, l->s->y, c->x, c->y);
408 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
409 l->e->x);
410 r /= len * len;
411 if (r < 0)
412 return dist (l->s->x, l->s->y, c->x, c->y);
413 if (r > 1)
414 return dist (l->e->x, l->e->y, c->x, c->y);
416 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
417 l->s->y);
418 return (int) (d / len);
421 static int
422 line_orient (line_s * l, corner_s * c)
424 int x1, y1, x2, y2;
425 if (c == l->s)
427 x1 = l->s->x;
428 y1 = l->s->y;
429 x2 = l->e->x;
430 y2 = l->e->y;
432 else
434 x1 = l->e->x;
435 y1 = l->e->y;
436 x2 = l->s->x;
437 y2 = l->s->y;
439 if (x1 == x2)
441 if (y1 < y2)
442 return DOWN;
443 return UP;
445 else if (y1 == y2)
447 if (x1 < x2)
448 return RIGHT;
449 return LEFT;
451 return DIAGONAL;
454 #if 0
455 /* Not used */
456 static corner_s *
457 common_corner (line_s * l1, line_s * l2)
459 if (l1->s == l2->s || l1->s == l2->e)
460 return l1->s;
461 if (l1->e == l2->s || l1->e == l2->e)
462 return l1->e;
463 dj_abort ("common_corner: no common corner found\n");
464 return NULL;
466 #endif
468 static corner_s *
469 other_corner (line_s * l, corner_s * c)
471 if (l->s == c)
472 return l->e;
473 if (l->e == c)
474 return l->s;
475 dj_abort ("other_corner: neither corner passed\n");
476 return NULL;
479 static corner_s *
480 find_corner_if (int x, int y, int l)
482 corner_s *c;
483 for (c = corners; c; c = c->next)
485 if (DELETED (c))
486 continue;
487 if (c->x != x || c->y != y)
488 continue;
489 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
490 continue;
491 return c;
493 return 0;
496 static corner_s *
497 find_corner (int x, int y, int l)
499 corner_s *c;
500 for (c = corners; c; c = c->next)
502 if (DELETED (c))
503 continue;
504 if (c->x != x || c->y != y)
505 continue;
506 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
507 continue;
508 return c;
510 c = (corner_s *) malloc (sizeof (corner_s));
511 c->next = corners;
512 corners = c;
513 c->x = x;
514 c->y = y;
515 c->net = 0;
516 c->via = 0;
517 c->pad = 0;
518 c->pin = 0;
519 c->layer = l;
520 c->n_lines = 0;
521 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
522 return c;
525 static void
526 add_line_to_corner (line_s * l, corner_s * c)
528 int n;
529 n = (c->n_lines + 1 + INC) & ~INC;
530 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
531 c->lines[c->n_lines] = l;
532 c->n_lines++;
533 dprintf ("add_line_to_corner %#mD\n", c->x, c->y);
536 static LineType *
537 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
538 int thick, int clear, FlagType flags)
540 char *from, *to;
541 LineType *nl;
542 LayerType *lyr = LAYER_PTR (layer);
544 from = (char *) lyr->Line;
545 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
546 x1, y1, x2, y2, thick, clear, flags);
547 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
549 to = (char *) lyr->Line;
550 if (from != to)
552 line_s *lp;
553 for (lp = lines; lp; lp = lp->next)
555 if (DELETED (lp))
556 continue;
557 if ((char *) (lp->line) >= from
558 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
559 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
562 return nl;
565 static void
566 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
568 line_s *ls;
570 if (layer >= max_copper_layer)
571 dj_abort ("layer %d\n", layer);
573 if (example == NULL)
574 dj_abort ("NULL example passed to new_line()\n", layer);
576 if (s->x == e->x && s->y == e->y)
577 return;
579 ls = (line_s *) malloc (sizeof (line_s));
580 ls->next = lines;
581 lines = ls;
582 ls->is_pad = 0;
583 ls->s = s;
584 ls->e = e;
585 ls->layer = layer;
586 #if 0
587 if ((example->Point1.X == s->x && example->Point1.Y == s->y
588 && example->Point2.X == e->x && example->Point2.Y == e->y)
589 || (example->Point2.X == s->x && example->Point2.Y == s->y
590 && example->Point1.X == e->x && example->Point1.Y == e->y))
592 ls->line = example;
594 else
595 #endif
597 LineType *nl;
598 dprintf
599 ("New line \033[35m%#mD to %#mD from l%d t%#mS c%#mS f%s\033[0m\n",
600 s->x, s->y, e->x, e->y, layer, example->Thickness,
601 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
602 nl =
603 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
604 example->Clearance, example->Flags);
606 if (!nl)
607 dj_abort ("can't create new line!");
608 ls->line = nl;
610 add_line_to_corner (ls, s);
611 add_line_to_corner (ls, e);
612 check (s, ls);
613 check (e, ls);
616 #if 0
617 /* Not used */
618 static int
619 c_orth_to (corner_s * c, line_s * l, int o)
621 int i, o2;
622 int rv = 0;
623 for (i = 0; i < c->n_lines; i++)
625 if (c->lines[i] == l)
626 continue;
627 o2 = line_orient (c->lines[i], c);
628 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
629 return 0;
630 rv++;
632 return rv;
634 #endif
636 static line_s *
637 other_line (corner_s * c, line_s * l)
639 int i;
640 line_s *rv = 0;
641 if (c->pin || c->pad || c->via)
642 return 0;
643 for (i = 0; i < c->n_lines; i++)
645 if (c->lines[i] == l)
646 continue;
647 if (rv)
648 return 0;
649 rv = c->lines[i];
651 return rv;
654 static void
655 empty_rect (rect_s * rect)
657 rect->x1 = rect->y1 = INT_MAX;
658 rect->x2 = rect->y2 = INT_MIN;
661 static void
662 add_point_to_rect (rect_s * rect, int x, int y, int w)
664 if (rect->x1 > x - w)
665 rect->x1 = x - w;
666 if (rect->x2 < x + w)
667 rect->x2 = x + w;
668 if (rect->y1 > y - w)
669 rect->y1 = y - w;
670 if (rect->y2 < y + w)
671 rect->y2 = y + w;
674 static void
675 add_line_to_rect (rect_s * rect, line_s * l)
677 add_point_to_rect (rect, l->s->x, l->s->y, 0);
678 add_point_to_rect (rect, l->e->x, l->e->y, 0);
681 static int
682 pin_in_rect (rect_s * r, int x, int y, int w)
684 if (x < r->x1 && x + w < r->x1)
685 return 0;
686 if (x > r->x2 && x - w > r->x2)
687 return 0;
688 if (y < r->y1 && y + w < r->y1)
689 return 0;
690 if (y > r->y2 && y - w > r->y2)
691 return 0;
692 return 1;
695 static int
696 line_in_rect (rect_s * r, line_s * l)
698 rect_s lr;
699 empty_rect (&lr);
700 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
701 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
702 dprintf ("line_in_rect %#mD-%#mD vs %#mD-%#mD\n",
703 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
704 /* simple intersection of rectangles */
705 if (lr.x1 < r->x1)
706 lr.x1 = r->x1;
707 if (lr.x2 > r->x2)
708 lr.x2 = r->x2;
709 if (lr.y1 < r->y1)
710 lr.y1 = r->y1;
711 if (lr.y2 > r->y2)
712 lr.y2 = r->y2;
713 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
714 return 1;
715 return 0;
718 static int
719 corner_radius (corner_s * c)
721 int diam = 0;
722 int i;
723 if (c->pin)
724 diam = djmax (c->pin->Thickness, diam);
725 if (c->via)
726 diam = djmax (c->via->Thickness, diam);
727 for (i = 0; i < c->n_lines; i++)
728 if (c->lines[i]->line)
729 diam = djmax (c->lines[i]->line->Thickness, diam);
730 diam = (diam + 1) / 2;
731 return diam;
734 #if 0
735 /* Not used */
736 static int
737 corner_layer (corner_s * c)
739 if (c->pin || c->via)
740 return -1;
741 if (c->n_lines < 1)
742 return -1;
743 return c->lines[0]->layer;
745 #endif
747 static void
748 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
750 int diam = corner_radius (c);
751 if (!pin_in_rect (e, c->x, c->y, diam))
752 return;
753 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
754 return;
755 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
756 return;
757 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
758 return;
759 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
760 return;
762 /*pcb_printf("add point %#mD diam %#mS\n", c->x, c->y, diam); */
763 add_point_to_rect (rect, c->x, c->y, diam);
766 static void
767 remove_line (line_s * l)
769 int i, j;
770 LayerType *layer = &(PCB->Data->Layer[l->layer]);
772 check (0, 0);
774 if (l->line)
775 RemoveLine (layer, l->line);
777 DELETE (l);
779 for (i = 0, j = 0; i < l->s->n_lines; i++)
780 if (l->s->lines[i] != l)
781 l->s->lines[j++] = l->s->lines[i];
782 l->s->n_lines = j;
784 for (i = 0, j = 0; i < l->e->n_lines; i++)
785 if (l->e->lines[i] != l)
786 l->e->lines[j++] = l->e->lines[i];
787 l->e->n_lines = j;
788 check (0, 0);
791 static void
792 move_line_to_layer (line_s * l, int layer)
794 LayerType *ls, *ld;
796 ls = LAYER_PTR (l->layer);
797 ld = LAYER_PTR (layer);
799 MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
800 l->layer = layer;
803 static void
804 remove_via_at (corner_s * c)
806 RemoveObject (VIA_TYPE, c->via, 0, 0);
807 c->via = 0;
810 static void
811 remove_corner (corner_s * c2)
813 corner_s *c;
814 dprintf ("remove corner %s\n", corner_name (c2));
815 if (corners == c2)
816 corners = c2->next;
817 for (c = corners; c; c = c->next)
819 if (DELETED (c))
820 continue;
821 if (c->next == c2)
822 c->next = c2->next;
824 if (next_corner == c2)
825 next_corner = c2->next;
826 free (c2->lines);
827 c2->lines = 0;
828 DELETE (c2);
831 static void
832 merge_corners (corner_s * c1, corner_s * c2)
834 int i;
835 if (c1 == c2)
836 abort ();
837 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
838 for (i = 0; i < c2->n_lines; i++)
840 add_line_to_corner (c2->lines[i], c1);
841 if (c2->lines[i]->s == c2)
842 c2->lines[i]->s = c1;
843 if (c2->lines[i]->e == c2)
844 c2->lines[i]->e = c1;
846 if (c1->via && c2->via)
847 remove_via_at (c2);
848 else if (c2->via)
849 c1->via = c2->via;
850 if (c2->pad)
851 c1->pad = c2->pad;
852 if (c2->pin)
853 c1->pin = c2->pin;
854 if (c2->layer != c1->layer)
855 c1->layer = -1;
857 remove_corner (c2);
860 static void
861 move_corner (corner_s * c, int x, int y)
863 PinType *via;
864 int i;
865 corner_s *pad;
867 check (c, 0);
868 if (c->pad || c->pin)
869 dj_abort ("move_corner: has pin or pad\n");
870 dprintf ("move_corner %p from %#mD to %#mD\n", (void *) c, c->x, c->y, x, y);
871 pad = find_corner_if (x, y, c->layer);
872 c->x = x;
873 c->y = y;
874 via = c->via;
875 if (via)
877 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
878 dprintf ("via move %#mD to %#mD\n", via->X, via->Y, x, y);
880 for (i = 0; i < c->n_lines; i++)
882 LineType *tl = c->lines[i]->line;
883 if (tl)
885 if (c->lines[i]->s == c)
887 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
888 &tl->Point1, x - (tl->Point1.X),
889 y - (tl->Point1.Y));
891 else
893 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
894 &tl->Point2, x - (tl->Point2.X),
895 y - (tl->Point2.Y));
897 dprintf ("Line %p moved to %#mD %#mD\n", (void *) tl,
898 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
901 if (pad && pad != c)
902 merge_corners (c, pad);
903 else
904 for (i = 0; i < c->n_lines; i++)
906 if (c->lines[i]->s->x == c->lines[i]->e->x
907 && c->lines[i]->s->y == c->lines[i]->e->y)
909 corner_s *c2 = other_corner (c->lines[i], c);
910 dprintf ("move_corner: removing line %#mD %#mD %p %p\n",
911 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
913 remove_line (c->lines[i]);
914 if (c != c2)
915 merge_corners (c, c2);
916 check (c, 0);
917 i--;
918 break;
921 gui->progress (0, 0, 0);
922 check (c, 0);
925 static int
926 any_line_selected ()
928 line_s *l;
929 for (l = lines; l; l = l->next)
931 if (DELETED (l))
932 continue;
933 if (l->line && selected (l->line))
934 return 1;
936 return 0;
939 static int
940 trim_step (int s, int l1, int l2)
942 dprintf ("trim %d %d %d\n", s, l1, l2);
943 if (s > l1)
944 s = l1;
945 if (s > l2)
946 s = l2;
947 if (s != l1 && s != l2)
948 s = gridsnap (s);
949 return s;
952 static int canonicalize_line (line_s * l);
954 static int
955 split_line (line_s * l, corner_s * c)
957 int i;
958 LineType *pcbline;
959 line_s *ls;
961 if (!intersecting_layers (l->layer, c->layer))
962 return 0;
963 if (l->is_pad)
964 return 0;
965 if (c->pad)
967 dprintf ("split on pad!\n");
968 if (l->s->pad == c->pad || l->e->pad == c->pad)
969 return 0;
970 dprintf ("splitting...\n");
973 check (c, l);
974 pcbline = create_pcb_line (l->layer,
975 c->x, c->y, l->e->x, l->e->y,
976 l->line->Thickness, l->line->Clearance,
977 l->line->Flags);
978 if (pcbline == 0)
979 return 0; /* already a line there */
981 check (c, l);
983 dprintf ("split line from %#mD to %#mD at %#mD\n",
984 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
985 ls = (line_s *) malloc (sizeof (line_s));
987 ls->next = lines;
988 lines = ls;
989 ls->is_pad = 0;
990 ls->s = c;
991 ls->e = l->e;
992 ls->line = pcbline;
993 ls->layer = l->layer;
994 for (i = 0; i < l->e->n_lines; i++)
995 if (l->e->lines[i] == l)
996 l->e->lines[i] = ls;
997 l->e = c;
998 add_line_to_corner (l, c);
999 add_line_to_corner (ls, c);
1001 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
1002 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
1004 return 1;
1007 static int
1008 canonicalize_line (line_s * l)
1010 /* This could be faster */
1011 corner_s *c;
1012 if (l->s->x == l->e->x)
1014 int y1 = l->s->y;
1015 int y2 = l->e->y;
1016 int x1 = l->s->x - l->line->Thickness / 2;
1017 int x2 = l->s->x + l->line->Thickness / 2;
1018 if (y1 > y2)
1020 int t = y1;
1021 y1 = y2;
1022 y2 = t;
1024 for (c = corners; c; c = c->next)
1026 if (DELETED (c))
1027 continue;
1028 if ((y1 < c->y && c->y < y2)
1029 && intersecting_layers (l->layer, c->layer))
1031 if (c->x != l->s->x
1032 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1034 move_corner (c, l->s->x, c->y);
1036 if (c->x == l->s->x)
1038 /* FIXME: if the line is split, we have to re-canonicalize
1039 both segments. */
1040 return split_line (l, c);
1045 else if (l->s->y == l->e->y)
1047 int x1 = l->s->x;
1048 int x2 = l->e->x;
1049 int y1 = l->s->y - l->line->Thickness / 2;
1050 int y2 = l->s->y + l->line->Thickness / 2;
1051 if (x1 > x2)
1053 int t = x1;
1054 x1 = x2;
1055 x2 = t;
1057 for (c = corners; c; c = c->next)
1059 if (DELETED (c))
1060 continue;
1061 if ((x1 < c->x && c->x < x2)
1062 && intersecting_layers (l->layer, c->layer))
1064 if (c->y != l->s->y
1065 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1067 move_corner (c, c->x, l->s->y);
1069 if (c->y == l->s->y)
1071 /* FIXME: Likewise. */
1072 return split_line (l, c);
1077 else
1079 /* diagonal lines. Let's try to split them at pins/vias
1080 anyway. */
1081 int x1 = l->s->x;
1082 int x2 = l->e->x;
1083 int y1 = l->s->y;
1084 int y2 = l->e->y;
1085 if (x1 > x2)
1087 int t = x1;
1088 x1 = x2;
1089 x2 = t;
1091 if (y1 > y2)
1093 int t = y1;
1094 y1 = y2;
1095 y2 = t;
1097 for (c = corners; c; c = c->next)
1099 if (DELETED (c))
1100 continue;
1101 if (!c->via && !c->pin)
1102 continue;
1103 if ((x1 < c->x && c->x < x2)
1104 && (y1 < c->y && c->y < y2)
1105 && intersecting_layers (l->layer, c->layer))
1107 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1108 th /= 2;
1109 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1110 && dist (l->e->x, l->e->y, c->x, c->y) > th
1111 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1113 return split_line (l, c);
1118 return 0;
1122 * \brief Make sure all vias are at line end points.
1124 static int
1125 canonicalize_lines ()
1127 int changes = 0;
1128 int count;
1129 line_s *l;
1130 while (1)
1132 count = 0;
1133 for (l = lines; l; l = l->next)
1135 if (DELETED (l))
1136 continue;
1137 count += canonicalize_line (l);
1139 changes += count;
1140 if (count == 0)
1141 break;
1143 return changes;
1146 static int
1147 simple_optimize_corner (corner_s * c)
1149 int i;
1150 int rv = 0;
1152 check (c, 0);
1153 if (c->via)
1155 /* see if no via is needed */
1156 if (selected (c->via))
1157 dprintf ("via check: line[0] layer %d at %#mD nl %d\n",
1158 c->lines[0]->layer, c->x, c->y, c->n_lines);
1159 /* We can't delete vias that connect to power planes, or vias
1160 that aren't tented (assume they're test points). */
1161 if (!TEST_ANY_THERMS (c->via)
1162 && c->via->Mask == 0)
1164 for (i = 1; i < c->n_lines; i++)
1166 if (selected (c->via))
1167 dprintf (" line[%d] layer %d %#mD to %#mD\n",
1168 i, c->lines[i]->layer,
1169 c->lines[i]->s->x, c->lines[i]->s->y,
1170 c->lines[i]->e->x, c->lines[i]->e->y);
1171 if (c->lines[i]->layer != c->lines[0]->layer)
1172 break;
1174 if (i == c->n_lines)
1176 if (selected (c->via))
1177 dprintf (" remove it\n");
1178 remove_via_at (c);
1179 rv++;
1184 check (c, 0);
1185 if (c->n_lines == 2 && !c->via)
1187 /* see if it is an unneeded corner */
1188 int o = line_orient (c->lines[0], c);
1189 corner_s *c2 = other_corner (c->lines[1], c);
1190 corner_s *c0 = other_corner (c->lines[0], c);
1191 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1193 dprintf ("straight %#mD to %#mD to %#mD\n",
1194 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1195 if (selected (c->lines[0]->line))
1196 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1197 if (selected (c->lines[1]->line))
1198 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1199 move_corner (c, c2->x, c2->y);
1202 check (c, 0);
1203 if (c->n_lines == 1 && !c->via)
1205 corner_s *c0 = other_corner (c->lines[0], c);
1206 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE)
1209 * Remove this line, as it is a "freckle". A freckle is an extremely
1210 * short line (around 0.01 thou) that is unconnected at one end.
1211 * Freckles are almost insignificantly small, but are annoying as
1212 * they prevent the mitering optimiser from working.
1213 * Freckles sometimes arise because of a bug in the autorouter that
1214 * causes it to create small overshoots (typically 0.01 thou) at the
1215 * intersections of vertical and horizontal lines. These overshoots
1216 * are converted to freckles as a side effect of canonicalize_line().
1217 * Note that canonicalize_line() is not at fault, the bug is in the
1218 * autorouter creating overshoots.
1219 * The autorouter bug arose some time between the 20080202 and 20091103
1220 * releases.
1221 * This code is probably worth keeping even when the autorouter bug is
1222 * fixed, as "freckles" could conceivably arise in other ways.
1224 dprintf ("freckle %#mD to %#mD\n", c->x, c->y, c0->x, c0->y);
1225 move_corner (c, c0->x, c0->y);
1228 check (c, 0);
1229 return rv;
1232 /* We always run these */
1233 static int
1234 simple_optimizations ()
1236 corner_s *c;
1237 int rv = 0;
1239 /* Look for corners that aren't */
1240 for (c = corners; c; c = c->next)
1242 if (DELETED (c))
1243 continue;
1244 if (c->pad || c->pin)
1245 continue;
1246 rv += simple_optimize_corner (c);
1248 return rv;
1251 static int
1252 is_hole (corner_s * c)
1254 return c->pin || c->pad || c->via;
1257 static int
1258 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1260 static corner_s **cs = 0;
1261 static int cm = 0;
1262 static line_s **ls = 0;
1263 static int lm = 0;
1264 int i, li, ln, cn, snap;
1265 line_s *l = 0;
1266 corner_s *c2, *cb;
1267 int adir = 0, sdir = 0, pull;
1268 int saw_sel = 0, saw_auto = 0;
1269 int max, len = 0, r1 = 0, r2;
1270 rect_s rr;
1271 int edir = 0, done;
1273 if (cs == 0)
1275 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1276 cm = 10;
1277 ls = (line_s **) malloc (10 * sizeof (line_s));
1278 lm = 10;
1281 for (i = 0; i < c->n_lines; i++)
1283 int o = line_orient (c->lines[i], c);
1284 if (o == rdir)
1285 return 0;
1288 switch (fdir)
1290 case RIGHT:
1291 adir = DOWN;
1292 sdir = UP;
1293 break;
1294 case DOWN:
1295 adir = RIGHT;
1296 sdir = LEFT;
1297 break;
1298 default:
1299 dj_abort ("fdir not right or down\n");
1302 c2 = c;
1303 cn = 0;
1304 ln = 0;
1305 pull = 0;
1306 while (c2)
1308 if (c2->pad || c2->pin || c2->n_lines < 2)
1309 return 0;
1310 if (cn >= cm)
1312 cm = cn + 10;
1313 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s *));
1315 cs[cn++] = c2;
1316 r2 = corner_radius (c2);
1317 if (r1 < r2)
1318 r1 = r2;
1319 l = 0;
1320 for (i = 0; i < c2->n_lines; i++)
1322 int o = line_orient (c2->lines[i], c2);
1323 if (o == DIAGONAL)
1324 return 0;
1325 if (o == fdir)
1327 if (l)
1328 return 0; /* we don't support overlapping lines yet */
1329 l = c2->lines[i];
1331 if (o == rdir && c2->lines[i] != ls[ln - 1])
1332 return 0; /* likewise */
1333 if (o == adir)
1334 pull++;
1335 if (o == sdir)
1336 pull--;
1338 if (!l)
1339 break;
1340 if (selected (l->line))
1341 saw_sel = 1;
1342 if (autorouted (l->line))
1343 saw_auto = 1;
1344 if (ln >= lm)
1346 lm = ln + 10;
1347 ls = (line_s **) realloc (ls, lm * sizeof (line_s *));
1349 ls[ln++] = l;
1350 c2 = other_corner (l, c2);
1352 if (cn < 2 || pull == 0)
1353 return 0;
1354 if (any_sel && !saw_sel)
1355 return 0;
1356 if (!any_sel && autorouted_only && !saw_auto)
1357 return 0;
1359 /* Ok, now look for other blockages. */
1361 empty_rect (&rr);
1362 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1363 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1365 if (fdir == RIGHT && pull < 0)
1366 edir = UP;
1367 else if (fdir == RIGHT && pull > 0)
1368 edir = DOWN;
1369 else if (fdir == DOWN && pull < 0)
1370 edir = LEFT;
1371 else if (fdir == DOWN && pull > 0)
1372 edir = RIGHT;
1374 max = -1;
1375 for (i = 0; i < cn; i++)
1376 for (li = 0; li < cs[i]->n_lines; li++)
1378 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1379 continue;
1380 len = line_length (cs[i]->lines[li]);
1381 if (max > len || max == -1)
1382 max = len;
1384 dprintf ("c %s %4#mD cn %d pull %3d max %4#mS\n",
1385 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1387 switch (edir)
1389 case UP:
1390 rr.y1 = c->y - r1 - max;
1391 break;
1392 case DOWN:
1393 rr.y2 = c->y + r1 + max;
1394 break;
1395 case LEFT:
1396 rr.x1 = c->x - r1 - max;
1397 break;
1398 case RIGHT:
1399 rr.x2 = c->x + r1 + max;
1400 break;
1402 rr.x1 -= SB + 1;
1403 rr.x2 += SB + 1;
1404 rr.y1 -= SB + 1;
1405 rr.y2 += SB + 1;
1407 snap = 0;
1408 for (cb = corners; cb; cb = cb->next)
1410 int sep;
1411 if (DELETED (cb))
1412 continue;
1413 r1 = corner_radius (cb);
1414 if (cb->net == c->net && !cb->pad)
1415 continue;
1416 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1417 continue;
1418 switch (edir)
1420 #define ECHK(X,Y,LT) \
1421 for (i=0; i<cn; i++) \
1423 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1424 continue; \
1425 r2 = corner_radius(cs[i]); \
1426 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1427 continue; \
1428 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1429 continue; \
1430 if (cb->Y LT cs[i]->Y) \
1431 continue; \
1432 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1433 if (max > sep) \
1434 { max = sep; snap = 1; }\
1436 for (i=0; i<ln; i++) \
1438 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1439 continue; \
1440 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1441 continue; \
1442 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1443 - r1 - SB - 1); \
1444 if (max > sep) \
1445 { max = sep; snap = 1; }\
1447 case UP:
1448 ECHK (x, y, >=);
1449 break;
1450 case DOWN:
1451 ECHK (x, y, <=);
1452 break;
1453 case LEFT:
1454 ECHK (y, x, >=);
1455 break;
1456 case RIGHT:
1457 ECHK (y, x, <=);
1458 break;
1462 /* We must now check every line segment against our corners. */
1463 for (l = lines; l; l = l->next)
1465 int o, x1, x2, y1, y2;
1466 if (DELETED (l))
1467 continue;
1468 dprintf ("check line %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1469 if (l->s->net == c->net)
1471 dprintf (" same net\n");
1472 continue;
1474 o = line_orient (l, 0);
1475 /* We don't need to check perpendicular lines, because their
1476 corners already take care of it. */
1477 if ((fdir == RIGHT && (o == UP || o == DOWN))
1478 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1480 dprintf (" perpendicular\n");
1481 continue;
1484 /* Choose so that x1,y1 is closest to corner C */
1485 if ((fdir == RIGHT && l->s->x < l->e->x)
1486 || (fdir == DOWN && l->s->y < l->e->y))
1488 x1 = l->s->x;
1489 y1 = l->s->y;
1490 x2 = l->e->x;
1491 y2 = l->e->y;
1493 else
1495 x1 = l->e->x;
1496 y1 = l->e->y;
1497 x2 = l->s->x;
1498 y2 = l->s->y;
1501 /* Eliminate all lines outside our range */
1502 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1503 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1505 dprintf (" outside our range\n");
1506 continue;
1509 /* Eliminate all lines on the wrong side of us */
1510 if ((edir == UP && y1 > c->y && y2 > c->y)
1511 || (edir == DOWN && y1 < c->y && y2 < c->y)
1512 || (edir == LEFT && x1 > c->x && x2 > c->x)
1513 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1515 dprintf (" wrong side\n");
1516 continue;
1519 /* For now, cheat on diagonals */
1520 switch (edir)
1522 case RIGHT:
1523 if (x1 > x2)
1524 x1 = x2;
1525 break;
1526 case LEFT:
1527 if (x1 < x2)
1528 x1 = x2;
1529 break;
1530 case DOWN:
1531 if (y1 > y2)
1532 y1 = y2;
1533 break;
1534 case UP:
1535 if (y1 < y2)
1536 y1 = y2;
1537 break;
1540 /* Ok, now see how far we can get for each of our corners. */
1541 for (i = 0; i < cn; i++)
1543 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1544 int len = 0;
1545 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1546 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1547 continue;
1548 if (!intersecting_layers (cs[i]->layer, l->layer))
1549 continue;
1550 switch (edir)
1552 case RIGHT:
1553 len = x1 - c->x;
1554 break;
1555 case LEFT:
1556 len = c->x - x1;
1557 break;
1558 case DOWN:
1559 len = y1 - c->y;
1560 break;
1561 case UP:
1562 len = c->y - y1;
1563 break;
1565 len -= r;
1566 dprintf (" len is %#mS vs corner at %#mD\n", len, cs[i]->x, cs[i]->y);
1567 if (len <= 0)
1568 return 0;
1569 if (max > len)
1570 max = len;
1575 /* We must make sure that if a segment isn't being completely
1576 removed, that any vias and/or pads don't overlap. */
1577 done = 0;
1578 while (!done)
1580 done = 1;
1581 for (i = 0; i < cn; i++)
1582 for (li = 0; li < cs[i]->n_lines; li++)
1584 line_s *l = cs[i]->lines[li];
1585 corner_s *oc = other_corner (l, cs[i]);
1586 if (line_orient (l, cs[i]) != edir)
1587 continue;
1588 len = line_length (l);
1589 if (!oc->pad || !cs[i]->via)
1591 if (!is_hole (l->s) || !is_hole (l->e))
1592 continue;
1593 if (len == max)
1594 continue;
1596 len -= corner_radius (l->s);
1597 len -= corner_radius (l->e);
1598 len -= SB + 1;
1599 if (max > len)
1601 max = len;
1602 done = 0;
1607 if (max <= 0)
1608 return 0;
1609 switch (edir)
1611 case UP:
1612 len = c->y - max;
1613 break;
1614 case DOWN:
1615 len = c->y + max;
1616 break;
1617 case LEFT:
1618 len = c->x - max;
1619 break;
1620 case RIGHT:
1621 len = c->x + max;
1622 break;
1624 if (snap && max > Settings.Grid)
1626 if (pull < 0)
1627 len += Settings.Grid - 1;
1628 len = gridsnap (len);
1630 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1631 return 0;
1632 for (i = 0; i < cn; i++)
1634 if (fdir == RIGHT)
1636 max = len - cs[i]->y;
1637 move_corner (cs[i], cs[i]->x, len);
1639 else
1641 max = len - cs[i]->x;
1642 move_corner (cs[i], len, cs[i]->y);
1645 return max * pull;
1649 * \brief Look for straight runs which could be moved to reduce total
1650 * trace length.
1652 static int
1653 orthopull ()
1655 int any_sel = any_line_selected ();
1656 corner_s *c;
1657 int rv = 0;
1659 for (c = corners; c;)
1661 if (DELETED (c))
1662 continue;
1663 if (c->pin || c->pad)
1665 c = c->next;
1666 continue;
1668 next_corner = c;
1669 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1670 if (c != next_corner)
1672 c = next_corner;
1673 continue;
1675 rv += orthopull_1 (c, DOWN, UP, any_sel);
1676 if (c != next_corner)
1678 c = next_corner;
1679 continue;
1681 c = c->next;
1683 if (rv)
1684 pcb_printf ("orthopull: %ml mils saved\n", rv);
1685 return rv;
1689 * \brief Look for "U" shaped traces we can shorten (or eliminate).
1691 static int
1692 debumpify ()
1694 int rv = 0;
1695 int any_selected = any_line_selected ();
1696 line_s *l, *l1, *l2;
1697 corner_s *c, *c1, *c2;
1698 rect_s rr, rp;
1699 int o, o1, o2, step, w;
1700 for (l = lines; l; l = l->next)
1702 if (DELETED (l))
1703 continue;
1704 if (!l->line)
1705 continue;
1706 if (any_selected && !selected (l->line))
1707 continue;
1708 if (!any_selected && autorouted_only && !autorouted (l->line))
1709 continue;
1710 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1711 continue;
1712 o = line_orient (l, 0);
1713 if (o == DIAGONAL)
1714 continue;
1715 l1 = other_line (l->s, l);
1716 if (!l1)
1717 continue;
1718 o1 = line_orient (l1, l->s);
1719 l2 = other_line (l->e, l);
1720 if (!l2)
1721 continue;
1722 o2 = line_orient (l2, l->e);
1723 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1724 continue;
1726 dprintf ("\nline: %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1727 w = l->line->Thickness / 2 + SB + 1;
1728 empty_rect (&rr);
1729 add_line_to_rect (&rr, l1);
1730 add_line_to_rect (&rr, l2);
1731 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1732 rr.x1 -= w;
1733 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1734 rr.x2 += w;
1735 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1736 rr.y1 -= w;
1737 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1738 rr.y2 += w;
1739 dprintf ("range: x %#mS..%#mS y %#mS..%#mS\n", rr.x1, rr.x2, rr.y1, rr.y2);
1741 c1 = other_corner (l1, l->s);
1742 c2 = other_corner (l2, l->e);
1744 empty_rect (&rp);
1745 for (c = corners; c; c = c->next)
1747 if (DELETED (c))
1748 continue;
1749 if (c->net != l->s->net
1750 && intersecting_layers (c->layer, l->s->layer))
1751 add_corner_to_rect_if (&rp, c, &rr);
1753 if (rp.x1 == INT_MAX)
1755 rp.x1 = rr.x2;
1756 rp.x2 = rr.x1;
1757 rp.y1 = rr.y2;
1758 rp.y2 = rr.y1;
1760 dprintf ("pin r: x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1762 switch (o1)
1764 case LEFT:
1765 step = l->s->x - rp.x2 - w;
1766 step = gridsnap (step);
1767 if (step > l->s->x - c1->x)
1768 step = l->s->x - c1->x;
1769 if (step > l->s->x - c2->x)
1770 step = l->s->x - c2->x;
1771 if (step > 0)
1773 dprintf ("left step %#mS at %#mD\n", step, l->s->x, l->s->y);
1774 move_corner (l->s, l->s->x - step, l->s->y);
1775 move_corner (l->e, l->e->x - step, l->e->y);
1776 rv += step;
1778 break;
1779 case RIGHT:
1780 step = rp.x1 - l->s->x - w;
1781 step = gridsnap (step);
1782 if (step > c1->x - l->s->x)
1783 step = c1->x - l->s->x;
1784 if (step > c2->x - l->s->x)
1785 step = c2->x - l->s->x;
1786 if (step > 0)
1788 dprintf ("right step %#mS at %#mD\n", step, l->s->x, l->s->y);
1789 move_corner (l->s, l->s->x + step, l->s->y);
1790 move_corner (l->e, l->e->x + step, l->e->y);
1791 rv += step;
1793 break;
1794 case UP:
1795 if (rp.y2 == INT_MIN)
1796 rp.y2 = rr.y1;
1797 step = trim_step (l->s->y - rp.y2 - w,
1798 l->s->y - c1->y, l->s->y - c2->y);
1799 if (step > 0)
1801 dprintf ("up step %#mS at %#mD\n", step, l->s->x, l->s->y);
1802 move_corner (l->s, l->s->x, l->s->y - step);
1803 move_corner (l->e, l->e->x, l->e->y - step);
1804 rv += step;
1806 break;
1807 case DOWN:
1808 step = rp.y1 - l->s->y - w;
1809 step = gridsnap (step);
1810 if (step > c1->y - l->s->y)
1811 step = c1->y - l->s->y;
1812 if (step > c2->y - l->s->y)
1813 step = c2->y - l->s->y;
1814 if (step > 0)
1816 dprintf ("down step %#mS at %#mD\n", step, l->s->x, l->s->y);
1817 move_corner (l->s, l->s->x, l->s->y + step);
1818 move_corner (l->e, l->e->x, l->e->y + step);
1819 rv += step;
1821 break;
1823 check (0, l);
1826 rv += simple_optimizations ();
1827 if (rv)
1828 pcb_printf ("debumpify: %ml mils saved\n", rv / 50);
1829 return rv;
1832 static int
1833 simple_corner (corner_s * c)
1835 int o1, o2;
1836 if (c->pad || c->pin || c->via)
1837 return 0;
1838 if (c->n_lines != 2)
1839 return 0;
1840 o1 = line_orient (c->lines[0], c);
1841 o2 = line_orient (c->lines[1], c);
1842 if (ORIENT (o1) == ORIENT (o2))
1843 return 0;
1844 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1845 return 0;
1846 return 1;
1850 * \brief Look for sequences of simple corners we can reduce.
1852 static int
1853 unjaggy_once ()
1855 int rv = 0;
1856 corner_s *c, *c0, *c1, *cc;
1857 int l, w, sel = any_line_selected ();
1858 int o0, o1, s0, s1;
1859 rect_s rr, rp;
1860 for (c = corners; c; c = c->next)
1862 if (DELETED (c))
1863 continue;
1864 if (!simple_corner (c))
1865 continue;
1866 if (!c->lines[0]->line || !c->lines[1]->line)
1867 continue;
1868 if (sel && !(selected (c->lines[0]->line)
1869 || selected (c->lines[1]->line)))
1870 continue;
1871 if (!sel && autorouted_only
1872 && !(autorouted (c->lines[0]->line)
1873 || autorouted (c->lines[1]->line)))
1874 continue;
1875 dprintf ("simple at %#mD\n", c->x, c->y);
1877 c0 = other_corner (c->lines[0], c);
1878 o0 = line_orient (c->lines[0], c);
1879 s0 = simple_corner (c0);
1881 c1 = other_corner (c->lines[1], c);
1882 o1 = line_orient (c->lines[1], c);
1883 s1 = simple_corner (c1);
1885 if (!s0 && !s1)
1886 continue;
1887 dprintf ("simples at %#mD\n", c->x, c->y);
1889 w = 1;
1890 for (l = 0; l < c0->n_lines; l++)
1891 if (c0->lines[l] != c->lines[0]
1892 && c0->lines[l]->layer == c->lines[0]->layer)
1894 int o = line_orient (c0->lines[l], c0);
1895 if (o == o1)
1896 w = 0;
1898 for (l = 0; l < c1->n_lines; l++)
1899 if (c1->lines[l] != c->lines[0]
1900 && c1->lines[l]->layer == c->lines[0]->layer)
1902 int o = line_orient (c1->lines[l], c1);
1903 if (o == o0)
1904 w = 0;
1906 if (!w)
1907 continue;
1908 dprintf ("orient ok\n");
1910 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1911 empty_rect (&rr);
1912 add_line_to_rect (&rr, c->lines[0]);
1913 add_line_to_rect (&rr, c->lines[1]);
1914 if (c->x != rr.x1)
1915 rr.x1 -= w;
1916 else
1917 rr.x2 += w;
1918 if (c->y != rr.y1)
1919 rr.y1 -= w;
1920 else
1921 rr.y2 += w;
1923 empty_rect (&rp);
1924 for (cc = corners; cc; cc = cc->next)
1926 if (DELETED (cc))
1927 continue;
1928 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1929 add_corner_to_rect_if (&rp, cc, &rr);
1931 dprintf ("rp x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1932 if (rp.x1 <= rp.x2) /* something triggered */
1933 continue;
1935 dprintf ("unjaggy at %#mD layer %d\n", c->x, c->y, c->layer);
1936 if (c->x == c0->x)
1937 move_corner (c, c1->x, c0->y);
1938 else
1939 move_corner (c, c0->x, c1->y);
1940 rv++;
1941 check (c, 0);
1943 rv += simple_optimizations ();
1944 check (c, 0);
1945 return rv;
1948 static int
1949 unjaggy ()
1951 int i, r = 0, j;
1952 for (i = 0; i < 100; i++)
1954 j = unjaggy_once ();
1955 if (j == 0)
1956 break;
1957 r += j;
1959 if (r)
1960 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1961 return r;
1965 * \brief Look for vias with all lines leaving the same way, try to
1966 * nudge via to eliminate one or more of them.
1968 static int
1969 vianudge ()
1971 int rv = 0;
1972 corner_s *c, *c2, *c3;
1973 line_s *l;
1974 unsigned char directions[MAX_LAYER];
1975 unsigned char counts[MAX_LAYER];
1977 memset (directions, 0, sizeof (directions));
1978 memset (counts, 0, sizeof (counts));
1980 for (c = corners; c; c = c->next)
1982 int o, i, vr, cr, oboth;
1983 int len = 0, saved = 0;
1985 if (DELETED (c))
1986 continue;
1988 if (!c->via)
1989 continue;
1991 memset (directions, 0, sizeof (directions));
1992 memset (counts, 0, sizeof (counts));
1994 for (i = 0; i < c->n_lines; i++)
1996 o = line_orient (c->lines[i], c);
1997 counts[c->lines[i]->layer]++;
1998 directions[c->lines[i]->layer] |= o;
2000 for (o = 0, i = 0; i < max_copper_layer; i++)
2001 if (counts[i] == 1)
2003 o = directions[i];
2004 break;
2006 switch (o)
2008 case LEFT:
2009 case RIGHT:
2010 oboth = LEFT | RIGHT;
2011 break;
2012 case UP:
2013 case DOWN:
2014 oboth = UP | DOWN;
2015 break;
2016 default:
2017 continue;
2019 for (i = 0; i < max_copper_layer; i++)
2020 if (counts[i] && directions[i] != o && directions[i] != oboth)
2021 goto vianudge_continue;
2023 c2 = 0;
2024 for (i = 0; i < c->n_lines; i++)
2026 int ll = line_length (c->lines[i]);
2027 if (line_orient (c->lines[i], c) != o)
2029 saved--;
2030 continue;
2032 saved++;
2033 if (c2 == 0 || len > ll)
2035 len = ll;
2036 c2 = other_corner (c->lines[i], c);
2039 if (c2->pad || c2->pin || c2->via)
2040 continue;
2042 /* Now look for clearance in the new position */
2043 vr = c->via->Thickness / 2 + SB + 1;
2044 for (c3 = corners; c3; c3 = c3->next)
2046 if (DELETED (c3))
2047 continue;
2048 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2050 cr = corner_radius (c3);
2051 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2052 goto vianudge_continue;
2055 for (l = lines; l; l = l->next)
2057 if (DELETED (l))
2058 continue;
2059 if (l->s->net != c->net)
2061 int ld = dist_line_to_point (l, c2);
2062 if (ld < l->line->Thickness / 2 + vr)
2063 goto vianudge_continue;
2067 /* at this point, we know we can move it */
2069 dprintf ("vianudge: nudging via at %#mD by %#mS saving %#mS\n",
2070 c->x, c->y, len, saved);
2071 rv += len * saved;
2072 move_corner (c, c2->x, c2->y);
2074 check (c, 0);
2076 vianudge_continue:
2077 continue;
2080 if (rv)
2081 pcb_printf ("vianudge: %ml mils saved\n", rv);
2082 return rv;
2086 * \brief Look for traces that can be moved to the other side of the
2087 * board, to reduce the number of vias needed.
2089 * For now, we look for simple lines, not multi-segmented lines.
2091 static int
2092 viatrim ()
2094 line_s *l, *l2;
2095 int i, rv = 0, vrm = 0;
2096 int any_sel = any_line_selected ();
2098 for (l = lines; l; l = l->next)
2100 rect_s r;
2101 int my_layer, other_layer;
2103 if (DELETED (l))
2104 continue;
2105 if (!l->s->via)
2106 continue;
2107 if (!l->e->via)
2108 continue;
2109 if (any_sel && !selected (l->line))
2110 continue;
2111 if (!any_sel && autorouted_only && !autorouted (l->line))
2112 continue;
2114 my_layer = l->layer;
2115 other_layer = -1;
2116 dprintf ("line %p on layer %d from %#mD to %#mD\n", (void *) l,
2117 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2118 for (i = 0; i < l->s->n_lines; i++)
2119 if (l->s->lines[i] != l)
2121 if (other_layer == -1)
2123 other_layer = l->s->lines[i]->layer;
2124 dprintf ("noting other line %p on layer %d\n",
2125 (void *) (l->s->lines[i]), my_layer);
2127 else if (l->s->lines[i]->layer != other_layer)
2129 dprintf ("saw other line %p on layer %d (not %d)\n",
2130 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2131 my_layer);
2132 other_layer = -1;
2133 goto viatrim_other_corner;
2136 viatrim_other_corner:
2137 if (other_layer == -1)
2138 for (i = 0; i < l->e->n_lines; i++)
2139 if (l->e->lines[i] != l)
2141 if (other_layer == -1)
2143 other_layer = l->s->lines[i]->layer;
2144 dprintf ("noting other line %p on layer %d\n",
2145 (void *) (l->s->lines[i]), my_layer);
2147 else if (l->e->lines[i]->layer != other_layer)
2149 dprintf ("saw end line on layer %d (not %d)\n",
2150 l->e->lines[i]->layer, other_layer);
2151 goto viatrim_continue;
2155 /* Now see if any other line intersects us. We don't need to
2156 check corners, because they'd either be pins/vias and
2157 already conflict, or pads, which we'll check here anyway. */
2158 empty_rect (&r);
2159 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2160 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2162 for (l2 = lines; l2; l2 = l2->next)
2164 if (DELETED (l2))
2165 continue;
2166 if (l2->s->net != l->s->net && l2->layer == other_layer)
2168 dprintf ("checking other line %#mD to %#mD\n", l2->s->x,
2169 l2->s->y, l2->e->x, l2->e->y);
2170 if (line_in_rect (&r, l2))
2172 dprintf ("line from %#mD to %#mD in the way\n",
2173 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2174 goto viatrim_continue;
2179 if (l->layer == other_layer)
2180 continue;
2181 move_line_to_layer (l, other_layer);
2182 rv++;
2184 viatrim_continue:
2185 continue;
2187 vrm = simple_optimizations ();
2188 if (rv > 0)
2189 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2190 return rv + vrm;
2193 static int
2194 automagic ()
2196 int more = 1, oldmore = 0;
2197 int toomany = 100;
2198 while (more != oldmore && --toomany)
2200 oldmore = more;
2201 more += debumpify ();
2202 more += unjaggy ();
2203 more += orthopull ();
2204 more += vianudge ();
2205 more += viatrim ();
2207 return more - 1;
2210 static int
2211 miter ()
2213 corner_s *c;
2214 int done, progress;
2215 int sel = any_line_selected ();
2216 int saved = 0;
2218 for (c = corners; c; c = c->next)
2220 if (DELETED (c))
2221 continue;
2222 c->miter = 0;
2223 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2225 int o1 = line_orient (c->lines[0], c);
2226 int o2 = line_orient (c->lines[1], c);
2227 if (ORIENT (o1) != ORIENT (o2)
2228 && o1 != DIAGONAL && o2 != DIAGONAL
2229 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2230 c->miter = -1;
2234 done = 0;
2235 progress = 1;
2236 while (!done && progress)
2238 done = 1;
2239 progress = 0;
2240 for (c = corners; c; c = c->next)
2242 if (DELETED (c))
2243 continue;
2244 if (c->miter == -1)
2246 int max = line_length (c->lines[0]);
2247 int len = line_length (c->lines[1]);
2248 int bloat;
2249 int ref, dist;
2250 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2251 int mx = 0, my = 0, x, y;
2252 int o1 = line_orient (c->lines[0], c);
2253 int o2 = line_orient (c->lines[1], c);
2255 if (c->pad || c->pin || c->via)
2257 c->miter = 0;
2258 progress = 1;
2259 continue;
2262 oc1 = other_corner (c->lines[0], c);
2263 oc2 = other_corner (c->lines[1], c);
2264 #if 0
2265 if (oc1->pad)
2266 oc1 = 0;
2267 if (oc2->pad)
2268 oc2 = 0;
2269 #endif
2271 if ((sel && !(selected (c->lines[0]->line)
2272 || selected (c->lines[1]->line)))
2273 || (!sel && autorouted_only
2274 && !(autorouted (c->lines[0]->line)
2275 || autorouted (c->lines[1]->line))))
2277 c->miter = 0;
2278 progress = 1;
2279 continue;
2282 if (max > len)
2283 max = len;
2284 switch (o1)
2286 case LEFT:
2287 mx = -1;
2288 break;
2289 case RIGHT:
2290 mx = 1;
2291 break;
2292 case UP:
2293 my = -1;
2294 break;
2295 case DOWN:
2296 my = 1;
2297 break;
2299 switch (o2)
2301 case LEFT:
2302 mx = -1;
2303 break;
2304 case RIGHT:
2305 mx = 1;
2306 break;
2307 case UP:
2308 my = -1;
2309 break;
2310 case DOWN:
2311 my = 1;
2312 break;
2314 ref = c->x * mx + c->y * my;
2315 dist = max;
2317 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2319 for (c2 = corners; c2; c2 = c2->next)
2321 if (DELETED (c2))
2322 continue;
2323 if (c2 != c && c2 != oc1 && c2 != oc2
2324 && c->x * mx <= c2->x * mx
2325 && c->y * my <= c2->y * my
2326 && c->net != c2->net
2327 && intersecting_layers (c->layer, c2->layer))
2329 int cr = corner_radius (c2);
2330 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2331 if (c->x != c2->x && c->y != c2->y)
2332 len -= cr;
2333 if (len < dist || (len == dist && c->miter != -1))
2335 dist = len;
2336 closest_corner = c2;
2341 if (closest_corner && closest_corner->miter == -1)
2343 done = 0;
2344 continue;
2347 #if 0
2348 if (dist < Settings.Grid)
2350 c->miter = 0;
2351 progress = 1;
2352 continue;
2355 dist -= dist % Settings.Grid;
2356 #endif
2357 if (dist <= 0)
2359 c->miter = 0;
2360 progress = 1;
2361 continue;
2364 x = c->x;
2365 y = c->y;
2366 switch (o1)
2368 case LEFT:
2369 x -= dist;
2370 break;
2371 case RIGHT:
2372 x += dist;
2373 break;
2374 case UP:
2375 y -= dist;
2376 break;
2377 case DOWN:
2378 y += dist;
2379 break;
2381 c2 = find_corner (x, y, c->layer);
2382 if (c2 != other_corner (c->lines[0], c))
2383 split_line (c->lines[0], c2);
2384 x = c->x;
2385 y = c->y;
2386 switch (o2)
2388 case LEFT:
2389 x -= dist;
2390 break;
2391 case RIGHT:
2392 x += dist;
2393 break;
2394 case UP:
2395 y -= dist;
2396 break;
2397 case DOWN:
2398 y += dist;
2399 break;
2401 move_corner (c, x, y);
2402 c->miter = 0;
2403 c2->miter = 0;
2404 progress = 1;
2405 saved++;
2409 return saved;
2412 static void
2413 classify_corner (corner_s * c, int this_net)
2415 int i;
2416 if (c->net == this_net)
2417 return;
2418 c->net = this_net;
2419 for (i = 0; i < c->n_lines; i++)
2420 classify_corner (other_corner (c->lines[i], c), this_net);
2423 static void
2424 classify_nets ()
2426 static int this_net = 1;
2427 corner_s *c;
2429 for (c = corners; c; c = c->next)
2431 if (DELETED (c))
2432 continue;
2433 if (c->net)
2434 continue;
2435 classify_corner (c, this_net);
2436 this_net++;
2440 #if 0
2441 /* Not used */
2442 static void
2443 dump_all ()
2445 corner_s *c;
2446 line_s *l;
2447 for (c = corners; c; c = c->next)
2449 if (DELETED (c))
2450 continue;
2451 printf ("%p corner %d,%d layer %d net %d\n",
2452 (void *) c, c->x, c->y, c->layer, c->net);
2454 for (l = lines; l; l = l->next)
2456 if (DELETED (l))
2457 continue;
2458 printf ("%p line %p to %p layer %d\n",
2459 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2462 #endif
2464 #if 0
2465 static void
2466 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2468 int ox = c->x;
2469 int oy = c->y;
2470 int l;
2471 if (prev_corner && (c->pin || c->pad))
2472 return;
2473 move_corner (c, ox + dx, oy + dy);
2474 for (l = 0; l < c->n_lines; l++)
2476 corner_s *oc = other_corner (c->lines[l], c);
2477 if (oc == prev_corner)
2478 continue;
2479 if (dx && oc->x == ox)
2480 nudge_corner (oc, dx, 0, c);
2481 if (dy && oc->y == oy)
2482 nudge_corner (oc, 0, dy, c);
2485 #endif
2487 static line_s *
2488 choose_example_line (corner_s * c1, corner_s * c2)
2490 int ci, li;
2491 corner_s *c[2];
2492 c[0] = c1;
2493 c[1] = c2;
2494 dprintf ("choose_example_line\n");
2495 for (ci = 0; ci < 2; ci++)
2496 for (li = 0; li < c[ci]->n_lines; li++)
2498 dprintf (" try[%d,%d] \033[36m<%#mD-%#mD t%#mS c%#mS f%s>\033[0m\n",
2499 ci, li,
2500 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2501 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2502 c[ci]->lines[li]->line->Thickness,
2503 c[ci]->lines[li]->line->Clearance,
2504 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2505 /* Pads are disqualified, as we want to mimic a trace line. */
2506 if (c[ci]->lines[li]->line == (LineType *) c[ci]->pad)
2508 dprintf (" bad, pad\n");
2509 continue;
2511 /* Lines on layers that don't connect to the other pad are bad too. */
2512 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2514 dprintf (" bad, layers\n");
2515 continue;
2517 dprintf (" good\n");
2518 return c[ci]->lines[li];
2520 dprintf ("choose_example_line: none found!\n");
2521 return 0;
2524 static int
2525 connect_corners (corner_s * c1, corner_s * c2)
2527 int layer;
2528 line_s *ex = choose_example_line (c1, c2);
2529 LineType *example = ex->line;
2531 dprintf
2532 ("connect_corners \033[32m%#mD to %#mD, example line %#mD to %#mD l%d\033[0m\n",
2533 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2534 ex->layer);
2536 layer = ex->layer;
2538 /* Assume c1 is the moveable one. */
2539 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2541 int nx, ny;
2542 /* Extend the line */
2543 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2544 nx = c1->x, ny = c2->y;
2545 else
2546 nx = c2->x, ny = c1->y;
2547 if (nx != c2->x || ny != c2->y)
2549 move_corner (c1, nx, ny);
2550 new_line (c1, c2, layer, example);
2551 return 1;
2553 else
2555 move_corner (c1, nx, ny);
2556 return 1;
2559 else
2561 corner_s *nc = find_corner (c1->x, c2->y, layer);
2562 new_line (c1, nc, layer, example);
2563 new_line (nc, c2, layer, example);
2564 return 0;
2569 * \brief Look for pins that have no connections.
2571 * See if there's a corner close by that should be connected to it.
2572 * This usually happens when the MUCS router needs to route to an
2573 * off-grid pin.
2575 static void
2576 pinsnap ()
2578 corner_s *c;
2579 int best_dist[MAX_LAYER + 1];
2580 corner_s *best_c[MAX_LAYER + 1];
2581 int l, got_one;
2582 int left = 0, right = 0, top = 0, bottom = 0;
2583 PinType *pin;
2584 int again = 1;
2586 int close = 0;
2587 corner_s *c2;
2589 while (again)
2591 again = 0;
2592 for (c = corners; c; c = c->next)
2594 if (DELETED (c))
2595 continue;
2596 if (!(c->pin || c->via || c->pad))
2597 continue;
2599 pin = 0;
2601 dprintf ("\ncorner %s\n", corner_name (c));
2602 if (c->pin || c->via)
2604 pin = c->pin ? c->pin : c->via;
2605 close = pin->Thickness / 2;
2606 left = c->x - close;
2607 right = c->x + close;
2608 bottom = c->y - close;
2609 top = c->y + close;
2611 else if (c->pad)
2613 close = c->pad->Thickness / 2 + 1;
2614 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2615 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2616 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2617 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2618 if (c->pad->Point1.X == c->pad->Point2.X)
2620 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2621 dprintf ("pad y %#mS %#mS hy %#mS c %#mS\n", c->pad->Point1.Y,
2622 c->pad->Point2.Y, hy, c->y);
2623 if (c->y < hy)
2624 top = hy;
2625 else
2626 bottom = hy + 1;
2628 else
2630 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2631 dprintf ("pad x %#mS %#mS hx %#mS c %#mS\n", c->pad->Point1.X,
2632 c->pad->Point2.X, hx, c->x);
2633 if (c->x < hx)
2634 right = hx;
2635 else
2636 left = hx + 1;
2640 dprintf ("%s x %#mS-%#mS y %#mS-%#mS\n", corner_name (c), left, right, bottom, top);
2641 for (l = 0; l <= max_copper_layer; l++)
2643 best_dist[l] = close * 2;
2644 best_c[l] = 0;
2646 got_one = 0;
2647 for (c2 = corners; c2; c2 = c2->next)
2649 int lt;
2651 if (DELETED (c2))
2652 continue;
2653 lt = corner_radius (c2);
2654 if (c2->n_lines
2655 && c2 != c
2656 && !(c2->pin || c2->pad || c2->via)
2657 && intersecting_layers (c->layer, c2->layer)
2658 && c2->x >= left - lt
2659 && c2->x <= right + lt
2660 && c2->y >= bottom - lt && c2->y <= top + lt)
2662 int d = dist (c->x, c->y, c2->x, c2->y);
2663 if (pin && d > pin->Thickness / 2 + lt)
2664 continue;
2665 if (c2->n_lines == 1)
2667 got_one++;
2668 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2669 corner_name (c));
2670 connect_corners (c, c2);
2671 again = 1;
2672 continue;
2674 if (best_c[c2->layer] == 0
2675 || c2->n_lines < best_c[c2->layer]->n_lines
2676 || (d < best_dist[c2->layer]
2677 && c2->n_lines <= best_c[c2->layer]->n_lines))
2679 best_dist[c2->layer] = d;
2680 best_c[c2->layer] = c2;
2681 dprintf ("layer %d best now %s\n", c2->layer,
2682 corner_name (c2));
2685 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2687 for (l = 0; l <= max_copper_layer; l++)
2688 if (best_c[l])
2689 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2690 for (l = 0; l <= max_copper_layer; l++)
2691 if (best_c[l])
2693 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2694 corner_name (c));
2695 connect_corners (best_c[l], c);
2696 again = 1;
2697 continue;
2704 /* Now look for line ends that don't connect, see if they need to be
2705 extended to intersect another line. */
2706 for (c = corners; c; c = c->next)
2708 line_s *l, *t;
2709 int lo;
2711 if (DELETED (c))
2712 continue;
2713 if (c->pin || c->via || c->pad)
2714 continue;
2715 if (c->n_lines != 1)
2716 continue;
2718 l = c->lines[0];
2719 lo = line_orient (l, c);
2720 dprintf ("line end %#mD orient %d\n", c->x, c->y, lo);
2722 for (t = lines; t; t = t->next)
2724 if (DELETED (t))
2725 continue;
2726 if (t->layer != c->lines[0]->layer)
2727 continue;
2728 switch (lo) /* remember, orient is for the line relative to the corner */
2730 case LEFT:
2731 if (t->s->x == t->e->x
2732 && c->x < t->s->x
2733 && t->s->x <
2734 c->x + (l->line->Thickness + t->line->Thickness) / 2
2735 && ((t->s->y < c->y && c->y < t->e->y)
2736 || (t->e->y < c->y && c->y < t->s->y)))
2738 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2739 move_corner (c, t->s->x, c->y);
2741 break;
2742 case RIGHT:
2743 if (t->s->x == t->e->x
2744 && c->x > t->s->x
2745 && t->s->x >
2746 c->x - (l->line->Thickness + t->line->Thickness) / 2
2747 && ((t->s->y < c->y && c->y < t->e->y)
2748 || (t->e->y < c->y && c->y < t->s->y)))
2750 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2751 move_corner (c, t->s->x, c->y);
2753 break;
2754 case UP:
2755 if (t->s->y == t->e->y
2756 && c->y < t->s->y
2757 && t->s->y <
2758 c->y + (l->line->Thickness + t->line->Thickness) / 2
2759 && ((t->s->x < c->x && c->x < t->e->x)
2760 || (t->e->x < c->x && c->x < t->s->x)))
2762 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2763 move_corner (c, c->x, t->s->y);
2765 break;
2766 case DOWN:
2767 if (t->s->y == t->e->y
2768 && c->y > t->s->y
2769 && t->s->y >
2770 c->y - (l->line->Thickness + t->line->Thickness) / 2
2771 && ((t->s->x < c->x && c->x < t->e->x)
2772 || (t->e->x < c->x && c->x < t->s->x)))
2774 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2775 move_corner (c, c->x, t->s->y);
2777 break;
2783 static int
2784 pad_orient (PadType * p)
2786 if (p->Point1.X == p->Point2.X)
2787 return O_VERT;
2788 if (p->Point1.Y == p->Point2.Y)
2789 return O_HORIZ;
2790 return DIAGONAL;
2793 static void
2794 padcleaner ()
2796 line_s *l, *nextl;
2797 int close;
2798 rect_s r;
2800 dprintf ("\ndj: padcleaner\n");
2801 for (l = lines; l; l = nextl)
2803 nextl = l->next;
2805 if (l->is_pad)
2806 continue;
2808 if (DELETED (l))
2809 continue;
2811 dprintf ("dj: line %p\n", (void *) l);
2812 check (0, l);
2814 if (l->s->pad && l->s->pad == l->e->pad)
2815 continue;
2817 ALLPAD_LOOP (PCB->Data);
2819 int layerflag =
2820 TEST_FLAG (ONSOLDERFLAG, element) ? LT_BOTTOM : LT_TOP;
2822 if (layer_type[l->layer] != layerflag)
2823 continue;
2825 empty_rect (&r);
2826 close = pad->Thickness / 2 + 1;
2827 add_point_to_rect (&r, pad->Point1.X, pad->Point1.Y, close - SB / 2);
2828 add_point_to_rect (&r, pad->Point2.X, pad->Point2.Y, close - SB / 2);
2829 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2830 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2831 && ORIENT (line_orient (l, 0)) == pad_orient (pad))
2833 dprintf
2834 ("padcleaner %#mD-%#mD %#mS vs line %#mD-%#mD %#mS\n",
2835 pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y,
2836 pad->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2837 l->line->Thickness);
2838 remove_line (l);
2839 goto next_line;
2842 ENDALL_LOOP;
2843 next_line:;
2847 static void
2848 grok_layer_groups ()
2850 int i, j, f;
2851 LayerGroupType *l = &(PCB->LayerGroups);
2853 solder_layer = component_layer = -1;
2854 for (i = 0; i < max_copper_layer; i++)
2856 layer_type[i] = 0;
2857 layer_groupings[i] = 0;
2859 for (i = 0; i < max_group; i++)
2861 f = 0;
2862 for (j = 0; j < l->Number[i]; j++)
2864 if (l->Entries[i][j] == bottom_silk_layer)
2865 f |= LT_BOTTOM;
2866 if (l->Entries[i][j] == top_silk_layer)
2867 f |= LT_TOP;
2869 for (j = 0; j < l->Number[i]; j++)
2871 if (l->Entries[i][j] < max_copper_layer)
2873 layer_type[l->Entries[i][j]] |= f;
2874 layer_groupings[l->Entries[i][j]] = i;
2875 if (solder_layer == -1 && f == LT_BOTTOM)
2876 solder_layer = l->Entries[i][j];
2877 if (component_layer == -1 && f == LT_TOP)
2878 component_layer = l->Entries[i][j];
2884 static const char djopt_syntax[] =
2885 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull|splitlines)\n"
2886 "djopt(auto) - all of the above\n"
2887 "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 Example:
2904 Before debumpify:
2906 @center @image{debumpify,,,Example pcb before debumpify,png}
2908 After debumpify:
2910 @center @image{debumpify.out,,,Example pcb after debumpify,png}
2913 @item unjaggy
2914 Looks for corners which could be flipped to eliminate one or more
2915 corners (i.e. jaggy lines become simpler).
2917 @item simple
2918 Removing uneeded vias, replacing two or more trace segments in a row
2919 with a single segment. This is usually performed automatically after
2920 other optimizations.
2922 @item vianudge
2923 Looks for vias where all traces leave in the same direction. Tries to
2924 move via in that direction to eliminate one of the traces (and thus a
2925 corner).
2927 @item viatrim
2928 Looks for traces that go from via to via, where moving that trace to a
2929 different layer eliminates one or both vias.
2931 @item orthopull
2932 Looks for chains of traces all going in one direction, with more
2933 traces orthogonal on one side than on the other. Moves the chain in
2934 that direction, causing a net reduction in trace length, possibly
2935 eliminating traces and/or corners.
2937 @item splitlines
2938 Looks for lines that pass through vias, pins, or pads, and splits them
2939 into separate lines so they can be managed separately.
2941 @item auto
2942 Performs the above options, repeating until no further optimizations
2943 can be made.
2945 @item miter
2946 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2947 RF losses and trace length.
2949 @end table
2951 %end-doc */
2953 static int
2954 ActionDJopt (int argc, char **argv, Coord x, Coord y)
2956 char *arg = argc > 0 ? argv[0] : 0;
2957 int layn, saved = 0;
2958 corner_s *c;
2960 hid_action("Busy");
2962 lines = 0;
2963 corners = 0;
2965 grok_layer_groups ();
2967 ELEMENT_LOOP (PCB->Data);
2968 PIN_LOOP (element);
2970 c = find_corner (pin->X, pin->Y, -1);
2971 c->pin = pin;
2973 END_LOOP;
2974 PAD_LOOP (element);
2976 int layern =
2977 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
2978 line_s *ls = (line_s *) malloc (sizeof (line_s));
2979 ls->next = lines;
2980 lines = ls;
2981 ls->is_pad = 1;
2982 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
2983 ls->s->pad = pad;
2984 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
2985 ls->e->pad = pad;
2986 ls->layer = layern;
2987 ls->line = (LineType *) pad;
2988 add_line_to_corner (ls, ls->s);
2989 add_line_to_corner (ls, ls->e);
2992 END_LOOP;
2993 END_LOOP;
2994 VIA_LOOP (PCB->Data);
2995 /* hace don't mess with vias that have thermals */
2996 /* but then again don't bump into them
2997 if (!TEST_FLAG(ALLTHERMFLAGS, via))
3000 c = find_corner (via->X, via->Y, -1);
3001 c->via = via;
3003 END_LOOP;
3004 check (0, 0);
3006 if (NSTRCMP (arg, "splitlines") == 0)
3008 if (canonicalize_lines ())
3009 IncrementUndoSerialNumber ();
3010 return 0;
3013 for (layn = 0; layn < max_copper_layer; layn++)
3015 LayerType *layer = LAYER_PTR (layn);
3017 LINE_LOOP (layer);
3019 line_s *ls;
3021 if(autorouted_only && !autorouted (line))
3022 continue;
3024 /* don't mess with thermals */
3025 if (TEST_FLAG (USETHERMALFLAG, line))
3026 continue;
3028 if (line->Point1.X == line->Point2.X &&
3029 line->Point1.Y == line->Point2.Y)
3031 RemoveLine (layer, line);
3032 continue;
3035 ls = (line_s *) malloc (sizeof (line_s));
3036 ls->next = lines;
3037 lines = ls;
3038 ls->is_pad = 0;
3039 ls->s = find_corner (line->Point1.X, line->Point1.Y, layn);
3040 ls->e = find_corner (line->Point2.X, line->Point2.Y, layn);
3041 ls->line = line;
3042 add_line_to_corner (ls, ls->s);
3043 add_line_to_corner (ls, ls->e);
3044 ls->layer = layn;
3046 END_LOOP;
3049 check (0, 0);
3050 pinsnap ();
3051 canonicalize_lines ();
3052 check (0, 0);
3053 classify_nets ();
3054 /*dump_all(); */
3055 check (0, 0);
3057 if (NSTRCMP (arg, "debumpify") == 0)
3058 saved += debumpify ();
3059 else if (NSTRCMP (arg, "unjaggy") == 0)
3060 saved += unjaggy ();
3061 else if (NSTRCMP (arg, "simple") == 0)
3062 saved += simple_optimizations ();
3063 else if (NSTRCMP (arg, "vianudge") == 0)
3064 saved += vianudge ();
3065 else if (NSTRCMP (arg, "viatrim") == 0)
3066 saved += viatrim ();
3067 else if (NSTRCMP (arg, "orthopull") == 0)
3068 saved += orthopull ();
3069 else if (NSTRCMP (arg, "auto") == 0)
3070 saved += automagic ();
3071 else if (NSTRCMP (arg, "miter") == 0)
3072 saved += miter ();
3073 else
3075 printf ("unknown command: %s\n", arg);
3076 return 1;
3079 padcleaner ();
3081 check (0, 0);
3082 if (saved)
3083 IncrementUndoSerialNumber ();
3084 return 0;
3087 HID_Action djopt_action_list[] = {
3088 {"djopt", 0, ActionDJopt,
3089 djopt_help, djopt_syntax}
3091 {"OptAutoOnly", 0, djopt_set_auto_only,
3092 djopt_sao_help, djopt_sao_syntax}
3095 REGISTER_ACTIONS (djopt_action_list)