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
48 #ifdef HAVE_LIBDMALLOC
55 #define rint(x) (ceil((x) - 0.5))
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)
75 #define ORIENT(x) ((x) & 0xf0)
76 #define DIRECT(x) ((x) & 0x0f)
78 /* Manhattan length of the longest "freckle" */
79 #define LONGEST_FRECKLE 2
83 typedef struct corner_s
86 struct corner_s
*next
;
94 struct line_s
**lines
;
106 typedef struct rect_s
111 #define DELETE(q) (q)->layer = 0xdeadbeef
112 #define DELETED(q) ((q)->layer == 0xdeadbeef)
114 static corner_s
*corners
, *next_corner
= 0;
115 static line_s
*lines
;
117 static int layer_groupings
[MAX_LAYER
];
118 static char layer_type
[MAX_LAYER
];
119 #define LT_COMPONENT 1
122 static int autorouted_only
= 1;
124 static const char djopt_sao_syntax
[] = "OptAutoOnly()";
126 static const char djopt_sao_help
[] =
127 "Toggles the optimize-only-autorouted flag.";
129 /* %start-doc actions OptAutoOnly
131 The original purpose of the trace optimizer was to clean up the traces
132 created by the various autorouters that have been used with PCB. When
133 a board has a mix of autorouted and carefully hand-routed traces, you
134 don't normally want the optimizer to move your hand-routed traces.
135 But, sometimes you do. By default, the optimizer only optimizes
136 autorouted traces. This action toggles that setting, so that you can
137 optimize hand-routed traces also.
142 djopt_set_auto_only (int argc
, char **argv
, int x
, int y
)
144 autorouted_only
= autorouted_only
? 0 : 1;
149 djopt_get_auto_only (int dummy
)
151 return autorouted_only
;
154 HID_Flag djopt_flag_list
[] = {
155 {"optautoonly", djopt_get_auto_only
, 0}
158 REGISTER_FLAGS (djopt_flag_list
)
161 element_name_for (corner_s
* c
)
166 for (i
= 0; i
< PCB
->Data
->ElementN
; i
++)
168 e
= PCB
->Data
->Element
+ i
;
169 for (p
= 0; p
< e
->PinN
; p
++)
170 if (e
->Pin
+ p
== c
->pin
)
171 return e
->Name
[1].TextString
;
172 for (p
= 0; p
< e
->PadN
; p
++)
173 if (e
->Pad
+ p
== c
->pad
)
174 return e
->Name
[1].TextString
;
180 corner_name (corner_s
* c
)
182 static char buf
[4][100];
187 if (c
->net
== 0xf1eef1ee)
189 sprintf (buf
[bn
], "\033[31m[%p freed corner]\033[0m", (void *) c
);
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
]);
198 sprintf (bp
, "pin %s:%s at %d,%d", element_name_for (c
), c
->pin
->Number
,
201 sprintf (bp
, "via at %d,%d", c
->x
, c
->y
);
204 sprintf (bp
, "pad %s:%s at %d,%d (%d,%d-%d,%d)",
205 element_name_for (c
), c
->pad
->Number
, c
->x
, c
->y
,
206 c
->pad
->Point1
.X
, c
->pad
->Point1
.Y
,
207 c
->pad
->Point2
.X
, c
->pad
->Point2
.Y
);
210 sprintf (bp
, "at %d,%d", c
->x
, c
->y
);
211 sprintf (bp
+ strlen (bp
), " n%d l%d]\033[0m", c
->n_lines
, c
->layer
);
215 static int solder_layer
, component_layer
;
218 dj_abort (char *msg
, ...)
231 #define check(c,l) check2(__LINE__,c,l)
233 check2 (int srcline
, corner_s
* c
, line_s
* l
)
235 int saw_c
= 0, saw_l
= 0;
240 for (cc
= corners
; cc
; cc
= cc
->next
)
246 for (i
= 0; i
< cc
->n_lines
; i
++)
247 if (cc
->lines
[i
]->s
!= cc
&& cc
->lines
[i
]->e
!= cc
)
248 dj_abort ("check:%d: cc has line without backref\n", srcline
);
249 if (cc
->via
&& (cc
->x
!= cc
->via
->X
|| cc
->y
!= cc
->via
->Y
))
250 dj_abort ("check:%d: via not at corner\n", srcline
);
251 if (cc
->pin
&& (cc
->x
!= cc
->pin
->X
|| cc
->y
!= cc
->pin
->Y
))
252 dj_abort ("check:%d: pin not at corner\n", srcline
);
255 dj_abort ("check:%d: corner not in corners list\n", srcline
);
256 for (ll
= lines
; ll
; ll
= ll
->next
)
262 for (i
= 0; i
< ll
->s
->n_lines
; i
++)
263 if (ll
->s
->lines
[i
] == ll
)
265 if (i
== ll
->s
->n_lines
)
266 dj_abort ("check:%d: ll->s has no backref\n", srcline
);
267 for (i
= 0; i
< ll
->e
->n_lines
; i
++)
268 if (ll
->e
->lines
[i
] == ll
)
270 if (i
== ll
->e
->n_lines
)
271 dj_abort ("check:%d: ll->e has no backref\n", srcline
);
273 && (ll
->s
->x
!= ll
->line
->Point1
.X
274 || ll
->s
->y
!= ll
->line
->Point1
.Y
275 || ll
->e
->x
!= ll
->line
->Point2
.X
276 || ll
->e
->y
!= ll
->line
->Point2
.Y
))
278 printf ("line: %d,%d to %d,%d pcbline: %d,%d to %d,%d\n",
282 ll
->line
->Point1
.Y
, ll
->line
->Point2
.X
, ll
->line
->Point2
.Y
);
283 dj_abort ("check:%d: line doesn't match pcbline\n", srcline
);
287 dj_abort ("check:%d: line not in lines list\n", srcline
);
292 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
299 return n
- n
% (int) (Settings
.Grid
);
302 /* Avoid commonly used names. */
307 return x
> 0 ? x
: -x
;
313 return x
> y
? x
: y
;
319 return x
< y
? x
: y
;
323 * Find distance between 2 points. We use floating point math here
324 * because we can fairly easily overflow a 32 bit integer here. In
325 * fact it only takes 0.46" to do so.
328 dist (int x1
, int y1
, int x2
, int y2
)
330 double dx1
, dy1
, dx2
, dy2
, d
;
337 d
= sqrt ((dx1
- dx2
) * (dx1
- dx2
) + (dy1
- dy2
) * (dy1
- dy2
));
344 line_length (line_s
* l
)
346 if (l
->s
->x
== l
->e
->x
)
347 return djabs (l
->s
->y
- l
->e
->y
);
348 if (l
->s
->y
== l
->e
->y
)
349 return djabs (l
->s
->x
- l
->e
->x
);
350 return dist (l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
);
354 dist_ltp2 (int dx
, int y
, int y1
, int y2
)
359 return dist (dx
, y
, 0, y1
);
361 return dist (dx
, y
, 0, y2
);
372 intersecting_layers (int l1
, int l2
)
374 if (l1
== -1 || l2
== -1)
378 if (layer_groupings
[l1
] == layer_groupings
[l2
])
384 dist_line_to_point (line_s
* l
, corner_s
* c
)
387 /* We can do this quickly if l is vertical or horizontal. */
388 if (l
->s
->x
== l
->e
->x
)
389 return dist_ltp2 (l
->s
->x
- c
->x
, c
->y
, l
->s
->y
, l
->e
->y
);
390 if (l
->s
->y
== l
->e
->y
)
391 return dist_ltp2 (l
->s
->y
- c
->y
, c
->x
, l
->s
->x
, l
->e
->x
);
393 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
394 len
= sqrt (sqr (l
->s
->x
- l
->e
->x
) + sqr (l
->s
->y
- l
->e
->y
));
396 return dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
);
398 (l
->s
->y
- c
->y
) * (l
->s
->y
- l
->e
->y
) + (l
->s
->x
- c
->x
) * (l
->s
->x
-
402 return dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
);
404 return dist (l
->e
->x
, l
->e
->y
, c
->x
, c
->y
);
406 (l
->e
->y
- l
->s
->y
) * (c
->x
* l
->s
->x
) + (l
->e
->x
- l
->s
->x
) * (c
->y
-
408 return (int) (d
/ len
);
412 line_orient (line_s
* l
, corner_s
* c
)
447 common_corner (line_s
* l1
, line_s
* l2
)
449 if (l1
->s
== l2
->s
|| l1
->s
== l2
->e
)
451 if (l1
->e
== l2
->s
|| l1
->e
== l2
->e
)
453 dj_abort ("common_corner: no common corner found\n");
459 other_corner (line_s
* l
, corner_s
* c
)
465 dj_abort ("other_corner: neither corner passed\n");
470 find_corner_if (int x
, int y
, int l
)
473 for (c
= corners
; c
; c
= c
->next
)
477 if (c
->x
!= x
|| c
->y
!= y
)
479 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
487 find_corner (int x
, int y
, int l
)
490 for (c
= corners
; c
; c
= c
->next
)
494 if (c
->x
!= x
|| c
->y
!= y
)
496 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
500 c
= (corner_s
*) malloc (sizeof (corner_s
));
511 c
->lines
= (line_s
**) malloc (INC
* sizeof (line_s
*));
516 add_line_to_corner (line_s
* l
, corner_s
* c
)
519 n
= (c
->n_lines
+ 1 + INC
) & ~INC
;
520 c
->lines
= (line_s
**) realloc (c
->lines
, n
* sizeof (line_s
*));
521 c
->lines
[c
->n_lines
] = l
;
523 dprintf ("add_line_to_corner %d %d\n", c
->x
, c
->y
);
527 create_pcb_line (int layer
, int x1
, int y1
, int x2
, int y2
,
528 int thick
, int clear
, FlagType flags
)
532 LayerType
*lyr
= LAYER_PTR (layer
);
534 from
= (char *) lyr
->Line
;
535 nl
= CreateNewLineOnLayer (PCB
->Data
->Layer
+ layer
,
536 x1
, y1
, x2
, y2
, thick
, clear
, flags
);
537 AddObjectToCreateUndoList (LINE_TYPE
, lyr
, nl
, nl
);
539 to
= (char *) lyr
->Line
;
543 for (lp
= lines
; lp
; lp
= lp
->next
)
547 if ((char *) (lp
->line
) >= from
548 && (char *) (lp
->line
) <= from
+ lyr
->LineN
* sizeof (LineType
))
549 lp
->line
= (LineType
*) ((char *) (lp
->line
) + (to
- from
));
556 new_line (corner_s
* s
, corner_s
* e
, int layer
, LineType
* example
)
560 if (layer
>= max_copper_layer
)
561 dj_abort ("layer %d\n", layer
);
564 dj_abort ("NULL example passed to new_line()\n", layer
);
566 if (s
->x
== e
->x
&& s
->y
== e
->y
)
569 ls
= (line_s
*) malloc (sizeof (line_s
));
577 if ((example
->Point1
.X
== s
->x
&& example
->Point1
.Y
== s
->y
578 && example
->Point2
.X
== e
->x
&& example
->Point2
.Y
== e
->y
)
579 || (example
->Point2
.X
== s
->x
&& example
->Point2
.Y
== s
->y
580 && example
->Point1
.X
== e
->x
&& example
->Point1
.Y
== e
->y
))
589 ("New line \033[35m%d,%d to %d,%d from l%d t%d c%d f%s\033[0m\n",
590 s
->x
, s
->y
, e
->x
, e
->y
, layer
, example
->Thickness
,
591 example
->Clearance
, flags_to_string (example
->Flags
, LINE_TYPE
));
593 create_pcb_line (layer
, s
->x
, s
->y
, e
->x
, e
->y
, example
->Thickness
,
594 example
->Clearance
, example
->Flags
);
597 dj_abort ("can't create new line!");
600 add_line_to_corner (ls
, s
);
601 add_line_to_corner (ls
, e
);
609 c_orth_to (corner_s
* c
, line_s
* l
, int o
)
613 for (i
= 0; i
< c
->n_lines
; i
++)
615 if (c
->lines
[i
] == l
)
617 o2
= line_orient (c
->lines
[i
], c
);
618 if (ORIENT (o
) == ORIENT (o2
) || o2
== DIAGONAL
)
627 other_line (corner_s
* c
, line_s
* l
)
631 if (c
->pin
|| c
->pad
|| c
->via
)
633 for (i
= 0; i
< c
->n_lines
; i
++)
635 if (c
->lines
[i
] == l
)
645 empty_rect (rect_s
* rect
)
647 rect
->x1
= rect
->y1
= INT_MAX
;
648 rect
->x2
= rect
->y2
= INT_MIN
;
652 add_point_to_rect (rect_s
* rect
, int x
, int y
, int w
)
654 if (rect
->x1
> x
- w
)
656 if (rect
->x2
< x
+ w
)
658 if (rect
->y1
> y
- w
)
660 if (rect
->y2
< y
+ w
)
665 add_line_to_rect (rect_s
* rect
, line_s
* l
)
667 add_point_to_rect (rect
, l
->s
->x
, l
->s
->y
, 0);
668 add_point_to_rect (rect
, l
->e
->x
, l
->e
->y
, 0);
672 pin_in_rect (rect_s
* r
, int x
, int y
, int w
)
674 if (x
< r
->x1
&& x
+ w
< r
->x1
)
676 if (x
> r
->x2
&& x
- w
> r
->x2
)
678 if (y
< r
->y1
&& y
+ w
< r
->y1
)
680 if (y
> r
->y2
&& y
- w
> r
->y2
)
686 line_in_rect (rect_s
* r
, line_s
* l
)
690 add_point_to_rect (&lr
, l
->s
->x
, l
->s
->y
, l
->line
->Thickness
/ 2);
691 add_point_to_rect (&lr
, l
->e
->x
, l
->e
->y
, l
->line
->Thickness
/ 2);
692 dprintf ("line_in_rect %d,%d-%d,%d vs %d,%d-%d,%d\n",
693 r
->x1
, r
->y1
, r
->x2
, r
->y2
, lr
.x1
, lr
.y1
, lr
.x2
, lr
.y2
);
694 /* simple intersection of rectangles */
703 if (lr
.x1
< lr
.x2
&& lr
.y1
< lr
.y2
)
709 corner_radius (corner_s
* c
)
714 diam
= djmax (c
->pin
->Thickness
, diam
);
716 diam
= djmax (c
->via
->Thickness
, diam
);
717 for (i
= 0; i
< c
->n_lines
; i
++)
718 if (c
->lines
[i
]->line
)
719 diam
= djmax (c
->lines
[i
]->line
->Thickness
, diam
);
720 diam
= (diam
+ 1) / 2;
727 corner_layer (corner_s
* c
)
729 if (c
->pin
|| c
->via
)
733 return c
->lines
[0]->layer
;
738 add_corner_to_rect_if (rect_s
* rect
, corner_s
* c
, rect_s
* e
)
740 int diam
= corner_radius (c
);
741 if (!pin_in_rect (e
, c
->x
, c
->y
, diam
))
743 if (c
->x
< e
->x1
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x1
, e
->y1
) > diam
)
745 if (c
->x
> e
->x2
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x2
, e
->y1
) > diam
)
747 if (c
->x
< e
->x1
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x1
, e
->y2
) > diam
)
749 if (c
->x
> e
->x2
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x2
, e
->y2
) > diam
)
752 /*printf("add point %d,%d diam %d\n", c->x, c->y, diam); */
753 add_point_to_rect (rect
, c
->x
, c
->y
, diam
);
757 remove_line (line_s
* l
)
761 LineType
*from
= 0, *to
= 0;
762 LayerType
*layer
= &(PCB
->Data
->Layer
[l
->layer
]);
768 /* compensate for having line pointers rearranged */
769 from
= &(layer
->Line
[layer
->LineN
- 1]);
771 RemoveLine (layer
, l
->line
);
775 for (l2
= lines
; l2
; l2
= l2
->next
)
779 if (l2
->line
== from
)
783 for (i
= 0, j
= 0; i
< l
->s
->n_lines
; i
++)
784 if (l
->s
->lines
[i
] != l
)
785 l
->s
->lines
[j
++] = l
->s
->lines
[i
];
788 for (i
= 0, j
= 0; i
< l
->e
->n_lines
; i
++)
789 if (l
->e
->lines
[i
] != l
)
790 l
->e
->lines
[j
++] = l
->e
->lines
[i
];
796 move_line_to_layer (line_s
* l
, int layer
)
800 LineType
*from
= 0, *to
= 0;
801 LineType
*oldbase
= 0, *newbase
= 0, *oldend
;
804 ls
= LAYER_PTR (l
->layer
);
805 from
= &(ls
->Line
[ls
->LineN
- 1]);
808 ld
= LAYER_PTR (layer
);
810 oldend
= oldbase
+ ld
->LineN
;
812 newline
= (LineType
*) MoveObjectToLayer (LINE_TYPE
, ls
, l
->line
, 0, ld
, 0);
815 for (l2
= lines
; l2
; l2
= l2
->next
)
819 if (l2
->line
== from
)
821 if (l2
->line
>= oldbase
&& l2
->line
< oldend
)
822 l2
->line
+= newbase
- oldbase
;
830 remove_via_at (corner_s
* c
)
833 PinType
*from
= PCB
->Data
->Via
+ PCB
->Data
->ViaN
- 1;
834 PinType
*to
= c
->via
;
835 RemoveObject (VIA_TYPE
, c
->via
, 0, 0);
837 for (cc
= corners
; cc
; cc
= cc
->next
)
847 remove_corner (corner_s
* c2
)
850 dprintf ("remove corner %s\n", corner_name (c2
));
853 for (c
= corners
; c
; c
= c
->next
)
860 if (next_corner
== c2
)
861 next_corner
= c2
->next
;
868 merge_corners (corner_s
* c1
, corner_s
* c2
)
873 dprintf ("merge corners %s %s\n", corner_name (c1
), corner_name (c2
));
874 for (i
= 0; i
< c2
->n_lines
; i
++)
876 add_line_to_corner (c2
->lines
[i
], c1
);
877 if (c2
->lines
[i
]->s
== c2
)
878 c2
->lines
[i
]->s
= c1
;
879 if (c2
->lines
[i
]->e
== c2
)
880 c2
->lines
[i
]->e
= c1
;
882 if (c1
->via
&& c2
->via
)
890 if (c2
->layer
!= c1
->layer
)
897 move_corner (corner_s
* c
, int x
, int y
)
904 if (c
->pad
|| c
->pin
)
905 dj_abort ("move_corner: has pin or pad\n");
906 dprintf ("move_corner %p from %d,%d to %d,%d\n", (void *) c
, c
->x
, c
->y
, x
,
908 pad
= find_corner_if (x
, y
, c
->layer
);
914 MoveObject (VIA_TYPE
, via
, via
, via
, x
- via
->X
, y
- via
->Y
);
915 dprintf ("via move %d,%d to %d,%d\n", via
->X
, via
->Y
, x
, y
);
917 for (i
= 0; i
< c
->n_lines
; i
++)
919 LineTypePtr tl
= c
->lines
[i
]->line
;
922 if (c
->lines
[i
]->s
== c
)
924 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (c
->lines
[i
]->layer
), tl
,
925 &tl
->Point1
, x
- (tl
->Point1
.X
),
930 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (c
->lines
[i
]->layer
), tl
,
931 &tl
->Point2
, x
- (tl
->Point2
.X
),
934 dprintf ("Line %p moved to %d,%d %d,%d\n", (void *) tl
,
935 tl
->Point1
.X
, tl
->Point1
.Y
, tl
->Point2
.X
, tl
->Point2
.Y
);
939 merge_corners (c
, pad
);
941 for (i
= 0; i
< c
->n_lines
; i
++)
943 if (c
->lines
[i
]->s
->x
== c
->lines
[i
]->e
->x
944 && c
->lines
[i
]->s
->y
== c
->lines
[i
]->e
->y
)
946 corner_s
*c2
= other_corner (c
->lines
[i
], c
);
947 dprintf ("move_corner: removing line %d,%d %d,%d %p %p\n",
948 c
->x
, c
->y
, c2
->x
, c2
->y
, (void *) c
, (void *) c2
);
950 remove_line (c
->lines
[i
]);
952 merge_corners (c
, c2
);
958 gui
->progress (0, 0, 0);
966 for (l
= lines
; l
; l
= l
->next
)
970 if (l
->line
&& selected (l
->line
))
977 trim_step (int s
, int l1
, int l2
)
979 dprintf ("trim %d %d %d\n", s
, l1
, l2
);
984 if (s
!= l1
&& s
!= l2
)
989 static int canonicalize_line (line_s
* l
);
992 split_line (line_s
* l
, corner_s
* c
)
999 if (!intersecting_layers (l
->layer
, c
->layer
))
1005 dprintf ("split on pad!\n");
1006 if (l
->s
->pad
== c
->pad
|| l
->e
->pad
== c
->pad
)
1008 dprintf ("splitting...\n");
1012 layer
= PCB
->Data
->Layer
+ l
->layer
;
1013 pcbline
= create_pcb_line (l
->layer
,
1014 c
->x
, c
->y
, l
->e
->x
, l
->e
->y
,
1015 l
->line
->Thickness
, l
->line
->Clearance
,
1018 return 0; /* already a line there */
1022 dprintf ("split line from %d,%d to %d,%d at %d,%d\n",
1023 l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
, c
->x
, c
->y
);
1024 ls
= (line_s
*) malloc (sizeof (line_s
));
1032 ls
->layer
= l
->layer
;
1033 for (i
= 0; i
< l
->e
->n_lines
; i
++)
1034 if (l
->e
->lines
[i
] == l
)
1035 l
->e
->lines
[i
] = ls
;
1037 add_line_to_corner (l
, c
);
1038 add_line_to_corner (ls
, c
);
1040 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (l
->layer
), l
->line
, &l
->line
->Point2
,
1041 c
->x
- (l
->line
->Point2
.X
), c
->y
- (l
->line
->Point2
.Y
));
1047 canonicalize_line (line_s
* l
)
1049 /* This could be faster */
1051 if (l
->s
->x
== l
->e
->x
)
1055 int x1
= l
->s
->x
- l
->line
->Thickness
/ 2;
1056 int x2
= l
->s
->x
+ l
->line
->Thickness
/ 2;
1063 for (c
= corners
; c
; c
= c
->next
)
1067 if ((y1
< c
->y
&& c
->y
< y2
)
1068 && intersecting_layers (l
->layer
, c
->layer
))
1071 && c
->x
< x2
&& c
->x
> x1
&& !(c
->pad
|| c
->pin
))
1073 move_corner (c
, l
->s
->x
, c
->y
);
1075 if (c
->x
== l
->s
->x
)
1077 /* FIXME: if the line is split, we have to re-canonicalize
1079 return split_line (l
, c
);
1084 else if (l
->s
->y
== l
->e
->y
)
1088 int y1
= l
->s
->y
- l
->line
->Thickness
/ 2;
1089 int y2
= l
->s
->y
+ l
->line
->Thickness
/ 2;
1096 for (c
= corners
; c
; c
= c
->next
)
1100 if ((x1
< c
->x
&& c
->x
< x2
)
1101 && intersecting_layers (l
->layer
, c
->layer
))
1104 && c
->y
< y2
&& c
->y
> y1
&& !(c
->pad
|| c
->pin
))
1106 move_corner (c
, c
->x
, l
->s
->y
);
1108 if (c
->y
== l
->s
->y
)
1110 /* FIXME: Likewise. */
1111 return split_line (l
, c
);
1118 /* diagonal lines. Let's try to split them at pins/vias
1136 for (c
= corners
; c
; c
= c
->next
)
1140 if (!c
->via
&& !c
->pin
)
1142 if ((x1
< c
->x
&& c
->x
< x2
)
1143 && (y1
< c
->y
&& c
->y
< y2
)
1144 && intersecting_layers (l
->layer
, c
->layer
))
1146 int th
= c
->pin
? c
->pin
->Thickness
: c
->via
->Thickness
;
1148 if (dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
) > th
1149 && dist (l
->e
->x
, l
->e
->y
, c
->x
, c
->y
) > th
1150 && PinLineIntersect (c
->pin
? c
->pin
: c
->via
, l
->line
))
1152 return split_line (l
, c
);
1160 /* Make sure all vias are at line end points */
1162 canonicalize_lines ()
1170 for (l
= lines
; l
; l
= l
->next
)
1174 count
+= canonicalize_line (l
);
1184 simple_optimize_corner (corner_s
* c
)
1192 /* see if no via is needed */
1193 if (selected (c
->via
))
1194 dprintf ("via check: line[0] layer %d at %d,%d nl %d\n",
1195 c
->lines
[0]->layer
, c
->x
, c
->y
, c
->n_lines
);
1196 /* We can't delete vias that connect to power planes, or vias
1197 that aren't tented (assume they're test points). */
1198 if (!TEST_ANY_THERMS (c
->via
)
1199 && c
->via
->Mask
== 0)
1201 for (i
= 1; i
< c
->n_lines
; i
++)
1203 if (selected (c
->via
))
1204 dprintf (" line[%d] layer %d %d,%d to %d,%d\n",
1205 i
, c
->lines
[i
]->layer
,
1206 c
->lines
[i
]->s
->x
, c
->lines
[i
]->s
->y
,
1207 c
->lines
[i
]->e
->x
, c
->lines
[i
]->e
->y
);
1208 if (c
->lines
[i
]->layer
!= c
->lines
[0]->layer
)
1211 if (i
== c
->n_lines
)
1213 if (selected (c
->via
))
1214 dprintf (" remove it\n");
1222 if (c
->n_lines
== 2 && !c
->via
)
1224 /* see if it is an unneeded corner */
1225 int o
= line_orient (c
->lines
[0], c
);
1226 corner_s
*c2
= other_corner (c
->lines
[1], c
);
1227 corner_s
*c0
= other_corner (c
->lines
[0], c
);
1228 if (o
== line_orient (c
->lines
[1], c2
) && o
!= DIAGONAL
)
1230 dprintf ("straight %d,%d to %d,%d to %d,%d\n",
1231 c0
->x
, c0
->y
, c
->x
, c
->y
, c2
->x
, c2
->y
);
1232 if (selected (c
->lines
[0]->line
))
1233 SET_FLAG (SELECTEDFLAG
, c
->lines
[1]->line
);
1234 if (selected (c
->lines
[1]->line
))
1235 SET_FLAG (SELECTEDFLAG
, c
->lines
[0]->line
);
1236 move_corner (c
, c2
->x
, c2
->y
);
1240 if (c
->n_lines
== 1 && !c
->via
)
1242 corner_s
*c0
= other_corner (c
->lines
[0], c
);
1243 if (abs(c
->x
- c0
->x
) + abs(c
->y
- c0
->y
) <= LONGEST_FRECKLE
)
1246 * Remove this line, as it is a "freckle". A freckle is an extremely
1247 * short line (around 0.01 thou) that is unconnected at one end.
1248 * Freckles are almost insignificantly small, but are annoying as
1249 * they prevent the mitering optimiser from working.
1250 * Freckles sometimes arise because of a bug in the autorouter that
1251 * causes it to create small overshoots (typically 0.01 thou) at the
1252 * intersections of vertical and horizontal lines. These overshoots
1253 * are converted to freckles as a side effect of canonicalize_line().
1254 * Note that canonicalize_line() is not at fault, the bug is in the
1255 * autorouter creating overshoots.
1256 * The autorouter bug arose some time between the 20080202 and 20091103
1258 * This code is probably worth keeping even when the autorouter bug is
1259 * fixed, as "freckles" could conceivably arise in other ways.
1261 dprintf ("freckle %d,%d to %d,%d\n",
1262 c
->x
, c
->y
, c0
->x
, c0
->y
);
1263 move_corner (c
, c0
->x
, c0
->y
);
1270 /* We always run these */
1272 simple_optimizations ()
1277 /* Look for corners that aren't */
1278 for (c
= corners
; c
; c
= c
->next
)
1282 if (c
->pad
|| c
->pin
)
1284 rv
+= simple_optimize_corner (c
);
1290 is_hole (corner_s
* c
)
1292 return c
->pin
|| c
->pad
|| c
->via
;
1296 orthopull_1 (corner_s
* c
, int fdir
, int rdir
, int any_sel
)
1298 static corner_s
**cs
= 0;
1300 static line_s
**ls
= 0;
1302 int i
, li
, ln
, cn
, snap
;
1305 int adir
= 0, sdir
= 0, pull
;
1306 int saw_sel
= 0, saw_auto
= 0;
1307 int max
, len
= 0, r1
= 0, r2
;
1313 cs
= (corner_s
**) malloc (10 * sizeof (corner_s
));
1315 ls
= (line_s
**) malloc (10 * sizeof (line_s
));
1319 for (i
= 0; i
< c
->n_lines
; i
++)
1321 int o
= line_orient (c
->lines
[i
], c
);
1337 dj_abort ("fdir not right or down\n");
1346 if (c2
->pad
|| c2
->pin
|| c2
->n_lines
< 2)
1351 cs
= (corner_s
**) realloc (cs
, cm
* sizeof (corner_s
));
1354 r2
= corner_radius (c2
);
1358 for (i
= 0; i
< c2
->n_lines
; i
++)
1360 int o
= line_orient (c2
->lines
[i
], c2
);
1366 return 0; /* we don't support overlapping lines yet */
1369 if (o
== rdir
&& c2
->lines
[i
] != ls
[ln
- 1])
1370 return 0; /* likewise */
1378 if (selected (l
->line
))
1380 if (autorouted (l
->line
))
1385 ls
= (line_s
**) realloc (ls
, lm
* sizeof (line_s
));
1388 c2
= other_corner (l
, c2
);
1390 if (cn
< 2 || pull
== 0)
1392 if (any_sel
&& !saw_sel
)
1394 if (!any_sel
&& autorouted_only
&& !saw_auto
)
1397 /* Ok, now look for other blockages. */
1400 add_point_to_rect (&rr
, c
->x
, c
->y
, corner_radius (c
));
1401 add_point_to_rect (&rr
, c2
->x
, c2
->y
, corner_radius (c2
));
1403 if (fdir
== RIGHT
&& pull
< 0)
1405 else if (fdir
== RIGHT
&& pull
> 0)
1407 else if (fdir
== DOWN
&& pull
< 0)
1409 else if (fdir
== DOWN
&& pull
> 0)
1413 for (i
= 0; i
< cn
; i
++)
1414 for (li
= 0; li
< cs
[i
]->n_lines
; li
++)
1416 if (line_orient (cs
[i
]->lines
[li
], cs
[i
]) != edir
)
1418 len
= line_length (cs
[i
]->lines
[li
]);
1419 if (max
> len
|| max
== -1)
1422 dprintf ("c %s %4d %4d cn %d pull %3d max %4d\n",
1423 fdir
== RIGHT
? "right" : "down ", c
->x
, c
->y
, cn
, pull
, max
);
1428 rr
.y1
= c
->y
- r1
- max
;
1431 rr
.y2
= c
->y
+ r1
+ max
;
1434 rr
.x1
= c
->x
- r1
- max
;
1437 rr
.x2
= c
->x
+ r1
+ max
;
1446 for (cb
= corners
; cb
; cb
= cb
->next
)
1451 r1
= corner_radius (cb
);
1452 if (cb
->net
== c
->net
&& !cb
->pad
)
1454 if (!pin_in_rect (&rr
, cb
->x
, cb
->y
, r1
))
1458 #define ECHK(X,Y,LT) \
1459 for (i=0; i<cn; i++) \
1461 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1463 r2 = corner_radius(cs[i]); \
1464 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1466 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1468 if (cb->Y LT cs[i]->Y) \
1470 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1472 { max = sep; snap = 1; }\
1474 for (i=0; i<ln; i++) \
1476 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1478 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1480 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1483 { max = sep; snap = 1; }\
1500 /* We must now check every line segment against our corners. */
1501 for (l
= lines
; l
; l
= l
->next
)
1503 int o
, x1
, x2
, y1
, y2
;
1506 dprintf ("check line %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1508 if (l
->s
->net
== c
->net
)
1510 dprintf (" same net\n");
1513 o
= line_orient (l
, 0);
1514 /* We don't need to check perpendicular lines, because their
1515 corners already take care of it. */
1516 if ((fdir
== RIGHT
&& (o
== UP
|| o
== DOWN
))
1517 || (fdir
== DOWN
&& (o
== RIGHT
|| o
== LEFT
)))
1519 dprintf (" perpendicular\n");
1523 /* Choose so that x1,y1 is closest to corner C */
1524 if ((fdir
== RIGHT
&& l
->s
->x
< l
->e
->x
)
1525 || (fdir
== DOWN
&& l
->s
->y
< l
->e
->y
))
1540 /* Eliminate all lines outside our range */
1541 if ((fdir
== RIGHT
&& (x2
< c
->x
|| x1
> c2
->x
))
1542 || (fdir
== DOWN
&& (y2
< c
->y
|| y1
> c2
->y
)))
1544 dprintf (" outside our range\n");
1548 /* Eliminate all lines on the wrong side of us */
1549 if ((edir
== UP
&& y1
> c
->y
&& y2
> c
->y
)
1550 || (edir
== DOWN
&& y1
< c
->y
&& y2
< c
->y
)
1551 || (edir
== LEFT
&& x1
> c
->x
&& x2
> c
->x
)
1552 || (edir
== RIGHT
&& x1
< c
->x
&& x2
< c
->x
))
1554 dprintf (" wrong side\n");
1558 /* For now, cheat on diagonals */
1579 /* Ok, now see how far we can get for each of our corners. */
1580 for (i
= 0; i
< cn
; i
++)
1582 int r
= l
->line
->Thickness
+ SB
+ corner_radius (cs
[i
]) + 1;
1584 if ((fdir
== RIGHT
&& (x2
< cs
[i
]->x
|| x1
> cs
[i
]->x
))
1585 || (fdir
== DOWN
&& (y2
< cs
[i
]->y
|| y1
> cs
[i
]->y
)))
1587 if (!intersecting_layers (cs
[i
]->layer
, l
->layer
))
1605 dprintf (" len is %d vs corner at %d,%d\n", len
, cs
[i
]->x
,
1615 /* We must make sure that if a segment isn't being completely
1616 removed, that any vias and/or pads don't overlap. */
1621 for (i
= 0; i
< cn
; i
++)
1622 for (li
= 0; li
< cs
[i
]->n_lines
; li
++)
1624 line_s
*l
= cs
[i
]->lines
[li
];
1625 corner_s
*oc
= other_corner (l
, cs
[i
]);
1626 if (line_orient (l
, cs
[i
]) != edir
)
1628 len
= line_length (l
);
1629 if (!oc
->pad
|| !cs
[i
]->via
)
1631 if (!is_hole (l
->s
) || !is_hole (l
->e
))
1636 len
-= corner_radius (l
->s
);
1637 len
-= corner_radius (l
->e
);
1664 if (snap
&& max
> Settings
.Grid
)
1667 len
+= Settings
.Grid
- 1;
1668 len
-= len
% (int) (Settings
.Grid
);
1670 if ((fdir
== RIGHT
&& len
== cs
[0]->y
) || (fdir
== DOWN
&& len
== cs
[0]->x
))
1672 for (i
= 0; i
< cn
; i
++)
1676 max
= len
- cs
[i
]->y
;
1677 move_corner (cs
[i
], cs
[i
]->x
, len
);
1681 max
= len
- cs
[i
]->x
;
1682 move_corner (cs
[i
], len
, cs
[i
]->y
);
1691 /* Look for straight runs which could be moved to reduce total trace
1693 int any_sel
= any_line_selected ();
1697 for (c
= corners
; c
;)
1701 if (c
->pin
|| c
->pad
)
1707 rv
+= orthopull_1 (c
, RIGHT
, LEFT
, any_sel
);
1708 if (c
!= next_corner
)
1713 rv
+= orthopull_1 (c
, DOWN
, UP
, any_sel
);
1714 if (c
!= next_corner
)
1722 printf ("orthopull: %d mils saved\n", rv
/ 100);
1729 /* Look for "U" shaped traces we can shorten (or eliminate) */
1731 int any_selected
= any_line_selected ();
1732 line_s
*l
, *l1
, *l2
;
1733 corner_s
*c
, *c1
, *c2
;
1735 int o
, o1
, o2
, step
, w
;
1736 for (l
= lines
; l
; l
= l
->next
)
1742 if (any_selected
&& !selected (l
->line
))
1744 if (!any_selected
&& autorouted_only
&& !autorouted (l
->line
))
1746 if (l
->s
->pin
|| l
->s
->pad
|| l
->e
->pin
|| l
->e
->pad
)
1748 o
= line_orient (l
, 0);
1751 l1
= other_line (l
->s
, l
);
1754 o1
= line_orient (l1
, l
->s
);
1755 l2
= other_line (l
->e
, l
);
1758 o2
= line_orient (l2
, l
->e
);
1759 if (ORIENT (o
) == ORIENT (o1
) || o1
!= o2
|| o1
== DIAGONAL
)
1762 dprintf ("\nline: %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1764 w
= l
->line
->Thickness
/ 2 + SB
+ 1;
1766 add_line_to_rect (&rr
, l1
);
1767 add_line_to_rect (&rr
, l2
);
1768 if (rr
.x1
!= l
->s
->x
&& rr
.x1
!= l
->e
->x
)
1770 if (rr
.x2
!= l
->s
->x
&& rr
.x2
!= l
->e
->x
)
1772 if (rr
.y1
!= l
->s
->y
&& rr
.y1
!= l
->e
->y
)
1774 if (rr
.y2
!= l
->s
->y
&& rr
.y2
!= l
->e
->y
)
1776 dprintf ("range: x %d..%d y %d..%d\n", rr
.x1
, rr
.x2
, rr
.y1
, rr
.y2
);
1778 c1
= other_corner (l1
, l
->s
);
1779 c2
= other_corner (l2
, l
->e
);
1782 for (c
= corners
; c
; c
= c
->next
)
1786 if (c
->net
!= l
->s
->net
1787 && intersecting_layers (c
->layer
, l
->s
->layer
))
1788 add_corner_to_rect_if (&rp
, c
, &rr
);
1790 if (rp
.x1
== INT_MAX
)
1797 dprintf ("pin r: x %d..%d y %d..%d\n", rp
.x1
, rp
.x2
, rp
.y1
, rp
.y2
);
1802 step
= l
->s
->x
- rp
.x2
- w
;
1803 step
= gridsnap (step
);
1804 if (step
> l
->s
->x
- c1
->x
)
1805 step
= l
->s
->x
- c1
->x
;
1806 if (step
> l
->s
->x
- c2
->x
)
1807 step
= l
->s
->x
- c2
->x
;
1810 dprintf ("left step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1811 move_corner (l
->s
, l
->s
->x
- step
, l
->s
->y
);
1812 move_corner (l
->e
, l
->e
->x
- step
, l
->e
->y
);
1817 step
= rp
.x1
- l
->s
->x
- w
;
1818 step
= gridsnap (step
);
1819 if (step
> c1
->x
- l
->s
->x
)
1820 step
= c1
->x
- l
->s
->x
;
1821 if (step
> c2
->x
- l
->s
->x
)
1822 step
= c2
->x
- l
->s
->x
;
1825 dprintf ("right step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1826 move_corner (l
->s
, l
->s
->x
+ step
, l
->s
->y
);
1827 move_corner (l
->e
, l
->e
->x
+ step
, l
->e
->y
);
1832 if (rp
.y2
== INT_MIN
)
1834 step
= trim_step (l
->s
->y
- rp
.y2
- w
,
1835 l
->s
->y
- c1
->y
, l
->s
->y
- c2
->y
);
1838 dprintf ("up step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1839 move_corner (l
->s
, l
->s
->x
, l
->s
->y
- step
);
1840 move_corner (l
->e
, l
->e
->x
, l
->e
->y
- step
);
1845 step
= rp
.y1
- l
->s
->y
- w
;
1846 step
= gridsnap (step
);
1847 if (step
> c1
->y
- l
->s
->y
)
1848 step
= c1
->y
- l
->s
->y
;
1849 if (step
> c2
->y
- l
->s
->y
)
1850 step
= c2
->y
- l
->s
->y
;
1853 dprintf ("down step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1854 move_corner (l
->s
, l
->s
->x
, l
->s
->y
+ step
);
1855 move_corner (l
->e
, l
->e
->x
, l
->e
->y
+ step
);
1863 rv
+= simple_optimizations ();
1865 printf ("debumpify: %d mils saved\n", rv
/ 50);
1870 simple_corner (corner_s
* c
)
1873 if (c
->pad
|| c
->pin
|| c
->via
)
1875 if (c
->n_lines
!= 2)
1877 o1
= line_orient (c
->lines
[0], c
);
1878 o2
= line_orient (c
->lines
[1], c
);
1879 if (ORIENT (o1
) == ORIENT (o2
))
1881 if (ORIENT (o1
) == DIAGONAL
|| ORIENT (o2
) == DIAGONAL
)
1889 /* Look for sequences of simple corners we can reduce. */
1891 corner_s
*c
, *c0
, *c1
, *cc
;
1892 int l
, w
, sel
= any_line_selected ();
1895 for (c
= corners
; c
; c
= c
->next
)
1899 if (!simple_corner (c
))
1901 if (!c
->lines
[0]->line
|| !c
->lines
[1]->line
)
1903 if (sel
&& !(selected (c
->lines
[0]->line
)
1904 || selected (c
->lines
[1]->line
)))
1906 if (!sel
&& autorouted_only
1907 && !(autorouted (c
->lines
[0]->line
)
1908 || autorouted (c
->lines
[1]->line
)))
1910 dprintf ("simple at %d,%d\n", c
->x
, c
->y
);
1912 c0
= other_corner (c
->lines
[0], c
);
1913 o0
= line_orient (c
->lines
[0], c
);
1914 s0
= simple_corner (c0
);
1916 c1
= other_corner (c
->lines
[1], c
);
1917 o1
= line_orient (c
->lines
[1], c
);
1918 s1
= simple_corner (c1
);
1922 dprintf ("simples at %d,%d\n", c
->x
, c
->y
);
1925 for (l
= 0; l
< c0
->n_lines
; l
++)
1926 if (c0
->lines
[l
] != c
->lines
[0]
1927 && c0
->lines
[l
]->layer
== c
->lines
[0]->layer
)
1929 int o
= line_orient (c0
->lines
[l
], c0
);
1933 for (l
= 0; l
< c1
->n_lines
; l
++)
1934 if (c1
->lines
[l
] != c
->lines
[0]
1935 && c1
->lines
[l
]->layer
== c
->lines
[0]->layer
)
1937 int o
= line_orient (c1
->lines
[l
], c1
);
1943 dprintf ("orient ok\n");
1945 w
= c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1;
1947 add_line_to_rect (&rr
, c
->lines
[0]);
1948 add_line_to_rect (&rr
, c
->lines
[1]);
1959 for (cc
= corners
; cc
; cc
= cc
->next
)
1963 if (cc
->net
!= c
->net
&& intersecting_layers (cc
->layer
, c
->layer
))
1964 add_corner_to_rect_if (&rp
, cc
, &rr
);
1966 dprintf ("rp x %d..%d y %d..%d\n", rp
.x1
, rp
.x2
, rp
.y1
, rp
.y2
);
1967 if (rp
.x1
<= rp
.x2
) /* something triggered */
1970 dprintf ("unjaggy at %d,%d layer %d\n", c
->x
, c
->y
, c
->layer
);
1972 move_corner (c
, c1
->x
, c0
->y
);
1974 move_corner (c
, c0
->x
, c1
->y
);
1978 rv
+= simple_optimizations ();
1987 for (i
= 0; i
< 100; i
++)
1989 j
= unjaggy_once ();
1995 printf ("%d unjagg%s \n", r
, r
== 1 ? "y" : "ies");
2002 /* Look for vias with all lines leaving the same way, try to nudge
2003 via to eliminate one or more of them. */
2005 corner_s
*c
, *c2
, *c3
;
2007 unsigned char directions
[MAX_LAYER
];
2008 unsigned char counts
[MAX_LAYER
];
2010 memset (directions
, 0, sizeof (directions
));
2011 memset (counts
, 0, sizeof (counts
));
2013 for (c
= corners
; c
; c
= c
->next
)
2015 int o
, i
, vr
, cr
, oboth
;
2016 int len
= 0, saved
= 0;
2024 memset (directions
, 0, sizeof (directions
));
2025 memset (counts
, 0, sizeof (counts
));
2027 for (i
= 0; i
< c
->n_lines
; i
++)
2029 o
= line_orient (c
->lines
[i
], c
);
2030 counts
[c
->lines
[i
]->layer
]++;
2031 directions
[c
->lines
[i
]->layer
] |= o
;
2033 for (o
= 0, i
= 0; i
< max_copper_layer
; i
++)
2043 oboth
= LEFT
| RIGHT
;
2052 for (i
= 0; i
< max_copper_layer
; i
++)
2053 if (counts
[i
] && directions
[i
] != o
&& directions
[i
] != oboth
)
2054 goto vianudge_continue
;
2057 for (i
= 0; i
< c
->n_lines
; i
++)
2059 int ll
= line_length (c
->lines
[i
]);
2060 if (line_orient (c
->lines
[i
], c
) != o
)
2066 if (c2
== 0 || len
> ll
)
2069 c2
= other_corner (c
->lines
[i
], c
);
2072 if (c2
->pad
|| c2
->pin
|| c2
->via
)
2075 /* Now look for clearance in the new position */
2076 vr
= c
->via
->Thickness
/ 2 + SB
+ 1;
2077 for (c3
= corners
; c3
; c3
= c3
->next
)
2081 if ((c3
->net
!= c
->net
&& (c3
->pin
|| c3
->via
)) || c3
->pad
)
2083 cr
= corner_radius (c3
);
2084 if (dist (c2
->x
, c2
->y
, c3
->x
, c3
->y
) < vr
+ cr
)
2085 goto vianudge_continue
;
2088 for (l
= lines
; l
; l
= l
->next
)
2092 if (l
->s
->net
!= c
->net
)
2094 int ld
= dist_line_to_point (l
, c2
);
2095 if (ld
< l
->line
->Thickness
/ 2 + vr
)
2096 goto vianudge_continue
;
2100 /* at this point, we know we can move it */
2102 dprintf ("vianudge: nudging via at %d,%d by %d mils saving %d\n",
2103 c
->x
, c
->y
, len
/ 100, saved
/ 100);
2105 move_corner (c
, c2
->x
, c2
->y
);
2114 printf ("vianudge: %d mils saved\n", rv
/ 100);
2121 /* Look for traces that can be moved to the other side of the board,
2122 to reduce the number of vias needed. For now, we look for simple
2123 lines, not multi-segmented lines. */
2125 int i
, rv
= 0, vrm
= 0;
2126 int any_sel
= any_line_selected ();
2128 for (l
= lines
; l
; l
= l
->next
)
2131 int my_layer
, other_layer
;
2139 if (any_sel
&& !selected (l
->line
))
2141 if (!any_sel
&& autorouted_only
&& !autorouted (l
->line
))
2144 my_layer
= l
->layer
;
2146 dprintf ("line %p on layer %d from %d,%d to %d,%d\n", (void *) l
,
2147 l
->layer
, l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
);
2148 for (i
= 0; i
< l
->s
->n_lines
; i
++)
2149 if (l
->s
->lines
[i
] != l
)
2151 if (other_layer
== -1)
2153 other_layer
= l
->s
->lines
[i
]->layer
;
2154 dprintf ("noting other line %p on layer %d\n",
2155 (void *) (l
->s
->lines
[i
]), my_layer
);
2157 else if (l
->s
->lines
[i
]->layer
!= other_layer
)
2159 dprintf ("saw other line %p on layer %d (not %d)\n",
2160 (void *) (l
->s
->lines
[i
]), l
->s
->lines
[i
]->layer
,
2163 goto viatrim_other_corner
;
2166 viatrim_other_corner
:
2167 if (other_layer
== -1)
2168 for (i
= 0; i
< l
->e
->n_lines
; i
++)
2169 if (l
->e
->lines
[i
] != l
)
2171 if (other_layer
== -1)
2173 other_layer
= l
->s
->lines
[i
]->layer
;
2174 dprintf ("noting other line %p on layer %d\n",
2175 (void *) (l
->s
->lines
[i
]), my_layer
);
2177 else if (l
->e
->lines
[i
]->layer
!= other_layer
)
2179 dprintf ("saw end line on layer %d (not %d)\n",
2180 l
->e
->lines
[i
]->layer
, other_layer
);
2181 goto viatrim_continue
;
2185 /* Now see if any other line intersects us. We don't need to
2186 check corners, because they'd either be pins/vias and
2187 already conflict, or pads, which we'll check here anyway. */
2189 add_point_to_rect (&r
, l
->s
->x
, l
->s
->y
, l
->line
->Thickness
);
2190 add_point_to_rect (&r
, l
->e
->x
, l
->e
->y
, l
->line
->Thickness
);
2192 for (l2
= lines
; l2
; l2
= l2
->next
)
2196 if (l2
->s
->net
!= l
->s
->net
&& l2
->layer
== other_layer
)
2198 dprintf ("checking other line %d,%d to %d,%d\n", l2
->s
->x
,
2199 l2
->s
->y
, l2
->e
->x
, l2
->e
->y
);
2200 if (line_in_rect (&r
, l2
))
2202 dprintf ("line from %d,%d to %d,%d in the way\n",
2203 l2
->s
->x
, l2
->s
->y
, l2
->e
->x
, l2
->e
->y
);
2204 goto viatrim_continue
;
2209 if (l
->layer
== other_layer
)
2211 move_line_to_layer (l
, other_layer
);
2217 vrm
= simple_optimizations ();
2219 printf ("viatrim: %d traces moved, %d vias removed\n", rv
, vrm
);
2226 int more
= 1, oldmore
= 0;
2228 while (more
!= oldmore
&& --toomany
)
2231 more
+= debumpify ();
2233 more
+= orthopull ();
2234 more
+= vianudge ();
2245 int sel
= any_line_selected ();
2248 for (c
= corners
; c
; c
= c
->next
)
2253 if (c
->n_lines
== 2 && !c
->via
&& !c
->pin
&& !c
->via
)
2255 int o1
= line_orient (c
->lines
[0], c
);
2256 int o2
= line_orient (c
->lines
[1], c
);
2257 if (ORIENT (o1
) != ORIENT (o2
)
2258 && o1
!= DIAGONAL
&& o2
!= DIAGONAL
2259 && c
->lines
[0]->line
->Thickness
== c
->lines
[1]->line
->Thickness
)
2266 while (!done
&& progress
)
2270 for (c
= corners
; c
; c
= c
->next
)
2276 int max
= line_length (c
->lines
[0]);
2277 int len
= line_length (c
->lines
[1]);
2280 corner_s
*closest_corner
= 0, *c2
, *oc1
, *oc2
;
2281 int mx
= 0, my
= 0, x
, y
;
2282 int o1
= line_orient (c
->lines
[0], c
);
2283 int o2
= line_orient (c
->lines
[1], c
);
2285 if (c
->pad
|| c
->pin
|| c
->via
)
2292 oc1
= other_corner (c
->lines
[0], c
);
2293 oc2
= other_corner (c
->lines
[1], c
);
2301 if ((sel
&& !(selected (c
->lines
[0]->line
)
2302 || selected (c
->lines
[1]->line
)))
2303 || (!sel
&& autorouted_only
2304 && !(autorouted (c
->lines
[0]->line
)
2305 || autorouted (c
->lines
[1]->line
))))
2344 ref
= c
->x
* mx
+ c
->y
* my
;
2347 bloat
= (c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1) * 3 / 2;
2349 for (c2
= corners
; c2
; c2
= c2
->next
)
2353 if (c2
!= c
&& c2
!= oc1
&& c2
!= oc2
2354 && c
->x
* mx
<= c2
->x
* mx
2355 && c
->y
* my
<= c2
->y
* my
2356 && c
->net
!= c2
->net
2357 && intersecting_layers (c
->layer
, c2
->layer
))
2359 int cr
= corner_radius (c2
);
2360 len
= c2
->x
* mx
+ c2
->y
* my
- ref
- cr
- bloat
;
2361 if (c
->x
!= c2
->x
&& c
->y
!= c2
->y
)
2363 if (len
< dist
|| (len
== dist
&& c
->miter
!= -1))
2366 closest_corner
= c2
;
2371 if (closest_corner
&& closest_corner
->miter
== -1)
2378 if (dist
< Settings
.Grid
)
2385 dist
-= dist
% Settings
.Grid
;
2411 c2
= find_corner (x
, y
, c
->layer
);
2412 if (c2
!= other_corner (c
->lines
[0], c
))
2413 split_line (c
->lines
[0], c2
);
2431 move_corner (c
, x
, y
);
2443 classify_corner (corner_s
* c
, int this_net
)
2446 if (c
->net
== this_net
)
2449 for (i
= 0; i
< c
->n_lines
; i
++)
2450 classify_corner (other_corner (c
->lines
[i
], c
), this_net
);
2456 static int this_net
= 1;
2459 for (c
= corners
; c
; c
= c
->next
)
2465 classify_corner (c
, this_net
);
2477 for (c
= corners
; c
; c
= c
->next
)
2481 printf ("%p corner %d,%d layer %d net %d\n",
2482 (void *) c
, c
->x
, c
->y
, c
->layer
, c
->net
);
2484 for (l
= lines
; l
; l
= l
->next
)
2488 printf ("%p line %p to %p layer %d\n",
2489 (void *) l
, (void *) (l
->s
), (void *) (l
->e
), l
->layer
);
2495 nudge_corner (corner_s
* c
, int dx
, int dy
, corner_s
* prev_corner
)
2500 if (prev_corner
&& (c
->pin
|| c
->pad
))
2502 move_corner (c
, ox
+ dx
, oy
+ dy
);
2503 for (l
= 0; l
< c
->n_lines
; l
++)
2505 corner_s
*oc
= other_corner (c
->lines
[l
], c
);
2506 if (oc
== prev_corner
)
2508 if (dx
&& oc
->x
== ox
)
2509 nudge_corner (oc
, dx
, 0, c
);
2510 if (dy
&& oc
->y
== oy
)
2511 nudge_corner (oc
, 0, dy
, c
);
2516 choose_example_line (corner_s
* c1
, corner_s
* c2
)
2522 dprintf ("choose_example_line\n");
2523 for (ci
= 0; ci
< 2; ci
++)
2524 for (li
= 0; li
< c
[ci
]->n_lines
; li
++)
2526 dprintf (" try[%d,%d] \033[36m<%d,%d-%d,%d t%d c%d f%s>\033[0m\n",
2528 c
[ci
]->lines
[li
]->s
->x
, c
[ci
]->lines
[li
]->s
->y
,
2529 c
[ci
]->lines
[li
]->e
->x
, c
[ci
]->lines
[li
]->e
->y
,
2530 c
[ci
]->lines
[li
]->line
->Thickness
,
2531 c
[ci
]->lines
[li
]->line
->Clearance
,
2532 flags_to_string (c
[ci
]->lines
[li
]->line
->Flags
, LINE_TYPE
));
2533 /* Pads are disqualified, as we want to mimic a trace line. */
2534 if (c
[ci
]->lines
[li
]->line
== (LineTypePtr
) c
[ci
]->pad
)
2536 dprintf (" bad, pad\n");
2539 /* Lines on layers that don't connect to the other pad are bad too. */
2540 if (!intersecting_layers (c
[ci
]->lines
[li
]->layer
, c
[1 - ci
]->layer
))
2542 dprintf (" bad, layers\n");
2545 dprintf (" good\n");
2546 return c
[ci
]->lines
[li
];
2548 dprintf ("choose_example_line: none found!\n");
2553 connect_corners (corner_s
* c1
, corner_s
* c2
)
2556 line_s
*ex
= choose_example_line (c1
, c2
);
2557 LineType
*example
= ex
->line
;
2560 ("connect_corners \033[32m%d,%d to %d,%d, example line %d,%d to %d,%d l%d\033[0m\n",
2561 c1
->x
, c1
->y
, c2
->x
, c2
->y
, ex
->s
->x
, ex
->s
->y
, ex
->e
->x
, ex
->e
->y
,
2566 /* Assume c1 is the moveable one. */
2567 if (!(c1
->pin
|| c1
->pad
|| c1
->via
) && c1
->n_lines
== 1)
2570 /* Extend the line */
2571 if (c1
->lines
[0]->s
->x
== c1
->lines
[0]->e
->x
)
2572 nx
= c1
->x
, ny
= c2
->y
;
2574 nx
= c2
->x
, ny
= c1
->y
;
2575 if (nx
!= c2
->x
|| ny
!= c2
->y
)
2577 move_corner (c1
, nx
, ny
);
2578 new_line (c1
, c2
, layer
, example
);
2583 move_corner (c1
, nx
, ny
);
2589 corner_s
*nc
= find_corner (c1
->x
, c2
->y
, layer
);
2590 new_line (c1
, nc
, layer
, example
);
2591 new_line (nc
, c2
, layer
, example
);
2600 int best_dist
[MAX_LAYER
+ 1];
2601 corner_s
*best_c
[MAX_LAYER
+ 1];
2603 int left
= 0, right
= 0, top
= 0, bottom
= 0;
2611 /* Look for pins that have no connections. See if there's a corner
2612 close by that should be connected to it. This usually happens
2613 when the MUCS router needs to route to an off-grid pin. */
2617 for (c
= corners
; c
; c
= c
->next
)
2621 if (!(c
->pin
|| c
->via
|| c
->pad
))
2627 dprintf ("\ncorner %s\n", corner_name (c
));
2628 if (c
->pin
|| c
->via
)
2630 pin
= c
->pin
? c
->pin
: c
->via
;
2631 close
= pin
->Thickness
/ 2;
2632 left
= c
->x
- close
;
2633 right
= c
->x
+ close
;
2634 bottom
= c
->y
- close
;
2639 close
= c
->pad
->Thickness
/ 2 + 1;
2640 left
= djmin (c
->pad
->Point1
.X
, c
->pad
->Point2
.X
) - close
;
2641 right
= djmax (c
->pad
->Point1
.X
, c
->pad
->Point2
.X
) + close
;
2642 bottom
= djmin (c
->pad
->Point1
.Y
, c
->pad
->Point2
.Y
) - close
;
2643 top
= djmax (c
->pad
->Point1
.Y
, c
->pad
->Point2
.Y
) + close
;
2644 if (c
->pad
->Point1
.X
== c
->pad
->Point2
.X
)
2646 int hy
= (c
->pad
->Point1
.Y
+ c
->pad
->Point2
.Y
) / 2;
2647 dprintf ("pad y %d %d hy %d c %d\n", c
->pad
->Point1
.Y
,
2648 c
->pad
->Point2
.Y
, hy
, c
->y
);
2656 int hx
= (c
->pad
->Point1
.X
+ c
->pad
->Point2
.X
) / 2;
2657 dprintf ("pad x %d %d hx %d c %d\n", c
->pad
->Point1
.X
,
2658 c
->pad
->Point2
.X
, hx
, c
->x
);
2666 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c
), left
, right
,
2668 for (l
= 0; l
<= max_copper_layer
; l
++)
2670 best_dist
[l
] = close
* 2;
2674 for (c2
= corners
; c2
; c2
= c2
->next
)
2680 lt
= corner_radius (c2
);
2683 && !(c2
->pin
|| c2
->pad
|| c2
->via
)
2684 && intersecting_layers (c
->layer
, c2
->layer
)
2685 && c2
->x
>= left
- lt
2686 && c2
->x
<= right
+ lt
2687 && c2
->y
>= bottom
- lt
&& c2
->y
<= top
+ lt
)
2689 int d
= dist (c
->x
, c
->y
, c2
->x
, c2
->y
);
2690 if (pin
&& d
> pin
->Thickness
/ 2 + lt
)
2692 if (c2
->n_lines
== 1)
2695 dprintf ("found orphan %s vs %s\n", corner_name (c2
),
2697 connect_corners (c
, c2
);
2701 if (best_c
[c2
->layer
] == 0
2702 || c2
->n_lines
< best_c
[c2
->layer
]->n_lines
2703 || (d
< best_dist
[c2
->layer
]
2704 && c2
->n_lines
<= best_c
[c2
->layer
]->n_lines
))
2706 best_dist
[c2
->layer
] = d
;
2707 best_c
[c2
->layer
] = c2
;
2708 dprintf ("layer %d best now %s\n", c2
->layer
,
2712 if (!got_one
&& c
->n_lines
== (c
->pad
? 1 : 0))
2714 for (l
= 0; l
<= max_copper_layer
; l
++)
2716 dprintf ("best[%d] = %s\n", l
, corner_name (best_c
[l
]));
2717 for (l
= 0; l
<= max_copper_layer
; l
++)
2720 dprintf ("move %s to %s\n", corner_name (best_c
[l
]),
2722 connect_corners (best_c
[l
], c
);
2731 /* Now look for line ends that don't connect, see if they need to be
2732 extended to intersect another line. */
2733 for (c
= corners
; c
; c
= c
->next
)
2740 if (c
->pin
|| c
->via
|| c
->pad
)
2742 if (c
->n_lines
!= 1)
2746 lo
= line_orient (l
, c
);
2747 dprintf ("line end %d,%d orient %d\n", c
->x
, c
->y
, lo
);
2749 for (t
= lines
; t
; t
= t
->next
)
2753 if (t
->layer
!= c
->lines
[0]->layer
)
2755 switch (lo
) /* remember, orient is for the line relative to the corner */
2758 if (t
->s
->x
== t
->e
->x
2761 c
->x
+ (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2762 && ((t
->s
->y
< c
->y
&& c
->y
< t
->e
->y
)
2763 || (t
->e
->y
< c
->y
&& c
->y
< t
->s
->y
)))
2765 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2767 move_corner (c
, t
->s
->x
, c
->y
);
2771 if (t
->s
->x
== t
->e
->x
2774 c
->x
- (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2775 && ((t
->s
->y
< c
->y
&& c
->y
< t
->e
->y
)
2776 || (t
->e
->y
< c
->y
&& c
->y
< t
->s
->y
)))
2778 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2780 move_corner (c
, t
->s
->x
, c
->y
);
2784 if (t
->s
->y
== t
->e
->y
2787 c
->y
+ (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2788 && ((t
->s
->x
< c
->x
&& c
->x
< t
->e
->x
)
2789 || (t
->e
->x
< c
->x
&& c
->x
< t
->s
->x
)))
2791 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2793 move_corner (c
, c
->x
, t
->s
->y
);
2797 if (t
->s
->y
== t
->e
->y
2800 c
->y
- (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2801 && ((t
->s
->x
< c
->x
&& c
->x
< t
->e
->x
)
2802 || (t
->e
->x
< c
->x
&& c
->x
< t
->s
->x
)))
2804 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2806 move_corner (c
, c
->x
, t
->s
->y
);
2815 pad_orient (PadType
* p
)
2817 if (p
->Point1
.X
== p
->Point2
.X
)
2819 if (p
->Point1
.Y
== p
->Point2
.Y
)
2832 dprintf ("\ndj: padcleaner\n");
2833 for (l
= lines
; l
; l
= nextl
)
2843 dprintf ("dj: line %p\n", (void *) l
);
2846 if (l
->s
->pad
&& l
->s
->pad
== l
->e
->pad
)
2849 for (ei
= 0; ei
< PCB
->Data
->ElementN
; ei
++)
2851 ElementType
*e
= &(PCB
->Data
->Element
[ei
]);
2852 for (pi
= 0; pi
< e
->PadN
; pi
++)
2854 PadType
*p
= e
->Pad
+ pi
;
2856 TEST_FLAG (ONSOLDERFLAG
, e
) ? LT_SOLDER
: LT_COMPONENT
;
2858 if (layer_type
[l
->layer
] != layerflag
)
2865 close
= p
->Thickness
/ 2 + 1;
2866 add_point_to_rect (&r
, p
->Point1
.X
, p
->Point1
.Y
,
2868 add_point_to_rect (&r
, p
->Point2
.X
, p
->Point2
.Y
,
2870 if (pin_in_rect (&r
, l
->s
->x
, l
->s
->y
, 0)
2871 && pin_in_rect (&r
, l
->e
->x
, l
->e
->y
, 0)
2872 && ORIENT (line_orient (l
, 0)) == pad_orient (p
))
2875 ("padcleaner %d,%d-%d,%d %d vs line %d,%d-%d,%d %d\n",
2876 p
->Point1
.X
, p
->Point1
.Y
, p
->Point2
.X
, p
->Point2
.Y
,
2877 p
->Thickness
, l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
,
2878 l
->line
->Thickness
);
2889 grok_layer_groups ()
2892 LayerGroupType
*l
= &(PCB
->LayerGroups
);
2894 solder_layer
= component_layer
= -1;
2895 for (i
= 0; i
< max_copper_layer
; i
++)
2898 layer_groupings
[i
] = 0;
2900 for (i
= 0; i
< max_group
; i
++)
2903 for (j
= 0; j
< l
->Number
[i
]; j
++)
2905 if (l
->Entries
[i
][j
] == solder_silk_layer
)
2907 if (l
->Entries
[i
][j
] == component_silk_layer
)
2910 for (j
= 0; j
< l
->Number
[i
]; j
++)
2912 if (l
->Entries
[i
][j
] >= 0 && l
->Entries
[i
][j
] < max_copper_layer
)
2914 layer_type
[l
->Entries
[i
][j
]] |= f
;
2915 layer_groupings
[l
->Entries
[i
][j
]] = i
;
2916 if (solder_layer
== -1 && f
== LT_SOLDER
)
2917 solder_layer
= l
->Entries
[i
][j
];
2918 if (component_layer
== -1 && f
== LT_COMPONENT
)
2919 component_layer
= l
->Entries
[i
][j
];
2925 static const char djopt_syntax
[] =
2926 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull)\n"
2927 "djopt(auto) - all of the above\n" "djopt(miter)";
2929 static const char djopt_help
[] =
2930 "Perform various optimizations on the current board";
2932 /* %start-doc actions djopt
2934 The different types of optimizations change your board in order to
2935 reduce the total trace length and via count.
2940 Looks for U-shaped traces that can be shortened or eliminated.
2943 Looks for corners which could be flipped to eliminate one or more
2944 corners (i.e. jaggy lines become simpler).
2947 Removing uneeded vias, replacing two or more trace segments in a row
2948 with a single segment. This is usually performed automatically after
2949 other optimizations.
2952 Looks for vias where all traces leave in the same direction. Tries to
2953 move via in that direction to eliminate one of the traces (and thus a
2957 Looks for traces that go from via to via, where moving that trace to a
2958 different layer eliminates one or both vias.
2961 Looks for chains of traces all going in one direction, with more
2962 traces orthogonal on one side than on the other. Moves the chain in
2963 that direction, causing a net reduction in trace length, possibly
2964 eliminating traces and/or corners.
2967 Looks for lines that pass through vias, pins, or pads, and splits them
2968 into separate lines so they can be managed separately.
2971 Performs the above options, repeating until no further optimizations
2975 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2976 RF losses and trace length.
2983 ActionDJopt (int argc
, char **argv
, int x
, int y
)
2985 char *arg
= argc
> 0 ? argv
[0] : 0;
2986 int layn
, saved
= 0;
2990 SwitchDrawingWindow (PCB
->Zoom
, Output
.drawing_area
->window
,
2991 Settings
.ShowSolderSide
, false);
2999 grok_layer_groups ();
3001 ELEMENT_LOOP (PCB
->Data
);
3004 c
= find_corner (pin
->X
, pin
->Y
, -1);
3011 TEST_FLAG (ONSOLDERFLAG
, pad
) ? solder_layer
: component_layer
;
3012 line_s
*ls
= (line_s
*) malloc (sizeof (line_s
));
3016 ls
->s
= find_corner (pad
->Point1
.X
, pad
->Point1
.Y
, layern
);
3018 ls
->e
= find_corner (pad
->Point2
.X
, pad
->Point2
.Y
, layern
);
3021 ls
->line
= (LineTypePtr
) pad
;
3022 add_line_to_corner (ls
, ls
->s
);
3023 add_line_to_corner (ls
, ls
->e
);
3028 VIA_LOOP (PCB
->Data
);
3029 /* hace don't mess with vias that have thermals */
3030 /* but then again don't bump into them
3031 if (!TEST_FLAG(ALLTHERMFLAGS, via))
3034 c
= find_corner (via
->X
, via
->Y
, -1);
3040 if (NSTRCMP (arg
, "splitlines") == 0)
3042 if (canonicalize_lines ())
3043 IncrementUndoSerialNumber ();
3047 for (layn
= 0; layn
< max_copper_layer
; layn
++)
3049 LayerType
*layer
= LAYER_PTR (layn
);
3051 for (ln
= 0; ln
< layer
->LineN
; ln
++)
3053 LineType
*l
= &(layer
->Line
[ln
]);
3056 /* don't mess with thermals */
3057 if (TEST_FLAG (USETHERMALFLAG
, l
))
3060 if (l
->Point1
.X
== l
->Point2
.X
&& l
->Point1
.Y
== l
->Point2
.Y
)
3062 RemoveLine (layer
, l
);
3067 ls
= (line_s
*) malloc (sizeof (line_s
));
3071 ls
->s
= find_corner (l
->Point1
.X
, l
->Point1
.Y
, layn
);
3072 ls
->e
= find_corner (l
->Point2
.X
, l
->Point2
.Y
, layn
);
3074 add_line_to_corner (ls
, ls
->s
);
3075 add_line_to_corner (ls
, ls
->e
);
3083 canonicalize_lines ();
3089 if (NSTRCMP (arg
, "debumpify") == 0)
3090 saved
+= debumpify ();
3091 else if (NSTRCMP (arg
, "unjaggy") == 0)
3092 saved
+= unjaggy ();
3093 else if (NSTRCMP (arg
, "simple") == 0)
3094 saved
+= simple_optimizations ();
3095 else if (NSTRCMP (arg
, "vianudge") == 0)
3096 saved
+= vianudge ();
3097 else if (NSTRCMP (arg
, "viatrim") == 0)
3098 saved
+= viatrim ();
3099 else if (NSTRCMP (arg
, "orthopull") == 0)
3100 saved
+= orthopull ();
3101 else if (NSTRCMP (arg
, "auto") == 0)
3102 saved
+= automagic ();
3103 else if (NSTRCMP (arg
, "miter") == 0)
3107 printf ("unknown command: %s\n", arg
);
3115 IncrementUndoSerialNumber ();
3119 HID_Action djopt_action_list
[] = {
3120 {"djopt", 0, ActionDJopt
,
3121 djopt_help
, djopt_syntax
}
3123 {"OptAutoOnly", 0, djopt_set_auto_only
,
3124 djopt_sao_help
, djopt_sao_syntax
}
3127 REGISTER_ACTIONS (djopt_action_list
)