hid/gtk (GL): I think the polygon renderer works in mask mode now
[geda-pcb/pcjc2.git] / src / autoroute.c
blob9ca83f4088103f0e4365bcaba045664d3c08754b
1 /*!
2 * \file src/autoroute.c
4 * \brief Functions used to autoroute nets.
6 * this file, autoroute.c, was written and is
8 * Copyright (c) 2001 C. Scott Ananian
10 * Copyright (c) 2006 harry eaton
12 * Copyright (c) 2009 harry eaton
14 * This file implements a rectangle-expansion router, based on
15 * "A Method for Gridless Routing of Printed Circuit Boards" by
16 * A. C. Finch, K. J. Mackenzie, G. J. Balsdon, and G. Symonds in the
17 * 1985 Proceedings of the 22nd ACM/IEEE Design Automation Conference.
19 * This reference is available from the ACM Digital Library at
20 * http://www.acm.org/dl for those with institutional or personal
21 * access to it. It's also available from your local engineering
22 * library.
24 * The code is much closer to what is described in the paper now,
25 * in that expansion areas can grow from corners and in all directions
26 * at once. Previously, these were emulated with discrete boxes moving
27 * in the cardinal directions. With the new method, there are fewer but
28 * larger expansion boxes that one might do a better job of routing in.
30 * <hr>
32 * <h1><b>Copyright.</b></h1>\n
34 * PCB, interactive printed circuit board design
36 * Copyright (C) 1994,1995,1996 Thomas Nau
38 * Copyright (C) 1998,1999,2000,2001 harry eaton
40 * This program is free software; you can redistribute it and/or modify
41 * it under the terms of the GNU General Public License as published by
42 * the Free Software Foundation; either version 2 of the License, or
43 * (at your option) any later version.
45 * This program is distributed in the hope that it will be useful,
46 * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 * GNU General Public License for more details.
50 * You should have received a copy of the GNU General Public License
51 * along with this program; if not, write to the Free Software
52 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
54 * Contact addresses for paper mail and Email:
55 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
56 * haceaton@aplcomm.jhuapl.edu
60 #define NET_HEAP 1
61 #ifdef HAVE_CONFIG_H
62 #include "config.h"
63 #endif
65 #include "global.h"
67 #include <assert.h>
68 #include <setjmp.h>
70 #include "data.h"
71 #include "macro.h"
72 #include "autoroute.h"
73 #include "box.h"
74 #include "create.h"
75 #include "draw.h"
76 #include "error.h"
77 #include "find.h"
78 #include "heap.h"
79 #include "rtree.h"
80 #include "misc.h"
81 #include "mtspace.h"
82 #include "mymem.h"
83 #include "polygon.h"
84 #include "rats.h"
85 #include "remove.h"
86 #include "thermal.h"
87 #include "undo.h"
88 #include "vector.h"
89 #include "pcb-printf.h"
90 #include "hid_draw.h"
92 #ifdef HAVE_LIBDMALLOC
93 #include <dmalloc.h>
94 #endif
96 /* #defines to enable some debugging output */
98 #define ROUTE_VERBOSE
102 #define ROUTE_DEBUG
103 //#define DEBUG_SHOW_ROUTE_BOXES
104 #define DEBUG_SHOW_EXPANSION_BOXES
105 //#define DEBUG_SHOW_EDGES
106 //#define DEBUG_SHOW_VIA_BOXES
107 #define DEBUG_SHOW_TARGETS
108 #define DEBUG_SHOW_SOURCES
109 //#define DEBUG_SHOW_ZIGZAG
112 static direction_t
113 directionIncrement(direction_t dir)
115 switch(dir)
117 case NORTH:
118 dir = EAST;
119 break;
120 case EAST:
121 dir = SOUTH;
122 break;
123 case SOUTH:
124 dir = WEST;
125 break;
126 case WEST:
127 dir = NE;
128 break;
129 case NE:
130 dir = SE;
131 break;
132 case SE:
133 dir = SW;
134 break;
135 case SW:
136 dir = NW;
137 break;
138 case NW:
139 dir = ALL;
140 break;
141 case ALL:
142 dir = NORTH;
143 break;
145 return dir;
148 #ifdef ROUTE_DEBUG
149 HID_DRAW *ddraw = NULL;
150 static hidGC ar_gc = 0;
151 #endif
153 #define EXPENSIVE 3e28
154 /* round up "half" thicknesses */
155 #define HALF_THICK(x) (((x)+1)/2)
156 /* a styles maximum bloat is its keepaway plus the larger of its via radius
157 * or line half-thickness. */
158 #define BLOAT(style)\
159 ((style)->Keepaway + HALF_THICK((style)->Thick))
160 /* conflict penalty is less for traces laid down during previous pass than
161 * it is for traces already laid down in this pass. */
162 #define CONFLICT_LEVEL(rb)\
163 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
164 HI_CONFLICT : LO_CONFLICT )
165 #define CONFLICT_PENALTY(rb)\
166 ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
167 AutoRouteParameters.ConflictPenalty : \
168 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
169 AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass)
171 #define _NORTH 1
172 #define _EAST 2
173 #define _SOUTH 4
174 #define _WEST 8
176 #define LIST_LOOP(init, which, x) do {\
177 routebox_t *__next_one__ = (init);\
178 x = NULL;\
179 if (!__next_one__)\
180 assert(__next_one__);\
181 else\
182 while (!x || __next_one__ != (init)) {\
183 x = __next_one__;\
184 /* save next one first in case the command modifies or frees it */\
185 __next_one__ = x->which.next
186 #define FOREACH_SUBNET(net, p) do {\
187 routebox_t *_pp_;\
188 /* fail-fast: check subnet_processed flags */\
189 LIST_LOOP(net, same_net, p); \
190 assert(!p->flags.subnet_processed);\
191 END_LOOP;\
192 /* iterate through *distinct* subnets */\
193 LIST_LOOP(net, same_net, p); \
194 if (!p->flags.subnet_processed) {\
195 LIST_LOOP(p, same_subnet, _pp_);\
196 _pp_->flags.subnet_processed=1;\
197 END_LOOP
198 #define END_FOREACH(net, p) \
199 }; \
200 END_LOOP;\
201 /* reset subnet_processed flags */\
202 LIST_LOOP(net, same_net, p); \
203 p->flags.subnet_processed=0;\
204 END_LOOP;\
205 } while (0)
206 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0)
207 /* notes:
208 * all rectangles are assumed to be closed on the top and left and
209 * open on the bottom and right. That is, they include their top-left
210 * corner but don't include their bottom and right edges.
212 * expansion regions are always half-closed. This means that when
213 * tracing paths, you must steer clear of the bottom and right edges.,
214 * because these are not actually in the allowed box.
216 * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by
217 * their particular required keepaway. This simplifies the tree searching.
218 * the "sbox" contains the unbloated box.
220 /* ---------------------------------------------------------------------------
221 * some local types
224 /* enumerated type for conflict levels */
225 typedef enum
226 { NO_CONFLICT = 0, LO_CONFLICT = 1, HI_CONFLICT = 2 }
227 conflict_t;
229 typedef struct routebox_list
231 struct routebox *next, *prev;
232 }routebox_list;
234 typedef enum etype
235 { PAD, PIN, VIA, VIA_SHADOW, LINE, OTHER, EXPANSION_AREA, PLANE, THERMAL }
236 etype;
238 typedef struct routebox
240 BoxType box, sbox;
241 union
243 PadType *pad;
244 PinType *pin;
245 PinType *via;
246 struct routebox *via_shadow; /* points to the via in r-tree which
247 * points to the PinType in the PCB. */
248 LineType *line;
249 void *generic; /* 'other' is polygon, arc, text */
250 struct routebox *expansion_area; /* previous expansion area in search */
252 parent;
253 unsigned short group;
254 unsigned short layer;
255 etype type;
256 struct
258 unsigned nonstraight:1;
259 unsigned fixed:1;
260 /* for searches */
261 unsigned source:1;
262 unsigned target:1;
263 /* rects on same net as source and target don't need clearance areas */
264 unsigned nobloat:1;
265 /* mark circular pins, so that we be sure to connect them up properly */
266 unsigned circular:1;
267 /* we sometimes create routeboxen that don't actually belong to a
268 * r-tree yet -- make sure refcount of homelesss is set properly */
269 unsigned homeless:1;
270 /* was this nonfixed obstacle generated on an odd or even pass? */
271 unsigned is_odd:1;
272 /* fixed route boxes that have already been "routed through" in this
273 * search have their "touched" flag set. */
274 unsigned touched:1;
275 /* this is a status bit for iterating through *different* subnets */
276 unsigned subnet_processed:1;
277 /* some expansion_areas represent via candidates */
278 unsigned is_via:1;
279 /* mark non-straight lines which go from bottom-left to upper-right,
280 * instead of from upper-left to bottom-right. */
281 unsigned bl_to_ur:1;
282 /* mark polygons which are "transparent" for via-placement; that is,
283 * vias through the polygon will automatically be given a keepaway
284 * and will not electrically connect to the polygon. */
285 unsigned clear_poly:1;
286 /* this marks "conflicting" routes that must be torn up to obtain
287 * a correct routing. This flag allows us to return a correct routing
288 * even if the user cancels auto-route after a non-final pass. */
289 unsigned is_bad:1;
290 /* for assertion that 'box' is never changed after creation */
291 unsigned inited:1;
292 /* indicate this expansion ares is a thermal between the pin and plane */
293 unsigned is_thermal;
295 flags;
296 /* indicate the direction an expansion box came from */
297 cost_t cost;
298 CheapPointType cost_point;
299 /* reference count for homeless routeboxes; free when refcount==0 */
300 int refcount;
301 /* when routing with conflicts, we keep a record of what we're
302 * conflicting with.
304 vector_t *conflicts_with;
305 /* route style of the net associated with this routebox */
306 RouteStyleType *style;
307 /* congestion values for the edges of an expansion box */
308 unsigned char n, e, s, w;
309 /* what pass this this track was laid down on */
310 unsigned char pass;
311 /* the direction this came from, if any */
312 direction_t came_from;
313 /* circular lists with connectivity information. */
314 routebox_list same_net, same_subnet, original_subnet, different_net;
315 union {
316 PinType *via;
317 LineType *line;
318 } livedraw_obj;
320 routebox_t;
322 typedef struct routedata
324 /* one rtree per layer *group */
325 rtree_t *layergrouptree[MAX_GROUP]; /* no silkscreen layers here =) */
326 /* root pointer into connectivity information */
327 routebox_t *first_net;
328 /* default routing style */
329 RouteStyleType defaultstyle;
330 /* style structures */
331 RouteStyleType *styles[NUM_STYLES + 1];
332 /* what is the maximum bloat (keepaway+line half-width or
333 * keepaway+via_radius) for any style we've seen? */
334 Coord max_bloat;
335 Coord max_keep;
336 mtspace_t *mtspace;
338 routedata_t;
340 typedef struct edge_struct
342 routebox_t *rb; /* path expansion edges are real routeboxen. */
343 CheapPointType cost_point;
344 cost_t cost_to_point; /* from source */
345 cost_t cost; /* cached edge cost */
346 routebox_t *mincost_target; /* minimum cost from cost_point to any target */
347 vetting_t *work; /* for via search edges */
348 direction_t expand_dir;
349 struct
351 /* this indicates that this 'edge' is a via candidate. */
352 unsigned is_via:1;
353 /* record "conflict level" of via candidates, in case we need to split
354 * them later. */
355 conflict_t via_conflict_level:2;
356 /* when "routing with conflicts", sometimes edge is interior. */
357 unsigned is_interior:1;
358 /* this is a fake edge used to defer searching for via spaces */
359 unsigned via_search:1;
360 /* this is a via edge in a plane where the cost point moves for free */
361 unsigned in_plane:1;
363 flags;
365 edge_t;
367 static struct
369 /* net style parameters */
370 RouteStyleType *style;
371 /* the present bloat */
372 Coord bloat;
373 /* cost parameters */
374 cost_t ViaCost, /* additional "length" cost for using a via */
375 LastConflictPenalty, /* length mult. for routing over last pass' trace */
376 ConflictPenalty, /* length multiplier for routing over another trace */
377 JogPenalty, /* additional "length" cost for changing direction */
378 CongestionPenalty, /* (rational) length multiplier for routing in */
379 NewLayerPenalty, /* penalty for routing on a previously unused layer */
380 MinPenalty; /* smallest Direction Penalty */
381 /* maximum conflict incidence before calling it "no path found" */
382 int hi_conflict;
383 /* are vias allowed? */
384 bool use_vias;
385 /* is this an odd or even pass? */
386 bool is_odd;
387 /* permit conflicts? */
388 bool with_conflicts;
389 /* is this a final "smoothing" pass? */
390 bool is_smoothing;
391 /* rip up nets regardless of conflicts? */
392 bool rip_always;
393 bool last_smooth;
394 unsigned char pass;
396 AutoRouteParameters;
398 struct routeone_state
400 /* heap of all candidate expansion edges */
401 heap_t *workheap;
402 /* information about the best path found so far. */
403 routebox_t *best_path, *best_target;
404 cost_t best_cost;
408 /* ---------------------------------------------------------------------------
409 * some local prototypes
411 static routebox_t *CreateExpansionArea (const BoxType * area, Cardinal group,
412 routebox_t * parent,
413 bool relax_edge_requirements,
414 edge_t * edge);
416 static cost_t edge_cost (const edge_t * e, const cost_t too_big);
417 static void best_path_candidate (struct routeone_state *s,
418 edge_t * e, routebox_t * best_target);
420 static BoxType edge_to_box (const routebox_t * rb, direction_t expand_dir);
422 static void add_or_destroy_edge (struct routeone_state *s, edge_t * e);
424 static void
425 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
426 Cardinal group, Cardinal layer, routebox_t * subnet,
427 bool is_bad);
428 static void ResetSubnet (routebox_t * net);
429 #ifdef ROUTE_DEBUG
430 static int showboxen = -2;
431 static int aabort = 0;
432 static void showroutebox (routebox_t * rb);
433 #endif
435 /* ---------------------------------------------------------------------------
436 * some local identifiers
438 /* group number of groups that hold surface mount pads */
439 static Cardinal front, back;
440 static bool usedGroup[MAX_GROUP];
441 static int x_cost[MAX_GROUP], y_cost[MAX_GROUP];
442 static bool is_layer_group_active[MAX_GROUP];
443 static int ro = 0;
444 static int smoothes = 1;
445 static int passes = 12;
446 static int routing_layers = 0;
447 static float total_wire_length = 0;
448 static int total_via_count = 0;
450 /* assertion helper for routeboxen */
451 #ifndef NDEBUG
452 static int
453 __routebox_is_good (routebox_t * rb)
455 assert (rb && (rb->group < max_group) &&
456 (rb->box.X1 <= rb->box.X2) && (rb->box.Y1 <= rb->box.Y2) &&
457 (rb->flags.homeless ?
458 (rb->box.X1 != rb->box.X2) || (rb->box.Y1 != rb->box.Y2) :
459 (rb->box.X1 != rb->box.X2) && (rb->box.Y1 != rb->box.Y2)));
460 assert ((rb->flags.source ? rb->flags.nobloat : 1) &&
461 (rb->flags.target ? rb->flags.nobloat : 1) &&
462 (rb->flags.homeless ? !rb->flags.touched : rb->refcount == 0) &&
463 (rb->flags.touched ? rb->type != EXPANSION_AREA : 1));
464 assert ((rb->flags.is_odd ? (!rb->flags.fixed) &&
465 (rb->type == VIA || rb->type == VIA_SHADOW || rb->type == LINE
466 || rb->type == PLANE) : 1));
467 assert (rb->flags.clear_poly ?
468 ((rb->type == OTHER || rb->type == PLANE) && rb->flags.fixed
469 && !rb->flags.homeless) : 1);
470 assert (rb->flags.inited);
471 /* run through conflict list showing none are homeless, targets or sources */
472 if (rb->conflicts_with)
474 int i;
475 for (i = 0; i < vector_size (rb->conflicts_with); i++)
477 routebox_t *c = vector_element (rb->conflicts_with, i);
478 assert (!c->flags.homeless && !c->flags.source && !c->flags.target
479 && !c->flags.fixed);
482 assert (rb->style != NULL && rb->style != NULL);
483 assert (rb->type == EXPANSION_AREA
484 || (rb->same_net.next && rb->same_net.prev && rb->same_subnet.next
485 && rb->same_subnet.prev && rb->original_subnet.next
486 && rb->original_subnet.prev && rb->different_net.next
487 && rb->different_net.prev));
488 return 1;
490 static int
491 __edge_is_good (edge_t * e)
493 assert (e && e->rb && __routebox_is_good (e->rb));
494 assert ((e->rb->flags.homeless ? e->rb->refcount > 0 : 1));
495 assert ((0 <= e->expand_dir) && (e->expand_dir < 9)
496 && (e->flags.
497 is_interior ? (e->expand_dir == ALL
498 && e->rb->conflicts_with) : 1));
499 assert ((e->flags.is_via ? e->rb->flags.is_via : 1)
500 && (e->flags.via_conflict_level >= 0
501 && e->flags.via_conflict_level <= 2)
502 && (e->flags.via_conflict_level != 0 ? e->flags.is_via : 1));
503 assert ((e->cost_to_point >= 0) && e->cost >= 0);
504 return 1;
508 no_planes (const BoxType * b, void *cl)
510 routebox_t *rb = (routebox_t *) b;
511 if (rb->type == PLANE)
512 return 0;
513 return 1;
515 #endif /* !NDEBUG */
517 /*---------------------------------------------------------------------
518 * route utility functions.
521 enum boxlist
522 { NET, SUBNET, ORIGINAL, DIFFERENT_NET };
523 static struct routebox_list *
524 __select_list (routebox_t * r, enum boxlist which)
526 assert (r);
527 switch (which)
529 default:
530 assert (0);
531 case NET:
532 return &(r->same_net);
533 case SUBNET:
534 return &(r->same_subnet);
535 case ORIGINAL:
536 return &(r->original_subnet);
537 case DIFFERENT_NET:
538 return &(r->different_net);
541 static void
542 InitLists (routebox_t * r)
544 static enum boxlist all[] =
545 { NET, SUBNET, ORIGINAL, DIFFERENT_NET }
546 , *p;
547 for (p = all; p < all + (sizeof (all) / sizeof (*p)); p++)
549 struct routebox_list *rl = __select_list (r, *p);
550 rl->prev = rl->next = r;
554 static void
555 MergeNets (routebox_t * a, routebox_t * b, enum boxlist which)
557 struct routebox_list *al, *bl, *anl, *bnl;
558 routebox_t *an, *bn;
559 assert (a && b);
560 assert (a != b);
561 assert (a->type != EXPANSION_AREA);
562 assert (b->type != EXPANSION_AREA);
563 al = __select_list (a, which);
564 bl = __select_list (b, which);
565 assert (al && bl);
566 an = al->next;
567 bn = bl->next;
568 assert (an && bn);
569 anl = __select_list (an, which);
570 bnl = __select_list (bn, which);
571 assert (anl && bnl);
572 bl->next = an;
573 anl->prev = b;
574 al->next = bn;
575 bnl->prev = a;
578 static void
579 RemoveFromNet (routebox_t * a, enum boxlist which)
581 struct routebox_list *al, *anl, *apl;
582 routebox_t *an, *ap;
583 assert (a);
584 al = __select_list (a, which);
585 assert (al);
586 an = al->next;
587 ap = al->prev;
588 if (an == a || ap == a)
589 return; /* not on any list */
590 assert (an && ap);
591 anl = __select_list (an, which);
592 apl = __select_list (ap, which);
593 assert (anl && apl);
594 anl->prev = ap;
595 apl->next = an;
596 al->next = al->prev = a;
597 return;
600 static void
601 init_const_box (routebox_t * rb,
602 Coord X1, Coord Y1, Coord X2,
603 Coord Y2, Coord keepaway)
605 BoxType *bp = (BoxType *) & rb->box; /* note discarding const! */
606 assert (!rb->flags.inited);
607 assert (X1 <= X2 && Y1 <= Y2);
608 bp->X1 = X1 - keepaway;
609 bp->Y1 = Y1 - keepaway;
610 bp->X2 = X2 + keepaway;
611 bp->Y2 = Y2 + keepaway;
612 bp = (BoxType *) & rb->sbox;
613 bp->X1 = X1;
614 bp->Y1 = Y1;
615 bp->X2 = X2;
616 bp->Y2 = Y2;
617 rb->flags.inited = 1;
620 static inline BoxType
621 shrink_routebox (const routebox_t * rb)
623 return rb->sbox;
626 static inline cost_t
627 box_area (const BoxType b)
629 cost_t ans = b.X2 - b.X1;
630 return ans * (b.Y2 - b.Y1);
633 static inline CheapPointType
634 closest_point_in_routebox (const CheapPointType * from, const routebox_t * rb)
636 return closest_point_in_box (from, &rb->sbox);
639 static inline bool
640 point_in_shrunk_box (const routebox_t * box, Coord X, Coord Y)
642 BoxType b = shrink_routebox (box);
643 return point_in_box (&b, X, Y);
646 /*---------------------------------------------------------------------
647 * routedata initialization functions.
650 static routebox_t *
651 AddPin (PointerListType layergroupboxes[], PinType *pin, bool is_via,
652 RouteStyleType * style)
654 routebox_t **rbpp, *lastrb = NULL;
655 int i, ht;
656 /* a pin cuts through every layer group */
657 for (i = 0; i < max_group; i++)
659 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[i]);
660 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
661 memset ((void *) *rbpp, 0, sizeof (**rbpp));
662 (*rbpp)->group = i;
663 ht = HALF_THICK (MAX (pin->Thickness, pin->DrillingHole));
664 init_const_box (*rbpp,
665 /*X1 */ pin->X - ht,
666 /*Y1 */ pin->Y - ht,
667 /*X2 */ pin->X + ht,
668 /*Y2 */ pin->Y + ht, style->Keepaway);
669 /* set aux. properties */
670 if (is_via)
672 (*rbpp)->type = VIA;
673 (*rbpp)->parent.via = pin;
675 else
677 (*rbpp)->type = PIN;
678 (*rbpp)->parent.pin = pin;
680 (*rbpp)->flags.fixed = 1;
681 (*rbpp)->came_from = ALL;
682 (*rbpp)->style = style;
683 (*rbpp)->flags.circular = !TEST_FLAG (SQUAREFLAG, pin);
684 /* circular lists */
685 InitLists (*rbpp);
686 /* link together */
687 if (lastrb)
689 MergeNets (*rbpp, lastrb, NET);
690 MergeNets (*rbpp, lastrb, SUBNET);
691 MergeNets (*rbpp, lastrb, ORIGINAL);
693 lastrb = *rbpp;
695 return lastrb;
697 static routebox_t *
698 AddPad (PointerListType layergroupboxes[],
699 ElementType *element, PadType *pad, RouteStyleType * style)
701 Coord halfthick;
702 routebox_t **rbpp;
703 int layergroup = (TEST_FLAG (ONSOLDERFLAG, pad) ? back : front);
704 assert (0 <= layergroup && layergroup < max_group);
705 assert (PCB->LayerGroups.Number[layergroup] > 0);
706 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
707 assert (rbpp);
708 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
709 assert (*rbpp);
710 memset (*rbpp, 0, sizeof (**rbpp));
711 (*rbpp)->group = layergroup;
712 halfthick = HALF_THICK (pad->Thickness);
713 init_const_box (*rbpp,
714 /*X1 */ MIN (pad->Point1.X, pad->Point2.X) - halfthick,
715 /*Y1 */ MIN (pad->Point1.Y, pad->Point2.Y) - halfthick,
716 /*X2 */ MAX (pad->Point1.X, pad->Point2.X) + halfthick,
717 /*Y2 */ MAX (pad->Point1.Y, pad->Point2.Y) + halfthick,
718 style->Keepaway);
719 /* kludge for non-manhattan pads (which are not allowed at present) */
720 if (pad->Point1.X != pad->Point2.X && pad->Point1.Y != pad->Point2.Y)
721 (*rbpp)->flags.nonstraight = 1;
722 /* set aux. properties */
723 (*rbpp)->type = PAD;
724 (*rbpp)->parent.pad = pad;
725 (*rbpp)->flags.fixed = 1;
726 (*rbpp)->came_from = ALL;
727 (*rbpp)->style = style;
728 /* circular lists */
729 InitLists (*rbpp);
730 return *rbpp;
732 static routebox_t *
733 AddLine (PointerListType layergroupboxes[], int layergroup, LineType *line,
734 LineType *ptr, RouteStyleType * style)
736 routebox_t **rbpp;
737 assert (layergroupboxes && line);
738 assert (0 <= layergroup && layergroup < max_group);
739 assert (PCB->LayerGroups.Number[layergroup] > 0);
741 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
742 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
743 memset (*rbpp, 0, sizeof (**rbpp));
744 (*rbpp)->group = layergroup;
745 init_const_box (*rbpp,
746 /*X1 */ MIN (line->Point1.X,
747 line->Point2.X) - HALF_THICK (line->Thickness),
748 /*Y1 */ MIN (line->Point1.Y,
749 line->Point2.Y) - HALF_THICK (line->Thickness),
750 /*X2 */ MAX (line->Point1.X,
751 line->Point2.X) + HALF_THICK (line->Thickness),
752 /*Y2 */ MAX (line->Point1.Y,
753 line->Point2.Y) +
754 HALF_THICK (line->Thickness), style->Keepaway);
755 /* kludge for non-manhattan lines */
756 if (line->Point1.X != line->Point2.X && line->Point1.Y != line->Point2.Y)
758 (*rbpp)->flags.nonstraight = 1;
759 (*rbpp)->flags.bl_to_ur =
760 (MIN (line->Point1.X, line->Point2.X) == line->Point1.X) !=
761 (MIN (line->Point1.Y, line->Point2.Y) == line->Point1.Y);
762 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
763 showroutebox (*rbpp);
764 #endif
766 /* set aux. properties */
767 (*rbpp)->type = LINE;
768 (*rbpp)->parent.line = ptr;
769 (*rbpp)->flags.fixed = 1;
770 (*rbpp)->came_from = ALL;
771 (*rbpp)->style = style;
772 /* circular lists */
773 InitLists (*rbpp);
774 return *rbpp;
776 static routebox_t *
777 AddIrregularObstacle (PointerListType layergroupboxes[],
778 Coord X1, Coord Y1,
779 Coord X2, Coord Y2, Cardinal layergroup,
780 void *parent, RouteStyleType * style)
782 routebox_t **rbpp;
783 Coord keep = style->Keepaway;
784 assert (layergroupboxes && parent);
785 assert (X1 <= X2 && Y1 <= Y2);
786 assert (0 <= layergroup && layergroup < max_group);
787 assert (PCB->LayerGroups.Number[layergroup] > 0);
789 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
790 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
791 memset (*rbpp, 0, sizeof (**rbpp));
792 (*rbpp)->group = layergroup;
793 init_const_box (*rbpp, X1, Y1, X2, Y2, keep);
794 (*rbpp)->flags.nonstraight = 1;
795 (*rbpp)->type = OTHER;
796 (*rbpp)->parent.generic = parent;
797 (*rbpp)->flags.fixed = 1;
798 (*rbpp)->style = style;
799 /* circular lists */
800 InitLists (*rbpp);
801 return *rbpp;
804 static routebox_t *
805 AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
806 PolygonType *polygon, RouteStyleType * style)
808 int is_not_rectangle = 1;
809 int layergroup = GetLayerGroupNumberByNumber (layer);
810 routebox_t *rb;
811 assert (0 <= layergroup && layergroup < max_group);
812 rb = AddIrregularObstacle (layergroupboxes,
813 polygon->BoundingBox.X1,
814 polygon->BoundingBox.Y1,
815 polygon->BoundingBox.X2,
816 polygon->BoundingBox.Y2,
817 layergroup, polygon, style);
818 if (polygon->PointN == 4 &&
819 polygon->HoleIndexN == 0 &&
820 (polygon->Points[0].X == polygon->Points[1].X ||
821 polygon->Points[0].Y == polygon->Points[1].Y) &&
822 (polygon->Points[1].X == polygon->Points[2].X ||
823 polygon->Points[1].Y == polygon->Points[2].Y) &&
824 (polygon->Points[2].X == polygon->Points[3].X ||
825 polygon->Points[2].Y == polygon->Points[3].Y) &&
826 (polygon->Points[3].X == polygon->Points[0].X ||
827 polygon->Points[3].Y == polygon->Points[0].Y))
828 is_not_rectangle = 0;
829 rb->flags.nonstraight = is_not_rectangle;
830 rb->layer = layer;
831 rb->came_from = ALL;
832 if (TEST_FLAG (CLEARPOLYFLAG, polygon))
834 rb->flags.clear_poly = 1;
835 if (!is_not_rectangle)
836 rb->type = PLANE;
838 return rb;
840 static void
841 AddText (PointerListType layergroupboxes[], Cardinal layergroup,
842 TextType *text, RouteStyleType * style)
844 AddIrregularObstacle (layergroupboxes,
845 text->BoundingBox.X1, text->BoundingBox.Y1,
846 text->BoundingBox.X2, text->BoundingBox.Y2,
847 layergroup, text, style);
849 static routebox_t *
850 AddArc (PointerListType layergroupboxes[], Cardinal layergroup,
851 ArcType *arc, RouteStyleType * style)
853 return AddIrregularObstacle (layergroupboxes,
854 arc->BoundingBox.X1, arc->BoundingBox.Y1,
855 arc->BoundingBox.X2, arc->BoundingBox.Y2,
856 layergroup, arc, style);
859 struct rb_info
861 BoxType query;
862 routebox_t *winner;
863 jmp_buf env;
866 static int
867 __found_one_on_lg (const BoxType * box, void *cl)
869 struct rb_info *inf = (struct rb_info *) cl;
870 routebox_t *rb = (routebox_t *) box;
871 BoxType sb;
873 if (rb->flags.nonstraight)
874 return 0;
875 sb = shrink_box (&rb->box, rb->style->Keepaway);
876 if (inf->query.X1 >= sb.X2 || inf->query.X2 <= sb.X1 ||
877 inf->query.Y1 >= sb.Y2 || inf->query.Y2 <= sb.Y1)
878 return 0;
879 inf->winner = rb;
880 if (rb->type == PLANE)
881 return 1; /* keep looking for something smaller if a plane was found */
882 longjmp (inf->env, 1);
883 return 0;
885 static routebox_t *
886 FindRouteBoxOnLayerGroup (routedata_t * rd,
887 Coord X, Coord Y, Cardinal layergroup)
889 struct rb_info info;
890 info.winner = NULL;
891 info.query = point_box (X, Y);
892 if (setjmp (info.env) == 0)
893 r_search (rd->layergrouptree[layergroup], &info.query, NULL,
894 __found_one_on_lg, &info);
895 return info.winner;
898 #ifdef ROUTE_DEBUG_VERBOSE
899 static void
900 DumpRouteBox (routebox_t * rb)
902 pcb_printf ("RB: %#mD-%#mD l%d; ",
903 rb->box.X1, rb->box.Y1, rb->box.X2, rb->box.Y2, (int) rb->group);
904 switch (rb->type)
906 case PAD:
907 printf ("PAD[%s %s] ", rb->parent.pad->Name, rb->parent.pad->Number);
908 break;
909 case PIN:
910 printf ("PIN[%s %s] ", rb->parent.pin->Name, rb->parent.pin->Number);
911 break;
912 case VIA:
913 if (!rb->parent.via)
914 break;
915 printf ("VIA[%s %s] ", rb->parent.via->Name, rb->parent.via->Number);
916 break;
917 case LINE:
918 printf ("LINE ");
919 break;
920 case OTHER:
921 printf ("OTHER ");
922 break;
923 case EXPANSION_AREA:
924 printf ("EXPAREA ");
925 break;
926 default:
927 printf ("UNKNOWN ");
928 break;
930 if (rb->flags.nonstraight)
931 printf ("(nonstraight) ");
932 if (rb->flags.fixed)
933 printf ("(fixed) ");
934 if (rb->flags.source)
935 printf ("(source) ");
936 if (rb->flags.target)
937 printf ("(target) ");
938 if (rb->flags.homeless)
939 printf ("(homeless) ");
940 printf ("\n");
942 #endif
944 static routedata_t *
945 CreateRouteData ()
947 NetListListType Nets;
948 PointerListType layergroupboxes[MAX_GROUP];
949 BoxType bbox;
950 routedata_t *rd;
951 int group, i;
953 /* check which layers are active first */
954 routing_layers = 0;
955 for (group = 0; group < max_group; group++)
957 for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
958 /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */
959 if ((PCB->LayerGroups.Entries[group][i] < max_copper_layer) &&
960 PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)
962 routing_layers++;
963 is_layer_group_active[group] = true;
964 break;
966 else
967 is_layer_group_active[group] = false;
969 /* if via visibility is turned off, don't use them */
970 AutoRouteParameters.use_vias = routing_layers > 1 && PCB->ViaOn;
971 front = GetLayerGroupNumberBySide (TOP_SIDE);
972 back = GetLayerGroupNumberBySide (BOTTOM_SIDE);
973 /* determine preferred routing direction on each group */
974 for (i = 0; i < max_group; i++)
976 if (i != back && i != front)
978 x_cost[i] = (i & 1) ? 2 : 1;
979 y_cost[i] = (i & 1) ? 1 : 2;
981 else if (i == back)
983 x_cost[i] = 4;
984 y_cost[i] = 2;
986 else
988 x_cost[i] = 2;
989 y_cost[i] = 2;
992 /* create routedata */
993 rd = (routedata_t *)malloc (sizeof (*rd));
994 memset ((void *) rd, 0, sizeof (*rd));
995 /* create default style */
996 rd->defaultstyle.Thick = Settings.LineThickness;
997 rd->defaultstyle.Diameter = Settings.ViaThickness;
998 rd->defaultstyle.Hole = Settings.ViaDrillingHole;
999 rd->defaultstyle.Keepaway = Settings.Keepaway;
1000 rd->max_bloat = BLOAT (&rd->defaultstyle);
1001 rd->max_keep = Settings.Keepaway;
1002 /* create styles structures */
1003 bbox.X1 = bbox.Y1 = 0;
1004 bbox.X2 = PCB->MaxWidth;
1005 bbox.Y2 = PCB->MaxHeight;
1006 for (i = 0; i < NUM_STYLES + 1; i++)
1008 RouteStyleType *style =
1009 (i < NUM_STYLES) ? &PCB->RouteStyle[i] : &rd->defaultstyle;
1010 rd->styles[i] = style;
1013 /* initialize pointerlisttype */
1014 for (i = 0; i < max_group; i++)
1016 layergroupboxes[i].Ptr = NULL;
1017 layergroupboxes[i].PtrN = 0;
1018 layergroupboxes[i].PtrMax = 0;
1019 GROUP_LOOP (PCB->Data, i);
1021 if (layer->LineN || layer->ArcN)
1022 usedGroup[i] = true;
1023 else
1024 usedGroup[i] = false;
1026 END_LOOP;
1028 usedGroup[front] = true;
1029 usedGroup[back] = true;
1030 /* add the objects in the netlist first.
1031 * then go and add all other objects that weren't already added
1033 * this saves on searching the trees to find the nets
1035 /* use the DRCFLAG to mark objects as they are entered */
1036 Nets = CollectSubnets (false);
1038 routebox_t *last_net = NULL;
1039 NETLIST_LOOP (&Nets);
1041 routebox_t *last_in_net = NULL;
1042 NET_LOOP (netlist);
1044 routebox_t *last_in_subnet = NULL;
1045 int j;
1047 for (j = 0; j < NUM_STYLES; j++)
1048 if (net->Style == rd->styles[j])
1049 break;
1050 CONNECTION_LOOP (net);
1052 routebox_t *rb = NULL;
1053 SET_FLAG (DRCFLAG, (PinType *) connection->ptr2);
1054 if (connection->type == LINE_TYPE)
1056 LineType *line = (LineType *) connection->ptr2;
1058 /* lines are listed at each end, so skip one */
1059 /* this should probably by a macro named "BUMP_LOOP" */
1060 n--;
1062 /* dice up non-straight lines into many tiny obstacles */
1063 if (line->Point1.X != line->Point2.X
1064 && line->Point1.Y != line->Point2.Y)
1066 LineType fake_line = *line;
1067 Coord dx = (line->Point2.X - line->Point1.X);
1068 Coord dy = (line->Point2.Y - line->Point1.Y);
1069 int segs = MAX (ABS (dx),
1070 ABS (dy)) / (4 * BLOAT (rd->styles[j]) + 1);
1071 int qq;
1072 segs = CLAMP (segs, 1, 32); /* don't go too crazy */
1073 dx /= segs;
1074 dy /= segs;
1075 for (qq = 0; qq < segs - 1; qq++)
1077 fake_line.Point2.X = fake_line.Point1.X + dx;
1078 fake_line.Point2.Y = fake_line.Point1.Y + dy;
1079 if (fake_line.Point2.X == line->Point2.X
1080 && fake_line.Point2.Y == line->Point2.Y)
1081 break;
1082 rb =
1083 AddLine (layergroupboxes, connection->group,
1084 &fake_line, line, rd->styles[j]);
1085 if (last_in_subnet && rb != last_in_subnet)
1086 MergeNets (last_in_subnet, rb, ORIGINAL);
1087 if (last_in_net && rb != last_in_net)
1088 MergeNets (last_in_net, rb, NET);
1089 last_in_subnet = last_in_net = rb;
1090 fake_line.Point1 = fake_line.Point2;
1092 fake_line.Point2 = line->Point2;
1093 rb =
1094 AddLine (layergroupboxes, connection->group, &fake_line,
1095 line, rd->styles[j]);
1097 else
1099 rb =
1100 AddLine (layergroupboxes, connection->group, line, line,
1101 rd->styles[j]);
1104 else
1105 switch (connection->type)
1107 case PAD_TYPE:
1108 rb =
1109 AddPad (layergroupboxes, (ElementType *)connection->ptr1,
1110 (PadType *)connection->ptr2, rd->styles[j]);
1111 break;
1112 case PIN_TYPE:
1113 rb =
1114 AddPin (layergroupboxes, (PinType *)connection->ptr2, false,
1115 rd->styles[j]);
1116 break;
1117 case VIA_TYPE:
1118 rb =
1119 AddPin (layergroupboxes, (PinType *)connection->ptr2, true,
1120 rd->styles[j]);
1121 break;
1122 case POLYGON_TYPE:
1123 rb =
1124 AddPolygon (layergroupboxes,
1125 GetLayerNumber (PCB->Data, (LayerType *)connection->ptr1),
1126 (struct polygon_st *)connection->ptr2, rd->styles[j]);
1127 break;
1129 assert (rb);
1130 /* update circular connectivity lists */
1131 if (last_in_subnet && rb != last_in_subnet)
1132 MergeNets (last_in_subnet, rb, ORIGINAL);
1133 if (last_in_net && rb != last_in_net)
1134 MergeNets (last_in_net, rb, NET);
1135 last_in_subnet = last_in_net = rb;
1136 rd->max_bloat = MAX (rd->max_bloat, BLOAT (rb->style));
1137 rd->max_keep = MAX (rd->max_keep, rb->style->Keepaway);
1139 END_LOOP;
1141 END_LOOP;
1142 if (last_net && last_in_net)
1143 MergeNets (last_net, last_in_net, DIFFERENT_NET);
1144 last_net = last_in_net;
1146 END_LOOP;
1147 rd->first_net = last_net;
1149 FreeNetListListMemory (&Nets);
1151 /* reset all nets to "original" connectivity (which we just set) */
1153 routebox_t *net;
1154 LIST_LOOP (rd->first_net, different_net, net);
1155 ResetSubnet (net);
1156 END_LOOP;
1159 /* add pins and pads of elements */
1160 ALLPIN_LOOP (PCB->Data);
1162 if (TEST_FLAG (DRCFLAG, pin))
1163 CLEAR_FLAG (DRCFLAG, pin);
1164 else
1165 AddPin (layergroupboxes, pin, false, rd->styles[NUM_STYLES]);
1167 ENDALL_LOOP;
1168 ALLPAD_LOOP (PCB->Data);
1170 if (TEST_FLAG (DRCFLAG, pad))
1171 CLEAR_FLAG (DRCFLAG, pad);
1172 else
1173 AddPad (layergroupboxes, element, pad, rd->styles[NUM_STYLES]);
1175 ENDALL_LOOP;
1176 /* add all vias */
1177 VIA_LOOP (PCB->Data);
1179 if (TEST_FLAG (DRCFLAG, via))
1180 CLEAR_FLAG (DRCFLAG, via);
1181 else
1182 AddPin (layergroupboxes, via, true, rd->styles[NUM_STYLES]);
1184 END_LOOP;
1186 for (i = 0; i < max_copper_layer; i++)
1188 int layergroup = GetLayerGroupNumberByNumber (i);
1189 /* add all (non-rat) lines */
1190 LINE_LOOP (LAYER_PTR (i));
1192 if (TEST_FLAG (DRCFLAG, line))
1194 CLEAR_FLAG (DRCFLAG, line);
1195 continue;
1197 /* dice up non-straight lines into many tiny obstacles */
1198 if (line->Point1.X != line->Point2.X
1199 && line->Point1.Y != line->Point2.Y)
1201 LineType fake_line = *line;
1202 Coord dx = (line->Point2.X - line->Point1.X);
1203 Coord dy = (line->Point2.Y - line->Point1.Y);
1204 int segs = MAX (ABS (dx), ABS (dy)) / (4 * rd->max_bloat + 1);
1205 int qq;
1206 segs = CLAMP (segs, 1, 32); /* don't go too crazy */
1207 dx /= segs;
1208 dy /= segs;
1209 for (qq = 0; qq < segs - 1; qq++)
1211 fake_line.Point2.X = fake_line.Point1.X + dx;
1212 fake_line.Point2.Y = fake_line.Point1.Y + dy;
1213 if (fake_line.Point2.X == line->Point2.X
1214 && fake_line.Point2.Y == line->Point2.Y)
1215 break;
1216 AddLine (layergroupboxes, layergroup, &fake_line, line,
1217 rd->styles[NUM_STYLES]);
1218 fake_line.Point1 = fake_line.Point2;
1220 fake_line.Point2 = line->Point2;
1221 AddLine (layergroupboxes, layergroup, &fake_line, line,
1222 rd->styles[NUM_STYLES]);
1224 else
1226 AddLine (layergroupboxes, layergroup, line, line,
1227 rd->styles[NUM_STYLES]);
1230 END_LOOP;
1231 /* add all polygons */
1232 POLYGON_LOOP (LAYER_PTR (i));
1234 if (TEST_FLAG (DRCFLAG, polygon))
1235 CLEAR_FLAG (DRCFLAG, polygon);
1236 else
1237 AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]);
1239 END_LOOP;
1240 /* add all copper text */
1241 TEXT_LOOP (LAYER_PTR (i));
1243 AddText (layergroupboxes, layergroup, text, rd->styles[NUM_STYLES]);
1245 END_LOOP;
1246 /* add all arcs */
1247 ARC_LOOP (LAYER_PTR (i));
1249 AddArc (layergroupboxes, layergroup, arc, rd->styles[NUM_STYLES]);
1251 END_LOOP;
1254 /* create r-trees from pointer lists */
1255 for (i = 0; i < max_group; i++)
1257 /* create the r-tree */
1258 rd->layergrouptree[i] =
1259 r_create_tree ((const BoxType **) layergroupboxes[i].Ptr,
1260 layergroupboxes[i].PtrN, 1);
1263 if (AutoRouteParameters.use_vias)
1265 rd->mtspace = mtspace_create ();
1267 /* create "empty-space" structures for via placement (now that we know
1268 * appropriate keepaways for all the fixed elements) */
1269 for (i = 0; i < max_group; i++)
1271 POINTER_LOOP (&layergroupboxes[i]);
1273 routebox_t *rb = (routebox_t *) * ptr;
1274 if (!rb->flags.clear_poly)
1275 mtspace_add (rd->mtspace, &rb->box, FIXED, rb->style->Keepaway);
1277 END_LOOP;
1280 /* free pointer lists */
1281 for (i = 0; i < max_group; i++)
1282 FreePointerListMemory (&layergroupboxes[i]);
1283 /* done! */
1284 return rd;
1287 void
1288 DestroyRouteData (routedata_t ** rd)
1290 int i;
1291 for (i = 0; i < max_group; i++)
1292 r_destroy_tree (&(*rd)->layergrouptree[i]);
1293 if (AutoRouteParameters.use_vias)
1294 mtspace_destroy (&(*rd)->mtspace);
1295 free (*rd);
1296 *rd = NULL;
1299 /*-----------------------------------------------------------------
1300 * routebox reference counting.
1304 * \brief Increment the reference count on a routebox.
1306 static void
1307 RB_up_count (routebox_t * rb)
1309 assert (rb->flags.homeless);
1310 rb->refcount++;
1314 * \brief Decrement the reference count on a routebox, freeing if this
1315 * box becomes unused.
1317 static void
1318 RB_down_count (routebox_t * rb)
1320 assert (rb->type == EXPANSION_AREA);
1321 assert (rb->flags.homeless);
1322 assert (rb->refcount > 0);
1323 if (--rb->refcount == 0)
1325 if (rb->parent.expansion_area->flags.homeless)
1326 RB_down_count (rb->parent.expansion_area);
1327 free (rb);
1331 /*-----------------------------------------------------------------
1332 * Rectangle-expansion routing code.
1335 static void
1336 ResetSubnet (routebox_t * net)
1338 routebox_t *rb;
1339 /* reset connectivity of everything on this net */
1340 LIST_LOOP (net, same_net, rb);
1341 rb->same_subnet = rb->original_subnet;
1342 END_LOOP;
1345 static inline cost_t
1346 cost_to_point_on_layer (const CheapPointType * p1,
1347 const CheapPointType * p2, Cardinal point_layer)
1349 cost_t x_dist = p1->X - p2->X, y_dist = p1->Y - p2->Y, r;
1350 x_dist *= x_cost[point_layer];
1351 y_dist *= y_cost[point_layer];
1352 /* cost is proportional to orthogonal distance. */
1353 r = ABS (x_dist) + ABS (y_dist);
1354 if (p1->X != p2->X && p1->Y != p2->Y)
1355 r += AutoRouteParameters.JogPenalty;
1356 return r;
1359 static cost_t
1360 cost_to_point (const CheapPointType * p1, Cardinal point_layer1,
1361 const CheapPointType * p2, Cardinal point_layer2)
1363 cost_t r = cost_to_point_on_layer (p1, p2, point_layer1);
1364 /* apply via cost penalty if layers differ */
1365 if (point_layer1 != point_layer2)
1366 r += AutoRouteParameters.ViaCost;
1367 return r;
1371 * \brief Return the minimum *cost* from a point to a box on any layer.
1373 * It's safe to return a smaller than minimum cost.
1375 static cost_t
1376 cost_to_layerless_box (const CheapPointType * p, Cardinal point_layer,
1377 const BoxType * b)
1379 CheapPointType p2 = closest_point_in_box (p, b);
1380 register cost_t c1, c2;
1382 c1 = p2.X - p->X;
1383 c2 = p2.Y - p->Y;
1385 c1 = ABS (c1);
1386 c2 = ABS (c2);
1387 if (c1 < c2)
1388 return c1 * AutoRouteParameters.MinPenalty + c2;
1389 else
1390 return c2 * AutoRouteParameters.MinPenalty + c1;
1394 * \brief Get to actual pins/pad target coordinates.
1396 bool
1397 TargetPoint (CheapPointType * nextpoint, const routebox_t * target)
1399 if (target->type == PIN)
1401 nextpoint->X = target->parent.pin->X;
1402 nextpoint->Y = target->parent.pin->Y;
1403 return true;
1405 else if (target->type == PAD)
1407 if (abs (target->parent.pad->Point1.X - nextpoint->X) <
1408 abs (target->parent.pad->Point2.X - nextpoint->X))
1409 nextpoint->X = target->parent.pad->Point1.X;
1410 else
1411 nextpoint->X = target->parent.pad->Point2.X;
1412 if (abs (target->parent.pad->Point1.Y - nextpoint->Y) <
1413 abs (target->parent.pad->Point2.Y - nextpoint->Y))
1414 nextpoint->Y = target->parent.pad->Point1.Y;
1415 else
1416 nextpoint->Y = target->parent.pad->Point2.Y;
1417 return true;
1419 else
1421 nextpoint->X = CENTER_X (target->sbox);
1422 nextpoint->Y = CENTER_Y (target->sbox);
1424 return false;
1428 * \brief Return the *minimum cost* from a point to a route box,
1429 * including possible via costs if the route box is on a different
1430 * layer.
1432 * Assume routbox is bloated unless it is an expansion area.
1434 static cost_t
1435 cost_to_routebox (const CheapPointType * p, Cardinal point_layer,
1436 const routebox_t * rb)
1438 register cost_t trial = 0;
1439 CheapPointType p2 = closest_point_in_routebox (p, rb);
1440 if (!usedGroup[point_layer] || !usedGroup[rb->group])
1441 trial = AutoRouteParameters.NewLayerPenalty;
1442 if ((p2.X - p->X) * (p2.Y - p->Y) != 0)
1443 trial += AutoRouteParameters.JogPenalty;
1444 /* special case for defered via searching */
1445 if (point_layer > max_group || point_layer == rb->group)
1446 return trial + ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
1447 /* if this target is only a via away, then the via is cheaper than the congestion */
1448 if (p->X == p2.X && p->Y == p2.Y)
1449 return trial + 1;
1450 trial += AutoRouteParameters.ViaCost;
1451 trial += ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
1452 return trial;
1456 static BoxType
1457 bloat_routebox (routebox_t * rb)
1459 BoxType r;
1460 Coord keepaway;
1461 assert (__routebox_is_good (rb));
1463 if (rb->flags.nobloat)
1464 return rb->sbox;
1466 /* Obstacle exclusion zones get bloated by the larger of
1467 * the two required clearances plus half the track width.
1469 keepaway = MAX (AutoRouteParameters.style->Keepaway, rb->style->Keepaway);
1470 r = bloat_box (&rb->sbox, keepaway +
1471 HALF_THICK (AutoRouteParameters.style->Thick));
1472 return r;
1476 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1479 * \brief Makes a line on the solder layer silk surrounding the box.
1481 void
1482 showbox (BoxType b, Dimension thickness, int group)
1484 LineType *line;
1485 LayerType *SLayer = LAYER_PTR (group);
1486 if (showboxen < -1)
1487 return;
1488 if (showboxen != -1 && showboxen != group)
1489 return;
1491 if (ddraw != NULL)
1493 hid_draw_set_line_width (ar_gc, thickness);
1494 hid_draw_set_line_cap (ar_gc, Trace_Cap);
1495 hid_draw_set_color (ar_gc, SLayer->Color);
1497 hid_draw_line (ar_gc, b.X1, b.Y1, b.X2, b.Y1);
1498 hid_draw_line (ar_gc, b.X1, b.Y2, b.X2, b.Y2);
1499 hid_draw_line (ar_gc, b.X1, b.Y1, b.X1, b.Y2);
1500 hid_draw_line (ar_gc, b.X2, b.Y1, b.X2, b.Y2);
1503 #if 1
1504 if (b.Y1 == b.Y2 || b.X1 == b.X2)
1505 thickness = 5;
1506 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1507 b.X1, b.Y1, b.X2, b.Y1, thickness, 0,
1508 MakeFlags (0));
1509 AddObjectToCreateUndoList (LINE_TYPE,
1510 LAYER_PTR (top_silk_layer), line,
1511 line);
1512 if (b.Y1 != b.Y2)
1514 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1515 b.X1, b.Y2, b.X2, b.Y2, thickness, 0,
1516 MakeFlags (0));
1517 AddObjectToCreateUndoList (LINE_TYPE,
1518 LAYER_PTR (bottom_silk_layer),
1519 line, line);
1521 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1522 b.X1, b.Y1, b.X1, b.Y2, thickness, 0,
1523 MakeFlags (0));
1524 AddObjectToCreateUndoList (LINE_TYPE,
1525 LAYER_PTR (top_silk_layer), line,
1526 line);
1527 if (b.X1 != b.X2)
1529 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1530 b.X2, b.Y1, b.X2, b.Y2, thickness, 0,
1531 MakeFlags (0));
1532 AddObjectToCreateUndoList (LINE_TYPE,
1533 LAYER_PTR (top_silk_layer),
1534 line, line);
1536 #endif
1538 #endif
1540 #if defined(ROUTE_DEBUG)
1541 static void
1542 showedge (edge_t * e)
1544 BoxType *b = (BoxType *) e->rb;
1546 if (ddraw == NULL)
1547 return;
1549 hid_draw_set_line_cap (ar_gc, Trace_Cap);
1550 hid_draw_set_line_width (ar_gc, 1);
1551 hid_draw_set_color (ar_gc, Settings.MaskColor);
1553 switch (e->expand_dir)
1555 case NORTH:
1556 hid_draw_line (ar_gc, b->X1, b->Y1, b->X2, b->Y1);
1557 break;
1558 case SOUTH:
1559 hid_draw_line (ar_gc, b->X1, b->Y2, b->X2, b->Y2);
1560 break;
1561 case WEST:
1562 hid_draw_line (ar_gc, b->X1, b->Y1, b->X1, b->Y2);
1563 break;
1564 case EAST:
1565 hid_draw_line (ar_gc, b->X2, b->Y1, b->X2, b->Y2);
1566 break;
1567 default:
1568 break;
1571 #endif
1573 #if defined(ROUTE_DEBUG)
1574 static void
1575 showroutebox (routebox_t * rb)
1577 showbox (rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1),
1578 rb->flags.is_via ? top_silk_layer : rb->group);
1580 #endif
1583 * \brief Return a "parent" of this edge which immediately precedes it
1584 * in the route.
1586 static routebox_t *
1587 route_parent (routebox_t * rb)
1589 while (rb->flags.homeless && !rb->flags.is_via && !rb->flags.is_thermal)
1591 assert (rb->type == EXPANSION_AREA);
1592 rb = rb->parent.expansion_area;
1593 assert (rb);
1595 return rb;
1598 static vector_t *
1599 path_conflicts (routebox_t * rb, routebox_t * conflictor, bool branch)
1601 if (branch)
1602 rb->conflicts_with = vector_duplicate (rb->conflicts_with);
1603 else if (!rb->conflicts_with)
1604 rb->conflicts_with = vector_create ();
1605 vector_append (rb->conflicts_with, conflictor);
1606 return rb->conflicts_with;
1610 * \brief Touch everything (except fixed) on each net found
1611 * in the conflicts vector. If the vector is different
1612 * from the last one touched, untouch the last batch
1613 * and touch the new one. Always call with touch=1
1614 * (except for recursive call). Call with NULL, 1 to
1615 * clear the last batch touched.
1617 * Touched items become invisible to current path
1618 * so we don't encounter the same conflictor more
1619 * than once.
1621 static void
1622 touch_conflicts (vector_t * conflicts, int touch)
1624 static vector_t *last = NULL;
1625 static int last_size = 0;
1626 int i, n;
1627 i = 0;
1628 if (touch)
1630 if (last && conflicts != last)
1631 touch_conflicts (last, 0);
1632 if (!conflicts)
1633 return;
1634 last = conflicts;
1635 i = last_size;
1637 n = vector_size (conflicts);
1638 for (; i < n; i++)
1640 routebox_t *rb = (routebox_t *) vector_element (conflicts, i);
1641 routebox_t *p;
1642 LIST_LOOP (rb, same_net, p);
1643 if (!p->flags.fixed)
1644 p->flags.touched = touch;
1645 END_LOOP;
1647 if (!touch)
1649 last = NULL;
1650 last_size = 0;
1652 else
1653 last_size = n;
1657 * \brief Return a "parent" of this edge which resides in a r-tree
1658 * somewhere.
1660 * Actually, this "parent" *may* be a via box, which doesn't live in
1661 * a r-tree.
1663 static routebox_t *
1664 nonhomeless_parent (routebox_t * rb)
1666 return route_parent (rb);
1670 * \brief Some routines to find the minimum *cost* from a cost point to
1671 * a target (any target).
1673 struct mincost_target_closure
1675 const CheapPointType *CostPoint;
1676 Cardinal CostPointLayer;
1677 routebox_t *nearest;
1678 cost_t nearest_cost;
1680 static int
1681 __region_within_guess (const BoxType * region, void *cl)
1683 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1684 cost_t cost_to_region;
1685 if (mtc->nearest == NULL)
1686 return 1;
1687 cost_to_region =
1688 cost_to_layerless_box (mtc->CostPoint, mtc->CostPointLayer, region);
1689 assert (cost_to_region >= 0);
1690 /* if no guess yet, all regions are "close enough" */
1691 /* note that cost is *strictly more* than minimum distance, so we'll
1692 * always search a region large enough. */
1693 return (cost_to_region < mtc->nearest_cost);
1695 static int
1696 __found_new_guess (const BoxType * box, void *cl)
1698 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1699 routebox_t *guess = (routebox_t *) box;
1700 cost_t cost_to_guess =
1701 cost_to_routebox (mtc->CostPoint, mtc->CostPointLayer, guess);
1702 assert (cost_to_guess >= 0);
1703 /* if this is cheaper than previous guess... */
1704 if (cost_to_guess < mtc->nearest_cost)
1706 mtc->nearest = guess;
1707 mtc->nearest_cost = cost_to_guess; /* this is our new guess! */
1708 return 1;
1710 else
1711 return 0; /* not less expensive than our last guess */
1715 * \brief .
1717 * \c target_guess is our guess at what the nearest target is, or
1718 * \c NULL if we just plum don't have a clue.
1720 static routebox_t *
1721 mincost_target_to_point (const CheapPointType * CostPoint,
1722 Cardinal CostPointLayer,
1723 rtree_t * targets, routebox_t * target_guess)
1725 struct mincost_target_closure mtc;
1726 assert (target_guess == NULL || target_guess->flags.target); /* this is a target, right? */
1727 mtc.CostPoint = CostPoint;
1728 mtc.CostPointLayer = CostPointLayer;
1729 mtc.nearest = target_guess;
1730 if (mtc.nearest)
1731 mtc.nearest_cost =
1732 cost_to_routebox (mtc.CostPoint, mtc.CostPointLayer, mtc.nearest);
1733 else
1734 mtc.nearest_cost = EXPENSIVE;
1735 r_search (targets, NULL, __region_within_guess, __found_new_guess, &mtc);
1736 assert (mtc.nearest != NULL && mtc.nearest_cost >= 0);
1737 assert (mtc.nearest->flags.target); /* this is a target, right? */
1738 return mtc.nearest;
1742 * \brief Create edge from field values.
1744 * mincost_target_guess can be \c NULL .
1746 static edge_t *
1747 CreateEdge (routebox_t * rb,
1748 Coord CostPointX, Coord CostPointY,
1749 cost_t cost_to_point,
1750 routebox_t * mincost_target_guess,
1751 direction_t expand_dir, rtree_t * targets)
1753 edge_t *e;
1754 assert (__routebox_is_good (rb));
1755 e = (edge_t *)malloc (sizeof (*e));
1756 memset ((void *) e, 0, sizeof (*e));
1757 assert (e);
1758 e->rb = rb;
1759 if (rb->flags.homeless)
1760 RB_up_count (rb);
1761 e->cost_point.X = CostPointX;
1762 e->cost_point.Y = CostPointY;
1763 e->cost_to_point = cost_to_point;
1764 e->flags.via_search = 0;
1765 /* if this edge is created in response to a target, use it */
1766 if (targets)
1767 e->mincost_target =
1768 mincost_target_to_point (&e->cost_point, rb->group,
1769 targets, mincost_target_guess);
1770 else
1771 e->mincost_target = mincost_target_guess;
1772 e->expand_dir = expand_dir;
1773 assert (e->rb && e->mincost_target); /* valid edge? */
1774 assert (!e->flags.is_via || e->expand_dir == ALL);
1775 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1776 #if 0
1777 assert (rb->type == PLANE || rb->conflicts_with != NULL || rb->flags.is_via
1778 || rb->flags.is_thermal
1779 || ((expand_dir == NORTH || expand_dir == SOUTH) ? rb->sbox.X1 <=
1780 CostPointX && CostPointX < rb->sbox.X2
1781 && CostPointY == (expand_dir ==
1782 NORTH ? rb->sbox.Y1 : rb->sbox.Y2 - 1) :
1783 /* expand_dir==EAST || expand_dir==WEST */
1784 rb->sbox.Y1 <= CostPointY && CostPointY < rb->sbox.Y2 &&
1785 CostPointX == (expand_dir ==
1786 EAST ? rb->sbox.X2 - 1 : rb->sbox.X1)));
1787 #endif
1788 assert (__edge_is_good (e));
1789 /* done */
1790 return e;
1794 * \brief Create edge, using previous edge to fill in defaults.
1796 * Most of the work here is in determining a new cost point.
1798 static edge_t *
1799 CreateEdge2 (routebox_t * rb, direction_t expand_dir,
1800 edge_t * previous_edge, rtree_t * targets, routebox_t * guess)
1802 BoxType thisbox;
1803 CheapPointType thiscost, prevcost;
1804 cost_t d;
1806 assert (rb && previous_edge);
1807 /* okay, find cheapest costpoint to costpoint of previous edge */
1808 thisbox = edge_to_box (rb, expand_dir);
1809 prevcost = previous_edge->cost_point;
1810 /* find point closest to target */
1811 thiscost = closest_point_in_box (&prevcost, &thisbox);
1812 /* compute cost-to-point */
1813 d = cost_to_point_on_layer (&prevcost, &thiscost, rb->group);
1814 /* add in jog penalty */
1815 if (previous_edge->expand_dir != expand_dir)
1816 d += AutoRouteParameters.JogPenalty;
1817 /* okay, new edge! */
1818 return CreateEdge (rb, thiscost.X, thiscost.Y,
1819 previous_edge->cost_to_point + d,
1820 guess ? guess : previous_edge->mincost_target,
1821 expand_dir, targets);
1825 * \brief Create via edge, using previous edge to fill in defaults.
1827 static edge_t *
1828 CreateViaEdge (const BoxType * area, Cardinal group,
1829 routebox_t * parent, edge_t * previous_edge,
1830 conflict_t to_site_conflict,
1831 conflict_t through_site_conflict, rtree_t * targets)
1833 routebox_t *rb;
1834 CheapPointType costpoint;
1835 cost_t d;
1836 edge_t *ne;
1837 cost_t scale[3];
1839 scale[0] = 1;
1840 scale[1] = AutoRouteParameters.LastConflictPenalty;
1841 scale[2] = AutoRouteParameters.ConflictPenalty;
1843 assert (box_is_good (area));
1844 assert (AutoRouteParameters.with_conflicts ||
1845 (to_site_conflict == NO_CONFLICT &&
1846 through_site_conflict == NO_CONFLICT));
1847 rb = CreateExpansionArea (area, group, parent, true, previous_edge);
1848 rb->flags.is_via = 1;
1849 rb->came_from = ALL;
1850 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1851 showroutebox (rb);
1852 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1853 /* for planes, choose a point near the target */
1854 if (previous_edge->flags.in_plane)
1856 routebox_t *target;
1857 CheapPointType pnt;
1858 /* find a target near this via box */
1859 pnt.X = CENTER_X (*area);
1860 pnt.Y = CENTER_Y (*area);
1861 target = mincost_target_to_point (&pnt, rb->group,
1862 targets,
1863 previous_edge->mincost_target);
1864 /* now find point near the target */
1865 pnt.X = CENTER_X (target->box);
1866 pnt.Y = CENTER_Y (target->box);
1867 costpoint = closest_point_in_routebox (&pnt, rb);
1868 /* we moved from the previous cost point through the plane which is free travel */
1870 (scale[through_site_conflict] *
1871 cost_to_point (&costpoint, group, &costpoint,
1872 previous_edge->rb->group));
1873 ne =
1874 CreateEdge (rb, costpoint.X, costpoint.Y,
1875 previous_edge->cost_to_point + d, target, ALL, NULL);
1876 ne->mincost_target = target;
1878 else
1880 routebox_t *target;
1881 target = previous_edge->mincost_target;
1882 costpoint = closest_point_in_routebox (&previous_edge->cost_point, rb);
1884 (scale[to_site_conflict] *
1885 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1886 previous_edge->rb->group)) +
1887 (scale[through_site_conflict] *
1888 cost_to_point (&costpoint, group, &costpoint,
1889 previous_edge->rb->group));
1890 /* if the target is just this via away, then this via is cheaper */
1891 if (target->group == group &&
1892 point_in_shrunk_box (target, costpoint.X, costpoint.Y))
1893 d -= AutoRouteParameters.ViaCost / 2;
1894 ne =
1895 CreateEdge (rb, costpoint.X, costpoint.Y,
1896 previous_edge->cost_to_point + d,
1897 previous_edge->mincost_target, ALL, targets);
1899 ne->flags.is_via = 1;
1900 ne->flags.via_conflict_level = to_site_conflict;
1901 assert (__edge_is_good (ne));
1902 return ne;
1906 * \brief Create "interior" edge for routing with conflicts.
1908 * Presently once we "jump inside" the conflicting object
1909 * we consider it a routing highway to travel inside since
1910 * it will become available if the conflict is elliminated.
1911 * That is why we ignore the interior_edge argument.
1913 static edge_t *
1914 CreateEdgeWithConflicts (const BoxType * interior_edge,
1915 routebox_t * container, edge_t * previous_edge,
1916 cost_t cost_penalty_to_box, rtree_t * targets)
1918 routebox_t *rb;
1919 CheapPointType costpoint;
1920 cost_t d;
1921 edge_t *ne;
1922 assert (interior_edge && container && previous_edge && targets);
1923 assert (!container->flags.homeless);
1924 assert (AutoRouteParameters.with_conflicts);
1925 assert (container->flags.touched == 0);
1926 assert (previous_edge->rb->group == container->group);
1927 /* use the caller's idea of what this box should be */
1928 rb =
1929 CreateExpansionArea (interior_edge, previous_edge->rb->group,
1930 previous_edge->rb, true, previous_edge);
1931 path_conflicts (rb, container, true); /* crucial! */
1932 costpoint =
1933 closest_point_in_box (&previous_edge->cost_point, interior_edge);
1935 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1936 previous_edge->rb->group);
1937 d *= cost_penalty_to_box;
1938 d += previous_edge->cost_to_point;
1939 ne = CreateEdge (rb, costpoint.X, costpoint.Y, d, NULL, ALL, targets);
1940 ne->flags.is_interior = 1;
1941 assert (__edge_is_good (ne));
1942 return ne;
1945 static void
1946 KillEdge (void *edge)
1948 edge_t *e = (edge_t *) edge;
1949 assert (e);
1950 if (e->rb->flags.homeless)
1951 RB_down_count (e->rb);
1952 if (e->flags.via_search)
1953 mtsFreeWork (&e->work);
1954 free (e);
1957 static void
1958 DestroyEdge (edge_t ** e)
1960 assert (e && *e);
1961 KillEdge (*e);
1962 *e = NULL;
1966 * \brief Cost function for an edge.
1968 static cost_t
1969 edge_cost (const edge_t * e, const cost_t too_big)
1971 cost_t penalty = e->cost_to_point;
1972 if (e->rb->flags.is_thermal || e->rb->type == PLANE)
1973 return penalty; /* thermals are cheap */
1974 if (penalty > too_big)
1975 return penalty;
1977 /* cost_to_routebox adds in our via correction, too. */
1978 return penalty +
1979 cost_to_routebox (&e->cost_point, e->rb->group, e->mincost_target);
1983 * \brief Given an edge of a box, return a box containing exactly the
1984 * points on that edge.
1986 * Note that the return box is treated as closed; that is, the bottom
1987 * and right "edges" consist of points (just barely) not in the
1988 * (half-open) box.
1990 static BoxType
1991 edge_to_box (const routebox_t * rb, direction_t expand_dir)
1993 BoxType b = shrink_routebox (rb);
1994 /* narrow box down to just the appropriate edge */
1995 switch (expand_dir)
1997 case NORTH:
1998 b.Y2 = b.Y1 + 1;
1999 break;
2000 case EAST:
2001 b.X1 = b.X2 - 1;
2002 break;
2003 case SOUTH:
2004 b.Y1 = b.Y2 - 1;
2005 break;
2006 case WEST:
2007 b.X2 = b.X1 + 1;
2008 break;
2009 default:
2010 assert (0);
2012 /* done! */
2013 return b;
2016 struct broken_boxes
2018 BoxType left, center, right;
2019 bool is_valid_left, is_valid_center, is_valid_right;
2022 static struct broken_boxes
2023 break_box_edge (const BoxType * original, direction_t which_edge,
2024 routebox_t * breaker)
2026 BoxType origbox, breakbox;
2027 struct broken_boxes result;
2029 assert (original && breaker);
2031 origbox = *original;
2032 breakbox = bloat_routebox (breaker);
2033 ROTATEBOX_TO_NORTH (origbox, which_edge);
2034 ROTATEBOX_TO_NORTH (breakbox, which_edge);
2035 result.right.Y1 = result.center.Y1 = result.left.Y1 = origbox.Y1;
2036 result.right.Y2 = result.center.Y2 = result.left.Y2 = origbox.Y1 + 1;
2037 /* validity of breaker is not important because the boxes are marked invalid */
2038 //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1);
2039 /* left edge piece */
2040 result.left.X1 = origbox.X1;
2041 result.left.X2 = breakbox.X1;
2042 /* center (ie blocked) edge piece */
2043 result.center.X1 = MAX (breakbox.X1, origbox.X1);
2044 result.center.X2 = MIN (breakbox.X2, origbox.X2);
2045 /* right edge piece */
2046 result.right.X1 = breakbox.X2;
2047 result.right.X2 = origbox.X2;
2048 /* validity: */
2049 result.is_valid_left = (result.left.X1 < result.left.X2);
2050 result.is_valid_center = (result.center.X1 < result.center.X2);
2051 result.is_valid_right = (result.right.X1 < result.right.X2);
2052 /* rotate back */
2053 ROTATEBOX_FROM_NORTH (result.left, which_edge);
2054 ROTATEBOX_FROM_NORTH (result.center, which_edge);
2055 ROTATEBOX_FROM_NORTH (result.right, which_edge);
2056 /* done */
2057 return result;
2060 #ifndef NDEBUG
2061 static int
2062 share_edge (const BoxType * child, const BoxType * parent)
2064 return
2065 (child->X1 == parent->X2 || child->X2 == parent->X1 ||
2066 child->Y1 == parent->Y2 || child->Y2 == parent->Y1) &&
2067 ((parent->X1 <= child->X1 && child->X2 <= parent->X2) ||
2068 (parent->Y1 <= child->Y1 && child->Y2 <= parent->Y2));
2070 static int
2071 edge_intersect (const BoxType * child, const BoxType * parent)
2073 return
2074 (child->X1 <= parent->X2) && (child->X2 >= parent->X1) &&
2075 (child->Y1 <= parent->Y2) && (child->Y2 >= parent->Y1);
2077 #endif
2080 * \brief Area is the expansion area, on layer group 'group'.
2082 * 'parent' is the immediately preceding expansion area, for backtracing.
2083 * 'lastarea' is the last expansion area created, we string these
2084 * together in a loop so we can remove them all easily at the end.
2086 static routebox_t *
2087 CreateExpansionArea (const BoxType * area, Cardinal group,
2088 routebox_t * parent,
2089 bool relax_edge_requirements, edge_t * src_edge)
2091 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
2092 memset ((void *) rb, 0, sizeof (*rb));
2093 assert (area && parent);
2094 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
2095 rb->group = group;
2096 rb->type = EXPANSION_AREA;
2097 /* should always share edge or overlap with parent */
2098 assert (relax_edge_requirements ? box_intersect (&rb->sbox, &parent->sbox)
2099 : share_edge (&rb->sbox, &parent->sbox));
2100 rb->parent.expansion_area = route_parent (parent);
2101 rb->cost_point =
2102 closest_point_in_box (&rb->parent.expansion_area->cost_point, area);
2103 rb->cost =
2104 rb->parent.expansion_area->cost +
2105 cost_to_point_on_layer (&rb->parent.expansion_area->cost_point,
2106 &rb->cost_point, rb->group);
2107 assert (relax_edge_requirements ? edge_intersect (&rb->sbox, &parent->sbox)
2108 : share_edge (&rb->sbox, &parent->sbox));
2109 if (rb->parent.expansion_area->flags.homeless)
2110 RB_up_count (rb->parent.expansion_area);
2111 rb->flags.homeless = 1;
2112 rb->flags.nobloat = 1;
2113 rb->style = AutoRouteParameters.style;
2114 rb->conflicts_with = parent->conflicts_with;
2115 /* we will never link an EXPANSION_AREA into the nets because they
2116 * are *ONLY* used for path searching. No need to call InitLists ()
2118 rb->came_from = src_edge->expand_dir;
2119 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
2120 showroutebox (rb);
2121 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
2122 return rb;
2125 /*------ Expand ------*/
2126 struct E_result
2128 routebox_t *parent;
2129 routebox_t *n, *e, *s, *w;
2130 Coord keep, bloat;
2131 BoxType inflated, orig;
2132 int done;
2136 * \brief Test method for Expand().
2138 * This routebox potentially is a blocker limiting expansion
2139 * if this is so, we limit the inflate box so another exactly
2140 * like it wouldn't be seen. We do this while keep the inflated
2141 * box as large as possible.
2143 static int
2144 __Expand_this_rect (const BoxType * box, void *cl)
2146 struct E_result *res = (struct E_result *) cl;
2147 routebox_t *rb = (routebox_t *) box;
2148 BoxType rbox;
2149 Coord dn, de, ds, dw, bloat;
2151 /* we don't see conflicts already encountered */
2152 if (rb->flags.touched)
2153 return 0;
2155 /* The inflated box outer edges include its own
2156 * track width plus its own keepaway.
2158 * To check for intersection, we need to expand
2159 * anything with greater keepaway by its excess
2160 * keepaway.
2162 * If something has nobloat then we need to shrink
2163 * the inflated box back and see if it still touches.
2166 if (rb->flags.nobloat)
2168 rbox = rb->sbox;
2169 bloat = res->bloat;
2170 if (rbox.X2 <= res->inflated.X1 + bloat ||
2171 rbox.X1 >= res->inflated.X2 - bloat ||
2172 rbox.Y1 >= res->inflated.Y2 - bloat ||
2173 rbox.Y2 <= res->inflated.Y1 + bloat)
2174 return 0; /* doesn't touch */
2176 else
2178 if (rb->style->Keepaway > res->keep)
2179 rbox = bloat_box (&rb->sbox, rb->style->Keepaway - res->keep);
2180 else
2181 rbox = rb->sbox;
2183 if (rbox.X2 <= res->inflated.X1 || rbox.X1 >= res->inflated.X2
2184 || rbox.Y1 >= res->inflated.Y2 || rbox.Y2 <= res->inflated.Y1)
2185 return 0; /* doesn't touch */
2186 bloat = 0;
2189 /* this is an intersecting box; it has to jump through a few more hoops */
2190 if (rb == res->parent || rb->parent.expansion_area == res->parent)
2191 return 0; /* don't see what we came from */
2193 /* if we are expanding a source edge, don't let other sources
2194 * or their expansions stop us.
2196 #if 1
2197 if (res->parent->flags.source)
2198 if (rb->flags.source
2199 || (rb->type == EXPANSION_AREA
2200 && rb->parent.expansion_area->flags.source))
2201 return 0;
2202 #endif
2204 /* we ignore via expansion boxes because maybe its
2205 * cheaper to get there without the via through
2206 * the path we're exploring now.
2208 if (rb->flags.is_via && rb->type == EXPANSION_AREA)
2209 return 0;
2211 if (rb->type == PLANE) /* expanding inside a plane is not good */
2213 if (rbox.X1 < res->orig.X1 && rbox.X2 > res->orig.X2 &&
2214 rbox.Y1 < res->orig.Y1 && rbox.Y2 > res->orig.Y2)
2216 res->inflated = bloat_box (&res->orig, res->bloat);
2217 return 1;
2220 /* calculate the distances from original box to this blocker */
2221 dn = de = ds = dw = 0;
2222 if (!(res->done & _NORTH) && rbox.Y1 <= res->orig.Y1
2223 && rbox.Y2 > res->inflated.Y1)
2224 dn = res->orig.Y1 - rbox.Y2;
2225 if (!(res->done & _EAST) && rbox.X2 >= res->orig.X2
2226 && rbox.X1 < res->inflated.X2)
2227 de = rbox.X1 - res->orig.X2;
2228 if (!(res->done & _SOUTH) && rbox.Y2 >= res->orig.Y2
2229 && rbox.Y1 < res->inflated.Y2)
2230 ds = rbox.Y1 - res->orig.Y2;
2231 if (!(res->done & _WEST) && rbox.X1 <= res->orig.X1
2232 && rbox.X2 > res->inflated.X1)
2233 dw = res->orig.X1 - rbox.X2;
2234 if (dn <= 0 && de <= 0 && ds <= 0 && dw <= 0)
2235 return 1;
2236 /* now shrink the inflated box to the largest blocking direction */
2237 if (dn >= de && dn >= ds && dn >= dw)
2239 res->inflated.Y1 = rbox.Y2 - bloat;
2240 res->n = rb;
2242 else if (de >= ds && de >= dw)
2244 res->inflated.X2 = rbox.X1 + bloat;
2245 res->e = rb;
2247 else if (ds >= dw)
2249 res->inflated.Y2 = rbox.Y1 + bloat;
2250 res->s = rb;
2252 else
2254 res->inflated.X1 = rbox.X2 - bloat;
2255 res->w = rb;
2257 return 1;
2260 static bool
2261 boink_box (routebox_t * rb, struct E_result *res, direction_t dir)
2263 Coord bloat;
2264 if (rb->style->Keepaway > res->keep)
2265 bloat = res->keep - rb->style->Keepaway;
2266 else
2267 bloat = 0;
2268 if (rb->flags.nobloat)
2269 bloat = res->bloat;
2270 switch (dir)
2272 case NORTH:
2273 case SOUTH:
2274 if (rb->sbox.X2 <= res->inflated.X1 + bloat
2275 || rb->sbox.X1 >= res->inflated.X2 - bloat)
2276 return false;
2277 return true;
2278 case EAST:
2279 case WEST:
2280 if (rb->sbox.Y1 >= res->inflated.Y2 - bloat
2281 || rb->sbox.Y2 <= res->inflated.Y1 + bloat)
2282 return false;
2283 return true;
2284 break;
2285 default:
2286 assert (0);
2288 return false;
2292 * \brief Main Expand routine.
2294 * The expansion probe edge includes the keepaway and half thickness
2295 * as the search is performed in order to see everything relevant.
2296 * The result is backed off by this amount before being returned.
2297 * Targets (and other no-bloat routeboxes) go all the way to touching.
2298 * This is accomplished by backing off the probe edge when checking
2299 * for touch against such an object. Usually the expanding edge
2300 * bumps into neighboring pins on the same device that require a
2301 * keepaway, preventing seeing a target immediately. Rather than await
2302 * another expansion to actually touch the target, the edge breaker code
2303 * looks past the keepaway to see these targets even though they
2304 * weren't actually touched in the expansion.
2306 struct E_result *
2307 Expand (rtree_t * rtree, edge_t * e, const BoxType * box)
2309 static struct E_result ans;
2310 int noshrink; /* bit field of which edges to not shrink */
2312 ans.bloat = AutoRouteParameters.bloat;
2313 ans.orig = *box;
2314 ans.n = ans.e = ans.s = ans.w = NULL;
2316 /* the inflated box must be bloated in all directions that it might
2317 * hit something in order to guarantee that we see object in the
2318 * tree it might hit. The tree holds objects bloated by their own
2319 * keepaway so we are guaranteed to honor that.
2321 switch (e->expand_dir)
2323 case ALL:
2324 ans.inflated.X1 = (e->rb->came_from == EAST ? ans.orig.X1 : 0);
2325 ans.inflated.Y1 = (e->rb->came_from == SOUTH ? ans.orig.Y1 : 0);
2326 ans.inflated.X2 =
2327 (e->rb->came_from == WEST ? ans.orig.X2 : PCB->MaxWidth);
2328 ans.inflated.Y2 =
2329 (e->rb->came_from == NORTH ? ans.orig.Y2 : PCB->MaxHeight);
2330 if (e->rb->came_from == NORTH)
2331 ans.done = noshrink = _SOUTH;
2332 else if (e->rb->came_from == EAST)
2333 ans.done = noshrink = _WEST;
2334 else if (e->rb->came_from == SOUTH)
2335 ans.done = noshrink = _NORTH;
2336 else if (e->rb->came_from == WEST)
2337 ans.done = noshrink = _EAST;
2338 else
2339 ans.done = noshrink = 0;
2340 break;
2341 case NORTH:
2342 ans.done = _SOUTH + _EAST + _WEST;
2343 noshrink = _SOUTH;
2344 ans.inflated.X1 = box->X1 - ans.bloat;
2345 ans.inflated.X2 = box->X2 + ans.bloat;
2346 ans.inflated.Y2 = box->Y2;
2347 ans.inflated.Y1 = 0; /* far north */
2348 break;
2349 case NE:
2350 ans.done = _SOUTH + _WEST;
2351 noshrink = 0;
2352 ans.inflated.X1 = box->X1 - ans.bloat;
2353 ans.inflated.X2 = PCB->MaxWidth;
2354 ans.inflated.Y2 = box->Y2 + ans.bloat;
2355 ans.inflated.Y1 = 0;
2356 break;
2357 case EAST:
2358 ans.done = _NORTH + _SOUTH + _WEST;
2359 noshrink = _WEST;
2360 ans.inflated.Y1 = box->Y1 - ans.bloat;
2361 ans.inflated.Y2 = box->Y2 + ans.bloat;
2362 ans.inflated.X1 = box->X1;
2363 ans.inflated.X2 = PCB->MaxWidth;
2364 break;
2365 case SE:
2366 ans.done = _NORTH + _WEST;
2367 noshrink = 0;
2368 ans.inflated.X1 = box->X1 - ans.bloat;
2369 ans.inflated.X2 = PCB->MaxWidth;
2370 ans.inflated.Y2 = PCB->MaxHeight;
2371 ans.inflated.Y1 = box->Y1 - ans.bloat;
2372 break;
2373 case SOUTH:
2374 ans.done = _NORTH + _EAST + _WEST;
2375 noshrink = _NORTH;
2376 ans.inflated.X1 = box->X1 - ans.bloat;
2377 ans.inflated.X2 = box->X2 + ans.bloat;
2378 ans.inflated.Y1 = box->Y1;
2379 ans.inflated.Y2 = PCB->MaxHeight;
2380 break;
2381 case SW:
2382 ans.done = _NORTH + _EAST;
2383 noshrink = 0;
2384 ans.inflated.X1 = 0;
2385 ans.inflated.X2 = box->X2 + ans.bloat;
2386 ans.inflated.Y2 = PCB->MaxHeight;
2387 ans.inflated.Y1 = box->Y1 - ans.bloat;
2388 break;
2389 case WEST:
2390 ans.done = _NORTH + _SOUTH + _EAST;
2391 noshrink = _EAST;
2392 ans.inflated.Y1 = box->Y1 - ans.bloat;
2393 ans.inflated.Y2 = box->Y2 + ans.bloat;
2394 ans.inflated.X1 = 0;
2395 ans.inflated.X2 = box->X2;
2396 break;
2397 case NW:
2398 ans.done = _SOUTH + _EAST;
2399 noshrink = 0;
2400 ans.inflated.X1 = 0;
2401 ans.inflated.X2 = box->X2 + ans.bloat;
2402 ans.inflated.Y2 = box->Y2 + ans.bloat;
2403 ans.inflated.Y1 = 0;
2404 break;
2405 default:
2406 noshrink = ans.done = 0;
2407 assert (0);
2409 ans.keep = e->rb->style->Keepaway;
2410 ans.parent = nonhomeless_parent (e->rb);
2411 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
2412 /* because the overlaping boxes are found in random order, some blockers
2413 * may have limited edges prematurely, so we check if the blockers realy
2414 * are blocking, and make another try if not
2416 if (ans.n && !boink_box (ans.n, &ans, NORTH))
2417 ans.inflated.Y1 = 0;
2418 else
2419 ans.done |= _NORTH;
2420 if (ans.e && !boink_box (ans.e, &ans, EAST))
2421 ans.inflated.X2 = PCB->MaxWidth;
2422 else
2423 ans.done |= _EAST;
2424 if (ans.s && !boink_box (ans.s, &ans, SOUTH))
2425 ans.inflated.Y2 = PCB->MaxHeight;
2426 else
2427 ans.done |= _SOUTH;
2428 if (ans.w && !boink_box (ans.w, &ans, WEST))
2429 ans.inflated.X1 = 0;
2430 else
2431 ans.done |= _WEST;
2432 if (ans.done != _NORTH + _EAST + _SOUTH + _WEST)
2434 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
2436 if ((noshrink & _NORTH) == 0)
2437 ans.inflated.Y1 += ans.bloat;
2438 if ((noshrink & _EAST) == 0)
2439 ans.inflated.X2 -= ans.bloat;
2440 if ((noshrink & _SOUTH) == 0)
2441 ans.inflated.Y2 -= ans.bloat;
2442 if ((noshrink & _WEST) == 0)
2443 ans.inflated.X1 += ans.bloat;
2444 return &ans;
2448 * \brief \c blocker_to_heap puts the blockers into a heap so they
2449 * can be retrieved in clockwise order. If a blocker
2450 * is also a target, it gets put into the vector too.
2451 * It returns 1 for any fixed blocker that is not part
2452 * of this net and zero otherwise.
2454 static int
2455 blocker_to_heap (heap_t * heap, routebox_t * rb,
2456 BoxType * box, direction_t dir)
2458 BoxType b = rb->sbox;
2459 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
2461 bloat_box (&b,
2462 rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
2463 b = clip_box (&b, box);
2464 assert (box_is_good (&b));
2465 /* we want to look at the blockers clockwise around the box */
2466 switch (dir)
2468 /* we need to use the other coordinate fraction to resolve
2469 * ties since we want the shorter of the furthest
2470 * first.
2472 case NORTH:
2473 heap_insert (heap, b.X1 - b.X1 / (b.X2 + 1.0), rb);
2474 break;
2475 case EAST:
2476 heap_insert (heap, b.Y1 - b.Y1 / (b.Y2 + 1.0), rb);
2477 break;
2478 case SOUTH:
2479 heap_insert (heap, -(b.X2 + b.X1 / (b.X2 + 1.0)), rb);
2480 break;
2481 case WEST:
2482 heap_insert (heap, -(b.Y2 + b.Y1 / (b.Y2 + 1.0)), rb);
2483 break;
2484 default:
2485 assert (0);
2487 if (rb->flags.fixed && !rb->flags.target && !rb->flags.source)
2488 return 1;
2489 return 0;
2493 * \brief This creates an EXPANSION_AREA to bridge small gaps or,
2494 * (more commonly) create a supper-thin box to provide a
2495 * home for an expansion edge.
2497 static routebox_t *
2498 CreateBridge (const BoxType * area, routebox_t * parent, direction_t dir)
2500 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
2501 memset ((void *) rb, 0, sizeof (*rb));
2502 assert (area && parent);
2503 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
2504 rb->group = parent->group;
2505 rb->type = EXPANSION_AREA;
2506 rb->came_from = dir;
2507 rb->cost_point = closest_point_in_box (&parent->cost_point, area);
2508 rb->cost = parent->cost + cost_to_point_on_layer (&parent->cost_point,
2509 &rb->cost_point,
2510 rb->group);
2511 rb->parent.expansion_area = route_parent (parent);
2512 if (rb->parent.expansion_area->flags.homeless)
2513 RB_up_count (rb->parent.expansion_area);
2514 rb->flags.homeless = 1;
2515 rb->flags.nobloat = 1;
2516 rb->style = parent->style;
2517 rb->conflicts_with = parent->conflicts_with;
2518 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES)
2519 showroutebox (rb);
2520 #endif
2521 return rb;
2525 * \brief \c moveable_edge prepares the new search edges based on the
2526 * starting box, direction and blocker if any.
2528 void
2529 moveable_edge (vector_t * result, const BoxType * box, direction_t dir,
2530 routebox_t * rb,
2531 routebox_t * blocker, edge_t * e, rtree_t * targets,
2532 struct routeone_state *s, rtree_t * tree, vector_t * area_vec)
2534 BoxType b;
2535 assert (box_is_good (box));
2536 b = *box;
2537 /* for the cardinal directions, move the box to overlap the
2538 * the parent by 1 unit. Corner expansions overlap more
2539 * and their starting boxes are pre-prepared.
2540 * Check if anything is headed off the board edges
2542 switch (dir)
2544 default:
2545 break;
2546 case NORTH:
2547 b.Y2 = b.Y1;
2548 b.Y1--;
2549 if (b.Y1 <= AutoRouteParameters.bloat)
2550 return; /* off board edge */
2551 break;
2552 case EAST:
2553 b.X1 = b.X2;
2554 b.X2++;
2555 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat)
2556 return; /* off board edge */
2557 break;
2558 case SOUTH:
2559 b.Y1 = b.Y2;
2560 b.Y2++;
2561 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat)
2562 return; /* off board edge */
2563 break;
2564 case WEST:
2565 b.X2 = b.X1;
2566 b.X1--;
2567 if (b.X1 <= AutoRouteParameters.bloat)
2568 return; /* off board edge */
2569 break;
2570 case NE:
2571 if (b.Y1 <= AutoRouteParameters.bloat + 1
2572 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2573 return; /* off board edge */
2574 if (b.Y1 <= AutoRouteParameters.bloat + 1)
2575 dir = EAST; /* north off board edge */
2576 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2577 dir = NORTH; /* east off board edge */
2578 break;
2579 case SE:
2580 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
2581 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2582 return; /* off board edge */
2583 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
2584 dir = EAST; /* south off board edge */
2585 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2586 dir = SOUTH; /* east off board edge */
2587 break;
2588 case SW:
2589 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
2590 && b.X1 <= AutoRouteParameters.bloat + 1)
2591 return; /* off board edge */
2592 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
2593 dir = WEST; /* south off board edge */
2594 if (b.X1 <= AutoRouteParameters.bloat + 1)
2595 dir = SOUTH; /* west off board edge */
2596 break;
2597 case NW:
2598 if (b.Y1 <= AutoRouteParameters.bloat + 1
2599 && b.X1 <= AutoRouteParameters.bloat + 1)
2600 return; /* off board edge */
2601 if (b.Y1 <= AutoRouteParameters.bloat + 1)
2602 dir = WEST; /* north off board edge */
2603 if (b.X1 <= AutoRouteParameters.bloat + 1)
2604 dir = NORTH; /* west off board edge */
2605 break;
2608 if (!blocker)
2610 edge_t *ne;
2611 routebox_t *nrb = CreateBridge (&b, rb, dir);
2612 /* move the cost point in corner expansions
2613 * these boxes are bigger, so move close to the target
2615 if (dir == NE || dir == SE || dir == SW || dir == NW)
2617 CheapPointType p;
2619 closest_point_in_box (&nrb->cost_point, &e->mincost_target->sbox);
2620 p = closest_point_in_box (&p, &b);
2621 nrb->cost += cost_to_point_on_layer (&p, &nrb->cost_point,
2622 nrb->group);
2623 nrb->cost_point = p;
2625 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
2626 nrb->cost, NULL, dir, targets);
2627 vector_append (result, ne);
2629 else if (AutoRouteParameters.with_conflicts && !blocker->flags.target
2630 && !blocker->flags.fixed && !blocker->flags.touched &&
2631 !blocker->flags.source && blocker->type != EXPANSION_AREA)
2633 edge_t *ne;
2634 routebox_t *nrb;
2635 /* make a bridge to the edge of the blocker
2636 * in all directions from there
2638 switch (dir)
2640 case NORTH:
2641 b.Y1 = blocker->sbox.Y2 - 1;
2642 break;
2643 case EAST:
2644 b.X2 = blocker->sbox.X1 + 1;
2645 break;
2646 case SOUTH:
2647 b.Y2 = blocker->sbox.Y1 + 1;
2648 break;
2649 case WEST:
2650 b.X1 = blocker->sbox.X2 - 1;
2651 break;
2652 default:
2653 assert (0);
2655 if (!box_is_good (&b))
2656 return; /* how did this happen ? */
2657 nrb = CreateBridge (&b, rb, dir);
2658 r_insert_entry (tree, &nrb->box, 1);
2659 vector_append (area_vec, nrb);
2660 nrb->flags.homeless = 0; /* not homeless any more */
2661 /* mark this one as conflicted */
2662 path_conflicts (nrb, blocker, true);
2663 /* and make an expansion edge */
2664 nrb->cost_point =
2665 closest_point_in_box (&nrb->cost_point, &blocker->sbox);
2666 nrb->cost +=
2667 cost_to_point_on_layer (&nrb->parent.expansion_area->cost_point,
2668 &nrb->cost_point,
2669 nrb->group) * CONFLICT_PENALTY (blocker);
2671 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, nrb->cost,
2672 NULL, ALL, targets);
2673 ne->flags.is_interior = 1;
2674 vector_append (result, ne);
2676 #if 1
2677 else if (blocker->type == EXPANSION_AREA)
2679 if (blocker->cost < rb->cost || blocker->cost <= rb->cost +
2680 cost_to_point_on_layer (&blocker->cost_point, &rb->cost_point,
2681 rb->group))
2682 return;
2683 if (blocker->conflicts_with || rb->conflicts_with)
2684 return;
2685 /* does the blocker overlap this routebox ?? */
2686 /* does this re-parenting operation leave a memory leak? */
2687 if (blocker->parent.expansion_area->flags.homeless)
2688 RB_down_count (blocker->parent.expansion_area);
2689 blocker->parent.expansion_area = rb;
2690 return;
2692 #endif
2693 else if (blocker->flags.target)
2695 routebox_t *nrb;
2696 edge_t *ne;
2697 b = bloat_box (&b, 1);
2698 if (!box_intersect (&b, &blocker->sbox))
2700 /* if the expansion edge stopped before touching, expand the bridge */
2701 switch (dir)
2703 case NORTH:
2704 b.Y1 -= AutoRouteParameters.bloat + 1;
2705 break;
2706 case EAST:
2707 b.X2 += AutoRouteParameters.bloat + 1;
2708 break;
2709 case SOUTH:
2710 b.Y2 += AutoRouteParameters.bloat + 1;
2711 break;
2712 case WEST:
2713 b.X1 -= AutoRouteParameters.bloat + 1;
2714 break;
2715 default:
2716 assert (0);
2719 assert (box_intersect (&b, &blocker->sbox));
2720 b = shrink_box (&b, 1);
2721 nrb = CreateBridge (&b, rb, dir);
2722 r_insert_entry (tree, &nrb->box, 1);
2723 vector_append (area_vec, nrb);
2724 nrb->flags.homeless = 0; /* not homeless any more */
2725 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
2726 nrb->cost, blocker, dir, NULL);
2727 best_path_candidate (s, ne, blocker);
2728 DestroyEdge (&ne);
2732 struct break_info
2734 heap_t *heap;
2735 routebox_t *parent;
2736 BoxType box;
2737 direction_t dir;
2738 bool ignore_source;
2741 static int
2742 __GatherBlockers (const BoxType * box, void *cl)
2744 routebox_t *rb = (routebox_t *) box;
2745 struct break_info *bi = (struct break_info *) cl;
2746 BoxType b;
2748 if (bi->parent == rb || rb->flags.touched ||
2749 bi->parent->parent.expansion_area == rb)
2750 return 0;
2751 if (rb->flags.source && bi->ignore_source)
2752 return 0;
2753 b = rb->sbox;
2754 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
2756 bloat_box (&b,
2757 rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
2758 if (b.X2 <= bi->box.X1 || b.X1 >= bi->box.X2
2759 || b.Y1 >= bi->box.Y2 || b.Y2 <= bi->box.Y1)
2760 return 0;
2761 return blocker_to_heap (bi->heap, rb, &bi->box, bi->dir);
2765 * \brief Shrink the box to the last limit for the previous direction,
2766 * i.e. if dir is SOUTH, then this means fixing up an EAST leftover
2767 * edge, which would be the southern most edge for that example.
2769 static inline BoxType
2770 previous_edge (Coord last, direction_t i, const BoxType * b)
2772 BoxType db = *b;
2773 switch (i)
2775 case EAST:
2776 db.X1 = last;
2777 break;
2778 case SOUTH:
2779 db.Y1 = last;
2780 break;
2781 case WEST:
2782 db.X2 = last;
2783 break;
2784 default:
2785 Message ("previous edge bogus direction!");
2786 assert (0);
2788 return db;
2792 * \brief Break all the edges of the box that need breaking, handling
2793 * targets as they are found, and putting any moveable edges
2794 * in the return vector.
2796 vector_t *
2797 BreakManyEdges (struct routeone_state * s, rtree_t * targets, rtree_t * tree,
2798 vector_t * area_vec, struct E_result * ans, routebox_t * rb,
2799 edge_t * e)
2801 struct break_info bi;
2802 vector_t *edges;
2803 heap_t *heap[4];
2804 Coord first, last;
2805 Coord bloat;
2806 direction_t dir;
2807 routebox_t fake;
2809 edges = vector_create ();
2810 bi.ignore_source = rb->parent.expansion_area->flags.source;
2811 bi.parent = rb;
2812 /* we add 2 to the bloat.
2813 * 1 will get us to the actual blocker that Expand() hit
2814 * but 1 more is needed because the new expansion edges
2815 * move out by 1 so they don't overlap their parents
2816 * this extra expansion could "trap" the edge if
2817 * there is a blocker 2 units from the original rb,
2818 * it is 1 unit from the new expansion edge which
2819 * would prevent expansion. So we want to break the
2820 * edge on it now to avoid the trap.
2823 bloat = AutoRouteParameters.bloat + 2;
2824 /* for corner expansion, we need to have a fake blocker
2825 * to prevent expansion back where we came from since
2826 * we still need to break portions of all 4 edges
2828 if (e->expand_dir == NE || e->expand_dir == SE ||
2829 e->expand_dir == SW || e->expand_dir == NW)
2831 BoxType *fb = (BoxType *) &fake.sbox;
2832 memset (&fake, 0, sizeof (fake));
2833 *fb = e->rb->sbox;
2834 fake.flags.fixed = 1; /* this stops expansion there */
2835 fake.type = LINE;
2836 fake.style = AutoRouteParameters.style;
2837 #ifndef NDEBUG
2838 /* the routbox_is_good checker wants a lot more! */
2839 fake.flags.inited = 1;
2840 fb = (BoxType *) &fake.box;
2841 *fb = e->rb->sbox;
2842 fake.same_net.next = fake.same_net.prev = &fake;
2843 fake.same_subnet.next = fake.same_subnet.prev = &fake;
2844 fake.original_subnet.next = fake.original_subnet.prev = &fake;
2845 fake.different_net.next = fake.different_net.prev = &fake;
2846 #endif
2848 /* gather all of the blockers in heaps so they can be accessed
2849 * in clockwise order, which allows finding corners that can
2850 * be expanded.
2852 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
2854 /* don't break the edge we came from */
2855 if (e->expand_dir != ((dir + 2) % 4))
2857 heap[dir] = heap_create ();
2858 bi.box = bloat_box (&rb->sbox, bloat);
2859 bi.heap = heap[dir];
2860 bi.dir = dir;
2861 /* convert to edge */
2862 switch (dir)
2864 case NORTH:
2865 bi.box.Y2 = bi.box.Y1 + bloat + 1;
2866 /* for corner expansion, block the start edges and
2867 * limit the blocker search to only the new edge segment
2869 if (e->expand_dir == SE || e->expand_dir == SW)
2870 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2871 if (e->expand_dir == SE)
2872 bi.box.X1 = e->rb->sbox.X2;
2873 if (e->expand_dir == SW)
2874 bi.box.X2 = e->rb->sbox.X1;
2875 rb->n = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2876 break;
2877 case EAST:
2878 bi.box.X1 = bi.box.X2 - bloat - 1;
2879 /* corner, same as above */
2880 if (e->expand_dir == SW || e->expand_dir == NW)
2881 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2882 if (e->expand_dir == SW)
2883 bi.box.Y1 = e->rb->sbox.Y2;
2884 if (e->expand_dir == NW)
2885 bi.box.Y2 = e->rb->sbox.Y1;
2886 rb->e = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2887 break;
2888 case SOUTH:
2889 bi.box.Y1 = bi.box.Y2 - bloat - 1;
2890 /* corner, same as above */
2891 if (e->expand_dir == NE || e->expand_dir == NW)
2892 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2893 if (e->expand_dir == NE)
2894 bi.box.X1 = e->rb->sbox.X2;
2895 if (e->expand_dir == NW)
2896 bi.box.X2 = e->rb->sbox.X1;
2897 rb->s = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2898 break;
2899 case WEST:
2900 bi.box.X2 = bi.box.X1 + bloat + 1;
2901 /* corner, same as above */
2902 if (e->expand_dir == NE || e->expand_dir == SE)
2903 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2904 if (e->expand_dir == SE)
2905 bi.box.Y1 = e->rb->sbox.Y2;
2906 if (e->expand_dir == NE)
2907 bi.box.Y2 = e->rb->sbox.Y1;
2908 rb->w = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2909 break;
2910 default:
2911 assert (0);
2914 else
2915 heap[dir] = NULL;
2917 #if 1
2918 rb->cost +=
2919 (rb->n + rb->e + rb->s +
2920 rb->w) * AutoRouteParameters.CongestionPenalty / box_area (rb->sbox);
2921 #endif
2922 /* now handle the blockers:
2923 * Go around the expansion area clockwise (North->East->South->West)
2924 * pulling blockers from the heap (which makes them come out in the right
2925 * order). Break the edges on the blocker and make the segments and corners
2926 * moveable as possible.
2928 first = last = -1;
2929 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
2931 if (heap[dir] && !heap_is_empty (heap[dir]))
2933 /* pull the very first one out of the heap outside of the
2934 * heap loop because it is special; it can be part of a corner
2936 routebox_t *blk = (routebox_t *) heap_remove_smallest (heap[dir]);
2937 BoxType b = rb->sbox;
2938 struct broken_boxes broke = break_box_edge (&b, dir, blk);
2939 if (broke.is_valid_left)
2941 /* if last > 0, then the previous edge had a segment
2942 * joining this one, so it forms a valid corner expansion
2944 if (last > 0)
2946 /* make a corner expansion */
2947 BoxType db = b;
2948 switch (dir)
2950 case EAST:
2951 /* possible NE expansion */
2952 db.X1 = last;
2953 db.Y2 = MIN (db.Y2, broke.left.Y2);
2954 break;
2955 case SOUTH:
2956 /* possible SE expansion */
2957 db.Y1 = last;
2958 db.X1 = MAX (db.X1, broke.left.X1);
2959 break;
2960 case WEST:
2961 /* possible SW expansion */
2962 db.X2 = last;
2963 db.Y1 = MAX (db.Y1, broke.left.Y1);
2964 break;
2965 default:
2966 assert (0);
2967 break;
2969 moveable_edge (edges, &db, (direction_t)(dir + 3), rb, NULL, e, targets,
2970 s, NULL, NULL);
2972 else if (dir == NORTH) /* north is start, so nothing "before" it */
2974 /* save for a possible corner once we've
2975 * finished circling the box
2977 first = MAX (b.X1, broke.left.X2);
2979 else
2981 /* this is just a boring straight expansion
2982 * since the orthogonal segment was blocked
2984 moveable_edge (edges, &broke.left, dir, rb, NULL, e,
2985 targets, s, NULL, NULL);
2987 } /* broke.is_valid_left */
2988 else if (last > 0)
2990 /* if the last one didn't become a corner,
2991 * we still want to expand it straight out
2992 * in the direction of the previous edge,
2993 * which it belongs to.
2995 BoxType db = previous_edge (last, dir, &rb->sbox);
2996 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
2997 NULL, NULL);
2999 if (broke.is_valid_center && !blk->flags.source)
3000 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets, s,
3001 tree, area_vec);
3002 /* this is the heap extraction loop. We break out
3003 * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can
3004 * just leave stuff in the heap when it is destroyed
3006 while (broke.is_valid_right)
3008 /* move the box edge to the next potential free point */
3009 switch (dir)
3011 case NORTH:
3012 last = b.X1 = MAX (broke.right.X1, b.X1);
3013 break;
3014 case EAST:
3015 last = b.Y1 = MAX (broke.right.Y1, b.Y1);
3016 break;
3017 case SOUTH:
3018 last = b.X2 = MIN (broke.right.X2, b.X2);
3019 break;
3020 case WEST:
3021 last = b.Y2 = MIN (broke.right.Y2, b.Y2);
3022 break;
3023 default:
3024 assert (0);
3026 if (heap_is_empty (heap[dir]))
3027 break;
3028 blk = (routebox_t *)heap_remove_smallest (heap[dir]);
3029 broke = break_box_edge (&b, dir, blk);
3030 if (broke.is_valid_left)
3031 moveable_edge (edges, &broke.left, dir, rb, NULL, e, targets,
3032 s, NULL, NULL);
3033 if (broke.is_valid_center && !blk->flags.source)
3034 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets,
3035 s, tree, area_vec);
3037 if (!broke.is_valid_right)
3038 last = -1;
3040 else /* if (heap[dir]) */
3042 /* nothing touched this edge! Expand the whole edge unless
3043 * (1) it hit the board edge or (2) was the source of our expansion
3045 * for this case (of hitting nothing) we give up trying for corner
3046 * expansions because it is likely that they're not possible anyway
3048 if ((e->expand_dir == ALL ? e->rb->came_from : e->expand_dir) !=
3049 ((dir + 2) % 4))
3051 /* ok, we are not going back on ourselves, and the whole edge seems free */
3052 moveable_edge (edges, &rb->sbox, dir, rb, NULL, e, targets, s,
3053 NULL, NULL);
3056 if (last > 0)
3058 /* expand the leftover from the prior direction */
3059 BoxType db = previous_edge (last, dir, &rb->sbox);
3060 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
3061 NULL, NULL);
3063 last = -1;
3065 } /* for loop */
3066 /* finally, check for the NW corner now that we've come full circle */
3067 if (first > 0 && last > 0)
3069 BoxType db = rb->sbox;
3070 db.X2 = first;
3071 db.Y2 = last;
3072 moveable_edge (edges, &db, NW, rb, NULL, e, targets, s, NULL, NULL);
3074 else
3076 if (first > 0)
3078 BoxType db = rb->sbox;
3079 db.X2 = first;
3080 moveable_edge (edges, &db, NORTH, rb, NULL, e, targets, s, NULL,
3081 NULL);
3083 else if (last > 0)
3085 BoxType db = rb->sbox;
3086 db.Y2 = last;
3087 moveable_edge (edges, &db, WEST, rb, NULL, e, targets, s, NULL,
3088 NULL);
3091 /* done with all expansion edges of this box */
3092 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
3094 if (heap[dir])
3095 heap_destroy (&heap[dir]);
3097 return edges;
3100 static routebox_t *
3101 rb_source (routebox_t * rb)
3103 while (rb && !rb->flags.source)
3105 assert (rb->type == EXPANSION_AREA);
3106 rb = rb->parent.expansion_area;
3108 assert (rb);
3109 return rb;
3112 /* ------------ */
3114 struct foib_info
3116 const BoxType *box;
3117 routebox_t *intersect;
3118 jmp_buf env;
3121 static int
3122 foib_rect_in_reg (const BoxType * box, void *cl)
3124 struct foib_info *foib = (struct foib_info *) cl;
3125 BoxType rbox;
3126 routebox_t *rb = (routebox_t *) box;
3127 if (rb->flags.touched)
3128 return 0;
3129 // if (rb->type == EXPANSION_AREA && !rb->flags.is_via)
3130 // return 0;
3131 rbox = bloat_routebox (rb);
3132 if (!box_intersect (&rbox, foib->box))
3133 return 0;
3134 /* this is an intersector! */
3135 foib->intersect = (routebox_t *) box;
3136 longjmp (foib->env, 1); /* skip to the end! */
3137 return 1;
3139 static routebox_t *
3140 FindOneInBox (rtree_t * rtree, routebox_t * rb)
3142 struct foib_info foib;
3143 BoxType r;
3145 r = rb->sbox;
3146 foib.box = &r;
3147 foib.intersect = NULL;
3149 if (setjmp (foib.env) == 0)
3150 r_search (rtree, &r, NULL, foib_rect_in_reg, &foib);
3151 return foib.intersect;
3154 struct therm_info
3156 routebox_t *plane;
3157 BoxType query;
3158 jmp_buf env;
3160 static int
3161 ftherm_rect_in_reg (const BoxType * box, void *cl)
3163 routebox_t *rbox = (routebox_t *) box;
3164 struct therm_info *ti = (struct therm_info *) cl;
3165 BoxType sq, sb;
3167 if (rbox->type != PIN && rbox->type != VIA && rbox->type != VIA_SHADOW)
3168 return 0;
3169 if (rbox->group != ti->plane->group)
3170 return 0;
3172 sb = shrink_routebox (rbox);
3173 switch (rbox->type)
3175 case PIN:
3176 sq = shrink_box (&ti->query, rbox->parent.pin->Thickness);
3177 if (!box_intersect (&sb, &sq))
3178 return 0;
3179 sb.X1 = rbox->parent.pin->X;
3180 sb.Y1 = rbox->parent.pin->Y;
3181 break;
3182 case VIA:
3183 if (rbox->flags.fixed)
3185 sq = shrink_box (&ti->query, rbox->parent.via->Thickness);
3186 sb.X1 = rbox->parent.pin->X;
3187 sb.Y1 = rbox->parent.pin->Y;
3189 else
3191 sq = shrink_box (&ti->query, rbox->style->Diameter);
3192 sb.X1 = CENTER_X (sb);
3193 sb.Y1 = CENTER_Y (sb);
3195 if (!box_intersect (&sb, &sq))
3196 return 0;
3197 break;
3198 case VIA_SHADOW:
3199 sq = shrink_box (&ti->query, rbox->style->Diameter);
3200 if (!box_intersect (&sb, &sq))
3201 return 0;
3202 sb.X1 = CENTER_X (sb);
3203 sb.Y1 = CENTER_Y (sb);
3204 break;
3205 default:
3206 assert (0);
3208 ti->plane = rbox;
3209 longjmp (ti->env, 1);
3210 return 1;
3214 * \brief Check for a pin or via target that a polygon can just use a
3215 * thermal to connect to.
3217 routebox_t *
3218 FindThermable (rtree_t * rtree, routebox_t * rb)
3220 struct therm_info info;
3222 info.plane = rb;
3223 info.query = shrink_routebox (rb);
3225 if (setjmp (info.env) == 0)
3227 r_search (rtree, &info.query, NULL, ftherm_rect_in_reg, &info);
3228 return NULL;
3230 return info.plane;
3234 * \brief Route-tracing code: once we've got a path of expansion boxes,
3235 * trace a line through them to actually create the connection.
3237 static void
3238 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
3239 Cardinal group, Cardinal layer, routebox_t * subnet,
3240 bool is_bad)
3242 routebox_t *rb;
3243 rb = (routebox_t *) malloc (sizeof (*rb));
3244 memset ((void *) rb, 0, sizeof (*rb));
3245 init_const_box (rb, X, Y, X + 1, Y + 1, 0);
3246 rb->group = group;
3247 rb->layer = layer;
3248 rb->flags.fixed = 0;
3249 rb->flags.is_bad = is_bad;
3250 rb->flags.is_odd = AutoRouteParameters.is_odd;
3251 rb->flags.circular = 0;
3252 rb->style = AutoRouteParameters.style;
3253 rb->type = THERMAL;
3254 InitLists (rb);
3255 MergeNets (rb, subnet, NET);
3256 MergeNets (rb, subnet, SUBNET);
3257 /* add it to the r-tree, this may be the whole route! */
3258 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3259 rb->flags.homeless = 0;
3262 static void
3263 RD_DrawVia (routedata_t * rd, Coord X, Coord Y,
3264 Coord radius, routebox_t * subnet, bool is_bad)
3266 routebox_t *rb, *first_via = NULL;
3267 int i;
3268 int ka = AutoRouteParameters.style->Keepaway;
3269 PinType *live_via = NULL;
3271 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3273 live_via = CreateNewVia (PCB->Data, X, Y, radius * 2,
3274 2 * AutoRouteParameters.style->Keepaway, 0,
3275 AutoRouteParameters.style->Hole, NULL,
3276 MakeFlags (0));
3277 if (live_via != NULL)
3278 DrawVia (live_via);
3281 /* a via cuts through every layer group */
3282 for (i = 0; i < max_group; i++)
3284 if (!is_layer_group_active[i])
3285 continue;
3286 rb = (routebox_t *) malloc (sizeof (*rb));
3287 memset ((void *) rb, 0, sizeof (*rb));
3288 init_const_box (rb,
3289 /*X1 */ X - radius, /*Y1 */ Y - radius,
3290 /*X2 */ X + radius + 1, /*Y2 */ Y + radius + 1, ka);
3291 rb->group = i;
3292 rb->flags.fixed = 0; /* indicates that not on PCB yet */
3293 rb->flags.is_odd = AutoRouteParameters.is_odd;
3294 rb->flags.is_bad = is_bad;
3295 rb->came_from = ALL;
3296 rb->flags.circular = true;
3297 rb->style = AutoRouteParameters.style;
3298 rb->pass = AutoRouteParameters.pass;
3299 if (first_via == NULL)
3301 rb->type = VIA;
3302 rb->parent.via = NULL; /* indicates that not on PCB yet */
3303 first_via = rb;
3304 /* only add the first via to mtspace, not the shadows too */
3305 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
3306 rb->style->Keepaway);
3308 else
3310 rb->type = VIA_SHADOW;
3311 rb->parent.via_shadow = first_via;
3313 InitLists (rb);
3314 /* add these to proper subnet. */
3315 MergeNets (rb, subnet, NET);
3316 MergeNets (rb, subnet, SUBNET);
3317 assert (__routebox_is_good (rb));
3318 /* and add it to the r-tree! */
3319 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3320 rb->flags.homeless = 0; /* not homeless anymore */
3321 rb->livedraw_obj.via = live_via;
3324 static void
3325 RD_DrawLine (routedata_t * rd,
3326 Coord X1, Coord Y1, Coord X2,
3327 Coord Y2, Coord halfthick, Cardinal group,
3328 routebox_t * subnet, bool is_bad, bool is_45)
3330 /* we hold the line in a queue to concatenate segments that
3331 * ajoin one another. That reduces the number of things in
3332 * the trees and allows conflict boxes to be larger, both of
3333 * which are really useful.
3335 static Coord qX1 = -1, qY1, qX2, qY2;
3336 static Coord qhthick;
3337 static Cardinal qgroup;
3338 static bool qis_45, qis_bad;
3339 static routebox_t *qsn;
3341 routebox_t *rb;
3342 Coord ka = AutoRouteParameters.style->Keepaway;
3344 /* don't draw zero-length segments. */
3345 if (X1 == X2 && Y1 == Y2)
3346 return;
3347 if (qX1 == -1) /* first ever */
3349 qX1 = X1;
3350 qY1 = Y1;
3351 qX2 = X2;
3352 qY2 = Y2;
3353 qhthick = halfthick;
3354 qgroup = group;
3355 qis_45 = is_45;
3356 qis_bad = is_bad;
3357 qsn = subnet;
3358 return;
3360 /* Check if the lines concatenat. We only check the
3361 * normal expected nextpoint=lastpoint condition
3363 if (X1 == qX2 && Y1 == qY2 && qhthick == halfthick && qgroup == group)
3365 if (qX1 == qX2 && X1 == X2) /* everybody on the same X here */
3367 qY2 = Y2;
3368 return;
3370 if (qY1 == qY2 && Y1 == Y2) /* same Y all around */
3372 qX2 = X2;
3373 return;
3376 /* dump the queue, no match here */
3377 if (qX1 == -1)
3378 return; /* but not this! */
3379 rb = (routebox_t *) malloc (sizeof (*rb));
3380 memset ((void *) rb, 0, sizeof (*rb));
3381 assert (is_45 ? (ABS (qX2 - qX1) == ABS (qY2 - qY1)) /* line must be 45-degrees */
3382 : (qX1 == qX2 || qY1 == qY2) /* line must be ortho */ );
3383 init_const_box (rb,
3384 /*X1 */ MIN (qX1, qX2) - qhthick,
3385 /*Y1 */ MIN (qY1, qY2) - qhthick,
3386 /*X2 */ MAX (qX1, qX2) + qhthick + 1,
3387 /*Y2 */ MAX (qY1, qY2) + qhthick + 1, ka);
3388 rb->group = qgroup;
3389 rb->type = LINE;
3390 rb->parent.line = NULL; /* indicates that not on PCB yet */
3391 rb->flags.fixed = 0; /* indicates that not on PCB yet */
3392 rb->flags.is_odd = AutoRouteParameters.is_odd;
3393 rb->flags.is_bad = qis_bad;
3394 rb->came_from = ALL;
3395 rb->flags.homeless = 0; /* we're putting this in the tree */
3396 rb->flags.nonstraight = qis_45;
3397 rb->flags.bl_to_ur = ((qX2 >= qX1 && qY2 <= qY1)
3398 || (qX2 <= qX1 && qY2 >= qY1));
3399 rb->style = AutoRouteParameters.style;
3400 rb->pass = AutoRouteParameters.pass;
3401 InitLists (rb);
3402 /* add these to proper subnet. */
3403 MergeNets (rb, qsn, NET);
3404 MergeNets (rb, qsn, SUBNET);
3405 assert (__routebox_is_good (rb));
3406 /* and add it to the r-tree! */
3407 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3409 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3411 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
3412 LineType *line = CreateNewLineOnLayer (layer, qX1, qY1, qX2, qY2,
3413 2 * qhthick, 0, MakeFlags (0));
3414 rb->livedraw_obj.line = line;
3415 if (line != NULL)
3416 DrawLine (layer, line);
3419 /* and to the via space structures */
3420 if (AutoRouteParameters.use_vias)
3421 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
3422 rb->style->Keepaway);
3423 usedGroup[rb->group] = true;
3424 /* and queue this one */
3425 qX1 = X1;
3426 qY1 = Y1;
3427 qX2 = X2;
3428 qY2 = Y2;
3429 qhthick = halfthick;
3430 qgroup = group;
3431 qis_45 = is_45;
3432 qis_bad = is_bad;
3433 qsn = subnet;
3436 static bool
3437 RD_DrawManhattanLine (routedata_t * rd,
3438 const BoxType * box1, const BoxType * box2,
3439 CheapPointType start, CheapPointType end,
3440 Coord halfthick, Cardinal group,
3441 routebox_t * subnet, bool is_bad, bool last_was_x)
3443 CheapPointType knee = start;
3444 if (end.X == start.X)
3446 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
3447 subnet, is_bad, false);
3448 return false;
3450 else if (end.Y == start.Y)
3452 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
3453 subnet, is_bad, false);
3454 return true;
3456 /* find where knee belongs */
3457 if (point_in_box (box1, end.X, start.Y)
3458 || point_in_box (box2, end.X, start.Y))
3460 knee.X = end.X;
3461 knee.Y = start.Y;
3463 else
3465 knee.X = start.X;
3466 knee.Y = end.Y;
3468 if ((knee.X == end.X && !last_was_x) &&
3469 (point_in_box (box1, start.X, end.Y)
3470 || point_in_box (box2, start.X, end.Y)))
3472 knee.X = start.X;
3473 knee.Y = end.Y;
3475 assert (AutoRouteParameters.is_smoothing
3476 || point_in_closed_box (box1, knee.X, knee.Y)
3477 || point_in_closed_box (box2, knee.X, knee.Y));
3479 if (1 || !AutoRouteParameters.is_smoothing)
3481 /* draw standard manhattan paths */
3482 RD_DrawLine (rd, start.X, start.Y, knee.X, knee.Y, halfthick, group,
3483 subnet, is_bad, false);
3484 RD_DrawLine (rd, knee.X, knee.Y, end.X, end.Y, halfthick, group,
3485 subnet, is_bad, false);
3487 else
3489 /* draw 45-degree path across knee */
3490 Coord len45 = MIN (ABS (start.X - end.X), ABS (start.Y - end.Y));
3491 CheapPointType kneestart = knee, kneeend = knee;
3492 if (kneestart.X == start.X)
3493 kneestart.Y += (kneestart.Y > start.Y) ? -len45 : len45;
3494 else
3495 kneestart.X += (kneestart.X > start.X) ? -len45 : len45;
3496 if (kneeend.X == end.X)
3497 kneeend.Y += (kneeend.Y > end.Y) ? -len45 : len45;
3498 else
3499 kneeend.X += (kneeend.X > end.X) ? -len45 : len45;
3500 RD_DrawLine (rd, start.X, start.Y, kneestart.X, kneestart.Y, halfthick,
3501 group, subnet, is_bad, false);
3502 RD_DrawLine (rd, kneestart.X, kneestart.Y, kneeend.X, kneeend.Y,
3503 halfthick, group, subnet, is_bad, true);
3504 RD_DrawLine (rd, kneeend.X, kneeend.Y, end.X, end.Y, halfthick, group,
3505 subnet, is_bad, false);
3507 return (knee.X != end.X);
3510 /* for smoothing, don't pack traces to min clearance gratuitously */
3511 #if 0
3512 static void
3513 add_clearance (CheapPointType * nextpoint, const BoxType * b)
3515 if (nextpoint->X == b->X1)
3517 if (nextpoint->X +
3518 AutoRouteParameters.style->Keepaway < (b->X1 + b->X2) / 2)
3519 nextpoint->X += AutoRouteParameters.style->Keepaway;
3520 else
3521 nextpoint->X = (b->X1 + b->X2) / 2;
3523 else if (nextpoint->X == b->X2)
3525 if (nextpoint->X -
3526 AutoRouteParameters.style->Keepaway > (b->X1 + b->X2) / 2)
3527 nextpoint->X -= AutoRouteParameters.style->Keepaway;
3528 else
3529 nextpoint->X = (b->X1 + b->X2) / 2;
3531 else if (nextpoint->Y == b->Y1)
3533 if (nextpoint->Y +
3534 AutoRouteParameters.style->Keepaway < (b->Y1 + b->Y2) / 2)
3535 nextpoint->Y += AutoRouteParameters.style->Keepaway;
3536 else
3537 nextpoint->Y = (b->Y1 + b->Y2) / 2;
3539 else if (nextpoint->Y == b->Y2)
3541 if (nextpoint->Y -
3542 AutoRouteParameters.style->Keepaway > (b->Y1 + b->Y2) / 2)
3543 nextpoint->Y -= AutoRouteParameters.style->Keepaway;
3544 else
3545 nextpoint->Y = (b->Y1 + b->Y2) / 2;
3548 #endif
3551 * \brief This back-traces the expansion boxes along the best path
3552 * it draws the lines that will make the actual path.
3554 * During refinement passes, it should try to maximize the area
3555 * for other tracks so routing completion is easier.
3557 * During smoothing passes, it should try to make a better path,
3558 * possibly using diagonals, etc. The path boxes are larger on
3559 * average now so there is more possiblity to decide on a nice
3560 * path. Any combination of lines and arcs is possible, so long
3561 * as they don't poke more than half thick outside the path box.
3564 static void
3565 TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target,
3566 routebox_t * subnet, bool is_bad)
3568 bool last_x = false;
3569 Coord halfwidth = HALF_THICK (AutoRouteParameters.style->Thick);
3570 Coord radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3571 CheapPointType lastpoint, nextpoint;
3572 routebox_t *lastpath;
3573 BoxType b;
3575 assert (subnet->style == AutoRouteParameters.style);
3576 /*XXX: because we round up odd thicknesses, there's the possibility that
3577 * a connecting line end-point might be 0.005 mil off the "real" edge.
3578 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
3580 /* if we start with a thermal the target was a plane
3581 * or the target was a pin and the source a plane
3582 * in which case this thermal is the whole path
3584 if (path->flags.is_thermal)
3586 /* the target was a plane, so we need to find a good spot for the via
3587 * now. It's logical to place it close to the source box which
3588 * is where we're utlimately headed on this path. However, it
3589 * must reside in the plane as well as the via area too.
3591 nextpoint.X = CENTER_X (path->sbox);
3592 nextpoint.Y = CENTER_Y (path->sbox);
3593 if (path->parent.expansion_area->flags.is_via)
3595 TargetPoint (&nextpoint, rb_source (path));
3596 /* nextpoint is the middle of the source terminal now */
3597 b = clip_box (&path->sbox, &path->parent.expansion_area->sbox);
3598 nextpoint = closest_point_in_box (&nextpoint, &b);
3599 /* now it's in the via and plane near the source */
3601 else /* no via coming, target must have been a pin */
3603 assert (target->type == PIN);
3604 TargetPoint (&nextpoint, target);
3606 assert (point_in_box (&path->sbox, nextpoint.X, nextpoint.Y));
3607 RD_DrawThermal (rd, nextpoint.X, nextpoint.Y, path->group,
3608 path->layer, subnet, is_bad);
3610 else
3612 /* start from best place of target box */
3613 lastpoint.X = CENTER_X (target->sbox);
3614 lastpoint.Y = CENTER_Y (target->sbox);
3615 TargetPoint (&lastpoint, target);
3616 if (AutoRouteParameters.last_smooth
3617 && box_in_box (&path->sbox, &target->sbox))
3618 path = path->parent.expansion_area;
3619 b = path->sbox;
3620 if (path->flags.circular)
3621 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
3622 nextpoint = closest_point_in_box (&lastpoint, &b);
3623 if (AutoRouteParameters.last_smooth)
3624 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3625 halfwidth, path->group, subnet, is_bad, TRUE);
3626 else
3627 last_x = RD_DrawManhattanLine (rd, &target->sbox, &path->sbox,
3628 lastpoint, nextpoint, halfwidth,
3629 path->group, subnet, is_bad, last_x);
3631 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3632 showroutebox (path);
3633 #if defined(ROUTE_VERBOSE)
3634 pcb_printf ("TRACEPOINT start %#mD\n", nextpoint.X, nextpoint.Y);
3635 #endif
3636 #endif
3640 lastpoint = nextpoint;
3641 lastpath = path;
3642 assert (path->type == EXPANSION_AREA);
3643 path = path->parent.expansion_area;
3644 b = path->sbox;
3645 if (path->flags.circular)
3646 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
3647 assert (b.X1 != b.X2 && b.Y1 != b.Y2); /* need someplace to put line! */
3648 /* find point on path perimeter closest to last point */
3649 /* if source terminal, try to hit a good place */
3650 nextpoint = closest_point_in_box (&lastpoint, &b);
3651 #if 0
3652 /* leave more clearance if this is a smoothing pass */
3653 if (AutoRouteParameters.is_smoothing &&
3654 (nextpoint.X != lastpoint.X || nextpoint.Y != lastpoint.Y))
3655 add_clearance (&nextpoint, &b);
3656 #endif
3657 if (path->flags.source && path->type != PLANE)
3658 TargetPoint (&nextpoint, path);
3659 assert (point_in_box (&lastpath->box, lastpoint.X, lastpoint.Y));
3660 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
3661 #if defined(ROUTE_DEBUG_VERBOSE)
3662 printf ("TRACEPATH: ");
3663 DumpRouteBox (path);
3664 pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n",
3665 lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3666 path->group);
3667 #endif
3669 /* draw orthogonal lines from lastpoint to nextpoint */
3670 /* knee is placed in lastpath box */
3671 /* should never cause line to leave union of lastpath/path boxes */
3672 if (AutoRouteParameters.last_smooth)
3673 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3674 halfwidth, path->group, subnet, is_bad, TRUE);
3675 else
3676 last_x = RD_DrawManhattanLine (rd, &lastpath->sbox, &path->sbox,
3677 lastpoint, nextpoint, halfwidth,
3678 path->group, subnet, is_bad, last_x);
3679 if (path->flags.is_via)
3680 { /* if via, then add via */
3681 #ifdef ROUTE_VERBOSE
3682 printf (" (vias)");
3683 #endif
3684 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
3685 RD_DrawVia (rd, nextpoint.X, nextpoint.Y, radius, subnet, is_bad);
3688 assert (lastpath->flags.is_via || path->group == lastpath->group);
3690 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3691 showroutebox (path);
3692 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
3693 /* if this is connected to a plane, draw the thermal */
3694 if (path->flags.is_thermal || path->type == PLANE)
3695 RD_DrawThermal (rd, lastpoint.X, lastpoint.Y, path->group,
3696 path->layer, subnet, is_bad);
3697 /* when one hop from the source, make an extra path in *this* box */
3698 if (path->type == EXPANSION_AREA
3699 && path->parent.expansion_area->flags.source
3700 && path->parent.expansion_area->type != PLANE)
3702 /* find special point on source (if it exists) */
3703 if (TargetPoint (&lastpoint, path->parent.expansion_area))
3705 lastpoint = closest_point_in_routebox (&lastpoint, path);
3706 b = shrink_routebox (path);
3707 #if 0
3708 if (AutoRouteParameters.is_smoothing)
3709 add_clearance (&lastpoint, &b);
3710 #else
3711 if (AutoRouteParameters.last_smooth)
3712 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X,
3713 nextpoint.Y, halfwidth, path->group, subnet,
3714 is_bad, TRUE);
3715 else
3716 #endif
3717 last_x = RD_DrawManhattanLine (rd, &b, &b,
3718 nextpoint, lastpoint,
3719 halfwidth, path->group, subnet,
3720 is_bad, last_x);
3721 #if defined(ROUTE_DEBUG_VERBOSE)
3722 printf ("TRACEPATH: ");
3723 DumpRouteBox (path);
3724 pcb_printf
3725 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n",
3726 nextpoint.X, nextpoint.Y, lastpoint.X, lastpoint.Y,
3727 path->group);
3728 #endif
3730 nextpoint = lastpoint;
3734 while (!path->flags.source);
3735 /* flush the line queue */
3736 RD_DrawLine (rd, -1, 0, 0, 0, 0, 0, NULL, false, false);
3738 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3739 Draw ();
3741 #ifdef ROUTE_DEBUG
3742 if (ddraw != NULL)
3743 gui->flush_debug_draw ();
3744 #endif
3748 * \brief Create a fake "edge" used to defer via site searching.
3750 static void
3751 CreateSearchEdge (struct routeone_state *s, vetting_t * work, edge_t * parent,
3752 routebox_t * rb, conflict_t conflict, rtree_t * targets,
3753 bool in_plane)
3755 routebox_t *target;
3756 BoxType b;
3757 cost_t cost;
3758 assert (__routebox_is_good (rb));
3759 /* find the cheapest target */
3760 #if 0
3761 target =
3762 mincost_target_to_point (&parent->cost_point, max_group + 1, targets,
3763 parent->mincost_target);
3764 #else
3765 target = parent->mincost_target;
3766 #endif
3767 b = shrink_routebox (target);
3768 cost =
3769 parent->cost_to_point + AutoRouteParameters.ViaCost +
3770 cost_to_layerless_box (&rb->cost_point, 0, &b);
3771 if (cost < s->best_cost)
3773 edge_t *ne;
3774 ne = (edge_t *)malloc (sizeof (*ne));
3775 memset ((void *) ne, 0, sizeof (*ne));
3776 assert (ne);
3777 ne->flags.via_search = 1;
3778 ne->flags.in_plane = in_plane;
3779 ne->rb = rb;
3780 if (rb->flags.homeless)
3781 RB_up_count (rb);
3782 ne->work = work;
3783 ne->mincost_target = target;
3784 ne->flags.via_conflict_level = conflict;
3785 ne->cost_to_point = parent->cost_to_point;
3786 ne->cost_point = parent->cost_point;
3787 ne->cost = cost;
3788 heap_insert (s->workheap, ne->cost, ne);
3790 else
3792 mtsFreeWork (&work);
3796 static void
3797 add_or_destroy_edge (struct routeone_state *s, edge_t * e)
3799 e->cost = edge_cost (e, s->best_cost);
3800 assert (__edge_is_good (e));
3801 assert (is_layer_group_active[e->rb->group]);
3802 if (e->cost < s->best_cost)
3803 heap_insert (s->workheap, e->cost, e);
3804 else
3805 DestroyEdge (&e);
3808 static void
3809 best_path_candidate (struct routeone_state *s,
3810 edge_t * e, routebox_t * best_target)
3812 e->cost = edge_cost (e, EXPENSIVE);
3813 if (s->best_path == NULL || e->cost < s->best_cost)
3815 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE)
3816 printf ("New best path seen! cost = %f\n", e->cost);
3817 #endif
3818 /* new best path! */
3819 if (s->best_path && s->best_path->flags.homeless)
3820 RB_down_count (s->best_path);
3821 s->best_path = e->rb;
3822 s->best_target = best_target;
3823 s->best_cost = e->cost;
3824 assert (s->best_cost >= 0);
3825 /* don't free this when we destroy edge! */
3826 if (s->best_path->flags.homeless)
3827 RB_up_count (s->best_path);
3833 * \brief Vectors for via site candidates (see mtspace.h).
3835 struct routeone_via_site_state
3837 vector_t *free_space_vec;
3838 vector_t *lo_conflict_space_vec;
3839 vector_t *hi_conflict_space_vec;
3842 void
3843 add_via_sites (struct routeone_state *s,
3844 struct routeone_via_site_state *vss,
3845 mtspace_t * mtspace, routebox_t * within,
3846 conflict_t within_conflict_level, edge_t * parent_edge,
3847 rtree_t * targets, Coord shrink, bool in_plane)
3849 Coord radius, keepaway;
3850 vetting_t *work;
3851 BoxType region = shrink_routebox (within);
3852 shrink_box (&region, shrink);
3854 radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3855 keepaway = AutoRouteParameters.style->Keepaway;
3856 assert (AutoRouteParameters.use_vias);
3857 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
3858 XXX: routing with conflicts may poke over edge. */
3860 /* ask for a via box near our cost_point first */
3861 work = mtspace_query_rect (mtspace, &region, radius, keepaway,
3862 NULL, vss->free_space_vec,
3863 vss->lo_conflict_space_vec,
3864 vss->hi_conflict_space_vec,
3865 AutoRouteParameters.is_odd,
3866 AutoRouteParameters.with_conflicts,
3867 &parent_edge->cost_point);
3868 if (!work)
3869 return;
3870 CreateSearchEdge (s, work, parent_edge, within, within_conflict_level,
3871 targets, in_plane);
3874 void
3875 do_via_search (edge_t * search, struct routeone_state *s,
3876 struct routeone_via_site_state *vss, mtspace_t * mtspace,
3877 rtree_t * targets)
3879 int i, j, count = 0;
3880 Coord radius, keepaway;
3881 vetting_t *work;
3882 routebox_t *within;
3883 conflict_t within_conflict_level;
3885 radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3886 keepaway = AutoRouteParameters.style->Keepaway;
3887 work = mtspace_query_rect (mtspace, NULL, 0, 0,
3888 search->work, vss->free_space_vec,
3889 vss->lo_conflict_space_vec,
3890 vss->hi_conflict_space_vec,
3891 AutoRouteParameters.is_odd,
3892 AutoRouteParameters.with_conflicts, NULL);
3893 within = search->rb;
3894 within_conflict_level = search->flags.via_conflict_level;
3895 for (i = 0; i < 3; i++)
3897 vector_t *v =
3898 (i == NO_CONFLICT ? vss->free_space_vec :
3899 i == LO_CONFLICT ? vss->lo_conflict_space_vec :
3900 i == HI_CONFLICT ? vss->hi_conflict_space_vec : NULL);
3901 assert (v);
3902 while (!vector_is_empty (v))
3904 BoxType cliparea;
3905 BoxType *area = (BoxType *)vector_remove_last (v);
3906 if (!(i == NO_CONFLICT || AutoRouteParameters.with_conflicts))
3908 free (area);
3909 continue;
3911 /* answers are bloated by radius + keepaway */
3912 cliparea = shrink_box (area, radius + keepaway);
3913 close_box (&cliparea);
3914 free (area);
3915 assert (box_is_good (&cliparea));
3916 count++;
3917 for (j = 0; j < max_group; j++)
3919 edge_t *ne;
3920 if (j == within->group || !is_layer_group_active[j])
3921 continue;
3922 ne = CreateViaEdge (&cliparea, j, within, search,
3923 within_conflict_level, (conflict_t)i, targets);
3924 add_or_destroy_edge (s, ne);
3928 /* prevent freeing of work when this edge is destroyed */
3929 search->flags.via_search = 0;
3930 if (!work)
3931 return;
3932 CreateSearchEdge (s, work, search, within, within_conflict_level, targets,
3933 search->flags.in_plane);
3934 assert (vector_is_empty (vss->free_space_vec));
3935 assert (vector_is_empty (vss->lo_conflict_space_vec));
3936 assert (vector_is_empty (vss->hi_conflict_space_vec));
3939 /* vector of expansion areas to be eventually removed from r-tree
3940 * this is a global for troubleshooting
3942 vector_t *area_vec;
3944 /* some routines for use in gdb while debugging */
3945 #if defined(ROUTE_DEBUG)
3946 static void
3947 list_conflicts (routebox_t * rb)
3949 int i, n;
3950 if (!rb->conflicts_with)
3951 return;
3952 n = vector_size (rb->conflicts_with);
3953 for (i = 0; i < n; i++)
3954 printf ("%p, ", vector_element (rb->conflicts_with, i));
3957 static void
3958 show_area_vec (int lay)
3960 int n, save;
3962 if (!area_vec)
3963 return;
3964 save = showboxen;
3965 showboxen = lay;
3966 for (n = 0; n < vector_size (area_vec); n++)
3968 routebox_t *rb = (routebox_t *) vector_element (area_vec, n);
3969 showroutebox (rb);
3971 showboxen = save;
3974 static bool
3975 net_id (routebox_t * rb, long int id)
3977 routebox_t *p;
3978 LIST_LOOP (rb, same_net, p);
3979 if (p->flags.source && p->parent.pad->ID == id)
3980 return true;
3981 END_LOOP;
3982 return false;
3985 static void
3986 trace_parents (routebox_t * rb)
3988 while (rb && rb->type == EXPANSION_AREA)
3990 printf (" %p ->", rb);
3991 rb = rb->parent.expansion_area;
3993 if (rb)
3994 printf (" %p is source\n", rb);
3995 else
3996 printf ("NULL!\n");
3999 static void
4000 show_one (routebox_t * rb)
4002 int save = showboxen;
4003 showboxen = -1;
4004 showroutebox (rb);
4005 showboxen = save;
4008 static void
4009 show_path (routebox_t * rb)
4011 while (rb && rb->type == EXPANSION_AREA)
4013 show_one (rb);
4014 rb = rb->parent.expansion_area;
4016 show_one (rb);
4019 static void
4020 show_sources (routebox_t * rb)
4022 routebox_t *p;
4023 if (!rb->flags.source && !rb->flags.target)
4025 printf ("start with a source or target please\n");
4026 return;
4028 LIST_LOOP (rb, same_net, p);
4029 if (p->flags.source)
4030 show_one (p);
4031 END_LOOP;
4034 #endif
4036 static int
4037 __conflict_source (const BoxType * box, void *cl)
4039 routebox_t *rb = (routebox_t *) box;
4040 if (rb->flags.touched || rb->flags.fixed)
4041 return 0;
4042 else
4044 routebox_t *dis = (routebox_t *) cl;
4045 path_conflicts (dis, rb, false);
4046 touch_conflicts (dis->conflicts_with, 1);
4048 return 1;
4051 static void
4052 source_conflicts (rtree_t * tree, routebox_t * rb)
4054 if (!AutoRouteParameters.with_conflicts)
4055 return;
4056 r_search (tree, &rb->sbox, NULL, __conflict_source, rb);
4057 touch_conflicts (NULL, 1);
4060 struct routeone_status
4062 bool found_route;
4063 int route_had_conflicts;
4064 cost_t best_route_cost;
4065 bool net_completely_routed;
4069 static struct routeone_status
4070 RouteOne (routedata_t * rd, routebox_t * from, routebox_t * to, int max_edges)
4072 struct routeone_status result;
4073 routebox_t *p;
4074 int seen, i;
4075 const BoxType **target_list;
4076 int num_targets;
4077 rtree_t *targets;
4078 /* vector of source edges for filtering */
4079 vector_t *source_vec;
4080 /* working vector */
4081 vector_t *edge_vec;
4083 struct routeone_state s;
4084 struct routeone_via_site_state vss;
4086 assert (rd && from);
4087 result.route_had_conflicts = 0;
4088 /* no targets on to/from net need keepaway areas */
4089 LIST_LOOP (from, same_net, p);
4090 p->flags.nobloat = 1;
4091 END_LOOP;
4092 /* set 'source' flags */
4093 LIST_LOOP (from, same_subnet, p);
4094 if (!p->flags.nonstraight)
4095 p->flags.source = 1;
4096 END_LOOP;
4098 /* count up the targets */
4099 num_targets = 0;
4100 seen = 0;
4101 /* remove source/target flags from non-straight obstacles, because they
4102 * don't fill their bounding boxes and so connecting to them
4103 * after we've routed is problematic. Better solution? */
4104 if (to)
4105 { /* if we're routing to a specific target */
4106 if (!to->flags.source)
4107 { /* not already connected */
4108 /* check that 'to' and 'from' are on the same net */
4109 seen = 0;
4110 #ifndef NDEBUG
4111 LIST_LOOP (from, same_net, p);
4112 if (p == to)
4113 seen = 1;
4114 END_LOOP;
4115 #endif
4116 assert (seen); /* otherwise from and to are on different nets! */
4117 /* set target flags only on 'to's subnet */
4118 LIST_LOOP (to, same_subnet, p);
4119 if (!p->flags.nonstraight && is_layer_group_active[p->group])
4121 p->flags.target = 1;
4122 num_targets++;
4124 END_LOOP;
4127 else
4129 /* all nodes on the net but not connected to from are targets */
4130 LIST_LOOP (from, same_net, p);
4131 if (!p->flags.source && is_layer_group_active[p->group]
4132 && !p->flags.nonstraight)
4134 p->flags.target = 1;
4135 num_targets++;
4137 END_LOOP;
4140 /* if no targets, then net is done! reset flags and return. */
4141 if (num_targets == 0)
4143 LIST_LOOP (from, same_net, p);
4144 p->flags.source = p->flags.target = p->flags.nobloat = 0;
4145 END_LOOP;
4146 result.found_route = false;
4147 result.net_completely_routed = true;
4148 result.best_route_cost = 0;
4149 result.route_had_conflicts = 0;
4151 return result;
4153 result.net_completely_routed = false;
4155 /* okay, there's stuff to route */
4156 assert (!from->flags.target);
4157 assert (num_targets > 0);
4158 /* create list of target pointers and from that a r-tree of targets */
4159 target_list = (const BoxType **)malloc (num_targets * sizeof (*target_list));
4160 i = 0;
4161 LIST_LOOP (from, same_net, p);
4162 if (p->flags.target)
4164 target_list[i++] = &p->box;
4165 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
4166 showroutebox (p);
4167 #endif
4169 END_LOOP;
4170 targets = r_create_tree ((const BoxType **)target_list, i, 0);
4171 assert (i <= num_targets);
4172 free (target_list);
4174 source_vec = vector_create ();
4175 /* touch the source subnet to prepare check for conflictors */
4176 LIST_LOOP (from, same_subnet, p);
4177 p->flags.touched = 1;
4178 END_LOOP;
4179 LIST_LOOP (from, same_subnet, p);
4181 /* we need the test for 'source' because this box may be nonstraight */
4182 if (p->flags.source && is_layer_group_active[p->group])
4184 CheapPointType cp;
4185 edge_t *e;
4186 BoxType b = shrink_routebox (p);
4188 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES)
4189 showroutebox (p);
4190 #endif
4191 /* may expand in all directions from source; center edge cost point. */
4192 /* note that planes shouldn't really expand, but we need an edge */
4194 cp.X = CENTER_X (b);
4195 cp.Y = CENTER_Y (b);
4196 e = CreateEdge (p, cp.X, cp.Y, 0, NULL, ALL, targets);
4197 cp = closest_point_in_box (&cp, &e->mincost_target->sbox);
4198 cp = closest_point_in_box (&cp, &b);
4199 e->cost_point = cp;
4200 p->cost_point = cp;
4201 source_conflicts (rd->layergrouptree[p->group], p);
4202 vector_append (source_vec, e);
4205 END_LOOP;
4206 LIST_LOOP (from, same_subnet, p);
4207 p->flags.touched = 0;
4208 END_LOOP;
4209 /* break source edges; some edges may be too near obstacles to be able
4210 * to exit from. */
4212 /* okay, main expansion-search routing loop. */
4213 /* set up the initial activity heap */
4214 s.workheap = heap_create ();
4215 assert (s.workheap);
4216 while (!vector_is_empty (source_vec))
4218 edge_t *e = (edge_t *)vector_remove_last (source_vec);
4219 assert (is_layer_group_active[e->rb->group]);
4220 e->cost = edge_cost (e, EXPENSIVE);
4221 heap_insert (s.workheap, e->cost, e);
4223 vector_destroy (&source_vec);
4224 /* okay, process items from heap until it is empty! */
4225 s.best_path = NULL;
4226 s.best_cost = EXPENSIVE;
4227 area_vec = vector_create ();
4228 edge_vec = vector_create ();
4229 vss.free_space_vec = vector_create ();
4230 vss.lo_conflict_space_vec = vector_create ();
4231 vss.hi_conflict_space_vec = vector_create ();
4232 while (!heap_is_empty (s.workheap))
4234 edge_t *e = (edge_t *)heap_remove_smallest (s.workheap);
4235 #ifdef ROUTE_DEBUG
4236 if (aabort)
4237 goto dontexpand;
4238 #endif
4239 /* don't bother expanding this edge if the minimum possible edge cost
4240 * is already larger than the best edge cost we've found. */
4241 if (s.best_path && e->cost >= s.best_cost)
4243 heap_free (s.workheap, KillEdge);
4244 goto dontexpand; /* skip this edge */
4246 /* surprisingly it helps to give up and not try too hard to find
4247 * a route! This is not only faster, but results in better routing.
4248 * who would have guessed?
4250 if (seen++ > max_edges)
4251 goto dontexpand;
4252 assert (__edge_is_good (e));
4253 /* mark or unmark conflictors as needed */
4254 touch_conflicts (e->rb->conflicts_with, 1);
4255 if (e->flags.via_search)
4257 do_via_search (e, &s, &vss, rd->mtspace, targets);
4258 goto dontexpand;
4260 /* we should never add edges on inactive layer groups to the heap. */
4261 assert (is_layer_group_active[e->rb->group]);
4262 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
4263 //showedge (e);
4264 #endif
4265 if (e->rb->flags.is_thermal)
4267 best_path_candidate (&s, e, e->mincost_target);
4268 goto dontexpand;
4270 /* for a plane, look for quick connections with thermals or vias */
4271 if (e->rb->type == PLANE)
4273 routebox_t *pin = FindThermable (targets, e->rb);
4274 if (pin)
4276 BoxType b = shrink_routebox (pin);
4277 edge_t *ne;
4278 routebox_t *nrb;
4279 assert (pin->flags.target);
4280 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
4281 nrb->flags.is_thermal = 1;
4282 /* moving through the plane is free */
4283 e->cost_point.X = b.X1;
4284 e->cost_point.Y = b.Y1;
4285 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, pin);
4286 best_path_candidate (&s, ne, pin);
4287 DestroyEdge (&ne);
4289 else
4291 /* add in possible via sites in plane */
4292 if (AutoRouteParameters.use_vias &&
4293 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
4295 /* we need a giant thermal */
4296 routebox_t *nrb =
4297 CreateExpansionArea (&e->rb->sbox, e->rb->group, e->rb,
4298 true, e);
4299 edge_t *ne = CreateEdge2 (nrb, e->expand_dir, e, NULL,
4300 e->mincost_target);
4301 nrb->flags.is_thermal = 1;
4302 add_via_sites (&s, &vss, rd->mtspace, nrb, NO_CONFLICT, ne,
4303 targets, e->rb->style->Diameter, true);
4306 goto dontexpand; /* planes only connect via thermals */
4308 if (e->flags.is_via)
4309 { /* special case via */
4310 routebox_t *intersecting;
4311 assert (AutoRouteParameters.use_vias);
4312 assert (e->expand_dir == ALL);
4313 assert (vector_is_empty (edge_vec));
4314 /* if there is already something here on this layer (like an
4315 * EXPANSION_AREA), then we don't want to expand from here
4316 * at least not inside the expansion area. A PLANE on the
4317 * other hand may be a target, or not.
4319 intersecting =
4320 FindOneInBox (rd->layergrouptree[e->rb->group], e->rb);
4322 if (intersecting && intersecting->flags.target
4323 && intersecting->type == PLANE)
4325 /* we have hit a plane */
4326 edge_t *ne;
4327 routebox_t *nrb;
4328 BoxType b = shrink_routebox (e->rb);
4329 /* limit via region to that inside the plane */
4330 clip_box (&b, &intersecting->sbox);
4331 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
4332 nrb->flags.is_thermal = 1;
4333 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, intersecting);
4334 best_path_candidate (&s, ne, intersecting);
4335 DestroyEdge (&ne);
4336 goto dontexpand;
4338 else if (intersecting == NULL)
4340 /* this via candidate is in an open area; add it to r-tree as
4341 * an expansion area */
4342 assert (e->rb->type == EXPANSION_AREA && e->rb->flags.is_via);
4343 /*assert (!r_search (rd->layergrouptree[e->rb->group],
4344 &e->rb->box, NULL, no_planes,0));
4346 r_insert_entry (rd->layergrouptree[e->rb->group], &e->rb->box,
4348 e->rb->flags.homeless = 0; /* not homeless any more */
4349 /* add to vector of all expansion areas in r-tree */
4350 vector_append (area_vec, e->rb);
4351 /* mark reset refcount to 0, since this is not homeless any more. */
4352 e->rb->refcount = 0;
4353 /* go ahead and expand this edge! */
4355 else if (1)
4356 goto dontexpand;
4357 else if (0)
4358 { /* XXX: disabling this causes no via
4359 collisions. */
4360 BoxType a = bloat_routebox (intersecting), b;
4361 edge_t *ne;
4362 int i, j;
4363 /* something intersects this via candidate. split via candidate
4364 * into pieces and add these pieces to the workheap. */
4365 for (i = 0; i < 3; i++)
4367 for (j = 0; j < 3; j++)
4369 b = shrink_routebox (e->rb);
4370 switch (i)
4372 case 0:
4373 b.X2 = MIN (b.X2, a.X1);
4374 break; /* left */
4375 case 1:
4376 b.X1 = MAX (b.X1, a.X1);
4377 b.X2 = MIN (b.X2, a.X2);
4378 break; /*c */
4379 case 2:
4380 b.X1 = MAX (b.X1, a.X2);
4381 break; /* right */
4382 default:
4383 assert (0);
4385 switch (j)
4387 case 0:
4388 b.Y2 = MIN (b.Y2, a.Y1);
4389 break; /* top */
4390 case 1:
4391 b.Y1 = MAX (b.Y1, a.Y1);
4392 b.Y2 = MIN (b.Y2, a.Y2);
4393 break; /*c */
4394 case 2:
4395 b.Y1 = MAX (b.Y1, a.Y2);
4396 break; /* bottom */
4397 default:
4398 assert (0);
4400 /* skip if this box is not valid */
4401 if (!(b.X1 < b.X2 && b.Y1 < b.Y2))
4402 continue;
4403 if (i == 1 && j == 1)
4405 /* this bit of the via space is obstructed. */
4406 if (intersecting->type == EXPANSION_AREA
4407 || intersecting->flags.fixed)
4408 continue; /* skip this bit, it's already been done. */
4409 /* create an edge with conflicts, if enabled */
4410 if (!AutoRouteParameters.with_conflicts)
4411 continue;
4412 ne = CreateEdgeWithConflicts (&b, intersecting, e, 1
4413 /*cost penalty to box */
4414 , targets);
4415 add_or_destroy_edge (&s, ne);
4417 else
4419 /* if this is not the intersecting piece, create a new
4420 * (hopefully unobstructed) via edge and add it back to the
4421 * workheap. */
4422 ne =
4423 CreateViaEdge (&b, e->rb->group,
4424 e->rb->parent.expansion_area, e,
4425 e->flags.via_conflict_level,
4426 NO_CONFLICT
4427 /* value here doesn't matter */
4428 , targets);
4429 add_or_destroy_edge (&s, ne);
4433 goto dontexpand;
4435 /* between the time these edges are inserted and the
4436 * time they are processed, new expansion boxes (which
4437 * conflict with these edges) may be added to the graph!
4438 * w.o vias this isn't a problem because the broken box
4439 * is not homeless. */
4441 if (1)
4443 routebox_t *nrb;
4444 struct E_result *ans;
4445 BoxType b;
4446 vector_t *broken;
4447 if (e->flags.is_interior)
4449 assert (AutoRouteParameters.with_conflicts); /* no interior edges unless
4450 routing with conflicts! */
4451 assert (e->rb->conflicts_with);
4452 b = e->rb->sbox;
4453 switch (e->rb->came_from)
4455 case NORTH:
4456 b.Y2 = b.Y1 + 1;
4457 b.X1 = CENTER_X (b);
4458 b.X2 = b.X1 + 1;
4459 break;
4460 case EAST:
4461 b.X1 = b.X2 - 1;
4462 b.Y1 = CENTER_Y (b);
4463 b.Y2 = b.Y1 + 1;
4464 break;
4465 case SOUTH:
4466 b.Y1 = b.Y2 - 1;
4467 b.X1 = CENTER_X (b);
4468 b.X2 = b.X1 + 1;
4469 break;
4470 case WEST:
4471 b.X2 = b.X1 + 1;
4472 b.Y1 = CENTER_Y (b);
4473 b.Y2 = b.Y1 + 1;
4474 break;
4475 default:
4476 assert (0);
4479 /* sources may not expand to their own edges because of
4480 * adjacent blockers.
4482 else if (e->rb->flags.source)
4483 b = box_center (&e->rb->sbox);
4484 else
4485 b = e->rb->sbox;
4486 ans = Expand (rd->layergrouptree[e->rb->group], e, &b);
4487 if (!box_intersect (&ans->inflated, &ans->orig))
4488 goto dontexpand;
4489 #if 0
4490 /* skip if it didn't actually expand */
4491 if (ans->inflated.X1 >= e->rb->sbox.X1 &&
4492 ans->inflated.X2 <= e->rb->sbox.X2 &&
4493 ans->inflated.Y1 >= e->rb->sbox.Y1 &&
4494 ans->inflated.Y2 <= e->rb->sbox.Y2)
4495 goto dontexpand;
4496 #endif
4498 if (!box_is_good (&ans->inflated))
4499 goto dontexpand;
4500 nrb = CreateExpansionArea (&ans->inflated, e->rb->group, e->rb,
4501 true, e);
4502 r_insert_entry (rd->layergrouptree[nrb->group], &nrb->box, 1);
4503 vector_append (area_vec, nrb);
4504 nrb->flags.homeless = 0; /* not homeless any more */
4505 broken =
4506 BreakManyEdges (&s, targets, rd->layergrouptree[nrb->group],
4507 area_vec, ans, nrb, e);
4508 while (!vector_is_empty (broken))
4510 edge_t *ne = (edge_t *)vector_remove_last (broken);
4511 add_or_destroy_edge (&s, ne);
4513 vector_destroy (&broken);
4515 /* add in possible via sites in nrb */
4516 if (AutoRouteParameters.use_vias && !e->rb->flags.is_via &&
4517 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
4518 add_via_sites (&s, &vss,
4519 rd->mtspace, nrb, NO_CONFLICT, e, targets, 0,
4520 false);
4521 goto dontexpand;
4523 dontexpand:
4524 DestroyEdge (&e);
4526 touch_conflicts (NULL, 1);
4527 heap_destroy (&s.workheap);
4528 r_destroy_tree (&targets);
4529 assert (vector_is_empty (edge_vec));
4530 vector_destroy (&edge_vec);
4532 /* we should have a path in best_path now */
4533 if (s.best_path)
4535 routebox_t *rb;
4536 #ifdef ROUTE_VERBOSE
4537 printf ("%d:%d RC %.0f", ro++, seen, s.best_cost);
4538 #endif
4539 result.found_route = true;
4540 result.best_route_cost = s.best_cost;
4541 /* determine if the best path had conflicts */
4542 result.route_had_conflicts = 0;
4543 if (AutoRouteParameters.with_conflicts && s.best_path->conflicts_with)
4545 while (!vector_is_empty (s.best_path->conflicts_with))
4547 rb = (routebox_t *)vector_remove_last (s.best_path->conflicts_with);
4548 rb->flags.is_bad = 1;
4549 result.route_had_conflicts++;
4552 #ifdef ROUTE_VERBOSE
4553 if (result.route_had_conflicts)
4554 printf (" (%d conflicts)", result.route_had_conflicts);
4555 #endif
4556 if (result.route_had_conflicts < AutoRouteParameters.hi_conflict)
4558 /* back-trace the path and add lines/vias to r-tree */
4559 TracePath (rd, s.best_path, s.best_target, from,
4560 result.route_had_conflicts);
4561 MergeNets (from, s.best_target, SUBNET);
4563 else
4565 #ifdef ROUTE_VERBOSE
4566 printf (" (too many in fact)");
4567 #endif
4568 result.found_route = false;
4570 #ifdef ROUTE_VERBOSE
4571 printf ("\n");
4572 #endif
4574 else
4576 #ifdef ROUTE_VERBOSE
4577 printf ("%d:%d NO PATH FOUND.\n", ro++, seen);
4578 #endif
4579 result.best_route_cost = s.best_cost;
4580 result.found_route = false;
4582 /* now remove all expansion areas from the r-tree. */
4583 while (!vector_is_empty (area_vec))
4585 routebox_t *rb = (routebox_t *)vector_remove_last (area_vec);
4586 assert (!rb->flags.homeless);
4587 if (rb->conflicts_with
4588 && rb->parent.expansion_area->conflicts_with != rb->conflicts_with)
4589 vector_destroy (&rb->conflicts_with);
4590 r_delete_entry (rd->layergrouptree[rb->group], &rb->box);
4592 vector_destroy (&area_vec);
4593 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
4594 LIST_LOOP (from, same_net, p);
4595 if (p->flags.source && p->conflicts_with)
4596 vector_destroy (&p->conflicts_with);
4597 p->flags.touched = p->flags.source = p->flags.target = p->flags.nobloat = 0;
4598 END_LOOP;
4600 vector_destroy (&vss.free_space_vec);
4601 vector_destroy (&vss.lo_conflict_space_vec);
4602 vector_destroy (&vss.hi_conflict_space_vec);
4604 return result;
4607 static void
4608 InitAutoRouteParameters (int pass,
4609 RouteStyleType * style,
4610 bool with_conflicts, bool is_smoothing,
4611 bool lastpass)
4613 int i;
4614 /* routing style */
4615 AutoRouteParameters.style = style;
4616 AutoRouteParameters.bloat = style->Keepaway + HALF_THICK (style->Thick);
4617 /* costs */
4618 AutoRouteParameters.ViaCost =
4619 INCH_TO_COORD (3.5) + style->Diameter * (is_smoothing ? 80 : 30);
4620 AutoRouteParameters.LastConflictPenalty =
4621 (400 * pass / passes + 2) / (pass + 1);
4622 AutoRouteParameters.ConflictPenalty =
4623 4 * AutoRouteParameters.LastConflictPenalty;
4624 AutoRouteParameters.JogPenalty = 1000 * (is_smoothing ? 20 : 4);
4625 AutoRouteParameters.CongestionPenalty = 1e6;
4626 AutoRouteParameters.MinPenalty = EXPENSIVE;
4627 for (i = 0; i < max_group; i++)
4629 if (is_layer_group_active[i])
4631 AutoRouteParameters.MinPenalty = MIN (x_cost[i],
4632 AutoRouteParameters.
4633 MinPenalty);
4634 AutoRouteParameters.MinPenalty =
4635 MIN (y_cost[i], AutoRouteParameters.MinPenalty);
4638 AutoRouteParameters.NewLayerPenalty = is_smoothing ?
4639 0.5 * EXPENSIVE : 10 * AutoRouteParameters.ViaCost;
4640 /* other */
4641 AutoRouteParameters.hi_conflict = MAX (8 * (passes - pass + 1), 6);
4642 AutoRouteParameters.is_odd = (pass & 1);
4643 AutoRouteParameters.with_conflicts = with_conflicts;
4644 AutoRouteParameters.is_smoothing = is_smoothing;
4645 AutoRouteParameters.rip_always = is_smoothing;
4646 AutoRouteParameters.last_smooth = 0; //lastpass;
4647 AutoRouteParameters.pass = pass + 1;
4650 #ifndef NDEBUG
4652 bad_boy (const BoxType * b, void *cl)
4654 routebox_t *box = (routebox_t *) b;
4655 if (box->type == EXPANSION_AREA)
4656 return 1;
4657 return 0;
4660 bool
4661 no_expansion_boxes (routedata_t * rd)
4663 int i;
4664 BoxType big;
4665 big.X1 = 0;
4666 big.X2 = MAX_COORD;
4667 big.Y1 = 0;
4668 big.Y2 = MAX_COORD;
4669 for (i = 0; i < max_group; i++)
4671 if (r_search (rd->layergrouptree[i], &big, NULL, bad_boy, NULL))
4672 return false;
4674 return true;
4676 #endif
4678 static void
4679 ripout_livedraw_obj (routebox_t *rb)
4681 if (rb->type == LINE && rb->livedraw_obj.line)
4683 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
4684 EraseLine (rb->livedraw_obj.line);
4685 DestroyObject (PCB->Data, LINE_TYPE, layer, rb->livedraw_obj.line, NULL);
4686 rb->livedraw_obj.line = NULL;
4688 if (rb->type == VIA && rb->livedraw_obj.via)
4690 EraseVia (rb->livedraw_obj.via);
4691 DestroyObject (PCB->Data, VIA_TYPE, rb->livedraw_obj.via, NULL, NULL);
4692 rb->livedraw_obj.via = NULL;
4696 static int
4697 ripout_livedraw_obj_cb (const BoxType * b, void *cl)
4699 routebox_t *box = (routebox_t *) b;
4700 ripout_livedraw_obj (box);
4701 return 0;
4704 struct routeall_status
4706 /* --- for completion rate statistics ---- */
4707 int total_subnets;
4708 /* total subnets routed without conflicts */
4709 int routed_subnets;
4710 /* total subnets routed with conflicts */
4711 int conflict_subnets;
4712 /* net failted entirely */
4713 int failed;
4714 /* net was ripped */
4715 int ripped;
4716 int total_nets_routed;
4719 static double
4720 calculate_progress (double this_heap_item, double this_heap_size,
4721 struct routeall_status *ras)
4723 double total_passes = passes + smoothes + 1; /* + 1 is the refinement pass */
4724 double this_pass = AutoRouteParameters.pass - 1; /* Number passes from zero */
4725 double heap_fraction = (double)(ras->routed_subnets + ras->conflict_subnets + ras->failed) /
4726 (double)ras->total_subnets;
4727 double pass_fraction = (this_heap_item + heap_fraction ) / this_heap_size;
4728 double process_fraction = (this_pass + pass_fraction) / total_passes;
4730 return process_fraction;
4733 struct routeall_status
4734 RouteAll (routedata_t * rd)
4736 struct routeall_status ras;
4737 struct routeone_status ros;
4738 bool rip;
4739 int request_cancel;
4740 #ifdef NET_HEAP
4741 heap_t *net_heap;
4742 #endif
4743 heap_t *this_pass, *next_pass, *tmp;
4744 routebox_t *net, *p, *pp;
4745 cost_t total_net_cost, last_cost = 0, this_cost = 0;
4746 int i;
4747 int this_heap_size;
4748 int this_heap_item;
4750 /* initialize heap for first pass;
4751 * do smallest area first; that makes
4752 * the subsequent costs more representative */
4753 this_pass = heap_create ();
4754 next_pass = heap_create ();
4755 #ifdef NET_HEAP
4756 net_heap = heap_create ();
4757 #endif
4758 LIST_LOOP (rd->first_net, different_net, net);
4760 double area;
4761 BoxType bb = shrink_routebox (net);
4762 LIST_LOOP (net, same_net, p);
4764 MAKEMIN (bb.X1, p->sbox.X1);
4765 MAKEMIN (bb.Y1, p->sbox.Y1);
4766 MAKEMAX (bb.X2, p->sbox.X2);
4767 MAKEMAX (bb.Y2, p->sbox.Y2);
4769 END_LOOP;
4770 area = (double) (bb.X2 - bb.X1) * (bb.Y2 - bb.Y1);
4771 heap_insert (this_pass, area, net);
4773 END_LOOP;
4775 ras.total_nets_routed = 0;
4776 /* refinement/finishing passes */
4777 for (i = 0; i <= passes + smoothes; i++)
4779 #ifdef ROUTE_VERBOSE
4780 if (i > 0 && i <= passes)
4781 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i);
4782 else if (i > passes)
4783 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
4784 i - passes);
4785 #endif
4786 ras.total_subnets = ras.routed_subnets = ras.conflict_subnets =
4787 ras.failed = ras.ripped = 0;
4788 assert (heap_is_empty (next_pass));
4790 this_heap_size = heap_size (this_pass);
4791 for (this_heap_item = 0; !heap_is_empty (this_pass); this_heap_item++)
4793 #ifdef ROUTE_DEBUG
4794 if (aabort)
4795 break;
4796 #endif
4797 net = (routebox_t *) heap_remove_smallest (this_pass);
4798 InitAutoRouteParameters (i, net->style, i < passes, i > passes,
4799 i == passes + smoothes);
4800 if (i > 0)
4802 /* rip up all unfixed traces in this net ? */
4803 if (AutoRouteParameters.rip_always)
4804 rip = true;
4805 else
4807 rip = false;
4808 LIST_LOOP (net, same_net, p);
4809 if (p->flags.is_bad)
4811 rip = true;
4812 break;
4814 END_LOOP;
4817 LIST_LOOP (net, same_net, p);
4818 p->flags.is_bad = 0;
4819 if (!p->flags.fixed)
4821 #ifndef NDEBUG
4822 bool del;
4823 #endif
4824 assert (!p->flags.homeless);
4825 if (rip)
4827 RemoveFromNet (p, NET);
4828 RemoveFromNet (p, SUBNET);
4830 if (AutoRouteParameters.use_vias && p->type != VIA_SHADOW
4831 && p->type != PLANE)
4833 mtspace_remove (rd->mtspace, &p->box,
4834 p->flags.is_odd ? ODD : EVEN,
4835 p->style->Keepaway);
4836 if (!rip)
4837 mtspace_add (rd->mtspace, &p->box,
4838 p->flags.is_odd ? EVEN : ODD,
4839 p->style->Keepaway);
4841 if (rip)
4843 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
4844 ripout_livedraw_obj (p);
4845 #ifndef NDEBUG
4846 del =
4847 #endif
4848 r_delete_entry (rd->layergrouptree[p->group],
4849 &p->box);
4850 #ifndef NDEBUG
4851 assert (del);
4852 #endif
4854 else
4856 p->flags.is_odd = AutoRouteParameters.is_odd;
4859 END_LOOP;
4860 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
4861 Draw ();
4862 /* reset to original connectivity */
4863 if (rip)
4865 ras.ripped++;
4866 ResetSubnet (net);
4868 else
4870 heap_insert (next_pass, 0, net);
4871 continue;
4874 /* count number of subnets */
4875 FOREACH_SUBNET (net, p);
4876 ras.total_subnets++;
4877 END_FOREACH (net, p);
4878 /* the first subnet doesn't require routing. */
4879 ras.total_subnets--;
4880 /* and re-route! */
4881 total_net_cost = 0;
4882 /* only route that which isn't fully routed */
4883 #ifdef ROUTE_DEBUG
4884 if (ras.total_subnets == 0 || aabort)
4885 #else
4886 if (ras.total_subnets == 0)
4887 #endif
4889 heap_insert (next_pass, 0, net);
4890 continue;
4893 /* the loop here ensures that we get to all subnets even if
4894 * some of them are unreachable from the first subnet. */
4895 LIST_LOOP (net, same_net, p);
4897 #ifdef NET_HEAP
4898 BoxType b = shrink_routebox (p);
4899 /* using a heap allows us to start from smaller objects and
4900 * end at bigger ones. also prefer to start at planes, then pads */
4901 heap_insert (net_heap, (float) (b.X2 - b.X1) *
4902 #if defined(ROUTE_RANDOMIZED)
4903 (0.3 + rand () / (RAND_MAX + 1.0)) *
4904 #endif
4905 (b.Y2 - b.Y1) * (p->type == PLANE ?
4906 -1 : (p->type ==
4907 PAD ? 1 : 10)), p);
4909 END_LOOP;
4910 ros.net_completely_routed = 0;
4911 while (!heap_is_empty (net_heap))
4913 p = (routebox_t *) heap_remove_smallest (net_heap);
4914 #endif
4915 if (!p->flags.fixed || p->flags.subnet_processed ||
4916 p->type == OTHER)
4917 continue;
4919 while (!ros.net_completely_routed)
4921 double percent;
4923 assert (no_expansion_boxes (rd));
4924 /* FIX ME: the number of edges to examine should be in autoroute parameters
4925 * i.e. the 2000 and 800 hard-coded below should be controllable by the user
4927 ros =
4928 RouteOne (rd, p, NULL,
4929 ((AutoRouteParameters.
4930 is_smoothing ? 2000 : 800) * (i +
4931 1)) *
4932 routing_layers);
4933 total_net_cost += ros.best_route_cost;
4934 if (ros.found_route)
4936 if (ros.route_had_conflicts)
4937 ras.conflict_subnets++;
4938 else
4940 ras.routed_subnets++;
4941 ras.total_nets_routed++;
4944 else
4946 if (!ros.net_completely_routed)
4947 ras.failed++;
4948 /* don't bother trying any other source in this subnet */
4949 LIST_LOOP (p, same_subnet, pp);
4950 pp->flags.subnet_processed = 1;
4951 END_LOOP;
4952 break;
4954 /* note that we can infer nothing about ras.total_subnets based
4955 * on the number of calls to RouteOne, because we may be unable
4956 * to route a net from a particular starting point, but perfectly
4957 * able to route it from some other. */
4958 percent = calculate_progress (this_heap_item, this_heap_size, &ras);
4959 request_cancel = gui->progress (percent * 100., 100,
4960 _("Autorouting tracks"));
4961 if (request_cancel)
4963 ras.total_nets_routed = 0;
4964 ras.conflict_subnets = 0;
4965 Message ("Autorouting cancelled\n");
4966 goto out;
4970 #ifndef NET_HEAP
4971 END_LOOP;
4972 #endif
4973 if (!ros.net_completely_routed)
4974 net->flags.is_bad = 1; /* don't skip this the next round */
4976 /* Route easiest nets from this pass first on next pass.
4977 * This works best because it's likely that the hardest
4978 * is the last one routed (since it has the most obstacles)
4979 * but it will do no good to rip it up and try it again
4980 * without first changing any of the other routes
4982 heap_insert (next_pass, total_net_cost, net);
4983 if (total_net_cost < EXPENSIVE)
4984 this_cost += total_net_cost;
4985 /* reset subnet_processed flags */
4986 LIST_LOOP (net, same_net, p);
4988 p->flags.subnet_processed = 0;
4990 END_LOOP;
4992 /* swap this_pass and next_pass and do it all over again! */
4993 ro = 0;
4994 assert (heap_is_empty (this_pass));
4995 tmp = this_pass;
4996 this_pass = next_pass;
4997 next_pass = tmp;
4998 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE)
4999 printf
5000 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n",
5001 i, ras.routed_subnets, ras.total_subnets, this_cost,
5002 ras.conflict_subnets, ras.failed, ras.ripped);
5003 #endif
5004 #ifdef ROUTE_DEBUG
5005 if (aabort)
5006 break;
5007 #endif
5008 /* if no conflicts found, skip directly to smoothing pass! */
5009 if (ras.conflict_subnets == 0 && ras.routed_subnets == ras.total_subnets
5010 && i <= passes)
5011 i = passes - (smoothes ? 0 : 1);
5012 /* if no changes in a smoothing round, then we're done */
5013 if (this_cost == last_cost && i > passes && i < passes + smoothes)
5014 i = passes + smoothes - 1;
5015 last_cost = this_cost;
5016 this_cost = 0;
5019 Message ("%d of %d nets successfully routed.\n",
5020 ras.routed_subnets, ras.total_subnets);
5022 out:
5023 heap_destroy (&this_pass);
5024 heap_destroy (&next_pass);
5025 #ifdef NET_HEAP
5026 heap_destroy (&net_heap);
5027 #endif
5029 /* no conflicts should be left at the end of the process. */
5030 assert (ras.conflict_subnets == 0);
5032 return ras;
5035 struct fpin_info
5037 PinType *pin;
5038 Coord X, Y;
5039 jmp_buf env;
5042 static int
5043 fpin_rect (const BoxType * b, void *cl)
5045 PinType *pin = (PinType *) b;
5046 struct fpin_info *info = (struct fpin_info *) cl;
5047 if (pin->X == info->X && pin->Y == info->Y)
5049 info->pin = (PinType *) b;
5050 longjmp (info->env, 1);
5052 return 0;
5055 static int
5056 FindPin (const BoxType * box, PinType ** pin)
5058 struct fpin_info info;
5060 info.pin = NULL;
5061 info.X = box->X1;
5062 info.Y = box->Y1;
5063 if (setjmp (info.env) == 0)
5064 r_search (PCB->Data->pin_tree, box, NULL, fpin_rect, &info);
5065 else
5067 *pin = info.pin;
5068 return PIN_TYPE;
5070 if (setjmp (info.env) == 0)
5071 r_search (PCB->Data->via_tree, box, NULL, fpin_rect, &info);
5072 else
5074 *pin = info.pin;
5075 return VIA_TYPE;
5077 *pin = NULL;
5078 return NO_TYPE;
5083 * \brief Paths go on first 'on' layer in group.
5085 * Returns 'true' if any paths were added.
5087 bool
5088 IronDownAllUnfixedPaths (routedata_t * rd)
5090 bool changed = false;
5091 LayerType *layer;
5092 routebox_t *net, *p;
5093 int i;
5094 LIST_LOOP (rd->first_net, different_net, net);
5096 LIST_LOOP (net, same_net, p);
5098 if (!p->flags.fixed)
5100 /* find first on layer in this group */
5101 assert (PCB->LayerGroups.Number[p->group] > 0);
5102 assert (is_layer_group_active[p->group]);
5103 for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group];
5104 i++)
5106 layer = LAYER_PTR (PCB->LayerGroups.Entries[p->group][i]);
5107 if (layer->On)
5108 break;
5110 assert (layer && layer->On); /*at least one layer must be on in this group! */
5111 assert (p->type != EXPANSION_AREA);
5112 if (p->type == LINE)
5114 Coord halfwidth = HALF_THICK (p->style->Thick);
5115 double th = halfwidth * 2 + 1;
5116 BoxType b;
5117 assert (p->parent.line == NULL);
5118 /* orthogonal; thickness is 2*halfwidth */
5119 /* flip coordinates, if bl_to_ur */
5120 b = p->sbox;
5121 total_wire_length +=
5122 sqrt ((b.X2 - b.X1 - th) * (b.X2 - b.X1 - th) +
5123 (b.Y2 - b.Y1 - th) * (b.Y2 - b.Y1 - th));
5124 b = shrink_box (&b, halfwidth);
5125 if (b.X2 == b.X1 + 1)
5126 b.X2 = b.X1;
5127 if (b.Y2 == b.Y1 + 1)
5128 b.Y2 = b.Y1;
5129 if (p->flags.bl_to_ur)
5131 Coord t;
5132 t = b.X1;
5133 b.X1 = b.X2;
5134 b.X2 = t;
5136 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
5137 p->parent.line = CreateDrawnLineOnLayer
5138 (layer, b.X1, b.Y1, b.X2, b.Y2,
5139 p->style->Thick,
5140 p->style->Keepaway * 2,
5141 MakeFlags (AUTOFLAG |
5142 (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG :
5143 0)));
5145 if (p->parent.line)
5147 AddObjectToCreateUndoList (LINE_TYPE, layer,
5148 p->parent.line, p->parent.line);
5149 changed = true;
5152 else if (p->type == VIA || p->type == VIA_SHADOW)
5154 routebox_t *pp =
5155 (p->type == VIA_SHADOW) ? p->parent.via_shadow : p;
5156 Coord radius = HALF_THICK (pp->style->Diameter);
5157 BoxType b = shrink_routebox (p);
5158 total_via_count++;
5159 assert (pp->type == VIA);
5160 if (pp->parent.via == NULL)
5162 assert (b.X1 + radius == b.X2 - radius);
5163 assert (b.Y1 + radius == b.Y2 - radius);
5164 pp->parent.via =
5165 CreateNewVia (PCB->Data, b.X1 + radius,
5166 b.Y1 + radius,
5167 pp->style->Diameter,
5168 2 * pp->style->Keepaway,
5169 0, pp->style->Hole, NULL,
5170 MakeFlags (AUTOFLAG));
5171 assert (pp->parent.via);
5172 if (pp->parent.via)
5174 AddObjectToCreateUndoList (VIA_TYPE,
5175 pp->parent.via,
5176 pp->parent.via,
5177 pp->parent.via);
5178 changed = true;
5181 assert (pp->parent.via);
5182 if (p->type == VIA_SHADOW)
5184 p->type = VIA;
5185 p->parent.via = pp->parent.via;
5188 else if (p->type == THERMAL)
5189 /* nothing to do because, the via might not be there yet */ ;
5190 else
5191 assert (0);
5194 END_LOOP;
5195 /* loop again to place all the thermals now that the vias are down */
5196 LIST_LOOP (net, same_net, p);
5198 if (p->type == THERMAL)
5200 PinType *pin = NULL;
5201 /* thermals are alread a single point search, no need to shrink */
5202 int type = FindPin (&p->box, &pin);
5203 if (pin)
5205 AddObjectToClearPolyUndoList (type,
5206 pin->Element ? pin->Element : pin,
5207 pin, pin, false);
5208 RestoreToPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
5209 pin);
5210 AddObjectToFlagUndoList (type,
5211 pin->Element ? pin->Element : pin, pin,
5212 pin);
5213 ASSIGN_THERM (p->layer, PCB->ThermStyle, pin);
5214 AddObjectToClearPolyUndoList (type,
5215 pin->Element ? pin->Element : pin,
5216 pin, pin, true);
5217 ClearFromPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
5218 pin);
5219 changed = true;
5223 END_LOOP;
5225 END_LOOP;
5226 return changed;
5229 bool
5230 AutoRoute (bool selected)
5232 bool changed = false;
5233 routedata_t *rd;
5234 int i;
5236 total_wire_length = 0;
5237 total_via_count = 0;
5239 #ifdef ROUTE_DEBUG
5240 ddraw = gui->request_debug_draw ();
5241 if (ddraw != NULL)
5243 ar_gc = hid_draw_make_gc (ddraw);
5244 hid_draw_set_line_cap (ar_gc, Round_Cap);
5246 #endif
5248 for (i = 0; i < NUM_STYLES; i++)
5250 if (PCB->RouteStyle[i].Thick == 0 ||
5251 PCB->RouteStyle[1].Diameter == 0 ||
5252 PCB->RouteStyle[1].Hole == 0 || PCB->RouteStyle[i].Keepaway == 0)
5254 Message ("You must define proper routing styles\n"
5255 "before auto-routing.\n");
5256 return (false);
5259 if (PCB->Data->RatN == 0)
5260 return (false);
5261 rd = CreateRouteData ();
5263 if (1)
5265 routebox_t *net, *rb, *last;
5266 int i = 0;
5267 /* count number of rats selected */
5268 RAT_LOOP (PCB->Data);
5270 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5271 i++;
5273 END_LOOP;
5274 #ifdef ROUTE_VERBOSE
5275 printf ("%d nets!\n", i);
5276 #endif
5277 if (i == 0)
5278 goto donerouting; /* nothing to do here */
5279 /* if only one rat selected, do things the quick way. =) */
5280 if (i == 1)
5282 RAT_LOOP (PCB->Data);
5283 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5285 /* look up the end points of this rat line */
5286 routebox_t *a =
5287 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
5288 line->Point1.Y, line->group1);
5289 routebox_t *b =
5290 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
5291 line->Point2.Y, line->group2);
5293 /* If the rat starts or ends at a non-straight pad (i.e., at a
5294 * rotated SMD), a or b will be NULL since the autorouter can't
5295 * handle these.
5297 if (a != NULL && b != NULL)
5299 assert (a->style == b->style);
5300 /* route exactly one net, without allowing conflicts */
5301 InitAutoRouteParameters (0, a->style, false, true, true);
5302 /* hace planes work better as sources than targets */
5303 changed = RouteOne (rd, a, b, 150000).found_route || changed;
5304 goto donerouting;
5307 END_LOOP;
5309 /* otherwise, munge the netlists so that only the selected rats
5310 * get connected. */
5311 /* first, separate all sub nets into separate nets */
5312 /* note that this code works because LIST_LOOP is clever enough not to
5313 * be fooled when the list is changing out from under it. */
5314 last = NULL;
5315 LIST_LOOP (rd->first_net, different_net, net);
5317 FOREACH_SUBNET (net, rb);
5319 if (last)
5321 last->different_net.next = rb;
5322 rb->different_net.prev = last;
5324 last = rb;
5326 END_FOREACH (net, rb);
5327 LIST_LOOP (net, same_net, rb);
5329 rb->same_net = rb->same_subnet;
5331 END_LOOP;
5332 /* at this point all nets are equal to their subnets */
5334 END_LOOP;
5335 if (last)
5337 last->different_net.next = rd->first_net;
5338 rd->first_net->different_net.prev = last;
5341 /* now merge only those subnets connected by a rat line */
5342 RAT_LOOP (PCB->Data);
5343 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5345 /* look up the end points of this rat line */
5346 routebox_t *a;
5347 routebox_t *b;
5349 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
5350 line->Point1.Y, line->group1);
5352 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
5353 line->Point2.Y, line->group2);
5354 if (!a || !b)
5356 #ifdef DEBUG_STALE_RATS
5357 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
5358 ASSIGN_FLAG (SELECTEDFLAG, true, line);
5359 DrawRat (line, 0);
5360 #endif /* DEBUG_STALE_RATS */
5361 Message ("The rats nest is stale! Aborting autoroute...\n");
5362 goto donerouting;
5364 /* merge subnets into a net! */
5365 MergeNets (a, b, NET);
5367 END_LOOP;
5368 /* now 'different_net' may point to too many different nets. Reset. */
5369 LIST_LOOP (rd->first_net, different_net, net);
5371 if (!net->flags.touched)
5373 LIST_LOOP (net, same_net, rb);
5374 rb->flags.touched = 1;
5375 END_LOOP;
5377 else /* this is not a "different net"! */
5378 RemoveFromNet (net, DIFFERENT_NET);
5380 END_LOOP;
5381 /* reset "touched" flag */
5382 LIST_LOOP (rd->first_net, different_net, net);
5384 LIST_LOOP (net, same_net, rb);
5386 assert (rb->flags.touched);
5387 rb->flags.touched = 0;
5389 END_LOOP;
5391 END_LOOP;
5393 /* okay, rd's idea of netlist now corresponds to what we want routed */
5394 /* auto-route all nets */
5395 changed = (RouteAll (rd).total_nets_routed > 0) || changed;
5396 donerouting:
5397 gui->progress (0, 0, NULL);
5398 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
5400 int i;
5401 BoxType big = {0, 0, MAX_COORD, MAX_COORD};
5402 for (i = 0; i < max_group; i++)
5404 r_search (rd->layergrouptree[i], &big, NULL, ripout_livedraw_obj_cb, NULL);
5407 #ifdef ROUTE_DEBUG
5408 if (ddraw != NULL)
5410 hid_draw_destroy_gc (ar_gc);
5411 gui->finish_debug_draw ();
5413 #endif
5415 if (changed)
5416 changed = IronDownAllUnfixedPaths (rd);
5417 Message ("Total added wire length = %$mS, %d vias added\n",
5418 (Coord) total_wire_length, total_via_count);
5419 DestroyRouteData (&rd);
5420 if (changed)
5422 SaveUndoSerialNumber ();
5424 /* optimize rats, we've changed connectivity a lot. */
5425 DeleteRats (false /*all rats */ );
5426 RestoreUndoSerialNumber ();
5427 AddAllRats (false /*all rats */ , NULL);
5428 RestoreUndoSerialNumber ();
5430 IncrementUndoSerialNumber ();
5432 Redraw ();
5434 #if defined (ROUTE_DEBUG)
5435 aabort = 0;
5436 #endif
5437 return (changed);