Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / autoroute.c
blob5c689e4d8e82f983f9b7a41d7662158a94d1a739
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 * Copyright (C) 1998,1999,2000,2001 harry eaton
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Contact addresses for paper mail and Email:
25 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
26 * haceaton@aplcomm.jhuapl.edu
29 /* this file, autoroute.c, was written and is
30 * Copyright (c) 2001 C. Scott Ananian
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.
44 *--------------------------------------------------------------------
46 #define NET_HEAP 1
47 #undef BREAK_ALL
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
52 #include "global.h"
54 #include <assert.h>
55 #include <setjmp.h>
57 #include "data.h"
58 #include "macro.h"
59 #include "autoroute.h"
60 #include "box.h"
61 /*#include "clip.h"*/
62 #include "create.h"
63 #include "draw.h"
64 #include "error.h"
65 #include "find.h"
66 #include "heap.h"
67 #include "rtree.h"
68 #include "misc.h"
69 #include "mtspace.h"
70 #include "mymem.h"
71 #include "polygon.h"
72 #include "rats.h"
73 #include "remove.h"
74 #include "thermal.h"
75 #include "undo.h"
76 #include "vector.h"
78 #ifdef HAVE_LIBDMALLOC
79 #include <dmalloc.h>
80 #endif
82 RCSID ("$Id$");
84 /* #defines to enable some debugging output */
86 #define ROUTE_VERBOSE
91 #define ROUTE_DEBUG
92 #define DEBUG_SHOW_ROUTE_BOXES
93 #define DEBUG_SHOW_EXPANSION_BOXES
94 #define DEBUG_SHOW_VIA_BOXES
95 #define DEBUG_SHOW_TARGETS
96 #define DEBUG_SHOW_ZIGZAG
99 static hidGC ar_gc = 0;
101 #define EXPENSIVE 3e28
102 /* round up "half" thicknesses */
103 #define HALF_THICK(x) (((x)+1)/2)
104 /* a styles maximum bloat is its keepaway plus the larger of its via radius
105 * or line half-thickness. */
106 #define BLOAT(style)\
107 ((style)->Keepaway + HALF_THICK((style)->Thick))
108 /* conflict penalty is less for traces laid down during previous pass than
109 * it is for traces already laid down in this pass. */
110 #define CONFLICT_LEVEL(rb)\
111 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
112 HI_CONFLICT : LO_CONFLICT )
113 #define CONFLICT_PENALTY(rb)\
114 (CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
115 AutoRouteParameters.ConflictPenalty : \
116 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
117 AutoRouteParameters.LastConflictPenalty : 1)
119 #if !defined(ABS)
120 #define ABS(x) (((x)<0)?-(x):(x))
121 #endif
123 #define LIST_LOOP(init, which, x) do {\
124 routebox_t *__next_one__ = (init);\
125 x = NULL;\
126 if (!__next_one__)\
127 assert(__next_one__);\
128 else\
129 while (!x || __next_one__ != (init)) {\
130 x = __next_one__;\
131 /* save next one first in case the command modifies or frees it */\
132 __next_one__ = x->which.next
133 #define FOREACH_SUBNET(net, p) do {\
134 routebox_t *_pp_;\
135 /* fail-fast: check subnet_processed flags */\
136 LIST_LOOP(net, same_net, p); \
137 assert(!p->flags.subnet_processed);\
138 END_LOOP;\
139 /* iterate through *distinct* subnets */\
140 LIST_LOOP(net, same_net, p); \
141 if (!p->flags.subnet_processed) {\
142 LIST_LOOP(p, same_subnet, _pp_);\
143 _pp_->flags.subnet_processed=1;\
144 END_LOOP
145 #define END_FOREACH(net, p) \
146 }; \
147 END_LOOP;\
148 /* reset subnet_processed flags */\
149 LIST_LOOP(net, same_net, p); \
150 p->flags.subnet_processed=0;\
151 END_LOOP;\
152 } while (0)
153 /* notes:
154 * all rectangles are assumed to be closed on the top and left and
155 * open on the bottom and right. That is, they include their top-left
156 * corner but don't include their bottom-right corner.
158 * Obstacles, however, are thought of to be closed on all sides,
159 * and exclusion zone *open* on all sides. We will ignore the infinitesimal
160 * difference w.r.t. obstacles, but exclusion zones will be consistently
161 * bumped in one unit on the top and left in order to exclose the same
162 * integer coordinates as their open-rectangle equivalents.
164 * expansion regions are always half-closed. This means that when
165 * tracing paths, you must steer clear of the bottom and right edges.
167 /* ---------------------------------------------------------------------------
168 * some local types
170 /* augmented RouteStyleType */
171 typedef struct
173 /* a routing style */
174 const RouteStyleType *style;
175 /* flag indicating whether this augmented style is ever used.
176 * We only update mtspace if the style is used somewhere in the netlist */
177 Boolean Used;
179 AugmentedRouteStyleType;
181 /* enumerated type for conflict levels */
182 typedef enum
183 { NO_CONFLICT = 0, LO_CONFLICT = 1, HI_CONFLICT = 2 }
184 conflict_t;
186 typedef struct routebox
188 const BoxType box;
189 union
191 PadTypePtr pad;
192 PinTypePtr pin;
193 PinTypePtr via;
194 struct routebox *via_shadow; /* points to the via in r-tree which
195 * points to the PinType in the PCB. */
196 LineTypePtr line;
197 void *generic; /* 'other' is polygon, arc, text */
198 struct routebox *expansion_area; /* previous expansion area in search */
200 parent;
201 unsigned short group;
202 unsigned short layer;
203 enum
204 { PAD, PIN, VIA, VIA_SHADOW, LINE, OTHER, EXPANSION_AREA, PLANE }
205 type;
206 struct
208 unsigned nonstraight:1;
209 unsigned fixed:1;
210 /* for searches */
211 unsigned source:1;
212 unsigned target:1;
213 /* rects on same net as source and target don't need clearance areas */
214 unsigned nobloat:1;
215 /* mark circular pins, so that we be sure to connect them up properly */
216 unsigned circular:1;
217 /* we sometimes create routeboxen that don't actually belong to a
218 * r-tree yet -- make sure refcount of orphans is set properly */
219 unsigned orphan:1;
220 /* was this nonfixed obstacle generated on an odd or even pass? */
221 unsigned is_odd:1;
222 /* fixed route boxes that have already been "routed through" in this
223 * search have their "touched" flag set. */
224 unsigned touched:1;
225 /* this is a status bit for iterating through *different* subnets */
226 unsigned subnet_processed:1;
227 /* some expansion_areas represent via candidates */
228 unsigned is_via:1;
229 /* mark non-straight lines which go from bottom-left to upper-right,
230 * instead of from upper-left to bottom-right. */
231 unsigned bl_to_ur:1;
232 /* mark polygons which are "transparent" for via-placement; that is,
233 * vias through the polygon will automatically be given a keepaway
234 * and will not electrically connect to the polygon. */
235 unsigned clear_poly:1;
236 /* this marks "conflicting" routes that must be torn up to obtain
237 * a correct routing. This flag allows us to return a correct routing
238 * even if the user cancels auto-route after a non-final pass. */
239 unsigned is_bad:1;
240 /* for assertion that 'box' is never changed after creation */
241 unsigned inited:1;
243 flags;
244 /* indicate the direction an expansion box came from */
245 cost_t cost;
246 CheapPointType cost_point;
247 /* reference count for orphan routeboxes; free when refcount==0 */
248 int refcount;
249 /* when routing with conflicts, we keep a record of what we're
250 * conflicting *with*. */
251 struct routebox *underlying;
252 /* route style of the net associated with this routebox */
253 AugmentedRouteStyleType *augStyle;
254 /* circular lists with connectivity information. */
255 struct routebox_list
257 struct routebox *next, *prev;
259 same_net, same_subnet, original_subnet, different_net;
261 routebox_t;
263 typedef struct routedata
265 /* one rtree per layer *group */
266 rtree_t *layergrouptree[MAX_LAYER]; /* no silkscreen layers here =) */
267 /* root pointer into connectivity information */
268 routebox_t *first_net;
269 /* default routing style */
270 RouteStyleType defaultStyle;
271 /* augmented style structures */
272 AugmentedRouteStyleType augStyles[NUM_STYLES + 1];
273 /* what is the maximum bloat (keepaway+line half-width or
274 * keepaway+via_radius) for any style we've seen? */
275 BDimension max_bloat;
276 mtspace_t *mtspace;
278 routedata_t;
280 typedef struct edge_struct
282 routebox_t *rb; /* path expansion edges are real routeboxen. */
283 CheapPointType cost_point;
284 cost_t cost_to_point; /* from source */
285 cost_t cost; /* cached edge cost */
286 routebox_t *mincost_target; /* minimum cost from cost_point to any target */
287 vetting_t *work; /* for via search edges */
288 direction_t expand_dir; /* ignored if expand_all_sides is set */
289 struct
291 /* ignore expand_dir and expand all sides if this is set. */
292 /* used for vias and the initial source objects */
293 unsigned expand_all_sides:1; /* XXX: this is redundant with is_via? */
294 /* this indicates that this 'edge' is a via candidate. */
295 unsigned is_via:1;
296 /* record "conflict level" of via candidates, in case we need to split
297 * them later. */
298 conflict_t via_conflict_level:2;
299 /* when "routing with conflicts", sometimes edge is interior. */
300 unsigned is_interior:1;
301 /* this is a fake edge used to defer searching for via spaces */
302 unsigned via_search:1;
304 flags;
306 edge_t;
308 static struct
310 /* net style parameters */
311 AugmentedRouteStyleType *augStyle;
312 /* cost parameters */
313 cost_t ViaCost, /* additional "length" cost for using a via */
314 WrongWayPenalty, /* cost for expanding an edge away from the target */
315 SurfacePenalty, /* scale for congestion on SMD layers */
316 LastConflictPenalty, /* length mult. for routing over last pass' trace */
317 ConflictPenalty, /* length multiplier for routing over another trace */
318 JogPenalty, /* additional "length" cost for changing direction */
319 DirectionPenalty, /* (rational) length multiplier for routing in */
320 AwayPenalty, /* length multiplier for getting further from the target */
321 NewLayerPenalty, SearchPenalty, MinPenalty; /* smallest of Surface, Direction Penalty */
322 /* maximum conflict incidence before calling it "no path found" */
323 int hi_conflict;
324 /* are vias allowed? */
325 Boolean use_vias;
326 /* is this an odd or even pass? */
327 Boolean is_odd;
328 /* permit conflicts? */
329 Boolean with_conflicts;
330 /* is this a final "smoothing" pass? */
331 Boolean is_smoothing;
332 /* rip up nets regardless of conflicts? */
333 Boolean rip_always;
335 AutoRouteParameters;
338 /* ---------------------------------------------------------------------------
339 * some local prototypes
341 static routebox_t *CreateExpansionArea (const BoxType * area, Cardinal group,
342 routebox_t * parent,
343 Boolean relax_edge_requirements,
344 edge_t * edge);
346 static cost_t edge_cost (const edge_t * e, const cost_t too_big);
348 static BoxType edge_to_box (const BoxType * box, direction_t expand_dir);
350 static void ResetSubnet (routebox_t * net);
351 #ifdef ROUTE_DEBUG
352 static int showboxen = 0;
353 static void showroutebox (routebox_t * rb);
354 #endif
356 /* ---------------------------------------------------------------------------
357 * some local identifiers
359 /* group number of groups that hold surface mount pads */
360 static Cardinal front, back;
361 static Boolean bad_x[MAX_LAYER], bad_y[MAX_LAYER], usedGroup[MAX_LAYER];
362 static Boolean is_layer_group_active[MAX_LAYER];
363 static int ro = 0;
364 static int smoothes = 3;
365 static int passes = 9;
366 static int routing_layers = 0;
368 /* assertion helper for routeboxen */
369 #ifndef NDEBUG
370 static int
371 __routebox_is_good (routebox_t * rb)
373 assert (rb && (rb->group < max_layer) &&
374 (rb->box.X1 <= rb->box.X2) && (rb->box.Y1 <= rb->box.Y2) &&
375 (rb->flags.orphan ?
376 (rb->box.X1 != rb->box.X2) || (rb->box.Y1 != rb->box.Y2) :
377 (rb->box.X1 != rb->box.X2) && (rb->box.Y1 != rb->box.Y2)));
378 assert ((rb->flags.source ? rb->flags.nobloat : 1) &&
379 (rb->flags.target ? rb->flags.nobloat : 1) &&
380 (rb->flags.orphan ? !rb->flags.touched : rb->refcount == 0) &&
381 (rb->flags.touched ? rb->type != EXPANSION_AREA : 1));
382 assert ((rb->flags.is_odd ? (!rb->flags.fixed) &&
383 (rb->type == VIA || rb->type == VIA_SHADOW || rb->type == LINE
384 || rb->type == PLANE) : 1));
385 assert ((rb->flags.bl_to_ur ? rb->flags.nonstraight : 1) &&
386 (rb->flags.clear_poly ?
387 ((rb->type == OTHER || rb->type == PLANE) && rb->flags.fixed
388 && !rb->flags.orphan) : 1));
389 assert ((rb->underlying == NULL || !rb->underlying->flags.orphan)
390 && rb->flags.inited);
391 assert (rb->augStyle != NULL && rb->augStyle->style != NULL);
392 assert (rb->same_net.next && rb->same_net.prev &&
393 rb->same_subnet.next && rb->same_subnet.prev &&
394 rb->original_subnet.next && rb->original_subnet.prev &&
395 rb->different_net.next && rb->different_net.prev);
396 return 1;
398 static int
399 __edge_is_good (edge_t * e)
401 assert (e && e->rb && __routebox_is_good (e->rb));
402 assert ((e->rb->flags.orphan ? e->rb->refcount > 0 : 1));
403 assert ((0 <= e->expand_dir) && (e->expand_dir < 4)
404 && (e->flags.
405 is_interior ? (e->flags.expand_all_sides
406 && e->rb->underlying) : 1));
407 assert ((e->flags.is_via ? e->rb->flags.is_via : 1)
408 && (e->flags.via_conflict_level >= 0
409 && e->flags.via_conflict_level <= 2)
410 && (e->flags.via_conflict_level != 0 ? e->flags.is_via : 1));
411 assert ((e->cost_to_point >= 0) && e->cost >= 0);
412 return 1;
414 #endif /* !NDEBUG */
416 /*---------------------------------------------------------------------
417 * route utility functions.
420 enum boxlist
421 { NET, SUBNET, ORIGINAL, DIFFERENT_NET };
422 static struct routebox_list *
423 __select_list (routebox_t * r, enum boxlist which)
425 assert (r);
426 switch (which)
428 default:
429 assert (0);
430 case NET:
431 return &(r->same_net);
432 case SUBNET:
433 return &(r->same_subnet);
434 case ORIGINAL:
435 return &(r->original_subnet);
436 case DIFFERENT_NET:
437 return &(r->different_net);
440 static void
441 InitLists (routebox_t * r)
443 static enum boxlist all[] =
444 { NET, SUBNET, ORIGINAL, DIFFERENT_NET }
445 , *p;
446 for (p = all; p < all + (sizeof (all) / sizeof (*p)); p++)
448 struct routebox_list *rl = __select_list (r, *p);
449 rl->prev = rl->next = r;
453 static void
454 MergeNets (routebox_t * a, routebox_t * b, enum boxlist which)
456 struct routebox_list *al, *bl, *anl, *bnl;
457 routebox_t *an, *bn;
458 assert (a && b);
459 assert (a != b);
460 al = __select_list (a, which);
461 bl = __select_list (b, which);
462 assert (al && bl);
463 an = al->next;
464 bn = bl->next;
465 assert (an && bn);
466 anl = __select_list (an, which);
467 bnl = __select_list (bn, which);
468 assert (anl && bnl);
469 bl->next = an;
470 anl->prev = b;
471 al->next = bn;
472 bnl->prev = a;
475 static void
476 RemoveFromNet (routebox_t * a, enum boxlist which)
478 struct routebox_list *al, *anl, *apl;
479 routebox_t *an, *ap;
480 assert (a);
481 al = __select_list (a, which);
482 assert (al);
483 an = al->next;
484 ap = al->prev;
485 if (an == a || ap == a)
486 return; /* not on any list */
487 assert (an && ap);
488 anl = __select_list (an, which);
489 apl = __select_list (ap, which);
490 assert (anl && apl);
491 anl->prev = ap;
492 apl->next = an;
493 al->next = al->prev = a;
494 return;
497 static void
498 init_const_box (routebox_t * rb,
499 LocationType X1, LocationType Y1, LocationType X2,
500 LocationType Y2)
502 BoxType *bp = (BoxType *) & rb->box; /* note discarding const! */
503 assert (!rb->flags.inited);
504 assert (X1 <= X2 && Y1 <= Y2);
505 bp->X1 = X1;
506 bp->Y1 = Y1;
507 bp->X2 = X2;
508 bp->Y2 = Y2;
509 rb->flags.inited = 1;
512 /*---------------------------------------------------------------------
513 * routedata initialization functions.
516 static routebox_t *
517 AddPin (PointerListType layergroupboxes[], PinTypePtr pin, Boolean is_via)
519 routebox_t **rbpp, *lastrb = NULL;
520 int i, ht;
521 /* a pin cuts through every layer group */
522 for (i = 0; i < max_layer; i++)
524 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[i]);
525 *rbpp = malloc (sizeof (**rbpp));
526 (*rbpp)->group = i;
527 ht = HALF_THICK (MAX (pin->Thickness, pin->DrillingHole));
528 init_const_box (*rbpp,
529 /*X1 */ pin->X - ht,
530 /*Y1 */ pin->Y - ht,
531 /*X2 */ pin->X + ht,
532 /*Y2 */ pin->Y + ht);
533 /* set aux. properties */
534 if (is_via)
536 (*rbpp)->type = VIA;
537 (*rbpp)->parent.via = pin;
539 else
541 (*rbpp)->type = PIN;
542 (*rbpp)->parent.pin = pin;
544 (*rbpp)->flags.fixed = 1;
545 (*rbpp)->flags.circular = !TEST_FLAG (SQUAREFLAG, pin);
546 /* circular lists */
547 InitLists (*rbpp);
548 /* link together */
549 if (lastrb)
551 MergeNets (*rbpp, lastrb, NET);
552 MergeNets (*rbpp, lastrb, SUBNET);
553 MergeNets (*rbpp, lastrb, ORIGINAL);
555 lastrb = *rbpp;
557 return lastrb;
559 static routebox_t *
560 AddPad (PointerListType layergroupboxes[],
561 ElementTypePtr element, PadTypePtr pad)
563 BDimension halfthick;
564 routebox_t **rbpp;
565 int layergroup = (TEST_FLAG (ONSOLDERFLAG, pad) ? back : front);
566 assert (0 <= layergroup && layergroup < max_layer);
567 assert (PCB->LayerGroups.Number[layergroup] > 0);
568 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
569 assert (rbpp);
570 *rbpp = malloc (sizeof (**rbpp));
571 assert (*rbpp);
572 (*rbpp)->group = layergroup;
573 halfthick = HALF_THICK (pad->Thickness);
574 init_const_box (*rbpp,
575 /*X1 */ MIN (pad->Point1.X, pad->Point2.X) - halfthick,
576 /*Y1 */ MIN (pad->Point1.Y, pad->Point2.Y) - halfthick,
577 /*X2 */ MAX (pad->Point1.X, pad->Point2.X) + halfthick,
578 /*Y2 */ MAX (pad->Point1.Y, pad->Point2.Y) + halfthick);
579 /* kludge for non-manhattan pads (which are not allowed at present) */
580 if (pad->Point1.X != pad->Point2.X && pad->Point1.Y != pad->Point2.Y)
581 (*rbpp)->flags.nonstraight = 1;
582 /* set aux. properties */
583 (*rbpp)->type = PAD;
584 (*rbpp)->parent.pad = pad;
585 (*rbpp)->flags.fixed = 1;
586 /* circular lists */
587 InitLists (*rbpp);
588 return *rbpp;
590 static routebox_t *
591 AddLine (PointerListType layergroupboxes[], int layergroup, LineTypePtr line,
592 LineTypePtr ptr)
594 routebox_t **rbpp;
595 assert (layergroupboxes && line);
596 assert (0 <= layergroup && layergroup < max_layer);
597 assert (PCB->LayerGroups.Number[layergroup] > 0);
599 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
600 *rbpp = malloc (sizeof (**rbpp));
601 (*rbpp)->group = layergroup;
602 init_const_box (*rbpp,
603 /*X1 */ MIN (line->Point1.X,
604 line->Point2.X) - HALF_THICK (line->Thickness),
605 /*Y1 */ MIN (line->Point1.Y,
606 line->Point2.Y) - HALF_THICK (line->Thickness),
607 /*X2 */ MAX (line->Point1.X,
608 line->Point2.X) + HALF_THICK (line->Thickness),
609 /*Y2 */ MAX (line->Point1.Y,
610 line->Point2.Y) +
611 HALF_THICK (line->Thickness));
612 /* kludge for non-manhattan lines */
613 if (line->Point1.X != line->Point2.X && line->Point1.Y != line->Point2.Y)
615 (*rbpp)->flags.nonstraight = 1;
616 (*rbpp)->flags.bl_to_ur =
617 (MIN (line->Point1.X, line->Point2.X) == line->Point1.X) !=
618 (MIN (line->Point1.Y, line->Point2.Y) == line->Point1.Y);
619 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
620 showroutebox (*rbpp);
621 #endif
623 /* set aux. properties */
624 (*rbpp)->type = LINE;
625 (*rbpp)->parent.line = ptr;
626 (*rbpp)->flags.fixed = 1;
627 /* circular lists */
628 InitLists (*rbpp);
629 return *rbpp;
631 static routebox_t *
632 AddIrregularObstacle (PointerListType layergroupboxes[],
633 LocationType X1, LocationType Y1,
634 LocationType X2, LocationType Y2, Cardinal layergroup,
635 void *parent)
637 routebox_t **rbpp;
638 assert (layergroupboxes && parent);
639 assert (X1 <= X2 && Y1 <= Y2);
640 assert (0 <= layergroup && layergroup < max_layer);
641 assert (PCB->LayerGroups.Number[layergroup] > 0);
643 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
644 *rbpp = malloc (sizeof (**rbpp));
645 (*rbpp)->group = layergroup;
646 init_const_box (*rbpp, X1, Y1, X2, Y2);
647 (*rbpp)->flags.nonstraight = 1;
648 (*rbpp)->type = OTHER;
649 (*rbpp)->parent.generic = parent;
650 (*rbpp)->flags.fixed = 1;
651 /* circular lists */
652 InitLists (*rbpp);
653 return *rbpp;
656 static routebox_t *
657 AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
658 PolygonTypePtr polygon)
660 int is_not_rectangle = 1;
661 int layergroup = GetLayerGroupNumberByNumber (layer);
662 routebox_t *rb;
663 assert (0 <= layergroup && layergroup < max_layer);
664 rb = AddIrregularObstacle (layergroupboxes,
665 polygon->BoundingBox.X1,
666 polygon->BoundingBox.Y1,
667 polygon->BoundingBox.X2,
668 polygon->BoundingBox.Y2,
669 layergroup, polygon);
670 if (polygon->PointN == 4 &&
671 (polygon->Points[0].X == polygon->Points[1].X ||
672 polygon->Points[0].Y == polygon->Points[1].Y) &&
673 (polygon->Points[1].X == polygon->Points[2].X ||
674 polygon->Points[1].Y == polygon->Points[2].Y) &&
675 (polygon->Points[2].X == polygon->Points[3].X ||
676 polygon->Points[2].Y == polygon->Points[3].Y) &&
677 (polygon->Points[3].X == polygon->Points[0].X ||
678 polygon->Points[3].Y == polygon->Points[0].Y))
679 is_not_rectangle = 0;
680 rb->flags.nonstraight = is_not_rectangle;
681 rb->layer = layer;
682 if (TEST_FLAG (CLEARPOLYFLAG, polygon))
684 rb->flags.clear_poly = 1;
685 if (!is_not_rectangle)
686 rb->type = PLANE;
688 return rb;
690 static void
691 AddText (PointerListType layergroupboxes[], Cardinal layergroup,
692 TextTypePtr text)
694 AddIrregularObstacle (layergroupboxes,
695 text->BoundingBox.X1, text->BoundingBox.Y1,
696 text->BoundingBox.X2, text->BoundingBox.Y2,
697 layergroup, text);
699 static routebox_t *
700 AddArc (PointerListType layergroupboxes[], Cardinal layergroup,
701 ArcTypePtr arc)
703 return AddIrregularObstacle (layergroupboxes,
704 arc->BoundingBox.X1, arc->BoundingBox.Y1,
705 arc->BoundingBox.X2, arc->BoundingBox.Y2,
706 layergroup, arc);
709 struct rb_info
711 routebox_t *winner;
712 jmp_buf env;
715 static int
716 __found_one_on_lg (const BoxType * box, void *cl)
718 struct rb_info *inf = (struct rb_info *) cl;
719 routebox_t *rb = (routebox_t *) box;
720 if (rb->flags.nonstraight)
721 return 1;
722 inf->winner = rb;
723 longjmp (inf->env, 1);
724 return 0;
726 static routebox_t *
727 FindRouteBoxOnLayerGroup (routedata_t * rd,
728 LocationType X, LocationType Y, Cardinal layergroup)
730 struct rb_info info;
731 BoxType region;
732 info.winner = NULL;
733 region.X1 = region.X2 = X;
734 region.Y1 = region.Y2 = Y;
735 if (setjmp (info.env) == 0)
736 r_search (rd->layergrouptree[layergroup], &region, NULL,
737 __found_one_on_lg, &info);
738 return info.winner;
741 #ifdef ROUTE_DEBUG
742 static void
743 DumpRouteBox (routebox_t * rb)
745 printf ("RB: (%d,%d)-(%d,%d) l%d; ",
746 rb->box.X1, rb->box.Y1, rb->box.X2, rb->box.Y2, (int) rb->group);
747 switch (rb->type)
749 case PAD:
750 printf ("PAD[%s %s] ", rb->parent.pad->Name, rb->parent.pad->Number);
751 break;
752 case PIN:
753 printf ("PIN[%s %s] ", rb->parent.pin->Name, rb->parent.pin->Number);
754 break;
755 case VIA:
756 if (!rb->parent.via)
757 break;
758 printf ("VIA[%s %s] ", rb->parent.via->Name, rb->parent.via->Number);
759 break;
760 case LINE:
761 printf ("LINE ");
762 break;
763 case OTHER:
764 printf ("OTHER ");
765 break;
766 case EXPANSION_AREA:
767 printf ("EXPAREA ");
768 break;
769 default:
770 printf ("UNKNOWN ");
771 break;
773 if (rb->flags.nonstraight)
774 printf ("(nonstraight) ");
775 if (rb->flags.fixed)
776 printf ("(fixed) ");
777 if (rb->flags.source)
778 printf ("(source) ");
779 if (rb->flags.target)
780 printf ("(target) ");
781 if (rb->flags.orphan)
782 printf ("(orphan) ");
783 printf ("\n");
785 #endif
787 static routedata_t *
788 CreateRouteData ()
790 NetListListType Nets;
791 PointerListType layergroupboxes[MAX_LAYER];
792 BoxType bbox;
793 routedata_t *rd;
794 Boolean other = True;
795 int group, i;
797 /* check which layers are active first */
798 routing_layers = 0;
799 for (group = 0; group < max_layer; group++)
801 for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
802 /* layer must be 1) not silk (ie, < max_layer) and 2) on */
803 if ((PCB->LayerGroups.Entries[group][i] < max_layer) &&
804 PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)
806 routing_layers++;
807 is_layer_group_active[group] = True;
808 break;
810 else
811 is_layer_group_active[group] = False;
813 AutoRouteParameters.use_vias = ((routing_layers > 1) ? True : False);
814 front = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
815 back = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
816 /* determine preferred routing direction on each group */
817 for (i = 0; i < max_layer; i++)
819 if (i != back && i != front)
821 bad_x[i] = other;
822 other = !other;
823 bad_y[i] = other;
825 else
827 bad_x[i] = False;
828 bad_y[i] = False;
831 /* create routedata */
832 rd = malloc (sizeof (*rd));
833 /* create default style */
834 rd->defaultStyle.Thick = Settings.LineThickness;
835 rd->defaultStyle.Diameter = Settings.ViaThickness;
836 rd->defaultStyle.Hole = Settings.ViaDrillingHole;
837 rd->defaultStyle.Keepaway = Settings.Keepaway;
838 rd->max_bloat = BLOAT (&rd->defaultStyle);
839 /* create augStyles structures */
840 bbox.X1 = bbox.Y1 = 0;
841 bbox.X2 = PCB->MaxWidth;
842 bbox.Y2 = PCB->MaxHeight;
843 for (i = 0; i < NUM_STYLES + 1; i++)
845 RouteStyleType *style =
846 (i < NUM_STYLES) ? &PCB->RouteStyle[i] : &rd->defaultStyle;
847 rd->augStyles[i].style = style;
848 rd->augStyles[i].Used = False;
851 /* initialize pointerlisttype */
852 for (i = 0; i < max_layer; i++)
854 layergroupboxes[i].Ptr = NULL;
855 layergroupboxes[i].PtrN = 0;
856 layergroupboxes[i].PtrMax = 0;
857 GROUP_LOOP (PCB->Data, i);
859 if (layer->LineN || layer->ArcN)
860 usedGroup[i] = True;
861 else
862 usedGroup[i] = False;
864 END_LOOP;
866 usedGroup[front] = True;
867 usedGroup[back] = True;
868 /* add the objects in the netlist first.
869 * then go and add all other objects that weren't already added
871 * this saves on searching the trees to find the nets
873 /* use the DRCFLAG to mark objects as their entered */
874 ResetFoundPinsViasAndPads (False);
875 ResetFoundLinesAndPolygons (False);
876 Nets = CollectSubnets (False);
878 routebox_t *last_net = NULL;
879 NETLIST_LOOP (&Nets);
881 routebox_t *last_in_net = NULL;
882 NET_LOOP (netlist);
884 routebox_t *last_in_subnet = NULL;
885 int j;
887 for (j = 0; j < NUM_STYLES; j++)
888 if (net->Style == rd->augStyles[j].style)
889 break;
890 CONNECTION_LOOP (net);
892 routebox_t *rb = NULL;
893 SET_FLAG (DRCFLAG, (PinTypePtr) connection->ptr2);
894 if (connection->type == LINE_TYPE)
896 LineType *line = (LineType *) connection->ptr2;
898 /* lines are listed at each end, so skip one */
899 /* this should probably by a macro named "BUMP_LOOP" */
900 n--;
902 /* dice up non-straight lines into many tiny obstacles */
903 if (line->Point1.X != line->Point2.X
904 && line->Point1.Y != line->Point2.Y)
906 LineType fake_line = *line;
907 int dx = (line->Point2.X - line->Point1.X);
908 int dy = (line->Point2.Y - line->Point1.Y);
909 int segs = MAX (ABS (dx),
910 ABS (dy)) / (4 *
911 BLOAT (rd->augStyles[j].
912 style) + 1);
913 int qq;
914 segs = MAX (1, MIN (segs, 32)); /* don't go too crazy */
915 dx /= segs;
916 dy /= segs;
917 for (qq = 0; qq < segs - 1; qq++)
919 fake_line.Point2.X = fake_line.Point1.X + dx;
920 fake_line.Point2.Y = fake_line.Point1.Y + dy;
921 if (fake_line.Point2.X == line->Point2.X
922 && fake_line.Point2.Y == line->Point2.Y)
923 break;
924 rb =
925 AddLine (layergroupboxes, connection->group,
926 &fake_line, line);
927 rb->augStyle = &rd->augStyles[j];
928 if (last_in_subnet && rb != last_in_subnet)
929 MergeNets (last_in_subnet, rb, ORIGINAL);
930 if (last_in_net && rb != last_in_net)
931 MergeNets (last_in_net, rb, NET);
932 last_in_subnet = last_in_net = rb;
933 fake_line.Point1 = fake_line.Point2;
935 fake_line.Point2 = line->Point2;
936 rb =
937 AddLine (layergroupboxes, connection->group, &fake_line,
938 line);
940 else
942 rb =
943 AddLine (layergroupboxes, connection->group, line, line);
946 else
947 switch (connection->type)
949 case PAD_TYPE:
950 rb =
951 AddPad (layergroupboxes, connection->ptr1,
952 connection->ptr2);
953 break;
954 case PIN_TYPE:
955 rb = AddPin (layergroupboxes, connection->ptr2, False);
956 break;
957 case VIA_TYPE:
958 rb = AddPin (layergroupboxes, connection->ptr2, True);
959 break;
960 case POLYGON_TYPE:
961 rb =
962 AddPolygon (layergroupboxes,
963 GetLayerNumber (PCB->Data, connection->ptr1),
964 connection->ptr2);
965 break;
967 assert (rb);
968 /* set rb->augStyle! */
969 rb->augStyle = &rd->augStyles[j];
970 rb->augStyle->Used = True;
971 /* update circular connectivity lists */
972 if (last_in_subnet && rb != last_in_subnet)
973 MergeNets (last_in_subnet, rb, ORIGINAL);
974 if (last_in_net && rb != last_in_net)
975 MergeNets (last_in_net, rb, NET);
976 last_in_subnet = last_in_net = rb;
977 rd->max_bloat = MAX (rd->max_bloat, BLOAT (rb->augStyle->style));
979 END_LOOP;
981 END_LOOP;
982 if (last_net && last_in_net)
983 MergeNets (last_net, last_in_net, DIFFERENT_NET);
984 last_net = last_in_net;
986 END_LOOP;
987 rd->first_net = last_net;
989 FreeNetListListMemory (&Nets);
991 /* reset all nets to "original" connectivity (which we just set) */
993 routebox_t *net;
994 LIST_LOOP (rd->first_net, different_net, net);
995 ResetSubnet (net);
996 END_LOOP;
999 /* add pins and pads of elements */
1000 ALLPIN_LOOP (PCB->Data);
1002 if (TEST_FLAG (DRCFLAG, pin))
1003 CLEAR_FLAG (DRCFLAG, pin);
1004 else
1005 AddPin (layergroupboxes, pin, False);
1007 ENDALL_LOOP;
1008 ALLPAD_LOOP (PCB->Data);
1010 if (TEST_FLAG (DRCFLAG, pad))
1011 CLEAR_FLAG (DRCFLAG, pad);
1012 else
1013 AddPad (layergroupboxes, element, pad);
1015 ENDALL_LOOP;
1016 /* add all vias */
1017 VIA_LOOP (PCB->Data);
1019 if (TEST_FLAG (DRCFLAG, via))
1020 CLEAR_FLAG (DRCFLAG, via);
1021 else
1022 AddPin (layergroupboxes, via, True);
1024 END_LOOP;
1026 for (i = 0; i < max_layer; i++)
1028 int layergroup = GetLayerGroupNumberByNumber (i);
1029 /* add all (non-rat) lines */
1030 LINE_LOOP (LAYER_PTR (i));
1032 if (TEST_FLAG (DRCFLAG, line))
1034 CLEAR_FLAG (DRCFLAG, line);
1035 continue;
1037 /* dice up non-straight lines into many tiny obstacles */
1038 if (line->Point1.X != line->Point2.X
1039 && line->Point1.Y != line->Point2.Y)
1041 LineType fake_line = *line;
1042 int dx = (line->Point2.X - line->Point1.X);
1043 int dy = (line->Point2.Y - line->Point1.Y);
1044 int segs = MAX (ABS (dx), ABS (dy)) / (4 * rd->max_bloat + 1);
1045 int qq;
1046 segs = MAX (1, MIN (segs, 32)); /* don't go too crazy */
1047 dx /= segs;
1048 dy /= segs;
1049 for (qq = 0; qq < segs - 1; qq++)
1051 fake_line.Point2.X = fake_line.Point1.X + dx;
1052 fake_line.Point2.Y = fake_line.Point1.Y + dy;
1053 if (fake_line.Point2.X == line->Point2.X
1054 && fake_line.Point2.Y == line->Point2.Y)
1055 break;
1056 AddLine (layergroupboxes, layergroup, &fake_line, line);
1057 fake_line.Point1 = fake_line.Point2;
1059 fake_line.Point2 = line->Point2;
1060 AddLine (layergroupboxes, layergroup, &fake_line, line);
1062 else
1064 AddLine (layergroupboxes, layergroup, line, line);
1067 END_LOOP;
1068 /* add all polygons */
1069 POLYGON_LOOP (LAYER_PTR (i));
1071 if (TEST_FLAG (DRCFLAG, polygon))
1072 CLEAR_FLAG (DRCFLAG, polygon);
1073 else
1074 AddPolygon (layergroupboxes, i, polygon);
1076 END_LOOP;
1077 /* add all copper text */
1078 TEXT_LOOP (LAYER_PTR (i));
1080 AddText (layergroupboxes, layergroup, text);
1082 END_LOOP;
1083 /* add all arcs */
1084 ARC_LOOP (LAYER_PTR (i));
1086 AddArc (layergroupboxes, layergroup, arc);
1088 END_LOOP;
1091 /* create r-trees from pointer lists */
1092 for (i = 0; i < max_layer; i++)
1094 /* initialize style (we'll fill in a "real" style later, when we add
1095 * the connectivity information) */
1096 POINTER_LOOP (&layergroupboxes[i]);
1098 /* we're initializing this to the "default" style */
1099 ((routebox_t *) * ptr)->augStyle = &rd->augStyles[NUM_STYLES];
1101 END_LOOP;
1102 /* create the r-tree */
1103 rd->layergrouptree[i] =
1104 r_create_tree ((const BoxType **) layergroupboxes[i].Ptr,
1105 layergroupboxes[i].PtrN, 1);
1108 if (AutoRouteParameters.use_vias)
1110 rd->mtspace = mtspace_create ();
1112 /* create "empty-space" structures for via placement (now that we know
1113 * appropriate keepaways for all the fixed elements) */
1114 for (i = 0; i < max_layer; i++)
1116 POINTER_LOOP (&layergroupboxes[i]);
1118 routebox_t *rb = (routebox_t *) * ptr;
1119 if (!rb->flags.clear_poly)
1120 mtspace_add (rd->mtspace, &rb->box, FIXED,
1121 rb->augStyle->style->Keepaway);
1123 END_LOOP;
1126 /* free pointer lists */
1127 for (i = 0; i < max_layer; i++)
1128 FreePointerListMemory (&layergroupboxes[i]);
1129 /* done! */
1130 return rd;
1133 void
1134 DestroyRouteData (routedata_t ** rd)
1136 int i;
1137 for (i = 0; i < max_layer; i++)
1138 r_destroy_tree (&(*rd)->layergrouptree[i]);
1139 if (AutoRouteParameters.use_vias)
1140 mtspace_destroy (&(*rd)->mtspace);
1141 free (*rd);
1142 *rd = NULL;
1145 /*-----------------------------------------------------------------
1146 * routebox reference counting.
1149 /* increment the reference count on a routebox. */
1150 static void
1151 RB_up_count (routebox_t * rb)
1153 assert (rb->flags.orphan);
1154 rb->refcount++;
1157 /* decrement the reference count on a routebox, freeing if this box becomes
1158 * unused. */
1159 static void
1160 RB_down_count (routebox_t * rb)
1162 assert (rb->flags.orphan);
1163 assert (rb->refcount > 0);
1164 if (--rb->refcount == 0)
1166 /* rb->underlying is guaranteed to not be an orphan, so we only need
1167 * to downcount the parent, if type==EXPANSION_AREA */
1168 if (rb->type == EXPANSION_AREA
1169 && rb->parent.expansion_area->flags.orphan)
1170 RB_down_count (rb->parent.expansion_area);
1171 free (rb);
1175 /*-----------------------------------------------------------------
1176 * Rectangle-expansion routing code.
1179 static void
1180 ResetSubnet (routebox_t * net)
1182 routebox_t *rb;
1183 /* reset connectivity of everything on this net */
1184 LIST_LOOP (net, same_net, rb);
1185 rb->same_subnet = rb->original_subnet;
1186 END_LOOP;
1189 static inline cost_t
1190 cost_to_point_on_layer (const CheapPointType * p1,
1191 const CheapPointType * p2, Cardinal point_layer)
1193 cost_t x_dist = p1->X - p2->X, y_dist = p1->Y - p2->Y, r;
1194 if (bad_x[point_layer])
1195 x_dist *= AutoRouteParameters.DirectionPenalty;
1196 else if (bad_y[point_layer])
1197 y_dist *= AutoRouteParameters.DirectionPenalty;
1198 /* cost is proportional to orthogonal distance. */
1199 r = ABS (x_dist) + ABS (y_dist);
1200 /* penalize the surface layers in order to minimize SMD pad congestion */
1201 if (point_layer == front || point_layer == back)
1202 r *= AutoRouteParameters.SurfacePenalty;
1203 return r;
1206 static cost_t
1207 cost_to_point (const CheapPointType * p1, Cardinal point_layer1,
1208 const CheapPointType * p2, Cardinal point_layer2)
1210 cost_t r = cost_to_point_on_layer (p1, p2, point_layer1);
1211 /* apply via cost penalty if layers differ */
1212 if (point_layer1 != point_layer2)
1213 r += AutoRouteParameters.ViaCost;
1214 return r;
1217 /* return the minimum *cost* from a point to a box on any layer.
1218 * It's safe to return a smaller than minimum cost
1220 static cost_t
1221 cost_to_layerless_box (const CheapPointType * p, Cardinal point_layer,
1222 const BoxType * b)
1224 CheapPointType p2 = closest_point_in_box (p, b);
1225 register cost_t c1, c2;
1227 c1 = p2.X - p->X;
1228 c2 = p2.Y - p->Y;
1230 c1 = ABS (c1);
1231 c2 = ABS (c2);
1232 if (c1 < c2)
1233 return c1 * AutoRouteParameters.MinPenalty + c2;
1234 else
1235 return c2 * AutoRouteParameters.MinPenalty + c1;
1238 /* get to actual pins/pad target coordinates */
1239 Boolean
1240 TargetPoint (CheapPointType * nextpoint, const routebox_t * target)
1242 if (target->type == PIN)
1244 nextpoint->X = target->parent.pin->X;
1245 nextpoint->Y = target->parent.pin->Y;
1246 return True;
1248 else if (target->type == PAD)
1250 if (abs (target->parent.pad->Point1.X - nextpoint->X) <
1251 abs (target->parent.pad->Point2.X - nextpoint->X))
1252 nextpoint->X = target->parent.pad->Point1.X;
1253 else
1254 nextpoint->X = target->parent.pad->Point2.X;
1255 if (abs (target->parent.pad->Point1.Y - nextpoint->Y) <
1256 abs (target->parent.pad->Point2.Y - nextpoint->Y))
1257 nextpoint->Y = target->parent.pad->Point1.Y;
1258 else
1259 nextpoint->Y = target->parent.pad->Point2.Y;
1260 return True;
1262 else if (target->type == VIA)
1264 nextpoint->X = (target->box.X1 + target->box.X2) / 2;
1265 nextpoint->Y = (target->box.Y1 + target->box.Y2) / 2;
1267 return False;
1270 /* return the *minimum cost* from a point to a route box, including possible
1271 * via costs if the route box is on a different layer. */
1272 static cost_t
1273 cost_to_routebox (const CheapPointType * p, Cardinal point_layer,
1274 const routebox_t * rb)
1276 register cost_t c1, c2, trial = 0;
1277 CheapPointType p2 = closest_point_in_box (p, &rb->box);
1278 // if (rb->flags.target)
1279 // TargetPoint (&p2, rb);
1280 if (!usedGroup[point_layer] || !usedGroup[rb->group])
1281 trial = AutoRouteParameters.NewLayerPenalty;
1282 if ((p->X - p2.X) * (p->Y - p2.Y) != 0)
1283 trial += AutoRouteParameters.JogPenalty;
1284 /* special case for defered via searching */
1285 if (point_layer > max_layer)
1286 return trial + cost_to_point_on_layer (p, &p2, rb->group);
1287 if (point_layer == rb->group)
1288 return trial + cost_to_point_on_layer (p, &p2, point_layer);
1289 trial += AutoRouteParameters.ViaCost;
1290 c1 = cost_to_point_on_layer (p, &p2, point_layer);
1291 c2 = cost_to_point_on_layer (p, &p2, rb->group);
1292 trial += MIN (c1, c2);
1293 return trial;
1296 static BoxType
1297 bloat_routebox (routebox_t * rb)
1299 BoxType r;
1300 BDimension keepaway;
1301 assert (__routebox_is_good (rb));
1302 if (rb->type == EXPANSION_AREA || rb->flags.nobloat)
1303 return rb->box; /* no bloat */
1305 /* obstacle exclusion zones get bloated, and then shrunk on their
1306 * top and left sides so that they approximate their "open"
1307 * brethren. */
1308 keepaway = MAX (AutoRouteParameters.augStyle->style->Keepaway,
1309 rb->augStyle->style->Keepaway);
1310 r = bloat_box (&rb->box, keepaway +
1311 HALF_THICK (AutoRouteParameters.augStyle->style->Thick));
1312 r.X1++;
1313 r.Y1++;
1314 return r;
1318 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1319 /* makes a line on the solder layer silk surrounding the box */
1320 void
1321 showbox (BoxType b, Dimension thickness, int group)
1323 LineTypePtr line;
1324 LayerTypePtr SLayer = LAYER_PTR (group);
1325 if (!showboxen)
1326 return;
1328 gui->set_line_width (Output.fgGC, thickness);
1329 gui->set_line_cap (Output.fgGC, Trace_Cap);
1330 gui->set_color (Output.fgGC, SLayer->Color);
1332 gui->draw_line (Output.fgGC, b.X1, b.Y1, b.X2, b.Y1);
1333 gui->draw_line (Output.fgGC, b.X1, b.Y2, b.X2, b.Y2);
1334 gui->draw_line (Output.fgGC, b.X1, b.Y1, b.X1, b.Y2);
1335 gui->draw_line (Output.fgGC, b.X2, b.Y1, b.X2, b.Y2);
1337 #if XXX
1338 if (XtAppPending (Context))
1339 XtAppProcessEvent (Context, XtIMAll);
1340 XSync (Dpy, False);
1341 #endif
1343 if (b.Y1 == b.Y2 || b.X1 == b.X2)
1344 thickness = 5;
1345 line = CreateNewLineOnLayer (LAYER_PTR (max_layer + COMPONENT_LAYER),
1346 b.X1, b.Y1, b.X2, b.Y1, thickness, 0,
1347 MakeFlags (0));
1348 AddObjectToCreateUndoList (LINE_TYPE,
1349 LAYER_PTR (max_layer + COMPONENT_LAYER), line,
1350 line);
1351 if (b.Y1 != b.Y2)
1353 line = CreateNewLineOnLayer (LAYER_PTR (max_layer + COMPONENT_LAYER),
1354 b.X1, b.Y2, b.X2, b.Y2, thickness, 0,
1355 MakeFlags (0));
1356 AddObjectToCreateUndoList (LINE_TYPE,
1357 LAYER_PTR (max_layer + COMPONENT_LAYER),
1358 line, line);
1360 line = CreateNewLineOnLayer (LAYER_PTR (max_layer + COMPONENT_LAYER),
1361 b.X1, b.Y1, b.X1, b.Y2, thickness, 0,
1362 MakeFlags (0));
1363 AddObjectToCreateUndoList (LINE_TYPE,
1364 LAYER_PTR (max_layer + COMPONENT_LAYER), line,
1365 line);
1366 if (b.X1 != b.X2)
1368 line = CreateNewLineOnLayer (LAYER_PTR (max_layer + COMPONENT_LAYER),
1369 b.X2, b.Y1, b.X2, b.Y2, thickness, 0,
1370 MakeFlags (0));
1371 AddObjectToCreateUndoList (LINE_TYPE,
1372 LAYER_PTR (max_layer + COMPONENT_LAYER),
1373 line, line);
1376 #endif
1378 #if defined(ROUTE_DEBUG)
1379 static void
1380 showedge (edge_t * e)
1382 BoxType *b = (BoxType *) e->rb;
1384 gui->set_line_cap (Output.fgGC, Trace_Cap);
1385 gui->set_line_width (Output.fgGC, 1);
1386 gui->set_color (Output.fgGC, Settings.MaskColor);
1388 switch (e->expand_dir)
1390 case NORTH:
1391 gui->draw_line (Output.fgGC, b->X1, b->Y1, b->X2, b->Y1);
1392 break;
1393 case SOUTH:
1394 gui->draw_line (Output.fgGC, b->X1, b->Y2, b->X2, b->Y2);
1395 break;
1396 case WEST:
1397 gui->draw_line (Output.fgGC, b->X1, b->Y1, b->X1, b->Y2);
1398 break;
1399 case EAST:
1400 gui->draw_line (Output.fgGC, b->X2, b->Y1, b->X2, b->Y2);
1401 break;
1404 #endif
1406 #if defined(ROUTE_DEBUG)
1407 static void
1408 showroutebox (routebox_t * rb)
1410 showbox (rb->box, rb->flags.source ? 8 : (rb->flags.target ? 4 : 1),
1411 rb->flags.is_via ? max_layer + COMPONENT_LAYER : rb->group);
1413 #endif
1415 static void
1416 EraseRouteBox (routebox_t * rb)
1418 LocationType X1, Y1, X2, Y2;
1419 BDimension thick;
1421 if (rb->box.X2 - rb->box.X1 < rb->box.Y2 - rb->box.Y1)
1423 thick = rb->box.X2 - rb->box.X1;
1424 X1 = X2 = (rb->box.X2 + rb->box.X1) / 2;
1425 Y1 = rb->box.Y1 + thick / 2;
1426 Y2 = rb->box.Y2 - thick / 2;
1428 else
1430 thick = rb->box.Y2 - rb->box.Y1;
1431 Y1 = Y2 = (rb->box.Y2 + rb->box.Y1) / 2;
1432 X1 = rb->box.X1 + thick / 2;
1433 X2 = rb->box.X2 - thick / 2;
1436 gui->set_line_width (ar_gc, thick);
1437 gui->set_color (ar_gc, Settings.BackgroundColor);
1438 gui->draw_line (ar_gc, X1, Y1, X2, Y2);
1441 /* return a "parent" of this edge which immediately precedes it in the route.*/
1442 static routebox_t *
1443 route_parent (routebox_t * rb)
1445 while (rb->flags.orphan && rb->underlying == NULL && !rb->flags.is_via)
1447 assert (rb->type == EXPANSION_AREA);
1448 rb = rb->parent.expansion_area;
1449 assert (rb);
1451 return rb;
1454 /* return a "parent" of this edge which resides in a r-tree somewhere */
1455 /* -- actually, this "parent" *may* be a via box, which doesn't live in
1456 * a r-tree. -- */
1457 static routebox_t *
1458 nonorphan_parent (routebox_t * rb)
1460 rb = route_parent (rb);
1461 return rb->underlying ? rb->underlying : rb;
1464 /* some routines to find the minimum *cost* from a cost point to
1465 * a target (any target) */
1466 struct mincost_target_closure
1468 const CheapPointType *CostPoint;
1469 Cardinal CostPointLayer;
1470 routebox_t *nearest;
1471 cost_t nearest_cost;
1473 static int
1474 __region_within_guess (const BoxType * region, void *cl)
1476 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1477 cost_t cost_to_region;
1478 if (mtc->nearest == NULL)
1479 return 1;
1480 cost_to_region =
1481 cost_to_layerless_box (mtc->CostPoint, mtc->CostPointLayer, region);
1482 assert (cost_to_region >= 0);
1483 /* if no guess yet, all regions are "close enough" */
1484 /* note that cost is *strictly more* than minimum distance, so we'll
1485 * always search a region large enough. */
1486 return (cost_to_region < mtc->nearest_cost);
1488 static int
1489 __found_new_guess (const BoxType * box, void *cl)
1491 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
1492 routebox_t *guess = (routebox_t *) box;
1493 cost_t cost_to_guess =
1494 cost_to_routebox (mtc->CostPoint, mtc->CostPointLayer, guess);
1495 assert (cost_to_guess >= 0);
1496 /* if this is cheaper than previous guess... */
1497 if (cost_to_guess < mtc->nearest_cost)
1499 mtc->nearest = guess;
1500 mtc->nearest_cost = cost_to_guess; /* this is our new guess! */
1501 return 1;
1503 else
1504 return 0; /* not less expensive than our last guess */
1507 /* target_guess is our guess at what the nearest target is, or NULL if we
1508 * just plum don't have a clue. */
1509 static routebox_t *
1510 mincost_target_to_point (const CheapPointType * CostPoint,
1511 Cardinal CostPointLayer,
1512 rtree_t * targets, routebox_t * target_guess)
1514 struct mincost_target_closure mtc;
1515 assert (target_guess == NULL || target_guess->flags.target); /* this is a target, right? */
1516 mtc.CostPoint = CostPoint;
1517 mtc.CostPointLayer = CostPointLayer;
1518 mtc.nearest = target_guess;
1519 if (mtc.nearest)
1520 mtc.nearest_cost =
1521 cost_to_routebox (mtc.CostPoint, mtc.CostPointLayer, mtc.nearest);
1522 else
1523 mtc.nearest_cost = EXPENSIVE;
1524 r_search (targets, NULL, __region_within_guess, __found_new_guess, &mtc);
1525 assert (mtc.nearest != NULL && mtc.nearest_cost >= 0);
1526 assert (mtc.nearest->flags.target); /* this is a target, right? */
1527 return mtc.nearest;
1530 /* create edge from field values */
1531 /* mincost_target_guess can be NULL */
1532 static edge_t *
1533 CreateEdge (routebox_t * rb,
1534 LocationType CostPointX, LocationType CostPointY,
1535 cost_t cost_to_point,
1536 routebox_t * mincost_target_guess,
1537 direction_t expand_dir, rtree_t * targets)
1539 edge_t *e;
1540 assert (__routebox_is_good (rb));
1541 e = malloc (sizeof (*e));
1542 assert (e);
1543 e->rb = rb;
1544 if (rb->flags.orphan)
1545 RB_up_count (rb);
1546 e->cost_point.X = CostPointX;
1547 e->cost_point.Y = CostPointY;
1548 e->cost_to_point = cost_to_point;
1549 e->flags.via_search = 0;
1550 /* if this edge is created in response to a target, use it */
1551 if (targets)
1552 e->mincost_target =
1553 mincost_target_to_point (&e->cost_point, rb->group,
1554 targets, mincost_target_guess);
1555 else
1556 e->mincost_target = mincost_target_guess;
1557 e->expand_dir = expand_dir;
1558 assert (e->rb && e->mincost_target); /* valid edge? */
1559 assert (!e->flags.is_via || e->flags.expand_all_sides);
1560 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1561 assert (rb->type == PLANE || rb->underlying != NULL || rb->flags.is_via ||
1562 ((expand_dir == NORTH || expand_dir == SOUTH) ?
1563 rb->box.X1 <= CostPointX && CostPointX <= rb->box.X2 &&
1564 CostPointY == (expand_dir == NORTH ? rb->box.Y1 : rb->box.Y2) :
1565 /* expand_dir==EAST || expand_dir==WEST */
1566 rb->box.Y1 <= CostPointY && CostPointY <= rb->box.Y2 &&
1567 CostPointX == (expand_dir == EAST ? rb->box.X2 : rb->box.X1)));
1568 assert (__edge_is_good (e));
1569 /* done */
1570 return e;
1573 static cost_t
1574 going_away (CheapPointType first, CheapPointType second, routebox_t * target)
1576 CheapPointType t = closest_point_in_box (&second, &target->box);
1577 if (SQUARE (t.X - second.X) + SQUARE (t.Y - second.Y) >
1578 SQUARE (t.X - first.X) + SQUARE (t.Y - first.Y))
1579 return AutoRouteParameters.AwayPenalty;
1580 return 1;
1583 /* create edge, using previous edge to fill in defaults. */
1584 /* most of the work here is in determining a new cost point */
1585 static edge_t *
1586 CreateEdge2 (routebox_t * rb, direction_t expand_dir,
1587 edge_t * previous_edge, rtree_t * targets, routebox_t * guess)
1589 BoxType thisbox;
1590 CheapPointType thiscost, prevcost;
1591 cost_t d;
1593 assert (rb && previous_edge);
1594 /* okay, find cheapest costpoint to costpoint of previous edge */
1595 thisbox = edge_to_box (&rb->box, expand_dir);
1596 prevcost = previous_edge->cost_point;
1597 /* find point closest to target */
1598 thiscost = closest_point_in_box (&prevcost, &thisbox);
1599 /* compute cost-to-point */
1600 d = cost_to_point_on_layer (&prevcost, &thiscost, rb->group);
1601 /* penalize getting further from the target */
1602 d *= going_away (prevcost, thiscost, previous_edge->mincost_target);
1603 /* add in jog penalty */
1604 if (previous_edge->expand_dir != expand_dir
1605 && (!guess || !guess->flags.target))
1606 d += AutoRouteParameters.JogPenalty;
1607 /* okay, new edge! */
1608 return CreateEdge (rb, thiscost.X, thiscost.Y,
1609 previous_edge->cost_to_point + d,
1610 guess ? guess : previous_edge->mincost_target,
1611 expand_dir, targets);
1614 /* create via edge, using previous edge to fill in defaults. */
1615 static edge_t *
1616 CreateViaEdge (const BoxType * area, Cardinal group,
1617 routebox_t * parent, edge_t * previous_edge,
1618 conflict_t to_site_conflict,
1619 conflict_t through_site_conflict, rtree_t * targets)
1621 routebox_t *rb;
1622 CheapPointType costpoint;
1623 cost_t d;
1624 edge_t *ne;
1625 cost_t scale[3];
1627 scale[0] = 1;
1628 scale[1] = AutoRouteParameters.LastConflictPenalty;
1629 scale[2] = AutoRouteParameters.ConflictPenalty;
1631 assert (__box_is_good (area));
1632 assert (AutoRouteParameters.with_conflicts ||
1633 (to_site_conflict == NO_CONFLICT &&
1634 through_site_conflict == NO_CONFLICT));
1635 rb = CreateExpansionArea (area, group, parent, True, previous_edge);
1636 rb->flags.is_via = 1;
1637 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1638 showroutebox (rb);
1639 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1640 /* for planes, choose a point near the target */
1641 if (parent->type == PLANE)
1643 routebox_t *target;
1644 CheapPointType pnt;
1645 /* find a target near this via box */
1646 pnt.X = (area->X2 + area->X1) / 2;
1647 pnt.Y = (area->Y2 + area->Y1) / 2;
1648 target = mincost_target_to_point (&pnt, rb->group,
1649 targets,
1650 previous_edge->mincost_target);
1651 /* now find point near the target */
1652 pnt.X = (target->box.X1 + target->box.X2) / 2;
1653 pnt.Y = (target->box.Y1 + target->box.Y2) / 2;
1654 costpoint = closest_point_in_box (&pnt, &rb->box);
1656 (scale[through_site_conflict] *
1657 cost_to_point (&costpoint, group, &costpoint,
1658 previous_edge->rb->group));
1659 ne = CreateEdge (rb, costpoint.X, costpoint.Y, previous_edge->cost_to_point + d, target, NORTH /*arbitrary */
1660 , NULL);
1662 else
1664 costpoint = closest_point_in_box (&previous_edge->cost_point, &rb->box);
1666 (scale[to_site_conflict] *
1667 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1668 previous_edge->rb->group)) +
1669 (scale[through_site_conflict] *
1670 cost_to_point (&costpoint, group, &costpoint,
1671 previous_edge->rb->group));
1672 ne = CreateEdge (rb, costpoint.X, costpoint.Y, previous_edge->cost_to_point + d, previous_edge->mincost_target, NORTH /*arbitrary */
1673 , targets);
1675 ne->flags.expand_all_sides = ne->flags.is_via = 1;
1676 ne->flags.via_conflict_level = to_site_conflict;
1677 assert (__edge_is_good (ne));
1678 return ne;
1681 /* create "interior" edge for routing with conflicts */
1682 static edge_t *
1683 CreateEdgeWithConflicts (const BoxType * interior_edge,
1684 routebox_t * container,
1685 edge_t * previous_edge,
1686 cost_t cost_penalty_to_box, rtree_t * targets)
1688 routebox_t *rb;
1689 BoxType b;
1690 CheapPointType costpoint;
1691 cost_t d;
1692 edge_t *ne;
1693 assert (interior_edge && container && previous_edge && targets);
1694 assert (!container->flags.orphan);
1695 assert (AutoRouteParameters.with_conflicts);
1696 /* create expansion area equal to the bloated container. Put costpoint
1697 * in this box. compute cost, but add jog penalty. */
1698 b = bloat_routebox (container);
1699 assert (previous_edge->rb->group == container->group);
1700 rb = CreateExpansionArea (&b, previous_edge->rb->group, previous_edge->rb,
1701 True, previous_edge);
1702 rb->underlying = container; /* crucial! */
1703 costpoint = closest_point_in_box (&previous_edge->cost_point, &b);
1704 d = cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
1705 previous_edge->rb->group);
1706 d *= cost_penalty_to_box;
1707 ne = CreateEdge (rb, costpoint.X, costpoint.Y, previous_edge->cost_to_point + d, previous_edge->mincost_target, NORTH /*arbitrary */
1708 , targets);
1709 ne->flags.expand_all_sides = ne->flags.is_interior = 1;
1710 assert (__edge_is_good (ne));
1711 return ne;
1714 static void
1715 DestroyEdge (edge_t ** e)
1717 assert (e && *e);
1718 if ((*e)->rb->flags.orphan)
1719 RB_down_count ((*e)->rb); /* possibly free rb */
1720 if ((*e)->flags.via_search)
1721 mtsFreeWork (&(*e)->work);
1722 free (*e);
1723 *e = NULL;
1726 /* cost function for an edge. */
1727 static cost_t
1728 edge_cost (const edge_t * e, const cost_t too_big)
1730 cost_t penalty = 0;
1731 if (e->rb->type == PLANE)
1732 return 1; /* thermals are cheap */
1733 if (!usedGroup[e->rb->group])
1734 penalty = AutoRouteParameters.NewLayerPenalty;
1735 switch (e->expand_dir)
1737 case NORTH:
1738 if (e->mincost_target->box.Y1 >= e->rb->box.Y1)
1739 penalty += AutoRouteParameters.WrongWayPenalty;
1740 break;
1741 case SOUTH:
1742 if (e->mincost_target->box.Y2 <= e->rb->box.Y2)
1743 penalty += AutoRouteParameters.WrongWayPenalty;
1744 break;
1745 case WEST:
1746 if (e->mincost_target->box.X1 >= e->rb->box.X1)
1747 penalty += AutoRouteParameters.WrongWayPenalty;
1748 break;
1749 case EAST:
1750 if (e->mincost_target->box.X2 >= e->rb->box.X2)
1751 penalty += AutoRouteParameters.WrongWayPenalty;
1752 break;
1754 penalty += e->cost_to_point;
1755 if (penalty > too_big)
1756 return penalty;
1758 /* cost_to_routebox adds in our via correction, too. */
1759 return penalty +
1760 cost_to_routebox (&e->cost_point, e->rb->group, e->mincost_target);
1763 static LocationType
1764 edge_length (const BoxType * cb, direction_t expand_dir)
1766 BoxType b = *cb;
1767 ROTATEBOX_TO_NORTH (b, expand_dir);
1768 assert (b.X1 <= b.X2);
1769 return b.X2 - b.X1;
1772 /* return a bounding box for the PCB board. */
1773 static BoxType
1774 pcb_bounds (void)
1776 BoxType b;
1777 b.X1 = 0;
1778 b.X2 = PCB->MaxWidth;
1779 b.Y1 = 0;
1780 b.Y2 = PCB->MaxHeight;
1781 /* adjust from closed to half-closed box */
1782 b.X2++;
1783 b.Y2++;
1784 /* done */
1785 return b;
1788 static BoxType
1789 shrunk_pcb_bounds ()
1791 BoxType b = pcb_bounds ();
1792 return shrink_box (&b, AutoRouteParameters.augStyle->style->Keepaway +
1793 HALF_THICK (AutoRouteParameters.augStyle->style->Thick));
1796 /* create a maximal expansion region from the specified edge to the edge
1797 * of the PCB (minus the required keepaway). */
1798 static BoxType
1799 edge_to_infinity_region (edge_t * e)
1801 BoxType max, ebox;
1802 ebox = e->rb->box;
1803 max = shrunk_pcb_bounds ();
1804 /* normalize to north */
1805 ROTATEBOX_TO_NORTH (max, e->expand_dir);
1806 ROTATEBOX_TO_NORTH (ebox, e->expand_dir);
1807 /* north case: */
1808 max.X1 = ebox.X1;
1809 max.X2 = ebox.X2;
1810 max.Y2 = ebox.Y1;
1811 /* unnormalize */
1812 ROTATEBOX_FROM_NORTH (max, e->expand_dir);
1813 /* done */
1814 return max;
1817 /* given an edge of a box, return a box containing exactly the points on that
1818 * edge. Note that the box is treated as closed; that is, the bottom and
1819 * right "edges" consist of points (just barely) not in the (half-open) box. */
1820 static BoxType
1821 edge_to_box (const BoxType * box, direction_t expand_dir)
1823 BoxType b = *box;
1824 /* narrow box down to just the appropriate edge */
1825 switch (expand_dir)
1827 case NORTH:
1828 b.Y2 = b.Y1;
1829 break;
1830 case EAST:
1831 b.X1 = b.X2;
1832 break;
1833 case SOUTH:
1834 b.Y1 = b.Y2;
1835 break;
1836 case WEST:
1837 b.X2 = b.X1;
1838 break;
1839 default:
1840 assert (0);
1842 /* treat b as *closed* instead of half-closed, by adding one to
1843 * the (normally-open) bottom and right edges. */
1844 b.X2++;
1845 b.Y2++;
1846 /* done! */
1847 return b;
1850 /* limit the specified expansion region so that it just touches the
1851 * given limit. Returns the limited region (which may be invalid). */
1852 static BoxType
1853 limit_region (BoxType region, edge_t * e, BoxType lbox)
1855 ROTATEBOX_TO_NORTH (region, e->expand_dir);
1856 ROTATEBOX_TO_NORTH (lbox, e->expand_dir);
1857 /* north case: */
1858 assert (lbox.X1 <= region.X2);
1859 assert (lbox.X2 >= region.X1);
1860 region.Y1 = lbox.Y2;
1861 /* now rotate back */
1862 ROTATEBOX_FROM_NORTH (region, e->expand_dir);
1863 return region;
1866 struct broken_boxes
1868 BoxType left, center, right;
1869 Boolean is_valid_left, is_valid_center, is_valid_right;
1872 static struct broken_boxes
1873 break_box_edge (const BoxType * original, direction_t which_edge,
1874 routebox_t * breaker)
1876 BoxType origbox, breakbox;
1877 struct broken_boxes result;
1879 assert (original && breaker);
1881 origbox = *original;
1882 breakbox = bloat_routebox (breaker);
1883 ROTATEBOX_TO_NORTH (origbox, which_edge);
1884 ROTATEBOX_TO_NORTH (breakbox, which_edge);
1885 result.right.Y1 = result.right.Y2 = result.center.Y1 = result.center.Y2 =
1886 result.left.Y1 = result.left.Y2 = origbox.Y1;
1887 /* validity of breaker */
1888 assert (breakbox.X1 < origbox.X2 && breakbox.X2 > origbox.X1);
1889 /* left edge piece */
1890 result.left.X1 = origbox.X1;
1891 result.left.X2 = breakbox.X1;
1892 /* center (ie blocked) edge piece */
1893 result.center.X1 = MAX (breakbox.X1, origbox.X1);
1894 result.center.X2 = MIN (breakbox.X2, origbox.X2);
1895 /* right edge piece */
1896 result.right.X1 = breakbox.X2;
1897 result.right.X2 = origbox.X2;
1898 /* validity: */
1899 result.is_valid_left = (result.left.X1 < result.left.X2);
1900 result.is_valid_center = (result.center.X1 < result.center.X2);
1901 result.is_valid_right = (result.right.X1 < result.right.X2);
1902 /* rotate back */
1903 ROTATEBOX_FROM_NORTH (result.left, which_edge);
1904 ROTATEBOX_FROM_NORTH (result.center, which_edge);
1905 ROTATEBOX_FROM_NORTH (result.right, which_edge);
1906 /* done */
1907 return result;
1910 #ifndef NDEBUG
1911 static int
1912 share_edge (const BoxType * child, const BoxType * parent)
1914 return
1915 (child->X1 == parent->X2 || child->X2 == parent->X1 ||
1916 child->Y1 == parent->Y2 || child->Y2 == parent->Y1) &&
1917 ((parent->X1 <= child->X1 && child->X2 <= parent->X2) ||
1918 (parent->Y1 <= child->Y1 && child->Y2 <= parent->Y2));
1920 static int
1921 edge_intersect (const BoxType * child, const BoxType * parent)
1923 return
1924 (child->X1 <= parent->X2) && (child->X2 >= parent->X1) &&
1925 (child->Y1 <= parent->Y2) && (child->Y2 >= parent->Y1);
1927 #endif
1929 /* area is the expansion area, on layer group 'group'. 'parent' is the
1930 * immediately preceding expansion area, for backtracing. 'lastarea' is
1931 * the last expansion area created, we string these together in a loop
1932 * so we can remove them all easily at the end. */
1933 static routebox_t *
1934 CreateExpansionArea (const BoxType * area, Cardinal group,
1935 routebox_t * parent,
1936 Boolean relax_edge_requirements, edge_t * src_edge)
1938 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
1939 assert (area && parent);
1940 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2);
1941 rb->group = group;
1942 rb->type = EXPANSION_AREA;
1943 rb->cost_point = src_edge->cost_point;
1944 rb->cost = src_edge->cost_to_point;
1945 /* should always share edge with parent */
1946 assert (relax_edge_requirements ? edge_intersect (&rb->box, &parent->box)
1947 : share_edge (&rb->box, &parent->box));
1948 rb->parent.expansion_area = route_parent (parent);
1949 assert (relax_edge_requirements ? edge_intersect (&rb->box, &parent->box)
1950 : share_edge (&rb->box, &parent->box));
1951 if (rb->parent.expansion_area->flags.orphan)
1952 RB_up_count (rb->parent.expansion_area);
1953 rb->flags.orphan = 1;
1954 rb->augStyle = AutoRouteParameters.augStyle;
1955 InitLists (rb);
1956 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
1957 showroutebox (rb);
1958 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
1959 return rb;
1962 Boolean
1963 no_loops (routebox_t * chain, routebox_t * rb)
1965 while (!rb->flags.source)
1967 rb = rb->parent.expansion_area;
1968 if (rb == chain)
1969 return False;
1971 return True;
1974 /*------ FindBlocker ------*/
1975 struct FindBlocker_info
1977 edge_t *expansion_edge;
1978 BDimension maxbloat;
1979 routebox_t *blocker;
1980 LocationType min_dist;
1981 BoxType north_box;
1982 Boolean not_via;
1985 /* helper methods for __FindBlocker */
1986 static int
1987 __FindBlocker_rect_in_reg (const BoxType * box, void *cl)
1989 struct FindBlocker_info *fbi = (struct FindBlocker_info *) cl;
1990 routebox_t *rb = (routebox_t *) box;
1991 BoxType rbox;
1992 rbox = bloat_routebox ((routebox_t *) box);
1993 ROTATEBOX_TO_NORTH (rbox, fbi->expansion_edge->expand_dir);
1994 if (rbox.X2 <= fbi->north_box.X1 || rbox.X1 >= fbi->north_box.X2
1995 || rbox.Y1 > fbi->north_box.Y1)
1996 return 0;
1997 if (rbox.Y2 < fbi->north_box.Y1 - fbi->min_dist)
1998 return 0;
1999 /* this is a box; it has to jump through a few more hoops */
2000 if (rb == nonorphan_parent (fbi->expansion_edge->rb))
2001 return 0; /* this is the parent */
2002 if (rb->type == EXPANSION_AREA && fbi->not_via
2003 && fbi->expansion_edge->cost_to_point +
2004 AutoRouteParameters.SearchPenalty < rb->cost)
2006 CheapPointType cp;
2007 cp = closest_point_in_box (&fbi->expansion_edge->cost_point, box);
2008 if (cost_to_point_on_layer
2009 (&fbi->expansion_edge->cost_point, &cp,
2010 rb->group) + fbi->expansion_edge->cost_to_point <
2011 1.2 * (rb->cost +
2012 cost_to_point_on_layer (&rb->cost_point, &cp, rb->group))
2013 && no_loops (rb, fbi->expansion_edge->rb))
2014 return 0; /* this region may cost less from this direction */
2016 /* okay, this is the closest we've found. */
2017 assert (fbi->blocker == NULL
2018 || (fbi->north_box.Y1 - rbox.Y2) <= fbi->min_dist);
2019 fbi->blocker = (routebox_t *) box;
2020 fbi->min_dist = fbi->north_box.Y1 - rbox.Y2;
2021 /* this assert can fail if the minimum keepaway is failed by an element
2022 pin spacing.
2023 assert (fbi->min_dist >= 0);
2025 return 1;
2027 static int
2028 __FindBlocker_reg_in_sea (const BoxType * region, void *cl)
2030 struct FindBlocker_info *fbi = (struct FindBlocker_info *) cl;
2031 BoxType rbox;
2032 rbox = bloat_box (region, fbi->maxbloat);
2033 switch (fbi->expansion_edge->expand_dir)
2035 case WEST:
2036 if (rbox.X2 < fbi->north_box.Y1 - fbi->min_dist ||
2037 -rbox.Y2 > fbi->north_box.X2 ||
2038 -rbox.Y1 < fbi->north_box.X1 || rbox.X1 > fbi->north_box.Y1)
2039 return 0;
2040 return 1;
2041 case SOUTH:
2042 if (-rbox.Y1 < fbi->north_box.Y1 - fbi->min_dist ||
2043 -rbox.X2 > fbi->north_box.X2 ||
2044 -rbox.X1 < fbi->north_box.X1 || -rbox.Y2 > fbi->north_box.Y1)
2045 return 0;
2046 return 1;
2047 case EAST:
2048 if (-rbox.X1 < fbi->north_box.Y1 - fbi->min_dist ||
2049 rbox.Y1 > fbi->north_box.X2 ||
2050 rbox.Y2 < fbi->north_box.X1 || -rbox.X2 > fbi->north_box.Y1)
2051 return 0;
2052 return 1;
2053 case NORTH:
2054 if (rbox.Y2 < fbi->north_box.Y1 - fbi->min_dist ||
2055 rbox.X1 > fbi->north_box.X2 ||
2056 rbox.X2 < fbi->north_box.X1 || rbox.Y1 > fbi->north_box.Y1)
2057 return 0;
2058 return 1;
2059 default:
2060 assert (0);
2062 return 1;
2065 /* main FindBlocker routine. Returns NULL if no neighbor in the
2066 * requested direction.
2067 * - region is closed on all edges -
2069 routebox_t *
2070 FindBlocker (rtree_t * rtree, edge_t * e, BDimension maxbloat)
2072 struct FindBlocker_info fbi;
2073 BoxType sbox;
2075 fbi.expansion_edge = e;
2076 fbi.maxbloat = maxbloat;
2077 fbi.blocker = NULL;
2078 fbi.min_dist = MAX_COORD;
2079 fbi.north_box = e->rb->box;
2080 fbi.not_via = !e->rb->flags.is_via;
2082 sbox = bloat_box (&e->rb->box, maxbloat);
2083 switch (e->expand_dir)
2085 case NORTH:
2086 sbox.Y1 = -MAX_COORD;
2087 break;
2088 case EAST:
2089 sbox.X2 = MAX_COORD;
2090 break;
2091 case SOUTH:
2092 sbox.Y2 = MAX_COORD;
2093 break;
2094 case WEST:
2095 sbox.X1 = -MAX_COORD;
2096 break;
2097 default:
2098 assert (0);
2100 ROTATEBOX_TO_NORTH (fbi.north_box, e->expand_dir);
2101 r_search (rtree, &sbox,
2102 __FindBlocker_reg_in_sea, __FindBlocker_rect_in_reg, &fbi);
2103 return fbi.blocker;
2106 /* ------------ */
2108 struct fio_info
2110 edge_t *edge;
2111 routebox_t *intersect;
2112 jmp_buf env;
2113 BoxType north_box;
2116 static int
2117 fio_rect_in_reg (const BoxType * box, void *cl)
2119 struct fio_info *fio = (struct fio_info *) cl;
2120 routebox_t *rb;
2121 BoxType rbox;
2122 rbox = bloat_routebox ((routebox_t *) box);
2123 ROTATEBOX_TO_NORTH (rbox, fio->edge->expand_dir);
2124 if (rbox.X2 <= fio->north_box.X1 || rbox.X1 >= fio->north_box.X2 ||
2125 rbox.Y1 > fio->north_box.Y1 || rbox.Y2 < fio->north_box.Y1)
2126 return 0;
2127 /* this is a box; it has to jump through a few more hoops */
2128 /* everything on same net is ignored */
2129 rb = (routebox_t *) box;
2130 assert (rb == nonorphan_parent (rb));
2131 if (rb == nonorphan_parent (fio->edge->rb))
2132 return 0;
2133 /* okay, this is an intersector! */
2134 fio->intersect = rb;
2135 longjmp (fio->env, 1); /* skip to the end! */
2136 return 1; /* never reached */
2139 static routebox_t *
2140 FindIntersectingObstacle (rtree_t * rtree, edge_t * e, BDimension maxbloat)
2142 struct fio_info fio;
2143 BoxType sbox;
2145 fio.edge = e;
2146 fio.intersect = NULL;
2147 fio.north_box = e->rb->box;
2149 sbox = bloat_box (&e->rb->box, maxbloat);
2150 /* exclude equality point from search depending on expansion direction */
2151 switch (e->expand_dir)
2153 case NORTH:
2154 case SOUTH:
2155 sbox.X1 += 1;
2156 sbox.X2 -= 1;
2157 break;
2158 case EAST:
2159 case WEST:
2160 sbox.Y1 += 1;
2161 sbox.Y2 -= 1;
2162 break;
2163 default:
2164 assert (0);
2166 ROTATEBOX_TO_NORTH (fio.north_box, e->expand_dir);
2167 if (setjmp (fio.env) == 0)
2168 r_search (rtree, &sbox, NULL, fio_rect_in_reg, &fio);
2169 return fio.intersect;
2172 /* ------------ */
2174 struct foib_info
2176 const BoxType *box;
2177 BDimension maxbloat;
2178 routebox_t *intersect;
2179 jmp_buf env;
2181 static int
2182 foib_check (const BoxType * region_or_box, struct foib_info *foib,
2183 Boolean is_region)
2185 BoxType rbox;
2186 rbox = is_region ? bloat_box (region_or_box, foib->maxbloat) :
2187 bloat_routebox ((routebox_t *) region_or_box);
2188 if (!box_intersect (&rbox, foib->box))
2189 return 0;
2190 if (!is_region)
2192 /* this is an intersector! */
2193 foib->intersect = (routebox_t *) region_or_box;
2194 longjmp (foib->env, 1); /* skip to the end! */
2196 return 1;
2198 static int
2199 foib_reg_in_sea (const BoxType * region, void *cl)
2201 return foib_check (region, (struct foib_info *) cl, True);
2203 static int
2204 foib_rect_in_reg (const BoxType * box, void *cl)
2206 return foib_check (box, (struct foib_info *) cl, False);
2208 static routebox_t *
2209 FindOneInBox (rtree_t * rtree, const BoxType * box, BDimension maxbloat)
2211 struct foib_info foib;
2213 foib.box = box;
2214 foib.maxbloat = maxbloat;
2215 foib.intersect = NULL;
2217 if (setjmp (foib.env) == 0)
2218 r_search (rtree, NULL, foib_reg_in_sea, foib_rect_in_reg, &foib);
2219 return foib.intersect;
2222 static int
2223 ftherm_rect_in_reg (const BoxType * box, void *cl)
2225 routebox_t *rbox = (routebox_t *) box;
2226 struct rb_info *ti = (struct rb_info *) cl;
2228 if (rbox->type == PIN || rbox->type == VIA || rbox->type == VIA_SHADOW)
2230 ti->winner = rbox;
2231 longjmp (ti->env, 1);
2233 return 0;
2236 /* check for a pin or via target that a polygon can just use a thermal to connect to */
2237 static routebox_t *
2238 FindThermable (rtree_t * rtree, const BoxType * box)
2240 struct rb_info info;
2242 info.winner = NULL;
2243 if (setjmp (info.env) == 0)
2244 r_search (rtree, box, NULL, ftherm_rect_in_reg, &info);
2245 return info.winner;
2248 /* create a new edge for every edge of the given routebox (e->rb) and
2249 * put the result edges in result_vec. */
2250 void
2251 ExpandAllEdges (edge_t * e, vector_t * result_vec,
2252 cost_t cost_penalty_in_box, rtree_t * targets)
2254 CheapPointType costpoint;
2255 cost_t cost;
2256 int i;
2257 assert (__edge_is_good (e));
2258 assert (e->flags.expand_all_sides);
2259 for (i = 0; i < 4; i++)
2260 { /* for all directions */
2261 switch (i)
2262 { /* assign appropriate cost point */
2263 case NORTH:
2264 costpoint.X = e->cost_point.X;
2265 costpoint.Y = e->rb->box.Y1;
2266 break;
2267 case EAST:
2268 costpoint.X = e->rb->box.X2;
2269 costpoint.Y = e->cost_point.Y;
2270 break;
2271 case SOUTH:
2272 costpoint.X = e->cost_point.X;
2273 costpoint.Y = e->rb->box.Y2;
2274 break;
2275 case WEST:
2276 costpoint.X = e->rb->box.X1;
2277 costpoint.Y = e->cost_point.Y;
2278 break;
2279 default:
2280 costpoint.X = 0;
2281 costpoint.Y = 0;
2282 assert (0);
2284 cost = cost_penalty_in_box *
2285 cost_to_point_on_layer (&e->cost_point, &costpoint, e->rb->group);
2286 vector_append (result_vec,
2287 CreateEdge (e->rb, costpoint.X, costpoint.Y,
2288 e->cost_to_point + cost, e->mincost_target,
2289 i, targets));
2291 /* done */
2292 return;
2295 /* find edges that intersect obstacles, and break them into
2296 * intersecting and non-intersecting edges. */
2297 void
2298 BreakEdges (routedata_t * rd, vector_t * edge_vec, rtree_t * targets)
2300 BoxType edgebox, bbox = shrunk_pcb_bounds ();
2301 vector_t *broken_vec = vector_create ();
2302 while (!vector_is_empty (edge_vec))
2304 edge_t *e, *ne;
2305 routebox_t *rb;
2306 /* pop off the top edge */
2307 e = vector_remove_last (edge_vec);
2308 if (e->rb->type == PLANE)
2310 vector_append (broken_vec, e);
2311 continue;
2313 assert (!e->flags.expand_all_sides);
2314 /* check for edges that poke off the edge of the routeable area */
2315 edgebox = edge_to_box (&e->rb->box, e->expand_dir);
2316 if (!box_intersect (&bbox, &edgebox))
2318 /* edge completely off the PCB, skip it. */
2319 DestroyEdge (&e);
2320 continue;
2322 if (!box_in_box (&bbox, &edgebox))
2324 /* edge partially off the PCB, clip it. */
2325 routebox_t *nrb;
2326 BoxType newbox = clip_box (&edgebox, &bbox);
2327 /* 'close' box (newbox is currently half-open) */
2328 newbox.X2--;
2329 newbox.Y2--;
2330 /* okay, create new, clipped, edge */
2331 nrb =
2332 CreateExpansionArea (&newbox, e->rb->group, route_parent (e->rb),
2333 True, e);
2334 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
2335 if (!e->rb->flags.circular)
2336 nrb->flags.source = e->rb->flags.source;
2337 nrb->flags.nobloat = e->rb->flags.nobloat;
2338 /* adjust cost */
2339 ne->cost_to_point = e->rb->flags.source ? e->cost_to_point :
2340 e->cost_to_point +
2341 (CONFLICT_PENALTY (nonorphan_parent (e->rb)) *
2342 (ne->cost_to_point - e->cost_to_point));
2343 assert (__edge_is_good (ne));
2344 /* replace e with ne and continue. */
2345 DestroyEdge (&e);
2346 e = ne;
2347 edgebox = edge_to_box (&e->rb->box, e->expand_dir);
2349 assert (box_intersect (&bbox, &edgebox));
2350 assert (box_in_box (&bbox, &edgebox));
2351 /* find an intersecting obstacle, and then break edge on it. */
2352 rb = FindIntersectingObstacle (rd->layergrouptree[e->rb->group],
2353 e, rd->max_bloat);
2354 assert (__edge_is_good (e));
2355 if (rb == NULL)
2356 { /* no intersecting obstacle, this baby's good! */
2357 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGE_BOXES)
2358 showroutebox (e->rb);
2359 printf ("GOOD EDGE FOUND!\n");
2360 #endif
2361 assert (__edge_is_good (e));
2362 vector_append (broken_vec, e);
2364 else
2365 { /* rb has an intersecting obstacle. break this in three pieces */
2366 struct broken_boxes r =
2367 break_box_edge (&e->rb->box, e->expand_dir, rb);
2368 routebox_t *parent;
2369 int i;
2371 /* "canonical parent" is the original source */
2372 parent = route_parent (e->rb);
2373 assert (parent->underlying || parent->flags.is_via ||
2374 parent->type != EXPANSION_AREA);
2376 for (i = 0; i < 2; i++)
2377 if (i ? r.is_valid_left : r.is_valid_right)
2379 routebox_t *nrb = CreateExpansionArea (i ? &r.left : &r.right,
2380 e->rb->group, parent,
2381 False, e);
2382 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
2383 if (!e->rb->flags.circular)
2384 nrb->flags.source = e->rb->flags.source;
2385 nrb->flags.nobloat = e->rb->flags.nobloat;
2386 /* adjust cost */
2387 ne->cost_to_point = e->rb->flags.source ? e->cost_to_point :
2388 e->cost_to_point +
2389 (CONFLICT_PENALTY (nonorphan_parent (e->rb)) *
2390 (ne->cost_to_point - e->cost_to_point));
2391 assert (__edge_is_good (ne));
2392 vector_append (edge_vec, ne);
2394 /* center edge is "interior" to obstacle */
2395 /* don't bother adding if this is a source-interior edge */
2396 /* or an expansion edge or the conflict is fixed */
2397 if (r.is_valid_center)
2399 /* an expansion area is not really an obstacle */
2400 if (rb->type == EXPANSION_AREA)
2402 routebox_t *nrb = CreateExpansionArea (&r.center,
2403 e->rb->group, parent,
2404 False, e);
2405 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
2406 nrb->flags.nobloat = e->rb->flags.nobloat;
2407 ne->cost_to_point =
2408 e->cost_to_point +
2409 (e->rb->flags.
2410 source ? 0 : (CONFLICT_PENALTY (nonorphan_parent (e->rb))
2411 * (ne->cost_to_point - e->cost_to_point)));
2412 assert (__edge_is_good (ne));
2413 vector_append (broken_vec, ne);
2415 else if (!rb->flags.source && (!rb->flags.fixed
2416 || rb->flags.target)
2417 && AutoRouteParameters.with_conflicts)
2419 ne = CreateEdgeWithConflicts (&r.center, rb, e,
2420 CONFLICT_PENALTY
2421 (nonorphan_parent (e->rb)),
2422 targets);
2423 assert (__edge_is_good (ne));
2424 vector_append (broken_vec, ne);
2426 /* we still want to hit targets if routing without conflicts
2427 * since a target is not really a conflict
2429 else if (rb->flags.target) /* good news */
2431 routebox_t *nrb = CreateExpansionArea (&r.center,
2432 e->rb->group, parent,
2433 False, e);
2434 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, rb);
2435 nrb->flags.nobloat = e->rb->flags.nobloat;
2436 ne->cost_to_point =
2437 e->cost_to_point +
2438 e->rb->flags.
2439 source ? 0 : (CONFLICT_PENALTY (nonorphan_parent (e->rb))
2440 * (ne->cost_to_point - e->cost_to_point));
2441 assert (__edge_is_good (ne));
2442 vector_append (broken_vec, ne);
2445 DestroyEdge (&e);
2447 /* done with this edge */
2449 /* all good edges are now on broken_vec list. */
2450 /* Transfer them back to edge_vec */
2451 assert (vector_size (edge_vec) == 0);
2452 vector_append_vector (edge_vec, broken_vec);
2453 vector_destroy (&broken_vec);
2454 /* done! */
2455 return;
2458 /*--------------------------------------------------------------------
2459 * Route-tracing code: once we've got a path of expansion boxes, trace
2460 * a line through them to actually create the connection.
2462 static void
2463 RD_DrawThermal (routedata_t * rd, LocationType X, LocationType Y,
2464 Cardinal group, Cardinal layer, routebox_t * subnet,
2465 Boolean is_bad)
2467 routebox_t *rb;
2468 rb = (routebox_t *) malloc (sizeof (*rb));
2469 init_const_box (rb, X, Y, X + 1, Y + 1);
2470 rb->group = group;
2471 rb->layer = layer;
2472 rb->flags.fixed = 0;
2473 rb->flags.is_bad = is_bad;
2474 rb->flags.is_odd = AutoRouteParameters.is_odd;
2475 rb->flags.circular = 0;
2476 rb->augStyle = AutoRouteParameters.augStyle;
2477 rb->type = PLANE;
2478 InitLists (rb);
2479 MergeNets (rb, subnet, NET);
2480 MergeNets (rb, subnet, SUBNET);
2483 static void
2484 RD_DrawVia (routedata_t * rd, LocationType X, LocationType Y,
2485 BDimension radius, routebox_t * subnet, Boolean is_bad)
2487 routebox_t *rb, *first_via = NULL;
2488 int i;
2489 /* a via cuts through every layer group */
2490 for (i = 0; i < max_layer; i++)
2492 if (!is_layer_group_active[i])
2493 continue;
2494 rb = (routebox_t *) malloc (sizeof (*rb));
2495 init_const_box (rb,
2496 /*X1 */ X - radius, /*Y1 */ Y - radius,
2497 /*X2 */ X + radius, /*Y2 */ Y + radius);
2498 rb->group = i;
2499 rb->flags.fixed = 0; /* indicates that not on PCB yet */
2500 rb->flags.is_odd = AutoRouteParameters.is_odd;
2501 rb->flags.is_bad = is_bad;
2502 rb->flags.circular = True;
2503 rb->augStyle = AutoRouteParameters.augStyle;
2504 if (first_via == NULL)
2506 rb->type = VIA;
2507 rb->parent.via = NULL; /* indicates that not on PCB yet */
2508 first_via = rb;
2509 /* only add the first via to mtspace, not the shadows too */
2510 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
2511 rb->augStyle->style->Keepaway);
2513 else
2515 rb->type = VIA_SHADOW;
2516 rb->parent.via_shadow = first_via;
2518 InitLists (rb);
2519 /* add these to proper subnet. */
2520 MergeNets (rb, subnet, NET);
2521 MergeNets (rb, subnet, SUBNET);
2522 assert (__routebox_is_good (rb));
2523 /* and add it to the r-tree! */
2524 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
2526 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
2528 gui->set_color (ar_gc, PCB->ViaColor);
2529 gui->fill_circle (ar_gc, X, Y, radius);
2533 static void
2534 RD_DrawLine (routedata_t * rd,
2535 LocationType X1, LocationType Y1, LocationType X2,
2536 LocationType Y2, BDimension halfthick, Cardinal group,
2537 routebox_t * subnet, Boolean is_bad, Boolean is_45)
2539 routebox_t *rb;
2540 /* don't draw zero-length segments. */
2541 if (X1 == X2 && Y1 == Y2)
2542 return;
2543 rb = (routebox_t *) malloc (sizeof (*rb));
2544 assert (is_45 ? (ABS (X2 - X1) == ABS (Y2 - Y1)) /* line must be 45-degrees */
2545 : (X1 == X2 || Y1 == Y2) /* line must be ortho */ );
2546 init_const_box (rb,
2547 /*X1 */ MIN (X1, X2) - halfthick,
2548 /*Y1 */ MIN (Y1, Y2) - halfthick,
2549 /*X2 */ MAX (X1, X2) + halfthick,
2550 /*Y2 */ MAX (Y1, Y2) + halfthick);
2551 rb->group = group;
2552 rb->type = LINE;
2553 rb->parent.line = NULL; /* indicates that not on PCB yet */
2554 rb->flags.fixed = 0; /* indicates that not on PCB yet */
2555 rb->flags.is_odd = AutoRouteParameters.is_odd;
2556 rb->flags.is_bad = is_bad;
2557 rb->flags.nonstraight = is_45;
2558 rb->flags.bl_to_ur = is_45 && (MIN (X1, X2) == X1) != (MIN (Y1, Y2) == Y1);
2559 rb->augStyle = AutoRouteParameters.augStyle;
2560 InitLists (rb);
2561 /* add these to proper subnet. */
2562 MergeNets (rb, subnet, NET);
2563 MergeNets (rb, subnet, SUBNET);
2564 assert (__routebox_is_good (rb));
2565 /* and add it to the r-tree! */
2566 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
2568 if (TEST_FLAG (LIVEROUTEFLAG, PCB))
2570 LayerTypePtr layp = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
2572 gui->set_line_width (ar_gc, 2*halfthick);
2573 gui->set_color (ar_gc, layp->Color);
2574 gui->draw_line (ar_gc, X1, Y1, X2, Y2);
2577 /* and to the via space structures */
2578 if (AutoRouteParameters.use_vias)
2579 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
2580 rb->augStyle->style->Keepaway);
2581 usedGroup[rb->group] = True;
2584 static Boolean
2585 RD_DrawManhattanLine (routedata_t * rd,
2586 const BoxType * box1, const BoxType * box2,
2587 CheapPointType start, CheapPointType end,
2588 BDimension halfthick, Cardinal group,
2589 routebox_t * subnet, Boolean is_bad, Boolean last_was_x)
2591 CheapPointType knee = start;
2592 if (end.X == start.X)
2594 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
2595 subnet, is_bad, False);
2596 return False;
2598 else if (end.Y == start.Y)
2600 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
2601 subnet, is_bad, False);
2602 return True;
2604 /* find where knee belongs */
2605 if (point_in_box (box1, end.X, start.Y)
2606 || point_in_box (box2, end.X, start.Y))
2608 knee.X = end.X;
2609 knee.Y = start.Y;
2611 else
2613 knee.X = start.X;
2614 knee.Y = end.Y;
2616 if ((knee.X == end.X && !last_was_x) &&
2617 (point_in_box (box1, start.X, end.Y)
2618 || point_in_box (box2, start.X, end.Y)))
2620 knee.X = start.X;
2621 knee.Y = end.Y;
2623 assert (point_in_box (box1, knee.X, knee.Y)
2624 || point_in_box (box2, knee.X, knee.Y));
2626 if (1 || !AutoRouteParameters.is_smoothing)
2628 /* draw standard manhattan paths */
2629 RD_DrawLine (rd, start.X, start.Y, knee.X, knee.Y, halfthick, group,
2630 subnet, is_bad, False);
2631 RD_DrawLine (rd, knee.X, knee.Y, end.X, end.Y, halfthick, group,
2632 subnet, is_bad, False);
2634 else
2636 /* draw 45-degree path across knee */
2637 BDimension len45 = MIN (ABS (start.X - end.X), ABS (start.Y - end.Y));
2638 CheapPointType kneestart = knee, kneeend = knee;
2639 if (kneestart.X == start.X)
2640 kneestart.Y += (kneestart.Y > start.Y) ? -len45 : len45;
2641 else
2642 kneestart.X += (kneestart.X > start.X) ? -len45 : len45;
2643 if (kneeend.X == end.X)
2644 kneeend.Y += (kneeend.Y > end.Y) ? -len45 : len45;
2645 else
2646 kneeend.X += (kneeend.X > end.X) ? -len45 : len45;
2647 RD_DrawLine (rd, start.X, start.Y, kneestart.X, kneestart.Y, halfthick,
2648 group, subnet, is_bad, False);
2649 RD_DrawLine (rd, kneestart.X, kneestart.Y, kneeend.X, kneeend.Y,
2650 halfthick, group, subnet, is_bad, True);
2651 RD_DrawLine (rd, kneeend.X, kneeend.Y, end.X, end.Y, halfthick, group,
2652 subnet, is_bad, False);
2654 return (knee.X != end.X);
2657 /* for smoothing, don't pack traces to min clearance gratuitously */
2658 static void
2659 add_clearance (CheapPointType * nextpoint, const BoxType * b)
2661 if (nextpoint->X == b->X1)
2663 if (nextpoint->X +
2664 AutoRouteParameters.augStyle->style->Keepaway < (b->X1 + b->X2) / 2)
2665 nextpoint->X += AutoRouteParameters.augStyle->style->Keepaway;
2666 else
2667 nextpoint->X = (b->X1 + b->X2) / 2;
2669 else if (nextpoint->X == b->X2)
2671 if (nextpoint->X -
2672 AutoRouteParameters.augStyle->style->Keepaway > (b->X1 + b->X2) / 2)
2673 nextpoint->X -= AutoRouteParameters.augStyle->style->Keepaway;
2674 else
2675 nextpoint->X = (b->X1 + b->X2) / 2;
2677 else if (nextpoint->Y == b->Y1)
2679 if (nextpoint->Y +
2680 AutoRouteParameters.augStyle->style->Keepaway < (b->Y1 + b->Y2) / 2)
2681 nextpoint->Y += AutoRouteParameters.augStyle->style->Keepaway;
2682 else
2683 nextpoint->Y = (b->Y1 + b->Y2) / 2;
2685 else if (nextpoint->Y == b->Y2)
2687 if (nextpoint->Y -
2688 AutoRouteParameters.augStyle->style->Keepaway > (b->Y1 + b->Y2) / 2)
2689 nextpoint->Y -= AutoRouteParameters.augStyle->style->Keepaway;
2690 else
2691 nextpoint->Y = (b->Y1 + b->Y2) / 2;
2695 static void
2696 TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target,
2697 routebox_t * subnet, Boolean is_bad)
2699 Boolean last_x = False;
2700 BDimension halfwidth =
2701 HALF_THICK (AutoRouteParameters.augStyle->style->Thick);
2702 BDimension radius =
2703 HALF_THICK (AutoRouteParameters.augStyle->style->Diameter);
2704 CheapPointType lastpoint, nextpoint;
2705 routebox_t *lastpath;
2706 BoxType b;
2708 assert (subnet->augStyle == AutoRouteParameters.augStyle);
2709 /* start from *edge* of target box */
2710 /*XXX: because we round up odd thicknesses, there's the possibility that
2711 * a connecting line end-point might be 0.005 mil off the "real" edge.
2712 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
2713 nextpoint.X = (path->box.X1 + path->box.X2) / 2;
2714 nextpoint.Y = (path->box.Y1 + path->box.Y2) / 2;
2715 nextpoint = closest_point_in_box (&nextpoint,
2716 &path->parent.expansion_area->box);
2717 /* for circular targets, use *inscribed* rectangle so we're sure to
2718 * connect. */
2719 b = path->box;
2720 if (target->flags.circular)
2721 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
2722 nextpoint = closest_point_in_box (&nextpoint, &b);
2723 TargetPoint (&nextpoint, target);
2724 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
2725 showroutebox (path);
2726 printf ("TRACEPOINT start (%d, %d)\n", nextpoint.X, nextpoint.Y);
2727 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
2731 lastpoint = nextpoint;
2732 lastpath = path;
2733 assert (path->type == EXPANSION_AREA);
2734 path = path->parent.expansion_area;
2736 b = path->box;
2737 if (path->flags.circular)
2738 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
2739 assert (b.X1 != b.X2 && b.Y1 != b.Y2); /* need someplace to put line! */
2740 /* find point on path perimeter closest to last point */
2741 /* if source terminal, try to hit a good place */
2742 nextpoint = closest_point_in_box (&lastpoint, &b);
2743 /* leave more clearance if this is a smoothing pass */
2744 if (AutoRouteParameters.is_smoothing)
2745 add_clearance (&nextpoint, &b);
2746 if (path->flags.source)
2747 TargetPoint (&nextpoint, path);
2748 assert (point_in_box (&lastpath->box, lastpoint.X, lastpoint.Y));
2749 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
2750 #if defined(ROUTE_DEBUG)
2751 printf ("TRACEPATH: ");
2752 DumpRouteBox (path);
2753 printf ("TRACEPATH: point (%d, %d) to point (%d, %d) layer %d\n",
2754 lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
2755 path->group);
2756 #endif
2758 /* draw orthogonal lines from lastpoint to nextpoint */
2759 /* knee is placed in lastpath box */
2760 /* should never cause line to leave union of lastpath/path boxes */
2761 last_x = RD_DrawManhattanLine (rd, &lastpath->box, &path->box,
2762 lastpoint, nextpoint, halfwidth,
2763 path->group, subnet, is_bad, last_x);
2764 if (path->flags.is_via)
2765 { /* if via, then add via */
2766 #ifdef ROUTE_VERBOSE
2767 printf (" (vias)");
2768 #endif
2769 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
2770 RD_DrawVia (rd, nextpoint.X, nextpoint.Y, radius, subnet, is_bad);
2773 assert (lastpath->flags.is_via || path->group == lastpath->group);
2775 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
2776 showroutebox (path);
2777 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
2778 /* if this is connected to a plane, draw the thermal */
2779 if (path->type == PLANE)
2780 RD_DrawThermal (rd, nextpoint.X, nextpoint.Y, path->group,
2781 path->layer, subnet, is_bad);
2782 /* when one hop from the source, make an extra path in *this* box */
2783 if (path->parent.expansion_area
2784 && path->parent.expansion_area->flags.source)
2786 /* find special point on source (if it exists) */
2787 if (TargetPoint (&lastpoint, path->parent.expansion_area))
2789 lastpoint = closest_point_in_box (&lastpoint, &path->box);
2790 if (AutoRouteParameters.is_smoothing)
2791 add_clearance (&lastpoint, &path->box);
2792 last_x = RD_DrawManhattanLine (rd, &path->box, &path->box,
2793 nextpoint, lastpoint, halfwidth,
2794 path->group, subnet, is_bad,
2795 last_x);
2796 #if defined(ROUTE_DEBUG)
2797 printf ("TRACEPATH: ");
2798 DumpRouteBox (path);
2799 printf
2800 ("TRACEPATH: (to source) point (%d, %d) to point (%d, %d) layer %d\n",
2801 nextpoint.X, nextpoint.Y, lastpoint.X, lastpoint.Y,
2802 path->group);
2803 #endif
2805 nextpoint = lastpoint;
2809 while (!path->flags.source);
2812 struct routeone_state
2814 /* heap of all candidate expansion edges */
2815 heap_t *workheap;
2816 /* information about the best path found so far. */
2817 routebox_t *best_path, *best_target;
2818 cost_t best_cost;
2821 /* create a fake "edge" used to defer via site searching. */
2822 static void
2823 CreateSearchEdge (struct routeone_state *s, vetting_t * work, edge_t * parent,
2824 routebox_t * rb, conflict_t conflict, rtree_t * targets)
2826 int boxes;
2827 routebox_t *target;
2828 cost_t cost;
2829 assert (__routebox_is_good (rb));
2830 /* find the cheapest target */
2831 boxes = mtsBoxCount (work);
2832 #if 0
2833 target =
2834 mincost_target_to_point (&parent->cost_point, max_layer + 1, targets,
2835 parent->mincost_target);
2836 #else
2837 target = parent->mincost_target;
2838 #endif
2839 cost =
2840 parent->cost_to_point + AutoRouteParameters.ViaCost +
2841 AutoRouteParameters.SearchPenalty * boxes +
2842 cost_to_layerless_box (&rb->cost_point, 0, &target->box);
2843 if (cost < s->best_cost)
2845 edge_t *ne;
2846 ne = malloc (sizeof (*ne));
2847 assert (ne);
2848 ne->flags.via_search = 1;
2849 ne->rb = rb;
2850 if (rb->flags.orphan)
2851 RB_up_count (rb);
2852 ne->work = work;
2853 ne->mincost_target = target;
2854 ne->flags.via_conflict_level = conflict;
2855 ne->cost_to_point = parent->cost_to_point;
2856 ne->cost_point = parent->cost_point;
2857 ne->cost = cost;
2858 heap_insert (s->workheap, ne->cost, ne);
2860 else
2862 mtsFreeWork (&work);
2866 static void
2867 add_or_destroy_edge (struct routeone_state *s, edge_t * e)
2869 e->cost = edge_cost (e, s->best_cost);
2870 assert (__edge_is_good (e));
2871 assert (is_layer_group_active[e->rb->group]);
2872 if (e->cost < s->best_cost)
2873 heap_insert (s->workheap, e->cost, e);
2874 else
2875 DestroyEdge (&e);
2878 static void
2879 best_path_candidate (struct routeone_state *s,
2880 edge_t * e, routebox_t * best_target)
2882 e->cost = edge_cost (e, EXPENSIVE);
2883 if (s->best_path == NULL || e->cost < s->best_cost)
2885 #if defined(ROUTE_DEBUG)
2886 printf ("New best path seen! cost = %f\n", e->cost);
2887 #endif
2888 /* new best path! */
2889 if (s->best_path && s->best_path->flags.orphan)
2890 RB_down_count (s->best_path);
2891 s->best_path = e->rb;
2892 s->best_target = best_target;
2893 s->best_cost = e->cost;
2894 assert (s->best_cost >= 0);
2895 /* don't free this when we destroy edge! */
2896 if (s->best_path->flags.orphan)
2897 RB_up_count (s->best_path);
2902 /* vectors for via site candidates (see mtspace.h) */
2903 struct routeone_via_site_state
2905 vector_t *free_space_vec;
2906 vector_t *lo_conflict_space_vec;
2907 vector_t *hi_conflict_space_vec;
2910 void
2911 add_via_sites (struct routeone_state *s,
2912 struct routeone_via_site_state *vss,
2913 mtspace_t * mtspace, routebox_t * within,
2914 conflict_t within_conflict_level, edge_t * parent_edge,
2915 rtree_t * targets, BDimension shrink)
2917 int radius, keepaway;
2918 vetting_t *work;
2919 BoxType region = shrink_box (&within->box, shrink);
2921 radius = HALF_THICK (AutoRouteParameters.augStyle->style->Diameter);
2922 keepaway = AutoRouteParameters.augStyle->style->Keepaway;
2923 assert (AutoRouteParameters.use_vias);
2924 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
2925 XXX: routing with conflicts may poke over edge. */
2927 if (region.X2 <= region.X1 || region.Y2 <= region.Y1)
2928 return;
2929 //showbox (region, 1, max_layer + COMPONENT_LAYER);
2930 work = mtspace_query_rect (mtspace, &region, radius, keepaway,
2931 NULL, vss->free_space_vec,
2932 vss->lo_conflict_space_vec,
2933 vss->hi_conflict_space_vec,
2934 AutoRouteParameters.is_odd,
2935 AutoRouteParameters.with_conflicts);
2936 if (!work)
2937 return;
2938 CreateSearchEdge (s, work, parent_edge, within, within_conflict_level,
2939 targets);
2942 void
2943 do_via_search (edge_t * search, struct routeone_state *s,
2944 struct routeone_via_site_state *vss, mtspace_t * mtspace,
2945 rtree_t * targets)
2947 int i, j, count = 0;
2948 int radius, keepaway;
2949 vetting_t *work;
2950 routebox_t *within;
2951 conflict_t within_conflict_level;
2953 radius = HALF_THICK (AutoRouteParameters.augStyle->style->Diameter);
2954 keepaway = AutoRouteParameters.augStyle->style->Keepaway;
2955 work = mtspace_query_rect (mtspace, NULL, 0, 0,
2956 search->work, vss->free_space_vec,
2957 vss->lo_conflict_space_vec,
2958 vss->hi_conflict_space_vec,
2959 AutoRouteParameters.is_odd,
2960 AutoRouteParameters.with_conflicts);
2961 within = search->rb;
2962 within_conflict_level = search->flags.via_conflict_level;
2963 for (i = 0; i < 3; i++)
2965 vector_t *v =
2966 (i == NO_CONFLICT ? vss->free_space_vec :
2967 i == LO_CONFLICT ? vss->lo_conflict_space_vec :
2968 i == HI_CONFLICT ? vss->hi_conflict_space_vec : NULL);
2969 assert (v);
2970 while (!vector_is_empty (v))
2972 BoxType cliparea;
2973 BoxType *area = vector_remove_last (v);
2974 if (!(i == NO_CONFLICT || AutoRouteParameters.with_conflicts))
2976 free (area);
2977 continue;
2979 /* answers are bloated by radius + keepaway */
2980 cliparea = shrink_box (area, radius + keepaway);
2981 cliparea.X2 += 1;
2982 cliparea.Y2 += 1;
2983 free (area);
2984 assert (__box_is_good (&cliparea));
2985 count++;
2986 for (j = 0; j < max_layer; j++)
2988 edge_t *ne;
2989 if (j == within->group)
2990 continue;
2991 if (!is_layer_group_active[j])
2992 continue;
2993 ne = CreateViaEdge (&cliparea, j, within, search,
2994 within_conflict_level, i, targets);
2995 add_or_destroy_edge (s, ne);
2999 /* prevent freeing of work when this edge is destroyed */
3000 search->flags.via_search = 0;
3001 if (!work)
3002 return;
3003 CreateSearchEdge (s, work, search, within, within_conflict_level, targets);
3004 assert (vector_is_empty (vss->free_space_vec));
3005 assert (vector_is_empty (vss->lo_conflict_space_vec));
3006 assert (vector_is_empty (vss->hi_conflict_space_vec));
3009 struct routeone_status
3011 Boolean found_route;
3012 int route_had_conflicts;
3013 cost_t best_route_cost;
3014 Boolean net_completely_routed;
3017 static struct routeone_status
3018 RouteOne (routedata_t * rd, routebox_t * from, routebox_t * to, int max_edges)
3020 struct routeone_status result;
3021 routebox_t *p;
3022 int seen, i;
3023 const BoxType **target_list;
3024 int num_targets;
3025 rtree_t *targets;
3026 /* vector of source edges for filtering */
3027 vector_t *source_vec;
3028 /* vector of expansion areas to be eventually removed from r-tree */
3029 vector_t *area_vec;
3030 /* vector of "touched" fixed regions to be reset upon completion */
3031 vector_t *touched_vec;
3032 /* working vector */
3033 vector_t *edge_vec;
3035 struct routeone_state s;
3036 struct routeone_via_site_state vss;
3038 assert (rd && from);
3039 /* no targets on to/from net need keepaway areas */
3040 LIST_LOOP (from, same_net, p);
3041 p->flags.nobloat = 1;
3042 END_LOOP;
3043 /* set 'source' flags */
3044 LIST_LOOP (from, same_subnet, p);
3045 if (!p->flags.nonstraight)
3046 p->flags.source = 1;
3047 END_LOOP;
3049 /* count up the targets */
3050 num_targets = 0;
3051 seen = 0;
3052 /* remove source/target flags from non-straight obstacles, because they
3053 * don't fill their bounding boxes and so connecting to them
3054 * after we've routed is problematic. Better solution? */
3055 if (to)
3056 { /* if we're routing to a specific target */
3057 if (!to->flags.source)
3058 { /* not already connected */
3059 /* check that 'to' and 'from' are on the same net */
3060 seen = 0;
3061 #ifndef NDEBUG
3062 LIST_LOOP (from, same_net, p);
3063 if (p == to)
3064 seen = 1;
3065 END_LOOP;
3066 #endif
3067 assert (seen); /* otherwise from and to are on different nets! */
3068 /* set target flags only on 'to's subnet */
3069 LIST_LOOP (to, same_subnet, p);
3070 if (!p->flags.nonstraight && is_layer_group_active[p->group])
3072 p->flags.target = 1;
3073 num_targets++;
3075 END_LOOP;
3078 else
3080 /* all nodes on the net but not connected to from are targets */
3081 LIST_LOOP (from, same_net, p);
3082 if (!p->flags.source && is_layer_group_active[p->group]
3083 && !p->flags.nonstraight)
3085 p->flags.target = 1;
3086 num_targets++;
3088 END_LOOP;
3091 /* if no targets, then net is done! reset flags and return. */
3092 if (num_targets == 0)
3094 LIST_LOOP (from, same_net, p);
3095 p->flags.source = p->flags.target = p->flags.nobloat = 0;
3096 END_LOOP;
3097 result.found_route = False;
3098 result.net_completely_routed = True;
3099 result.best_route_cost = 0;
3100 result.route_had_conflicts = 0;
3102 return result;
3104 result.net_completely_routed = False;
3106 /* okay, there's stuff to route */
3107 assert (!from->flags.target);
3108 assert (num_targets > 0);
3109 /* create list of target pointers and from that a r-tree of targets */
3110 target_list = malloc (num_targets * sizeof (*target_list));
3111 i = 0;
3112 LIST_LOOP (from, same_net, p);
3113 if (p->flags.target)
3115 target_list[i++] = &p->box;
3116 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
3117 showroutebox (p);
3118 #endif
3120 END_LOOP;
3121 targets = r_create_tree (target_list, i, 0);
3122 assert (i <= num_targets);
3123 free (target_list);
3125 /* add all sources to a vector (since we need to BreakEdges) */
3126 source_vec = vector_create ();
3127 LIST_LOOP (from, same_subnet, p);
3129 /* we need the test for 'source' because this box may be nonstraight */
3130 if (p->flags.source && is_layer_group_active[p->group])
3132 edge_t *e;
3133 cost_t ns_penalty = 0, ew_penalty = 0;
3134 /* penalize long-side expansion of pads */
3135 if (p->type == PAD)
3137 if (p->box.X2 - p->box.X1 > p->box.Y2 - p->box.Y1)
3138 ns_penalty = p->box.X2 - p->box.X1;
3139 if (p->box.Y2 - p->box.Y1 > p->box.X2 - p->box.X1)
3140 ew_penalty = p->box.Y2 - p->box.Y1;
3142 /* may expand in all directions from source; center edge cost point. */
3143 /* note that planes shouldn't really expand, but we need an edge */
3144 if (p->type != PLANE)
3146 e = CreateEdge (p, (p->box.X1 + p->box.X2) / 2,
3147 p->box.Y1, ns_penalty, NULL, NORTH, targets);
3148 e->cost = edge_cost (e, EXPENSIVE);
3149 vector_append (source_vec, e);
3150 e = CreateEdge (p, (p->box.X1 + p->box.X2) / 2,
3151 p->box.Y2, ns_penalty, NULL, SOUTH, targets);
3152 e->cost = edge_cost (e, EXPENSIVE);
3153 vector_append (source_vec, e);
3154 e = CreateEdge (p, p->box.X2,
3155 (p->box.Y1 + p->box.Y2) / 2,
3156 ew_penalty, NULL, EAST, targets);
3157 e->cost = edge_cost (e, EXPENSIVE);
3158 vector_append (source_vec, e);
3160 e = CreateEdge (p, p->box.X1,
3161 (p->box.Y1 + p->box.Y2) / 2, ew_penalty,
3162 NULL, p->type == PLANE ? EAST : WEST, targets);
3163 e->cost = edge_cost (e, EXPENSIVE);
3164 vector_append (source_vec, e);
3167 END_LOOP;
3168 /* break source edges; some edges may be too near obstacles to be able
3169 * to exit from. */
3170 BreakEdges (rd, source_vec, targets);
3172 /* okay, main expansion-search routing loop. */
3173 /* set up the initial activity heap */
3174 s.workheap = heap_create ();
3175 assert (s.workheap);
3176 while (!vector_is_empty (source_vec))
3178 edge_t *e = vector_remove_last (source_vec);
3179 assert (is_layer_group_active[e->rb->group]);
3180 e->cost = edge_cost (e, EXPENSIVE);
3181 heap_insert (s.workheap, e->cost, e);
3183 vector_destroy (&source_vec);
3184 /* okay, process items from heap until it is empty! */
3185 s.best_path = NULL;
3186 s.best_cost = EXPENSIVE;
3187 area_vec = vector_create ();
3188 edge_vec = vector_create ();
3189 touched_vec = vector_create ();
3190 vss.free_space_vec = vector_create ();
3191 vss.lo_conflict_space_vec = vector_create ();
3192 vss.hi_conflict_space_vec = vector_create ();
3193 while (!heap_is_empty (s.workheap))
3195 edge_t *e = heap_remove_smallest (s.workheap);
3196 if (e->flags.via_search)
3198 if (seen++ <= max_edges)
3199 do_via_search (e, &s, &vss, rd->mtspace, targets);
3200 goto dontexpand;
3202 assert (__edge_is_good (e));
3203 /* we should never add edges on inactive layer groups to the heap. */
3204 assert (is_layer_group_active[e->rb->group]);
3205 /* don't bother expanding this edge if the minimum possible edge cost
3206 * is already larger than the best edge cost we've found. */
3207 if (s.best_path && e->cost > s.best_cost)
3208 goto dontexpand; /* skip this edge */
3209 /* surprisingly it helps to give up and not try too hard to find
3210 * a route! This is not only faster, but results in better routing.
3211 * who would have guessed?
3213 if (seen++ > max_edges)
3214 goto dontexpand;
3215 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
3216 //showedge (e);
3217 #endif
3218 /* for a plane, look for quick connections with thermals or vias */
3219 if (e->rb->type == PLANE)
3221 routebox_t *pin = FindThermable (targets, &e->rb->box);
3222 if (pin)
3224 edge_t *ne;
3225 routebox_t *nrb =
3226 CreateExpansionArea (&pin->box, e->rb->group, e->rb, True, e);
3227 nrb->type = PLANE;
3228 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, pin);
3229 best_path_candidate (&s, ne, pin);
3230 DestroyEdge (&ne);
3232 else
3234 /* add in possible via sites in nrb */
3235 if (AutoRouteParameters.use_vias &&
3236 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
3237 add_via_sites (&s, &vss, rd->mtspace, e->rb, NO_CONFLICT, e,
3238 targets, e->rb->augStyle->style->Diameter);
3240 goto dontexpand; /* planes only connect via thermals */
3242 if (e->flags.is_interior)
3244 assert (AutoRouteParameters.with_conflicts); /* no interior edges unless
3245 routing with conflicts! */
3246 assert (e->rb->underlying);
3247 if (e->rb->underlying->flags.touched)
3248 goto dontexpand; /* already done this one */
3249 /* touch this interior box */
3250 e->rb->underlying->flags.touched = 1;
3251 vector_append (touched_vec, e->rb->underlying);
3252 /* is this a target? */
3253 if (e->rb->underlying->flags.target)
3254 best_path_candidate (&s, e, e->rb->underlying); /* new best path? */
3255 /* don't allow conflicts with fixed edges */
3256 if (e->rb->underlying->flags.fixed)
3257 goto dontexpand;
3258 /* break all edges and come up with a new vector of edges */
3259 assert (__edge_is_good (e));
3260 assert (e->flags.expand_all_sides);
3261 assert (vector_is_empty (edge_vec));
3262 ExpandAllEdges (e, edge_vec, CONFLICT_PENALTY (e->rb->underlying),
3263 targets);
3264 BreakEdges (rd, edge_vec, targets);
3265 /* add broken edges to s.workheap */
3266 while (!vector_is_empty (edge_vec))
3267 add_or_destroy_edge (&s,
3268 (edge_t *) vector_remove_last (edge_vec));
3269 /* add in possible via sites on conflict rect. */
3270 /* note that e->rb should be bloated version of conflict rect */
3271 if (AutoRouteParameters.use_vias &&
3272 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
3273 add_via_sites (&s, &vss, rd->mtspace, e->rb,
3274 CONFLICT_LEVEL (e->rb->underlying), e, targets, 0);
3276 else if (e->flags.is_via)
3277 { /* special case via */
3278 routebox_t *intersecting;
3279 assert (AutoRouteParameters.use_vias);
3280 assert (e->flags.expand_all_sides);
3281 assert (vector_is_empty (edge_vec));
3282 intersecting = FindOneInBox (rd->layergrouptree[e->rb->group],
3283 &e->rb->box, rd->max_bloat);
3284 if (intersecting == NULL)
3286 /* this via candidate is in an open area; add it to r-tree as
3287 * an expansion area */
3288 assert (e->rb->type == EXPANSION_AREA && e->rb->flags.is_via);
3289 assert (r_region_is_empty (rd->layergrouptree[e->rb->group],
3290 &e->rb->box));
3291 r_insert_entry (rd->layergrouptree[e->rb->group], &e->rb->box,
3293 e->rb->flags.orphan = 0; /* not an orphan any more */
3294 /* add to vector of all expansion areas in r-tree */
3295 vector_append (area_vec, e->rb);
3296 /* mark reset refcount to 0, since this is not an orphan any more. */
3297 e->rb->refcount = 0;
3298 /* expand from all four edges! */
3299 for (i = 0; i < 4; i++)
3301 edge_t *ne = CreateEdge2 (e->rb, i, e, targets, NULL);
3302 add_or_destroy_edge (&s, ne);
3305 else
3306 { /* XXX: disabling this causes no via
3307 collisions. */
3308 BoxType a = bloat_routebox (intersecting), b;
3309 edge_t *ne;
3310 int i, j;
3311 /* something intersects this via candidate. split via candidate
3312 * into pieces and add these pieces to the workheap. */
3313 for (i = 0; i < 3; i++)
3315 for (j = 0; j < 3; j++)
3317 b = e->rb->box;
3318 switch (i)
3320 case 0:
3321 b.X2 = MIN (b.X2, a.X1);
3322 break; /* left */
3323 case 1:
3324 b.X1 = MAX (b.X1, a.X1);
3325 b.X2 = MIN (b.X2, a.X2);
3326 break; /*c */
3327 case 2:
3328 b.X1 = MAX (b.X1, a.X2);
3329 break; /* right */
3330 default:
3331 assert (0);
3333 switch (j)
3335 case 0:
3336 b.Y2 = MIN (b.Y2, a.Y1);
3337 break; /* top */
3338 case 1:
3339 b.Y1 = MAX (b.Y1, a.Y1);
3340 b.Y2 = MIN (b.Y2, a.Y2);
3341 break; /*c */
3342 case 2:
3343 b.Y1 = MAX (b.Y1, a.Y2);
3344 break; /* bottom */
3345 default:
3346 assert (0);
3348 /* skip if this box is not valid */
3349 if (!(b.X1 < b.X2 && b.Y1 < b.Y2))
3350 continue;
3351 if (i == 1 && j == 1)
3353 /* this bit of the via space is obstructed. */
3354 if (intersecting->type == EXPANSION_AREA
3355 || intersecting->flags.fixed)
3356 continue; /* skip this bit, it's already been done. */
3357 /* create an edge with conflicts, if enabled */
3358 if (!AutoRouteParameters.with_conflicts)
3359 continue;
3360 ne = CreateEdgeWithConflicts (&b, intersecting, e, 1
3361 /*cost penalty to box */
3362 , targets);
3363 add_or_destroy_edge (&s, ne);
3365 else
3367 /* if this is not the intersecting piece, create a new
3368 * (hopefully unobstructed) via edge and add it back to the
3369 * workheap. */
3370 ne =
3371 CreateViaEdge (&b, e->rb->group,
3372 e->rb->parent.expansion_area, e,
3373 e->flags.via_conflict_level,
3374 NO_CONFLICT
3375 /* value here doesn't matter */
3376 , targets);
3377 add_or_destroy_edge (&s, ne);
3382 /* between the time these edges are inserted and the
3383 * time they are processed, new expansion boxes (which
3384 * conflict with these edges) may be added to the graph!
3385 * w.o vias this isn't a problem because the broken box
3386 * is not an orphan. */
3388 else
3389 { /* create expansion area from edge */
3390 BoxType expand_region; /* next expansion area */
3391 routebox_t *next; /* this is the obstacle limiting the expansion area */
3392 struct broken_boxes bb; /* edges split by the obstacle */
3393 routebox_t *nrb = NULL; /* new route box */
3394 edge_t *ne; /* new edge */
3395 /* the 'expand_dir' edges of the expansion area have to be split.
3396 * this is the parent of those edges */
3397 routebox_t *top_parent = e->rb;
3399 /* expand this edge */
3400 #if defined(ROUTE_DEBUG)
3401 printf ("EXPANDING EDGE %p: cost %f ", e, e->cost_to_point);
3402 switch (e->expand_dir)
3404 case NORTH:
3405 printf ("(X:%d to %d NORTH of %d)\n", e->rb->box.X1,
3406 e->rb->box.X2, e->rb->box.Y1);
3407 break;
3408 case SOUTH:
3409 printf ("(X:%d to %d SOUTH of %d)\n", e->rb->box.X1,
3410 e->rb->box.X2, e->rb->box.Y2);
3411 break;
3412 case WEST:
3413 printf ("(Y:%d to %d WEST of %d)\n", e->rb->box.Y1,
3414 e->rb->box.Y2, e->rb->box.X1);
3415 break;
3416 case EAST:
3417 printf ("(Y:%d to %d EAST of %d)\n", e->rb->box.Y1,
3418 e->rb->box.Y2, e->rb->box.X2);
3419 break;
3421 #endif
3422 next =
3423 FindBlocker (rd->layergrouptree[e->rb->group], e, rd->max_bloat);
3424 /* limit region to next box. */
3425 expand_region = edge_to_infinity_region (e);
3426 if (expand_region.X1 >= expand_region.X2 ||
3427 expand_region.Y1 >= expand_region.Y2)
3429 #ifdef ROUTE_DEBUG
3430 printf ("past pcb edge\n");
3431 #endif
3432 goto dontexpand; /* expansion edge is past PCB edge */
3434 if (next)
3435 expand_region =
3436 limit_region (expand_region, e, bloat_routebox (next));
3437 if (expand_region.X1 > expand_region.X2
3438 || expand_region.Y1 > expand_region.Y2)
3440 #ifdef ROUTE_DEBUG
3441 printf ("copper violates spacing\n");
3442 #endif
3443 goto dontexpand; /* existing copper violates spacing rule */
3446 if (edge_length (&expand_region, (e->expand_dir + 1) % 4) > 0)
3448 assert (edge_length (&expand_region, e->expand_dir) > 0);
3449 /* ooh, a non-zero area expansion region! add it to the r-tree! */
3450 /* create new route box nrb and add it to the tree */
3451 nrb =
3452 CreateExpansionArea (&expand_region, e->rb->group, e->rb,
3453 False, e);
3454 #ifdef ROUTE_DEBUG
3455 DumpRouteBox (nrb);
3456 #endif
3457 r_insert_entry (rd->layergrouptree[nrb->group], &nrb->box, 1);
3458 nrb->flags.orphan = 0; /* not an orphan any more */
3459 /* add to vector of all expansion areas in r-tree */
3460 vector_append (area_vec, nrb);
3461 /* parent of orphan expansion edges on top should be this */
3462 top_parent = nrb;
3463 if (next && next->flags.source)
3464 goto dontexpand;
3465 /* no sense in expanding edges on targets */
3466 if (!next || !next->flags.target)
3468 /* add side edges to the expansion activity heap */
3469 for (i = 1; i < 4; i += 2)
3470 { /* directions +/- 1 */
3471 ne =
3472 CreateEdge2 (nrb, (e->expand_dir + i) % 4, e, targets,
3473 NULL);
3474 add_or_destroy_edge (&s, ne);
3477 /* add in possible via sites in nrb */
3478 if (AutoRouteParameters.use_vias &&
3479 e->cost + AutoRouteParameters.ViaCost < s.best_cost)
3480 add_via_sites (&s, &vss,
3481 rd->mtspace, nrb, NO_CONFLICT, e, targets, 0);
3483 /* if we didn't hit *anything* (i.e. we hit the edge of the board),
3484 * then don't expand any more in this direction. */
3485 if (next == NULL)
3486 goto dontexpand;
3487 if (next->flags.source)
3489 #ifdef ROUTE_DEBUG
3490 printf ("hit source terminal\n");
3491 #endif
3492 goto dontexpand;
3494 /* now deal with blocker... */
3495 /* maybe we've found a target? */
3496 if (next->flags.target)
3498 #ifdef ROUTE_DEBUG
3499 printf ("hit target!\n");
3500 #endif
3501 /* we've won! */
3502 nrb =
3503 CreateExpansionArea (&next->box, e->rb->group, top_parent,
3504 True, e);
3505 /* the expansion area we just created is the target box
3506 * we hit it coming from the e->expand_dir direction, but
3507 * the edge we hit is the opposite one on *this* box
3508 * so be sure to create ne as the new struck edge in order
3509 * to compute the cost right.
3511 /* sometime the minimum cost target is a *different* target,
3512 * because of where the cost point was. But *this* cost is to
3513 * *this* target, so manually set mincost_target before we
3514 * call edge_cost() inside best_path_candidate. */
3515 ne = CreateEdge2 (nrb, (e->expand_dir + 2) % 4, e, NULL, next);
3516 assert (ne->rb == nrb);
3517 best_path_candidate (&s, ne, next); /* new best path? */
3518 DestroyEdge (&ne);
3519 goto dontexpand;
3521 /* split the blocked edge at the obstacle. Add the two
3522 * free edges; the edge that abuts the obstacle is also a
3523 * (high-cost) expansion edge as long as the thing we hit isn't
3524 * an expansion area. If the thing we hit is a target, then
3525 * celebrate! */
3526 bb = break_box_edge (&expand_region, e->expand_dir, next);
3527 /* "left" is in rotate_north coordinates */
3528 if (bb.is_valid_left)
3529 { /* left edge valid? */
3530 nrb =
3531 CreateExpansionArea (&bb.left, e->rb->group, top_parent,
3532 False, e);
3533 #ifdef ROUTE_DEBUG
3534 printf ("left::");
3535 DumpRouteBox (nrb);
3536 #endif
3537 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
3538 #ifdef BREAK_ALL
3539 assert (vector_is_empty (edge_vec));
3540 vector_append (edge_vec, ne);
3541 #else
3542 add_or_destroy_edge (&s, ne);
3543 #endif
3545 /* "right" is in rotate_north coordinates */
3546 if (bb.is_valid_right)
3547 { /* right edge valid? */
3548 nrb =
3549 CreateExpansionArea (&bb.right, e->rb->group, top_parent,
3550 False, e);
3551 #ifdef ROUTE_DEBUG
3552 printf ("right::");
3553 DumpRouteBox (nrb);
3554 #endif
3555 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
3556 #ifdef BREAK_ALL
3557 vector_append (edge_vec, ne);
3558 #else
3559 add_or_destroy_edge (&s, ne);
3560 #endif
3562 #ifdef BREAK_ALL
3563 BreakEdges (rd, edge_vec, targets);
3564 /* add broken edges to s.workheap */
3565 while (!vector_is_empty (edge_vec))
3566 add_or_destroy_edge (&s,
3567 (edge_t *) vector_remove_last (edge_vec));
3568 #endif
3569 if (next->type != EXPANSION_AREA && !next->flags.target
3570 && !next->flags.fixed && AutoRouteParameters.with_conflicts)
3572 edge_t *ne2;
3573 /* is center valid for expansion? (with conflicts) */
3574 assert (bb.is_valid_center); /* how could it not be? */
3575 nrb =
3576 CreateExpansionArea (&bb.center, e->rb->group, top_parent,
3577 False, e);
3578 ne = CreateEdge2 (nrb, e->expand_dir, e, targets, NULL);
3579 /* no penalty to reach conflict box, since we're still outside here */
3580 ne2 =
3581 CreateEdgeWithConflicts (&bb.center, next, ne, 1, targets);
3582 add_or_destroy_edge (&s, ne2);
3583 DestroyEdge (&ne);
3586 dontexpand:
3587 DestroyEdge (&e);
3589 heap_destroy (&s.workheap);
3590 r_destroy_tree (&targets);
3591 assert (vector_is_empty (edge_vec));
3592 vector_destroy (&edge_vec);
3594 /* we should have a path in best_path now */
3595 if (s.best_path)
3597 routebox_t *rb;
3598 #ifdef ROUTE_VERBOSE
3599 printf ("%d:%d RC %.0f", ro++, seen, s.best_cost);
3600 #endif
3601 result.found_route = True;
3602 result.best_route_cost = s.best_cost;
3603 /* determine if the best path had conflicts */
3604 result.route_had_conflicts = 0;
3605 if (AutoRouteParameters.with_conflicts)
3606 for (rb = s.best_path; !rb->flags.source;
3607 rb = rb->parent.expansion_area)
3608 if (rb->underlying)
3610 rb->underlying->flags.is_bad = 1;
3611 result.route_had_conflicts++;
3613 #ifdef ROUTE_VERBOSE
3614 if (result.route_had_conflicts)
3615 printf (" (%d conflicts)", result.route_had_conflicts);
3616 #endif
3617 if (result.route_had_conflicts < AutoRouteParameters.hi_conflict)
3619 /* back-trace the path and add lines/vias to r-tree */
3620 TracePath (rd, s.best_path, s.best_target, from,
3621 result.route_had_conflicts);
3622 MergeNets (from, s.best_target, SUBNET);
3623 RB_down_count (s.best_path); /* free routeboxen along path */
3625 else
3627 #ifdef ROUTE_VERBOSE
3628 printf (" (too many in fact)");
3629 #endif
3630 result.found_route = False;
3632 #ifdef ROUTE_VERBOSE
3633 printf ("\n");
3634 #endif
3636 else
3638 #ifdef ROUTE_VERBOSE
3639 printf ("%d:%d NO PATH FOUND.\n", ro++, seen);
3640 #endif
3641 result.best_route_cost = s.best_cost;
3642 result.found_route = False;
3644 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
3645 LIST_LOOP (from, same_net, p);
3646 p->flags.source = p->flags.target = p->flags.nobloat = 0;
3647 END_LOOP;
3648 /* now remove all expansion areas from the r-tree. */
3649 while (!vector_is_empty (area_vec))
3651 routebox_t *rb = vector_remove_last (area_vec);
3652 assert (!rb->flags.orphan);
3653 r_delete_entry (rd->layergrouptree[rb->group], &rb->box);
3655 vector_destroy (&area_vec);
3656 /* reset flags on touched fixed rects */
3657 while (!vector_is_empty (touched_vec))
3659 routebox_t *rb = vector_remove_last (touched_vec);
3660 assert (rb->flags.touched);
3661 rb->flags.touched = 0;
3663 vector_destroy (&touched_vec);
3665 vector_destroy (&vss.free_space_vec);
3666 vector_destroy (&vss.lo_conflict_space_vec);
3667 vector_destroy (&vss.hi_conflict_space_vec);
3669 return result;
3672 static void
3673 InitAutoRouteParameters (int pass,
3674 AugmentedRouteStyleType * augStyle,
3675 Boolean with_conflicts, Boolean is_smoothing)
3677 /* routing style */
3678 AutoRouteParameters.augStyle = augStyle;
3679 /* costs */
3680 AutoRouteParameters.ViaCost =
3681 50000 + augStyle->style->Diameter * (is_smoothing ? 80 : 10);
3682 AutoRouteParameters.LastConflictPenalty = 500 * pass / passes + 2;
3683 AutoRouteParameters.ConflictPenalty =
3684 5 * AutoRouteParameters.LastConflictPenalty;
3685 AutoRouteParameters.JogPenalty = 1000 * (is_smoothing ? 20 : 4);
3686 AutoRouteParameters.WrongWayPenalty = 2000 * (is_smoothing ? 2 : 4);
3687 AutoRouteParameters.DirectionPenalty = 2;
3688 AutoRouteParameters.SurfacePenalty = 3;
3689 AutoRouteParameters.AwayPenalty = 4;
3690 AutoRouteParameters.MinPenalty = MIN (AutoRouteParameters.DirectionPenalty,
3691 AutoRouteParameters.SurfacePenalty);
3692 AutoRouteParameters.SearchPenalty = 200000;
3693 AutoRouteParameters.NewLayerPenalty = is_smoothing ?
3694 0.5 * EXPENSIVE : 6 * AutoRouteParameters.ViaCost +
3695 AutoRouteParameters.SearchPenalty;
3696 /* other */
3697 AutoRouteParameters.hi_conflict = MAX (passes - pass + 3, 3);
3698 AutoRouteParameters.is_odd = (pass & 1);
3699 AutoRouteParameters.with_conflicts = with_conflicts;
3700 AutoRouteParameters.is_smoothing = is_smoothing;
3701 AutoRouteParameters.rip_always = is_smoothing;
3704 #ifndef NDEBUG
3706 bad_boy (const BoxType * b, void *cl)
3708 routebox_t *box = (routebox_t *) b;
3709 if (box->type == EXPANSION_AREA)
3710 return 1;
3711 return 0;
3714 Boolean
3715 no_expansion_boxes (routedata_t * rd)
3717 int i;
3718 BoxType big;
3719 big.X1 = 0;
3720 big.X2 = MAX_COORD;
3721 big.Y1 = 0;
3722 big.Y2 = MAX_COORD;
3723 for (i = 0; i < max_layer; i++)
3725 if (r_search (rd->layergrouptree[i], &big, NULL, bad_boy, NULL))
3726 return False;
3728 return True;
3730 #endif
3732 struct routeall_status
3734 /* --- for completion rate statistics ---- */
3735 int total_subnets;
3736 /* total subnets routed without conflicts */
3737 int routed_subnets;
3738 /* total subnets routed with conflicts */
3739 int conflict_subnets;
3741 struct routeall_status
3742 RouteAll (routedata_t * rd)
3744 struct routeall_status ras;
3745 struct routeone_status ros;
3746 Boolean rip;
3747 #ifdef NET_HEAP
3748 heap_t *net_heap;
3749 #endif
3750 heap_t *this_pass, *next_pass, *tmp;
3751 routebox_t *net, *p, *pp;
3752 cost_t total_net_cost, last_cost = 0, this_cost = 0;
3753 int i;
3755 /* initialize heap for first pass;
3756 * do smallest area first; that makes
3757 * the subsequent costs more representative */
3758 this_pass = heap_create ();
3759 next_pass = heap_create ();
3760 #ifdef NET_HEAP
3761 net_heap = heap_create ();
3762 #endif
3763 LIST_LOOP (rd->first_net, different_net, net);
3765 float area;
3766 BoxType bb = net->box;
3767 LIST_LOOP (net, same_net, p);
3769 MAKEMIN (bb.X1, p->box.X1);
3770 MAKEMIN (bb.Y1, p->box.Y1);
3771 MAKEMAX (bb.X2, p->box.X2);
3772 MAKEMAX (bb.Y2, p->box.Y2);
3774 END_LOOP;
3775 area = (float) (bb.X2 - bb.X1) * (bb.Y2 - bb.Y1);
3776 heap_insert (this_pass, area, net);
3778 END_LOOP;
3780 /* refinement/finishing passes */
3781 for (i = 0; i <= passes + smoothes; i++)
3783 #ifdef ROUTE_VERBOSE
3784 if (i > 0 && i <= passes)
3785 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i);
3786 else if (i > passes)
3787 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
3788 i - passes);
3789 #endif
3790 ras.total_subnets = ras.routed_subnets = ras.conflict_subnets = 0;
3791 assert (heap_is_empty (next_pass));
3792 while (!heap_is_empty (this_pass))
3794 net = (routebox_t *) heap_remove_smallest (this_pass);
3795 InitAutoRouteParameters (i, net->augStyle, i < passes, i > passes);
3796 if (i > 0)
3798 /* rip up all unfixed traces in this net ? */
3799 if (AutoRouteParameters.rip_always)
3800 rip = True;
3801 else
3803 rip = False;
3804 LIST_LOOP (net, same_net, p);
3805 if (!p->flags.fixed && p->flags.is_bad)
3807 rip = True;
3808 break;
3810 END_LOOP;
3813 LIST_LOOP (net, same_net, p);
3814 if (!p->flags.fixed)
3816 Boolean del;
3817 assert (!p->flags.orphan);
3818 p->flags.is_bad = 0;
3819 if (rip)
3821 RemoveFromNet (p, NET);
3822 RemoveFromNet (p, SUBNET);
3824 if (AutoRouteParameters.use_vias && p->type != VIA_SHADOW)
3826 mtspace_remove (rd->mtspace, &p->box,
3827 p->flags.is_odd ? ODD : EVEN,
3828 p->augStyle->style->Keepaway);
3829 if (!rip)
3830 mtspace_add (rd->mtspace, &p->box,
3831 p->flags.is_odd ? EVEN : ODD,
3832 p->augStyle->style->Keepaway);
3834 if (rip)
3836 if (TEST_FLAG (LIVEROUTEFLAG, PCB)
3837 && (p->type == LINE || p->type == VIA))
3838 EraseRouteBox (p);
3839 del =
3840 r_delete_entry (rd->layergrouptree[p->group],
3841 &p->box);
3842 assert (del);
3844 else
3846 p->flags.is_odd = AutoRouteParameters.is_odd;
3849 END_LOOP;
3850 /* reset to original connectivity */
3851 if (rip)
3852 ResetSubnet (net);
3853 else
3855 heap_insert (next_pass, 0, net);
3856 continue;
3859 /* count number of subnets */
3860 FOREACH_SUBNET (net, p);
3861 ras.total_subnets++;
3862 END_FOREACH (net, p);
3863 /* the first subnet doesn't require routing. */
3864 ras.total_subnets--;
3865 /* and re-route! */
3866 total_net_cost = 0;
3867 /* only route that which isn't fully routed */
3868 if (ras.total_subnets)
3870 /* the loop here ensures that we get to all subnets even if
3871 * some of them are unreachable from the first subnet. */
3872 LIST_LOOP (net, same_net, p);
3874 #ifdef NET_HEAP
3875 /* using a heap allows us to start from smaller objects and
3876 * end at bigger ones. also prefer to start at planes, then pads */
3877 heap_insert (net_heap, (float) (p->box.X2 - p->box.X1) *
3878 (p->box.Y2 - p->box.Y1) * (p->type == PLANE ?
3879 -1 : (p->type ==
3880 PAD ? 1 :
3881 10)), p);
3883 END_LOOP;
3884 while (!heap_is_empty (net_heap))
3886 p = (routebox_t *) heap_remove_smallest (net_heap);
3887 #endif
3888 if (p->flags.fixed && !p->flags.subnet_processed
3889 && p->type != OTHER)
3893 assert (no_expansion_boxes (rd));
3894 ros =
3895 RouteOne (rd, p, NULL,
3896 ((AutoRouteParameters.
3897 is_smoothing ? 2000 : 800) * (i +
3898 1)) *
3899 routing_layers);
3900 total_net_cost += ros.best_route_cost;
3901 if (ros.found_route)
3903 if (ros.route_had_conflicts)
3904 ras.conflict_subnets++;
3905 else
3906 ras.routed_subnets++;
3908 else
3910 /* don't bother trying any other source in this subnet */
3911 LIST_LOOP (p, same_subnet, pp);
3912 pp->flags.subnet_processed = 1;
3913 END_LOOP;
3915 /* note that we can infer nothing about ras.total_subnets based
3916 * on the number of calls to RouteOne, because we may be unable
3917 * to route a net from a particular starting point, but perfectly
3918 * able to route it from some other. */
3920 while (ros.found_route && !ros.net_completely_routed);
3923 #ifndef NET_HEAP
3924 END_LOOP;
3925 #endif
3928 /* Route easiest nets from this pass first on next pass.
3929 * This works best because it's likely that the hardest
3930 * is the last one routed (since it has the most obstacles)
3931 * but it will do no good to rip it up and try it again
3932 * without first changing any of the other routes
3934 heap_insert (next_pass, total_net_cost, net);
3935 if (total_net_cost < EXPENSIVE)
3936 this_cost += total_net_cost;
3937 /* reset subnet_processed flags */
3938 LIST_LOOP (net, same_net, p);
3940 p->flags.subnet_processed = 0;
3942 END_LOOP;
3944 /* swap this_pass and next_pass and do it all over again! */
3945 ro = 0;
3946 assert (heap_is_empty (this_pass));
3947 tmp = this_pass;
3948 this_pass = next_pass;
3949 next_pass = tmp;
3950 /* XXX: here we should update a status bar */
3951 #ifdef ROUTE_VERBOSE
3952 printf
3953 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f\n",
3954 i, ras.routed_subnets, ras.total_subnets, this_cost);
3955 #endif
3956 /* if no conflicts found, skip directly to smoothing pass! */
3957 if (ras.conflict_subnets == 0 && ras.routed_subnets == ras.total_subnets
3958 && i < passes)
3959 i = passes - (smoothes ? 0 : 1);
3960 /* if no changes in a smoothing round, then we're done */
3961 if (this_cost == last_cost && i > passes)
3962 break;
3963 last_cost = this_cost;
3964 this_cost = 0;
3966 Message ("%d of %d nets successfully routed.\n", ras.routed_subnets,
3967 ras.total_subnets);
3969 heap_destroy (&this_pass);
3970 heap_destroy (&next_pass);
3971 #ifdef NET_HEAP
3972 heap_destroy (&net_heap);
3973 #endif
3975 /* no conflicts should be left at the end of the process. */
3976 assert (ras.conflict_subnets == 0);
3978 return ras;
3981 struct fpin_info
3983 PinTypePtr pin;
3984 LocationType X, Y;
3985 jmp_buf env;
3988 static int
3989 fpin_rect (const BoxType * b, void *cl)
3991 PinTypePtr pin = (PinTypePtr) b;
3992 struct fpin_info *info = (struct fpin_info *) cl;
3993 if (pin->X == info->X && pin->Y == info->Y)
3995 info->pin = (PinTypePtr) b;
3996 longjmp (info->env, 1);
3998 return 0;
4001 static int
4002 FindPin (const BoxType * box, PinTypePtr * pin)
4004 struct fpin_info info;
4006 info.pin = NULL;
4007 info.X = box->X1;
4008 info.Y = box->Y1;
4009 if (setjmp (info.env) == 0)
4010 r_search (PCB->Data->pin_tree, box, NULL, fpin_rect, &info);
4011 else
4013 *pin = info.pin;
4014 return PIN_TYPE;
4016 if (setjmp (info.env) == 0)
4017 r_search (PCB->Data->via_tree, box, NULL, fpin_rect, &info);
4018 else
4020 *pin = info.pin;
4021 return VIA_TYPE;
4023 *pin = NULL;
4024 return NO_TYPE;
4028 /* paths go on first 'on' layer in group */
4029 /* returns 'True' if any paths were added. */
4030 Boolean
4031 IronDownAllUnfixedPaths (routedata_t * rd)
4033 Boolean changed = False;
4034 LayerTypePtr layer;
4035 routebox_t *net, *p;
4036 int i;
4037 LIST_LOOP (rd->first_net, different_net, net);
4039 LIST_LOOP (net, same_net, p);
4041 if (!p->flags.fixed)
4043 /* find first on layer in this group */
4044 assert (PCB->LayerGroups.Number[p->group] > 0);
4045 assert (is_layer_group_active[p->group]);
4046 for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group];
4047 i++)
4049 layer = LAYER_PTR (PCB->LayerGroups.Entries[p->group][i]);
4050 if (layer->On)
4051 break;
4053 assert (layer && layer->On); /*at least one layer must be on in this group! */
4054 assert (p->type != EXPANSION_AREA);
4055 if (p->type == LINE)
4057 BDimension halfwidth = HALF_THICK (p->augStyle->style->Thick);
4058 BoxType b;
4059 assert (p->parent.line == NULL);
4060 /* orthogonal; thickness is 2*halfwidth */
4061 /* hace
4062 assert (p->flags.nonstraight ||
4063 p->box.X1 + halfwidth ==
4064 p->box.X2 - halfwidth
4065 || p->box.Y1 + halfwidth ==
4066 p->box.Y2 - halfwidth);
4068 /* flip coordinates, if bl_to_ur */
4069 b = shrink_box (&p->box, halfwidth);
4070 if (p->flags.bl_to_ur)
4072 BDimension t;
4073 t = b.X1;
4074 b.X1 = b.X2;
4075 b.X2 = t;
4077 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
4078 p->parent.line = CreateDrawnLineOnLayer
4079 (layer, b.X1, b.Y1, b.X2, b.Y2,
4080 p->augStyle->style->Thick,
4081 p->augStyle->style->Keepaway * 2,
4082 MakeFlags (AUTOFLAG |
4083 (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG :
4084 0)));
4086 if (p->parent.line)
4088 AddObjectToCreateUndoList (LINE_TYPE, layer,
4089 p->parent.line, p->parent.line);
4090 changed = True;
4093 else if (p->type == VIA || p->type == VIA_SHADOW)
4095 routebox_t *pp =
4096 (p->type == VIA_SHADOW) ? p->parent.via_shadow : p;
4097 BDimension radius = HALF_THICK (pp->augStyle->style->Diameter);
4098 assert (pp->type == VIA);
4099 if (pp->parent.via == NULL)
4101 assert (pp->box.X1 + radius == pp->box.X2 - radius);
4102 assert (pp->box.Y1 + radius == pp->box.Y2 - radius);
4103 pp->parent.via =
4104 CreateNewVia (PCB->Data, pp->box.X1 + radius,
4105 pp->box.Y1 + radius,
4106 pp->augStyle->style->Diameter,
4107 2 * pp->augStyle->style->Keepaway,
4108 0, pp->augStyle->style->Hole, NULL,
4109 MakeFlags (AUTOFLAG));
4110 assert (pp->parent.via);
4111 if (pp->parent.via)
4113 AddObjectToCreateUndoList (VIA_TYPE,
4114 pp->parent.via,
4115 pp->parent.via,
4116 pp->parent.via);
4117 changed = True;
4120 assert (pp->parent.via);
4121 if (p->type == VIA_SHADOW)
4123 p->type = VIA;
4124 p->parent.via = pp->parent.via;
4127 else if (p->type == PLANE)
4129 else
4130 assert (0);
4133 END_LOOP;
4134 /* loop again to place all the thermals now that the vias are down */
4135 LIST_LOOP (net, same_net, p);
4137 if (!p->flags.fixed && p->type == PLANE)
4139 PinTypePtr pin = NULL;
4140 int type = FindPin (&p->box, &pin);
4141 if (pin)
4143 AddObjectToFlagUndoList (type,
4144 pin->Element ? pin->Element : pin,
4145 pin, pin);
4146 ASSIGN_THERM (p->layer, PCB->ThermStyle, pin);
4150 END_LOOP;
4152 END_LOOP;
4153 return changed;
4156 Boolean
4157 AutoRoute (Boolean selected)
4159 Boolean changed = False;
4160 routedata_t *rd;
4161 int i;
4163 if (ar_gc == 0)
4165 ar_gc = gui->make_gc ();
4166 gui->set_line_cap (ar_gc, Round_Cap);
4169 for (i = 0; i < NUM_STYLES; i++)
4171 if (PCB->RouteStyle[i].Thick == 0 ||
4172 PCB->RouteStyle[1].Diameter == 0 ||
4173 PCB->RouteStyle[1].Hole == 0 || PCB->RouteStyle[i].Keepaway == 0)
4175 Message ("You must define proper routing styles\n"
4176 "before auto-routing.\n");
4177 return (False);
4180 if (PCB->Data->RatN == 0)
4181 return (False);
4182 SaveFindFlag (DRCFLAG);
4183 rd = CreateRouteData ();
4185 if (1)
4187 routebox_t *net, *rb, *last;
4188 int i = 0;
4189 /* count number of rats selected */
4190 RAT_LOOP (PCB->Data);
4192 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
4193 i++;
4195 END_LOOP;
4196 #ifdef ROUTE_VERBOSE
4197 printf ("%d nets!\n", i);
4198 #endif
4199 if (i == 0)
4200 goto donerouting; /* nothing to do here */
4201 /* if only one rat selected, do things the quick way. =) */
4202 if (i == 1)
4204 RAT_LOOP (PCB->Data);
4205 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
4207 /* look up the end points of this rat line */
4208 routebox_t *a;
4209 routebox_t *b;
4211 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
4212 line->Point1.Y, line->group1);
4214 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
4215 line->Point2.Y, line->group2);
4216 assert (a != NULL && b != NULL);
4217 assert (a->augStyle == b->augStyle);
4218 /* route exactly one net, without allowing conflicts */
4219 InitAutoRouteParameters (0, a->augStyle, False, True);
4220 changed = RouteOne (rd, a, b, 150000).found_route || changed;
4221 goto donerouting;
4223 END_LOOP;
4225 /* otherwise, munge the netlists so that only the selected rats
4226 * get connected. */
4227 /* first, separate all sub nets into separate nets */
4228 /* note that this code works because LIST_LOOP is clever enough not to
4229 * be fooled when the list is changing out from under it. */
4230 last = NULL;
4231 LIST_LOOP (rd->first_net, different_net, net);
4233 FOREACH_SUBNET (net, rb);
4235 if (last)
4237 last->different_net.next = rb;
4238 rb->different_net.prev = last;
4240 last = rb;
4242 END_FOREACH (net, rb);
4243 LIST_LOOP (net, same_net, rb);
4245 rb->same_net = rb->same_subnet;
4247 END_LOOP;
4248 /* at this point all nets are equal to their subnets */
4250 END_LOOP;
4251 if (last)
4253 last->different_net.next = rd->first_net;
4254 rd->first_net->different_net.prev = last;
4257 /* now merge only those subnets connected by a rat line */
4258 RAT_LOOP (PCB->Data);
4259 if (!selected || TEST_FLAG (SELECTEDFLAG, line))
4261 /* look up the end points of this rat line */
4262 routebox_t *a;
4263 routebox_t *b;
4265 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
4266 line->Point1.Y, line->group1);
4268 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
4269 line->Point2.Y, line->group2);
4270 if (!a || !b)
4272 #ifdef DEBUG_STALE_RATS
4273 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
4274 ASSIGN_FLAG (SELECTEDFLAG, True, line);
4275 DrawRat (line, 0);
4276 #endif /* DEBUG_STALE_RATS */
4277 Message ("The rats nest is stale! Aborting autoroute...\n");
4278 goto donerouting;
4280 /* merge subnets into a net! */
4281 MergeNets (a, b, NET);
4283 END_LOOP;
4284 /* now 'different_net' may point to too many different nets. Reset. */
4285 LIST_LOOP (rd->first_net, different_net, net);
4287 if (!net->flags.touched)
4289 LIST_LOOP (net, same_net, rb);
4290 rb->flags.touched = 1;
4291 END_LOOP;
4293 else /* this is not a "different net"! */
4294 RemoveFromNet (net, DIFFERENT_NET);
4296 END_LOOP;
4297 /* reset "touched" flag */
4298 LIST_LOOP (rd->first_net, different_net, net);
4300 LIST_LOOP (net, same_net, rb);
4302 assert (rb->flags.touched);
4303 rb->flags.touched = 0;
4305 END_LOOP;
4307 END_LOOP;
4309 /* okay, rd's idea of netlist now corresponds to what we want routed */
4310 /* auto-route all nets */
4311 changed = (RouteAll (rd).routed_subnets > 0) || changed;
4312 donerouting:
4313 if (changed)
4314 changed = IronDownAllUnfixedPaths (rd);
4315 DestroyRouteData (&rd);
4316 if (changed)
4318 SaveUndoSerialNumber ();
4320 /* optimize rats, we've changed connectivity a lot. */
4321 DeleteRats (False /*all rats */ );
4322 RestoreUndoSerialNumber ();
4323 AddAllRats (False /*all rats */ , NULL);
4324 RestoreUndoSerialNumber ();
4326 IncrementUndoSerialNumber ();
4328 ClearAndRedrawOutput ();
4330 RestoreFindFlag ();
4331 return (changed);