6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 * Copyright (C) 1998,1999,2000,2001 harry eaton
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Contact addresses for paper mail and Email:
25 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
26 * haceaton@aplcomm.jhuapl.edu
29 /* this file, autoroute.c, was written and is
30 * Copyright (c) 2001 C. Scott Ananian
32 /* functions used to autoroute nets.
35 *-------------------------------------------------------------------
36 * This file implements a rectangle-expansion router, based on
37 * "A Method for Gridless Routing of Printed Circuit Boards" by
38 * A. C. Finch, K. J. Mackenzie, G. J. Balsdon, and G. Symonds in the
39 * 1985 Proceedings of the 22nd ACM/IEEE Design Automation Conference.
40 * This reference is available from the ACM Digital Library at
41 * http://www.acm.org/dl for those with institutional or personal
42 * access to it. It's also available from your local engineering
44 *--------------------------------------------------------------------
59 #include "autoroute.h"
78 #ifdef HAVE_LIBDMALLOC
84 /* #defines to enable some debugging output */
92 #define DEBUG_SHOW_ROUTE_BOXES
93 #define DEBUG_SHOW_EXPANSION_BOXES
94 #define DEBUG_SHOW_VIA_BOXES
95 #define DEBUG_SHOW_TARGETS
96 #define DEBUG_SHOW_ZIGZAG
99 static hidGC ar_gc
= 0;
101 #define EXPENSIVE 3e28
102 /* round up "half" thicknesses */
103 #define HALF_THICK(x) (((x)+1)/2)
104 /* a styles maximum bloat is its keepaway plus the larger of its via radius
105 * or line half-thickness. */
106 #define BLOAT(style)\
107 ((style)->Keepaway + HALF_THICK((style)->Thick))
108 /* conflict penalty is less for traces laid down during previous pass than
109 * it is for traces already laid down in this pass. */
110 #define CONFLICT_LEVEL(rb)\
111 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
112 HI_CONFLICT : LO_CONFLICT )
113 #define CONFLICT_PENALTY(rb)\
114 (CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
115 AutoRouteParameters.ConflictPenalty : \
116 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
117 AutoRouteParameters.LastConflictPenalty : 1)
120 #define ABS(x) (((x)<0)?-(x):(x))
123 #define LIST_LOOP(init, which, x) do {\
124 routebox_t *__next_one__ = (init);\
127 assert(__next_one__);\
129 while (!x || __next_one__ != (init)) {\
131 /* save next one first in case the command modifies or frees it */\
132 __next_one__ = x->which.next
133 #define FOREACH_SUBNET(net, p) do {\
135 /* fail-fast: check subnet_processed flags */\
136 LIST_LOOP(net, same_net, p); \
137 assert(!p->flags.subnet_processed);\
139 /* iterate through *distinct* subnets */\
140 LIST_LOOP(net, same_net, p); \
141 if (!p->flags.subnet_processed) {\
142 LIST_LOOP(p, same_subnet, _pp_);\
143 _pp_->flags.subnet_processed=1;\
145 #define END_FOREACH(net, p) \
148 /* reset subnet_processed flags */\
149 LIST_LOOP(net, same_net, p); \
150 p->flags.subnet_processed=0;\
154 * all rectangles are assumed to be closed on the top and left and
155 * open on the bottom and right. That is, they include their top-left
156 * corner but don't include their bottom-right corner.
158 * Obstacles, however, are thought of to be closed on all sides,
159 * and exclusion zone *open* on all sides. We will ignore the infinitesimal
160 * difference w.r.t. obstacles, but exclusion zones will be consistently
161 * bumped in one unit on the top and left in order to exclose the same
162 * integer coordinates as their open-rectangle equivalents.
164 * expansion regions are always half-closed. This means that when
165 * tracing paths, you must steer clear of the bottom and right edges.
167 /* ---------------------------------------------------------------------------
170 /* augmented RouteStyleType */
173 /* a routing style */
174 const RouteStyleType
*style
;
175 /* flag indicating whether this augmented style is ever used.
176 * We only update mtspace if the style is used somewhere in the netlist */
179 AugmentedRouteStyleType
;
181 /* enumerated type for conflict levels */
183 { NO_CONFLICT
= 0, LO_CONFLICT
= 1, HI_CONFLICT
= 2 }
186 typedef struct routebox
194 struct routebox
*via_shadow
; /* points to the via in r-tree which
195 * points to the PinType in the PCB. */
197 void *generic
; /* 'other' is polygon, arc, text */
198 struct routebox
*expansion_area
; /* previous expansion area in search */
201 unsigned short group
;
202 unsigned short layer
;
204 { PAD
, PIN
, VIA
, VIA_SHADOW
, LINE
, OTHER
, EXPANSION_AREA
, PLANE
}
208 unsigned nonstraight
:1;
213 /* rects on same net as source and target don't need clearance areas */
215 /* mark circular pins, so that we be sure to connect them up properly */
217 /* we sometimes create routeboxen that don't actually belong to a
218 * r-tree yet -- make sure refcount of orphans is set properly */
220 /* was this nonfixed obstacle generated on an odd or even pass? */
222 /* fixed route boxes that have already been "routed through" in this
223 * search have their "touched" flag set. */
225 /* this is a status bit for iterating through *different* subnets */
226 unsigned subnet_processed
:1;
227 /* some expansion_areas represent via candidates */
229 /* mark non-straight lines which go from bottom-left to upper-right,
230 * instead of from upper-left to bottom-right. */
232 /* mark polygons which are "transparent" for via-placement; that is,
233 * vias through the polygon will automatically be given a keepaway
234 * and will not electrically connect to the polygon. */
235 unsigned clear_poly
:1;
236 /* this marks "conflicting" routes that must be torn up to obtain
237 * a correct routing. This flag allows us to return a correct routing
238 * even if the user cancels auto-route after a non-final pass. */
240 /* for assertion that 'box' is never changed after creation */
244 /* indicate the direction an expansion box came from */
246 CheapPointType cost_point
;
247 /* reference count for orphan routeboxes; free when refcount==0 */
249 /* when routing with conflicts, we keep a record of what we're
250 * conflicting *with*. */
251 struct routebox
*underlying
;
252 /* route style of the net associated with this routebox */
253 AugmentedRouteStyleType
*augStyle
;
254 /* circular lists with connectivity information. */
257 struct routebox
*next
, *prev
;
259 same_net
, same_subnet
, original_subnet
, different_net
;
263 typedef struct routedata
265 /* one rtree per layer *group */
266 rtree_t
*layergrouptree
[MAX_LAYER
]; /* no silkscreen layers here =) */
267 /* root pointer into connectivity information */
268 routebox_t
*first_net
;
269 /* default routing style */
270 RouteStyleType defaultStyle
;
271 /* augmented style structures */
272 AugmentedRouteStyleType augStyles
[NUM_STYLES
+ 1];
273 /* what is the maximum bloat (keepaway+line half-width or
274 * keepaway+via_radius) for any style we've seen? */
275 BDimension max_bloat
;
280 typedef struct edge_struct
282 routebox_t
*rb
; /* path expansion edges are real routeboxen. */
283 CheapPointType cost_point
;
284 cost_t cost_to_point
; /* from source */
285 cost_t cost
; /* cached edge cost */
286 routebox_t
*mincost_target
; /* minimum cost from cost_point to any target */
287 vetting_t
*work
; /* for via search edges */
288 direction_t expand_dir
; /* ignored if expand_all_sides is set */
291 /* ignore expand_dir and expand all sides if this is set. */
292 /* used for vias and the initial source objects */
293 unsigned expand_all_sides
:1; /* XXX: this is redundant with is_via? */
294 /* this indicates that this 'edge' is a via candidate. */
296 /* record "conflict level" of via candidates, in case we need to split
298 conflict_t via_conflict_level
:2;
299 /* when "routing with conflicts", sometimes edge is interior. */
300 unsigned is_interior
:1;
301 /* this is a fake edge used to defer searching for via spaces */
302 unsigned via_search
:1;
310 /* net style parameters */
311 AugmentedRouteStyleType
*augStyle
;
312 /* cost parameters */
313 cost_t ViaCost
, /* additional "length" cost for using a via */
314 WrongWayPenalty
, /* cost for expanding an edge away from the target */
315 SurfacePenalty
, /* scale for congestion on SMD layers */
316 LastConflictPenalty
, /* length mult. for routing over last pass' trace */
317 ConflictPenalty
, /* length multiplier for routing over another trace */
318 JogPenalty
, /* additional "length" cost for changing direction */
319 DirectionPenalty
, /* (rational) length multiplier for routing in */
320 AwayPenalty
, /* length multiplier for getting further from the target */
321 NewLayerPenalty
, SearchPenalty
, MinPenalty
; /* smallest of Surface, Direction Penalty */
322 /* maximum conflict incidence before calling it "no path found" */
324 /* are vias allowed? */
326 /* is this an odd or even pass? */
328 /* permit conflicts? */
329 Boolean with_conflicts
;
330 /* is this a final "smoothing" pass? */
331 Boolean is_smoothing
;
332 /* rip up nets regardless of conflicts? */
338 /* ---------------------------------------------------------------------------
339 * some local prototypes
341 static routebox_t
*CreateExpansionArea (const BoxType
* area
, Cardinal group
,
343 Boolean relax_edge_requirements
,
346 static cost_t
edge_cost (const edge_t
* e
, const cost_t too_big
);
348 static BoxType
edge_to_box (const BoxType
* box
, direction_t expand_dir
);
350 static void ResetSubnet (routebox_t
* net
);
352 static int showboxen
= 0;
353 static void showroutebox (routebox_t
* rb
);
356 /* ---------------------------------------------------------------------------
357 * some local identifiers
359 /* group number of groups that hold surface mount pads */
360 static Cardinal front
, back
;
361 static Boolean bad_x
[MAX_LAYER
], bad_y
[MAX_LAYER
], usedGroup
[MAX_LAYER
];
362 static Boolean is_layer_group_active
[MAX_LAYER
];
364 static int smoothes
= 3;
365 static int passes
= 9;
366 static int routing_layers
= 0;
368 /* assertion helper for routeboxen */
371 __routebox_is_good (routebox_t
* rb
)
373 assert (rb
&& (rb
->group
< max_layer
) &&
374 (rb
->box
.X1
<= rb
->box
.X2
) && (rb
->box
.Y1
<= rb
->box
.Y2
) &&
376 (rb
->box
.X1
!= rb
->box
.X2
) || (rb
->box
.Y1
!= rb
->box
.Y2
) :
377 (rb
->box
.X1
!= rb
->box
.X2
) && (rb
->box
.Y1
!= rb
->box
.Y2
)));
378 assert ((rb
->flags
.source
? rb
->flags
.nobloat
: 1) &&
379 (rb
->flags
.target
? rb
->flags
.nobloat
: 1) &&
380 (rb
->flags
.orphan
? !rb
->flags
.touched
: rb
->refcount
== 0) &&
381 (rb
->flags
.touched
? rb
->type
!= EXPANSION_AREA
: 1));
382 assert ((rb
->flags
.is_odd
? (!rb
->flags
.fixed
) &&
383 (rb
->type
== VIA
|| rb
->type
== VIA_SHADOW
|| rb
->type
== LINE
384 || rb
->type
== PLANE
) : 1));
385 assert ((rb
->flags
.bl_to_ur
? rb
->flags
.nonstraight
: 1) &&
386 (rb
->flags
.clear_poly
?
387 ((rb
->type
== OTHER
|| rb
->type
== PLANE
) && rb
->flags
.fixed
388 && !rb
->flags
.orphan
) : 1));
389 assert ((rb
->underlying
== NULL
|| !rb
->underlying
->flags
.orphan
)
390 && rb
->flags
.inited
);
391 assert (rb
->augStyle
!= NULL
&& rb
->augStyle
->style
!= NULL
);
392 assert (rb
->same_net
.next
&& rb
->same_net
.prev
&&
393 rb
->same_subnet
.next
&& rb
->same_subnet
.prev
&&
394 rb
->original_subnet
.next
&& rb
->original_subnet
.prev
&&
395 rb
->different_net
.next
&& rb
->different_net
.prev
);
399 __edge_is_good (edge_t
* e
)
401 assert (e
&& e
->rb
&& __routebox_is_good (e
->rb
));
402 assert ((e
->rb
->flags
.orphan
? e
->rb
->refcount
> 0 : 1));
403 assert ((0 <= e
->expand_dir
) && (e
->expand_dir
< 4)
405 is_interior
? (e
->flags
.expand_all_sides
406 && e
->rb
->underlying
) : 1));
407 assert ((e
->flags
.is_via
? e
->rb
->flags
.is_via
: 1)
408 && (e
->flags
.via_conflict_level
>= 0
409 && e
->flags
.via_conflict_level
<= 2)
410 && (e
->flags
.via_conflict_level
!= 0 ? e
->flags
.is_via
: 1));
411 assert ((e
->cost_to_point
>= 0) && e
->cost
>= 0);
416 /*---------------------------------------------------------------------
417 * route utility functions.
421 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
};
422 static struct routebox_list
*
423 __select_list (routebox_t
* r
, enum boxlist which
)
431 return &(r
->same_net
);
433 return &(r
->same_subnet
);
435 return &(r
->original_subnet
);
437 return &(r
->different_net
);
441 InitLists (routebox_t
* r
)
443 static enum boxlist all
[] =
444 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
}
446 for (p
= all
; p
< all
+ (sizeof (all
) / sizeof (*p
)); p
++)
448 struct routebox_list
*rl
= __select_list (r
, *p
);
449 rl
->prev
= rl
->next
= r
;
454 MergeNets (routebox_t
* a
, routebox_t
* b
, enum boxlist which
)
456 struct routebox_list
*al
, *bl
, *anl
, *bnl
;
460 al
= __select_list (a
, which
);
461 bl
= __select_list (b
, which
);
466 anl
= __select_list (an
, which
);
467 bnl
= __select_list (bn
, which
);
476 RemoveFromNet (routebox_t
* a
, enum boxlist which
)
478 struct routebox_list
*al
, *anl
, *apl
;
481 al
= __select_list (a
, which
);
485 if (an
== a
|| ap
== a
)
486 return; /* not on any list */
488 anl
= __select_list (an
, which
);
489 apl
= __select_list (ap
, which
);
493 al
->next
= al
->prev
= a
;
498 init_const_box (routebox_t
* rb
,
499 LocationType X1
, LocationType Y1
, LocationType X2
,
502 BoxType
*bp
= (BoxType
*) & rb
->box
; /* note discarding const! */
503 assert (!rb
->flags
.inited
);
504 assert (X1
<= X2
&& Y1
<= Y2
);
509 rb
->flags
.inited
= 1;
512 /*---------------------------------------------------------------------
513 * routedata initialization functions.
517 AddPin (PointerListType layergroupboxes
[], PinTypePtr pin
, Boolean is_via
)
519 routebox_t
**rbpp
, *lastrb
= NULL
;
521 /* a pin cuts through every layer group */
522 for (i
= 0; i
< max_layer
; i
++)
524 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[i
]);
525 *rbpp
= malloc (sizeof (**rbpp
));
527 ht
= HALF_THICK (MAX (pin
->Thickness
, pin
->DrillingHole
));
528 init_const_box (*rbpp
,
532 /*Y2 */ pin
->Y
+ ht
);
533 /* set aux. properties */
537 (*rbpp
)->parent
.via
= pin
;
542 (*rbpp
)->parent
.pin
= pin
;
544 (*rbpp
)->flags
.fixed
= 1;
545 (*rbpp
)->flags
.circular
= !TEST_FLAG (SQUAREFLAG
, pin
);
551 MergeNets (*rbpp
, lastrb
, NET
);
552 MergeNets (*rbpp
, lastrb
, SUBNET
);
553 MergeNets (*rbpp
, lastrb
, ORIGINAL
);
560 AddPad (PointerListType layergroupboxes
[],
561 ElementTypePtr element
, PadTypePtr pad
)
563 BDimension halfthick
;
565 int layergroup
= (TEST_FLAG (ONSOLDERFLAG
, pad
) ? back
: front
);
566 assert (0 <= layergroup
&& layergroup
< max_layer
);
567 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
568 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
570 *rbpp
= malloc (sizeof (**rbpp
));
572 (*rbpp
)->group
= layergroup
;
573 halfthick
= HALF_THICK (pad
->Thickness
);
574 init_const_box (*rbpp
,
575 /*X1 */ MIN (pad
->Point1
.X
, pad
->Point2
.X
) - halfthick
,
576 /*Y1 */ MIN (pad
->Point1
.Y
, pad
->Point2
.Y
) - halfthick
,
577 /*X2 */ MAX (pad
->Point1
.X
, pad
->Point2
.X
) + halfthick
,
578 /*Y2 */ MAX (pad
->Point1
.Y
, pad
->Point2
.Y
) + halfthick
);
579 /* kludge for non-manhattan pads (which are not allowed at present) */
580 if (pad
->Point1
.X
!= pad
->Point2
.X
&& pad
->Point1
.Y
!= pad
->Point2
.Y
)
581 (*rbpp
)->flags
.nonstraight
= 1;
582 /* set aux. properties */
584 (*rbpp
)->parent
.pad
= pad
;
585 (*rbpp
)->flags
.fixed
= 1;
591 AddLine (PointerListType layergroupboxes
[], int layergroup
, LineTypePtr line
,
595 assert (layergroupboxes
&& line
);
596 assert (0 <= layergroup
&& layergroup
< max_layer
);
597 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
599 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
600 *rbpp
= malloc (sizeof (**rbpp
));
601 (*rbpp
)->group
= layergroup
;
602 init_const_box (*rbpp
,
603 /*X1 */ MIN (line
->Point1
.X
,
604 line
->Point2
.X
) - HALF_THICK (line
->Thickness
),
605 /*Y1 */ MIN (line
->Point1
.Y
,
606 line
->Point2
.Y
) - HALF_THICK (line
->Thickness
),
607 /*X2 */ MAX (line
->Point1
.X
,
608 line
->Point2
.X
) + HALF_THICK (line
->Thickness
),
609 /*Y2 */ MAX (line
->Point1
.Y
,
611 HALF_THICK (line
->Thickness
));
612 /* kludge for non-manhattan lines */
613 if (line
->Point1
.X
!= line
->Point2
.X
&& line
->Point1
.Y
!= line
->Point2
.Y
)
615 (*rbpp
)->flags
.nonstraight
= 1;
616 (*rbpp
)->flags
.bl_to_ur
=
617 (MIN (line
->Point1
.X
, line
->Point2
.X
) == line
->Point1
.X
) !=
618 (MIN (line
->Point1
.Y
, line
->Point2
.Y
) == line
->Point1
.Y
);
619 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
620 showroutebox (*rbpp
);
623 /* set aux. properties */
624 (*rbpp
)->type
= LINE
;
625 (*rbpp
)->parent
.line
= ptr
;
626 (*rbpp
)->flags
.fixed
= 1;
632 AddIrregularObstacle (PointerListType layergroupboxes
[],
633 LocationType X1
, LocationType Y1
,
634 LocationType X2
, LocationType Y2
, Cardinal layergroup
,
638 assert (layergroupboxes
&& parent
);
639 assert (X1
<= X2
&& Y1
<= Y2
);
640 assert (0 <= layergroup
&& layergroup
< max_layer
);
641 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
643 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
644 *rbpp
= malloc (sizeof (**rbpp
));
645 (*rbpp
)->group
= layergroup
;
646 init_const_box (*rbpp
, X1
, Y1
, X2
, Y2
);
647 (*rbpp
)->flags
.nonstraight
= 1;
648 (*rbpp
)->type
= OTHER
;
649 (*rbpp
)->parent
.generic
= parent
;
650 (*rbpp
)->flags
.fixed
= 1;
657 AddPolygon (PointerListType layergroupboxes
[], Cardinal layer
,
658 PolygonTypePtr polygon
)
660 int is_not_rectangle
= 1;
661 int layergroup
= GetLayerGroupNumberByNumber (layer
);
663 assert (0 <= layergroup
&& layergroup
< max_layer
);
664 rb
= AddIrregularObstacle (layergroupboxes
,
665 polygon
->BoundingBox
.X1
,
666 polygon
->BoundingBox
.Y1
,
667 polygon
->BoundingBox
.X2
,
668 polygon
->BoundingBox
.Y2
,
669 layergroup
, polygon
);
670 if (polygon
->PointN
== 4 &&
671 (polygon
->Points
[0].X
== polygon
->Points
[1].X
||
672 polygon
->Points
[0].Y
== polygon
->Points
[1].Y
) &&
673 (polygon
->Points
[1].X
== polygon
->Points
[2].X
||
674 polygon
->Points
[1].Y
== polygon
->Points
[2].Y
) &&
675 (polygon
->Points
[2].X
== polygon
->Points
[3].X
||
676 polygon
->Points
[2].Y
== polygon
->Points
[3].Y
) &&
677 (polygon
->Points
[3].X
== polygon
->Points
[0].X
||
678 polygon
->Points
[3].Y
== polygon
->Points
[0].Y
))
679 is_not_rectangle
= 0;
680 rb
->flags
.nonstraight
= is_not_rectangle
;
682 if (TEST_FLAG (CLEARPOLYFLAG
, polygon
))
684 rb
->flags
.clear_poly
= 1;
685 if (!is_not_rectangle
)
691 AddText (PointerListType layergroupboxes
[], Cardinal layergroup
,
694 AddIrregularObstacle (layergroupboxes
,
695 text
->BoundingBox
.X1
, text
->BoundingBox
.Y1
,
696 text
->BoundingBox
.X2
, text
->BoundingBox
.Y2
,
700 AddArc (PointerListType layergroupboxes
[], Cardinal layergroup
,
703 return AddIrregularObstacle (layergroupboxes
,
704 arc
->BoundingBox
.X1
, arc
->BoundingBox
.Y1
,
705 arc
->BoundingBox
.X2
, arc
->BoundingBox
.Y2
,
716 __found_one_on_lg (const BoxType
* box
, void *cl
)
718 struct rb_info
*inf
= (struct rb_info
*) cl
;
719 routebox_t
*rb
= (routebox_t
*) box
;
720 if (rb
->flags
.nonstraight
)
723 longjmp (inf
->env
, 1);
727 FindRouteBoxOnLayerGroup (routedata_t
* rd
,
728 LocationType X
, LocationType Y
, Cardinal layergroup
)
733 region
.X1
= region
.X2
= X
;
734 region
.Y1
= region
.Y2
= Y
;
735 if (setjmp (info
.env
) == 0)
736 r_search (rd
->layergrouptree
[layergroup
], ®ion
, NULL
,
737 __found_one_on_lg
, &info
);
743 DumpRouteBox (routebox_t
* rb
)
745 printf ("RB: (%d,%d)-(%d,%d) l%d; ",
746 rb
->box
.X1
, rb
->box
.Y1
, rb
->box
.X2
, rb
->box
.Y2
, (int) rb
->group
);
750 printf ("PAD[%s %s] ", rb
->parent
.pad
->Name
, rb
->parent
.pad
->Number
);
753 printf ("PIN[%s %s] ", rb
->parent
.pin
->Name
, rb
->parent
.pin
->Number
);
758 printf ("VIA[%s %s] ", rb
->parent
.via
->Name
, rb
->parent
.via
->Number
);
773 if (rb
->flags
.nonstraight
)
774 printf ("(nonstraight) ");
777 if (rb
->flags
.source
)
778 printf ("(source) ");
779 if (rb
->flags
.target
)
780 printf ("(target) ");
781 if (rb
->flags
.orphan
)
782 printf ("(orphan) ");
790 NetListListType Nets
;
791 PointerListType layergroupboxes
[MAX_LAYER
];
794 Boolean other
= True
;
797 /* check which layers are active first */
799 for (group
= 0; group
< max_layer
; group
++)
801 for (i
= 0; i
< PCB
->LayerGroups
.Number
[group
]; i
++)
802 /* layer must be 1) not silk (ie, < max_layer) and 2) on */
803 if ((PCB
->LayerGroups
.Entries
[group
][i
] < max_layer
) &&
804 PCB
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][i
]].On
)
807 is_layer_group_active
[group
] = True
;
811 is_layer_group_active
[group
] = False
;
813 AutoRouteParameters
.use_vias
= ((routing_layers
> 1) ? True
: False
);
814 front
= GetLayerGroupNumberByNumber (max_layer
+ COMPONENT_LAYER
);
815 back
= GetLayerGroupNumberByNumber (max_layer
+ SOLDER_LAYER
);
816 /* determine preferred routing direction on each group */
817 for (i
= 0; i
< max_layer
; i
++)
819 if (i
!= back
&& i
!= front
)
831 /* create routedata */
832 rd
= malloc (sizeof (*rd
));
833 /* create default style */
834 rd
->defaultStyle
.Thick
= Settings
.LineThickness
;
835 rd
->defaultStyle
.Diameter
= Settings
.ViaThickness
;
836 rd
->defaultStyle
.Hole
= Settings
.ViaDrillingHole
;
837 rd
->defaultStyle
.Keepaway
= Settings
.Keepaway
;
838 rd
->max_bloat
= BLOAT (&rd
->defaultStyle
);
839 /* create augStyles structures */
840 bbox
.X1
= bbox
.Y1
= 0;
841 bbox
.X2
= PCB
->MaxWidth
;
842 bbox
.Y2
= PCB
->MaxHeight
;
843 for (i
= 0; i
< NUM_STYLES
+ 1; i
++)
845 RouteStyleType
*style
=
846 (i
< NUM_STYLES
) ? &PCB
->RouteStyle
[i
] : &rd
->defaultStyle
;
847 rd
->augStyles
[i
].style
= style
;
848 rd
->augStyles
[i
].Used
= False
;
851 /* initialize pointerlisttype */
852 for (i
= 0; i
< max_layer
; i
++)
854 layergroupboxes
[i
].Ptr
= NULL
;
855 layergroupboxes
[i
].PtrN
= 0;
856 layergroupboxes
[i
].PtrMax
= 0;
857 GROUP_LOOP (PCB
->Data
, i
);
859 if (layer
->LineN
|| layer
->ArcN
)
862 usedGroup
[i
] = False
;
866 usedGroup
[front
] = True
;
867 usedGroup
[back
] = True
;
868 /* add the objects in the netlist first.
869 * then go and add all other objects that weren't already added
871 * this saves on searching the trees to find the nets
873 /* use the DRCFLAG to mark objects as their entered */
874 ResetFoundPinsViasAndPads (False
);
875 ResetFoundLinesAndPolygons (False
);
876 Nets
= CollectSubnets (False
);
878 routebox_t
*last_net
= NULL
;
879 NETLIST_LOOP (&Nets
);
881 routebox_t
*last_in_net
= NULL
;
884 routebox_t
*last_in_subnet
= NULL
;
887 for (j
= 0; j
< NUM_STYLES
; j
++)
888 if (net
->Style
== rd
->augStyles
[j
].style
)
890 CONNECTION_LOOP (net
);
892 routebox_t
*rb
= NULL
;
893 SET_FLAG (DRCFLAG
, (PinTypePtr
) connection
->ptr2
);
894 if (connection
->type
== LINE_TYPE
)
896 LineType
*line
= (LineType
*) connection
->ptr2
;
898 /* lines are listed at each end, so skip one */
899 /* this should probably by a macro named "BUMP_LOOP" */
902 /* dice up non-straight lines into many tiny obstacles */
903 if (line
->Point1
.X
!= line
->Point2
.X
904 && line
->Point1
.Y
!= line
->Point2
.Y
)
906 LineType fake_line
= *line
;
907 int dx
= (line
->Point2
.X
- line
->Point1
.X
);
908 int dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
909 int segs
= MAX (ABS (dx
),
911 BLOAT (rd
->augStyles
[j
].
914 segs
= MAX (1, MIN (segs
, 32)); /* don't go too crazy */
917 for (qq
= 0; qq
< segs
- 1; qq
++)
919 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
920 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
921 if (fake_line
.Point2
.X
== line
->Point2
.X
922 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
925 AddLine (layergroupboxes
, connection
->group
,
927 rb
->augStyle
= &rd
->augStyles
[j
];
928 if (last_in_subnet
&& rb
!= last_in_subnet
)
929 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
930 if (last_in_net
&& rb
!= last_in_net
)
931 MergeNets (last_in_net
, rb
, NET
);
932 last_in_subnet
= last_in_net
= rb
;
933 fake_line
.Point1
= fake_line
.Point2
;
935 fake_line
.Point2
= line
->Point2
;
937 AddLine (layergroupboxes
, connection
->group
, &fake_line
,
943 AddLine (layergroupboxes
, connection
->group
, line
, line
);
947 switch (connection
->type
)
951 AddPad (layergroupboxes
, connection
->ptr1
,
955 rb
= AddPin (layergroupboxes
, connection
->ptr2
, False
);
958 rb
= AddPin (layergroupboxes
, connection
->ptr2
, True
);
962 AddPolygon (layergroupboxes
,
963 GetLayerNumber (PCB
->Data
, connection
->ptr1
),
968 /* set rb->augStyle! */
969 rb
->augStyle
= &rd
->augStyles
[j
];
970 rb
->augStyle
->Used
= True
;
971 /* update circular connectivity lists */
972 if (last_in_subnet
&& rb
!= last_in_subnet
)
973 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
974 if (last_in_net
&& rb
!= last_in_net
)
975 MergeNets (last_in_net
, rb
, NET
);
976 last_in_subnet
= last_in_net
= rb
;
977 rd
->max_bloat
= MAX (rd
->max_bloat
, BLOAT (rb
->augStyle
->style
));
982 if (last_net
&& last_in_net
)
983 MergeNets (last_net
, last_in_net
, DIFFERENT_NET
);
984 last_net
= last_in_net
;
987 rd
->first_net
= last_net
;
989 FreeNetListListMemory (&Nets
);
991 /* reset all nets to "original" connectivity (which we just set) */
994 LIST_LOOP (rd
->first_net
, different_net
, net
);
999 /* add pins and pads of elements */
1000 ALLPIN_LOOP (PCB
->Data
);
1002 if (TEST_FLAG (DRCFLAG
, pin
))
1003 CLEAR_FLAG (DRCFLAG
, pin
);
1005 AddPin (layergroupboxes
, pin
, False
);
1008 ALLPAD_LOOP (PCB
->Data
);
1010 if (TEST_FLAG (DRCFLAG
, pad
))
1011 CLEAR_FLAG (DRCFLAG
, pad
);
1013 AddPad (layergroupboxes
, element
, pad
);
1017 VIA_LOOP (PCB
->Data
);
1019 if (TEST_FLAG (DRCFLAG
, via
))
1020 CLEAR_FLAG (DRCFLAG
, via
);
1022 AddPin (layergroupboxes
, via
, True
);
1026 for (i
= 0; i
< max_layer
; i
++)
1028 int layergroup
= GetLayerGroupNumberByNumber (i
);
1029 /* add all (non-rat) lines */
1030 LINE_LOOP (LAYER_PTR (i
));
1032 if (TEST_FLAG (DRCFLAG
, line
))
1034 CLEAR_FLAG (DRCFLAG
, line
);
1037 /* dice up non-straight lines into many tiny obstacles */
1038 if (line
->Point1
.X
!= line
->Point2
.X
1039 && line
->Point1
.Y
!= line
->Point2
.Y
)
1041 LineType fake_line
= *line
;
1042 int dx
= (line
->Point2
.X
- line
->Point1
.X
);
1043 int dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
1044 int segs
= MAX (ABS (dx
), ABS (dy
)) / (4 * rd
->max_bloat
+ 1);
1046 segs
= MAX (1, MIN (segs
, 32)); /* don't go too crazy */
1049 for (qq
= 0; qq
< segs
- 1; qq
++)
1051 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
1052 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
1053 if (fake_line
.Point2
.X
== line
->Point2
.X
1054 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
1056 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
);
1057 fake_line
.Point1
= fake_line
.Point2
;
1059 fake_line
.Point2
= line
->Point2
;
1060 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
);
1064 AddLine (layergroupboxes
, layergroup
, line
, line
);
1068 /* add all polygons */
1069 POLYGON_LOOP (LAYER_PTR (i
));
1071 if (TEST_FLAG (DRCFLAG
, polygon
))
1072 CLEAR_FLAG (DRCFLAG
, polygon
);
1074 AddPolygon (layergroupboxes
, i
, polygon
);
1077 /* add all copper text */
1078 TEXT_LOOP (LAYER_PTR (i
));
1080 AddText (layergroupboxes
, layergroup
, text
);
1084 ARC_LOOP (LAYER_PTR (i
));
1086 AddArc (layergroupboxes
, layergroup
, arc
);
1091 /* create r-trees from pointer lists */
1092 for (i
= 0; i
< max_layer
; i
++)
1094 /* initialize style (we'll fill in a "real" style later, when we add
1095 * the connectivity information) */
1096 POINTER_LOOP (&layergroupboxes
[i
]);
1098 /* we're initializing this to the "default" style */
1099 ((routebox_t
*) * ptr
)->augStyle
= &rd
->augStyles
[NUM_STYLES
];
1102 /* create the r-tree */
1103 rd
->layergrouptree
[i
] =
1104 r_create_tree ((const BoxType
**) layergroupboxes
[i
].Ptr
,
1105 layergroupboxes
[i
].PtrN
, 1);
1108 if (AutoRouteParameters
.use_vias
)
1110 rd
->mtspace
= mtspace_create ();
1112 /* create "empty-space" structures for via placement (now that we know
1113 * appropriate keepaways for all the fixed elements) */
1114 for (i
= 0; i
< max_layer
; i
++)
1116 POINTER_LOOP (&layergroupboxes
[i
]);
1118 routebox_t
*rb
= (routebox_t
*) * ptr
;
1119 if (!rb
->flags
.clear_poly
)
1120 mtspace_add (rd
->mtspace
, &rb
->box
, FIXED
,
1121 rb
->augStyle
->style
->Keepaway
);
1126 /* free pointer lists */
1127 for (i
= 0; i
< max_layer
; i
++)
1128 FreePointerListMemory (&layergroupboxes
[i
]);
1134 DestroyRouteData (routedata_t
** rd
)
1137 for (i
= 0; i
< max_layer
; i
++)
1138 r_destroy_tree (&(*rd
)->layergrouptree
[i
]);
1139 if (AutoRouteParameters
.use_vias
)
1140 mtspace_destroy (&(*rd
)->mtspace
);
1145 /*-----------------------------------------------------------------
1146 * routebox reference counting.
1149 /* increment the reference count on a routebox. */
1151 RB_up_count (routebox_t
* rb
)
1153 assert (rb
->flags
.orphan
);
1157 /* decrement the reference count on a routebox, freeing if this box becomes
1160 RB_down_count (routebox_t
* rb
)
1162 assert (rb
->flags
.orphan
);
1163 assert (rb
->refcount
> 0);
1164 if (--rb
->refcount
== 0)
1166 /* rb->underlying is guaranteed to not be an orphan, so we only need
1167 * to downcount the parent, if type==EXPANSION_AREA */
1168 if (rb
->type
== EXPANSION_AREA
1169 && rb
->parent
.expansion_area
->flags
.orphan
)
1170 RB_down_count (rb
->parent
.expansion_area
);
1175 /*-----------------------------------------------------------------
1176 * Rectangle-expansion routing code.
1180 ResetSubnet (routebox_t
* net
)
1183 /* reset connectivity of everything on this net */
1184 LIST_LOOP (net
, same_net
, rb
);
1185 rb
->same_subnet
= rb
->original_subnet
;
1189 static inline cost_t
1190 cost_to_point_on_layer (const CheapPointType
* p1
,
1191 const CheapPointType
* p2
, Cardinal point_layer
)
1193 cost_t x_dist
= p1
->X
- p2
->X
, y_dist
= p1
->Y
- p2
->Y
, r
;
1194 if (bad_x
[point_layer
])
1195 x_dist
*= AutoRouteParameters
.DirectionPenalty
;
1196 else if (bad_y
[point_layer
])
1197 y_dist
*= AutoRouteParameters
.DirectionPenalty
;
1198 /* cost is proportional to orthogonal distance. */
1199 r
= ABS (x_dist
) + ABS (y_dist
);
1200 /* penalize the surface layers in order to minimize SMD pad congestion */
1201 if (point_layer
== front
|| point_layer
== back
)
1202 r
*= AutoRouteParameters
.SurfacePenalty
;
1207 cost_to_point (const CheapPointType
* p1
, Cardinal point_layer1
,
1208 const CheapPointType
* p2
, Cardinal point_layer2
)
1210 cost_t r
= cost_to_point_on_layer (p1
, p2
, point_layer1
);
1211 /* apply via cost penalty if layers differ */
1212 if (point_layer1
!= point_layer2
)
1213 r
+= AutoRouteParameters
.ViaCost
;
1217 /* return the minimum *cost* from a point to a box on any layer.
1218 * It's safe to return a smaller than minimum cost
1221 cost_to_layerless_box (const CheapPointType
* p
, Cardinal point_layer
,
1224 CheapPointType p2
= closest_point_in_box (p
, b
);
1225 register cost_t c1
, c2
;
1233 return c1
* AutoRouteParameters
.MinPenalty
+ c2
;
1235 return c2
* AutoRouteParameters
.MinPenalty
+ c1
;
1238 /* get to actual pins/pad target coordinates */
1240 TargetPoint (CheapPointType
* nextpoint
, const routebox_t
* target
)
1242 if (target
->type
== PIN
)
1244 nextpoint
->X
= target
->parent
.pin
->X
;
1245 nextpoint
->Y
= target
->parent
.pin
->Y
;
1248 else if (target
->type
== PAD
)
1250 if (abs (target
->parent
.pad
->Point1
.X
- nextpoint
->X
) <
1251 abs (target
->parent
.pad
->Point2
.X
- nextpoint
->X
))
1252 nextpoint
->X
= target
->parent
.pad
->Point1
.X
;
1254 nextpoint
->X
= target
->parent
.pad
->Point2
.X
;
1255 if (abs (target
->parent
.pad
->Point1
.Y
- nextpoint
->Y
) <
1256 abs (target
->parent
.pad
->Point2
.Y
- nextpoint
->Y
))
1257 nextpoint
->Y
= target
->parent
.pad
->Point1
.Y
;
1259 nextpoint
->Y
= target
->parent
.pad
->Point2
.Y
;
1262 else if (target
->type
== VIA
)
1264 nextpoint
->X
= (target
->box
.X1
+ target
->box
.X2
) / 2;
1265 nextpoint
->Y
= (target
->box
.Y1
+ target
->box
.Y2
) / 2;
1270 /* return the *minimum cost* from a point to a route box, including possible
1271 * via costs if the route box is on a different layer. */
1273 cost_to_routebox (const CheapPointType
* p
, Cardinal point_layer
,
1274 const routebox_t
* rb
)
1276 register cost_t c1
, c2
, trial
= 0;
1277 CheapPointType p2
= closest_point_in_box (p
, &rb
->box
);
1278 // if (rb->flags.target)
1279 // TargetPoint (&p2, rb);
1280 if (!usedGroup
[point_layer
] || !usedGroup
[rb
->group
])
1281 trial
= AutoRouteParameters
.NewLayerPenalty
;
1282 if ((p
->X
- p2
.X
) * (p
->Y
- p2
.Y
) != 0)
1283 trial
+= AutoRouteParameters
.JogPenalty
;
1284 /* special case for defered via searching */
1285 if (point_layer
> max_layer
)
1286 return trial
+ cost_to_point_on_layer (p
, &p2
, rb
->group
);
1287 if (point_layer
== rb
->group
)
1288 return trial
+ cost_to_point_on_layer (p
, &p2
, point_layer
);
1289 trial
+= AutoRouteParameters
.ViaCost
;
1290 c1
= cost_to_point_on_layer (p
, &p2
, point_layer
);
1291 c2
= cost_to_point_on_layer (p
, &p2
, rb
->group
);
1292 trial
+= MIN (c1
, c2
);
1297 bloat_routebox (routebox_t
* rb
)
1300 BDimension keepaway
;
1301 assert (__routebox_is_good (rb
));
1302 if (rb
->type
== EXPANSION_AREA
|| rb
->flags
.nobloat
)
1303 return rb
->box
; /* no bloat */
1305 /* obstacle exclusion zones get bloated, and then shrunk on their
1306 * top and left sides so that they approximate their "open"
1308 keepaway
= MAX (AutoRouteParameters
.augStyle
->style
->Keepaway
,
1309 rb
->augStyle
->style
->Keepaway
);
1310 r
= bloat_box (&rb
->box
, keepaway
+
1311 HALF_THICK (AutoRouteParameters
.augStyle
->style
->Thick
));
1318 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1319 /* makes a line on the solder layer silk surrounding the box */
1321 showbox (BoxType b
, Dimension thickness
, int group
)
1324 LayerTypePtr SLayer
= LAYER_PTR (group
);
1328 gui
->set_line_width (Output
.fgGC
, thickness
);
1329 gui
->set_line_cap (Output
.fgGC
, Trace_Cap
);
1330 gui
->set_color (Output
.fgGC
, SLayer
->Color
);
1332 gui
->draw_line (Output
.fgGC
, b
.X1
, b
.Y1
, b
.X2
, b
.Y1
);
1333 gui
->draw_line (Output
.fgGC
, b
.X1
, b
.Y2
, b
.X2
, b
.Y2
);
1334 gui
->draw_line (Output
.fgGC
, b
.X1
, b
.Y1
, b
.X1
, b
.Y2
);
1335 gui
->draw_line (Output
.fgGC
, b
.X2
, b
.Y1
, b
.X2
, b
.Y2
);
1338 if (XtAppPending (Context
))
1339 XtAppProcessEvent (Context
, XtIMAll
);
1343 if (b
.Y1
== b
.Y2
|| b
.X1
== b
.X2
)
1345 line
= CreateNewLineOnLayer (LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1346 b
.X1
, b
.Y1
, b
.X2
, b
.Y1
, thickness
, 0,
1348 AddObjectToCreateUndoList (LINE_TYPE
,
1349 LAYER_PTR (max_layer
+ COMPONENT_LAYER
), line
,
1353 line
= CreateNewLineOnLayer (LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1354 b
.X1
, b
.Y2
, b
.X2
, b
.Y2
, thickness
, 0,
1356 AddObjectToCreateUndoList (LINE_TYPE
,
1357 LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1360 line
= CreateNewLineOnLayer (LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1361 b
.X1
, b
.Y1
, b
.X1
, b
.Y2
, thickness
, 0,
1363 AddObjectToCreateUndoList (LINE_TYPE
,
1364 LAYER_PTR (max_layer
+ COMPONENT_LAYER
), line
,
1368 line
= CreateNewLineOnLayer (LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1369 b
.X2
, b
.Y1
, b
.X2
, b
.Y2
, thickness
, 0,
1371 AddObjectToCreateUndoList (LINE_TYPE
,
1372 LAYER_PTR (max_layer
+ COMPONENT_LAYER
),
1378 #if defined(ROUTE_DEBUG)
1380 showedge (edge_t
* e
)
1382 BoxType
*b
= (BoxType
*) e
->rb
;
1384 gui
->set_line_cap (Output
.fgGC
, Trace_Cap
);
1385 gui
->set_line_width (Output
.fgGC
, 1);
1386 gui
->set_color (Output
.fgGC
, Settings
.MaskColor
);
1388 switch (e
->expand_dir
)
1391 gui
->draw_line (Output
.fgGC
, b
->X1
, b
->Y1
, b
->X2
, b
->Y1
);
1394 gui
->draw_line (Output
.fgGC
, b
->X1
, b
->Y2
, b
->X2
, b
->Y2
);
1397 gui
->draw_line (Output
.fgGC
, b
->X1
, b
->Y1
, b
->X1
, b
->Y2
);
1400 gui
->draw_line (Output
.fgGC
, b
->X2
, b
->Y1
, b
->X2
, b
->Y2
);
1406 #if defined(ROUTE_DEBUG)
1408 showroutebox (routebox_t
* rb
)
1410 showbox (rb
->box
, rb
->flags
.source
? 8 : (rb
->flags
.target
? 4 : 1),
1411 rb
->flags
.is_via
? max_layer
+ COMPONENT_LAYER
: rb
->group
);
1416 EraseRouteBox (routebox_t
* rb
)
1418 LocationType X1
, Y1
, X2
, Y2
;
1421 if (rb
->box
.X2
- rb
->box
.X1
< rb
->box
.Y2
- rb
->box
.Y1
)
1423 thick
= rb
->box
.X2
- rb
->box
.X1
;
1424 X1
= X2
= (rb
->box
.X2
+ rb
->box
.X1
) / 2;
1425 Y1
= rb
->box
.Y1
+ thick
/ 2;
1426 Y2
= rb
->box
.Y2
- thick
/ 2;
1430 thick
= rb
->box
.Y2
- rb
->box
.Y1
;
1431 Y1
= Y2
= (rb
->box
.Y2
+ rb
->box
.Y1
) / 2;
1432 X1
= rb
->box
.X1
+ thick
/ 2;
1433 X2
= rb
->box
.X2
- thick
/ 2;
1436 gui
->set_line_width (ar_gc
, thick
);
1437 gui
->set_color (ar_gc
, Settings
.BackgroundColor
);
1438 gui
->draw_line (ar_gc
, X1
, Y1
, X2
, Y2
);
1441 /* return a "parent" of this edge which immediately precedes it in the route.*/
1443 route_parent (routebox_t
* rb
)
1445 while (rb
->flags
.orphan
&& rb
->underlying
== NULL
&& !rb
->flags
.is_via
)
1447 assert (rb
->type
== EXPANSION_AREA
);
1448 rb
= rb
->parent
.expansion_area
;
1454 /* return a "parent" of this edge which resides in a r-tree somewhere */
1455 /* -- actually, this "parent" *may* be a via box, which doesn't live in
1458 nonorphan_parent (routebox_t
* rb
)
1460 rb
= route_parent (rb
);
1461 return rb
->underlying
? rb
->underlying
: rb
;
1464 /* some routines to find the minimum *cost* from a cost point to
1465 * a target (any target) */
1466 struct mincost_target_closure
1468 const CheapPointType
*CostPoint
;
1469 Cardinal CostPointLayer
;
1470 routebox_t
*nearest
;
1471 cost_t nearest_cost
;
1474 __region_within_guess (const BoxType
* region
, void *cl
)
1476 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1477 cost_t cost_to_region
;
1478 if (mtc
->nearest
== NULL
)
1481 cost_to_layerless_box (mtc
->CostPoint
, mtc
->CostPointLayer
, region
);
1482 assert (cost_to_region
>= 0);
1483 /* if no guess yet, all regions are "close enough" */
1484 /* note that cost is *strictly more* than minimum distance, so we'll
1485 * always search a region large enough. */
1486 return (cost_to_region
< mtc
->nearest_cost
);
1489 __found_new_guess (const BoxType
* box
, void *cl
)
1491 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1492 routebox_t
*guess
= (routebox_t
*) box
;
1493 cost_t cost_to_guess
=
1494 cost_to_routebox (mtc
->CostPoint
, mtc
->CostPointLayer
, guess
);
1495 assert (cost_to_guess
>= 0);
1496 /* if this is cheaper than previous guess... */
1497 if (cost_to_guess
< mtc
->nearest_cost
)
1499 mtc
->nearest
= guess
;
1500 mtc
->nearest_cost
= cost_to_guess
; /* this is our new guess! */
1504 return 0; /* not less expensive than our last guess */
1507 /* target_guess is our guess at what the nearest target is, or NULL if we
1508 * just plum don't have a clue. */
1510 mincost_target_to_point (const CheapPointType
* CostPoint
,
1511 Cardinal CostPointLayer
,
1512 rtree_t
* targets
, routebox_t
* target_guess
)
1514 struct mincost_target_closure mtc
;
1515 assert (target_guess
== NULL
|| target_guess
->flags
.target
); /* this is a target, right? */
1516 mtc
.CostPoint
= CostPoint
;
1517 mtc
.CostPointLayer
= CostPointLayer
;
1518 mtc
.nearest
= target_guess
;
1521 cost_to_routebox (mtc
.CostPoint
, mtc
.CostPointLayer
, mtc
.nearest
);
1523 mtc
.nearest_cost
= EXPENSIVE
;
1524 r_search (targets
, NULL
, __region_within_guess
, __found_new_guess
, &mtc
);
1525 assert (mtc
.nearest
!= NULL
&& mtc
.nearest_cost
>= 0);
1526 assert (mtc
.nearest
->flags
.target
); /* this is a target, right? */
1530 /* create edge from field values */
1531 /* mincost_target_guess can be NULL */
1533 CreateEdge (routebox_t
* rb
,
1534 LocationType CostPointX
, LocationType CostPointY
,
1535 cost_t cost_to_point
,
1536 routebox_t
* mincost_target_guess
,
1537 direction_t expand_dir
, rtree_t
* targets
)
1540 assert (__routebox_is_good (rb
));
1541 e
= malloc (sizeof (*e
));
1544 if (rb
->flags
.orphan
)
1546 e
->cost_point
.X
= CostPointX
;
1547 e
->cost_point
.Y
= CostPointY
;
1548 e
->cost_to_point
= cost_to_point
;
1549 e
->flags
.via_search
= 0;
1550 /* if this edge is created in response to a target, use it */
1553 mincost_target_to_point (&e
->cost_point
, rb
->group
,
1554 targets
, mincost_target_guess
);
1556 e
->mincost_target
= mincost_target_guess
;
1557 e
->expand_dir
= expand_dir
;
1558 assert (e
->rb
&& e
->mincost_target
); /* valid edge? */
1559 assert (!e
->flags
.is_via
|| e
->flags
.expand_all_sides
);
1560 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1561 assert (rb
->type
== PLANE
|| rb
->underlying
!= NULL
|| rb
->flags
.is_via
||
1562 ((expand_dir
== NORTH
|| expand_dir
== SOUTH
) ?
1563 rb
->box
.X1
<= CostPointX
&& CostPointX
<= rb
->box
.X2
&&
1564 CostPointY
== (expand_dir
== NORTH
? rb
->box
.Y1
: rb
->box
.Y2
) :
1565 /* expand_dir==EAST || expand_dir==WEST */
1566 rb
->box
.Y1
<= CostPointY
&& CostPointY
<= rb
->box
.Y2
&&
1567 CostPointX
== (expand_dir
== EAST
? rb
->box
.X2
: rb
->box
.X1
)));
1568 assert (__edge_is_good (e
));
1574 going_away (CheapPointType first
, CheapPointType second
, routebox_t
* target
)
1576 CheapPointType t
= closest_point_in_box (&second
, &target
->box
);
1577 if (SQUARE (t
.X
- second
.X
) + SQUARE (t
.Y
- second
.Y
) >
1578 SQUARE (t
.X
- first
.X
) + SQUARE (t
.Y
- first
.Y
))
1579 return AutoRouteParameters
.AwayPenalty
;
1583 /* create edge, using previous edge to fill in defaults. */
1584 /* most of the work here is in determining a new cost point */
1586 CreateEdge2 (routebox_t
* rb
, direction_t expand_dir
,
1587 edge_t
* previous_edge
, rtree_t
* targets
, routebox_t
* guess
)
1590 CheapPointType thiscost
, prevcost
;
1593 assert (rb
&& previous_edge
);
1594 /* okay, find cheapest costpoint to costpoint of previous edge */
1595 thisbox
= edge_to_box (&rb
->box
, expand_dir
);
1596 prevcost
= previous_edge
->cost_point
;
1597 /* find point closest to target */
1598 thiscost
= closest_point_in_box (&prevcost
, &thisbox
);
1599 /* compute cost-to-point */
1600 d
= cost_to_point_on_layer (&prevcost
, &thiscost
, rb
->group
);
1601 /* penalize getting further from the target */
1602 d
*= going_away (prevcost
, thiscost
, previous_edge
->mincost_target
);
1603 /* add in jog penalty */
1604 if (previous_edge
->expand_dir
!= expand_dir
1605 && (!guess
|| !guess
->flags
.target
))
1606 d
+= AutoRouteParameters
.JogPenalty
;
1607 /* okay, new edge! */
1608 return CreateEdge (rb
, thiscost
.X
, thiscost
.Y
,
1609 previous_edge
->cost_to_point
+ d
,
1610 guess
? guess
: previous_edge
->mincost_target
,
1611 expand_dir
, targets
);
1614 /* create via edge, using previous edge to fill in defaults. */
1616 CreateViaEdge (const BoxType
* area
, Cardinal group
,
1617 routebox_t
* parent
, edge_t
* previous_edge
,
1618 conflict_t to_site_conflict
,
1619 conflict_t through_site_conflict
, rtree_t
* targets
)
1622 CheapPointType costpoint
;
1628 scale
[1] = AutoRouteParameters
.LastConflictPenalty
;
1629 scale
[2] = AutoRouteParameters
.ConflictPenalty
;
1631 assert (__box_is_good (area
));
1632 assert (AutoRouteParameters
.with_conflicts
||
1633 (to_site_conflict
== NO_CONFLICT
&&
1634 through_site_conflict
== NO_CONFLICT
));
1635 rb
= CreateExpansionArea (area
, group
, parent
, True
, previous_edge
);
1636 rb
->flags
.is_via
= 1;
1637 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1639 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1640 /* for planes, choose a point near the target */
1641 if (parent
->type
== PLANE
)
1645 /* find a target near this via box */
1646 pnt
.X
= (area
->X2
+ area
->X1
) / 2;
1647 pnt
.Y
= (area
->Y2
+ area
->Y1
) / 2;
1648 target
= mincost_target_to_point (&pnt
, rb
->group
,
1650 previous_edge
->mincost_target
);
1651 /* now find point near the target */
1652 pnt
.X
= (target
->box
.X1
+ target
->box
.X2
) / 2;
1653 pnt
.Y
= (target
->box
.Y1
+ target
->box
.Y2
) / 2;
1654 costpoint
= closest_point_in_box (&pnt
, &rb
->box
);
1656 (scale
[through_site_conflict
] *
1657 cost_to_point (&costpoint
, group
, &costpoint
,
1658 previous_edge
->rb
->group
));
1659 ne
= CreateEdge (rb
, costpoint
.X
, costpoint
.Y
, previous_edge
->cost_to_point
+ d
, target
, NORTH
/*arbitrary */
1664 costpoint
= closest_point_in_box (&previous_edge
->cost_point
, &rb
->box
);
1666 (scale
[to_site_conflict
] *
1667 cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1668 previous_edge
->rb
->group
)) +
1669 (scale
[through_site_conflict
] *
1670 cost_to_point (&costpoint
, group
, &costpoint
,
1671 previous_edge
->rb
->group
));
1672 ne
= CreateEdge (rb
, costpoint
.X
, costpoint
.Y
, previous_edge
->cost_to_point
+ d
, previous_edge
->mincost_target
, NORTH
/*arbitrary */
1675 ne
->flags
.expand_all_sides
= ne
->flags
.is_via
= 1;
1676 ne
->flags
.via_conflict_level
= to_site_conflict
;
1677 assert (__edge_is_good (ne
));
1681 /* create "interior" edge for routing with conflicts */
1683 CreateEdgeWithConflicts (const BoxType
* interior_edge
,
1684 routebox_t
* container
,
1685 edge_t
* previous_edge
,
1686 cost_t cost_penalty_to_box
, rtree_t
* targets
)
1690 CheapPointType costpoint
;
1693 assert (interior_edge
&& container
&& previous_edge
&& targets
);
1694 assert (!container
->flags
.orphan
);
1695 assert (AutoRouteParameters
.with_conflicts
);
1696 /* create expansion area equal to the bloated container. Put costpoint
1697 * in this box. compute cost, but add jog penalty. */
1698 b
= bloat_routebox (container
);
1699 assert (previous_edge
->rb
->group
== container
->group
);
1700 rb
= CreateExpansionArea (&b
, previous_edge
->rb
->group
, previous_edge
->rb
,
1701 True
, previous_edge
);
1702 rb
->underlying
= container
; /* crucial! */
1703 costpoint
= closest_point_in_box (&previous_edge
->cost_point
, &b
);
1704 d
= cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1705 previous_edge
->rb
->group
);
1706 d
*= cost_penalty_to_box
;
1707 ne
= CreateEdge (rb
, costpoint
.X
, costpoint
.Y
, previous_edge
->cost_to_point
+ d
, previous_edge
->mincost_target
, NORTH
/*arbitrary */
1709 ne
->flags
.expand_all_sides
= ne
->flags
.is_interior
= 1;
1710 assert (__edge_is_good (ne
));
1715 DestroyEdge (edge_t
** e
)
1718 if ((*e
)->rb
->flags
.orphan
)
1719 RB_down_count ((*e
)->rb
); /* possibly free rb */
1720 if ((*e
)->flags
.via_search
)
1721 mtsFreeWork (&(*e
)->work
);
1726 /* cost function for an edge. */
1728 edge_cost (const edge_t
* e
, const cost_t too_big
)
1731 if (e
->rb
->type
== PLANE
)
1732 return 1; /* thermals are cheap */
1733 if (!usedGroup
[e
->rb
->group
])
1734 penalty
= AutoRouteParameters
.NewLayerPenalty
;
1735 switch (e
->expand_dir
)
1738 if (e
->mincost_target
->box
.Y1
>= e
->rb
->box
.Y1
)
1739 penalty
+= AutoRouteParameters
.WrongWayPenalty
;
1742 if (e
->mincost_target
->box
.Y2
<= e
->rb
->box
.Y2
)
1743 penalty
+= AutoRouteParameters
.WrongWayPenalty
;
1746 if (e
->mincost_target
->box
.X1
>= e
->rb
->box
.X1
)
1747 penalty
+= AutoRouteParameters
.WrongWayPenalty
;
1750 if (e
->mincost_target
->box
.X2
>= e
->rb
->box
.X2
)
1751 penalty
+= AutoRouteParameters
.WrongWayPenalty
;
1754 penalty
+= e
->cost_to_point
;
1755 if (penalty
> too_big
)
1758 /* cost_to_routebox adds in our via correction, too. */
1760 cost_to_routebox (&e
->cost_point
, e
->rb
->group
, e
->mincost_target
);
1764 edge_length (const BoxType
* cb
, direction_t expand_dir
)
1767 ROTATEBOX_TO_NORTH (b
, expand_dir
);
1768 assert (b
.X1
<= b
.X2
);
1772 /* return a bounding box for the PCB board. */
1778 b
.X2
= PCB
->MaxWidth
;
1780 b
.Y2
= PCB
->MaxHeight
;
1781 /* adjust from closed to half-closed box */
1789 shrunk_pcb_bounds ()
1791 BoxType b
= pcb_bounds ();
1792 return shrink_box (&b
, AutoRouteParameters
.augStyle
->style
->Keepaway
+
1793 HALF_THICK (AutoRouteParameters
.augStyle
->style
->Thick
));
1796 /* create a maximal expansion region from the specified edge to the edge
1797 * of the PCB (minus the required keepaway). */
1799 edge_to_infinity_region (edge_t
* e
)
1803 max
= shrunk_pcb_bounds ();
1804 /* normalize to north */
1805 ROTATEBOX_TO_NORTH (max
, e
->expand_dir
);
1806 ROTATEBOX_TO_NORTH (ebox
, e
->expand_dir
);
1812 ROTATEBOX_FROM_NORTH (max
, e
->expand_dir
);
1817 /* given an edge of a box, return a box containing exactly the points on that
1818 * edge. Note that the box is treated as closed; that is, the bottom and
1819 * right "edges" consist of points (just barely) not in the (half-open) box. */
1821 edge_to_box (const BoxType
* box
, direction_t expand_dir
)
1824 /* narrow box down to just the appropriate edge */
1842 /* treat b as *closed* instead of half-closed, by adding one to
1843 * the (normally-open) bottom and right edges. */
1850 /* limit the specified expansion region so that it just touches the
1851 * given limit. Returns the limited region (which may be invalid). */
1853 limit_region (BoxType region
, edge_t
* e
, BoxType lbox
)
1855 ROTATEBOX_TO_NORTH (region
, e
->expand_dir
);
1856 ROTATEBOX_TO_NORTH (lbox
, e
->expand_dir
);
1858 assert (lbox
.X1
<= region
.X2
);
1859 assert (lbox
.X2
>= region
.X1
);
1860 region
.Y1
= lbox
.Y2
;
1861 /* now rotate back */
1862 ROTATEBOX_FROM_NORTH (region
, e
->expand_dir
);
1868 BoxType left
, center
, right
;
1869 Boolean is_valid_left
, is_valid_center
, is_valid_right
;
1872 static struct broken_boxes
1873 break_box_edge (const BoxType
* original
, direction_t which_edge
,
1874 routebox_t
* breaker
)
1876 BoxType origbox
, breakbox
;
1877 struct broken_boxes result
;
1879 assert (original
&& breaker
);
1881 origbox
= *original
;
1882 breakbox
= bloat_routebox (breaker
);
1883 ROTATEBOX_TO_NORTH (origbox
, which_edge
);
1884 ROTATEBOX_TO_NORTH (breakbox
, which_edge
);
1885 result
.right
.Y1
= result
.right
.Y2
= result
.center
.Y1
= result
.center
.Y2
=
1886 result
.left
.Y1
= result
.left
.Y2
= origbox
.Y1
;
1887 /* validity of breaker */
1888 assert (breakbox
.X1
< origbox
.X2
&& breakbox
.X2
> origbox
.X1
);
1889 /* left edge piece */
1890 result
.left
.X1
= origbox
.X1
;
1891 result
.left
.X2
= breakbox
.X1
;
1892 /* center (ie blocked) edge piece */
1893 result
.center
.X1
= MAX (breakbox
.X1
, origbox
.X1
);
1894 result
.center
.X2
= MIN (breakbox
.X2
, origbox
.X2
);
1895 /* right edge piece */
1896 result
.right
.X1
= breakbox
.X2
;
1897 result
.right
.X2
= origbox
.X2
;
1899 result
.is_valid_left
= (result
.left
.X1
< result
.left
.X2
);
1900 result
.is_valid_center
= (result
.center
.X1
< result
.center
.X2
);
1901 result
.is_valid_right
= (result
.right
.X1
< result
.right
.X2
);
1903 ROTATEBOX_FROM_NORTH (result
.left
, which_edge
);
1904 ROTATEBOX_FROM_NORTH (result
.center
, which_edge
);
1905 ROTATEBOX_FROM_NORTH (result
.right
, which_edge
);
1912 share_edge (const BoxType
* child
, const BoxType
* parent
)
1915 (child
->X1
== parent
->X2
|| child
->X2
== parent
->X1
||
1916 child
->Y1
== parent
->Y2
|| child
->Y2
== parent
->Y1
) &&
1917 ((parent
->X1
<= child
->X1
&& child
->X2
<= parent
->X2
) ||
1918 (parent
->Y1
<= child
->Y1
&& child
->Y2
<= parent
->Y2
));
1921 edge_intersect (const BoxType
* child
, const BoxType
* parent
)
1924 (child
->X1
<= parent
->X2
) && (child
->X2
>= parent
->X1
) &&
1925 (child
->Y1
<= parent
->Y2
) && (child
->Y2
>= parent
->Y1
);
1929 /* area is the expansion area, on layer group 'group'. 'parent' is the
1930 * immediately preceding expansion area, for backtracing. 'lastarea' is
1931 * the last expansion area created, we string these together in a loop
1932 * so we can remove them all easily at the end. */
1934 CreateExpansionArea (const BoxType
* area
, Cardinal group
,
1935 routebox_t
* parent
,
1936 Boolean relax_edge_requirements
, edge_t
* src_edge
)
1938 routebox_t
*rb
= (routebox_t
*) malloc (sizeof (*rb
));
1939 assert (area
&& parent
);
1940 init_const_box (rb
, area
->X1
, area
->Y1
, area
->X2
, area
->Y2
);
1942 rb
->type
= EXPANSION_AREA
;
1943 rb
->cost_point
= src_edge
->cost_point
;
1944 rb
->cost
= src_edge
->cost_to_point
;
1945 /* should always share edge with parent */
1946 assert (relax_edge_requirements
? edge_intersect (&rb
->box
, &parent
->box
)
1947 : share_edge (&rb
->box
, &parent
->box
));
1948 rb
->parent
.expansion_area
= route_parent (parent
);
1949 assert (relax_edge_requirements
? edge_intersect (&rb
->box
, &parent
->box
)
1950 : share_edge (&rb
->box
, &parent
->box
));
1951 if (rb
->parent
.expansion_area
->flags
.orphan
)
1952 RB_up_count (rb
->parent
.expansion_area
);
1953 rb
->flags
.orphan
= 1;
1954 rb
->augStyle
= AutoRouteParameters
.augStyle
;
1956 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
1958 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
1963 no_loops (routebox_t
* chain
, routebox_t
* rb
)
1965 while (!rb
->flags
.source
)
1967 rb
= rb
->parent
.expansion_area
;
1974 /*------ FindBlocker ------*/
1975 struct FindBlocker_info
1977 edge_t
*expansion_edge
;
1978 BDimension maxbloat
;
1979 routebox_t
*blocker
;
1980 LocationType min_dist
;
1985 /* helper methods for __FindBlocker */
1987 __FindBlocker_rect_in_reg (const BoxType
* box
, void *cl
)
1989 struct FindBlocker_info
*fbi
= (struct FindBlocker_info
*) cl
;
1990 routebox_t
*rb
= (routebox_t
*) box
;
1992 rbox
= bloat_routebox ((routebox_t
*) box
);
1993 ROTATEBOX_TO_NORTH (rbox
, fbi
->expansion_edge
->expand_dir
);
1994 if (rbox
.X2
<= fbi
->north_box
.X1
|| rbox
.X1
>= fbi
->north_box
.X2
1995 || rbox
.Y1
> fbi
->north_box
.Y1
)
1997 if (rbox
.Y2
< fbi
->north_box
.Y1
- fbi
->min_dist
)
1999 /* this is a box; it has to jump through a few more hoops */
2000 if (rb
== nonorphan_parent (fbi
->expansion_edge
->rb
))
2001 return 0; /* this is the parent */
2002 if (rb
->type
== EXPANSION_AREA
&& fbi
->not_via
2003 && fbi
->expansion_edge
->cost_to_point
+
2004 AutoRouteParameters
.SearchPenalty
< rb
->cost
)
2007 cp
= closest_point_in_box (&fbi
->expansion_edge
->cost_point
, box
);
2008 if (cost_to_point_on_layer
2009 (&fbi
->expansion_edge
->cost_point
, &cp
,
2010 rb
->group
) + fbi
->expansion_edge
->cost_to_point
<
2012 cost_to_point_on_layer (&rb
->cost_point
, &cp
, rb
->group
))
2013 && no_loops (rb
, fbi
->expansion_edge
->rb
))
2014 return 0; /* this region may cost less from this direction */
2016 /* okay, this is the closest we've found. */
2017 assert (fbi
->blocker
== NULL
2018 || (fbi
->north_box
.Y1
- rbox
.Y2
) <= fbi
->min_dist
);
2019 fbi
->blocker
= (routebox_t
*) box
;
2020 fbi
->min_dist
= fbi
->north_box
.Y1
- rbox
.Y2
;
2021 /* this assert can fail if the minimum keepaway is failed by an element
2023 assert (fbi->min_dist >= 0);
2028 __FindBlocker_reg_in_sea (const BoxType
* region
, void *cl
)
2030 struct FindBlocker_info
*fbi
= (struct FindBlocker_info
*) cl
;
2032 rbox
= bloat_box (region
, fbi
->maxbloat
);
2033 switch (fbi
->expansion_edge
->expand_dir
)
2036 if (rbox
.X2
< fbi
->north_box
.Y1
- fbi
->min_dist
||
2037 -rbox
.Y2
> fbi
->north_box
.X2
||
2038 -rbox
.Y1
< fbi
->north_box
.X1
|| rbox
.X1
> fbi
->north_box
.Y1
)
2042 if (-rbox
.Y1
< fbi
->north_box
.Y1
- fbi
->min_dist
||
2043 -rbox
.X2
> fbi
->north_box
.X2
||
2044 -rbox
.X1
< fbi
->north_box
.X1
|| -rbox
.Y2
> fbi
->north_box
.Y1
)
2048 if (-rbox
.X1
< fbi
->north_box
.Y1
- fbi
->min_dist
||
2049 rbox
.Y1
> fbi
->north_box
.X2
||
2050 rbox
.Y2
< fbi
->north_box
.X1
|| -rbox
.X2
> fbi
->north_box
.Y1
)
2054 if (rbox
.Y2
< fbi
->north_box
.Y1
- fbi
->min_dist
||
2055 rbox
.X1
> fbi
->north_box
.X2
||
2056 rbox
.X2
< fbi
->north_box
.X1
|| rbox
.Y1
> fbi
->north_box
.Y1
)
2065 /* main FindBlocker routine. Returns NULL if no neighbor in the
2066 * requested direction.
2067 * - region is closed on all edges -
2070 FindBlocker (rtree_t
* rtree
, edge_t
* e
, BDimension maxbloat
)
2072 struct FindBlocker_info fbi
;
2075 fbi
.expansion_edge
= e
;
2076 fbi
.maxbloat
= maxbloat
;
2078 fbi
.min_dist
= MAX_COORD
;
2079 fbi
.north_box
= e
->rb
->box
;
2080 fbi
.not_via
= !e
->rb
->flags
.is_via
;
2082 sbox
= bloat_box (&e
->rb
->box
, maxbloat
);
2083 switch (e
->expand_dir
)
2086 sbox
.Y1
= -MAX_COORD
;
2089 sbox
.X2
= MAX_COORD
;
2092 sbox
.Y2
= MAX_COORD
;
2095 sbox
.X1
= -MAX_COORD
;
2100 ROTATEBOX_TO_NORTH (fbi
.north_box
, e
->expand_dir
);
2101 r_search (rtree
, &sbox
,
2102 __FindBlocker_reg_in_sea
, __FindBlocker_rect_in_reg
, &fbi
);
2111 routebox_t
*intersect
;
2117 fio_rect_in_reg (const BoxType
* box
, void *cl
)
2119 struct fio_info
*fio
= (struct fio_info
*) cl
;
2122 rbox
= bloat_routebox ((routebox_t
*) box
);
2123 ROTATEBOX_TO_NORTH (rbox
, fio
->edge
->expand_dir
);
2124 if (rbox
.X2
<= fio
->north_box
.X1
|| rbox
.X1
>= fio
->north_box
.X2
||
2125 rbox
.Y1
> fio
->north_box
.Y1
|| rbox
.Y2
< fio
->north_box
.Y1
)
2127 /* this is a box; it has to jump through a few more hoops */
2128 /* everything on same net is ignored */
2129 rb
= (routebox_t
*) box
;
2130 assert (rb
== nonorphan_parent (rb
));
2131 if (rb
== nonorphan_parent (fio
->edge
->rb
))
2133 /* okay, this is an intersector! */
2134 fio
->intersect
= rb
;
2135 longjmp (fio
->env
, 1); /* skip to the end! */
2136 return 1; /* never reached */
2140 FindIntersectingObstacle (rtree_t
* rtree
, edge_t
* e
, BDimension maxbloat
)
2142 struct fio_info fio
;
2146 fio
.intersect
= NULL
;
2147 fio
.north_box
= e
->rb
->box
;
2149 sbox
= bloat_box (&e
->rb
->box
, maxbloat
);
2150 /* exclude equality point from search depending on expansion direction */
2151 switch (e
->expand_dir
)
2166 ROTATEBOX_TO_NORTH (fio
.north_box
, e
->expand_dir
);
2167 if (setjmp (fio
.env
) == 0)
2168 r_search (rtree
, &sbox
, NULL
, fio_rect_in_reg
, &fio
);
2169 return fio
.intersect
;
2177 BDimension maxbloat
;
2178 routebox_t
*intersect
;
2182 foib_check (const BoxType
* region_or_box
, struct foib_info
*foib
,
2186 rbox
= is_region
? bloat_box (region_or_box
, foib
->maxbloat
) :
2187 bloat_routebox ((routebox_t
*) region_or_box
);
2188 if (!box_intersect (&rbox
, foib
->box
))
2192 /* this is an intersector! */
2193 foib
->intersect
= (routebox_t
*) region_or_box
;
2194 longjmp (foib
->env
, 1); /* skip to the end! */
2199 foib_reg_in_sea (const BoxType
* region
, void *cl
)
2201 return foib_check (region
, (struct foib_info
*) cl
, True
);
2204 foib_rect_in_reg (const BoxType
* box
, void *cl
)
2206 return foib_check (box
, (struct foib_info
*) cl
, False
);
2209 FindOneInBox (rtree_t
* rtree
, const BoxType
* box
, BDimension maxbloat
)
2211 struct foib_info foib
;
2214 foib
.maxbloat
= maxbloat
;
2215 foib
.intersect
= NULL
;
2217 if (setjmp (foib
.env
) == 0)
2218 r_search (rtree
, NULL
, foib_reg_in_sea
, foib_rect_in_reg
, &foib
);
2219 return foib
.intersect
;
2223 ftherm_rect_in_reg (const BoxType
* box
, void *cl
)
2225 routebox_t
*rbox
= (routebox_t
*) box
;
2226 struct rb_info
*ti
= (struct rb_info
*) cl
;
2228 if (rbox
->type
== PIN
|| rbox
->type
== VIA
|| rbox
->type
== VIA_SHADOW
)
2231 longjmp (ti
->env
, 1);
2236 /* check for a pin or via target that a polygon can just use a thermal to connect to */
2238 FindThermable (rtree_t
* rtree
, const BoxType
* box
)
2240 struct rb_info info
;
2243 if (setjmp (info
.env
) == 0)
2244 r_search (rtree
, box
, NULL
, ftherm_rect_in_reg
, &info
);
2248 /* create a new edge for every edge of the given routebox (e->rb) and
2249 * put the result edges in result_vec. */
2251 ExpandAllEdges (edge_t
* e
, vector_t
* result_vec
,
2252 cost_t cost_penalty_in_box
, rtree_t
* targets
)
2254 CheapPointType costpoint
;
2257 assert (__edge_is_good (e
));
2258 assert (e
->flags
.expand_all_sides
);
2259 for (i
= 0; i
< 4; i
++)
2260 { /* for all directions */
2262 { /* assign appropriate cost point */
2264 costpoint
.X
= e
->cost_point
.X
;
2265 costpoint
.Y
= e
->rb
->box
.Y1
;
2268 costpoint
.X
= e
->rb
->box
.X2
;
2269 costpoint
.Y
= e
->cost_point
.Y
;
2272 costpoint
.X
= e
->cost_point
.X
;
2273 costpoint
.Y
= e
->rb
->box
.Y2
;
2276 costpoint
.X
= e
->rb
->box
.X1
;
2277 costpoint
.Y
= e
->cost_point
.Y
;
2284 cost
= cost_penalty_in_box
*
2285 cost_to_point_on_layer (&e
->cost_point
, &costpoint
, e
->rb
->group
);
2286 vector_append (result_vec
,
2287 CreateEdge (e
->rb
, costpoint
.X
, costpoint
.Y
,
2288 e
->cost_to_point
+ cost
, e
->mincost_target
,
2295 /* find edges that intersect obstacles, and break them into
2296 * intersecting and non-intersecting edges. */
2298 BreakEdges (routedata_t
* rd
, vector_t
* edge_vec
, rtree_t
* targets
)
2300 BoxType edgebox
, bbox
= shrunk_pcb_bounds ();
2301 vector_t
*broken_vec
= vector_create ();
2302 while (!vector_is_empty (edge_vec
))
2306 /* pop off the top edge */
2307 e
= vector_remove_last (edge_vec
);
2308 if (e
->rb
->type
== PLANE
)
2310 vector_append (broken_vec
, e
);
2313 assert (!e
->flags
.expand_all_sides
);
2314 /* check for edges that poke off the edge of the routeable area */
2315 edgebox
= edge_to_box (&e
->rb
->box
, e
->expand_dir
);
2316 if (!box_intersect (&bbox
, &edgebox
))
2318 /* edge completely off the PCB, skip it. */
2322 if (!box_in_box (&bbox
, &edgebox
))
2324 /* edge partially off the PCB, clip it. */
2326 BoxType newbox
= clip_box (&edgebox
, &bbox
);
2327 /* 'close' box (newbox is currently half-open) */
2330 /* okay, create new, clipped, edge */
2332 CreateExpansionArea (&newbox
, e
->rb
->group
, route_parent (e
->rb
),
2334 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
2335 if (!e
->rb
->flags
.circular
)
2336 nrb
->flags
.source
= e
->rb
->flags
.source
;
2337 nrb
->flags
.nobloat
= e
->rb
->flags
.nobloat
;
2339 ne
->cost_to_point
= e
->rb
->flags
.source
? e
->cost_to_point
:
2341 (CONFLICT_PENALTY (nonorphan_parent (e
->rb
)) *
2342 (ne
->cost_to_point
- e
->cost_to_point
));
2343 assert (__edge_is_good (ne
));
2344 /* replace e with ne and continue. */
2347 edgebox
= edge_to_box (&e
->rb
->box
, e
->expand_dir
);
2349 assert (box_intersect (&bbox
, &edgebox
));
2350 assert (box_in_box (&bbox
, &edgebox
));
2351 /* find an intersecting obstacle, and then break edge on it. */
2352 rb
= FindIntersectingObstacle (rd
->layergrouptree
[e
->rb
->group
],
2354 assert (__edge_is_good (e
));
2356 { /* no intersecting obstacle, this baby's good! */
2357 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGE_BOXES)
2358 showroutebox (e
->rb
);
2359 printf ("GOOD EDGE FOUND!\n");
2361 assert (__edge_is_good (e
));
2362 vector_append (broken_vec
, e
);
2365 { /* rb has an intersecting obstacle. break this in three pieces */
2366 struct broken_boxes r
=
2367 break_box_edge (&e
->rb
->box
, e
->expand_dir
, rb
);
2371 /* "canonical parent" is the original source */
2372 parent
= route_parent (e
->rb
);
2373 assert (parent
->underlying
|| parent
->flags
.is_via
||
2374 parent
->type
!= EXPANSION_AREA
);
2376 for (i
= 0; i
< 2; i
++)
2377 if (i
? r
.is_valid_left
: r
.is_valid_right
)
2379 routebox_t
*nrb
= CreateExpansionArea (i
? &r
.left
: &r
.right
,
2380 e
->rb
->group
, parent
,
2382 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
2383 if (!e
->rb
->flags
.circular
)
2384 nrb
->flags
.source
= e
->rb
->flags
.source
;
2385 nrb
->flags
.nobloat
= e
->rb
->flags
.nobloat
;
2387 ne
->cost_to_point
= e
->rb
->flags
.source
? e
->cost_to_point
:
2389 (CONFLICT_PENALTY (nonorphan_parent (e
->rb
)) *
2390 (ne
->cost_to_point
- e
->cost_to_point
));
2391 assert (__edge_is_good (ne
));
2392 vector_append (edge_vec
, ne
);
2394 /* center edge is "interior" to obstacle */
2395 /* don't bother adding if this is a source-interior edge */
2396 /* or an expansion edge or the conflict is fixed */
2397 if (r
.is_valid_center
)
2399 /* an expansion area is not really an obstacle */
2400 if (rb
->type
== EXPANSION_AREA
)
2402 routebox_t
*nrb
= CreateExpansionArea (&r
.center
,
2403 e
->rb
->group
, parent
,
2405 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
2406 nrb
->flags
.nobloat
= e
->rb
->flags
.nobloat
;
2410 source
? 0 : (CONFLICT_PENALTY (nonorphan_parent (e
->rb
))
2411 * (ne
->cost_to_point
- e
->cost_to_point
)));
2412 assert (__edge_is_good (ne
));
2413 vector_append (broken_vec
, ne
);
2415 else if (!rb
->flags
.source
&& (!rb
->flags
.fixed
2416 || rb
->flags
.target
)
2417 && AutoRouteParameters
.with_conflicts
)
2419 ne
= CreateEdgeWithConflicts (&r
.center
, rb
, e
,
2421 (nonorphan_parent (e
->rb
)),
2423 assert (__edge_is_good (ne
));
2424 vector_append (broken_vec
, ne
);
2426 /* we still want to hit targets if routing without conflicts
2427 * since a target is not really a conflict
2429 else if (rb
->flags
.target
) /* good news */
2431 routebox_t
*nrb
= CreateExpansionArea (&r
.center
,
2432 e
->rb
->group
, parent
,
2434 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, rb
);
2435 nrb
->flags
.nobloat
= e
->rb
->flags
.nobloat
;
2439 source
? 0 : (CONFLICT_PENALTY (nonorphan_parent (e
->rb
))
2440 * (ne
->cost_to_point
- e
->cost_to_point
));
2441 assert (__edge_is_good (ne
));
2442 vector_append (broken_vec
, ne
);
2447 /* done with this edge */
2449 /* all good edges are now on broken_vec list. */
2450 /* Transfer them back to edge_vec */
2451 assert (vector_size (edge_vec
) == 0);
2452 vector_append_vector (edge_vec
, broken_vec
);
2453 vector_destroy (&broken_vec
);
2458 /*--------------------------------------------------------------------
2459 * Route-tracing code: once we've got a path of expansion boxes, trace
2460 * a line through them to actually create the connection.
2463 RD_DrawThermal (routedata_t
* rd
, LocationType X
, LocationType Y
,
2464 Cardinal group
, Cardinal layer
, routebox_t
* subnet
,
2468 rb
= (routebox_t
*) malloc (sizeof (*rb
));
2469 init_const_box (rb
, X
, Y
, X
+ 1, Y
+ 1);
2472 rb
->flags
.fixed
= 0;
2473 rb
->flags
.is_bad
= is_bad
;
2474 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
2475 rb
->flags
.circular
= 0;
2476 rb
->augStyle
= AutoRouteParameters
.augStyle
;
2479 MergeNets (rb
, subnet
, NET
);
2480 MergeNets (rb
, subnet
, SUBNET
);
2484 RD_DrawVia (routedata_t
* rd
, LocationType X
, LocationType Y
,
2485 BDimension radius
, routebox_t
* subnet
, Boolean is_bad
)
2487 routebox_t
*rb
, *first_via
= NULL
;
2489 /* a via cuts through every layer group */
2490 for (i
= 0; i
< max_layer
; i
++)
2492 if (!is_layer_group_active
[i
])
2494 rb
= (routebox_t
*) malloc (sizeof (*rb
));
2496 /*X1 */ X
- radius
, /*Y1 */ Y
- radius
,
2497 /*X2 */ X
+ radius
, /*Y2 */ Y
+ radius
);
2499 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
2500 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
2501 rb
->flags
.is_bad
= is_bad
;
2502 rb
->flags
.circular
= True
;
2503 rb
->augStyle
= AutoRouteParameters
.augStyle
;
2504 if (first_via
== NULL
)
2507 rb
->parent
.via
= NULL
; /* indicates that not on PCB yet */
2509 /* only add the first via to mtspace, not the shadows too */
2510 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
2511 rb
->augStyle
->style
->Keepaway
);
2515 rb
->type
= VIA_SHADOW
;
2516 rb
->parent
.via_shadow
= first_via
;
2519 /* add these to proper subnet. */
2520 MergeNets (rb
, subnet
, NET
);
2521 MergeNets (rb
, subnet
, SUBNET
);
2522 assert (__routebox_is_good (rb
));
2523 /* and add it to the r-tree! */
2524 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
2526 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
2528 gui
->set_color (ar_gc
, PCB
->ViaColor
);
2529 gui
->fill_circle (ar_gc
, X
, Y
, radius
);
2534 RD_DrawLine (routedata_t
* rd
,
2535 LocationType X1
, LocationType Y1
, LocationType X2
,
2536 LocationType Y2
, BDimension halfthick
, Cardinal group
,
2537 routebox_t
* subnet
, Boolean is_bad
, Boolean is_45
)
2540 /* don't draw zero-length segments. */
2541 if (X1
== X2
&& Y1
== Y2
)
2543 rb
= (routebox_t
*) malloc (sizeof (*rb
));
2544 assert (is_45
? (ABS (X2
- X1
) == ABS (Y2
- Y1
)) /* line must be 45-degrees */
2545 : (X1
== X2
|| Y1
== Y2
) /* line must be ortho */ );
2547 /*X1 */ MIN (X1
, X2
) - halfthick
,
2548 /*Y1 */ MIN (Y1
, Y2
) - halfthick
,
2549 /*X2 */ MAX (X1
, X2
) + halfthick
,
2550 /*Y2 */ MAX (Y1
, Y2
) + halfthick
);
2553 rb
->parent
.line
= NULL
; /* indicates that not on PCB yet */
2554 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
2555 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
2556 rb
->flags
.is_bad
= is_bad
;
2557 rb
->flags
.nonstraight
= is_45
;
2558 rb
->flags
.bl_to_ur
= is_45
&& (MIN (X1
, X2
) == X1
) != (MIN (Y1
, Y2
) == Y1
);
2559 rb
->augStyle
= AutoRouteParameters
.augStyle
;
2561 /* add these to proper subnet. */
2562 MergeNets (rb
, subnet
, NET
);
2563 MergeNets (rb
, subnet
, SUBNET
);
2564 assert (__routebox_is_good (rb
));
2565 /* and add it to the r-tree! */
2566 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
2568 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
2570 LayerTypePtr layp
= LAYER_PTR (PCB
->LayerGroups
.Entries
[rb
->group
][0]);
2572 gui
->set_line_width (ar_gc
, 2*halfthick
);
2573 gui
->set_color (ar_gc
, layp
->Color
);
2574 gui
->draw_line (ar_gc
, X1
, Y1
, X2
, Y2
);
2577 /* and to the via space structures */
2578 if (AutoRouteParameters
.use_vias
)
2579 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
2580 rb
->augStyle
->style
->Keepaway
);
2581 usedGroup
[rb
->group
] = True
;
2585 RD_DrawManhattanLine (routedata_t
* rd
,
2586 const BoxType
* box1
, const BoxType
* box2
,
2587 CheapPointType start
, CheapPointType end
,
2588 BDimension halfthick
, Cardinal group
,
2589 routebox_t
* subnet
, Boolean is_bad
, Boolean last_was_x
)
2591 CheapPointType knee
= start
;
2592 if (end
.X
== start
.X
)
2594 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
2595 subnet
, is_bad
, False
);
2598 else if (end
.Y
== start
.Y
)
2600 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
2601 subnet
, is_bad
, False
);
2604 /* find where knee belongs */
2605 if (point_in_box (box1
, end
.X
, start
.Y
)
2606 || point_in_box (box2
, end
.X
, start
.Y
))
2616 if ((knee
.X
== end
.X
&& !last_was_x
) &&
2617 (point_in_box (box1
, start
.X
, end
.Y
)
2618 || point_in_box (box2
, start
.X
, end
.Y
)))
2623 assert (point_in_box (box1
, knee
.X
, knee
.Y
)
2624 || point_in_box (box2
, knee
.X
, knee
.Y
));
2626 if (1 || !AutoRouteParameters
.is_smoothing
)
2628 /* draw standard manhattan paths */
2629 RD_DrawLine (rd
, start
.X
, start
.Y
, knee
.X
, knee
.Y
, halfthick
, group
,
2630 subnet
, is_bad
, False
);
2631 RD_DrawLine (rd
, knee
.X
, knee
.Y
, end
.X
, end
.Y
, halfthick
, group
,
2632 subnet
, is_bad
, False
);
2636 /* draw 45-degree path across knee */
2637 BDimension len45
= MIN (ABS (start
.X
- end
.X
), ABS (start
.Y
- end
.Y
));
2638 CheapPointType kneestart
= knee
, kneeend
= knee
;
2639 if (kneestart
.X
== start
.X
)
2640 kneestart
.Y
+= (kneestart
.Y
> start
.Y
) ? -len45
: len45
;
2642 kneestart
.X
+= (kneestart
.X
> start
.X
) ? -len45
: len45
;
2643 if (kneeend
.X
== end
.X
)
2644 kneeend
.Y
+= (kneeend
.Y
> end
.Y
) ? -len45
: len45
;
2646 kneeend
.X
+= (kneeend
.X
> end
.X
) ? -len45
: len45
;
2647 RD_DrawLine (rd
, start
.X
, start
.Y
, kneestart
.X
, kneestart
.Y
, halfthick
,
2648 group
, subnet
, is_bad
, False
);
2649 RD_DrawLine (rd
, kneestart
.X
, kneestart
.Y
, kneeend
.X
, kneeend
.Y
,
2650 halfthick
, group
, subnet
, is_bad
, True
);
2651 RD_DrawLine (rd
, kneeend
.X
, kneeend
.Y
, end
.X
, end
.Y
, halfthick
, group
,
2652 subnet
, is_bad
, False
);
2654 return (knee
.X
!= end
.X
);
2657 /* for smoothing, don't pack traces to min clearance gratuitously */
2659 add_clearance (CheapPointType
* nextpoint
, const BoxType
* b
)
2661 if (nextpoint
->X
== b
->X1
)
2664 AutoRouteParameters
.augStyle
->style
->Keepaway
< (b
->X1
+ b
->X2
) / 2)
2665 nextpoint
->X
+= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2667 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
2669 else if (nextpoint
->X
== b
->X2
)
2672 AutoRouteParameters
.augStyle
->style
->Keepaway
> (b
->X1
+ b
->X2
) / 2)
2673 nextpoint
->X
-= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2675 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
2677 else if (nextpoint
->Y
== b
->Y1
)
2680 AutoRouteParameters
.augStyle
->style
->Keepaway
< (b
->Y1
+ b
->Y2
) / 2)
2681 nextpoint
->Y
+= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2683 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
2685 else if (nextpoint
->Y
== b
->Y2
)
2688 AutoRouteParameters
.augStyle
->style
->Keepaway
> (b
->Y1
+ b
->Y2
) / 2)
2689 nextpoint
->Y
-= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2691 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
2696 TracePath (routedata_t
* rd
, routebox_t
* path
, const routebox_t
* target
,
2697 routebox_t
* subnet
, Boolean is_bad
)
2699 Boolean last_x
= False
;
2700 BDimension halfwidth
=
2701 HALF_THICK (AutoRouteParameters
.augStyle
->style
->Thick
);
2703 HALF_THICK (AutoRouteParameters
.augStyle
->style
->Diameter
);
2704 CheapPointType lastpoint
, nextpoint
;
2705 routebox_t
*lastpath
;
2708 assert (subnet
->augStyle
== AutoRouteParameters
.augStyle
);
2709 /* start from *edge* of target box */
2710 /*XXX: because we round up odd thicknesses, there's the possibility that
2711 * a connecting line end-point might be 0.005 mil off the "real" edge.
2712 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
2713 nextpoint
.X
= (path
->box
.X1
+ path
->box
.X2
) / 2;
2714 nextpoint
.Y
= (path
->box
.Y1
+ path
->box
.Y2
) / 2;
2715 nextpoint
= closest_point_in_box (&nextpoint
,
2716 &path
->parent
.expansion_area
->box
);
2717 /* for circular targets, use *inscribed* rectangle so we're sure to
2720 if (target
->flags
.circular
)
2721 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
2722 nextpoint
= closest_point_in_box (&nextpoint
, &b
);
2723 TargetPoint (&nextpoint
, target
);
2724 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
2725 showroutebox (path
);
2726 printf ("TRACEPOINT start (%d, %d)\n", nextpoint
.X
, nextpoint
.Y
);
2727 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
2731 lastpoint
= nextpoint
;
2733 assert (path
->type
== EXPANSION_AREA
);
2734 path
= path
->parent
.expansion_area
;
2737 if (path
->flags
.circular
)
2738 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
2739 assert (b
.X1
!= b
.X2
&& b
.Y1
!= b
.Y2
); /* need someplace to put line! */
2740 /* find point on path perimeter closest to last point */
2741 /* if source terminal, try to hit a good place */
2742 nextpoint
= closest_point_in_box (&lastpoint
, &b
);
2743 /* leave more clearance if this is a smoothing pass */
2744 if (AutoRouteParameters
.is_smoothing
)
2745 add_clearance (&nextpoint
, &b
);
2746 if (path
->flags
.source
)
2747 TargetPoint (&nextpoint
, path
);
2748 assert (point_in_box (&lastpath
->box
, lastpoint
.X
, lastpoint
.Y
));
2749 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
2750 #if defined(ROUTE_DEBUG)
2751 printf ("TRACEPATH: ");
2752 DumpRouteBox (path
);
2753 printf ("TRACEPATH: point (%d, %d) to point (%d, %d) layer %d\n",
2754 lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
2758 /* draw orthogonal lines from lastpoint to nextpoint */
2759 /* knee is placed in lastpath box */
2760 /* should never cause line to leave union of lastpath/path boxes */
2761 last_x
= RD_DrawManhattanLine (rd
, &lastpath
->box
, &path
->box
,
2762 lastpoint
, nextpoint
, halfwidth
,
2763 path
->group
, subnet
, is_bad
, last_x
);
2764 if (path
->flags
.is_via
)
2765 { /* if via, then add via */
2766 #ifdef ROUTE_VERBOSE
2769 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
2770 RD_DrawVia (rd
, nextpoint
.X
, nextpoint
.Y
, radius
, subnet
, is_bad
);
2773 assert (lastpath
->flags
.is_via
|| path
->group
== lastpath
->group
);
2775 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
2776 showroutebox (path
);
2777 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
2778 /* if this is connected to a plane, draw the thermal */
2779 if (path
->type
== PLANE
)
2780 RD_DrawThermal (rd
, nextpoint
.X
, nextpoint
.Y
, path
->group
,
2781 path
->layer
, subnet
, is_bad
);
2782 /* when one hop from the source, make an extra path in *this* box */
2783 if (path
->parent
.expansion_area
2784 && path
->parent
.expansion_area
->flags
.source
)
2786 /* find special point on source (if it exists) */
2787 if (TargetPoint (&lastpoint
, path
->parent
.expansion_area
))
2789 lastpoint
= closest_point_in_box (&lastpoint
, &path
->box
);
2790 if (AutoRouteParameters
.is_smoothing
)
2791 add_clearance (&lastpoint
, &path
->box
);
2792 last_x
= RD_DrawManhattanLine (rd
, &path
->box
, &path
->box
,
2793 nextpoint
, lastpoint
, halfwidth
,
2794 path
->group
, subnet
, is_bad
,
2796 #if defined(ROUTE_DEBUG)
2797 printf ("TRACEPATH: ");
2798 DumpRouteBox (path
);
2800 ("TRACEPATH: (to source) point (%d, %d) to point (%d, %d) layer %d\n",
2801 nextpoint
.X
, nextpoint
.Y
, lastpoint
.X
, lastpoint
.Y
,
2805 nextpoint
= lastpoint
;
2809 while (!path
->flags
.source
);
2812 struct routeone_state
2814 /* heap of all candidate expansion edges */
2816 /* information about the best path found so far. */
2817 routebox_t
*best_path
, *best_target
;
2821 /* create a fake "edge" used to defer via site searching. */
2823 CreateSearchEdge (struct routeone_state
*s
, vetting_t
* work
, edge_t
* parent
,
2824 routebox_t
* rb
, conflict_t conflict
, rtree_t
* targets
)
2829 assert (__routebox_is_good (rb
));
2830 /* find the cheapest target */
2831 boxes
= mtsBoxCount (work
);
2834 mincost_target_to_point (&parent
->cost_point
, max_layer
+ 1, targets
,
2835 parent
->mincost_target
);
2837 target
= parent
->mincost_target
;
2840 parent
->cost_to_point
+ AutoRouteParameters
.ViaCost
+
2841 AutoRouteParameters
.SearchPenalty
* boxes
+
2842 cost_to_layerless_box (&rb
->cost_point
, 0, &target
->box
);
2843 if (cost
< s
->best_cost
)
2846 ne
= malloc (sizeof (*ne
));
2848 ne
->flags
.via_search
= 1;
2850 if (rb
->flags
.orphan
)
2853 ne
->mincost_target
= target
;
2854 ne
->flags
.via_conflict_level
= conflict
;
2855 ne
->cost_to_point
= parent
->cost_to_point
;
2856 ne
->cost_point
= parent
->cost_point
;
2858 heap_insert (s
->workheap
, ne
->cost
, ne
);
2862 mtsFreeWork (&work
);
2867 add_or_destroy_edge (struct routeone_state
*s
, edge_t
* e
)
2869 e
->cost
= edge_cost (e
, s
->best_cost
);
2870 assert (__edge_is_good (e
));
2871 assert (is_layer_group_active
[e
->rb
->group
]);
2872 if (e
->cost
< s
->best_cost
)
2873 heap_insert (s
->workheap
, e
->cost
, e
);
2879 best_path_candidate (struct routeone_state
*s
,
2880 edge_t
* e
, routebox_t
* best_target
)
2882 e
->cost
= edge_cost (e
, EXPENSIVE
);
2883 if (s
->best_path
== NULL
|| e
->cost
< s
->best_cost
)
2885 #if defined(ROUTE_DEBUG)
2886 printf ("New best path seen! cost = %f\n", e
->cost
);
2888 /* new best path! */
2889 if (s
->best_path
&& s
->best_path
->flags
.orphan
)
2890 RB_down_count (s
->best_path
);
2891 s
->best_path
= e
->rb
;
2892 s
->best_target
= best_target
;
2893 s
->best_cost
= e
->cost
;
2894 assert (s
->best_cost
>= 0);
2895 /* don't free this when we destroy edge! */
2896 if (s
->best_path
->flags
.orphan
)
2897 RB_up_count (s
->best_path
);
2902 /* vectors for via site candidates (see mtspace.h) */
2903 struct routeone_via_site_state
2905 vector_t
*free_space_vec
;
2906 vector_t
*lo_conflict_space_vec
;
2907 vector_t
*hi_conflict_space_vec
;
2911 add_via_sites (struct routeone_state
*s
,
2912 struct routeone_via_site_state
*vss
,
2913 mtspace_t
* mtspace
, routebox_t
* within
,
2914 conflict_t within_conflict_level
, edge_t
* parent_edge
,
2915 rtree_t
* targets
, BDimension shrink
)
2917 int radius
, keepaway
;
2919 BoxType region
= shrink_box (&within
->box
, shrink
);
2921 radius
= HALF_THICK (AutoRouteParameters
.augStyle
->style
->Diameter
);
2922 keepaway
= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2923 assert (AutoRouteParameters
.use_vias
);
2924 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
2925 XXX: routing with conflicts may poke over edge. */
2927 if (region
.X2
<= region
.X1
|| region
.Y2
<= region
.Y1
)
2929 //showbox (region, 1, max_layer + COMPONENT_LAYER);
2930 work
= mtspace_query_rect (mtspace
, ®ion
, radius
, keepaway
,
2931 NULL
, vss
->free_space_vec
,
2932 vss
->lo_conflict_space_vec
,
2933 vss
->hi_conflict_space_vec
,
2934 AutoRouteParameters
.is_odd
,
2935 AutoRouteParameters
.with_conflicts
);
2938 CreateSearchEdge (s
, work
, parent_edge
, within
, within_conflict_level
,
2943 do_via_search (edge_t
* search
, struct routeone_state
*s
,
2944 struct routeone_via_site_state
*vss
, mtspace_t
* mtspace
,
2947 int i
, j
, count
= 0;
2948 int radius
, keepaway
;
2951 conflict_t within_conflict_level
;
2953 radius
= HALF_THICK (AutoRouteParameters
.augStyle
->style
->Diameter
);
2954 keepaway
= AutoRouteParameters
.augStyle
->style
->Keepaway
;
2955 work
= mtspace_query_rect (mtspace
, NULL
, 0, 0,
2956 search
->work
, vss
->free_space_vec
,
2957 vss
->lo_conflict_space_vec
,
2958 vss
->hi_conflict_space_vec
,
2959 AutoRouteParameters
.is_odd
,
2960 AutoRouteParameters
.with_conflicts
);
2961 within
= search
->rb
;
2962 within_conflict_level
= search
->flags
.via_conflict_level
;
2963 for (i
= 0; i
< 3; i
++)
2966 (i
== NO_CONFLICT
? vss
->free_space_vec
:
2967 i
== LO_CONFLICT
? vss
->lo_conflict_space_vec
:
2968 i
== HI_CONFLICT
? vss
->hi_conflict_space_vec
: NULL
);
2970 while (!vector_is_empty (v
))
2973 BoxType
*area
= vector_remove_last (v
);
2974 if (!(i
== NO_CONFLICT
|| AutoRouteParameters
.with_conflicts
))
2979 /* answers are bloated by radius + keepaway */
2980 cliparea
= shrink_box (area
, radius
+ keepaway
);
2984 assert (__box_is_good (&cliparea
));
2986 for (j
= 0; j
< max_layer
; j
++)
2989 if (j
== within
->group
)
2991 if (!is_layer_group_active
[j
])
2993 ne
= CreateViaEdge (&cliparea
, j
, within
, search
,
2994 within_conflict_level
, i
, targets
);
2995 add_or_destroy_edge (s
, ne
);
2999 /* prevent freeing of work when this edge is destroyed */
3000 search
->flags
.via_search
= 0;
3003 CreateSearchEdge (s
, work
, search
, within
, within_conflict_level
, targets
);
3004 assert (vector_is_empty (vss
->free_space_vec
));
3005 assert (vector_is_empty (vss
->lo_conflict_space_vec
));
3006 assert (vector_is_empty (vss
->hi_conflict_space_vec
));
3009 struct routeone_status
3011 Boolean found_route
;
3012 int route_had_conflicts
;
3013 cost_t best_route_cost
;
3014 Boolean net_completely_routed
;
3017 static struct routeone_status
3018 RouteOne (routedata_t
* rd
, routebox_t
* from
, routebox_t
* to
, int max_edges
)
3020 struct routeone_status result
;
3023 const BoxType
**target_list
;
3026 /* vector of source edges for filtering */
3027 vector_t
*source_vec
;
3028 /* vector of expansion areas to be eventually removed from r-tree */
3030 /* vector of "touched" fixed regions to be reset upon completion */
3031 vector_t
*touched_vec
;
3032 /* working vector */
3035 struct routeone_state s
;
3036 struct routeone_via_site_state vss
;
3038 assert (rd
&& from
);
3039 /* no targets on to/from net need keepaway areas */
3040 LIST_LOOP (from
, same_net
, p
);
3041 p
->flags
.nobloat
= 1;
3043 /* set 'source' flags */
3044 LIST_LOOP (from
, same_subnet
, p
);
3045 if (!p
->flags
.nonstraight
)
3046 p
->flags
.source
= 1;
3049 /* count up the targets */
3052 /* remove source/target flags from non-straight obstacles, because they
3053 * don't fill their bounding boxes and so connecting to them
3054 * after we've routed is problematic. Better solution? */
3056 { /* if we're routing to a specific target */
3057 if (!to
->flags
.source
)
3058 { /* not already connected */
3059 /* check that 'to' and 'from' are on the same net */
3062 LIST_LOOP (from
, same_net
, p
);
3067 assert (seen
); /* otherwise from and to are on different nets! */
3068 /* set target flags only on 'to's subnet */
3069 LIST_LOOP (to
, same_subnet
, p
);
3070 if (!p
->flags
.nonstraight
&& is_layer_group_active
[p
->group
])
3072 p
->flags
.target
= 1;
3080 /* all nodes on the net but not connected to from are targets */
3081 LIST_LOOP (from
, same_net
, p
);
3082 if (!p
->flags
.source
&& is_layer_group_active
[p
->group
]
3083 && !p
->flags
.nonstraight
)
3085 p
->flags
.target
= 1;
3091 /* if no targets, then net is done! reset flags and return. */
3092 if (num_targets
== 0)
3094 LIST_LOOP (from
, same_net
, p
);
3095 p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
3097 result
.found_route
= False
;
3098 result
.net_completely_routed
= True
;
3099 result
.best_route_cost
= 0;
3100 result
.route_had_conflicts
= 0;
3104 result
.net_completely_routed
= False
;
3106 /* okay, there's stuff to route */
3107 assert (!from
->flags
.target
);
3108 assert (num_targets
> 0);
3109 /* create list of target pointers and from that a r-tree of targets */
3110 target_list
= malloc (num_targets
* sizeof (*target_list
));
3112 LIST_LOOP (from
, same_net
, p
);
3113 if (p
->flags
.target
)
3115 target_list
[i
++] = &p
->box
;
3116 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
3121 targets
= r_create_tree (target_list
, i
, 0);
3122 assert (i
<= num_targets
);
3125 /* add all sources to a vector (since we need to BreakEdges) */
3126 source_vec
= vector_create ();
3127 LIST_LOOP (from
, same_subnet
, p
);
3129 /* we need the test for 'source' because this box may be nonstraight */
3130 if (p
->flags
.source
&& is_layer_group_active
[p
->group
])
3133 cost_t ns_penalty
= 0, ew_penalty
= 0;
3134 /* penalize long-side expansion of pads */
3137 if (p
->box
.X2
- p
->box
.X1
> p
->box
.Y2
- p
->box
.Y1
)
3138 ns_penalty
= p
->box
.X2
- p
->box
.X1
;
3139 if (p
->box
.Y2
- p
->box
.Y1
> p
->box
.X2
- p
->box
.X1
)
3140 ew_penalty
= p
->box
.Y2
- p
->box
.Y1
;
3142 /* may expand in all directions from source; center edge cost point. */
3143 /* note that planes shouldn't really expand, but we need an edge */
3144 if (p
->type
!= PLANE
)
3146 e
= CreateEdge (p
, (p
->box
.X1
+ p
->box
.X2
) / 2,
3147 p
->box
.Y1
, ns_penalty
, NULL
, NORTH
, targets
);
3148 e
->cost
= edge_cost (e
, EXPENSIVE
);
3149 vector_append (source_vec
, e
);
3150 e
= CreateEdge (p
, (p
->box
.X1
+ p
->box
.X2
) / 2,
3151 p
->box
.Y2
, ns_penalty
, NULL
, SOUTH
, targets
);
3152 e
->cost
= edge_cost (e
, EXPENSIVE
);
3153 vector_append (source_vec
, e
);
3154 e
= CreateEdge (p
, p
->box
.X2
,
3155 (p
->box
.Y1
+ p
->box
.Y2
) / 2,
3156 ew_penalty
, NULL
, EAST
, targets
);
3157 e
->cost
= edge_cost (e
, EXPENSIVE
);
3158 vector_append (source_vec
, e
);
3160 e
= CreateEdge (p
, p
->box
.X1
,
3161 (p
->box
.Y1
+ p
->box
.Y2
) / 2, ew_penalty
,
3162 NULL
, p
->type
== PLANE
? EAST
: WEST
, targets
);
3163 e
->cost
= edge_cost (e
, EXPENSIVE
);
3164 vector_append (source_vec
, e
);
3168 /* break source edges; some edges may be too near obstacles to be able
3170 BreakEdges (rd
, source_vec
, targets
);
3172 /* okay, main expansion-search routing loop. */
3173 /* set up the initial activity heap */
3174 s
.workheap
= heap_create ();
3175 assert (s
.workheap
);
3176 while (!vector_is_empty (source_vec
))
3178 edge_t
*e
= vector_remove_last (source_vec
);
3179 assert (is_layer_group_active
[e
->rb
->group
]);
3180 e
->cost
= edge_cost (e
, EXPENSIVE
);
3181 heap_insert (s
.workheap
, e
->cost
, e
);
3183 vector_destroy (&source_vec
);
3184 /* okay, process items from heap until it is empty! */
3186 s
.best_cost
= EXPENSIVE
;
3187 area_vec
= vector_create ();
3188 edge_vec
= vector_create ();
3189 touched_vec
= vector_create ();
3190 vss
.free_space_vec
= vector_create ();
3191 vss
.lo_conflict_space_vec
= vector_create ();
3192 vss
.hi_conflict_space_vec
= vector_create ();
3193 while (!heap_is_empty (s
.workheap
))
3195 edge_t
*e
= heap_remove_smallest (s
.workheap
);
3196 if (e
->flags
.via_search
)
3198 if (seen
++ <= max_edges
)
3199 do_via_search (e
, &s
, &vss
, rd
->mtspace
, targets
);
3202 assert (__edge_is_good (e
));
3203 /* we should never add edges on inactive layer groups to the heap. */
3204 assert (is_layer_group_active
[e
->rb
->group
]);
3205 /* don't bother expanding this edge if the minimum possible edge cost
3206 * is already larger than the best edge cost we've found. */
3207 if (s
.best_path
&& e
->cost
> s
.best_cost
)
3208 goto dontexpand
; /* skip this edge */
3209 /* surprisingly it helps to give up and not try too hard to find
3210 * a route! This is not only faster, but results in better routing.
3211 * who would have guessed?
3213 if (seen
++ > max_edges
)
3215 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
3218 /* for a plane, look for quick connections with thermals or vias */
3219 if (e
->rb
->type
== PLANE
)
3221 routebox_t
*pin
= FindThermable (targets
, &e
->rb
->box
);
3226 CreateExpansionArea (&pin
->box
, e
->rb
->group
, e
->rb
, True
, e
);
3228 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, pin
);
3229 best_path_candidate (&s
, ne
, pin
);
3234 /* add in possible via sites in nrb */
3235 if (AutoRouteParameters
.use_vias
&&
3236 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
3237 add_via_sites (&s
, &vss
, rd
->mtspace
, e
->rb
, NO_CONFLICT
, e
,
3238 targets
, e
->rb
->augStyle
->style
->Diameter
);
3240 goto dontexpand
; /* planes only connect via thermals */
3242 if (e
->flags
.is_interior
)
3244 assert (AutoRouteParameters
.with_conflicts
); /* no interior edges unless
3245 routing with conflicts! */
3246 assert (e
->rb
->underlying
);
3247 if (e
->rb
->underlying
->flags
.touched
)
3248 goto dontexpand
; /* already done this one */
3249 /* touch this interior box */
3250 e
->rb
->underlying
->flags
.touched
= 1;
3251 vector_append (touched_vec
, e
->rb
->underlying
);
3252 /* is this a target? */
3253 if (e
->rb
->underlying
->flags
.target
)
3254 best_path_candidate (&s
, e
, e
->rb
->underlying
); /* new best path? */
3255 /* don't allow conflicts with fixed edges */
3256 if (e
->rb
->underlying
->flags
.fixed
)
3258 /* break all edges and come up with a new vector of edges */
3259 assert (__edge_is_good (e
));
3260 assert (e
->flags
.expand_all_sides
);
3261 assert (vector_is_empty (edge_vec
));
3262 ExpandAllEdges (e
, edge_vec
, CONFLICT_PENALTY (e
->rb
->underlying
),
3264 BreakEdges (rd
, edge_vec
, targets
);
3265 /* add broken edges to s.workheap */
3266 while (!vector_is_empty (edge_vec
))
3267 add_or_destroy_edge (&s
,
3268 (edge_t
*) vector_remove_last (edge_vec
));
3269 /* add in possible via sites on conflict rect. */
3270 /* note that e->rb should be bloated version of conflict rect */
3271 if (AutoRouteParameters
.use_vias
&&
3272 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
3273 add_via_sites (&s
, &vss
, rd
->mtspace
, e
->rb
,
3274 CONFLICT_LEVEL (e
->rb
->underlying
), e
, targets
, 0);
3276 else if (e
->flags
.is_via
)
3277 { /* special case via */
3278 routebox_t
*intersecting
;
3279 assert (AutoRouteParameters
.use_vias
);
3280 assert (e
->flags
.expand_all_sides
);
3281 assert (vector_is_empty (edge_vec
));
3282 intersecting
= FindOneInBox (rd
->layergrouptree
[e
->rb
->group
],
3283 &e
->rb
->box
, rd
->max_bloat
);
3284 if (intersecting
== NULL
)
3286 /* this via candidate is in an open area; add it to r-tree as
3287 * an expansion area */
3288 assert (e
->rb
->type
== EXPANSION_AREA
&& e
->rb
->flags
.is_via
);
3289 assert (r_region_is_empty (rd
->layergrouptree
[e
->rb
->group
],
3291 r_insert_entry (rd
->layergrouptree
[e
->rb
->group
], &e
->rb
->box
,
3293 e
->rb
->flags
.orphan
= 0; /* not an orphan any more */
3294 /* add to vector of all expansion areas in r-tree */
3295 vector_append (area_vec
, e
->rb
);
3296 /* mark reset refcount to 0, since this is not an orphan any more. */
3297 e
->rb
->refcount
= 0;
3298 /* expand from all four edges! */
3299 for (i
= 0; i
< 4; i
++)
3301 edge_t
*ne
= CreateEdge2 (e
->rb
, i
, e
, targets
, NULL
);
3302 add_or_destroy_edge (&s
, ne
);
3306 { /* XXX: disabling this causes no via
3308 BoxType a
= bloat_routebox (intersecting
), b
;
3311 /* something intersects this via candidate. split via candidate
3312 * into pieces and add these pieces to the workheap. */
3313 for (i
= 0; i
< 3; i
++)
3315 for (j
= 0; j
< 3; j
++)
3321 b
.X2
= MIN (b
.X2
, a
.X1
);
3324 b
.X1
= MAX (b
.X1
, a
.X1
);
3325 b
.X2
= MIN (b
.X2
, a
.X2
);
3328 b
.X1
= MAX (b
.X1
, a
.X2
);
3336 b
.Y2
= MIN (b
.Y2
, a
.Y1
);
3339 b
.Y1
= MAX (b
.Y1
, a
.Y1
);
3340 b
.Y2
= MIN (b
.Y2
, a
.Y2
);
3343 b
.Y1
= MAX (b
.Y1
, a
.Y2
);
3348 /* skip if this box is not valid */
3349 if (!(b
.X1
< b
.X2
&& b
.Y1
< b
.Y2
))
3351 if (i
== 1 && j
== 1)
3353 /* this bit of the via space is obstructed. */
3354 if (intersecting
->type
== EXPANSION_AREA
3355 || intersecting
->flags
.fixed
)
3356 continue; /* skip this bit, it's already been done. */
3357 /* create an edge with conflicts, if enabled */
3358 if (!AutoRouteParameters
.with_conflicts
)
3360 ne
= CreateEdgeWithConflicts (&b
, intersecting
, e
, 1
3361 /*cost penalty to box */
3363 add_or_destroy_edge (&s
, ne
);
3367 /* if this is not the intersecting piece, create a new
3368 * (hopefully unobstructed) via edge and add it back to the
3371 CreateViaEdge (&b
, e
->rb
->group
,
3372 e
->rb
->parent
.expansion_area
, e
,
3373 e
->flags
.via_conflict_level
,
3375 /* value here doesn't matter */
3377 add_or_destroy_edge (&s
, ne
);
3382 /* between the time these edges are inserted and the
3383 * time they are processed, new expansion boxes (which
3384 * conflict with these edges) may be added to the graph!
3385 * w.o vias this isn't a problem because the broken box
3386 * is not an orphan. */
3389 { /* create expansion area from edge */
3390 BoxType expand_region
; /* next expansion area */
3391 routebox_t
*next
; /* this is the obstacle limiting the expansion area */
3392 struct broken_boxes bb
; /* edges split by the obstacle */
3393 routebox_t
*nrb
= NULL
; /* new route box */
3394 edge_t
*ne
; /* new edge */
3395 /* the 'expand_dir' edges of the expansion area have to be split.
3396 * this is the parent of those edges */
3397 routebox_t
*top_parent
= e
->rb
;
3399 /* expand this edge */
3400 #if defined(ROUTE_DEBUG)
3401 printf ("EXPANDING EDGE %p: cost %f ", e
, e
->cost_to_point
);
3402 switch (e
->expand_dir
)
3405 printf ("(X:%d to %d NORTH of %d)\n", e
->rb
->box
.X1
,
3406 e
->rb
->box
.X2
, e
->rb
->box
.Y1
);
3409 printf ("(X:%d to %d SOUTH of %d)\n", e
->rb
->box
.X1
,
3410 e
->rb
->box
.X2
, e
->rb
->box
.Y2
);
3413 printf ("(Y:%d to %d WEST of %d)\n", e
->rb
->box
.Y1
,
3414 e
->rb
->box
.Y2
, e
->rb
->box
.X1
);
3417 printf ("(Y:%d to %d EAST of %d)\n", e
->rb
->box
.Y1
,
3418 e
->rb
->box
.Y2
, e
->rb
->box
.X2
);
3423 FindBlocker (rd
->layergrouptree
[e
->rb
->group
], e
, rd
->max_bloat
);
3424 /* limit region to next box. */
3425 expand_region
= edge_to_infinity_region (e
);
3426 if (expand_region
.X1
>= expand_region
.X2
||
3427 expand_region
.Y1
>= expand_region
.Y2
)
3430 printf ("past pcb edge\n");
3432 goto dontexpand
; /* expansion edge is past PCB edge */
3436 limit_region (expand_region
, e
, bloat_routebox (next
));
3437 if (expand_region
.X1
> expand_region
.X2
3438 || expand_region
.Y1
> expand_region
.Y2
)
3441 printf ("copper violates spacing\n");
3443 goto dontexpand
; /* existing copper violates spacing rule */
3446 if (edge_length (&expand_region
, (e
->expand_dir
+ 1) % 4) > 0)
3448 assert (edge_length (&expand_region
, e
->expand_dir
) > 0);
3449 /* ooh, a non-zero area expansion region! add it to the r-tree! */
3450 /* create new route box nrb and add it to the tree */
3452 CreateExpansionArea (&expand_region
, e
->rb
->group
, e
->rb
,
3457 r_insert_entry (rd
->layergrouptree
[nrb
->group
], &nrb
->box
, 1);
3458 nrb
->flags
.orphan
= 0; /* not an orphan any more */
3459 /* add to vector of all expansion areas in r-tree */
3460 vector_append (area_vec
, nrb
);
3461 /* parent of orphan expansion edges on top should be this */
3463 if (next
&& next
->flags
.source
)
3465 /* no sense in expanding edges on targets */
3466 if (!next
|| !next
->flags
.target
)
3468 /* add side edges to the expansion activity heap */
3469 for (i
= 1; i
< 4; i
+= 2)
3470 { /* directions +/- 1 */
3472 CreateEdge2 (nrb
, (e
->expand_dir
+ i
) % 4, e
, targets
,
3474 add_or_destroy_edge (&s
, ne
);
3477 /* add in possible via sites in nrb */
3478 if (AutoRouteParameters
.use_vias
&&
3479 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
3480 add_via_sites (&s
, &vss
,
3481 rd
->mtspace
, nrb
, NO_CONFLICT
, e
, targets
, 0);
3483 /* if we didn't hit *anything* (i.e. we hit the edge of the board),
3484 * then don't expand any more in this direction. */
3487 if (next
->flags
.source
)
3490 printf ("hit source terminal\n");
3494 /* now deal with blocker... */
3495 /* maybe we've found a target? */
3496 if (next
->flags
.target
)
3499 printf ("hit target!\n");
3503 CreateExpansionArea (&next
->box
, e
->rb
->group
, top_parent
,
3505 /* the expansion area we just created is the target box
3506 * we hit it coming from the e->expand_dir direction, but
3507 * the edge we hit is the opposite one on *this* box
3508 * so be sure to create ne as the new struck edge in order
3509 * to compute the cost right.
3511 /* sometime the minimum cost target is a *different* target,
3512 * because of where the cost point was. But *this* cost is to
3513 * *this* target, so manually set mincost_target before we
3514 * call edge_cost() inside best_path_candidate. */
3515 ne
= CreateEdge2 (nrb
, (e
->expand_dir
+ 2) % 4, e
, NULL
, next
);
3516 assert (ne
->rb
== nrb
);
3517 best_path_candidate (&s
, ne
, next
); /* new best path? */
3521 /* split the blocked edge at the obstacle. Add the two
3522 * free edges; the edge that abuts the obstacle is also a
3523 * (high-cost) expansion edge as long as the thing we hit isn't
3524 * an expansion area. If the thing we hit is a target, then
3526 bb
= break_box_edge (&expand_region
, e
->expand_dir
, next
);
3527 /* "left" is in rotate_north coordinates */
3528 if (bb
.is_valid_left
)
3529 { /* left edge valid? */
3531 CreateExpansionArea (&bb
.left
, e
->rb
->group
, top_parent
,
3537 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
3539 assert (vector_is_empty (edge_vec
));
3540 vector_append (edge_vec
, ne
);
3542 add_or_destroy_edge (&s
, ne
);
3545 /* "right" is in rotate_north coordinates */
3546 if (bb
.is_valid_right
)
3547 { /* right edge valid? */
3549 CreateExpansionArea (&bb
.right
, e
->rb
->group
, top_parent
,
3555 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
3557 vector_append (edge_vec
, ne
);
3559 add_or_destroy_edge (&s
, ne
);
3563 BreakEdges (rd
, edge_vec
, targets
);
3564 /* add broken edges to s.workheap */
3565 while (!vector_is_empty (edge_vec
))
3566 add_or_destroy_edge (&s
,
3567 (edge_t
*) vector_remove_last (edge_vec
));
3569 if (next
->type
!= EXPANSION_AREA
&& !next
->flags
.target
3570 && !next
->flags
.fixed
&& AutoRouteParameters
.with_conflicts
)
3573 /* is center valid for expansion? (with conflicts) */
3574 assert (bb
.is_valid_center
); /* how could it not be? */
3576 CreateExpansionArea (&bb
.center
, e
->rb
->group
, top_parent
,
3578 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, targets
, NULL
);
3579 /* no penalty to reach conflict box, since we're still outside here */
3581 CreateEdgeWithConflicts (&bb
.center
, next
, ne
, 1, targets
);
3582 add_or_destroy_edge (&s
, ne2
);
3589 heap_destroy (&s
.workheap
);
3590 r_destroy_tree (&targets
);
3591 assert (vector_is_empty (edge_vec
));
3592 vector_destroy (&edge_vec
);
3594 /* we should have a path in best_path now */
3598 #ifdef ROUTE_VERBOSE
3599 printf ("%d:%d RC %.0f", ro
++, seen
, s
.best_cost
);
3601 result
.found_route
= True
;
3602 result
.best_route_cost
= s
.best_cost
;
3603 /* determine if the best path had conflicts */
3604 result
.route_had_conflicts
= 0;
3605 if (AutoRouteParameters
.with_conflicts
)
3606 for (rb
= s
.best_path
; !rb
->flags
.source
;
3607 rb
= rb
->parent
.expansion_area
)
3610 rb
->underlying
->flags
.is_bad
= 1;
3611 result
.route_had_conflicts
++;
3613 #ifdef ROUTE_VERBOSE
3614 if (result
.route_had_conflicts
)
3615 printf (" (%d conflicts)", result
.route_had_conflicts
);
3617 if (result
.route_had_conflicts
< AutoRouteParameters
.hi_conflict
)
3619 /* back-trace the path and add lines/vias to r-tree */
3620 TracePath (rd
, s
.best_path
, s
.best_target
, from
,
3621 result
.route_had_conflicts
);
3622 MergeNets (from
, s
.best_target
, SUBNET
);
3623 RB_down_count (s
.best_path
); /* free routeboxen along path */
3627 #ifdef ROUTE_VERBOSE
3628 printf (" (too many in fact)");
3630 result
.found_route
= False
;
3632 #ifdef ROUTE_VERBOSE
3638 #ifdef ROUTE_VERBOSE
3639 printf ("%d:%d NO PATH FOUND.\n", ro
++, seen
);
3641 result
.best_route_cost
= s
.best_cost
;
3642 result
.found_route
= False
;
3644 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
3645 LIST_LOOP (from
, same_net
, p
);
3646 p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
3648 /* now remove all expansion areas from the r-tree. */
3649 while (!vector_is_empty (area_vec
))
3651 routebox_t
*rb
= vector_remove_last (area_vec
);
3652 assert (!rb
->flags
.orphan
);
3653 r_delete_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
);
3655 vector_destroy (&area_vec
);
3656 /* reset flags on touched fixed rects */
3657 while (!vector_is_empty (touched_vec
))
3659 routebox_t
*rb
= vector_remove_last (touched_vec
);
3660 assert (rb
->flags
.touched
);
3661 rb
->flags
.touched
= 0;
3663 vector_destroy (&touched_vec
);
3665 vector_destroy (&vss
.free_space_vec
);
3666 vector_destroy (&vss
.lo_conflict_space_vec
);
3667 vector_destroy (&vss
.hi_conflict_space_vec
);
3673 InitAutoRouteParameters (int pass
,
3674 AugmentedRouteStyleType
* augStyle
,
3675 Boolean with_conflicts
, Boolean is_smoothing
)
3678 AutoRouteParameters
.augStyle
= augStyle
;
3680 AutoRouteParameters
.ViaCost
=
3681 50000 + augStyle
->style
->Diameter
* (is_smoothing
? 80 : 10);
3682 AutoRouteParameters
.LastConflictPenalty
= 500 * pass
/ passes
+ 2;
3683 AutoRouteParameters
.ConflictPenalty
=
3684 5 * AutoRouteParameters
.LastConflictPenalty
;
3685 AutoRouteParameters
.JogPenalty
= 1000 * (is_smoothing
? 20 : 4);
3686 AutoRouteParameters
.WrongWayPenalty
= 2000 * (is_smoothing
? 2 : 4);
3687 AutoRouteParameters
.DirectionPenalty
= 2;
3688 AutoRouteParameters
.SurfacePenalty
= 3;
3689 AutoRouteParameters
.AwayPenalty
= 4;
3690 AutoRouteParameters
.MinPenalty
= MIN (AutoRouteParameters
.DirectionPenalty
,
3691 AutoRouteParameters
.SurfacePenalty
);
3692 AutoRouteParameters
.SearchPenalty
= 200000;
3693 AutoRouteParameters
.NewLayerPenalty
= is_smoothing
?
3694 0.5 * EXPENSIVE
: 6 * AutoRouteParameters
.ViaCost
+
3695 AutoRouteParameters
.SearchPenalty
;
3697 AutoRouteParameters
.hi_conflict
= MAX (passes
- pass
+ 3, 3);
3698 AutoRouteParameters
.is_odd
= (pass
& 1);
3699 AutoRouteParameters
.with_conflicts
= with_conflicts
;
3700 AutoRouteParameters
.is_smoothing
= is_smoothing
;
3701 AutoRouteParameters
.rip_always
= is_smoothing
;
3706 bad_boy (const BoxType
* b
, void *cl
)
3708 routebox_t
*box
= (routebox_t
*) b
;
3709 if (box
->type
== EXPANSION_AREA
)
3715 no_expansion_boxes (routedata_t
* rd
)
3723 for (i
= 0; i
< max_layer
; i
++)
3725 if (r_search (rd
->layergrouptree
[i
], &big
, NULL
, bad_boy
, NULL
))
3732 struct routeall_status
3734 /* --- for completion rate statistics ---- */
3736 /* total subnets routed without conflicts */
3738 /* total subnets routed with conflicts */
3739 int conflict_subnets
;
3741 struct routeall_status
3742 RouteAll (routedata_t
* rd
)
3744 struct routeall_status ras
;
3745 struct routeone_status ros
;
3750 heap_t
*this_pass
, *next_pass
, *tmp
;
3751 routebox_t
*net
, *p
, *pp
;
3752 cost_t total_net_cost
, last_cost
= 0, this_cost
= 0;
3755 /* initialize heap for first pass;
3756 * do smallest area first; that makes
3757 * the subsequent costs more representative */
3758 this_pass
= heap_create ();
3759 next_pass
= heap_create ();
3761 net_heap
= heap_create ();
3763 LIST_LOOP (rd
->first_net
, different_net
, net
);
3766 BoxType bb
= net
->box
;
3767 LIST_LOOP (net
, same_net
, p
);
3769 MAKEMIN (bb
.X1
, p
->box
.X1
);
3770 MAKEMIN (bb
.Y1
, p
->box
.Y1
);
3771 MAKEMAX (bb
.X2
, p
->box
.X2
);
3772 MAKEMAX (bb
.Y2
, p
->box
.Y2
);
3775 area
= (float) (bb
.X2
- bb
.X1
) * (bb
.Y2
- bb
.Y1
);
3776 heap_insert (this_pass
, area
, net
);
3780 /* refinement/finishing passes */
3781 for (i
= 0; i
<= passes
+ smoothes
; i
++)
3783 #ifdef ROUTE_VERBOSE
3784 if (i
> 0 && i
<= passes
)
3785 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i
);
3786 else if (i
> passes
)
3787 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
3790 ras
.total_subnets
= ras
.routed_subnets
= ras
.conflict_subnets
= 0;
3791 assert (heap_is_empty (next_pass
));
3792 while (!heap_is_empty (this_pass
))
3794 net
= (routebox_t
*) heap_remove_smallest (this_pass
);
3795 InitAutoRouteParameters (i
, net
->augStyle
, i
< passes
, i
> passes
);
3798 /* rip up all unfixed traces in this net ? */
3799 if (AutoRouteParameters
.rip_always
)
3804 LIST_LOOP (net
, same_net
, p
);
3805 if (!p
->flags
.fixed
&& p
->flags
.is_bad
)
3813 LIST_LOOP (net
, same_net
, p
);
3814 if (!p
->flags
.fixed
)
3817 assert (!p
->flags
.orphan
);
3818 p
->flags
.is_bad
= 0;
3821 RemoveFromNet (p
, NET
);
3822 RemoveFromNet (p
, SUBNET
);
3824 if (AutoRouteParameters
.use_vias
&& p
->type
!= VIA_SHADOW
)
3826 mtspace_remove (rd
->mtspace
, &p
->box
,
3827 p
->flags
.is_odd
? ODD
: EVEN
,
3828 p
->augStyle
->style
->Keepaway
);
3830 mtspace_add (rd
->mtspace
, &p
->box
,
3831 p
->flags
.is_odd
? EVEN
: ODD
,
3832 p
->augStyle
->style
->Keepaway
);
3836 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
)
3837 && (p
->type
== LINE
|| p
->type
== VIA
))
3840 r_delete_entry (rd
->layergrouptree
[p
->group
],
3846 p
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3850 /* reset to original connectivity */
3855 heap_insert (next_pass
, 0, net
);
3859 /* count number of subnets */
3860 FOREACH_SUBNET (net
, p
);
3861 ras
.total_subnets
++;
3862 END_FOREACH (net
, p
);
3863 /* the first subnet doesn't require routing. */
3864 ras
.total_subnets
--;
3867 /* only route that which isn't fully routed */
3868 if (ras
.total_subnets
)
3870 /* the loop here ensures that we get to all subnets even if
3871 * some of them are unreachable from the first subnet. */
3872 LIST_LOOP (net
, same_net
, p
);
3875 /* using a heap allows us to start from smaller objects and
3876 * end at bigger ones. also prefer to start at planes, then pads */
3877 heap_insert (net_heap
, (float) (p
->box
.X2
- p
->box
.X1
) *
3878 (p
->box
.Y2
- p
->box
.Y1
) * (p
->type
== PLANE
?
3884 while (!heap_is_empty (net_heap
))
3886 p
= (routebox_t
*) heap_remove_smallest (net_heap
);
3888 if (p
->flags
.fixed
&& !p
->flags
.subnet_processed
3889 && p
->type
!= OTHER
)
3893 assert (no_expansion_boxes (rd
));
3895 RouteOne (rd
, p
, NULL
,
3896 ((AutoRouteParameters
.
3897 is_smoothing
? 2000 : 800) * (i
+
3900 total_net_cost
+= ros
.best_route_cost
;
3901 if (ros
.found_route
)
3903 if (ros
.route_had_conflicts
)
3904 ras
.conflict_subnets
++;
3906 ras
.routed_subnets
++;
3910 /* don't bother trying any other source in this subnet */
3911 LIST_LOOP (p
, same_subnet
, pp
);
3912 pp
->flags
.subnet_processed
= 1;
3915 /* note that we can infer nothing about ras.total_subnets based
3916 * on the number of calls to RouteOne, because we may be unable
3917 * to route a net from a particular starting point, but perfectly
3918 * able to route it from some other. */
3920 while (ros
.found_route
&& !ros
.net_completely_routed
);
3928 /* Route easiest nets from this pass first on next pass.
3929 * This works best because it's likely that the hardest
3930 * is the last one routed (since it has the most obstacles)
3931 * but it will do no good to rip it up and try it again
3932 * without first changing any of the other routes
3934 heap_insert (next_pass
, total_net_cost
, net
);
3935 if (total_net_cost
< EXPENSIVE
)
3936 this_cost
+= total_net_cost
;
3937 /* reset subnet_processed flags */
3938 LIST_LOOP (net
, same_net
, p
);
3940 p
->flags
.subnet_processed
= 0;
3944 /* swap this_pass and next_pass and do it all over again! */
3946 assert (heap_is_empty (this_pass
));
3948 this_pass
= next_pass
;
3950 /* XXX: here we should update a status bar */
3951 #ifdef ROUTE_VERBOSE
3953 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f\n",
3954 i
, ras
.routed_subnets
, ras
.total_subnets
, this_cost
);
3956 /* if no conflicts found, skip directly to smoothing pass! */
3957 if (ras
.conflict_subnets
== 0 && ras
.routed_subnets
== ras
.total_subnets
3959 i
= passes
- (smoothes
? 0 : 1);
3960 /* if no changes in a smoothing round, then we're done */
3961 if (this_cost
== last_cost
&& i
> passes
)
3963 last_cost
= this_cost
;
3966 Message ("%d of %d nets successfully routed.\n", ras
.routed_subnets
,
3969 heap_destroy (&this_pass
);
3970 heap_destroy (&next_pass
);
3972 heap_destroy (&net_heap
);
3975 /* no conflicts should be left at the end of the process. */
3976 assert (ras
.conflict_subnets
== 0);
3989 fpin_rect (const BoxType
* b
, void *cl
)
3991 PinTypePtr pin
= (PinTypePtr
) b
;
3992 struct fpin_info
*info
= (struct fpin_info
*) cl
;
3993 if (pin
->X
== info
->X
&& pin
->Y
== info
->Y
)
3995 info
->pin
= (PinTypePtr
) b
;
3996 longjmp (info
->env
, 1);
4002 FindPin (const BoxType
* box
, PinTypePtr
* pin
)
4004 struct fpin_info info
;
4009 if (setjmp (info
.env
) == 0)
4010 r_search (PCB
->Data
->pin_tree
, box
, NULL
, fpin_rect
, &info
);
4016 if (setjmp (info
.env
) == 0)
4017 r_search (PCB
->Data
->via_tree
, box
, NULL
, fpin_rect
, &info
);
4028 /* paths go on first 'on' layer in group */
4029 /* returns 'True' if any paths were added. */
4031 IronDownAllUnfixedPaths (routedata_t
* rd
)
4033 Boolean changed
= False
;
4035 routebox_t
*net
, *p
;
4037 LIST_LOOP (rd
->first_net
, different_net
, net
);
4039 LIST_LOOP (net
, same_net
, p
);
4041 if (!p
->flags
.fixed
)
4043 /* find first on layer in this group */
4044 assert (PCB
->LayerGroups
.Number
[p
->group
] > 0);
4045 assert (is_layer_group_active
[p
->group
]);
4046 for (i
= 0, layer
= NULL
; i
< PCB
->LayerGroups
.Number
[p
->group
];
4049 layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[p
->group
][i
]);
4053 assert (layer
&& layer
->On
); /*at least one layer must be on in this group! */
4054 assert (p
->type
!= EXPANSION_AREA
);
4055 if (p
->type
== LINE
)
4057 BDimension halfwidth
= HALF_THICK (p
->augStyle
->style
->Thick
);
4059 assert (p
->parent
.line
== NULL
);
4060 /* orthogonal; thickness is 2*halfwidth */
4062 assert (p->flags.nonstraight ||
4063 p->box.X1 + halfwidth ==
4064 p->box.X2 - halfwidth
4065 || p->box.Y1 + halfwidth ==
4066 p->box.Y2 - halfwidth);
4068 /* flip coordinates, if bl_to_ur */
4069 b
= shrink_box (&p
->box
, halfwidth
);
4070 if (p
->flags
.bl_to_ur
)
4077 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
4078 p
->parent
.line
= CreateDrawnLineOnLayer
4079 (layer
, b
.X1
, b
.Y1
, b
.X2
, b
.Y2
,
4080 p
->augStyle
->style
->Thick
,
4081 p
->augStyle
->style
->Keepaway
* 2,
4082 MakeFlags (AUTOFLAG
|
4083 (TEST_FLAG (CLEARNEWFLAG
, PCB
) ? CLEARLINEFLAG
:
4088 AddObjectToCreateUndoList (LINE_TYPE
, layer
,
4089 p
->parent
.line
, p
->parent
.line
);
4093 else if (p
->type
== VIA
|| p
->type
== VIA_SHADOW
)
4096 (p
->type
== VIA_SHADOW
) ? p
->parent
.via_shadow
: p
;
4097 BDimension radius
= HALF_THICK (pp
->augStyle
->style
->Diameter
);
4098 assert (pp
->type
== VIA
);
4099 if (pp
->parent
.via
== NULL
)
4101 assert (pp
->box
.X1
+ radius
== pp
->box
.X2
- radius
);
4102 assert (pp
->box
.Y1
+ radius
== pp
->box
.Y2
- radius
);
4104 CreateNewVia (PCB
->Data
, pp
->box
.X1
+ radius
,
4105 pp
->box
.Y1
+ radius
,
4106 pp
->augStyle
->style
->Diameter
,
4107 2 * pp
->augStyle
->style
->Keepaway
,
4108 0, pp
->augStyle
->style
->Hole
, NULL
,
4109 MakeFlags (AUTOFLAG
));
4110 assert (pp
->parent
.via
);
4113 AddObjectToCreateUndoList (VIA_TYPE
,
4120 assert (pp
->parent
.via
);
4121 if (p
->type
== VIA_SHADOW
)
4124 p
->parent
.via
= pp
->parent
.via
;
4127 else if (p
->type
== PLANE
)
4134 /* loop again to place all the thermals now that the vias are down */
4135 LIST_LOOP (net
, same_net
, p
);
4137 if (!p
->flags
.fixed
&& p
->type
== PLANE
)
4139 PinTypePtr pin
= NULL
;
4140 int type
= FindPin (&p
->box
, &pin
);
4143 AddObjectToFlagUndoList (type
,
4144 pin
->Element
? pin
->Element
: pin
,
4146 ASSIGN_THERM (p
->layer
, PCB
->ThermStyle
, pin
);
4157 AutoRoute (Boolean selected
)
4159 Boolean changed
= False
;
4165 ar_gc
= gui
->make_gc ();
4166 gui
->set_line_cap (ar_gc
, Round_Cap
);
4169 for (i
= 0; i
< NUM_STYLES
; i
++)
4171 if (PCB
->RouteStyle
[i
].Thick
== 0 ||
4172 PCB
->RouteStyle
[1].Diameter
== 0 ||
4173 PCB
->RouteStyle
[1].Hole
== 0 || PCB
->RouteStyle
[i
].Keepaway
== 0)
4175 Message ("You must define proper routing styles\n"
4176 "before auto-routing.\n");
4180 if (PCB
->Data
->RatN
== 0)
4182 SaveFindFlag (DRCFLAG
);
4183 rd
= CreateRouteData ();
4187 routebox_t
*net
, *rb
, *last
;
4189 /* count number of rats selected */
4190 RAT_LOOP (PCB
->Data
);
4192 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
4196 #ifdef ROUTE_VERBOSE
4197 printf ("%d nets!\n", i
);
4200 goto donerouting
; /* nothing to do here */
4201 /* if only one rat selected, do things the quick way. =) */
4204 RAT_LOOP (PCB
->Data
);
4205 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
4207 /* look up the end points of this rat line */
4211 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
4212 line
->Point1
.Y
, line
->group1
);
4214 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
4215 line
->Point2
.Y
, line
->group2
);
4216 assert (a
!= NULL
&& b
!= NULL
);
4217 assert (a
->augStyle
== b
->augStyle
);
4218 /* route exactly one net, without allowing conflicts */
4219 InitAutoRouteParameters (0, a
->augStyle
, False
, True
);
4220 changed
= RouteOne (rd
, a
, b
, 150000).found_route
|| changed
;
4225 /* otherwise, munge the netlists so that only the selected rats
4227 /* first, separate all sub nets into separate nets */
4228 /* note that this code works because LIST_LOOP is clever enough not to
4229 * be fooled when the list is changing out from under it. */
4231 LIST_LOOP (rd
->first_net
, different_net
, net
);
4233 FOREACH_SUBNET (net
, rb
);
4237 last
->different_net
.next
= rb
;
4238 rb
->different_net
.prev
= last
;
4242 END_FOREACH (net
, rb
);
4243 LIST_LOOP (net
, same_net
, rb
);
4245 rb
->same_net
= rb
->same_subnet
;
4248 /* at this point all nets are equal to their subnets */
4253 last
->different_net
.next
= rd
->first_net
;
4254 rd
->first_net
->different_net
.prev
= last
;
4257 /* now merge only those subnets connected by a rat line */
4258 RAT_LOOP (PCB
->Data
);
4259 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
4261 /* look up the end points of this rat line */
4265 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
4266 line
->Point1
.Y
, line
->group1
);
4268 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
4269 line
->Point2
.Y
, line
->group2
);
4272 #ifdef DEBUG_STALE_RATS
4273 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
4274 ASSIGN_FLAG (SELECTEDFLAG
, True
, line
);
4276 #endif /* DEBUG_STALE_RATS */
4277 Message ("The rats nest is stale! Aborting autoroute...\n");
4280 /* merge subnets into a net! */
4281 MergeNets (a
, b
, NET
);
4284 /* now 'different_net' may point to too many different nets. Reset. */
4285 LIST_LOOP (rd
->first_net
, different_net
, net
);
4287 if (!net
->flags
.touched
)
4289 LIST_LOOP (net
, same_net
, rb
);
4290 rb
->flags
.touched
= 1;
4293 else /* this is not a "different net"! */
4294 RemoveFromNet (net
, DIFFERENT_NET
);
4297 /* reset "touched" flag */
4298 LIST_LOOP (rd
->first_net
, different_net
, net
);
4300 LIST_LOOP (net
, same_net
, rb
);
4302 assert (rb
->flags
.touched
);
4303 rb
->flags
.touched
= 0;
4309 /* okay, rd's idea of netlist now corresponds to what we want routed */
4310 /* auto-route all nets */
4311 changed
= (RouteAll (rd
).routed_subnets
> 0) || changed
;
4314 changed
= IronDownAllUnfixedPaths (rd
);
4315 DestroyRouteData (&rd
);
4318 SaveUndoSerialNumber ();
4320 /* optimize rats, we've changed connectivity a lot. */
4321 DeleteRats (False
/*all rats */ );
4322 RestoreUndoSerialNumber ();
4323 AddAllRats (False
/*all rats */ , NULL
);
4324 RestoreUndoSerialNumber ();
4326 IncrementUndoSerialNumber ();
4328 ClearAndRedrawOutput ();