(no commit message)
[geda-pcb/pcjc2.git] / src / autoroute.c
blob58ff35176f8fd01fcc45de5b9634205fcb7c4582
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1998,1999,2000,2001 harry eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Contact addresses for paper mail and Email:
23 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
24 * haceaton@aplcomm.jhuapl.edu
27 /* this file, autoroute.c, was written and is
28 * Copyright (c) 2001 C. Scott Ananian
29 * Copyright (c) 2006 harry eaton
30 * Copyright (c) 2009 harry eaton
32 /* functions used to autoroute nets.
35 *-------------------------------------------------------------------
36 * This file implements a rectangle-expansion router, based on
37 * "A Method for Gridless Routing of Printed Circuit Boards" by
38 * A. C. Finch, K. J. Mackenzie, G. J. Balsdon, and G. Symonds in the
39 * 1985 Proceedings of the 22nd ACM/IEEE Design Automation Conference.
40 * This reference is available from the ACM Digital Library at
41 * http://www.acm.org/dl for those with institutional or personal
42 * access to it. It's also available from your local engineering
43 * library.
45 * The code is much closer to what is described in the paper now,
46 * in that expansion areas can grow from corners and in all directions
47 * at once. Previously, these were emulated with discrete boxes moving
48 * in the cardinal directions. With the new method, there are fewer but
49 * larger expansion boxes that one might do a better job of routing in.
50 *--------------------------------------------------------------------
52 #define NET_HEAP 1
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
57 #include "global.h"
59 #include <assert.h>
60 #include <setjmp.h>
62 #include "data.h"
63 #include "macro.h"
64 #include "autoroute.h"
65 #include "box.h"
66 #include "create.h"
67 #include "draw.h"
68 #include "error.h"
69 #include "find.h"
70 #include "heap.h"
71 #include "rtree.h"
72 #include "misc.h"
73 #include "mtspace.h"
74 #include "mymem.h"
75 #include "polygon.h"
76 #include "rats.h"
77 #include "remove.h"
78 #include "thermal.h"
79 #include "undo.h"
80 #include "vector.h"
81 #include "pcb-printf.h"
83 #ifdef HAVE_LIBDMALLOC
84 #include <dmalloc.h>
85 #endif
87 /* #defines to enable some debugging output */
89 #define ROUTE_VERBOSE
93 #define ROUTE_DEBUG
94 //#define DEBUG_SHOW_ROUTE_BOXES
95 #define DEBUG_SHOW_EXPANSION_BOXES
96 //#define DEBUG_SHOW_EDGES
97 //#define DEBUG_SHOW_VIA_BOXES
98 #define DEBUG_SHOW_TARGETS
99 #define DEBUG_SHOW_SOURCES
100 //#define DEBUG_SHOW_ZIGZAG
103 static direction_t
104 directionIncrement(direction_t dir)
106 switch(dir)
108 case NORTH:
109 dir = EAST;
110 break;
111 case EAST:
112 dir = SOUTH;
113 break;
114 case SOUTH:
115 dir = WEST;
116 break;
117 case WEST:
118 dir = NE;
119 break;
120 case NE:
121 dir = SE;
122 break;
123 case SE:
124 dir = SW;
125 break;
126 case SW:
127 dir = NW;
128 break;
129 case NW:
130 dir = ALL;
131 break;
132 case ALL:
133 dir = NORTH;
134 break;
136 return dir;
139 #ifdef ROUTE_DEBUG
140 HID *ddraw = NULL;
141 static hidGC ar_gc = 0;
142 #endif
144 #define EXPENSIVE 3e28
145 /* round up "half" thicknesses */
146 #define HALF_THICK(x) (((x)+1)/2)
147 /* a styles maximum bloat is its keepaway plus the larger of its via radius
148 * or line half-thickness. */
149 #define BLOAT(style)\
150 ((style)->Keepaway + HALF_THICK((style)->Thick))
151 /* conflict penalty is less for traces laid down during previous pass than
152 * it is for traces already laid down in this pass. */
153 #define CONFLICT_LEVEL(rb)\
154 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
155 HI_CONFLICT : LO_CONFLICT )
156 #define CONFLICT_PENALTY(rb)\
157 ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
158 AutoRouteParameters.ConflictPenalty : \
159 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
160 AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass)
162 #define _NORTH 1
163 #define _EAST 2
164 #define _SOUTH 4
165 #define _WEST 8
167 #define LIST_LOOP(init, which, x) do {\
168 routebox_t *__next_one__ = (init);\
169 x = NULL;\
170 if (!__next_one__)\
171 assert(__next_one__);\
172 else\
173 while (!x || __next_one__ != (init)) {\
174 x = __next_one__;\
175 /* save next one first in case the command modifies or frees it */\
176 __next_one__ = x->which.next
177 #define FOREACH_SUBNET(net, p) do {\
178 routebox_t *_pp_;\
179 /* fail-fast: check subnet_processed flags */\
180 LIST_LOOP(net, same_net, p); \
181 assert(!p->flags.subnet_processed);\
182 END_LOOP;\
183 /* iterate through *distinct* subnets */\
184 LIST_LOOP(net, same_net, p); \
185 if (!p->flags.subnet_processed) {\
186 LIST_LOOP(p, same_subnet, _pp_);\
187 _pp_->flags.subnet_processed=1;\
188 END_LOOP
189 #define END_FOREACH(net, p) \
190 }; \
191 END_LOOP;\
192 /* reset subnet_processed flags */\
193 LIST_LOOP(net, same_net, p); \
194 p->flags.subnet_processed=0;\
195 END_LOOP;\
196 } while (0)
197 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0)
198 /* notes:
199 * all rectangles are assumed to be closed on the top and left and
200 * open on the bottom and right. That is, they include their top-left
201 * corner but don't include their bottom and right edges.
203 * expansion regions are always half-closed. This means that when
204 * tracing paths, you must steer clear of the bottom and right edges.,
205 * because these are not actually in the allowed box.
207 * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by
208 * their particular required keepaway. This simplifies the tree searching.
209 * the "sbox" contains the unbloated box.
211 /* ---------------------------------------------------------------------------
212 * some local types
215 /* enumerated type for conflict levels */
216 typedef enum
217 { NO_CONFLICT = 0, LO_CONFLICT = 1, HI_CONFLICT = 2 }
218 conflict_t;
220 typedef struct routebox_list
222 struct routebox *next, *prev;
223 }routebox_list;
225 typedef enum etype
226 { PAD, PIN, VIA, VIA_SHADOW, LINE, OTHER, EXPANSION_AREA, PLANE, THERMAL }
227 etype;
229 typedef struct routebox
231 BoxType box, sbox;
232 union
234 PadType *pad;
235 PinType *pin;
236 PinType *via;
237 struct routebox *via_shadow; /* points to the via in r-tree which
238 * points to the PinType in the PCB. */
239 LineType *line;
240 void *generic; /* 'other' is polygon, arc, text */
241 struct routebox *expansion_area; /* previous expansion area in search */
243 parent;
244 unsigned short group;
245 unsigned short layer;
246 etype type;
247 struct
249 unsigned nonstraight:1;
250 unsigned fixed:1;
251 /* for searches */
252 unsigned source:1;
253 unsigned target:1;
254 /* rects on same net as source and target don't need clearance areas */
255 unsigned nobloat:1;
256 /* mark circular pins, so that we be sure to connect them up properly */
257 unsigned circular:1;
258 /* we sometimes create routeboxen that don't actually belong to a
259 * r-tree yet -- make sure refcount of homelesss is set properly */
260 unsigned homeless:1;
261 /* was this nonfixed obstacle generated on an odd or even pass? */
262 unsigned is_odd:1;
263 /* fixed route boxes that have already been "routed through" in this
264 * search have their "touched" flag set. */
265 unsigned touched:1;
266 /* this is a status bit for iterating through *different* subnets */
267 unsigned subnet_processed:1;
268 /* some expansion_areas represent via candidates */
269 unsigned is_via:1;
270 /* mark non-straight lines which go from bottom-left to upper-right,
271 * instead of from upper-left to bottom-right. */
272 unsigned bl_to_ur:1;
273 /* mark polygons which are "transparent" for via-placement; that is,
274 * vias through the polygon will automatically be given a keepaway
275 * and will not electrically connect to the polygon. */
276 unsigned clear_poly:1;
277 /* this marks "conflicting" routes that must be torn up to obtain
278 * a correct routing. This flag allows us to return a correct routing
279 * even if the user cancels auto-route after a non-final pass. */
280 unsigned is_bad:1;
281 /* for assertion that 'box' is never changed after creation */
282 unsigned inited:1;
283 /* indicate this expansion ares is a thermal between the pin and plane */
284 unsigned is_thermal;
286 flags;
287 /* indicate the direction an expansion box came from */
288 cost_t cost;
289 CheapPointType cost_point;
290 /* reference count for homeless routeboxes; free when refcount==0 */
291 int refcount;
292 /* when routing with conflicts, we keep a record of what we're
293 * conflicting with.
295 vector_t *conflicts_with;
296 /* route style of the net associated with this routebox */
297 RouteStyleType *style;
298 /* congestion values for the edges of an expansion box */
299 unsigned char n, e, s, w;
300 /* what pass this this track was laid down on */
301 unsigned char pass;
302 /* the direction this came from, if any */
303 direction_t came_from;
304 /* circular lists with connectivity information. */
305 routebox_list same_net, same_subnet, original_subnet, different_net;
306 union {
307 PinType *via;
308 LineType *line;
309 } livedraw_obj;
311 routebox_t;
313 typedef struct routedata
315 /* one rtree per layer *group */
316 rtree_t *layergrouptree[MAX_GROUP]; /* no silkscreen layers here =) */
317 /* root pointer into connectivity information */
318 routebox_t *first_net;
319 /* default routing style */
320 RouteStyleType defaultstyle;
321 /* style structures */
322 RouteStyleType *styles[NUM_STYLES + 1];
323 /* what is the maximum bloat (keepaway+line half-width or
324 * keepaway+via_radius) for any style we've seen? */
325 Coord max_bloat;
326 Coord max_keep;
327 mtspace_t *mtspace;
329 routedata_t;
331 typedef struct edge_struct
333 routebox_t *rb; /* path expansion edges are real routeboxen. */
334 CheapPointType cost_point;
335 cost_t cost_to_point; /* from source */
336 cost_t cost; /* cached edge cost */
337 routebox_t *mincost_target; /* minimum cost from cost_point to any target */
338 vetting_t *work; /* for via search edges */
339 direction_t expand_dir;
340 struct
342 /* this indicates that this 'edge' is a via candidate. */
343 unsigned is_via:1;
344 /* record "conflict level" of via candidates, in case we need to split
345 * them later. */
346 conflict_t via_conflict_level:2;
347 /* when "routing with conflicts", sometimes edge is interior. */
348 unsigned is_interior:1;
349 /* this is a fake edge used to defer searching for via spaces */
350 unsigned via_search:1;
351 /* this is a via edge in a plane where the cost point moves for free */
352 unsigned in_plane:1;
354 flags;
356 edge_t;
358 static struct
360 /* net style parameters */
361 RouteStyleType *style;
362 /* the present bloat */
363 Coord bloat;
364 /* cost parameters */
365 cost_t ViaCost, /* additional "length" cost for using a via */
366 LastConflictPenalty, /* length mult. for routing over last pass' trace */
367 ConflictPenalty, /* length multiplier for routing over another trace */
368 JogPenalty, /* additional "length" cost for changing direction */
369 CongestionPenalty, /* (rational) length multiplier for routing in */
370 NewLayerPenalty, /* penalty for routing on a previously unused layer */
371 MinPenalty; /* smallest Direction Penalty */
372 /* maximum conflict incidence before calling it "no path found" */
373 int hi_conflict;
374 /* are vias allowed? */
375 bool use_vias;
376 /* is this an odd or even pass? */
377 bool is_odd;
378 /* permit conflicts? */
379 bool with_conflicts;
380 /* is this a final "smoothing" pass? */
381 bool is_smoothing;
382 /* rip up nets regardless of conflicts? */
383 bool rip_always;
384 bool last_smooth;
385 unsigned char pass;
387 AutoRouteParameters;
389 struct routeone_state
391 /* heap of all candidate expansion edges */
392 heap_t *workheap;
393 /* information about the best path found so far. */
394 routebox_t *best_path, *best_target;
395 cost_t best_cost;
399 /* ---------------------------------------------------------------------------
400 * some local prototypes
402 static routebox_t *CreateExpansionArea (const BoxType * area, Cardinal group,
403 routebox_t * parent,
404 bool relax_edge_requirements,
405 edge_t * edge);
407 static cost_t edge_cost (const edge_t * e, const cost_t too_big);
408 static void best_path_candidate (struct routeone_state *s,
409 edge_t * e, routebox_t * best_target);
411 static BoxType edge_to_box (const routebox_t * rb, direction_t expand_dir);
413 static void add_or_destroy_edge (struct routeone_state *s, edge_t * e);
415 static void
416 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
417 Cardinal group, Cardinal layer, routebox_t * subnet,
418 bool is_bad);
419 static void ResetSubnet (routebox_t * net);
420 #ifdef ROUTE_DEBUG
421 static int showboxen = -2;
422 static int aabort = 0;
423 static void showroutebox (routebox_t * rb);
424 #endif
426 /* ---------------------------------------------------------------------------
427 * some local identifiers
429 /* group number of groups that hold surface mount pads */
430 static Cardinal front, back;
431 static bool usedGroup[MAX_GROUP];
432 static int x_cost[MAX_GROUP], y_cost[MAX_GROUP];
433 static bool is_layer_group_active[MAX_GROUP];
434 static int ro = 0;
435 static int smoothes = 1;
436 static int passes = 12;
437 static int routing_layers = 0;
438 static float total_wire_length = 0;
439 static int total_via_count = 0;
441 /* assertion helper for routeboxen */
442 #ifndef NDEBUG
443 static int
444 __routebox_is_good (routebox_t * rb)
446 assert (rb && (rb->group < max_group) &&
447 (rb->box.X1 <= rb->box.X2) && (rb->box.Y1 <= rb->box.Y2) &&
448 (rb->flags.homeless ?
449 (rb->box.X1 != rb->box.X2) || (rb->box.Y1 != rb->box.Y2) :
450 (rb->box.X1 != rb->box.X2) && (rb->box.Y1 != rb->box.Y2)));
451 assert ((rb->flags.source ? rb->flags.nobloat : 1) &&
452 (rb->flags.target ? rb->flags.nobloat : 1) &&
453 (rb->flags.homeless ? !rb->flags.touched : rb->refcount == 0) &&
454 (rb->flags.touched ? rb->type != EXPANSION_AREA : 1));
455 assert ((rb->flags.is_odd ? (!rb->flags.fixed) &&
456 (rb->type == VIA || rb->type == VIA_SHADOW || rb->type == LINE
457 || rb->type == PLANE) : 1));
458 assert (rb->flags.clear_poly ?
459 ((rb->type == OTHER || rb->type == PLANE) && rb->flags.fixed
460 && !rb->flags.homeless) : 1);
461 assert (rb->flags.inited);
462 /* run through conflict list showing none are homeless, targets or sources */
463 if (rb->conflicts_with)
465 int i;
466 for (i = 0; i < vector_size (rb->conflicts_with); i++)
468 routebox_t *c = vector_element (rb->conflicts_with, i);
469 assert (!c->flags.homeless && !c->flags.source && !c->flags.target
470 && !c->flags.fixed);
473 assert (rb->style != NULL && rb->style != NULL);
474 assert (rb->type == EXPANSION_AREA
475 || (rb->same_net.next && rb->same_net.prev && rb->same_subnet.next
476 && rb->same_subnet.prev && rb->original_subnet.next
477 && rb->original_subnet.prev && rb->different_net.next
478 && rb->different_net.prev));
479 return 1;
481 static int
482 __edge_is_good (edge_t * e)
484 assert (e && e->rb && __routebox_is_good (e->rb));
485 assert ((e->rb->flags.homeless ? e->rb->refcount > 0 : 1));
486 assert ((0 <= e->expand_dir) && (e->expand_dir < 9)
487 && (e->flags.
488 is_interior ? (e->expand_dir == ALL
489 && e->rb->conflicts_with) : 1));
490 assert ((e->flags.is_via ? e->rb->flags.is_via : 1)
491 && (e->flags.via_conflict_level >= 0
492 && e->flags.via_conflict_level <= 2)
493 && (e->flags.via_conflict_level != 0 ? e->flags.is_via : 1));
494 assert ((e->cost_to_point >= 0) && e->cost >= 0);
495 return 1;
499 no_planes (const BoxType * b, void *cl)
501 routebox_t *rb = (routebox_t *) b;
502 if (rb->type == PLANE)
503 return 0;
504 return 1;
506 #endif /* !NDEBUG */
508 /*---------------------------------------------------------------------
509 * route utility functions.
512 enum boxlist
513 { NET, SUBNET, ORIGINAL, DIFFERENT_NET };
514 static struct routebox_list *
515 __select_list (routebox_t * r, enum boxlist which)
517 assert (r);
518 switch (which)
520 default:
521 assert (0);
522 case NET:
523 return &(r->same_net);
524 case SUBNET:
525 return &(r->same_subnet);
526 case ORIGINAL:
527 return &(r->original_subnet);
528 case DIFFERENT_NET:
529 return &(r->different_net);
532 static void
533 InitLists (routebox_t * r)
535 static enum boxlist all[] =
536 { NET, SUBNET, ORIGINAL, DIFFERENT_NET }
537 , *p;
538 for (p = all; p < all + (sizeof (all) / sizeof (*p)); p++)
540 struct routebox_list *rl = __select_list (r, *p);
541 rl->prev = rl->next = r;
545 static void
546 MergeNets (routebox_t * a, routebox_t * b, enum boxlist which)
548 struct routebox_list *al, *bl, *anl, *bnl;
549 routebox_t *an, *bn;
550 assert (a && b);
551 assert (a != b);
552 assert (a->type != EXPANSION_AREA);
553 assert (b->type != EXPANSION_AREA);
554 al = __select_list (a, which);
555 bl = __select_list (b, which);
556 assert (al && bl);
557 an = al->next;
558 bn = bl->next;
559 assert (an && bn);
560 anl = __select_list (an, which);
561 bnl = __select_list (bn, which);
562 assert (anl && bnl);
563 bl->next = an;
564 anl->prev = b;
565 al->next = bn;
566 bnl->prev = a;
569 static void
570 RemoveFromNet (routebox_t * a, enum boxlist which)
572 struct routebox_list *al, *anl, *apl;
573 routebox_t *an, *ap;
574 assert (a);
575 al = __select_list (a, which);
576 assert (al);
577 an = al->next;
578 ap = al->prev;
579 if (an == a || ap == a)
580 return; /* not on any list */
581 assert (an && ap);
582 anl = __select_list (an, which);
583 apl = __select_list (ap, which);
584 assert (anl && apl);
585 anl->prev = ap;
586 apl->next = an;
587 al->next = al->prev = a;
588 return;
591 static void
592 init_const_box (routebox_t * rb,
593 Coord X1, Coord Y1, Coord X2,
594 Coord Y2, Coord keepaway)
596 BoxType *bp = (BoxType *) & rb->box; /* note discarding const! */
597 assert (!rb->flags.inited);
598 assert (X1 <= X2 && Y1 <= Y2);
599 bp->X1 = X1 - keepaway;
600 bp->Y1 = Y1 - keepaway;
601 bp->X2 = X2 + keepaway;
602 bp->Y2 = Y2 + keepaway;
603 bp = (BoxType *) & rb->sbox;
604 bp->X1 = X1;
605 bp->Y1 = Y1;
606 bp->X2 = X2;
607 bp->Y2 = Y2;
608 rb->flags.inited = 1;
611 static inline BoxType
612 shrink_routebox (const routebox_t * rb)
614 return rb->sbox;
617 static inline cost_t
618 box_area (const BoxType b)
620 cost_t ans = b.X2 - b.X1;
621 return ans * (b.Y2 - b.Y1);
624 static inline CheapPointType
625 closest_point_in_routebox (const CheapPointType * from, const routebox_t * rb)
627 return closest_point_in_box (from, &rb->sbox);
630 static inline bool
631 point_in_shrunk_box (const routebox_t * box, Coord X, Coord Y)
633 BoxType b = shrink_routebox (box);
634 return point_in_box (&b, X, Y);
637 /*---------------------------------------------------------------------
638 * routedata initialization functions.
641 static routebox_t *
642 AddPin (PointerListType layergroupboxes[], PinType *pin, bool is_via,
643 RouteStyleType * style)
645 routebox_t **rbpp, *lastrb = NULL;
646 int i, ht;
647 /* a pin cuts through every layer group */
648 for (i = 0; i < max_group; i++)
650 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[i]);
651 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
652 memset ((void *) *rbpp, 0, sizeof (**rbpp));
653 (*rbpp)->group = i;
654 ht = HALF_THICK (MAX (pin->Thickness, pin->DrillingHole));
655 init_const_box (*rbpp,
656 /*X1 */ pin->X - ht,
657 /*Y1 */ pin->Y - ht,
658 /*X2 */ pin->X + ht,
659 /*Y2 */ pin->Y + ht, style->Keepaway);
660 /* set aux. properties */
661 if (is_via)
663 (*rbpp)->type = VIA;
664 (*rbpp)->parent.via = pin;
666 else
668 (*rbpp)->type = PIN;
669 (*rbpp)->parent.pin = pin;
671 (*rbpp)->flags.fixed = 1;
672 (*rbpp)->came_from = ALL;
673 (*rbpp)->style = style;
674 (*rbpp)->flags.circular = !TEST_FLAG (SQUAREFLAG, pin);
675 /* circular lists */
676 InitLists (*rbpp);
677 /* link together */
678 if (lastrb)
680 MergeNets (*rbpp, lastrb, NET);
681 MergeNets (*rbpp, lastrb, SUBNET);
682 MergeNets (*rbpp, lastrb, ORIGINAL);
684 lastrb = *rbpp;
686 return lastrb;
688 static routebox_t *
689 AddPad (PointerListType layergroupboxes[],
690 ElementType *element, PadType *pad, RouteStyleType * style)
692 Coord halfthick;
693 routebox_t **rbpp;
694 int layergroup = (TEST_FLAG (ONSOLDERFLAG, pad) ? back : front);
695 assert (0 <= layergroup && layergroup < max_group);
696 assert (PCB->LayerGroups.Number[layergroup] > 0);
697 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
698 assert (rbpp);
699 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
700 assert (*rbpp);
701 memset (*rbpp, 0, sizeof (**rbpp));
702 (*rbpp)->group = layergroup;
703 halfthick = HALF_THICK (pad->Thickness);
704 init_const_box (*rbpp,
705 /*X1 */ MIN (pad->Point1.X, pad->Point2.X) - halfthick,
706 /*Y1 */ MIN (pad->Point1.Y, pad->Point2.Y) - halfthick,
707 /*X2 */ MAX (pad->Point1.X, pad->Point2.X) + halfthick,
708 /*Y2 */ MAX (pad->Point1.Y, pad->Point2.Y) + halfthick,
709 style->Keepaway);
710 /* kludge for non-manhattan pads (which are not allowed at present) */
711 if (pad->Point1.X != pad->Point2.X && pad->Point1.Y != pad->Point2.Y)
712 (*rbpp)->flags.nonstraight = 1;
713 /* set aux. properties */
714 (*rbpp)->type = PAD;
715 (*rbpp)->parent.pad = pad;
716 (*rbpp)->flags.fixed = 1;
717 (*rbpp)->came_from = ALL;
718 (*rbpp)->style = style;
719 /* circular lists */
720 InitLists (*rbpp);
721 return *rbpp;
723 static routebox_t *
724 AddLine (PointerListType layergroupboxes[], int layergroup, LineType *line,
725 LineType *ptr, RouteStyleType * style)
727 routebox_t **rbpp;
728 assert (layergroupboxes && line);
729 assert (0 <= layergroup && layergroup < max_group);
730 assert (PCB->LayerGroups.Number[layergroup] > 0);
732 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
733 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
734 memset (*rbpp, 0, sizeof (**rbpp));
735 (*rbpp)->group = layergroup;
736 init_const_box (*rbpp,
737 /*X1 */ MIN (line->Point1.X,
738 line->Point2.X) - HALF_THICK (line->Thickness),
739 /*Y1 */ MIN (line->Point1.Y,
740 line->Point2.Y) - HALF_THICK (line->Thickness),
741 /*X2 */ MAX (line->Point1.X,
742 line->Point2.X) + HALF_THICK (line->Thickness),
743 /*Y2 */ MAX (line->Point1.Y,
744 line->Point2.Y) +
745 HALF_THICK (line->Thickness), style->Keepaway);
746 /* kludge for non-manhattan lines */
747 if (line->Point1.X != line->Point2.X && line->Point1.Y != line->Point2.Y)
749 (*rbpp)->flags.nonstraight = 1;
750 (*rbpp)->flags.bl_to_ur =
751 (MIN (line->Point1.X, line->Point2.X) == line->Point1.X) !=
752 (MIN (line->Point1.Y, line->Point2.Y) == line->Point1.Y);
753 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
754 showroutebox (*rbpp);
755 #endif
757 /* set aux. properties */
758 (*rbpp)->type = LINE;
759 (*rbpp)->parent.line = ptr;
760 (*rbpp)->flags.fixed = 1;
761 (*rbpp)->came_from = ALL;
762 (*rbpp)->style = style;
763 /* circular lists */
764 InitLists (*rbpp);
765 return *rbpp;
767 static routebox_t *
768 AddIrregularObstacle (PointerListType layergroupboxes[],
769 Coord X1, Coord Y1,
770 Coord X2, Coord Y2, Cardinal layergroup,
771 void *parent, RouteStyleType * style)
773 routebox_t **rbpp;
774 Coord keep = style->Keepaway;
775 assert (layergroupboxes && parent);
776 assert (X1 <= X2 && Y1 <= Y2);
777 assert (0 <= layergroup && layergroup < max_group);
778 assert (PCB->LayerGroups.Number[layergroup] > 0);
780 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
781 *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
782 memset (*rbpp, 0, sizeof (**rbpp));
783 (*rbpp)->group = layergroup;
784 init_const_box (*rbpp, X1, Y1, X2, Y2, keep);
785 (*rbpp)->flags.nonstraight = 1;
786 (*rbpp)->type = OTHER;
787 (*rbpp)->parent.generic = parent;
788 (*rbpp)->flags.fixed = 1;
789 (*rbpp)->style = style;
790 /* circular lists */
791 InitLists (*rbpp);
792 return *rbpp;
795 static routebox_t *
796 AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
797 PolygonType *polygon, RouteStyleType * style)
799 int is_not_rectangle = 1;
800 int layergroup = GetLayerGroupNumberByNumber (layer);
801 routebox_t *rb;
802 assert (0 <= layergroup && layergroup < max_group);
803 rb = AddIrregularObstacle (layergroupboxes,
804 polygon->BoundingBox.X1,
805 polygon->BoundingBox.Y1,
806 polygon->BoundingBox.X2,
807 polygon->BoundingBox.Y2,
808 layergroup, polygon, style);
809 if (polygon->PointN == 4 &&
810 polygon->HoleIndexN == 0 &&
811 (polygon->Points[0].X == polygon->Points[1].X ||
812 polygon->Points[0].Y == polygon->Points[1].Y) &&
813 (polygon->Points[1].X == polygon->Points[2].X ||
814 polygon->Points[1].Y == polygon->Points[2].Y) &&
815 (polygon->Points[2].X == polygon->Points[3].X ||
816 polygon->Points[2].Y == polygon->Points[3].Y) &&
817 (polygon->Points[3].X == polygon->Points[0].X ||
818 polygon->Points[3].Y == polygon->Points[0].Y))
819 is_not_rectangle = 0;
820 rb->flags.nonstraight = is_not_rectangle;
821 rb->layer = layer;
822 rb->came_from = ALL;
823 if (TEST_FLAG (CLEARPOLYFLAG, polygon))
825 rb->flags.clear_poly = 1;
826 if (!is_not_rectangle)
827 rb->type = PLANE;
829 return rb;
831 static void
832 AddText (PointerListType layergroupboxes[], Cardinal layergroup,
833 TextType *text, RouteStyleType * style)
835 AddIrregularObstacle (layergroupboxes,
836 text->BoundingBox.X1, text->BoundingBox.Y1,
837 text->BoundingBox.X2, text->BoundingBox.Y2,
838 layergroup, text, style);
840 static routebox_t *
841 AddArc (PointerListType layergroupboxes[], Cardinal layergroup,
842 ArcType *arc, RouteStyleType * style)
844 return AddIrregularObstacle (layergroupboxes,
845 arc->BoundingBox.X1, arc->BoundingBox.Y1,
846 arc->BoundingBox.X2, arc->BoundingBox.Y2,
847 layergroup, arc, style);
850 struct rb_info
852 BoxType query;
853 routebox_t *winner;
854 jmp_buf env;
857 static int
858 __found_one_on_lg (const BoxType * box, void *cl)
860 struct rb_info *inf = (struct rb_info *) cl;
861 routebox_t *rb = (routebox_t *) box;
862 BoxType sb;
864 if (rb->flags.nonstraight)
865 return 0;
866 sb = shrink_box (&rb->box, rb->style->Keepaway);
867 if (inf->query.X1 >= sb.X2 || inf->query.X2 <= sb.X1 ||
868 inf->query.Y1 >= sb.Y2 || inf->query.Y2 <= sb.Y1)
869 return 0;
870 inf->winner = rb;
871 if (rb->type == PLANE)
872 return 1; /* keep looking for something smaller if a plane was found */
873 longjmp (inf->env, 1);
874 return 0;
876 static routebox_t *
877 FindRouteBoxOnLayerGroup (routedata_t * rd,
878 Coord X, Coord Y, Cardinal layergroup)
880 struct rb_info info;
881 info.winner = NULL;
882 info.query = point_box (X, Y);
883 if (setjmp (info.env) == 0)
884 r_search (rd->layergrouptree[layergroup], &info.query, NULL,
885 __found_one_on_lg, &info);
886 return info.winner;
889 #ifdef ROUTE_DEBUG_VERBOSE
890 static void
891 DumpRouteBox (routebox_t * rb)
893 pcb_printf ("RB: %#mD-%#mD l%d; ",
894 rb->box.X1, rb->box.Y1, rb->box.X2, rb->box.Y2, (int) rb->group);
895 switch (rb->type)
897 case PAD:
898 printf ("PAD[%s %s] ", rb->parent.pad->Name, rb->parent.pad->Number);
899 break;
900 case PIN:
901 printf ("PIN[%s %s] ", rb->parent.pin->Name, rb->parent.pin->Number);
902 break;
903 case VIA:
904 if (!rb->parent.via)
905 break;
906 printf ("VIA[%s %s] ", rb->parent.via->Name, rb->parent.via->Number);
907 break;
908 case LINE:
909 printf ("LINE ");
910 break;
911 case OTHER:
912 printf ("OTHER ");
913 break;
914 case EXPANSION_AREA:
915 printf ("EXPAREA ");
916 break;
917 default:
918 printf ("UNKNOWN ");
919 break;
921 if (rb->flags.nonstraight)
922 printf ("(nonstraight) ");
923 if (rb->flags.fixed)
924 printf ("(fixed) ");
925 if (rb->flags.source)
926 printf ("(source) ");
927 if (rb->flags.target)
928 printf ("(target) ");
929 if (rb->flags.homeless)
930 printf ("(homeless) ");
931 printf ("\n");
933 #endif
935 static routedata_t *
936 CreateRouteData ()
938 NetListListType Nets;
939 PointerListType layergroupboxes[MAX_GROUP];
940 BoxType bbox;
941 routedata_t *rd;
942 int group, i;
944 /* check which layers are active first */
945 routing_layers = 0;
946 for (group = 0; group < max_group; group++)
948 for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
949 /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */
950 if ((PCB->LayerGroups.Entries[group][i] < max_copper_layer) &&
951 PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)
953 routing_layers++;
954 is_layer_group_active[group] = true;
955 break;
957 else
958 is_layer_group_active[group] = false;
960 /* if via visibility is turned off, don't use them */
961 AutoRouteParameters.use_vias = routing_layers > 1 && PCB->ViaOn;
962 front = GetLayerGroupNumberBySide (TOP_SIDE);
963 back = GetLayerGroupNumberBySide (BOTTOM_SIDE);
964 /* determine preferred routing direction on each group */
965 for (i = 0; i < max_group; i++)
967 if (i != back && i != front)
969 x_cost[i] = (i & 1) ? 2 : 1;
970 y_cost[i] = (i & 1) ? 1 : 2;
972 else if (i == back)
974 x_cost[i] = 4;
975 y_cost[i] = 2;
977 else
979 x_cost[i] = 2;
980 y_cost[i] = 2;
983 /* create routedata */
984 rd = (routedata_t *)malloc (sizeof (*rd));
985 memset ((void *) rd, 0, sizeof (*rd));
986 /* create default style */
987 rd->defaultstyle.Thick = Settings.LineThickness;
988 rd->defaultstyle.Diameter = Settings.ViaThickness;
989 rd->defaultstyle.Hole = Settings.ViaDrillingHole;
990 rd->defaultstyle.Keepaway = Settings.Keepaway;
991 rd->max_bloat = BLOAT (&rd->defaultstyle);
992 rd->max_keep = Settings.Keepaway;
993 /* create styles structures */
994 bbox.X1 = bbox.Y1 = 0;
995 bbox.X2 = PCB->MaxWidth;
996 bbox.Y2 = PCB->MaxHeight;
997 for (i = 0; i < NUM_STYLES + 1; i++)
999 RouteStyleType *style =
1000 (i < NUM_STYLES) ? &PCB->RouteStyle[i] : &rd->defaultstyle;
1001 rd->styles[i] = style;
1004 /* initialize pointerlisttype */
1005 for (i = 0; i < max_group; i++)
1007 layergroupboxes[i].Ptr = NULL;
1008 layergroupboxes[i].PtrN = 0;
1009 layergroupboxes[i].PtrMax = 0;
1010 GROUP_LOOP (PCB->Data, i);
1012 if (layer->LineN || layer->ArcN)
1013 usedGroup[i] = true;
1014 else
1015 usedGroup[i] = false;
1017 END_LOOP;
1019 usedGroup[front] = true;
1020 usedGroup[back] = true;
1021 /* add the objects in the netlist first.
1022 * then go and add all other objects that weren't already added
1024 * this saves on searching the trees to find the nets
1026 /* use the DRCFLAG to mark objects as they are entered */
1027 Nets = CollectSubnets (false);
1029 routebox_t *last_net = NULL;
1030 NETLIST_LOOP (&Nets);
1032 routebox_t *last_in_net = NULL;
1033 NET_LOOP (netlist);
1035 routebox_t *last_in_subnet = NULL;
1036 int j;
1038 for (j = 0; j < NUM_STYLES; j++)
1039 if (net->Style == rd->styles[j])
1040 break;
1041 CONNECTION_LOOP (net);
1043 routebox_t *rb = NULL;
1044 SET_FLAG (DRCFLAG, (PinType *) connection->ptr2);
1045 if (connection->type == LINE_TYPE)
1047 LineType *line = (LineType *) connection->ptr2;
1049 /* lines are listed at each end, so skip one */
1050 /* this should probably by a macro named "BUMP_LOOP" */
1051 n--;
1053 /* dice up non-straight lines into many tiny obstacles */
1054 if (line->Point1.X != line->Point2.X
1055 && line->Point1.Y != line->Point2.Y)
1057 LineType fake_line = *line;
1058 Coord dx = (line->Point2.X - line->Point1.X);
1059 Coord dy = (line->Point2.Y - line->Point1.Y);
1060 int segs = MAX (ABS (dx),
1061 ABS (dy)) / (4 * BLOAT (rd->styles[j]) + 1);
1062 int qq;
1063 segs = CLAMP (segs, 1, 32); /* don't go too crazy */
1064 dx /= segs;
1065 dy /= segs;
1066 for (qq = 0; qq < segs - 1; qq++)
1068 fake_line.Point2.X = fake_line.Point1.X + dx;
1069 fake_line.Point2.Y = fake_line.Point1.Y + dy;
1070 if (fake_line.Point2.X == line->Point2.X
1071 && fake_line.Point2.Y == line->Point2.Y)
1072 break;
1073 rb =
1074 AddLine (layergroupboxes, connection->group,
1075 &fake_line, line, rd->styles[j]);
1076 if (last_in_subnet && rb != last_in_subnet)
1077 MergeNets (last_in_subnet, rb, ORIGINAL);
1078 if (last_in_net && rb != last_in_net)
1079 MergeNets (last_in_net, rb, NET);
1080 last_in_subnet = last_in_net = rb;
1081 fake_line.Point1 = fake_line.Point2;
1083 fake_line.Point2 = line->Point2;
1084 rb =
1085 AddLine (layergroupboxes, connection->group, &fake_line,
1086 line, rd->styles[j]);
1088 else
1090 rb =
1091 AddLine (layergroupboxes, connection->group, line, line,
1092 rd->styles[j]);
1095 else
1096 switch (connection->type)
1098 case PAD_TYPE:
1099 rb =
1100 AddPad (layergroupboxes, (ElementType *)connection->ptr1,
1101 (PadType *)connection->ptr2, rd->styles[j]);
1102 break;
1103 case PIN_TYPE:
1104 rb =
1105 AddPin (layergroupboxes, (PinType *)connection->ptr2, false,
1106 rd->styles[j]);
1107 break;
1108 case VIA_TYPE:
1109 rb =
1110 AddPin (layergroupboxes, (PinType *)connection->ptr2, true,
1111 rd->styles[j]);
1112 break;
1113 case POLYGON_TYPE:
1114 rb =
1115 AddPolygon (layergroupboxes,
1116 GetLayerNumber (PCB->Data, (LayerType *)connection->ptr1),
1117 (struct polygon_st *)connection->ptr2, rd->styles[j]);
1118 break;
1120 assert (rb);
1121 /* update circular connectivity lists */
1122 if (last_in_subnet && rb != last_in_subnet)
1123 MergeNets (last_in_subnet, rb, ORIGINAL);
1124 if (last_in_net && rb != last_in_net)
1125 MergeNets (last_in_net, rb, NET);
1126 last_in_subnet = last_in_net = rb;
1127 rd->max_bloat = MAX (rd->max_bloat, BLOAT (rb->style));
1128 rd->max_keep = MAX (rd->max_keep, rb->style->Keepaway);
1130 END_LOOP;
1132 END_LOOP;
1133 if (last_net && last_in_net)
1134 MergeNets (last_net, last_in_net, DIFFERENT_NET);
1135 last_net = last_in_net;
1137 END_LOOP;
1138 rd->first_net = last_net;
1140 FreeNetListListMemory (&Nets);
1142 /* reset all nets to "original" connectivity (which we just set) */
1144 routebox_t *net;
1145 LIST_LOOP (rd->first_net, different_net, net);
1146 ResetSubnet (net);
1147 END_LOOP;
1150 /* add pins and pads of elements */
1151 ALLPIN_LOOP (PCB->Data);
1153 if (TEST_FLAG (DRCFLAG, pin))
1154 CLEAR_FLAG (DRCFLAG, pin);
1155 else
1156 AddPin (layergroupboxes, pin, false, rd->styles[NUM_STYLES]);
1158 ENDALL_LOOP;
1159 ALLPAD_LOOP (PCB->Data);
1161 if (TEST_FLAG (DRCFLAG, pad))
1162 CLEAR_FLAG (DRCFLAG, pad);
1163 else
1164 AddPad (layergroupboxes, element, pad, rd->styles[NUM_STYLES]);
1166 ENDALL_LOOP;
1167 /* add all vias */
1168 VIA_LOOP (PCB->Data);
1170 if (TEST_FLAG (DRCFLAG, via))
1171 CLEAR_FLAG (DRCFLAG, via);
1172 else
1173 AddPin (layergroupboxes, via, true, rd->styles[NUM_STYLES]);
1175 END_LOOP;
1177 for (i = 0; i < max_copper_layer; i++)
1179 int layergroup = GetLayerGroupNumberByNumber (i);
1180 /* add all (non-rat) lines */
1181 LINE_LOOP (LAYER_PTR (i));
1183 if (TEST_FLAG (DRCFLAG, line))
1185 CLEAR_FLAG (DRCFLAG, line);
1186 continue;
1188 /* dice up non-straight lines into many tiny obstacles */
1189 if (line->Point1.X != line->Point2.X
1190 && line->Point1.Y != line->Point2.Y)
1192 LineType fake_line = *line;
1193 Coord dx = (line->Point2.X - line->Point1.X);
1194 Coord dy = (line->Point2.Y - line->Point1.Y);
1195 int segs = MAX (ABS (dx), ABS (dy)) / (4 * rd->max_bloat + 1);
1196 int qq;
1197 segs = CLAMP (segs, 1, 32); /* don't go too crazy */
1198 dx /= segs;
1199 dy /= segs;
1200 for (qq = 0; qq < segs - 1; qq++)
1202 fake_line.Point2.X = fake_line.Point1.X + dx;
1203 fake_line.Point2.Y = fake_line.Point1.Y + dy;
1204 if (fake_line.Point2.X == line->Point2.X
1205 && fake_line.Point2.Y == line->Point2.Y)
1206 break;
1207 AddLine (layergroupboxes, layergroup, &fake_line, line,
1208 rd->styles[NUM_STYLES]);
1209 fake_line.Point1 = fake_line.Point2;
1211 fake_line.Point2 = line->Point2;
1212 AddLine (layergroupboxes, layergroup, &fake_line, line,
1213 rd->styles[NUM_STYLES]);
1215 else
1217 AddLine (layergroupboxes, layergroup, line, line,
1218 rd->styles[NUM_STYLES]);
1221 END_LOOP;
1222 /* add all polygons */
1223 POLYGON_LOOP (LAYER_PTR (i));
1225 if (TEST_FLAG (DRCFLAG, polygon))
1226 CLEAR_FLAG (DRCFLAG, polygon);
1227 else
1228 AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]);
1230 END_LOOP;
1231 /* add all copper text */
1232 TEXT_LOOP (LAYER_PTR (i));
1234 AddText (layergroupboxes, layergroup, text, rd->styles[NUM_STYLES]);
1236 END_LOOP;
1237 /* add all arcs */
1238 ARC_LOOP (LAYER_PTR (i));
1240 AddArc (layergroupboxes, layergroup, arc, rd->styles[NUM_STYLES]);
1242 END_LOOP;
1245 /* create r-trees from pointer lists */
1246 for (i = 0; i < max_group; i++)
1248 /* create the r-tree */
1249 rd->layergrouptree[i] =
1250 r_create_tree ((const BoxType **) layergroupboxes[i].Ptr,
1251 layergroupboxes[i].PtrN, 1);
1254 if (AutoRouteParameters.use_vias)
1256 rd->mtspace = mtspace_create ();
1258 /* create "empty-space" structures for via placement (now that we know
1259 * appropriate keepaways for all the fixed elements) */
1260 for (i = 0; i < max_group; i++)
1262 POINTER_LOOP (&layergroupboxes[i]);
1264 routebox_t *rb = (routebox_t *) * ptr;
1265 if (!rb->flags.clear_poly)
1266 mtspace_add (rd->mtspace, &rb->box, FIXED, rb->style->Keepaway);
1268 END_LOOP;
1271 /* free pointer lists */
1272 for (i = 0; i < max_group; i++)
1273 FreePointerListMemory (&layergroupboxes[i]);
1274 /* done! */
1275 return rd;
1278 void
1279 DestroyRouteData (routedata_t ** rd)
1281 int i;
1282 for (i = 0; i < max_group; i++)
1283 r_destroy_tree (&(*rd)->layergrouptree[i]);
1284 if (AutoRouteParameters.use_vias)
1285 mtspace_destroy (&(*rd)->mtspace);
1286 free (*rd);
1287 *rd = NULL;
1290 /*-----------------------------------------------------------------
1291 * routebox reference counting.
1294 /* increment the reference count on a routebox. */
1295 static void
1296 RB_up_count (routebox_t * rb)
1298 assert (rb->flags.homeless);
1299 rb->refcount++;
1302 /* decrement the reference count on a routebox, freeing if this box becomes
1303 * unused. */
1304 static void
1305 RB_down_count (routebox_t * rb)
1307 assert (rb->type == EXPANSION_AREA);
1308 assert (rb->flags.homeless);
1309 assert (rb->refcount > 0);
1310 if (--rb->refcount == 0)
1312 if (rb->parent.expansion_area->flags.homeless)
1313 RB_down_count (rb->parent.expansion_area);
1314 free (rb);
1318 /*-----------------------------------------------------------------
1319 * Rectangle-expansion routing code.
1322 static void
1323 ResetSubnet (routebox_t * net)
1325 routebox_t *rb;
1326 /* reset connectivity of everything on this net */
1327 LIST_LOOP (net, same_net, rb);
1328 rb->same_subnet = rb->original_subnet;
1329 END_LOOP;
1332 static inline cost_t
1333 cost_to_point_on_layer (const CheapPointType * p1,
1334 const CheapPointType * p2, Cardinal point_layer)
1336 cost_t x_dist = p1->X - p2->X, y_dist = p1->Y - p2->Y, r;
1337 x_dist *= x_cost[point_layer];
1338 y_dist *= y_cost[point_layer];
1339 /* cost is proportional to orthogonal distance. */
1340 r = ABS (x_dist) + ABS (y_dist);
1341 if (p1->X != p2->X && p1->Y != p2->Y)
1342 r += AutoRouteParameters.JogPenalty;
1343 return r;
1346 static cost_t
1347 cost_to_point (const CheapPointType * p1, Cardinal point_layer1,
1348 const CheapPointType * p2, Cardinal point_layer2)
1350 cost_t r = cost_to_point_on_layer (p1, p2, point_layer1);
1351 /* apply via cost penalty if layers differ */
1352 if (point_layer1 != point_layer2)
1353 r += AutoRouteParameters.ViaCost;
1354 return r;
1357 /* return the minimum *cost* from a point to a box on any layer.
1358 * It's safe to return a smaller than minimum cost
1360 static cost_t
1361 cost_to_layerless_box (const CheapPointType * p, Cardinal point_layer,
1362 const BoxType * b)
1364 CheapPointType p2 = closest_point_in_box (p, b);
1365 register cost_t c1, c2;
1367 c1 = p2.X - p->X;
1368 c2 = p2.Y - p->Y;
1370 c1 = ABS (c1);
1371 c2 = ABS (c2);
1372 if (c1 < c2)
1373 return c1 * AutoRouteParameters.MinPenalty + c2;
1374 else
1375 return c2 * AutoRouteParameters.MinPenalty + c1;
1378 /* get to actual pins/pad target coordinates */
1379 bool
1380 TargetPoint (CheapPointType * nextpoint, const routebox_t * target)
1382 if (target->type == PIN)
1384 nextpoint->X = target->parent.pin->X;
1385 nextpoint->Y = target->parent.pin->Y;
1386 return true;
1388 else if (target->type == PAD)
1390 if (abs (target->parent.pad->Point1.X - nextpoint->X) <
1391 abs (target->parent.pad->Point2.X - nextpoint->X))
1392 nextpoint->X = target->parent.pad->Point1.X;
1393 else
1394 nextpoint->X = target->parent.pad->Point2.X;
1395 if (abs (target->parent.pad->Point1.Y - nextpoint->Y) <
1396 abs (target->parent.pad->Point2.Y - nextpoint->Y))
1397 nextpoint->Y = target->parent.pad->Point1.Y;
1398 else
1399 nextpoint->Y = target->parent.pad->Point2.Y;
1400 return true;
1402 else
1404 nextpoint->X = CENTER_X (target->sbox);
1405 nextpoint->Y = CENTER_Y (target->sbox);
1407 return false;
1410 /* return the *minimum cost* from a point to a route box, including possible
1411 * via costs if the route box is on a different layer.
1412 * assume routbox is bloated unless it is an expansion area
1414 static cost_t
1415 cost_to_routebox (const CheapPointType * p, Cardinal point_layer,
1416 const routebox_t * rb)
1418 register cost_t trial = 0;
1419 CheapPointType p2 = closest_point_in_routebox (p, rb);
1420 if (!usedGroup[point_layer] || !usedGroup[rb->group])
1421 trial = AutoRouteParameters.NewLayerPenalty;
1422 if ((p2.X - p->X) * (p2.Y - p->Y) != 0)
1423 trial += AutoRouteParameters.JogPenalty;
1424 /* special case for defered via searching */
1425 if (point_layer > max_group || point_layer == rb->group)
1426 return trial + ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
1427 /* if this target is only a via away, then the via is cheaper than the congestion */
1428 if (p->X == p2.X && p->Y == p2.Y)
1429 return trial + 1;
1430 trial += AutoRouteParameters.ViaCost;
1431 trial += ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
1432 return trial;
1436 static BoxType
1437 bloat_routebox (routebox_t * rb)
1439 BoxType r;
1440 Coord keepaway;
1441 assert (__routebox_is_good (rb));
1443 if (rb->flags.nobloat)
1444 return rb->sbox;
1446 /* Obstacle exclusion zones get bloated by the larger of
1447 * the two required clearances plus half the track width.
1449 keepaway = MAX (AutoRouteParameters.style->Keepaway, rb->style->Keepaway);
1450 r = bloat_box (&rb->sbox, keepaway +
1451 HALF_THICK (AutoRouteParameters.style->Thick));
1452 return r;
1456 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1458 /* makes a line on the solder layer silk surrounding the box */
1459 void
1460 showbox (BoxType b, Dimension thickness, int group)
1462 LineType *line;
1463 LayerType *SLayer = LAYER_PTR (group);
1464 if (showboxen < -1)
1465 return;
1466 if (showboxen != -1 && showboxen != group)
1467 return;
1469 if (ddraw != NULL)
1471 ddraw->graphics->set_line_width (ar_gc, thickness);
1472 ddraw->graphics->set_line_cap (ar_gc, Trace_Cap);
1473 ddraw->graphics->set_color (ar_gc, SLayer->Color);
1475 ddraw->graphics->draw_line (ar_gc, b.X1, b.Y1, b.X2, b.Y1);
1476 ddraw->graphics->draw_line (ar_gc, b.X1, b.Y2, b.X2, b.Y2);
1477 ddraw->graphics->draw_line (ar_gc, b.X1, b.Y1, b.X1, b.Y2);
1478 ddraw->graphics->draw_line (ar_gc, b.X2, b.Y1, b.X2, b.Y2);
1481 #if 1
1482 if (b.Y1 == b.Y2 || b.X1 == b.X2)
1483 thickness = 5;
1484 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1485 b.X1, b.Y1, b.X2, b.Y1, thickness, 0,
1486 MakeFlags (0));
1487 AddObjectToCreateUndoList (LINE_TYPE,
1488 LAYER_PTR (top_silk_layer), line,
1489 line);
1490 if (b.Y1 != b.Y2)
1492 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1493 b.X1, b.Y2, b.X2, b.Y2, thickness, 0,
1494 MakeFlags (0));
1495 AddObjectToCreateUndoList (LINE_TYPE,
1496 LAYER_PTR (bottom_silk_layer),
1497 line, line);
1499 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1500 b.X1, b.Y1, b.X1, b.Y2, thickness, 0,
1501 MakeFlags (0));
1502 AddObjectToCreateUndoList (LINE_TYPE,
1503 LAYER_PTR (top_silk_layer), line,
1504 line);
1505 if (b.X1 != b.X2)
1507 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
1508 b.X2, b.Y1, b.X2, b.Y2, thickness, 0,
1509 MakeFlags (0));
1510 AddObjectToCreateUndoList (LINE_TYPE,
1511 LAYER_PTR (top_silk_layer),
1512 line, line);
1514 #endif
1516 #endif
1518 #if defined(ROUTE_DEBUG)
1519 static void
1520 showedge (edge_t * e)
1522 BoxType *b = (BoxType *) e->rb;
1524 if (ddraw == NULL)
1525 return;
1527 ddraw->graphics->set_line_cap (ar_gc, Trace_Cap);
1528 ddraw->graphics->set_line_width (ar_gc, 1);
1529 ddraw->graphics->set_color (ar_gc, Settings.MaskColor);
1531 switch (e->expand_dir)
1533 case NORTH:
1534 ddraw->graphics->draw_line (ar_gc, b->X1, b->Y1, b->X2, b->Y1);
1535 break;
1536 case SOUTH:
1537 ddraw->graphics->draw_line (ar_gc, b->X1, b->Y2, b->X2, b->Y2);
1538 break;
1539 case WEST:
1540 ddraw->graphics->draw_line (ar_gc, b->X1, b->Y1, b->X1, b->Y2);
1541 break;
1542 case EAST:
1543 ddraw->graphics->draw_line (ar_gc, b->X2, b->Y1, b->X2, b->Y2);
1544 break;
1545 default:
1546 break;
1549 #endif
1551 #if defined(ROUTE_DEBUG)
1552 static void
1553 showroutebox (routebox_t * rb)
1555 showbox (rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1),
1556 rb->flags.is_via ? top_silk_layer : rb->group);
1558 #endif
1560 /* return a "parent" of this edge which immediately precedes it in the route.*/
1561 static routebox_t *
1562 route_parent (routebox_t * rb)
1564 while (rb->flags.homeless && !rb->flags.is_via && !rb->flags.is_thermal)
1566 assert (rb->type == EXPANSION_AREA);
1567 rb = rb->parent.expansion_area;
1568 assert (rb);
1570 return rb;
1573 static vector_t *
1574 path_conflicts (routebox_t * rb, routebox_t * conflictor, bool branch)
1576 if (branch)
1577 rb->conflicts_with = vector_duplicate (rb->conflicts_with);
1578 else if (!rb->conflicts_with)
1579 rb->conflicts_with = vector_create ();
1580 vector_append (rb->conflicts_with, conflictor);
1581 return rb->conflicts_with;
1584 /* Touch everything (except fixed) on each net found
1585 * in the conflicts vector. If the vector is different
1586 * from the last one touched, untouch the last batch
1587 * and touch the new one. Always call with touch=1
1588 * (except for recursive call). Call with NULL, 1 to
1589 * clear the last batch touched.
1591 * touched items become invisible to current path
1592 * so we don't encounter the same conflictor more
1593 * than once
1596 static void
1597 touch_conflicts (vector_t * conflicts, int touch)
1599 static vector_t *last = NULL;
1600 static int last_size = 0;
1601 int i, n;
1602 i = 0;
1603 if (touch)
1605 if (last && conflicts != last)
1606 touch_conflicts (last, 0);
1607 if (!conflicts)
1608 return;
1609 last = conflicts;
1610 i = last_size;
1612 n = vector_size (conflicts);
1613 for (; i < n; i++)
1615 routebox_t *rb = (routebox_t *) vector_element (conflicts, i);
1616 routebox_t *p;
1617 LIST_LOOP (rb, same_net, p);
1618 if (!p->flags.fixed)
1619 p->flags.touched = touch;
1620 END_LOOP;
1622 if (!touch)
1624 last = NULL;
1625 last_size = 0;
1627 else
1628 last_size = n;
1631 /* return a "parent" of this edge which resides in a r-tree somewhere */
1632 /* -- actually, this "parent" *may* be a via box, which doesn't live in
1633 * a r-tree. -- */
1634 static routebox_t *
1635 nonhomeless_parent (routebox_t * rb)
1637 return route_parent (rb);
1640 /* some routines to find the minimum *cost* from a cost point to
1641 * a target (any target) */
1642 struct mincost_target_closure
1644 const CheapPointType *CostPoint;
1645 Cardinal CostPointLayer;
1646 routebox_t *nearest;
1647 cost_t nearest_cost;
1649 static int
1650 __region_within_guess (const BoxType * region, void *cl)
1652 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1653 cost_t cost_to_region;
1654 if (mtc->nearest == NULL)
1655 return 1;
1656 cost_to_region =
1657 cost_to_layerless_box (mtc->CostPoint, mtc->CostPointLayer, region);
1658 assert (cost_to_region >= 0);
1659 /* if no guess yet, all regions are "close enough" */
1660 /* note that cost is *strictly more* than minimum distance, so we'll
1661 * always search a region large enough. */
1662 return (cost_to_region < mtc->nearest_cost);
1664 static int
1665 __found_new_guess (const BoxType * box, void *cl)
1667 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1668 routebox_t *guess = (routebox_t *) box;
1669 cost_t cost_to_guess =
1670 cost_to_routebox (mtc->CostPoint, mtc->CostPointLayer, guess);
1671 assert (cost_to_guess >= 0);
1672 /* if this is cheaper than previous guess... */
1673 if (cost_to_guess < mtc->nearest_cost)
1675 mtc->nearest = guess;
1676 mtc->nearest_cost = cost_to_guess; /* this is our new guess! */
1677 return 1;
1679 else
1680 return 0; /* not less expensive than our last guess */
1683 /* target_guess is our guess at what the nearest target is, or NULL if we
1684 * just plum don't have a clue. */
1685 static routebox_t *
1686 mincost_target_to_point (const CheapPointType * CostPoint,
1687 Cardinal CostPointLayer,
1688 rtree_t * targets, routebox_t * target_guess)
1690 struct mincost_target_closure mtc;
1691 assert (target_guess == NULL || target_guess->flags.target); /* this is a target, right? */
1692 mtc.CostPoint = CostPoint;
1693 mtc.CostPointLayer = CostPointLayer;
1694 mtc.nearest = target_guess;
1695 if (mtc.nearest)
1696 mtc.nearest_cost =
1697 cost_to_routebox (mtc.CostPoint, mtc.CostPointLayer, mtc.nearest);
1698 else
1699 mtc.nearest_cost = EXPENSIVE;
1700 r_search (targets, NULL, __region_within_guess, __found_new_guess, &mtc);
1701 assert (mtc.nearest != NULL && mtc.nearest_cost >= 0);
1702 assert (mtc.nearest->flags.target); /* this is a target, right? */
1703 return mtc.nearest;
1706 /* create edge from field values */
1707 /* mincost_target_guess can be NULL */
1708 static edge_t *
1709 CreateEdge (routebox_t * rb,
1710 Coord CostPointX, Coord CostPointY,
1711 cost_t cost_to_point,
1712 routebox_t * mincost_target_guess,
1713 direction_t expand_dir, rtree_t * targets)
1715 edge_t *e;
1716 assert (__routebox_is_good (rb));
1717 e = (edge_t *)malloc (sizeof (*e));
1718 memset ((void *) e, 0, sizeof (*e));
1719 assert (e);
1720 e->rb = rb;
1721 if (rb->flags.homeless)
1722 RB_up_count (rb);
1723 e->cost_point.X = CostPointX;
1724 e->cost_point.Y = CostPointY;
1725 e->cost_to_point = cost_to_point;
1726 e->flags.via_search = 0;
1727 /* if this edge is created in response to a target, use it */
1728 if (targets)
1729 e->mincost_target =
1730 mincost_target_to_point (&e->cost_point, rb->group,
1731 targets, mincost_target_guess);
1732 else
1733 e->mincost_target = mincost_target_guess;
1734 e->expand_dir = expand_dir;
1735 assert (e->rb && e->mincost_target); /* valid edge? */
1736 assert (!e->flags.is_via || e->expand_dir == ALL);
1737 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1738 #if 0
1739 assert (rb->type == PLANE || rb->conflicts_with != NULL || rb->flags.is_via
1740 || rb->flags.is_thermal
1741 || ((expand_dir == NORTH || expand_dir == SOUTH) ? rb->sbox.X1 <=
1742 CostPointX && CostPointX < rb->sbox.X2
1743 && CostPointY == (expand_dir ==
1744 NORTH ? rb->sbox.Y1 : rb->sbox.Y2 - 1) :
1745 /* expand_dir==EAST || expand_dir==WEST */
1746 rb->sbox.Y1 <= CostPointY && CostPointY < rb->sbox.Y2 &&
1747 CostPointX == (expand_dir ==
1748 EAST ? rb->sbox.X2 - 1 : rb->sbox.X1)));
1749 #endif
1750 assert (__edge_is_good (e));
1751 /* done */
1752 return e;
1755 /* create edge, using previous edge to fill in defaults. */
1756 /* most of the work here is in determining a new cost point */
1757 static edge_t *
1758 CreateEdge2 (routebox_t * rb, direction_t expand_dir,
1759 edge_t * previous_edge, rtree_t * targets, routebox_t * guess)
1761 BoxType thisbox;
1762 CheapPointType thiscost, prevcost;
1763 cost_t d;
1765 assert (rb && previous_edge);
1766 /* okay, find cheapest costpoint to costpoint of previous edge */
1767 thisbox = edge_to_box (rb, expand_dir);
1768 prevcost = previous_edge->cost_point;
1769 /* find point closest to target */
1770 thiscost = closest_point_in_box (&prevcost, &thisbox);
1771 /* compute cost-to-point */
1772 d = cost_to_point_on_layer (&prevcost, &thiscost, rb->group);
1773 /* add in jog penalty */
1774 if (previous_edge->expand_dir != expand_dir)
1775 d += AutoRouteParameters.JogPenalty;
1776 /* okay, new edge! */
1777 return CreateEdge (rb, thiscost.X, thiscost.Y,
1778 previous_edge->cost_to_point + d,
1779 guess ? guess : previous_edge->mincost_target,
1780 expand_dir, targets);
1783 /* create via edge, using previous edge to fill in defaults. */
1784 static edge_t *
1785 CreateViaEdge (const BoxType * area, Cardinal group,
1786 routebox_t * parent, edge_t * previous_edge,
1787 conflict_t to_site_conflict,
1788 conflict_t through_site_conflict, rtree_t * targets)
1790 routebox_t *rb;
1791 CheapPointType costpoint;
1792 cost_t d;
1793 edge_t *ne;
1794 cost_t scale[3];
1796 scale[0] = 1;
1797 scale[1] = AutoRouteParameters.LastConflictPenalty;
1798 scale[2] = AutoRouteParameters.ConflictPenalty;
1800 assert (box_is_good (area));
1801 assert (AutoRouteParameters.with_conflicts ||
1802 (to_site_conflict == NO_CONFLICT &&
1803 through_site_conflict == NO_CONFLICT));
1804 rb = CreateExpansionArea (area, group, parent, true, previous_edge);
1805 rb->flags.is_via = 1;
1806 rb->came_from = ALL;
1807 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1808 showroutebox (rb);
1809 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1810 /* for planes, choose a point near the target */
1811 if (previous_edge->flags.in_plane)
1813 routebox_t *target;
1814 CheapPointType pnt;
1815 /* find a target near this via box */
1816 pnt.X = CENTER_X (*area);
1817 pnt.Y = CENTER_Y (*area);
1818 target = mincost_target_to_point (&pnt, rb->group,
1819 targets,
1820 previous_edge->mincost_target);
1821 /* now find point near the target */
1822 pnt.X = CENTER_X (target->box);
1823 pnt.Y = CENTER_Y (target->box);
1824 costpoint = closest_point_in_routebox (&pnt, rb);
1825 /* we moved from the previous cost point through the plane which is free travel */
1827 (scale[through_site_conflict] *
1828 cost_to_point (&costpoint, group, &costpoint,
1829 previous_edge->rb->group));
1830 ne =
1831 CreateEdge (rb, costpoint.X, costpoint.Y,
1832 previous_edge->cost_to_point + d, target, ALL, NULL);
1833 ne->mincost_target = target;
1835 else
1837 routebox_t *target;
1838 target = previous_edge->mincost_target;
1839 costpoint = closest_point_in_routebox (&previous_edge->cost_point, rb);
1841 (scale[to_site_conflict] *
1842 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1843 previous_edge->rb->group)) +
1844 (scale[through_site_conflict] *
1845 cost_to_point (&costpoint, group, &costpoint,
1846 previous_edge->rb->group));
1847 /* if the target is just this via away, then this via is cheaper */
1848 if (target->group == group &&
1849 point_in_shrunk_box (target, costpoint.X, costpoint.Y))
1850 d -= AutoRouteParameters.ViaCost / 2;
1851 ne =
1852 CreateEdge (rb, costpoint.X, costpoint.Y,
1853 previous_edge->cost_to_point + d,
1854 previous_edge->mincost_target, ALL, targets);
1856 ne->flags.is_via = 1;
1857 ne->flags.via_conflict_level = to_site_conflict;
1858 assert (__edge_is_good (ne));
1859 return ne;
1862 /* create "interior" edge for routing with conflicts */
1863 /* Presently once we "jump inside" the conflicting object
1864 * we consider it a routing highway to travel inside since
1865 * it will become available if the conflict is elliminated.
1866 * That is why we ignore the interior_edge argument.
1868 static edge_t *
1869 CreateEdgeWithConflicts (const BoxType * interior_edge,
1870 routebox_t * container, edge_t * previous_edge,
1871 cost_t cost_penalty_to_box, rtree_t * targets)
1873 routebox_t *rb;
1874 CheapPointType costpoint;
1875 cost_t d;
1876 edge_t *ne;
1877 assert (interior_edge && container && previous_edge && targets);
1878 assert (!container->flags.homeless);
1879 assert (AutoRouteParameters.with_conflicts);
1880 assert (container->flags.touched == 0);
1881 assert (previous_edge->rb->group == container->group);
1882 /* use the caller's idea of what this box should be */
1883 rb =
1884 CreateExpansionArea (interior_edge, previous_edge->rb->group,
1885 previous_edge->rb, true, previous_edge);
1886 path_conflicts (rb, container, true); /* crucial! */
1887 costpoint =
1888 closest_point_in_box (&previous_edge->cost_point, interior_edge);
1890 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1891 previous_edge->rb->group);
1892 d *= cost_penalty_to_box;
1893 d += previous_edge->cost_to_point;
1894 ne = CreateEdge (rb, costpoint.X, costpoint.Y, d, NULL, ALL, targets);
1895 ne->flags.is_interior = 1;
1896 assert (__edge_is_good (ne));
1897 return ne;
1900 static void
1901 KillEdge (void *edge)
1903 edge_t *e = (edge_t *) edge;
1904 assert (e);
1905 if (e->rb->flags.homeless)
1906 RB_down_count (e->rb);
1907 if (e->flags.via_search)
1908 mtsFreeWork (&e->work);
1909 free (e);
1912 static void
1913 DestroyEdge (edge_t ** e)
1915 assert (e && *e);
1916 KillEdge (*e);
1917 *e = NULL;
1920 /* cost function for an edge. */
1921 static cost_t
1922 edge_cost (const edge_t * e, const cost_t too_big)
1924 cost_t penalty = e->cost_to_point;
1925 if (e->rb->flags.is_thermal || e->rb->type == PLANE)
1926 return penalty; /* thermals are cheap */
1927 if (penalty > too_big)
1928 return penalty;
1930 /* cost_to_routebox adds in our via correction, too. */
1931 return penalty +
1932 cost_to_routebox (&e->cost_point, e->rb->group, e->mincost_target);
1935 /* given an edge of a box, return a box containing exactly the points on that
1936 * edge. Note that the return box is treated as closed; that is, the bottom and
1937 * right "edges" consist of points (just barely) not in the (half-open) box. */
1938 static BoxType
1939 edge_to_box (const routebox_t * rb, direction_t expand_dir)
1941 BoxType b = shrink_routebox (rb);
1942 /* narrow box down to just the appropriate edge */
1943 switch (expand_dir)
1945 case NORTH:
1946 b.Y2 = b.Y1 + 1;
1947 break;
1948 case EAST:
1949 b.X1 = b.X2 - 1;
1950 break;
1951 case SOUTH:
1952 b.Y1 = b.Y2 - 1;
1953 break;
1954 case WEST:
1955 b.X2 = b.X1 + 1;
1956 break;
1957 default:
1958 assert (0);
1960 /* done! */
1961 return b;
1964 struct broken_boxes
1966 BoxType left, center, right;
1967 bool is_valid_left, is_valid_center, is_valid_right;
1970 static struct broken_boxes
1971 break_box_edge (const BoxType * original, direction_t which_edge,
1972 routebox_t * breaker)
1974 BoxType origbox, breakbox;
1975 struct broken_boxes result;
1977 assert (original && breaker);
1979 origbox = *original;
1980 breakbox = bloat_routebox (breaker);
1981 ROTATEBOX_TO_NORTH (origbox, which_edge);
1982 ROTATEBOX_TO_NORTH (breakbox, which_edge);
1983 result.right.Y1 = result.center.Y1 = result.left.Y1 = origbox.Y1;
1984 result.right.Y2 = result.center.Y2 = result.left.Y2 = origbox.Y1 + 1;
1985 /* validity of breaker is not important because the boxes are marked invalid */
1986 //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1);
1987 /* left edge piece */
1988 result.left.X1 = origbox.X1;
1989 result.left.X2 = breakbox.X1;
1990 /* center (ie blocked) edge piece */
1991 result.center.X1 = MAX (breakbox.X1, origbox.X1);
1992 result.center.X2 = MIN (breakbox.X2, origbox.X2);
1993 /* right edge piece */
1994 result.right.X1 = breakbox.X2;
1995 result.right.X2 = origbox.X2;
1996 /* validity: */
1997 result.is_valid_left = (result.left.X1 < result.left.X2);
1998 result.is_valid_center = (result.center.X1 < result.center.X2);
1999 result.is_valid_right = (result.right.X1 < result.right.X2);
2000 /* rotate back */
2001 ROTATEBOX_FROM_NORTH (result.left, which_edge);
2002 ROTATEBOX_FROM_NORTH (result.center, which_edge);
2003 ROTATEBOX_FROM_NORTH (result.right, which_edge);
2004 /* done */
2005 return result;
2008 #ifndef NDEBUG
2009 static int
2010 share_edge (const BoxType * child, const BoxType * parent)
2012 return
2013 (child->X1 == parent->X2 || child->X2 == parent->X1 ||
2014 child->Y1 == parent->Y2 || child->Y2 == parent->Y1) &&
2015 ((parent->X1 <= child->X1 && child->X2 <= parent->X2) ||
2016 (parent->Y1 <= child->Y1 && child->Y2 <= parent->Y2));
2018 static int
2019 edge_intersect (const BoxType * child, const BoxType * parent)
2021 return
2022 (child->X1 <= parent->X2) && (child->X2 >= parent->X1) &&
2023 (child->Y1 <= parent->Y2) && (child->Y2 >= parent->Y1);
2025 #endif
2027 /* area is the expansion area, on layer group 'group'. 'parent' is the
2028 * immediately preceding expansion area, for backtracing. 'lastarea' is
2029 * the last expansion area created, we string these together in a loop
2030 * so we can remove them all easily at the end. */
2031 static routebox_t *
2032 CreateExpansionArea (const BoxType * area, Cardinal group,
2033 routebox_t * parent,
2034 bool relax_edge_requirements, edge_t * src_edge)
2036 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
2037 memset ((void *) rb, 0, sizeof (*rb));
2038 assert (area && parent);
2039 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
2040 rb->group = group;
2041 rb->type = EXPANSION_AREA;
2042 /* should always share edge or overlap with parent */
2043 assert (relax_edge_requirements ? box_intersect (&rb->sbox, &parent->sbox)
2044 : share_edge (&rb->sbox, &parent->sbox));
2045 rb->parent.expansion_area = route_parent (parent);
2046 rb->cost_point =
2047 closest_point_in_box (&rb->parent.expansion_area->cost_point, area);
2048 rb->cost =
2049 rb->parent.expansion_area->cost +
2050 cost_to_point_on_layer (&rb->parent.expansion_area->cost_point,
2051 &rb->cost_point, rb->group);
2052 assert (relax_edge_requirements ? edge_intersect (&rb->sbox, &parent->sbox)
2053 : share_edge (&rb->sbox, &parent->sbox));
2054 if (rb->parent.expansion_area->flags.homeless)
2055 RB_up_count (rb->parent.expansion_area);
2056 rb->flags.homeless = 1;
2057 rb->flags.nobloat = 1;
2058 rb->style = AutoRouteParameters.style;
2059 rb->conflicts_with = parent->conflicts_with;
2060 /* we will never link an EXPANSION_AREA into the nets because they
2061 * are *ONLY* used for path searching. No need to call InitLists ()
2063 rb->came_from = src_edge->expand_dir;
2064 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
2065 showroutebox (rb);
2066 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
2067 return rb;
2070 /*------ Expand ------*/
2071 struct E_result
2073 routebox_t *parent;
2074 routebox_t *n, *e, *s, *w;
2075 Coord keep, bloat;
2076 BoxType inflated, orig;
2077 int done;
2080 /* test method for Expand()
2081 * this routebox potentially is a blocker limiting expansion
2082 * if this is so, we limit the inflate box so another exactly
2083 * like it wouldn't be seen. We do this while keep the inflated
2084 * box as large as possible.
2086 static int
2087 __Expand_this_rect (const BoxType * box, void *cl)
2089 struct E_result *res = (struct E_result *) cl;
2090 routebox_t *rb = (routebox_t *) box;
2091 BoxType rbox;
2092 Coord dn, de, ds, dw, bloat;
2094 /* we don't see conflicts already encountered */
2095 if (rb->flags.touched)
2096 return 0;
2098 /* The inflated box outer edges include its own
2099 * track width plus its own keepaway.
2101 * To check for intersection, we need to expand
2102 * anything with greater keepaway by its excess
2103 * keepaway.
2105 * If something has nobloat then we need to shrink
2106 * the inflated box back and see if it still touches.
2109 if (rb->flags.nobloat)
2111 rbox = rb->sbox;
2112 bloat = res->bloat;
2113 if (rbox.X2 <= res->inflated.X1 + bloat ||
2114 rbox.X1 >= res->inflated.X2 - bloat ||
2115 rbox.Y1 >= res->inflated.Y2 - bloat ||
2116 rbox.Y2 <= res->inflated.Y1 + bloat)
2117 return 0; /* doesn't touch */
2119 else
2121 if (rb->style->Keepaway > res->keep)
2122 rbox = bloat_box (&rb->sbox, rb->style->Keepaway - res->keep);
2123 else
2124 rbox = rb->sbox;
2126 if (rbox.X2 <= res->inflated.X1 || rbox.X1 >= res->inflated.X2
2127 || rbox.Y1 >= res->inflated.Y2 || rbox.Y2 <= res->inflated.Y1)
2128 return 0; /* doesn't touch */
2129 bloat = 0;
2132 /* this is an intersecting box; it has to jump through a few more hoops */
2133 if (rb == res->parent || rb->parent.expansion_area == res->parent)
2134 return 0; /* don't see what we came from */
2136 /* if we are expanding a source edge, don't let other sources
2137 * or their expansions stop us.
2139 #if 1
2140 if (res->parent->flags.source)
2141 if (rb->flags.source
2142 || (rb->type == EXPANSION_AREA
2143 && rb->parent.expansion_area->flags.source))
2144 return 0;
2145 #endif
2147 /* we ignore via expansion boxes because maybe its
2148 * cheaper to get there without the via through
2149 * the path we're exploring now.
2151 if (rb->flags.is_via && rb->type == EXPANSION_AREA)
2152 return 0;
2154 if (rb->type == PLANE) /* expanding inside a plane is not good */
2156 if (rbox.X1 < res->orig.X1 && rbox.X2 > res->orig.X2 &&
2157 rbox.Y1 < res->orig.Y1 && rbox.Y2 > res->orig.Y2)
2159 res->inflated = bloat_box (&res->orig, res->bloat);
2160 return 1;
2163 /* calculate the distances from original box to this blocker */
2164 dn = de = ds = dw = 0;
2165 if (!(res->done & _NORTH) && rbox.Y1 <= res->orig.Y1
2166 && rbox.Y2 > res->inflated.Y1)
2167 dn = res->orig.Y1 - rbox.Y2;
2168 if (!(res->done & _EAST) && rbox.X2 >= res->orig.X2
2169 && rbox.X1 < res->inflated.X2)
2170 de = rbox.X1 - res->orig.X2;
2171 if (!(res->done & _SOUTH) && rbox.Y2 >= res->orig.Y2
2172 && rbox.Y1 < res->inflated.Y2)
2173 ds = rbox.Y1 - res->orig.Y2;
2174 if (!(res->done & _WEST) && rbox.X1 <= res->orig.X1
2175 && rbox.X2 > res->inflated.X1)
2176 dw = res->orig.X1 - rbox.X2;
2177 if (dn <= 0 && de <= 0 && ds <= 0 && dw <= 0)
2178 return 1;
2179 /* now shrink the inflated box to the largest blocking direction */
2180 if (dn >= de && dn >= ds && dn >= dw)
2182 res->inflated.Y1 = rbox.Y2 - bloat;
2183 res->n = rb;
2185 else if (de >= ds && de >= dw)
2187 res->inflated.X2 = rbox.X1 + bloat;
2188 res->e = rb;
2190 else if (ds >= dw)
2192 res->inflated.Y2 = rbox.Y1 + bloat;
2193 res->s = rb;
2195 else
2197 res->inflated.X1 = rbox.X2 - bloat;
2198 res->w = rb;
2200 return 1;
2203 static bool
2204 boink_box (routebox_t * rb, struct E_result *res, direction_t dir)
2206 Coord bloat;
2207 if (rb->style->Keepaway > res->keep)
2208 bloat = res->keep - rb->style->Keepaway;
2209 else
2210 bloat = 0;
2211 if (rb->flags.nobloat)
2212 bloat = res->bloat;
2213 switch (dir)
2215 case NORTH:
2216 case SOUTH:
2217 if (rb->sbox.X2 <= res->inflated.X1 + bloat
2218 || rb->sbox.X1 >= res->inflated.X2 - bloat)
2219 return false;
2220 return true;
2221 case EAST:
2222 case WEST:
2223 if (rb->sbox.Y1 >= res->inflated.Y2 - bloat
2224 || rb->sbox.Y2 <= res->inflated.Y1 + bloat)
2225 return false;
2226 return true;
2227 break;
2228 default:
2229 assert (0);
2231 return false;
2234 /* main Expand routine.
2236 * The expansion probe edge includes the keepaway and half thickness
2237 * as the search is performed in order to see everything relevant.
2238 * The result is backed off by this amount before being returned.
2239 * Targets (and other no-bloat routeboxes) go all the way to touching.
2240 * This is accomplished by backing off the probe edge when checking
2241 * for touch against such an object. Usually the expanding edge
2242 * bumps into neighboring pins on the same device that require a
2243 * keepaway, preventing seeing a target immediately. Rather than await
2244 * another expansion to actually touch the target, the edge breaker code
2245 * looks past the keepaway to see these targets even though they
2246 * weren't actually touched in the expansion.
2248 struct E_result *
2249 Expand (rtree_t * rtree, edge_t * e, const BoxType * box)
2251 static struct E_result ans;
2252 int noshrink; /* bit field of which edges to not shrink */
2254 ans.bloat = AutoRouteParameters.bloat;
2255 ans.orig = *box;
2256 ans.n = ans.e = ans.s = ans.w = NULL;
2258 /* the inflated box must be bloated in all directions that it might
2259 * hit something in order to guarantee that we see object in the
2260 * tree it might hit. The tree holds objects bloated by their own
2261 * keepaway so we are guaranteed to honor that.
2263 switch (e->expand_dir)
2265 case ALL:
2266 ans.inflated.X1 = (e->rb->came_from == EAST ? ans.orig.X1 : 0);
2267 ans.inflated.Y1 = (e->rb->came_from == SOUTH ? ans.orig.Y1 : 0);
2268 ans.inflated.X2 =
2269 (e->rb->came_from == WEST ? ans.orig.X2 : PCB->MaxWidth);
2270 ans.inflated.Y2 =
2271 (e->rb->came_from == NORTH ? ans.orig.Y2 : PCB->MaxHeight);
2272 if (e->rb->came_from == NORTH)
2273 ans.done = noshrink = _SOUTH;
2274 else if (e->rb->came_from == EAST)
2275 ans.done = noshrink = _WEST;
2276 else if (e->rb->came_from == SOUTH)
2277 ans.done = noshrink = _NORTH;
2278 else if (e->rb->came_from == WEST)
2279 ans.done = noshrink = _EAST;
2280 else
2281 ans.done = noshrink = 0;
2282 break;
2283 case NORTH:
2284 ans.done = _SOUTH + _EAST + _WEST;
2285 noshrink = _SOUTH;
2286 ans.inflated.X1 = box->X1 - ans.bloat;
2287 ans.inflated.X2 = box->X2 + ans.bloat;
2288 ans.inflated.Y2 = box->Y2;
2289 ans.inflated.Y1 = 0; /* far north */
2290 break;
2291 case NE:
2292 ans.done = _SOUTH + _WEST;
2293 noshrink = 0;
2294 ans.inflated.X1 = box->X1 - ans.bloat;
2295 ans.inflated.X2 = PCB->MaxWidth;
2296 ans.inflated.Y2 = box->Y2 + ans.bloat;
2297 ans.inflated.Y1 = 0;
2298 break;
2299 case EAST:
2300 ans.done = _NORTH + _SOUTH + _WEST;
2301 noshrink = _WEST;
2302 ans.inflated.Y1 = box->Y1 - ans.bloat;
2303 ans.inflated.Y2 = box->Y2 + ans.bloat;
2304 ans.inflated.X1 = box->X1;
2305 ans.inflated.X2 = PCB->MaxWidth;
2306 break;
2307 case SE:
2308 ans.done = _NORTH + _WEST;
2309 noshrink = 0;
2310 ans.inflated.X1 = box->X1 - ans.bloat;
2311 ans.inflated.X2 = PCB->MaxWidth;
2312 ans.inflated.Y2 = PCB->MaxHeight;
2313 ans.inflated.Y1 = box->Y1 - ans.bloat;
2314 break;
2315 case SOUTH:
2316 ans.done = _NORTH + _EAST + _WEST;
2317 noshrink = _NORTH;
2318 ans.inflated.X1 = box->X1 - ans.bloat;
2319 ans.inflated.X2 = box->X2 + ans.bloat;
2320 ans.inflated.Y1 = box->Y1;
2321 ans.inflated.Y2 = PCB->MaxHeight;
2322 break;
2323 case SW:
2324 ans.done = _NORTH + _EAST;
2325 noshrink = 0;
2326 ans.inflated.X1 = 0;
2327 ans.inflated.X2 = box->X2 + ans.bloat;
2328 ans.inflated.Y2 = PCB->MaxHeight;
2329 ans.inflated.Y1 = box->Y1 - ans.bloat;
2330 break;
2331 case WEST:
2332 ans.done = _NORTH + _SOUTH + _EAST;
2333 noshrink = _EAST;
2334 ans.inflated.Y1 = box->Y1 - ans.bloat;
2335 ans.inflated.Y2 = box->Y2 + ans.bloat;
2336 ans.inflated.X1 = 0;
2337 ans.inflated.X2 = box->X2;
2338 break;
2339 case NW:
2340 ans.done = _SOUTH + _EAST;
2341 noshrink = 0;
2342 ans.inflated.X1 = 0;
2343 ans.inflated.X2 = box->X2 + ans.bloat;
2344 ans.inflated.Y2 = box->Y2 + ans.bloat;
2345 ans.inflated.Y1 = 0;
2346 break;
2347 default:
2348 noshrink = ans.done = 0;
2349 assert (0);
2351 ans.keep = e->rb->style->Keepaway;
2352 ans.parent = nonhomeless_parent (e->rb);
2353 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
2354 /* because the overlaping boxes are found in random order, some blockers
2355 * may have limited edges prematurely, so we check if the blockers realy
2356 * are blocking, and make another try if not
2358 if (ans.n && !boink_box (ans.n, &ans, NORTH))
2359 ans.inflated.Y1 = 0;
2360 else
2361 ans.done |= _NORTH;
2362 if (ans.e && !boink_box (ans.e, &ans, EAST))
2363 ans.inflated.X2 = PCB->MaxWidth;
2364 else
2365 ans.done |= _EAST;
2366 if (ans.s && !boink_box (ans.s, &ans, SOUTH))
2367 ans.inflated.Y2 = PCB->MaxHeight;
2368 else
2369 ans.done |= _SOUTH;
2370 if (ans.w && !boink_box (ans.w, &ans, WEST))
2371 ans.inflated.X1 = 0;
2372 else
2373 ans.done |= _WEST;
2374 if (ans.done != _NORTH + _EAST + _SOUTH + _WEST)
2376 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
2378 if ((noshrink & _NORTH) == 0)
2379 ans.inflated.Y1 += ans.bloat;
2380 if ((noshrink & _EAST) == 0)
2381 ans.inflated.X2 -= ans.bloat;
2382 if ((noshrink & _SOUTH) == 0)
2383 ans.inflated.Y2 -= ans.bloat;
2384 if ((noshrink & _WEST) == 0)
2385 ans.inflated.X1 += ans.bloat;
2386 return &ans;
2389 /* blocker_to_heap puts the blockers into a heap so they
2390 * can be retrieved in clockwise order. If a blocker
2391 * is also a target, it gets put into the vector too.
2392 * It returns 1 for any fixed blocker that is not part
2393 * of this net and zero otherwise.
2395 static int
2396 blocker_to_heap (heap_t * heap, routebox_t * rb,
2397 BoxType * box, direction_t dir)
2399 BoxType b = rb->sbox;
2400 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
2402 bloat_box (&b,
2403 rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
2404 b = clip_box (&b, box);
2405 assert (box_is_good (&b));
2406 /* we want to look at the blockers clockwise around the box */
2407 switch (dir)
2409 /* we need to use the other coordinate fraction to resolve
2410 * ties since we want the shorter of the furthest
2411 * first.
2413 case NORTH:
2414 heap_insert (heap, b.X1 - b.X1 / (b.X2 + 1.0), rb);
2415 break;
2416 case EAST:
2417 heap_insert (heap, b.Y1 - b.Y1 / (b.Y2 + 1.0), rb);
2418 break;
2419 case SOUTH:
2420 heap_insert (heap, -(b.X2 + b.X1 / (b.X2 + 1.0)), rb);
2421 break;
2422 case WEST:
2423 heap_insert (heap, -(b.Y2 + b.Y1 / (b.Y2 + 1.0)), rb);
2424 break;
2425 default:
2426 assert (0);
2428 if (rb->flags.fixed && !rb->flags.target && !rb->flags.source)
2429 return 1;
2430 return 0;
2433 /* this creates an EXPANSION_AREA to bridge small gaps or,
2434 * (more commonly) create a supper-thin box to provide a
2435 * home for an expansion edge.
2437 static routebox_t *
2438 CreateBridge (const BoxType * area, routebox_t * parent, direction_t dir)
2440 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
2441 memset ((void *) rb, 0, sizeof (*rb));
2442 assert (area && parent);
2443 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
2444 rb->group = parent->group;
2445 rb->type = EXPANSION_AREA;
2446 rb->came_from = dir;
2447 rb->cost_point = closest_point_in_box (&parent->cost_point, area);
2448 rb->cost = parent->cost + cost_to_point_on_layer (&parent->cost_point,
2449 &rb->cost_point,
2450 rb->group);
2451 rb->parent.expansion_area = route_parent (parent);
2452 if (rb->parent.expansion_area->flags.homeless)
2453 RB_up_count (rb->parent.expansion_area);
2454 rb->flags.homeless = 1;
2455 rb->flags.nobloat = 1;
2456 rb->style = parent->style;
2457 rb->conflicts_with = parent->conflicts_with;
2458 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES)
2459 showroutebox (rb);
2460 #endif
2461 return rb;
2464 /* moveable_edge prepares the new search edges based on the
2465 * starting box, direction and blocker if any.
2467 void
2468 moveable_edge (vector_t * result, const BoxType * box, direction_t dir,
2469 routebox_t * rb,
2470 routebox_t * blocker, edge_t * e, rtree_t * targets,
2471 struct routeone_state *s, rtree_t * tree, vector_t * area_vec)
2473 BoxType b;
2474 assert (box_is_good (box));
2475 b = *box;
2476 /* for the cardinal directions, move the box to overlap the
2477 * the parent by 1 unit. Corner expansions overlap more
2478 * and their starting boxes are pre-prepared.
2479 * Check if anything is headed off the board edges
2481 switch (dir)
2483 default:
2484 break;
2485 case NORTH:
2486 b.Y2 = b.Y1;
2487 b.Y1--;
2488 if (b.Y1 <= AutoRouteParameters.bloat)
2489 return; /* off board edge */
2490 break;
2491 case EAST:
2492 b.X1 = b.X2;
2493 b.X2++;
2494 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat)
2495 return; /* off board edge */
2496 break;
2497 case SOUTH:
2498 b.Y1 = b.Y2;
2499 b.Y2++;
2500 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat)
2501 return; /* off board edge */
2502 break;
2503 case WEST:
2504 b.X2 = b.X1;
2505 b.X1--;
2506 if (b.X1 <= AutoRouteParameters.bloat)
2507 return; /* off board edge */
2508 break;
2509 case NE:
2510 if (b.Y1 <= AutoRouteParameters.bloat + 1
2511 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2512 return; /* off board edge */
2513 if (b.Y1 <= AutoRouteParameters.bloat + 1)
2514 dir = EAST; /* north off board edge */
2515 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2516 dir = NORTH; /* east off board edge */
2517 break;
2518 case SE:
2519 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
2520 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2521 return; /* off board edge */
2522 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
2523 dir = EAST; /* south off board edge */
2524 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
2525 dir = SOUTH; /* east off board edge */
2526 break;
2527 case SW:
2528 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
2529 && b.X1 <= AutoRouteParameters.bloat + 1)
2530 return; /* off board edge */
2531 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
2532 dir = WEST; /* south off board edge */
2533 if (b.X1 <= AutoRouteParameters.bloat + 1)
2534 dir = SOUTH; /* west off board edge */
2535 break;
2536 case NW:
2537 if (b.Y1 <= AutoRouteParameters.bloat + 1
2538 && b.X1 <= AutoRouteParameters.bloat + 1)
2539 return; /* off board edge */
2540 if (b.Y1 <= AutoRouteParameters.bloat + 1)
2541 dir = WEST; /* north off board edge */
2542 if (b.X1 <= AutoRouteParameters.bloat + 1)
2543 dir = NORTH; /* west off board edge */
2544 break;
2547 if (!blocker)
2549 edge_t *ne;
2550 routebox_t *nrb = CreateBridge (&b, rb, dir);
2551 /* move the cost point in corner expansions
2552 * these boxes are bigger, so move close to the target
2554 if (dir == NE || dir == SE || dir == SW || dir == NW)
2556 CheapPointType p;
2558 closest_point_in_box (&nrb->cost_point, &e->mincost_target->sbox);
2559 p = closest_point_in_box (&p, &b);
2560 nrb->cost += cost_to_point_on_layer (&p, &nrb->cost_point,
2561 nrb->group);
2562 nrb->cost_point = p;
2564 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
2565 nrb->cost, NULL, dir, targets);
2566 vector_append (result, ne);
2568 else if (AutoRouteParameters.with_conflicts && !blocker->flags.target
2569 && !blocker->flags.fixed && !blocker->flags.touched &&
2570 !blocker->flags.source && blocker->type != EXPANSION_AREA)
2572 edge_t *ne;
2573 routebox_t *nrb;
2574 /* make a bridge to the edge of the blocker
2575 * in all directions from there
2577 switch (dir)
2579 case NORTH:
2580 b.Y1 = blocker->sbox.Y2 - 1;
2581 break;
2582 case EAST:
2583 b.X2 = blocker->sbox.X1 + 1;
2584 break;
2585 case SOUTH:
2586 b.Y2 = blocker->sbox.Y1 + 1;
2587 break;
2588 case WEST:
2589 b.X1 = blocker->sbox.X2 - 1;
2590 break;
2591 default:
2592 assert (0);
2594 if (!box_is_good (&b))
2595 return; /* how did this happen ? */
2596 nrb = CreateBridge (&b, rb, dir);
2597 r_insert_entry (tree, &nrb->box, 1);
2598 vector_append (area_vec, nrb);
2599 nrb->flags.homeless = 0; /* not homeless any more */
2600 /* mark this one as conflicted */
2601 path_conflicts (nrb, blocker, true);
2602 /* and make an expansion edge */
2603 nrb->cost_point =
2604 closest_point_in_box (&nrb->cost_point, &blocker->sbox);
2605 nrb->cost +=
2606 cost_to_point_on_layer (&nrb->parent.expansion_area->cost_point,
2607 &nrb->cost_point,
2608 nrb->group) * CONFLICT_PENALTY (blocker);
2610 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, nrb->cost,
2611 NULL, ALL, targets);
2612 ne->flags.is_interior = 1;
2613 vector_append (result, ne);
2615 #if 1
2616 else if (blocker->type == EXPANSION_AREA)
2618 if (blocker->cost < rb->cost || blocker->cost <= rb->cost +
2619 cost_to_point_on_layer (&blocker->cost_point, &rb->cost_point,
2620 rb->group))
2621 return;
2622 if (blocker->conflicts_with || rb->conflicts_with)
2623 return;
2624 /* does the blocker overlap this routebox ?? */
2625 /* does this re-parenting operation leave a memory leak? */
2626 if (blocker->parent.expansion_area->flags.homeless)
2627 RB_down_count (blocker->parent.expansion_area);
2628 blocker->parent.expansion_area = rb;
2629 return;
2631 #endif
2632 else if (blocker->flags.target)
2634 routebox_t *nrb;
2635 edge_t *ne;
2636 b = bloat_box (&b, 1);
2637 if (!box_intersect (&b, &blocker->sbox))
2639 /* if the expansion edge stopped before touching, expand the bridge */
2640 switch (dir)
2642 case NORTH:
2643 b.Y1 -= AutoRouteParameters.bloat + 1;
2644 break;
2645 case EAST:
2646 b.X2 += AutoRouteParameters.bloat + 1;
2647 break;
2648 case SOUTH:
2649 b.Y2 += AutoRouteParameters.bloat + 1;
2650 break;
2651 case WEST:
2652 b.X1 -= AutoRouteParameters.bloat + 1;
2653 break;
2654 default:
2655 assert (0);
2658 assert (box_intersect (&b, &blocker->sbox));
2659 b = shrink_box (&b, 1);
2660 nrb = CreateBridge (&b, rb, dir);
2661 r_insert_entry (tree, &nrb->box, 1);
2662 vector_append (area_vec, nrb);
2663 nrb->flags.homeless = 0; /* not homeless any more */
2664 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
2665 nrb->cost, blocker, dir, NULL);
2666 best_path_candidate (s, ne, blocker);
2667 DestroyEdge (&ne);
2671 struct break_info
2673 heap_t *heap;
2674 routebox_t *parent;
2675 BoxType box;
2676 direction_t dir;
2677 bool ignore_source;
2680 static int
2681 __GatherBlockers (const BoxType * box, void *cl)
2683 routebox_t *rb = (routebox_t *) box;
2684 struct break_info *bi = (struct break_info *) cl;
2685 BoxType b;
2687 if (bi->parent == rb || rb->flags.touched ||
2688 bi->parent->parent.expansion_area == rb)
2689 return 0;
2690 if (rb->flags.source && bi->ignore_source)
2691 return 0;
2692 b = rb->sbox;
2693 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
2695 bloat_box (&b,
2696 rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
2697 if (b.X2 <= bi->box.X1 || b.X1 >= bi->box.X2
2698 || b.Y1 >= bi->box.Y2 || b.Y2 <= bi->box.Y1)
2699 return 0;
2700 return blocker_to_heap (bi->heap, rb, &bi->box, bi->dir);
2703 /* shrink the box to the last limit for the previous direction,
2704 * i.e. if dir is SOUTH, then this means fixing up an EAST leftover
2705 * edge, which would be the southern most edge for that example.
2707 static inline BoxType
2708 previous_edge (Coord last, direction_t i, const BoxType * b)
2710 BoxType db = *b;
2711 switch (i)
2713 case EAST:
2714 db.X1 = last;
2715 break;
2716 case SOUTH:
2717 db.Y1 = last;
2718 break;
2719 case WEST:
2720 db.X2 = last;
2721 break;
2722 default:
2723 Message ("previous edge bogus direction!");
2724 assert (0);
2726 return db;
2729 /* Break all the edges of the box that need breaking, handling
2730 * targets as they are found, and putting any moveable edges
2731 * in the return vector.
2733 vector_t *
2734 BreakManyEdges (struct routeone_state * s, rtree_t * targets, rtree_t * tree,
2735 vector_t * area_vec, struct E_result * ans, routebox_t * rb,
2736 edge_t * e)
2738 struct break_info bi;
2739 vector_t *edges;
2740 heap_t *heap[4];
2741 Coord first, last;
2742 Coord bloat;
2743 direction_t dir;
2744 routebox_t fake;
2746 edges = vector_create ();
2747 bi.ignore_source = rb->parent.expansion_area->flags.source;
2748 bi.parent = rb;
2749 /* we add 2 to the bloat.
2750 * 1 will get us to the actual blocker that Expand() hit
2751 * but 1 more is needed because the new expansion edges
2752 * move out by 1 so they don't overlap their parents
2753 * this extra expansion could "trap" the edge if
2754 * there is a blocker 2 units from the original rb,
2755 * it is 1 unit from the new expansion edge which
2756 * would prevent expansion. So we want to break the
2757 * edge on it now to avoid the trap.
2760 bloat = AutoRouteParameters.bloat + 2;
2761 /* for corner expansion, we need to have a fake blocker
2762 * to prevent expansion back where we came from since
2763 * we still need to break portions of all 4 edges
2765 if (e->expand_dir == NE || e->expand_dir == SE ||
2766 e->expand_dir == SW || e->expand_dir == NW)
2768 BoxType *fb = (BoxType *) &fake.sbox;
2769 memset (&fake, 0, sizeof (fake));
2770 *fb = e->rb->sbox;
2771 fake.flags.fixed = 1; /* this stops expansion there */
2772 fake.type = LINE;
2773 fake.style = AutoRouteParameters.style;
2774 #ifndef NDEBUG
2775 /* the routbox_is_good checker wants a lot more! */
2776 fake.flags.inited = 1;
2777 fb = (BoxType *) &fake.box;
2778 *fb = e->rb->sbox;
2779 fake.same_net.next = fake.same_net.prev = &fake;
2780 fake.same_subnet.next = fake.same_subnet.prev = &fake;
2781 fake.original_subnet.next = fake.original_subnet.prev = &fake;
2782 fake.different_net.next = fake.different_net.prev = &fake;
2783 #endif
2785 /* gather all of the blockers in heaps so they can be accessed
2786 * in clockwise order, which allows finding corners that can
2787 * be expanded.
2789 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
2791 /* don't break the edge we came from */
2792 if (e->expand_dir != ((dir + 2) % 4))
2794 heap[dir] = heap_create ();
2795 bi.box = bloat_box (&rb->sbox, bloat);
2796 bi.heap = heap[dir];
2797 bi.dir = dir;
2798 /* convert to edge */
2799 switch (dir)
2801 case NORTH:
2802 bi.box.Y2 = bi.box.Y1 + bloat + 1;
2803 /* for corner expansion, block the start edges and
2804 * limit the blocker search to only the new edge segment
2806 if (e->expand_dir == SE || e->expand_dir == SW)
2807 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2808 if (e->expand_dir == SE)
2809 bi.box.X1 = e->rb->sbox.X2;
2810 if (e->expand_dir == SW)
2811 bi.box.X2 = e->rb->sbox.X1;
2812 rb->n = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2813 break;
2814 case EAST:
2815 bi.box.X1 = bi.box.X2 - bloat - 1;
2816 /* corner, same as above */
2817 if (e->expand_dir == SW || e->expand_dir == NW)
2818 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2819 if (e->expand_dir == SW)
2820 bi.box.Y1 = e->rb->sbox.Y2;
2821 if (e->expand_dir == NW)
2822 bi.box.Y2 = e->rb->sbox.Y1;
2823 rb->e = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2824 break;
2825 case SOUTH:
2826 bi.box.Y1 = bi.box.Y2 - bloat - 1;
2827 /* corner, same as above */
2828 if (e->expand_dir == NE || e->expand_dir == NW)
2829 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2830 if (e->expand_dir == NE)
2831 bi.box.X1 = e->rb->sbox.X2;
2832 if (e->expand_dir == NW)
2833 bi.box.X2 = e->rb->sbox.X1;
2834 rb->s = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2835 break;
2836 case WEST:
2837 bi.box.X2 = bi.box.X1 + bloat + 1;
2838 /* corner, same as above */
2839 if (e->expand_dir == NE || e->expand_dir == SE)
2840 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
2841 if (e->expand_dir == SE)
2842 bi.box.Y1 = e->rb->sbox.Y2;
2843 if (e->expand_dir == NE)
2844 bi.box.Y2 = e->rb->sbox.Y1;
2845 rb->w = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
2846 break;
2847 default:
2848 assert (0);
2851 else
2852 heap[dir] = NULL;
2854 #if 1
2855 rb->cost +=
2856 (rb->n + rb->e + rb->s +
2857 rb->w) * AutoRouteParameters.CongestionPenalty / box_area (rb->sbox);
2858 #endif
2859 /* now handle the blockers:
2860 * Go around the expansion area clockwise (North->East->South->West)
2861 * pulling blockers from the heap (which makes them come out in the right
2862 * order). Break the edges on the blocker and make the segments and corners
2863 * moveable as possible.
2865 first = last = -1;
2866 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
2868 if (heap[dir] && !heap_is_empty (heap[dir]))
2870 /* pull the very first one out of the heap outside of the
2871 * heap loop because it is special; it can be part of a corner
2873 routebox_t *blk = (routebox_t *) heap_remove_smallest (heap[dir]);
2874 BoxType b = rb->sbox;
2875 struct broken_boxes broke = break_box_edge (&b, dir, blk);
2876 if (broke.is_valid_left)
2878 /* if last > 0, then the previous edge had a segment
2879 * joining this one, so it forms a valid corner expansion
2881 if (last > 0)
2883 /* make a corner expansion */
2884 BoxType db = b;
2885 switch (dir)
2887 case EAST:
2888 /* possible NE expansion */
2889 db.X1 = last;
2890 db.Y2 = MIN (db.Y2, broke.left.Y2);
2891 break;
2892 case SOUTH:
2893 /* possible SE expansion */
2894 db.Y1 = last;
2895 db.X1 = MAX (db.X1, broke.left.X1);
2896 break;
2897 case WEST:
2898 /* possible SW expansion */
2899 db.X2 = last;
2900 db.Y1 = MAX (db.Y1, broke.left.Y1);
2901 break;
2902 default:
2903 assert (0);
2904 break;
2906 moveable_edge (edges, &db, (direction_t)(dir + 3), rb, NULL, e, targets,
2907 s, NULL, NULL);
2909 else if (dir == NORTH) /* north is start, so nothing "before" it */
2911 /* save for a possible corner once we've
2912 * finished circling the box
2914 first = MAX (b.X1, broke.left.X2);
2916 else
2918 /* this is just a boring straight expansion
2919 * since the orthogonal segment was blocked
2921 moveable_edge (edges, &broke.left, dir, rb, NULL, e,
2922 targets, s, NULL, NULL);
2924 } /* broke.is_valid_left */
2925 else if (last > 0)
2927 /* if the last one didn't become a corner,
2928 * we still want to expand it straight out
2929 * in the direction of the previous edge,
2930 * which it belongs to.
2932 BoxType db = previous_edge (last, dir, &rb->sbox);
2933 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
2934 NULL, NULL);
2936 if (broke.is_valid_center && !blk->flags.source)
2937 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets, s,
2938 tree, area_vec);
2939 /* this is the heap extraction loop. We break out
2940 * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can
2941 * just leave stuff in the heap when it is destroyed
2943 while (broke.is_valid_right)
2945 /* move the box edge to the next potential free point */
2946 switch (dir)
2948 case NORTH:
2949 last = b.X1 = MAX (broke.right.X1, b.X1);
2950 break;
2951 case EAST:
2952 last = b.Y1 = MAX (broke.right.Y1, b.Y1);
2953 break;
2954 case SOUTH:
2955 last = b.X2 = MIN (broke.right.X2, b.X2);
2956 break;
2957 case WEST:
2958 last = b.Y2 = MIN (broke.right.Y2, b.Y2);
2959 break;
2960 default:
2961 assert (0);
2963 if (heap_is_empty (heap[dir]))
2964 break;
2965 blk = (routebox_t *)heap_remove_smallest (heap[dir]);
2966 broke = break_box_edge (&b, dir, blk);
2967 if (broke.is_valid_left)
2968 moveable_edge (edges, &broke.left, dir, rb, NULL, e, targets,
2969 s, NULL, NULL);
2970 if (broke.is_valid_center && !blk->flags.source)
2971 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets,
2972 s, tree, area_vec);
2974 if (!broke.is_valid_right)
2975 last = -1;
2977 else /* if (heap[dir]) */
2979 /* nothing touched this edge! Expand the whole edge unless
2980 * (1) it hit the board edge or (2) was the source of our expansion
2982 * for this case (of hitting nothing) we give up trying for corner
2983 * expansions because it is likely that they're not possible anyway
2985 if ((e->expand_dir == ALL ? e->rb->came_from : e->expand_dir) !=
2986 ((dir + 2) % 4))
2988 /* ok, we are not going back on ourselves, and the whole edge seems free */
2989 moveable_edge (edges, &rb->sbox, dir, rb, NULL, e, targets, s,
2990 NULL, NULL);
2993 if (last > 0)
2995 /* expand the leftover from the prior direction */
2996 BoxType db = previous_edge (last, dir, &rb->sbox);
2997 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
2998 NULL, NULL);
3000 last = -1;
3002 } /* for loop */
3003 /* finally, check for the NW corner now that we've come full circle */
3004 if (first > 0 && last > 0)
3006 BoxType db = rb->sbox;
3007 db.X2 = first;
3008 db.Y2 = last;
3009 moveable_edge (edges, &db, NW, rb, NULL, e, targets, s, NULL, NULL);
3011 else
3013 if (first > 0)
3015 BoxType db = rb->sbox;
3016 db.X2 = first;
3017 moveable_edge (edges, &db, NORTH, rb, NULL, e, targets, s, NULL,
3018 NULL);
3020 else if (last > 0)
3022 BoxType db = rb->sbox;
3023 db.Y2 = last;
3024 moveable_edge (edges, &db, WEST, rb, NULL, e, targets, s, NULL,
3025 NULL);
3028 /* done with all expansion edges of this box */
3029 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
3031 if (heap[dir])
3032 heap_destroy (&heap[dir]);
3034 return edges;
3037 static routebox_t *
3038 rb_source (routebox_t * rb)
3040 while (rb && !rb->flags.source)
3042 assert (rb->type == EXPANSION_AREA);
3043 rb = rb->parent.expansion_area;
3045 assert (rb);
3046 return rb;
3049 /* ------------ */
3051 struct foib_info
3053 const BoxType *box;
3054 routebox_t *intersect;
3055 jmp_buf env;
3058 static int
3059 foib_rect_in_reg (const BoxType * box, void *cl)
3061 struct foib_info *foib = (struct foib_info *) cl;
3062 BoxType rbox;
3063 routebox_t *rb = (routebox_t *) box;
3064 if (rb->flags.touched)
3065 return 0;
3066 // if (rb->type == EXPANSION_AREA && !rb->flags.is_via)
3067 // return 0;
3068 rbox = bloat_routebox (rb);
3069 if (!box_intersect (&rbox, foib->box))
3070 return 0;
3071 /* this is an intersector! */
3072 foib->intersect = (routebox_t *) box;
3073 longjmp (foib->env, 1); /* skip to the end! */
3074 return 1;
3076 static routebox_t *
3077 FindOneInBox (rtree_t * rtree, routebox_t * rb)
3079 struct foib_info foib;
3080 BoxType r;
3082 r = rb->sbox;
3083 foib.box = &r;
3084 foib.intersect = NULL;
3086 if (setjmp (foib.env) == 0)
3087 r_search (rtree, &r, NULL, foib_rect_in_reg, &foib);
3088 return foib.intersect;
3091 struct therm_info
3093 routebox_t *plane;
3094 BoxType query;
3095 jmp_buf env;
3097 static int
3098 ftherm_rect_in_reg (const BoxType * box, void *cl)
3100 routebox_t *rbox = (routebox_t *) box;
3101 struct therm_info *ti = (struct therm_info *) cl;
3102 BoxType sq, sb;
3104 if (rbox->type != PIN && rbox->type != VIA && rbox->type != VIA_SHADOW)
3105 return 0;
3106 if (rbox->group != ti->plane->group)
3107 return 0;
3109 sb = shrink_routebox (rbox);
3110 switch (rbox->type)
3112 case PIN:
3113 sq = shrink_box (&ti->query, rbox->parent.pin->Thickness);
3114 if (!box_intersect (&sb, &sq))
3115 return 0;
3116 sb.X1 = rbox->parent.pin->X;
3117 sb.Y1 = rbox->parent.pin->Y;
3118 break;
3119 case VIA:
3120 if (rbox->flags.fixed)
3122 sq = shrink_box (&ti->query, rbox->parent.via->Thickness);
3123 sb.X1 = rbox->parent.pin->X;
3124 sb.Y1 = rbox->parent.pin->Y;
3126 else
3128 sq = shrink_box (&ti->query, rbox->style->Diameter);
3129 sb.X1 = CENTER_X (sb);
3130 sb.Y1 = CENTER_Y (sb);
3132 if (!box_intersect (&sb, &sq))
3133 return 0;
3134 break;
3135 case VIA_SHADOW:
3136 sq = shrink_box (&ti->query, rbox->style->Diameter);
3137 if (!box_intersect (&sb, &sq))
3138 return 0;
3139 sb.X1 = CENTER_X (sb);
3140 sb.Y1 = CENTER_Y (sb);
3141 break;
3142 default:
3143 assert (0);
3145 ti->plane = rbox;
3146 longjmp (ti->env, 1);
3147 return 1;
3150 /* check for a pin or via target that a polygon can just use a thermal to connect to */
3151 routebox_t *
3152 FindThermable (rtree_t * rtree, routebox_t * rb)
3154 struct therm_info info;
3156 info.plane = rb;
3157 info.query = shrink_routebox (rb);
3159 if (setjmp (info.env) == 0)
3161 r_search (rtree, &info.query, NULL, ftherm_rect_in_reg, &info);
3162 return NULL;
3164 return info.plane;
3167 /*--------------------------------------------------------------------
3168 * Route-tracing code: once we've got a path of expansion boxes, trace
3169 * a line through them to actually create the connection.
3171 static void
3172 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
3173 Cardinal group, Cardinal layer, routebox_t * subnet,
3174 bool is_bad)
3176 routebox_t *rb;
3177 rb = (routebox_t *) malloc (sizeof (*rb));
3178 memset ((void *) rb, 0, sizeof (*rb));
3179 init_const_box (rb, X, Y, X + 1, Y + 1, 0);
3180 rb->group = group;
3181 rb->layer = layer;
3182 rb->flags.fixed = 0;
3183 rb->flags.is_bad = is_bad;
3184 rb->flags.is_odd = AutoRouteParameters.is_odd;
3185 rb->flags.circular = 0;
3186 rb->style = AutoRouteParameters.style;
3187 rb->type = THERMAL;
3188 InitLists (rb);
3189 MergeNets (rb, subnet, NET);
3190 MergeNets (rb, subnet, SUBNET);
3191 /* add it to the r-tree, this may be the whole route! */
3192 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3193 rb->flags.homeless = 0;
3196 static void
3197 RD_DrawVia (routedata_t * rd, Coord X, Coord Y,
3198 Coord radius, routebox_t * subnet, bool is_bad)
3200 routebox_t *rb, *first_via = NULL;
3201 int i;
3202 int ka = AutoRouteParameters.style->Keepaway;
3203 PinType *live_via = NULL;
3205 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3207 live_via = CreateNewVia (PCB->Data, X, Y, radius * 2,
3208 2 * AutoRouteParameters.style->Keepaway, 0,
3209 AutoRouteParameters.style->Hole, NULL,
3210 MakeFlags (0));
3211 if (live_via != NULL)
3212 DrawVia (live_via);
3215 /* a via cuts through every layer group */
3216 for (i = 0; i < max_group; i++)
3218 if (!is_layer_group_active[i])
3219 continue;
3220 rb = (routebox_t *) malloc (sizeof (*rb));
3221 memset ((void *) rb, 0, sizeof (*rb));
3222 init_const_box (rb,
3223 /*X1 */ X - radius, /*Y1 */ Y - radius,
3224 /*X2 */ X + radius + 1, /*Y2 */ Y + radius + 1, ka);
3225 rb->group = i;
3226 rb->flags.fixed = 0; /* indicates that not on PCB yet */
3227 rb->flags.is_odd = AutoRouteParameters.is_odd;
3228 rb->flags.is_bad = is_bad;
3229 rb->came_from = ALL;
3230 rb->flags.circular = true;
3231 rb->style = AutoRouteParameters.style;
3232 rb->pass = AutoRouteParameters.pass;
3233 if (first_via == NULL)
3235 rb->type = VIA;
3236 rb->parent.via = NULL; /* indicates that not on PCB yet */
3237 first_via = rb;
3238 /* only add the first via to mtspace, not the shadows too */
3239 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
3240 rb->style->Keepaway);
3242 else
3244 rb->type = VIA_SHADOW;
3245 rb->parent.via_shadow = first_via;
3247 InitLists (rb);
3248 /* add these to proper subnet. */
3249 MergeNets (rb, subnet, NET);
3250 MergeNets (rb, subnet, SUBNET);
3251 assert (__routebox_is_good (rb));
3252 /* and add it to the r-tree! */
3253 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3254 rb->flags.homeless = 0; /* not homeless anymore */
3255 rb->livedraw_obj.via = live_via;
3258 static void
3259 RD_DrawLine (routedata_t * rd,
3260 Coord X1, Coord Y1, Coord X2,
3261 Coord Y2, Coord halfthick, Cardinal group,
3262 routebox_t * subnet, bool is_bad, bool is_45)
3264 /* we hold the line in a queue to concatenate segments that
3265 * ajoin one another. That reduces the number of things in
3266 * the trees and allows conflict boxes to be larger, both of
3267 * which are really useful.
3269 static Coord qX1 = -1, qY1, qX2, qY2;
3270 static Coord qhthick;
3271 static Cardinal qgroup;
3272 static bool qis_45, qis_bad;
3273 static routebox_t *qsn;
3275 routebox_t *rb;
3276 Coord ka = AutoRouteParameters.style->Keepaway;
3278 /* don't draw zero-length segments. */
3279 if (X1 == X2 && Y1 == Y2)
3280 return;
3281 if (qX1 == -1) /* first ever */
3283 qX1 = X1;
3284 qY1 = Y1;
3285 qX2 = X2;
3286 qY2 = Y2;
3287 qhthick = halfthick;
3288 qgroup = group;
3289 qis_45 = is_45;
3290 qis_bad = is_bad;
3291 qsn = subnet;
3292 return;
3294 /* Check if the lines concatenat. We only check the
3295 * normal expected nextpoint=lastpoint condition
3297 if (X1 == qX2 && Y1 == qY2 && qhthick == halfthick && qgroup == group)
3299 if (qX1 == qX2 && X1 == X2) /* everybody on the same X here */
3301 qY2 = Y2;
3302 return;
3304 if (qY1 == qY2 && Y1 == Y2) /* same Y all around */
3306 qX2 = X2;
3307 return;
3310 /* dump the queue, no match here */
3311 if (qX1 == -1)
3312 return; /* but not this! */
3313 rb = (routebox_t *) malloc (sizeof (*rb));
3314 memset ((void *) rb, 0, sizeof (*rb));
3315 assert (is_45 ? (ABS (qX2 - qX1) == ABS (qY2 - qY1)) /* line must be 45-degrees */
3316 : (qX1 == qX2 || qY1 == qY2) /* line must be ortho */ );
3317 init_const_box (rb,
3318 /*X1 */ MIN (qX1, qX2) - qhthick,
3319 /*Y1 */ MIN (qY1, qY2) - qhthick,
3320 /*X2 */ MAX (qX1, qX2) + qhthick + 1,
3321 /*Y2 */ MAX (qY1, qY2) + qhthick + 1, ka);
3322 rb->group = qgroup;
3323 rb->type = LINE;
3324 rb->parent.line = NULL; /* indicates that not on PCB yet */
3325 rb->flags.fixed = 0; /* indicates that not on PCB yet */
3326 rb->flags.is_odd = AutoRouteParameters.is_odd;
3327 rb->flags.is_bad = qis_bad;
3328 rb->came_from = ALL;
3329 rb->flags.homeless = 0; /* we're putting this in the tree */
3330 rb->flags.nonstraight = qis_45;
3331 rb->flags.bl_to_ur = ((qX2 >= qX1 && qY2 <= qY1)
3332 || (qX2 <= qX1 && qY2 >= qY1));
3333 rb->style = AutoRouteParameters.style;
3334 rb->pass = AutoRouteParameters.pass;
3335 InitLists (rb);
3336 /* add these to proper subnet. */
3337 MergeNets (rb, qsn, NET);
3338 MergeNets (rb, qsn, SUBNET);
3339 assert (__routebox_is_good (rb));
3340 /* and add it to the r-tree! */
3341 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
3343 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3345 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
3346 LineType *line = CreateNewLineOnLayer (layer, qX1, qY1, qX2, qY2,
3347 2 * qhthick, 0, MakeFlags (0));
3348 rb->livedraw_obj.line = line;
3349 if (line != NULL)
3350 DrawLine (layer, line);
3353 /* and to the via space structures */
3354 if (AutoRouteParameters.use_vias)
3355 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
3356 rb->style->Keepaway);
3357 usedGroup[rb->group] = true;
3358 /* and queue this one */
3359 qX1 = X1;
3360 qY1 = Y1;
3361 qX2 = X2;
3362 qY2 = Y2;
3363 qhthick = halfthick;
3364 qgroup = group;
3365 qis_45 = is_45;
3366 qis_bad = is_bad;
3367 qsn = subnet;
3370 static bool
3371 RD_DrawManhattanLine (routedata_t * rd,
3372 const BoxType * box1, const BoxType * box2,
3373 CheapPointType start, CheapPointType end,
3374 Coord halfthick, Cardinal group,
3375 routebox_t * subnet, bool is_bad, bool last_was_x)
3377 CheapPointType knee = start;
3378 if (end.X == start.X)
3380 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
3381 subnet, is_bad, false);
3382 return false;
3384 else if (end.Y == start.Y)
3386 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
3387 subnet, is_bad, false);
3388 return true;
3390 /* find where knee belongs */
3391 if (point_in_box (box1, end.X, start.Y)
3392 || point_in_box (box2, end.X, start.Y))
3394 knee.X = end.X;
3395 knee.Y = start.Y;
3397 else
3399 knee.X = start.X;
3400 knee.Y = end.Y;
3402 if ((knee.X == end.X && !last_was_x) &&
3403 (point_in_box (box1, start.X, end.Y)
3404 || point_in_box (box2, start.X, end.Y)))
3406 knee.X = start.X;
3407 knee.Y = end.Y;
3409 assert (AutoRouteParameters.is_smoothing
3410 || point_in_closed_box (box1, knee.X, knee.Y)
3411 || point_in_closed_box (box2, knee.X, knee.Y));
3413 if (1 || !AutoRouteParameters.is_smoothing)
3415 /* draw standard manhattan paths */
3416 RD_DrawLine (rd, start.X, start.Y, knee.X, knee.Y, halfthick, group,
3417 subnet, is_bad, false);
3418 RD_DrawLine (rd, knee.X, knee.Y, end.X, end.Y, halfthick, group,
3419 subnet, is_bad, false);
3421 else
3423 /* draw 45-degree path across knee */
3424 Coord len45 = MIN (ABS (start.X - end.X), ABS (start.Y - end.Y));
3425 CheapPointType kneestart = knee, kneeend = knee;
3426 if (kneestart.X == start.X)
3427 kneestart.Y += (kneestart.Y > start.Y) ? -len45 : len45;
3428 else
3429 kneestart.X += (kneestart.X > start.X) ? -len45 : len45;
3430 if (kneeend.X == end.X)
3431 kneeend.Y += (kneeend.Y > end.Y) ? -len45 : len45;
3432 else
3433 kneeend.X += (kneeend.X > end.X) ? -len45 : len45;
3434 RD_DrawLine (rd, start.X, start.Y, kneestart.X, kneestart.Y, halfthick,
3435 group, subnet, is_bad, false);
3436 RD_DrawLine (rd, kneestart.X, kneestart.Y, kneeend.X, kneeend.Y,
3437 halfthick, group, subnet, is_bad, true);
3438 RD_DrawLine (rd, kneeend.X, kneeend.Y, end.X, end.Y, halfthick, group,
3439 subnet, is_bad, false);
3441 return (knee.X != end.X);
3444 /* for smoothing, don't pack traces to min clearance gratuitously */
3445 #if 0
3446 static void
3447 add_clearance (CheapPointType * nextpoint, const BoxType * b)
3449 if (nextpoint->X == b->X1)
3451 if (nextpoint->X +
3452 AutoRouteParameters.style->Keepaway < (b->X1 + b->X2) / 2)
3453 nextpoint->X += AutoRouteParameters.style->Keepaway;
3454 else
3455 nextpoint->X = (b->X1 + b->X2) / 2;
3457 else if (nextpoint->X == b->X2)
3459 if (nextpoint->X -
3460 AutoRouteParameters.style->Keepaway > (b->X1 + b->X2) / 2)
3461 nextpoint->X -= AutoRouteParameters.style->Keepaway;
3462 else
3463 nextpoint->X = (b->X1 + b->X2) / 2;
3465 else if (nextpoint->Y == b->Y1)
3467 if (nextpoint->Y +
3468 AutoRouteParameters.style->Keepaway < (b->Y1 + b->Y2) / 2)
3469 nextpoint->Y += AutoRouteParameters.style->Keepaway;
3470 else
3471 nextpoint->Y = (b->Y1 + b->Y2) / 2;
3473 else if (nextpoint->Y == b->Y2)
3475 if (nextpoint->Y -
3476 AutoRouteParameters.style->Keepaway > (b->Y1 + b->Y2) / 2)
3477 nextpoint->Y -= AutoRouteParameters.style->Keepaway;
3478 else
3479 nextpoint->Y = (b->Y1 + b->Y2) / 2;
3482 #endif
3484 /* This back-traces the expansion boxes along the best path
3485 * it draws the lines that will make the actual path.
3486 * during refinement passes, it should try to maximize the area
3487 * for other tracks so routing completion is easier.
3489 * during smoothing passes, it should try to make a better path,
3490 * possibly using diagonals, etc. The path boxes are larger on
3491 * average now so there is more possiblity to decide on a nice
3492 * path. Any combination of lines and arcs is possible, so long
3493 * as they don't poke more than half thick outside the path box.
3496 static void
3497 TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target,
3498 routebox_t * subnet, bool is_bad)
3500 bool last_x = false;
3501 Coord halfwidth = HALF_THICK (AutoRouteParameters.style->Thick);
3502 Coord radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3503 CheapPointType lastpoint, nextpoint;
3504 routebox_t *lastpath;
3505 BoxType b;
3507 assert (subnet->style == AutoRouteParameters.style);
3508 /*XXX: because we round up odd thicknesses, there's the possibility that
3509 * a connecting line end-point might be 0.005 mil off the "real" edge.
3510 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
3512 /* if we start with a thermal the target was a plane
3513 * or the target was a pin and the source a plane
3514 * in which case this thermal is the whole path
3516 if (path->flags.is_thermal)
3518 /* the target was a plane, so we need to find a good spot for the via
3519 * now. It's logical to place it close to the source box which
3520 * is where we're utlimately headed on this path. However, it
3521 * must reside in the plane as well as the via area too.
3523 nextpoint.X = CENTER_X (path->sbox);
3524 nextpoint.Y = CENTER_Y (path->sbox);
3525 if (path->parent.expansion_area->flags.is_via)
3527 TargetPoint (&nextpoint, rb_source (path));
3528 /* nextpoint is the middle of the source terminal now */
3529 b = clip_box (&path->sbox, &path->parent.expansion_area->sbox);
3530 nextpoint = closest_point_in_box (&nextpoint, &b);
3531 /* now it's in the via and plane near the source */
3533 else /* no via coming, target must have been a pin */
3535 assert (target->type == PIN);
3536 TargetPoint (&nextpoint, target);
3538 assert (point_in_box (&path->sbox, nextpoint.X, nextpoint.Y));
3539 RD_DrawThermal (rd, nextpoint.X, nextpoint.Y, path->group,
3540 path->layer, subnet, is_bad);
3542 else
3544 /* start from best place of target box */
3545 lastpoint.X = CENTER_X (target->sbox);
3546 lastpoint.Y = CENTER_Y (target->sbox);
3547 TargetPoint (&lastpoint, target);
3548 if (AutoRouteParameters.last_smooth
3549 && box_in_box (&path->sbox, &target->sbox))
3550 path = path->parent.expansion_area;
3551 b = path->sbox;
3552 if (path->flags.circular)
3553 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
3554 nextpoint = closest_point_in_box (&lastpoint, &b);
3555 if (AutoRouteParameters.last_smooth)
3556 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3557 halfwidth, path->group, subnet, is_bad, TRUE);
3558 else
3559 last_x = RD_DrawManhattanLine (rd, &target->sbox, &path->sbox,
3560 lastpoint, nextpoint, halfwidth,
3561 path->group, subnet, is_bad, last_x);
3563 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3564 showroutebox (path);
3565 #if defined(ROUTE_VERBOSE)
3566 pcb_printf ("TRACEPOINT start %#mD\n", nextpoint.X, nextpoint.Y);
3567 #endif
3568 #endif
3572 lastpoint = nextpoint;
3573 lastpath = path;
3574 assert (path->type == EXPANSION_AREA);
3575 path = path->parent.expansion_area;
3576 b = path->sbox;
3577 if (path->flags.circular)
3578 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
3579 assert (b.X1 != b.X2 && b.Y1 != b.Y2); /* need someplace to put line! */
3580 /* find point on path perimeter closest to last point */
3581 /* if source terminal, try to hit a good place */
3582 nextpoint = closest_point_in_box (&lastpoint, &b);
3583 #if 0
3584 /* leave more clearance if this is a smoothing pass */
3585 if (AutoRouteParameters.is_smoothing &&
3586 (nextpoint.X != lastpoint.X || nextpoint.Y != lastpoint.Y))
3587 add_clearance (&nextpoint, &b);
3588 #endif
3589 if (path->flags.source && path->type != PLANE)
3590 TargetPoint (&nextpoint, path);
3591 assert (point_in_box (&lastpath->box, lastpoint.X, lastpoint.Y));
3592 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
3593 #if defined(ROUTE_DEBUG_VERBOSE)
3594 printf ("TRACEPATH: ");
3595 DumpRouteBox (path);
3596 pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n",
3597 lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3598 path->group);
3599 #endif
3601 /* draw orthogonal lines from lastpoint to nextpoint */
3602 /* knee is placed in lastpath box */
3603 /* should never cause line to leave union of lastpath/path boxes */
3604 if (AutoRouteParameters.last_smooth)
3605 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
3606 halfwidth, path->group, subnet, is_bad, TRUE);
3607 else
3608 last_x = RD_DrawManhattanLine (rd, &lastpath->sbox, &path->sbox,
3609 lastpoint, nextpoint, halfwidth,
3610 path->group, subnet, is_bad, last_x);
3611 if (path->flags.is_via)
3612 { /* if via, then add via */
3613 #ifdef ROUTE_VERBOSE
3614 printf (" (vias)");
3615 #endif
3616 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
3617 RD_DrawVia (rd, nextpoint.X, nextpoint.Y, radius, subnet, is_bad);
3620 assert (lastpath->flags.is_via || path->group == lastpath->group);
3622 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3623 showroutebox (path);
3624 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
3625 /* if this is connected to a plane, draw the thermal */
3626 if (path->flags.is_thermal || path->type == PLANE)
3627 RD_DrawThermal (rd, lastpoint.X, lastpoint.Y, path->group,
3628 path->layer, subnet, is_bad);
3629 /* when one hop from the source, make an extra path in *this* box */
3630 if (path->type == EXPANSION_AREA
3631 && path->parent.expansion_area->flags.source
3632 && path->parent.expansion_area->type != PLANE)
3634 /* find special point on source (if it exists) */
3635 if (TargetPoint (&lastpoint, path->parent.expansion_area))
3637 lastpoint = closest_point_in_routebox (&lastpoint, path);
3638 b = shrink_routebox (path);
3639 #if 0
3640 if (AutoRouteParameters.is_smoothing)
3641 add_clearance (&lastpoint, &b);
3642 #else
3643 if (AutoRouteParameters.last_smooth)
3644 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X,
3645 nextpoint.Y, halfwidth, path->group, subnet,
3646 is_bad, TRUE);
3647 else
3648 #endif
3649 last_x = RD_DrawManhattanLine (rd, &b, &b,
3650 nextpoint, lastpoint,
3651 halfwidth, path->group, subnet,
3652 is_bad, last_x);
3653 #if defined(ROUTE_DEBUG_VERBOSE)
3654 printf ("TRACEPATH: ");
3655 DumpRouteBox (path);
3656 pcb_printf
3657 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n",
3658 nextpoint.X, nextpoint.Y, lastpoint.X, lastpoint.Y,
3659 path->group);
3660 #endif
3662 nextpoint = lastpoint;
3666 while (!path->flags.source);
3667 /* flush the line queue */
3668 RD_DrawLine (rd, -1, 0, 0, 0, 0, 0, NULL, false, false);
3670 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
3671 Draw ();
3673 #ifdef ROUTE_DEBUG
3674 if (ddraw != NULL)
3675 ddraw->flush_debug_draw ();
3676 #endif
3679 /* create a fake "edge" used to defer via site searching. */
3680 static void
3681 CreateSearchEdge (struct routeone_state *s, vetting_t * work, edge_t * parent,
3682 routebox_t * rb, conflict_t conflict, rtree_t * targets,
3683 bool in_plane)
3685 routebox_t *target;
3686 BoxType b;
3687 cost_t cost;
3688 assert (__routebox_is_good (rb));
3689 /* find the cheapest target */
3690 #if 0
3691 target =
3692 mincost_target_to_point (&parent->cost_point, max_group + 1, targets,
3693 parent->mincost_target);
3694 #else
3695 target = parent->mincost_target;
3696 #endif
3697 b = shrink_routebox (target);
3698 cost =
3699 parent->cost_to_point + AutoRouteParameters.ViaCost +
3700 cost_to_layerless_box (&rb->cost_point, 0, &b);
3701 if (cost < s->best_cost)
3703 edge_t *ne;
3704 ne = (edge_t *)malloc (sizeof (*ne));
3705 memset ((void *) ne, 0, sizeof (*ne));
3706 assert (ne);
3707 ne->flags.via_search = 1;
3708 ne->flags.in_plane = in_plane;
3709 ne->rb = rb;
3710 if (rb->flags.homeless)
3711 RB_up_count (rb);
3712 ne->work = work;
3713 ne->mincost_target = target;
3714 ne->flags.via_conflict_level = conflict;
3715 ne->cost_to_point = parent->cost_to_point;
3716 ne->cost_point = parent->cost_point;
3717 ne->cost = cost;
3718 heap_insert (s->workheap, ne->cost, ne);
3720 else
3722 mtsFreeWork (&work);
3726 static void
3727 add_or_destroy_edge (struct routeone_state *s, edge_t * e)
3729 e->cost = edge_cost (e, s->best_cost);
3730 assert (__edge_is_good (e));
3731 assert (is_layer_group_active[e->rb->group]);
3732 if (e->cost < s->best_cost)
3733 heap_insert (s->workheap, e->cost, e);
3734 else
3735 DestroyEdge (&e);
3738 static void
3739 best_path_candidate (struct routeone_state *s,
3740 edge_t * e, routebox_t * best_target)
3742 e->cost = edge_cost (e, EXPENSIVE);
3743 if (s->best_path == NULL || e->cost < s->best_cost)
3745 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE)
3746 printf ("New best path seen! cost = %f\n", e->cost);
3747 #endif
3748 /* new best path! */
3749 if (s->best_path && s->best_path->flags.homeless)
3750 RB_down_count (s->best_path);
3751 s->best_path = e->rb;
3752 s->best_target = best_target;
3753 s->best_cost = e->cost;
3754 assert (s->best_cost >= 0);
3755 /* don't free this when we destroy edge! */
3756 if (s->best_path->flags.homeless)
3757 RB_up_count (s->best_path);
3762 /* vectors for via site candidates (see mtspace.h) */
3763 struct routeone_via_site_state
3765 vector_t *free_space_vec;
3766 vector_t *lo_conflict_space_vec;
3767 vector_t *hi_conflict_space_vec;
3770 void
3771 add_via_sites (struct routeone_state *s,
3772 struct routeone_via_site_state *vss,
3773 mtspace_t * mtspace, routebox_t * within,
3774 conflict_t within_conflict_level, edge_t * parent_edge,
3775 rtree_t * targets, Coord shrink, bool in_plane)
3777 Coord radius, keepaway;
3778 vetting_t *work;
3779 BoxType region = shrink_routebox (within);
3780 shrink_box (&region, shrink);
3782 radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3783 keepaway = AutoRouteParameters.style->Keepaway;
3784 assert (AutoRouteParameters.use_vias);
3785 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
3786 XXX: routing with conflicts may poke over edge. */
3788 /* ask for a via box near our cost_point first */
3789 work = mtspace_query_rect (mtspace, &region, radius, keepaway,
3790 NULL, vss->free_space_vec,
3791 vss->lo_conflict_space_vec,
3792 vss->hi_conflict_space_vec,
3793 AutoRouteParameters.is_odd,
3794 AutoRouteParameters.with_conflicts,
3795 &parent_edge->cost_point);
3796 if (!work)
3797 return;
3798 CreateSearchEdge (s, work, parent_edge, within, within_conflict_level,
3799 targets, in_plane);
3802 void
3803 do_via_search (edge_t * search, struct routeone_state *s,
3804 struct routeone_via_site_state *vss, mtspace_t * mtspace,
3805 rtree_t * targets)
3807 int i, j, count = 0;
3808 Coord radius, keepaway;
3809 vetting_t *work;
3810 routebox_t *within;
3811 conflict_t within_conflict_level;
3813 radius = HALF_THICK (AutoRouteParameters.style->Diameter);
3814 keepaway = AutoRouteParameters.style->Keepaway;
3815 work = mtspace_query_rect (mtspace, NULL, 0, 0,
3816 search->work, vss->free_space_vec,
3817 vss->lo_conflict_space_vec,
3818 vss->hi_conflict_space_vec,
3819 AutoRouteParameters.is_odd,
3820 AutoRouteParameters.with_conflicts, NULL);
3821 within = search->rb;
3822 within_conflict_level = search->flags.via_conflict_level;
3823 for (i = 0; i < 3; i++)
3825 vector_t *v =
3826 (i == NO_CONFLICT ? vss->free_space_vec :
3827 i == LO_CONFLICT ? vss->lo_conflict_space_vec :
3828 i == HI_CONFLICT ? vss->hi_conflict_space_vec : NULL);
3829 assert (v);
3830 while (!vector_is_empty (v))
3832 BoxType cliparea;
3833 BoxType *area = (BoxType *)vector_remove_last (v);
3834 if (!(i == NO_CONFLICT || AutoRouteParameters.with_conflicts))
3836 free (area);
3837 continue;
3839 /* answers are bloated by radius + keepaway */
3840 cliparea = shrink_box (area, radius + keepaway);
3841 close_box (&cliparea);
3842 free (area);
3843 assert (box_is_good (&cliparea));
3844 count++;
3845 for (j = 0; j < max_group; j++)
3847 edge_t *ne;
3848 if (j == within->group || !is_layer_group_active[j])
3849 continue;
3850 ne = CreateViaEdge (&cliparea, j, within, search,
3851 within_conflict_level, (conflict_t)i, targets);
3852 add_or_destroy_edge (s, ne);
3856 /* prevent freeing of work when this edge is destroyed */
3857 search->flags.via_search = 0;
3858 if (!work)
3859 return;
3860 CreateSearchEdge (s, work, search, within, within_conflict_level, targets,
3861 search->flags.in_plane);
3862 assert (vector_is_empty (vss->free_space_vec));
3863 assert (vector_is_empty (vss->lo_conflict_space_vec));
3864 assert (vector_is_empty (vss->hi_conflict_space_vec));
3867 /* vector of expansion areas to be eventually removed from r-tree
3868 * this is a global for troubleshooting
3870 vector_t *area_vec;
3872 /* some routines for use in gdb while debugging */
3873 #if defined(ROUTE_DEBUG)
3874 static void
3875 list_conflicts (routebox_t * rb)
3877 int i, n;
3878 if (!rb->conflicts_with)
3879 return;
3880 n = vector_size (rb->conflicts_with);
3881 for (i = 0; i < n; i++)
3882 printf ("%p, ", vector_element (rb->conflicts_with, i));
3885 static void
3886 show_area_vec (int lay)
3888 int n, save;
3890 if (!area_vec)
3891 return;
3892 save = showboxen;
3893 showboxen = lay;
3894 for (n = 0; n < vector_size (area_vec); n++)
3896 routebox_t *rb = (routebox_t *) vector_element (area_vec, n);
3897 showroutebox (rb);
3899 showboxen = save;
3902 static bool
3903 net_id (routebox_t * rb, long int id)
3905 routebox_t *p;
3906 LIST_LOOP (rb, same_net, p);
3907 if (p->flags.source && p->parent.pad->ID == id)
3908 return true;
3909 END_LOOP;
3910 return false;
3913 static void
3914 trace_parents (routebox_t * rb)
3916 while (rb && rb->type == EXPANSION_AREA)
3918 printf (" %p ->", rb);
3919 rb = rb->parent.expansion_area;
3921 if (rb)
3922 printf (" %p is source\n", rb);
3923 else
3924 printf ("NULL!\n");
3927 static void
3928 show_one (routebox_t * rb)
3930 int save = showboxen;
3931 showboxen = -1;
3932 showroutebox (rb);
3933 showboxen = save;
3936 static void
3937 show_path (routebox_t * rb)
3939 while (rb && rb->type == EXPANSION_AREA)
3941 show_one (rb);
3942 rb = rb->parent.expansion_area;
3944 show_one (rb);
3947 static void
3948 show_sources (routebox_t * rb)
3950 routebox_t *p;
3951 if (!rb->flags.source && !rb->flags.target)
3953 printf ("start with a source or target please\n");
3954 return;
3956 LIST_LOOP (rb, same_net, p);
3957 if (p->flags.source)
3958 show_one (p);
3959 END_LOOP;
3962 #endif
3964 static int
3965 __conflict_source (const BoxType * box, void *cl)
3967 routebox_t *rb = (routebox_t *) box;
3968 if (rb->flags.touched || rb->flags.fixed)
3969 return 0;
3970 else
3972 routebox_t *dis = (routebox_t *) cl;
3973 path_conflicts (dis, rb, false);
3974 touch_conflicts (dis->conflicts_with, 1);
3976 return 1;
3979 static void
3980 source_conflicts (rtree_t * tree, routebox_t * rb)
3982 if (!AutoRouteParameters.with_conflicts)
3983 return;
3984 r_search (tree, &rb->sbox, NULL, __conflict_source, rb);
3985 touch_conflicts (NULL, 1);
3988 struct routeone_status
3990 bool found_route;
3991 int route_had_conflicts;
3992 cost_t best_route_cost;
3993 bool net_completely_routed;
3997 static struct routeone_status
3998 RouteOne (routedata_t * rd, routebox_t * from, routebox_t * to, int max_edges)
4000 struct routeone_status result;
4001 routebox_t *p;
4002 int seen, i;
4003 const BoxType **target_list;
4004 int num_targets;
4005 rtree_t *targets;
4006 /* vector of source edges for filtering */
4007 vector_t *source_vec;
4008 /* working vector */
4009 vector_t *edge_vec;
4011 struct routeone_state s;
4012 struct routeone_via_site_state vss;
4014 assert (rd && from);
4015 result.route_had_conflicts = 0;
4016 /* no targets on to/from net need keepaway areas */
4017 LIST_LOOP (from, same_net, p);
4018 p->flags.nobloat = 1;
4019 END_LOOP;
4020 /* set 'source' flags */
4021 LIST_LOOP (from, same_subnet, p);
4022 if (!p->flags.nonstraight)
4023 p->flags.source = 1;
4024 END_LOOP;
4026 /* count up the targets */
4027 num_targets = 0;
4028 seen = 0;
4029 /* remove source/target flags from non-straight obstacles, because they
4030 * don't fill their bounding boxes and so connecting to them
4031 * after we've routed is problematic. Better solution? */
4032 if (to)
4033 { /* if we're routing to a specific target */
4034 if (!to->flags.source)
4035 { /* not already connected */
4036 /* check that 'to' and 'from' are on the same net */
4037 seen = 0;
4038 #ifndef NDEBUG
4039 LIST_LOOP (from, same_net, p);
4040 if (p == to)
4041 seen = 1;
4042 END_LOOP;
4043 #endif
4044 assert (seen); /* otherwise from and to are on different nets! */
4045 /* set target flags only on 'to's subnet */
4046 LIST_LOOP (to, same_subnet, p);
4047 if (!p->flags.nonstraight && is_layer_group_active[p->group])
4049 p->flags.target = 1;
4050 num_targets++;
4052 END_LOOP;
4055 else
4057 /* all nodes on the net but not connected to from are targets */
4058 LIST_LOOP (from, same_net, p);
4059 if (!p->flags.source && is_layer_group_active[p->group]
4060 && !p->flags.nonstraight)
4062 p->flags.target = 1;
4063 num_targets++;
4065 END_LOOP;
4068 /* if no targets, then net is done! reset flags and return. */
4069 if (num_targets == 0)
4071 LIST_LOOP (from, same_net, p);
4072 p->flags.source = p->flags.target = p->flags.nobloat = 0;
4073 END_LOOP;
4074 result.found_route = false;
4075 result.net_completely_routed = true;
4076 result.best_route_cost = 0;
4077 result.route_had_conflicts = 0;
4079 return result;
4081 result.net_completely_routed = false;
4083 /* okay, there's stuff to route */
4084 assert (!from->flags.target);
4085 assert (num_targets > 0);
4086 /* create list of target pointers and from that a r-tree of targets */
4087 target_list = (const BoxType **)malloc (num_targets * sizeof (*target_list));
4088 i = 0;
4089 LIST_LOOP (from, same_net, p);
4090 if (p->flags.target)
4092 target_list[i++] = &p->box;
4093 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
4094 showroutebox (p);
4095 #endif
4097 END_LOOP;
4098 targets = r_create_tree ((const BoxType **)target_list, i, 0);
4099 assert (i <= num_targets);
4100 free (target_list);
4102 source_vec = vector_create ();
4103 /* touch the source subnet to prepare check for conflictors */
4104 LIST_LOOP (from, same_subnet, p);
4105 p->flags.touched = 1;
4106 END_LOOP;
4107 LIST_LOOP (from, same_subnet, p);
4109 /* we need the test for 'source' because this box may be nonstraight */
4110 if (p->flags.source && is_layer_group_active[p->group])
4112 CheapPointType cp;
4113 edge_t *e;
4114 BoxType b = shrink_routebox (p);
4116 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES)
4117 showroutebox (p);
4118 #endif
4119 /* may expand in all directions from source; center edge cost point. */
4120 /* note that planes shouldn't really expand, but we need an edge */
4122 cp.X = CENTER_X (b);
4123 cp.Y = CENTER_Y (b);
4124 e = CreateEdge (p, cp.X, cp.Y, 0, NULL, ALL, targets);
4125 cp = closest_point_in_box (&cp, &e->mincost_target->sbox);
4126 cp = closest_point_in_box (&cp, &b);
4127 e->cost_point = cp;
4128 p->cost_point = cp;
4129 source_conflicts (rd->layergrouptree[p->group], p);
4130 vector_append (source_vec, e);
4133 END_LOOP;
4134 LIST_LOOP (from, same_subnet, p);
4135 p->flags.touched = 0;
4136 END_LOOP;
4137 /* break source edges; some edges may be too near obstacles to be able
4138 * to exit from. */
4140 /* okay, main expansion-search routing loop. */
4141 /* set up the initial activity heap */
4142 s.workheap = heap_create ();
4143 assert (s.workheap);
4144 while (!vector_is_empty (source_vec))
4146 edge_t *e = (edge_t *)vector_remove_last (source_vec);
4147 assert (is_layer_group_active[e->rb->group]);
4148 e->cost = edge_cost (e, EXPENSIVE);
4149 heap_insert (s.workheap, e->cost, e);
4151 vector_destroy (&source_vec);
4152 /* okay, process items from heap until it is empty! */
4153 s.best_path = NULL;
4154 s.best_cost = EXPENSIVE;
4155 area_vec = vector_create ();
4156 edge_vec = vector_create ();
4157 vss.free_space_vec = vector_create ();
4158 vss.lo_conflict_space_vec = vector_create ();
4159 vss.hi_conflict_space_vec = vector_create ();
4160 while (!heap_is_empty (s.workheap))
4162 edge_t *e = (edge_t *)heap_remove_smallest (s.workheap);
4163 #ifdef ROUTE_DEBUG
4164 if (aabort)
4165 goto dontexpand;
4166 #endif
4167 /* don't bother expanding this edge if the minimum possible edge cost
4168 * is already larger than the best edge cost we've found. */
4169 if (s.best_path && e->cost >= s.best_cost)
4171 heap_free (s.workheap, KillEdge);
4172 goto dontexpand; /* skip this edge */
4174 /* surprisingly it helps to give up and not try too hard to find
4175 * a route! This is not only faster, but results in better routing.
4176 * who would have guessed?
4178 if (seen++ > max_edges)
4179 goto dontexpand;
4180 assert (__edge_is_good (e));
4181 /* mark or unmark conflictors as needed */
4182 touch_conflicts (e->rb->conflicts_with, 1);
4183 if (e->flags.via_search)
4185 do_via_search (e, &s, &vss, rd->mtspace, targets);
4186 goto dontexpand;
4188 /* we should never add edges on inactive layer groups to the heap. */
4189 assert (is_layer_group_active[e->rb->group]);
4190 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
4191 //showedge (e);
4192 #endif
4193 if (e->rb->flags.is_thermal)
4195 best_path_candidate (&s, e, e->mincost_target);
4196 goto dontexpand;
4198 /* for a plane, look for quick connections with thermals or vias */
4199 if (e->rb->type == PLANE)
4201 routebox_t *pin = FindThermable (targets, e->rb);
4202 if (pin)
4204 BoxType b = shrink_routebox (pin);
4205 edge_t *ne;
4206 routebox_t *nrb;
4207 assert (pin->flags.target);
4208 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
4209 nrb->flags.is_thermal = 1;
4210 /* moving through the plane is free */
4211 e->cost_point.X = b.X1;
4212 e->cost_point.Y = b.Y1;
4213 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, pin);
4214 best_path_candidate (&s, ne, pin);
4215 DestroyEdge (&ne);
4217 else
4219 /* add in possible via sites in plane */
4220 if (AutoRouteParameters.use_vias &&
4221 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
4223 /* we need a giant thermal */
4224 routebox_t *nrb =
4225 CreateExpansionArea (&e->rb->sbox, e->rb->group, e->rb,
4226 true, e);
4227 edge_t *ne = CreateEdge2 (nrb, e->expand_dir, e, NULL,
4228 e->mincost_target);
4229 nrb->flags.is_thermal = 1;
4230 add_via_sites (&s, &vss, rd->mtspace, nrb, NO_CONFLICT, ne,
4231 targets, e->rb->style->Diameter, true);
4234 goto dontexpand; /* planes only connect via thermals */
4236 if (e->flags.is_via)
4237 { /* special case via */
4238 routebox_t *intersecting;
4239 assert (AutoRouteParameters.use_vias);
4240 assert (e->expand_dir == ALL);
4241 assert (vector_is_empty (edge_vec));
4242 /* if there is already something here on this layer (like an
4243 * EXPANSION_AREA), then we don't want to expand from here
4244 * at least not inside the expansion area. A PLANE on the
4245 * other hand may be a target, or not.
4247 intersecting =
4248 FindOneInBox (rd->layergrouptree[e->rb->group], e->rb);
4250 if (intersecting && intersecting->flags.target
4251 && intersecting->type == PLANE)
4253 /* we have hit a plane */
4254 edge_t *ne;
4255 routebox_t *nrb;
4256 BoxType b = shrink_routebox (e->rb);
4257 /* limit via region to that inside the plane */
4258 clip_box (&b, &intersecting->sbox);
4259 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
4260 nrb->flags.is_thermal = 1;
4261 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, intersecting);
4262 best_path_candidate (&s, ne, intersecting);
4263 DestroyEdge (&ne);
4264 goto dontexpand;
4266 else if (intersecting == NULL)
4268 /* this via candidate is in an open area; add it to r-tree as
4269 * an expansion area */
4270 assert (e->rb->type == EXPANSION_AREA && e->rb->flags.is_via);
4271 /*assert (!r_search (rd->layergrouptree[e->rb->group],
4272 &e->rb->box, NULL, no_planes,0));
4274 r_insert_entry (rd->layergrouptree[e->rb->group], &e->rb->box,
4276 e->rb->flags.homeless = 0; /* not homeless any more */
4277 /* add to vector of all expansion areas in r-tree */
4278 vector_append (area_vec, e->rb);
4279 /* mark reset refcount to 0, since this is not homeless any more. */
4280 e->rb->refcount = 0;
4281 /* go ahead and expand this edge! */
4283 else if (1)
4284 goto dontexpand;
4285 else if (0)
4286 { /* XXX: disabling this causes no via
4287 collisions. */
4288 BoxType a = bloat_routebox (intersecting), b;
4289 edge_t *ne;
4290 int i, j;
4291 /* something intersects this via candidate. split via candidate
4292 * into pieces and add these pieces to the workheap. */
4293 for (i = 0; i < 3; i++)
4295 for (j = 0; j < 3; j++)
4297 b = shrink_routebox (e->rb);
4298 switch (i)
4300 case 0:
4301 b.X2 = MIN (b.X2, a.X1);
4302 break; /* left */
4303 case 1:
4304 b.X1 = MAX (b.X1, a.X1);
4305 b.X2 = MIN (b.X2, a.X2);
4306 break; /*c */
4307 case 2:
4308 b.X1 = MAX (b.X1, a.X2);
4309 break; /* right */
4310 default:
4311 assert (0);
4313 switch (j)
4315 case 0:
4316 b.Y2 = MIN (b.Y2, a.Y1);
4317 break; /* top */
4318 case 1:
4319 b.Y1 = MAX (b.Y1, a.Y1);
4320 b.Y2 = MIN (b.Y2, a.Y2);
4321 break; /*c */
4322 case 2:
4323 b.Y1 = MAX (b.Y1, a.Y2);
4324 break; /* bottom */
4325 default:
4326 assert (0);
4328 /* skip if this box is not valid */
4329 if (!(b.X1 < b.X2 && b.Y1 < b.Y2))
4330 continue;
4331 if (i == 1 && j == 1)
4333 /* this bit of the via space is obstructed. */
4334 if (intersecting->type == EXPANSION_AREA
4335 || intersecting->flags.fixed)
4336 continue; /* skip this bit, it's already been done. */
4337 /* create an edge with conflicts, if enabled */
4338 if (!AutoRouteParameters.with_conflicts)
4339 continue;
4340 ne = CreateEdgeWithConflicts (&b, intersecting, e, 1
4341 /*cost penalty to box */
4342 , targets);
4343 add_or_destroy_edge (&s, ne);
4345 else
4347 /* if this is not the intersecting piece, create a new
4348 * (hopefully unobstructed) via edge and add it back to the
4349 * workheap. */
4350 ne =
4351 CreateViaEdge (&b, e->rb->group,
4352 e->rb->parent.expansion_area, e,
4353 e->flags.via_conflict_level,
4354 NO_CONFLICT
4355 /* value here doesn't matter */
4356 , targets);
4357 add_or_destroy_edge (&s, ne);
4361 goto dontexpand;
4363 /* between the time these edges are inserted and the
4364 * time they are processed, new expansion boxes (which
4365 * conflict with these edges) may be added to the graph!
4366 * w.o vias this isn't a problem because the broken box
4367 * is not homeless. */
4369 if (1)
4371 routebox_t *nrb;
4372 struct E_result *ans;
4373 BoxType b;
4374 vector_t *broken;
4375 if (e->flags.is_interior)
4377 assert (AutoRouteParameters.with_conflicts); /* no interior edges unless
4378 routing with conflicts! */
4379 assert (e->rb->conflicts_with);
4380 b = e->rb->sbox;
4381 switch (e->rb->came_from)
4383 case NORTH:
4384 b.Y2 = b.Y1 + 1;
4385 b.X1 = CENTER_X (b);
4386 b.X2 = b.X1 + 1;
4387 break;
4388 case EAST:
4389 b.X1 = b.X2 - 1;
4390 b.Y1 = CENTER_Y (b);
4391 b.Y2 = b.Y1 + 1;
4392 break;
4393 case SOUTH:
4394 b.Y1 = b.Y2 - 1;
4395 b.X1 = CENTER_X (b);
4396 b.X2 = b.X1 + 1;
4397 break;
4398 case WEST:
4399 b.X2 = b.X1 + 1;
4400 b.Y1 = CENTER_Y (b);
4401 b.Y2 = b.Y1 + 1;
4402 break;
4403 default:
4404 assert (0);
4407 /* sources may not expand to their own edges because of
4408 * adjacent blockers.
4410 else if (e->rb->flags.source)
4411 b = box_center (&e->rb->sbox);
4412 else
4413 b = e->rb->sbox;
4414 ans = Expand (rd->layergrouptree[e->rb->group], e, &b);
4415 if (!box_intersect (&ans->inflated, &ans->orig))
4416 goto dontexpand;
4417 #if 0
4418 /* skip if it didn't actually expand */
4419 if (ans->inflated.X1 >= e->rb->sbox.X1 &&
4420 ans->inflated.X2 <= e->rb->sbox.X2 &&
4421 ans->inflated.Y1 >= e->rb->sbox.Y1 &&
4422 ans->inflated.Y2 <= e->rb->sbox.Y2)
4423 goto dontexpand;
4424 #endif
4426 if (!box_is_good (&ans->inflated))
4427 goto dontexpand;
4428 nrb = CreateExpansionArea (&ans->inflated, e->rb->group, e->rb,
4429 true, e);
4430 r_insert_entry (rd->layergrouptree[nrb->group], &nrb->box, 1);
4431 vector_append (area_vec, nrb);
4432 nrb->flags.homeless = 0; /* not homeless any more */
4433 broken =
4434 BreakManyEdges (&s, targets, rd->layergrouptree[nrb->group],
4435 area_vec, ans, nrb, e);
4436 while (!vector_is_empty (broken))
4438 edge_t *ne = (edge_t *)vector_remove_last (broken);
4439 add_or_destroy_edge (&s, ne);
4441 vector_destroy (&broken);
4443 /* add in possible via sites in nrb */
4444 if (AutoRouteParameters.use_vias && !e->rb->flags.is_via &&
4445 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
4446 add_via_sites (&s, &vss,
4447 rd->mtspace, nrb, NO_CONFLICT, e, targets, 0,
4448 false);
4449 goto dontexpand;
4451 dontexpand:
4452 DestroyEdge (&e);
4454 touch_conflicts (NULL, 1);
4455 heap_destroy (&s.workheap);
4456 r_destroy_tree (&targets);
4457 assert (vector_is_empty (edge_vec));
4458 vector_destroy (&edge_vec);
4460 /* we should have a path in best_path now */
4461 if (s.best_path)
4463 routebox_t *rb;
4464 #ifdef ROUTE_VERBOSE
4465 printf ("%d:%d RC %.0f", ro++, seen, s.best_cost);
4466 #endif
4467 result.found_route = true;
4468 result.best_route_cost = s.best_cost;
4469 /* determine if the best path had conflicts */
4470 result.route_had_conflicts = 0;
4471 if (AutoRouteParameters.with_conflicts && s.best_path->conflicts_with)
4473 while (!vector_is_empty (s.best_path->conflicts_with))
4475 rb = (routebox_t *)vector_remove_last (s.best_path->conflicts_with);
4476 rb->flags.is_bad = 1;
4477 result.route_had_conflicts++;
4480 #ifdef ROUTE_VERBOSE
4481 if (result.route_had_conflicts)
4482 printf (" (%d conflicts)", result.route_had_conflicts);
4483 #endif
4484 if (result.route_had_conflicts < AutoRouteParameters.hi_conflict)
4486 /* back-trace the path and add lines/vias to r-tree */
4487 TracePath (rd, s.best_path, s.best_target, from,
4488 result.route_had_conflicts);
4489 MergeNets (from, s.best_target, SUBNET);
4491 else
4493 #ifdef ROUTE_VERBOSE
4494 printf (" (too many in fact)");
4495 #endif
4496 result.found_route = false;
4498 #ifdef ROUTE_VERBOSE
4499 printf ("\n");
4500 #endif
4502 else
4504 #ifdef ROUTE_VERBOSE
4505 printf ("%d:%d NO PATH FOUND.\n", ro++, seen);
4506 #endif
4507 result.best_route_cost = s.best_cost;
4508 result.found_route = false;
4510 /* now remove all expansion areas from the r-tree. */
4511 while (!vector_is_empty (area_vec))
4513 routebox_t *rb = (routebox_t *)vector_remove_last (area_vec);
4514 assert (!rb->flags.homeless);
4515 if (rb->conflicts_with
4516 && rb->parent.expansion_area->conflicts_with != rb->conflicts_with)
4517 vector_destroy (&rb->conflicts_with);
4518 r_delete_entry (rd->layergrouptree[rb->group], &rb->box);
4520 vector_destroy (&area_vec);
4521 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
4522 LIST_LOOP (from, same_net, p);
4523 if (p->flags.source && p->conflicts_with)
4524 vector_destroy (&p->conflicts_with);
4525 p->flags.touched = p->flags.source = p->flags.target = p->flags.nobloat = 0;
4526 END_LOOP;
4528 vector_destroy (&vss.free_space_vec);
4529 vector_destroy (&vss.lo_conflict_space_vec);
4530 vector_destroy (&vss.hi_conflict_space_vec);
4532 return result;
4535 static void
4536 InitAutoRouteParameters (int pass,
4537 RouteStyleType * style,
4538 bool with_conflicts, bool is_smoothing,
4539 bool lastpass)
4541 int i;
4542 /* routing style */
4543 AutoRouteParameters.style = style;
4544 AutoRouteParameters.bloat = style->Keepaway + HALF_THICK (style->Thick);
4545 /* costs */
4546 AutoRouteParameters.ViaCost =
4547 INCH_TO_COORD (3.5) + style->Diameter * (is_smoothing ? 80 : 30);
4548 AutoRouteParameters.LastConflictPenalty =
4549 (400 * pass / passes + 2) / (pass + 1);
4550 AutoRouteParameters.ConflictPenalty =
4551 4 * AutoRouteParameters.LastConflictPenalty;
4552 AutoRouteParameters.JogPenalty = 1000 * (is_smoothing ? 20 : 4);
4553 AutoRouteParameters.CongestionPenalty = 1e6;
4554 AutoRouteParameters.MinPenalty = EXPENSIVE;
4555 for (i = 0; i < max_group; i++)
4557 if (is_layer_group_active[i])
4559 AutoRouteParameters.MinPenalty = MIN (x_cost[i],
4560 AutoRouteParameters.
4561 MinPenalty);
4562 AutoRouteParameters.MinPenalty =
4563 MIN (y_cost[i], AutoRouteParameters.MinPenalty);
4566 AutoRouteParameters.NewLayerPenalty = is_smoothing ?
4567 0.5 * EXPENSIVE : 10 * AutoRouteParameters.ViaCost;
4568 /* other */
4569 AutoRouteParameters.hi_conflict = MAX (8 * (passes - pass + 1), 6);
4570 AutoRouteParameters.is_odd = (pass & 1);
4571 AutoRouteParameters.with_conflicts = with_conflicts;
4572 AutoRouteParameters.is_smoothing = is_smoothing;
4573 AutoRouteParameters.rip_always = is_smoothing;
4574 AutoRouteParameters.last_smooth = 0; //lastpass;
4575 AutoRouteParameters.pass = pass + 1;
4578 #ifndef NDEBUG
4580 bad_boy (const BoxType * b, void *cl)
4582 routebox_t *box = (routebox_t *) b;
4583 if (box->type == EXPANSION_AREA)
4584 return 1;
4585 return 0;
4588 bool
4589 no_expansion_boxes (routedata_t * rd)
4591 int i;
4592 BoxType big;
4593 big.X1 = 0;
4594 big.X2 = MAX_COORD;
4595 big.Y1 = 0;
4596 big.Y2 = MAX_COORD;
4597 for (i = 0; i < max_group; i++)
4599 if (r_search (rd->layergrouptree[i], &big, NULL, bad_boy, NULL))
4600 return false;
4602 return true;
4604 #endif
4606 static void
4607 ripout_livedraw_obj (routebox_t *rb)
4609 if (rb->type == LINE && rb->livedraw_obj.line)
4611 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
4612 EraseLine (rb->livedraw_obj.line);
4613 DestroyObject (PCB->Data, LINE_TYPE, layer, rb->livedraw_obj.line, NULL);
4614 rb->livedraw_obj.line = NULL;
4616 if (rb->type == VIA && rb->livedraw_obj.via)
4618 EraseVia (rb->livedraw_obj.via);
4619 DestroyObject (PCB->Data, VIA_TYPE, rb->livedraw_obj.via, NULL, NULL);
4620 rb->livedraw_obj.via = NULL;
4624 static int
4625 ripout_livedraw_obj_cb (const BoxType * b, void *cl)
4627 routebox_t *box = (routebox_t *) b;
4628 ripout_livedraw_obj (box);
4629 return 0;
4632 struct routeall_status
4634 /* --- for completion rate statistics ---- */
4635 int total_subnets;
4636 /* total subnets routed without conflicts */
4637 int routed_subnets;
4638 /* total subnets routed with conflicts */
4639 int conflict_subnets;
4640 /* net failted entirely */
4641 int failed;
4642 /* net was ripped */
4643 int ripped;
4644 int total_nets_routed;
4647 static double
4648 calculate_progress (double this_heap_item, double this_heap_size,
4649 struct routeall_status *ras)
4651 double total_passes = passes + smoothes + 1; /* + 1 is the refinement pass */
4652 double this_pass = AutoRouteParameters.pass - 1; /* Number passes from zero */
4653 double heap_fraction = (double)(ras->routed_subnets + ras->conflict_subnets + ras->failed) /
4654 (double)ras->total_subnets;
4655 double pass_fraction = (this_heap_item + heap_fraction ) / this_heap_size;
4656 double process_fraction = (this_pass + pass_fraction) / total_passes;
4658 return process_fraction;
4661 struct routeall_status
4662 RouteAll (routedata_t * rd)
4664 struct routeall_status ras;
4665 struct routeone_status ros;
4666 bool rip;
4667 int request_cancel;
4668 #ifdef NET_HEAP
4669 heap_t *net_heap;
4670 #endif
4671 heap_t *this_pass, *next_pass, *tmp;
4672 routebox_t *net, *p, *pp;
4673 cost_t total_net_cost, last_cost = 0, this_cost = 0;
4674 int i;
4675 int this_heap_size;
4676 int this_heap_item;
4678 /* initialize heap for first pass;
4679 * do smallest area first; that makes
4680 * the subsequent costs more representative */
4681 this_pass = heap_create ();
4682 next_pass = heap_create ();
4683 #ifdef NET_HEAP
4684 net_heap = heap_create ();
4685 #endif
4686 LIST_LOOP (rd->first_net, different_net, net);
4688 double area;
4689 BoxType bb = shrink_routebox (net);
4690 LIST_LOOP (net, same_net, p);
4692 MAKEMIN (bb.X1, p->sbox.X1);
4693 MAKEMIN (bb.Y1, p->sbox.Y1);
4694 MAKEMAX (bb.X2, p->sbox.X2);
4695 MAKEMAX (bb.Y2, p->sbox.Y2);
4697 END_LOOP;
4698 area = (double) (bb.X2 - bb.X1) * (bb.Y2 - bb.Y1);
4699 heap_insert (this_pass, area, net);
4701 END_LOOP;
4703 ras.total_nets_routed = 0;
4704 /* refinement/finishing passes */
4705 for (i = 0; i <= passes + smoothes; i++)
4707 #ifdef ROUTE_VERBOSE
4708 if (i > 0 && i <= passes)
4709 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i);
4710 else if (i > passes)
4711 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
4712 i - passes);
4713 #endif
4714 ras.total_subnets = ras.routed_subnets = ras.conflict_subnets =
4715 ras.failed = ras.ripped = 0;
4716 assert (heap_is_empty (next_pass));
4718 this_heap_size = heap_size (this_pass);
4719 for (this_heap_item = 0; !heap_is_empty (this_pass); this_heap_item++)
4721 #ifdef ROUTE_DEBUG
4722 if (aabort)
4723 break;
4724 #endif
4725 net = (routebox_t *) heap_remove_smallest (this_pass);
4726 InitAutoRouteParameters (i, net->style, i < passes, i > passes,
4727 i == passes + smoothes);
4728 if (i > 0)
4730 /* rip up all unfixed traces in this net ? */
4731 if (AutoRouteParameters.rip_always)
4732 rip = true;
4733 else
4735 rip = false;
4736 LIST_LOOP (net, same_net, p);
4737 if (p->flags.is_bad)
4739 rip = true;
4740 break;
4742 END_LOOP;
4745 LIST_LOOP (net, same_net, p);
4746 p->flags.is_bad = 0;
4747 if (!p->flags.fixed)
4749 #ifndef NDEBUG
4750 bool del;
4751 #endif
4752 assert (!p->flags.homeless);
4753 if (rip)
4755 RemoveFromNet (p, NET);
4756 RemoveFromNet (p, SUBNET);
4758 if (AutoRouteParameters.use_vias && p->type != VIA_SHADOW
4759 && p->type != PLANE)
4761 mtspace_remove (rd->mtspace, &p->box,
4762 p->flags.is_odd ? ODD : EVEN,
4763 p->style->Keepaway);
4764 if (!rip)
4765 mtspace_add (rd->mtspace, &p->box,
4766 p->flags.is_odd ? EVEN : ODD,
4767 p->style->Keepaway);
4769 if (rip)
4771 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
4772 ripout_livedraw_obj (p);
4773 #ifndef NDEBUG
4774 del =
4775 #endif
4776 r_delete_entry (rd->layergrouptree[p->group],
4777 &p->box);
4778 #ifndef NDEBUG
4779 assert (del);
4780 #endif
4782 else
4784 p->flags.is_odd = AutoRouteParameters.is_odd;
4787 END_LOOP;
4788 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
4789 Draw ();
4790 /* reset to original connectivity */
4791 if (rip)
4793 ras.ripped++;
4794 ResetSubnet (net);
4796 else
4798 heap_insert (next_pass, 0, net);
4799 continue;
4802 /* count number of subnets */
4803 FOREACH_SUBNET (net, p);
4804 ras.total_subnets++;
4805 END_FOREACH (net, p);
4806 /* the first subnet doesn't require routing. */
4807 ras.total_subnets--;
4808 /* and re-route! */
4809 total_net_cost = 0;
4810 /* only route that which isn't fully routed */
4811 #ifdef ROUTE_DEBUG
4812 if (ras.total_subnets == 0 || aabort)
4813 #else
4814 if (ras.total_subnets == 0)
4815 #endif
4817 heap_insert (next_pass, 0, net);
4818 continue;
4821 /* the loop here ensures that we get to all subnets even if
4822 * some of them are unreachable from the first subnet. */
4823 LIST_LOOP (net, same_net, p);
4825 #ifdef NET_HEAP
4826 BoxType b = shrink_routebox (p);
4827 /* using a heap allows us to start from smaller objects and
4828 * end at bigger ones. also prefer to start at planes, then pads */
4829 heap_insert (net_heap, (float) (b.X2 - b.X1) *
4830 #if defined(ROUTE_RANDOMIZED)
4831 (0.3 + rand () / (RAND_MAX + 1.0)) *
4832 #endif
4833 (b.Y2 - b.Y1) * (p->type == PLANE ?
4834 -1 : (p->type ==
4835 PAD ? 1 : 10)), p);
4837 END_LOOP;
4838 ros.net_completely_routed = 0;
4839 while (!heap_is_empty (net_heap))
4841 p = (routebox_t *) heap_remove_smallest (net_heap);
4842 #endif
4843 if (!p->flags.fixed || p->flags.subnet_processed ||
4844 p->type == OTHER)
4845 continue;
4847 while (!ros.net_completely_routed)
4849 double percent;
4851 assert (no_expansion_boxes (rd));
4852 /* FIX ME: the number of edges to examine should be in autoroute parameters
4853 * i.e. the 2000 and 800 hard-coded below should be controllable by the user
4855 ros =
4856 RouteOne (rd, p, NULL,
4857 ((AutoRouteParameters.
4858 is_smoothing ? 2000 : 800) * (i +
4859 1)) *
4860 routing_layers);
4861 total_net_cost += ros.best_route_cost;
4862 if (ros.found_route)
4864 if (ros.route_had_conflicts)
4865 ras.conflict_subnets++;
4866 else
4868 ras.routed_subnets++;
4869 ras.total_nets_routed++;
4872 else
4874 if (!ros.net_completely_routed)
4875 ras.failed++;
4876 /* don't bother trying any other source in this subnet */
4877 LIST_LOOP (p, same_subnet, pp);
4878 pp->flags.subnet_processed = 1;
4879 END_LOOP;
4880 break;
4882 /* note that we can infer nothing about ras.total_subnets based
4883 * on the number of calls to RouteOne, because we may be unable
4884 * to route a net from a particular starting point, but perfectly
4885 * able to route it from some other. */
4886 percent = calculate_progress (this_heap_item, this_heap_size, &ras);
4887 request_cancel = gui->progress (percent * 100., 100,
4888 _("Autorouting tracks"));
4889 if (request_cancel)
4891 ras.total_nets_routed = 0;
4892 ras.conflict_subnets = 0;
4893 Message ("Autorouting cancelled\n");
4894 goto out;
4898 #ifndef NET_HEAP
4899 END_LOOP;
4900 #endif
4901 if (!ros.net_completely_routed)
4902 net->flags.is_bad = 1; /* don't skip this the next round */
4904 /* Route easiest nets from this pass first on next pass.
4905 * This works best because it's likely that the hardest
4906 * is the last one routed (since it has the most obstacles)
4907 * but it will do no good to rip it up and try it again
4908 * without first changing any of the other routes
4910 heap_insert (next_pass, total_net_cost, net);
4911 if (total_net_cost < EXPENSIVE)
4912 this_cost += total_net_cost;
4913 /* reset subnet_processed flags */
4914 LIST_LOOP (net, same_net, p);
4916 p->flags.subnet_processed = 0;
4918 END_LOOP;
4920 /* swap this_pass and next_pass and do it all over again! */
4921 ro = 0;
4922 assert (heap_is_empty (this_pass));
4923 tmp = this_pass;
4924 this_pass = next_pass;
4925 next_pass = tmp;
4926 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE)
4927 printf
4928 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n",
4929 i, ras.routed_subnets, ras.total_subnets, this_cost,
4930 ras.conflict_subnets, ras.failed, ras.ripped);
4931 #endif
4932 #ifdef ROUTE_DEBUG
4933 if (aabort)
4934 break;
4935 #endif
4936 /* if no conflicts found, skip directly to smoothing pass! */
4937 if (ras.conflict_subnets == 0 && ras.routed_subnets == ras.total_subnets
4938 && i <= passes)
4939 i = passes - (smoothes ? 0 : 1);
4940 /* if no changes in a smoothing round, then we're done */
4941 if (this_cost == last_cost && i > passes && i < passes + smoothes)
4942 i = passes + smoothes - 1;
4943 last_cost = this_cost;
4944 this_cost = 0;
4947 Message ("%d of %d nets successfully routed.\n",
4948 ras.routed_subnets, ras.total_subnets);
4950 out:
4951 heap_destroy (&this_pass);
4952 heap_destroy (&next_pass);
4953 #ifdef NET_HEAP
4954 heap_destroy (&net_heap);
4955 #endif
4957 /* no conflicts should be left at the end of the process. */
4958 assert (ras.conflict_subnets == 0);
4960 return ras;
4963 struct fpin_info
4965 PinType *pin;
4966 Coord X, Y;
4967 jmp_buf env;
4970 static int
4971 fpin_rect (const BoxType * b, void *cl)
4973 PinType *pin = (PinType *) b;
4974 struct fpin_info *info = (struct fpin_info *) cl;
4975 if (pin->X == info->X && pin->Y == info->Y)
4977 info->pin = (PinType *) b;
4978 longjmp (info->env, 1);
4980 return 0;
4983 static int
4984 FindPin (const BoxType * box, PinType ** pin)
4986 struct fpin_info info;
4988 info.pin = NULL;
4989 info.X = box->X1;
4990 info.Y = box->Y1;
4991 if (setjmp (info.env) == 0)
4992 r_search (PCB->Data->pin_tree, box, NULL, fpin_rect, &info);
4993 else
4995 *pin = info.pin;
4996 return PIN_TYPE;
4998 if (setjmp (info.env) == 0)
4999 r_search (PCB->Data->via_tree, box, NULL, fpin_rect, &info);
5000 else
5002 *pin = info.pin;
5003 return VIA_TYPE;
5005 *pin = NULL;
5006 return NO_TYPE;
5010 /* paths go on first 'on' layer in group */
5011 /* returns 'true' if any paths were added. */
5012 bool
5013 IronDownAllUnfixedPaths (routedata_t * rd)
5015 bool changed = false;
5016 LayerType *layer;
5017 routebox_t *net, *p;
5018 int i;
5019 LIST_LOOP (rd->first_net, different_net, net);
5021 LIST_LOOP (net, same_net, p);
5023 if (!p->flags.fixed)
5025 /* find first on layer in this group */
5026 assert (PCB->LayerGroups.Number[p->group] > 0);
5027 assert (is_layer_group_active[p->group]);
5028 for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group];
5029 i++)
5031 layer = LAYER_PTR (PCB->LayerGroups.Entries[p->group][i]);
5032 if (layer->On)
5033 break;
5035 assert (layer && layer->On); /*at least one layer must be on in this group! */
5036 assert (p->type != EXPANSION_AREA);
5037 if (p->type == LINE)
5039 Coord halfwidth = HALF_THICK (p->style->Thick);
5040 double th = halfwidth * 2 + 1;
5041 BoxType b;
5042 assert (p->parent.line == NULL);
5043 /* orthogonal; thickness is 2*halfwidth */
5044 /* flip coordinates, if bl_to_ur */
5045 b = p->sbox;
5046 total_wire_length +=
5047 sqrt ((b.X2 - b.X1 - th) * (b.X2 - b.X1 - th) +
5048 (b.Y2 - b.Y1 - th) * (b.Y2 - b.Y1 - th));
5049 b = shrink_box (&b, halfwidth);
5050 if (b.X2 == b.X1 + 1)
5051 b.X2 = b.X1;
5052 if (b.Y2 == b.Y1 + 1)
5053 b.Y2 = b.Y1;
5054 if (p->flags.bl_to_ur)
5056 Coord t;
5057 t = b.X1;
5058 b.X1 = b.X2;
5059 b.X2 = t;
5061 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
5062 p->parent.line = CreateDrawnLineOnLayer
5063 (layer, b.X1, b.Y1, b.X2, b.Y2,
5064 p->style->Thick,
5065 p->style->Keepaway * 2,
5066 MakeFlags (AUTOFLAG |
5067 (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG :
5068 0)));
5070 if (p->parent.line)
5072 AddObjectToCreateUndoList (LINE_TYPE, layer,
5073 p->parent.line, p->parent.line);
5074 changed = true;
5077 else if (p->type == VIA || p->type == VIA_SHADOW)
5079 routebox_t *pp =
5080 (p->type == VIA_SHADOW) ? p->parent.via_shadow : p;
5081 Coord radius = HALF_THICK (pp->style->Diameter);
5082 BoxType b = shrink_routebox (p);
5083 total_via_count++;
5084 assert (pp->type == VIA);
5085 if (pp->parent.via == NULL)
5087 assert (b.X1 + radius == b.X2 - radius);
5088 assert (b.Y1 + radius == b.Y2 - radius);
5089 pp->parent.via =
5090 CreateNewVia (PCB->Data, b.X1 + radius,
5091 b.Y1 + radius,
5092 pp->style->Diameter,
5093 2 * pp->style->Keepaway,
5094 0, pp->style->Hole, NULL,
5095 MakeFlags (AUTOFLAG));
5096 assert (pp->parent.via);
5097 if (pp->parent.via)
5099 AddObjectToCreateUndoList (VIA_TYPE,
5100 pp->parent.via,
5101 pp->parent.via,
5102 pp->parent.via);
5103 changed = true;
5106 assert (pp->parent.via);
5107 if (p->type == VIA_SHADOW)
5109 p->type = VIA;
5110 p->parent.via = pp->parent.via;
5113 else if (p->type == THERMAL)
5114 /* nothing to do because, the via might not be there yet */ ;
5115 else
5116 assert (0);
5119 END_LOOP;
5120 /* loop again to place all the thermals now that the vias are down */
5121 LIST_LOOP (net, same_net, p);
5123 if (p->type == THERMAL)
5125 PinType *pin = NULL;
5126 /* thermals are alread a single point search, no need to shrink */
5127 int type = FindPin (&p->box, &pin);
5128 if (pin)
5130 AddObjectToClearPolyUndoList (type,
5131 pin->Element ? pin->Element : pin,
5132 pin, pin, false);
5133 RestoreToPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
5134 pin);
5135 AddObjectToFlagUndoList (type,
5136 pin->Element ? pin->Element : pin, pin,
5137 pin);
5138 ASSIGN_THERM (p->layer, PCB->ThermStyle, pin);
5139 AddObjectToClearPolyUndoList (type,
5140 pin->Element ? pin->Element : pin,
5141 pin, pin, true);
5142 ClearFromPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
5143 pin);
5144 changed = true;
5148 END_LOOP;
5150 END_LOOP;
5151 return changed;
5154 bool
5155 AutoRoute (bool selected)
5157 bool changed = false;
5158 routedata_t *rd;
5159 int i;
5161 total_wire_length = 0;
5162 total_via_count = 0;
5164 #ifdef ROUTE_DEBUG
5165 ddraw = gui->request_debug_draw ();
5166 if (ddraw != NULL)
5168 ar_gc = ddraw->graphics->make_gc ();
5169 ddraw->graphics->set_line_cap (ar_gc, Round_Cap);
5171 #endif
5173 for (i = 0; i < NUM_STYLES; i++)
5175 if (PCB->RouteStyle[i].Thick == 0 ||
5176 PCB->RouteStyle[1].Diameter == 0 ||
5177 PCB->RouteStyle[1].Hole == 0 || PCB->RouteStyle[i].Keepaway == 0)
5179 Message ("You must define proper routing styles\n"
5180 "before auto-routing.\n");
5181 return (false);
5184 if (PCB->Data->RatN == 0)
5185 return (false);
5186 rd = CreateRouteData ();
5188 if (1)
5190 routebox_t *net, *rb, *last;
5191 int i = 0;
5192 /* count number of rats selected */
5193 RAT_LOOP (PCB->Data);
5195 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5196 i++;
5198 END_LOOP;
5199 #ifdef ROUTE_VERBOSE
5200 printf ("%d nets!\n", i);
5201 #endif
5202 if (i == 0)
5203 goto donerouting; /* nothing to do here */
5204 /* if only one rat selected, do things the quick way. =) */
5205 if (i == 1)
5207 RAT_LOOP (PCB->Data);
5208 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5210 /* look up the end points of this rat line */
5211 routebox_t *a =
5212 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
5213 line->Point1.Y, line->group1);
5214 routebox_t *b =
5215 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
5216 line->Point2.Y, line->group2);
5218 /* If the rat starts or ends at a non-straight pad (i.e., at a
5219 * rotated SMD), a or b will be NULL since the autorouter can't
5220 * handle these.
5222 if (a != NULL && b != NULL)
5224 assert (a->style == b->style);
5225 /* route exactly one net, without allowing conflicts */
5226 InitAutoRouteParameters (0, a->style, false, true, true);
5227 /* hace planes work better as sources than targets */
5228 changed = RouteOne (rd, a, b, 150000).found_route || changed;
5229 goto donerouting;
5232 END_LOOP;
5234 /* otherwise, munge the netlists so that only the selected rats
5235 * get connected. */
5236 /* first, separate all sub nets into separate nets */
5237 /* note that this code works because LIST_LOOP is clever enough not to
5238 * be fooled when the list is changing out from under it. */
5239 last = NULL;
5240 LIST_LOOP (rd->first_net, different_net, net);
5242 FOREACH_SUBNET (net, rb);
5244 if (last)
5246 last->different_net.next = rb;
5247 rb->different_net.prev = last;
5249 last = rb;
5251 END_FOREACH (net, rb);
5252 LIST_LOOP (net, same_net, rb);
5254 rb->same_net = rb->same_subnet;
5256 END_LOOP;
5257 /* at this point all nets are equal to their subnets */
5259 END_LOOP;
5260 if (last)
5262 last->different_net.next = rd->first_net;
5263 rd->first_net->different_net.prev = last;
5266 /* now merge only those subnets connected by a rat line */
5267 RAT_LOOP (PCB->Data);
5268 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
5270 /* look up the end points of this rat line */
5271 routebox_t *a;
5272 routebox_t *b;
5274 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
5275 line->Point1.Y, line->group1);
5277 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
5278 line->Point2.Y, line->group2);
5279 if (!a || !b)
5281 #ifdef DEBUG_STALE_RATS
5282 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
5283 ASSIGN_FLAG (SELECTEDFLAG, true, line);
5284 DrawRat (line, 0);
5285 #endif /* DEBUG_STALE_RATS */
5286 Message ("The rats nest is stale! Aborting autoroute...\n");
5287 goto donerouting;
5289 /* merge subnets into a net! */
5290 MergeNets (a, b, NET);
5292 END_LOOP;
5293 /* now 'different_net' may point to too many different nets. Reset. */
5294 LIST_LOOP (rd->first_net, different_net, net);
5296 if (!net->flags.touched)
5298 LIST_LOOP (net, same_net, rb);
5299 rb->flags.touched = 1;
5300 END_LOOP;
5302 else /* this is not a "different net"! */
5303 RemoveFromNet (net, DIFFERENT_NET);
5305 END_LOOP;
5306 /* reset "touched" flag */
5307 LIST_LOOP (rd->first_net, different_net, net);
5309 LIST_LOOP (net, same_net, rb);
5311 assert (rb->flags.touched);
5312 rb->flags.touched = 0;
5314 END_LOOP;
5316 END_LOOP;
5318 /* okay, rd's idea of netlist now corresponds to what we want routed */
5319 /* auto-route all nets */
5320 changed = (RouteAll (rd).total_nets_routed > 0) || changed;
5321 donerouting:
5322 gui->progress (0, 0, NULL);
5323 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
5325 int i;
5326 BoxType big = {0, 0, MAX_COORD, MAX_COORD};
5327 for (i = 0; i < max_group; i++)
5329 r_search (rd->layergrouptree[i], &big, NULL, ripout_livedraw_obj_cb, NULL);
5332 #ifdef ROUTE_DEBUG
5333 if (ddraw != NULL)
5335 ddraw->graphics->destroy_gc (ar_gc);
5336 ddraw->finish_debug_draw ();
5338 #endif
5340 if (changed)
5341 changed = IronDownAllUnfixedPaths (rd);
5342 Message ("Total added wire length = %$mS, %d vias added\n",
5343 (Coord) total_wire_length, total_via_count);
5344 DestroyRouteData (&rd);
5345 if (changed)
5347 SaveUndoSerialNumber ();
5349 /* optimize rats, we've changed connectivity a lot. */
5350 DeleteRats (false /*all rats */ );
5351 RestoreUndoSerialNumber ();
5352 AddAllRats (false /*all rats */ , NULL);
5353 RestoreUndoSerialNumber ();
5355 IncrementUndoSerialNumber ();
5357 Redraw ();
5359 #if defined (ROUTE_DEBUG)
5360 aabort = 0;
5361 #endif
5362 return (changed);