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
;
105 typedef struct 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
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.
141 djopt_set_auto_only (int argc
, char **argv
, int x
, int y
)
143 autorouted_only
= autorouted_only
? 0 : 1;
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
)
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
;
178 corner_name (corner_s
* c
)
180 static char buf
[4][100];
185 if (c
->net
== 0xf1eef1ee)
187 sprintf (buf
[bn
], "\033[31m[%p freed corner]\033[0m", (void *) c
);
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
]);
196 sprintf (bp
, "pin %s:%s at %d,%d", element_name_for (c
), c
->pin
->Number
,
199 sprintf (bp
, "via at %d,%d", c
->x
, c
->y
);
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
);
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
);
213 static int solder_layer
, component_layer
;
216 dj_abort (char *msg
, ...)
229 #define check(c,l) check2(__LINE__,c,l)
231 check2 (int srcline
, corner_s
* c
, line_s
* l
)
233 int saw_c
= 0, saw_l
= 0;
238 for (cc
= corners
; cc
; cc
= cc
->next
)
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
);
253 dj_abort ("check:%d: corner not in corners list\n", srcline
);
254 for (ll
= lines
; ll
; ll
= ll
->next
)
260 for (i
= 0; i
< ll
->s
->n_lines
; i
++)
261 if (ll
->s
->lines
[i
] == ll
)
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
)
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",
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
);
285 dj_abort ("check:%d: line not in lines list\n", srcline
);
290 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
297 return n
- n
% (int) (Settings
.Grid
);
300 /* Avoid commonly used names. */
305 return x
> 0 ? x
: -x
;
311 return x
> y
? x
: 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.
326 dist (int x1
, int y1
, int x2
, int y2
)
328 double dx1
, dy1
, dx2
, dy2
, d
;
335 d
= sqrt ((dx1
- dx2
) * (dx1
- dx2
) + (dy1
- dy2
) * (dy1
- dy2
));
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
);
352 dist_ltp2 (int dx
, int y
, int y1
, int y2
)
357 return dist (dx
, y
, 0, y1
);
359 return dist (dx
, y
, 0, y2
);
370 intersecting_layers (int l1
, int l2
)
372 if (l1
== -1 || l2
== -1)
376 if (layer_groupings
[l1
] == layer_groupings
[l2
])
382 dist_line_to_point (line_s
* l
, corner_s
* c
)
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
));
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
-
400 return dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
);
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
-
406 return (int) (d
/ len
);
410 line_orient (line_s
* l
, corner_s
* c
)
445 common_corner (line_s
* l1
, line_s
* l2
)
447 if (l1
->s
== l2
->s
|| l1
->s
== l2
->e
)
449 if (l1
->e
== l2
->s
|| l1
->e
== l2
->e
)
451 dj_abort ("common_corner: no common corner found\n");
457 other_corner (line_s
* l
, corner_s
* c
)
463 dj_abort ("other_corner: neither corner passed\n");
468 find_corner_if (int x
, int y
, int l
)
471 for (c
= corners
; c
; c
= c
->next
)
475 if (c
->x
!= x
|| c
->y
!= y
)
477 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
485 find_corner (int x
, int y
, int l
)
488 for (c
= corners
; c
; c
= c
->next
)
492 if (c
->x
!= x
|| c
->y
!= y
)
494 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
498 c
= (corner_s
*) malloc (sizeof (corner_s
));
509 c
->lines
= (line_s
**) malloc (INC
* sizeof (line_s
*));
514 add_line_to_corner (line_s
* l
, corner_s
* c
)
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
;
521 dprintf ("add_line_to_corner %d %d\n", c
->x
, c
->y
);
525 create_pcb_line (int layer
, int x1
, int y1
, int x2
, int y2
,
526 int thick
, int clear
, FlagType flags
)
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
;
541 for (lp
= lines
; lp
; lp
= lp
->next
)
545 if ((char *) (lp
->line
) >= from
546 && (char *) (lp
->line
) <= from
+ lyr
->LineN
* sizeof (LineType
))
547 lp
->line
= (LineType
*) ((char *) (lp
->line
) + (to
- from
));
554 new_line (corner_s
* s
, corner_s
* e
, int layer
, LineType
* example
)
558 if (layer
>= max_layer
)
559 dj_abort ("layer %d\n", layer
);
562 dj_abort ("NULL example passed to new_line()\n", layer
);
564 if (s
->x
== e
->x
&& s
->y
== e
->y
)
567 ls
= (line_s
*) malloc (sizeof (line_s
));
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
))
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
));
590 create_pcb_line (layer
, s
->x
, s
->y
, e
->x
, e
->y
, example
->Thickness
,
591 example
->Clearance
, example
->Flags
);
594 dj_abort ("can't create new line!");
597 add_line_to_corner (ls
, s
);
598 add_line_to_corner (ls
, e
);
606 c_orth_to (corner_s
* c
, line_s
* l
, int o
)
610 for (i
= 0; i
< c
->n_lines
; i
++)
612 if (c
->lines
[i
] == l
)
614 o2
= line_orient (c
->lines
[i
], c
);
615 if (ORIENT (o
) == ORIENT (o2
) || o2
== DIAGONAL
)
624 other_line (corner_s
* c
, line_s
* l
)
628 if (c
->pin
|| c
->pad
|| c
->via
)
630 for (i
= 0; i
< c
->n_lines
; i
++)
632 if (c
->lines
[i
] == l
)
642 empty_rect (rect_s
* rect
)
644 rect
->x1
= rect
->y1
= INT_MAX
;
645 rect
->x2
= rect
->y2
= INT_MIN
;
649 add_point_to_rect (rect_s
* rect
, int x
, int y
, int w
)
651 if (rect
->x1
> x
- w
)
653 if (rect
->x2
< x
+ w
)
655 if (rect
->y1
> y
- w
)
657 if (rect
->y2
< y
+ w
)
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);
669 pin_in_rect (rect_s
* r
, int x
, int y
, int w
)
671 if (x
< r
->x1
&& x
+ w
< r
->x1
)
673 if (x
> r
->x2
&& x
- w
> r
->x2
)
675 if (y
< r
->y1
&& y
+ w
< r
->y1
)
677 if (y
> r
->y2
&& y
- w
> r
->y2
)
683 line_in_rect (rect_s
* r
, line_s
* l
)
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 */
700 if (lr
.x1
< lr
.x2
&& lr
.y1
< lr
.y2
)
706 corner_radius (corner_s
* c
)
711 diam
= djmax (c
->pin
->Thickness
, diam
);
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;
724 corner_layer (corner_s
* c
)
726 if (c
->pin
|| c
->via
)
730 return c
->lines
[0]->layer
;
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
))
740 if (c
->x
< e
->x1
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x1
, e
->y1
) > diam
)
742 if (c
->x
> e
->x2
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x2
, e
->y1
) > diam
)
744 if (c
->x
< e
->x1
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x1
, e
->y2
) > diam
)
746 if (c
->x
> e
->x2
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x2
, e
->y2
) > diam
)
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
);
754 remove_line (line_s
* l
)
758 LineType
*from
= 0, *to
= 0;
759 LayerType
*layer
= &(PCB
->Data
->Layer
[l
->layer
]);
765 /* compensate for having line pointers rearranged */
766 from
= &(layer
->Line
[layer
->LineN
- 1]);
768 RemoveLine (layer
, l
->line
);
772 for (l2
= lines
; l2
; l2
= l2
->next
)
776 if (l2
->line
== from
)
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
];
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
];
793 move_line_to_layer (line_s
* l
, int layer
)
797 LineType
*from
= 0, *to
= 0;
798 LineType
*oldbase
= 0, *newbase
= 0, *oldend
;
801 ls
= LAYER_PTR (l
->layer
);
802 from
= &(ls
->Line
[ls
->LineN
- 1]);
805 ld
= LAYER_PTR (layer
);
807 oldend
= oldbase
+ ld
->LineN
;
809 newline
= (LineType
*) MoveObjectToLayer (LINE_TYPE
, ls
, l
->line
, 0, ld
, 0);
812 for (l2
= lines
; l2
; l2
= l2
->next
)
816 if (l2
->line
== from
)
818 if (l2
->line
>= oldbase
&& l2
->line
< oldend
)
819 l2
->line
+= newbase
- oldbase
;
827 remove_via_at (corner_s
* c
)
830 PinType
*from
= PCB
->Data
->Via
+ PCB
->Data
->ViaN
- 1;
831 PinType
*to
= c
->via
;
832 RemoveObject (VIA_TYPE
, c
->via
, 0, 0);
834 for (cc
= corners
; cc
; cc
= cc
->next
)
844 remove_corner (corner_s
* c2
)
847 dprintf ("remove corner %s\n", corner_name (c2
));
850 for (c
= corners
; c
; c
= c
->next
)
857 if (next_corner
== c2
)
858 next_corner
= c2
->next
;
865 merge_corners (corner_s
* c1
, corner_s
* c2
)
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
)
887 if (c2
->layer
!= c1
->layer
)
894 move_corner (corner_s
* c
, int x
, int y
)
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
);
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
;
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
),
927 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (c
->lines
[i
]->layer
), tl
,
928 &tl
->Point2
, x
- (tl
->Point2
.X
),
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
);
936 merge_corners (c
, pad
);
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
]);
949 merge_corners (c
, c2
);
955 gui
->progress (0, 0, 0);
963 for (l
= lines
; l
; l
= l
->next
)
967 if (l
->line
&& selected (l
->line
))
974 trim_step (int s
, int l1
, int l2
)
976 dprintf ("trim %d %d %d\n", s
, l1
, l2
);
981 if (s
!= l1
&& s
!= l2
)
986 static int canonicalize_line (line_s
* l
);
989 split_line (line_s
* l
, corner_s
* c
)
996 if (!intersecting_layers (l
->layer
, c
->layer
))
1002 dprintf ("split on pad!\n");
1003 if (l
->s
->pad
== c
->pad
|| l
->e
->pad
== c
->pad
)
1005 dprintf ("splitting...\n");
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
,
1015 return 0; /* already a line there */
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
));
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
;
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
));
1043 canonicalize_line (line_s
* l
)
1045 /* This could be faster */
1047 if (l
->s
->x
== l
->e
->x
)
1051 int x1
= l
->s
->x
- l
->line
->Thickness
/ 2;
1052 int x2
= l
->s
->x
+ l
->line
->Thickness
/ 2;
1059 for (c
= corners
; c
; c
= c
->next
)
1063 if ((y1
< c
->y
&& c
->y
< y2
)
1064 && intersecting_layers (l
->layer
, c
->layer
))
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
1075 return split_line (l
, c
);
1080 else if (l
->s
->y
== l
->e
->y
)
1084 int y1
= l
->s
->y
- l
->line
->Thickness
/ 2;
1085 int y2
= l
->s
->y
+ l
->line
->Thickness
/ 2;
1092 for (c
= corners
; c
; c
= c
->next
)
1096 if ((x1
< c
->x
&& c
->x
< x2
)
1097 && intersecting_layers (l
->layer
, c
->layer
))
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
);
1114 /* diagonal lines. Let's try to split them at pins/vias
1132 for (c
= corners
; c
; c
= c
->next
)
1136 if (!c
->via
&& !c
->pin
)
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
;
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
);
1156 /* Make sure all vias are at line end points */
1158 canonicalize_lines ()
1166 for (l
= lines
; l
; l
= l
->next
)
1170 count
+= canonicalize_line (l
);
1180 simple_optimize_corner (corner_s
* c
)
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
)
1207 if (i
== c
->n_lines
)
1209 if (selected (c
->via
))
1210 dprintf (" remove it\n");
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
);
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
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
);
1266 /* We always run these */
1268 simple_optimizations ()
1273 /* Look for corners that aren't */
1274 for (c
= corners
; c
; c
= c
->next
)
1278 if (c
->pad
|| c
->pin
)
1280 rv
+= simple_optimize_corner (c
);
1286 is_hole (corner_s
* c
)
1288 return c
->pin
|| c
->pad
|| c
->via
;
1292 orthopull_1 (corner_s
* c
, int fdir
, int rdir
, int any_sel
)
1294 static corner_s
**cs
= 0;
1296 static line_s
**ls
= 0;
1298 int i
, li
, ln
, cn
, snap
;
1301 int adir
= 0, sdir
= 0, pull
;
1302 int saw_sel
= 0, saw_auto
= 0;
1303 int max
, len
= 0, r1
= 0, r2
;
1309 cs
= (corner_s
**) malloc (10 * sizeof (corner_s
));
1311 ls
= (line_s
**) malloc (10 * sizeof (line_s
));
1315 for (i
= 0; i
< c
->n_lines
; i
++)
1317 int o
= line_orient (c
->lines
[i
], c
);
1333 dj_abort ("fdir not right or down\n");
1342 if (c2
->pad
|| c2
->pin
|| c2
->n_lines
< 2)
1347 cs
= (corner_s
**) realloc (cs
, cm
* sizeof (corner_s
));
1350 r2
= corner_radius (c2
);
1354 for (i
= 0; i
< c2
->n_lines
; i
++)
1356 int o
= line_orient (c2
->lines
[i
], c2
);
1362 return 0; /* we don't support overlapping lines yet */
1365 if (o
== rdir
&& c2
->lines
[i
] != ls
[ln
- 1])
1366 return 0; /* likewise */
1374 if (selected (l
->line
))
1376 if (autorouted (l
->line
))
1381 ls
= (line_s
**) realloc (ls
, lm
* sizeof (line_s
));
1384 c2
= other_corner (l
, c2
);
1386 if (cn
< 2 || pull
== 0)
1388 if (any_sel
&& !saw_sel
)
1390 if (!any_sel
&& autorouted_only
&& !saw_auto
)
1393 /* Ok, now look for other blockages. */
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)
1401 else if (fdir
== RIGHT
&& pull
> 0)
1403 else if (fdir
== DOWN
&& pull
< 0)
1405 else if (fdir
== DOWN
&& pull
> 0)
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
)
1414 len
= line_length (cs
[i
]->lines
[li
]);
1415 if (max
> len
|| max
== -1)
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
);
1424 rr
.y1
= c
->y
- r1
- max
;
1427 rr
.y2
= c
->y
+ r1
+ max
;
1430 rr
.x1
= c
->x
- r1
- max
;
1433 rr
.x2
= c
->x
+ r1
+ max
;
1442 for (cb
= corners
; cb
; cb
= cb
->next
)
1447 r1
= corner_radius (cb
);
1448 if (cb
->net
== c
->net
&& !cb
->pad
)
1450 if (!pin_in_rect (&rr
, cb
->x
, cb
->y
, r1
))
1454 #define ECHK(X,Y,LT) \
1455 for (i=0; i<cn; i++) \
1457 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1459 r2 = corner_radius(cs[i]); \
1460 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1462 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1464 if (cb->Y LT cs[i]->Y) \
1466 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1468 { max = sep; snap = 1; }\
1470 for (i=0; i<ln; i++) \
1472 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1474 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1476 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1479 { max = sep; snap = 1; }\
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
;
1502 dprintf ("check line %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1504 if (l
->s
->net
== c
->net
)
1506 dprintf (" same net\n");
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");
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
))
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");
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");
1554 /* For now, cheat on diagonals */
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;
1580 if ((fdir
== RIGHT
&& (x2
< cs
[i
]->x
|| x1
> cs
[i
]->x
))
1581 || (fdir
== DOWN
&& (y2
< cs
[i
]->y
|| y1
> cs
[i
]->y
)))
1583 if (!intersecting_layers (cs
[i
]->layer
, l
->layer
))
1601 dprintf (" len is %d vs corner at %d,%d\n", len
, cs
[i
]->x
,
1611 /* We must make sure that if a segment isn't being completely
1612 removed, that any vias and/or pads don't overlap. */
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
)
1624 len
= line_length (l
);
1625 if (!oc
->pad
|| !cs
[i
]->via
)
1627 if (!is_hole (l
->s
) || !is_hole (l
->e
))
1632 len
-= corner_radius (l
->s
);
1633 len
-= corner_radius (l
->e
);
1660 if (snap
&& max
> Settings
.Grid
)
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
))
1668 for (i
= 0; i
< cn
; i
++)
1672 max
= len
- cs
[i
]->y
;
1673 move_corner (cs
[i
], cs
[i
]->x
, len
);
1677 max
= len
- cs
[i
]->x
;
1678 move_corner (cs
[i
], len
, cs
[i
]->y
);
1687 /* Look for straight runs which could be moved to reduce total trace
1689 int any_sel
= any_line_selected ();
1693 for (c
= corners
; c
;)
1697 if (c
->pin
|| c
->pad
)
1703 rv
+= orthopull_1 (c
, RIGHT
, LEFT
, any_sel
);
1704 if (c
!= next_corner
)
1709 rv
+= orthopull_1 (c
, DOWN
, UP
, any_sel
);
1710 if (c
!= next_corner
)
1718 printf ("orthopull: %d mils saved\n", rv
/ 100);
1725 /* Look for "U" shaped traces we can shorten (or eliminate) */
1727 int any_selected
= any_line_selected ();
1728 line_s
*l
, *l1
, *l2
;
1729 corner_s
*c
, *c1
, *c2
;
1731 int o
, o1
, o2
, step
, w
;
1732 for (l
= lines
; l
; l
= l
->next
)
1738 if (any_selected
&& !selected (l
->line
))
1740 if (!any_selected
&& autorouted_only
&& !autorouted (l
->line
))
1742 if (l
->s
->pin
|| l
->s
->pad
|| l
->e
->pin
|| l
->e
->pad
)
1744 o
= line_orient (l
, 0);
1747 l1
= other_line (l
->s
, l
);
1750 o1
= line_orient (l1
, l
->s
);
1751 l2
= other_line (l
->e
, l
);
1754 o2
= line_orient (l2
, l
->e
);
1755 if (ORIENT (o
) == ORIENT (o1
) || o1
!= o2
|| o1
== DIAGONAL
)
1758 dprintf ("\nline: %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1760 w
= l
->line
->Thickness
/ 2 + SB
+ 1;
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
)
1766 if (rr
.x2
!= l
->s
->x
&& rr
.x2
!= l
->e
->x
)
1768 if (rr
.y1
!= l
->s
->y
&& rr
.y1
!= l
->e
->y
)
1770 if (rr
.y2
!= l
->s
->y
&& rr
.y2
!= l
->e
->y
)
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
);
1778 for (c
= corners
; c
; c
= c
->next
)
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
)
1793 dprintf ("pin r: x %d..%d y %d..%d\n", rp
.x1
, rp
.x2
, rp
.y1
, rp
.y2
);
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
;
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
);
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
;
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
);
1828 if (rp
.y2
== INT_MIN
)
1830 step
= trim_step (l
->s
->y
- rp
.y2
- w
,
1831 l
->s
->y
- c1
->y
, l
->s
->y
- c2
->y
);
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
);
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
;
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
);
1859 rv
+= simple_optimizations ();
1861 printf ("debumpify: %d mils saved\n", rv
/ 50);
1866 simple_corner (corner_s
* c
)
1869 if (c
->pad
|| c
->pin
|| c
->via
)
1871 if (c
->n_lines
!= 2)
1873 o1
= line_orient (c
->lines
[0], c
);
1874 o2
= line_orient (c
->lines
[1], c
);
1875 if (ORIENT (o1
) == ORIENT (o2
))
1877 if (ORIENT (o1
) == DIAGONAL
|| ORIENT (o2
) == DIAGONAL
)
1885 /* Look for sequences of simple corners we can reduce. */
1887 corner_s
*c
, *c0
, *c1
, *cc
;
1888 int l
, w
, sel
= any_line_selected ();
1891 for (c
= corners
; c
; c
= c
->next
)
1895 if (!simple_corner (c
))
1897 if (!c
->lines
[0]->line
|| !c
->lines
[1]->line
)
1899 if (sel
&& !(selected (c
->lines
[0]->line
)
1900 || selected (c
->lines
[1]->line
)))
1902 if (!sel
&& autorouted_only
1903 && !(autorouted (c
->lines
[0]->line
)
1904 || autorouted (c
->lines
[1]->line
)))
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
);
1918 dprintf ("simples at %d,%d\n", c
->x
, c
->y
);
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
);
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
);
1939 dprintf ("orient ok\n");
1941 w
= c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1;
1943 add_line_to_rect (&rr
, c
->lines
[0]);
1944 add_line_to_rect (&rr
, c
->lines
[1]);
1955 for (cc
= corners
; cc
; cc
= cc
->next
)
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 */
1966 dprintf ("unjaggy at %d,%d layer %d\n", c
->x
, c
->y
, c
->layer
);
1968 move_corner (c
, c1
->x
, c0
->y
);
1970 move_corner (c
, c0
->x
, c1
->y
);
1974 rv
+= simple_optimizations ();
1983 for (i
= 0; i
< 100; i
++)
1985 j
= unjaggy_once ();
1991 printf ("%d unjagg%s \n", r
, r
== 1 ? "y" : "ies");
1998 /* Look for vias with all lines leaving the same way, try to nudge
1999 via to eliminate one or more of them. */
2001 corner_s
*c
, *c2
, *c3
;
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;
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
++)
2039 oboth
= LEFT
| RIGHT
;
2048 for (i
= 0; i
< max_layer
; i
++)
2049 if (counts
[i
] && directions
[i
] != o
&& directions
[i
] != oboth
)
2050 goto vianudge_continue
;
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
)
2062 if (c2
== 0 || len
> ll
)
2065 c2
= other_corner (c
->lines
[i
], c
);
2068 if (c2
->pad
|| c2
->pin
|| c2
->via
)
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
)
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
)
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);
2101 move_corner (c
, c2
->x
, c2
->y
);
2110 printf ("vianudge: %d mils saved\n", rv
/ 100);
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. */
2121 int i
, rv
= 0, vrm
= 0;
2122 int any_sel
= any_line_selected ();
2124 for (l
= lines
; l
; l
= l
->next
)
2127 int my_layer
, other_layer
;
2135 if (any_sel
&& !selected (l
->line
))
2137 if (!any_sel
&& autorouted_only
&& !autorouted (l
->line
))
2140 my_layer
= l
->layer
;
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
,
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. */
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
)
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
)
2207 move_line_to_layer (l
, other_layer
);
2213 vrm
= simple_optimizations ();
2215 printf ("viatrim: %d traces moved, %d vias removed\n", rv
, vrm
);
2222 int more
= 1, oldmore
= 0;
2224 while (more
!= oldmore
&& --toomany
)
2227 more
+= debumpify ();
2229 more
+= orthopull ();
2230 more
+= vianudge ();
2241 int sel
= any_line_selected ();
2244 for (c
= corners
; c
; c
= c
->next
)
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
)
2262 while (!done
&& progress
)
2266 for (c
= corners
; c
; c
= c
->next
)
2272 int max
= line_length (c
->lines
[0]);
2273 int len
= line_length (c
->lines
[1]);
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
)
2288 oc1
= other_corner (c
->lines
[0], c
);
2289 oc2
= other_corner (c
->lines
[1], c
);
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
))))
2340 ref
= c
->x
* mx
+ c
->y
* my
;
2343 bloat
= (c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1) * 3 / 2;
2345 for (c2
= corners
; c2
; c2
= c2
->next
)
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
)
2359 if (len
< dist
|| (len
== dist
&& c
->miter
!= -1))
2362 closest_corner
= c2
;
2367 if (closest_corner
&& closest_corner
->miter
== -1)
2374 if (dist
< Settings
.Grid
)
2381 dist
-= dist
% Settings
.Grid
;
2407 c2
= find_corner (x
, y
, c
->layer
);
2408 if (c2
!= other_corner (c
->lines
[0], c
))
2409 split_line (c
->lines
[0], c2
);
2427 move_corner (c
, x
, y
);
2439 classify_corner (corner_s
* c
, int this_net
)
2442 if (c
->net
== this_net
)
2445 for (i
= 0; i
< c
->n_lines
; i
++)
2446 classify_corner (other_corner (c
->lines
[i
], c
), this_net
);
2452 static int this_net
= 1;
2455 for (c
= corners
; c
; c
= c
->next
)
2461 classify_corner (c
, this_net
);
2473 for (c
= corners
; c
; c
= c
->next
)
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
)
2484 printf ("%p line %p to %p layer %d\n",
2485 (void *) l
, (void *) (l
->s
), (void *) (l
->e
), l
->layer
);
2491 nudge_corner (corner_s
* c
, int dx
, int dy
, corner_s
* prev_corner
)
2496 if (prev_corner
&& (c
->pin
|| c
->pad
))
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
)
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
);
2512 choose_example_line (corner_s
* c1
, corner_s
* 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",
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");
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");
2541 dprintf (" good\n");
2542 return c
[ci
]->lines
[li
];
2544 dprintf ("choose_example_line: none found!\n");
2549 connect_corners (corner_s
* c1
, corner_s
* c2
)
2552 line_s
*ex
= choose_example_line (c1
, c2
);
2553 LineType
*example
= ex
->line
;
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
,
2562 /* Assume c1 is the moveable one. */
2563 if (!(c1
->pin
|| c1
->pad
|| c1
->via
) && c1
->n_lines
== 1)
2566 /* Extend the line */
2567 if (c1
->lines
[0]->s
->x
== c1
->lines
[0]->e
->x
)
2568 nx
= c1
->x
, ny
= c2
->y
;
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
);
2579 move_corner (c1
, nx
, ny
);
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
);
2596 int best_dist
[MAX_LAYER
+ 1];
2597 corner_s
*best_c
[MAX_LAYER
+ 1];
2599 int left
= 0, right
= 0, top
= 0, bottom
= 0;
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. */
2613 for (c
= corners
; c
; c
= c
->next
)
2617 if (!(c
->pin
|| c
->via
|| c
->pad
))
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
;
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
);
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
);
2662 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c
), left
, right
,
2664 for (l
= 0; l
<= max_layer
; l
++)
2666 best_dist
[l
] = close
* 2;
2670 for (c2
= corners
; c2
; c2
= c2
->next
)
2676 lt
= corner_radius (c2
);
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
)
2688 if (c2
->n_lines
== 1)
2691 dprintf ("found orphan %s vs %s\n", corner_name (c2
),
2693 connect_corners (c
, c2
);
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
,
2708 if (!got_one
&& c
->n_lines
== (c
->pad
? 1 : 0))
2710 for (l
= 0; l
<= max_layer
; l
++)
2712 dprintf ("best[%d] = %s\n", l
, corner_name (best_c
[l
]));
2713 for (l
= 0; l
<= max_layer
; l
++)
2716 dprintf ("move %s to %s\n", corner_name (best_c
[l
]),
2718 connect_corners (best_c
[l
], c
);
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
)
2736 if (c
->pin
|| c
->via
|| c
->pad
)
2738 if (c
->n_lines
!= 1)
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
)
2749 if (t
->layer
!= c
->lines
[0]->layer
)
2751 switch (lo
) /* remember, orient is for the line relative to the corner */
2754 if (t
->s
->x
== t
->e
->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
,
2763 move_corner (c
, t
->s
->x
, c
->y
);
2767 if (t
->s
->x
== t
->e
->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
,
2776 move_corner (c
, t
->s
->x
, c
->y
);
2780 if (t
->s
->y
== t
->e
->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
,
2789 move_corner (c
, c
->x
, t
->s
->y
);
2793 if (t
->s
->y
== t
->e
->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
,
2802 move_corner (c
, c
->x
, t
->s
->y
);
2811 pad_orient (PadType
* p
)
2813 if (p
->Point1
.X
== p
->Point2
.X
)
2815 if (p
->Point1
.Y
== p
->Point2
.Y
)
2828 dprintf ("\ndj: padcleaner\n");
2829 for (l
= lines
; l
; l
= nextl
)
2836 dprintf ("dj: line %p\n", (void *) l
);
2839 if (l
->s
->pad
&& l
->s
->pad
== l
->e
->pad
)
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
;
2849 TEST_FLAG (ONSOLDERFLAG
, e
) ? LT_SOLDER
: LT_COMPONENT
;
2851 if (layer_type
[l
->layer
] != layerflag
)
2855 close
= p
->Thickness
/ 2 + 1;
2856 add_point_to_rect (&r
, p
->Point1
.X
, p
->Point1
.Y
,
2858 add_point_to_rect (&r
, p
->Point2
.X
, p
->Point2
.Y
,
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
))
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
);
2879 grok_layer_groups ()
2882 LayerGroupType
*l
= &(PCB
->LayerGroups
);
2884 solder_layer
= component_layer
= -1;
2885 for (i
= 0; i
< max_layer
; i
++)
2888 layer_groupings
[i
] = 0;
2890 for (i
= 0; i
< max_layer
; i
++)
2893 for (j
= 0; j
< l
->Number
[i
]; j
++)
2895 if (l
->Entries
[i
][j
] == max_layer
+ SOLDER_LAYER
)
2897 if (l
->Entries
[i
][j
] == max_layer
+ COMPONENT_LAYER
)
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.
2930 Looks for U-shaped traces that can be shortened or eliminated.
2933 Looks for corners which could be flipped to eliminate one or more
2934 corners (i.e. jaggy lines become simpler).
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.
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
2947 Looks for traces that go from via to via, where moving that trace to a
2948 different layer eliminates one or both vias.
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.
2957 Looks for lines that pass through vias, pins, or pads, and splits them
2958 into separate lines so they can be managed separately.
2961 Performs the above options, repeating until no further optimizations
2965 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2966 RF losses and trace length.
2973 ActionDJopt (int argc
, char **argv
, int x
, int y
)
2975 char *arg
= argc
> 0 ? argv
[0] : 0;
2976 int layn
, saved
= 0;
2980 SwitchDrawingWindow (PCB
->Zoom
, Output
.drawing_area
->window
,
2981 Settings
.ShowSolderSide
, False
);
2989 grok_layer_groups ();
2991 ELEMENT_LOOP (PCB
->Data
);
2994 c
= find_corner (pin
->X
, pin
->Y
, -1);
3001 TEST_FLAG (ONSOLDERFLAG
, pad
) ? solder_layer
: component_layer
;
3002 line_s
*ls
= (line_s
*) malloc (sizeof (line_s
));
3005 ls
->s
= find_corner (pad
->Point1
.X
, pad
->Point1
.Y
, layern
);
3007 ls
->e
= find_corner (pad
->Point2
.X
, pad
->Point2
.Y
, layern
);
3010 ls
->line
= (LineTypePtr
) pad
;
3011 add_line_to_corner (ls
, ls
->s
);
3013 ls
->line
= (LineTypePtr
) pad
;
3014 add_line_to_corner (ls
, ls
->s
);
3015 add_line_to_corner (ls
, ls
->e
);
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);
3032 if (NSTRCMP (arg
, "splitlines") == 0)
3034 if (canonicalize_lines ())
3035 IncrementUndoSerialNumber ();
3039 for (layn
= 0; layn
< max_layer
; layn
++)
3041 LayerType
*layer
= LAYER_PTR (layn
);
3043 for (ln
= 0; ln
< layer
->LineN
; ln
++)
3045 LineType
*l
= &(layer
->Line
[ln
]);
3048 /* don't mess with thermals */
3049 if (TEST_FLAG (USETHERMALFLAG
, l
))
3052 if (l
->Point1
.X
== l
->Point2
.X
&& l
->Point1
.Y
== l
->Point2
.Y
)
3054 RemoveLine (layer
, l
);
3059 ls
= (line_s
*) malloc (sizeof (line_s
));
3062 ls
->s
= find_corner (l
->Point1
.X
, l
->Point1
.Y
, layn
);
3063 ls
->e
= find_corner (l
->Point2
.X
, l
->Point2
.Y
, layn
);
3065 add_line_to_corner (ls
, ls
->s
);
3066 add_line_to_corner (ls
, ls
->e
);
3074 canonicalize_lines ();
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)
3098 printf ("unknown command: %s\n", arg
);
3106 IncrementUndoSerialNumber ();
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
)