4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1998,1999,2000,2001 harry eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Contact addresses for paper mail and Email:
23 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
24 * haceaton@aplcomm.jhuapl.edu
27 /* this file, autoroute.c, was written and is
28 * Copyright (c) 2001 C. Scott Ananian
29 * Copyright (c) 2006 harry eaton
30 * Copyright (c) 2009 harry eaton
32 /* functions used to autoroute nets.
35 *-------------------------------------------------------------------
36 * This file implements a rectangle-expansion router, based on
37 * "A Method for Gridless Routing of Printed Circuit Boards" by
38 * A. C. Finch, K. J. Mackenzie, G. J. Balsdon, and G. Symonds in the
39 * 1985 Proceedings of the 22nd ACM/IEEE Design Automation Conference.
40 * This reference is available from the ACM Digital Library at
41 * http://www.acm.org/dl for those with institutional or personal
42 * access to it. It's also available from your local engineering
45 * The code is much closer to what is described in the paper now,
46 * in that expansion areas can grow from corners and in all directions
47 * at once. Previously, these were emulated with discrete boxes moving
48 * in the cardinal directions. With the new method, there are fewer but
49 * larger expansion boxes that one might do a better job of routing in.
50 *--------------------------------------------------------------------
64 #include "autoroute.h"
81 #include "pcb-printf.h"
83 #ifdef HAVE_LIBDMALLOC
87 /* #defines to enable some debugging output */
94 //#define DEBUG_SHOW_ROUTE_BOXES
95 #define DEBUG_SHOW_EXPANSION_BOXES
96 //#define DEBUG_SHOW_EDGES
97 //#define DEBUG_SHOW_VIA_BOXES
98 #define DEBUG_SHOW_TARGETS
99 #define DEBUG_SHOW_SOURCES
100 //#define DEBUG_SHOW_ZIGZAG
104 directionIncrement(direction_t dir
)
141 static hidGC ar_gc
= 0;
144 #define EXPENSIVE 3e28
145 /* round up "half" thicknesses */
146 #define HALF_THICK(x) (((x)+1)/2)
147 /* a styles maximum bloat is its keepaway plus the larger of its via radius
148 * or line half-thickness. */
149 #define BLOAT(style)\
150 ((style)->Keepaway + HALF_THICK((style)->Thick))
151 /* conflict penalty is less for traces laid down during previous pass than
152 * it is for traces already laid down in this pass. */
153 #define CONFLICT_LEVEL(rb)\
154 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
155 HI_CONFLICT : LO_CONFLICT )
156 #define CONFLICT_PENALTY(rb)\
157 ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
158 AutoRouteParameters.ConflictPenalty : \
159 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
160 AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass)
167 #define LIST_LOOP(init, which, x) do {\
168 routebox_t *__next_one__ = (init);\
171 assert(__next_one__);\
173 while (!x || __next_one__ != (init)) {\
175 /* save next one first in case the command modifies or frees it */\
176 __next_one__ = x->which.next
177 #define FOREACH_SUBNET(net, p) do {\
179 /* fail-fast: check subnet_processed flags */\
180 LIST_LOOP(net, same_net, p); \
181 assert(!p->flags.subnet_processed);\
183 /* iterate through *distinct* subnets */\
184 LIST_LOOP(net, same_net, p); \
185 if (!p->flags.subnet_processed) {\
186 LIST_LOOP(p, same_subnet, _pp_);\
187 _pp_->flags.subnet_processed=1;\
189 #define END_FOREACH(net, p) \
192 /* reset subnet_processed flags */\
193 LIST_LOOP(net, same_net, p); \
194 p->flags.subnet_processed=0;\
197 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0)
199 * all rectangles are assumed to be closed on the top and left and
200 * open on the bottom and right. That is, they include their top-left
201 * corner but don't include their bottom and right edges.
203 * expansion regions are always half-closed. This means that when
204 * tracing paths, you must steer clear of the bottom and right edges.,
205 * because these are not actually in the allowed box.
207 * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by
208 * their particular required keepaway. This simplifies the tree searching.
209 * the "sbox" contains the unbloated box.
211 /* ---------------------------------------------------------------------------
215 /* enumerated type for conflict levels */
217 { NO_CONFLICT
= 0, LO_CONFLICT
= 1, HI_CONFLICT
= 2 }
220 typedef struct routebox_list
222 struct routebox
*next
, *prev
;
226 { PAD
, PIN
, VIA
, VIA_SHADOW
, LINE
, OTHER
, EXPANSION_AREA
, PLANE
, THERMAL
}
229 typedef struct routebox
237 struct routebox
*via_shadow
; /* points to the via in r-tree which
238 * points to the PinType in the PCB. */
240 void *generic
; /* 'other' is polygon, arc, text */
241 struct routebox
*expansion_area
; /* previous expansion area in search */
244 unsigned short group
;
245 unsigned short layer
;
249 unsigned nonstraight
:1;
254 /* rects on same net as source and target don't need clearance areas */
256 /* mark circular pins, so that we be sure to connect them up properly */
258 /* we sometimes create routeboxen that don't actually belong to a
259 * r-tree yet -- make sure refcount of homelesss is set properly */
261 /* was this nonfixed obstacle generated on an odd or even pass? */
263 /* fixed route boxes that have already been "routed through" in this
264 * search have their "touched" flag set. */
266 /* this is a status bit for iterating through *different* subnets */
267 unsigned subnet_processed
:1;
268 /* some expansion_areas represent via candidates */
270 /* mark non-straight lines which go from bottom-left to upper-right,
271 * instead of from upper-left to bottom-right. */
273 /* mark polygons which are "transparent" for via-placement; that is,
274 * vias through the polygon will automatically be given a keepaway
275 * and will not electrically connect to the polygon. */
276 unsigned clear_poly
:1;
277 /* this marks "conflicting" routes that must be torn up to obtain
278 * a correct routing. This flag allows us to return a correct routing
279 * even if the user cancels auto-route after a non-final pass. */
281 /* for assertion that 'box' is never changed after creation */
283 /* indicate this expansion ares is a thermal between the pin and plane */
287 /* indicate the direction an expansion box came from */
289 CheapPointType cost_point
;
290 /* reference count for homeless routeboxes; free when refcount==0 */
292 /* when routing with conflicts, we keep a record of what we're
295 vector_t
*conflicts_with
;
296 /* route style of the net associated with this routebox */
297 RouteStyleType
*style
;
298 /* congestion values for the edges of an expansion box */
299 unsigned char n
, e
, s
, w
;
300 /* what pass this this track was laid down on */
302 /* the direction this came from, if any */
303 direction_t came_from
;
304 /* circular lists with connectivity information. */
305 routebox_list same_net
, same_subnet
, original_subnet
, different_net
;
313 typedef struct routedata
315 /* one rtree per layer *group */
316 rtree_t
*layergrouptree
[MAX_LAYER
]; /* no silkscreen layers here =) */
317 /* root pointer into connectivity information */
318 routebox_t
*first_net
;
319 /* default routing style */
320 RouteStyleType defaultstyle
;
321 /* style structures */
322 RouteStyleType
*styles
[NUM_STYLES
+ 1];
323 /* what is the maximum bloat (keepaway+line half-width or
324 * keepaway+via_radius) for any style we've seen? */
331 typedef struct edge_struct
333 routebox_t
*rb
; /* path expansion edges are real routeboxen. */
334 CheapPointType cost_point
;
335 cost_t cost_to_point
; /* from source */
336 cost_t cost
; /* cached edge cost */
337 routebox_t
*mincost_target
; /* minimum cost from cost_point to any target */
338 vetting_t
*work
; /* for via search edges */
339 direction_t expand_dir
;
342 /* this indicates that this 'edge' is a via candidate. */
344 /* record "conflict level" of via candidates, in case we need to split
346 conflict_t via_conflict_level
:2;
347 /* when "routing with conflicts", sometimes edge is interior. */
348 unsigned is_interior
:1;
349 /* this is a fake edge used to defer searching for via spaces */
350 unsigned via_search
:1;
351 /* this is a via edge in a plane where the cost point moves for free */
360 /* net style parameters */
361 RouteStyleType
*style
;
362 /* the present bloat */
364 /* cost parameters */
365 cost_t ViaCost
, /* additional "length" cost for using a via */
366 LastConflictPenalty
, /* length mult. for routing over last pass' trace */
367 ConflictPenalty
, /* length multiplier for routing over another trace */
368 JogPenalty
, /* additional "length" cost for changing direction */
369 CongestionPenalty
, /* (rational) length multiplier for routing in */
370 NewLayerPenalty
, /* penalty for routing on a previously unused layer */
371 MinPenalty
; /* smallest Direction Penalty */
372 /* maximum conflict incidence before calling it "no path found" */
374 /* are vias allowed? */
376 /* is this an odd or even pass? */
378 /* permit conflicts? */
380 /* is this a final "smoothing" pass? */
382 /* rip up nets regardless of conflicts? */
389 struct routeone_state
391 /* heap of all candidate expansion edges */
393 /* information about the best path found so far. */
394 routebox_t
*best_path
, *best_target
;
399 /* ---------------------------------------------------------------------------
400 * some local prototypes
402 static routebox_t
*CreateExpansionArea (const BoxType
* area
, Cardinal group
,
404 bool relax_edge_requirements
,
407 static cost_t
edge_cost (const edge_t
* e
, const cost_t too_big
);
408 static void best_path_candidate (struct routeone_state
*s
,
409 edge_t
* e
, routebox_t
* best_target
);
411 static BoxType
edge_to_box (const routebox_t
* rb
, direction_t expand_dir
);
413 static void add_or_destroy_edge (struct routeone_state
*s
, edge_t
* e
);
416 RD_DrawThermal (routedata_t
* rd
, Coord X
, Coord Y
,
417 Cardinal group
, Cardinal layer
, routebox_t
* subnet
,
419 static void ResetSubnet (routebox_t
* net
);
421 static int showboxen
= -2;
422 static int aabort
= 0;
423 static void showroutebox (routebox_t
* rb
);
426 /* ---------------------------------------------------------------------------
427 * some local identifiers
429 /* group number of groups that hold surface mount pads */
430 static Cardinal front
, back
;
431 static bool usedGroup
[MAX_LAYER
];
432 static int x_cost
[MAX_LAYER
], y_cost
[MAX_LAYER
];
433 static bool is_layer_group_active
[MAX_LAYER
];
435 static int smoothes
= 1;
436 static int passes
= 12;
437 static int routing_layers
= 0;
438 static float total_wire_length
= 0;
439 static int total_via_count
= 0;
441 /* assertion helper for routeboxen */
444 __routebox_is_good (routebox_t
* rb
)
446 assert (rb
&& (rb
->group
< max_group
) &&
447 (rb
->box
.X1
<= rb
->box
.X2
) && (rb
->box
.Y1
<= rb
->box
.Y2
) &&
448 (rb
->flags
.homeless
?
449 (rb
->box
.X1
!= rb
->box
.X2
) || (rb
->box
.Y1
!= rb
->box
.Y2
) :
450 (rb
->box
.X1
!= rb
->box
.X2
) && (rb
->box
.Y1
!= rb
->box
.Y2
)));
451 assert ((rb
->flags
.source
? rb
->flags
.nobloat
: 1) &&
452 (rb
->flags
.target
? rb
->flags
.nobloat
: 1) &&
453 (rb
->flags
.homeless
? !rb
->flags
.touched
: rb
->refcount
== 0) &&
454 (rb
->flags
.touched
? rb
->type
!= EXPANSION_AREA
: 1));
455 assert ((rb
->flags
.is_odd
? (!rb
->flags
.fixed
) &&
456 (rb
->type
== VIA
|| rb
->type
== VIA_SHADOW
|| rb
->type
== LINE
457 || rb
->type
== PLANE
) : 1));
458 assert (rb
->flags
.clear_poly
?
459 ((rb
->type
== OTHER
|| rb
->type
== PLANE
) && rb
->flags
.fixed
460 && !rb
->flags
.homeless
) : 1);
461 assert (rb
->flags
.inited
);
462 /* run through conflict list showing none are homeless, targets or sources */
463 if (rb
->conflicts_with
)
466 for (i
= 0; i
< vector_size (rb
->conflicts_with
); i
++)
468 routebox_t
*c
= vector_element (rb
->conflicts_with
, i
);
469 assert (!c
->flags
.homeless
&& !c
->flags
.source
&& !c
->flags
.target
473 assert (rb
->style
!= NULL
&& rb
->style
!= NULL
);
474 assert (rb
->type
== EXPANSION_AREA
475 || (rb
->same_net
.next
&& rb
->same_net
.prev
&& rb
->same_subnet
.next
476 && rb
->same_subnet
.prev
&& rb
->original_subnet
.next
477 && rb
->original_subnet
.prev
&& rb
->different_net
.next
478 && rb
->different_net
.prev
));
482 __edge_is_good (edge_t
* e
)
484 assert (e
&& e
->rb
&& __routebox_is_good (e
->rb
));
485 assert ((e
->rb
->flags
.homeless
? e
->rb
->refcount
> 0 : 1));
486 assert ((0 <= e
->expand_dir
) && (e
->expand_dir
< 9)
488 is_interior
? (e
->expand_dir
== ALL
489 && e
->rb
->conflicts_with
) : 1));
490 assert ((e
->flags
.is_via
? e
->rb
->flags
.is_via
: 1)
491 && (e
->flags
.via_conflict_level
>= 0
492 && e
->flags
.via_conflict_level
<= 2)
493 && (e
->flags
.via_conflict_level
!= 0 ? e
->flags
.is_via
: 1));
494 assert ((e
->cost_to_point
>= 0) && e
->cost
>= 0);
499 no_planes (const BoxType
* b
, void *cl
)
501 routebox_t
*rb
= (routebox_t
*) b
;
502 if (rb
->type
== PLANE
)
508 /*---------------------------------------------------------------------
509 * route utility functions.
513 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
};
514 static struct routebox_list
*
515 __select_list (routebox_t
* r
, enum boxlist which
)
523 return &(r
->same_net
);
525 return &(r
->same_subnet
);
527 return &(r
->original_subnet
);
529 return &(r
->different_net
);
533 InitLists (routebox_t
* r
)
535 static enum boxlist all
[] =
536 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
}
538 for (p
= all
; p
< all
+ (sizeof (all
) / sizeof (*p
)); p
++)
540 struct routebox_list
*rl
= __select_list (r
, *p
);
541 rl
->prev
= rl
->next
= r
;
546 MergeNets (routebox_t
* a
, routebox_t
* b
, enum boxlist which
)
548 struct routebox_list
*al
, *bl
, *anl
, *bnl
;
552 assert (a
->type
!= EXPANSION_AREA
);
553 assert (b
->type
!= EXPANSION_AREA
);
554 al
= __select_list (a
, which
);
555 bl
= __select_list (b
, which
);
560 anl
= __select_list (an
, which
);
561 bnl
= __select_list (bn
, which
);
570 RemoveFromNet (routebox_t
* a
, enum boxlist which
)
572 struct routebox_list
*al
, *anl
, *apl
;
575 al
= __select_list (a
, which
);
579 if (an
== a
|| ap
== a
)
580 return; /* not on any list */
582 anl
= __select_list (an
, which
);
583 apl
= __select_list (ap
, which
);
587 al
->next
= al
->prev
= a
;
592 init_const_box (routebox_t
* rb
,
593 Coord X1
, Coord Y1
, Coord X2
,
594 Coord Y2
, Coord keepaway
)
596 BoxType
*bp
= (BoxType
*) & rb
->box
; /* note discarding const! */
597 assert (!rb
->flags
.inited
);
598 assert (X1
<= X2
&& Y1
<= Y2
);
599 bp
->X1
= X1
- keepaway
;
600 bp
->Y1
= Y1
- keepaway
;
601 bp
->X2
= X2
+ keepaway
;
602 bp
->Y2
= Y2
+ keepaway
;
603 bp
= (BoxType
*) & rb
->sbox
;
608 rb
->flags
.inited
= 1;
611 static inline BoxType
612 shrink_routebox (const routebox_t
* rb
)
618 box_area (const BoxType b
)
620 cost_t ans
= b
.X2
- b
.X1
;
621 return ans
* (b
.Y2
- b
.Y1
);
624 static inline CheapPointType
625 closest_point_in_routebox (const CheapPointType
* from
, const routebox_t
* rb
)
627 return closest_point_in_box (from
, &rb
->sbox
);
631 point_in_shrunk_box (const routebox_t
* box
, Coord X
, Coord Y
)
633 BoxType b
= shrink_routebox (box
);
634 return point_in_box (&b
, X
, Y
);
637 /*---------------------------------------------------------------------
638 * routedata initialization functions.
642 AddPin (PointerListType layergroupboxes
[], PinType
*pin
, bool is_via
,
643 RouteStyleType
* style
)
645 routebox_t
**rbpp
, *lastrb
= NULL
;
647 /* a pin cuts through every layer group */
648 for (i
= 0; i
< max_group
; i
++)
650 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[i
]);
651 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
652 memset ((void *) *rbpp
, 0, sizeof (**rbpp
));
654 ht
= HALF_THICK (MAX (pin
->Thickness
, pin
->DrillingHole
));
655 init_const_box (*rbpp
,
659 /*Y2 */ pin
->Y
+ ht
, style
->Keepaway
);
660 /* set aux. properties */
664 (*rbpp
)->parent
.via
= pin
;
669 (*rbpp
)->parent
.pin
= pin
;
671 (*rbpp
)->flags
.fixed
= 1;
672 (*rbpp
)->came_from
= ALL
;
673 (*rbpp
)->style
= style
;
674 (*rbpp
)->flags
.circular
= !TEST_FLAG (SQUAREFLAG
, pin
);
680 MergeNets (*rbpp
, lastrb
, NET
);
681 MergeNets (*rbpp
, lastrb
, SUBNET
);
682 MergeNets (*rbpp
, lastrb
, ORIGINAL
);
689 AddPad (PointerListType layergroupboxes
[],
690 ElementType
*element
, PadType
*pad
, RouteStyleType
* style
)
694 int layergroup
= (TEST_FLAG (ONSOLDERFLAG
, pad
) ? back
: front
);
695 assert (0 <= layergroup
&& layergroup
< max_group
);
696 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
697 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
699 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
701 memset (*rbpp
, 0, sizeof (**rbpp
));
702 (*rbpp
)->group
= layergroup
;
703 halfthick
= HALF_THICK (pad
->Thickness
);
704 init_const_box (*rbpp
,
705 /*X1 */ MIN (pad
->Point1
.X
, pad
->Point2
.X
) - halfthick
,
706 /*Y1 */ MIN (pad
->Point1
.Y
, pad
->Point2
.Y
) - halfthick
,
707 /*X2 */ MAX (pad
->Point1
.X
, pad
->Point2
.X
) + halfthick
,
708 /*Y2 */ MAX (pad
->Point1
.Y
, pad
->Point2
.Y
) + halfthick
,
710 /* kludge for non-manhattan pads (which are not allowed at present) */
711 if (pad
->Point1
.X
!= pad
->Point2
.X
&& pad
->Point1
.Y
!= pad
->Point2
.Y
)
712 (*rbpp
)->flags
.nonstraight
= 1;
713 /* set aux. properties */
715 (*rbpp
)->parent
.pad
= pad
;
716 (*rbpp
)->flags
.fixed
= 1;
717 (*rbpp
)->came_from
= ALL
;
718 (*rbpp
)->style
= style
;
724 AddLine (PointerListType layergroupboxes
[], int layergroup
, LineType
*line
,
725 LineType
*ptr
, RouteStyleType
* style
)
728 assert (layergroupboxes
&& line
);
729 assert (0 <= layergroup
&& layergroup
< max_group
);
730 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
732 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
733 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
734 memset (*rbpp
, 0, sizeof (**rbpp
));
735 (*rbpp
)->group
= layergroup
;
736 init_const_box (*rbpp
,
737 /*X1 */ MIN (line
->Point1
.X
,
738 line
->Point2
.X
) - HALF_THICK (line
->Thickness
),
739 /*Y1 */ MIN (line
->Point1
.Y
,
740 line
->Point2
.Y
) - HALF_THICK (line
->Thickness
),
741 /*X2 */ MAX (line
->Point1
.X
,
742 line
->Point2
.X
) + HALF_THICK (line
->Thickness
),
743 /*Y2 */ MAX (line
->Point1
.Y
,
745 HALF_THICK (line
->Thickness
), style
->Keepaway
);
746 /* kludge for non-manhattan lines */
747 if (line
->Point1
.X
!= line
->Point2
.X
&& line
->Point1
.Y
!= line
->Point2
.Y
)
749 (*rbpp
)->flags
.nonstraight
= 1;
750 (*rbpp
)->flags
.bl_to_ur
=
751 (MIN (line
->Point1
.X
, line
->Point2
.X
) == line
->Point1
.X
) !=
752 (MIN (line
->Point1
.Y
, line
->Point2
.Y
) == line
->Point1
.Y
);
753 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
754 showroutebox (*rbpp
);
757 /* set aux. properties */
758 (*rbpp
)->type
= LINE
;
759 (*rbpp
)->parent
.line
= ptr
;
760 (*rbpp
)->flags
.fixed
= 1;
761 (*rbpp
)->came_from
= ALL
;
762 (*rbpp
)->style
= style
;
768 AddIrregularObstacle (PointerListType layergroupboxes
[],
770 Coord X2
, Coord Y2
, Cardinal layergroup
,
771 void *parent
, RouteStyleType
* style
)
774 Coord keep
= style
->Keepaway
;
775 assert (layergroupboxes
&& parent
);
776 assert (X1
<= X2
&& Y1
<= Y2
);
777 assert (0 <= layergroup
&& layergroup
< max_group
);
778 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
780 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
781 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
782 memset (*rbpp
, 0, sizeof (**rbpp
));
783 (*rbpp
)->group
= layergroup
;
784 init_const_box (*rbpp
, X1
, Y1
, X2
, Y2
, keep
);
785 (*rbpp
)->flags
.nonstraight
= 1;
786 (*rbpp
)->type
= OTHER
;
787 (*rbpp
)->parent
.generic
= parent
;
788 (*rbpp
)->flags
.fixed
= 1;
789 (*rbpp
)->style
= style
;
796 AddPolygon (PointerListType layergroupboxes
[], Cardinal layer
,
797 PolygonType
*polygon
, RouteStyleType
* style
)
799 int is_not_rectangle
= 1;
800 int layergroup
= GetLayerGroupNumberByNumber (layer
);
802 assert (0 <= layergroup
&& layergroup
< max_group
);
803 rb
= AddIrregularObstacle (layergroupboxes
,
804 polygon
->BoundingBox
.X1
,
805 polygon
->BoundingBox
.Y1
,
806 polygon
->BoundingBox
.X2
,
807 polygon
->BoundingBox
.Y2
,
808 layergroup
, polygon
, style
);
809 if (polygon
->PointN
== 4 &&
810 polygon
->HoleIndexN
== 0 &&
811 (polygon
->Points
[0].X
== polygon
->Points
[1].X
||
812 polygon
->Points
[0].Y
== polygon
->Points
[1].Y
) &&
813 (polygon
->Points
[1].X
== polygon
->Points
[2].X
||
814 polygon
->Points
[1].Y
== polygon
->Points
[2].Y
) &&
815 (polygon
->Points
[2].X
== polygon
->Points
[3].X
||
816 polygon
->Points
[2].Y
== polygon
->Points
[3].Y
) &&
817 (polygon
->Points
[3].X
== polygon
->Points
[0].X
||
818 polygon
->Points
[3].Y
== polygon
->Points
[0].Y
))
819 is_not_rectangle
= 0;
820 rb
->flags
.nonstraight
= is_not_rectangle
;
823 if (TEST_FLAG (CLEARPOLYFLAG
, polygon
))
825 rb
->flags
.clear_poly
= 1;
826 if (!is_not_rectangle
)
832 AddText (PointerListType layergroupboxes
[], Cardinal layergroup
,
833 TextType
*text
, RouteStyleType
* style
)
835 AddIrregularObstacle (layergroupboxes
,
836 text
->BoundingBox
.X1
, text
->BoundingBox
.Y1
,
837 text
->BoundingBox
.X2
, text
->BoundingBox
.Y2
,
838 layergroup
, text
, style
);
841 AddArc (PointerListType layergroupboxes
[], Cardinal layergroup
,
842 ArcType
*arc
, RouteStyleType
* style
)
844 return AddIrregularObstacle (layergroupboxes
,
845 arc
->BoundingBox
.X1
, arc
->BoundingBox
.Y1
,
846 arc
->BoundingBox
.X2
, arc
->BoundingBox
.Y2
,
847 layergroup
, arc
, style
);
858 __found_one_on_lg (const BoxType
* box
, void *cl
)
860 struct rb_info
*inf
= (struct rb_info
*) cl
;
861 routebox_t
*rb
= (routebox_t
*) box
;
864 if (rb
->flags
.nonstraight
)
866 sb
= shrink_box (&rb
->box
, rb
->style
->Keepaway
);
867 if (inf
->query
.X1
>= sb
.X2
|| inf
->query
.X2
<= sb
.X1
||
868 inf
->query
.Y1
>= sb
.Y2
|| inf
->query
.Y2
<= sb
.Y1
)
871 if (rb
->type
== PLANE
)
872 return 1; /* keep looking for something smaller if a plane was found */
873 longjmp (inf
->env
, 1);
877 FindRouteBoxOnLayerGroup (routedata_t
* rd
,
878 Coord X
, Coord Y
, Cardinal layergroup
)
882 info
.query
= point_box (X
, Y
);
883 if (setjmp (info
.env
) == 0)
884 r_search (rd
->layergrouptree
[layergroup
], &info
.query
, NULL
,
885 __found_one_on_lg
, &info
);
889 #ifdef ROUTE_DEBUG_VERBOSE
891 DumpRouteBox (routebox_t
* rb
)
893 pcb_printf ("RB: %#mD-%#mD l%d; ",
894 rb
->box
.X1
, rb
->box
.Y1
, rb
->box
.X2
, rb
->box
.Y2
, (int) rb
->group
);
898 printf ("PAD[%s %s] ", rb
->parent
.pad
->Name
, rb
->parent
.pad
->Number
);
901 printf ("PIN[%s %s] ", rb
->parent
.pin
->Name
, rb
->parent
.pin
->Number
);
906 printf ("VIA[%s %s] ", rb
->parent
.via
->Name
, rb
->parent
.via
->Number
);
921 if (rb
->flags
.nonstraight
)
922 printf ("(nonstraight) ");
925 if (rb
->flags
.source
)
926 printf ("(source) ");
927 if (rb
->flags
.target
)
928 printf ("(target) ");
929 if (rb
->flags
.homeless
)
930 printf ("(homeless) ");
938 NetListListType Nets
;
939 PointerListType layergroupboxes
[MAX_LAYER
];
944 /* check which layers are active first */
946 for (group
= 0; group
< max_group
; group
++)
948 for (i
= 0; i
< PCB
->LayerGroups
.Number
[group
]; i
++)
949 /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */
950 if ((PCB
->LayerGroups
.Entries
[group
][i
] < max_copper_layer
) &&
951 PCB
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][i
]].On
)
954 is_layer_group_active
[group
] = true;
958 is_layer_group_active
[group
] = false;
960 /* if via visibility is turned off, don't use them */
961 AutoRouteParameters
.use_vias
= routing_layers
> 1 && PCB
->ViaOn
;
962 front
= GetLayerGroupNumberByNumber (component_silk_layer
);
963 back
= GetLayerGroupNumberByNumber (solder_silk_layer
);
964 /* determine preferred routing direction on each group */
965 for (i
= 0; i
< max_group
; i
++)
967 if (i
!= back
&& i
!= front
)
969 x_cost
[i
] = (i
& 1) ? 2 : 1;
970 y_cost
[i
] = (i
& 1) ? 1 : 2;
983 /* create routedata */
984 rd
= (routedata_t
*)malloc (sizeof (*rd
));
985 memset ((void *) rd
, 0, sizeof (*rd
));
986 /* create default style */
987 rd
->defaultstyle
.Thick
= Settings
.LineThickness
;
988 rd
->defaultstyle
.Diameter
= Settings
.ViaThickness
;
989 rd
->defaultstyle
.Hole
= Settings
.ViaDrillingHole
;
990 rd
->defaultstyle
.Keepaway
= Settings
.Keepaway
;
991 rd
->max_bloat
= BLOAT (&rd
->defaultstyle
);
992 rd
->max_keep
= Settings
.Keepaway
;
993 /* create styles structures */
994 bbox
.X1
= bbox
.Y1
= 0;
995 bbox
.X2
= PCB
->MaxWidth
;
996 bbox
.Y2
= PCB
->MaxHeight
;
997 for (i
= 0; i
< NUM_STYLES
+ 1; i
++)
999 RouteStyleType
*style
=
1000 (i
< NUM_STYLES
) ? &PCB
->RouteStyle
[i
] : &rd
->defaultstyle
;
1001 rd
->styles
[i
] = style
;
1004 /* initialize pointerlisttype */
1005 for (i
= 0; i
< max_group
; i
++)
1007 layergroupboxes
[i
].Ptr
= NULL
;
1008 layergroupboxes
[i
].PtrN
= 0;
1009 layergroupboxes
[i
].PtrMax
= 0;
1010 GROUP_LOOP (PCB
->Data
, i
);
1012 if (layer
->LineN
|| layer
->ArcN
)
1013 usedGroup
[i
] = true;
1015 usedGroup
[i
] = false;
1019 usedGroup
[front
] = true;
1020 usedGroup
[back
] = true;
1021 /* add the objects in the netlist first.
1022 * then go and add all other objects that weren't already added
1024 * this saves on searching the trees to find the nets
1026 /* use the DRCFLAG to mark objects as they are entered */
1027 Nets
= CollectSubnets (false);
1029 routebox_t
*last_net
= NULL
;
1030 NETLIST_LOOP (&Nets
);
1032 routebox_t
*last_in_net
= NULL
;
1035 routebox_t
*last_in_subnet
= NULL
;
1038 for (j
= 0; j
< NUM_STYLES
; j
++)
1039 if (net
->Style
== rd
->styles
[j
])
1041 CONNECTION_LOOP (net
);
1043 routebox_t
*rb
= NULL
;
1044 SET_FLAG (DRCFLAG
, (PinType
*) connection
->ptr2
);
1045 if (connection
->type
== LINE_TYPE
)
1047 LineType
*line
= (LineType
*) connection
->ptr2
;
1049 /* lines are listed at each end, so skip one */
1050 /* this should probably by a macro named "BUMP_LOOP" */
1053 /* dice up non-straight lines into many tiny obstacles */
1054 if (line
->Point1
.X
!= line
->Point2
.X
1055 && line
->Point1
.Y
!= line
->Point2
.Y
)
1057 LineType fake_line
= *line
;
1058 Coord dx
= (line
->Point2
.X
- line
->Point1
.X
);
1059 Coord dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
1060 int segs
= MAX (ABS (dx
),
1061 ABS (dy
)) / (4 * BLOAT (rd
->styles
[j
]) + 1);
1063 segs
= CLAMP (segs
, 1, 32); /* don't go too crazy */
1066 for (qq
= 0; qq
< segs
- 1; qq
++)
1068 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
1069 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
1070 if (fake_line
.Point2
.X
== line
->Point2
.X
1071 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
1074 AddLine (layergroupboxes
, connection
->group
,
1075 &fake_line
, line
, rd
->styles
[j
]);
1076 if (last_in_subnet
&& rb
!= last_in_subnet
)
1077 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
1078 if (last_in_net
&& rb
!= last_in_net
)
1079 MergeNets (last_in_net
, rb
, NET
);
1080 last_in_subnet
= last_in_net
= rb
;
1081 fake_line
.Point1
= fake_line
.Point2
;
1083 fake_line
.Point2
= line
->Point2
;
1085 AddLine (layergroupboxes
, connection
->group
, &fake_line
,
1086 line
, rd
->styles
[j
]);
1091 AddLine (layergroupboxes
, connection
->group
, line
, line
,
1096 switch (connection
->type
)
1100 AddPad (layergroupboxes
, (ElementType
*)connection
->ptr1
,
1101 (PadType
*)connection
->ptr2
, rd
->styles
[j
]);
1105 AddPin (layergroupboxes
, (PinType
*)connection
->ptr2
, false,
1110 AddPin (layergroupboxes
, (PinType
*)connection
->ptr2
, true,
1115 AddPolygon (layergroupboxes
,
1116 GetLayerNumber (PCB
->Data
, (LayerType
*)connection
->ptr1
),
1117 (struct polygon_st
*)connection
->ptr2
, rd
->styles
[j
]);
1121 /* update circular connectivity lists */
1122 if (last_in_subnet
&& rb
!= last_in_subnet
)
1123 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
1124 if (last_in_net
&& rb
!= last_in_net
)
1125 MergeNets (last_in_net
, rb
, NET
);
1126 last_in_subnet
= last_in_net
= rb
;
1127 rd
->max_bloat
= MAX (rd
->max_bloat
, BLOAT (rb
->style
));
1128 rd
->max_keep
= MAX (rd
->max_keep
, rb
->style
->Keepaway
);
1133 if (last_net
&& last_in_net
)
1134 MergeNets (last_net
, last_in_net
, DIFFERENT_NET
);
1135 last_net
= last_in_net
;
1138 rd
->first_net
= last_net
;
1140 FreeNetListListMemory (&Nets
);
1142 /* reset all nets to "original" connectivity (which we just set) */
1145 LIST_LOOP (rd
->first_net
, different_net
, net
);
1150 /* add pins and pads of elements */
1151 ALLPIN_LOOP (PCB
->Data
);
1153 if (TEST_FLAG (DRCFLAG
, pin
))
1154 CLEAR_FLAG (DRCFLAG
, pin
);
1156 AddPin (layergroupboxes
, pin
, false, rd
->styles
[NUM_STYLES
]);
1159 ALLPAD_LOOP (PCB
->Data
);
1161 if (TEST_FLAG (DRCFLAG
, pad
))
1162 CLEAR_FLAG (DRCFLAG
, pad
);
1164 AddPad (layergroupboxes
, element
, pad
, rd
->styles
[NUM_STYLES
]);
1168 VIA_LOOP (PCB
->Data
);
1170 if (TEST_FLAG (DRCFLAG
, via
))
1171 CLEAR_FLAG (DRCFLAG
, via
);
1173 AddPin (layergroupboxes
, via
, true, rd
->styles
[NUM_STYLES
]);
1177 for (i
= 0; i
< max_copper_layer
; i
++)
1179 int layergroup
= GetLayerGroupNumberByNumber (i
);
1180 /* add all (non-rat) lines */
1181 LINE_LOOP (LAYER_PTR (i
));
1183 if (TEST_FLAG (DRCFLAG
, line
))
1185 CLEAR_FLAG (DRCFLAG
, line
);
1188 /* dice up non-straight lines into many tiny obstacles */
1189 if (line
->Point1
.X
!= line
->Point2
.X
1190 && line
->Point1
.Y
!= line
->Point2
.Y
)
1192 LineType fake_line
= *line
;
1193 Coord dx
= (line
->Point2
.X
- line
->Point1
.X
);
1194 Coord dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
1195 int segs
= MAX (ABS (dx
), ABS (dy
)) / (4 * rd
->max_bloat
+ 1);
1197 segs
= CLAMP (segs
, 1, 32); /* don't go too crazy */
1200 for (qq
= 0; qq
< segs
- 1; qq
++)
1202 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
1203 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
1204 if (fake_line
.Point2
.X
== line
->Point2
.X
1205 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
1207 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
,
1208 rd
->styles
[NUM_STYLES
]);
1209 fake_line
.Point1
= fake_line
.Point2
;
1211 fake_line
.Point2
= line
->Point2
;
1212 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
,
1213 rd
->styles
[NUM_STYLES
]);
1217 AddLine (layergroupboxes
, layergroup
, line
, line
,
1218 rd
->styles
[NUM_STYLES
]);
1222 /* add all polygons */
1223 POLYGON_LOOP (LAYER_PTR (i
));
1225 if (TEST_FLAG (DRCFLAG
, polygon
))
1226 CLEAR_FLAG (DRCFLAG
, polygon
);
1228 AddPolygon (layergroupboxes
, i
, polygon
, rd
->styles
[NUM_STYLES
]);
1231 /* add all copper text */
1232 TEXT_LOOP (LAYER_PTR (i
));
1234 AddText (layergroupboxes
, layergroup
, text
, rd
->styles
[NUM_STYLES
]);
1238 ARC_LOOP (LAYER_PTR (i
));
1240 AddArc (layergroupboxes
, layergroup
, arc
, rd
->styles
[NUM_STYLES
]);
1245 /* create r-trees from pointer lists */
1246 for (i
= 0; i
< max_group
; i
++)
1248 /* create the r-tree */
1249 rd
->layergrouptree
[i
] =
1250 r_create_tree ((const BoxType
**) layergroupboxes
[i
].Ptr
,
1251 layergroupboxes
[i
].PtrN
, 1);
1254 if (AutoRouteParameters
.use_vias
)
1256 rd
->mtspace
= mtspace_create ();
1258 /* create "empty-space" structures for via placement (now that we know
1259 * appropriate keepaways for all the fixed elements) */
1260 for (i
= 0; i
< max_group
; i
++)
1262 POINTER_LOOP (&layergroupboxes
[i
]);
1264 routebox_t
*rb
= (routebox_t
*) * ptr
;
1265 if (!rb
->flags
.clear_poly
)
1266 mtspace_add (rd
->mtspace
, &rb
->box
, FIXED
, rb
->style
->Keepaway
);
1271 /* free pointer lists */
1272 for (i
= 0; i
< max_group
; i
++)
1273 FreePointerListMemory (&layergroupboxes
[i
]);
1279 DestroyRouteData (routedata_t
** rd
)
1282 for (i
= 0; i
< max_group
; i
++)
1283 r_destroy_tree (&(*rd
)->layergrouptree
[i
]);
1284 if (AutoRouteParameters
.use_vias
)
1285 mtspace_destroy (&(*rd
)->mtspace
);
1290 /*-----------------------------------------------------------------
1291 * routebox reference counting.
1294 /* increment the reference count on a routebox. */
1296 RB_up_count (routebox_t
* rb
)
1298 assert (rb
->flags
.homeless
);
1302 /* decrement the reference count on a routebox, freeing if this box becomes
1305 RB_down_count (routebox_t
* rb
)
1307 assert (rb
->type
== EXPANSION_AREA
);
1308 assert (rb
->flags
.homeless
);
1309 assert (rb
->refcount
> 0);
1310 if (--rb
->refcount
== 0)
1312 if (rb
->parent
.expansion_area
->flags
.homeless
)
1313 RB_down_count (rb
->parent
.expansion_area
);
1318 /*-----------------------------------------------------------------
1319 * Rectangle-expansion routing code.
1323 ResetSubnet (routebox_t
* net
)
1326 /* reset connectivity of everything on this net */
1327 LIST_LOOP (net
, same_net
, rb
);
1328 rb
->same_subnet
= rb
->original_subnet
;
1332 static inline cost_t
1333 cost_to_point_on_layer (const CheapPointType
* p1
,
1334 const CheapPointType
* p2
, Cardinal point_layer
)
1336 cost_t x_dist
= p1
->X
- p2
->X
, y_dist
= p1
->Y
- p2
->Y
, r
;
1337 x_dist
*= x_cost
[point_layer
];
1338 y_dist
*= y_cost
[point_layer
];
1339 /* cost is proportional to orthogonal distance. */
1340 r
= ABS (x_dist
) + ABS (y_dist
);
1341 if (p1
->X
!= p2
->X
&& p1
->Y
!= p2
->Y
)
1342 r
+= AutoRouteParameters
.JogPenalty
;
1347 cost_to_point (const CheapPointType
* p1
, Cardinal point_layer1
,
1348 const CheapPointType
* p2
, Cardinal point_layer2
)
1350 cost_t r
= cost_to_point_on_layer (p1
, p2
, point_layer1
);
1351 /* apply via cost penalty if layers differ */
1352 if (point_layer1
!= point_layer2
)
1353 r
+= AutoRouteParameters
.ViaCost
;
1357 /* return the minimum *cost* from a point to a box on any layer.
1358 * It's safe to return a smaller than minimum cost
1361 cost_to_layerless_box (const CheapPointType
* p
, Cardinal point_layer
,
1364 CheapPointType p2
= closest_point_in_box (p
, b
);
1365 register cost_t c1
, c2
;
1373 return c1
* AutoRouteParameters
.MinPenalty
+ c2
;
1375 return c2
* AutoRouteParameters
.MinPenalty
+ c1
;
1378 /* get to actual pins/pad target coordinates */
1380 TargetPoint (CheapPointType
* nextpoint
, const routebox_t
* target
)
1382 if (target
->type
== PIN
)
1384 nextpoint
->X
= target
->parent
.pin
->X
;
1385 nextpoint
->Y
= target
->parent
.pin
->Y
;
1388 else if (target
->type
== PAD
)
1390 if (abs (target
->parent
.pad
->Point1
.X
- nextpoint
->X
) <
1391 abs (target
->parent
.pad
->Point2
.X
- nextpoint
->X
))
1392 nextpoint
->X
= target
->parent
.pad
->Point1
.X
;
1394 nextpoint
->X
= target
->parent
.pad
->Point2
.X
;
1395 if (abs (target
->parent
.pad
->Point1
.Y
- nextpoint
->Y
) <
1396 abs (target
->parent
.pad
->Point2
.Y
- nextpoint
->Y
))
1397 nextpoint
->Y
= target
->parent
.pad
->Point1
.Y
;
1399 nextpoint
->Y
= target
->parent
.pad
->Point2
.Y
;
1404 nextpoint
->X
= CENTER_X (target
->sbox
);
1405 nextpoint
->Y
= CENTER_Y (target
->sbox
);
1410 /* return the *minimum cost* from a point to a route box, including possible
1411 * via costs if the route box is on a different layer.
1412 * assume routbox is bloated unless it is an expansion area
1415 cost_to_routebox (const CheapPointType
* p
, Cardinal point_layer
,
1416 const routebox_t
* rb
)
1418 register cost_t trial
= 0;
1419 CheapPointType p2
= closest_point_in_routebox (p
, rb
);
1420 if (!usedGroup
[point_layer
] || !usedGroup
[rb
->group
])
1421 trial
= AutoRouteParameters
.NewLayerPenalty
;
1422 if ((p2
.X
- p
->X
) * (p2
.Y
- p
->Y
) != 0)
1423 trial
+= AutoRouteParameters
.JogPenalty
;
1424 /* special case for defered via searching */
1425 if (point_layer
> max_group
|| point_layer
== rb
->group
)
1426 return trial
+ ABS (p2
.X
- p
->X
) + ABS (p2
.Y
- p
->Y
);
1427 /* if this target is only a via away, then the via is cheaper than the congestion */
1428 if (p
->X
== p2
.X
&& p
->Y
== p2
.Y
)
1430 trial
+= AutoRouteParameters
.ViaCost
;
1431 trial
+= ABS (p2
.X
- p
->X
) + ABS (p2
.Y
- p
->Y
);
1437 bloat_routebox (routebox_t
* rb
)
1441 assert (__routebox_is_good (rb
));
1443 if (rb
->flags
.nobloat
)
1446 /* Obstacle exclusion zones get bloated by the larger of
1447 * the two required clearances plus half the track width.
1449 keepaway
= MAX (AutoRouteParameters
.style
->Keepaway
, rb
->style
->Keepaway
);
1450 r
= bloat_box (&rb
->sbox
, keepaway
+
1451 HALF_THICK (AutoRouteParameters
.style
->Thick
));
1456 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1458 /* makes a line on the solder layer silk surrounding the box */
1460 showbox (BoxType b
, Dimension thickness
, int group
)
1463 LayerType
*SLayer
= LAYER_PTR (group
);
1466 if (showboxen
!= -1 && showboxen
!= group
)
1471 ddraw
->graphics
->set_line_width (ar_gc
, thickness
);
1472 ddraw
->graphics
->set_line_cap (ar_gc
, Trace_Cap
);
1473 ddraw
->graphics
->set_color (ar_gc
, SLayer
->Color
);
1475 ddraw
->graphics
->draw_line (ar_gc
, b
.X1
, b
.Y1
, b
.X2
, b
.Y1
);
1476 ddraw
->graphics
->draw_line (ar_gc
, b
.X1
, b
.Y2
, b
.X2
, b
.Y2
);
1477 ddraw
->graphics
->draw_line (ar_gc
, b
.X1
, b
.Y1
, b
.X1
, b
.Y2
);
1478 ddraw
->graphics
->draw_line (ar_gc
, b
.X2
, b
.Y1
, b
.X2
, b
.Y2
);
1482 if (b
.Y1
== b
.Y2
|| b
.X1
== b
.X2
)
1484 line
= CreateNewLineOnLayer (LAYER_PTR (component_silk_layer
),
1485 b
.X1
, b
.Y1
, b
.X2
, b
.Y1
, thickness
, 0,
1487 AddObjectToCreateUndoList (LINE_TYPE
,
1488 LAYER_PTR (component_silk_layer
), line
,
1492 line
= CreateNewLineOnLayer (LAYER_PTR (component_silk_layer
),
1493 b
.X1
, b
.Y2
, b
.X2
, b
.Y2
, thickness
, 0,
1495 AddObjectToCreateUndoList (LINE_TYPE
,
1496 LAYER_PTR (component_silk_layer
),
1499 line
= CreateNewLineOnLayer (LAYER_PTR (component_silk_layer
),
1500 b
.X1
, b
.Y1
, b
.X1
, b
.Y2
, thickness
, 0,
1502 AddObjectToCreateUndoList (LINE_TYPE
,
1503 LAYER_PTR (component_silk_layer
), line
,
1507 line
= CreateNewLineOnLayer (LAYER_PTR (component_silk_layer
),
1508 b
.X2
, b
.Y1
, b
.X2
, b
.Y2
, thickness
, 0,
1510 AddObjectToCreateUndoList (LINE_TYPE
,
1511 LAYER_PTR (component_silk_layer
),
1518 #if defined(ROUTE_DEBUG)
1520 showedge (edge_t
* e
)
1522 BoxType
*b
= (BoxType
*) e
->rb
;
1527 ddraw
->graphics
->set_line_cap (ar_gc
, Trace_Cap
);
1528 ddraw
->graphics
->set_line_width (ar_gc
, 1);
1529 ddraw
->graphics
->set_color (ar_gc
, Settings
.MaskColor
);
1531 switch (e
->expand_dir
)
1534 ddraw
->graphics
->draw_line (ar_gc
, b
->X1
, b
->Y1
, b
->X2
, b
->Y1
);
1537 ddraw
->graphics
->draw_line (ar_gc
, b
->X1
, b
->Y2
, b
->X2
, b
->Y2
);
1540 ddraw
->graphics
->draw_line (ar_gc
, b
->X1
, b
->Y1
, b
->X1
, b
->Y2
);
1543 ddraw
->graphics
->draw_line (ar_gc
, b
->X2
, b
->Y1
, b
->X2
, b
->Y2
);
1551 #if defined(ROUTE_DEBUG)
1553 showroutebox (routebox_t
* rb
)
1555 showbox (rb
->sbox
, rb
->flags
.source
? 20 : (rb
->flags
.target
? 10 : 1),
1556 rb
->flags
.is_via
? component_silk_layer
: rb
->group
);
1560 /* return a "parent" of this edge which immediately precedes it in the route.*/
1562 route_parent (routebox_t
* rb
)
1564 while (rb
->flags
.homeless
&& !rb
->flags
.is_via
&& !rb
->flags
.is_thermal
)
1566 assert (rb
->type
== EXPANSION_AREA
);
1567 rb
= rb
->parent
.expansion_area
;
1574 path_conflicts (routebox_t
* rb
, routebox_t
* conflictor
, bool branch
)
1577 rb
->conflicts_with
= vector_duplicate (rb
->conflicts_with
);
1578 else if (!rb
->conflicts_with
)
1579 rb
->conflicts_with
= vector_create ();
1580 vector_append (rb
->conflicts_with
, conflictor
);
1581 return rb
->conflicts_with
;
1584 /* Touch everything (except fixed) on each net found
1585 * in the conflicts vector. If the vector is different
1586 * from the last one touched, untouch the last batch
1587 * and touch the new one. Always call with touch=1
1588 * (except for recursive call). Call with NULL, 1 to
1589 * clear the last batch touched.
1591 * touched items become invisible to current path
1592 * so we don't encounter the same conflictor more
1597 touch_conflicts (vector_t
* conflicts
, int touch
)
1599 static vector_t
*last
= NULL
;
1600 static int last_size
= 0;
1605 if (last
&& conflicts
!= last
)
1606 touch_conflicts (last
, 0);
1612 n
= vector_size (conflicts
);
1615 routebox_t
*rb
= (routebox_t
*) vector_element (conflicts
, i
);
1617 LIST_LOOP (rb
, same_net
, p
);
1618 if (!p
->flags
.fixed
)
1619 p
->flags
.touched
= touch
;
1631 /* return a "parent" of this edge which resides in a r-tree somewhere */
1632 /* -- actually, this "parent" *may* be a via box, which doesn't live in
1635 nonhomeless_parent (routebox_t
* rb
)
1637 return route_parent (rb
);
1640 /* some routines to find the minimum *cost* from a cost point to
1641 * a target (any target) */
1642 struct mincost_target_closure
1644 const CheapPointType
*CostPoint
;
1645 Cardinal CostPointLayer
;
1646 routebox_t
*nearest
;
1647 cost_t nearest_cost
;
1650 __region_within_guess (const BoxType
* region
, void *cl
)
1652 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1653 cost_t cost_to_region
;
1654 if (mtc
->nearest
== NULL
)
1657 cost_to_layerless_box (mtc
->CostPoint
, mtc
->CostPointLayer
, region
);
1658 assert (cost_to_region
>= 0);
1659 /* if no guess yet, all regions are "close enough" */
1660 /* note that cost is *strictly more* than minimum distance, so we'll
1661 * always search a region large enough. */
1662 return (cost_to_region
< mtc
->nearest_cost
);
1665 __found_new_guess (const BoxType
* box
, void *cl
)
1667 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1668 routebox_t
*guess
= (routebox_t
*) box
;
1669 cost_t cost_to_guess
=
1670 cost_to_routebox (mtc
->CostPoint
, mtc
->CostPointLayer
, guess
);
1671 assert (cost_to_guess
>= 0);
1672 /* if this is cheaper than previous guess... */
1673 if (cost_to_guess
< mtc
->nearest_cost
)
1675 mtc
->nearest
= guess
;
1676 mtc
->nearest_cost
= cost_to_guess
; /* this is our new guess! */
1680 return 0; /* not less expensive than our last guess */
1683 /* target_guess is our guess at what the nearest target is, or NULL if we
1684 * just plum don't have a clue. */
1686 mincost_target_to_point (const CheapPointType
* CostPoint
,
1687 Cardinal CostPointLayer
,
1688 rtree_t
* targets
, routebox_t
* target_guess
)
1690 struct mincost_target_closure mtc
;
1691 assert (target_guess
== NULL
|| target_guess
->flags
.target
); /* this is a target, right? */
1692 mtc
.CostPoint
= CostPoint
;
1693 mtc
.CostPointLayer
= CostPointLayer
;
1694 mtc
.nearest
= target_guess
;
1697 cost_to_routebox (mtc
.CostPoint
, mtc
.CostPointLayer
, mtc
.nearest
);
1699 mtc
.nearest_cost
= EXPENSIVE
;
1700 r_search (targets
, NULL
, __region_within_guess
, __found_new_guess
, &mtc
);
1701 assert (mtc
.nearest
!= NULL
&& mtc
.nearest_cost
>= 0);
1702 assert (mtc
.nearest
->flags
.target
); /* this is a target, right? */
1706 /* create edge from field values */
1707 /* mincost_target_guess can be NULL */
1709 CreateEdge (routebox_t
* rb
,
1710 Coord CostPointX
, Coord CostPointY
,
1711 cost_t cost_to_point
,
1712 routebox_t
* mincost_target_guess
,
1713 direction_t expand_dir
, rtree_t
* targets
)
1716 assert (__routebox_is_good (rb
));
1717 e
= (edge_t
*)malloc (sizeof (*e
));
1718 memset ((void *) e
, 0, sizeof (*e
));
1721 if (rb
->flags
.homeless
)
1723 e
->cost_point
.X
= CostPointX
;
1724 e
->cost_point
.Y
= CostPointY
;
1725 e
->cost_to_point
= cost_to_point
;
1726 e
->flags
.via_search
= 0;
1727 /* if this edge is created in response to a target, use it */
1730 mincost_target_to_point (&e
->cost_point
, rb
->group
,
1731 targets
, mincost_target_guess
);
1733 e
->mincost_target
= mincost_target_guess
;
1734 e
->expand_dir
= expand_dir
;
1735 assert (e
->rb
&& e
->mincost_target
); /* valid edge? */
1736 assert (!e
->flags
.is_via
|| e
->expand_dir
== ALL
);
1737 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1739 assert (rb
->type
== PLANE
|| rb
->conflicts_with
!= NULL
|| rb
->flags
.is_via
1740 || rb
->flags
.is_thermal
1741 || ((expand_dir
== NORTH
|| expand_dir
== SOUTH
) ? rb
->sbox
.X1
<=
1742 CostPointX
&& CostPointX
< rb
->sbox
.X2
1743 && CostPointY
== (expand_dir
==
1744 NORTH
? rb
->sbox
.Y1
: rb
->sbox
.Y2
- 1) :
1745 /* expand_dir==EAST || expand_dir==WEST */
1746 rb
->sbox
.Y1
<= CostPointY
&& CostPointY
< rb
->sbox
.Y2
&&
1747 CostPointX
== (expand_dir
==
1748 EAST
? rb
->sbox
.X2
- 1 : rb
->sbox
.X1
)));
1750 assert (__edge_is_good (e
));
1755 /* create edge, using previous edge to fill in defaults. */
1756 /* most of the work here is in determining a new cost point */
1758 CreateEdge2 (routebox_t
* rb
, direction_t expand_dir
,
1759 edge_t
* previous_edge
, rtree_t
* targets
, routebox_t
* guess
)
1762 CheapPointType thiscost
, prevcost
;
1765 assert (rb
&& previous_edge
);
1766 /* okay, find cheapest costpoint to costpoint of previous edge */
1767 thisbox
= edge_to_box (rb
, expand_dir
);
1768 prevcost
= previous_edge
->cost_point
;
1769 /* find point closest to target */
1770 thiscost
= closest_point_in_box (&prevcost
, &thisbox
);
1771 /* compute cost-to-point */
1772 d
= cost_to_point_on_layer (&prevcost
, &thiscost
, rb
->group
);
1773 /* add in jog penalty */
1774 if (previous_edge
->expand_dir
!= expand_dir
)
1775 d
+= AutoRouteParameters
.JogPenalty
;
1776 /* okay, new edge! */
1777 return CreateEdge (rb
, thiscost
.X
, thiscost
.Y
,
1778 previous_edge
->cost_to_point
+ d
,
1779 guess
? guess
: previous_edge
->mincost_target
,
1780 expand_dir
, targets
);
1783 /* create via edge, using previous edge to fill in defaults. */
1785 CreateViaEdge (const BoxType
* area
, Cardinal group
,
1786 routebox_t
* parent
, edge_t
* previous_edge
,
1787 conflict_t to_site_conflict
,
1788 conflict_t through_site_conflict
, rtree_t
* targets
)
1791 CheapPointType costpoint
;
1797 scale
[1] = AutoRouteParameters
.LastConflictPenalty
;
1798 scale
[2] = AutoRouteParameters
.ConflictPenalty
;
1800 assert (box_is_good (area
));
1801 assert (AutoRouteParameters
.with_conflicts
||
1802 (to_site_conflict
== NO_CONFLICT
&&
1803 through_site_conflict
== NO_CONFLICT
));
1804 rb
= CreateExpansionArea (area
, group
, parent
, true, previous_edge
);
1805 rb
->flags
.is_via
= 1;
1806 rb
->came_from
= ALL
;
1807 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1809 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1810 /* for planes, choose a point near the target */
1811 if (previous_edge
->flags
.in_plane
)
1815 /* find a target near this via box */
1816 pnt
.X
= CENTER_X (*area
);
1817 pnt
.Y
= CENTER_Y (*area
);
1818 target
= mincost_target_to_point (&pnt
, rb
->group
,
1820 previous_edge
->mincost_target
);
1821 /* now find point near the target */
1822 pnt
.X
= CENTER_X (target
->box
);
1823 pnt
.Y
= CENTER_Y (target
->box
);
1824 costpoint
= closest_point_in_routebox (&pnt
, rb
);
1825 /* we moved from the previous cost point through the plane which is free travel */
1827 (scale
[through_site_conflict
] *
1828 cost_to_point (&costpoint
, group
, &costpoint
,
1829 previous_edge
->rb
->group
));
1831 CreateEdge (rb
, costpoint
.X
, costpoint
.Y
,
1832 previous_edge
->cost_to_point
+ d
, target
, ALL
, NULL
);
1833 ne
->mincost_target
= target
;
1838 target
= previous_edge
->mincost_target
;
1839 costpoint
= closest_point_in_routebox (&previous_edge
->cost_point
, rb
);
1841 (scale
[to_site_conflict
] *
1842 cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1843 previous_edge
->rb
->group
)) +
1844 (scale
[through_site_conflict
] *
1845 cost_to_point (&costpoint
, group
, &costpoint
,
1846 previous_edge
->rb
->group
));
1847 /* if the target is just this via away, then this via is cheaper */
1848 if (target
->group
== group
&&
1849 point_in_shrunk_box (target
, costpoint
.X
, costpoint
.Y
))
1850 d
-= AutoRouteParameters
.ViaCost
/ 2;
1852 CreateEdge (rb
, costpoint
.X
, costpoint
.Y
,
1853 previous_edge
->cost_to_point
+ d
,
1854 previous_edge
->mincost_target
, ALL
, targets
);
1856 ne
->flags
.is_via
= 1;
1857 ne
->flags
.via_conflict_level
= to_site_conflict
;
1858 assert (__edge_is_good (ne
));
1862 /* create "interior" edge for routing with conflicts */
1863 /* Presently once we "jump inside" the conflicting object
1864 * we consider it a routing highway to travel inside since
1865 * it will become available if the conflict is elliminated.
1866 * That is why we ignore the interior_edge argument.
1869 CreateEdgeWithConflicts (const BoxType
* interior_edge
,
1870 routebox_t
* container
, edge_t
* previous_edge
,
1871 cost_t cost_penalty_to_box
, rtree_t
* targets
)
1874 CheapPointType costpoint
;
1877 assert (interior_edge
&& container
&& previous_edge
&& targets
);
1878 assert (!container
->flags
.homeless
);
1879 assert (AutoRouteParameters
.with_conflicts
);
1880 assert (container
->flags
.touched
== 0);
1881 assert (previous_edge
->rb
->group
== container
->group
);
1882 /* use the caller's idea of what this box should be */
1884 CreateExpansionArea (interior_edge
, previous_edge
->rb
->group
,
1885 previous_edge
->rb
, true, previous_edge
);
1886 path_conflicts (rb
, container
, true); /* crucial! */
1888 closest_point_in_box (&previous_edge
->cost_point
, interior_edge
);
1890 cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1891 previous_edge
->rb
->group
);
1892 d
*= cost_penalty_to_box
;
1893 d
+= previous_edge
->cost_to_point
;
1894 ne
= CreateEdge (rb
, costpoint
.X
, costpoint
.Y
, d
, NULL
, ALL
, targets
);
1895 ne
->flags
.is_interior
= 1;
1896 assert (__edge_is_good (ne
));
1901 KillEdge (void *edge
)
1903 edge_t
*e
= (edge_t
*) edge
;
1905 if (e
->rb
->flags
.homeless
)
1906 RB_down_count (e
->rb
);
1907 if (e
->flags
.via_search
)
1908 mtsFreeWork (&e
->work
);
1913 DestroyEdge (edge_t
** e
)
1920 /* cost function for an edge. */
1922 edge_cost (const edge_t
* e
, const cost_t too_big
)
1924 cost_t penalty
= e
->cost_to_point
;
1925 if (e
->rb
->flags
.is_thermal
|| e
->rb
->type
== PLANE
)
1926 return penalty
; /* thermals are cheap */
1927 if (penalty
> too_big
)
1930 /* cost_to_routebox adds in our via correction, too. */
1932 cost_to_routebox (&e
->cost_point
, e
->rb
->group
, e
->mincost_target
);
1935 /* given an edge of a box, return a box containing exactly the points on that
1936 * edge. Note that the return box is treated as closed; that is, the bottom and
1937 * right "edges" consist of points (just barely) not in the (half-open) box. */
1939 edge_to_box (const routebox_t
* rb
, direction_t expand_dir
)
1941 BoxType b
= shrink_routebox (rb
);
1942 /* narrow box down to just the appropriate edge */
1966 BoxType left
, center
, right
;
1967 bool is_valid_left
, is_valid_center
, is_valid_right
;
1970 static struct broken_boxes
1971 break_box_edge (const BoxType
* original
, direction_t which_edge
,
1972 routebox_t
* breaker
)
1974 BoxType origbox
, breakbox
;
1975 struct broken_boxes result
;
1977 assert (original
&& breaker
);
1979 origbox
= *original
;
1980 breakbox
= bloat_routebox (breaker
);
1981 ROTATEBOX_TO_NORTH (origbox
, which_edge
);
1982 ROTATEBOX_TO_NORTH (breakbox
, which_edge
);
1983 result
.right
.Y1
= result
.center
.Y1
= result
.left
.Y1
= origbox
.Y1
;
1984 result
.right
.Y2
= result
.center
.Y2
= result
.left
.Y2
= origbox
.Y1
+ 1;
1985 /* validity of breaker is not important because the boxes are marked invalid */
1986 //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1);
1987 /* left edge piece */
1988 result
.left
.X1
= origbox
.X1
;
1989 result
.left
.X2
= breakbox
.X1
;
1990 /* center (ie blocked) edge piece */
1991 result
.center
.X1
= MAX (breakbox
.X1
, origbox
.X1
);
1992 result
.center
.X2
= MIN (breakbox
.X2
, origbox
.X2
);
1993 /* right edge piece */
1994 result
.right
.X1
= breakbox
.X2
;
1995 result
.right
.X2
= origbox
.X2
;
1997 result
.is_valid_left
= (result
.left
.X1
< result
.left
.X2
);
1998 result
.is_valid_center
= (result
.center
.X1
< result
.center
.X2
);
1999 result
.is_valid_right
= (result
.right
.X1
< result
.right
.X2
);
2001 ROTATEBOX_FROM_NORTH (result
.left
, which_edge
);
2002 ROTATEBOX_FROM_NORTH (result
.center
, which_edge
);
2003 ROTATEBOX_FROM_NORTH (result
.right
, which_edge
);
2010 share_edge (const BoxType
* child
, const BoxType
* parent
)
2013 (child
->X1
== parent
->X2
|| child
->X2
== parent
->X1
||
2014 child
->Y1
== parent
->Y2
|| child
->Y2
== parent
->Y1
) &&
2015 ((parent
->X1
<= child
->X1
&& child
->X2
<= parent
->X2
) ||
2016 (parent
->Y1
<= child
->Y1
&& child
->Y2
<= parent
->Y2
));
2019 edge_intersect (const BoxType
* child
, const BoxType
* parent
)
2022 (child
->X1
<= parent
->X2
) && (child
->X2
>= parent
->X1
) &&
2023 (child
->Y1
<= parent
->Y2
) && (child
->Y2
>= parent
->Y1
);
2027 /* area is the expansion area, on layer group 'group'. 'parent' is the
2028 * immediately preceding expansion area, for backtracing. 'lastarea' is
2029 * the last expansion area created, we string these together in a loop
2030 * so we can remove them all easily at the end. */
2032 CreateExpansionArea (const BoxType
* area
, Cardinal group
,
2033 routebox_t
* parent
,
2034 bool relax_edge_requirements
, edge_t
* src_edge
)
2036 routebox_t
*rb
= (routebox_t
*) malloc (sizeof (*rb
));
2037 memset ((void *) rb
, 0, sizeof (*rb
));
2038 assert (area
&& parent
);
2039 init_const_box (rb
, area
->X1
, area
->Y1
, area
->X2
, area
->Y2
, 0);
2041 rb
->type
= EXPANSION_AREA
;
2042 /* should always share edge or overlap with parent */
2043 assert (relax_edge_requirements
? box_intersect (&rb
->sbox
, &parent
->sbox
)
2044 : share_edge (&rb
->sbox
, &parent
->sbox
));
2045 rb
->parent
.expansion_area
= route_parent (parent
);
2047 closest_point_in_box (&rb
->parent
.expansion_area
->cost_point
, area
);
2049 rb
->parent
.expansion_area
->cost
+
2050 cost_to_point_on_layer (&rb
->parent
.expansion_area
->cost_point
,
2051 &rb
->cost_point
, rb
->group
);
2052 assert (relax_edge_requirements
? edge_intersect (&rb
->sbox
, &parent
->sbox
)
2053 : share_edge (&rb
->sbox
, &parent
->sbox
));
2054 if (rb
->parent
.expansion_area
->flags
.homeless
)
2055 RB_up_count (rb
->parent
.expansion_area
);
2056 rb
->flags
.homeless
= 1;
2057 rb
->flags
.nobloat
= 1;
2058 rb
->style
= AutoRouteParameters
.style
;
2059 rb
->conflicts_with
= parent
->conflicts_with
;
2060 /* we will never link an EXPANSION_AREA into the nets because they
2061 * are *ONLY* used for path searching. No need to call InitLists ()
2063 rb
->came_from
= src_edge
->expand_dir
;
2064 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
2066 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
2070 /*------ Expand ------*/
2074 routebox_t
*n
, *e
, *s
, *w
;
2076 BoxType inflated
, orig
;
2080 /* test method for Expand()
2081 * this routebox potentially is a blocker limiting expansion
2082 * if this is so, we limit the inflate box so another exactly
2083 * like it wouldn't be seen. We do this while keep the inflated
2084 * box as large as possible.
2087 __Expand_this_rect (const BoxType
* box
, void *cl
)
2089 struct E_result
*res
= (struct E_result
*) cl
;
2090 routebox_t
*rb
= (routebox_t
*) box
;
2092 Coord dn
, de
, ds
, dw
, bloat
;
2094 /* we don't see conflicts already encountered */
2095 if (rb
->flags
.touched
)
2098 /* The inflated box outer edges include its own
2099 * track width plus its own keepaway.
2101 * To check for intersection, we need to expand
2102 * anything with greater keepaway by its excess
2105 * If something has nobloat then we need to shrink
2106 * the inflated box back and see if it still touches.
2109 if (rb
->flags
.nobloat
)
2113 if (rbox
.X2
<= res
->inflated
.X1
+ bloat
||
2114 rbox
.X1
>= res
->inflated
.X2
- bloat
||
2115 rbox
.Y1
>= res
->inflated
.Y2
- bloat
||
2116 rbox
.Y2
<= res
->inflated
.Y1
+ bloat
)
2117 return 0; /* doesn't touch */
2121 if (rb
->style
->Keepaway
> res
->keep
)
2122 rbox
= bloat_box (&rb
->sbox
, rb
->style
->Keepaway
- res
->keep
);
2126 if (rbox
.X2
<= res
->inflated
.X1
|| rbox
.X1
>= res
->inflated
.X2
2127 || rbox
.Y1
>= res
->inflated
.Y2
|| rbox
.Y2
<= res
->inflated
.Y1
)
2128 return 0; /* doesn't touch */
2132 /* this is an intersecting box; it has to jump through a few more hoops */
2133 if (rb
== res
->parent
|| rb
->parent
.expansion_area
== res
->parent
)
2134 return 0; /* don't see what we came from */
2136 /* if we are expanding a source edge, don't let other sources
2137 * or their expansions stop us.
2140 if (res
->parent
->flags
.source
)
2141 if (rb
->flags
.source
2142 || (rb
->type
== EXPANSION_AREA
2143 && rb
->parent
.expansion_area
->flags
.source
))
2147 /* we ignore via expansion boxes because maybe its
2148 * cheaper to get there without the via through
2149 * the path we're exploring now.
2151 if (rb
->flags
.is_via
&& rb
->type
== EXPANSION_AREA
)
2154 if (rb
->type
== PLANE
) /* expanding inside a plane is not good */
2156 if (rbox
.X1
< res
->orig
.X1
&& rbox
.X2
> res
->orig
.X2
&&
2157 rbox
.Y1
< res
->orig
.Y1
&& rbox
.Y2
> res
->orig
.Y2
)
2159 res
->inflated
= bloat_box (&res
->orig
, res
->bloat
);
2163 /* calculate the distances from original box to this blocker */
2164 dn
= de
= ds
= dw
= 0;
2165 if (!(res
->done
& _NORTH
) && rbox
.Y1
<= res
->orig
.Y1
2166 && rbox
.Y2
> res
->inflated
.Y1
)
2167 dn
= res
->orig
.Y1
- rbox
.Y2
;
2168 if (!(res
->done
& _EAST
) && rbox
.X2
>= res
->orig
.X2
2169 && rbox
.X1
< res
->inflated
.X2
)
2170 de
= rbox
.X1
- res
->orig
.X2
;
2171 if (!(res
->done
& _SOUTH
) && rbox
.Y2
>= res
->orig
.Y2
2172 && rbox
.Y1
< res
->inflated
.Y2
)
2173 ds
= rbox
.Y1
- res
->orig
.Y2
;
2174 if (!(res
->done
& _WEST
) && rbox
.X1
<= res
->orig
.X1
2175 && rbox
.X2
> res
->inflated
.X1
)
2176 dw
= res
->orig
.X1
- rbox
.X2
;
2177 if (dn
<= 0 && de
<= 0 && ds
<= 0 && dw
<= 0)
2179 /* now shrink the inflated box to the largest blocking direction */
2180 if (dn
>= de
&& dn
>= ds
&& dn
>= dw
)
2182 res
->inflated
.Y1
= rbox
.Y2
- bloat
;
2185 else if (de
>= ds
&& de
>= dw
)
2187 res
->inflated
.X2
= rbox
.X1
+ bloat
;
2192 res
->inflated
.Y2
= rbox
.Y1
+ bloat
;
2197 res
->inflated
.X1
= rbox
.X2
- bloat
;
2204 boink_box (routebox_t
* rb
, struct E_result
*res
, direction_t dir
)
2207 if (rb
->style
->Keepaway
> res
->keep
)
2208 bloat
= res
->keep
- rb
->style
->Keepaway
;
2211 if (rb
->flags
.nobloat
)
2217 if (rb
->sbox
.X2
<= res
->inflated
.X1
+ bloat
2218 || rb
->sbox
.X1
>= res
->inflated
.X2
- bloat
)
2223 if (rb
->sbox
.Y1
>= res
->inflated
.Y2
- bloat
2224 || rb
->sbox
.Y2
<= res
->inflated
.Y1
+ bloat
)
2234 /* main Expand routine.
2236 * The expansion probe edge includes the keepaway and half thickness
2237 * as the search is performed in order to see everything relevant.
2238 * The result is backed off by this amount before being returned.
2239 * Targets (and other no-bloat routeboxes) go all the way to touching.
2240 * This is accomplished by backing off the probe edge when checking
2241 * for touch against such an object. Usually the expanding edge
2242 * bumps into neighboring pins on the same device that require a
2243 * keepaway, preventing seeing a target immediately. Rather than await
2244 * another expansion to actually touch the target, the edge breaker code
2245 * looks past the keepaway to see these targets even though they
2246 * weren't actually touched in the expansion.
2249 Expand (rtree_t
* rtree
, edge_t
* e
, const BoxType
* box
)
2251 static struct E_result ans
;
2252 int noshrink
; /* bit field of which edges to not shrink */
2254 ans
.bloat
= AutoRouteParameters
.bloat
;
2256 ans
.n
= ans
.e
= ans
.s
= ans
.w
= NULL
;
2258 /* the inflated box must be bloated in all directions that it might
2259 * hit something in order to guarantee that we see object in the
2260 * tree it might hit. The tree holds objects bloated by their own
2261 * keepaway so we are guaranteed to honor that.
2263 switch (e
->expand_dir
)
2266 ans
.inflated
.X1
= (e
->rb
->came_from
== EAST
? ans
.orig
.X1
: 0);
2267 ans
.inflated
.Y1
= (e
->rb
->came_from
== SOUTH
? ans
.orig
.Y1
: 0);
2269 (e
->rb
->came_from
== WEST
? ans
.orig
.X2
: PCB
->MaxWidth
);
2271 (e
->rb
->came_from
== NORTH
? ans
.orig
.Y2
: PCB
->MaxHeight
);
2272 if (e
->rb
->came_from
== NORTH
)
2273 ans
.done
= noshrink
= _SOUTH
;
2274 else if (e
->rb
->came_from
== EAST
)
2275 ans
.done
= noshrink
= _WEST
;
2276 else if (e
->rb
->came_from
== SOUTH
)
2277 ans
.done
= noshrink
= _NORTH
;
2278 else if (e
->rb
->came_from
== WEST
)
2279 ans
.done
= noshrink
= _EAST
;
2281 ans
.done
= noshrink
= 0;
2284 ans
.done
= _SOUTH
+ _EAST
+ _WEST
;
2286 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2287 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2288 ans
.inflated
.Y2
= box
->Y2
;
2289 ans
.inflated
.Y1
= 0; /* far north */
2292 ans
.done
= _SOUTH
+ _WEST
;
2294 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2295 ans
.inflated
.X2
= PCB
->MaxWidth
;
2296 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2297 ans
.inflated
.Y1
= 0;
2300 ans
.done
= _NORTH
+ _SOUTH
+ _WEST
;
2302 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2303 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2304 ans
.inflated
.X1
= box
->X1
;
2305 ans
.inflated
.X2
= PCB
->MaxWidth
;
2308 ans
.done
= _NORTH
+ _WEST
;
2310 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2311 ans
.inflated
.X2
= PCB
->MaxWidth
;
2312 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2313 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2316 ans
.done
= _NORTH
+ _EAST
+ _WEST
;
2318 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2319 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2320 ans
.inflated
.Y1
= box
->Y1
;
2321 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2324 ans
.done
= _NORTH
+ _EAST
;
2326 ans
.inflated
.X1
= 0;
2327 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2328 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2329 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2332 ans
.done
= _NORTH
+ _SOUTH
+ _EAST
;
2334 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2335 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2336 ans
.inflated
.X1
= 0;
2337 ans
.inflated
.X2
= box
->X2
;
2340 ans
.done
= _SOUTH
+ _EAST
;
2342 ans
.inflated
.X1
= 0;
2343 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2344 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2345 ans
.inflated
.Y1
= 0;
2348 noshrink
= ans
.done
= 0;
2351 ans
.keep
= e
->rb
->style
->Keepaway
;
2352 ans
.parent
= nonhomeless_parent (e
->rb
);
2353 r_search (rtree
, &ans
.inflated
, NULL
, __Expand_this_rect
, &ans
);
2354 /* because the overlaping boxes are found in random order, some blockers
2355 * may have limited edges prematurely, so we check if the blockers realy
2356 * are blocking, and make another try if not
2358 if (ans
.n
&& !boink_box (ans
.n
, &ans
, NORTH
))
2359 ans
.inflated
.Y1
= 0;
2362 if (ans
.e
&& !boink_box (ans
.e
, &ans
, EAST
))
2363 ans
.inflated
.X2
= PCB
->MaxWidth
;
2366 if (ans
.s
&& !boink_box (ans
.s
, &ans
, SOUTH
))
2367 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2370 if (ans
.w
&& !boink_box (ans
.w
, &ans
, WEST
))
2371 ans
.inflated
.X1
= 0;
2374 if (ans
.done
!= _NORTH
+ _EAST
+ _SOUTH
+ _WEST
)
2376 r_search (rtree
, &ans
.inflated
, NULL
, __Expand_this_rect
, &ans
);
2378 if ((noshrink
& _NORTH
) == 0)
2379 ans
.inflated
.Y1
+= ans
.bloat
;
2380 if ((noshrink
& _EAST
) == 0)
2381 ans
.inflated
.X2
-= ans
.bloat
;
2382 if ((noshrink
& _SOUTH
) == 0)
2383 ans
.inflated
.Y2
-= ans
.bloat
;
2384 if ((noshrink
& _WEST
) == 0)
2385 ans
.inflated
.X1
+= ans
.bloat
;
2389 /* blocker_to_heap puts the blockers into a heap so they
2390 * can be retrieved in clockwise order. If a blocker
2391 * is also a target, it gets put into the vector too.
2392 * It returns 1 for any fixed blocker that is not part
2393 * of this net and zero otherwise.
2396 blocker_to_heap (heap_t
* heap
, routebox_t
* rb
,
2397 BoxType
* box
, direction_t dir
)
2399 BoxType b
= rb
->sbox
;
2400 if (rb
->style
->Keepaway
> AutoRouteParameters
.style
->Keepaway
)
2403 rb
->style
->Keepaway
- AutoRouteParameters
.style
->Keepaway
);
2404 b
= clip_box (&b
, box
);
2405 assert (box_is_good (&b
));
2406 /* we want to look at the blockers clockwise around the box */
2409 /* we need to use the other coordinate fraction to resolve
2410 * ties since we want the shorter of the furthest
2414 heap_insert (heap
, b
.X1
- b
.X1
/ (b
.X2
+ 1.0), rb
);
2417 heap_insert (heap
, b
.Y1
- b
.Y1
/ (b
.Y2
+ 1.0), rb
);
2420 heap_insert (heap
, -(b
.X2
+ b
.X1
/ (b
.X2
+ 1.0)), rb
);
2423 heap_insert (heap
, -(b
.Y2
+ b
.Y1
/ (b
.Y2
+ 1.0)), rb
);
2428 if (rb
->flags
.fixed
&& !rb
->flags
.target
&& !rb
->flags
.source
)
2433 /* this creates an EXPANSION_AREA to bridge small gaps or,
2434 * (more commonly) create a supper-thin box to provide a
2435 * home for an expansion edge.
2438 CreateBridge (const BoxType
* area
, routebox_t
* parent
, direction_t dir
)
2440 routebox_t
*rb
= (routebox_t
*) malloc (sizeof (*rb
));
2441 memset ((void *) rb
, 0, sizeof (*rb
));
2442 assert (area
&& parent
);
2443 init_const_box (rb
, area
->X1
, area
->Y1
, area
->X2
, area
->Y2
, 0);
2444 rb
->group
= parent
->group
;
2445 rb
->type
= EXPANSION_AREA
;
2446 rb
->came_from
= dir
;
2447 rb
->cost_point
= closest_point_in_box (&parent
->cost_point
, area
);
2448 rb
->cost
= parent
->cost
+ cost_to_point_on_layer (&parent
->cost_point
,
2451 rb
->parent
.expansion_area
= route_parent (parent
);
2452 if (rb
->parent
.expansion_area
->flags
.homeless
)
2453 RB_up_count (rb
->parent
.expansion_area
);
2454 rb
->flags
.homeless
= 1;
2455 rb
->flags
.nobloat
= 1;
2456 rb
->style
= parent
->style
;
2457 rb
->conflicts_with
= parent
->conflicts_with
;
2458 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES)
2464 /* moveable_edge prepares the new search edges based on the
2465 * starting box, direction and blocker if any.
2468 moveable_edge (vector_t
* result
, const BoxType
* box
, direction_t dir
,
2470 routebox_t
* blocker
, edge_t
* e
, rtree_t
* targets
,
2471 struct routeone_state
*s
, rtree_t
* tree
, vector_t
* area_vec
)
2474 assert (box_is_good (box
));
2476 /* for the cardinal directions, move the box to overlap the
2477 * the parent by 1 unit. Corner expansions overlap more
2478 * and their starting boxes are pre-prepared.
2479 * Check if anything is headed off the board edges
2488 if (b
.Y1
<= AutoRouteParameters
.bloat
)
2489 return; /* off board edge */
2494 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
)
2495 return; /* off board edge */
2500 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
)
2501 return; /* off board edge */
2506 if (b
.X1
<= AutoRouteParameters
.bloat
)
2507 return; /* off board edge */
2510 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1
2511 && b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2512 return; /* off board edge */
2513 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1)
2514 dir
= EAST
; /* north off board edge */
2515 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2516 dir
= NORTH
; /* east off board edge */
2519 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1
2520 && b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2521 return; /* off board edge */
2522 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1)
2523 dir
= EAST
; /* south off board edge */
2524 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2525 dir
= SOUTH
; /* east off board edge */
2528 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1
2529 && b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2530 return; /* off board edge */
2531 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1)
2532 dir
= WEST
; /* south off board edge */
2533 if (b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2534 dir
= SOUTH
; /* west off board edge */
2537 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1
2538 && b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2539 return; /* off board edge */
2540 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1)
2541 dir
= WEST
; /* north off board edge */
2542 if (b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2543 dir
= NORTH
; /* west off board edge */
2550 routebox_t
*nrb
= CreateBridge (&b
, rb
, dir
);
2551 /* move the cost point in corner expansions
2552 * these boxes are bigger, so move close to the target
2554 if (dir
== NE
|| dir
== SE
|| dir
== SW
|| dir
== NW
)
2558 closest_point_in_box (&nrb
->cost_point
, &e
->mincost_target
->sbox
);
2559 p
= closest_point_in_box (&p
, &b
);
2560 nrb
->cost
+= cost_to_point_on_layer (&p
, &nrb
->cost_point
,
2562 nrb
->cost_point
= p
;
2564 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
,
2565 nrb
->cost
, NULL
, dir
, targets
);
2566 vector_append (result
, ne
);
2568 else if (AutoRouteParameters
.with_conflicts
&& !blocker
->flags
.target
2569 && !blocker
->flags
.fixed
&& !blocker
->flags
.touched
&&
2570 !blocker
->flags
.source
&& blocker
->type
!= EXPANSION_AREA
)
2574 /* make a bridge to the edge of the blocker
2575 * in all directions from there
2580 b
.Y1
= blocker
->sbox
.Y2
- 1;
2583 b
.X2
= blocker
->sbox
.X1
+ 1;
2586 b
.Y2
= blocker
->sbox
.Y1
+ 1;
2589 b
.X1
= blocker
->sbox
.X2
- 1;
2594 if (!box_is_good (&b
))
2595 return; /* how did this happen ? */
2596 nrb
= CreateBridge (&b
, rb
, dir
);
2597 r_insert_entry (tree
, &nrb
->box
, 1);
2598 vector_append (area_vec
, nrb
);
2599 nrb
->flags
.homeless
= 0; /* not homeless any more */
2600 /* mark this one as conflicted */
2601 path_conflicts (nrb
, blocker
, true);
2602 /* and make an expansion edge */
2604 closest_point_in_box (&nrb
->cost_point
, &blocker
->sbox
);
2606 cost_to_point_on_layer (&nrb
->parent
.expansion_area
->cost_point
,
2608 nrb
->group
) * CONFLICT_PENALTY (blocker
);
2610 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
, nrb
->cost
,
2611 NULL
, ALL
, targets
);
2612 ne
->flags
.is_interior
= 1;
2613 vector_append (result
, ne
);
2616 else if (blocker
->type
== EXPANSION_AREA
)
2618 if (blocker
->cost
< rb
->cost
|| blocker
->cost
<= rb
->cost
+
2619 cost_to_point_on_layer (&blocker
->cost_point
, &rb
->cost_point
,
2622 if (blocker
->conflicts_with
|| rb
->conflicts_with
)
2624 /* does the blocker overlap this routebox ?? */
2625 /* does this re-parenting operation leave a memory leak? */
2626 if (blocker
->parent
.expansion_area
->flags
.homeless
)
2627 RB_down_count (blocker
->parent
.expansion_area
);
2628 blocker
->parent
.expansion_area
= rb
;
2632 else if (blocker
->flags
.target
)
2636 b
= bloat_box (&b
, 1);
2637 if (!box_intersect (&b
, &blocker
->sbox
))
2639 /* if the expansion edge stopped before touching, expand the bridge */
2643 b
.Y1
-= AutoRouteParameters
.bloat
+ 1;
2646 b
.X2
+= AutoRouteParameters
.bloat
+ 1;
2649 b
.Y2
+= AutoRouteParameters
.bloat
+ 1;
2652 b
.X1
-= AutoRouteParameters
.bloat
+ 1;
2658 assert (box_intersect (&b
, &blocker
->sbox
));
2659 b
= shrink_box (&b
, 1);
2660 nrb
= CreateBridge (&b
, rb
, dir
);
2661 r_insert_entry (tree
, &nrb
->box
, 1);
2662 vector_append (area_vec
, nrb
);
2663 nrb
->flags
.homeless
= 0; /* not homeless any more */
2664 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
,
2665 nrb
->cost
, blocker
, dir
, NULL
);
2666 best_path_candidate (s
, ne
, blocker
);
2681 __GatherBlockers (const BoxType
* box
, void *cl
)
2683 routebox_t
*rb
= (routebox_t
*) box
;
2684 struct break_info
*bi
= (struct break_info
*) cl
;
2687 if (bi
->parent
== rb
|| rb
->flags
.touched
||
2688 bi
->parent
->parent
.expansion_area
== rb
)
2690 if (rb
->flags
.source
&& bi
->ignore_source
)
2693 if (rb
->style
->Keepaway
> AutoRouteParameters
.style
->Keepaway
)
2696 rb
->style
->Keepaway
- AutoRouteParameters
.style
->Keepaway
);
2697 if (b
.X2
<= bi
->box
.X1
|| b
.X1
>= bi
->box
.X2
2698 || b
.Y1
>= bi
->box
.Y2
|| b
.Y2
<= bi
->box
.Y1
)
2700 return blocker_to_heap (bi
->heap
, rb
, &bi
->box
, bi
->dir
);
2703 /* shrink the box to the last limit for the previous direction,
2704 * i.e. if dir is SOUTH, then this means fixing up an EAST leftover
2705 * edge, which would be the southern most edge for that example.
2707 static inline BoxType
2708 previous_edge (Coord last
, direction_t i
, const BoxType
* b
)
2723 Message ("previous edge bogus direction!");
2729 /* Break all the edges of the box that need breaking, handling
2730 * targets as they are found, and putting any moveable edges
2731 * in the return vector.
2734 BreakManyEdges (struct routeone_state
* s
, rtree_t
* targets
, rtree_t
* tree
,
2735 vector_t
* area_vec
, struct E_result
* ans
, routebox_t
* rb
,
2738 struct break_info bi
;
2746 edges
= vector_create ();
2747 bi
.ignore_source
= rb
->parent
.expansion_area
->flags
.source
;
2749 /* we add 2 to the bloat.
2750 * 1 will get us to the actual blocker that Expand() hit
2751 * but 1 more is needed because the new expansion edges
2752 * move out by 1 so they don't overlap their parents
2753 * this extra expansion could "trap" the edge if
2754 * there is a blocker 2 units from the original rb,
2755 * it is 1 unit from the new expansion edge which
2756 * would prevent expansion. So we want to break the
2757 * edge on it now to avoid the trap.
2760 bloat
= AutoRouteParameters
.bloat
+ 2;
2761 /* for corner expansion, we need to have a fake blocker
2762 * to prevent expansion back where we came from since
2763 * we still need to break portions of all 4 edges
2765 if (e
->expand_dir
== NE
|| e
->expand_dir
== SE
||
2766 e
->expand_dir
== SW
|| e
->expand_dir
== NW
)
2768 BoxType
*fb
= (BoxType
*) &fake
.sbox
;
2769 memset (&fake
, 0, sizeof (fake
));
2771 fake
.flags
.fixed
= 1; /* this stops expansion there */
2773 fake
.style
= AutoRouteParameters
.style
;
2775 /* the routbox_is_good checker wants a lot more! */
2776 fake
.flags
.inited
= 1;
2777 fb
= (BoxType
*) &fake
.box
;
2779 fake
.same_net
.next
= fake
.same_net
.prev
= &fake
;
2780 fake
.same_subnet
.next
= fake
.same_subnet
.prev
= &fake
;
2781 fake
.original_subnet
.next
= fake
.original_subnet
.prev
= &fake
;
2782 fake
.different_net
.next
= fake
.different_net
.prev
= &fake
;
2785 /* gather all of the blockers in heaps so they can be accessed
2786 * in clockwise order, which allows finding corners that can
2789 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
2791 /* don't break the edge we came from */
2792 if (e
->expand_dir
!= ((dir
+ 2) % 4))
2794 heap
[dir
] = heap_create ();
2795 bi
.box
= bloat_box (&rb
->sbox
, bloat
);
2796 bi
.heap
= heap
[dir
];
2798 /* convert to edge */
2802 bi
.box
.Y2
= bi
.box
.Y1
+ bloat
+ 1;
2803 /* for corner expansion, block the start edges and
2804 * limit the blocker search to only the new edge segment
2806 if (e
->expand_dir
== SE
|| e
->expand_dir
== SW
)
2807 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2808 if (e
->expand_dir
== SE
)
2809 bi
.box
.X1
= e
->rb
->sbox
.X2
;
2810 if (e
->expand_dir
== SW
)
2811 bi
.box
.X2
= e
->rb
->sbox
.X1
;
2812 rb
->n
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2815 bi
.box
.X1
= bi
.box
.X2
- bloat
- 1;
2816 /* corner, same as above */
2817 if (e
->expand_dir
== SW
|| e
->expand_dir
== NW
)
2818 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2819 if (e
->expand_dir
== SW
)
2820 bi
.box
.Y1
= e
->rb
->sbox
.Y2
;
2821 if (e
->expand_dir
== NW
)
2822 bi
.box
.Y2
= e
->rb
->sbox
.Y1
;
2823 rb
->e
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2826 bi
.box
.Y1
= bi
.box
.Y2
- bloat
- 1;
2827 /* corner, same as above */
2828 if (e
->expand_dir
== NE
|| e
->expand_dir
== NW
)
2829 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2830 if (e
->expand_dir
== NE
)
2831 bi
.box
.X1
= e
->rb
->sbox
.X2
;
2832 if (e
->expand_dir
== NW
)
2833 bi
.box
.X2
= e
->rb
->sbox
.X1
;
2834 rb
->s
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2837 bi
.box
.X2
= bi
.box
.X1
+ bloat
+ 1;
2838 /* corner, same as above */
2839 if (e
->expand_dir
== NE
|| e
->expand_dir
== SE
)
2840 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2841 if (e
->expand_dir
== SE
)
2842 bi
.box
.Y1
= e
->rb
->sbox
.Y2
;
2843 if (e
->expand_dir
== NE
)
2844 bi
.box
.Y2
= e
->rb
->sbox
.Y1
;
2845 rb
->w
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2856 (rb
->n
+ rb
->e
+ rb
->s
+
2857 rb
->w
) * AutoRouteParameters
.CongestionPenalty
/ box_area (rb
->sbox
);
2859 /* now handle the blockers:
2860 * Go around the expansion area clockwise (North->East->South->West)
2861 * pulling blockers from the heap (which makes them come out in the right
2862 * order). Break the edges on the blocker and make the segments and corners
2863 * moveable as possible.
2866 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
2868 if (heap
[dir
] && !heap_is_empty (heap
[dir
]))
2870 /* pull the very first one out of the heap outside of the
2871 * heap loop because it is special; it can be part of a corner
2873 routebox_t
*blk
= (routebox_t
*) heap_remove_smallest (heap
[dir
]);
2874 BoxType b
= rb
->sbox
;
2875 struct broken_boxes broke
= break_box_edge (&b
, dir
, blk
);
2876 if (broke
.is_valid_left
)
2878 /* if last > 0, then the previous edge had a segment
2879 * joining this one, so it forms a valid corner expansion
2883 /* make a corner expansion */
2888 /* possible NE expansion */
2890 db
.Y2
= MIN (db
.Y2
, broke
.left
.Y2
);
2893 /* possible SE expansion */
2895 db
.X1
= MAX (db
.X1
, broke
.left
.X1
);
2898 /* possible SW expansion */
2900 db
.Y1
= MAX (db
.Y1
, broke
.left
.Y1
);
2906 moveable_edge (edges
, &db
, (direction_t
)(dir
+ 3), rb
, NULL
, e
, targets
,
2909 else if (dir
== NORTH
) /* north is start, so nothing "before" it */
2911 /* save for a possible corner once we've
2912 * finished circling the box
2914 first
= MAX (b
.X1
, broke
.left
.X2
);
2918 /* this is just a boring straight expansion
2919 * since the orthogonal segment was blocked
2921 moveable_edge (edges
, &broke
.left
, dir
, rb
, NULL
, e
,
2922 targets
, s
, NULL
, NULL
);
2924 } /* broke.is_valid_left */
2927 /* if the last one didn't become a corner,
2928 * we still want to expand it straight out
2929 * in the direction of the previous edge,
2930 * which it belongs to.
2932 BoxType db
= previous_edge (last
, dir
, &rb
->sbox
);
2933 moveable_edge (edges
, &db
, (direction_t
)(dir
- 1), rb
, NULL
, e
, targets
, s
,
2936 if (broke
.is_valid_center
&& !blk
->flags
.source
)
2937 moveable_edge (edges
, &broke
.center
, dir
, rb
, blk
, e
, targets
, s
,
2939 /* this is the heap extraction loop. We break out
2940 * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can
2941 * just leave stuff in the heap when it is destroyed
2943 while (broke
.is_valid_right
)
2945 /* move the box edge to the next potential free point */
2949 last
= b
.X1
= MAX (broke
.right
.X1
, b
.X1
);
2952 last
= b
.Y1
= MAX (broke
.right
.Y1
, b
.Y1
);
2955 last
= b
.X2
= MIN (broke
.right
.X2
, b
.X2
);
2958 last
= b
.Y2
= MIN (broke
.right
.Y2
, b
.Y2
);
2963 if (heap_is_empty (heap
[dir
]))
2965 blk
= (routebox_t
*)heap_remove_smallest (heap
[dir
]);
2966 broke
= break_box_edge (&b
, dir
, blk
);
2967 if (broke
.is_valid_left
)
2968 moveable_edge (edges
, &broke
.left
, dir
, rb
, NULL
, e
, targets
,
2970 if (broke
.is_valid_center
&& !blk
->flags
.source
)
2971 moveable_edge (edges
, &broke
.center
, dir
, rb
, blk
, e
, targets
,
2974 if (!broke
.is_valid_right
)
2977 else /* if (heap[dir]) */
2979 /* nothing touched this edge! Expand the whole edge unless
2980 * (1) it hit the board edge or (2) was the source of our expansion
2982 * for this case (of hitting nothing) we give up trying for corner
2983 * expansions because it is likely that they're not possible anyway
2985 if ((e
->expand_dir
== ALL
? e
->rb
->came_from
: e
->expand_dir
) !=
2988 /* ok, we are not going back on ourselves, and the whole edge seems free */
2989 moveable_edge (edges
, &rb
->sbox
, dir
, rb
, NULL
, e
, targets
, s
,
2995 /* expand the leftover from the prior direction */
2996 BoxType db
= previous_edge (last
, dir
, &rb
->sbox
);
2997 moveable_edge (edges
, &db
, (direction_t
)(dir
- 1), rb
, NULL
, e
, targets
, s
,
3003 /* finally, check for the NW corner now that we've come full circle */
3004 if (first
> 0 && last
> 0)
3006 BoxType db
= rb
->sbox
;
3009 moveable_edge (edges
, &db
, NW
, rb
, NULL
, e
, targets
, s
, NULL
, NULL
);
3015 BoxType db
= rb
->sbox
;
3017 moveable_edge (edges
, &db
, NORTH
, rb
, NULL
, e
, targets
, s
, NULL
,
3022 BoxType db
= rb
->sbox
;
3024 moveable_edge (edges
, &db
, WEST
, rb
, NULL
, e
, targets
, s
, NULL
,
3028 /* done with all expansion edges of this box */
3029 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
3032 heap_destroy (&heap
[dir
]);
3038 rb_source (routebox_t
* rb
)
3040 while (rb
&& !rb
->flags
.source
)
3042 assert (rb
->type
== EXPANSION_AREA
);
3043 rb
= rb
->parent
.expansion_area
;
3054 routebox_t
*intersect
;
3059 foib_rect_in_reg (const BoxType
* box
, void *cl
)
3061 struct foib_info
*foib
= (struct foib_info
*) cl
;
3063 routebox_t
*rb
= (routebox_t
*) box
;
3064 if (rb
->flags
.touched
)
3066 // if (rb->type == EXPANSION_AREA && !rb->flags.is_via)
3068 rbox
= bloat_routebox (rb
);
3069 if (!box_intersect (&rbox
, foib
->box
))
3071 /* this is an intersector! */
3072 foib
->intersect
= (routebox_t
*) box
;
3073 longjmp (foib
->env
, 1); /* skip to the end! */
3077 FindOneInBox (rtree_t
* rtree
, routebox_t
* rb
)
3079 struct foib_info foib
;
3084 foib
.intersect
= NULL
;
3086 if (setjmp (foib
.env
) == 0)
3087 r_search (rtree
, &r
, NULL
, foib_rect_in_reg
, &foib
);
3088 return foib
.intersect
;
3098 ftherm_rect_in_reg (const BoxType
* box
, void *cl
)
3100 routebox_t
*rbox
= (routebox_t
*) box
;
3101 struct therm_info
*ti
= (struct therm_info
*) cl
;
3104 if (rbox
->type
!= PIN
&& rbox
->type
!= VIA
&& rbox
->type
!= VIA_SHADOW
)
3106 if (rbox
->group
!= ti
->plane
->group
)
3109 sb
= shrink_routebox (rbox
);
3113 sq
= shrink_box (&ti
->query
, rbox
->parent
.pin
->Thickness
);
3114 if (!box_intersect (&sb
, &sq
))
3116 sb
.X1
= rbox
->parent
.pin
->X
;
3117 sb
.Y1
= rbox
->parent
.pin
->Y
;
3120 if (rbox
->flags
.fixed
)
3122 sq
= shrink_box (&ti
->query
, rbox
->parent
.via
->Thickness
);
3123 sb
.X1
= rbox
->parent
.pin
->X
;
3124 sb
.Y1
= rbox
->parent
.pin
->Y
;
3128 sq
= shrink_box (&ti
->query
, rbox
->style
->Diameter
);
3129 sb
.X1
= CENTER_X (sb
);
3130 sb
.Y1
= CENTER_Y (sb
);
3132 if (!box_intersect (&sb
, &sq
))
3136 sq
= shrink_box (&ti
->query
, rbox
->style
->Diameter
);
3137 if (!box_intersect (&sb
, &sq
))
3139 sb
.X1
= CENTER_X (sb
);
3140 sb
.Y1
= CENTER_Y (sb
);
3146 longjmp (ti
->env
, 1);
3150 /* check for a pin or via target that a polygon can just use a thermal to connect to */
3152 FindThermable (rtree_t
* rtree
, routebox_t
* rb
)
3154 struct therm_info info
;
3157 info
.query
= shrink_routebox (rb
);
3159 if (setjmp (info
.env
) == 0)
3161 r_search (rtree
, &info
.query
, NULL
, ftherm_rect_in_reg
, &info
);
3167 /*--------------------------------------------------------------------
3168 * Route-tracing code: once we've got a path of expansion boxes, trace
3169 * a line through them to actually create the connection.
3172 RD_DrawThermal (routedata_t
* rd
, Coord X
, Coord Y
,
3173 Cardinal group
, Cardinal layer
, routebox_t
* subnet
,
3177 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3178 memset ((void *) rb
, 0, sizeof (*rb
));
3179 init_const_box (rb
, X
, Y
, X
+ 1, Y
+ 1, 0);
3182 rb
->flags
.fixed
= 0;
3183 rb
->flags
.is_bad
= is_bad
;
3184 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3185 rb
->flags
.circular
= 0;
3186 rb
->style
= AutoRouteParameters
.style
;
3189 MergeNets (rb
, subnet
, NET
);
3190 MergeNets (rb
, subnet
, SUBNET
);
3191 /* add it to the r-tree, this may be the whole route! */
3192 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3193 rb
->flags
.homeless
= 0;
3197 RD_DrawVia (routedata_t
* rd
, Coord X
, Coord Y
,
3198 Coord radius
, routebox_t
* subnet
, bool is_bad
)
3200 routebox_t
*rb
, *first_via
= NULL
;
3202 int ka
= AutoRouteParameters
.style
->Keepaway
;
3203 PinType
*live_via
= NULL
;
3205 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3207 live_via
= CreateNewVia (PCB
->Data
, X
, Y
, radius
* 2,
3208 2 * AutoRouteParameters
.style
->Keepaway
, 0,
3209 AutoRouteParameters
.style
->Hole
, NULL
,
3211 if (live_via
!= NULL
)
3215 /* a via cuts through every layer group */
3216 for (i
= 0; i
< max_group
; i
++)
3218 if (!is_layer_group_active
[i
])
3220 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3221 memset ((void *) rb
, 0, sizeof (*rb
));
3223 /*X1 */ X
- radius
, /*Y1 */ Y
- radius
,
3224 /*X2 */ X
+ radius
+ 1, /*Y2 */ Y
+ radius
+ 1, ka
);
3226 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
3227 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3228 rb
->flags
.is_bad
= is_bad
;
3229 rb
->came_from
= ALL
;
3230 rb
->flags
.circular
= true;
3231 rb
->style
= AutoRouteParameters
.style
;
3232 rb
->pass
= AutoRouteParameters
.pass
;
3233 if (first_via
== NULL
)
3236 rb
->parent
.via
= NULL
; /* indicates that not on PCB yet */
3238 /* only add the first via to mtspace, not the shadows too */
3239 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
3240 rb
->style
->Keepaway
);
3244 rb
->type
= VIA_SHADOW
;
3245 rb
->parent
.via_shadow
= first_via
;
3248 /* add these to proper subnet. */
3249 MergeNets (rb
, subnet
, NET
);
3250 MergeNets (rb
, subnet
, SUBNET
);
3251 assert (__routebox_is_good (rb
));
3252 /* and add it to the r-tree! */
3253 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3254 rb
->flags
.homeless
= 0; /* not homeless anymore */
3255 rb
->livedraw_obj
.via
= live_via
;
3259 RD_DrawLine (routedata_t
* rd
,
3260 Coord X1
, Coord Y1
, Coord X2
,
3261 Coord Y2
, Coord halfthick
, Cardinal group
,
3262 routebox_t
* subnet
, bool is_bad
, bool is_45
)
3264 /* we hold the line in a queue to concatenate segments that
3265 * ajoin one another. That reduces the number of things in
3266 * the trees and allows conflict boxes to be larger, both of
3267 * which are really useful.
3269 static Coord qX1
= -1, qY1
, qX2
, qY2
;
3270 static Coord qhthick
;
3271 static Cardinal qgroup
;
3272 static bool qis_45
, qis_bad
;
3273 static routebox_t
*qsn
;
3276 Coord ka
= AutoRouteParameters
.style
->Keepaway
;
3278 /* don't draw zero-length segments. */
3279 if (X1
== X2
&& Y1
== Y2
)
3281 if (qX1
== -1) /* first ever */
3287 qhthick
= halfthick
;
3294 /* Check if the lines concatenat. We only check the
3295 * normal expected nextpoint=lastpoint condition
3297 if (X1
== qX2
&& Y1
== qY2
&& qhthick
== halfthick
&& qgroup
== group
)
3299 if (qX1
== qX2
&& X1
== X2
) /* everybody on the same X here */
3304 if (qY1
== qY2
&& Y1
== Y2
) /* same Y all around */
3310 /* dump the queue, no match here */
3312 return; /* but not this! */
3313 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3314 memset ((void *) rb
, 0, sizeof (*rb
));
3315 assert (is_45
? (ABS (qX2
- qX1
) == ABS (qY2
- qY1
)) /* line must be 45-degrees */
3316 : (qX1
== qX2
|| qY1
== qY2
) /* line must be ortho */ );
3318 /*X1 */ MIN (qX1
, qX2
) - qhthick
,
3319 /*Y1 */ MIN (qY1
, qY2
) - qhthick
,
3320 /*X2 */ MAX (qX1
, qX2
) + qhthick
+ 1,
3321 /*Y2 */ MAX (qY1
, qY2
) + qhthick
+ 1, ka
);
3324 rb
->parent
.line
= NULL
; /* indicates that not on PCB yet */
3325 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
3326 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3327 rb
->flags
.is_bad
= qis_bad
;
3328 rb
->came_from
= ALL
;
3329 rb
->flags
.homeless
= 0; /* we're putting this in the tree */
3330 rb
->flags
.nonstraight
= qis_45
;
3331 rb
->flags
.bl_to_ur
= ((qX2
>= qX1
&& qY2
<= qY1
)
3332 || (qX2
<= qX1
&& qY2
>= qY1
));
3333 rb
->style
= AutoRouteParameters
.style
;
3334 rb
->pass
= AutoRouteParameters
.pass
;
3336 /* add these to proper subnet. */
3337 MergeNets (rb
, qsn
, NET
);
3338 MergeNets (rb
, qsn
, SUBNET
);
3339 assert (__routebox_is_good (rb
));
3340 /* and add it to the r-tree! */
3341 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3343 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3345 LayerType
*layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[rb
->group
][0]);
3346 LineType
*line
= CreateNewLineOnLayer (layer
, qX1
, qY1
, qX2
, qY2
,
3347 2 * qhthick
, 0, MakeFlags (0));
3348 rb
->livedraw_obj
.line
= line
;
3350 DrawLine (layer
, line
);
3353 /* and to the via space structures */
3354 if (AutoRouteParameters
.use_vias
)
3355 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
3356 rb
->style
->Keepaway
);
3357 usedGroup
[rb
->group
] = true;
3358 /* and queue this one */
3363 qhthick
= halfthick
;
3371 RD_DrawManhattanLine (routedata_t
* rd
,
3372 const BoxType
* box1
, const BoxType
* box2
,
3373 CheapPointType start
, CheapPointType end
,
3374 Coord halfthick
, Cardinal group
,
3375 routebox_t
* subnet
, bool is_bad
, bool last_was_x
)
3377 CheapPointType knee
= start
;
3378 if (end
.X
== start
.X
)
3380 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3381 subnet
, is_bad
, false);
3384 else if (end
.Y
== start
.Y
)
3386 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3387 subnet
, is_bad
, false);
3390 /* find where knee belongs */
3391 if (point_in_box (box1
, end
.X
, start
.Y
)
3392 || point_in_box (box2
, end
.X
, start
.Y
))
3402 if ((knee
.X
== end
.X
&& !last_was_x
) &&
3403 (point_in_box (box1
, start
.X
, end
.Y
)
3404 || point_in_box (box2
, start
.X
, end
.Y
)))
3409 assert (AutoRouteParameters
.is_smoothing
3410 || point_in_closed_box (box1
, knee
.X
, knee
.Y
)
3411 || point_in_closed_box (box2
, knee
.X
, knee
.Y
));
3413 if (1 || !AutoRouteParameters
.is_smoothing
)
3415 /* draw standard manhattan paths */
3416 RD_DrawLine (rd
, start
.X
, start
.Y
, knee
.X
, knee
.Y
, halfthick
, group
,
3417 subnet
, is_bad
, false);
3418 RD_DrawLine (rd
, knee
.X
, knee
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3419 subnet
, is_bad
, false);
3423 /* draw 45-degree path across knee */
3424 Coord len45
= MIN (ABS (start
.X
- end
.X
), ABS (start
.Y
- end
.Y
));
3425 CheapPointType kneestart
= knee
, kneeend
= knee
;
3426 if (kneestart
.X
== start
.X
)
3427 kneestart
.Y
+= (kneestart
.Y
> start
.Y
) ? -len45
: len45
;
3429 kneestart
.X
+= (kneestart
.X
> start
.X
) ? -len45
: len45
;
3430 if (kneeend
.X
== end
.X
)
3431 kneeend
.Y
+= (kneeend
.Y
> end
.Y
) ? -len45
: len45
;
3433 kneeend
.X
+= (kneeend
.X
> end
.X
) ? -len45
: len45
;
3434 RD_DrawLine (rd
, start
.X
, start
.Y
, kneestart
.X
, kneestart
.Y
, halfthick
,
3435 group
, subnet
, is_bad
, false);
3436 RD_DrawLine (rd
, kneestart
.X
, kneestart
.Y
, kneeend
.X
, kneeend
.Y
,
3437 halfthick
, group
, subnet
, is_bad
, true);
3438 RD_DrawLine (rd
, kneeend
.X
, kneeend
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3439 subnet
, is_bad
, false);
3441 return (knee
.X
!= end
.X
);
3444 /* for smoothing, don't pack traces to min clearance gratuitously */
3447 add_clearance (CheapPointType
* nextpoint
, const BoxType
* b
)
3449 if (nextpoint
->X
== b
->X1
)
3452 AutoRouteParameters
.style
->Keepaway
< (b
->X1
+ b
->X2
) / 2)
3453 nextpoint
->X
+= AutoRouteParameters
.style
->Keepaway
;
3455 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
3457 else if (nextpoint
->X
== b
->X2
)
3460 AutoRouteParameters
.style
->Keepaway
> (b
->X1
+ b
->X2
) / 2)
3461 nextpoint
->X
-= AutoRouteParameters
.style
->Keepaway
;
3463 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
3465 else if (nextpoint
->Y
== b
->Y1
)
3468 AutoRouteParameters
.style
->Keepaway
< (b
->Y1
+ b
->Y2
) / 2)
3469 nextpoint
->Y
+= AutoRouteParameters
.style
->Keepaway
;
3471 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
3473 else if (nextpoint
->Y
== b
->Y2
)
3476 AutoRouteParameters
.style
->Keepaway
> (b
->Y1
+ b
->Y2
) / 2)
3477 nextpoint
->Y
-= AutoRouteParameters
.style
->Keepaway
;
3479 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
3484 /* This back-traces the expansion boxes along the best path
3485 * it draws the lines that will make the actual path.
3486 * during refinement passes, it should try to maximize the area
3487 * for other tracks so routing completion is easier.
3489 * during smoothing passes, it should try to make a better path,
3490 * possibly using diagonals, etc. The path boxes are larger on
3491 * average now so there is more possiblity to decide on a nice
3492 * path. Any combination of lines and arcs is possible, so long
3493 * as they don't poke more than half thick outside the path box.
3497 TracePath (routedata_t
* rd
, routebox_t
* path
, const routebox_t
* target
,
3498 routebox_t
* subnet
, bool is_bad
)
3500 bool last_x
= false;
3501 Coord halfwidth
= HALF_THICK (AutoRouteParameters
.style
->Thick
);
3502 Coord radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3503 CheapPointType lastpoint
, nextpoint
;
3504 routebox_t
*lastpath
;
3507 assert (subnet
->style
== AutoRouteParameters
.style
);
3508 /*XXX: because we round up odd thicknesses, there's the possibility that
3509 * a connecting line end-point might be 0.005 mil off the "real" edge.
3510 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
3512 /* if we start with a thermal the target was a plane
3513 * or the target was a pin and the source a plane
3514 * in which case this thermal is the whole path
3516 if (path
->flags
.is_thermal
)
3518 /* the target was a plane, so we need to find a good spot for the via
3519 * now. It's logical to place it close to the source box which
3520 * is where we're utlimately headed on this path. However, it
3521 * must reside in the plane as well as the via area too.
3523 nextpoint
.X
= CENTER_X (path
->sbox
);
3524 nextpoint
.Y
= CENTER_Y (path
->sbox
);
3525 if (path
->parent
.expansion_area
->flags
.is_via
)
3527 TargetPoint (&nextpoint
, rb_source (path
));
3528 /* nextpoint is the middle of the source terminal now */
3529 b
= clip_box (&path
->sbox
, &path
->parent
.expansion_area
->sbox
);
3530 nextpoint
= closest_point_in_box (&nextpoint
, &b
);
3531 /* now it's in the via and plane near the source */
3533 else /* no via coming, target must have been a pin */
3535 assert (target
->type
== PIN
);
3536 TargetPoint (&nextpoint
, target
);
3538 assert (point_in_box (&path
->sbox
, nextpoint
.X
, nextpoint
.Y
));
3539 RD_DrawThermal (rd
, nextpoint
.X
, nextpoint
.Y
, path
->group
,
3540 path
->layer
, subnet
, is_bad
);
3544 /* start from best place of target box */
3545 lastpoint
.X
= CENTER_X (target
->sbox
);
3546 lastpoint
.Y
= CENTER_Y (target
->sbox
);
3547 TargetPoint (&lastpoint
, target
);
3548 if (AutoRouteParameters
.last_smooth
3549 && box_in_box (&path
->sbox
, &target
->sbox
))
3550 path
= path
->parent
.expansion_area
;
3552 if (path
->flags
.circular
)
3553 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
3554 nextpoint
= closest_point_in_box (&lastpoint
, &b
);
3555 if (AutoRouteParameters
.last_smooth
)
3556 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3557 halfwidth
, path
->group
, subnet
, is_bad
, TRUE
);
3559 last_x
= RD_DrawManhattanLine (rd
, &target
->sbox
, &path
->sbox
,
3560 lastpoint
, nextpoint
, halfwidth
,
3561 path
->group
, subnet
, is_bad
, last_x
);
3563 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3564 showroutebox (path
);
3565 #if defined(ROUTE_VERBOSE)
3566 pcb_printf ("TRACEPOINT start %#mD\n", nextpoint
.X
, nextpoint
.Y
);
3572 lastpoint
= nextpoint
;
3574 assert (path
->type
== EXPANSION_AREA
);
3575 path
= path
->parent
.expansion_area
;
3577 if (path
->flags
.circular
)
3578 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
3579 assert (b
.X1
!= b
.X2
&& b
.Y1
!= b
.Y2
); /* need someplace to put line! */
3580 /* find point on path perimeter closest to last point */
3581 /* if source terminal, try to hit a good place */
3582 nextpoint
= closest_point_in_box (&lastpoint
, &b
);
3584 /* leave more clearance if this is a smoothing pass */
3585 if (AutoRouteParameters
.is_smoothing
&&
3586 (nextpoint
.X
!= lastpoint
.X
|| nextpoint
.Y
!= lastpoint
.Y
))
3587 add_clearance (&nextpoint
, &b
);
3589 if (path
->flags
.source
&& path
->type
!= PLANE
)
3590 TargetPoint (&nextpoint
, path
);
3591 assert (point_in_box (&lastpath
->box
, lastpoint
.X
, lastpoint
.Y
));
3592 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
3593 #if defined(ROUTE_DEBUG_VERBOSE)
3594 printf ("TRACEPATH: ");
3595 DumpRouteBox (path
);
3596 pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n",
3597 lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3601 /* draw orthogonal lines from lastpoint to nextpoint */
3602 /* knee is placed in lastpath box */
3603 /* should never cause line to leave union of lastpath/path boxes */
3604 if (AutoRouteParameters
.last_smooth
)
3605 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3606 halfwidth
, path
->group
, subnet
, is_bad
, TRUE
);
3608 last_x
= RD_DrawManhattanLine (rd
, &lastpath
->sbox
, &path
->sbox
,
3609 lastpoint
, nextpoint
, halfwidth
,
3610 path
->group
, subnet
, is_bad
, last_x
);
3611 if (path
->flags
.is_via
)
3612 { /* if via, then add via */
3613 #ifdef ROUTE_VERBOSE
3616 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
3617 RD_DrawVia (rd
, nextpoint
.X
, nextpoint
.Y
, radius
, subnet
, is_bad
);
3620 assert (lastpath
->flags
.is_via
|| path
->group
== lastpath
->group
);
3622 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3623 showroutebox (path
);
3624 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
3625 /* if this is connected to a plane, draw the thermal */
3626 if (path
->flags
.is_thermal
|| path
->type
== PLANE
)
3627 RD_DrawThermal (rd
, lastpoint
.X
, lastpoint
.Y
, path
->group
,
3628 path
->layer
, subnet
, is_bad
);
3629 /* when one hop from the source, make an extra path in *this* box */
3630 if (path
->type
== EXPANSION_AREA
3631 && path
->parent
.expansion_area
->flags
.source
3632 && path
->parent
.expansion_area
->type
!= PLANE
)
3634 /* find special point on source (if it exists) */
3635 if (TargetPoint (&lastpoint
, path
->parent
.expansion_area
))
3637 lastpoint
= closest_point_in_routebox (&lastpoint
, path
);
3638 b
= shrink_routebox (path
);
3640 if (AutoRouteParameters
.is_smoothing
)
3641 add_clearance (&lastpoint
, &b
);
3643 if (AutoRouteParameters
.last_smooth
)
3644 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
,
3645 nextpoint
.Y
, halfwidth
, path
->group
, subnet
,
3649 last_x
= RD_DrawManhattanLine (rd
, &b
, &b
,
3650 nextpoint
, lastpoint
,
3651 halfwidth
, path
->group
, subnet
,
3653 #if defined(ROUTE_DEBUG_VERBOSE)
3654 printf ("TRACEPATH: ");
3655 DumpRouteBox (path
);
3657 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n",
3658 nextpoint
.X
, nextpoint
.Y
, lastpoint
.X
, lastpoint
.Y
,
3662 nextpoint
= lastpoint
;
3666 while (!path
->flags
.source
);
3667 /* flush the line queue */
3668 RD_DrawLine (rd
, -1, 0, 0, 0, 0, 0, NULL
, false, false);
3670 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3675 ddraw
->flush_debug_draw ();
3679 /* create a fake "edge" used to defer via site searching. */
3681 CreateSearchEdge (struct routeone_state
*s
, vetting_t
* work
, edge_t
* parent
,
3682 routebox_t
* rb
, conflict_t conflict
, rtree_t
* targets
,
3688 assert (__routebox_is_good (rb
));
3689 /* find the cheapest target */
3692 mincost_target_to_point (&parent
->cost_point
, max_group
+ 1, targets
,
3693 parent
->mincost_target
);
3695 target
= parent
->mincost_target
;
3697 b
= shrink_routebox (target
);
3699 parent
->cost_to_point
+ AutoRouteParameters
.ViaCost
+
3700 cost_to_layerless_box (&rb
->cost_point
, 0, &b
);
3701 if (cost
< s
->best_cost
)
3704 ne
= (edge_t
*)malloc (sizeof (*ne
));
3705 memset ((void *) ne
, 0, sizeof (*ne
));
3707 ne
->flags
.via_search
= 1;
3708 ne
->flags
.in_plane
= in_plane
;
3710 if (rb
->flags
.homeless
)
3713 ne
->mincost_target
= target
;
3714 ne
->flags
.via_conflict_level
= conflict
;
3715 ne
->cost_to_point
= parent
->cost_to_point
;
3716 ne
->cost_point
= parent
->cost_point
;
3718 heap_insert (s
->workheap
, ne
->cost
, ne
);
3722 mtsFreeWork (&work
);
3727 add_or_destroy_edge (struct routeone_state
*s
, edge_t
* e
)
3729 e
->cost
= edge_cost (e
, s
->best_cost
);
3730 assert (__edge_is_good (e
));
3731 assert (is_layer_group_active
[e
->rb
->group
]);
3732 if (e
->cost
< s
->best_cost
)
3733 heap_insert (s
->workheap
, e
->cost
, e
);
3739 best_path_candidate (struct routeone_state
*s
,
3740 edge_t
* e
, routebox_t
* best_target
)
3742 e
->cost
= edge_cost (e
, EXPENSIVE
);
3743 if (s
->best_path
== NULL
|| e
->cost
< s
->best_cost
)
3745 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE)
3746 printf ("New best path seen! cost = %f\n", e
->cost
);
3748 /* new best path! */
3749 if (s
->best_path
&& s
->best_path
->flags
.homeless
)
3750 RB_down_count (s
->best_path
);
3751 s
->best_path
= e
->rb
;
3752 s
->best_target
= best_target
;
3753 s
->best_cost
= e
->cost
;
3754 assert (s
->best_cost
>= 0);
3755 /* don't free this when we destroy edge! */
3756 if (s
->best_path
->flags
.homeless
)
3757 RB_up_count (s
->best_path
);
3762 /* vectors for via site candidates (see mtspace.h) */
3763 struct routeone_via_site_state
3765 vector_t
*free_space_vec
;
3766 vector_t
*lo_conflict_space_vec
;
3767 vector_t
*hi_conflict_space_vec
;
3771 add_via_sites (struct routeone_state
*s
,
3772 struct routeone_via_site_state
*vss
,
3773 mtspace_t
* mtspace
, routebox_t
* within
,
3774 conflict_t within_conflict_level
, edge_t
* parent_edge
,
3775 rtree_t
* targets
, Coord shrink
, bool in_plane
)
3777 Coord radius
, keepaway
;
3779 BoxType region
= shrink_routebox (within
);
3780 shrink_box (®ion
, shrink
);
3782 radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3783 keepaway
= AutoRouteParameters
.style
->Keepaway
;
3784 assert (AutoRouteParameters
.use_vias
);
3785 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
3786 XXX: routing with conflicts may poke over edge. */
3788 /* ask for a via box near our cost_point first */
3789 work
= mtspace_query_rect (mtspace
, ®ion
, radius
, keepaway
,
3790 NULL
, vss
->free_space_vec
,
3791 vss
->lo_conflict_space_vec
,
3792 vss
->hi_conflict_space_vec
,
3793 AutoRouteParameters
.is_odd
,
3794 AutoRouteParameters
.with_conflicts
,
3795 &parent_edge
->cost_point
);
3798 CreateSearchEdge (s
, work
, parent_edge
, within
, within_conflict_level
,
3803 do_via_search (edge_t
* search
, struct routeone_state
*s
,
3804 struct routeone_via_site_state
*vss
, mtspace_t
* mtspace
,
3807 int i
, j
, count
= 0;
3808 Coord radius
, keepaway
;
3811 conflict_t within_conflict_level
;
3813 radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3814 keepaway
= AutoRouteParameters
.style
->Keepaway
;
3815 work
= mtspace_query_rect (mtspace
, NULL
, 0, 0,
3816 search
->work
, vss
->free_space_vec
,
3817 vss
->lo_conflict_space_vec
,
3818 vss
->hi_conflict_space_vec
,
3819 AutoRouteParameters
.is_odd
,
3820 AutoRouteParameters
.with_conflicts
, NULL
);
3821 within
= search
->rb
;
3822 within_conflict_level
= search
->flags
.via_conflict_level
;
3823 for (i
= 0; i
< 3; i
++)
3826 (i
== NO_CONFLICT
? vss
->free_space_vec
:
3827 i
== LO_CONFLICT
? vss
->lo_conflict_space_vec
:
3828 i
== HI_CONFLICT
? vss
->hi_conflict_space_vec
: NULL
);
3830 while (!vector_is_empty (v
))
3833 BoxType
*area
= (BoxType
*)vector_remove_last (v
);
3834 if (!(i
== NO_CONFLICT
|| AutoRouteParameters
.with_conflicts
))
3839 /* answers are bloated by radius + keepaway */
3840 cliparea
= shrink_box (area
, radius
+ keepaway
);
3841 close_box (&cliparea
);
3843 assert (box_is_good (&cliparea
));
3845 for (j
= 0; j
< max_group
; j
++)
3848 if (j
== within
->group
|| !is_layer_group_active
[j
])
3850 ne
= CreateViaEdge (&cliparea
, j
, within
, search
,
3851 within_conflict_level
, (conflict_t
)i
, targets
);
3852 add_or_destroy_edge (s
, ne
);
3856 /* prevent freeing of work when this edge is destroyed */
3857 search
->flags
.via_search
= 0;
3860 CreateSearchEdge (s
, work
, search
, within
, within_conflict_level
, targets
,
3861 search
->flags
.in_plane
);
3862 assert (vector_is_empty (vss
->free_space_vec
));
3863 assert (vector_is_empty (vss
->lo_conflict_space_vec
));
3864 assert (vector_is_empty (vss
->hi_conflict_space_vec
));
3867 /* vector of expansion areas to be eventually removed from r-tree
3868 * this is a global for troubleshooting
3872 /* some routines for use in gdb while debugging */
3873 #if defined(ROUTE_DEBUG)
3875 list_conflicts (routebox_t
* rb
)
3878 if (!rb
->conflicts_with
)
3880 n
= vector_size (rb
->conflicts_with
);
3881 for (i
= 0; i
< n
; i
++)
3882 printf ("%p, ", vector_element (rb
->conflicts_with
, i
));
3886 show_area_vec (int lay
)
3894 for (n
= 0; n
< vector_size (area_vec
); n
++)
3896 routebox_t
*rb
= (routebox_t
*) vector_element (area_vec
, n
);
3903 net_id (routebox_t
* rb
, long int id
)
3906 LIST_LOOP (rb
, same_net
, p
);
3907 if (p
->flags
.source
&& p
->parent
.pad
->ID
== id
)
3914 trace_parents (routebox_t
* rb
)
3916 while (rb
&& rb
->type
== EXPANSION_AREA
)
3918 printf (" %p ->", rb
);
3919 rb
= rb
->parent
.expansion_area
;
3922 printf (" %p is source\n", rb
);
3928 show_one (routebox_t
* rb
)
3930 int save
= showboxen
;
3937 show_path (routebox_t
* rb
)
3939 while (rb
&& rb
->type
== EXPANSION_AREA
)
3942 rb
= rb
->parent
.expansion_area
;
3948 show_sources (routebox_t
* rb
)
3951 if (!rb
->flags
.source
&& !rb
->flags
.target
)
3953 printf ("start with a source or target please\n");
3956 LIST_LOOP (rb
, same_net
, p
);
3957 if (p
->flags
.source
)
3965 __conflict_source (const BoxType
* box
, void *cl
)
3967 routebox_t
*rb
= (routebox_t
*) box
;
3968 if (rb
->flags
.touched
|| rb
->flags
.fixed
)
3972 routebox_t
*dis
= (routebox_t
*) cl
;
3973 path_conflicts (dis
, rb
, false);
3974 touch_conflicts (dis
->conflicts_with
, 1);
3980 source_conflicts (rtree_t
* tree
, routebox_t
* rb
)
3982 if (!AutoRouteParameters
.with_conflicts
)
3984 r_search (tree
, &rb
->sbox
, NULL
, __conflict_source
, rb
);
3985 touch_conflicts (NULL
, 1);
3988 struct routeone_status
3991 int route_had_conflicts
;
3992 cost_t best_route_cost
;
3993 bool net_completely_routed
;
3997 static struct routeone_status
3998 RouteOne (routedata_t
* rd
, routebox_t
* from
, routebox_t
* to
, int max_edges
)
4000 struct routeone_status result
;
4003 const BoxType
**target_list
;
4006 /* vector of source edges for filtering */
4007 vector_t
*source_vec
;
4008 /* working vector */
4011 struct routeone_state s
;
4012 struct routeone_via_site_state vss
;
4014 assert (rd
&& from
);
4015 result
.route_had_conflicts
= 0;
4016 /* no targets on to/from net need keepaway areas */
4017 LIST_LOOP (from
, same_net
, p
);
4018 p
->flags
.nobloat
= 1;
4020 /* set 'source' flags */
4021 LIST_LOOP (from
, same_subnet
, p
);
4022 if (!p
->flags
.nonstraight
)
4023 p
->flags
.source
= 1;
4026 /* count up the targets */
4029 /* remove source/target flags from non-straight obstacles, because they
4030 * don't fill their bounding boxes and so connecting to them
4031 * after we've routed is problematic. Better solution? */
4033 { /* if we're routing to a specific target */
4034 if (!to
->flags
.source
)
4035 { /* not already connected */
4036 /* check that 'to' and 'from' are on the same net */
4039 LIST_LOOP (from
, same_net
, p
);
4044 assert (seen
); /* otherwise from and to are on different nets! */
4045 /* set target flags only on 'to's subnet */
4046 LIST_LOOP (to
, same_subnet
, p
);
4047 if (!p
->flags
.nonstraight
&& is_layer_group_active
[p
->group
])
4049 p
->flags
.target
= 1;
4057 /* all nodes on the net but not connected to from are targets */
4058 LIST_LOOP (from
, same_net
, p
);
4059 if (!p
->flags
.source
&& is_layer_group_active
[p
->group
]
4060 && !p
->flags
.nonstraight
)
4062 p
->flags
.target
= 1;
4068 /* if no targets, then net is done! reset flags and return. */
4069 if (num_targets
== 0)
4071 LIST_LOOP (from
, same_net
, p
);
4072 p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
4074 result
.found_route
= false;
4075 result
.net_completely_routed
= true;
4076 result
.best_route_cost
= 0;
4077 result
.route_had_conflicts
= 0;
4081 result
.net_completely_routed
= false;
4083 /* okay, there's stuff to route */
4084 assert (!from
->flags
.target
);
4085 assert (num_targets
> 0);
4086 /* create list of target pointers and from that a r-tree of targets */
4087 target_list
= (const BoxType
**)malloc (num_targets
* sizeof (*target_list
));
4089 LIST_LOOP (from
, same_net
, p
);
4090 if (p
->flags
.target
)
4092 target_list
[i
++] = &p
->box
;
4093 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
4098 targets
= r_create_tree ((const BoxType
**)target_list
, i
, 0);
4099 assert (i
<= num_targets
);
4102 source_vec
= vector_create ();
4103 /* touch the source subnet to prepare check for conflictors */
4104 LIST_LOOP (from
, same_subnet
, p
);
4105 p
->flags
.touched
= 1;
4107 LIST_LOOP (from
, same_subnet
, p
);
4109 /* we need the test for 'source' because this box may be nonstraight */
4110 if (p
->flags
.source
&& is_layer_group_active
[p
->group
])
4114 BoxType b
= shrink_routebox (p
);
4116 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES)
4119 /* may expand in all directions from source; center edge cost point. */
4120 /* note that planes shouldn't really expand, but we need an edge */
4122 cp
.X
= CENTER_X (b
);
4123 cp
.Y
= CENTER_Y (b
);
4124 e
= CreateEdge (p
, cp
.X
, cp
.Y
, 0, NULL
, ALL
, targets
);
4125 cp
= closest_point_in_box (&cp
, &e
->mincost_target
->sbox
);
4126 cp
= closest_point_in_box (&cp
, &b
);
4129 source_conflicts (rd
->layergrouptree
[p
->group
], p
);
4130 vector_append (source_vec
, e
);
4134 LIST_LOOP (from
, same_subnet
, p
);
4135 p
->flags
.touched
= 0;
4137 /* break source edges; some edges may be too near obstacles to be able
4140 /* okay, main expansion-search routing loop. */
4141 /* set up the initial activity heap */
4142 s
.workheap
= heap_create ();
4143 assert (s
.workheap
);
4144 while (!vector_is_empty (source_vec
))
4146 edge_t
*e
= (edge_t
*)vector_remove_last (source_vec
);
4147 assert (is_layer_group_active
[e
->rb
->group
]);
4148 e
->cost
= edge_cost (e
, EXPENSIVE
);
4149 heap_insert (s
.workheap
, e
->cost
, e
);
4151 vector_destroy (&source_vec
);
4152 /* okay, process items from heap until it is empty! */
4154 s
.best_cost
= EXPENSIVE
;
4155 area_vec
= vector_create ();
4156 edge_vec
= vector_create ();
4157 vss
.free_space_vec
= vector_create ();
4158 vss
.lo_conflict_space_vec
= vector_create ();
4159 vss
.hi_conflict_space_vec
= vector_create ();
4160 while (!heap_is_empty (s
.workheap
))
4162 edge_t
*e
= (edge_t
*)heap_remove_smallest (s
.workheap
);
4167 /* don't bother expanding this edge if the minimum possible edge cost
4168 * is already larger than the best edge cost we've found. */
4169 if (s
.best_path
&& e
->cost
>= s
.best_cost
)
4171 heap_free (s
.workheap
, KillEdge
);
4172 goto dontexpand
; /* skip this edge */
4174 /* surprisingly it helps to give up and not try too hard to find
4175 * a route! This is not only faster, but results in better routing.
4176 * who would have guessed?
4178 if (seen
++ > max_edges
)
4180 assert (__edge_is_good (e
));
4181 /* mark or unmark conflictors as needed */
4182 touch_conflicts (e
->rb
->conflicts_with
, 1);
4183 if (e
->flags
.via_search
)
4185 do_via_search (e
, &s
, &vss
, rd
->mtspace
, targets
);
4188 /* we should never add edges on inactive layer groups to the heap. */
4189 assert (is_layer_group_active
[e
->rb
->group
]);
4190 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
4193 if (e
->rb
->flags
.is_thermal
)
4195 best_path_candidate (&s
, e
, e
->mincost_target
);
4198 /* for a plane, look for quick connections with thermals or vias */
4199 if (e
->rb
->type
== PLANE
)
4201 routebox_t
*pin
= FindThermable (targets
, e
->rb
);
4204 BoxType b
= shrink_routebox (pin
);
4207 assert (pin
->flags
.target
);
4208 nrb
= CreateExpansionArea (&b
, e
->rb
->group
, e
->rb
, true, e
);
4209 nrb
->flags
.is_thermal
= 1;
4210 /* moving through the plane is free */
4211 e
->cost_point
.X
= b
.X1
;
4212 e
->cost_point
.Y
= b
.Y1
;
4213 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, pin
);
4214 best_path_candidate (&s
, ne
, pin
);
4219 /* add in possible via sites in plane */
4220 if (AutoRouteParameters
.use_vias
&&
4221 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
4223 /* we need a giant thermal */
4225 CreateExpansionArea (&e
->rb
->sbox
, e
->rb
->group
, e
->rb
,
4227 edge_t
*ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
,
4229 nrb
->flags
.is_thermal
= 1;
4230 add_via_sites (&s
, &vss
, rd
->mtspace
, nrb
, NO_CONFLICT
, ne
,
4231 targets
, e
->rb
->style
->Diameter
, true);
4234 goto dontexpand
; /* planes only connect via thermals */
4236 if (e
->flags
.is_via
)
4237 { /* special case via */
4238 routebox_t
*intersecting
;
4239 assert (AutoRouteParameters
.use_vias
);
4240 assert (e
->expand_dir
== ALL
);
4241 assert (vector_is_empty (edge_vec
));
4242 /* if there is already something here on this layer (like an
4243 * EXPANSION_AREA), then we don't want to expand from here
4244 * at least not inside the expansion area. A PLANE on the
4245 * other hand may be a target, or not.
4248 FindOneInBox (rd
->layergrouptree
[e
->rb
->group
], e
->rb
);
4250 if (intersecting
&& intersecting
->flags
.target
4251 && intersecting
->type
== PLANE
)
4253 /* we have hit a plane */
4256 BoxType b
= shrink_routebox (e
->rb
);
4257 /* limit via region to that inside the plane */
4258 clip_box (&b
, &intersecting
->sbox
);
4259 nrb
= CreateExpansionArea (&b
, e
->rb
->group
, e
->rb
, true, e
);
4260 nrb
->flags
.is_thermal
= 1;
4261 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, intersecting
);
4262 best_path_candidate (&s
, ne
, intersecting
);
4266 else if (intersecting
== NULL
)
4268 /* this via candidate is in an open area; add it to r-tree as
4269 * an expansion area */
4270 assert (e
->rb
->type
== EXPANSION_AREA
&& e
->rb
->flags
.is_via
);
4271 /*assert (!r_search (rd->layergrouptree[e->rb->group],
4272 &e->rb->box, NULL, no_planes,0));
4274 r_insert_entry (rd
->layergrouptree
[e
->rb
->group
], &e
->rb
->box
,
4276 e
->rb
->flags
.homeless
= 0; /* not homeless any more */
4277 /* add to vector of all expansion areas in r-tree */
4278 vector_append (area_vec
, e
->rb
);
4279 /* mark reset refcount to 0, since this is not homeless any more. */
4280 e
->rb
->refcount
= 0;
4281 /* go ahead and expand this edge! */
4286 { /* XXX: disabling this causes no via
4288 BoxType a
= bloat_routebox (intersecting
), b
;
4291 /* something intersects this via candidate. split via candidate
4292 * into pieces and add these pieces to the workheap. */
4293 for (i
= 0; i
< 3; i
++)
4295 for (j
= 0; j
< 3; j
++)
4297 b
= shrink_routebox (e
->rb
);
4301 b
.X2
= MIN (b
.X2
, a
.X1
);
4304 b
.X1
= MAX (b
.X1
, a
.X1
);
4305 b
.X2
= MIN (b
.X2
, a
.X2
);
4308 b
.X1
= MAX (b
.X1
, a
.X2
);
4316 b
.Y2
= MIN (b
.Y2
, a
.Y1
);
4319 b
.Y1
= MAX (b
.Y1
, a
.Y1
);
4320 b
.Y2
= MIN (b
.Y2
, a
.Y2
);
4323 b
.Y1
= MAX (b
.Y1
, a
.Y2
);
4328 /* skip if this box is not valid */
4329 if (!(b
.X1
< b
.X2
&& b
.Y1
< b
.Y2
))
4331 if (i
== 1 && j
== 1)
4333 /* this bit of the via space is obstructed. */
4334 if (intersecting
->type
== EXPANSION_AREA
4335 || intersecting
->flags
.fixed
)
4336 continue; /* skip this bit, it's already been done. */
4337 /* create an edge with conflicts, if enabled */
4338 if (!AutoRouteParameters
.with_conflicts
)
4340 ne
= CreateEdgeWithConflicts (&b
, intersecting
, e
, 1
4341 /*cost penalty to box */
4343 add_or_destroy_edge (&s
, ne
);
4347 /* if this is not the intersecting piece, create a new
4348 * (hopefully unobstructed) via edge and add it back to the
4351 CreateViaEdge (&b
, e
->rb
->group
,
4352 e
->rb
->parent
.expansion_area
, e
,
4353 e
->flags
.via_conflict_level
,
4355 /* value here doesn't matter */
4357 add_or_destroy_edge (&s
, ne
);
4363 /* between the time these edges are inserted and the
4364 * time they are processed, new expansion boxes (which
4365 * conflict with these edges) may be added to the graph!
4366 * w.o vias this isn't a problem because the broken box
4367 * is not homeless. */
4372 struct E_result
*ans
;
4375 if (e
->flags
.is_interior
)
4377 assert (AutoRouteParameters
.with_conflicts
); /* no interior edges unless
4378 routing with conflicts! */
4379 assert (e
->rb
->conflicts_with
);
4381 switch (e
->rb
->came_from
)
4385 b
.X1
= CENTER_X (b
);
4390 b
.Y1
= CENTER_Y (b
);
4395 b
.X1
= CENTER_X (b
);
4400 b
.Y1
= CENTER_Y (b
);
4407 /* sources may not expand to their own edges because of
4408 * adjacent blockers.
4410 else if (e
->rb
->flags
.source
)
4411 b
= box_center (&e
->rb
->sbox
);
4414 ans
= Expand (rd
->layergrouptree
[e
->rb
->group
], e
, &b
);
4415 if (!box_intersect (&ans
->inflated
, &ans
->orig
))
4418 /* skip if it didn't actually expand */
4419 if (ans
->inflated
.X1
>= e
->rb
->sbox
.X1
&&
4420 ans
->inflated
.X2
<= e
->rb
->sbox
.X2
&&
4421 ans
->inflated
.Y1
>= e
->rb
->sbox
.Y1
&&
4422 ans
->inflated
.Y2
<= e
->rb
->sbox
.Y2
)
4426 if (!box_is_good (&ans
->inflated
))
4428 nrb
= CreateExpansionArea (&ans
->inflated
, e
->rb
->group
, e
->rb
,
4430 r_insert_entry (rd
->layergrouptree
[nrb
->group
], &nrb
->box
, 1);
4431 vector_append (area_vec
, nrb
);
4432 nrb
->flags
.homeless
= 0; /* not homeless any more */
4434 BreakManyEdges (&s
, targets
, rd
->layergrouptree
[nrb
->group
],
4435 area_vec
, ans
, nrb
, e
);
4436 while (!vector_is_empty (broken
))
4438 edge_t
*ne
= (edge_t
*)vector_remove_last (broken
);
4439 add_or_destroy_edge (&s
, ne
);
4441 vector_destroy (&broken
);
4443 /* add in possible via sites in nrb */
4444 if (AutoRouteParameters
.use_vias
&& !e
->rb
->flags
.is_via
&&
4445 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
4446 add_via_sites (&s
, &vss
,
4447 rd
->mtspace
, nrb
, NO_CONFLICT
, e
, targets
, 0,
4454 touch_conflicts (NULL
, 1);
4455 heap_destroy (&s
.workheap
);
4456 r_destroy_tree (&targets
);
4457 assert (vector_is_empty (edge_vec
));
4458 vector_destroy (&edge_vec
);
4460 /* we should have a path in best_path now */
4464 #ifdef ROUTE_VERBOSE
4465 printf ("%d:%d RC %.0f", ro
++, seen
, s
.best_cost
);
4467 result
.found_route
= true;
4468 result
.best_route_cost
= s
.best_cost
;
4469 /* determine if the best path had conflicts */
4470 result
.route_had_conflicts
= 0;
4471 if (AutoRouteParameters
.with_conflicts
&& s
.best_path
->conflicts_with
)
4473 while (!vector_is_empty (s
.best_path
->conflicts_with
))
4475 rb
= (routebox_t
*)vector_remove_last (s
.best_path
->conflicts_with
);
4476 rb
->flags
.is_bad
= 1;
4477 result
.route_had_conflicts
++;
4480 #ifdef ROUTE_VERBOSE
4481 if (result
.route_had_conflicts
)
4482 printf (" (%d conflicts)", result
.route_had_conflicts
);
4484 if (result
.route_had_conflicts
< AutoRouteParameters
.hi_conflict
)
4486 /* back-trace the path and add lines/vias to r-tree */
4487 TracePath (rd
, s
.best_path
, s
.best_target
, from
,
4488 result
.route_had_conflicts
);
4489 MergeNets (from
, s
.best_target
, SUBNET
);
4493 #ifdef ROUTE_VERBOSE
4494 printf (" (too many in fact)");
4496 result
.found_route
= false;
4498 #ifdef ROUTE_VERBOSE
4504 #ifdef ROUTE_VERBOSE
4505 printf ("%d:%d NO PATH FOUND.\n", ro
++, seen
);
4507 result
.best_route_cost
= s
.best_cost
;
4508 result
.found_route
= false;
4510 /* now remove all expansion areas from the r-tree. */
4511 while (!vector_is_empty (area_vec
))
4513 routebox_t
*rb
= (routebox_t
*)vector_remove_last (area_vec
);
4514 assert (!rb
->flags
.homeless
);
4515 if (rb
->conflicts_with
4516 && rb
->parent
.expansion_area
->conflicts_with
!= rb
->conflicts_with
)
4517 vector_destroy (&rb
->conflicts_with
);
4518 r_delete_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
);
4520 vector_destroy (&area_vec
);
4521 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
4522 LIST_LOOP (from
, same_net
, p
);
4523 if (p
->flags
.source
&& p
->conflicts_with
)
4524 vector_destroy (&p
->conflicts_with
);
4525 p
->flags
.touched
= p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
4528 vector_destroy (&vss
.free_space_vec
);
4529 vector_destroy (&vss
.lo_conflict_space_vec
);
4530 vector_destroy (&vss
.hi_conflict_space_vec
);
4536 InitAutoRouteParameters (int pass
,
4537 RouteStyleType
* style
,
4538 bool with_conflicts
, bool is_smoothing
,
4543 AutoRouteParameters
.style
= style
;
4544 AutoRouteParameters
.bloat
= style
->Keepaway
+ HALF_THICK (style
->Thick
);
4546 AutoRouteParameters
.ViaCost
=
4547 INCH_TO_COORD (3.5) + style
->Diameter
* (is_smoothing
? 80 : 30);
4548 AutoRouteParameters
.LastConflictPenalty
=
4549 (400 * pass
/ passes
+ 2) / (pass
+ 1);
4550 AutoRouteParameters
.ConflictPenalty
=
4551 4 * AutoRouteParameters
.LastConflictPenalty
;
4552 AutoRouteParameters
.JogPenalty
= 1000 * (is_smoothing
? 20 : 4);
4553 AutoRouteParameters
.CongestionPenalty
= 1e6
;
4554 AutoRouteParameters
.MinPenalty
= EXPENSIVE
;
4555 for (i
= 0; i
< max_group
; i
++)
4557 if (is_layer_group_active
[i
])
4559 AutoRouteParameters
.MinPenalty
= MIN (x_cost
[i
],
4560 AutoRouteParameters
.
4562 AutoRouteParameters
.MinPenalty
=
4563 MIN (y_cost
[i
], AutoRouteParameters
.MinPenalty
);
4566 AutoRouteParameters
.NewLayerPenalty
= is_smoothing
?
4567 0.5 * EXPENSIVE
: 10 * AutoRouteParameters
.ViaCost
;
4569 AutoRouteParameters
.hi_conflict
= MAX (8 * (passes
- pass
+ 1), 6);
4570 AutoRouteParameters
.is_odd
= (pass
& 1);
4571 AutoRouteParameters
.with_conflicts
= with_conflicts
;
4572 AutoRouteParameters
.is_smoothing
= is_smoothing
;
4573 AutoRouteParameters
.rip_always
= is_smoothing
;
4574 AutoRouteParameters
.last_smooth
= 0; //lastpass;
4575 AutoRouteParameters
.pass
= pass
+ 1;
4580 bad_boy (const BoxType
* b
, void *cl
)
4582 routebox_t
*box
= (routebox_t
*) b
;
4583 if (box
->type
== EXPANSION_AREA
)
4589 no_expansion_boxes (routedata_t
* rd
)
4597 for (i
= 0; i
< max_group
; i
++)
4599 if (r_search (rd
->layergrouptree
[i
], &big
, NULL
, bad_boy
, NULL
))
4607 ripout_livedraw_obj (routebox_t
*rb
)
4609 if (rb
->type
== LINE
&& rb
->livedraw_obj
.line
)
4611 LayerType
*layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[rb
->group
][0]);
4612 EraseLine (rb
->livedraw_obj
.line
);
4613 DestroyObject (PCB
->Data
, LINE_TYPE
, layer
, rb
->livedraw_obj
.line
, NULL
);
4614 rb
->livedraw_obj
.line
= NULL
;
4616 if (rb
->type
== VIA
&& rb
->livedraw_obj
.via
)
4618 EraseVia (rb
->livedraw_obj
.via
);
4619 DestroyObject (PCB
->Data
, VIA_TYPE
, rb
->livedraw_obj
.via
, NULL
, NULL
);
4620 rb
->livedraw_obj
.via
= NULL
;
4625 ripout_livedraw_obj_cb (const BoxType
* b
, void *cl
)
4627 routebox_t
*box
= (routebox_t
*) b
;
4628 ripout_livedraw_obj (box
);
4632 struct routeall_status
4634 /* --- for completion rate statistics ---- */
4636 /* total subnets routed without conflicts */
4638 /* total subnets routed with conflicts */
4639 int conflict_subnets
;
4640 /* net failted entirely */
4642 /* net was ripped */
4644 int total_nets_routed
;
4648 calculate_progress (double this_heap_item
, double this_heap_size
,
4649 struct routeall_status
*ras
)
4651 double total_passes
= passes
+ smoothes
+ 1; /* + 1 is the refinement pass */
4652 double this_pass
= AutoRouteParameters
.pass
- 1; /* Number passes from zero */
4653 double heap_fraction
= (double)(ras
->routed_subnets
+ ras
->conflict_subnets
+ ras
->failed
) /
4654 (double)ras
->total_subnets
;
4655 double pass_fraction
= (this_heap_item
+ heap_fraction
) / this_heap_size
;
4656 double process_fraction
= (this_pass
+ pass_fraction
) / total_passes
;
4658 return process_fraction
;
4661 struct routeall_status
4662 RouteAll (routedata_t
* rd
)
4664 struct routeall_status ras
;
4665 struct routeone_status ros
;
4671 heap_t
*this_pass
, *next_pass
, *tmp
;
4672 routebox_t
*net
, *p
, *pp
;
4673 cost_t total_net_cost
, last_cost
= 0, this_cost
= 0;
4678 /* initialize heap for first pass;
4679 * do smallest area first; that makes
4680 * the subsequent costs more representative */
4681 this_pass
= heap_create ();
4682 next_pass
= heap_create ();
4684 net_heap
= heap_create ();
4686 LIST_LOOP (rd
->first_net
, different_net
, net
);
4689 BoxType bb
= shrink_routebox (net
);
4690 LIST_LOOP (net
, same_net
, p
);
4692 MAKEMIN (bb
.X1
, p
->sbox
.X1
);
4693 MAKEMIN (bb
.Y1
, p
->sbox
.Y1
);
4694 MAKEMAX (bb
.X2
, p
->sbox
.X2
);
4695 MAKEMAX (bb
.Y2
, p
->sbox
.Y2
);
4698 area
= (double) (bb
.X2
- bb
.X1
) * (bb
.Y2
- bb
.Y1
);
4699 heap_insert (this_pass
, area
, net
);
4703 ras
.total_nets_routed
= 0;
4704 /* refinement/finishing passes */
4705 for (i
= 0; i
<= passes
+ smoothes
; i
++)
4707 #ifdef ROUTE_VERBOSE
4708 if (i
> 0 && i
<= passes
)
4709 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i
);
4710 else if (i
> passes
)
4711 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
4714 ras
.total_subnets
= ras
.routed_subnets
= ras
.conflict_subnets
=
4715 ras
.failed
= ras
.ripped
= 0;
4716 assert (heap_is_empty (next_pass
));
4718 this_heap_size
= heap_size (this_pass
);
4719 for (this_heap_item
= 0; !heap_is_empty (this_pass
); this_heap_item
++)
4725 net
= (routebox_t
*) heap_remove_smallest (this_pass
);
4726 InitAutoRouteParameters (i
, net
->style
, i
< passes
, i
> passes
,
4727 i
== passes
+ smoothes
);
4730 /* rip up all unfixed traces in this net ? */
4731 if (AutoRouteParameters
.rip_always
)
4736 LIST_LOOP (net
, same_net
, p
);
4737 if (p
->flags
.is_bad
)
4745 LIST_LOOP (net
, same_net
, p
);
4746 p
->flags
.is_bad
= 0;
4747 if (!p
->flags
.fixed
)
4752 assert (!p
->flags
.homeless
);
4755 RemoveFromNet (p
, NET
);
4756 RemoveFromNet (p
, SUBNET
);
4758 if (AutoRouteParameters
.use_vias
&& p
->type
!= VIA_SHADOW
4759 && p
->type
!= PLANE
)
4761 mtspace_remove (rd
->mtspace
, &p
->box
,
4762 p
->flags
.is_odd
? ODD
: EVEN
,
4763 p
->style
->Keepaway
);
4765 mtspace_add (rd
->mtspace
, &p
->box
,
4766 p
->flags
.is_odd
? EVEN
: ODD
,
4767 p
->style
->Keepaway
);
4771 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
4772 ripout_livedraw_obj (p
);
4776 r_delete_entry (rd
->layergrouptree
[p
->group
],
4784 p
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
4788 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
4790 /* reset to original connectivity */
4798 heap_insert (next_pass
, 0, net
);
4802 /* count number of subnets */
4803 FOREACH_SUBNET (net
, p
);
4804 ras
.total_subnets
++;
4805 END_FOREACH (net
, p
);
4806 /* the first subnet doesn't require routing. */
4807 ras
.total_subnets
--;
4810 /* only route that which isn't fully routed */
4812 if (ras
.total_subnets
== 0 || aabort
)
4814 if (ras
.total_subnets
== 0)
4817 heap_insert (next_pass
, 0, net
);
4821 /* the loop here ensures that we get to all subnets even if
4822 * some of them are unreachable from the first subnet. */
4823 LIST_LOOP (net
, same_net
, p
);
4826 BoxType b
= shrink_routebox (p
);
4827 /* using a heap allows us to start from smaller objects and
4828 * end at bigger ones. also prefer to start at planes, then pads */
4829 heap_insert (net_heap
, (float) (b
.X2
- b
.X1
) *
4830 #if defined(ROUTE_RANDOMIZED)
4831 (0.3 + rand () / (RAND_MAX
+ 1.0)) *
4833 (b
.Y2
- b
.Y1
) * (p
->type
== PLANE
?
4838 ros
.net_completely_routed
= 0;
4839 while (!heap_is_empty (net_heap
))
4841 p
= (routebox_t
*) heap_remove_smallest (net_heap
);
4843 if (!p
->flags
.fixed
|| p
->flags
.subnet_processed
||
4847 while (!ros
.net_completely_routed
)
4851 assert (no_expansion_boxes (rd
));
4852 /* FIX ME: the number of edges to examine should be in autoroute parameters
4853 * i.e. the 2000 and 800 hard-coded below should be controllable by the user
4856 RouteOne (rd
, p
, NULL
,
4857 ((AutoRouteParameters
.
4858 is_smoothing
? 2000 : 800) * (i
+
4861 total_net_cost
+= ros
.best_route_cost
;
4862 if (ros
.found_route
)
4864 if (ros
.route_had_conflicts
)
4865 ras
.conflict_subnets
++;
4868 ras
.routed_subnets
++;
4869 ras
.total_nets_routed
++;
4874 if (!ros
.net_completely_routed
)
4876 /* don't bother trying any other source in this subnet */
4877 LIST_LOOP (p
, same_subnet
, pp
);
4878 pp
->flags
.subnet_processed
= 1;
4882 /* note that we can infer nothing about ras.total_subnets based
4883 * on the number of calls to RouteOne, because we may be unable
4884 * to route a net from a particular starting point, but perfectly
4885 * able to route it from some other. */
4886 percent
= calculate_progress (this_heap_item
, this_heap_size
, &ras
);
4887 request_cancel
= gui
->progress (percent
* 100., 100,
4888 _("Autorouting tracks"));
4891 ras
.total_nets_routed
= 0;
4892 ras
.conflict_subnets
= 0;
4893 Message ("Autorouting cancelled\n");
4901 if (!ros
.net_completely_routed
)
4902 net
->flags
.is_bad
= 1; /* don't skip this the next round */
4904 /* Route easiest nets from this pass first on next pass.
4905 * This works best because it's likely that the hardest
4906 * is the last one routed (since it has the most obstacles)
4907 * but it will do no good to rip it up and try it again
4908 * without first changing any of the other routes
4910 heap_insert (next_pass
, total_net_cost
, net
);
4911 if (total_net_cost
< EXPENSIVE
)
4912 this_cost
+= total_net_cost
;
4913 /* reset subnet_processed flags */
4914 LIST_LOOP (net
, same_net
, p
);
4916 p
->flags
.subnet_processed
= 0;
4920 /* swap this_pass and next_pass and do it all over again! */
4922 assert (heap_is_empty (this_pass
));
4924 this_pass
= next_pass
;
4926 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE)
4928 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n",
4929 i
, ras
.routed_subnets
, ras
.total_subnets
, this_cost
,
4930 ras
.conflict_subnets
, ras
.failed
, ras
.ripped
);
4936 /* if no conflicts found, skip directly to smoothing pass! */
4937 if (ras
.conflict_subnets
== 0 && ras
.routed_subnets
== ras
.total_subnets
4939 i
= passes
- (smoothes
? 0 : 1);
4940 /* if no changes in a smoothing round, then we're done */
4941 if (this_cost
== last_cost
&& i
> passes
&& i
< passes
+ smoothes
)
4942 i
= passes
+ smoothes
- 1;
4943 last_cost
= this_cost
;
4947 Message ("%d of %d nets successfully routed.\n",
4948 ras
.routed_subnets
, ras
.total_subnets
);
4951 heap_destroy (&this_pass
);
4952 heap_destroy (&next_pass
);
4954 heap_destroy (&net_heap
);
4957 /* no conflicts should be left at the end of the process. */
4958 assert (ras
.conflict_subnets
== 0);
4971 fpin_rect (const BoxType
* b
, void *cl
)
4973 PinType
*pin
= (PinType
*) b
;
4974 struct fpin_info
*info
= (struct fpin_info
*) cl
;
4975 if (pin
->X
== info
->X
&& pin
->Y
== info
->Y
)
4977 info
->pin
= (PinType
*) b
;
4978 longjmp (info
->env
, 1);
4984 FindPin (const BoxType
* box
, PinType
** pin
)
4986 struct fpin_info info
;
4991 if (setjmp (info
.env
) == 0)
4992 r_search (PCB
->Data
->pin_tree
, box
, NULL
, fpin_rect
, &info
);
4998 if (setjmp (info
.env
) == 0)
4999 r_search (PCB
->Data
->via_tree
, box
, NULL
, fpin_rect
, &info
);
5010 /* paths go on first 'on' layer in group */
5011 /* returns 'true' if any paths were added. */
5013 IronDownAllUnfixedPaths (routedata_t
* rd
)
5015 bool changed
= false;
5017 routebox_t
*net
, *p
;
5019 LIST_LOOP (rd
->first_net
, different_net
, net
);
5021 LIST_LOOP (net
, same_net
, p
);
5023 if (!p
->flags
.fixed
)
5025 /* find first on layer in this group */
5026 assert (PCB
->LayerGroups
.Number
[p
->group
] > 0);
5027 assert (is_layer_group_active
[p
->group
]);
5028 for (i
= 0, layer
= NULL
; i
< PCB
->LayerGroups
.Number
[p
->group
];
5031 layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[p
->group
][i
]);
5035 assert (layer
&& layer
->On
); /*at least one layer must be on in this group! */
5036 assert (p
->type
!= EXPANSION_AREA
);
5037 if (p
->type
== LINE
)
5039 Coord halfwidth
= HALF_THICK (p
->style
->Thick
);
5040 double th
= halfwidth
* 2 + 1;
5042 assert (p
->parent
.line
== NULL
);
5043 /* orthogonal; thickness is 2*halfwidth */
5044 /* flip coordinates, if bl_to_ur */
5046 total_wire_length
+=
5047 sqrt ((b
.X2
- b
.X1
- th
) * (b
.X2
- b
.X1
- th
) +
5048 (b
.Y2
- b
.Y1
- th
) * (b
.Y2
- b
.Y1
- th
));
5049 b
= shrink_box (&b
, halfwidth
);
5050 if (b
.X2
== b
.X1
+ 1)
5052 if (b
.Y2
== b
.Y1
+ 1)
5054 if (p
->flags
.bl_to_ur
)
5061 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
5062 p
->parent
.line
= CreateDrawnLineOnLayer
5063 (layer
, b
.X1
, b
.Y1
, b
.X2
, b
.Y2
,
5065 p
->style
->Keepaway
* 2,
5066 MakeFlags (AUTOFLAG
|
5067 (TEST_FLAG (CLEARNEWFLAG
, PCB
) ? CLEARLINEFLAG
:
5072 AddObjectToCreateUndoList (LINE_TYPE
, layer
,
5073 p
->parent
.line
, p
->parent
.line
);
5077 else if (p
->type
== VIA
|| p
->type
== VIA_SHADOW
)
5080 (p
->type
== VIA_SHADOW
) ? p
->parent
.via_shadow
: p
;
5081 Coord radius
= HALF_THICK (pp
->style
->Diameter
);
5082 BoxType b
= shrink_routebox (p
);
5084 assert (pp
->type
== VIA
);
5085 if (pp
->parent
.via
== NULL
)
5087 assert (b
.X1
+ radius
== b
.X2
- radius
);
5088 assert (b
.Y1
+ radius
== b
.Y2
- radius
);
5090 CreateNewVia (PCB
->Data
, b
.X1
+ radius
,
5092 pp
->style
->Diameter
,
5093 2 * pp
->style
->Keepaway
,
5094 0, pp
->style
->Hole
, NULL
,
5095 MakeFlags (AUTOFLAG
));
5096 assert (pp
->parent
.via
);
5099 AddObjectToCreateUndoList (VIA_TYPE
,
5106 assert (pp
->parent
.via
);
5107 if (p
->type
== VIA_SHADOW
)
5110 p
->parent
.via
= pp
->parent
.via
;
5113 else if (p
->type
== THERMAL
)
5114 /* nothing to do because, the via might not be there yet */ ;
5120 /* loop again to place all the thermals now that the vias are down */
5121 LIST_LOOP (net
, same_net
, p
);
5123 if (p
->type
== THERMAL
)
5125 PinType
*pin
= NULL
;
5126 /* thermals are alread a single point search, no need to shrink */
5127 int type
= FindPin (&p
->box
, &pin
);
5130 AddObjectToClearPolyUndoList (type
,
5131 pin
->Element
? pin
->Element
: pin
,
5133 RestoreToPolygon (PCB
->Data
, VIA_TYPE
, LAYER_PTR (p
->layer
),
5135 AddObjectToFlagUndoList (type
,
5136 pin
->Element
? pin
->Element
: pin
, pin
,
5138 ASSIGN_THERM (p
->layer
, PCB
->ThermStyle
, pin
);
5139 AddObjectToClearPolyUndoList (type
,
5140 pin
->Element
? pin
->Element
: pin
,
5142 ClearFromPolygon (PCB
->Data
, VIA_TYPE
, LAYER_PTR (p
->layer
),
5155 AutoRoute (bool selected
)
5157 bool changed
= false;
5161 total_wire_length
= 0;
5162 total_via_count
= 0;
5165 ddraw
= gui
->request_debug_draw ();
5168 ar_gc
= ddraw
->graphics
->make_gc ();
5169 ddraw
->graphics
->set_line_cap (ar_gc
, Round_Cap
);
5173 for (i
= 0; i
< NUM_STYLES
; i
++)
5175 if (PCB
->RouteStyle
[i
].Thick
== 0 ||
5176 PCB
->RouteStyle
[1].Diameter
== 0 ||
5177 PCB
->RouteStyle
[1].Hole
== 0 || PCB
->RouteStyle
[i
].Keepaway
== 0)
5179 Message ("You must define proper routing styles\n"
5180 "before auto-routing.\n");
5184 if (PCB
->Data
->RatN
== 0)
5186 rd
= CreateRouteData ();
5190 routebox_t
*net
, *rb
, *last
;
5192 /* count number of rats selected */
5193 RAT_LOOP (PCB
->Data
);
5195 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5199 #ifdef ROUTE_VERBOSE
5200 printf ("%d nets!\n", i
);
5203 goto donerouting
; /* nothing to do here */
5204 /* if only one rat selected, do things the quick way. =) */
5207 RAT_LOOP (PCB
->Data
);
5208 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5210 /* look up the end points of this rat line */
5212 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
5213 line
->Point1
.Y
, line
->group1
);
5215 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
5216 line
->Point2
.Y
, line
->group2
);
5218 /* If the rat starts or ends at a non-straight pad (i.e., at a
5219 * rotated SMD), a or b will be NULL since the autorouter can't
5222 if (a
!= NULL
&& b
!= NULL
)
5224 assert (a
->style
== b
->style
);
5225 /* route exactly one net, without allowing conflicts */
5226 InitAutoRouteParameters (0, a
->style
, false, true, true);
5227 /* hace planes work better as sources than targets */
5228 changed
= RouteOne (rd
, a
, b
, 150000).found_route
|| changed
;
5234 /* otherwise, munge the netlists so that only the selected rats
5236 /* first, separate all sub nets into separate nets */
5237 /* note that this code works because LIST_LOOP is clever enough not to
5238 * be fooled when the list is changing out from under it. */
5240 LIST_LOOP (rd
->first_net
, different_net
, net
);
5242 FOREACH_SUBNET (net
, rb
);
5246 last
->different_net
.next
= rb
;
5247 rb
->different_net
.prev
= last
;
5251 END_FOREACH (net
, rb
);
5252 LIST_LOOP (net
, same_net
, rb
);
5254 rb
->same_net
= rb
->same_subnet
;
5257 /* at this point all nets are equal to their subnets */
5262 last
->different_net
.next
= rd
->first_net
;
5263 rd
->first_net
->different_net
.prev
= last
;
5266 /* now merge only those subnets connected by a rat line */
5267 RAT_LOOP (PCB
->Data
);
5268 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5270 /* look up the end points of this rat line */
5274 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
5275 line
->Point1
.Y
, line
->group1
);
5277 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
5278 line
->Point2
.Y
, line
->group2
);
5281 #ifdef DEBUG_STALE_RATS
5282 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
5283 ASSIGN_FLAG (SELECTEDFLAG
, true, line
);
5285 #endif /* DEBUG_STALE_RATS */
5286 Message ("The rats nest is stale! Aborting autoroute...\n");
5289 /* merge subnets into a net! */
5290 MergeNets (a
, b
, NET
);
5293 /* now 'different_net' may point to too many different nets. Reset. */
5294 LIST_LOOP (rd
->first_net
, different_net
, net
);
5296 if (!net
->flags
.touched
)
5298 LIST_LOOP (net
, same_net
, rb
);
5299 rb
->flags
.touched
= 1;
5302 else /* this is not a "different net"! */
5303 RemoveFromNet (net
, DIFFERENT_NET
);
5306 /* reset "touched" flag */
5307 LIST_LOOP (rd
->first_net
, different_net
, net
);
5309 LIST_LOOP (net
, same_net
, rb
);
5311 assert (rb
->flags
.touched
);
5312 rb
->flags
.touched
= 0;
5318 /* okay, rd's idea of netlist now corresponds to what we want routed */
5319 /* auto-route all nets */
5320 changed
= (RouteAll (rd
).total_nets_routed
> 0) || changed
;
5322 gui
->progress (0, 0, NULL
);
5323 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
5326 BoxType big
= {0, 0, MAX_COORD
, MAX_COORD
};
5327 for (i
= 0; i
< max_group
; i
++)
5329 r_search (rd
->layergrouptree
[i
], &big
, NULL
, ripout_livedraw_obj_cb
, NULL
);
5335 ddraw
->graphics
->destroy_gc (ar_gc
);
5336 ddraw
->finish_debug_draw ();
5341 changed
= IronDownAllUnfixedPaths (rd
);
5342 Message ("Total added wire length = %$mS, %d vias added\n",
5343 (Coord
) total_wire_length
, total_via_count
);
5344 DestroyRouteData (&rd
);
5347 SaveUndoSerialNumber ();
5349 /* optimize rats, we've changed connectivity a lot. */
5350 DeleteRats (false /*all rats */ );
5351 RestoreUndoSerialNumber ();
5352 AddAllRats (false /*all rats */ , NULL
);
5353 RestoreUndoSerialNumber ();
5355 IncrementUndoSerialNumber ();
5359 #if defined (ROUTE_DEBUG)