(no commit message)
[geda-pcb/pcjc2.git] / src / djopt.c
blob2398f758a0826b4b6a425d01636de28c90bd6462
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2003 DJ Delorie
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
23 * dj@delorie.com
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
31 #include "global.h"
33 #include <memory.h>
34 #include <limits.h>
37 #include "data.h"
38 #include "create.h"
39 #include "remove.h"
40 #include "move.h"
41 #include "draw.h"
42 #include "undo.h"
43 #include "strflags.h"
44 #include "find.h"
45 #include "pcb-printf.h"
47 #ifdef HAVE_LIBDMALLOC
48 #include <dmalloc.h>
49 #endif
51 #ifndef HAVE_RINT
52 #define rint(x) (ceil((x) - 0.5))
53 #endif
55 #define dprintf if(0)pcb_printf
57 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x))
58 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x))
60 #define SB (PCB->Bloat+1)
62 /* must be 2^N-1 */
63 #define INC 7
65 #define O_HORIZ 0x10
66 #define O_VERT 0x20
67 #define LEFT 0x11
68 #define RIGHT 0x12
69 #define UP 0x24
70 #define DOWN 0x28
71 #define DIAGONAL 0xf0
72 #define ORIENT(x) ((x) & 0xf0)
73 #define DIRECT(x) ((x) & 0x0f)
75 /* Manhattan length of the longest "freckle" */
76 #define LONGEST_FRECKLE 2
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 char is_pad;
101 } line_s;
103 typedef struct rect_s
105 int x1, y1, x2, y2;
106 } rect_s;
108 #define DELETE(q) (q)->layer = 0xdeadbeef
109 #define DELETED(q) ((q)->layer == 0xdeadbeef)
111 static corner_s *corners, *next_corner = 0;
112 static line_s *lines;
114 static int layer_groupings[MAX_LAYER];
115 static char layer_type[MAX_LAYER];
116 #define LT_TOP 1
117 #define LT_BOTTOM 2
119 static int autorouted_only = 1;
121 static const char djopt_sao_syntax[] = "OptAutoOnly()";
123 static const char djopt_sao_help[] =
124 "Toggles the optimize-only-autorouted flag.";
126 /* %start-doc actions OptAutoOnly
128 The original purpose of the trace optimizer was to clean up the traces
129 created by the various autorouters that have been used with PCB. When
130 a board has a mix of autorouted and carefully hand-routed traces, you
131 don't normally want the optimizer to move your hand-routed traces.
132 But, sometimes you do. By default, the optimizer only optimizes
133 autorouted traces. This action toggles that setting, so that you can
134 optimize hand-routed traces also.
136 %end-doc */
139 djopt_set_auto_only (int argc, char **argv, Coord x, Coord y)
141 autorouted_only = autorouted_only ? 0 : 1;
142 return 0;
145 static int
146 djopt_get_auto_only (void *data)
148 return autorouted_only;
151 HID_Flag djopt_flag_list[] = {
152 {"optautoonly", djopt_get_auto_only, NULL}
155 REGISTER_FLAGS (djopt_flag_list)
157 static char *
158 element_name_for (corner_s * c)
160 ELEMENT_LOOP (PCB->Data);
162 PIN_LOOP (element);
164 if (pin == c->pin)
165 return element->Name[1].TextString;
167 END_LOOP;
168 PAD_LOOP (element);
170 if (pad == c->pad)
171 return element->Name[1].TextString;
173 END_LOOP;
175 END_LOOP;
176 return "unknown";
179 static char *
180 corner_name (corner_s * c)
182 static char buf[4][100];
183 static int bn = 0;
184 char *bp;
185 bn = (bn + 1) % 4;
187 if (c->net == 0xf1eef1ee)
189 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
190 return buf[bn];
193 sprintf (buf[bn], "\033[%dm[%p ",
194 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
195 bp = buf[bn] + strlen (buf[bn]);
197 if (c->pin)
198 pcb_sprintf (bp, "pin %s:%s at %#mD", element_name_for (c), c->pin->Number, c->x, c->y);
199 else if (c->via)
200 pcb_sprintf (bp, "via at %#mD", c->x, c->y);
201 else if (c->pad)
203 pcb_sprintf (bp, "pad %s:%s at %#mD %#mD-%#mD",
204 element_name_for (c), c->pad->Number, c->x, c->y,
205 c->pad->Point1.X, c->pad->Point1.Y,
206 c->pad->Point2.X, c->pad->Point2.Y);
208 else
209 pcb_sprintf (bp, "at %#mD", c->x, c->y);
210 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
211 return buf[bn];
214 static int solder_layer, component_layer;
216 static void
217 dj_abort (char *msg, ...)
219 va_list a;
220 va_start (a, msg);
221 vprintf (msg, a);
222 va_end (a);
223 fflush (stdout);
224 abort ();
227 #if 1
228 #define check(c,l)
229 #else
230 #define check(c,l) check2(__LINE__,c,l)
231 static void
232 check2 (int srcline, corner_s * c, line_s * l)
234 int saw_c = 0, saw_l = 0;
235 corner_s *cc;
236 line_s *ll;
237 int i;
239 for (cc = corners; cc; cc = cc->next)
241 if (DELETED (cc))
242 continue;
243 if (cc == c)
244 saw_c = 1;
245 for (i = 0; i < cc->n_lines; i++)
246 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
247 dj_abort ("check:%d: cc has line without backref\n", srcline);
248 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
249 dj_abort ("check:%d: via not at corner\n", srcline);
250 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
251 dj_abort ("check:%d: pin not at corner\n", srcline);
253 if (c && !saw_c)
254 dj_abort ("check:%d: corner not in corners list\n", srcline);
255 for (ll = lines; ll; ll = ll->next)
257 if (DELETED (ll))
258 continue;
259 if (ll == l)
260 saw_l = 1;
261 for (i = 0; i < ll->s->n_lines; i++)
262 if (ll->s->lines[i] == ll)
263 break;
264 if (i == ll->s->n_lines)
265 dj_abort ("check:%d: ll->s has no backref\n", srcline);
266 for (i = 0; i < ll->e->n_lines; i++)
267 if (ll->e->lines[i] == ll)
268 break;
269 if (i == ll->e->n_lines)
270 dj_abort ("check:%d: ll->e has no backref\n", srcline);
271 if (!ll->is_pad
272 && (ll->s->x != ll->line->Point1.X
273 || ll->s->y != ll->line->Point1.Y
274 || ll->e->x != ll->line->Point2.X
275 || ll->e->y != ll->line->Point2.Y))
277 pcb_printf ("line: %#mD to %#mD pcbline: %#mD to %#mD\n",
278 ll->s->x, ll->s->y,
279 ll->e->x, ll->e->y,
280 ll->line->Point1.X,
281 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
282 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
285 if (l && !saw_l)
286 dj_abort ("check:%d: line not in lines list\n", srcline);
289 #endif
291 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
293 static int
294 gridsnap (Coord n)
296 if (n <= 0)
297 return 0;
298 return n - n % (Settings.Grid);
301 /* Avoid commonly used names. */
303 static int
304 djabs (int x)
306 return x > 0 ? x : -x;
309 static int
310 djmax (int x, int y)
312 return x > y ? x : y;
315 static int
316 djmin (int x, int y)
318 return x < y ? x : y;
322 * Find distance between 2 points. We use floating point math here
323 * because we can fairly easily overflow a 32 bit integer here. In
324 * fact it only takes 0.46" to do so.
326 static int
327 dist (int x1, int y1, int x2, int y2)
329 double dx1, dy1, dx2, dy2, d;
331 dx1 = (double) x1;
332 dy1 = (double) y1;
333 dx2 = (double) x2;
334 dy2 = (double) y2;
336 d = sqrt ((dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2));
337 d = rint (d);
339 return (int) d;
342 static int
343 line_length (line_s * l)
345 if (l->s->x == l->e->x)
346 return djabs (l->s->y - l->e->y);
347 if (l->s->y == l->e->y)
348 return djabs (l->s->x - l->e->x);
349 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
352 static int
353 dist_ltp2 (int dx, int y, int y1, int y2)
355 if (y1 > y2)
356 SWAP (y1, y2);
357 if (y < y1)
358 return dist (dx, y, 0, y1);
359 if (y > y2)
360 return dist (dx, y, 0, y2);
361 return djabs (dx);
365 sqr (int a)
367 return a * a;
370 static int
371 intersecting_layers (int l1, int l2)
373 if (l1 == -1 || l2 == -1)
374 return 1;
375 if (l1 == l2)
376 return 1;
377 if (layer_groupings[l1] == layer_groupings[l2])
378 return 1;
379 return 0;
382 static int
383 dist_line_to_point (line_s * l, corner_s * c)
385 double len, r, d;
386 /* We can do this quickly if l is vertical or horizontal. */
387 if (l->s->x == l->e->x)
388 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
389 if (l->s->y == l->e->y)
390 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
392 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
393 len = sqrt (sqr (l->s->x - l->e->x) + sqr (l->s->y - l->e->y));
394 if (len == 0)
395 return dist (l->s->x, l->s->y, c->x, c->y);
397 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
398 l->e->x);
399 r /= len * len;
400 if (r < 0)
401 return dist (l->s->x, l->s->y, c->x, c->y);
402 if (r > 1)
403 return dist (l->e->x, l->e->y, c->x, c->y);
405 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
406 l->s->y);
407 return (int) (d / len);
410 static int
411 line_orient (line_s * l, corner_s * c)
413 int x1, y1, x2, y2;
414 if (c == l->s)
416 x1 = l->s->x;
417 y1 = l->s->y;
418 x2 = l->e->x;
419 y2 = l->e->y;
421 else
423 x1 = l->e->x;
424 y1 = l->e->y;
425 x2 = l->s->x;
426 y2 = l->s->y;
428 if (x1 == x2)
430 if (y1 < y2)
431 return DOWN;
432 return UP;
434 else if (y1 == y2)
436 if (x1 < x2)
437 return RIGHT;
438 return LEFT;
440 return DIAGONAL;
443 #if 0
444 /* Not used */
445 static corner_s *
446 common_corner (line_s * l1, line_s * l2)
448 if (l1->s == l2->s || l1->s == l2->e)
449 return l1->s;
450 if (l1->e == l2->s || l1->e == l2->e)
451 return l1->e;
452 dj_abort ("common_corner: no common corner found\n");
453 return NULL;
455 #endif
457 static corner_s *
458 other_corner (line_s * l, corner_s * c)
460 if (l->s == c)
461 return l->e;
462 if (l->e == c)
463 return l->s;
464 dj_abort ("other_corner: neither corner passed\n");
465 return NULL;
468 static corner_s *
469 find_corner_if (int x, int y, int l)
471 corner_s *c;
472 for (c = corners; c; c = c->next)
474 if (DELETED (c))
475 continue;
476 if (c->x != x || c->y != y)
477 continue;
478 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
479 continue;
480 return c;
482 return 0;
485 static corner_s *
486 find_corner (int x, int y, int l)
488 corner_s *c;
489 for (c = corners; c; c = c->next)
491 if (DELETED (c))
492 continue;
493 if (c->x != x || c->y != y)
494 continue;
495 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
496 continue;
497 return c;
499 c = (corner_s *) malloc (sizeof (corner_s));
500 c->next = corners;
501 corners = c;
502 c->x = x;
503 c->y = y;
504 c->net = 0;
505 c->via = 0;
506 c->pad = 0;
507 c->pin = 0;
508 c->layer = l;
509 c->n_lines = 0;
510 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
511 return c;
514 static void
515 add_line_to_corner (line_s * l, corner_s * c)
517 int n;
518 n = (c->n_lines + 1 + INC) & ~INC;
519 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
520 c->lines[c->n_lines] = l;
521 c->n_lines++;
522 dprintf ("add_line_to_corner %#mD\n", c->x, c->y);
525 static LineType *
526 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
527 int thick, int clear, FlagType flags)
529 char *from, *to;
530 LineType *nl;
531 LayerType *lyr = LAYER_PTR (layer);
533 from = (char *) lyr->Line;
534 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
535 x1, y1, x2, y2, thick, clear, flags);
536 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
538 to = (char *) lyr->Line;
539 if (from != to)
541 line_s *lp;
542 for (lp = lines; lp; lp = lp->next)
544 if (DELETED (lp))
545 continue;
546 if ((char *) (lp->line) >= from
547 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
548 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
551 return nl;
554 static void
555 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
557 line_s *ls;
559 if (layer >= max_copper_layer)
560 dj_abort ("layer %d\n", layer);
562 if (example == NULL)
563 dj_abort ("NULL example passed to new_line()\n", layer);
565 if (s->x == e->x && s->y == e->y)
566 return;
568 ls = (line_s *) malloc (sizeof (line_s));
569 ls->next = lines;
570 lines = ls;
571 ls->is_pad = 0;
572 ls->s = s;
573 ls->e = e;
574 ls->layer = layer;
575 #if 0
576 if ((example->Point1.X == s->x && example->Point1.Y == s->y
577 && example->Point2.X == e->x && example->Point2.Y == e->y)
578 || (example->Point2.X == s->x && example->Point2.Y == s->y
579 && example->Point1.X == e->x && example->Point1.Y == e->y))
581 ls->line = example;
583 else
584 #endif
586 LineType *nl;
587 dprintf
588 ("New line \033[35m%#mD to %#mD from l%d t%#mS c%#mS f%s\033[0m\n",
589 s->x, s->y, e->x, e->y, layer, example->Thickness,
590 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
591 nl =
592 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
593 example->Clearance, example->Flags);
595 if (!nl)
596 dj_abort ("can't create new line!");
597 ls->line = nl;
599 add_line_to_corner (ls, s);
600 add_line_to_corner (ls, e);
601 check (s, ls);
602 check (e, ls);
605 #if 0
606 /* Not used */
607 static int
608 c_orth_to (corner_s * c, line_s * l, int o)
610 int i, o2;
611 int rv = 0;
612 for (i = 0; i < c->n_lines; i++)
614 if (c->lines[i] == l)
615 continue;
616 o2 = line_orient (c->lines[i], c);
617 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
618 return 0;
619 rv++;
621 return rv;
623 #endif
625 static line_s *
626 other_line (corner_s * c, line_s * l)
628 int i;
629 line_s *rv = 0;
630 if (c->pin || c->pad || c->via)
631 return 0;
632 for (i = 0; i < c->n_lines; i++)
634 if (c->lines[i] == l)
635 continue;
636 if (rv)
637 return 0;
638 rv = c->lines[i];
640 return rv;
643 static void
644 empty_rect (rect_s * rect)
646 rect->x1 = rect->y1 = INT_MAX;
647 rect->x2 = rect->y2 = INT_MIN;
650 static void
651 add_point_to_rect (rect_s * rect, int x, int y, int w)
653 if (rect->x1 > x - w)
654 rect->x1 = x - w;
655 if (rect->x2 < x + w)
656 rect->x2 = x + w;
657 if (rect->y1 > y - w)
658 rect->y1 = y - w;
659 if (rect->y2 < y + w)
660 rect->y2 = y + w;
663 static void
664 add_line_to_rect (rect_s * rect, line_s * l)
666 add_point_to_rect (rect, l->s->x, l->s->y, 0);
667 add_point_to_rect (rect, l->e->x, l->e->y, 0);
670 static int
671 pin_in_rect (rect_s * r, int x, int y, int w)
673 if (x < r->x1 && x + w < r->x1)
674 return 0;
675 if (x > r->x2 && x - w > r->x2)
676 return 0;
677 if (y < r->y1 && y + w < r->y1)
678 return 0;
679 if (y > r->y2 && y - w > r->y2)
680 return 0;
681 return 1;
684 static int
685 line_in_rect (rect_s * r, line_s * l)
687 rect_s lr;
688 empty_rect (&lr);
689 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
690 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
691 dprintf ("line_in_rect %#mD-%#mD vs %#mD-%#mD\n",
692 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
693 /* simple intersection of rectangles */
694 if (lr.x1 < r->x1)
695 lr.x1 = r->x1;
696 if (lr.x2 > r->x2)
697 lr.x2 = r->x2;
698 if (lr.y1 < r->y1)
699 lr.y1 = r->y1;
700 if (lr.y2 > r->y2)
701 lr.y2 = r->y2;
702 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
703 return 1;
704 return 0;
707 static int
708 corner_radius (corner_s * c)
710 int diam = 0;
711 int i;
712 if (c->pin)
713 diam = djmax (c->pin->Thickness, diam);
714 if (c->via)
715 diam = djmax (c->via->Thickness, diam);
716 for (i = 0; i < c->n_lines; i++)
717 if (c->lines[i]->line)
718 diam = djmax (c->lines[i]->line->Thickness, diam);
719 diam = (diam + 1) / 2;
720 return diam;
723 #if 0
724 /* Not used */
725 static int
726 corner_layer (corner_s * c)
728 if (c->pin || c->via)
729 return -1;
730 if (c->n_lines < 1)
731 return -1;
732 return c->lines[0]->layer;
734 #endif
736 static void
737 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
739 int diam = corner_radius (c);
740 if (!pin_in_rect (e, c->x, c->y, diam))
741 return;
742 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
743 return;
744 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
745 return;
746 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
747 return;
748 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
749 return;
751 /*pcb_printf("add point %#mD diam %#mS\n", c->x, c->y, diam); */
752 add_point_to_rect (rect, c->x, c->y, diam);
755 static void
756 remove_line (line_s * l)
758 int i, j;
759 LayerType *layer = &(PCB->Data->Layer[l->layer]);
761 check (0, 0);
763 if (l->line)
764 RemoveLine (layer, l->line);
766 DELETE (l);
768 for (i = 0, j = 0; i < l->s->n_lines; i++)
769 if (l->s->lines[i] != l)
770 l->s->lines[j++] = l->s->lines[i];
771 l->s->n_lines = j;
773 for (i = 0, j = 0; i < l->e->n_lines; i++)
774 if (l->e->lines[i] != l)
775 l->e->lines[j++] = l->e->lines[i];
776 l->e->n_lines = j;
777 check (0, 0);
780 static void
781 move_line_to_layer (line_s * l, int layer)
783 LayerType *ls, *ld;
785 ls = LAYER_PTR (l->layer);
786 ld = LAYER_PTR (layer);
788 MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
789 l->layer = layer;
792 static void
793 remove_via_at (corner_s * c)
795 RemoveObject (VIA_TYPE, c->via, 0, 0);
796 c->via = 0;
799 static void
800 remove_corner (corner_s * c2)
802 corner_s *c;
803 dprintf ("remove corner %s\n", corner_name (c2));
804 if (corners == c2)
805 corners = c2->next;
806 for (c = corners; c; c = c->next)
808 if (DELETED (c))
809 continue;
810 if (c->next == c2)
811 c->next = c2->next;
813 if (next_corner == c2)
814 next_corner = c2->next;
815 free (c2->lines);
816 c2->lines = 0;
817 DELETE (c2);
820 static void
821 merge_corners (corner_s * c1, corner_s * c2)
823 int i;
824 if (c1 == c2)
825 abort ();
826 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
827 for (i = 0; i < c2->n_lines; i++)
829 add_line_to_corner (c2->lines[i], c1);
830 if (c2->lines[i]->s == c2)
831 c2->lines[i]->s = c1;
832 if (c2->lines[i]->e == c2)
833 c2->lines[i]->e = c1;
835 if (c1->via && c2->via)
836 remove_via_at (c2);
837 else if (c2->via)
838 c1->via = c2->via;
839 if (c2->pad)
840 c1->pad = c2->pad;
841 if (c2->pin)
842 c1->pin = c2->pin;
843 if (c2->layer != c1->layer)
844 c1->layer = -1;
846 remove_corner (c2);
849 static void
850 move_corner (corner_s * c, int x, int y)
852 PinType *via;
853 int i;
854 corner_s *pad;
856 check (c, 0);
857 if (c->pad || c->pin)
858 dj_abort ("move_corner: has pin or pad\n");
859 dprintf ("move_corner %p from %#mD to %#mD\n", (void *) c, c->x, c->y, x, y);
860 pad = find_corner_if (x, y, c->layer);
861 c->x = x;
862 c->y = y;
863 via = c->via;
864 if (via)
866 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
867 dprintf ("via move %#mD to %#mD\n", via->X, via->Y, x, y);
869 for (i = 0; i < c->n_lines; i++)
871 LineType *tl = c->lines[i]->line;
872 if (tl)
874 if (c->lines[i]->s == c)
876 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
877 &tl->Point1, x - (tl->Point1.X),
878 y - (tl->Point1.Y));
880 else
882 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
883 &tl->Point2, x - (tl->Point2.X),
884 y - (tl->Point2.Y));
886 dprintf ("Line %p moved to %#mD %#mD\n", (void *) tl,
887 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
890 if (pad && pad != c)
891 merge_corners (c, pad);
892 else
893 for (i = 0; i < c->n_lines; i++)
895 if (c->lines[i]->s->x == c->lines[i]->e->x
896 && c->lines[i]->s->y == c->lines[i]->e->y)
898 corner_s *c2 = other_corner (c->lines[i], c);
899 dprintf ("move_corner: removing line %#mD %#mD %p %p\n",
900 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
902 remove_line (c->lines[i]);
903 if (c != c2)
904 merge_corners (c, c2);
905 check (c, 0);
906 i--;
907 break;
910 gui->progress (0, 0, 0);
911 check (c, 0);
914 static int
915 any_line_selected ()
917 line_s *l;
918 for (l = lines; l; l = l->next)
920 if (DELETED (l))
921 continue;
922 if (l->line && selected (l->line))
923 return 1;
925 return 0;
928 static int
929 trim_step (int s, int l1, int l2)
931 dprintf ("trim %d %d %d\n", s, l1, l2);
932 if (s > l1)
933 s = l1;
934 if (s > l2)
935 s = l2;
936 if (s != l1 && s != l2)
937 s = gridsnap (s);
938 return s;
941 static int canonicalize_line (line_s * l);
943 static int
944 split_line (line_s * l, corner_s * c)
946 int i;
947 LineType *pcbline;
948 line_s *ls;
950 if (!intersecting_layers (l->layer, c->layer))
951 return 0;
952 if (l->is_pad)
953 return 0;
954 if (c->pad)
956 dprintf ("split on pad!\n");
957 if (l->s->pad == c->pad || l->e->pad == c->pad)
958 return 0;
959 dprintf ("splitting...\n");
962 check (c, l);
963 pcbline = create_pcb_line (l->layer,
964 c->x, c->y, l->e->x, l->e->y,
965 l->line->Thickness, l->line->Clearance,
966 l->line->Flags);
967 if (pcbline == 0)
968 return 0; /* already a line there */
970 check (c, l);
972 dprintf ("split line from %#mD to %#mD at %#mD\n",
973 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
974 ls = (line_s *) malloc (sizeof (line_s));
976 ls->next = lines;
977 lines = ls;
978 ls->is_pad = 0;
979 ls->s = c;
980 ls->e = l->e;
981 ls->line = pcbline;
982 ls->layer = l->layer;
983 for (i = 0; i < l->e->n_lines; i++)
984 if (l->e->lines[i] == l)
985 l->e->lines[i] = ls;
986 l->e = c;
987 add_line_to_corner (l, c);
988 add_line_to_corner (ls, c);
990 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
991 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
993 return 1;
996 static int
997 canonicalize_line (line_s * l)
999 /* This could be faster */
1000 corner_s *c;
1001 if (l->s->x == l->e->x)
1003 int y1 = l->s->y;
1004 int y2 = l->e->y;
1005 int x1 = l->s->x - l->line->Thickness / 2;
1006 int x2 = l->s->x + l->line->Thickness / 2;
1007 if (y1 > y2)
1009 int t = y1;
1010 y1 = y2;
1011 y2 = t;
1013 for (c = corners; c; c = c->next)
1015 if (DELETED (c))
1016 continue;
1017 if ((y1 < c->y && c->y < y2)
1018 && intersecting_layers (l->layer, c->layer))
1020 if (c->x != l->s->x
1021 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1023 move_corner (c, l->s->x, c->y);
1025 if (c->x == l->s->x)
1027 /* FIXME: if the line is split, we have to re-canonicalize
1028 both segments. */
1029 return split_line (l, c);
1034 else if (l->s->y == l->e->y)
1036 int x1 = l->s->x;
1037 int x2 = l->e->x;
1038 int y1 = l->s->y - l->line->Thickness / 2;
1039 int y2 = l->s->y + l->line->Thickness / 2;
1040 if (x1 > x2)
1042 int t = x1;
1043 x1 = x2;
1044 x2 = t;
1046 for (c = corners; c; c = c->next)
1048 if (DELETED (c))
1049 continue;
1050 if ((x1 < c->x && c->x < x2)
1051 && intersecting_layers (l->layer, c->layer))
1053 if (c->y != l->s->y
1054 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1056 move_corner (c, c->x, l->s->y);
1058 if (c->y == l->s->y)
1060 /* FIXME: Likewise. */
1061 return split_line (l, c);
1066 else
1068 /* diagonal lines. Let's try to split them at pins/vias
1069 anyway. */
1070 int x1 = l->s->x;
1071 int x2 = l->e->x;
1072 int y1 = l->s->y;
1073 int y2 = l->e->y;
1074 if (x1 > x2)
1076 int t = x1;
1077 x1 = x2;
1078 x2 = t;
1080 if (y1 > y2)
1082 int t = y1;
1083 y1 = y2;
1084 y2 = t;
1086 for (c = corners; c; c = c->next)
1088 if (DELETED (c))
1089 continue;
1090 if (!c->via && !c->pin)
1091 continue;
1092 if ((x1 < c->x && c->x < x2)
1093 && (y1 < c->y && c->y < y2)
1094 && intersecting_layers (l->layer, c->layer))
1096 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1097 th /= 2;
1098 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1099 && dist (l->e->x, l->e->y, c->x, c->y) > th
1100 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1102 return split_line (l, c);
1107 return 0;
1110 /* Make sure all vias are at line end points */
1111 static int
1112 canonicalize_lines ()
1114 int changes = 0;
1115 int count;
1116 line_s *l;
1117 while (1)
1119 count = 0;
1120 for (l = lines; l; l = l->next)
1122 if (DELETED (l))
1123 continue;
1124 count += canonicalize_line (l);
1126 changes += count;
1127 if (count == 0)
1128 break;
1130 return changes;
1133 static int
1134 simple_optimize_corner (corner_s * c)
1136 int i;
1137 int rv = 0;
1139 check (c, 0);
1140 if (c->via)
1142 /* see if no via is needed */
1143 if (selected (c->via))
1144 dprintf ("via check: line[0] layer %d at %#mD nl %d\n",
1145 c->lines[0]->layer, c->x, c->y, c->n_lines);
1146 /* We can't delete vias that connect to power planes, or vias
1147 that aren't tented (assume they're test points). */
1148 if (!TEST_ANY_THERMS (c->via)
1149 && c->via->Mask == 0)
1151 for (i = 1; i < c->n_lines; i++)
1153 if (selected (c->via))
1154 dprintf (" line[%d] layer %d %#mD to %#mD\n",
1155 i, c->lines[i]->layer,
1156 c->lines[i]->s->x, c->lines[i]->s->y,
1157 c->lines[i]->e->x, c->lines[i]->e->y);
1158 if (c->lines[i]->layer != c->lines[0]->layer)
1159 break;
1161 if (i == c->n_lines)
1163 if (selected (c->via))
1164 dprintf (" remove it\n");
1165 remove_via_at (c);
1166 rv++;
1171 check (c, 0);
1172 if (c->n_lines == 2 && !c->via)
1174 /* see if it is an unneeded corner */
1175 int o = line_orient (c->lines[0], c);
1176 corner_s *c2 = other_corner (c->lines[1], c);
1177 corner_s *c0 = other_corner (c->lines[0], c);
1178 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1180 dprintf ("straight %#mD to %#mD to %#mD\n",
1181 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1182 if (selected (c->lines[0]->line))
1183 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1184 if (selected (c->lines[1]->line))
1185 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1186 move_corner (c, c2->x, c2->y);
1189 check (c, 0);
1190 if (c->n_lines == 1 && !c->via)
1192 corner_s *c0 = other_corner (c->lines[0], c);
1193 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE)
1196 * Remove this line, as it is a "freckle". A freckle is an extremely
1197 * short line (around 0.01 thou) that is unconnected at one end.
1198 * Freckles are almost insignificantly small, but are annoying as
1199 * they prevent the mitering optimiser from working.
1200 * Freckles sometimes arise because of a bug in the autorouter that
1201 * causes it to create small overshoots (typically 0.01 thou) at the
1202 * intersections of vertical and horizontal lines. These overshoots
1203 * are converted to freckles as a side effect of canonicalize_line().
1204 * Note that canonicalize_line() is not at fault, the bug is in the
1205 * autorouter creating overshoots.
1206 * The autorouter bug arose some time between the 20080202 and 20091103
1207 * releases.
1208 * This code is probably worth keeping even when the autorouter bug is
1209 * fixed, as "freckles" could conceivably arise in other ways.
1211 dprintf ("freckle %#mD to %#mD\n", c->x, c->y, c0->x, c0->y);
1212 move_corner (c, c0->x, c0->y);
1215 check (c, 0);
1216 return rv;
1219 /* We always run these */
1220 static int
1221 simple_optimizations ()
1223 corner_s *c;
1224 int rv = 0;
1226 /* Look for corners that aren't */
1227 for (c = corners; c; c = c->next)
1229 if (DELETED (c))
1230 continue;
1231 if (c->pad || c->pin)
1232 continue;
1233 rv += simple_optimize_corner (c);
1235 return rv;
1238 static int
1239 is_hole (corner_s * c)
1241 return c->pin || c->pad || c->via;
1244 static int
1245 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1247 static corner_s **cs = 0;
1248 static int cm = 0;
1249 static line_s **ls = 0;
1250 static int lm = 0;
1251 int i, li, ln, cn, snap;
1252 line_s *l = 0;
1253 corner_s *c2, *cb;
1254 int adir = 0, sdir = 0, pull;
1255 int saw_sel = 0, saw_auto = 0;
1256 int max, len = 0, r1 = 0, r2;
1257 rect_s rr;
1258 int edir = 0, done;
1260 if (cs == 0)
1262 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1263 cm = 10;
1264 ls = (line_s **) malloc (10 * sizeof (line_s));
1265 lm = 10;
1268 for (i = 0; i < c->n_lines; i++)
1270 int o = line_orient (c->lines[i], c);
1271 if (o == rdir)
1272 return 0;
1275 switch (fdir)
1277 case RIGHT:
1278 adir = DOWN;
1279 sdir = UP;
1280 break;
1281 case DOWN:
1282 adir = RIGHT;
1283 sdir = LEFT;
1284 break;
1285 default:
1286 dj_abort ("fdir not right or down\n");
1289 c2 = c;
1290 cn = 0;
1291 ln = 0;
1292 pull = 0;
1293 while (c2)
1295 if (c2->pad || c2->pin || c2->n_lines < 2)
1296 return 0;
1297 if (cn >= cm)
1299 cm = cn + 10;
1300 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s *));
1302 cs[cn++] = c2;
1303 r2 = corner_radius (c2);
1304 if (r1 < r2)
1305 r1 = r2;
1306 l = 0;
1307 for (i = 0; i < c2->n_lines; i++)
1309 int o = line_orient (c2->lines[i], c2);
1310 if (o == DIAGONAL)
1311 return 0;
1312 if (o == fdir)
1314 if (l)
1315 return 0; /* we don't support overlapping lines yet */
1316 l = c2->lines[i];
1318 if (o == rdir && c2->lines[i] != ls[ln - 1])
1319 return 0; /* likewise */
1320 if (o == adir)
1321 pull++;
1322 if (o == sdir)
1323 pull--;
1325 if (!l)
1326 break;
1327 if (selected (l->line))
1328 saw_sel = 1;
1329 if (autorouted (l->line))
1330 saw_auto = 1;
1331 if (ln >= lm)
1333 lm = ln + 10;
1334 ls = (line_s **) realloc (ls, lm * sizeof (line_s *));
1336 ls[ln++] = l;
1337 c2 = other_corner (l, c2);
1339 if (cn < 2 || pull == 0)
1340 return 0;
1341 if (any_sel && !saw_sel)
1342 return 0;
1343 if (!any_sel && autorouted_only && !saw_auto)
1344 return 0;
1346 /* Ok, now look for other blockages. */
1348 empty_rect (&rr);
1349 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1350 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1352 if (fdir == RIGHT && pull < 0)
1353 edir = UP;
1354 else if (fdir == RIGHT && pull > 0)
1355 edir = DOWN;
1356 else if (fdir == DOWN && pull < 0)
1357 edir = LEFT;
1358 else if (fdir == DOWN && pull > 0)
1359 edir = RIGHT;
1361 max = -1;
1362 for (i = 0; i < cn; i++)
1363 for (li = 0; li < cs[i]->n_lines; li++)
1365 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1366 continue;
1367 len = line_length (cs[i]->lines[li]);
1368 if (max > len || max == -1)
1369 max = len;
1371 dprintf ("c %s %4#mD cn %d pull %3d max %4#mS\n",
1372 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1374 switch (edir)
1376 case UP:
1377 rr.y1 = c->y - r1 - max;
1378 break;
1379 case DOWN:
1380 rr.y2 = c->y + r1 + max;
1381 break;
1382 case LEFT:
1383 rr.x1 = c->x - r1 - max;
1384 break;
1385 case RIGHT:
1386 rr.x2 = c->x + r1 + max;
1387 break;
1389 rr.x1 -= SB + 1;
1390 rr.x2 += SB + 1;
1391 rr.y1 -= SB + 1;
1392 rr.y2 += SB + 1;
1394 snap = 0;
1395 for (cb = corners; cb; cb = cb->next)
1397 int sep;
1398 if (DELETED (cb))
1399 continue;
1400 r1 = corner_radius (cb);
1401 if (cb->net == c->net && !cb->pad)
1402 continue;
1403 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1404 continue;
1405 switch (edir)
1407 #define ECHK(X,Y,LT) \
1408 for (i=0; i<cn; i++) \
1410 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1411 continue; \
1412 r2 = corner_radius(cs[i]); \
1413 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1414 continue; \
1415 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1416 continue; \
1417 if (cb->Y LT cs[i]->Y) \
1418 continue; \
1419 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1420 if (max > sep) \
1421 { max = sep; snap = 1; }\
1423 for (i=0; i<ln; i++) \
1425 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1426 continue; \
1427 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1428 continue; \
1429 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1430 - r1 - SB - 1); \
1431 if (max > sep) \
1432 { max = sep; snap = 1; }\
1434 case UP:
1435 ECHK (x, y, >=);
1436 break;
1437 case DOWN:
1438 ECHK (x, y, <=);
1439 break;
1440 case LEFT:
1441 ECHK (y, x, >=);
1442 break;
1443 case RIGHT:
1444 ECHK (y, x, <=);
1445 break;
1449 /* We must now check every line segment against our corners. */
1450 for (l = lines; l; l = l->next)
1452 int o, x1, x2, y1, y2;
1453 if (DELETED (l))
1454 continue;
1455 dprintf ("check line %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1456 if (l->s->net == c->net)
1458 dprintf (" same net\n");
1459 continue;
1461 o = line_orient (l, 0);
1462 /* We don't need to check perpendicular lines, because their
1463 corners already take care of it. */
1464 if ((fdir == RIGHT && (o == UP || o == DOWN))
1465 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1467 dprintf (" perpendicular\n");
1468 continue;
1471 /* Choose so that x1,y1 is closest to corner C */
1472 if ((fdir == RIGHT && l->s->x < l->e->x)
1473 || (fdir == DOWN && l->s->y < l->e->y))
1475 x1 = l->s->x;
1476 y1 = l->s->y;
1477 x2 = l->e->x;
1478 y2 = l->e->y;
1480 else
1482 x1 = l->e->x;
1483 y1 = l->e->y;
1484 x2 = l->s->x;
1485 y2 = l->s->y;
1488 /* Eliminate all lines outside our range */
1489 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1490 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1492 dprintf (" outside our range\n");
1493 continue;
1496 /* Eliminate all lines on the wrong side of us */
1497 if ((edir == UP && y1 > c->y && y2 > c->y)
1498 || (edir == DOWN && y1 < c->y && y2 < c->y)
1499 || (edir == LEFT && x1 > c->x && x2 > c->x)
1500 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1502 dprintf (" wrong side\n");
1503 continue;
1506 /* For now, cheat on diagonals */
1507 switch (edir)
1509 case RIGHT:
1510 if (x1 > x2)
1511 x1 = x2;
1512 break;
1513 case LEFT:
1514 if (x1 < x2)
1515 x1 = x2;
1516 break;
1517 case DOWN:
1518 if (y1 > y2)
1519 y1 = y2;
1520 break;
1521 case UP:
1522 if (y1 < y2)
1523 y1 = y2;
1524 break;
1527 /* Ok, now see how far we can get for each of our corners. */
1528 for (i = 0; i < cn; i++)
1530 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1531 int len = 0;
1532 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1533 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1534 continue;
1535 if (!intersecting_layers (cs[i]->layer, l->layer))
1536 continue;
1537 switch (edir)
1539 case RIGHT:
1540 len = x1 - c->x;
1541 break;
1542 case LEFT:
1543 len = c->x - x1;
1544 break;
1545 case DOWN:
1546 len = y1 - c->y;
1547 break;
1548 case UP:
1549 len = c->y - y1;
1550 break;
1552 len -= r;
1553 dprintf (" len is %#mS vs corner at %#mD\n", len, cs[i]->x, cs[i]->y);
1554 if (len <= 0)
1555 return 0;
1556 if (max > len)
1557 max = len;
1562 /* We must make sure that if a segment isn't being completely
1563 removed, that any vias and/or pads don't overlap. */
1564 done = 0;
1565 while (!done)
1567 done = 1;
1568 for (i = 0; i < cn; i++)
1569 for (li = 0; li < cs[i]->n_lines; li++)
1571 line_s *l = cs[i]->lines[li];
1572 corner_s *oc = other_corner (l, cs[i]);
1573 if (line_orient (l, cs[i]) != edir)
1574 continue;
1575 len = line_length (l);
1576 if (!oc->pad || !cs[i]->via)
1578 if (!is_hole (l->s) || !is_hole (l->e))
1579 continue;
1580 if (len == max)
1581 continue;
1583 len -= corner_radius (l->s);
1584 len -= corner_radius (l->e);
1585 len -= SB + 1;
1586 if (max > len)
1588 max = len;
1589 done = 0;
1594 if (max <= 0)
1595 return 0;
1596 switch (edir)
1598 case UP:
1599 len = c->y - max;
1600 break;
1601 case DOWN:
1602 len = c->y + max;
1603 break;
1604 case LEFT:
1605 len = c->x - max;
1606 break;
1607 case RIGHT:
1608 len = c->x + max;
1609 break;
1611 if (snap && max > Settings.Grid)
1613 if (pull < 0)
1614 len += Settings.Grid - 1;
1615 len = gridsnap (len);
1617 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1618 return 0;
1619 for (i = 0; i < cn; i++)
1621 if (fdir == RIGHT)
1623 max = len - cs[i]->y;
1624 move_corner (cs[i], cs[i]->x, len);
1626 else
1628 max = len - cs[i]->x;
1629 move_corner (cs[i], len, cs[i]->y);
1632 return max * pull;
1635 static int
1636 orthopull ()
1638 /* Look for straight runs which could be moved to reduce total trace
1639 length. */
1640 int any_sel = any_line_selected ();
1641 corner_s *c;
1642 int rv = 0;
1644 for (c = corners; c;)
1646 if (DELETED (c))
1647 continue;
1648 if (c->pin || c->pad)
1650 c = c->next;
1651 continue;
1653 next_corner = c;
1654 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1655 if (c != next_corner)
1657 c = next_corner;
1658 continue;
1660 rv += orthopull_1 (c, DOWN, UP, any_sel);
1661 if (c != next_corner)
1663 c = next_corner;
1664 continue;
1666 c = c->next;
1668 if (rv)
1669 pcb_printf ("orthopull: %ml mils saved\n", rv);
1670 return rv;
1673 static int
1674 debumpify ()
1676 /* Look for "U" shaped traces we can shorten (or eliminate) */
1677 int rv = 0;
1678 int any_selected = any_line_selected ();
1679 line_s *l, *l1, *l2;
1680 corner_s *c, *c1, *c2;
1681 rect_s rr, rp;
1682 int o, o1, o2, step, w;
1683 for (l = lines; l; l = l->next)
1685 if (DELETED (l))
1686 continue;
1687 if (!l->line)
1688 continue;
1689 if (any_selected && !selected (l->line))
1690 continue;
1691 if (!any_selected && autorouted_only && !autorouted (l->line))
1692 continue;
1693 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1694 continue;
1695 o = line_orient (l, 0);
1696 if (o == DIAGONAL)
1697 continue;
1698 l1 = other_line (l->s, l);
1699 if (!l1)
1700 continue;
1701 o1 = line_orient (l1, l->s);
1702 l2 = other_line (l->e, l);
1703 if (!l2)
1704 continue;
1705 o2 = line_orient (l2, l->e);
1706 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1707 continue;
1709 dprintf ("\nline: %#mD to %#mD\n", l->s->x, l->s->y, l->e->x, l->e->y);
1710 w = l->line->Thickness / 2 + SB + 1;
1711 empty_rect (&rr);
1712 add_line_to_rect (&rr, l1);
1713 add_line_to_rect (&rr, l2);
1714 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1715 rr.x1 -= w;
1716 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1717 rr.x2 += w;
1718 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1719 rr.y1 -= w;
1720 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1721 rr.y2 += w;
1722 dprintf ("range: x %#mS..%#mS y %#mS..%#mS\n", rr.x1, rr.x2, rr.y1, rr.y2);
1724 c1 = other_corner (l1, l->s);
1725 c2 = other_corner (l2, l->e);
1727 empty_rect (&rp);
1728 for (c = corners; c; c = c->next)
1730 if (DELETED (c))
1731 continue;
1732 if (c->net != l->s->net
1733 && intersecting_layers (c->layer, l->s->layer))
1734 add_corner_to_rect_if (&rp, c, &rr);
1736 if (rp.x1 == INT_MAX)
1738 rp.x1 = rr.x2;
1739 rp.x2 = rr.x1;
1740 rp.y1 = rr.y2;
1741 rp.y2 = rr.y1;
1743 dprintf ("pin r: x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1745 switch (o1)
1747 case LEFT:
1748 step = l->s->x - rp.x2 - w;
1749 step = gridsnap (step);
1750 if (step > l->s->x - c1->x)
1751 step = l->s->x - c1->x;
1752 if (step > l->s->x - c2->x)
1753 step = l->s->x - c2->x;
1754 if (step > 0)
1756 dprintf ("left step %#mS at %#mD\n", step, l->s->x, l->s->y);
1757 move_corner (l->s, l->s->x - step, l->s->y);
1758 move_corner (l->e, l->e->x - step, l->e->y);
1759 rv += step;
1761 break;
1762 case RIGHT:
1763 step = rp.x1 - l->s->x - w;
1764 step = gridsnap (step);
1765 if (step > c1->x - l->s->x)
1766 step = c1->x - l->s->x;
1767 if (step > c2->x - l->s->x)
1768 step = c2->x - l->s->x;
1769 if (step > 0)
1771 dprintf ("right step %#mS at %#mD\n", step, l->s->x, l->s->y);
1772 move_corner (l->s, l->s->x + step, l->s->y);
1773 move_corner (l->e, l->e->x + step, l->e->y);
1774 rv += step;
1776 break;
1777 case UP:
1778 if (rp.y2 == INT_MIN)
1779 rp.y2 = rr.y1;
1780 step = trim_step (l->s->y - rp.y2 - w,
1781 l->s->y - c1->y, l->s->y - c2->y);
1782 if (step > 0)
1784 dprintf ("up step %#mS at %#mD\n", step, l->s->x, l->s->y);
1785 move_corner (l->s, l->s->x, l->s->y - step);
1786 move_corner (l->e, l->e->x, l->e->y - step);
1787 rv += step;
1789 break;
1790 case DOWN:
1791 step = rp.y1 - l->s->y - w;
1792 step = gridsnap (step);
1793 if (step > c1->y - l->s->y)
1794 step = c1->y - l->s->y;
1795 if (step > c2->y - l->s->y)
1796 step = c2->y - l->s->y;
1797 if (step > 0)
1799 dprintf ("down step %#mS at %#mD\n", step, l->s->x, l->s->y);
1800 move_corner (l->s, l->s->x, l->s->y + step);
1801 move_corner (l->e, l->e->x, l->e->y + step);
1802 rv += step;
1804 break;
1806 check (0, l);
1809 rv += simple_optimizations ();
1810 if (rv)
1811 pcb_printf ("debumpify: %ml mils saved\n", rv / 50);
1812 return rv;
1815 static int
1816 simple_corner (corner_s * c)
1818 int o1, o2;
1819 if (c->pad || c->pin || c->via)
1820 return 0;
1821 if (c->n_lines != 2)
1822 return 0;
1823 o1 = line_orient (c->lines[0], c);
1824 o2 = line_orient (c->lines[1], c);
1825 if (ORIENT (o1) == ORIENT (o2))
1826 return 0;
1827 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1828 return 0;
1829 return 1;
1832 static int
1833 unjaggy_once ()
1835 /* Look for sequences of simple corners we can reduce. */
1836 int rv = 0;
1837 corner_s *c, *c0, *c1, *cc;
1838 int l, w, sel = any_line_selected ();
1839 int o0, o1, s0, s1;
1840 rect_s rr, rp;
1841 for (c = corners; c; c = c->next)
1843 if (DELETED (c))
1844 continue;
1845 if (!simple_corner (c))
1846 continue;
1847 if (!c->lines[0]->line || !c->lines[1]->line)
1848 continue;
1849 if (sel && !(selected (c->lines[0]->line)
1850 || selected (c->lines[1]->line)))
1851 continue;
1852 if (!sel && autorouted_only
1853 && !(autorouted (c->lines[0]->line)
1854 || autorouted (c->lines[1]->line)))
1855 continue;
1856 dprintf ("simple at %#mD\n", c->x, c->y);
1858 c0 = other_corner (c->lines[0], c);
1859 o0 = line_orient (c->lines[0], c);
1860 s0 = simple_corner (c0);
1862 c1 = other_corner (c->lines[1], c);
1863 o1 = line_orient (c->lines[1], c);
1864 s1 = simple_corner (c1);
1866 if (!s0 && !s1)
1867 continue;
1868 dprintf ("simples at %#mD\n", c->x, c->y);
1870 w = 1;
1871 for (l = 0; l < c0->n_lines; l++)
1872 if (c0->lines[l] != c->lines[0]
1873 && c0->lines[l]->layer == c->lines[0]->layer)
1875 int o = line_orient (c0->lines[l], c0);
1876 if (o == o1)
1877 w = 0;
1879 for (l = 0; l < c1->n_lines; l++)
1880 if (c1->lines[l] != c->lines[0]
1881 && c1->lines[l]->layer == c->lines[0]->layer)
1883 int o = line_orient (c1->lines[l], c1);
1884 if (o == o0)
1885 w = 0;
1887 if (!w)
1888 continue;
1889 dprintf ("orient ok\n");
1891 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1892 empty_rect (&rr);
1893 add_line_to_rect (&rr, c->lines[0]);
1894 add_line_to_rect (&rr, c->lines[1]);
1895 if (c->x != rr.x1)
1896 rr.x1 -= w;
1897 else
1898 rr.x2 += w;
1899 if (c->y != rr.y1)
1900 rr.y1 -= w;
1901 else
1902 rr.y2 += w;
1904 empty_rect (&rp);
1905 for (cc = corners; cc; cc = cc->next)
1907 if (DELETED (cc))
1908 continue;
1909 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1910 add_corner_to_rect_if (&rp, cc, &rr);
1912 dprintf ("rp x %#mS..%#mS y %#mS..%#mS\n", rp.x1, rp.x2, rp.y1, rp.y2);
1913 if (rp.x1 <= rp.x2) /* something triggered */
1914 continue;
1916 dprintf ("unjaggy at %#mD layer %d\n", c->x, c->y, c->layer);
1917 if (c->x == c0->x)
1918 move_corner (c, c1->x, c0->y);
1919 else
1920 move_corner (c, c0->x, c1->y);
1921 rv++;
1922 check (c, 0);
1924 rv += simple_optimizations ();
1925 check (c, 0);
1926 return rv;
1929 static int
1930 unjaggy ()
1932 int i, r = 0, j;
1933 for (i = 0; i < 100; i++)
1935 j = unjaggy_once ();
1936 if (j == 0)
1937 break;
1938 r += j;
1940 if (r)
1941 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1942 return r;
1945 static int
1946 vianudge ()
1948 /* Look for vias with all lines leaving the same way, try to nudge
1949 via to eliminate one or more of them. */
1950 int rv = 0;
1951 corner_s *c, *c2, *c3;
1952 line_s *l;
1953 unsigned char directions[MAX_LAYER];
1954 unsigned char counts[MAX_LAYER];
1956 memset (directions, 0, sizeof (directions));
1957 memset (counts, 0, sizeof (counts));
1959 for (c = corners; c; c = c->next)
1961 int o, i, vr, cr, oboth;
1962 int len = 0, saved = 0;
1964 if (DELETED (c))
1965 continue;
1967 if (!c->via)
1968 continue;
1970 memset (directions, 0, sizeof (directions));
1971 memset (counts, 0, sizeof (counts));
1973 for (i = 0; i < c->n_lines; i++)
1975 o = line_orient (c->lines[i], c);
1976 counts[c->lines[i]->layer]++;
1977 directions[c->lines[i]->layer] |= o;
1979 for (o = 0, i = 0; i < max_copper_layer; i++)
1980 if (counts[i] == 1)
1982 o = directions[i];
1983 break;
1985 switch (o)
1987 case LEFT:
1988 case RIGHT:
1989 oboth = LEFT | RIGHT;
1990 break;
1991 case UP:
1992 case DOWN:
1993 oboth = UP | DOWN;
1994 break;
1995 default:
1996 continue;
1998 for (i = 0; i < max_copper_layer; i++)
1999 if (counts[i] && directions[i] != o && directions[i] != oboth)
2000 goto vianudge_continue;
2002 c2 = 0;
2003 for (i = 0; i < c->n_lines; i++)
2005 int ll = line_length (c->lines[i]);
2006 if (line_orient (c->lines[i], c) != o)
2008 saved--;
2009 continue;
2011 saved++;
2012 if (c2 == 0 || len > ll)
2014 len = ll;
2015 c2 = other_corner (c->lines[i], c);
2018 if (c2->pad || c2->pin || c2->via)
2019 continue;
2021 /* Now look for clearance in the new position */
2022 vr = c->via->Thickness / 2 + SB + 1;
2023 for (c3 = corners; c3; c3 = c3->next)
2025 if (DELETED (c3))
2026 continue;
2027 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2029 cr = corner_radius (c3);
2030 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2031 goto vianudge_continue;
2034 for (l = lines; l; l = l->next)
2036 if (DELETED (l))
2037 continue;
2038 if (l->s->net != c->net)
2040 int ld = dist_line_to_point (l, c2);
2041 if (ld < l->line->Thickness / 2 + vr)
2042 goto vianudge_continue;
2046 /* at this point, we know we can move it */
2048 dprintf ("vianudge: nudging via at %#mD by %#mS saving %#mS\n",
2049 c->x, c->y, len, saved);
2050 rv += len * saved;
2051 move_corner (c, c2->x, c2->y);
2053 check (c, 0);
2055 vianudge_continue:
2056 continue;
2059 if (rv)
2060 pcb_printf ("vianudge: %ml mils saved\n", rv);
2061 return rv;
2064 static int
2065 viatrim ()
2067 /* Look for traces that can be moved to the other side of the board,
2068 to reduce the number of vias needed. For now, we look for simple
2069 lines, not multi-segmented lines. */
2070 line_s *l, *l2;
2071 int i, rv = 0, vrm = 0;
2072 int any_sel = any_line_selected ();
2074 for (l = lines; l; l = l->next)
2076 rect_s r;
2077 int my_layer, other_layer;
2079 if (DELETED (l))
2080 continue;
2081 if (!l->s->via)
2082 continue;
2083 if (!l->e->via)
2084 continue;
2085 if (any_sel && !selected (l->line))
2086 continue;
2087 if (!any_sel && autorouted_only && !autorouted (l->line))
2088 continue;
2090 my_layer = l->layer;
2091 other_layer = -1;
2092 dprintf ("line %p on layer %d from %#mD to %#mD\n", (void *) l,
2093 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2094 for (i = 0; i < l->s->n_lines; i++)
2095 if (l->s->lines[i] != l)
2097 if (other_layer == -1)
2099 other_layer = l->s->lines[i]->layer;
2100 dprintf ("noting other line %p on layer %d\n",
2101 (void *) (l->s->lines[i]), my_layer);
2103 else if (l->s->lines[i]->layer != other_layer)
2105 dprintf ("saw other line %p on layer %d (not %d)\n",
2106 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2107 my_layer);
2108 other_layer = -1;
2109 goto viatrim_other_corner;
2112 viatrim_other_corner:
2113 if (other_layer == -1)
2114 for (i = 0; i < l->e->n_lines; i++)
2115 if (l->e->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->e->lines[i]->layer != other_layer)
2125 dprintf ("saw end line on layer %d (not %d)\n",
2126 l->e->lines[i]->layer, other_layer);
2127 goto viatrim_continue;
2131 /* Now see if any other line intersects us. We don't need to
2132 check corners, because they'd either be pins/vias and
2133 already conflict, or pads, which we'll check here anyway. */
2134 empty_rect (&r);
2135 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2136 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2138 for (l2 = lines; l2; l2 = l2->next)
2140 if (DELETED (l2))
2141 continue;
2142 if (l2->s->net != l->s->net && l2->layer == other_layer)
2144 dprintf ("checking other line %#mD to %#mD\n", l2->s->x,
2145 l2->s->y, l2->e->x, l2->e->y);
2146 if (line_in_rect (&r, l2))
2148 dprintf ("line from %#mD to %#mD in the way\n",
2149 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2150 goto viatrim_continue;
2155 if (l->layer == other_layer)
2156 continue;
2157 move_line_to_layer (l, other_layer);
2158 rv++;
2160 viatrim_continue:
2161 continue;
2163 vrm = simple_optimizations ();
2164 if (rv > 0)
2165 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2166 return rv + vrm;
2169 static int
2170 automagic ()
2172 int more = 1, oldmore = 0;
2173 int toomany = 100;
2174 while (more != oldmore && --toomany)
2176 oldmore = more;
2177 more += debumpify ();
2178 more += unjaggy ();
2179 more += orthopull ();
2180 more += vianudge ();
2181 more += viatrim ();
2183 return more - 1;
2186 static int
2187 miter ()
2189 corner_s *c;
2190 int done, progress;
2191 int sel = any_line_selected ();
2192 int saved = 0;
2194 for (c = corners; c; c = c->next)
2196 if (DELETED (c))
2197 continue;
2198 c->miter = 0;
2199 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2201 int o1 = line_orient (c->lines[0], c);
2202 int o2 = line_orient (c->lines[1], c);
2203 if (ORIENT (o1) != ORIENT (o2)
2204 && o1 != DIAGONAL && o2 != DIAGONAL
2205 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2206 c->miter = -1;
2210 done = 0;
2211 progress = 1;
2212 while (!done && progress)
2214 done = 1;
2215 progress = 0;
2216 for (c = corners; c; c = c->next)
2218 if (DELETED (c))
2219 continue;
2220 if (c->miter == -1)
2222 int max = line_length (c->lines[0]);
2223 int len = line_length (c->lines[1]);
2224 int bloat;
2225 int ref, dist;
2226 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2227 int mx = 0, my = 0, x, y;
2228 int o1 = line_orient (c->lines[0], c);
2229 int o2 = line_orient (c->lines[1], c);
2231 if (c->pad || c->pin || c->via)
2233 c->miter = 0;
2234 progress = 1;
2235 continue;
2238 oc1 = other_corner (c->lines[0], c);
2239 oc2 = other_corner (c->lines[1], c);
2240 #if 0
2241 if (oc1->pad)
2242 oc1 = 0;
2243 if (oc2->pad)
2244 oc2 = 0;
2245 #endif
2247 if ((sel && !(selected (c->lines[0]->line)
2248 || selected (c->lines[1]->line)))
2249 || (!sel && autorouted_only
2250 && !(autorouted (c->lines[0]->line)
2251 || autorouted (c->lines[1]->line))))
2253 c->miter = 0;
2254 progress = 1;
2255 continue;
2258 if (max > len)
2259 max = len;
2260 switch (o1)
2262 case LEFT:
2263 mx = -1;
2264 break;
2265 case RIGHT:
2266 mx = 1;
2267 break;
2268 case UP:
2269 my = -1;
2270 break;
2271 case DOWN:
2272 my = 1;
2273 break;
2275 switch (o2)
2277 case LEFT:
2278 mx = -1;
2279 break;
2280 case RIGHT:
2281 mx = 1;
2282 break;
2283 case UP:
2284 my = -1;
2285 break;
2286 case DOWN:
2287 my = 1;
2288 break;
2290 ref = c->x * mx + c->y * my;
2291 dist = max;
2293 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2295 for (c2 = corners; c2; c2 = c2->next)
2297 if (DELETED (c2))
2298 continue;
2299 if (c2 != c && c2 != oc1 && c2 != oc2
2300 && c->x * mx <= c2->x * mx
2301 && c->y * my <= c2->y * my
2302 && c->net != c2->net
2303 && intersecting_layers (c->layer, c2->layer))
2305 int cr = corner_radius (c2);
2306 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2307 if (c->x != c2->x && c->y != c2->y)
2308 len -= cr;
2309 if (len < dist || (len == dist && c->miter != -1))
2311 dist = len;
2312 closest_corner = c2;
2317 if (closest_corner && closest_corner->miter == -1)
2319 done = 0;
2320 continue;
2323 #if 0
2324 if (dist < Settings.Grid)
2326 c->miter = 0;
2327 progress = 1;
2328 continue;
2331 dist -= dist % Settings.Grid;
2332 #endif
2333 if (dist <= 0)
2335 c->miter = 0;
2336 progress = 1;
2337 continue;
2340 x = c->x;
2341 y = c->y;
2342 switch (o1)
2344 case LEFT:
2345 x -= dist;
2346 break;
2347 case RIGHT:
2348 x += dist;
2349 break;
2350 case UP:
2351 y -= dist;
2352 break;
2353 case DOWN:
2354 y += dist;
2355 break;
2357 c2 = find_corner (x, y, c->layer);
2358 if (c2 != other_corner (c->lines[0], c))
2359 split_line (c->lines[0], c2);
2360 x = c->x;
2361 y = c->y;
2362 switch (o2)
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 move_corner (c, x, y);
2378 c->miter = 0;
2379 c2->miter = 0;
2380 progress = 1;
2381 saved++;
2385 return saved;
2388 static void
2389 classify_corner (corner_s * c, int this_net)
2391 int i;
2392 if (c->net == this_net)
2393 return;
2394 c->net = this_net;
2395 for (i = 0; i < c->n_lines; i++)
2396 classify_corner (other_corner (c->lines[i], c), this_net);
2399 static void
2400 classify_nets ()
2402 static int this_net = 1;
2403 corner_s *c;
2405 for (c = corners; c; c = c->next)
2407 if (DELETED (c))
2408 continue;
2409 if (c->net)
2410 continue;
2411 classify_corner (c, this_net);
2412 this_net++;
2416 #if 0
2417 /* Not used */
2418 static void
2419 dump_all ()
2421 corner_s *c;
2422 line_s *l;
2423 for (c = corners; c; c = c->next)
2425 if (DELETED (c))
2426 continue;
2427 printf ("%p corner %d,%d layer %d net %d\n",
2428 (void *) c, c->x, c->y, c->layer, c->net);
2430 for (l = lines; l; l = l->next)
2432 if (DELETED (l))
2433 continue;
2434 printf ("%p line %p to %p layer %d\n",
2435 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2438 #endif
2440 #if 0
2441 static void
2442 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2444 int ox = c->x;
2445 int oy = c->y;
2446 int l;
2447 if (prev_corner && (c->pin || c->pad))
2448 return;
2449 move_corner (c, ox + dx, oy + dy);
2450 for (l = 0; l < c->n_lines; l++)
2452 corner_s *oc = other_corner (c->lines[l], c);
2453 if (oc == prev_corner)
2454 continue;
2455 if (dx && oc->x == ox)
2456 nudge_corner (oc, dx, 0, c);
2457 if (dy && oc->y == oy)
2458 nudge_corner (oc, 0, dy, c);
2461 #endif
2463 static line_s *
2464 choose_example_line (corner_s * c1, corner_s * c2)
2466 int ci, li;
2467 corner_s *c[2];
2468 c[0] = c1;
2469 c[1] = c2;
2470 dprintf ("choose_example_line\n");
2471 for (ci = 0; ci < 2; ci++)
2472 for (li = 0; li < c[ci]->n_lines; li++)
2474 dprintf (" try[%d,%d] \033[36m<%#mD-%#mD t%#mS c%#mS f%s>\033[0m\n",
2475 ci, li,
2476 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2477 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2478 c[ci]->lines[li]->line->Thickness,
2479 c[ci]->lines[li]->line->Clearance,
2480 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2481 /* Pads are disqualified, as we want to mimic a trace line. */
2482 if (c[ci]->lines[li]->line == (LineType *) c[ci]->pad)
2484 dprintf (" bad, pad\n");
2485 continue;
2487 /* Lines on layers that don't connect to the other pad are bad too. */
2488 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2490 dprintf (" bad, layers\n");
2491 continue;
2493 dprintf (" good\n");
2494 return c[ci]->lines[li];
2496 dprintf ("choose_example_line: none found!\n");
2497 return 0;
2500 static int
2501 connect_corners (corner_s * c1, corner_s * c2)
2503 int layer;
2504 line_s *ex = choose_example_line (c1, c2);
2505 LineType *example = ex->line;
2507 dprintf
2508 ("connect_corners \033[32m%#mD to %#mD, example line %#mD to %#mD l%d\033[0m\n",
2509 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2510 ex->layer);
2512 layer = ex->layer;
2514 /* Assume c1 is the moveable one. */
2515 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2517 int nx, ny;
2518 /* Extend the line */
2519 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2520 nx = c1->x, ny = c2->y;
2521 else
2522 nx = c2->x, ny = c1->y;
2523 if (nx != c2->x || ny != c2->y)
2525 move_corner (c1, nx, ny);
2526 new_line (c1, c2, layer, example);
2527 return 1;
2529 else
2531 move_corner (c1, nx, ny);
2532 return 1;
2535 else
2537 corner_s *nc = find_corner (c1->x, c2->y, layer);
2538 new_line (c1, nc, layer, example);
2539 new_line (nc, c2, layer, example);
2540 return 0;
2544 static void
2545 pinsnap ()
2547 corner_s *c;
2548 int best_dist[MAX_LAYER + 1];
2549 corner_s *best_c[MAX_LAYER + 1];
2550 int l, got_one;
2551 int left = 0, right = 0, top = 0, bottom = 0;
2552 PinType *pin;
2553 int again = 1;
2555 int close = 0;
2556 corner_s *c2;
2558 /* Look for pins that have no connections. See if there's a corner
2559 close by that should be connected to it. This usually happens
2560 when the MUCS router needs to route to an off-grid pin. */
2561 while (again)
2563 again = 0;
2564 for (c = corners; c; c = c->next)
2566 if (DELETED (c))
2567 continue;
2568 if (!(c->pin || c->via || c->pad))
2569 continue;
2571 pin = 0;
2573 dprintf ("\ncorner %s\n", corner_name (c));
2574 if (c->pin || c->via)
2576 pin = c->pin ? c->pin : c->via;
2577 close = pin->Thickness / 2;
2578 left = c->x - close;
2579 right = c->x + close;
2580 bottom = c->y - close;
2581 top = c->y + close;
2583 else if (c->pad)
2585 close = c->pad->Thickness / 2 + 1;
2586 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2587 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2588 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2589 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2590 if (c->pad->Point1.X == c->pad->Point2.X)
2592 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2593 dprintf ("pad y %#mS %#mS hy %#mS c %#mS\n", c->pad->Point1.Y,
2594 c->pad->Point2.Y, hy, c->y);
2595 if (c->y < hy)
2596 top = hy;
2597 else
2598 bottom = hy + 1;
2600 else
2602 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2603 dprintf ("pad x %#mS %#mS hx %#mS c %#mS\n", c->pad->Point1.X,
2604 c->pad->Point2.X, hx, c->x);
2605 if (c->x < hx)
2606 right = hx;
2607 else
2608 left = hx + 1;
2612 dprintf ("%s x %#mS-%#mS y %#mS-%#mS\n", corner_name (c), left, right, bottom, top);
2613 for (l = 0; l <= max_copper_layer; l++)
2615 best_dist[l] = close * 2;
2616 best_c[l] = 0;
2618 got_one = 0;
2619 for (c2 = corners; c2; c2 = c2->next)
2621 int lt;
2623 if (DELETED (c2))
2624 continue;
2625 lt = corner_radius (c2);
2626 if (c2->n_lines
2627 && c2 != c
2628 && !(c2->pin || c2->pad || c2->via)
2629 && intersecting_layers (c->layer, c2->layer)
2630 && c2->x >= left - lt
2631 && c2->x <= right + lt
2632 && c2->y >= bottom - lt && c2->y <= top + lt)
2634 int d = dist (c->x, c->y, c2->x, c2->y);
2635 if (pin && d > pin->Thickness / 2 + lt)
2636 continue;
2637 if (c2->n_lines == 1)
2639 got_one++;
2640 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2641 corner_name (c));
2642 connect_corners (c, c2);
2643 again = 1;
2644 continue;
2646 if (best_c[c2->layer] == 0
2647 || c2->n_lines < best_c[c2->layer]->n_lines
2648 || (d < best_dist[c2->layer]
2649 && c2->n_lines <= best_c[c2->layer]->n_lines))
2651 best_dist[c2->layer] = d;
2652 best_c[c2->layer] = c2;
2653 dprintf ("layer %d best now %s\n", c2->layer,
2654 corner_name (c2));
2657 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2659 for (l = 0; l <= max_copper_layer; l++)
2660 if (best_c[l])
2661 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2662 for (l = 0; l <= max_copper_layer; l++)
2663 if (best_c[l])
2665 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2666 corner_name (c));
2667 connect_corners (best_c[l], c);
2668 again = 1;
2669 continue;
2676 /* Now look for line ends that don't connect, see if they need to be
2677 extended to intersect another line. */
2678 for (c = corners; c; c = c->next)
2680 line_s *l, *t;
2681 int lo;
2683 if (DELETED (c))
2684 continue;
2685 if (c->pin || c->via || c->pad)
2686 continue;
2687 if (c->n_lines != 1)
2688 continue;
2690 l = c->lines[0];
2691 lo = line_orient (l, c);
2692 dprintf ("line end %#mD orient %d\n", c->x, c->y, lo);
2694 for (t = lines; t; t = t->next)
2696 if (DELETED (t))
2697 continue;
2698 if (t->layer != c->lines[0]->layer)
2699 continue;
2700 switch (lo) /* remember, orient is for the line relative to the corner */
2702 case LEFT:
2703 if (t->s->x == t->e->x
2704 && c->x < t->s->x
2705 && t->s->x <
2706 c->x + (l->line->Thickness + t->line->Thickness) / 2
2707 && ((t->s->y < c->y && c->y < t->e->y)
2708 || (t->e->y < c->y && c->y < t->s->y)))
2710 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2711 move_corner (c, t->s->x, c->y);
2713 break;
2714 case RIGHT:
2715 if (t->s->x == t->e->x
2716 && c->x > t->s->x
2717 && t->s->x >
2718 c->x - (l->line->Thickness + t->line->Thickness) / 2
2719 && ((t->s->y < c->y && c->y < t->e->y)
2720 || (t->e->y < c->y && c->y < t->s->y)))
2722 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2723 move_corner (c, t->s->x, c->y);
2725 break;
2726 case UP:
2727 if (t->s->y == t->e->y
2728 && c->y < t->s->y
2729 && t->s->y <
2730 c->y + (l->line->Thickness + t->line->Thickness) / 2
2731 && ((t->s->x < c->x && c->x < t->e->x)
2732 || (t->e->x < c->x && c->x < t->s->x)))
2734 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2735 move_corner (c, c->x, t->s->y);
2737 break;
2738 case DOWN:
2739 if (t->s->y == t->e->y
2740 && c->y > t->s->y
2741 && t->s->y >
2742 c->y - (l->line->Thickness + t->line->Thickness) / 2
2743 && ((t->s->x < c->x && c->x < t->e->x)
2744 || (t->e->x < c->x && c->x < t->s->x)))
2746 dprintf ("found %#mD - %#mD\n", t->s->x, t->s->y, t->e->x, t->e->y);
2747 move_corner (c, c->x, t->s->y);
2749 break;
2755 static int
2756 pad_orient (PadType * p)
2758 if (p->Point1.X == p->Point2.X)
2759 return O_VERT;
2760 if (p->Point1.Y == p->Point2.Y)
2761 return O_HORIZ;
2762 return DIAGONAL;
2765 static void
2766 padcleaner ()
2768 line_s *l, *nextl;
2769 int close;
2770 rect_s r;
2772 dprintf ("\ndj: padcleaner\n");
2773 for (l = lines; l; l = nextl)
2775 nextl = l->next;
2777 if (l->is_pad)
2778 continue;
2780 if (DELETED (l))
2781 continue;
2783 dprintf ("dj: line %p\n", (void *) l);
2784 check (0, l);
2786 if (l->s->pad && l->s->pad == l->e->pad)
2787 continue;
2789 ALLPAD_LOOP (PCB->Data);
2791 int layerflag =
2792 TEST_FLAG (ONSOLDERFLAG, element) ? LT_BOTTOM : LT_TOP;
2794 if (layer_type[l->layer] != layerflag)
2795 continue;
2797 empty_rect (&r);
2798 close = pad->Thickness / 2 + 1;
2799 add_point_to_rect (&r, pad->Point1.X, pad->Point1.Y, close - SB / 2);
2800 add_point_to_rect (&r, pad->Point2.X, pad->Point2.Y, close - SB / 2);
2801 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2802 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2803 && ORIENT (line_orient (l, 0)) == pad_orient (pad))
2805 dprintf
2806 ("padcleaner %#mD-%#mD %#mS vs line %#mD-%#mD %#mS\n",
2807 pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y,
2808 pad->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2809 l->line->Thickness);
2810 remove_line (l);
2811 goto next_line;
2814 ENDALL_LOOP;
2815 next_line:;
2819 static void
2820 grok_layer_groups ()
2822 int i, j, f;
2823 LayerGroupType *l = &(PCB->LayerGroups);
2825 solder_layer = component_layer = -1;
2826 for (i = 0; i < max_copper_layer; i++)
2828 layer_type[i] = 0;
2829 layer_groupings[i] = 0;
2831 for (i = 0; i < max_group; i++)
2833 f = 0;
2834 for (j = 0; j < l->Number[i]; j++)
2836 if (l->Entries[i][j] == bottom_silk_layer)
2837 f |= LT_BOTTOM;
2838 if (l->Entries[i][j] == top_silk_layer)
2839 f |= LT_TOP;
2841 for (j = 0; j < l->Number[i]; j++)
2843 if (l->Entries[i][j] < max_copper_layer)
2845 layer_type[l->Entries[i][j]] |= f;
2846 layer_groupings[l->Entries[i][j]] = i;
2847 if (solder_layer == -1 && f == LT_BOTTOM)
2848 solder_layer = l->Entries[i][j];
2849 if (component_layer == -1 && f == LT_TOP)
2850 component_layer = l->Entries[i][j];
2856 static const char djopt_syntax[] =
2857 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull|splitlines)\n"
2858 "djopt(auto) - all of the above\n"
2859 "djopt(miter)";
2861 static const char djopt_help[] =
2862 "Perform various optimizations on the current board.";
2864 /* %start-doc actions djopt
2866 The different types of optimizations change your board in order to
2867 reduce the total trace length and via count.
2869 @table @code
2871 @item debumpify
2872 Looks for U-shaped traces that can be shortened or eliminated.
2874 @item unjaggy
2875 Looks for corners which could be flipped to eliminate one or more
2876 corners (i.e. jaggy lines become simpler).
2878 @item simple
2879 Removing uneeded vias, replacing two or more trace segments in a row
2880 with a single segment. This is usually performed automatically after
2881 other optimizations.
2883 @item vianudge
2884 Looks for vias where all traces leave in the same direction. Tries to
2885 move via in that direction to eliminate one of the traces (and thus a
2886 corner).
2888 @item viatrim
2889 Looks for traces that go from via to via, where moving that trace to a
2890 different layer eliminates one or both vias.
2892 @item orthopull
2893 Looks for chains of traces all going in one direction, with more
2894 traces orthogonal on one side than on the other. Moves the chain in
2895 that direction, causing a net reduction in trace length, possibly
2896 eliminating traces and/or corners.
2898 @item splitlines
2899 Looks for lines that pass through vias, pins, or pads, and splits them
2900 into separate lines so they can be managed separately.
2902 @item auto
2903 Performs the above options, repeating until no further optimizations
2904 can be made.
2906 @item miter
2907 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2908 RF losses and trace length.
2910 @end table
2912 %end-doc */
2914 static int
2915 ActionDJopt (int argc, char **argv, Coord x, Coord y)
2917 char *arg = argc > 0 ? argv[0] : 0;
2918 int layn, saved = 0;
2919 corner_s *c;
2921 hid_action("Busy");
2923 lines = 0;
2924 corners = 0;
2926 grok_layer_groups ();
2928 ELEMENT_LOOP (PCB->Data);
2929 PIN_LOOP (element);
2931 c = find_corner (pin->X, pin->Y, -1);
2932 c->pin = pin;
2934 END_LOOP;
2935 PAD_LOOP (element);
2937 int layern =
2938 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
2939 line_s *ls = (line_s *) malloc (sizeof (line_s));
2940 ls->next = lines;
2941 lines = ls;
2942 ls->is_pad = 1;
2943 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
2944 ls->s->pad = pad;
2945 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
2946 ls->e->pad = pad;
2947 ls->layer = layern;
2948 ls->line = (LineType *) pad;
2949 add_line_to_corner (ls, ls->s);
2950 add_line_to_corner (ls, ls->e);
2953 END_LOOP;
2954 END_LOOP;
2955 VIA_LOOP (PCB->Data);
2956 /* hace don't mess with vias that have thermals */
2957 /* but then again don't bump into them
2958 if (!TEST_FLAG(ALLTHERMFLAGS, via))
2961 c = find_corner (via->X, via->Y, -1);
2962 c->via = via;
2964 END_LOOP;
2965 check (0, 0);
2967 if (NSTRCMP (arg, "splitlines") == 0)
2969 if (canonicalize_lines ())
2970 IncrementUndoSerialNumber ();
2971 return 0;
2974 for (layn = 0; layn < max_copper_layer; layn++)
2976 LayerType *layer = LAYER_PTR (layn);
2978 LINE_LOOP (layer);
2980 line_s *ls;
2982 if(autorouted_only && !autorouted (line))
2983 continue;
2985 /* don't mess with thermals */
2986 if (TEST_FLAG (USETHERMALFLAG, line))
2987 continue;
2989 if (line->Point1.X == line->Point2.X &&
2990 line->Point1.Y == line->Point2.Y)
2992 RemoveLine (layer, line);
2993 continue;
2996 ls = (line_s *) malloc (sizeof (line_s));
2997 ls->next = lines;
2998 lines = ls;
2999 ls->is_pad = 0;
3000 ls->s = find_corner (line->Point1.X, line->Point1.Y, layn);
3001 ls->e = find_corner (line->Point2.X, line->Point2.Y, layn);
3002 ls->line = line;
3003 add_line_to_corner (ls, ls->s);
3004 add_line_to_corner (ls, ls->e);
3005 ls->layer = layn;
3007 END_LOOP;
3010 check (0, 0);
3011 pinsnap ();
3012 canonicalize_lines ();
3013 check (0, 0);
3014 classify_nets ();
3015 /*dump_all(); */
3016 check (0, 0);
3018 if (NSTRCMP (arg, "debumpify") == 0)
3019 saved += debumpify ();
3020 else if (NSTRCMP (arg, "unjaggy") == 0)
3021 saved += unjaggy ();
3022 else if (NSTRCMP (arg, "simple") == 0)
3023 saved += simple_optimizations ();
3024 else if (NSTRCMP (arg, "vianudge") == 0)
3025 saved += vianudge ();
3026 else if (NSTRCMP (arg, "viatrim") == 0)
3027 saved += viatrim ();
3028 else if (NSTRCMP (arg, "orthopull") == 0)
3029 saved += orthopull ();
3030 else if (NSTRCMP (arg, "auto") == 0)
3031 saved += automagic ();
3032 else if (NSTRCMP (arg, "miter") == 0)
3033 saved += miter ();
3034 else
3036 printf ("unknown command: %s\n", arg);
3037 return 1;
3040 padcleaner ();
3042 check (0, 0);
3043 if (saved)
3044 IncrementUndoSerialNumber ();
3045 return 0;
3048 HID_Action djopt_action_list[] = {
3049 {"djopt", 0, ActionDJopt,
3050 djopt_help, djopt_syntax}
3052 {"OptAutoOnly", 0, djopt_set_auto_only,
3053 djopt_sao_help, djopt_sao_syntax}
3056 REGISTER_ACTIONS (djopt_action_list)