pcb 4.1.1
An interactive printed circuit board layout editor.

autoroute.c

Go to the documentation of this file.
00001 
00060 #define NET_HEAP 1
00061 #ifdef HAVE_CONFIG_H
00062 #include "config.h"
00063 #endif
00064 
00065 #include "global.h"
00066 
00067 #include <assert.h>
00068 #include <setjmp.h>
00069 
00070 #include "data.h"
00071 #include "macro.h"
00072 #include "autoroute.h"
00073 #include "box.h"
00074 #include "create.h"
00075 #include "draw.h"
00076 #include "error.h"
00077 #include "find.h"
00078 #include "heap.h"
00079 #include "rtree.h"
00080 #include "misc.h"
00081 #include "mtspace.h"
00082 #include "mymem.h"
00083 #include "polygon.h"
00084 #include "rats.h"
00085 #include "remove.h"
00086 #include "thermal.h"
00087 #include "undo.h"
00088 #include "vector.h"
00089 #include "pcb-printf.h"
00090 #include "hid_draw.h"
00091 
00092 #ifdef HAVE_LIBDMALLOC
00093 #include <dmalloc.h>
00094 #endif
00095 
00096 /* #defines to enable some debugging output */
00097 /*
00098 #define ROUTE_VERBOSE
00099 */
00100 
00101 /*
00102 #define ROUTE_DEBUG
00103 //#define DEBUG_SHOW_ROUTE_BOXES
00104 #define DEBUG_SHOW_EXPANSION_BOXES
00105 //#define DEBUG_SHOW_EDGES
00106 //#define DEBUG_SHOW_VIA_BOXES
00107 #define DEBUG_SHOW_TARGETS
00108 #define DEBUG_SHOW_SOURCES
00109 //#define DEBUG_SHOW_ZIGZAG
00110 */
00111 
00112 static direction_t
00113 directionIncrement(direction_t dir)
00114 {
00115   switch(dir)
00116   {
00117   case NORTH:
00118     dir = EAST;
00119     break;
00120   case EAST:
00121     dir = SOUTH;
00122     break;
00123   case SOUTH:
00124     dir = WEST;
00125     break;
00126   case WEST:
00127     dir = NE;
00128     break;
00129   case NE:
00130     dir = SE;
00131     break;
00132   case SE:
00133     dir = SW;
00134     break;
00135   case SW:
00136     dir = NW;
00137     break;
00138   case NW:
00139     dir = ALL;
00140     break;
00141   case ALL:
00142     dir = NORTH;
00143     break;
00144   }
00145 return dir;
00146 }
00147 
00148 #ifdef ROUTE_DEBUG
00149 HID_DRAW *ddraw = NULL;
00150 static hidGC ar_gc = 0;
00151 #endif
00152 
00153 #define EXPENSIVE 3e28
00154 /* round up "half" thicknesses */
00155 #define HALF_THICK(x) (((x)+1)/2)
00156 /* a styles maximum bloat is its keepaway plus the larger of its via radius
00157  * or line half-thickness. */
00158 #define BLOAT(style)\
00159         ((style)->Keepaway + HALF_THICK((style)->Thick))
00160 /* conflict penalty is less for traces laid down during previous pass than
00161  * it is for traces already laid down in this pass. */
00162 #define CONFLICT_LEVEL(rb)\
00163         (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
00164          HI_CONFLICT : LO_CONFLICT )
00165 #define CONFLICT_PENALTY(rb)\
00166         ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
00167          AutoRouteParameters.ConflictPenalty : \
00168          CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
00169          AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass)
00170 
00171 #define _NORTH 1
00172 #define _EAST 2
00173 #define _SOUTH 4
00174 #define _WEST 8
00175 
00176 #define LIST_LOOP(init, which, x) do {\
00177      routebox_t *__next_one__ = (init);\
00178    x = NULL;\
00179    if (!__next_one__)\
00180      assert(__next_one__);\
00181    else\
00182    while (!x  || __next_one__ != (init)) {\
00183      x = __next_one__;\
00184      /* save next one first in case the command modifies or frees it */\
00185      __next_one__ = x->which.next
00186 #define FOREACH_SUBNET(net, p) do {\
00187   routebox_t *_pp_;\
00188   /* fail-fast: check subnet_processed flags */\
00189   LIST_LOOP(net, same_net, p); \
00190   assert(!p->flags.subnet_processed);\
00191   END_LOOP;\
00192   /* iterate through *distinct* subnets */\
00193   LIST_LOOP(net, same_net, p); \
00194   if (!p->flags.subnet_processed) {\
00195     LIST_LOOP(p, same_subnet, _pp_);\
00196     _pp_->flags.subnet_processed=1;\
00197     END_LOOP
00198 #define END_FOREACH(net, p) \
00199   }; \
00200   END_LOOP;\
00201   /* reset subnet_processed flags */\
00202   LIST_LOOP(net, same_net, p); \
00203   p->flags.subnet_processed=0;\
00204   END_LOOP;\
00205 } while (0)
00206 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0)
00207 /* notes:
00208  * all rectangles are assumed to be closed on the top and left and
00209  * open on the bottom and right.   That is, they include their top-left
00210  * corner but don't include their bottom and right edges.
00211  *
00212  * expansion regions are always half-closed.  This means that when
00213  * tracing paths, you must steer clear of the bottom and right edges.,
00214  * because these are not actually in the allowed box.
00215  *
00216  * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by
00217  * their particular required keepaway. This simplifies the tree searching.
00218  * the "sbox" contains the unbloated box.
00219  */
00220 /* ---------------------------------------------------------------------------
00221  * some local types
00222  */
00223 
00224 /* enumerated type for conflict levels */
00225 typedef enum
00226 { NO_CONFLICT = 0, LO_CONFLICT = 1, HI_CONFLICT = 2 }
00227 conflict_t;
00228 
00229 typedef struct routebox_list
00230 {
00231   struct routebox *next, *prev;
00232 }routebox_list;
00233 
00234 typedef enum etype
00235   { PAD, PIN, VIA, VIA_SHADOW, LINE, OTHER, EXPANSION_AREA, PLANE, THERMAL }
00236   etype;
00237 
00238 typedef struct routebox
00239 {
00240   BoxType box, sbox;
00241   union
00242   {
00243     PadType *pad;
00244     PinType *pin;
00245     PinType *via;
00246     struct routebox *via_shadow;        /* points to the via in r-tree which
00247                                          * points to the PinType in the PCB. */
00248     LineType *line;
00249     void *generic;              /* 'other' is polygon, arc, text */
00250     struct routebox *expansion_area;    /* previous expansion area in search */
00251   }
00252   parent;
00253   unsigned short group;
00254   unsigned short layer;
00255   etype type;
00256   struct
00257   {
00258     unsigned nonstraight:1;
00259     unsigned fixed:1;
00260     /* for searches */
00261     unsigned source:1;
00262     unsigned target:1;
00263     /* rects on same net as source and target don't need clearance areas */
00264     unsigned nobloat:1;
00265     /* mark circular pins, so that we be sure to connect them up properly */
00266     unsigned circular:1;
00267     /* we sometimes create routeboxen that don't actually belong to a
00268      * r-tree yet -- make sure refcount of homelesss is set properly */
00269     unsigned homeless:1;
00270     /* was this nonfixed obstacle generated on an odd or even pass? */
00271     unsigned is_odd:1;
00272     /* fixed route boxes that have already been "routed through" in this
00273      * search have their "touched" flag set. */
00274     unsigned touched:1;
00275     /* this is a status bit for iterating through *different* subnets */
00276     unsigned subnet_processed:1;
00277     /* some expansion_areas represent via candidates */
00278     unsigned is_via:1;
00279     /* mark non-straight lines which go from bottom-left to upper-right,
00280      * instead of from upper-left to bottom-right. */
00281     unsigned bl_to_ur:1;
00282     /* mark polygons which are "transparent" for via-placement; that is,
00283      * vias through the polygon will automatically be given a keepaway
00284      * and will not electrically connect to the polygon. */
00285     unsigned clear_poly:1;
00286     /* this marks "conflicting" routes that must be torn up to obtain
00287      * a correct routing.  This flag allows us to return a correct routing
00288      * even if the user cancels auto-route after a non-final pass. */
00289     unsigned is_bad:1;
00290     /* for assertion that 'box' is never changed after creation */
00291     unsigned inited:1;
00292     /* indicate this expansion ares is a thermal between the pin and plane */
00293     unsigned is_thermal;
00294   }
00295   flags;
00296   /* indicate the direction an expansion box came from */
00297   cost_t cost;
00298   CheapPointType cost_point;
00299   /* reference count for homeless routeboxes; free when refcount==0 */
00300   int refcount;
00301   /* when routing with conflicts, we keep a record of what we're
00302    * conflicting with.
00303    */
00304   vector_t *conflicts_with;
00305   /* route style of the net associated with this routebox */
00306   RouteStyleType *style;
00307   /* congestion values for the edges of an expansion box */
00308   unsigned char n, e, s, w;
00309   /* what pass this this track was laid down on */
00310   unsigned char pass;
00311   /* the direction this came from, if any */
00312   direction_t came_from;
00313   /* circular lists with connectivity information. */
00314   routebox_list same_net, same_subnet, original_subnet, different_net;
00315   union {
00316     PinType *via;
00317     LineType *line;
00318   } livedraw_obj;
00319 }
00320 routebox_t;
00321 
00322 typedef struct routedata
00323 {
00324   /* one rtree per layer *group */
00325   rtree_t *layergrouptree[MAX_GROUP];   /* no silkscreen layers here =) */
00326   /* root pointer into connectivity information */
00327   routebox_t *first_net;
00328   /* default routing style */
00329   RouteStyleType defaultstyle;
00330   /* style structures */
00331   RouteStyleType *styles[NUM_STYLES + 1];
00332   /* what is the maximum bloat (keepaway+line half-width or
00333    * keepaway+via_radius) for any style we've seen? */
00334   Coord max_bloat;
00335   Coord max_keep;
00336   mtspace_t *mtspace;
00337 }
00338 routedata_t;
00339 
00340 typedef struct edge_struct
00341 {
00342   routebox_t *rb;               /* path expansion edges are real routeboxen. */
00343   CheapPointType cost_point;
00344   cost_t cost_to_point;         /* from source */
00345   cost_t cost;                  /* cached edge cost */
00346   routebox_t *mincost_target;   /* minimum cost from cost_point to any target */
00347   vetting_t *work;              /* for via search edges */
00348   direction_t expand_dir;
00349   struct
00350   {
00351     /* this indicates that this 'edge' is a via candidate. */
00352     unsigned is_via:1;
00353     /* record "conflict level" of via candidates, in case we need to split
00354      * them later. */
00355     conflict_t via_conflict_level:2;
00356     /* when "routing with conflicts", sometimes edge is interior. */
00357     unsigned is_interior:1;
00358     /* this is a fake edge used to defer searching for via spaces */
00359     unsigned via_search:1;
00360     /* this is a via edge in a plane where the cost point moves for free */
00361     unsigned in_plane:1;
00362   }
00363   flags;
00364 }
00365 edge_t;
00366 
00367 static struct
00368 {
00369   /* net style parameters */
00370   RouteStyleType *style;
00371   /* the present bloat */
00372   Coord bloat;
00373   /* cost parameters */
00374   cost_t ViaCost,               /* additional "length" cost for using a via */
00375     LastConflictPenalty,        /* length mult. for routing over last pass' trace */
00376     ConflictPenalty,            /* length multiplier for routing over another trace */
00377     JogPenalty,                 /* additional "length" cost for changing direction */
00378     CongestionPenalty,          /* (rational) length multiplier for routing in */
00379     NewLayerPenalty,            /* penalty for routing on a previously unused layer */
00380     MinPenalty;                 /* smallest Direction Penalty */
00381   /* maximum conflict incidence before calling it "no path found" */
00382   int hi_conflict;
00383   /* are vias allowed? */
00384   bool use_vias;
00385   /* is this an odd or even pass? */
00386   bool is_odd;
00387   /* permit conflicts? */
00388   bool with_conflicts;
00389   /* is this a final "smoothing" pass? */
00390   bool is_smoothing;
00391   /* rip up nets regardless of conflicts? */
00392   bool rip_always;
00393   bool last_smooth;
00394   unsigned char pass;
00395 }
00396 AutoRouteParameters;
00397 
00398 struct routeone_state
00399 {
00400   /* heap of all candidate expansion edges */
00401   heap_t *workheap;
00402   /* information about the best path found so far. */
00403   routebox_t *best_path, *best_target;
00404   cost_t best_cost;
00405 };
00406 
00407 
00408 /* ---------------------------------------------------------------------------
00409  * some local prototypes
00410  */
00411 static routebox_t *CreateExpansionArea (const BoxType * area, Cardinal group,
00412                                         routebox_t * parent,
00413                                         bool relax_edge_requirements,
00414                                         edge_t * edge);
00415 
00416 static cost_t edge_cost (const edge_t * e, const cost_t too_big);
00417 static void best_path_candidate (struct routeone_state *s,
00418                                  edge_t * e, routebox_t * best_target);
00419 
00420 static BoxType edge_to_box (const routebox_t * rb, direction_t expand_dir);
00421 
00422 static void add_or_destroy_edge (struct routeone_state *s, edge_t * e);
00423 
00424 static void
00425 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
00426                 Cardinal group, Cardinal layer, routebox_t * subnet,
00427                 bool is_bad);
00428 static void ResetSubnet (routebox_t * net);
00429 #ifdef ROUTE_DEBUG
00430 static int showboxen = -2;
00431 static int aabort = 0;
00432 static void showroutebox (routebox_t * rb);
00433 #endif
00434 
00435 /* ---------------------------------------------------------------------------
00436  * some local identifiers
00437  */
00438 /* group number of groups that hold surface mount pads */
00439 static Cardinal front, back;
00440 static bool usedGroup[MAX_GROUP];
00441 static int x_cost[MAX_GROUP], y_cost[MAX_GROUP];
00442 static bool is_layer_group_active[MAX_GROUP];
00443 static int ro = 0;
00444 static int smoothes = 1;
00445 static int passes = 12;
00446 static int routing_layers = 0;
00447 static float total_wire_length = 0;
00448 static int total_via_count = 0;
00449 
00450 /* assertion helper for routeboxen */
00451 #ifndef NDEBUG
00452 static int
00453 __routebox_is_good (routebox_t * rb)
00454 {
00455   assert (rb && (rb->group < max_group) &&
00456           (rb->box.X1 <= rb->box.X2) && (rb->box.Y1 <= rb->box.Y2) &&
00457           (rb->flags.homeless ?
00458            (rb->box.X1 != rb->box.X2) || (rb->box.Y1 != rb->box.Y2) :
00459            (rb->box.X1 != rb->box.X2) && (rb->box.Y1 != rb->box.Y2)));
00460   assert ((rb->flags.source ? rb->flags.nobloat : 1) &&
00461           (rb->flags.target ? rb->flags.nobloat : 1) &&
00462           (rb->flags.homeless ? !rb->flags.touched : rb->refcount == 0) &&
00463           (rb->flags.touched ? rb->type != EXPANSION_AREA : 1));
00464   assert ((rb->flags.is_odd ? (!rb->flags.fixed) &&
00465            (rb->type == VIA || rb->type == VIA_SHADOW || rb->type == LINE
00466             || rb->type == PLANE) : 1));
00467   assert (rb->flags.clear_poly ?
00468           ((rb->type == OTHER || rb->type == PLANE) && rb->flags.fixed
00469            && !rb->flags.homeless) : 1);
00470   assert (rb->flags.inited);
00471 /* run through conflict list showing none are homeless, targets or sources */
00472   if (rb->conflicts_with)
00473     {
00474       int i;
00475       for (i = 0; i < vector_size (rb->conflicts_with); i++)
00476         {
00477           routebox_t *c = vector_element (rb->conflicts_with, i);
00478           assert (!c->flags.homeless && !c->flags.source && !c->flags.target
00479                   && !c->flags.fixed);
00480         }
00481     }
00482   assert (rb->style != NULL && rb->style != NULL);
00483   assert (rb->type == EXPANSION_AREA
00484           || (rb->same_net.next && rb->same_net.prev && rb->same_subnet.next
00485               && rb->same_subnet.prev && rb->original_subnet.next
00486               && rb->original_subnet.prev && rb->different_net.next
00487               && rb->different_net.prev));
00488   return 1;
00489 }
00490 static int
00491 __edge_is_good (edge_t * e)
00492 {
00493   assert (e && e->rb && __routebox_is_good (e->rb));
00494   assert ((e->rb->flags.homeless ? e->rb->refcount > 0 : 1));
00495   assert ((0 <= e->expand_dir) && (e->expand_dir < 9)
00496           && (e->flags.
00497               is_interior ? (e->expand_dir == ALL
00498                              && e->rb->conflicts_with) : 1));
00499   assert ((e->flags.is_via ? e->rb->flags.is_via : 1)
00500           && (e->flags.via_conflict_level >= 0
00501               && e->flags.via_conflict_level <= 2)
00502           && (e->flags.via_conflict_level != 0 ? e->flags.is_via : 1));
00503   assert ((e->cost_to_point >= 0) && e->cost >= 0);
00504   return 1;
00505 }
00506 
00507 int
00508 no_planes (const BoxType * b, void *cl)
00509 {
00510   routebox_t *rb = (routebox_t *) b;
00511   if (rb->type == PLANE)
00512     return 0;
00513   return 1;
00514 }
00515 #endif /* !NDEBUG */
00516 
00517 /*---------------------------------------------------------------------
00518  * route utility functions.
00519  */
00520 
00521 enum boxlist
00522 { NET, SUBNET, ORIGINAL, DIFFERENT_NET };
00523 static struct routebox_list *
00524 __select_list (routebox_t * r, enum boxlist which)
00525 {
00526   assert (r);
00527   switch (which)
00528     {
00529     default:
00530       assert (0);
00531     case NET:
00532       return &(r->same_net);
00533     case SUBNET:
00534       return &(r->same_subnet);
00535     case ORIGINAL:
00536       return &(r->original_subnet);
00537     case DIFFERENT_NET:
00538       return &(r->different_net);
00539     }
00540 }
00541 static void
00542 InitLists (routebox_t * r)
00543 {
00544   static enum boxlist all[] =
00545   { NET, SUBNET, ORIGINAL, DIFFERENT_NET }
00546   , *p;
00547   for (p = all; p < all + (sizeof (all) / sizeof (*p)); p++)
00548     {
00549       struct routebox_list *rl = __select_list (r, *p);
00550       rl->prev = rl->next = r;
00551     }
00552 }
00553 
00554 static void
00555 MergeNets (routebox_t * a, routebox_t * b, enum boxlist which)
00556 {
00557   struct routebox_list *al, *bl, *anl, *bnl;
00558   routebox_t *an, *bn;
00559   assert (a && b);
00560   assert (a != b);
00561   assert (a->type != EXPANSION_AREA);
00562   assert (b->type != EXPANSION_AREA);
00563   al = __select_list (a, which);
00564   bl = __select_list (b, which);
00565   assert (al && bl);
00566   an = al->next;
00567   bn = bl->next;
00568   assert (an && bn);
00569   anl = __select_list (an, which);
00570   bnl = __select_list (bn, which);
00571   assert (anl && bnl);
00572   bl->next = an;
00573   anl->prev = b;
00574   al->next = bn;
00575   bnl->prev = a;
00576 }
00577 
00578 static void
00579 RemoveFromNet (routebox_t * a, enum boxlist which)
00580 {
00581   struct routebox_list *al, *anl, *apl;
00582   routebox_t *an, *ap;
00583   assert (a);
00584   al = __select_list (a, which);
00585   assert (al);
00586   an = al->next;
00587   ap = al->prev;
00588   if (an == a || ap == a)
00589     return;                     /* not on any list */
00590   assert (an && ap);
00591   anl = __select_list (an, which);
00592   apl = __select_list (ap, which);
00593   assert (anl && apl);
00594   anl->prev = ap;
00595   apl->next = an;
00596   al->next = al->prev = a;
00597   return;
00598 }
00599 
00600 static void
00601 init_const_box (routebox_t * rb,
00602                 Coord X1, Coord Y1, Coord X2,
00603                 Coord Y2, Coord keepaway)
00604 {
00605   BoxType *bp = (BoxType *) & rb->box;  /* note discarding const! */
00606   assert (!rb->flags.inited);
00607   assert (X1 <= X2 && Y1 <= Y2);
00608   bp->X1 = X1 - keepaway;
00609   bp->Y1 = Y1 - keepaway;
00610   bp->X2 = X2 + keepaway;
00611   bp->Y2 = Y2 + keepaway;
00612   bp = (BoxType *) & rb->sbox;
00613   bp->X1 = X1;
00614   bp->Y1 = Y1;
00615   bp->X2 = X2;
00616   bp->Y2 = Y2;
00617   rb->flags.inited = 1;
00618 }
00619 
00620 static inline BoxType
00621 shrink_routebox (const routebox_t * rb)
00622 {
00623   return rb->sbox;
00624 }
00625 
00626 static inline cost_t
00627 box_area (const BoxType b)
00628 {
00629   cost_t ans = b.X2 - b.X1;
00630   return ans * (b.Y2 - b.Y1);
00631 }
00632 
00633 static inline CheapPointType
00634 closest_point_in_routebox (const CheapPointType * from, const routebox_t * rb)
00635 {
00636   return closest_point_in_box (from, &rb->sbox);
00637 }
00638 
00639 static inline bool
00640 point_in_shrunk_box (const routebox_t * box, Coord X, Coord Y)
00641 {
00642   BoxType b = shrink_routebox (box);
00643   return point_in_box (&b, X, Y);
00644 }
00645 
00646 /*---------------------------------------------------------------------
00647  * routedata initialization functions.
00648  */
00649 
00650 static routebox_t *
00651 AddPin (PointerListType layergroupboxes[], PinType *pin, bool is_via,
00652         RouteStyleType * style)
00653 {
00654   routebox_t **rbpp, *lastrb = NULL;
00655   int i, ht;
00656   /* a pin cuts through every layer group */
00657   for (i = 0; i < max_group; i++)
00658     {
00659       rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[i]);
00660       *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
00661       memset ((void *) *rbpp, 0, sizeof (**rbpp));
00662       (*rbpp)->group = i;
00663       ht = HALF_THICK (MAX (pin->Thickness, pin->DrillingHole));
00664       init_const_box (*rbpp,
00665                       /*X1 */ pin->X - ht,
00666                       /*Y1 */ pin->Y - ht,
00667                       /*X2 */ pin->X + ht,
00668                       /*Y2 */ pin->Y + ht, style->Keepaway);
00669       /* set aux. properties */
00670       if (is_via)
00671         {
00672           (*rbpp)->type = VIA;
00673           (*rbpp)->parent.via = pin;
00674         }
00675       else
00676         {
00677           (*rbpp)->type = PIN;
00678           (*rbpp)->parent.pin = pin;
00679         }
00680       (*rbpp)->flags.fixed = 1;
00681       (*rbpp)->came_from = ALL;
00682       (*rbpp)->style = style;
00683       (*rbpp)->flags.circular = !TEST_FLAG (SQUAREFLAG, pin);
00684       /* circular lists */
00685       InitLists (*rbpp);
00686       /* link together */
00687       if (lastrb)
00688         {
00689           MergeNets (*rbpp, lastrb, NET);
00690           MergeNets (*rbpp, lastrb, SUBNET);
00691           MergeNets (*rbpp, lastrb, ORIGINAL);
00692         }
00693       lastrb = *rbpp;
00694     }
00695   return lastrb;
00696 }
00697 static routebox_t *
00698 AddPad (PointerListType layergroupboxes[],
00699         ElementType *element, PadType *pad, RouteStyleType * style)
00700 {
00701   Coord halfthick;
00702   routebox_t **rbpp;
00703   int layergroup = (TEST_FLAG (ONSOLDERFLAG, pad) ? back : front);
00704   assert (0 <= layergroup && layergroup < max_group);
00705   assert (PCB->LayerGroups.Number[layergroup] > 0);
00706   rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
00707   assert (rbpp);
00708   *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
00709   assert (*rbpp);
00710   memset (*rbpp, 0, sizeof (**rbpp));
00711   (*rbpp)->group = layergroup;
00712   halfthick = HALF_THICK (pad->Thickness);
00713   init_const_box (*rbpp,
00714                   /*X1 */ MIN (pad->Point1.X, pad->Point2.X) - halfthick,
00715                   /*Y1 */ MIN (pad->Point1.Y, pad->Point2.Y) - halfthick,
00716                   /*X2 */ MAX (pad->Point1.X, pad->Point2.X) + halfthick,
00717                   /*Y2 */ MAX (pad->Point1.Y, pad->Point2.Y) + halfthick,
00718                   style->Keepaway);
00719   /* kludge for non-manhattan pads (which are not allowed at present) */
00720   if (pad->Point1.X != pad->Point2.X && pad->Point1.Y != pad->Point2.Y)
00721     (*rbpp)->flags.nonstraight = 1;
00722   /* set aux. properties */
00723   (*rbpp)->type = PAD;
00724   (*rbpp)->parent.pad = pad;
00725   (*rbpp)->flags.fixed = 1;
00726   (*rbpp)->came_from = ALL;
00727   (*rbpp)->style = style;
00728   /* circular lists */
00729   InitLists (*rbpp);
00730   return *rbpp;
00731 }
00732 static routebox_t *
00733 AddLine (PointerListType layergroupboxes[], int layergroup, LineType *line,
00734          LineType *ptr, RouteStyleType * style)
00735 {
00736   routebox_t **rbpp;
00737   assert (layergroupboxes && line);
00738   assert (0 <= layergroup && layergroup < max_group);
00739   assert (PCB->LayerGroups.Number[layergroup] > 0);
00740 
00741   rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
00742   *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
00743   memset (*rbpp, 0, sizeof (**rbpp));
00744   (*rbpp)->group = layergroup;
00745   init_const_box (*rbpp,
00746                   /*X1 */ MIN (line->Point1.X,
00747                                line->Point2.X) - HALF_THICK (line->Thickness),
00748                   /*Y1 */ MIN (line->Point1.Y,
00749                                line->Point2.Y) - HALF_THICK (line->Thickness),
00750                   /*X2 */ MAX (line->Point1.X,
00751                                line->Point2.X) + HALF_THICK (line->Thickness),
00752                   /*Y2 */ MAX (line->Point1.Y,
00753                                line->Point2.Y) +
00754                   HALF_THICK (line->Thickness), style->Keepaway);
00755   /* kludge for non-manhattan lines */
00756   if (line->Point1.X != line->Point2.X && line->Point1.Y != line->Point2.Y)
00757     {
00758       (*rbpp)->flags.nonstraight = 1;
00759       (*rbpp)->flags.bl_to_ur =
00760         (MIN (line->Point1.X, line->Point2.X) == line->Point1.X) !=
00761         (MIN (line->Point1.Y, line->Point2.Y) == line->Point1.Y);
00762 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
00763       showroutebox (*rbpp);
00764 #endif
00765     }
00766   /* set aux. properties */
00767   (*rbpp)->type = LINE;
00768   (*rbpp)->parent.line = ptr;
00769   (*rbpp)->flags.fixed = 1;
00770   (*rbpp)->came_from = ALL;
00771   (*rbpp)->style = style;
00772   /* circular lists */
00773   InitLists (*rbpp);
00774   return *rbpp;
00775 }
00776 static routebox_t *
00777 AddIrregularObstacle (PointerListType layergroupboxes[],
00778                       Coord X1, Coord Y1,
00779                       Coord X2, Coord Y2, Cardinal layergroup,
00780                       void *parent, RouteStyleType * style)
00781 {
00782   routebox_t **rbpp;
00783   Coord keep = style->Keepaway;
00784   assert (layergroupboxes && parent);
00785   assert (X1 <= X2 && Y1 <= Y2);
00786   assert (0 <= layergroup && layergroup < max_group);
00787   assert (PCB->LayerGroups.Number[layergroup] > 0);
00788 
00789   rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]);
00790   *rbpp = (routebox_t *)malloc (sizeof (**rbpp));
00791   memset (*rbpp, 0, sizeof (**rbpp));
00792   (*rbpp)->group = layergroup;
00793   init_const_box (*rbpp, X1, Y1, X2, Y2, keep);
00794   (*rbpp)->flags.nonstraight = 1;
00795   (*rbpp)->type = OTHER;
00796   (*rbpp)->parent.generic = parent;
00797   (*rbpp)->flags.fixed = 1;
00798   (*rbpp)->style = style;
00799   /* circular lists */
00800   InitLists (*rbpp);
00801   return *rbpp;
00802 }
00803 
00804 static routebox_t *
00805 AddPolygon (PointerListType layergroupboxes[], Cardinal layer,
00806             PolygonType *polygon, RouteStyleType * style)
00807 {
00808   int is_not_rectangle = 1;
00809   int layergroup = GetLayerGroupNumberByNumber (layer);
00810   routebox_t *rb;
00811   assert (0 <= layergroup && layergroup < max_group);
00812   rb = AddIrregularObstacle (layergroupboxes,
00813                              polygon->BoundingBox.X1,
00814                              polygon->BoundingBox.Y1,
00815                              polygon->BoundingBox.X2,
00816                              polygon->BoundingBox.Y2,
00817                              layergroup, polygon, style);
00818   if (polygon->PointN == 4 &&
00819       polygon->HoleIndexN == 0 &&
00820       (polygon->Points[0].X == polygon->Points[1].X ||
00821        polygon->Points[0].Y == polygon->Points[1].Y) &&
00822       (polygon->Points[1].X == polygon->Points[2].X ||
00823        polygon->Points[1].Y == polygon->Points[2].Y) &&
00824       (polygon->Points[2].X == polygon->Points[3].X ||
00825        polygon->Points[2].Y == polygon->Points[3].Y) &&
00826       (polygon->Points[3].X == polygon->Points[0].X ||
00827        polygon->Points[3].Y == polygon->Points[0].Y))
00828     is_not_rectangle = 0;
00829   rb->flags.nonstraight = is_not_rectangle;
00830   rb->layer = layer;
00831   rb->came_from = ALL;
00832   if (TEST_FLAG (CLEARPOLYFLAG, polygon))
00833     {
00834       rb->flags.clear_poly = 1;
00835       if (!is_not_rectangle)
00836         rb->type = PLANE;
00837     }
00838   return rb;
00839 }
00840 static void
00841 AddText (PointerListType layergroupboxes[], Cardinal layergroup,
00842          TextType *text, RouteStyleType * style)
00843 {
00844   AddIrregularObstacle (layergroupboxes,
00845                         text->BoundingBox.X1, text->BoundingBox.Y1,
00846                         text->BoundingBox.X2, text->BoundingBox.Y2,
00847                         layergroup, text, style);
00848 }
00849 static routebox_t *
00850 AddArc (PointerListType layergroupboxes[], Cardinal layergroup,
00851         ArcType *arc, RouteStyleType * style)
00852 {
00853   return AddIrregularObstacle (layergroupboxes,
00854                                arc->BoundingBox.X1, arc->BoundingBox.Y1,
00855                                arc->BoundingBox.X2, arc->BoundingBox.Y2,
00856                                layergroup, arc, style);
00857 }
00858 
00859 struct rb_info
00860 {
00861   BoxType query;
00862   routebox_t *winner;
00863   jmp_buf env;
00864 };
00865 
00866 static int
00867 __found_one_on_lg (const BoxType * box, void *cl)
00868 {
00869   struct rb_info *inf = (struct rb_info *) cl;
00870   routebox_t *rb = (routebox_t *) box;
00871   BoxType sb;
00872 
00873   if (rb->flags.nonstraight)
00874     return 0;
00875   sb = shrink_box (&rb->box, rb->style->Keepaway);
00876   if (inf->query.X1 >= sb.X2 || inf->query.X2 <= sb.X1 ||
00877       inf->query.Y1 >= sb.Y2 || inf->query.Y2 <= sb.Y1)
00878     return 0;
00879   inf->winner = rb;
00880   if (rb->type == PLANE)
00881     return 1;                   /* keep looking for something smaller if a plane was found */
00882   longjmp (inf->env, 1);
00883   return 0;
00884 }
00885 static routebox_t *
00886 FindRouteBoxOnLayerGroup (routedata_t * rd,
00887                           Coord X, Coord Y, Cardinal layergroup)
00888 {
00889   struct rb_info info;
00890   info.winner = NULL;
00891   info.query = point_box (X, Y);
00892   if (setjmp (info.env) == 0)
00893     r_search (rd->layergrouptree[layergroup], &info.query, NULL,
00894               __found_one_on_lg, &info);
00895   return info.winner;
00896 }
00897 
00898 #ifdef ROUTE_DEBUG_VERBOSE
00899 static void
00900 DumpRouteBox (routebox_t * rb)
00901 {
00902   pcb_printf ("RB: %#mD-%#mD l%d; ",
00903           rb->box.X1, rb->box.Y1, rb->box.X2, rb->box.Y2, (int) rb->group);
00904   switch (rb->type)
00905     {
00906     case PAD:
00907       printf ("PAD[%s %s] ", rb->parent.pad->Name, rb->parent.pad->Number);
00908       break;
00909     case PIN:
00910       printf ("PIN[%s %s] ", rb->parent.pin->Name, rb->parent.pin->Number);
00911       break;
00912     case VIA:
00913       if (!rb->parent.via)
00914         break;
00915       printf ("VIA[%s %s] ", rb->parent.via->Name, rb->parent.via->Number);
00916       break;
00917     case LINE:
00918       printf ("LINE ");
00919       break;
00920     case OTHER:
00921       printf ("OTHER ");
00922       break;
00923     case EXPANSION_AREA:
00924       printf ("EXPAREA ");
00925       break;
00926     default:
00927       printf ("UNKNOWN ");
00928       break;
00929     }
00930   if (rb->flags.nonstraight)
00931     printf ("(nonstraight) ");
00932   if (rb->flags.fixed)
00933     printf ("(fixed) ");
00934   if (rb->flags.source)
00935     printf ("(source) ");
00936   if (rb->flags.target)
00937     printf ("(target) ");
00938   if (rb->flags.homeless)
00939     printf ("(homeless) ");
00940   printf ("\n");
00941 }
00942 #endif
00943 
00944 static routedata_t *
00945 CreateRouteData ()
00946 {
00947   NetListListType Nets;
00948   PointerListType layergroupboxes[MAX_GROUP];
00949   BoxType bbox;
00950   routedata_t *rd;
00951   int group, i;
00952 
00953   /* check which layers are active first */
00954   routing_layers = 0;
00955   for (group = 0; group < max_group; group++)
00956     {
00957       for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
00958         /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */
00959         if ((PCB->LayerGroups.Entries[group][i] < max_copper_layer) &&
00960             PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)
00961           {
00962             routing_layers++;
00963             is_layer_group_active[group] = true;
00964             break;
00965           }
00966         else
00967           is_layer_group_active[group] = false;
00968     }
00969   /* if via visibility is turned off, don't use them */
00970   AutoRouteParameters.use_vias = routing_layers > 1 && PCB->ViaOn;
00971   front = GetLayerGroupNumberBySide (TOP_SIDE);
00972   back = GetLayerGroupNumberBySide (BOTTOM_SIDE);
00973   /* determine preferred routing direction on each group */
00974   for (i = 0; i < max_group; i++)
00975     {
00976       if (i != back && i != front)
00977         {
00978           x_cost[i] = (i & 1) ? 2 : 1;
00979           y_cost[i] = (i & 1) ? 1 : 2;
00980         }
00981       else if (i == back)
00982         {
00983           x_cost[i] = 4;
00984           y_cost[i] = 2;
00985         }
00986       else
00987         {
00988           x_cost[i] = 2;
00989           y_cost[i] = 2;
00990         }
00991     }
00992   /* create routedata */
00993   rd = (routedata_t *)malloc (sizeof (*rd));
00994   memset ((void *) rd, 0, sizeof (*rd));
00995   /* create default style */
00996   rd->defaultstyle.Thick = Settings.LineThickness;
00997   rd->defaultstyle.Diameter = Settings.ViaThickness;
00998   rd->defaultstyle.Hole = Settings.ViaDrillingHole;
00999   rd->defaultstyle.Keepaway = Settings.Keepaway;
01000   rd->max_bloat = BLOAT (&rd->defaultstyle);
01001   rd->max_keep = Settings.Keepaway;
01002   /* create styles structures */
01003   bbox.X1 = bbox.Y1 = 0;
01004   bbox.X2 = PCB->MaxWidth;
01005   bbox.Y2 = PCB->MaxHeight;
01006   for (i = 0; i < NUM_STYLES + 1; i++)
01007     {
01008       RouteStyleType *style =
01009         (i < NUM_STYLES) ? &PCB->RouteStyle[i] : &rd->defaultstyle;
01010       rd->styles[i] = style;
01011     }
01012 
01013   /* initialize pointerlisttype */
01014   for (i = 0; i < max_group; i++)
01015     {
01016       layergroupboxes[i].Ptr = NULL;
01017       layergroupboxes[i].PtrN = 0;
01018       layergroupboxes[i].PtrMax = 0;
01019       GROUP_LOOP (PCB->Data, i);
01020       {
01021         if (layer->LineN || layer->ArcN)
01022           usedGroup[i] = true;
01023         else
01024           usedGroup[i] = false;
01025       }
01026       END_LOOP;
01027     }
01028   usedGroup[front] = true;
01029   usedGroup[back] = true;
01030   /* add the objects in the netlist first.
01031    * then go and add all other objects that weren't already added
01032    *
01033    * this saves on searching the trees to find the nets
01034    */
01035   /* use the DRCFLAG to mark objects as they are entered */
01036   Nets = CollectSubnets (false);
01037   {
01038     routebox_t *last_net = NULL;
01039     NETLIST_LOOP (&Nets);
01040     {
01041       routebox_t *last_in_net = NULL;
01042       NET_LOOP (netlist);
01043       {
01044         routebox_t *last_in_subnet = NULL;
01045         int j;
01046 
01047         for (j = 0; j < NUM_STYLES; j++)
01048           if (net->Style == rd->styles[j])
01049             break;
01050         CONNECTION_LOOP (net);
01051         {
01052           routebox_t *rb = NULL;
01053           SET_FLAG (DRCFLAG, (PinType *) connection->ptr2);
01054           if (connection->type == LINE_TYPE)
01055             {
01056               LineType *line = (LineType *) connection->ptr2;
01057 
01058               /* lines are listed at each end, so skip one */
01059               /* this should probably by a macro named "BUMP_LOOP" */
01060               n--;
01061 
01062               /* dice up non-straight lines into many tiny obstacles */
01063               if (line->Point1.X != line->Point2.X
01064                   && line->Point1.Y != line->Point2.Y)
01065                 {
01066                   LineType fake_line = *line;
01067                   Coord dx = (line->Point2.X - line->Point1.X);
01068                   Coord dy = (line->Point2.Y - line->Point1.Y);
01069                   int segs = MAX (ABS (dx),
01070                                   ABS (dy)) / (4 * BLOAT (rd->styles[j]) + 1);
01071                   int qq;
01072                   segs = CLAMP (segs, 1, 32);   /* don't go too crazy */
01073                   dx /= segs;
01074                   dy /= segs;
01075                   for (qq = 0; qq < segs - 1; qq++)
01076                     {
01077                       fake_line.Point2.X = fake_line.Point1.X + dx;
01078                       fake_line.Point2.Y = fake_line.Point1.Y + dy;
01079                       if (fake_line.Point2.X == line->Point2.X
01080                           && fake_line.Point2.Y == line->Point2.Y)
01081                         break;
01082                       rb =
01083                         AddLine (layergroupboxes, connection->group,
01084                                  &fake_line, line, rd->styles[j]);
01085                       if (last_in_subnet && rb != last_in_subnet)
01086                         MergeNets (last_in_subnet, rb, ORIGINAL);
01087                       if (last_in_net && rb != last_in_net)
01088                         MergeNets (last_in_net, rb, NET);
01089                       last_in_subnet = last_in_net = rb;
01090                       fake_line.Point1 = fake_line.Point2;
01091                     }
01092                   fake_line.Point2 = line->Point2;
01093                   rb =
01094                     AddLine (layergroupboxes, connection->group, &fake_line,
01095                              line, rd->styles[j]);
01096                 }
01097               else
01098                 {
01099                   rb =
01100                     AddLine (layergroupboxes, connection->group, line, line,
01101                              rd->styles[j]);
01102                 }
01103             }
01104           else
01105             switch (connection->type)
01106               {
01107               case PAD_TYPE:
01108                 rb =
01109                   AddPad (layergroupboxes, (ElementType *)connection->ptr1,
01110                           (PadType *)connection->ptr2, rd->styles[j]);
01111                 break;
01112               case PIN_TYPE:
01113                 rb =
01114                   AddPin (layergroupboxes, (PinType *)connection->ptr2, false,
01115                           rd->styles[j]);
01116                 break;
01117               case VIA_TYPE:
01118                 rb =
01119                   AddPin (layergroupboxes, (PinType *)connection->ptr2, true,
01120                           rd->styles[j]);
01121                 break;
01122               case POLYGON_TYPE:
01123                 rb =
01124                   AddPolygon (layergroupboxes,
01125                               GetLayerNumber (PCB->Data, (LayerType *)connection->ptr1),
01126                               (struct polygon_st *)connection->ptr2, rd->styles[j]);
01127                 break;
01128               }
01129           assert (rb);
01130           /* update circular connectivity lists */
01131           if (last_in_subnet && rb != last_in_subnet)
01132             MergeNets (last_in_subnet, rb, ORIGINAL);
01133           if (last_in_net && rb != last_in_net)
01134             MergeNets (last_in_net, rb, NET);
01135           last_in_subnet = last_in_net = rb;
01136           rd->max_bloat = MAX (rd->max_bloat, BLOAT (rb->style));
01137           rd->max_keep = MAX (rd->max_keep, rb->style->Keepaway);
01138         }
01139         END_LOOP;
01140       }
01141       END_LOOP;
01142       if (last_net && last_in_net)
01143         MergeNets (last_net, last_in_net, DIFFERENT_NET);
01144       last_net = last_in_net;
01145     }
01146     END_LOOP;
01147     rd->first_net = last_net;
01148   }
01149   FreeNetListListMemory (&Nets);
01150 
01151   /* reset all nets to "original" connectivity (which we just set) */
01152   {
01153     routebox_t *net;
01154     LIST_LOOP (rd->first_net, different_net, net);
01155     ResetSubnet (net);
01156     END_LOOP;
01157   }
01158 
01159   /* add pins and pads of elements */
01160   ALLPIN_LOOP (PCB->Data);
01161   {
01162     if (TEST_FLAG (DRCFLAG, pin))
01163       CLEAR_FLAG (DRCFLAG, pin);
01164     else
01165       AddPin (layergroupboxes, pin, false, rd->styles[NUM_STYLES]);
01166   }
01167   ENDALL_LOOP;
01168   ALLPAD_LOOP (PCB->Data);
01169   {
01170     if (TEST_FLAG (DRCFLAG, pad))
01171       CLEAR_FLAG (DRCFLAG, pad);
01172     else
01173       AddPad (layergroupboxes, element, pad, rd->styles[NUM_STYLES]);
01174   }
01175   ENDALL_LOOP;
01176   /* add all vias */
01177   VIA_LOOP (PCB->Data);
01178   {
01179     if (TEST_FLAG (DRCFLAG, via))
01180       CLEAR_FLAG (DRCFLAG, via);
01181     else
01182       AddPin (layergroupboxes, via, true, rd->styles[NUM_STYLES]);
01183   }
01184   END_LOOP;
01185 
01186   for (i = 0; i < max_copper_layer; i++)
01187     {
01188       int layergroup = GetLayerGroupNumberByNumber (i);
01189       /* add all (non-rat) lines */
01190       LINE_LOOP (LAYER_PTR (i));
01191       {
01192         if (TEST_FLAG (DRCFLAG, line))
01193           {
01194             CLEAR_FLAG (DRCFLAG, line);
01195             continue;
01196           }
01197         /* dice up non-straight lines into many tiny obstacles */
01198         if (line->Point1.X != line->Point2.X
01199             && line->Point1.Y != line->Point2.Y)
01200           {
01201             LineType fake_line = *line;
01202             Coord dx = (line->Point2.X - line->Point1.X);
01203             Coord dy = (line->Point2.Y - line->Point1.Y);
01204             int segs = MAX (ABS (dx), ABS (dy)) / (4 * rd->max_bloat + 1);
01205             int qq;
01206             segs = CLAMP (segs, 1, 32); /* don't go too crazy */
01207             dx /= segs;
01208             dy /= segs;
01209             for (qq = 0; qq < segs - 1; qq++)
01210               {
01211                 fake_line.Point2.X = fake_line.Point1.X + dx;
01212                 fake_line.Point2.Y = fake_line.Point1.Y + dy;
01213                 if (fake_line.Point2.X == line->Point2.X
01214                     && fake_line.Point2.Y == line->Point2.Y)
01215                   break;
01216                 AddLine (layergroupboxes, layergroup, &fake_line, line,
01217                          rd->styles[NUM_STYLES]);
01218                 fake_line.Point1 = fake_line.Point2;
01219               }
01220             fake_line.Point2 = line->Point2;
01221             AddLine (layergroupboxes, layergroup, &fake_line, line,
01222                      rd->styles[NUM_STYLES]);
01223           }
01224         else
01225           {
01226             AddLine (layergroupboxes, layergroup, line, line,
01227                      rd->styles[NUM_STYLES]);
01228           }
01229       }
01230       END_LOOP;
01231       /* add all polygons */
01232       POLYGON_LOOP (LAYER_PTR (i));
01233       {
01234         if (TEST_FLAG (DRCFLAG, polygon))
01235           CLEAR_FLAG (DRCFLAG, polygon);
01236         else
01237           AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]);
01238       }
01239       END_LOOP;
01240       /* add all copper text */
01241       TEXT_LOOP (LAYER_PTR (i));
01242       {
01243         AddText (layergroupboxes, layergroup, text, rd->styles[NUM_STYLES]);
01244       }
01245       END_LOOP;
01246       /* add all arcs */
01247       ARC_LOOP (LAYER_PTR (i));
01248       {
01249         AddArc (layergroupboxes, layergroup, arc, rd->styles[NUM_STYLES]);
01250       }
01251       END_LOOP;
01252     }
01253 
01254   /* create r-trees from pointer lists */
01255   for (i = 0; i < max_group; i++)
01256     {
01257       /* create the r-tree */
01258       rd->layergrouptree[i] =
01259         r_create_tree ((const BoxType **) layergroupboxes[i].Ptr,
01260                        layergroupboxes[i].PtrN, 1);
01261     }
01262 
01263   if (AutoRouteParameters.use_vias)
01264     {
01265       rd->mtspace = mtspace_create ();
01266 
01267       /* create "empty-space" structures for via placement (now that we know
01268        * appropriate keepaways for all the fixed elements) */
01269       for (i = 0; i < max_group; i++)
01270         {
01271           POINTER_LOOP (&layergroupboxes[i]);
01272           {
01273             routebox_t *rb = (routebox_t *) * ptr;
01274             if (!rb->flags.clear_poly)
01275               mtspace_add (rd->mtspace, &rb->box, FIXED, rb->style->Keepaway);
01276           }
01277           END_LOOP;
01278         }
01279     }
01280   /* free pointer lists */
01281   for (i = 0; i < max_group; i++)
01282     FreePointerListMemory (&layergroupboxes[i]);
01283   /* done! */
01284   return rd;
01285 }
01286 
01287 void
01288 DestroyRouteData (routedata_t ** rd)
01289 {
01290   int i;
01291   for (i = 0; i < max_group; i++)
01292     r_destroy_tree (&(*rd)->layergrouptree[i]);
01293   if (AutoRouteParameters.use_vias)
01294     mtspace_destroy (&(*rd)->mtspace);
01295   free (*rd);
01296   *rd = NULL;
01297 }
01298 
01299 /*-----------------------------------------------------------------
01300  * routebox reference counting.
01301  */
01302 
01306 static void
01307 RB_up_count (routebox_t * rb)
01308 {
01309   assert (rb->flags.homeless);
01310   rb->refcount++;
01311 }
01312 
01317 static void
01318 RB_down_count (routebox_t * rb)
01319 {
01320   assert (rb->type == EXPANSION_AREA);
01321   assert (rb->flags.homeless);
01322   assert (rb->refcount > 0);
01323   if (--rb->refcount == 0)
01324     {
01325       if (rb->parent.expansion_area->flags.homeless)
01326         RB_down_count (rb->parent.expansion_area);
01327       free (rb);
01328     }
01329 }
01330 
01331 /*-----------------------------------------------------------------
01332  * Rectangle-expansion routing code.
01333  */
01334 
01335 static void
01336 ResetSubnet (routebox_t * net)
01337 {
01338   routebox_t *rb;
01339   /* reset connectivity of everything on this net */
01340   LIST_LOOP (net, same_net, rb);
01341   rb->same_subnet = rb->original_subnet;
01342   END_LOOP;
01343 }
01344 
01345 static inline cost_t
01346 cost_to_point_on_layer (const CheapPointType * p1,
01347                         const CheapPointType * p2, Cardinal point_layer)
01348 {
01349   cost_t x_dist = p1->X - p2->X, y_dist = p1->Y - p2->Y, r;
01350   x_dist *= x_cost[point_layer];
01351   y_dist *= y_cost[point_layer];
01352   /* cost is proportional to orthogonal distance. */
01353   r = ABS (x_dist) + ABS (y_dist);
01354   if (p1->X != p2->X && p1->Y != p2->Y)
01355     r += AutoRouteParameters.JogPenalty;
01356   return r;
01357 }
01358 
01359 static cost_t
01360 cost_to_point (const CheapPointType * p1, Cardinal point_layer1,
01361                const CheapPointType * p2, Cardinal point_layer2)
01362 {
01363   cost_t r = cost_to_point_on_layer (p1, p2, point_layer1);
01364   /* apply via cost penalty if layers differ */
01365   if (point_layer1 != point_layer2)
01366     r += AutoRouteParameters.ViaCost;
01367   return r;
01368 }
01369 
01375 static cost_t
01376 cost_to_layerless_box (const CheapPointType * p, Cardinal point_layer,
01377                        const BoxType * b)
01378 {
01379   CheapPointType p2 = closest_point_in_box (p, b);
01380   register cost_t c1, c2;
01381 
01382   c1 = p2.X - p->X;
01383   c2 = p2.Y - p->Y;
01384 
01385   c1 = ABS (c1);
01386   c2 = ABS (c2);
01387   if (c1 < c2)
01388     return c1 * AutoRouteParameters.MinPenalty + c2;
01389   else
01390     return c2 * AutoRouteParameters.MinPenalty + c1;
01391 }
01392 
01396 bool
01397 TargetPoint (CheapPointType * nextpoint, const routebox_t * target)
01398 {
01399   if (target->type == PIN)
01400     {
01401       nextpoint->X = target->parent.pin->X;
01402       nextpoint->Y = target->parent.pin->Y;
01403       return true;
01404     }
01405   else if (target->type == PAD)
01406     {
01407       if (abs (target->parent.pad->Point1.X - nextpoint->X) <
01408           abs (target->parent.pad->Point2.X - nextpoint->X))
01409         nextpoint->X = target->parent.pad->Point1.X;
01410       else
01411         nextpoint->X = target->parent.pad->Point2.X;
01412       if (abs (target->parent.pad->Point1.Y - nextpoint->Y) <
01413           abs (target->parent.pad->Point2.Y - nextpoint->Y))
01414         nextpoint->Y = target->parent.pad->Point1.Y;
01415       else
01416         nextpoint->Y = target->parent.pad->Point2.Y;
01417       return true;
01418     }
01419   else
01420     {
01421       nextpoint->X = CENTER_X (target->sbox);
01422       nextpoint->Y = CENTER_Y (target->sbox);
01423     }
01424   return false;
01425 }
01426 
01434 static cost_t
01435 cost_to_routebox (const CheapPointType * p, Cardinal point_layer,
01436                   const routebox_t * rb)
01437 {
01438   register cost_t trial = 0;
01439   CheapPointType p2 = closest_point_in_routebox (p, rb);
01440   if (!usedGroup[point_layer] || !usedGroup[rb->group])
01441     trial = AutoRouteParameters.NewLayerPenalty;
01442   if ((p2.X - p->X) * (p2.Y - p->Y) != 0)
01443     trial += AutoRouteParameters.JogPenalty;
01444   /* special case for defered via searching */
01445   if (point_layer > max_group || point_layer == rb->group)
01446     return trial + ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
01447   /* if this target is only a via away, then the via is cheaper than the congestion */
01448   if (p->X == p2.X && p->Y == p2.Y)
01449     return trial + 1;
01450   trial += AutoRouteParameters.ViaCost;
01451   trial += ABS (p2.X - p->X) + ABS (p2.Y - p->Y);
01452   return trial;
01453 }
01454 
01455 
01456 static BoxType
01457 bloat_routebox (routebox_t * rb)
01458 {
01459   BoxType r;
01460   Coord keepaway;
01461   assert (__routebox_is_good (rb));
01462 
01463   if (rb->flags.nobloat)
01464     return rb->sbox;
01465 
01466   /* Obstacle exclusion zones get bloated by the larger of
01467    * the two required clearances plus half the track width.
01468    */
01469   keepaway = MAX (AutoRouteParameters.style->Keepaway, rb->style->Keepaway);
01470   r = bloat_box (&rb->sbox, keepaway +
01471                  HALF_THICK (AutoRouteParameters.style->Thick));
01472   return r;
01473 }
01474 
01475 
01476 #ifdef ROUTE_DEBUG              /* only for debugging expansion areas */
01477 
01481 void
01482 showbox (BoxType b, Dimension thickness, int group)
01483 {
01484   LineType *line;
01485   LayerType *SLayer = LAYER_PTR (group);
01486   if (showboxen < -1)
01487     return;
01488   if (showboxen != -1 && showboxen != group)
01489     return;
01490 
01491   if (ddraw != NULL)
01492     {
01493       ddraw->set_line_width (ar_gc, thickness);
01494       ddraw->set_line_cap (ar_gc, Trace_Cap);
01495       ddraw->set_color (ar_gc, SLayer->Color);
01496 
01497       ddraw->draw_line (ar_gc, b.X1, b.Y1, b.X2, b.Y1);
01498       ddraw->draw_line (ar_gc, b.X1, b.Y2, b.X2, b.Y2);
01499       ddraw->draw_line (ar_gc, b.X1, b.Y1, b.X1, b.Y2);
01500       ddraw->draw_line (ar_gc, b.X2, b.Y1, b.X2, b.Y2);
01501     }
01502 
01503 #if 1
01504   if (b.Y1 == b.Y2 || b.X1 == b.X2)
01505     thickness = 5;
01506   line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
01507                                b.X1, b.Y1, b.X2, b.Y1, thickness, 0,
01508                                MakeFlags (0));
01509   AddObjectToCreateUndoList (LINE_TYPE,
01510                              LAYER_PTR (top_silk_layer), line,
01511                              line);
01512   if (b.Y1 != b.Y2)
01513     {
01514       line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
01515                                    b.X1, b.Y2, b.X2, b.Y2, thickness, 0,
01516                                    MakeFlags (0));
01517       AddObjectToCreateUndoList (LINE_TYPE,
01518                                  LAYER_PTR (bottom_silk_layer),
01519                                  line, line);
01520     }
01521   line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
01522                                b.X1, b.Y1, b.X1, b.Y2, thickness, 0,
01523                                MakeFlags (0));
01524   AddObjectToCreateUndoList (LINE_TYPE,
01525                              LAYER_PTR (top_silk_layer), line,
01526                              line);
01527   if (b.X1 != b.X2)
01528     {
01529       line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer),
01530                                    b.X2, b.Y1, b.X2, b.Y2, thickness, 0,
01531                                    MakeFlags (0));
01532       AddObjectToCreateUndoList (LINE_TYPE,
01533                                  LAYER_PTR (top_silk_layer),
01534                                  line, line);
01535     }
01536 #endif
01537 }
01538 #endif
01539 
01540 #if defined(ROUTE_DEBUG)
01541 static void
01542 showedge (edge_t * e)
01543 {
01544   BoxType *b = (BoxType *) e->rb;
01545 
01546   if (ddraw == NULL)
01547     return;
01548 
01549   ddraw->set_line_cap (ar_gc, Trace_Cap);
01550   ddraw->set_line_width (ar_gc, 1);
01551   ddraw->set_color (ar_gc, Settings.MaskColor);
01552 
01553   switch (e->expand_dir)
01554     {
01555     case NORTH:
01556       ddraw->draw_line (ar_gc, b->X1, b->Y1, b->X2, b->Y1);
01557       break;
01558     case SOUTH:
01559       ddraw->draw_line (ar_gc, b->X1, b->Y2, b->X2, b->Y2);
01560       break;
01561     case WEST:
01562       ddraw->draw_line (ar_gc, b->X1, b->Y1, b->X1, b->Y2);
01563       break;
01564     case EAST:
01565       ddraw->draw_line (ar_gc, b->X2, b->Y1, b->X2, b->Y2);
01566       break;
01567     default:
01568       break;
01569     }
01570 }
01571 #endif
01572 
01573 #if defined(ROUTE_DEBUG)
01574 static void
01575 showroutebox (routebox_t * rb)
01576 {
01577   showbox (rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1),
01578            rb->flags.is_via ? top_silk_layer : rb->group);
01579 }
01580 #endif
01581 
01586 static routebox_t *
01587 route_parent (routebox_t * rb)
01588 {
01589   while (rb->flags.homeless && !rb->flags.is_via && !rb->flags.is_thermal)
01590     {
01591       assert (rb->type == EXPANSION_AREA);
01592       rb = rb->parent.expansion_area;
01593       assert (rb);
01594     }
01595   return rb;
01596 }
01597 
01598 static vector_t *
01599 path_conflicts (routebox_t * rb, routebox_t * conflictor, bool branch)
01600 {
01601   if (branch)
01602     rb->conflicts_with = vector_duplicate (rb->conflicts_with);
01603   else if (!rb->conflicts_with)
01604     rb->conflicts_with = vector_create ();
01605   vector_append (rb->conflicts_with, conflictor);
01606   return rb->conflicts_with;
01607 }
01608 
01621 static void
01622 touch_conflicts (vector_t * conflicts, int touch)
01623 {
01624   static vector_t *last = NULL;
01625   static int last_size = 0;
01626   int i, n;
01627   i = 0;
01628   if (touch)
01629     {
01630       if (last && conflicts != last)
01631         touch_conflicts (last, 0);
01632       if (!conflicts)
01633         return;
01634       last = conflicts;
01635       i = last_size;
01636     }
01637   n = vector_size (conflicts);
01638   for (; i < n; i++)
01639     {
01640       routebox_t *rb = (routebox_t *) vector_element (conflicts, i);
01641       routebox_t *p;
01642       LIST_LOOP (rb, same_net, p);
01643       if (!p->flags.fixed)
01644         p->flags.touched = touch;
01645       END_LOOP;
01646     }
01647   if (!touch)
01648     {
01649       last = NULL;
01650       last_size = 0;
01651     }
01652   else
01653     last_size = n;
01654 }
01655 
01663 static routebox_t *
01664 nonhomeless_parent (routebox_t * rb)
01665 {
01666   return route_parent (rb);
01667 }
01668 
01673 struct mincost_target_closure
01674 {
01675   const CheapPointType *CostPoint;
01676   Cardinal CostPointLayer;
01677   routebox_t *nearest;
01678   cost_t nearest_cost;
01679 };
01680 static int
01681 __region_within_guess (const BoxType * region, void *cl)
01682 {
01683   struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
01684   cost_t cost_to_region;
01685   if (mtc->nearest == NULL)
01686     return 1;
01687   cost_to_region =
01688     cost_to_layerless_box (mtc->CostPoint, mtc->CostPointLayer, region);
01689   assert (cost_to_region >= 0);
01690   /* if no guess yet, all regions are "close enough" */
01691   /* note that cost is *strictly more* than minimum distance, so we'll
01692    * always search a region large enough. */
01693   return (cost_to_region < mtc->nearest_cost);
01694 }
01695 static int
01696 __found_new_guess (const BoxType * box, void *cl)
01697 {
01698   struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl;
01699   routebox_t *guess = (routebox_t *) box;
01700   cost_t cost_to_guess =
01701     cost_to_routebox (mtc->CostPoint, mtc->CostPointLayer, guess);
01702   assert (cost_to_guess >= 0);
01703   /* if this is cheaper than previous guess... */
01704   if (cost_to_guess < mtc->nearest_cost)
01705     {
01706       mtc->nearest = guess;
01707       mtc->nearest_cost = cost_to_guess;        /* this is our new guess! */
01708       return 1;
01709     }
01710   else
01711     return 0;                   /* not less expensive than our last guess */
01712 }
01713 
01720 static routebox_t *
01721 mincost_target_to_point (const CheapPointType * CostPoint,
01722                          Cardinal CostPointLayer,
01723                          rtree_t * targets, routebox_t * target_guess)
01724 {
01725   struct mincost_target_closure mtc;
01726   assert (target_guess == NULL || target_guess->flags.target);  /* this is a target, right? */
01727   mtc.CostPoint = CostPoint;
01728   mtc.CostPointLayer = CostPointLayer;
01729   mtc.nearest = target_guess;
01730   if (mtc.nearest)
01731     mtc.nearest_cost =
01732       cost_to_routebox (mtc.CostPoint, mtc.CostPointLayer, mtc.nearest);
01733   else
01734     mtc.nearest_cost = EXPENSIVE;
01735   r_search (targets, NULL, __region_within_guess, __found_new_guess, &mtc);
01736   assert (mtc.nearest != NULL && mtc.nearest_cost >= 0);
01737   assert (mtc.nearest->flags.target);   /* this is a target, right? */
01738   return mtc.nearest;
01739 }
01740 
01746 static edge_t *
01747 CreateEdge (routebox_t * rb,
01748             Coord CostPointX, Coord CostPointY,
01749             cost_t cost_to_point,
01750             routebox_t * mincost_target_guess,
01751             direction_t expand_dir, rtree_t * targets)
01752 {
01753   edge_t *e;
01754   assert (__routebox_is_good (rb));
01755   e = (edge_t *)malloc (sizeof (*e));
01756   memset ((void *) e, 0, sizeof (*e));
01757   assert (e);
01758   e->rb = rb;
01759   if (rb->flags.homeless)
01760     RB_up_count (rb);
01761   e->cost_point.X = CostPointX;
01762   e->cost_point.Y = CostPointY;
01763   e->cost_to_point = cost_to_point;
01764   e->flags.via_search = 0;
01765   /* if this edge is created in response to a target, use it */
01766   if (targets)
01767     e->mincost_target =
01768       mincost_target_to_point (&e->cost_point, rb->group,
01769                                targets, mincost_target_guess);
01770   else
01771     e->mincost_target = mincost_target_guess;
01772   e->expand_dir = expand_dir;
01773   assert (e->rb && e->mincost_target);  /* valid edge? */
01774   assert (!e->flags.is_via || e->expand_dir == ALL);
01775   /* cost point should be on edge (unless this is a plane/via/conflict edge) */
01776 #if 0
01777   assert (rb->type == PLANE || rb->conflicts_with != NULL || rb->flags.is_via
01778           || rb->flags.is_thermal
01779           || ((expand_dir == NORTH || expand_dir == SOUTH) ? rb->sbox.X1 <=
01780               CostPointX && CostPointX < rb->sbox.X2
01781               && CostPointY == (expand_dir ==
01782                                 NORTH ? rb->sbox.Y1 : rb->sbox.Y2 - 1) :
01783               /* expand_dir==EAST || expand_dir==WEST */
01784               rb->sbox.Y1 <= CostPointY && CostPointY < rb->sbox.Y2 &&
01785               CostPointX == (expand_dir ==
01786                              EAST ? rb->sbox.X2 - 1 : rb->sbox.X1)));
01787 #endif
01788   assert (__edge_is_good (e));
01789   /* done */
01790   return e;
01791 }
01792 
01798 static edge_t *
01799 CreateEdge2 (routebox_t * rb, direction_t expand_dir,
01800              edge_t * previous_edge, rtree_t * targets, routebox_t * guess)
01801 {
01802   BoxType thisbox;
01803   CheapPointType thiscost, prevcost;
01804   cost_t d;
01805 
01806   assert (rb && previous_edge);
01807   /* okay, find cheapest costpoint to costpoint of previous edge */
01808   thisbox = edge_to_box (rb, expand_dir);
01809   prevcost = previous_edge->cost_point;
01810   /* find point closest to target */
01811   thiscost = closest_point_in_box (&prevcost, &thisbox);
01812   /* compute cost-to-point */
01813   d = cost_to_point_on_layer (&prevcost, &thiscost, rb->group);
01814   /* add in jog penalty */
01815   if (previous_edge->expand_dir != expand_dir)
01816     d += AutoRouteParameters.JogPenalty;
01817   /* okay, new edge! */
01818   return CreateEdge (rb, thiscost.X, thiscost.Y,
01819                      previous_edge->cost_to_point + d,
01820                      guess ? guess : previous_edge->mincost_target,
01821                      expand_dir, targets);
01822 }
01823 
01827 static edge_t *
01828 CreateViaEdge (const BoxType * area, Cardinal group,
01829                routebox_t * parent, edge_t * previous_edge,
01830                conflict_t to_site_conflict,
01831                conflict_t through_site_conflict, rtree_t * targets)
01832 {
01833   routebox_t *rb;
01834   CheapPointType costpoint;
01835   cost_t d;
01836   edge_t *ne;
01837   cost_t scale[3];
01838 
01839   scale[0] = 1;
01840   scale[1] = AutoRouteParameters.LastConflictPenalty;
01841   scale[2] = AutoRouteParameters.ConflictPenalty;
01842 
01843   assert (box_is_good (area));
01844   assert (AutoRouteParameters.with_conflicts ||
01845           (to_site_conflict == NO_CONFLICT &&
01846            through_site_conflict == NO_CONFLICT));
01847   rb = CreateExpansionArea (area, group, parent, true, previous_edge);
01848   rb->flags.is_via = 1;
01849   rb->came_from = ALL;
01850 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
01851   showroutebox (rb);
01852 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
01853   /* for planes, choose a point near the target */
01854   if (previous_edge->flags.in_plane)
01855     {
01856       routebox_t *target;
01857       CheapPointType pnt;
01858       /* find a target near this via box */
01859       pnt.X = CENTER_X (*area);
01860       pnt.Y = CENTER_Y (*area);
01861       target = mincost_target_to_point (&pnt, rb->group,
01862                                         targets,
01863                                         previous_edge->mincost_target);
01864       /* now find point near the target */
01865       pnt.X = CENTER_X (target->box);
01866       pnt.Y = CENTER_Y (target->box);
01867       costpoint = closest_point_in_routebox (&pnt, rb);
01868       /* we moved from the previous cost point through the plane which is free travel */
01869       d =
01870         (scale[through_site_conflict] *
01871          cost_to_point (&costpoint, group, &costpoint,
01872                         previous_edge->rb->group));
01873       ne =
01874         CreateEdge (rb, costpoint.X, costpoint.Y,
01875                     previous_edge->cost_to_point + d, target, ALL, NULL);
01876       ne->mincost_target = target;
01877     }
01878   else
01879     {
01880       routebox_t *target;
01881       target = previous_edge->mincost_target;
01882       costpoint = closest_point_in_routebox (&previous_edge->cost_point, rb);
01883       d =
01884         (scale[to_site_conflict] *
01885          cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
01886                                  previous_edge->rb->group)) +
01887         (scale[through_site_conflict] *
01888          cost_to_point (&costpoint, group, &costpoint,
01889                         previous_edge->rb->group));
01890       /* if the target is just this via away, then this via is cheaper */
01891       if (target->group == group &&
01892           point_in_shrunk_box (target, costpoint.X, costpoint.Y))
01893         d -= AutoRouteParameters.ViaCost / 2;
01894       ne =
01895         CreateEdge (rb, costpoint.X, costpoint.Y,
01896                     previous_edge->cost_to_point + d,
01897                     previous_edge->mincost_target, ALL, targets);
01898     }
01899   ne->flags.is_via = 1;
01900   ne->flags.via_conflict_level = to_site_conflict;
01901   assert (__edge_is_good (ne));
01902   return ne;
01903 }
01904 
01913 static edge_t *
01914 CreateEdgeWithConflicts (const BoxType * interior_edge,
01915                          routebox_t * container, edge_t * previous_edge,
01916                          cost_t cost_penalty_to_box, rtree_t * targets)
01917 {
01918   routebox_t *rb;
01919   CheapPointType costpoint;
01920   cost_t d;
01921   edge_t *ne;
01922   assert (interior_edge && container && previous_edge && targets);
01923   assert (!container->flags.homeless);
01924   assert (AutoRouteParameters.with_conflicts);
01925   assert (container->flags.touched == 0);
01926   assert (previous_edge->rb->group == container->group);
01927   /* use the caller's idea of what this box should be */
01928   rb =
01929     CreateExpansionArea (interior_edge, previous_edge->rb->group,
01930                          previous_edge->rb, true, previous_edge);
01931   path_conflicts (rb, container, true); /* crucial! */
01932   costpoint =
01933     closest_point_in_box (&previous_edge->cost_point, interior_edge);
01934   d =
01935     cost_to_point_on_layer (&costpoint, &previous_edge->cost_point,
01936                             previous_edge->rb->group);
01937   d *= cost_penalty_to_box;
01938   d += previous_edge->cost_to_point;
01939   ne = CreateEdge (rb, costpoint.X, costpoint.Y, d, NULL, ALL, targets);
01940   ne->flags.is_interior = 1;
01941   assert (__edge_is_good (ne));
01942   return ne;
01943 }
01944 
01945 static void
01946 KillEdge (void *edge)
01947 {
01948   edge_t *e = (edge_t *) edge;
01949   assert (e);
01950   if (e->rb->flags.homeless)
01951     RB_down_count (e->rb);
01952   if (e->flags.via_search)
01953     mtsFreeWork (&e->work);
01954   free (e);
01955 }
01956 
01957 static void
01958 DestroyEdge (edge_t ** e)
01959 {
01960   assert (e && *e);
01961   KillEdge (*e);
01962   *e = NULL;
01963 }
01964 
01968 static cost_t
01969 edge_cost (const edge_t * e, const cost_t too_big)
01970 {
01971   cost_t penalty = e->cost_to_point;
01972   if (e->rb->flags.is_thermal || e->rb->type == PLANE)
01973     return penalty;             /* thermals are cheap */
01974   if (penalty > too_big)
01975     return penalty;
01976 
01977   /* cost_to_routebox adds in our via correction, too. */
01978   return penalty +
01979     cost_to_routebox (&e->cost_point, e->rb->group, e->mincost_target);
01980 }
01981 
01990 static BoxType
01991 edge_to_box (const routebox_t * rb, direction_t expand_dir)
01992 {
01993   BoxType b = shrink_routebox (rb);
01994   /* narrow box down to just the appropriate edge */
01995   switch (expand_dir)
01996     {
01997     case NORTH:
01998       b.Y2 = b.Y1 + 1;
01999       break;
02000     case EAST:
02001       b.X1 = b.X2 - 1;
02002       break;
02003     case SOUTH:
02004       b.Y1 = b.Y2 - 1;
02005       break;
02006     case WEST:
02007       b.X2 = b.X1 + 1;
02008       break;
02009     default:
02010       assert (0);
02011     }
02012   /* done! */
02013   return b;
02014 }
02015 
02016 struct broken_boxes
02017 {
02018   BoxType left, center, right;
02019   bool is_valid_left, is_valid_center, is_valid_right;
02020 };
02021 
02022 static struct broken_boxes
02023 break_box_edge (const BoxType * original, direction_t which_edge,
02024                 routebox_t * breaker)
02025 {
02026   BoxType origbox, breakbox;
02027   struct broken_boxes result;
02028 
02029   assert (original && breaker);
02030 
02031   origbox = *original;
02032   breakbox = bloat_routebox (breaker);
02033   ROTATEBOX_TO_NORTH (origbox, which_edge);
02034   ROTATEBOX_TO_NORTH (breakbox, which_edge);
02035   result.right.Y1 = result.center.Y1 = result.left.Y1 = origbox.Y1;
02036   result.right.Y2 = result.center.Y2 = result.left.Y2 = origbox.Y1 + 1;
02037   /* validity of breaker is not important because the boxes are marked invalid */
02038   //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1);
02039   /* left edge piece */
02040   result.left.X1 = origbox.X1;
02041   result.left.X2 = breakbox.X1;
02042   /* center (ie blocked) edge piece */
02043   result.center.X1 = MAX (breakbox.X1, origbox.X1);
02044   result.center.X2 = MIN (breakbox.X2, origbox.X2);
02045   /* right edge piece */
02046   result.right.X1 = breakbox.X2;
02047   result.right.X2 = origbox.X2;
02048   /* validity: */
02049   result.is_valid_left = (result.left.X1 < result.left.X2);
02050   result.is_valid_center = (result.center.X1 < result.center.X2);
02051   result.is_valid_right = (result.right.X1 < result.right.X2);
02052   /* rotate back */
02053   ROTATEBOX_FROM_NORTH (result.left, which_edge);
02054   ROTATEBOX_FROM_NORTH (result.center, which_edge);
02055   ROTATEBOX_FROM_NORTH (result.right, which_edge);
02056   /* done */
02057   return result;
02058 }
02059 
02060 #ifndef NDEBUG
02061 static int
02062 share_edge (const BoxType * child, const BoxType * parent)
02063 {
02064   return
02065     (child->X1 == parent->X2 || child->X2 == parent->X1 ||
02066      child->Y1 == parent->Y2 || child->Y2 == parent->Y1) &&
02067     ((parent->X1 <= child->X1 && child->X2 <= parent->X2) ||
02068      (parent->Y1 <= child->Y1 && child->Y2 <= parent->Y2));
02069 }
02070 static int
02071 edge_intersect (const BoxType * child, const BoxType * parent)
02072 {
02073   return
02074     (child->X1 <= parent->X2) && (child->X2 >= parent->X1) &&
02075     (child->Y1 <= parent->Y2) && (child->Y2 >= parent->Y1);
02076 }
02077 #endif
02078 
02086 static routebox_t *
02087 CreateExpansionArea (const BoxType * area, Cardinal group,
02088                      routebox_t * parent,
02089                      bool relax_edge_requirements, edge_t * src_edge)
02090 {
02091   routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
02092   memset ((void *) rb, 0, sizeof (*rb));
02093   assert (area && parent);
02094   init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
02095   rb->group = group;
02096   rb->type = EXPANSION_AREA;
02097   /* should always share edge or overlap with parent */
02098   assert (relax_edge_requirements ? box_intersect (&rb->sbox, &parent->sbox)
02099           : share_edge (&rb->sbox, &parent->sbox));
02100   rb->parent.expansion_area = route_parent (parent);
02101   rb->cost_point =
02102     closest_point_in_box (&rb->parent.expansion_area->cost_point, area);
02103   rb->cost =
02104     rb->parent.expansion_area->cost +
02105     cost_to_point_on_layer (&rb->parent.expansion_area->cost_point,
02106                             &rb->cost_point, rb->group);
02107   assert (relax_edge_requirements ? edge_intersect (&rb->sbox, &parent->sbox)
02108           : share_edge (&rb->sbox, &parent->sbox));
02109   if (rb->parent.expansion_area->flags.homeless)
02110     RB_up_count (rb->parent.expansion_area);
02111   rb->flags.homeless = 1;
02112   rb->flags.nobloat = 1;
02113   rb->style = AutoRouteParameters.style;
02114   rb->conflicts_with = parent->conflicts_with;
02115 /* we will never link an EXPANSION_AREA into the nets because they
02116  * are *ONLY* used for path searching. No need to call  InitLists ()
02117  */
02118   rb->came_from = src_edge->expand_dir;
02119 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
02120   showroutebox (rb);
02121 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
02122   return rb;
02123 }
02124 
02125 /*------ Expand ------*/
02126 struct E_result
02127 {
02128   routebox_t *parent;
02129   routebox_t *n, *e, *s, *w;
02130   Coord keep, bloat;
02131   BoxType inflated, orig;
02132   int done;
02133 };
02134 
02143 static int
02144 __Expand_this_rect (const BoxType * box, void *cl)
02145 {
02146   struct E_result *res = (struct E_result *) cl;
02147   routebox_t *rb = (routebox_t *) box;
02148   BoxType rbox;
02149   Coord dn, de, ds, dw, bloat;
02150 
02151   /* we don't see conflicts already encountered */
02152   if (rb->flags.touched)
02153     return 0;
02154 
02155   /* The inflated box outer edges include its own 
02156    * track width plus its own keepaway.
02157    *
02158    * To check for intersection, we need to expand
02159    * anything with greater keepaway by its excess
02160    * keepaway.
02161    *
02162    * If something has nobloat then we need to shrink
02163    * the inflated box back and see if it still touches.
02164    */
02165 
02166   if (rb->flags.nobloat)
02167     {
02168       rbox = rb->sbox;
02169       bloat = res->bloat;
02170       if (rbox.X2 <= res->inflated.X1 + bloat ||
02171           rbox.X1 >= res->inflated.X2 - bloat ||
02172           rbox.Y1 >= res->inflated.Y2 - bloat ||
02173           rbox.Y2 <= res->inflated.Y1 + bloat)
02174         return 0;               /* doesn't touch */
02175     }
02176   else
02177     {
02178       if (rb->style->Keepaway > res->keep)
02179         rbox = bloat_box (&rb->sbox, rb->style->Keepaway - res->keep);
02180       else
02181         rbox = rb->sbox;
02182 
02183       if (rbox.X2 <= res->inflated.X1 || rbox.X1 >= res->inflated.X2
02184           || rbox.Y1 >= res->inflated.Y2 || rbox.Y2 <= res->inflated.Y1)
02185         return 0;               /* doesn't touch */
02186       bloat = 0;
02187     }
02188 
02189   /* this is an intersecting box; it has to jump through a few more hoops */
02190   if (rb == res->parent || rb->parent.expansion_area == res->parent)
02191     return 0;                   /* don't see what we came from */
02192 
02193   /* if we are expanding a source edge, don't let other sources
02194    * or their expansions stop us.
02195    */
02196 #if 1
02197   if (res->parent->flags.source)
02198     if (rb->flags.source
02199         || (rb->type == EXPANSION_AREA
02200             && rb->parent.expansion_area->flags.source))
02201       return 0;
02202 #endif
02203 
02204   /* we ignore via expansion boxes because maybe its
02205    * cheaper to get there without the via through
02206    * the path we're exploring  now.
02207    */
02208   if (rb->flags.is_via && rb->type == EXPANSION_AREA)
02209     return 0;
02210 
02211   if (rb->type == PLANE)        /* expanding inside a plane is not good */
02212     {
02213       if (rbox.X1 < res->orig.X1 && rbox.X2 > res->orig.X2 &&
02214           rbox.Y1 < res->orig.Y1 && rbox.Y2 > res->orig.Y2)
02215         {
02216           res->inflated = bloat_box (&res->orig, res->bloat);
02217           return 1;
02218         }
02219     }
02220   /* calculate the distances from original box to this blocker */
02221   dn = de = ds = dw = 0;
02222   if (!(res->done & _NORTH) && rbox.Y1 <= res->orig.Y1
02223       && rbox.Y2 > res->inflated.Y1)
02224     dn = res->orig.Y1 - rbox.Y2;
02225   if (!(res->done & _EAST) && rbox.X2 >= res->orig.X2
02226       && rbox.X1 < res->inflated.X2)
02227     de = rbox.X1 - res->orig.X2;
02228   if (!(res->done & _SOUTH) && rbox.Y2 >= res->orig.Y2
02229       && rbox.Y1 < res->inflated.Y2)
02230     ds = rbox.Y1 - res->orig.Y2;
02231   if (!(res->done & _WEST) && rbox.X1 <= res->orig.X1
02232       && rbox.X2 > res->inflated.X1)
02233     dw = res->orig.X1 - rbox.X2;
02234   if (dn <= 0 && de <= 0 && ds <= 0 && dw <= 0)
02235     return 1;
02236   /* now shrink the inflated box to the largest blocking direction */
02237   if (dn >= de && dn >= ds && dn >= dw)
02238     {
02239       res->inflated.Y1 = rbox.Y2 - bloat;
02240       res->n = rb;
02241     }
02242   else if (de >= ds && de >= dw)
02243     {
02244       res->inflated.X2 = rbox.X1 + bloat;
02245       res->e = rb;
02246     }
02247   else if (ds >= dw)
02248     {
02249       res->inflated.Y2 = rbox.Y1 + bloat;
02250       res->s = rb;
02251     }
02252   else
02253     {
02254       res->inflated.X1 = rbox.X2 - bloat;
02255       res->w = rb;
02256     }
02257   return 1;
02258 }
02259 
02260 static bool
02261 boink_box (routebox_t * rb, struct E_result *res, direction_t dir)
02262 {
02263   Coord bloat;
02264   if (rb->style->Keepaway > res->keep)
02265     bloat = res->keep - rb->style->Keepaway;
02266   else
02267     bloat = 0;
02268   if (rb->flags.nobloat)
02269     bloat = res->bloat;
02270   switch (dir)
02271     {
02272     case NORTH:
02273     case SOUTH:
02274       if (rb->sbox.X2 <= res->inflated.X1 + bloat
02275           || rb->sbox.X1 >= res->inflated.X2 - bloat)
02276         return false;
02277       return true;
02278     case EAST:
02279     case WEST:
02280       if (rb->sbox.Y1 >= res->inflated.Y2 - bloat
02281           || rb->sbox.Y2 <= res->inflated.Y1 + bloat)
02282         return false;
02283       return true;
02284       break;
02285     default:
02286       assert (0);
02287     }
02288   return false;
02289 }
02290 
02306 struct E_result *
02307 Expand (rtree_t * rtree, edge_t * e, const BoxType * box)
02308 {
02309   static struct E_result ans;
02310   int noshrink;                 /* bit field of which edges to not shrink */
02311 
02312   ans.bloat = AutoRouteParameters.bloat;
02313   ans.orig = *box;
02314   ans.n = ans.e = ans.s = ans.w = NULL;
02315 
02316   /* the inflated box must be bloated in all directions that it might
02317    * hit something in order to guarantee that we see object in the
02318    * tree it might hit. The tree holds objects bloated by their own
02319    * keepaway so we are guaranteed to honor that.
02320    */
02321   switch (e->expand_dir)
02322     {
02323     case ALL:
02324       ans.inflated.X1 = (e->rb->came_from == EAST ? ans.orig.X1 : 0);
02325       ans.inflated.Y1 = (e->rb->came_from == SOUTH ? ans.orig.Y1 : 0);
02326       ans.inflated.X2 =
02327         (e->rb->came_from == WEST ? ans.orig.X2 : PCB->MaxWidth);
02328       ans.inflated.Y2 =
02329         (e->rb->came_from == NORTH ? ans.orig.Y2 : PCB->MaxHeight);
02330       if (e->rb->came_from == NORTH)
02331         ans.done = noshrink = _SOUTH;
02332       else if (e->rb->came_from == EAST)
02333         ans.done = noshrink = _WEST;
02334       else if (e->rb->came_from == SOUTH)
02335         ans.done = noshrink = _NORTH;
02336       else if (e->rb->came_from == WEST)
02337         ans.done = noshrink = _EAST;
02338       else
02339         ans.done = noshrink = 0;
02340       break;
02341     case NORTH:
02342       ans.done = _SOUTH + _EAST + _WEST;
02343       noshrink = _SOUTH;
02344       ans.inflated.X1 = box->X1 - ans.bloat;
02345       ans.inflated.X2 = box->X2 + ans.bloat;
02346       ans.inflated.Y2 = box->Y2;
02347       ans.inflated.Y1 = 0;      /* far north */
02348       break;
02349     case NE:
02350       ans.done = _SOUTH + _WEST;
02351       noshrink = 0;
02352       ans.inflated.X1 = box->X1 - ans.bloat;
02353       ans.inflated.X2 = PCB->MaxWidth;
02354       ans.inflated.Y2 = box->Y2 + ans.bloat;
02355       ans.inflated.Y1 = 0;
02356       break;
02357     case EAST:
02358       ans.done = _NORTH + _SOUTH + _WEST;
02359       noshrink = _WEST;
02360       ans.inflated.Y1 = box->Y1 - ans.bloat;
02361       ans.inflated.Y2 = box->Y2 + ans.bloat;
02362       ans.inflated.X1 = box->X1;
02363       ans.inflated.X2 = PCB->MaxWidth;
02364       break;
02365     case SE:
02366       ans.done = _NORTH + _WEST;
02367       noshrink = 0;
02368       ans.inflated.X1 = box->X1 - ans.bloat;
02369       ans.inflated.X2 = PCB->MaxWidth;
02370       ans.inflated.Y2 = PCB->MaxHeight;
02371       ans.inflated.Y1 = box->Y1 - ans.bloat;
02372       break;
02373     case SOUTH:
02374       ans.done = _NORTH + _EAST + _WEST;
02375       noshrink = _NORTH;
02376       ans.inflated.X1 = box->X1 - ans.bloat;
02377       ans.inflated.X2 = box->X2 + ans.bloat;
02378       ans.inflated.Y1 = box->Y1;
02379       ans.inflated.Y2 = PCB->MaxHeight;
02380       break;
02381     case SW:
02382       ans.done = _NORTH + _EAST;
02383       noshrink = 0;
02384       ans.inflated.X1 = 0;
02385       ans.inflated.X2 = box->X2 + ans.bloat;
02386       ans.inflated.Y2 = PCB->MaxHeight;
02387       ans.inflated.Y1 = box->Y1 - ans.bloat;
02388       break;
02389     case WEST:
02390       ans.done = _NORTH + _SOUTH + _EAST;
02391       noshrink = _EAST;
02392       ans.inflated.Y1 = box->Y1 - ans.bloat;
02393       ans.inflated.Y2 = box->Y2 + ans.bloat;
02394       ans.inflated.X1 = 0;
02395       ans.inflated.X2 = box->X2;
02396       break;
02397     case NW:
02398       ans.done = _SOUTH + _EAST;
02399       noshrink = 0;
02400       ans.inflated.X1 = 0;
02401       ans.inflated.X2 = box->X2 + ans.bloat;
02402       ans.inflated.Y2 = box->Y2 + ans.bloat;
02403       ans.inflated.Y1 = 0;
02404       break;
02405     default:
02406       noshrink = ans.done = 0;
02407       assert (0);
02408     }
02409   ans.keep = e->rb->style->Keepaway;
02410   ans.parent = nonhomeless_parent (e->rb);
02411   r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
02412 /* because the overlaping boxes are found in random order, some blockers
02413  * may have limited edges prematurely, so we check if the blockers realy
02414  * are blocking, and make another try if not
02415  */
02416   if (ans.n && !boink_box (ans.n, &ans, NORTH))
02417     ans.inflated.Y1 = 0;
02418   else
02419     ans.done |= _NORTH;
02420   if (ans.e && !boink_box (ans.e, &ans, EAST))
02421     ans.inflated.X2 = PCB->MaxWidth;
02422   else
02423     ans.done |= _EAST;
02424   if (ans.s && !boink_box (ans.s, &ans, SOUTH))
02425     ans.inflated.Y2 = PCB->MaxHeight;
02426   else
02427     ans.done |= _SOUTH;
02428   if (ans.w && !boink_box (ans.w, &ans, WEST))
02429     ans.inflated.X1 = 0;
02430   else
02431     ans.done |= _WEST;
02432   if (ans.done != _NORTH + _EAST + _SOUTH + _WEST)
02433     {
02434       r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans);
02435     }
02436   if ((noshrink & _NORTH) == 0)
02437     ans.inflated.Y1 += ans.bloat;
02438   if ((noshrink & _EAST) == 0)
02439     ans.inflated.X2 -= ans.bloat;
02440   if ((noshrink & _SOUTH) == 0)
02441     ans.inflated.Y2 -= ans.bloat;
02442   if ((noshrink & _WEST) == 0)
02443     ans.inflated.X1 += ans.bloat;
02444   return &ans;
02445 }
02446 
02454 static int
02455 blocker_to_heap (heap_t * heap, routebox_t * rb,
02456                  BoxType * box, direction_t dir)
02457 {
02458   BoxType b = rb->sbox;
02459   if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
02460     b =
02461       bloat_box (&b,
02462                  rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
02463   b = clip_box (&b, box);
02464   assert (box_is_good (&b));
02465   /* we want to look at the blockers clockwise around the box */
02466   switch (dir)
02467     {
02468       /* we need to use the other coordinate fraction to resolve
02469        * ties since we want the shorter of the furthest
02470        * first.
02471        */
02472     case NORTH:
02473       heap_insert (heap, b.X1 - b.X1 / (b.X2 + 1.0), rb);
02474       break;
02475     case EAST:
02476       heap_insert (heap, b.Y1 - b.Y1 / (b.Y2 + 1.0), rb);
02477       break;
02478     case SOUTH:
02479       heap_insert (heap, -(b.X2 + b.X1 / (b.X2 + 1.0)), rb);
02480       break;
02481     case WEST:
02482       heap_insert (heap, -(b.Y2 + b.Y1 / (b.Y2 + 1.0)), rb);
02483       break;
02484     default:
02485       assert (0);
02486     }
02487   if (rb->flags.fixed && !rb->flags.target && !rb->flags.source)
02488     return 1;
02489   return 0;
02490 }
02491 
02497 static routebox_t *
02498 CreateBridge (const BoxType * area, routebox_t * parent, direction_t dir)
02499 {
02500   routebox_t *rb = (routebox_t *) malloc (sizeof (*rb));
02501   memset ((void *) rb, 0, sizeof (*rb));
02502   assert (area && parent);
02503   init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0);
02504   rb->group = parent->group;
02505   rb->type = EXPANSION_AREA;
02506   rb->came_from = dir;
02507   rb->cost_point = closest_point_in_box (&parent->cost_point, area);
02508   rb->cost = parent->cost + cost_to_point_on_layer (&parent->cost_point,
02509                                                     &rb->cost_point,
02510                                                     rb->group);
02511   rb->parent.expansion_area = route_parent (parent);
02512   if (rb->parent.expansion_area->flags.homeless)
02513     RB_up_count (rb->parent.expansion_area);
02514   rb->flags.homeless = 1;
02515   rb->flags.nobloat = 1;
02516   rb->style = parent->style;
02517   rb->conflicts_with = parent->conflicts_with;
02518 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES)
02519   showroutebox (rb);
02520 #endif
02521   return rb;
02522 }
02523 
02528 void
02529 moveable_edge (vector_t * result, const BoxType * box, direction_t dir,
02530                routebox_t * rb,
02531                routebox_t * blocker, edge_t * e, rtree_t * targets,
02532                struct routeone_state *s, rtree_t * tree, vector_t * area_vec)
02533 {
02534   BoxType b;
02535   assert (box_is_good (box));
02536   b = *box;
02537   /* for the cardinal directions, move the box to overlap the
02538    * the parent by 1 unit. Corner expansions overlap more
02539    * and their starting boxes are pre-prepared.
02540    * Check if anything is headed off the board edges
02541    */
02542   switch (dir)
02543     {
02544     default:
02545       break;
02546     case NORTH:
02547       b.Y2 = b.Y1;
02548       b.Y1--;
02549       if (b.Y1 <= AutoRouteParameters.bloat)
02550         return;                 /* off board edge */
02551       break;
02552     case EAST:
02553       b.X1 = b.X2;
02554       b.X2++;
02555       if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat)
02556         return;                 /* off board edge */
02557       break;
02558     case SOUTH:
02559       b.Y1 = b.Y2;
02560       b.Y2++;
02561       if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat)
02562         return;                 /* off board edge */
02563       break;
02564     case WEST:
02565       b.X2 = b.X1;
02566       b.X1--;
02567       if (b.X1 <= AutoRouteParameters.bloat)
02568         return;                 /* off board edge */
02569       break;
02570     case NE:
02571       if (b.Y1 <= AutoRouteParameters.bloat + 1
02572           && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
02573         return;                 /* off board edge */
02574       if (b.Y1 <= AutoRouteParameters.bloat + 1)
02575         dir = EAST;             /* north off board edge */
02576       if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
02577         dir = NORTH;            /* east off board edge */
02578       break;
02579     case SE:
02580       if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
02581           && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
02582         return;                 /* off board edge */
02583       if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
02584         dir = EAST;             /* south off board edge */
02585       if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1)
02586         dir = SOUTH;            /* east off board edge */
02587       break;
02588     case SW:
02589       if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1
02590           && b.X1 <= AutoRouteParameters.bloat + 1)
02591         return;                 /* off board edge */
02592       if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1)
02593         dir = WEST;             /* south off board edge */
02594       if (b.X1 <= AutoRouteParameters.bloat + 1)
02595         dir = SOUTH;            /* west off board edge */
02596       break;
02597     case NW:
02598       if (b.Y1 <= AutoRouteParameters.bloat + 1
02599           && b.X1 <= AutoRouteParameters.bloat + 1)
02600         return;                 /* off board edge */
02601       if (b.Y1 <= AutoRouteParameters.bloat + 1)
02602         dir = WEST;             /* north off board edge */
02603       if (b.X1 <= AutoRouteParameters.bloat + 1)
02604         dir = NORTH;            /* west off board edge */
02605       break;
02606     }
02607 
02608   if (!blocker)
02609     {
02610       edge_t *ne;
02611       routebox_t *nrb = CreateBridge (&b, rb, dir);
02612       /* move the cost point in corner expansions
02613        * these boxes are bigger, so move close to the target
02614        */
02615       if (dir == NE || dir == SE || dir == SW || dir == NW)
02616         {
02617           CheapPointType p;
02618           p =
02619             closest_point_in_box (&nrb->cost_point, &e->mincost_target->sbox);
02620           p = closest_point_in_box (&p, &b);
02621           nrb->cost += cost_to_point_on_layer (&p, &nrb->cost_point,
02622                                                nrb->group);
02623           nrb->cost_point = p;
02624         }
02625       ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
02626                        nrb->cost, NULL, dir, targets);
02627       vector_append (result, ne);
02628     }
02629   else if (AutoRouteParameters.with_conflicts && !blocker->flags.target
02630            && !blocker->flags.fixed && !blocker->flags.touched &&
02631            !blocker->flags.source && blocker->type != EXPANSION_AREA)
02632     {
02633       edge_t *ne;
02634       routebox_t *nrb;
02635       /* make a bridge to the edge of the blocker
02636        * in all directions from there
02637        */
02638       switch (dir)
02639         {
02640         case NORTH:
02641           b.Y1 = blocker->sbox.Y2 - 1;
02642           break;
02643         case EAST:
02644           b.X2 = blocker->sbox.X1 + 1;
02645           break;
02646         case SOUTH:
02647           b.Y2 = blocker->sbox.Y1 + 1;
02648           break;
02649         case WEST:
02650           b.X1 = blocker->sbox.X2 - 1;
02651           break;
02652         default:
02653           assert (0);
02654         }
02655       if (!box_is_good (&b))
02656         return;                 /* how did this happen ? */
02657       nrb = CreateBridge (&b, rb, dir);
02658       r_insert_entry (tree, &nrb->box, 1);
02659       vector_append (area_vec, nrb);
02660       nrb->flags.homeless = 0;  /* not homeless any more */
02661       /* mark this one as conflicted */
02662       path_conflicts (nrb, blocker, true);
02663       /* and make an expansion edge */
02664       nrb->cost_point =
02665         closest_point_in_box (&nrb->cost_point, &blocker->sbox);
02666       nrb->cost +=
02667         cost_to_point_on_layer (&nrb->parent.expansion_area->cost_point,
02668                                 &nrb->cost_point,
02669                                 nrb->group) * CONFLICT_PENALTY (blocker);
02670 
02671       ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, nrb->cost,
02672                        NULL, ALL, targets);
02673       ne->flags.is_interior = 1;
02674       vector_append (result, ne);
02675     }
02676 #if 1
02677   else if (blocker->type == EXPANSION_AREA)
02678     {
02679       if (blocker->cost < rb->cost || blocker->cost <= rb->cost +
02680           cost_to_point_on_layer (&blocker->cost_point, &rb->cost_point,
02681                                   rb->group))
02682         return;
02683       if (blocker->conflicts_with || rb->conflicts_with)
02684         return;
02685       /* does the blocker overlap this routebox ?? */
02686       /* does this re-parenting operation leave a memory leak? */
02687       if (blocker->parent.expansion_area->flags.homeless)
02688         RB_down_count (blocker->parent.expansion_area);
02689       blocker->parent.expansion_area = rb;
02690       return;
02691     }
02692 #endif
02693   else if (blocker->flags.target)
02694     {
02695       routebox_t *nrb;
02696       edge_t *ne;
02697       b = bloat_box (&b, 1);
02698       if (!box_intersect (&b, &blocker->sbox))
02699         {
02700           /* if the expansion edge stopped before touching, expand the bridge */
02701           switch (dir)
02702             {
02703             case NORTH:
02704               b.Y1 -= AutoRouteParameters.bloat + 1;
02705               break;
02706             case EAST:
02707               b.X2 += AutoRouteParameters.bloat + 1;
02708               break;
02709             case SOUTH:
02710               b.Y2 += AutoRouteParameters.bloat + 1;
02711               break;
02712             case WEST:
02713               b.X1 -= AutoRouteParameters.bloat + 1;
02714               break;
02715             default:
02716               assert (0);
02717             }
02718         }
02719       assert (box_intersect (&b, &blocker->sbox));
02720       b = shrink_box (&b, 1);
02721       nrb = CreateBridge (&b, rb, dir);
02722       r_insert_entry (tree, &nrb->box, 1);
02723       vector_append (area_vec, nrb);
02724       nrb->flags.homeless = 0;  /* not homeless any more */
02725       ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y,
02726                        nrb->cost, blocker, dir, NULL);
02727       best_path_candidate (s, ne, blocker);
02728       DestroyEdge (&ne);
02729     }
02730 }
02731 
02732 struct break_info
02733 {
02734   heap_t *heap;
02735   routebox_t *parent;
02736   BoxType box;
02737   direction_t dir;
02738   bool ignore_source;
02739 };
02740 
02741 static int
02742 __GatherBlockers (const BoxType * box, void *cl)
02743 {
02744   routebox_t *rb = (routebox_t *) box;
02745   struct break_info *bi = (struct break_info *) cl;
02746   BoxType b;
02747 
02748   if (bi->parent == rb || rb->flags.touched ||
02749       bi->parent->parent.expansion_area == rb)
02750     return 0;
02751   if (rb->flags.source && bi->ignore_source)
02752     return 0;
02753   b = rb->sbox;
02754   if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway)
02755     b =
02756       bloat_box (&b,
02757                  rb->style->Keepaway - AutoRouteParameters.style->Keepaway);
02758   if (b.X2 <= bi->box.X1 || b.X1 >= bi->box.X2
02759       || b.Y1 >= bi->box.Y2 || b.Y2 <= bi->box.Y1)
02760     return 0;
02761   return blocker_to_heap (bi->heap, rb, &bi->box, bi->dir);
02762 }
02763 
02769 static inline BoxType
02770 previous_edge (Coord last, direction_t i, const BoxType * b)
02771 {
02772   BoxType db = *b;
02773   switch (i)
02774     {
02775     case EAST:
02776       db.X1 = last;
02777       break;
02778     case SOUTH:
02779       db.Y1 = last;
02780       break;
02781     case WEST:
02782       db.X2 = last;
02783       break;
02784     default:
02785       Message ("previous edge bogus direction!");
02786       assert (0);
02787     }
02788   return db;
02789 }
02790 
02796 vector_t *
02797 BreakManyEdges (struct routeone_state * s, rtree_t * targets, rtree_t * tree,
02798                 vector_t * area_vec, struct E_result * ans, routebox_t * rb,
02799                 edge_t * e)
02800 {
02801   struct break_info bi;
02802   vector_t *edges;
02803   heap_t *heap[4];
02804   Coord first, last;
02805   Coord bloat;
02806   direction_t dir;
02807   routebox_t fake;
02808 
02809   edges = vector_create ();
02810   bi.ignore_source = rb->parent.expansion_area->flags.source;
02811   bi.parent = rb;
02812   /* we add 2 to the bloat.
02813    * 1 will get us to the actual blocker that Expand() hit
02814    * but 1 more is needed because the new expansion edges
02815    * move out by 1 so they don't overlap their parents
02816    * this extra expansion could "trap" the edge if
02817    * there is a blocker 2 units from the original rb,
02818    * it is 1 unit from the new expansion edge which
02819    * would prevent expansion. So we want to break the
02820    * edge on it now to avoid the trap.
02821    */
02822 
02823   bloat = AutoRouteParameters.bloat + 2;
02824   /* for corner expansion, we need to have a fake blocker
02825    * to prevent expansion back where we came from since
02826    * we still need to break portions of all 4 edges
02827    */
02828   if (e->expand_dir == NE || e->expand_dir == SE ||
02829       e->expand_dir == SW || e->expand_dir == NW)
02830     {
02831       BoxType *fb = (BoxType *) &fake.sbox;
02832       memset (&fake, 0, sizeof (fake));
02833       *fb = e->rb->sbox;
02834       fake.flags.fixed = 1;     /* this stops expansion there */
02835       fake.type = LINE;
02836       fake.style = AutoRouteParameters.style;
02837 #ifndef NDEBUG
02838       /* the routbox_is_good checker wants a lot more! */
02839       fake.flags.inited = 1;
02840       fb = (BoxType *) &fake.box;
02841       *fb = e->rb->sbox;
02842       fake.same_net.next = fake.same_net.prev = &fake;
02843       fake.same_subnet.next = fake.same_subnet.prev = &fake;
02844       fake.original_subnet.next = fake.original_subnet.prev = &fake;
02845       fake.different_net.next = fake.different_net.prev = &fake;
02846 #endif
02847     }
02848   /* gather all of the blockers in heaps so they can be accessed
02849    * in clockwise order, which allows finding corners that can
02850    * be expanded.
02851    */
02852   for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
02853     {
02854       /* don't break the edge we came from */
02855       if (e->expand_dir != ((dir + 2) % 4))
02856         {
02857           heap[dir] = heap_create ();
02858           bi.box = bloat_box (&rb->sbox, bloat);
02859           bi.heap = heap[dir];
02860           bi.dir = dir;
02861           /* convert to edge */
02862           switch (dir)
02863             {
02864             case NORTH:
02865               bi.box.Y2 = bi.box.Y1 + bloat + 1;
02866               /* for corner expansion, block the start edges and
02867                * limit the blocker search to only the new edge segment
02868                */
02869               if (e->expand_dir == SE || e->expand_dir == SW)
02870                 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
02871               if (e->expand_dir == SE)
02872                 bi.box.X1 = e->rb->sbox.X2;
02873               if (e->expand_dir == SW)
02874                 bi.box.X2 = e->rb->sbox.X1;
02875               rb->n = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
02876               break;
02877             case EAST:
02878               bi.box.X1 = bi.box.X2 - bloat - 1;
02879               /* corner, same as above */
02880               if (e->expand_dir == SW || e->expand_dir == NW)
02881                 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
02882               if (e->expand_dir == SW)
02883                 bi.box.Y1 = e->rb->sbox.Y2;
02884               if (e->expand_dir == NW)
02885                 bi.box.Y2 = e->rb->sbox.Y1;
02886               rb->e = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
02887               break;
02888             case SOUTH:
02889               bi.box.Y1 = bi.box.Y2 - bloat - 1;
02890               /* corner, same as above */
02891               if (e->expand_dir == NE || e->expand_dir == NW)
02892                 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
02893               if (e->expand_dir == NE)
02894                 bi.box.X1 = e->rb->sbox.X2;
02895               if (e->expand_dir == NW)
02896                 bi.box.X2 = e->rb->sbox.X1;
02897               rb->s = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
02898               break;
02899             case WEST:
02900               bi.box.X2 = bi.box.X1 + bloat + 1;
02901               /* corner, same as above */
02902               if (e->expand_dir == NE || e->expand_dir == SE)
02903                 blocker_to_heap (heap[dir], &fake, &bi.box, dir);
02904               if (e->expand_dir == SE)
02905                 bi.box.Y1 = e->rb->sbox.Y2;
02906               if (e->expand_dir == NE)
02907                 bi.box.Y2 = e->rb->sbox.Y1;
02908               rb->w = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi);
02909               break;
02910             default:
02911               assert (0);
02912             }
02913         }
02914       else
02915         heap[dir] = NULL;
02916     }
02917 #if 1
02918   rb->cost +=
02919     (rb->n + rb->e + rb->s +
02920      rb->w) * AutoRouteParameters.CongestionPenalty / box_area (rb->sbox);
02921 #endif
02922 /* now handle the blockers:
02923  * Go around the expansion area clockwise (North->East->South->West)
02924  * pulling blockers from the heap (which makes them come out in the right
02925  * order). Break the edges on the blocker and make the segments and corners
02926  * moveable as possible.
02927  */
02928   first = last = -1;
02929   for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
02930     {
02931       if (heap[dir] && !heap_is_empty (heap[dir]))
02932         {
02933           /* pull the very first one out of the heap outside of the
02934            * heap loop because it is special; it can be part of a corner
02935            */
02936           routebox_t *blk = (routebox_t *) heap_remove_smallest (heap[dir]);
02937           BoxType b = rb->sbox;
02938           struct broken_boxes broke = break_box_edge (&b, dir, blk);
02939           if (broke.is_valid_left)
02940             {
02941               /* if last > 0, then the previous edge had a segment
02942                * joining this one, so it forms a valid corner expansion
02943                */
02944               if (last > 0)
02945                 {
02946                   /* make a corner expansion */
02947                   BoxType db = b;
02948                   switch (dir)
02949                     {
02950                     case EAST:
02951                       /* possible NE expansion */
02952                       db.X1 = last;
02953                       db.Y2 = MIN (db.Y2, broke.left.Y2);
02954                       break;
02955                     case SOUTH:
02956                       /* possible SE expansion */
02957                       db.Y1 = last;
02958                       db.X1 = MAX (db.X1, broke.left.X1);
02959                       break;
02960                     case WEST:
02961                       /* possible SW expansion */
02962                       db.X2 = last;
02963                       db.Y1 = MAX (db.Y1, broke.left.Y1);
02964                       break;
02965                     default:
02966                       assert (0);
02967                       break;
02968                     }
02969                   moveable_edge (edges, &db, (direction_t)(dir + 3), rb, NULL, e, targets,
02970                                  s, NULL, NULL);
02971                 }
02972               else if (dir == NORTH)    /* north is start, so nothing "before" it */
02973                 {
02974                   /* save for a possible corner once we've
02975                    * finished circling the box
02976                    */
02977                   first = MAX (b.X1, broke.left.X2);
02978                 }
02979               else
02980                 {
02981                   /* this is just a boring straight expansion
02982                    * since the orthogonal segment was blocked
02983                    */
02984                   moveable_edge (edges, &broke.left, dir, rb, NULL, e,
02985                                  targets, s, NULL, NULL);
02986                 }
02987             }                   /* broke.is_valid_left */
02988           else if (last > 0)
02989             {
02990               /* if the last one didn't become a corner,
02991                * we still want to expand it straight out
02992                * in the direction of the previous edge,
02993                * which it belongs to. 
02994                */
02995               BoxType db = previous_edge (last, dir, &rb->sbox);
02996               moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
02997                              NULL, NULL);
02998             }
02999           if (broke.is_valid_center && !blk->flags.source)
03000             moveable_edge (edges, &broke.center, dir, rb, blk, e, targets, s,
03001                            tree, area_vec);
03002           /* this is the heap extraction loop. We break out
03003            * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can
03004            * just leave stuff in the heap when it is destroyed
03005            */
03006           while (broke.is_valid_right)
03007             {
03008               /* move the box edge to the next potential free point */
03009               switch (dir)
03010                 {
03011                 case NORTH:
03012                   last = b.X1 = MAX (broke.right.X1, b.X1);
03013                   break;
03014                 case EAST:
03015                   last = b.Y1 = MAX (broke.right.Y1, b.Y1);
03016                   break;
03017                 case SOUTH:
03018                   last = b.X2 = MIN (broke.right.X2, b.X2);
03019                   break;
03020                 case WEST:
03021                   last = b.Y2 = MIN (broke.right.Y2, b.Y2);
03022                   break;
03023                 default:
03024                   assert (0);
03025                 }
03026               if (heap_is_empty (heap[dir]))
03027                 break;
03028               blk = (routebox_t *)heap_remove_smallest (heap[dir]);
03029               broke = break_box_edge (&b, dir, blk);
03030               if (broke.is_valid_left)
03031                 moveable_edge (edges, &broke.left, dir, rb, NULL, e, targets,
03032                                s, NULL, NULL);
03033               if (broke.is_valid_center && !blk->flags.source)
03034                 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets,
03035                                s, tree, area_vec);
03036             }
03037           if (!broke.is_valid_right)
03038             last = -1;
03039         }
03040       else                      /* if (heap[dir]) */
03041         {
03042           /* nothing touched this edge! Expand the whole edge unless
03043            * (1) it hit the board edge or (2) was the source of our expansion
03044            *
03045            * for this case (of hitting nothing) we give up trying for corner
03046            * expansions because it is likely that they're not possible anyway 
03047            */
03048           if ((e->expand_dir == ALL ? e->rb->came_from : e->expand_dir) !=
03049               ((dir + 2) % 4))
03050             {
03051               /* ok, we are not going back on ourselves, and the whole edge seems free */
03052               moveable_edge (edges, &rb->sbox, dir, rb, NULL, e, targets, s,
03053                              NULL, NULL);
03054             }
03055 
03056           if (last > 0)
03057             {
03058               /* expand the leftover from the prior direction */
03059               BoxType db = previous_edge (last, dir, &rb->sbox);
03060               moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s,
03061                              NULL, NULL);
03062             }
03063           last = -1;
03064         }
03065     }                           /* for loop */
03066   /* finally, check for the NW corner now that we've come full circle */
03067   if (first > 0 && last > 0)
03068     {
03069       BoxType db = rb->sbox;
03070       db.X2 = first;
03071       db.Y2 = last;
03072       moveable_edge (edges, &db, NW, rb, NULL, e, targets, s, NULL, NULL);
03073     }
03074   else
03075     {
03076       if (first > 0)
03077         {
03078           BoxType db = rb->sbox;
03079           db.X2 = first;
03080           moveable_edge (edges, &db, NORTH, rb, NULL, e, targets, s, NULL,
03081                          NULL);
03082         }
03083       else if (last > 0)
03084         {
03085           BoxType db = rb->sbox;
03086           db.Y2 = last;
03087           moveable_edge (edges, &db, WEST, rb, NULL, e, targets, s, NULL,
03088                          NULL);
03089         }
03090     }
03091   /* done with all expansion edges of this box */
03092   for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir))
03093     {
03094       if (heap[dir])
03095         heap_destroy (&heap[dir]);
03096     }
03097   return edges;
03098 }
03099 
03100 static routebox_t *
03101 rb_source (routebox_t * rb)
03102 {
03103   while (rb && !rb->flags.source)
03104     {
03105       assert (rb->type == EXPANSION_AREA);
03106       rb = rb->parent.expansion_area;
03107     }
03108   assert (rb);
03109   return rb;
03110 }
03111 
03112 /* ------------ */
03113 
03114 struct foib_info
03115 {
03116   const BoxType *box;
03117   routebox_t *intersect;
03118   jmp_buf env;
03119 };
03120 
03121 static int
03122 foib_rect_in_reg (const BoxType * box, void *cl)
03123 {
03124   struct foib_info *foib = (struct foib_info *) cl;
03125   BoxType rbox;
03126   routebox_t *rb = (routebox_t *) box;
03127   if (rb->flags.touched)
03128     return 0;
03129 //  if (rb->type == EXPANSION_AREA && !rb->flags.is_via)
03130   //   return 0;
03131   rbox = bloat_routebox (rb);
03132   if (!box_intersect (&rbox, foib->box))
03133     return 0;
03134   /* this is an intersector! */
03135   foib->intersect = (routebox_t *) box;
03136   longjmp (foib->env, 1);       /* skip to the end! */
03137   return 1;
03138 }
03139 static routebox_t *
03140 FindOneInBox (rtree_t * rtree, routebox_t * rb)
03141 {
03142   struct foib_info foib;
03143   BoxType r;
03144 
03145   r = rb->sbox;
03146   foib.box = &r;
03147   foib.intersect = NULL;
03148 
03149   if (setjmp (foib.env) == 0)
03150     r_search (rtree, &r, NULL, foib_rect_in_reg, &foib);
03151   return foib.intersect;
03152 }
03153 
03154 struct therm_info
03155 {
03156   routebox_t *plane;
03157   BoxType query;
03158   jmp_buf env;
03159 };
03160 static int
03161 ftherm_rect_in_reg (const BoxType * box, void *cl)
03162 {
03163   routebox_t *rbox = (routebox_t *) box;
03164   struct therm_info *ti = (struct therm_info *) cl;
03165   BoxType sq, sb;
03166 
03167   if (rbox->type != PIN && rbox->type != VIA && rbox->type != VIA_SHADOW)
03168     return 0;
03169   if (rbox->group != ti->plane->group)
03170     return 0;
03171 
03172   sb = shrink_routebox (rbox);
03173   switch (rbox->type)
03174     {
03175     case PIN:
03176       sq = shrink_box (&ti->query, rbox->parent.pin->Thickness);
03177       if (!box_intersect (&sb, &sq))
03178         return 0;
03179       sb.X1 = rbox->parent.pin->X;
03180       sb.Y1 = rbox->parent.pin->Y;
03181       break;
03182     case VIA:
03183       if (rbox->flags.fixed)
03184         {
03185           sq = shrink_box (&ti->query, rbox->parent.via->Thickness);
03186           sb.X1 = rbox->parent.pin->X;
03187           sb.Y1 = rbox->parent.pin->Y;
03188         }
03189       else
03190         {
03191           sq = shrink_box (&ti->query, rbox->style->Diameter);
03192           sb.X1 = CENTER_X (sb);
03193           sb.Y1 = CENTER_Y (sb);
03194         }
03195       if (!box_intersect (&sb, &sq))
03196         return 0;
03197       break;
03198     case VIA_SHADOW:
03199       sq = shrink_box (&ti->query, rbox->style->Diameter);
03200       if (!box_intersect (&sb, &sq))
03201         return 0;
03202       sb.X1 = CENTER_X (sb);
03203       sb.Y1 = CENTER_Y (sb);
03204       break;
03205     default:
03206       assert (0);
03207     }
03208   ti->plane = rbox;
03209   longjmp (ti->env, 1);
03210   return 1;
03211 }
03212 
03217 routebox_t *
03218 FindThermable (rtree_t * rtree, routebox_t * rb)
03219 {
03220   struct therm_info info;
03221 
03222   info.plane = rb;
03223   info.query = shrink_routebox (rb);
03224 
03225   if (setjmp (info.env) == 0)
03226     {
03227       r_search (rtree, &info.query, NULL, ftherm_rect_in_reg, &info);
03228       return NULL;
03229     }
03230   return info.plane;
03231 }
03232 
03237 static void
03238 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y,
03239                 Cardinal group, Cardinal layer, routebox_t * subnet,
03240                 bool is_bad)
03241 {
03242   routebox_t *rb;
03243   rb = (routebox_t *) malloc (sizeof (*rb));
03244   memset ((void *) rb, 0, sizeof (*rb));
03245   init_const_box (rb, X, Y, X + 1, Y + 1, 0);
03246   rb->group = group;
03247   rb->layer = layer;
03248   rb->flags.fixed = 0;
03249   rb->flags.is_bad = is_bad;
03250   rb->flags.is_odd = AutoRouteParameters.is_odd;
03251   rb->flags.circular = 0;
03252   rb->style = AutoRouteParameters.style;
03253   rb->type = THERMAL;
03254   InitLists (rb);
03255   MergeNets (rb, subnet, NET);
03256   MergeNets (rb, subnet, SUBNET);
03257   /* add it to the r-tree, this may be the whole route! */
03258   r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
03259   rb->flags.homeless = 0;
03260 }
03261 
03262 static void
03263 RD_DrawVia (routedata_t * rd, Coord X, Coord Y,
03264             Coord radius, routebox_t * subnet, bool is_bad)
03265 {
03266   routebox_t *rb, *first_via = NULL;
03267   int i;
03268   int ka = AutoRouteParameters.style->Keepaway;
03269   PinType *live_via = NULL;
03270 
03271   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
03272     {
03273        live_via = CreateNewVia (PCB->Data, X, Y, radius * 2,
03274                                 2 * AutoRouteParameters.style->Keepaway, 0,
03275                                 AutoRouteParameters.style->Hole, NULL,
03276                                 MakeFlags (0));
03277        if (live_via != NULL)
03278          DrawVia (live_via);
03279     }
03280 
03281   /* a via cuts through every layer group */
03282   for (i = 0; i < max_group; i++)
03283     {
03284       if (!is_layer_group_active[i])
03285         continue;
03286       rb = (routebox_t *) malloc (sizeof (*rb));
03287       memset ((void *) rb, 0, sizeof (*rb));
03288       init_const_box (rb,
03289                       /*X1 */ X - radius, /*Y1 */ Y - radius,
03290                       /*X2 */ X + radius + 1, /*Y2 */ Y + radius + 1, ka);
03291       rb->group = i;
03292       rb->flags.fixed = 0;      /* indicates that not on PCB yet */
03293       rb->flags.is_odd = AutoRouteParameters.is_odd;
03294       rb->flags.is_bad = is_bad;
03295       rb->came_from = ALL;
03296       rb->flags.circular = true;
03297       rb->style = AutoRouteParameters.style;
03298       rb->pass = AutoRouteParameters.pass;
03299       if (first_via == NULL)
03300         {
03301           rb->type = VIA;
03302           rb->parent.via = NULL;        /* indicates that not on PCB yet */
03303           first_via = rb;
03304           /* only add the first via to mtspace, not the shadows too */
03305           mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
03306                        rb->style->Keepaway);
03307         }
03308       else
03309         {
03310           rb->type = VIA_SHADOW;
03311           rb->parent.via_shadow = first_via;
03312         }
03313       InitLists (rb);
03314       /* add these to proper subnet. */
03315       MergeNets (rb, subnet, NET);
03316       MergeNets (rb, subnet, SUBNET);
03317       assert (__routebox_is_good (rb));
03318       /* and add it to the r-tree! */
03319       r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
03320       rb->flags.homeless = 0;   /* not homeless anymore */
03321       rb->livedraw_obj.via = live_via;
03322     }
03323 }
03324 static void
03325 RD_DrawLine (routedata_t * rd,
03326              Coord X1, Coord Y1, Coord X2,
03327              Coord Y2, Coord halfthick, Cardinal group,
03328              routebox_t * subnet, bool is_bad, bool is_45)
03329 {
03330   /* we hold the line in a queue to concatenate segments that
03331    * ajoin one another. That reduces the number of things in
03332    * the trees and allows conflict boxes to be larger, both of
03333    * which are really useful.
03334    */
03335   static Coord qX1 = -1, qY1, qX2, qY2;
03336   static Coord qhthick;
03337   static Cardinal qgroup;
03338   static bool qis_45, qis_bad;
03339   static routebox_t *qsn;
03340 
03341   routebox_t *rb;
03342   Coord ka = AutoRouteParameters.style->Keepaway;
03343 
03344   /* don't draw zero-length segments. */
03345   if (X1 == X2 && Y1 == Y2)
03346     return;
03347   if (qX1 == -1)                /* first ever */
03348     {
03349       qX1 = X1;
03350       qY1 = Y1;
03351       qX2 = X2;
03352       qY2 = Y2;
03353       qhthick = halfthick;
03354       qgroup = group;
03355       qis_45 = is_45;
03356       qis_bad = is_bad;
03357       qsn = subnet;
03358       return;
03359     }
03360   /* Check if the lines concatenat. We only check the
03361    * normal expected nextpoint=lastpoint condition 
03362    */
03363   if (X1 == qX2 && Y1 == qY2 && qhthick == halfthick && qgroup == group)
03364     {
03365       if (qX1 == qX2 && X1 == X2)       /* everybody on the same X here */
03366         {
03367           qY2 = Y2;
03368           return;
03369         }
03370       if (qY1 == qY2 && Y1 == Y2)       /* same Y all around */
03371         {
03372           qX2 = X2;
03373           return;
03374         }
03375     }
03376   /* dump the queue, no match here */
03377   if (qX1 == -1)
03378     return;                     /* but not this! */
03379   rb = (routebox_t *) malloc (sizeof (*rb));
03380   memset ((void *) rb, 0, sizeof (*rb));
03381   assert (is_45 ? (ABS (qX2 - qX1) == ABS (qY2 - qY1))  /* line must be 45-degrees */
03382           : (qX1 == qX2 || qY1 == qY2) /* line must be ortho */ );
03383   init_const_box (rb,
03384                   /*X1 */ MIN (qX1, qX2) - qhthick,
03385                   /*Y1 */ MIN (qY1, qY2) - qhthick,
03386                   /*X2 */ MAX (qX1, qX2) + qhthick + 1,
03387                   /*Y2 */ MAX (qY1, qY2) + qhthick + 1, ka);
03388   rb->group = qgroup;
03389   rb->type = LINE;
03390   rb->parent.line = NULL;       /* indicates that not on PCB yet */
03391   rb->flags.fixed = 0;          /* indicates that not on PCB yet */
03392   rb->flags.is_odd = AutoRouteParameters.is_odd;
03393   rb->flags.is_bad = qis_bad;
03394   rb->came_from = ALL;
03395   rb->flags.homeless = 0;       /* we're putting this in the tree */
03396   rb->flags.nonstraight = qis_45;
03397   rb->flags.bl_to_ur = ((qX2 >= qX1 && qY2 <= qY1)
03398                         || (qX2 <= qX1 && qY2 >= qY1));
03399   rb->style = AutoRouteParameters.style;
03400   rb->pass = AutoRouteParameters.pass;
03401   InitLists (rb);
03402   /* add these to proper subnet. */
03403   MergeNets (rb, qsn, NET);
03404   MergeNets (rb, qsn, SUBNET);
03405   assert (__routebox_is_good (rb));
03406   /* and add it to the r-tree! */
03407   r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1);
03408 
03409   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
03410     {
03411       LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
03412       LineType *line = CreateNewLineOnLayer (layer, qX1, qY1, qX2, qY2,
03413                                              2 * qhthick, 0, MakeFlags (0));
03414       rb->livedraw_obj.line = line;
03415       if (line != NULL)
03416         DrawLine (layer, line);
03417     }
03418 
03419   /* and to the via space structures */
03420   if (AutoRouteParameters.use_vias)
03421     mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN,
03422                  rb->style->Keepaway);
03423   usedGroup[rb->group] = true;
03424   /* and queue this one */
03425   qX1 = X1;
03426   qY1 = Y1;
03427   qX2 = X2;
03428   qY2 = Y2;
03429   qhthick = halfthick;
03430   qgroup = group;
03431   qis_45 = is_45;
03432   qis_bad = is_bad;
03433   qsn = subnet;
03434 }
03435 
03436 static bool
03437 RD_DrawManhattanLine (routedata_t * rd,
03438                       const BoxType * box1, const BoxType * box2,
03439                       CheapPointType start, CheapPointType end,
03440                       Coord halfthick, Cardinal group,
03441                       routebox_t * subnet, bool is_bad, bool last_was_x)
03442 {
03443   CheapPointType knee = start;
03444   if (end.X == start.X)
03445     {
03446       RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
03447                    subnet, is_bad, false);
03448       return false;
03449     }
03450   else if (end.Y == start.Y)
03451     {
03452       RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group,
03453                    subnet, is_bad, false);
03454       return true;
03455     }
03456   /* find where knee belongs */
03457   if (point_in_box (box1, end.X, start.Y)
03458       || point_in_box (box2, end.X, start.Y))
03459     {
03460       knee.X = end.X;
03461       knee.Y = start.Y;
03462     }
03463   else
03464     {
03465       knee.X = start.X;
03466       knee.Y = end.Y;
03467     }
03468   if ((knee.X == end.X && !last_was_x) &&
03469       (point_in_box (box1, start.X, end.Y)
03470        || point_in_box (box2, start.X, end.Y)))
03471     {
03472       knee.X = start.X;
03473       knee.Y = end.Y;
03474     }
03475   assert (AutoRouteParameters.is_smoothing
03476           || point_in_closed_box (box1, knee.X, knee.Y)
03477           || point_in_closed_box (box2, knee.X, knee.Y));
03478 
03479   if (1 || !AutoRouteParameters.is_smoothing)
03480     {
03481       /* draw standard manhattan paths */
03482       RD_DrawLine (rd, start.X, start.Y, knee.X, knee.Y, halfthick, group,
03483                    subnet, is_bad, false);
03484       RD_DrawLine (rd, knee.X, knee.Y, end.X, end.Y, halfthick, group,
03485                    subnet, is_bad, false);
03486     }
03487   else
03488     {
03489       /* draw 45-degree path across knee */
03490       Coord len45 = MIN (ABS (start.X - end.X), ABS (start.Y - end.Y));
03491       CheapPointType kneestart = knee, kneeend = knee;
03492       if (kneestart.X == start.X)
03493         kneestart.Y += (kneestart.Y > start.Y) ? -len45 : len45;
03494       else
03495         kneestart.X += (kneestart.X > start.X) ? -len45 : len45;
03496       if (kneeend.X == end.X)
03497         kneeend.Y += (kneeend.Y > end.Y) ? -len45 : len45;
03498       else
03499         kneeend.X += (kneeend.X > end.X) ? -len45 : len45;
03500       RD_DrawLine (rd, start.X, start.Y, kneestart.X, kneestart.Y, halfthick,
03501                    group, subnet, is_bad, false);
03502       RD_DrawLine (rd, kneestart.X, kneestart.Y, kneeend.X, kneeend.Y,
03503                    halfthick, group, subnet, is_bad, true);
03504       RD_DrawLine (rd, kneeend.X, kneeend.Y, end.X, end.Y, halfthick, group,
03505                    subnet, is_bad, false);
03506     }
03507   return (knee.X != end.X);
03508 }
03509 
03510 /* for smoothing, don't pack traces to min clearance gratuitously */
03511 #if 0
03512 static void
03513 add_clearance (CheapPointType * nextpoint, const BoxType * b)
03514 {
03515   if (nextpoint->X == b->X1)
03516     {
03517       if (nextpoint->X +
03518           AutoRouteParameters.style->Keepaway < (b->X1 + b->X2) / 2)
03519         nextpoint->X += AutoRouteParameters.style->Keepaway;
03520       else
03521         nextpoint->X = (b->X1 + b->X2) / 2;
03522     }
03523   else if (nextpoint->X == b->X2)
03524     {
03525       if (nextpoint->X -
03526           AutoRouteParameters.style->Keepaway > (b->X1 + b->X2) / 2)
03527         nextpoint->X -= AutoRouteParameters.style->Keepaway;
03528       else
03529         nextpoint->X = (b->X1 + b->X2) / 2;
03530     }
03531   else if (nextpoint->Y == b->Y1)
03532     {
03533       if (nextpoint->Y +
03534           AutoRouteParameters.style->Keepaway < (b->Y1 + b->Y2) / 2)
03535         nextpoint->Y += AutoRouteParameters.style->Keepaway;
03536       else
03537         nextpoint->Y = (b->Y1 + b->Y2) / 2;
03538     }
03539   else if (nextpoint->Y == b->Y2)
03540     {
03541       if (nextpoint->Y -
03542           AutoRouteParameters.style->Keepaway > (b->Y1 + b->Y2) / 2)
03543         nextpoint->Y -= AutoRouteParameters.style->Keepaway;
03544       else
03545         nextpoint->Y = (b->Y1 + b->Y2) / 2;
03546     }
03547 }
03548 #endif
03549 
03564 static void
03565 TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target,
03566            routebox_t * subnet, bool is_bad)
03567 {
03568   bool last_x = false;
03569   Coord halfwidth = HALF_THICK (AutoRouteParameters.style->Thick);
03570   Coord radius = HALF_THICK (AutoRouteParameters.style->Diameter);
03571   CheapPointType lastpoint, nextpoint;
03572   routebox_t *lastpath;
03573   BoxType b;
03574 
03575   assert (subnet->style == AutoRouteParameters.style);
03576   /*XXX: because we round up odd thicknesses, there's the possibility that
03577    * a connecting line end-point might be 0.005 mil off the "real" edge.
03578    * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
03579 
03580   /* if we start with a thermal the target was a plane
03581    * or the target was a pin and the source a plane
03582    * in which case this thermal is the whole path
03583    */
03584   if (path->flags.is_thermal)
03585     {
03586       /* the target was a plane, so we need to find a good spot for the via
03587        * now. It's logical to place it close to the source box which
03588        * is where we're utlimately headed on this path. However, it
03589        * must reside in the plane as well as the via area too. 
03590        */
03591       nextpoint.X = CENTER_X (path->sbox);
03592       nextpoint.Y = CENTER_Y (path->sbox);
03593       if (path->parent.expansion_area->flags.is_via)
03594         {
03595           TargetPoint (&nextpoint, rb_source (path));
03596           /* nextpoint is the middle of the source terminal now */
03597           b = clip_box (&path->sbox, &path->parent.expansion_area->sbox);
03598           nextpoint = closest_point_in_box (&nextpoint, &b);
03599           /* now it's in the via and plane near the source */
03600         }
03601       else                      /* no via coming, target must have been a pin */
03602         {
03603           assert (target->type == PIN);
03604           TargetPoint (&nextpoint, target);
03605         }
03606       assert (point_in_box (&path->sbox, nextpoint.X, nextpoint.Y));
03607       RD_DrawThermal (rd, nextpoint.X, nextpoint.Y, path->group,
03608                       path->layer, subnet, is_bad);
03609     }
03610   else
03611     {
03612       /* start from best place of target box */
03613       lastpoint.X = CENTER_X (target->sbox);
03614       lastpoint.Y = CENTER_Y (target->sbox);
03615       TargetPoint (&lastpoint, target);
03616       if (AutoRouteParameters.last_smooth
03617           && box_in_box (&path->sbox, &target->sbox))
03618         path = path->parent.expansion_area;
03619       b = path->sbox;
03620       if (path->flags.circular)
03621         b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
03622       nextpoint = closest_point_in_box (&lastpoint, &b);
03623       if (AutoRouteParameters.last_smooth)
03624         RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
03625                      halfwidth, path->group, subnet, is_bad, TRUE);
03626       else
03627         last_x = RD_DrawManhattanLine (rd, &target->sbox, &path->sbox,
03628                                        lastpoint, nextpoint, halfwidth,
03629                                        path->group, subnet, is_bad, last_x);
03630     }
03631 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
03632   showroutebox (path);
03633 #if defined(ROUTE_VERBOSE)
03634   pcb_printf ("TRACEPOINT start %#mD\n", nextpoint.X, nextpoint.Y);
03635 #endif
03636 #endif
03637 
03638   do
03639     {
03640       lastpoint = nextpoint;
03641       lastpath = path;
03642       assert (path->type == EXPANSION_AREA);
03643       path = path->parent.expansion_area;
03644       b = path->sbox;
03645       if (path->flags.circular)
03646         b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5);
03647       assert (b.X1 != b.X2 && b.Y1 != b.Y2);    /* need someplace to put line! */
03648       /* find point on path perimeter closest to last point */
03649       /* if source terminal, try to hit a good place */
03650       nextpoint = closest_point_in_box (&lastpoint, &b);
03651 #if 0
03652       /* leave more clearance if this is a smoothing pass */
03653       if (AutoRouteParameters.is_smoothing &&
03654           (nextpoint.X != lastpoint.X || nextpoint.Y != lastpoint.Y))
03655         add_clearance (&nextpoint, &b);
03656 #endif
03657       if (path->flags.source && path->type != PLANE)
03658         TargetPoint (&nextpoint, path);
03659       assert (point_in_box (&lastpath->box, lastpoint.X, lastpoint.Y));
03660       assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
03661 #if defined(ROUTE_DEBUG_VERBOSE)
03662       printf ("TRACEPATH: ");
03663       DumpRouteBox (path);
03664       pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n",
03665               lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
03666               path->group);
03667 #endif
03668 
03669       /* draw orthogonal lines from lastpoint to nextpoint */
03670       /* knee is placed in lastpath box */
03671       /* should never cause line to leave union of lastpath/path boxes */
03672       if (AutoRouteParameters.last_smooth)
03673         RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y,
03674                      halfwidth, path->group, subnet, is_bad, TRUE);
03675       else
03676         last_x = RD_DrawManhattanLine (rd, &lastpath->sbox, &path->sbox,
03677                                        lastpoint, nextpoint, halfwidth,
03678                                        path->group, subnet, is_bad, last_x);
03679       if (path->flags.is_via)
03680         {                       /* if via, then add via */
03681 #ifdef ROUTE_VERBOSE
03682           printf (" (vias)");
03683 #endif
03684           assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y));
03685           RD_DrawVia (rd, nextpoint.X, nextpoint.Y, radius, subnet, is_bad);
03686         }
03687 
03688       assert (lastpath->flags.is_via || path->group == lastpath->group);
03689 
03690 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
03691       showroutebox (path);
03692 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
03693       /* if this is connected to a plane, draw the thermal */
03694       if (path->flags.is_thermal || path->type == PLANE)
03695         RD_DrawThermal (rd, lastpoint.X, lastpoint.Y, path->group,
03696                         path->layer, subnet, is_bad);
03697       /* when one hop from the source, make an extra path in *this* box */
03698       if (path->type == EXPANSION_AREA
03699           && path->parent.expansion_area->flags.source
03700           && path->parent.expansion_area->type != PLANE)
03701         {
03702           /* find special point on source (if it exists) */
03703           if (TargetPoint (&lastpoint, path->parent.expansion_area))
03704             {
03705               lastpoint = closest_point_in_routebox (&lastpoint, path);
03706               b = shrink_routebox (path);
03707 #if 0
03708               if (AutoRouteParameters.is_smoothing)
03709                 add_clearance (&lastpoint, &b);
03710 #else
03711               if (AutoRouteParameters.last_smooth)
03712                 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X,
03713                              nextpoint.Y, halfwidth, path->group, subnet,
03714                              is_bad, TRUE);
03715               else
03716 #endif
03717                 last_x = RD_DrawManhattanLine (rd, &b, &b,
03718                                                nextpoint, lastpoint,
03719                                                halfwidth, path->group, subnet,
03720                                                is_bad, last_x);
03721 #if defined(ROUTE_DEBUG_VERBOSE)
03722               printf ("TRACEPATH: ");
03723               DumpRouteBox (path);
03724               pcb_printf
03725                 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n",
03726                  nextpoint.X, nextpoint.Y, lastpoint.X, lastpoint.Y,
03727                  path->group);
03728 #endif
03729 
03730               nextpoint = lastpoint;
03731             }
03732         }
03733     }
03734   while (!path->flags.source);
03735   /* flush the line queue */
03736   RD_DrawLine (rd, -1, 0, 0, 0, 0, 0, NULL, false, false);
03737 
03738   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
03739     Draw ();
03740 
03741 #ifdef ROUTE_DEBUG
03742   if (ddraw != NULL)
03743     gui->flush_debug_draw ();
03744 #endif
03745 }
03746 
03750 static void
03751 CreateSearchEdge (struct routeone_state *s, vetting_t * work, edge_t * parent,
03752                   routebox_t * rb, conflict_t conflict, rtree_t * targets,
03753                   bool in_plane)
03754 {
03755   routebox_t *target;
03756   BoxType b;
03757   cost_t cost;
03758   assert (__routebox_is_good (rb));
03759   /* find the cheapest target */
03760 #if 0
03761   target =
03762     mincost_target_to_point (&parent->cost_point, max_group + 1, targets,
03763                              parent->mincost_target);
03764 #else
03765   target = parent->mincost_target;
03766 #endif
03767   b = shrink_routebox (target);
03768   cost =
03769     parent->cost_to_point + AutoRouteParameters.ViaCost +
03770     cost_to_layerless_box (&rb->cost_point, 0, &b);
03771   if (cost < s->best_cost)
03772     {
03773       edge_t *ne;
03774       ne = (edge_t *)malloc (sizeof (*ne));
03775       memset ((void *) ne, 0, sizeof (*ne));
03776       assert (ne);
03777       ne->flags.via_search = 1;
03778       ne->flags.in_plane = in_plane;
03779       ne->rb = rb;
03780       if (rb->flags.homeless)
03781         RB_up_count (rb);
03782       ne->work = work;
03783       ne->mincost_target = target;
03784       ne->flags.via_conflict_level = conflict;
03785       ne->cost_to_point = parent->cost_to_point;
03786       ne->cost_point = parent->cost_point;
03787       ne->cost = cost;
03788       heap_insert (s->workheap, ne->cost, ne);
03789     }
03790   else
03791     {
03792       mtsFreeWork (&work);
03793     }
03794 }
03795 
03796 static void
03797 add_or_destroy_edge (struct routeone_state *s, edge_t * e)
03798 {
03799   e->cost = edge_cost (e, s->best_cost);
03800   assert (__edge_is_good (e));
03801   assert (is_layer_group_active[e->rb->group]);
03802   if (e->cost < s->best_cost)
03803     heap_insert (s->workheap, e->cost, e);
03804   else
03805     DestroyEdge (&e);
03806 }
03807 
03808 static void
03809 best_path_candidate (struct routeone_state *s,
03810                      edge_t * e, routebox_t * best_target)
03811 {
03812   e->cost = edge_cost (e, EXPENSIVE);
03813   if (s->best_path == NULL || e->cost < s->best_cost)
03814     {
03815 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE)
03816       printf ("New best path seen! cost = %f\n", e->cost);
03817 #endif
03818       /* new best path! */
03819       if (s->best_path && s->best_path->flags.homeless)
03820         RB_down_count (s->best_path);
03821       s->best_path = e->rb;
03822       s->best_target = best_target;
03823       s->best_cost = e->cost;
03824       assert (s->best_cost >= 0);
03825       /* don't free this when we destroy edge! */
03826       if (s->best_path->flags.homeless)
03827         RB_up_count (s->best_path);
03828     }
03829 }
03830 
03831 
03835 struct routeone_via_site_state
03836 {
03837   vector_t *free_space_vec;
03838   vector_t *lo_conflict_space_vec;
03839   vector_t *hi_conflict_space_vec;
03840 };
03841 
03842 void
03843 add_via_sites (struct routeone_state *s,
03844                struct routeone_via_site_state *vss,
03845                mtspace_t * mtspace, routebox_t * within,
03846                conflict_t within_conflict_level, edge_t * parent_edge,
03847                rtree_t * targets, Coord shrink, bool in_plane)
03848 {
03849   Coord radius, keepaway;
03850   vetting_t *work;
03851   BoxType region = shrink_routebox (within);
03852   shrink_box (&region, shrink);
03853 
03854   radius = HALF_THICK (AutoRouteParameters.style->Diameter);
03855   keepaway = AutoRouteParameters.style->Keepaway;
03856   assert (AutoRouteParameters.use_vias);
03857   /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
03858      XXX: routing with conflicts may poke over edge. */
03859 
03860   /* ask for a via box near our cost_point first */
03861   work = mtspace_query_rect (mtspace, &region, radius, keepaway,
03862                              NULL, vss->free_space_vec,
03863                              vss->lo_conflict_space_vec,
03864                              vss->hi_conflict_space_vec,
03865                              AutoRouteParameters.is_odd,
03866                              AutoRouteParameters.with_conflicts,
03867                              &parent_edge->cost_point);
03868   if (!work)
03869     return;
03870   CreateSearchEdge (s, work, parent_edge, within, within_conflict_level,
03871                     targets, in_plane);
03872 }
03873 
03874 void
03875 do_via_search (edge_t * search, struct routeone_state *s,
03876                struct routeone_via_site_state *vss, mtspace_t * mtspace,
03877                rtree_t * targets)
03878 {
03879   int i, j, count = 0;
03880   Coord radius, keepaway;
03881   vetting_t *work;
03882   routebox_t *within;
03883   conflict_t within_conflict_level;
03884 
03885   radius = HALF_THICK (AutoRouteParameters.style->Diameter);
03886   keepaway = AutoRouteParameters.style->Keepaway;
03887   work = mtspace_query_rect (mtspace, NULL, 0, 0,
03888                              search->work, vss->free_space_vec,
03889                              vss->lo_conflict_space_vec,
03890                              vss->hi_conflict_space_vec,
03891                              AutoRouteParameters.is_odd,
03892                              AutoRouteParameters.with_conflicts, NULL);
03893   within = search->rb;
03894   within_conflict_level = search->flags.via_conflict_level;
03895   for (i = 0; i < 3; i++)
03896     {
03897       vector_t *v =
03898         (i == NO_CONFLICT ? vss->free_space_vec :
03899          i == LO_CONFLICT ? vss->lo_conflict_space_vec :
03900          i == HI_CONFLICT ? vss->hi_conflict_space_vec : NULL);
03901       assert (v);
03902       while (!vector_is_empty (v))
03903         {
03904           BoxType cliparea;
03905           BoxType *area = (BoxType *)vector_remove_last (v);
03906           if (!(i == NO_CONFLICT || AutoRouteParameters.with_conflicts))
03907             {
03908               free (area);
03909               continue;
03910             }
03911           /* answers are bloated by radius + keepaway */
03912           cliparea = shrink_box (area, radius + keepaway);
03913           close_box (&cliparea);
03914           free (area);
03915           assert (box_is_good (&cliparea));
03916           count++;
03917           for (j = 0; j < max_group; j++)
03918             {
03919               edge_t *ne;
03920               if (j == within->group || !is_layer_group_active[j])
03921                 continue;
03922               ne = CreateViaEdge (&cliparea, j, within, search,
03923                                   within_conflict_level, (conflict_t)i, targets);
03924               add_or_destroy_edge (s, ne);
03925             }
03926         }
03927     }
03928   /* prevent freeing of work when this edge is destroyed */
03929   search->flags.via_search = 0;
03930   if (!work)
03931     return;
03932   CreateSearchEdge (s, work, search, within, within_conflict_level, targets,
03933                     search->flags.in_plane);
03934   assert (vector_is_empty (vss->free_space_vec));
03935   assert (vector_is_empty (vss->lo_conflict_space_vec));
03936   assert (vector_is_empty (vss->hi_conflict_space_vec));
03937 }
03938 
03939 /* vector of expansion areas to be eventually removed from r-tree
03940  * this is a global for troubleshooting
03941  */
03942 vector_t *area_vec;
03943 
03944 /* some routines for use in gdb while debugging */
03945 #if defined(ROUTE_DEBUG)
03946 static void
03947 list_conflicts (routebox_t * rb)
03948 {
03949   int i, n;
03950   if (!rb->conflicts_with)
03951     return;
03952   n = vector_size (rb->conflicts_with);
03953   for (i = 0; i < n; i++)
03954     printf ("%p, ", vector_element (rb->conflicts_with, i));
03955 }
03956 
03957 static void
03958 show_area_vec (int lay)
03959 {
03960   int n, save;
03961 
03962   if (!area_vec)
03963     return;
03964   save = showboxen;
03965   showboxen = lay;
03966   for (n = 0; n < vector_size (area_vec); n++)
03967     {
03968       routebox_t *rb = (routebox_t *) vector_element (area_vec, n);
03969       showroutebox (rb);
03970     }
03971   showboxen = save;
03972 }
03973 
03974 static bool
03975 net_id (routebox_t * rb, long int id)
03976 {
03977   routebox_t *p;
03978   LIST_LOOP (rb, same_net, p);
03979   if (p->flags.source && p->parent.pad->ID == id)
03980     return true;
03981   END_LOOP;
03982   return false;
03983 }
03984 
03985 static void
03986 trace_parents (routebox_t * rb)
03987 {
03988   while (rb && rb->type == EXPANSION_AREA)
03989     {
03990       printf (" %p ->", rb);
03991       rb = rb->parent.expansion_area;
03992     }
03993   if (rb)
03994     printf (" %p is source\n", rb);
03995   else
03996     printf ("NULL!\n");
03997 }
03998 
03999 static void
04000 show_one (routebox_t * rb)
04001 {
04002   int save = showboxen;
04003   showboxen = -1;
04004   showroutebox (rb);
04005   showboxen = save;
04006 }
04007 
04008 static void
04009 show_path (routebox_t * rb)
04010 {
04011   while (rb && rb->type == EXPANSION_AREA)
04012     {
04013       show_one (rb);
04014       rb = rb->parent.expansion_area;
04015     }
04016   show_one (rb);
04017 }
04018 
04019 static void
04020 show_sources (routebox_t * rb)
04021 {
04022   routebox_t *p;
04023   if (!rb->flags.source && !rb->flags.target)
04024     {
04025       printf ("start with a source or target please\n");
04026       return;
04027     }
04028   LIST_LOOP (rb, same_net, p);
04029   if (p->flags.source)
04030     show_one (p);
04031   END_LOOP;
04032 }
04033 
04034 #endif
04035 
04036 static int
04037 __conflict_source (const BoxType * box, void *cl)
04038 {
04039   routebox_t *rb = (routebox_t *) box;
04040   if (rb->flags.touched || rb->flags.fixed)
04041     return 0;
04042   else
04043     {
04044       routebox_t *dis = (routebox_t *) cl;
04045       path_conflicts (dis, rb, false);
04046       touch_conflicts (dis->conflicts_with, 1);
04047     }
04048   return 1;
04049 }
04050 
04051 static void
04052 source_conflicts (rtree_t * tree, routebox_t * rb)
04053 {
04054   if (!AutoRouteParameters.with_conflicts)
04055     return;
04056   r_search (tree, &rb->sbox, NULL, __conflict_source, rb);
04057   touch_conflicts (NULL, 1);
04058 }
04059 
04060 struct routeone_status
04061 {
04062   bool found_route;
04063   int route_had_conflicts;
04064   cost_t best_route_cost;
04065   bool net_completely_routed;
04066 };
04067 
04068 
04069 static struct routeone_status
04070 RouteOne (routedata_t * rd, routebox_t * from, routebox_t * to, int max_edges)
04071 {
04072   struct routeone_status result;
04073   routebox_t *p;
04074   int seen, i;
04075   const BoxType **target_list;
04076   int num_targets;
04077   rtree_t *targets;
04078   /* vector of source edges for filtering */
04079   vector_t *source_vec;
04080   /* working vector */
04081   vector_t *edge_vec;
04082 
04083   struct routeone_state s;
04084   struct routeone_via_site_state vss;
04085 
04086   assert (rd && from);
04087   result.route_had_conflicts = 0;
04088   /* no targets on to/from net need keepaway areas */
04089   LIST_LOOP (from, same_net, p);
04090   p->flags.nobloat = 1;
04091   END_LOOP;
04092   /* set 'source' flags */
04093   LIST_LOOP (from, same_subnet, p);
04094   if (!p->flags.nonstraight)
04095     p->flags.source = 1;
04096   END_LOOP;
04097 
04098   /* count up the targets */
04099   num_targets = 0;
04100   seen = 0;
04101   /* remove source/target flags from non-straight obstacles, because they
04102    * don't fill their bounding boxes and so connecting to them
04103    * after we've routed is problematic.  Better solution? */
04104   if (to)
04105     {                           /* if we're routing to a specific target */
04106       if (!to->flags.source)
04107         {                       /* not already connected */
04108           /* check that 'to' and 'from' are on the same net */
04109           seen = 0;
04110 #ifndef NDEBUG
04111           LIST_LOOP (from, same_net, p);
04112           if (p == to)
04113             seen = 1;
04114           END_LOOP;
04115 #endif
04116           assert (seen);        /* otherwise from and to are on different nets! */
04117           /* set target flags only on 'to's subnet */
04118           LIST_LOOP (to, same_subnet, p);
04119           if (!p->flags.nonstraight && is_layer_group_active[p->group])
04120             {
04121               p->flags.target = 1;
04122               num_targets++;
04123             }
04124           END_LOOP;
04125         }
04126     }
04127   else
04128     {
04129       /* all nodes on the net but not connected to from are targets */
04130       LIST_LOOP (from, same_net, p);
04131       if (!p->flags.source && is_layer_group_active[p->group]
04132           && !p->flags.nonstraight)
04133         {
04134           p->flags.target = 1;
04135           num_targets++;
04136         }
04137       END_LOOP;
04138     }
04139 
04140   /* if no targets, then net is done!  reset flags and return. */
04141   if (num_targets == 0)
04142     {
04143       LIST_LOOP (from, same_net, p);
04144       p->flags.source = p->flags.target = p->flags.nobloat = 0;
04145       END_LOOP;
04146       result.found_route = false;
04147       result.net_completely_routed = true;
04148       result.best_route_cost = 0;
04149       result.route_had_conflicts = 0;
04150 
04151       return result;
04152     }
04153   result.net_completely_routed = false;
04154 
04155   /* okay, there's stuff to route */
04156   assert (!from->flags.target);
04157   assert (num_targets > 0);
04158   /* create list of target pointers and from that a r-tree of targets */
04159   target_list = (const BoxType **)malloc (num_targets * sizeof (*target_list));
04160   i = 0;
04161   LIST_LOOP (from, same_net, p);
04162   if (p->flags.target)
04163     {
04164       target_list[i++] = &p->box;
04165 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
04166       showroutebox (p);
04167 #endif
04168     }
04169   END_LOOP;
04170   targets = r_create_tree ((const BoxType **)target_list, i, 0);
04171   assert (i <= num_targets);
04172   free (target_list);
04173 
04174   source_vec = vector_create ();
04175   /* touch the source subnet to prepare check for conflictors */
04176   LIST_LOOP (from, same_subnet, p);
04177   p->flags.touched = 1;
04178   END_LOOP;
04179   LIST_LOOP (from, same_subnet, p);
04180   {
04181     /* we need the test for 'source' because this box may be nonstraight */
04182     if (p->flags.source && is_layer_group_active[p->group])
04183       {
04184         CheapPointType cp;
04185         edge_t *e;
04186         BoxType b = shrink_routebox (p);
04187 
04188 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES)
04189         showroutebox (p);
04190 #endif
04191         /* may expand in all directions from source; center edge cost point. */
04192         /* note that planes shouldn't really expand, but we need an edge */
04193 
04194         cp.X = CENTER_X (b);
04195         cp.Y = CENTER_Y (b);
04196         e = CreateEdge (p, cp.X, cp.Y, 0, NULL, ALL, targets);
04197         cp = closest_point_in_box (&cp, &e->mincost_target->sbox);
04198         cp = closest_point_in_box (&cp, &b);
04199         e->cost_point = cp;
04200         p->cost_point = cp;
04201         source_conflicts (rd->layergrouptree[p->group], p);
04202         vector_append (source_vec, e);
04203       }
04204   }
04205   END_LOOP;
04206   LIST_LOOP (from, same_subnet, p);
04207   p->flags.touched = 0;
04208   END_LOOP;
04209   /* break source edges; some edges may be too near obstacles to be able
04210    * to exit from. */
04211 
04212   /* okay, main expansion-search routing loop. */
04213   /* set up the initial activity heap */
04214   s.workheap = heap_create ();
04215   assert (s.workheap);
04216   while (!vector_is_empty (source_vec))
04217     {
04218       edge_t *e = (edge_t *)vector_remove_last (source_vec);
04219       assert (is_layer_group_active[e->rb->group]);
04220       e->cost = edge_cost (e, EXPENSIVE);
04221       heap_insert (s.workheap, e->cost, e);
04222     }
04223   vector_destroy (&source_vec);
04224   /* okay, process items from heap until it is empty! */
04225   s.best_path = NULL;
04226   s.best_cost = EXPENSIVE;
04227   area_vec = vector_create ();
04228   edge_vec = vector_create ();
04229   vss.free_space_vec = vector_create ();
04230   vss.lo_conflict_space_vec = vector_create ();
04231   vss.hi_conflict_space_vec = vector_create ();
04232   while (!heap_is_empty (s.workheap))
04233     {
04234       edge_t *e = (edge_t *)heap_remove_smallest (s.workheap);
04235 #ifdef ROUTE_DEBUG
04236       if (aabort)
04237         goto dontexpand;
04238 #endif
04239       /* don't bother expanding this edge if the minimum possible edge cost
04240        * is already larger than the best edge cost we've found. */
04241       if (s.best_path && e->cost >= s.best_cost)
04242         {
04243           heap_free (s.workheap, KillEdge);
04244           goto dontexpand;      /* skip this edge */
04245         }
04246       /* surprisingly it helps to give up and not try too hard to find
04247        * a route! This is not only faster, but results in better routing.
04248        * who would have guessed?
04249        */
04250       if (seen++ > max_edges)
04251         goto dontexpand;
04252       assert (__edge_is_good (e));
04253       /* mark or unmark conflictors as needed */
04254       touch_conflicts (e->rb->conflicts_with, 1);
04255       if (e->flags.via_search)
04256         {
04257           do_via_search (e, &s, &vss, rd->mtspace, targets);
04258           goto dontexpand;
04259         }
04260       /* we should never add edges on inactive layer groups to the heap. */
04261       assert (is_layer_group_active[e->rb->group]);
04262 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
04263       //showedge (e);
04264 #endif
04265       if (e->rb->flags.is_thermal)
04266         {
04267           best_path_candidate (&s, e, e->mincost_target);
04268           goto dontexpand;
04269         }
04270       /* for a plane, look for quick connections with thermals or vias */
04271       if (e->rb->type == PLANE)
04272         {
04273           routebox_t *pin = FindThermable (targets, e->rb);
04274           if (pin)
04275             {
04276               BoxType b = shrink_routebox (pin);
04277               edge_t *ne;
04278               routebox_t *nrb;
04279               assert (pin->flags.target);
04280               nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
04281               nrb->flags.is_thermal = 1;
04282               /* moving through the plane is free */
04283               e->cost_point.X = b.X1;
04284               e->cost_point.Y = b.Y1;
04285               ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, pin);
04286               best_path_candidate (&s, ne, pin);
04287               DestroyEdge (&ne);
04288             }
04289           else
04290             {
04291               /* add in possible via sites in plane */
04292               if (AutoRouteParameters.use_vias &&
04293                   e->cost + AutoRouteParameters.ViaCost < s.best_cost)
04294                 {
04295                   /* we need a giant thermal */
04296                   routebox_t *nrb =
04297                     CreateExpansionArea (&e->rb->sbox, e->rb->group, e->rb,
04298                                          true, e);
04299                   edge_t *ne = CreateEdge2 (nrb, e->expand_dir, e, NULL,
04300                                             e->mincost_target);
04301                   nrb->flags.is_thermal = 1;
04302                   add_via_sites (&s, &vss, rd->mtspace, nrb, NO_CONFLICT, ne,
04303                                  targets, e->rb->style->Diameter, true);
04304                 }
04305             }
04306           goto dontexpand;      /* planes only connect via thermals */
04307         }
04308       if (e->flags.is_via)
04309         {                       /* special case via */
04310           routebox_t *intersecting;
04311           assert (AutoRouteParameters.use_vias);
04312           assert (e->expand_dir == ALL);
04313           assert (vector_is_empty (edge_vec));
04314           /* if there is already something here on this layer (like an
04315            * EXPANSION_AREA), then we don't want to expand from here
04316            * at least not inside the expansion area. A PLANE on the
04317            * other hand may be a target, or not. 
04318            */
04319           intersecting =
04320             FindOneInBox (rd->layergrouptree[e->rb->group], e->rb);
04321 
04322           if (intersecting && intersecting->flags.target
04323               && intersecting->type == PLANE)
04324             {
04325               /* we have hit a plane */
04326               edge_t *ne;
04327               routebox_t *nrb;
04328               BoxType b = shrink_routebox (e->rb);
04329               /* limit via region to that inside the plane */
04330               clip_box (&b, &intersecting->sbox);
04331               nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e);
04332               nrb->flags.is_thermal = 1;
04333               ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, intersecting);
04334               best_path_candidate (&s, ne, intersecting);
04335               DestroyEdge (&ne);
04336               goto dontexpand;
04337             }
04338           else if (intersecting == NULL)
04339             {
04340               /* this via candidate is in an open area; add it to r-tree as
04341                * an expansion area */
04342               assert (e->rb->type == EXPANSION_AREA && e->rb->flags.is_via);
04343               /*assert (!r_search (rd->layergrouptree[e->rb->group],
04344                  &e->rb->box, NULL, no_planes,0));
04345                */
04346               r_insert_entry (rd->layergrouptree[e->rb->group], &e->rb->box,
04347                               1);
04348               e->rb->flags.homeless = 0;        /* not homeless any more */
04349               /* add to vector of all expansion areas in r-tree */
04350               vector_append (area_vec, e->rb);
04351               /* mark reset refcount to 0, since this is not homeless any more. */
04352               e->rb->refcount = 0;
04353               /* go ahead and expand this edge! */
04354             }
04355           else if (1)
04356             goto dontexpand;
04357           else if (0)
04358             {                   /* XXX: disabling this causes no via
04359                                    collisions. */
04360               BoxType a = bloat_routebox (intersecting), b;
04361               edge_t *ne;
04362               int i, j;
04363               /* something intersects this via candidate.  split via candidate
04364                * into pieces and add these pieces to the workheap. */
04365               for (i = 0; i < 3; i++)
04366                 {
04367                   for (j = 0; j < 3; j++)
04368                     {
04369                       b = shrink_routebox (e->rb);
04370                       switch (i)
04371                         {
04372                         case 0:
04373                           b.X2 = MIN (b.X2, a.X1);
04374                           break;        /* left */
04375                         case 1:
04376                           b.X1 = MAX (b.X1, a.X1);
04377                           b.X2 = MIN (b.X2, a.X2);
04378                           break;        /*c */
04379                         case 2:
04380                           b.X1 = MAX (b.X1, a.X2);
04381                           break;        /* right */
04382                         default:
04383                           assert (0);
04384                         }
04385                       switch (j)
04386                         {
04387                         case 0:
04388                           b.Y2 = MIN (b.Y2, a.Y1);
04389                           break;        /* top */
04390                         case 1:
04391                           b.Y1 = MAX (b.Y1, a.Y1);
04392                           b.Y2 = MIN (b.Y2, a.Y2);
04393                           break;        /*c */
04394                         case 2:
04395                           b.Y1 = MAX (b.Y1, a.Y2);
04396                           break;        /* bottom */
04397                         default:
04398                           assert (0);
04399                         }
04400                       /* skip if this box is not valid */
04401                       if (!(b.X1 < b.X2 && b.Y1 < b.Y2))
04402                         continue;
04403                       if (i == 1 && j == 1)
04404                         {
04405                           /* this bit of the via space is obstructed. */
04406                           if (intersecting->type == EXPANSION_AREA
04407                               || intersecting->flags.fixed)
04408                             continue;   /* skip this bit, it's already been done. */
04409                           /* create an edge with conflicts, if enabled */
04410                           if (!AutoRouteParameters.with_conflicts)
04411                             continue;
04412                           ne = CreateEdgeWithConflicts (&b, intersecting, e, 1
04413                                                         /*cost penalty to box */
04414                                                         , targets);
04415                           add_or_destroy_edge (&s, ne);
04416                         }
04417                       else
04418                         {
04419                           /* if this is not the intersecting piece, create a new
04420                            * (hopefully unobstructed) via edge and add it back to the
04421                            * workheap. */
04422                           ne =
04423                             CreateViaEdge (&b, e->rb->group,
04424                                            e->rb->parent.expansion_area, e,
04425                                            e->flags.via_conflict_level,
04426                                            NO_CONFLICT
04427                                            /* value here doesn't matter */
04428                                            , targets);
04429                           add_or_destroy_edge (&s, ne);
04430                         }
04431                     }
04432                 }
04433               goto dontexpand;
04434             }
04435           /* between the time these edges are inserted and the
04436            * time they are processed, new expansion boxes (which
04437            * conflict with these edges) may be added to the graph!
04438            * w.o vias this isn't a problem because the broken box
04439            * is not homeless. */
04440         }
04441       if (1)
04442         {
04443           routebox_t *nrb;
04444           struct E_result *ans;
04445           BoxType b;
04446           vector_t *broken;
04447           if (e->flags.is_interior)
04448             {
04449               assert (AutoRouteParameters.with_conflicts);      /* no interior edges unless
04450                                                                    routing with conflicts! */
04451               assert (e->rb->conflicts_with);
04452               b = e->rb->sbox;
04453               switch (e->rb->came_from)
04454                 {
04455                 case NORTH:
04456                   b.Y2 = b.Y1 + 1;
04457                   b.X1 = CENTER_X (b);
04458                   b.X2 = b.X1 + 1;
04459                   break;
04460                 case EAST:
04461                   b.X1 = b.X2 - 1;
04462                   b.Y1 = CENTER_Y (b);
04463                   b.Y2 = b.Y1 + 1;
04464                   break;
04465                 case SOUTH:
04466                   b.Y1 = b.Y2 - 1;
04467                   b.X1 = CENTER_X (b);
04468                   b.X2 = b.X1 + 1;
04469                   break;
04470                 case WEST:
04471                   b.X2 = b.X1 + 1;
04472                   b.Y1 = CENTER_Y (b);
04473                   b.Y2 = b.Y1 + 1;
04474                   break;
04475                 default:
04476                   assert (0);
04477                 }
04478             }
04479           /* sources may not expand to their own edges because of
04480            * adjacent blockers.
04481            */
04482           else if (e->rb->flags.source)
04483             b = box_center (&e->rb->sbox);
04484           else
04485             b = e->rb->sbox;
04486           ans = Expand (rd->layergrouptree[e->rb->group], e, &b);
04487           if (!box_intersect (&ans->inflated, &ans->orig))
04488             goto dontexpand;
04489 #if 0
04490           /* skip if it didn't actually expand */
04491           if (ans->inflated.X1 >= e->rb->sbox.X1 &&
04492               ans->inflated.X2 <= e->rb->sbox.X2 &&
04493               ans->inflated.Y1 >= e->rb->sbox.Y1 &&
04494               ans->inflated.Y2 <= e->rb->sbox.Y2)
04495             goto dontexpand;
04496 #endif
04497 
04498           if (!box_is_good (&ans->inflated))
04499             goto dontexpand;
04500           nrb = CreateExpansionArea (&ans->inflated, e->rb->group, e->rb,
04501                                      true, e);
04502           r_insert_entry (rd->layergrouptree[nrb->group], &nrb->box, 1);
04503           vector_append (area_vec, nrb);
04504           nrb->flags.homeless = 0;      /* not homeless any more */
04505           broken =
04506             BreakManyEdges (&s, targets, rd->layergrouptree[nrb->group],
04507                             area_vec, ans, nrb, e);
04508           while (!vector_is_empty (broken))
04509             {
04510               edge_t *ne = (edge_t *)vector_remove_last (broken);
04511               add_or_destroy_edge (&s, ne);
04512             }
04513           vector_destroy (&broken);
04514 
04515           /* add in possible via sites in nrb */
04516           if (AutoRouteParameters.use_vias && !e->rb->flags.is_via &&
04517               e->cost + AutoRouteParameters.ViaCost < s.best_cost)
04518             add_via_sites (&s, &vss,
04519                            rd->mtspace, nrb, NO_CONFLICT, e, targets, 0,
04520                            false);
04521           goto dontexpand;
04522         }
04523     dontexpand:
04524       DestroyEdge (&e);
04525     }
04526   touch_conflicts (NULL, 1);
04527   heap_destroy (&s.workheap);
04528   r_destroy_tree (&targets);
04529   assert (vector_is_empty (edge_vec));
04530   vector_destroy (&edge_vec);
04531 
04532   /* we should have a path in best_path now */
04533   if (s.best_path)
04534     {
04535       routebox_t *rb;
04536 #ifdef ROUTE_VERBOSE
04537       printf ("%d:%d RC %.0f", ro++, seen, s.best_cost);
04538 #endif
04539       result.found_route = true;
04540       result.best_route_cost = s.best_cost;
04541       /* determine if the best path had conflicts */
04542       result.route_had_conflicts = 0;
04543       if (AutoRouteParameters.with_conflicts && s.best_path->conflicts_with)
04544         {
04545           while (!vector_is_empty (s.best_path->conflicts_with))
04546             {
04547               rb = (routebox_t *)vector_remove_last (s.best_path->conflicts_with);
04548               rb->flags.is_bad = 1;
04549               result.route_had_conflicts++;
04550             }
04551         }
04552 #ifdef ROUTE_VERBOSE
04553       if (result.route_had_conflicts)
04554         printf (" (%d conflicts)", result.route_had_conflicts);
04555 #endif
04556       if (result.route_had_conflicts < AutoRouteParameters.hi_conflict)
04557         {
04558           /* back-trace the path and add lines/vias to r-tree */
04559           TracePath (rd, s.best_path, s.best_target, from,
04560                      result.route_had_conflicts);
04561           MergeNets (from, s.best_target, SUBNET);
04562         }
04563       else
04564         {
04565 #ifdef ROUTE_VERBOSE
04566           printf (" (too many in fact)");
04567 #endif
04568           result.found_route = false;
04569         }
04570 #ifdef ROUTE_VERBOSE
04571       printf ("\n");
04572 #endif
04573     }
04574   else
04575     {
04576 #ifdef ROUTE_VERBOSE
04577       printf ("%d:%d NO PATH FOUND.\n", ro++, seen);
04578 #endif
04579       result.best_route_cost = s.best_cost;
04580       result.found_route = false;
04581     }
04582   /* now remove all expansion areas from the r-tree. */
04583   while (!vector_is_empty (area_vec))
04584     {
04585       routebox_t *rb = (routebox_t *)vector_remove_last (area_vec);
04586       assert (!rb->flags.homeless);
04587       if (rb->conflicts_with
04588           && rb->parent.expansion_area->conflicts_with != rb->conflicts_with)
04589         vector_destroy (&rb->conflicts_with);
04590       r_delete_entry (rd->layergrouptree[rb->group], &rb->box);
04591     }
04592   vector_destroy (&area_vec);
04593   /* clean up; remove all 'source', 'target', and 'nobloat' flags */
04594   LIST_LOOP (from, same_net, p);
04595   if (p->flags.source && p->conflicts_with)
04596     vector_destroy (&p->conflicts_with);
04597   p->flags.touched = p->flags.source = p->flags.target = p->flags.nobloat = 0;
04598   END_LOOP;
04599 
04600   vector_destroy (&vss.free_space_vec);
04601   vector_destroy (&vss.lo_conflict_space_vec);
04602   vector_destroy (&vss.hi_conflict_space_vec);
04603 
04604   return result;
04605 }
04606 
04607 static void
04608 InitAutoRouteParameters (int pass,
04609                          RouteStyleType * style,
04610                          bool with_conflicts, bool is_smoothing,
04611                          bool lastpass)
04612 {
04613   int i;
04614   /* routing style */
04615   AutoRouteParameters.style = style;
04616   AutoRouteParameters.bloat = style->Keepaway + HALF_THICK (style->Thick);
04617   /* costs */
04618   AutoRouteParameters.ViaCost =
04619     INCH_TO_COORD (3.5) + style->Diameter * (is_smoothing ? 80 : 30);
04620   AutoRouteParameters.LastConflictPenalty =
04621     (400 * pass / passes + 2) / (pass + 1);
04622   AutoRouteParameters.ConflictPenalty =
04623     4 * AutoRouteParameters.LastConflictPenalty;
04624   AutoRouteParameters.JogPenalty = 1000 * (is_smoothing ? 20 : 4);
04625   AutoRouteParameters.CongestionPenalty = 1e6;
04626   AutoRouteParameters.MinPenalty = EXPENSIVE;
04627   for (i = 0; i < max_group; i++)
04628     {
04629       if (is_layer_group_active[i])
04630         {
04631           AutoRouteParameters.MinPenalty = MIN (x_cost[i],
04632                                                 AutoRouteParameters.
04633                                                 MinPenalty);
04634           AutoRouteParameters.MinPenalty =
04635             MIN (y_cost[i], AutoRouteParameters.MinPenalty);
04636         }
04637     }
04638   AutoRouteParameters.NewLayerPenalty = is_smoothing ?
04639     0.5 * EXPENSIVE : 10 * AutoRouteParameters.ViaCost;
04640   /* other */
04641   AutoRouteParameters.hi_conflict = MAX (8 * (passes - pass + 1), 6);
04642   AutoRouteParameters.is_odd = (pass & 1);
04643   AutoRouteParameters.with_conflicts = with_conflicts;
04644   AutoRouteParameters.is_smoothing = is_smoothing;
04645   AutoRouteParameters.rip_always = is_smoothing;
04646   AutoRouteParameters.last_smooth = 0;  //lastpass;
04647   AutoRouteParameters.pass = pass + 1;
04648 }
04649 
04650 #ifndef NDEBUG
04651 int
04652 bad_boy (const BoxType * b, void *cl)
04653 {
04654   routebox_t *box = (routebox_t *) b;
04655   if (box->type == EXPANSION_AREA)
04656     return 1;
04657   return 0;
04658 }
04659 
04660 bool
04661 no_expansion_boxes (routedata_t * rd)
04662 {
04663   int i;
04664   BoxType big;
04665   big.X1 = 0;
04666   big.X2 = MAX_COORD;
04667   big.Y1 = 0;
04668   big.Y2 = MAX_COORD;
04669   for (i = 0; i < max_group; i++)
04670     {
04671       if (r_search (rd->layergrouptree[i], &big, NULL, bad_boy, NULL))
04672         return false;
04673     }
04674   return true;
04675 }
04676 #endif
04677 
04678 static void
04679 ripout_livedraw_obj (routebox_t *rb)
04680 {
04681   if (rb->type == LINE && rb->livedraw_obj.line)
04682     {
04683       LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]);
04684       EraseLine (rb->livedraw_obj.line);
04685       DestroyObject (PCB->Data, LINE_TYPE, layer, rb->livedraw_obj.line, NULL);
04686       rb->livedraw_obj.line = NULL;
04687     }
04688   if (rb->type == VIA && rb->livedraw_obj.via)
04689     {
04690       EraseVia (rb->livedraw_obj.via);
04691       DestroyObject (PCB->Data, VIA_TYPE, rb->livedraw_obj.via, NULL, NULL);
04692       rb->livedraw_obj.via = NULL;
04693     }
04694 }
04695 
04696 static int
04697 ripout_livedraw_obj_cb (const BoxType * b, void *cl)
04698 {
04699   routebox_t *box = (routebox_t *) b;
04700   ripout_livedraw_obj (box);
04701   return 0;
04702 }
04703 
04704 struct routeall_status
04705 {
04706   /* --- for completion rate statistics ---- */
04707   int total_subnets;
04708   /* total subnets routed without conflicts */
04709   int routed_subnets;
04710   /* total subnets routed with conflicts */
04711   int conflict_subnets;
04712   /* net failted entirely */
04713   int failed;
04714   /* net was ripped */
04715   int ripped;
04716   int total_nets_routed;
04717 };
04718 
04719 static double
04720 calculate_progress (double this_heap_item, double this_heap_size,
04721                     struct routeall_status *ras)
04722 {
04723   double total_passes = passes + smoothes + 1;      /* + 1 is the refinement pass */
04724   double this_pass = AutoRouteParameters.pass - 1; /* Number passes from zero */
04725   double heap_fraction = (double)(ras->routed_subnets + ras->conflict_subnets + ras->failed) /
04726                          (double)ras->total_subnets;
04727   double pass_fraction = (this_heap_item + heap_fraction ) / this_heap_size;
04728   double process_fraction = (this_pass + pass_fraction) / total_passes;
04729 
04730   return process_fraction;
04731 }
04732 
04733 struct routeall_status
04734 RouteAll (routedata_t * rd)
04735 {
04736   struct routeall_status ras;
04737   struct routeone_status ros;
04738   bool rip;
04739   int request_cancel;
04740 #ifdef NET_HEAP
04741   heap_t *net_heap;
04742 #endif
04743   heap_t *this_pass, *next_pass, *tmp;
04744   routebox_t *net, *p, *pp;
04745   cost_t total_net_cost, last_cost = 0, this_cost = 0;
04746   int i;
04747   int this_heap_size;
04748   int this_heap_item;
04749 
04750   /* initialize heap for first pass; 
04751    * do smallest area first; that makes
04752    * the subsequent costs more representative */
04753   this_pass = heap_create ();
04754   next_pass = heap_create ();
04755 #ifdef NET_HEAP
04756   net_heap = heap_create ();
04757 #endif
04758   LIST_LOOP (rd->first_net, different_net, net);
04759   {
04760     double area;
04761     BoxType bb = shrink_routebox (net);
04762     LIST_LOOP (net, same_net, p);
04763     {
04764       MAKEMIN (bb.X1, p->sbox.X1);
04765       MAKEMIN (bb.Y1, p->sbox.Y1);
04766       MAKEMAX (bb.X2, p->sbox.X2);
04767       MAKEMAX (bb.Y2, p->sbox.Y2);
04768     }
04769     END_LOOP;
04770     area = (double) (bb.X2 - bb.X1) * (bb.Y2 - bb.Y1);
04771     heap_insert (this_pass, area, net);
04772   }
04773   END_LOOP;
04774 
04775   ras.total_nets_routed = 0;
04776   /* refinement/finishing passes */
04777   for (i = 0; i <= passes + smoothes; i++)
04778     {
04779 #ifdef ROUTE_VERBOSE
04780       if (i > 0 && i <= passes)
04781         printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i);
04782       else if (i > passes)
04783         printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
04784                 i - passes);
04785 #endif
04786       ras.total_subnets = ras.routed_subnets = ras.conflict_subnets =
04787         ras.failed = ras.ripped = 0;
04788       assert (heap_is_empty (next_pass));
04789 
04790       this_heap_size = heap_size (this_pass);
04791       for (this_heap_item = 0; !heap_is_empty (this_pass); this_heap_item++)
04792         {
04793 #ifdef ROUTE_DEBUG
04794           if (aabort)
04795             break;
04796 #endif
04797           net = (routebox_t *) heap_remove_smallest (this_pass);
04798           InitAutoRouteParameters (i, net->style, i < passes, i > passes,
04799                                    i == passes + smoothes);
04800           if (i > 0)
04801             {
04802               /* rip up all unfixed traces in this net ? */
04803               if (AutoRouteParameters.rip_always)
04804                 rip = true;
04805               else
04806                 {
04807                   rip = false;
04808                   LIST_LOOP (net, same_net, p);
04809                   if (p->flags.is_bad)
04810                     {
04811                       rip = true;
04812                       break;
04813                     }
04814                   END_LOOP;
04815                 }
04816 
04817               LIST_LOOP (net, same_net, p);
04818               p->flags.is_bad = 0;
04819               if (!p->flags.fixed)
04820                 {
04821 #ifndef NDEBUG
04822                   bool del;
04823 #endif
04824                   assert (!p->flags.homeless);
04825                   if (rip)
04826                     {
04827                       RemoveFromNet (p, NET);
04828                       RemoveFromNet (p, SUBNET);
04829                     }
04830                   if (AutoRouteParameters.use_vias && p->type != VIA_SHADOW
04831                       && p->type != PLANE)
04832                     {
04833                       mtspace_remove (rd->mtspace, &p->box,
04834                                       p->flags.is_odd ? ODD : EVEN,
04835                                       p->style->Keepaway);
04836                       if (!rip)
04837                         mtspace_add (rd->mtspace, &p->box,
04838                                      p->flags.is_odd ? EVEN : ODD,
04839                                      p->style->Keepaway);
04840                     }
04841                   if (rip)
04842                     {
04843                       if (TEST_FLAG (LIVEROUTEFLAG, PCB))
04844                         ripout_livedraw_obj (p);
04845 #ifndef NDEBUG
04846                       del =
04847 #endif
04848                         r_delete_entry (rd->layergrouptree[p->group],
04849                                         &p->box);
04850 #ifndef NDEBUG
04851                       assert (del);
04852 #endif
04853                     }
04854                   else
04855                     {
04856                       p->flags.is_odd = AutoRouteParameters.is_odd;
04857                     }
04858                 }
04859               END_LOOP;
04860               if (TEST_FLAG (LIVEROUTEFLAG, PCB))
04861                 Draw ();
04862               /* reset to original connectivity */
04863               if (rip)
04864                 {
04865                   ras.ripped++;
04866                   ResetSubnet (net);
04867                 }
04868               else
04869                 {
04870                   heap_insert (next_pass, 0, net);
04871                   continue;
04872                 }
04873             }
04874           /* count number of subnets */
04875           FOREACH_SUBNET (net, p);
04876           ras.total_subnets++;
04877           END_FOREACH (net, p);
04878           /* the first subnet doesn't require routing. */
04879           ras.total_subnets--;
04880           /* and re-route! */
04881           total_net_cost = 0;
04882           /* only route that which isn't fully routed */
04883 #ifdef ROUTE_DEBUG
04884           if (ras.total_subnets == 0 || aabort)
04885 #else
04886           if (ras.total_subnets == 0)
04887 #endif
04888             {
04889               heap_insert (next_pass, 0, net);
04890               continue;
04891             }
04892 
04893           /* the loop here ensures that we get to all subnets even if
04894            * some of them are unreachable from the first subnet. */
04895           LIST_LOOP (net, same_net, p);
04896           {
04897 #ifdef NET_HEAP
04898             BoxType b = shrink_routebox (p);
04899             /* using a heap allows us to start from smaller objects and
04900              * end at bigger ones. also prefer to start at planes, then pads */
04901             heap_insert (net_heap, (float) (b.X2 - b.X1) *
04902 #if defined(ROUTE_RANDOMIZED)
04903                          (0.3 + rand () / (RAND_MAX + 1.0)) *
04904 #endif
04905                          (b.Y2 - b.Y1) * (p->type == PLANE ?
04906                                           -1 : (p->type ==
04907                                                 PAD ? 1 : 10)), p);
04908           }
04909           END_LOOP;
04910           ros.net_completely_routed = 0;
04911           while (!heap_is_empty (net_heap))
04912             {
04913               p = (routebox_t *) heap_remove_smallest (net_heap);
04914 #endif
04915               if (!p->flags.fixed || p->flags.subnet_processed ||
04916                   p->type == OTHER)
04917                 continue;
04918 
04919               while (!ros.net_completely_routed)
04920                 {
04921                   double percent;
04922 
04923                   assert (no_expansion_boxes (rd));
04924                   /* FIX ME: the number of edges to examine should be in autoroute parameters
04925                    * i.e. the 2000 and 800 hard-coded below should be controllable by the user
04926                    */
04927                   ros =
04928                     RouteOne (rd, p, NULL,
04929                               ((AutoRouteParameters.
04930                                 is_smoothing ? 2000 : 800) * (i +
04931                                                               1)) *
04932                               routing_layers);
04933                   total_net_cost += ros.best_route_cost;
04934                   if (ros.found_route)
04935                     {
04936                       if (ros.route_had_conflicts)
04937                         ras.conflict_subnets++;
04938                       else
04939                         {
04940                           ras.routed_subnets++;
04941                           ras.total_nets_routed++;
04942                         }
04943                     }
04944                   else
04945                     {
04946                       if (!ros.net_completely_routed)
04947                         ras.failed++;
04948                       /* don't bother trying any other source in this subnet */
04949                       LIST_LOOP (p, same_subnet, pp);
04950                       pp->flags.subnet_processed = 1;
04951                       END_LOOP;
04952                       break;
04953                     }
04954                   /* note that we can infer nothing about ras.total_subnets based
04955                    * on the number of calls to RouteOne, because we may be unable
04956                    * to route a net from a particular starting point, but perfectly
04957                    * able to route it from some other. */
04958                   percent = calculate_progress (this_heap_item, this_heap_size, &ras);
04959                   request_cancel = gui->progress (percent * 100., 100,
04960                                                   _("Autorouting tracks"));
04961                   if (request_cancel)
04962                     {
04963                       ras.total_nets_routed = 0;
04964                       ras.conflict_subnets = 0;
04965                       Message ("Autorouting cancelled\n");
04966                       goto out;
04967                     }
04968                 }
04969             }
04970 #ifndef NET_HEAP
04971           END_LOOP;
04972 #endif
04973           if (!ros.net_completely_routed)
04974             net->flags.is_bad = 1;      /* don't skip this the next round */
04975 
04976           /* Route easiest nets from this pass first on next pass.
04977            * This works best because it's likely that the hardest
04978            * is the last one routed (since it has the most obstacles)
04979            * but it will do no good to rip it up and try it again
04980            * without first changing any of the other routes
04981            */
04982           heap_insert (next_pass, total_net_cost, net);
04983           if (total_net_cost < EXPENSIVE)
04984             this_cost += total_net_cost;
04985           /* reset subnet_processed flags */
04986           LIST_LOOP (net, same_net, p);
04987           {
04988             p->flags.subnet_processed = 0;
04989           }
04990           END_LOOP;
04991         }
04992       /* swap this_pass and next_pass and do it all over again! */
04993       ro = 0;
04994       assert (heap_is_empty (this_pass));
04995       tmp = this_pass;
04996       this_pass = next_pass;
04997       next_pass = tmp;
04998 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE)
04999       printf
05000         ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n",
05001          i, ras.routed_subnets, ras.total_subnets, this_cost,
05002          ras.conflict_subnets, ras.failed, ras.ripped);
05003 #endif
05004 #ifdef ROUTE_DEBUG
05005       if (aabort)
05006         break;
05007 #endif
05008       /* if no conflicts found, skip directly to smoothing pass! */
05009       if (ras.conflict_subnets == 0 && ras.routed_subnets == ras.total_subnets
05010           && i <= passes)
05011         i = passes - (smoothes ? 0 : 1);
05012       /* if no changes in a smoothing round, then we're done */
05013       if (this_cost == last_cost && i > passes && i < passes + smoothes)
05014         i = passes + smoothes - 1;
05015       last_cost = this_cost;
05016       this_cost = 0;
05017     }
05018 
05019   Message ("%d of %d nets successfully routed.\n",
05020            ras.routed_subnets, ras.total_subnets);
05021 
05022 out:
05023   heap_destroy (&this_pass);
05024   heap_destroy (&next_pass);
05025 #ifdef NET_HEAP
05026   heap_destroy (&net_heap);
05027 #endif
05028 
05029   /* no conflicts should be left at the end of the process. */
05030   assert (ras.conflict_subnets == 0);
05031 
05032   return ras;
05033 }
05034 
05035 struct fpin_info
05036 {
05037   PinType *pin;
05038   Coord X, Y;
05039   jmp_buf env;
05040 };
05041 
05042 static int
05043 fpin_rect (const BoxType * b, void *cl)
05044 {
05045   PinType *pin = (PinType *) b;
05046   struct fpin_info *info = (struct fpin_info *) cl;
05047   if (pin->X == info->X && pin->Y == info->Y)
05048     {
05049       info->pin = (PinType *) b;
05050       longjmp (info->env, 1);
05051     }
05052   return 0;
05053 }
05054 
05055 static int
05056 FindPin (const BoxType * box, PinType ** pin)
05057 {
05058   struct fpin_info info;
05059 
05060   info.pin = NULL;
05061   info.X = box->X1;
05062   info.Y = box->Y1;
05063   if (setjmp (info.env) == 0)
05064     r_search (PCB->Data->pin_tree, box, NULL, fpin_rect, &info);
05065   else
05066     {
05067       *pin = info.pin;
05068       return PIN_TYPE;
05069     }
05070   if (setjmp (info.env) == 0)
05071     r_search (PCB->Data->via_tree, box, NULL, fpin_rect, &info);
05072   else
05073     {
05074       *pin = info.pin;
05075       return VIA_TYPE;
05076     }
05077   *pin = NULL;
05078   return NO_TYPE;
05079 }
05080 
05081 
05087 bool
05088 IronDownAllUnfixedPaths (routedata_t * rd)
05089 {
05090   bool changed = false;
05091   LayerType *layer;
05092   routebox_t *net, *p;
05093   int i;
05094   LIST_LOOP (rd->first_net, different_net, net);
05095   {
05096     LIST_LOOP (net, same_net, p);
05097     {
05098       if (!p->flags.fixed)
05099         {
05100           /* find first on layer in this group */
05101           assert (PCB->LayerGroups.Number[p->group] > 0);
05102           assert (is_layer_group_active[p->group]);
05103           for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group];
05104                i++)
05105             {
05106               layer = LAYER_PTR (PCB->LayerGroups.Entries[p->group][i]);
05107               if (layer->On)
05108                 break;
05109             }
05110           assert (layer && layer->On);  /*at least one layer must be on in this group! */
05111           assert (p->type != EXPANSION_AREA);
05112           if (p->type == LINE)
05113             {
05114               Coord halfwidth = HALF_THICK (p->style->Thick);
05115               double th = halfwidth * 2 + 1;
05116               BoxType b;
05117               assert (p->parent.line == NULL);
05118               /* orthogonal; thickness is 2*halfwidth */
05119               /* flip coordinates, if bl_to_ur */
05120               b = p->sbox;
05121               total_wire_length += hypot (b.X2 - b.X1 - th, b.Y2 - b.Y1 - th);
05122               b = shrink_box (&b, halfwidth);
05123               if (b.X2 == b.X1 + 1)
05124                 b.X2 = b.X1;
05125               if (b.Y2 == b.Y1 + 1)
05126                 b.Y2 = b.Y1;
05127               if (p->flags.bl_to_ur)
05128                 {
05129                   Coord t;
05130                   t = b.X1;
05131                   b.X1 = b.X2;
05132                   b.X2 = t;
05133                 }
05134               /* using CreateDrawn instead of CreateNew concatenates sequential lines */
05135               p->parent.line = CreateDrawnLineOnLayer
05136                 (layer, b.X1, b.Y1, b.X2, b.Y2,
05137                  p->style->Thick,
05138                  p->style->Keepaway * 2,
05139                  MakeFlags (AUTOFLAG |
05140                             (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG :
05141                              0)));
05142 
05143               if (p->parent.line)
05144                 {
05145                   AddObjectToCreateUndoList (LINE_TYPE, layer,
05146                                              p->parent.line, p->parent.line);
05147                   changed = true;
05148                 }
05149             }
05150           else if (p->type == VIA || p->type == VIA_SHADOW)
05151             {
05152               routebox_t *pp =
05153                 (p->type == VIA_SHADOW) ? p->parent.via_shadow : p;
05154               Coord radius = HALF_THICK (pp->style->Diameter);
05155               BoxType b = shrink_routebox (p);
05156               total_via_count++;
05157               assert (pp->type == VIA);
05158               if (pp->parent.via == NULL)
05159                 {
05160                   assert (b.X1 + radius == b.X2 - radius);
05161                   assert (b.Y1 + radius == b.Y2 - radius);
05162                   pp->parent.via =
05163                     CreateNewVia (PCB->Data, b.X1 + radius,
05164                                   b.Y1 + radius,
05165                                   pp->style->Diameter,
05166                                   2 * pp->style->Keepaway,
05167                                   0, pp->style->Hole, NULL,
05168                                   MakeFlags (AUTOFLAG));
05169                   assert (pp->parent.via);
05170                   if (pp->parent.via)
05171                     {
05172                       AddObjectToCreateUndoList (VIA_TYPE,
05173                                                  pp->parent.via,
05174                                                  pp->parent.via,
05175                                                  pp->parent.via);
05176                       changed = true;
05177                     }
05178                 }
05179               assert (pp->parent.via);
05180               if (p->type == VIA_SHADOW)
05181                 {
05182                   p->type = VIA;
05183                   p->parent.via = pp->parent.via;
05184                 }
05185             }
05186           else if (p->type == THERMAL)
05187             /* nothing to do because, the via might not be there yet */ ;
05188           else
05189             assert (0);
05190         }
05191     }
05192     END_LOOP;
05193     /* loop again to place all the thermals now that the vias are down */
05194     LIST_LOOP (net, same_net, p);
05195     {
05196       if (p->type == THERMAL)
05197         {
05198           PinType *pin = NULL;
05199           /* thermals are alread a single point search, no need to shrink */
05200           int type = FindPin (&p->box, &pin);
05201           if (pin)
05202             {
05203               AddObjectToClearPolyUndoList (type,
05204                                             pin->Element ? pin->Element : pin,
05205                                             pin, pin, false);
05206               RestoreToPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
05207                                 pin);
05208               AddObjectToFlagUndoList (type,
05209                                        pin->Element ? pin->Element : pin, pin,
05210                                        pin);
05211               ASSIGN_THERM (p->layer, PCB->ThermStyle, pin);
05212               AddObjectToClearPolyUndoList (type,
05213                                             pin->Element ? pin->Element : pin,
05214                                             pin, pin, true);
05215               ClearFromPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer),
05216                                 pin);
05217               changed = true;
05218             }
05219         }
05220     }
05221     END_LOOP;
05222   }
05223   END_LOOP;
05224   return changed;
05225 }
05226 
05227 bool
05228 AutoRoute (bool selected)
05229 {
05230   bool changed = false;
05231   routedata_t *rd;
05232   int i;
05233 
05234   total_wire_length = 0;
05235   total_via_count = 0;
05236 
05237 #ifdef ROUTE_DEBUG
05238   ddraw = gui->request_debug_draw ();
05239   if (ddraw != NULL)
05240     {
05241       ar_gc = ddraw->make_gc ();
05242       ddraw->set_line_cap (ar_gc, Round_Cap);
05243     }
05244 #endif
05245 
05246   for (i = 0; i < NUM_STYLES; i++)
05247     {
05248       if (PCB->RouteStyle[i].Thick == 0 ||
05249           PCB->RouteStyle[i].Diameter == 0 ||
05250           PCB->RouteStyle[i].Hole == 0 || PCB->RouteStyle[i].Keepaway == 0)
05251         {
05252           Message ("You must define proper routing styles\n"
05253                    "before auto-routing.\n");
05254           return (false);
05255         }
05256     }
05257   if (PCB->Data->RatN == 0)
05258     return (false);
05259   rd = CreateRouteData ();
05260 
05261   if (1)
05262     {
05263       routebox_t *net, *rb, *last;
05264       int i = 0;
05265       /* count number of rats selected */
05266       RAT_LOOP (PCB->Data);
05267       {
05268         if (!selected || TEST_FLAG (SELECTEDFLAG, line))
05269           i++;
05270       }
05271       END_LOOP;
05272 #ifdef ROUTE_VERBOSE
05273       printf ("%d nets!\n", i);
05274 #endif
05275       if (i == 0)
05276         goto donerouting;       /* nothing to do here */
05277       /* if only one rat selected, do things the quick way. =) */
05278       if (i == 1)
05279         {
05280           RAT_LOOP (PCB->Data);
05281           if (!selected || TEST_FLAG (SELECTEDFLAG, line))
05282             {
05283               /* look up the end points of this rat line */
05284               routebox_t *a =
05285                 FindRouteBoxOnLayerGroup (rd, line->Point1.X,
05286                                           line->Point1.Y, line->group1);
05287               routebox_t *b =
05288                 FindRouteBoxOnLayerGroup (rd, line->Point2.X,
05289                                           line->Point2.Y, line->group2);
05290 
05291               /* If the rat starts or ends at a non-straight pad (i.e., at a
05292                * rotated SMD), a or b will be NULL since the autorouter can't
05293                * handle these.
05294                */
05295               if (a != NULL && b != NULL)
05296                 {
05297                   assert (a->style == b->style);
05298                   /* route exactly one net, without allowing conflicts */
05299                   InitAutoRouteParameters (0, a->style, false, true, true);
05300                   /* hace planes work better as sources than targets */
05301                   changed = RouteOne (rd, a, b, 150000).found_route || changed;
05302                   goto donerouting;
05303                 }
05304             }
05305           END_LOOP;
05306         }
05307       /* otherwise, munge the netlists so that only the selected rats
05308        * get connected. */
05309       /* first, separate all sub nets into separate nets */
05310       /* note that this code works because LIST_LOOP is clever enough not to
05311        * be fooled when the list is changing out from under it. */
05312       last = NULL;
05313       LIST_LOOP (rd->first_net, different_net, net);
05314       {
05315         FOREACH_SUBNET (net, rb);
05316         {
05317           if (last)
05318             {
05319               last->different_net.next = rb;
05320               rb->different_net.prev = last;
05321             }
05322           last = rb;
05323         }
05324         END_FOREACH (net, rb);
05325         LIST_LOOP (net, same_net, rb);
05326         {
05327           rb->same_net = rb->same_subnet;
05328         }
05329         END_LOOP;
05330         /* at this point all nets are equal to their subnets */
05331       }
05332       END_LOOP;
05333       if (last)
05334         {
05335           last->different_net.next = rd->first_net;
05336           rd->first_net->different_net.prev = last;
05337         }
05338 
05339       /* now merge only those subnets connected by a rat line */
05340       RAT_LOOP (PCB->Data);
05341       if (!selected || TEST_FLAG (SELECTEDFLAG, line))
05342         {
05343           /* look up the end points of this rat line */
05344           routebox_t *a;
05345           routebox_t *b;
05346           a =
05347             FindRouteBoxOnLayerGroup (rd, line->Point1.X,
05348                                       line->Point1.Y, line->group1);
05349           b =
05350             FindRouteBoxOnLayerGroup (rd, line->Point2.X,
05351                                       line->Point2.Y, line->group2);
05352           if (!a || !b)
05353             {
05354 #ifdef DEBUG_STALE_RATS
05355               AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
05356               ASSIGN_FLAG (SELECTEDFLAG, true, line);
05357               DrawRat (line, 0);
05358 #endif /* DEBUG_STALE_RATS */
05359               Message ("The rats nest is stale! Aborting autoroute...\n");
05360               goto donerouting;
05361             }
05362           /* merge subnets into a net! */
05363           MergeNets (a, b, NET);
05364         }
05365       END_LOOP;
05366       /* now 'different_net' may point to too many different nets.  Reset. */
05367       LIST_LOOP (rd->first_net, different_net, net);
05368       {
05369         if (!net->flags.touched)
05370           {
05371             LIST_LOOP (net, same_net, rb);
05372             rb->flags.touched = 1;
05373             END_LOOP;
05374           }
05375         else                    /* this is not a "different net"! */
05376           RemoveFromNet (net, DIFFERENT_NET);
05377       }
05378       END_LOOP;
05379       /* reset "touched" flag */
05380       LIST_LOOP (rd->first_net, different_net, net);
05381       {
05382         LIST_LOOP (net, same_net, rb);
05383         {
05384           assert (rb->flags.touched);
05385           rb->flags.touched = 0;
05386         }
05387         END_LOOP;
05388       }
05389       END_LOOP;
05390     }
05391   /* okay, rd's idea of netlist now corresponds to what we want routed */
05392   /* auto-route all nets */
05393   changed = (RouteAll (rd).total_nets_routed > 0) || changed;
05394 donerouting:
05395   gui->progress (0, 0, NULL);
05396   if (TEST_FLAG (LIVEROUTEFLAG, PCB))
05397     {
05398       int i;
05399       BoxType big = {0, 0, MAX_COORD, MAX_COORD};
05400       for (i = 0; i < max_group; i++)
05401         {
05402           r_search (rd->layergrouptree[i], &big, NULL, ripout_livedraw_obj_cb, NULL);
05403         }
05404     }
05405 #ifdef ROUTE_DEBUG
05406   if (ddraw != NULL)
05407     {
05408       ddraw->destroy_gc (ar_gc);
05409       gui->finish_debug_draw ();
05410     }
05411 #endif
05412 
05413   if (changed)
05414     changed = IronDownAllUnfixedPaths (rd);
05415   Message ("Total added wire length = %$mS, %d vias added\n",
05416            (Coord) total_wire_length, total_via_count);
05417   DestroyRouteData (&rd);
05418   if (changed)
05419     {
05420       SaveUndoSerialNumber ();
05421 
05422       /* optimize rats, we've changed connectivity a lot. */
05423       DeleteRats (false /*all rats */ );
05424       RestoreUndoSerialNumber ();
05425       AddAllRats (false /*all rats */ , NULL);
05426       RestoreUndoSerialNumber ();
05427 
05428       IncrementUndoSerialNumber ();
05429 
05430       Redraw ();
05431     }
05432 #if defined (ROUTE_DEBUG)
05433   aabort = 0;
05434 #endif
05435   return (changed);
05436 }