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)
80 typedef struct corner_s
83 struct corner_s
*next
;
91 struct line_s
**lines
;
102 typedef struct rect_s
107 #define DELETE(q) (q)->layer = 0xdeadbeef
108 #define DELETED(q) ((q)->layer == 0xdeadbeef)
110 static corner_s
*corners
, *next_corner
= 0;
111 static line_s
*lines
;
113 static int layer_groupings
[MAX_LAYER
];
114 static char layer_type
[MAX_LAYER
];
115 #define LT_COMPONENT 1
118 static int autorouted_only
= 1;
120 static const char djopt_sao_syntax
[] = "OptAutoOnly()";
122 static const char djopt_sao_help
[] =
123 "Toggles the optimize-only-autorouted flag.";
125 /* %start-doc actions OptAutoOnly
127 The original purpose of the trace optimizer was to clean up the traces
128 created by the various autorouters that have been used with PCB. When
129 a board has a mix of autorouted and carefully hand-routed traces, you
130 don't normally want the optimizer to move your hand-routed traces.
131 But, sometimes you do. By default, the optimizer only optimizes
132 autorouted traces. This action toggles that setting, so that you can
133 optimize hand-routed traces also.
138 djopt_set_auto_only (int argc
, char **argv
, int x
, int y
)
140 autorouted_only
= autorouted_only
? 0 : 1;
145 djopt_get_auto_only (int dummy
)
147 return autorouted_only
;
150 HID_Flag djopt_flag_list
[] = {
151 {"optautoonly", djopt_get_auto_only
, 0}
154 REGISTER_FLAGS (djopt_flag_list
)
155 #define line_is_pad(l) ((l)->line == (LineType *)(l)->s->pad)
156 static char *element_name_for (corner_s
* c
)
161 for (i
= 0; i
< PCB
->Data
->ElementN
; i
++)
163 e
= PCB
->Data
->Element
+ i
;
164 for (p
= 0; p
< e
->PinN
; p
++)
165 if (e
->Pin
+ p
== c
->pin
)
166 return e
->Name
[1].TextString
;
167 for (p
= 0; p
< e
->PadN
; p
++)
168 if (e
->Pad
+ p
== c
->pad
)
169 return e
->Name
[1].TextString
;
175 corner_name (corner_s
* c
)
177 static char buf
[4][100];
182 if (c
->net
== 0xf1eef1ee)
184 sprintf (buf
[bn
], "\033[31m[%p freed corner]\033[0m", (void *) c
);
188 sprintf (buf
[bn
], "\033[%dm[%p ",
189 (c
->pin
|| c
->pad
|| c
->via
) ? 33 : 34, (void *) c
);
190 bp
= buf
[bn
] + strlen (buf
[bn
]);
193 sprintf (bp
, "pin %s:%s at %d,%d", element_name_for (c
), c
->pin
->Number
,
196 sprintf (bp
, "via at %d,%d", c
->x
, c
->y
);
199 sprintf (bp
, "pad %s:%s at %d,%d (%d,%d-%d,%d)",
200 element_name_for (c
), c
->pad
->Number
, c
->x
, c
->y
,
201 c
->pad
->Point1
.X
, c
->pad
->Point1
.Y
,
202 c
->pad
->Point2
.X
, c
->pad
->Point2
.Y
);
205 sprintf (bp
, "at %d,%d", c
->x
, c
->y
);
206 sprintf (bp
+ strlen (bp
), " n%d l%d]\033[0m", c
->n_lines
, c
->layer
);
210 static int solder_layer
, component_layer
;
213 dj_abort (char *msg
, ...)
226 #define check(c,l) check2(__LINE__,c,l)
228 check2 (int srcline
, corner_s
* c
, line_s
* l
)
230 int saw_c
= 0, saw_l
= 0;
235 for (cc
= corners
; cc
; cc
= cc
->next
)
241 for (i
= 0; i
< cc
->n_lines
; i
++)
242 if (cc
->lines
[i
]->s
!= cc
&& cc
->lines
[i
]->e
!= cc
)
243 dj_abort ("check:%d: cc has line without backref\n", srcline
);
244 if (cc
->via
&& (cc
->x
!= cc
->via
->X
|| cc
->y
!= cc
->via
->Y
))
245 dj_abort ("check:%d: via not at corner\n", srcline
);
246 if (cc
->pin
&& (cc
->x
!= cc
->pin
->X
|| cc
->y
!= cc
->pin
->Y
))
247 dj_abort ("check:%d: pin not at corner\n", srcline
);
250 dj_abort ("check:%d: corner not in corners list\n", srcline
);
251 for (ll
= lines
; ll
; ll
= ll
->next
)
257 for (i
= 0; i
< ll
->s
->n_lines
; i
++)
258 if (ll
->s
->lines
[i
] == ll
)
260 if (i
== ll
->s
->n_lines
)
261 dj_abort ("check:%d: ll->s has no backref\n", srcline
);
262 for (i
= 0; i
< ll
->e
->n_lines
; i
++)
263 if (ll
->e
->lines
[i
] == ll
)
265 if (i
== ll
->e
->n_lines
)
266 dj_abort ("check:%d: ll->e has no backref\n", srcline
);
267 if (!line_is_pad (ll
)
268 && (ll
->s
->x
!= ll
->line
->Point1
.X
269 || ll
->s
->y
!= ll
->line
->Point1
.Y
270 || ll
->e
->x
!= ll
->line
->Point2
.X
271 || ll
->e
->y
!= ll
->line
->Point2
.Y
))
273 printf ("line: %d,%d to %d,%d pcbline: %d,%d to %d,%d\n",
277 ll
->line
->Point1
.Y
, ll
->line
->Point2
.X
, ll
->line
->Point2
.Y
);
278 dj_abort ("check:%d: line doesn't match pcbline\n", srcline
);
282 dj_abort ("check:%d: line not in lines list\n", srcline
);
287 #define SWAP(a,b) { a^=b; b^=a; a^=b; }
294 return n
- n
% (int) (Settings
.Grid
);
297 /* Avoid commonly used names. */
302 return x
> 0 ? x
: -x
;
308 return x
> y
? x
: y
;
314 return x
< y
? x
: y
;
318 * Find distance between 2 points. We use floating point math here
319 * because we can fairly easily overflow a 32 bit integer here. In
320 * fact it only takes 0.46" to do so.
323 dist (int x1
, int y1
, int x2
, int y2
)
325 double dx1
, dy1
, dx2
, dy2
, d
;
332 d
= sqrt ((dx1
- dx2
) * (dx1
- dx2
) + (dy1
- dy2
) * (dy1
- dy2
));
339 line_length (line_s
* l
)
341 if (l
->s
->x
== l
->e
->x
)
342 return djabs (l
->s
->y
- l
->e
->y
);
343 if (l
->s
->y
== l
->e
->y
)
344 return djabs (l
->s
->x
- l
->e
->x
);
345 return dist (l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
);
349 dist_ltp2 (int dx
, int y
, int y1
, int y2
)
354 return dist (dx
, y
, 0, y1
);
356 return dist (dx
, y
, 0, y2
);
367 intersecting_layers (int l1
, int l2
)
369 if (l1
== -1 || l2
== -1)
373 if (layer_groupings
[l1
] == layer_groupings
[l2
])
379 dist_line_to_point (line_s
* l
, corner_s
* c
)
382 /* We can do this quickly if l is vertical or horizontal. */
383 if (l
->s
->x
== l
->e
->x
)
384 return dist_ltp2 (l
->s
->x
- c
->x
, c
->y
, l
->s
->y
, l
->e
->y
);
385 if (l
->s
->y
== l
->e
->y
)
386 return dist_ltp2 (l
->s
->y
- c
->y
, c
->x
, l
->s
->x
, l
->e
->x
);
388 /* Do it the hard way. See comments for IsPointOnLine() in search.c */
389 len
= sqrt (sqr (l
->s
->x
- l
->e
->x
) + sqr (l
->s
->y
- l
->e
->y
));
391 return dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
);
393 (l
->s
->y
- c
->y
) * (l
->s
->y
- l
->e
->y
) + (l
->s
->x
- c
->x
) * (l
->s
->x
-
397 return dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
);
399 return dist (l
->e
->x
, l
->e
->y
, c
->x
, c
->y
);
401 (l
->e
->y
- l
->s
->y
) * (c
->x
* l
->s
->x
) + (l
->e
->x
- l
->s
->x
) * (c
->y
-
403 return (int) (d
/ len
);
407 line_orient (line_s
* l
, corner_s
* c
)
442 common_corner (line_s
* l1
, line_s
* l2
)
444 if (l1
->s
== l2
->s
|| l1
->s
== l2
->e
)
446 if (l1
->e
== l2
->s
|| l1
->e
== l2
->e
)
448 dj_abort ("common_corner: no common corner found\n");
454 other_corner (line_s
* l
, corner_s
* c
)
460 dj_abort ("other_corner: neither corner passed\n");
465 find_corner_if (int x
, int y
, int l
)
468 for (c
= corners
; c
; c
= c
->next
)
472 if (c
->x
!= x
|| c
->y
!= y
)
474 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
482 find_corner (int x
, int y
, int l
)
485 for (c
= corners
; c
; c
= c
->next
)
489 if (c
->x
!= x
|| c
->y
!= y
)
491 if (!(c
->layer
== -1 || intersecting_layers (c
->layer
, l
)))
495 c
= (corner_s
*) malloc (sizeof (corner_s
));
506 c
->lines
= (line_s
**) malloc (INC
* sizeof (line_s
*));
511 add_line_to_corner (line_s
* l
, corner_s
* c
)
514 n
= (c
->n_lines
+ 1 + INC
) & ~INC
;
515 c
->lines
= (line_s
**) realloc (c
->lines
, n
* sizeof (line_s
*));
516 c
->lines
[c
->n_lines
] = l
;
518 dprintf ("add_line_to_corner %d %d\n", c
->x
, c
->y
);
522 create_pcb_line (int layer
, int x1
, int y1
, int x2
, int y2
,
523 int thick
, int clear
, FlagType flags
)
527 LayerType
*lyr
= LAYER_PTR (layer
);
529 from
= (char *) lyr
->Line
;
530 nl
= CreateNewLineOnLayer (PCB
->Data
->Layer
+ layer
,
531 x1
, y1
, x2
, y2
, thick
, clear
, flags
);
532 AddObjectToCreateUndoList (LINE_TYPE
, lyr
, nl
, nl
);
534 to
= (char *) lyr
->Line
;
538 for (lp
= lines
; lp
; lp
= lp
->next
)
542 if ((char *) (lp
->line
) >= from
543 && (char *) (lp
->line
) <= from
+ lyr
->LineN
* sizeof (LineType
))
544 lp
->line
= (LineType
*) ((char *) (lp
->line
) + (to
- from
));
551 new_line (corner_s
* s
, corner_s
* e
, int layer
, LineType
* example
)
555 if (layer
>= max_layer
)
556 dj_abort ("layer %d\n", layer
);
559 dj_abort ("NULL example passed to new_line()\n", layer
);
561 if (s
->x
== e
->x
&& s
->y
== e
->y
)
564 ls
= (line_s
*) malloc (sizeof (line_s
));
571 if ((example
->Point1
.X
== s
->x
&& example
->Point1
.Y
== s
->y
572 && example
->Point2
.X
== e
->x
&& example
->Point2
.Y
== e
->y
)
573 || (example
->Point2
.X
== s
->x
&& example
->Point2
.Y
== s
->y
574 && example
->Point1
.X
== e
->x
&& example
->Point1
.Y
== e
->y
))
583 ("New line \033[35m%d,%d to %d,%d from l%d t%d c%d f%s\033[0m\n",
584 s
->x
, s
->y
, e
->x
, e
->y
, layer
, example
->Thickness
,
585 example
->Clearance
, flags_to_string (example
->Flags
, LINE_TYPE
));
587 create_pcb_line (layer
, s
->x
, s
->y
, e
->x
, e
->y
, example
->Thickness
,
588 example
->Clearance
, example
->Flags
);
591 dj_abort ("can't create new line!");
594 add_line_to_corner (ls
, s
);
595 add_line_to_corner (ls
, e
);
603 c_orth_to (corner_s
* c
, line_s
* l
, int o
)
607 for (i
= 0; i
< c
->n_lines
; i
++)
609 if (c
->lines
[i
] == l
)
611 o2
= line_orient (c
->lines
[i
], c
);
612 if (ORIENT (o
) == ORIENT (o2
) || o2
== DIAGONAL
)
621 other_line (corner_s
* c
, line_s
* l
)
625 if (c
->pin
|| c
->pad
|| c
->via
)
627 for (i
= 0; i
< c
->n_lines
; i
++)
629 if (c
->lines
[i
] == l
)
639 empty_rect (rect_s
* rect
)
641 rect
->x1
= rect
->y1
= INT_MAX
;
642 rect
->x2
= rect
->y2
= INT_MIN
;
646 add_point_to_rect (rect_s
* rect
, int x
, int y
, int w
)
648 if (rect
->x1
> x
- w
)
650 if (rect
->x2
< x
+ w
)
652 if (rect
->y1
> y
- w
)
654 if (rect
->y2
< y
+ w
)
659 add_line_to_rect (rect_s
* rect
, line_s
* l
)
661 add_point_to_rect (rect
, l
->s
->x
, l
->s
->y
, 0);
662 add_point_to_rect (rect
, l
->e
->x
, l
->e
->y
, 0);
666 pin_in_rect (rect_s
* r
, int x
, int y
, int w
)
668 if (x
< r
->x1
&& x
+ w
< r
->x1
)
670 if (x
> r
->x2
&& x
- w
> r
->x2
)
672 if (y
< r
->y1
&& y
+ w
< r
->y1
)
674 if (y
> r
->y2
&& y
- w
> r
->y2
)
680 line_in_rect (rect_s
* r
, line_s
* l
)
684 add_point_to_rect (&lr
, l
->s
->x
, l
->s
->y
, l
->line
->Thickness
/ 2);
685 add_point_to_rect (&lr
, l
->e
->x
, l
->e
->y
, l
->line
->Thickness
/ 2);
686 dprintf ("line_in_rect %d,%d-%d,%d vs %d,%d-%d,%d\n",
687 r
->x1
, r
->y1
, r
->x2
, r
->y2
, lr
.x1
, lr
.y1
, lr
.x2
, lr
.y2
);
688 /* simple intersection of rectangles */
697 if (lr
.x1
< lr
.x2
&& lr
.y1
< lr
.y2
)
703 corner_radius (corner_s
* c
)
708 diam
= djmax (c
->pin
->Thickness
, diam
);
710 diam
= djmax (c
->via
->Thickness
, diam
);
711 for (i
= 0; i
< c
->n_lines
; i
++)
712 if (c
->lines
[i
]->line
)
713 diam
= djmax (c
->lines
[i
]->line
->Thickness
, diam
);
714 diam
= (diam
+ 1) / 2;
721 corner_layer (corner_s
* c
)
723 if (c
->pin
|| c
->via
)
727 return c
->lines
[0]->layer
;
732 add_corner_to_rect_if (rect_s
* rect
, corner_s
* c
, rect_s
* e
)
734 int diam
= corner_radius (c
);
735 if (!pin_in_rect (e
, c
->x
, c
->y
, diam
))
737 if (c
->x
< e
->x1
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x1
, e
->y1
) > diam
)
739 if (c
->x
> e
->x2
&& c
->y
< e
->y1
&& dist (c
->x
, c
->y
, e
->x2
, e
->y1
) > diam
)
741 if (c
->x
< e
->x1
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x1
, e
->y2
) > diam
)
743 if (c
->x
> e
->x2
&& c
->y
> e
->y2
&& dist (c
->x
, c
->y
, e
->x2
, e
->y2
) > diam
)
746 /*printf("add point %d,%d diam %d\n", c->x, c->y, diam); */
747 add_point_to_rect (rect
, c
->x
, c
->y
, diam
);
751 remove_line (line_s
* l
)
755 LineType
*from
= 0, *to
= 0;
756 LayerType
*layer
= &(PCB
->Data
->Layer
[l
->layer
]);
762 /* compensate for having line pointers rearranged */
763 from
= &(layer
->Line
[layer
->LineN
- 1]);
765 RemoveLine (layer
, l
->line
);
769 for (l2
= lines
; l2
; l2
= l2
->next
)
773 if (l2
->line
== from
)
777 for (i
= 0, j
= 0; i
< l
->s
->n_lines
; i
++)
778 if (l
->s
->lines
[i
] != l
)
779 l
->s
->lines
[j
++] = l
->s
->lines
[i
];
782 for (i
= 0, j
= 0; i
< l
->e
->n_lines
; i
++)
783 if (l
->e
->lines
[i
] != l
)
784 l
->e
->lines
[j
++] = l
->e
->lines
[i
];
790 move_line_to_layer (line_s
* l
, int layer
)
794 LineType
*from
= 0, *to
= 0;
795 LineType
*oldbase
= 0, *newbase
= 0, *oldend
;
798 ls
= LAYER_PTR (l
->layer
);
799 from
= &(ls
->Line
[ls
->LineN
- 1]);
802 ld
= LAYER_PTR (layer
);
804 oldend
= oldbase
+ ld
->LineN
;
806 newline
= (LineType
*) MoveObjectToLayer (LINE_TYPE
, ls
, l
->line
, 0, ld
, 0);
809 for (l2
= lines
; l2
; l2
= l2
->next
)
813 if (l2
->line
== from
)
815 if (l2
->line
>= oldbase
&& l2
->line
< oldend
)
816 l2
->line
+= newbase
- oldbase
;
824 remove_via_at (corner_s
* c
)
827 PinType
*from
= PCB
->Data
->Via
+ PCB
->Data
->ViaN
- 1;
828 PinType
*to
= c
->via
;
829 RemoveObject (VIA_TYPE
, c
->via
, 0, 0);
831 for (cc
= corners
; cc
; cc
= cc
->next
)
841 remove_corner (corner_s
* c2
)
844 dprintf ("remove corner %s\n", corner_name (c2
));
847 for (c
= corners
; c
; c
= c
->next
)
854 if (next_corner
== c2
)
855 next_corner
= c2
->next
;
862 merge_corners (corner_s
* c1
, corner_s
* c2
)
867 dprintf ("merge corners %s %s\n", corner_name (c1
), corner_name (c2
));
868 for (i
= 0; i
< c2
->n_lines
; i
++)
870 add_line_to_corner (c2
->lines
[i
], c1
);
871 if (c2
->lines
[i
]->s
== c2
)
872 c2
->lines
[i
]->s
= c1
;
873 if (c2
->lines
[i
]->e
== c2
)
874 c2
->lines
[i
]->e
= c1
;
876 if (c1
->via
&& c2
->via
)
884 if (c2
->layer
!= c1
->layer
)
891 move_corner (corner_s
* c
, int x
, int y
)
898 if (c
->pad
|| c
->pin
)
899 dj_abort ("move_corner: has pin or pad\n");
900 dprintf ("move_corner %p from %d,%d to %d,%d\n", (void *) c
, c
->x
, c
->y
, x
,
902 pad
= find_corner_if (x
, y
, c
->layer
);
908 MoveObject (VIA_TYPE
, via
, via
, via
, x
- via
->X
, y
- via
->Y
);
909 dprintf ("via move %d,%d to %d,%d\n", via
->X
, via
->Y
, x
, y
);
911 for (i
= 0; i
< c
->n_lines
; i
++)
913 LineTypePtr tl
= c
->lines
[i
]->line
;
916 if (c
->lines
[i
]->s
== c
)
918 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (c
->lines
[i
]->layer
), tl
,
919 &tl
->Point1
, x
- (tl
->Point1
.X
),
924 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (c
->lines
[i
]->layer
), tl
,
925 &tl
->Point2
, x
- (tl
->Point2
.X
),
928 dprintf ("Line %p moved to %d,%d %d,%d\n", (void *) tl
,
929 tl
->Point1
.X
, tl
->Point1
.Y
, tl
->Point2
.X
, tl
->Point2
.Y
);
933 merge_corners (c
, pad
);
935 for (i
= 0; i
< c
->n_lines
; i
++)
937 if (c
->lines
[i
]->s
->x
== c
->lines
[i
]->e
->x
938 && c
->lines
[i
]->s
->y
== c
->lines
[i
]->e
->y
)
940 corner_s
*c2
= other_corner (c
->lines
[i
], c
);
941 dprintf ("move_corner: removing line %d,%d %d,%d %p %p\n",
942 c
->x
, c
->y
, c2
->x
, c2
->y
, (void *) c
, (void *) c2
);
944 remove_line (c
->lines
[i
]);
946 merge_corners (c
, c2
);
952 gui
->progress (0, 0, 0);
960 for (l
= lines
; l
; l
= l
->next
)
964 if (l
->line
&& selected (l
->line
))
971 trim_step (int s
, int l1
, int l2
)
973 dprintf ("trim %d %d %d\n", s
, l1
, l2
);
978 if (s
!= l1
&& s
!= l2
)
983 static int canonicalize_line (line_s
* l
);
986 split_line (line_s
* l
, corner_s
* c
)
993 if (!intersecting_layers (l
->layer
, c
->layer
))
999 dprintf ("split on pad!\n");
1000 if (l
->s
->pad
== c
->pad
|| l
->e
->pad
== c
->pad
)
1002 dprintf ("splitting...\n");
1006 layer
= PCB
->Data
->Layer
+ l
->layer
;
1007 pcbline
= create_pcb_line (l
->layer
,
1008 c
->x
, c
->y
, l
->e
->x
, l
->e
->y
,
1009 l
->line
->Thickness
, l
->line
->Clearance
,
1012 return 0; /* already a line there */
1016 dprintf ("split line from %d,%d to %d,%d at %d,%d\n",
1017 l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
, c
->x
, c
->y
);
1018 ls
= (line_s
*) malloc (sizeof (line_s
));
1025 ls
->layer
= l
->layer
;
1026 for (i
= 0; i
< l
->e
->n_lines
; i
++)
1027 if (l
->e
->lines
[i
] == l
)
1028 l
->e
->lines
[i
] = ls
;
1030 add_line_to_corner (l
, c
);
1031 add_line_to_corner (ls
, c
);
1033 MoveObject (LINEPOINT_TYPE
, LAYER_PTR (l
->layer
), l
->line
, &l
->line
->Point2
,
1034 c
->x
- (l
->line
->Point2
.X
), c
->y
- (l
->line
->Point2
.Y
));
1040 canonicalize_line (line_s
* l
)
1042 /* This could be faster */
1044 if (l
->s
->x
== l
->e
->x
)
1048 int x1
= l
->s
->x
- l
->line
->Thickness
/ 2;
1049 int x2
= l
->s
->x
+ l
->line
->Thickness
/ 2;
1056 for (c
= corners
; c
; c
= c
->next
)
1060 if ((y1
< c
->y
&& c
->y
< y2
)
1061 && intersecting_layers (l
->layer
, c
->layer
))
1064 && c
->x
< x2
&& c
->x
> x1
&& !(c
->pad
|| c
->pin
))
1066 move_corner (c
, l
->s
->x
, c
->y
);
1068 if (c
->x
== l
->s
->x
)
1070 /* FIXME: if the line is split, we have to re-canonicalize
1072 return split_line (l
, c
);
1077 else if (l
->s
->y
== l
->e
->y
)
1081 int y1
= l
->s
->y
- l
->line
->Thickness
/ 2;
1082 int y2
= l
->s
->y
+ l
->line
->Thickness
/ 2;
1089 for (c
= corners
; c
; c
= c
->next
)
1093 if ((x1
< c
->x
&& c
->x
< x2
)
1094 && intersecting_layers (l
->layer
, c
->layer
))
1097 && c
->y
< y2
&& c
->y
> y1
&& !(c
->pad
|| c
->pin
))
1099 move_corner (c
, c
->x
, l
->s
->y
);
1101 if (c
->y
== l
->s
->y
)
1103 /* FIXME: Likewise. */
1104 return split_line (l
, c
);
1111 /* diagonal lines. Let's try to split them at pins/vias
1129 for (c
= corners
; c
; c
= c
->next
)
1133 if (!c
->via
&& !c
->pin
)
1135 if ((x1
< c
->x
&& c
->x
< x2
)
1136 && (y1
< c
->y
&& c
->y
< y2
)
1137 && intersecting_layers (l
->layer
, c
->layer
))
1139 int th
= c
->pin
? c
->pin
->Thickness
: c
->via
->Thickness
;
1141 if (dist (l
->s
->x
, l
->s
->y
, c
->x
, c
->y
) > th
1142 && dist (l
->e
->x
, l
->e
->y
, c
->x
, c
->y
) > th
1143 && PinLineIntersect (c
->pin
? c
->pin
: c
->via
, l
->line
))
1145 return split_line (l
, c
);
1153 /* Make sure all vias are at line end points */
1155 canonicalize_lines ()
1163 for (l
= lines
; l
; l
= l
->next
)
1167 count
+= canonicalize_line (l
);
1177 simple_optimize_corner (corner_s
* c
)
1185 /* see if no via is needed */
1186 if (selected (c
->via
))
1187 dprintf ("via check: line[0] layer %d at %d,%d nl %d\n",
1188 c
->lines
[0]->layer
, c
->x
, c
->y
, c
->n_lines
);
1189 /* We can't delete vias that connect to power planes, or vias
1190 that aren't tented (assume they're test points). */
1191 if (!TEST_ANY_THERMS (c
->via
)
1192 && c
->via
->Mask
== 0)
1194 for (i
= 1; i
< c
->n_lines
; i
++)
1196 if (selected (c
->via
))
1197 dprintf (" line[%d] layer %d %d,%d to %d,%d\n",
1198 i
, c
->lines
[i
]->layer
,
1199 c
->lines
[i
]->s
->x
, c
->lines
[i
]->s
->y
,
1200 c
->lines
[i
]->e
->x
, c
->lines
[i
]->e
->y
);
1201 if (c
->lines
[i
]->layer
!= c
->lines
[0]->layer
)
1204 if (i
== c
->n_lines
)
1206 if (selected (c
->via
))
1207 dprintf (" remove it\n");
1215 if (c
->n_lines
== 2 && !c
->via
)
1217 /* see if it is an unneeded corner */
1218 int o
= line_orient (c
->lines
[0], c
);
1219 corner_s
*c2
= other_corner (c
->lines
[1], c
);
1220 corner_s
*c0
= other_corner (c
->lines
[0], c
);
1221 if (o
== line_orient (c
->lines
[1], c2
) && o
!= DIAGONAL
)
1223 dprintf ("straight %d,%d to %d,%d to %d,%d\n",
1224 c0
->x
, c0
->y
, c
->x
, c
->y
, c2
->x
, c2
->y
);
1225 if (selected (c
->lines
[0]->line
))
1226 SET_FLAG (SELECTEDFLAG
, c
->lines
[1]->line
);
1227 if (selected (c
->lines
[1]->line
))
1228 SET_FLAG (SELECTEDFLAG
, c
->lines
[0]->line
);
1229 move_corner (c
, c2
->x
, c2
->y
);
1236 /* We always run these */
1238 simple_optimizations ()
1243 /* Look for corners that aren't */
1244 for (c
= corners
; c
; c
= c
->next
)
1248 if (c
->pad
|| c
->pin
)
1250 rv
+= simple_optimize_corner (c
);
1256 is_hole (corner_s
* c
)
1258 return c
->pin
|| c
->pad
|| c
->via
;
1262 orthopull_1 (corner_s
* c
, int fdir
, int rdir
, int any_sel
)
1264 static corner_s
**cs
= 0;
1266 static line_s
**ls
= 0;
1268 int i
, li
, ln
, cn
, snap
;
1271 int adir
= 0, sdir
= 0, pull
;
1272 int saw_sel
= 0, saw_auto
= 0;
1273 int max
, len
= 0, r1
= 0, r2
;
1279 cs
= (corner_s
**) malloc (10 * sizeof (corner_s
));
1281 ls
= (line_s
**) malloc (10 * sizeof (line_s
));
1285 for (i
= 0; i
< c
->n_lines
; i
++)
1287 int o
= line_orient (c
->lines
[i
], c
);
1303 dj_abort ("fdir not right or down\n");
1312 if (c2
->pad
|| c2
->pin
|| c2
->n_lines
< 2)
1317 cs
= (corner_s
**) realloc (cs
, cm
* sizeof (corner_s
));
1320 r2
= corner_radius (c2
);
1324 for (i
= 0; i
< c2
->n_lines
; i
++)
1326 int o
= line_orient (c2
->lines
[i
], c2
);
1332 return 0; /* we don't support overlapping lines yet */
1335 if (o
== rdir
&& c2
->lines
[i
] != ls
[ln
- 1])
1336 return 0; /* likewise */
1344 if (selected (l
->line
))
1346 if (autorouted (l
->line
))
1351 ls
= (line_s
**) realloc (ls
, lm
* sizeof (line_s
));
1354 c2
= other_corner (l
, c2
);
1356 if (cn
< 2 || pull
== 0)
1358 if (any_sel
&& !saw_sel
)
1360 if (!any_sel
&& autorouted_only
&& !saw_auto
)
1363 /* Ok, now look for other blockages. */
1366 add_point_to_rect (&rr
, c
->x
, c
->y
, corner_radius (c
));
1367 add_point_to_rect (&rr
, c2
->x
, c2
->y
, corner_radius (c2
));
1369 if (fdir
== RIGHT
&& pull
< 0)
1371 else if (fdir
== RIGHT
&& pull
> 0)
1373 else if (fdir
== DOWN
&& pull
< 0)
1375 else if (fdir
== DOWN
&& pull
> 0)
1379 for (i
= 0; i
< cn
; i
++)
1380 for (li
= 0; li
< cs
[i
]->n_lines
; li
++)
1382 if (line_orient (cs
[i
]->lines
[li
], cs
[i
]) != edir
)
1384 len
= line_length (cs
[i
]->lines
[li
]);
1385 if (max
> len
|| max
== -1)
1388 dprintf ("c %s %4d %4d cn %d pull %3d max %4d\n",
1389 fdir
== RIGHT
? "right" : "down ", c
->x
, c
->y
, cn
, pull
, max
);
1394 rr
.y1
= c
->y
- r1
- max
;
1397 rr
.y2
= c
->y
+ r1
+ max
;
1400 rr
.x1
= c
->x
- r1
- max
;
1403 rr
.x2
= c
->x
+ r1
+ max
;
1412 for (cb
= corners
; cb
; cb
= cb
->next
)
1417 r1
= corner_radius (cb
);
1418 if (cb
->net
== c
->net
&& !cb
->pad
)
1420 if (!pin_in_rect (&rr
, cb
->x
, cb
->y
, r1
))
1424 #define ECHK(X,Y,LT) \
1425 for (i=0; i<cn; i++) \
1427 if (!intersecting_layers(cs[i]->layer, cb->layer)) \
1429 r2 = corner_radius(cs[i]); \
1430 if (cb->X + r1 <= cs[i]->X - r2 - SB - 1) \
1432 if (cb->X - r1 >= cs[i]->X + r2 + SB + 1) \
1434 if (cb->Y LT cs[i]->Y) \
1436 sep = djabs(cb->Y - cs[i]->Y) - r1 - r2 - SB - 1; \
1438 { max = sep; snap = 1; }\
1440 for (i=0; i<ln; i++) \
1442 if (!intersecting_layers(ls[i]->layer, cb->layer)) \
1444 if (cb->X <= cs[i]->X || cb->X >= cs[i+1]->X) \
1446 sep = (djabs(cb->Y - cs[i]->Y) - ls[i]->line->Thickness/2 \
1449 { max = sep; snap = 1; }\
1466 /* We must now check every line segment against our corners. */
1467 for (l
= lines
; l
; l
= l
->next
)
1469 int o
, x1
, x2
, y1
, y2
;
1472 dprintf ("check line %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1474 if (l
->s
->net
== c
->net
)
1476 dprintf (" same net\n");
1479 o
= line_orient (l
, 0);
1480 /* We don't need to check perpendicular lines, because their
1481 corners already take care of it. */
1482 if ((fdir
== RIGHT
&& (o
== UP
|| o
== DOWN
))
1483 || (fdir
== DOWN
&& (o
== RIGHT
|| o
== LEFT
)))
1485 dprintf (" perpendicular\n");
1489 /* Choose so that x1,y1 is closest to corner C */
1490 if ((fdir
== RIGHT
&& l
->s
->x
< l
->e
->x
)
1491 || (fdir
== DOWN
&& l
->s
->y
< l
->e
->y
))
1506 /* Eliminate all lines outside our range */
1507 if ((fdir
== RIGHT
&& (x2
< c
->x
|| x1
> c2
->x
))
1508 || (fdir
== DOWN
&& (y2
< c
->y
|| y1
> c2
->y
)))
1510 dprintf (" outside our range\n");
1514 /* Eliminate all lines on the wrong side of us */
1515 if ((edir
== UP
&& y1
> c
->y
&& y2
> c
->y
)
1516 || (edir
== DOWN
&& y1
< c
->y
&& y2
< c
->y
)
1517 || (edir
== LEFT
&& x1
> c
->x
&& x2
> c
->x
)
1518 || (edir
== RIGHT
&& x1
< c
->x
&& x2
< c
->x
))
1520 dprintf (" wrong side\n");
1524 /* For now, cheat on diagonals */
1545 /* Ok, now see how far we can get for each of our corners. */
1546 for (i
= 0; i
< cn
; i
++)
1548 int r
= l
->line
->Thickness
+ SB
+ corner_radius (cs
[i
]) + 1;
1550 if ((fdir
== RIGHT
&& (x2
< cs
[i
]->x
|| x1
> cs
[i
]->x
))
1551 || (fdir
== DOWN
&& (y2
< cs
[i
]->y
|| y1
> cs
[i
]->y
)))
1553 if (!intersecting_layers (cs
[i
]->layer
, l
->layer
))
1571 dprintf (" len is %d vs corner at %d,%d\n", len
, cs
[i
]->x
,
1581 /* We must make sure that if a segment isn't being completely
1582 removed, that any vias and/or pads don't overlap. */
1587 for (i
= 0; i
< cn
; i
++)
1588 for (li
= 0; li
< cs
[i
]->n_lines
; li
++)
1590 line_s
*l
= cs
[i
]->lines
[li
];
1591 corner_s
*oc
= other_corner (l
, cs
[i
]);
1592 if (line_orient (l
, cs
[i
]) != edir
)
1594 len
= line_length (l
);
1595 if (!oc
->pad
|| !cs
[i
]->via
)
1597 if (!is_hole (l
->s
) || !is_hole (l
->e
))
1602 len
-= corner_radius (l
->s
);
1603 len
-= corner_radius (l
->e
);
1630 if (snap
&& max
> Settings
.Grid
)
1633 len
+= Settings
.Grid
- 1;
1634 len
-= len
% (int) (Settings
.Grid
);
1636 if ((fdir
== RIGHT
&& len
== cs
[0]->y
) || (fdir
== DOWN
&& len
== cs
[0]->x
))
1638 for (i
= 0; i
< cn
; i
++)
1642 max
= len
- cs
[i
]->y
;
1643 move_corner (cs
[i
], cs
[i
]->x
, len
);
1647 max
= len
- cs
[i
]->x
;
1648 move_corner (cs
[i
], len
, cs
[i
]->y
);
1657 /* Look for straight runs which could be moved to reduce total trace
1659 int any_sel
= any_line_selected ();
1663 for (c
= corners
; c
;)
1667 if (c
->pin
|| c
->pad
)
1673 rv
+= orthopull_1 (c
, RIGHT
, LEFT
, any_sel
);
1674 if (c
!= next_corner
)
1679 rv
+= orthopull_1 (c
, DOWN
, UP
, any_sel
);
1680 if (c
!= next_corner
)
1688 printf ("orthopull: %d mils saved\n", rv
/ 100);
1695 /* Look for "U" shaped traces we can shorten (or eliminate) */
1697 int any_selected
= any_line_selected ();
1698 line_s
*l
, *l1
, *l2
;
1699 corner_s
*c
, *c1
, *c2
;
1701 int o
, o1
, o2
, step
, w
;
1702 for (l
= lines
; l
; l
= l
->next
)
1708 if (any_selected
&& !selected (l
->line
))
1710 if (!any_selected
&& autorouted_only
&& !autorouted (l
->line
))
1712 if (l
->s
->pin
|| l
->s
->pad
|| l
->e
->pin
|| l
->e
->pad
)
1714 o
= line_orient (l
, 0);
1717 l1
= other_line (l
->s
, l
);
1720 o1
= line_orient (l1
, l
->s
);
1721 l2
= other_line (l
->e
, l
);
1724 o2
= line_orient (l2
, l
->e
);
1725 if (ORIENT (o
) == ORIENT (o1
) || o1
!= o2
|| o1
== DIAGONAL
)
1728 dprintf ("\nline: %d,%d to %d,%d\n", l
->s
->x
, l
->s
->y
, l
->e
->x
,
1730 w
= l
->line
->Thickness
/ 2 + SB
+ 1;
1732 add_line_to_rect (&rr
, l1
);
1733 add_line_to_rect (&rr
, l2
);
1734 if (rr
.x1
!= l
->s
->x
&& rr
.x1
!= l
->e
->x
)
1736 if (rr
.x2
!= l
->s
->x
&& rr
.x2
!= l
->e
->x
)
1738 if (rr
.y1
!= l
->s
->y
&& rr
.y1
!= l
->e
->y
)
1740 if (rr
.y2
!= l
->s
->y
&& rr
.y2
!= l
->e
->y
)
1742 dprintf ("range: x %d..%d y %d..%d\n", rr
.x1
, rr
.x2
, rr
.y1
, rr
.y2
);
1744 c1
= other_corner (l1
, l
->s
);
1745 c2
= other_corner (l2
, l
->e
);
1748 for (c
= corners
; c
; c
= c
->next
)
1752 if (c
->net
!= l
->s
->net
1753 && intersecting_layers (c
->layer
, l
->s
->layer
))
1754 add_corner_to_rect_if (&rp
, c
, &rr
);
1756 if (rp
.x1
== INT_MAX
)
1763 dprintf ("pin r: x %d..%d y %d..%d\n", rp
.x1
, rp
.x2
, rp
.y1
, rp
.y2
);
1768 step
= l
->s
->x
- rp
.x2
- w
;
1769 step
= gridsnap (step
);
1770 if (step
> l
->s
->x
- c1
->x
)
1771 step
= l
->s
->x
- c1
->x
;
1772 if (step
> l
->s
->x
- c2
->x
)
1773 step
= l
->s
->x
- c2
->x
;
1776 dprintf ("left step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1777 move_corner (l
->s
, l
->s
->x
- step
, l
->s
->y
);
1778 move_corner (l
->e
, l
->e
->x
- step
, l
->e
->y
);
1783 step
= rp
.x1
- l
->s
->x
- w
;
1784 step
= gridsnap (step
);
1785 if (step
> c1
->x
- l
->s
->x
)
1786 step
= c1
->x
- l
->s
->x
;
1787 if (step
> c2
->x
- l
->s
->x
)
1788 step
= c2
->x
- l
->s
->x
;
1791 dprintf ("right step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1792 move_corner (l
->s
, l
->s
->x
+ step
, l
->s
->y
);
1793 move_corner (l
->e
, l
->e
->x
+ step
, l
->e
->y
);
1798 if (rp
.y2
== INT_MIN
)
1800 step
= trim_step (l
->s
->y
- rp
.y2
- w
,
1801 l
->s
->y
- c1
->y
, l
->s
->y
- c2
->y
);
1804 dprintf ("up step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1805 move_corner (l
->s
, l
->s
->x
, l
->s
->y
- step
);
1806 move_corner (l
->e
, l
->e
->x
, l
->e
->y
- step
);
1811 step
= rp
.y1
- l
->s
->y
- w
;
1812 step
= gridsnap (step
);
1813 if (step
> c1
->y
- l
->s
->y
)
1814 step
= c1
->y
- l
->s
->y
;
1815 if (step
> c2
->y
- l
->s
->y
)
1816 step
= c2
->y
- l
->s
->y
;
1819 dprintf ("down step %d at %d,%d\n", step
, l
->s
->x
, l
->s
->y
);
1820 move_corner (l
->s
, l
->s
->x
, l
->s
->y
+ step
);
1821 move_corner (l
->e
, l
->e
->x
, l
->e
->y
+ step
);
1829 rv
+= simple_optimizations ();
1831 printf ("debumpify: %d mils saved\n", rv
/ 50);
1836 simple_corner (corner_s
* c
)
1839 if (c
->pad
|| c
->pin
|| c
->via
)
1841 if (c
->n_lines
!= 2)
1843 o1
= line_orient (c
->lines
[0], c
);
1844 o2
= line_orient (c
->lines
[1], c
);
1845 if (ORIENT (o1
) == ORIENT (o2
))
1847 if (ORIENT (o1
) == DIAGONAL
|| ORIENT (o2
) == DIAGONAL
)
1855 /* Look for sequences of simple corners we can reduce. */
1857 corner_s
*c
, *c0
, *c1
, *cc
;
1858 int l
, w
, sel
= any_line_selected ();
1861 for (c
= corners
; c
; c
= c
->next
)
1865 if (!simple_corner (c
))
1867 if (!c
->lines
[0]->line
|| !c
->lines
[1]->line
)
1869 if (sel
&& !(selected (c
->lines
[0]->line
)
1870 || selected (c
->lines
[1]->line
)))
1872 if (!sel
&& autorouted_only
1873 && !(autorouted (c
->lines
[0]->line
)
1874 || autorouted (c
->lines
[1]->line
)))
1876 dprintf ("simple at %d,%d\n", c
->x
, c
->y
);
1878 c0
= other_corner (c
->lines
[0], c
);
1879 o0
= line_orient (c
->lines
[0], c
);
1880 s0
= simple_corner (c0
);
1882 c1
= other_corner (c
->lines
[1], c
);
1883 o1
= line_orient (c
->lines
[1], c
);
1884 s1
= simple_corner (c1
);
1888 dprintf ("simples at %d,%d\n", c
->x
, c
->y
);
1891 for (l
= 0; l
< c0
->n_lines
; l
++)
1892 if (c0
->lines
[l
] != c
->lines
[0]
1893 && c0
->lines
[l
]->layer
== c
->lines
[0]->layer
)
1895 int o
= line_orient (c0
->lines
[l
], c0
);
1899 for (l
= 0; l
< c1
->n_lines
; l
++)
1900 if (c1
->lines
[l
] != c
->lines
[0]
1901 && c1
->lines
[l
]->layer
== c
->lines
[0]->layer
)
1903 int o
= line_orient (c1
->lines
[l
], c1
);
1909 dprintf ("orient ok\n");
1911 w
= c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1;
1913 add_line_to_rect (&rr
, c
->lines
[0]);
1914 add_line_to_rect (&rr
, c
->lines
[1]);
1925 for (cc
= corners
; cc
; cc
= cc
->next
)
1929 if (cc
->net
!= c
->net
&& intersecting_layers (cc
->layer
, c
->layer
))
1930 add_corner_to_rect_if (&rp
, cc
, &rr
);
1932 dprintf ("rp x %d..%d y %d..%d\n", rp
.x1
, rp
.x2
, rp
.y1
, rp
.y2
);
1933 if (rp
.x1
<= rp
.x2
) /* something triggered */
1936 dprintf ("unjaggy at %d,%d layer %d\n", c
->x
, c
->y
, c
->layer
);
1938 move_corner (c
, c1
->x
, c0
->y
);
1940 move_corner (c
, c0
->x
, c1
->y
);
1944 rv
+= simple_optimizations ();
1953 for (i
= 0; i
< 100; i
++)
1955 j
= unjaggy_once ();
1961 printf ("%d unjagg%s \n", r
, r
== 1 ? "y" : "ies");
1968 /* Look for vias with all lines leaving the same way, try to nudge
1969 via to eliminate one or more of them. */
1971 corner_s
*c
, *c2
, *c3
;
1973 unsigned char directions
[MAX_LAYER
];
1974 unsigned char counts
[MAX_LAYER
];
1976 memset (directions
, 0, sizeof (directions
));
1977 memset (counts
, 0, sizeof (counts
));
1979 for (c
= corners
; c
; c
= c
->next
)
1981 int o
, i
, vr
, cr
, oboth
;
1982 int len
= 0, saved
= 0;
1990 memset (directions
, 0, sizeof (directions
));
1991 memset (counts
, 0, sizeof (counts
));
1993 for (i
= 0; i
< c
->n_lines
; i
++)
1995 o
= line_orient (c
->lines
[i
], c
);
1996 counts
[c
->lines
[i
]->layer
]++;
1997 directions
[c
->lines
[i
]->layer
] |= o
;
1999 for (o
= 0, i
= 0; i
< max_layer
; i
++)
2009 oboth
= LEFT
| RIGHT
;
2018 for (i
= 0; i
< max_layer
; i
++)
2019 if (counts
[i
] && directions
[i
] != o
&& directions
[i
] != oboth
)
2020 goto vianudge_continue
;
2023 for (i
= 0; i
< c
->n_lines
; i
++)
2025 int ll
= line_length (c
->lines
[i
]);
2026 if (line_orient (c
->lines
[i
], c
) != o
)
2032 if (c2
== 0 || len
> ll
)
2035 c2
= other_corner (c
->lines
[i
], c
);
2038 if (c2
->pad
|| c2
->pin
|| c2
->via
)
2041 /* Now look for clearance in the new position */
2042 vr
= c
->via
->Thickness
/ 2 + SB
+ 1;
2043 for (c3
= corners
; c3
; c3
= c3
->next
)
2047 if ((c3
->net
!= c
->net
&& (c3
->pin
|| c3
->via
)) || c3
->pad
)
2049 cr
= corner_radius (c3
);
2050 if (dist (c2
->x
, c2
->y
, c3
->x
, c3
->y
) < vr
+ cr
)
2051 goto vianudge_continue
;
2054 for (l
= lines
; l
; l
= l
->next
)
2058 if (l
->s
->net
!= c
->net
)
2060 int ld
= dist_line_to_point (l
, c2
);
2061 if (ld
< l
->line
->Thickness
/ 2 + vr
)
2062 goto vianudge_continue
;
2066 /* at this point, we know we can move it */
2068 dprintf ("vianudge: nudging via at %d,%d by %d mils saving %d\n",
2069 c
->x
, c
->y
, len
/ 100, saved
/ 100);
2071 move_corner (c
, c2
->x
, c2
->y
);
2080 printf ("vianudge: %d mils saved\n", rv
/ 100);
2087 /* Look for traces that can be moved to the other side of the board,
2088 to reduce the number of vias needed. For now, we look for simple
2089 lines, not multi-segmented lines. */
2091 int i
, rv
= 0, vrm
= 0;
2092 int any_sel
= any_line_selected ();
2094 for (l
= lines
; l
; l
= l
->next
)
2097 int my_layer
, other_layer
;
2105 if (any_sel
&& !selected (l
->line
))
2107 if (!any_sel
&& autorouted_only
&& !autorouted (l
->line
))
2110 my_layer
= l
->layer
;
2112 dprintf ("line %p on layer %d from %d,%d to %d,%d\n", (void *) l
,
2113 l
->layer
, l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
);
2114 for (i
= 0; i
< l
->s
->n_lines
; i
++)
2115 if (l
->s
->lines
[i
] != l
)
2117 if (other_layer
== -1)
2119 other_layer
= l
->s
->lines
[i
]->layer
;
2120 dprintf ("noting other line %p on layer %d\n",
2121 (void *) (l
->s
->lines
[i
]), my_layer
);
2123 else if (l
->s
->lines
[i
]->layer
!= other_layer
)
2125 dprintf ("saw other line %p on layer %d (not %d)\n",
2126 (void *) (l
->s
->lines
[i
]), l
->s
->lines
[i
]->layer
,
2129 goto viatrim_other_corner
;
2132 viatrim_other_corner
:
2133 if (other_layer
== -1)
2134 for (i
= 0; i
< l
->e
->n_lines
; i
++)
2135 if (l
->e
->lines
[i
] != l
)
2137 if (other_layer
== -1)
2139 other_layer
= l
->s
->lines
[i
]->layer
;
2140 dprintf ("noting other line %p on layer %d\n",
2141 (void *) (l
->s
->lines
[i
]), my_layer
);
2143 else if (l
->e
->lines
[i
]->layer
!= other_layer
)
2145 dprintf ("saw end line on layer %d (not %d)\n",
2146 l
->e
->lines
[i
]->layer
, other_layer
);
2147 goto viatrim_continue
;
2151 /* Now see if any other line intersects us. We don't need to
2152 check corners, because they'd either be pins/vias and
2153 already conflict, or pads, which we'll check here anyway. */
2155 add_point_to_rect (&r
, l
->s
->x
, l
->s
->y
, l
->line
->Thickness
);
2156 add_point_to_rect (&r
, l
->e
->x
, l
->e
->y
, l
->line
->Thickness
);
2158 for (l2
= lines
; l2
; l2
= l2
->next
)
2162 if (l2
->s
->net
!= l
->s
->net
&& l2
->layer
== other_layer
)
2164 dprintf ("checking other line %d,%d to %d,%d\n", l2
->s
->x
,
2165 l2
->s
->y
, l2
->e
->x
, l2
->e
->y
);
2166 if (line_in_rect (&r
, l2
))
2168 dprintf ("line from %d,%d to %d,%d in the way\n",
2169 l2
->s
->x
, l2
->s
->y
, l2
->e
->x
, l2
->e
->y
);
2170 goto viatrim_continue
;
2175 if (l
->layer
== other_layer
)
2177 move_line_to_layer (l
, other_layer
);
2183 vrm
= simple_optimizations ();
2185 printf ("viatrim: %d traces moved, %d vias removed\n", rv
, vrm
);
2192 int more
= 1, oldmore
= 0;
2194 while (more
!= oldmore
&& --toomany
)
2197 more
+= debumpify ();
2199 more
+= orthopull ();
2200 more
+= vianudge ();
2211 int sel
= any_line_selected ();
2214 for (c
= corners
; c
; c
= c
->next
)
2219 if (c
->n_lines
== 2 && !c
->via
&& !c
->pin
&& !c
->via
)
2221 int o1
= line_orient (c
->lines
[0], c
);
2222 int o2
= line_orient (c
->lines
[1], c
);
2223 if (ORIENT (o1
) != ORIENT (o2
)
2224 && o1
!= DIAGONAL
&& o2
!= DIAGONAL
2225 && c
->lines
[0]->line
->Thickness
== c
->lines
[1]->line
->Thickness
)
2232 while (!done
&& progress
)
2236 for (c
= corners
; c
; c
= c
->next
)
2242 int max
= line_length (c
->lines
[0]);
2243 int len
= line_length (c
->lines
[1]);
2246 corner_s
*closest_corner
= 0, *c2
, *oc1
, *oc2
;
2247 int mx
= 0, my
= 0, x
, y
;
2248 int o1
= line_orient (c
->lines
[0], c
);
2249 int o2
= line_orient (c
->lines
[1], c
);
2251 if (c
->pad
|| c
->pin
|| c
->via
)
2258 oc1
= other_corner (c
->lines
[0], c
);
2259 oc2
= other_corner (c
->lines
[1], c
);
2267 if ((sel
&& !(selected (c
->lines
[0]->line
)
2268 || selected (c
->lines
[1]->line
)))
2269 || (!sel
&& autorouted_only
2270 && !(autorouted (c
->lines
[0]->line
)
2271 || autorouted (c
->lines
[1]->line
))))
2310 ref
= c
->x
* mx
+ c
->y
* my
;
2313 bloat
= (c
->lines
[0]->line
->Thickness
/ 2 + SB
+ 1) * 3 / 2;
2315 for (c2
= corners
; c2
; c2
= c2
->next
)
2319 if (c2
!= c
&& c2
!= oc1
&& c2
!= oc2
2320 && c
->x
* mx
<= c2
->x
* mx
2321 && c
->y
* my
<= c2
->y
* my
2322 && c
->net
!= c2
->net
2323 && intersecting_layers (c
->layer
, c2
->layer
))
2325 int cr
= corner_radius (c2
);
2326 len
= c2
->x
* mx
+ c2
->y
* my
- ref
- cr
- bloat
;
2327 if (c
->x
!= c2
->x
&& c
->y
!= c2
->y
)
2329 if (len
< dist
|| (len
== dist
&& c
->miter
!= -1))
2332 closest_corner
= c2
;
2337 if (closest_corner
&& closest_corner
->miter
== -1)
2344 if (dist
< Settings
.Grid
)
2351 dist
-= dist
% Settings
.Grid
;
2377 c2
= find_corner (x
, y
, c
->layer
);
2378 if (c2
!= other_corner (c
->lines
[0], c
))
2379 split_line (c
->lines
[0], c2
);
2397 move_corner (c
, x
, y
);
2409 classify_corner (corner_s
* c
, int this_net
)
2412 if (c
->net
== this_net
)
2415 for (i
= 0; i
< c
->n_lines
; i
++)
2416 classify_corner (other_corner (c
->lines
[i
], c
), this_net
);
2422 static int this_net
= 1;
2425 for (c
= corners
; c
; c
= c
->next
)
2431 classify_corner (c
, this_net
);
2443 for (c
= corners
; c
; c
= c
->next
)
2447 printf ("%p corner %d,%d layer %d net %d\n",
2448 (void *) c
, c
->x
, c
->y
, c
->layer
, c
->net
);
2450 for (l
= lines
; l
; l
= l
->next
)
2454 printf ("%p line %p to %p layer %d\n",
2455 (void *) l
, (void *) (l
->s
), (void *) (l
->e
), l
->layer
);
2461 nudge_corner (corner_s
* c
, int dx
, int dy
, corner_s
* prev_corner
)
2466 if (prev_corner
&& (c
->pin
|| c
->pad
))
2468 move_corner (c
, ox
+ dx
, oy
+ dy
);
2469 for (l
= 0; l
< c
->n_lines
; l
++)
2471 corner_s
*oc
= other_corner (c
->lines
[l
], c
);
2472 if (oc
== prev_corner
)
2474 if (dx
&& oc
->x
== ox
)
2475 nudge_corner (oc
, dx
, 0, c
);
2476 if (dy
&& oc
->y
== oy
)
2477 nudge_corner (oc
, 0, dy
, c
);
2482 choose_example_line (corner_s
* c1
, corner_s
* c2
)
2488 dprintf ("choose_example_line\n");
2489 for (ci
= 0; ci
< 2; ci
++)
2490 for (li
= 0; li
< c
[ci
]->n_lines
; li
++)
2492 dprintf (" try[%d,%d] \033[36m<%d,%d-%d,%d t%d c%d f%s>\033[0m\n",
2494 c
[ci
]->lines
[li
]->s
->x
, c
[ci
]->lines
[li
]->s
->y
,
2495 c
[ci
]->lines
[li
]->e
->x
, c
[ci
]->lines
[li
]->e
->y
,
2496 c
[ci
]->lines
[li
]->line
->Thickness
,
2497 c
[ci
]->lines
[li
]->line
->Clearance
,
2498 flags_to_string (c
[ci
]->lines
[li
]->line
->Flags
, LINE_TYPE
));
2499 /* Pads are disqualified, as we want to mimic a trace line. */
2500 if (c
[ci
]->lines
[li
]->line
== (LineTypePtr
) c
[ci
]->pad
)
2502 dprintf (" bad, pad\n");
2505 /* Lines on layers that don't connect to the other pad are bad too. */
2506 if (!intersecting_layers (c
[ci
]->lines
[li
]->layer
, c
[1 - ci
]->layer
))
2508 dprintf (" bad, layers\n");
2511 dprintf (" good\n");
2512 return c
[ci
]->lines
[li
];
2514 dprintf ("choose_example_line: none found!\n");
2519 connect_corners (corner_s
* c1
, corner_s
* c2
)
2522 line_s
*ex
= choose_example_line (c1
, c2
);
2523 LineType
*example
= ex
->line
;
2526 ("connect_corners \033[32m%d,%d to %d,%d, example line %d,%d to %d,%d l%d\033[0m\n",
2527 c1
->x
, c1
->y
, c2
->x
, c2
->y
, ex
->s
->x
, ex
->s
->y
, ex
->e
->x
, ex
->e
->y
,
2532 /* Assume c1 is the moveable one. */
2533 if (!(c1
->pin
|| c1
->pad
|| c1
->via
) && c1
->n_lines
== 1)
2536 /* Extend the line */
2537 if (c1
->lines
[0]->s
->x
== c1
->lines
[0]->e
->x
)
2538 nx
= c1
->x
, ny
= c2
->y
;
2540 nx
= c2
->x
, ny
= c1
->y
;
2541 if (nx
!= c2
->x
|| ny
!= c2
->y
)
2543 move_corner (c1
, nx
, ny
);
2544 new_line (c1
, c2
, layer
, example
);
2549 move_corner (c1
, nx
, ny
);
2555 corner_s
*nc
= find_corner (c1
->x
, c2
->y
, layer
);
2556 new_line (c1
, nc
, layer
, example
);
2557 new_line (nc
, c2
, layer
, example
);
2566 int best_dist
[MAX_LAYER
+ 1];
2567 corner_s
*best_c
[MAX_LAYER
+ 1];
2569 int left
= 0, right
= 0, top
= 0, bottom
= 0;
2577 /* Look for pins that have no connections. See if there's a corner
2578 close by that should be connected to it. This usually happens
2579 when the MUCS router needs to route to an off-grid pin. */
2583 for (c
= corners
; c
; c
= c
->next
)
2587 if (!(c
->pin
|| c
->via
|| c
->pad
))
2593 dprintf ("\ncorner %s\n", corner_name (c
));
2594 if (c
->pin
|| c
->via
)
2596 pin
= c
->pin
? c
->pin
: c
->via
;
2597 close
= pin
->Thickness
/ 2;
2598 left
= c
->x
- close
;
2599 right
= c
->x
+ close
;
2600 bottom
= c
->y
- close
;
2605 close
= c
->pad
->Thickness
/ 2 + 1;
2606 left
= djmin (c
->pad
->Point1
.X
, c
->pad
->Point2
.X
) - close
;
2607 right
= djmax (c
->pad
->Point1
.X
, c
->pad
->Point2
.X
) + close
;
2608 bottom
= djmin (c
->pad
->Point1
.Y
, c
->pad
->Point2
.Y
) - close
;
2609 top
= djmax (c
->pad
->Point1
.Y
, c
->pad
->Point2
.Y
) + close
;
2610 if (c
->pad
->Point1
.X
== c
->pad
->Point2
.X
)
2612 int hy
= (c
->pad
->Point1
.Y
+ c
->pad
->Point2
.Y
) / 2;
2613 dprintf ("pad y %d %d hy %d c %d\n", c
->pad
->Point1
.Y
,
2614 c
->pad
->Point2
.Y
, hy
, c
->y
);
2622 int hx
= (c
->pad
->Point1
.X
+ c
->pad
->Point2
.X
) / 2;
2623 dprintf ("pad x %d %d hx %d c %d\n", c
->pad
->Point1
.X
,
2624 c
->pad
->Point2
.X
, hx
, c
->x
);
2632 dprintf ("%s x %d-%d y %d-%d\n", corner_name (c
), left
, right
,
2634 for (l
= 0; l
<= max_layer
; l
++)
2636 best_dist
[l
] = close
* 2;
2640 for (c2
= corners
; c2
; c2
= c2
->next
)
2646 lt
= corner_radius (c2
);
2649 && !(c2
->pin
|| c2
->pad
|| c2
->via
)
2650 && intersecting_layers (c
->layer
, c2
->layer
)
2651 && c2
->x
>= left
- lt
2652 && c2
->x
<= right
+ lt
2653 && c2
->y
>= bottom
- lt
&& c2
->y
<= top
+ lt
)
2655 int d
= dist (c
->x
, c
->y
, c2
->x
, c2
->y
);
2656 if (pin
&& d
> pin
->Thickness
/ 2 + lt
)
2658 if (c2
->n_lines
== 1)
2661 dprintf ("found orphan %s vs %s\n", corner_name (c2
),
2663 connect_corners (c
, c2
);
2667 if (best_c
[c2
->layer
] == 0
2668 || c2
->n_lines
< best_c
[c2
->layer
]->n_lines
2669 || (d
< best_dist
[c2
->layer
]
2670 && c2
->n_lines
<= best_c
[c2
->layer
]->n_lines
))
2672 best_dist
[c2
->layer
] = d
;
2673 best_c
[c2
->layer
] = c2
;
2674 dprintf ("layer %d best now %s\n", c2
->layer
,
2678 if (!got_one
&& c
->n_lines
== (c
->pad
? 1 : 0))
2680 for (l
= 0; l
<= max_layer
; l
++)
2682 dprintf ("best[%d] = %s\n", l
, corner_name (best_c
[l
]));
2683 for (l
= 0; l
<= max_layer
; l
++)
2686 dprintf ("move %s to %s\n", corner_name (best_c
[l
]),
2688 connect_corners (best_c
[l
], c
);
2697 /* Now look for line ends that don't connect, see if they need to be
2698 extended to intersect another line. */
2699 for (c
= corners
; c
; c
= c
->next
)
2706 if (c
->pin
|| c
->via
|| c
->pad
)
2708 if (c
->n_lines
!= 1)
2712 lo
= line_orient (l
, c
);
2713 dprintf ("line end %d,%d orient %d\n", c
->x
, c
->y
, lo
);
2715 for (t
= lines
; t
; t
= t
->next
)
2719 if (t
->layer
!= c
->lines
[0]->layer
)
2721 switch (lo
) /* remember, orient is for the line relative to the corner */
2724 if (t
->s
->x
== t
->e
->x
2727 c
->x
+ (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2728 && ((t
->s
->y
< c
->y
&& c
->y
< t
->e
->y
)
2729 || (t
->e
->y
< c
->y
&& c
->y
< t
->s
->y
)))
2731 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2733 move_corner (c
, t
->s
->x
, c
->y
);
2737 if (t
->s
->x
== t
->e
->x
2740 c
->x
- (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2741 && ((t
->s
->y
< c
->y
&& c
->y
< t
->e
->y
)
2742 || (t
->e
->y
< c
->y
&& c
->y
< t
->s
->y
)))
2744 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2746 move_corner (c
, t
->s
->x
, c
->y
);
2750 if (t
->s
->y
== t
->e
->y
2753 c
->y
+ (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2754 && ((t
->s
->x
< c
->x
&& c
->x
< t
->e
->x
)
2755 || (t
->e
->x
< c
->x
&& c
->x
< t
->s
->x
)))
2757 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2759 move_corner (c
, c
->x
, t
->s
->y
);
2763 if (t
->s
->y
== t
->e
->y
2766 c
->y
- (l
->line
->Thickness
+ t
->line
->Thickness
) / 2
2767 && ((t
->s
->x
< c
->x
&& c
->x
< t
->e
->x
)
2768 || (t
->e
->x
< c
->x
&& c
->x
< t
->s
->x
)))
2770 dprintf ("found %d,%d - %d,%d\n", t
->s
->x
, t
->s
->y
, t
->e
->x
,
2772 move_corner (c
, c
->x
, t
->s
->y
);
2781 pad_orient (PadType
* p
)
2783 if (p
->Point1
.X
== p
->Point2
.X
)
2785 if (p
->Point1
.Y
== p
->Point2
.Y
)
2798 dprintf ("\ndj: padcleaner\n");
2799 for (l
= lines
; l
; l
= nextl
)
2806 dprintf ("dj: line %p\n", (void *) l
);
2809 if (l
->s
->pad
&& l
->s
->pad
== l
->e
->pad
)
2812 for (ei
= 0; ei
< PCB
->Data
->ElementN
; ei
++)
2814 ElementType
*e
= &(PCB
->Data
->Element
[ei
]);
2815 for (pi
= 0; pi
< e
->PadN
; pi
++)
2817 PadType
*p
= e
->Pad
+ pi
;
2819 TEST_FLAG (ONSOLDERFLAG
, e
) ? LT_SOLDER
: LT_COMPONENT
;
2821 if (layer_type
[l
->layer
] != layerflag
)
2825 close
= p
->Thickness
/ 2 + 1;
2826 add_point_to_rect (&r
, p
->Point1
.X
, p
->Point1
.Y
,
2828 add_point_to_rect (&r
, p
->Point2
.X
, p
->Point2
.Y
,
2830 if (pin_in_rect (&r
, l
->s
->x
, l
->s
->y
, 0)
2831 && pin_in_rect (&r
, l
->e
->x
, l
->e
->y
, 0)
2832 && ORIENT (line_orient (l
, 0)) == pad_orient (p
))
2835 ("padcleaner %d,%d-%d,%d %d vs line %d,%d-%d,%d %d\n",
2836 p
->Point1
.X
, p
->Point1
.Y
, p
->Point2
.X
, p
->Point2
.Y
,
2837 p
->Thickness
, l
->s
->x
, l
->s
->y
, l
->e
->x
, l
->e
->y
,
2838 l
->line
->Thickness
);
2849 grok_layer_groups ()
2852 LayerGroupType
*l
= &(PCB
->LayerGroups
);
2854 solder_layer
= component_layer
= -1;
2855 for (i
= 0; i
< max_layer
; i
++)
2858 layer_groupings
[i
] = 0;
2860 for (i
= 0; i
< max_layer
; i
++)
2863 for (j
= 0; j
< l
->Number
[i
]; j
++)
2865 if (l
->Entries
[i
][j
] == max_layer
+ SOLDER_LAYER
)
2867 if (l
->Entries
[i
][j
] == max_layer
+ COMPONENT_LAYER
)
2870 for (j
= 0; j
< l
->Number
[i
]; j
++)
2872 if (l
->Entries
[i
][j
] >= 0 && l
->Entries
[i
][j
] < max_layer
)
2874 layer_type
[l
->Entries
[i
][j
]] |= f
;
2875 layer_groupings
[l
->Entries
[i
][j
]] = i
;
2876 if (solder_layer
== -1 && f
== LT_SOLDER
)
2877 solder_layer
= l
->Entries
[i
][j
];
2878 if (component_layer
== -1 && f
== LT_COMPONENT
)
2879 component_layer
= l
->Entries
[i
][j
];
2885 static const char djopt_syntax
[] =
2886 "djopt(debumpify|unjaggy|simple|vianudge|viatrim|orthopull)\n"
2887 "djopt(auto) - all of the above\n" "djopt(miter)";
2889 static const char djopt_help
[] =
2890 "Perform various optimizations on the current board";
2892 /* %start-doc actions djopt
2894 The different types of optimizations change your board in order to
2895 reduce the total trace length and via count.
2900 Looks for U-shaped traces that can be shortened or eliminated.
2903 Looks for corners which could be flipped to eliminate one or more
2904 corners (i.e. jaggy lines become simpler).
2907 Removing uneeded vias, replacing two or more trace segments in a row
2908 with a single segment. This is usually performed automatically after
2909 other optimizations.
2912 Looks for vias where all traces leave in the same direction. Tries to
2913 move via in that direction to eliminate one of the traces (and thus a
2917 Looks for traces that go from via to via, where moving that trace to a
2918 different layer eliminates one or both vias.
2921 Looks for chains of traces all going in one direction, with more
2922 traces orthogonal on one side than on the other. Moves the chain in
2923 that direction, causing a net reduction in trace length, possibly
2924 eliminating traces and/or corners.
2927 Looks for lines that pass through vias, pins, or pads, and splits them
2928 into separate lines so they can be managed separately.
2931 Performs the above options, repeating until no further optimizations
2935 Replaces 90 degree corners with a pair of 45 degree corners, to reduce
2936 RF losses and trace length.
2943 ActionDJopt (int argc
, char **argv
, int x
, int y
)
2945 char *arg
= argc
> 0 ? argv
[0] : 0;
2946 int layn
, saved
= 0;
2950 SwitchDrawingWindow (PCB
->Zoom
, Output
.drawing_area
->window
,
2951 Settings
.ShowSolderSide
, False
);
2959 grok_layer_groups ();
2961 ELEMENT_LOOP (PCB
->Data
);
2964 c
= find_corner (pin
->X
, pin
->Y
, -1);
2971 TEST_FLAG (ONSOLDERFLAG
, pad
) ? solder_layer
: component_layer
;
2972 line_s
*ls
= (line_s
*) malloc (sizeof (line_s
));
2975 ls
->s
= find_corner (pad
->Point1
.X
, pad
->Point1
.Y
, layern
);
2977 ls
->e
= find_corner (pad
->Point2
.X
, pad
->Point2
.Y
, layern
);
2980 ls
->line
= (LineTypePtr
) pad
;
2981 add_line_to_corner (ls
, ls
->s
);
2983 ls
->line
= (LineTypePtr
) pad
;
2984 add_line_to_corner (ls
, ls
->s
);
2985 add_line_to_corner (ls
, ls
->e
);
2990 VIA_LOOP (PCB
->Data
);
2991 /* hace don't mess with vias that have thermals */
2992 /* but then again don't bump into them
2993 if (!TEST_FLAG(ALLTHERMFLAGS, via))
2996 c
= find_corner (via
->X
, via
->Y
, -1);
3002 if (NSTRCMP (arg
, "splitlines") == 0)
3004 if (canonicalize_lines ())
3005 IncrementUndoSerialNumber ();
3009 for (layn
= 0; layn
< max_layer
; layn
++)
3011 LayerType
*layer
= LAYER_PTR (layn
);
3013 for (ln
= 0; ln
< layer
->LineN
; ln
++)
3015 LineType
*l
= &(layer
->Line
[ln
]);
3018 /* don't mess with thermals */
3019 if (TEST_FLAG (USETHERMALFLAG
, l
))
3022 if (l
->Point1
.X
== l
->Point2
.X
&& l
->Point1
.Y
== l
->Point2
.Y
)
3024 RemoveLine (layer
, l
);
3029 ls
= (line_s
*) malloc (sizeof (line_s
));
3032 ls
->s
= find_corner (l
->Point1
.X
, l
->Point1
.Y
, layn
);
3033 ls
->e
= find_corner (l
->Point2
.X
, l
->Point2
.Y
, layn
);
3035 add_line_to_corner (ls
, ls
->s
);
3036 add_line_to_corner (ls
, ls
->e
);
3044 canonicalize_lines ();
3050 if (NSTRCMP (arg
, "debumpify") == 0)
3051 saved
+= debumpify ();
3052 else if (NSTRCMP (arg
, "unjaggy") == 0)
3053 saved
+= unjaggy ();
3054 else if (NSTRCMP (arg
, "simple") == 0)
3055 saved
+= simple_optimizations ();
3056 else if (NSTRCMP (arg
, "vianudge") == 0)
3057 saved
+= vianudge ();
3058 else if (NSTRCMP (arg
, "viatrim") == 0)
3059 saved
+= viatrim ();
3060 else if (NSTRCMP (arg
, "orthopull") == 0)
3061 saved
+= orthopull ();
3062 else if (NSTRCMP (arg
, "auto") == 0)
3063 saved
+= automagic ();
3064 else if (NSTRCMP (arg
, "miter") == 0)
3068 printf ("unknown command: %s\n", arg
);
3076 IncrementUndoSerialNumber ();
3080 HID_Action djopt_action_list
[] = {
3081 {"djopt", 0, ActionDJopt
,
3082 djopt_help
, djopt_syntax
}
3084 {"OptAutoOnly", 0, djopt_set_auto_only
,
3085 djopt_sao_help
, djopt_sao_syntax
}
3088 REGISTER_ACTIONS (djopt_action_list
)