Move internationalization macros to one header
[geda-pcb/gde.git] / src / djopt.c
blobc8ae9611ff0e583e06077c01598d8133aa0c02c2
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2003 DJ Delorie
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
25 * dj@delorie.com
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include "global.h"
35 #include <memory.h>
36 #include <limits.h>
39 #include "data.h"
40 #include "create.h"
41 #include "remove.h"
42 #include "move.h"
43 #include "draw.h"
44 #include "undo.h"
45 #include "strflags.h"
46 #include "find.h"
48 #ifdef HAVE_LIBDMALLOC
49 #include <dmalloc.h>
50 #endif
52 RCSID ("$Id$");
54 #ifndef HAVE_RINT
55 #define rint(x) (ceil((x) - 0.5))
56 #endif
58 #define dprintf if(0)printf
60 #define selected(x) TEST_FLAG (SELECTEDFLAG, (x))
61 #define autorouted(x) TEST_FLAG (AUTOFLAG, (x))
63 #define SB (PCB->Bloat+1)
65 /* must be 2^N-1 */
66 #define INC 7
68 #define O_HORIZ 0x10
69 #define O_VERT 0x20
70 #define LEFT 0x11
71 #define RIGHT 0x12
72 #define UP 0x24
73 #define DOWN 0x28
74 #define DIAGONAL 0xf0
75 #define ORIENT(x) ((x) & 0xf0)
76 #define DIRECT(x) ((x) & 0x0f)
78 /* Manhattan length of the longest "freckle" */
79 #define LONGEST_FRECKLE 2
81 struct line_s;
83 typedef struct corner_s
85 int layer;
86 struct corner_s *next;
87 int x, y;
88 int net;
89 PinType *via;
90 PadType *pad;
91 PinType *pin;
92 int miter;
93 int n_lines;
94 struct line_s **lines;
95 } corner_s;
97 typedef struct line_s
99 int layer;
100 struct line_s *next;
101 corner_s *s, *e;
102 LineType *line;
103 } line_s;
105 typedef struct rect_s
107 int x1, y1, x2, y2;
108 } rect_s;
110 #define DELETE(q) (q)->layer = 0xdeadbeef
111 #define DELETED(q) ((q)->layer == 0xdeadbeef)
113 static corner_s *corners, *next_corner = 0;
114 static line_s *lines;
116 static int layer_groupings[MAX_LAYER];
117 static char layer_type[MAX_LAYER];
118 #define LT_COMPONENT 1
119 #define LT_SOLDER 2
121 static int autorouted_only = 1;
123 static const char djopt_sao_syntax[] = "OptAutoOnly()";
125 static const char djopt_sao_help[] =
126 "Toggles the optimize-only-autorouted flag.";
128 /* %start-doc actions OptAutoOnly
130 The original purpose of the trace optimizer was to clean up the traces
131 created by the various autorouters that have been used with PCB. When
132 a board has a mix of autorouted and carefully hand-routed traces, you
133 don't normally want the optimizer to move your hand-routed traces.
134 But, sometimes you do. By default, the optimizer only optimizes
135 autorouted traces. This action toggles that setting, so that you can
136 optimize hand-routed traces also.
138 %end-doc */
141 djopt_set_auto_only (int argc, char **argv, int x, int y)
143 autorouted_only = autorouted_only ? 0 : 1;
144 return 0;
147 static int
148 djopt_get_auto_only (int dummy)
150 return autorouted_only;
153 HID_Flag djopt_flag_list[] = {
154 {"optautoonly", djopt_get_auto_only, 0}
157 REGISTER_FLAGS (djopt_flag_list)
158 #define line_is_pad(l) ((l)->line == (LineType *)(l)->s->pad)
159 static char *element_name_for (corner_s * c)
161 int i, p;
162 ElementType *e;
164 for (i = 0; i < PCB->Data->ElementN; i++)
166 e = PCB->Data->Element + i;
167 for (p = 0; p < e->PinN; p++)
168 if (e->Pin + p == c->pin)
169 return e->Name[1].TextString;
170 for (p = 0; p < e->PadN; p++)
171 if (e->Pad + p == c->pad)
172 return e->Name[1].TextString;
174 return "unknown";
177 static char *
178 corner_name (corner_s * c)
180 static char buf[4][100];
181 static int bn = 0;
182 char *bp;
183 bn = (bn + 1) % 4;
185 if (c->net == 0xf1eef1ee)
187 sprintf (buf[bn], "\033[31m[%p freed corner]\033[0m", (void *) c);
188 return buf[bn];
191 sprintf (buf[bn], "\033[%dm[%p ",
192 (c->pin || c->pad || c->via) ? 33 : 34, (void *) c);
193 bp = buf[bn] + strlen (buf[bn]);
195 if (c->pin)
196 sprintf (bp, "pin %s:%s at %d,%d", element_name_for (c), c->pin->Number,
197 c->x, c->y);
198 else if (c->via)
199 sprintf (bp, "via at %d,%d", c->x, c->y);
200 else if (c->pad)
202 sprintf (bp, "pad %s:%s at %d,%d (%d,%d-%d,%d)",
203 element_name_for (c), c->pad->Number, c->x, c->y,
204 c->pad->Point1.X, c->pad->Point1.Y,
205 c->pad->Point2.X, c->pad->Point2.Y);
207 else
208 sprintf (bp, "at %d,%d", c->x, c->y);
209 sprintf (bp + strlen (bp), " n%d l%d]\033[0m", c->n_lines, c->layer);
210 return buf[bn];
213 static int solder_layer, component_layer;
215 static void
216 dj_abort (char *msg, ...)
218 va_list a;
219 va_start (a, msg);
220 vprintf (msg, a);
221 va_end (a);
222 fflush (stdout);
223 abort ();
226 #if 1
227 #define check(c,l)
228 #else
229 #define check(c,l) check2(__LINE__,c,l)
230 static void
231 check2 (int srcline, corner_s * c, line_s * l)
233 int saw_c = 0, saw_l = 0;
234 corner_s *cc;
235 line_s *ll;
236 int i;
238 for (cc = corners; cc; cc = cc->next)
240 if (DELETED (cc))
241 continue;
242 if (cc == c)
243 saw_c = 1;
244 for (i = 0; i < cc->n_lines; i++)
245 if (cc->lines[i]->s != cc && cc->lines[i]->e != cc)
246 dj_abort ("check:%d: cc has line without backref\n", srcline);
247 if (cc->via && (cc->x != cc->via->X || cc->y != cc->via->Y))
248 dj_abort ("check:%d: via not at corner\n", srcline);
249 if (cc->pin && (cc->x != cc->pin->X || cc->y != cc->pin->Y))
250 dj_abort ("check:%d: pin not at corner\n", srcline);
252 if (c && !saw_c)
253 dj_abort ("check:%d: corner not in corners list\n", srcline);
254 for (ll = lines; ll; ll = ll->next)
256 if (DELETED (ll))
257 continue;
258 if (ll == l)
259 saw_l = 1;
260 for (i = 0; i < ll->s->n_lines; i++)
261 if (ll->s->lines[i] == ll)
262 break;
263 if (i == ll->s->n_lines)
264 dj_abort ("check:%d: ll->s has no backref\n", srcline);
265 for (i = 0; i < ll->e->n_lines; i++)
266 if (ll->e->lines[i] == ll)
267 break;
268 if (i == ll->e->n_lines)
269 dj_abort ("check:%d: ll->e has no backref\n", srcline);
270 if (!line_is_pad (ll)
271 && (ll->s->x != ll->line->Point1.X
272 || ll->s->y != ll->line->Point1.Y
273 || ll->e->x != ll->line->Point2.X
274 || ll->e->y != ll->line->Point2.Y))
276 printf ("line: %d,%d to %d,%d pcbline: %d,%d to %d,%d\n",
277 ll->s->x, ll->s->y,
278 ll->e->x, ll->e->y,
279 ll->line->Point1.X,
280 ll->line->Point1.Y, ll->line->Point2.X, ll->line->Point2.Y);
281 dj_abort ("check:%d: line doesn't match pcbline\n", srcline);
284 if (l && !saw_l)
285 dj_abort ("check:%d: line not in lines list\n", srcline);
288 #endif
290 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
292 static int
293 gridsnap (int n)
295 if (n <= 0)
296 return 0;
297 return n - n % (int) (Settings.Grid);
300 /* Avoid commonly used names. */
302 static int
303 djabs (int x)
305 return x > 0 ? x : -x;
308 static int
309 djmax (int x, int y)
311 return x > y ? x : y;
314 static int
315 djmin (int x, int y)
317 return x < y ? x : y;
321 * Find distance between 2 points. We use floating point math here
322 * because we can fairly easily overflow a 32 bit integer here. In
323 * fact it only takes 0.46" to do so.
325 static int
326 dist (int x1, int y1, int x2, int y2)
328 double dx1, dy1, dx2, dy2, d;
330 dx1 = (double) x1;
331 dy1 = (double) y1;
332 dx2 = (double) x2;
333 dy2 = (double) y2;
335 d = sqrt ((dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2));
336 d = rint (d);
338 return (int) d;
341 static int
342 line_length (line_s * l)
344 if (l->s->x == l->e->x)
345 return djabs (l->s->y - l->e->y);
346 if (l->s->y == l->e->y)
347 return djabs (l->s->x - l->e->x);
348 return dist (l->s->x, l->s->y, l->e->x, l->e->y);
351 static int
352 dist_ltp2 (int dx, int y, int y1, int y2)
354 if (y1 > y2)
355 SWAP (y1, y2);
356 if (y < y1)
357 return dist (dx, y, 0, y1);
358 if (y > y2)
359 return dist (dx, y, 0, y2);
360 return djabs (dx);
364 sqr (int a)
366 return a * a;
369 static int
370 intersecting_layers (int l1, int l2)
372 if (l1 == -1 || l2 == -1)
373 return 1;
374 if (l1 == l2)
375 return 1;
376 if (layer_groupings[l1] == layer_groupings[l2])
377 return 1;
378 return 0;
381 static int
382 dist_line_to_point (line_s * l, corner_s * c)
384 double len, r, d;
385 /* We can do this quickly if l is vertical or horizontal. */
386 if (l->s->x == l->e->x)
387 return dist_ltp2 (l->s->x - c->x, c->y, l->s->y, l->e->y);
388 if (l->s->y == l->e->y)
389 return dist_ltp2 (l->s->y - c->y, c->x, l->s->x, l->e->x);
391 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
392 len = sqrt (sqr (l->s->x - l->e->x) + sqr (l->s->y - l->e->y));
393 if (len == 0)
394 return dist (l->s->x, l->s->y, c->x, c->y);
396 (l->s->y - c->y) * (l->s->y - l->e->y) + (l->s->x - c->x) * (l->s->x -
397 l->e->x);
398 r /= len * len;
399 if (r < 0)
400 return dist (l->s->x, l->s->y, c->x, c->y);
401 if (r > 1)
402 return dist (l->e->x, l->e->y, c->x, c->y);
404 (l->e->y - l->s->y) * (c->x * l->s->x) + (l->e->x - l->s->x) * (c->y -
405 l->s->y);
406 return (int) (d / len);
409 static int
410 line_orient (line_s * l, corner_s * c)
412 int x1, y1, x2, y2;
413 if (c == l->s)
415 x1 = l->s->x;
416 y1 = l->s->y;
417 x2 = l->e->x;
418 y2 = l->e->y;
420 else
422 x1 = l->e->x;
423 y1 = l->e->y;
424 x2 = l->s->x;
425 y2 = l->s->y;
427 if (x1 == x2)
429 if (y1 < y2)
430 return DOWN;
431 return UP;
433 else if (y1 == y2)
435 if (x1 < x2)
436 return RIGHT;
437 return LEFT;
439 return DIAGONAL;
442 #if 0
443 /* Not used */
444 static corner_s *
445 common_corner (line_s * l1, line_s * l2)
447 if (l1->s == l2->s || l1->s == l2->e)
448 return l1->s;
449 if (l1->e == l2->s || l1->e == l2->e)
450 return l1->e;
451 dj_abort ("common_corner: no common corner found\n");
452 return NULL;
454 #endif
456 static corner_s *
457 other_corner (line_s * l, corner_s * c)
459 if (l->s == c)
460 return l->e;
461 if (l->e == c)
462 return l->s;
463 dj_abort ("other_corner: neither corner passed\n");
464 return NULL;
467 static corner_s *
468 find_corner_if (int x, int y, int l)
470 corner_s *c;
471 for (c = corners; c; c = c->next)
473 if (DELETED (c))
474 continue;
475 if (c->x != x || c->y != y)
476 continue;
477 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
478 continue;
479 return c;
481 return 0;
484 static corner_s *
485 find_corner (int x, int y, int l)
487 corner_s *c;
488 for (c = corners; c; c = c->next)
490 if (DELETED (c))
491 continue;
492 if (c->x != x || c->y != y)
493 continue;
494 if (!(c->layer == -1 || intersecting_layers (c->layer, l)))
495 continue;
496 return c;
498 c = (corner_s *) malloc (sizeof (corner_s));
499 c->next = corners;
500 corners = c;
501 c->x = x;
502 c->y = y;
503 c->net = 0;
504 c->via = 0;
505 c->pad = 0;
506 c->pin = 0;
507 c->layer = l;
508 c->n_lines = 0;
509 c->lines = (line_s **) malloc (INC * sizeof (line_s *));
510 return c;
513 static void
514 add_line_to_corner (line_s * l, corner_s * c)
516 int n;
517 n = (c->n_lines + 1 + INC) & ~INC;
518 c->lines = (line_s **) realloc (c->lines, n * sizeof (line_s *));
519 c->lines[c->n_lines] = l;
520 c->n_lines++;
521 dprintf ("add_line_to_corner %d %d\n", c->x, c->y);
524 static LineType *
525 create_pcb_line (int layer, int x1, int y1, int x2, int y2,
526 int thick, int clear, FlagType flags)
528 char *from, *to;
529 LineType *nl;
530 LayerType *lyr = LAYER_PTR (layer);
532 from = (char *) lyr->Line;
533 nl = CreateNewLineOnLayer (PCB->Data->Layer + layer,
534 x1, y1, x2, y2, thick, clear, flags);
535 AddObjectToCreateUndoList (LINE_TYPE, lyr, nl, nl);
537 to = (char *) lyr->Line;
538 if (from != to)
540 line_s *lp;
541 for (lp = lines; lp; lp = lp->next)
543 if (DELETED (lp))
544 continue;
545 if ((char *) (lp->line) >= from
546 && (char *) (lp->line) <= from + lyr->LineN * sizeof (LineType))
547 lp->line = (LineType *) ((char *) (lp->line) + (to - from));
550 return nl;
553 static void
554 new_line (corner_s * s, corner_s * e, int layer, LineType * example)
556 line_s *ls;
558 if (layer >= max_layer)
559 dj_abort ("layer %d\n", layer);
561 if (example == NULL)
562 dj_abort ("NULL example passed to new_line()\n", layer);
564 if (s->x == e->x && s->y == e->y)
565 return;
567 ls = (line_s *) malloc (sizeof (line_s));
568 ls->next = lines;
569 lines = ls;
570 ls->s = s;
571 ls->e = e;
572 ls->layer = layer;
573 #if 0
574 if ((example->Point1.X == s->x && example->Point1.Y == s->y
575 && example->Point2.X == e->x && example->Point2.Y == e->y)
576 || (example->Point2.X == s->x && example->Point2.Y == s->y
577 && example->Point1.X == e->x && example->Point1.Y == e->y))
579 ls->line = example;
581 else
582 #endif
584 LineType *nl;
585 dprintf
586 ("New line \033[35m%d,%d to %d,%d from l%d t%d c%d f%s\033[0m\n",
587 s->x, s->y, e->x, e->y, layer, example->Thickness,
588 example->Clearance, flags_to_string (example->Flags, LINE_TYPE));
589 nl =
590 create_pcb_line (layer, s->x, s->y, e->x, e->y, example->Thickness,
591 example->Clearance, example->Flags);
593 if (!nl)
594 dj_abort ("can't create new line!");
595 ls->line = nl;
597 add_line_to_corner (ls, s);
598 add_line_to_corner (ls, e);
599 check (s, ls);
600 check (e, ls);
603 #if 0
604 /* Not used */
605 static int
606 c_orth_to (corner_s * c, line_s * l, int o)
608 int i, o2;
609 int rv = 0;
610 for (i = 0; i < c->n_lines; i++)
612 if (c->lines[i] == l)
613 continue;
614 o2 = line_orient (c->lines[i], c);
615 if (ORIENT (o) == ORIENT (o2) || o2 == DIAGONAL)
616 return 0;
617 rv++;
619 return rv;
621 #endif
623 static line_s *
624 other_line (corner_s * c, line_s * l)
626 int i;
627 line_s *rv = 0;
628 if (c->pin || c->pad || c->via)
629 return 0;
630 for (i = 0; i < c->n_lines; i++)
632 if (c->lines[i] == l)
633 continue;
634 if (rv)
635 return 0;
636 rv = c->lines[i];
638 return rv;
641 static void
642 empty_rect (rect_s * rect)
644 rect->x1 = rect->y1 = INT_MAX;
645 rect->x2 = rect->y2 = INT_MIN;
648 static void
649 add_point_to_rect (rect_s * rect, int x, int y, int w)
651 if (rect->x1 > x - w)
652 rect->x1 = x - w;
653 if (rect->x2 < x + w)
654 rect->x2 = x + w;
655 if (rect->y1 > y - w)
656 rect->y1 = y - w;
657 if (rect->y2 < y + w)
658 rect->y2 = y + w;
661 static void
662 add_line_to_rect (rect_s * rect, line_s * l)
664 add_point_to_rect (rect, l->s->x, l->s->y, 0);
665 add_point_to_rect (rect, l->e->x, l->e->y, 0);
668 static int
669 pin_in_rect (rect_s * r, int x, int y, int w)
671 if (x < r->x1 && x + w < r->x1)
672 return 0;
673 if (x > r->x2 && x - w > r->x2)
674 return 0;
675 if (y < r->y1 && y + w < r->y1)
676 return 0;
677 if (y > r->y2 && y - w > r->y2)
678 return 0;
679 return 1;
682 static int
683 line_in_rect (rect_s * r, line_s * l)
685 rect_s lr;
686 empty_rect (&lr);
687 add_point_to_rect (&lr, l->s->x, l->s->y, l->line->Thickness / 2);
688 add_point_to_rect (&lr, l->e->x, l->e->y, l->line->Thickness / 2);
689 dprintf ("line_in_rect %d,%d-%d,%d vs %d,%d-%d,%d\n",
690 r->x1, r->y1, r->x2, r->y2, lr.x1, lr.y1, lr.x2, lr.y2);
691 /* simple intersection of rectangles */
692 if (lr.x1 < r->x1)
693 lr.x1 = r->x1;
694 if (lr.x2 > r->x2)
695 lr.x2 = r->x2;
696 if (lr.y1 < r->y1)
697 lr.y1 = r->y1;
698 if (lr.y2 > r->y2)
699 lr.y2 = r->y2;
700 if (lr.x1 < lr.x2 && lr.y1 < lr.y2)
701 return 1;
702 return 0;
705 static int
706 corner_radius (corner_s * c)
708 int diam = 0;
709 int i;
710 if (c->pin)
711 diam = djmax (c->pin->Thickness, diam);
712 if (c->via)
713 diam = djmax (c->via->Thickness, diam);
714 for (i = 0; i < c->n_lines; i++)
715 if (c->lines[i]->line)
716 diam = djmax (c->lines[i]->line->Thickness, diam);
717 diam = (diam + 1) / 2;
718 return diam;
721 #if 0
722 /* Not used */
723 static int
724 corner_layer (corner_s * c)
726 if (c->pin || c->via)
727 return -1;
728 if (c->n_lines < 1)
729 return -1;
730 return c->lines[0]->layer;
732 #endif
734 static void
735 add_corner_to_rect_if (rect_s * rect, corner_s * c, rect_s * e)
737 int diam = corner_radius (c);
738 if (!pin_in_rect (e, c->x, c->y, diam))
739 return;
740 if (c->x < e->x1 && c->y < e->y1 && dist (c->x, c->y, e->x1, e->y1) > diam)
741 return;
742 if (c->x > e->x2 && c->y < e->y1 && dist (c->x, c->y, e->x2, e->y1) > diam)
743 return;
744 if (c->x < e->x1 && c->y > e->y2 && dist (c->x, c->y, e->x1, e->y2) > diam)
745 return;
746 if (c->x > e->x2 && c->y > e->y2 && dist (c->x, c->y, e->x2, e->y2) > diam)
747 return;
749 /*printf("add point %d,%d diam %d\n", c->x, c->y, diam); */
750 add_point_to_rect (rect, c->x, c->y, diam);
753 static void
754 remove_line (line_s * l)
756 int i, j;
757 line_s *l2;
758 LineType *from = 0, *to = 0;
759 LayerType *layer = &(PCB->Data->Layer[l->layer]);
761 check (0, 0);
763 if (l->line)
765 /* compensate for having line pointers rearranged */
766 from = &(layer->Line[layer->LineN - 1]);
767 to = l->line;
768 RemoveLine (layer, l->line);
771 DELETE (l);
772 for (l2 = lines; l2; l2 = l2->next)
774 if (DELETED (l2))
775 continue;
776 if (l2->line == from)
777 l2->line = to;
780 for (i = 0, j = 0; i < l->s->n_lines; i++)
781 if (l->s->lines[i] != l)
782 l->s->lines[j++] = l->s->lines[i];
783 l->s->n_lines = j;
785 for (i = 0, j = 0; i < l->e->n_lines; i++)
786 if (l->e->lines[i] != l)
787 l->e->lines[j++] = l->e->lines[i];
788 l->e->n_lines = j;
789 check (0, 0);
792 static void
793 move_line_to_layer (line_s * l, int layer)
795 line_s *l2;
796 LayerType *ls, *ld;
797 LineType *from = 0, *to = 0;
798 LineType *oldbase = 0, *newbase = 0, *oldend;
799 LineType *newline;
801 ls = LAYER_PTR (l->layer);
802 from = &(ls->Line[ls->LineN - 1]);
803 to = l->line;
805 ld = LAYER_PTR (layer);
806 oldbase = ld->Line;
807 oldend = oldbase + ld->LineN;
809 newline = (LineType *) MoveObjectToLayer (LINE_TYPE, ls, l->line, 0, ld, 0);
810 newbase = ld->Line;
812 for (l2 = lines; l2; l2 = l2->next)
814 if (DELETED (l2))
815 continue;
816 if (l2->line == from)
817 l2->line = to;
818 if (l2->line >= oldbase && l2->line < oldend)
819 l2->line += newbase - oldbase;
822 l->line = newline;
823 l->layer = layer;
826 static void
827 remove_via_at (corner_s * c)
829 corner_s *cc;
830 PinType *from = PCB->Data->Via + PCB->Data->ViaN - 1;
831 PinType *to = c->via;
832 RemoveObject (VIA_TYPE, c->via, 0, 0);
833 c->via = 0;
834 for (cc = corners; cc; cc = cc->next)
836 if (DELETED (cc))
837 continue;
838 if (cc->via == from)
839 cc->via = to;
843 static void
844 remove_corner (corner_s * c2)
846 corner_s *c;
847 dprintf ("remove corner %s\n", corner_name (c2));
848 if (corners == c2)
849 corners = c2->next;
850 for (c = corners; c; c = c->next)
852 if (DELETED (c))
853 continue;
854 if (c->next == c2)
855 c->next = c2->next;
857 if (next_corner == c2)
858 next_corner = c2->next;
859 free (c2->lines);
860 c2->lines = 0;
861 DELETE (c2);
864 static void
865 merge_corners (corner_s * c1, corner_s * c2)
867 int i;
868 if (c1 == c2)
869 abort ();
870 dprintf ("merge corners %s %s\n", corner_name (c1), corner_name (c2));
871 for (i = 0; i < c2->n_lines; i++)
873 add_line_to_corner (c2->lines[i], c1);
874 if (c2->lines[i]->s == c2)
875 c2->lines[i]->s = c1;
876 if (c2->lines[i]->e == c2)
877 c2->lines[i]->e = c1;
879 if (c1->via && c2->via)
880 remove_via_at (c2);
881 else if (c2->via)
882 c1->via = c2->via;
883 if (c2->pad)
884 c1->pad = c2->pad;
885 if (c2->pin)
886 c1->pin = c2->pin;
887 if (c2->layer != c1->layer)
888 c1->layer = -1;
890 remove_corner (c2);
893 static void
894 move_corner (corner_s * c, int x, int y)
896 PinType *via;
897 int i;
898 corner_s *pad;
900 check (c, 0);
901 if (c->pad || c->pin)
902 dj_abort ("move_corner: has pin or pad\n");
903 dprintf ("move_corner %p from %d,%d to %d,%d\n", (void *) c, c->x, c->y, x,
905 pad = find_corner_if (x, y, c->layer);
906 c->x = x;
907 c->y = y;
908 via = c->via;
909 if (via)
911 MoveObject (VIA_TYPE, via, via, via, x - via->X, y - via->Y);
912 dprintf ("via move %d,%d to %d,%d\n", via->X, via->Y, x, y);
914 for (i = 0; i < c->n_lines; i++)
916 LineTypePtr tl = c->lines[i]->line;
917 if (tl)
919 if (c->lines[i]->s == c)
921 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
922 &tl->Point1, x - (tl->Point1.X),
923 y - (tl->Point1.Y));
925 else
927 MoveObject (LINEPOINT_TYPE, LAYER_PTR (c->lines[i]->layer), tl,
928 &tl->Point2, x - (tl->Point2.X),
929 y - (tl->Point2.Y));
931 dprintf ("Line %p moved to %d,%d %d,%d\n", (void *) tl,
932 tl->Point1.X, tl->Point1.Y, tl->Point2.X, tl->Point2.Y);
935 if (pad && pad != c)
936 merge_corners (c, pad);
937 else
938 for (i = 0; i < c->n_lines; i++)
940 if (c->lines[i]->s->x == c->lines[i]->e->x
941 && c->lines[i]->s->y == c->lines[i]->e->y)
943 corner_s *c2 = other_corner (c->lines[i], c);
944 dprintf ("move_corner: removing line %d,%d %d,%d %p %p\n",
945 c->x, c->y, c2->x, c2->y, (void *) c, (void *) c2);
947 remove_line (c->lines[i]);
948 if (c != c2)
949 merge_corners (c, c2);
950 check (c, 0);
951 i--;
952 break;
955 gui->progress (0, 0, 0);
956 check (c, 0);
959 static int
960 any_line_selected ()
962 line_s *l;
963 for (l = lines; l; l = l->next)
965 if (DELETED (l))
966 continue;
967 if (l->line && selected (l->line))
968 return 1;
970 return 0;
973 static int
974 trim_step (int s, int l1, int l2)
976 dprintf ("trim %d %d %d\n", s, l1, l2);
977 if (s > l1)
978 s = l1;
979 if (s > l2)
980 s = l2;
981 if (s != l1 && s != l2)
982 s = gridsnap (s);
983 return s;
986 static int canonicalize_line (line_s * l);
988 static int
989 split_line (line_s * l, corner_s * c)
991 int i;
992 LayerType *layer;
993 LineType *pcbline;
994 line_s *ls;
996 if (!intersecting_layers (l->layer, c->layer))
997 return 0;
998 if (line_is_pad (l))
999 return 0;
1000 if (c->pad)
1002 dprintf ("split on pad!\n");
1003 if (l->s->pad == c->pad || l->e->pad == c->pad)
1004 return 0;
1005 dprintf ("splitting...\n");
1008 check (c, l);
1009 layer = PCB->Data->Layer + l->layer;
1010 pcbline = create_pcb_line (l->layer,
1011 c->x, c->y, l->e->x, l->e->y,
1012 l->line->Thickness, l->line->Clearance,
1013 l->line->Flags);
1014 if (pcbline == 0)
1015 return 0; /* already a line there */
1017 check (c, l);
1019 dprintf ("split line from %d,%d to %d,%d at %d,%d\n",
1020 l->s->x, l->s->y, l->e->x, l->e->y, c->x, c->y);
1021 ls = (line_s *) malloc (sizeof (line_s));
1023 ls->next = lines;
1024 lines = ls;
1025 ls->s = c;
1026 ls->e = l->e;
1027 ls->line = pcbline;
1028 ls->layer = l->layer;
1029 for (i = 0; i < l->e->n_lines; i++)
1030 if (l->e->lines[i] == l)
1031 l->e->lines[i] = ls;
1032 l->e = c;
1033 add_line_to_corner (l, c);
1034 add_line_to_corner (ls, c);
1036 MoveObject (LINEPOINT_TYPE, LAYER_PTR (l->layer), l->line, &l->line->Point2,
1037 c->x - (l->line->Point2.X), c->y - (l->line->Point2.Y));
1039 return 1;
1042 static int
1043 canonicalize_line (line_s * l)
1045 /* This could be faster */
1046 corner_s *c;
1047 if (l->s->x == l->e->x)
1049 int y1 = l->s->y;
1050 int y2 = l->e->y;
1051 int x1 = l->s->x - l->line->Thickness / 2;
1052 int x2 = l->s->x + l->line->Thickness / 2;
1053 if (y1 > y2)
1055 int t = y1;
1056 y1 = y2;
1057 y2 = t;
1059 for (c = corners; c; c = c->next)
1061 if (DELETED (c))
1062 continue;
1063 if ((y1 < c->y && c->y < y2)
1064 && intersecting_layers (l->layer, c->layer))
1066 if (c->x != l->s->x
1067 && c->x < x2 && c->x > x1 && !(c->pad || c->pin))
1069 move_corner (c, l->s->x, c->y);
1071 if (c->x == l->s->x)
1073 /* FIXME: if the line is split, we have to re-canonicalize
1074 both segments. */
1075 return split_line (l, c);
1080 else if (l->s->y == l->e->y)
1082 int x1 = l->s->x;
1083 int x2 = l->e->x;
1084 int y1 = l->s->y - l->line->Thickness / 2;
1085 int y2 = l->s->y + l->line->Thickness / 2;
1086 if (x1 > x2)
1088 int t = x1;
1089 x1 = x2;
1090 x2 = t;
1092 for (c = corners; c; c = c->next)
1094 if (DELETED (c))
1095 continue;
1096 if ((x1 < c->x && c->x < x2)
1097 && intersecting_layers (l->layer, c->layer))
1099 if (c->y != l->s->y
1100 && c->y < y2 && c->y > y1 && !(c->pad || c->pin))
1102 move_corner (c, c->x, l->s->y);
1104 if (c->y == l->s->y)
1106 /* FIXME: Likewise. */
1107 return split_line (l, c);
1112 else
1114 /* diagonal lines. Let's try to split them at pins/vias
1115 anyway. */
1116 int x1 = l->s->x;
1117 int x2 = l->e->x;
1118 int y1 = l->s->y;
1119 int y2 = l->e->y;
1120 if (x1 > x2)
1122 int t = x1;
1123 x1 = x2;
1124 x2 = t;
1126 if (y1 > y2)
1128 int t = y1;
1129 y1 = y2;
1130 y2 = t;
1132 for (c = corners; c; c = c->next)
1134 if (DELETED (c))
1135 continue;
1136 if (!c->via && !c->pin)
1137 continue;
1138 if ((x1 < c->x && c->x < x2)
1139 && (y1 < c->y && c->y < y2)
1140 && intersecting_layers (l->layer, c->layer))
1142 int th = c->pin ? c->pin->Thickness : c->via->Thickness;
1143 th /= 2;
1144 if (dist (l->s->x, l->s->y, c->x, c->y) > th
1145 && dist (l->e->x, l->e->y, c->x, c->y) > th
1146 && PinLineIntersect (c->pin ? c->pin : c->via, l->line))
1148 return split_line (l, c);
1153 return 0;
1156 /* Make sure all vias are at line end points */
1157 static int
1158 canonicalize_lines ()
1160 int changes = 0;
1161 int count;
1162 line_s *l;
1163 while (1)
1165 count = 0;
1166 for (l = lines; l; l = l->next)
1168 if (DELETED (l))
1169 continue;
1170 count += canonicalize_line (l);
1172 changes += count;
1173 if (count == 0)
1174 break;
1176 return changes;
1179 static int
1180 simple_optimize_corner (corner_s * c)
1182 int i;
1183 int rv = 0;
1185 check (c, 0);
1186 if (c->via)
1188 /* see if no via is needed */
1189 if (selected (c->via))
1190 dprintf ("via check: line[0] layer %d at %d,%d nl %d\n",
1191 c->lines[0]->layer, c->x, c->y, c->n_lines);
1192 /* We can't delete vias that connect to power planes, or vias
1193 that aren't tented (assume they're test points). */
1194 if (!TEST_ANY_THERMS (c->via)
1195 && c->via->Mask == 0)
1197 for (i = 1; i < c->n_lines; i++)
1199 if (selected (c->via))
1200 dprintf (" line[%d] layer %d %d,%d to %d,%d\n",
1201 i, c->lines[i]->layer,
1202 c->lines[i]->s->x, c->lines[i]->s->y,
1203 c->lines[i]->e->x, c->lines[i]->e->y);
1204 if (c->lines[i]->layer != c->lines[0]->layer)
1205 break;
1207 if (i == c->n_lines)
1209 if (selected (c->via))
1210 dprintf (" remove it\n");
1211 remove_via_at (c);
1212 rv++;
1217 check (c, 0);
1218 if (c->n_lines == 2 && !c->via)
1220 /* see if it is an unneeded corner */
1221 int o = line_orient (c->lines[0], c);
1222 corner_s *c2 = other_corner (c->lines[1], c);
1223 corner_s *c0 = other_corner (c->lines[0], c);
1224 if (o == line_orient (c->lines[1], c2) && o != DIAGONAL)
1226 dprintf ("straight %d,%d to %d,%d to %d,%d\n",
1227 c0->x, c0->y, c->x, c->y, c2->x, c2->y);
1228 if (selected (c->lines[0]->line))
1229 SET_FLAG (SELECTEDFLAG, c->lines[1]->line);
1230 if (selected (c->lines[1]->line))
1231 SET_FLAG (SELECTEDFLAG, c->lines[0]->line);
1232 move_corner (c, c2->x, c2->y);
1235 check (c, 0);
1236 if (c->n_lines == 1 && !c->via)
1238 corner_s *c0 = other_corner (c->lines[0], c);
1239 if (abs(c->x - c0->x) + abs(c->y - c0->y) <= LONGEST_FRECKLE)
1242 * Remove this line, as it is a "freckle". A freckle is an extremely
1243 * short line (around 0.01 thou) that is unconnected at one end.
1244 * Freckles are almost insignificantly small, but are annoying as
1245 * they prevent the mitering optimiser from working.
1246 * Freckles sometimes arise because of a bug in the autorouter that
1247 * causes it to create small overshoots (typically 0.01 thou) at the
1248 * intersections of vertical and horizontal lines. These overshoots
1249 * are converted to freckles as a side effect of canonicalize_line().
1250 * Note that canonicalize_line() is not at fault, the bug is in the
1251 * autorouter creating overshoots.
1252 * The autorouter bug arose some time between the 20080202 and 20091103
1253 * releases.
1254 * This code is probably worth keeping even when the autorouter bug is
1255 * fixed, as "freckles" could conceivably arise in other ways.
1257 dprintf ("freckle %d,%d to %d,%d\n",
1258 c->x, c->y, c0->x, c0->y);
1259 move_corner (c, c0->x, c0->y);
1262 check (c, 0);
1263 return rv;
1266 /* We always run these */
1267 static int
1268 simple_optimizations ()
1270 corner_s *c;
1271 int rv = 0;
1273 /* Look for corners that aren't */
1274 for (c = corners; c; c = c->next)
1276 if (DELETED (c))
1277 continue;
1278 if (c->pad || c->pin)
1279 continue;
1280 rv += simple_optimize_corner (c);
1282 return rv;
1285 static int
1286 is_hole (corner_s * c)
1288 return c->pin || c->pad || c->via;
1291 static int
1292 orthopull_1 (corner_s * c, int fdir, int rdir, int any_sel)
1294 static corner_s **cs = 0;
1295 static int cm = 0;
1296 static line_s **ls = 0;
1297 static int lm = 0;
1298 int i, li, ln, cn, snap;
1299 line_s *l = 0;
1300 corner_s *c2, *cb;
1301 int adir = 0, sdir = 0, pull;
1302 int saw_sel = 0, saw_auto = 0;
1303 int max, len = 0, r1 = 0, r2;
1304 rect_s rr;
1305 int edir = 0, done;
1307 if (cs == 0)
1309 cs = (corner_s **) malloc (10 * sizeof (corner_s));
1310 cm = 10;
1311 ls = (line_s **) malloc (10 * sizeof (line_s));
1312 lm = 10;
1315 for (i = 0; i < c->n_lines; i++)
1317 int o = line_orient (c->lines[i], c);
1318 if (o == rdir)
1319 return 0;
1322 switch (fdir)
1324 case RIGHT:
1325 adir = DOWN;
1326 sdir = UP;
1327 break;
1328 case DOWN:
1329 adir = RIGHT;
1330 sdir = LEFT;
1331 break;
1332 default:
1333 dj_abort ("fdir not right or down\n");
1336 c2 = c;
1337 cn = 0;
1338 ln = 0;
1339 pull = 0;
1340 while (c2)
1342 if (c2->pad || c2->pin || c2->n_lines < 2)
1343 return 0;
1344 if (cn >= cm)
1346 cm = cn + 10;
1347 cs = (corner_s **) realloc (cs, cm * sizeof (corner_s));
1349 cs[cn++] = c2;
1350 r2 = corner_radius (c2);
1351 if (r1 < r2)
1352 r1 = r2;
1353 l = 0;
1354 for (i = 0; i < c2->n_lines; i++)
1356 int o = line_orient (c2->lines[i], c2);
1357 if (o == DIAGONAL)
1358 return 0;
1359 if (o == fdir)
1361 if (l)
1362 return 0; /* we don't support overlapping lines yet */
1363 l = c2->lines[i];
1365 if (o == rdir && c2->lines[i] != ls[ln - 1])
1366 return 0; /* likewise */
1367 if (o == adir)
1368 pull++;
1369 if (o == sdir)
1370 pull--;
1372 if (!l)
1373 break;
1374 if (selected (l->line))
1375 saw_sel = 1;
1376 if (autorouted (l->line))
1377 saw_auto = 1;
1378 if (ln >= lm)
1380 lm = ln + 10;
1381 ls = (line_s **) realloc (ls, lm * sizeof (line_s));
1383 ls[ln++] = l;
1384 c2 = other_corner (l, c2);
1386 if (cn < 2 || pull == 0)
1387 return 0;
1388 if (any_sel && !saw_sel)
1389 return 0;
1390 if (!any_sel && autorouted_only && !saw_auto)
1391 return 0;
1393 /* Ok, now look for other blockages. */
1395 empty_rect (&rr);
1396 add_point_to_rect (&rr, c->x, c->y, corner_radius (c));
1397 add_point_to_rect (&rr, c2->x, c2->y, corner_radius (c2));
1399 if (fdir == RIGHT && pull < 0)
1400 edir = UP;
1401 else if (fdir == RIGHT && pull > 0)
1402 edir = DOWN;
1403 else if (fdir == DOWN && pull < 0)
1404 edir = LEFT;
1405 else if (fdir == DOWN && pull > 0)
1406 edir = RIGHT;
1408 max = -1;
1409 for (i = 0; i < cn; i++)
1410 for (li = 0; li < cs[i]->n_lines; li++)
1412 if (line_orient (cs[i]->lines[li], cs[i]) != edir)
1413 continue;
1414 len = line_length (cs[i]->lines[li]);
1415 if (max > len || max == -1)
1416 max = len;
1418 dprintf ("c %s %4d %4d cn %d pull %3d max %4d\n",
1419 fdir == RIGHT ? "right" : "down ", c->x, c->y, cn, pull, max);
1421 switch (edir)
1423 case UP:
1424 rr.y1 = c->y - r1 - max;
1425 break;
1426 case DOWN:
1427 rr.y2 = c->y + r1 + max;
1428 break;
1429 case LEFT:
1430 rr.x1 = c->x - r1 - max;
1431 break;
1432 case RIGHT:
1433 rr.x2 = c->x + r1 + max;
1434 break;
1436 rr.x1 -= SB + 1;
1437 rr.x2 += SB + 1;
1438 rr.y1 -= SB + 1;
1439 rr.y2 += SB + 1;
1441 snap = 0;
1442 for (cb = corners; cb; cb = cb->next)
1444 int sep;
1445 if (DELETED (cb))
1446 continue;
1447 r1 = corner_radius (cb);
1448 if (cb->net == c->net && !cb->pad)
1449 continue;
1450 if (!pin_in_rect (&rr, cb->x, cb->y, r1))
1451 continue;
1452 switch (edir)
1454 #define ECHK(X,Y,LT) \
1455 for (i=0; i<cn; i++) \
1457 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1458 continue; \
1459 r2 = corner_radius(cs[i]); \
1460 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1461 continue; \
1462 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1463 continue; \
1464 if (cb->Y LT cs[i]->Y) \
1465 continue; \
1466 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1467 if (max > sep) \
1468 { max = sep; snap = 1; }\
1470 for (i=0; i<ln; i++) \
1472 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1473 continue; \
1474 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1475 continue; \
1476 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1477 - r1 - SB - 1); \
1478 if (max > sep) \
1479 { max = sep; snap = 1; }\
1481 case UP:
1482 ECHK (x, y, >=);
1483 break;
1484 case DOWN:
1485 ECHK (x, y, <=);
1486 break;
1487 case LEFT:
1488 ECHK (y, x, >=);
1489 break;
1490 case RIGHT:
1491 ECHK (y, x, <=);
1492 break;
1496 /* We must now check every line segment against our corners. */
1497 for (l = lines; l; l = l->next)
1499 int o, x1, x2, y1, y2;
1500 if (DELETED (l))
1501 continue;
1502 dprintf ("check line %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1503 l->e->y);
1504 if (l->s->net == c->net)
1506 dprintf (" same net\n");
1507 continue;
1509 o = line_orient (l, 0);
1510 /* We don't need to check perpendicular lines, because their
1511 corners already take care of it. */
1512 if ((fdir == RIGHT && (o == UP || o == DOWN))
1513 || (fdir == DOWN && (o == RIGHT || o == LEFT)))
1515 dprintf (" perpendicular\n");
1516 continue;
1519 /* Choose so that x1,y1 is closest to corner C */
1520 if ((fdir == RIGHT && l->s->x < l->e->x)
1521 || (fdir == DOWN && l->s->y < l->e->y))
1523 x1 = l->s->x;
1524 y1 = l->s->y;
1525 x2 = l->e->x;
1526 y2 = l->e->y;
1528 else
1530 x1 = l->e->x;
1531 y1 = l->e->y;
1532 x2 = l->s->x;
1533 y2 = l->s->y;
1536 /* Eliminate all lines outside our range */
1537 if ((fdir == RIGHT && (x2 < c->x || x1 > c2->x))
1538 || (fdir == DOWN && (y2 < c->y || y1 > c2->y)))
1540 dprintf (" outside our range\n");
1541 continue;
1544 /* Eliminate all lines on the wrong side of us */
1545 if ((edir == UP && y1 > c->y && y2 > c->y)
1546 || (edir == DOWN && y1 < c->y && y2 < c->y)
1547 || (edir == LEFT && x1 > c->x && x2 > c->x)
1548 || (edir == RIGHT && x1 < c->x && x2 < c->x))
1550 dprintf (" wrong side\n");
1551 continue;
1554 /* For now, cheat on diagonals */
1555 switch (edir)
1557 case RIGHT:
1558 if (x1 > x2)
1559 x1 = x2;
1560 break;
1561 case LEFT:
1562 if (x1 < x2)
1563 x1 = x2;
1564 break;
1565 case DOWN:
1566 if (y1 > y2)
1567 y1 = y2;
1568 break;
1569 case UP:
1570 if (y1 < y2)
1571 y1 = y2;
1572 break;
1575 /* Ok, now see how far we can get for each of our corners. */
1576 for (i = 0; i < cn; i++)
1578 int r = l->line->Thickness + SB + corner_radius (cs[i]) + 1;
1579 int len = 0;
1580 if ((fdir == RIGHT && (x2 < cs[i]->x || x1 > cs[i]->x))
1581 || (fdir == DOWN && (y2 < cs[i]->y || y1 > cs[i]->y)))
1582 continue;
1583 if (!intersecting_layers (cs[i]->layer, l->layer))
1584 continue;
1585 switch (edir)
1587 case RIGHT:
1588 len = x1 - c->x;
1589 break;
1590 case LEFT:
1591 len = c->x - x1;
1592 break;
1593 case DOWN:
1594 len = y1 - c->y;
1595 break;
1596 case UP:
1597 len = c->y - y1;
1598 break;
1600 len -= r;
1601 dprintf (" len is %d vs corner at %d,%d\n", len, cs[i]->x,
1602 cs[i]->y);
1603 if (len <= 0)
1604 return 0;
1605 if (max > len)
1606 max = len;
1611 /* We must make sure that if a segment isn't being completely
1612 removed, that any vias and/or pads don't overlap. */
1613 done = 0;
1614 while (!done)
1616 done = 1;
1617 for (i = 0; i < cn; i++)
1618 for (li = 0; li < cs[i]->n_lines; li++)
1620 line_s *l = cs[i]->lines[li];
1621 corner_s *oc = other_corner (l, cs[i]);
1622 if (line_orient (l, cs[i]) != edir)
1623 continue;
1624 len = line_length (l);
1625 if (!oc->pad || !cs[i]->via)
1627 if (!is_hole (l->s) || !is_hole (l->e))
1628 continue;
1629 if (len == max)
1630 continue;
1632 len -= corner_radius (l->s);
1633 len -= corner_radius (l->e);
1634 len -= SB + 1;
1635 if (max > len)
1637 max = len;
1638 done = 0;
1643 if (max <= 0)
1644 return 0;
1645 switch (edir)
1647 case UP:
1648 len = c->y - max;
1649 break;
1650 case DOWN:
1651 len = c->y + max;
1652 break;
1653 case LEFT:
1654 len = c->x - max;
1655 break;
1656 case RIGHT:
1657 len = c->x + max;
1658 break;
1660 if (snap && max > Settings.Grid)
1662 if (pull < 0)
1663 len += Settings.Grid - 1;
1664 len -= len % (int) (Settings.Grid);
1666 if ((fdir == RIGHT && len == cs[0]->y) || (fdir == DOWN && len == cs[0]->x))
1667 return 0;
1668 for (i = 0; i < cn; i++)
1670 if (fdir == RIGHT)
1672 max = len - cs[i]->y;
1673 move_corner (cs[i], cs[i]->x, len);
1675 else
1677 max = len - cs[i]->x;
1678 move_corner (cs[i], len, cs[i]->y);
1681 return max * pull;
1684 static int
1685 orthopull ()
1687 /* Look for straight runs which could be moved to reduce total trace
1688 length. */
1689 int any_sel = any_line_selected ();
1690 corner_s *c;
1691 int rv = 0;
1693 for (c = corners; c;)
1695 if (DELETED (c))
1696 continue;
1697 if (c->pin || c->pad)
1699 c = c->next;
1700 continue;
1702 next_corner = c;
1703 rv += orthopull_1 (c, RIGHT, LEFT, any_sel);
1704 if (c != next_corner)
1706 c = next_corner;
1707 continue;
1709 rv += orthopull_1 (c, DOWN, UP, any_sel);
1710 if (c != next_corner)
1712 c = next_corner;
1713 continue;
1715 c = c->next;
1717 if (rv)
1718 printf ("orthopull: %d mils saved\n", rv / 100);
1719 return rv;
1722 static int
1723 debumpify ()
1725 /* Look for "U" shaped traces we can shorten (or eliminate) */
1726 int rv = 0;
1727 int any_selected = any_line_selected ();
1728 line_s *l, *l1, *l2;
1729 corner_s *c, *c1, *c2;
1730 rect_s rr, rp;
1731 int o, o1, o2, step, w;
1732 for (l = lines; l; l = l->next)
1734 if (DELETED (l))
1735 continue;
1736 if (!l->line)
1737 continue;
1738 if (any_selected && !selected (l->line))
1739 continue;
1740 if (!any_selected && autorouted_only && !autorouted (l->line))
1741 continue;
1742 if (l->s->pin || l->s->pad || l->e->pin || l->e->pad)
1743 continue;
1744 o = line_orient (l, 0);
1745 if (o == DIAGONAL)
1746 continue;
1747 l1 = other_line (l->s, l);
1748 if (!l1)
1749 continue;
1750 o1 = line_orient (l1, l->s);
1751 l2 = other_line (l->e, l);
1752 if (!l2)
1753 continue;
1754 o2 = line_orient (l2, l->e);
1755 if (ORIENT (o) == ORIENT (o1) || o1 != o2 || o1 == DIAGONAL)
1756 continue;
1758 dprintf ("\nline: %d,%d to %d,%d\n", l->s->x, l->s->y, l->e->x,
1759 l->e->y);
1760 w = l->line->Thickness / 2 + SB + 1;
1761 empty_rect (&rr);
1762 add_line_to_rect (&rr, l1);
1763 add_line_to_rect (&rr, l2);
1764 if (rr.x1 != l->s->x && rr.x1 != l->e->x)
1765 rr.x1 -= w;
1766 if (rr.x2 != l->s->x && rr.x2 != l->e->x)
1767 rr.x2 += w;
1768 if (rr.y1 != l->s->y && rr.y1 != l->e->y)
1769 rr.y1 -= w;
1770 if (rr.y2 != l->s->y && rr.y2 != l->e->y)
1771 rr.y2 += w;
1772 dprintf ("range: x %d..%d y %d..%d\n", rr.x1, rr.x2, rr.y1, rr.y2);
1774 c1 = other_corner (l1, l->s);
1775 c2 = other_corner (l2, l->e);
1777 empty_rect (&rp);
1778 for (c = corners; c; c = c->next)
1780 if (DELETED (c))
1781 continue;
1782 if (c->net != l->s->net
1783 && intersecting_layers (c->layer, l->s->layer))
1784 add_corner_to_rect_if (&rp, c, &rr);
1786 if (rp.x1 == INT_MAX)
1788 rp.x1 = rr.x2;
1789 rp.x2 = rr.x1;
1790 rp.y1 = rr.y2;
1791 rp.y2 = rr.y1;
1793 dprintf ("pin r: x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1795 switch (o1)
1797 case LEFT:
1798 step = l->s->x - rp.x2 - w;
1799 step = gridsnap (step);
1800 if (step > l->s->x - c1->x)
1801 step = l->s->x - c1->x;
1802 if (step > l->s->x - c2->x)
1803 step = l->s->x - c2->x;
1804 if (step > 0)
1806 dprintf ("left step %d at %d,%d\n", step, l->s->x, l->s->y);
1807 move_corner (l->s, l->s->x - step, l->s->y);
1808 move_corner (l->e, l->e->x - step, l->e->y);
1809 rv += step;
1811 break;
1812 case RIGHT:
1813 step = rp.x1 - l->s->x - w;
1814 step = gridsnap (step);
1815 if (step > c1->x - l->s->x)
1816 step = c1->x - l->s->x;
1817 if (step > c2->x - l->s->x)
1818 step = c2->x - l->s->x;
1819 if (step > 0)
1821 dprintf ("right step %d at %d,%d\n", step, l->s->x, l->s->y);
1822 move_corner (l->s, l->s->x + step, l->s->y);
1823 move_corner (l->e, l->e->x + step, l->e->y);
1824 rv += step;
1826 break;
1827 case UP:
1828 if (rp.y2 == INT_MIN)
1829 rp.y2 = rr.y1;
1830 step = trim_step (l->s->y - rp.y2 - w,
1831 l->s->y - c1->y, l->s->y - c2->y);
1832 if (step > 0)
1834 dprintf ("up step %d at %d,%d\n", step, l->s->x, l->s->y);
1835 move_corner (l->s, l->s->x, l->s->y - step);
1836 move_corner (l->e, l->e->x, l->e->y - step);
1837 rv += step;
1839 break;
1840 case DOWN:
1841 step = rp.y1 - l->s->y - w;
1842 step = gridsnap (step);
1843 if (step > c1->y - l->s->y)
1844 step = c1->y - l->s->y;
1845 if (step > c2->y - l->s->y)
1846 step = c2->y - l->s->y;
1847 if (step > 0)
1849 dprintf ("down step %d at %d,%d\n", step, l->s->x, l->s->y);
1850 move_corner (l->s, l->s->x, l->s->y + step);
1851 move_corner (l->e, l->e->x, l->e->y + step);
1852 rv += step;
1854 break;
1856 check (0, l);
1859 rv += simple_optimizations ();
1860 if (rv)
1861 printf ("debumpify: %d mils saved\n", rv / 50);
1862 return rv;
1865 static int
1866 simple_corner (corner_s * c)
1868 int o1, o2;
1869 if (c->pad || c->pin || c->via)
1870 return 0;
1871 if (c->n_lines != 2)
1872 return 0;
1873 o1 = line_orient (c->lines[0], c);
1874 o2 = line_orient (c->lines[1], c);
1875 if (ORIENT (o1) == ORIENT (o2))
1876 return 0;
1877 if (ORIENT (o1) == DIAGONAL || ORIENT (o2) == DIAGONAL)
1878 return 0;
1879 return 1;
1882 static int
1883 unjaggy_once ()
1885 /* Look for sequences of simple corners we can reduce. */
1886 int rv = 0;
1887 corner_s *c, *c0, *c1, *cc;
1888 int l, w, sel = any_line_selected ();
1889 int o0, o1, s0, s1;
1890 rect_s rr, rp;
1891 for (c = corners; c; c = c->next)
1893 if (DELETED (c))
1894 continue;
1895 if (!simple_corner (c))
1896 continue;
1897 if (!c->lines[0]->line || !c->lines[1]->line)
1898 continue;
1899 if (sel && !(selected (c->lines[0]->line)
1900 || selected (c->lines[1]->line)))
1901 continue;
1902 if (!sel && autorouted_only
1903 && !(autorouted (c->lines[0]->line)
1904 || autorouted (c->lines[1]->line)))
1905 continue;
1906 dprintf ("simple at %d,%d\n", c->x, c->y);
1908 c0 = other_corner (c->lines[0], c);
1909 o0 = line_orient (c->lines[0], c);
1910 s0 = simple_corner (c0);
1912 c1 = other_corner (c->lines[1], c);
1913 o1 = line_orient (c->lines[1], c);
1914 s1 = simple_corner (c1);
1916 if (!s0 && !s1)
1917 continue;
1918 dprintf ("simples at %d,%d\n", c->x, c->y);
1920 w = 1;
1921 for (l = 0; l < c0->n_lines; l++)
1922 if (c0->lines[l] != c->lines[0]
1923 && c0->lines[l]->layer == c->lines[0]->layer)
1925 int o = line_orient (c0->lines[l], c0);
1926 if (o == o1)
1927 w = 0;
1929 for (l = 0; l < c1->n_lines; l++)
1930 if (c1->lines[l] != c->lines[0]
1931 && c1->lines[l]->layer == c->lines[0]->layer)
1933 int o = line_orient (c1->lines[l], c1);
1934 if (o == o0)
1935 w = 0;
1937 if (!w)
1938 continue;
1939 dprintf ("orient ok\n");
1941 w = c->lines[0]->line->Thickness / 2 + SB + 1;
1942 empty_rect (&rr);
1943 add_line_to_rect (&rr, c->lines[0]);
1944 add_line_to_rect (&rr, c->lines[1]);
1945 if (c->x != rr.x1)
1946 rr.x1 -= w;
1947 else
1948 rr.x2 += w;
1949 if (c->y != rr.y1)
1950 rr.y1 -= w;
1951 else
1952 rr.y2 += w;
1954 empty_rect (&rp);
1955 for (cc = corners; cc; cc = cc->next)
1957 if (DELETED (cc))
1958 continue;
1959 if (cc->net != c->net && intersecting_layers (cc->layer, c->layer))
1960 add_corner_to_rect_if (&rp, cc, &rr);
1962 dprintf ("rp x %d..%d y %d..%d\n", rp.x1, rp.x2, rp.y1, rp.y2);
1963 if (rp.x1 <= rp.x2) /* something triggered */
1964 continue;
1966 dprintf ("unjaggy at %d,%d layer %d\n", c->x, c->y, c->layer);
1967 if (c->x == c0->x)
1968 move_corner (c, c1->x, c0->y);
1969 else
1970 move_corner (c, c0->x, c1->y);
1971 rv++;
1972 check (c, 0);
1974 rv += simple_optimizations ();
1975 check (c, 0);
1976 return rv;
1979 static int
1980 unjaggy ()
1982 int i, r = 0, j;
1983 for (i = 0; i < 100; i++)
1985 j = unjaggy_once ();
1986 if (j == 0)
1987 break;
1988 r += j;
1990 if (r)
1991 printf ("%d unjagg%s \n", r, r == 1 ? "y" : "ies");
1992 return r;
1995 static int
1996 vianudge ()
1998 /* Look for vias with all lines leaving the same way, try to nudge
1999 via to eliminate one or more of them. */
2000 int rv = 0;
2001 corner_s *c, *c2, *c3;
2002 line_s *l;
2003 unsigned char directions[MAX_LAYER];
2004 unsigned char counts[MAX_LAYER];
2006 memset (directions, 0, sizeof (directions));
2007 memset (counts, 0, sizeof (counts));
2009 for (c = corners; c; c = c->next)
2011 int o, i, vr, cr, oboth;
2012 int len = 0, saved = 0;
2014 if (DELETED (c))
2015 continue;
2017 if (!c->via)
2018 continue;
2020 memset (directions, 0, sizeof (directions));
2021 memset (counts, 0, sizeof (counts));
2023 for (i = 0; i < c->n_lines; i++)
2025 o = line_orient (c->lines[i], c);
2026 counts[c->lines[i]->layer]++;
2027 directions[c->lines[i]->layer] |= o;
2029 for (o = 0, i = 0; i < max_layer; i++)
2030 if (counts[i] == 1)
2032 o = directions[i];
2033 break;
2035 switch (o)
2037 case LEFT:
2038 case RIGHT:
2039 oboth = LEFT | RIGHT;
2040 break;
2041 case UP:
2042 case DOWN:
2043 oboth = UP | DOWN;
2044 break;
2045 default:
2046 continue;
2048 for (i = 0; i < max_layer; i++)
2049 if (counts[i] && directions[i] != o && directions[i] != oboth)
2050 goto vianudge_continue;
2052 c2 = 0;
2053 for (i = 0; i < c->n_lines; i++)
2055 int ll = line_length (c->lines[i]);
2056 if (line_orient (c->lines[i], c) != o)
2058 saved--;
2059 continue;
2061 saved++;
2062 if (c2 == 0 || len > ll)
2064 len = ll;
2065 c2 = other_corner (c->lines[i], c);
2068 if (c2->pad || c2->pin || c2->via)
2069 continue;
2071 /* Now look for clearance in the new position */
2072 vr = c->via->Thickness / 2 + SB + 1;
2073 for (c3 = corners; c3; c3 = c3->next)
2075 if (DELETED (c3))
2076 continue;
2077 if ((c3->net != c->net && (c3->pin || c3->via)) || c3->pad)
2079 cr = corner_radius (c3);
2080 if (dist (c2->x, c2->y, c3->x, c3->y) < vr + cr)
2081 goto vianudge_continue;
2084 for (l = lines; l; l = l->next)
2086 if (DELETED (l))
2087 continue;
2088 if (l->s->net != c->net)
2090 int ld = dist_line_to_point (l, c2);
2091 if (ld < l->line->Thickness / 2 + vr)
2092 goto vianudge_continue;
2096 /* at this point, we know we can move it */
2098 dprintf ("vianudge: nudging via at %d,%d by %d mils saving %d\n",
2099 c->x, c->y, len / 100, saved / 100);
2100 rv += len * saved;
2101 move_corner (c, c2->x, c2->y);
2103 check (c, 0);
2105 vianudge_continue:
2106 continue;
2109 if (rv)
2110 printf ("vianudge: %d mils saved\n", rv / 100);
2111 return rv;
2114 static int
2115 viatrim ()
2117 /* Look for traces that can be moved to the other side of the board,
2118 to reduce the number of vias needed. For now, we look for simple
2119 lines, not multi-segmented lines. */
2120 line_s *l, *l2;
2121 int i, rv = 0, vrm = 0;
2122 int any_sel = any_line_selected ();
2124 for (l = lines; l; l = l->next)
2126 rect_s r;
2127 int my_layer, other_layer;
2129 if (DELETED (l))
2130 continue;
2131 if (!l->s->via)
2132 continue;
2133 if (!l->e->via)
2134 continue;
2135 if (any_sel && !selected (l->line))
2136 continue;
2137 if (!any_sel && autorouted_only && !autorouted (l->line))
2138 continue;
2140 my_layer = l->layer;
2141 other_layer = -1;
2142 dprintf ("line %p on layer %d from %d,%d to %d,%d\n", (void *) l,
2143 l->layer, l->s->x, l->s->y, l->e->x, l->e->y);
2144 for (i = 0; i < l->s->n_lines; i++)
2145 if (l->s->lines[i] != l)
2147 if (other_layer == -1)
2149 other_layer = l->s->lines[i]->layer;
2150 dprintf ("noting other line %p on layer %d\n",
2151 (void *) (l->s->lines[i]), my_layer);
2153 else if (l->s->lines[i]->layer != other_layer)
2155 dprintf ("saw other line %p on layer %d (not %d)\n",
2156 (void *) (l->s->lines[i]), l->s->lines[i]->layer,
2157 my_layer);
2158 other_layer = -1;
2159 goto viatrim_other_corner;
2162 viatrim_other_corner:
2163 if (other_layer == -1)
2164 for (i = 0; i < l->e->n_lines; i++)
2165 if (l->e->lines[i] != l)
2167 if (other_layer == -1)
2169 other_layer = l->s->lines[i]->layer;
2170 dprintf ("noting other line %p on layer %d\n",
2171 (void *) (l->s->lines[i]), my_layer);
2173 else if (l->e->lines[i]->layer != other_layer)
2175 dprintf ("saw end line on layer %d (not %d)\n",
2176 l->e->lines[i]->layer, other_layer);
2177 goto viatrim_continue;
2181 /* Now see if any other line intersects us. We don't need to
2182 check corners, because they'd either be pins/vias and
2183 already conflict, or pads, which we'll check here anyway. */
2184 empty_rect (&r);
2185 add_point_to_rect (&r, l->s->x, l->s->y, l->line->Thickness);
2186 add_point_to_rect (&r, l->e->x, l->e->y, l->line->Thickness);
2188 for (l2 = lines; l2; l2 = l2->next)
2190 if (DELETED (l2))
2191 continue;
2192 if (l2->s->net != l->s->net && l2->layer == other_layer)
2194 dprintf ("checking other line %d,%d to %d,%d\n", l2->s->x,
2195 l2->s->y, l2->e->x, l2->e->y);
2196 if (line_in_rect (&r, l2))
2198 dprintf ("line from %d,%d to %d,%d in the way\n",
2199 l2->s->x, l2->s->y, l2->e->x, l2->e->y);
2200 goto viatrim_continue;
2205 if (l->layer == other_layer)
2206 continue;
2207 move_line_to_layer (l, other_layer);
2208 rv++;
2210 viatrim_continue:
2211 continue;
2213 vrm = simple_optimizations ();
2214 if (rv > 0)
2215 printf ("viatrim: %d traces moved, %d vias removed\n", rv, vrm);
2216 return rv + vrm;
2219 static int
2220 automagic ()
2222 int more = 1, oldmore = 0;
2223 int toomany = 100;
2224 while (more != oldmore && --toomany)
2226 oldmore = more;
2227 more += debumpify ();
2228 more += unjaggy ();
2229 more += orthopull ();
2230 more += vianudge ();
2231 more += viatrim ();
2233 return more - 1;
2236 static int
2237 miter ()
2239 corner_s *c;
2240 int done, progress;
2241 int sel = any_line_selected ();
2242 int saved = 0;
2244 for (c = corners; c; c = c->next)
2246 if (DELETED (c))
2247 continue;
2248 c->miter = 0;
2249 if (c->n_lines == 2 && !c->via && !c->pin && !c->via)
2251 int o1 = line_orient (c->lines[0], c);
2252 int o2 = line_orient (c->lines[1], c);
2253 if (ORIENT (o1) != ORIENT (o2)
2254 && o1 != DIAGONAL && o2 != DIAGONAL
2255 && c->lines[0]->line->Thickness == c->lines[1]->line->Thickness)
2256 c->miter = -1;
2260 done = 0;
2261 progress = 1;
2262 while (!done && progress)
2264 done = 1;
2265 progress = 0;
2266 for (c = corners; c; c = c->next)
2268 if (DELETED (c))
2269 continue;
2270 if (c->miter == -1)
2272 int max = line_length (c->lines[0]);
2273 int len = line_length (c->lines[1]);
2274 int bloat;
2275 int ref, dist;
2276 corner_s *closest_corner = 0, *c2, *oc1, *oc2;
2277 int mx = 0, my = 0, x, y;
2278 int o1 = line_orient (c->lines[0], c);
2279 int o2 = line_orient (c->lines[1], c);
2281 if (c->pad || c->pin || c->via)
2283 c->miter = 0;
2284 progress = 1;
2285 continue;
2288 oc1 = other_corner (c->lines[0], c);
2289 oc2 = other_corner (c->lines[1], c);
2290 #if 0
2291 if (oc1->pad)
2292 oc1 = 0;
2293 if (oc2->pad)
2294 oc2 = 0;
2295 #endif
2297 if ((sel && !(selected (c->lines[0]->line)
2298 || selected (c->lines[1]->line)))
2299 || (!sel && autorouted_only
2300 && !(autorouted (c->lines[0]->line)
2301 || autorouted (c->lines[1]->line))))
2303 c->miter = 0;
2304 progress = 1;
2305 continue;
2308 if (max > len)
2309 max = len;
2310 switch (o1)
2312 case LEFT:
2313 mx = -1;
2314 break;
2315 case RIGHT:
2316 mx = 1;
2317 break;
2318 case UP:
2319 my = -1;
2320 break;
2321 case DOWN:
2322 my = 1;
2323 break;
2325 switch (o2)
2327 case LEFT:
2328 mx = -1;
2329 break;
2330 case RIGHT:
2331 mx = 1;
2332 break;
2333 case UP:
2334 my = -1;
2335 break;
2336 case DOWN:
2337 my = 1;
2338 break;
2340 ref = c->x * mx + c->y * my;
2341 dist = max;
2343 bloat = (c->lines[0]->line->Thickness / 2 + SB + 1) * 3 / 2;
2345 for (c2 = corners; c2; c2 = c2->next)
2347 if (DELETED (c2))
2348 continue;
2349 if (c2 != c && c2 != oc1 && c2 != oc2
2350 && c->x * mx <= c2->x * mx
2351 && c->y * my <= c2->y * my
2352 && c->net != c2->net
2353 && intersecting_layers (c->layer, c2->layer))
2355 int cr = corner_radius (c2);
2356 len = c2->x * mx + c2->y * my - ref - cr - bloat;
2357 if (c->x != c2->x && c->y != c2->y)
2358 len -= cr;
2359 if (len < dist || (len == dist && c->miter != -1))
2361 dist = len;
2362 closest_corner = c2;
2367 if (closest_corner && closest_corner->miter == -1)
2369 done = 0;
2370 continue;
2373 #if 0
2374 if (dist < Settings.Grid)
2376 c->miter = 0;
2377 progress = 1;
2378 continue;
2381 dist -= dist % Settings.Grid;
2382 #endif
2383 if (dist <= 0)
2385 c->miter = 0;
2386 progress = 1;
2387 continue;
2390 x = c->x;
2391 y = c->y;
2392 switch (o1)
2394 case LEFT:
2395 x -= dist;
2396 break;
2397 case RIGHT:
2398 x += dist;
2399 break;
2400 case UP:
2401 y -= dist;
2402 break;
2403 case DOWN:
2404 y += dist;
2405 break;
2407 c2 = find_corner (x, y, c->layer);
2408 if (c2 != other_corner (c->lines[0], c))
2409 split_line (c->lines[0], c2);
2410 x = c->x;
2411 y = c->y;
2412 switch (o2)
2414 case LEFT:
2415 x -= dist;
2416 break;
2417 case RIGHT:
2418 x += dist;
2419 break;
2420 case UP:
2421 y -= dist;
2422 break;
2423 case DOWN:
2424 y += dist;
2425 break;
2427 move_corner (c, x, y);
2428 c->miter = 0;
2429 c2->miter = 0;
2430 progress = 1;
2431 saved++;
2435 return saved;
2438 static void
2439 classify_corner (corner_s * c, int this_net)
2441 int i;
2442 if (c->net == this_net)
2443 return;
2444 c->net = this_net;
2445 for (i = 0; i < c->n_lines; i++)
2446 classify_corner (other_corner (c->lines[i], c), this_net);
2449 static void
2450 classify_nets ()
2452 static int this_net = 1;
2453 corner_s *c;
2455 for (c = corners; c; c = c->next)
2457 if (DELETED (c))
2458 continue;
2459 if (c->net)
2460 continue;
2461 classify_corner (c, this_net);
2462 this_net++;
2466 #if 0
2467 /* Not used */
2468 static void
2469 dump_all ()
2471 corner_s *c;
2472 line_s *l;
2473 for (c = corners; c; c = c->next)
2475 if (DELETED (c))
2476 continue;
2477 printf ("%p corner %d,%d layer %d net %d\n",
2478 (void *) c, c->x, c->y, c->layer, c->net);
2480 for (l = lines; l; l = l->next)
2482 if (DELETED (l))
2483 continue;
2484 printf ("%p line %p to %p layer %d\n",
2485 (void *) l, (void *) (l->s), (void *) (l->e), l->layer);
2488 #endif
2490 static void
2491 nudge_corner (corner_s * c, int dx, int dy, corner_s * prev_corner)
2493 int ox = c->x;
2494 int oy = c->y;
2495 int l;
2496 if (prev_corner && (c->pin || c->pad))
2497 return;
2498 move_corner (c, ox + dx, oy + dy);
2499 for (l = 0; l < c->n_lines; l++)
2501 corner_s *oc = other_corner (c->lines[l], c);
2502 if (oc == prev_corner)
2503 continue;
2504 if (dx && oc->x == ox)
2505 nudge_corner (oc, dx, 0, c);
2506 if (dy && oc->y == oy)
2507 nudge_corner (oc, 0, dy, c);
2511 static line_s *
2512 choose_example_line (corner_s * c1, corner_s * c2)
2514 int ci, li;
2515 corner_s *c[2];
2516 c[0] = c1;
2517 c[1] = c2;
2518 dprintf ("choose_example_line\n");
2519 for (ci = 0; ci < 2; ci++)
2520 for (li = 0; li < c[ci]->n_lines; li++)
2522 dprintf (" try[%d,%d] \033[36m<%d,%d-%d,%d t%d c%d f%s>\033[0m\n",
2523 ci, li,
2524 c[ci]->lines[li]->s->x, c[ci]->lines[li]->s->y,
2525 c[ci]->lines[li]->e->x, c[ci]->lines[li]->e->y,
2526 c[ci]->lines[li]->line->Thickness,
2527 c[ci]->lines[li]->line->Clearance,
2528 flags_to_string (c[ci]->lines[li]->line->Flags, LINE_TYPE));
2529 /* Pads are disqualified, as we want to mimic a trace line. */
2530 if (c[ci]->lines[li]->line == (LineTypePtr) c[ci]->pad)
2532 dprintf (" bad, pad\n");
2533 continue;
2535 /* Lines on layers that don't connect to the other pad are bad too. */
2536 if (!intersecting_layers (c[ci]->lines[li]->layer, c[1 - ci]->layer))
2538 dprintf (" bad, layers\n");
2539 continue;
2541 dprintf (" good\n");
2542 return c[ci]->lines[li];
2544 dprintf ("choose_example_line: none found!\n");
2545 return 0;
2548 static int
2549 connect_corners (corner_s * c1, corner_s * c2)
2551 int layer;
2552 line_s *ex = choose_example_line (c1, c2);
2553 LineType *example = ex->line;
2555 dprintf
2556 ("connect_corners \033[32m%d,%d to %d,%d, example line %d,%d to %d,%d l%d\033[0m\n",
2557 c1->x, c1->y, c2->x, c2->y, ex->s->x, ex->s->y, ex->e->x, ex->e->y,
2558 ex->layer);
2560 layer = ex->layer;
2562 /* Assume c1 is the moveable one. */
2563 if (!(c1->pin || c1->pad || c1->via) && c1->n_lines == 1)
2565 int nx, ny;
2566 /* Extend the line */
2567 if (c1->lines[0]->s->x == c1->lines[0]->e->x)
2568 nx = c1->x, ny = c2->y;
2569 else
2570 nx = c2->x, ny = c1->y;
2571 if (nx != c2->x || ny != c2->y)
2573 move_corner (c1, nx, ny);
2574 new_line (c1, c2, layer, example);
2575 return 1;
2577 else
2579 move_corner (c1, nx, ny);
2580 return 1;
2583 else
2585 corner_s *nc = find_corner (c1->x, c2->y, layer);
2586 new_line (c1, nc, layer, example);
2587 new_line (nc, c2, layer, example);
2588 return 0;
2592 static void
2593 pinsnap ()
2595 corner_s *c;
2596 int best_dist[MAX_LAYER + 1];
2597 corner_s *best_c[MAX_LAYER + 1];
2598 int l, got_one;
2599 int left = 0, right = 0, top = 0, bottom = 0;
2600 PinType *pin;
2601 int again = 1;
2603 corner_s *prev_c;
2604 int close = 0;
2605 corner_s *c2;
2607 /* Look for pins that have no connections. See if there's a corner
2608 close by that should be connected to it. This usually happens
2609 when the MUCS router needs to route to an off-grid pin. */
2610 while (again)
2612 again = 0;
2613 for (c = corners; c; c = c->next)
2615 if (DELETED (c))
2616 continue;
2617 if (!(c->pin || c->via || c->pad))
2618 continue;
2620 prev_c = c;
2621 pin = 0;
2623 dprintf ("\ncorner %s\n", corner_name (c));
2624 if (c->pin || c->via)
2626 pin = c->pin ? c->pin : c->via;
2627 close = pin->Thickness / 2;
2628 left = c->x - close;
2629 right = c->x + close;
2630 bottom = c->y - close;
2631 top = c->y + close;
2633 else if (c->pad)
2635 close = c->pad->Thickness / 2 + 1;
2636 left = djmin (c->pad->Point1.X, c->pad->Point2.X) - close;
2637 right = djmax (c->pad->Point1.X, c->pad->Point2.X) + close;
2638 bottom = djmin (c->pad->Point1.Y, c->pad->Point2.Y) - close;
2639 top = djmax (c->pad->Point1.Y, c->pad->Point2.Y) + close;
2640 if (c->pad->Point1.X == c->pad->Point2.X)
2642 int hy = (c->pad->Point1.Y + c->pad->Point2.Y) / 2;
2643 dprintf ("pad y %d %d hy %d c %d\n", c->pad->Point1.Y,
2644 c->pad->Point2.Y, hy, c->y);
2645 if (c->y < hy)
2646 top = hy;
2647 else
2648 bottom = hy + 1;
2650 else
2652 int hx = (c->pad->Point1.X + c->pad->Point2.X) / 2;
2653 dprintf ("pad x %d %d hx %d c %d\n", c->pad->Point1.X,
2654 c->pad->Point2.X, hx, c->x);
2655 if (c->x < hx)
2656 right = hx;
2657 else
2658 left = hx + 1;
2662 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c), left, right,
2663 bottom, top);
2664 for (l = 0; l <= max_layer; l++)
2666 best_dist[l] = close * 2;
2667 best_c[l] = 0;
2669 got_one = 0;
2670 for (c2 = corners; c2; c2 = c2->next)
2672 int lt;
2674 if (DELETED (c2))
2675 continue;
2676 lt = corner_radius (c2);
2677 if (c2->n_lines
2678 && c2 != c
2679 && !(c2->pin || c2->pad || c2->via)
2680 && intersecting_layers (c->layer, c2->layer)
2681 && c2->x >= left - lt
2682 && c2->x <= right + lt
2683 && c2->y >= bottom - lt && c2->y <= top + lt)
2685 int d = dist (c->x, c->y, c2->x, c2->y);
2686 if (pin && d > pin->Thickness / 2 + lt)
2687 continue;
2688 if (c2->n_lines == 1)
2690 got_one++;
2691 dprintf ("found orphan %s vs %s\n", corner_name (c2),
2692 corner_name (c));
2693 connect_corners (c, c2);
2694 again = 1;
2695 continue;
2697 if (best_c[c2->layer] == 0
2698 || c2->n_lines < best_c[c2->layer]->n_lines
2699 || (d < best_dist[c2->layer]
2700 && c2->n_lines <= best_c[c2->layer]->n_lines))
2702 best_dist[c2->layer] = d;
2703 best_c[c2->layer] = c2;
2704 dprintf ("layer %d best now %s\n", c2->layer,
2705 corner_name (c2));
2708 if (!got_one && c->n_lines == (c->pad ? 1 : 0))
2710 for (l = 0; l <= max_layer; l++)
2711 if (best_c[l])
2712 dprintf ("best[%d] = %s\n", l, corner_name (best_c[l]));
2713 for (l = 0; l <= max_layer; l++)
2714 if (best_c[l])
2716 dprintf ("move %s to %s\n", corner_name (best_c[l]),
2717 corner_name (c));
2718 connect_corners (best_c[l], c);
2719 again = 1;
2720 continue;
2727 /* Now look for line ends that don't connect, see if they need to be
2728 extended to intersect another line. */
2729 for (c = corners; c; c = c->next)
2731 line_s *l, *t;
2732 int lo;
2734 if (DELETED (c))
2735 continue;
2736 if (c->pin || c->via || c->pad)
2737 continue;
2738 if (c->n_lines != 1)
2739 continue;
2741 l = c->lines[0];
2742 lo = line_orient (l, c);
2743 dprintf ("line end %d,%d orient %d\n", c->x, c->y, lo);
2745 for (t = lines; t; t = t->next)
2747 if (DELETED (t))
2748 continue;
2749 if (t->layer != c->lines[0]->layer)
2750 continue;
2751 switch (lo) /* remember, orient is for the line relative to the corner */
2753 case LEFT:
2754 if (t->s->x == t->e->x
2755 && c->x < t->s->x
2756 && t->s->x <
2757 c->x + (l->line->Thickness + t->line->Thickness) / 2
2758 && ((t->s->y < c->y && c->y < t->e->y)
2759 || (t->e->y < c->y && c->y < t->s->y)))
2761 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2762 t->e->y);
2763 move_corner (c, t->s->x, c->y);
2765 break;
2766 case RIGHT:
2767 if (t->s->x == t->e->x
2768 && c->x > t->s->x
2769 && t->s->x >
2770 c->x - (l->line->Thickness + t->line->Thickness) / 2
2771 && ((t->s->y < c->y && c->y < t->e->y)
2772 || (t->e->y < c->y && c->y < t->s->y)))
2774 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2775 t->e->y);
2776 move_corner (c, t->s->x, c->y);
2778 break;
2779 case UP:
2780 if (t->s->y == t->e->y
2781 && c->y < t->s->y
2782 && t->s->y <
2783 c->y + (l->line->Thickness + t->line->Thickness) / 2
2784 && ((t->s->x < c->x && c->x < t->e->x)
2785 || (t->e->x < c->x && c->x < t->s->x)))
2787 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2788 t->e->y);
2789 move_corner (c, c->x, t->s->y);
2791 break;
2792 case DOWN:
2793 if (t->s->y == t->e->y
2794 && c->y > t->s->y
2795 && t->s->y >
2796 c->y - (l->line->Thickness + t->line->Thickness) / 2
2797 && ((t->s->x < c->x && c->x < t->e->x)
2798 || (t->e->x < c->x && c->x < t->s->x)))
2800 dprintf ("found %d,%d - %d,%d\n", t->s->x, t->s->y, t->e->x,
2801 t->e->y);
2802 move_corner (c, c->x, t->s->y);
2804 break;
2810 static int
2811 pad_orient (PadType * p)
2813 if (p->Point1.X == p->Point2.X)
2814 return O_VERT;
2815 if (p->Point1.Y == p->Point2.Y)
2816 return O_HORIZ;
2817 return DIAGONAL;
2820 static void
2821 padcleaner ()
2823 line_s *l, *nextl;
2824 int close;
2825 rect_s r;
2826 int ei, pi;
2828 dprintf ("\ndj: padcleaner\n");
2829 for (l = lines; l; l = nextl)
2831 nextl = l->next;
2833 if (DELETED (l))
2834 continue;
2836 dprintf ("dj: line %p\n", (void *) l);
2837 check (0, l);
2839 if (l->s->pad && l->s->pad == l->e->pad)
2840 continue;
2842 for (ei = 0; ei < PCB->Data->ElementN; ei++)
2844 ElementType *e = &(PCB->Data->Element[ei]);
2845 for (pi = 0; pi < e->PadN; pi++)
2847 PadType *p = e->Pad + pi;
2848 int layerflag =
2849 TEST_FLAG (ONSOLDERFLAG, e) ? LT_SOLDER : LT_COMPONENT;
2851 if (layer_type[l->layer] != layerflag)
2852 continue;
2854 empty_rect (&r);
2855 close = p->Thickness / 2 + 1;
2856 add_point_to_rect (&r, p->Point1.X, p->Point1.Y,
2857 close - SB / 2);
2858 add_point_to_rect (&r, p->Point2.X, p->Point2.Y,
2859 close - SB / 2);
2860 if (pin_in_rect (&r, l->s->x, l->s->y, 0)
2861 && pin_in_rect (&r, l->e->x, l->e->y, 0)
2862 && ORIENT (line_orient (l, 0)) == pad_orient (p))
2864 dprintf
2865 ("padcleaner %d,%d-%d,%d %d vs line %d,%d-%d,%d %d\n",
2866 p->Point1.X, p->Point1.Y, p->Point2.X, p->Point2.Y,
2867 p->Thickness, l->s->x, l->s->y, l->e->x, l->e->y,
2868 l->line->Thickness);
2869 remove_line (l);
2870 goto next_line;
2874 next_line:;
2878 static void
2879 grok_layer_groups ()
2881 int i, j, f;
2882 LayerGroupType *l = &(PCB->LayerGroups);
2884 solder_layer = component_layer = -1;
2885 for (i = 0; i < max_layer; i++)
2887 layer_type[i] = 0;
2888 layer_groupings[i] = 0;
2890 for (i = 0; i < max_layer; i++)
2892 f = 0;
2893 for (j = 0; j < l->Number[i]; j++)
2895 if (l->Entries[i][j] == max_layer + SOLDER_LAYER)
2896 f |= LT_SOLDER;
2897 if (l->Entries[i][j] == max_layer + COMPONENT_LAYER)
2898 f |= LT_COMPONENT;
2900 for (j = 0; j < l->Number[i]; j++)
2902 if (l->Entries[i][j] >= 0 && l->Entries[i][j] < max_layer)
2904 layer_type[l->Entries[i][j]] |= f;
2905 layer_groupings[l->Entries[i][j]] = i;
2906 if (solder_layer == -1 && f == LT_SOLDER)
2907 solder_layer = l->Entries[i][j];
2908 if (component_layer == -1 && f == LT_COMPONENT)
2909 component_layer = l->Entries[i][j];
2915 static const char djopt_syntax[] =
2916 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull)\n"
2917 "djopt(auto) - all of the above\n" "djopt(miter)";
2919 static const char djopt_help[] =
2920 "Perform various optimizations on the current board";
2922 /* %start-doc actions djopt
2924 The different types of optimizations change your board in order to
2925 reduce the total trace length and via count.
2927 @table @code
2929 @item debumpify
2930 Looks for U-shaped traces that can be shortened or eliminated.
2932 @item unjaggy
2933 Looks for corners which could be flipped to eliminate one or more
2934 corners (i.e. jaggy lines become simpler).
2936 @item simple
2937 Removing uneeded vias, replacing two or more trace segments in a row
2938 with a single segment. This is usually performed automatically after
2939 other optimizations.
2941 @item vianudge
2942 Looks for vias where all traces leave in the same direction. Tries to
2943 move via in that direction to eliminate one of the traces (and thus a
2944 corner).
2946 @item viatrim
2947 Looks for traces that go from via to via, where moving that trace to a
2948 different layer eliminates one or both vias.
2950 @item orthopull
2951 Looks for chains of traces all going in one direction, with more
2952 traces orthogonal on one side than on the other. Moves the chain in
2953 that direction, causing a net reduction in trace length, possibly
2954 eliminating traces and/or corners.
2956 @item splitlines
2957 Looks for lines that pass through vias, pins, or pads, and splits them
2958 into separate lines so they can be managed separately.
2960 @item auto
2961 Performs the above options, repeating until no further optimizations
2962 can be made.
2964 @item miter
2965 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2966 RF losses and trace length.
2968 @end table
2970 %end-doc */
2972 static int
2973 ActionDJopt (int argc, char **argv, int x, int y)
2975 char *arg = argc > 0 ? argv[0] : 0;
2976 int layn, saved = 0;
2977 corner_s *c;
2979 #ifdef ENDIF
2980 SwitchDrawingWindow (PCB->Zoom, Output.drawing_area->window,
2981 Settings.ShowSolderSide, False);
2982 #endif
2984 hid_action("Busy");
2986 lines = 0;
2987 corners = 0;
2989 grok_layer_groups ();
2991 ELEMENT_LOOP (PCB->Data);
2992 PIN_LOOP (element);
2994 c = find_corner (pin->X, pin->Y, -1);
2995 c->pin = pin;
2997 END_LOOP;
2998 PAD_LOOP (element);
3000 int layern =
3001 TEST_FLAG (ONSOLDERFLAG, pad) ? solder_layer : component_layer;
3002 line_s *ls = (line_s *) malloc (sizeof (line_s));
3003 ls->next = lines;
3004 lines = ls;
3005 ls->s = find_corner (pad->Point1.X, pad->Point1.Y, layern);
3006 ls->s->pad = pad;
3007 ls->e = find_corner (pad->Point2.X, pad->Point2.Y, layern);
3008 ls->e->pad = pad;
3009 ls->layer = layern;
3010 ls->line = (LineTypePtr) pad;
3011 add_line_to_corner (ls, ls->s);
3012 ls->layer = layern;
3013 ls->line = (LineTypePtr) pad;
3014 add_line_to_corner (ls, ls->s);
3015 add_line_to_corner (ls, ls->e);
3018 END_LOOP;
3019 END_LOOP;
3020 VIA_LOOP (PCB->Data);
3021 /* hace don't mess with vias that have thermals */
3022 /* but then again don't bump into them
3023 if (!TEST_FLAG(ALLTHERMFLAGS, via))
3026 c = find_corner (via->X, via->Y, -1);
3027 c->via = via;
3029 END_LOOP;
3030 check (0, 0);
3032 if (NSTRCMP (arg, "splitlines") == 0)
3034 if (canonicalize_lines ())
3035 IncrementUndoSerialNumber ();
3036 return 0;
3039 for (layn = 0; layn < max_layer; layn++)
3041 LayerType *layer = LAYER_PTR (layn);
3042 int ln;
3043 for (ln = 0; ln < layer->LineN; ln++)
3045 LineType *l = &(layer->Line[ln]);
3046 line_s *ls;
3048 /* don't mess with thermals */
3049 if (TEST_FLAG (USETHERMALFLAG, l))
3050 continue;
3052 if (l->Point1.X == l->Point2.X && l->Point1.Y == l->Point2.Y)
3054 RemoveLine (layer, l);
3055 ln--;
3056 continue;
3059 ls = (line_s *) malloc (sizeof (line_s));
3060 ls->next = lines;
3061 lines = ls;
3062 ls->s = find_corner (l->Point1.X, l->Point1.Y, layn);
3063 ls->e = find_corner (l->Point2.X, l->Point2.Y, layn);
3064 ls->line = l;
3065 add_line_to_corner (ls, ls->s);
3066 add_line_to_corner (ls, ls->e);
3067 ls->layer = layn;
3072 check (0, 0);
3073 pinsnap ();
3074 canonicalize_lines ();
3075 check (0, 0);
3076 classify_nets ();
3077 /*dump_all(); */
3078 check (0, 0);
3080 if (NSTRCMP (arg, "debumpify") == 0)
3081 saved += debumpify ();
3082 else if (NSTRCMP (arg, "unjaggy") == 0)
3083 saved += unjaggy ();
3084 else if (NSTRCMP (arg, "simple") == 0)
3085 saved += simple_optimizations ();
3086 else if (NSTRCMP (arg, "vianudge") == 0)
3087 saved += vianudge ();
3088 else if (NSTRCMP (arg, "viatrim") == 0)
3089 saved += viatrim ();
3090 else if (NSTRCMP (arg, "orthopull") == 0)
3091 saved += orthopull ();
3092 else if (NSTRCMP (arg, "auto") == 0)
3093 saved += automagic ();
3094 else if (NSTRCMP (arg, "miter") == 0)
3095 saved += miter ();
3096 else
3098 printf ("unknown command: %s\n", arg);
3099 return 1;
3102 padcleaner ();
3104 check (0, 0);
3105 if (saved)
3106 IncrementUndoSerialNumber ();
3107 return 0;
3110 HID_Action djopt_action_list[] = {
3111 {"djopt", 0, ActionDJopt,
3112 djopt_help, djopt_syntax}
3114 {"OptAutoOnly", 0, djopt_set_auto_only,
3115 djopt_sao_help, djopt_sao_syntax}
3118 REGISTER_ACTIONS (djopt_action_list)