2 * \file src/autoroute.c
4 * \brief Functions used to autoroute nets.
6 * this file, autoroute.c, was written and is
8 * Copyright (c) 2001 C. Scott Ananian
10 * Copyright (c) 2006 harry eaton
12 * Copyright (c) 2009 harry eaton
14 * This file implements a rectangle-expansion router, based on
15 * "A Method for Gridless Routing of Printed Circuit Boards" by
16 * A. C. Finch, K. J. Mackenzie, G. J. Balsdon, and G. Symonds in the
17 * 1985 Proceedings of the 22nd ACM/IEEE Design Automation Conference.
19 * This reference is available from the ACM Digital Library at
20 * http://www.acm.org/dl for those with institutional or personal
21 * access to it. It's also available from your local engineering
24 * The code is much closer to what is described in the paper now,
25 * in that expansion areas can grow from corners and in all directions
26 * at once. Previously, these were emulated with discrete boxes moving
27 * in the cardinal directions. With the new method, there are fewer but
28 * larger expansion boxes that one might do a better job of routing in.
32 * <h1><b>Copyright.</b></h1>\n
34 * PCB, interactive printed circuit board design
36 * Copyright (C) 1994,1995,1996 Thomas Nau
38 * Copyright (C) 1998,1999,2000,2001 harry eaton
40 * This program is free software; you can redistribute it and/or modify
41 * it under the terms of the GNU General Public License as published by
42 * the Free Software Foundation; either version 2 of the License, or
43 * (at your option) any later version.
45 * This program is distributed in the hope that it will be useful,
46 * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 * GNU General Public License for more details.
50 * You should have received a copy of the GNU General Public License
51 * along with this program; if not, write to the Free Software
52 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
54 * Contact addresses for paper mail and Email:
55 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
56 * haceaton@aplcomm.jhuapl.edu
72 #include "autoroute.h"
89 #include "pcb-printf.h"
92 #ifdef HAVE_LIBDMALLOC
96 /* #defines to enable some debugging output */
103 //#define DEBUG_SHOW_ROUTE_BOXES
104 #define DEBUG_SHOW_EXPANSION_BOXES
105 //#define DEBUG_SHOW_EDGES
106 //#define DEBUG_SHOW_VIA_BOXES
107 #define DEBUG_SHOW_TARGETS
108 #define DEBUG_SHOW_SOURCES
109 //#define DEBUG_SHOW_ZIGZAG
113 directionIncrement(direction_t dir
)
149 HID_DRAW
*ddraw
= NULL
;
150 static hidGC ar_gc
= 0;
153 #define EXPENSIVE 3e28
154 /* round up "half" thicknesses */
155 #define HALF_THICK(x) (((x)+1)/2)
156 /* a styles maximum bloat is its keepaway plus the larger of its via radius
157 * or line half-thickness. */
158 #define BLOAT(style)\
159 ((style)->Keepaway + HALF_THICK((style)->Thick))
160 /* conflict penalty is less for traces laid down during previous pass than
161 * it is for traces already laid down in this pass. */
162 #define CONFLICT_LEVEL(rb)\
163 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\
164 HI_CONFLICT : LO_CONFLICT )
165 #define CONFLICT_PENALTY(rb)\
166 ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \
167 AutoRouteParameters.ConflictPenalty : \
168 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \
169 AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass)
176 #define LIST_LOOP(init, which, x) do {\
177 routebox_t *__next_one__ = (init);\
180 assert(__next_one__);\
182 while (!x || __next_one__ != (init)) {\
184 /* save next one first in case the command modifies or frees it */\
185 __next_one__ = x->which.next
186 #define FOREACH_SUBNET(net, p) do {\
188 /* fail-fast: check subnet_processed flags */\
189 LIST_LOOP(net, same_net, p); \
190 assert(!p->flags.subnet_processed);\
192 /* iterate through *distinct* subnets */\
193 LIST_LOOP(net, same_net, p); \
194 if (!p->flags.subnet_processed) {\
195 LIST_LOOP(p, same_subnet, _pp_);\
196 _pp_->flags.subnet_processed=1;\
198 #define END_FOREACH(net, p) \
201 /* reset subnet_processed flags */\
202 LIST_LOOP(net, same_net, p); \
203 p->flags.subnet_processed=0;\
206 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0)
208 * all rectangles are assumed to be closed on the top and left and
209 * open on the bottom and right. That is, they include their top-left
210 * corner but don't include their bottom and right edges.
212 * expansion regions are always half-closed. This means that when
213 * tracing paths, you must steer clear of the bottom and right edges.,
214 * because these are not actually in the allowed box.
216 * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by
217 * their particular required keepaway. This simplifies the tree searching.
218 * the "sbox" contains the unbloated box.
220 /* ---------------------------------------------------------------------------
224 /* enumerated type for conflict levels */
226 { NO_CONFLICT
= 0, LO_CONFLICT
= 1, HI_CONFLICT
= 2 }
229 typedef struct routebox_list
231 struct routebox
*next
, *prev
;
235 { PAD
, PIN
, VIA
, VIA_SHADOW
, LINE
, OTHER
, EXPANSION_AREA
, PLANE
, THERMAL
}
238 typedef struct routebox
246 struct routebox
*via_shadow
; /* points to the via in r-tree which
247 * points to the PinType in the PCB. */
249 void *generic
; /* 'other' is polygon, arc, text */
250 struct routebox
*expansion_area
; /* previous expansion area in search */
253 unsigned short group
;
254 unsigned short layer
;
258 unsigned nonstraight
:1;
263 /* rects on same net as source and target don't need clearance areas */
265 /* mark circular pins, so that we be sure to connect them up properly */
267 /* we sometimes create routeboxen that don't actually belong to a
268 * r-tree yet -- make sure refcount of homelesss is set properly */
270 /* was this nonfixed obstacle generated on an odd or even pass? */
272 /* fixed route boxes that have already been "routed through" in this
273 * search have their "touched" flag set. */
275 /* this is a status bit for iterating through *different* subnets */
276 unsigned subnet_processed
:1;
277 /* some expansion_areas represent via candidates */
279 /* mark non-straight lines which go from bottom-left to upper-right,
280 * instead of from upper-left to bottom-right. */
282 /* mark polygons which are "transparent" for via-placement; that is,
283 * vias through the polygon will automatically be given a keepaway
284 * and will not electrically connect to the polygon. */
285 unsigned clear_poly
:1;
286 /* this marks "conflicting" routes that must be torn up to obtain
287 * a correct routing. This flag allows us to return a correct routing
288 * even if the user cancels auto-route after a non-final pass. */
290 /* for assertion that 'box' is never changed after creation */
292 /* indicate this expansion ares is a thermal between the pin and plane */
296 /* indicate the direction an expansion box came from */
298 CheapPointType cost_point
;
299 /* reference count for homeless routeboxes; free when refcount==0 */
301 /* when routing with conflicts, we keep a record of what we're
304 vector_t
*conflicts_with
;
305 /* route style of the net associated with this routebox */
306 RouteStyleType
*style
;
307 /* congestion values for the edges of an expansion box */
308 unsigned char n
, e
, s
, w
;
309 /* what pass this this track was laid down on */
311 /* the direction this came from, if any */
312 direction_t came_from
;
313 /* circular lists with connectivity information. */
314 routebox_list same_net
, same_subnet
, original_subnet
, different_net
;
322 typedef struct routedata
324 /* one rtree per layer *group */
325 rtree_t
*layergrouptree
[MAX_GROUP
]; /* no silkscreen layers here =) */
326 /* root pointer into connectivity information */
327 routebox_t
*first_net
;
328 /* default routing style */
329 RouteStyleType defaultstyle
;
330 /* style structures */
331 RouteStyleType
*styles
[NUM_STYLES
+ 1];
332 /* what is the maximum bloat (keepaway+line half-width or
333 * keepaway+via_radius) for any style we've seen? */
340 typedef struct edge_struct
342 routebox_t
*rb
; /* path expansion edges are real routeboxen. */
343 CheapPointType cost_point
;
344 cost_t cost_to_point
; /* from source */
345 cost_t cost
; /* cached edge cost */
346 routebox_t
*mincost_target
; /* minimum cost from cost_point to any target */
347 vetting_t
*work
; /* for via search edges */
348 direction_t expand_dir
;
351 /* this indicates that this 'edge' is a via candidate. */
353 /* record "conflict level" of via candidates, in case we need to split
355 conflict_t via_conflict_level
:2;
356 /* when "routing with conflicts", sometimes edge is interior. */
357 unsigned is_interior
:1;
358 /* this is a fake edge used to defer searching for via spaces */
359 unsigned via_search
:1;
360 /* this is a via edge in a plane where the cost point moves for free */
369 /* net style parameters */
370 RouteStyleType
*style
;
371 /* the present bloat */
373 /* cost parameters */
374 cost_t ViaCost
, /* additional "length" cost for using a via */
375 LastConflictPenalty
, /* length mult. for routing over last pass' trace */
376 ConflictPenalty
, /* length multiplier for routing over another trace */
377 JogPenalty
, /* additional "length" cost for changing direction */
378 CongestionPenalty
, /* (rational) length multiplier for routing in */
379 NewLayerPenalty
, /* penalty for routing on a previously unused layer */
380 MinPenalty
; /* smallest Direction Penalty */
381 /* maximum conflict incidence before calling it "no path found" */
383 /* are vias allowed? */
385 /* is this an odd or even pass? */
387 /* permit conflicts? */
389 /* is this a final "smoothing" pass? */
391 /* rip up nets regardless of conflicts? */
398 struct routeone_state
400 /* heap of all candidate expansion edges */
402 /* information about the best path found so far. */
403 routebox_t
*best_path
, *best_target
;
408 /* ---------------------------------------------------------------------------
409 * some local prototypes
411 static routebox_t
*CreateExpansionArea (const BoxType
* area
, Cardinal group
,
413 bool relax_edge_requirements
,
416 static cost_t
edge_cost (const edge_t
* e
, const cost_t too_big
);
417 static void best_path_candidate (struct routeone_state
*s
,
418 edge_t
* e
, routebox_t
* best_target
);
420 static BoxType
edge_to_box (const routebox_t
* rb
, direction_t expand_dir
);
422 static void add_or_destroy_edge (struct routeone_state
*s
, edge_t
* e
);
425 RD_DrawThermal (routedata_t
* rd
, Coord X
, Coord Y
,
426 Cardinal group
, Cardinal layer
, routebox_t
* subnet
,
428 static void ResetSubnet (routebox_t
* net
);
430 static int showboxen
= -2;
431 static int aabort
= 0;
432 static void showroutebox (routebox_t
* rb
);
435 /* ---------------------------------------------------------------------------
436 * some local identifiers
438 /* group number of groups that hold surface mount pads */
439 static Cardinal front
, back
;
440 static bool usedGroup
[MAX_GROUP
];
441 static int x_cost
[MAX_GROUP
], y_cost
[MAX_GROUP
];
442 static bool is_layer_group_active
[MAX_GROUP
];
444 static int smoothes
= 1;
445 static int passes
= 12;
446 static int routing_layers
= 0;
447 static float total_wire_length
= 0;
448 static int total_via_count
= 0;
450 /* assertion helper for routeboxen */
453 __routebox_is_good (routebox_t
* rb
)
455 assert (rb
&& (rb
->group
< max_group
) &&
456 (rb
->box
.X1
<= rb
->box
.X2
) && (rb
->box
.Y1
<= rb
->box
.Y2
) &&
457 (rb
->flags
.homeless
?
458 (rb
->box
.X1
!= rb
->box
.X2
) || (rb
->box
.Y1
!= rb
->box
.Y2
) :
459 (rb
->box
.X1
!= rb
->box
.X2
) && (rb
->box
.Y1
!= rb
->box
.Y2
)));
460 assert ((rb
->flags
.source
? rb
->flags
.nobloat
: 1) &&
461 (rb
->flags
.target
? rb
->flags
.nobloat
: 1) &&
462 (rb
->flags
.homeless
? !rb
->flags
.touched
: rb
->refcount
== 0) &&
463 (rb
->flags
.touched
? rb
->type
!= EXPANSION_AREA
: 1));
464 assert ((rb
->flags
.is_odd
? (!rb
->flags
.fixed
) &&
465 (rb
->type
== VIA
|| rb
->type
== VIA_SHADOW
|| rb
->type
== LINE
466 || rb
->type
== PLANE
) : 1));
467 assert (rb
->flags
.clear_poly
?
468 ((rb
->type
== OTHER
|| rb
->type
== PLANE
) && rb
->flags
.fixed
469 && !rb
->flags
.homeless
) : 1);
470 assert (rb
->flags
.inited
);
471 /* run through conflict list showing none are homeless, targets or sources */
472 if (rb
->conflicts_with
)
475 for (i
= 0; i
< vector_size (rb
->conflicts_with
); i
++)
477 routebox_t
*c
= vector_element (rb
->conflicts_with
, i
);
478 assert (!c
->flags
.homeless
&& !c
->flags
.source
&& !c
->flags
.target
482 assert (rb
->style
!= NULL
&& rb
->style
!= NULL
);
483 assert (rb
->type
== EXPANSION_AREA
484 || (rb
->same_net
.next
&& rb
->same_net
.prev
&& rb
->same_subnet
.next
485 && rb
->same_subnet
.prev
&& rb
->original_subnet
.next
486 && rb
->original_subnet
.prev
&& rb
->different_net
.next
487 && rb
->different_net
.prev
));
491 __edge_is_good (edge_t
* e
)
493 assert (e
&& e
->rb
&& __routebox_is_good (e
->rb
));
494 assert ((e
->rb
->flags
.homeless
? e
->rb
->refcount
> 0 : 1));
495 assert ((0 <= e
->expand_dir
) && (e
->expand_dir
< 9)
497 is_interior
? (e
->expand_dir
== ALL
498 && e
->rb
->conflicts_with
) : 1));
499 assert ((e
->flags
.is_via
? e
->rb
->flags
.is_via
: 1)
500 && (e
->flags
.via_conflict_level
>= 0
501 && e
->flags
.via_conflict_level
<= 2)
502 && (e
->flags
.via_conflict_level
!= 0 ? e
->flags
.is_via
: 1));
503 assert ((e
->cost_to_point
>= 0) && e
->cost
>= 0);
508 no_planes (const BoxType
* b
, void *cl
)
510 routebox_t
*rb
= (routebox_t
*) b
;
511 if (rb
->type
== PLANE
)
517 /*---------------------------------------------------------------------
518 * route utility functions.
522 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
};
523 static struct routebox_list
*
524 __select_list (routebox_t
* r
, enum boxlist which
)
532 return &(r
->same_net
);
534 return &(r
->same_subnet
);
536 return &(r
->original_subnet
);
538 return &(r
->different_net
);
542 InitLists (routebox_t
* r
)
544 static enum boxlist all
[] =
545 { NET
, SUBNET
, ORIGINAL
, DIFFERENT_NET
}
547 for (p
= all
; p
< all
+ (sizeof (all
) / sizeof (*p
)); p
++)
549 struct routebox_list
*rl
= __select_list (r
, *p
);
550 rl
->prev
= rl
->next
= r
;
555 MergeNets (routebox_t
* a
, routebox_t
* b
, enum boxlist which
)
557 struct routebox_list
*al
, *bl
, *anl
, *bnl
;
561 assert (a
->type
!= EXPANSION_AREA
);
562 assert (b
->type
!= EXPANSION_AREA
);
563 al
= __select_list (a
, which
);
564 bl
= __select_list (b
, which
);
569 anl
= __select_list (an
, which
);
570 bnl
= __select_list (bn
, which
);
579 RemoveFromNet (routebox_t
* a
, enum boxlist which
)
581 struct routebox_list
*al
, *anl
, *apl
;
584 al
= __select_list (a
, which
);
588 if (an
== a
|| ap
== a
)
589 return; /* not on any list */
591 anl
= __select_list (an
, which
);
592 apl
= __select_list (ap
, which
);
596 al
->next
= al
->prev
= a
;
601 init_const_box (routebox_t
* rb
,
602 Coord X1
, Coord Y1
, Coord X2
,
603 Coord Y2
, Coord keepaway
)
605 BoxType
*bp
= (BoxType
*) & rb
->box
; /* note discarding const! */
606 assert (!rb
->flags
.inited
);
607 assert (X1
<= X2
&& Y1
<= Y2
);
608 bp
->X1
= X1
- keepaway
;
609 bp
->Y1
= Y1
- keepaway
;
610 bp
->X2
= X2
+ keepaway
;
611 bp
->Y2
= Y2
+ keepaway
;
612 bp
= (BoxType
*) & rb
->sbox
;
617 rb
->flags
.inited
= 1;
620 static inline BoxType
621 shrink_routebox (const routebox_t
* rb
)
627 box_area (const BoxType b
)
629 cost_t ans
= b
.X2
- b
.X1
;
630 return ans
* (b
.Y2
- b
.Y1
);
633 static inline CheapPointType
634 closest_point_in_routebox (const CheapPointType
* from
, const routebox_t
* rb
)
636 return closest_point_in_box (from
, &rb
->sbox
);
640 point_in_shrunk_box (const routebox_t
* box
, Coord X
, Coord Y
)
642 BoxType b
= shrink_routebox (box
);
643 return point_in_box (&b
, X
, Y
);
646 /*---------------------------------------------------------------------
647 * routedata initialization functions.
651 AddPin (PointerListType layergroupboxes
[], PinType
*pin
, bool is_via
,
652 RouteStyleType
* style
)
654 routebox_t
**rbpp
, *lastrb
= NULL
;
656 /* a pin cuts through every layer group */
657 for (i
= 0; i
< max_group
; i
++)
659 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[i
]);
660 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
661 memset ((void *) *rbpp
, 0, sizeof (**rbpp
));
663 ht
= HALF_THICK (MAX (pin
->Thickness
, pin
->DrillingHole
));
664 init_const_box (*rbpp
,
668 /*Y2 */ pin
->Y
+ ht
, style
->Keepaway
);
669 /* set aux. properties */
673 (*rbpp
)->parent
.via
= pin
;
678 (*rbpp
)->parent
.pin
= pin
;
680 (*rbpp
)->flags
.fixed
= 1;
681 (*rbpp
)->came_from
= ALL
;
682 (*rbpp
)->style
= style
;
683 (*rbpp
)->flags
.circular
= !TEST_FLAG (SQUAREFLAG
, pin
);
689 MergeNets (*rbpp
, lastrb
, NET
);
690 MergeNets (*rbpp
, lastrb
, SUBNET
);
691 MergeNets (*rbpp
, lastrb
, ORIGINAL
);
698 AddPad (PointerListType layergroupboxes
[],
699 ElementType
*element
, PadType
*pad
, RouteStyleType
* style
)
703 int layergroup
= (TEST_FLAG (ONSOLDERFLAG
, pad
) ? back
: front
);
704 assert (0 <= layergroup
&& layergroup
< max_group
);
705 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
706 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
708 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
710 memset (*rbpp
, 0, sizeof (**rbpp
));
711 (*rbpp
)->group
= layergroup
;
712 halfthick
= HALF_THICK (pad
->Thickness
);
713 init_const_box (*rbpp
,
714 /*X1 */ MIN (pad
->Point1
.X
, pad
->Point2
.X
) - halfthick
,
715 /*Y1 */ MIN (pad
->Point1
.Y
, pad
->Point2
.Y
) - halfthick
,
716 /*X2 */ MAX (pad
->Point1
.X
, pad
->Point2
.X
) + halfthick
,
717 /*Y2 */ MAX (pad
->Point1
.Y
, pad
->Point2
.Y
) + halfthick
,
719 /* kludge for non-manhattan pads (which are not allowed at present) */
720 if (pad
->Point1
.X
!= pad
->Point2
.X
&& pad
->Point1
.Y
!= pad
->Point2
.Y
)
721 (*rbpp
)->flags
.nonstraight
= 1;
722 /* set aux. properties */
724 (*rbpp
)->parent
.pad
= pad
;
725 (*rbpp
)->flags
.fixed
= 1;
726 (*rbpp
)->came_from
= ALL
;
727 (*rbpp
)->style
= style
;
733 AddLine (PointerListType layergroupboxes
[], int layergroup
, LineType
*line
,
734 LineType
*ptr
, RouteStyleType
* style
)
737 assert (layergroupboxes
&& line
);
738 assert (0 <= layergroup
&& layergroup
< max_group
);
739 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
741 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
742 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
743 memset (*rbpp
, 0, sizeof (**rbpp
));
744 (*rbpp
)->group
= layergroup
;
745 init_const_box (*rbpp
,
746 /*X1 */ MIN (line
->Point1
.X
,
747 line
->Point2
.X
) - HALF_THICK (line
->Thickness
),
748 /*Y1 */ MIN (line
->Point1
.Y
,
749 line
->Point2
.Y
) - HALF_THICK (line
->Thickness
),
750 /*X2 */ MAX (line
->Point1
.X
,
751 line
->Point2
.X
) + HALF_THICK (line
->Thickness
),
752 /*Y2 */ MAX (line
->Point1
.Y
,
754 HALF_THICK (line
->Thickness
), style
->Keepaway
);
755 /* kludge for non-manhattan lines */
756 if (line
->Point1
.X
!= line
->Point2
.X
&& line
->Point1
.Y
!= line
->Point2
.Y
)
758 (*rbpp
)->flags
.nonstraight
= 1;
759 (*rbpp
)->flags
.bl_to_ur
=
760 (MIN (line
->Point1
.X
, line
->Point2
.X
) == line
->Point1
.X
) !=
761 (MIN (line
->Point1
.Y
, line
->Point2
.Y
) == line
->Point1
.Y
);
762 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG)
763 showroutebox (*rbpp
);
766 /* set aux. properties */
767 (*rbpp
)->type
= LINE
;
768 (*rbpp
)->parent
.line
= ptr
;
769 (*rbpp
)->flags
.fixed
= 1;
770 (*rbpp
)->came_from
= ALL
;
771 (*rbpp
)->style
= style
;
777 AddIrregularObstacle (PointerListType layergroupboxes
[],
779 Coord X2
, Coord Y2
, Cardinal layergroup
,
780 void *parent
, RouteStyleType
* style
)
783 Coord keep
= style
->Keepaway
;
784 assert (layergroupboxes
&& parent
);
785 assert (X1
<= X2
&& Y1
<= Y2
);
786 assert (0 <= layergroup
&& layergroup
< max_group
);
787 assert (PCB
->LayerGroups
.Number
[layergroup
] > 0);
789 rbpp
= (routebox_t
**) GetPointerMemory (&layergroupboxes
[layergroup
]);
790 *rbpp
= (routebox_t
*)malloc (sizeof (**rbpp
));
791 memset (*rbpp
, 0, sizeof (**rbpp
));
792 (*rbpp
)->group
= layergroup
;
793 init_const_box (*rbpp
, X1
, Y1
, X2
, Y2
, keep
);
794 (*rbpp
)->flags
.nonstraight
= 1;
795 (*rbpp
)->type
= OTHER
;
796 (*rbpp
)->parent
.generic
= parent
;
797 (*rbpp
)->flags
.fixed
= 1;
798 (*rbpp
)->style
= style
;
805 AddPolygon (PointerListType layergroupboxes
[], Cardinal layer
,
806 PolygonType
*polygon
, RouteStyleType
* style
)
808 int is_not_rectangle
= 1;
809 int layergroup
= GetLayerGroupNumberByNumber (layer
);
811 assert (0 <= layergroup
&& layergroup
< max_group
);
812 rb
= AddIrregularObstacle (layergroupboxes
,
813 polygon
->BoundingBox
.X1
,
814 polygon
->BoundingBox
.Y1
,
815 polygon
->BoundingBox
.X2
,
816 polygon
->BoundingBox
.Y2
,
817 layergroup
, polygon
, style
);
818 if (polygon
->PointN
== 4 &&
819 polygon
->HoleIndexN
== 0 &&
820 (polygon
->Points
[0].X
== polygon
->Points
[1].X
||
821 polygon
->Points
[0].Y
== polygon
->Points
[1].Y
) &&
822 (polygon
->Points
[1].X
== polygon
->Points
[2].X
||
823 polygon
->Points
[1].Y
== polygon
->Points
[2].Y
) &&
824 (polygon
->Points
[2].X
== polygon
->Points
[3].X
||
825 polygon
->Points
[2].Y
== polygon
->Points
[3].Y
) &&
826 (polygon
->Points
[3].X
== polygon
->Points
[0].X
||
827 polygon
->Points
[3].Y
== polygon
->Points
[0].Y
))
828 is_not_rectangle
= 0;
829 rb
->flags
.nonstraight
= is_not_rectangle
;
832 if (TEST_FLAG (CLEARPOLYFLAG
, polygon
))
834 rb
->flags
.clear_poly
= 1;
835 if (!is_not_rectangle
)
841 AddText (PointerListType layergroupboxes
[], Cardinal layergroup
,
842 TextType
*text
, RouteStyleType
* style
)
844 AddIrregularObstacle (layergroupboxes
,
845 text
->BoundingBox
.X1
, text
->BoundingBox
.Y1
,
846 text
->BoundingBox
.X2
, text
->BoundingBox
.Y2
,
847 layergroup
, text
, style
);
850 AddArc (PointerListType layergroupboxes
[], Cardinal layergroup
,
851 ArcType
*arc
, RouteStyleType
* style
)
853 return AddIrregularObstacle (layergroupboxes
,
854 arc
->BoundingBox
.X1
, arc
->BoundingBox
.Y1
,
855 arc
->BoundingBox
.X2
, arc
->BoundingBox
.Y2
,
856 layergroup
, arc
, style
);
867 __found_one_on_lg (const BoxType
* box
, void *cl
)
869 struct rb_info
*inf
= (struct rb_info
*) cl
;
870 routebox_t
*rb
= (routebox_t
*) box
;
873 if (rb
->flags
.nonstraight
)
875 sb
= shrink_box (&rb
->box
, rb
->style
->Keepaway
);
876 if (inf
->query
.X1
>= sb
.X2
|| inf
->query
.X2
<= sb
.X1
||
877 inf
->query
.Y1
>= sb
.Y2
|| inf
->query
.Y2
<= sb
.Y1
)
880 if (rb
->type
== PLANE
)
881 return 1; /* keep looking for something smaller if a plane was found */
882 longjmp (inf
->env
, 1);
886 FindRouteBoxOnLayerGroup (routedata_t
* rd
,
887 Coord X
, Coord Y
, Cardinal layergroup
)
891 info
.query
= point_box (X
, Y
);
892 if (setjmp (info
.env
) == 0)
893 r_search (rd
->layergrouptree
[layergroup
], &info
.query
, NULL
,
894 __found_one_on_lg
, &info
);
898 #ifdef ROUTE_DEBUG_VERBOSE
900 DumpRouteBox (routebox_t
* rb
)
902 pcb_printf ("RB: %#mD-%#mD l%d; ",
903 rb
->box
.X1
, rb
->box
.Y1
, rb
->box
.X2
, rb
->box
.Y2
, (int) rb
->group
);
907 printf ("PAD[%s %s] ", rb
->parent
.pad
->Name
, rb
->parent
.pad
->Number
);
910 printf ("PIN[%s %s] ", rb
->parent
.pin
->Name
, rb
->parent
.pin
->Number
);
915 printf ("VIA[%s %s] ", rb
->parent
.via
->Name
, rb
->parent
.via
->Number
);
930 if (rb
->flags
.nonstraight
)
931 printf ("(nonstraight) ");
934 if (rb
->flags
.source
)
935 printf ("(source) ");
936 if (rb
->flags
.target
)
937 printf ("(target) ");
938 if (rb
->flags
.homeless
)
939 printf ("(homeless) ");
947 NetListListType Nets
;
948 PointerListType layergroupboxes
[MAX_GROUP
];
953 /* check which layers are active first */
955 for (group
= 0; group
< max_group
; group
++)
957 for (i
= 0; i
< PCB
->LayerGroups
.Number
[group
]; i
++)
958 /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */
959 if ((PCB
->LayerGroups
.Entries
[group
][i
] < max_copper_layer
) &&
960 PCB
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][i
]].On
)
963 is_layer_group_active
[group
] = true;
967 is_layer_group_active
[group
] = false;
969 /* if via visibility is turned off, don't use them */
970 AutoRouteParameters
.use_vias
= routing_layers
> 1 && PCB
->ViaOn
;
971 front
= GetLayerGroupNumberBySide (TOP_SIDE
);
972 back
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
973 /* determine preferred routing direction on each group */
974 for (i
= 0; i
< max_group
; i
++)
976 if (i
!= back
&& i
!= front
)
978 x_cost
[i
] = (i
& 1) ? 2 : 1;
979 y_cost
[i
] = (i
& 1) ? 1 : 2;
992 /* create routedata */
993 rd
= (routedata_t
*)malloc (sizeof (*rd
));
994 memset ((void *) rd
, 0, sizeof (*rd
));
995 /* create default style */
996 rd
->defaultstyle
.Thick
= Settings
.LineThickness
;
997 rd
->defaultstyle
.Diameter
= Settings
.ViaThickness
;
998 rd
->defaultstyle
.Hole
= Settings
.ViaDrillingHole
;
999 rd
->defaultstyle
.Keepaway
= Settings
.Keepaway
;
1000 rd
->max_bloat
= BLOAT (&rd
->defaultstyle
);
1001 rd
->max_keep
= Settings
.Keepaway
;
1002 /* create styles structures */
1003 bbox
.X1
= bbox
.Y1
= 0;
1004 bbox
.X2
= PCB
->MaxWidth
;
1005 bbox
.Y2
= PCB
->MaxHeight
;
1006 for (i
= 0; i
< NUM_STYLES
+ 1; i
++)
1008 RouteStyleType
*style
=
1009 (i
< NUM_STYLES
) ? &PCB
->RouteStyle
[i
] : &rd
->defaultstyle
;
1010 rd
->styles
[i
] = style
;
1013 /* initialize pointerlisttype */
1014 for (i
= 0; i
< max_group
; i
++)
1016 layergroupboxes
[i
].Ptr
= NULL
;
1017 layergroupboxes
[i
].PtrN
= 0;
1018 layergroupboxes
[i
].PtrMax
= 0;
1019 GROUP_LOOP (PCB
->Data
, i
);
1021 if (layer
->LineN
|| layer
->ArcN
)
1022 usedGroup
[i
] = true;
1024 usedGroup
[i
] = false;
1028 usedGroup
[front
] = true;
1029 usedGroup
[back
] = true;
1030 /* add the objects in the netlist first.
1031 * then go and add all other objects that weren't already added
1033 * this saves on searching the trees to find the nets
1035 /* use the DRCFLAG to mark objects as they are entered */
1036 Nets
= CollectSubnets (false);
1038 routebox_t
*last_net
= NULL
;
1039 NETLIST_LOOP (&Nets
);
1041 routebox_t
*last_in_net
= NULL
;
1044 routebox_t
*last_in_subnet
= NULL
;
1047 for (j
= 0; j
< NUM_STYLES
; j
++)
1048 if (net
->Style
== rd
->styles
[j
])
1050 CONNECTION_LOOP (net
);
1052 routebox_t
*rb
= NULL
;
1053 SET_FLAG (DRCFLAG
, (PinType
*) connection
->ptr2
);
1054 if (connection
->type
== LINE_TYPE
)
1056 LineType
*line
= (LineType
*) connection
->ptr2
;
1058 /* lines are listed at each end, so skip one */
1059 /* this should probably by a macro named "BUMP_LOOP" */
1062 /* dice up non-straight lines into many tiny obstacles */
1063 if (line
->Point1
.X
!= line
->Point2
.X
1064 && line
->Point1
.Y
!= line
->Point2
.Y
)
1066 LineType fake_line
= *line
;
1067 Coord dx
= (line
->Point2
.X
- line
->Point1
.X
);
1068 Coord dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
1069 int segs
= MAX (ABS (dx
),
1070 ABS (dy
)) / (4 * BLOAT (rd
->styles
[j
]) + 1);
1072 segs
= CLAMP (segs
, 1, 32); /* don't go too crazy */
1075 for (qq
= 0; qq
< segs
- 1; qq
++)
1077 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
1078 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
1079 if (fake_line
.Point2
.X
== line
->Point2
.X
1080 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
1083 AddLine (layergroupboxes
, connection
->group
,
1084 &fake_line
, line
, rd
->styles
[j
]);
1085 if (last_in_subnet
&& rb
!= last_in_subnet
)
1086 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
1087 if (last_in_net
&& rb
!= last_in_net
)
1088 MergeNets (last_in_net
, rb
, NET
);
1089 last_in_subnet
= last_in_net
= rb
;
1090 fake_line
.Point1
= fake_line
.Point2
;
1092 fake_line
.Point2
= line
->Point2
;
1094 AddLine (layergroupboxes
, connection
->group
, &fake_line
,
1095 line
, rd
->styles
[j
]);
1100 AddLine (layergroupboxes
, connection
->group
, line
, line
,
1105 switch (connection
->type
)
1109 AddPad (layergroupboxes
, (ElementType
*)connection
->ptr1
,
1110 (PadType
*)connection
->ptr2
, rd
->styles
[j
]);
1114 AddPin (layergroupboxes
, (PinType
*)connection
->ptr2
, false,
1119 AddPin (layergroupboxes
, (PinType
*)connection
->ptr2
, true,
1124 AddPolygon (layergroupboxes
,
1125 GetLayerNumber (PCB
->Data
, (LayerType
*)connection
->ptr1
),
1126 (struct polygon_st
*)connection
->ptr2
, rd
->styles
[j
]);
1130 /* update circular connectivity lists */
1131 if (last_in_subnet
&& rb
!= last_in_subnet
)
1132 MergeNets (last_in_subnet
, rb
, ORIGINAL
);
1133 if (last_in_net
&& rb
!= last_in_net
)
1134 MergeNets (last_in_net
, rb
, NET
);
1135 last_in_subnet
= last_in_net
= rb
;
1136 rd
->max_bloat
= MAX (rd
->max_bloat
, BLOAT (rb
->style
));
1137 rd
->max_keep
= MAX (rd
->max_keep
, rb
->style
->Keepaway
);
1142 if (last_net
&& last_in_net
)
1143 MergeNets (last_net
, last_in_net
, DIFFERENT_NET
);
1144 last_net
= last_in_net
;
1147 rd
->first_net
= last_net
;
1149 FreeNetListListMemory (&Nets
);
1151 /* reset all nets to "original" connectivity (which we just set) */
1154 LIST_LOOP (rd
->first_net
, different_net
, net
);
1159 /* add pins and pads of elements */
1160 ALLPIN_LOOP (PCB
->Data
);
1162 if (TEST_FLAG (DRCFLAG
, pin
))
1163 CLEAR_FLAG (DRCFLAG
, pin
);
1165 AddPin (layergroupboxes
, pin
, false, rd
->styles
[NUM_STYLES
]);
1168 ALLPAD_LOOP (PCB
->Data
);
1170 if (TEST_FLAG (DRCFLAG
, pad
))
1171 CLEAR_FLAG (DRCFLAG
, pad
);
1173 AddPad (layergroupboxes
, element
, pad
, rd
->styles
[NUM_STYLES
]);
1177 VIA_LOOP (PCB
->Data
);
1179 if (TEST_FLAG (DRCFLAG
, via
))
1180 CLEAR_FLAG (DRCFLAG
, via
);
1182 AddPin (layergroupboxes
, via
, true, rd
->styles
[NUM_STYLES
]);
1186 for (i
= 0; i
< max_copper_layer
; i
++)
1188 int layergroup
= GetLayerGroupNumberByNumber (i
);
1189 /* add all (non-rat) lines */
1190 LINE_LOOP (LAYER_PTR (i
));
1192 if (TEST_FLAG (DRCFLAG
, line
))
1194 CLEAR_FLAG (DRCFLAG
, line
);
1197 /* dice up non-straight lines into many tiny obstacles */
1198 if (line
->Point1
.X
!= line
->Point2
.X
1199 && line
->Point1
.Y
!= line
->Point2
.Y
)
1201 LineType fake_line
= *line
;
1202 Coord dx
= (line
->Point2
.X
- line
->Point1
.X
);
1203 Coord dy
= (line
->Point2
.Y
- line
->Point1
.Y
);
1204 int segs
= MAX (ABS (dx
), ABS (dy
)) / (4 * rd
->max_bloat
+ 1);
1206 segs
= CLAMP (segs
, 1, 32); /* don't go too crazy */
1209 for (qq
= 0; qq
< segs
- 1; qq
++)
1211 fake_line
.Point2
.X
= fake_line
.Point1
.X
+ dx
;
1212 fake_line
.Point2
.Y
= fake_line
.Point1
.Y
+ dy
;
1213 if (fake_line
.Point2
.X
== line
->Point2
.X
1214 && fake_line
.Point2
.Y
== line
->Point2
.Y
)
1216 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
,
1217 rd
->styles
[NUM_STYLES
]);
1218 fake_line
.Point1
= fake_line
.Point2
;
1220 fake_line
.Point2
= line
->Point2
;
1221 AddLine (layergroupboxes
, layergroup
, &fake_line
, line
,
1222 rd
->styles
[NUM_STYLES
]);
1226 AddLine (layergroupboxes
, layergroup
, line
, line
,
1227 rd
->styles
[NUM_STYLES
]);
1231 /* add all polygons */
1232 POLYGON_LOOP (LAYER_PTR (i
));
1234 if (TEST_FLAG (DRCFLAG
, polygon
))
1235 CLEAR_FLAG (DRCFLAG
, polygon
);
1237 AddPolygon (layergroupboxes
, i
, polygon
, rd
->styles
[NUM_STYLES
]);
1240 /* add all copper text */
1241 TEXT_LOOP (LAYER_PTR (i
));
1243 AddText (layergroupboxes
, layergroup
, text
, rd
->styles
[NUM_STYLES
]);
1247 ARC_LOOP (LAYER_PTR (i
));
1249 AddArc (layergroupboxes
, layergroup
, arc
, rd
->styles
[NUM_STYLES
]);
1254 /* create r-trees from pointer lists */
1255 for (i
= 0; i
< max_group
; i
++)
1257 /* create the r-tree */
1258 rd
->layergrouptree
[i
] =
1259 r_create_tree ((const BoxType
**) layergroupboxes
[i
].Ptr
,
1260 layergroupboxes
[i
].PtrN
, 1);
1263 if (AutoRouteParameters
.use_vias
)
1265 rd
->mtspace
= mtspace_create ();
1267 /* create "empty-space" structures for via placement (now that we know
1268 * appropriate keepaways for all the fixed elements) */
1269 for (i
= 0; i
< max_group
; i
++)
1271 POINTER_LOOP (&layergroupboxes
[i
]);
1273 routebox_t
*rb
= (routebox_t
*) * ptr
;
1274 if (!rb
->flags
.clear_poly
)
1275 mtspace_add (rd
->mtspace
, &rb
->box
, FIXED
, rb
->style
->Keepaway
);
1280 /* free pointer lists */
1281 for (i
= 0; i
< max_group
; i
++)
1282 FreePointerListMemory (&layergroupboxes
[i
]);
1288 DestroyRouteData (routedata_t
** rd
)
1291 for (i
= 0; i
< max_group
; i
++)
1292 r_destroy_tree (&(*rd
)->layergrouptree
[i
]);
1293 if (AutoRouteParameters
.use_vias
)
1294 mtspace_destroy (&(*rd
)->mtspace
);
1299 /*-----------------------------------------------------------------
1300 * routebox reference counting.
1304 * \brief Increment the reference count on a routebox.
1307 RB_up_count (routebox_t
* rb
)
1309 assert (rb
->flags
.homeless
);
1314 * \brief Decrement the reference count on a routebox, freeing if this
1315 * box becomes unused.
1318 RB_down_count (routebox_t
* rb
)
1320 assert (rb
->type
== EXPANSION_AREA
);
1321 assert (rb
->flags
.homeless
);
1322 assert (rb
->refcount
> 0);
1323 if (--rb
->refcount
== 0)
1325 if (rb
->parent
.expansion_area
->flags
.homeless
)
1326 RB_down_count (rb
->parent
.expansion_area
);
1331 /*-----------------------------------------------------------------
1332 * Rectangle-expansion routing code.
1336 ResetSubnet (routebox_t
* net
)
1339 /* reset connectivity of everything on this net */
1340 LIST_LOOP (net
, same_net
, rb
);
1341 rb
->same_subnet
= rb
->original_subnet
;
1345 static inline cost_t
1346 cost_to_point_on_layer (const CheapPointType
* p1
,
1347 const CheapPointType
* p2
, Cardinal point_layer
)
1349 cost_t x_dist
= p1
->X
- p2
->X
, y_dist
= p1
->Y
- p2
->Y
, r
;
1350 x_dist
*= x_cost
[point_layer
];
1351 y_dist
*= y_cost
[point_layer
];
1352 /* cost is proportional to orthogonal distance. */
1353 r
= ABS (x_dist
) + ABS (y_dist
);
1354 if (p1
->X
!= p2
->X
&& p1
->Y
!= p2
->Y
)
1355 r
+= AutoRouteParameters
.JogPenalty
;
1360 cost_to_point (const CheapPointType
* p1
, Cardinal point_layer1
,
1361 const CheapPointType
* p2
, Cardinal point_layer2
)
1363 cost_t r
= cost_to_point_on_layer (p1
, p2
, point_layer1
);
1364 /* apply via cost penalty if layers differ */
1365 if (point_layer1
!= point_layer2
)
1366 r
+= AutoRouteParameters
.ViaCost
;
1371 * \brief Return the minimum *cost* from a point to a box on any layer.
1373 * It's safe to return a smaller than minimum cost.
1376 cost_to_layerless_box (const CheapPointType
* p
, Cardinal point_layer
,
1379 CheapPointType p2
= closest_point_in_box (p
, b
);
1380 register cost_t c1
, c2
;
1388 return c1
* AutoRouteParameters
.MinPenalty
+ c2
;
1390 return c2
* AutoRouteParameters
.MinPenalty
+ c1
;
1394 * \brief Get to actual pins/pad target coordinates.
1397 TargetPoint (CheapPointType
* nextpoint
, const routebox_t
* target
)
1399 if (target
->type
== PIN
)
1401 nextpoint
->X
= target
->parent
.pin
->X
;
1402 nextpoint
->Y
= target
->parent
.pin
->Y
;
1405 else if (target
->type
== PAD
)
1407 if (abs (target
->parent
.pad
->Point1
.X
- nextpoint
->X
) <
1408 abs (target
->parent
.pad
->Point2
.X
- nextpoint
->X
))
1409 nextpoint
->X
= target
->parent
.pad
->Point1
.X
;
1411 nextpoint
->X
= target
->parent
.pad
->Point2
.X
;
1412 if (abs (target
->parent
.pad
->Point1
.Y
- nextpoint
->Y
) <
1413 abs (target
->parent
.pad
->Point2
.Y
- nextpoint
->Y
))
1414 nextpoint
->Y
= target
->parent
.pad
->Point1
.Y
;
1416 nextpoint
->Y
= target
->parent
.pad
->Point2
.Y
;
1421 nextpoint
->X
= CENTER_X (target
->sbox
);
1422 nextpoint
->Y
= CENTER_Y (target
->sbox
);
1428 * \brief Return the *minimum cost* from a point to a route box,
1429 * including possible via costs if the route box is on a different
1432 * Assume routbox is bloated unless it is an expansion area.
1435 cost_to_routebox (const CheapPointType
* p
, Cardinal point_layer
,
1436 const routebox_t
* rb
)
1438 register cost_t trial
= 0;
1439 CheapPointType p2
= closest_point_in_routebox (p
, rb
);
1440 if (!usedGroup
[point_layer
] || !usedGroup
[rb
->group
])
1441 trial
= AutoRouteParameters
.NewLayerPenalty
;
1442 if ((p2
.X
- p
->X
) * (p2
.Y
- p
->Y
) != 0)
1443 trial
+= AutoRouteParameters
.JogPenalty
;
1444 /* special case for defered via searching */
1445 if (point_layer
> max_group
|| point_layer
== rb
->group
)
1446 return trial
+ ABS (p2
.X
- p
->X
) + ABS (p2
.Y
- p
->Y
);
1447 /* if this target is only a via away, then the via is cheaper than the congestion */
1448 if (p
->X
== p2
.X
&& p
->Y
== p2
.Y
)
1450 trial
+= AutoRouteParameters
.ViaCost
;
1451 trial
+= ABS (p2
.X
- p
->X
) + ABS (p2
.Y
- p
->Y
);
1457 bloat_routebox (routebox_t
* rb
)
1461 assert (__routebox_is_good (rb
));
1463 if (rb
->flags
.nobloat
)
1466 /* Obstacle exclusion zones get bloated by the larger of
1467 * the two required clearances plus half the track width.
1469 keepaway
= MAX (AutoRouteParameters
.style
->Keepaway
, rb
->style
->Keepaway
);
1470 r
= bloat_box (&rb
->sbox
, keepaway
+
1471 HALF_THICK (AutoRouteParameters
.style
->Thick
));
1476 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */
1479 * \brief Makes a line on the solder layer silk surrounding the box.
1482 showbox (BoxType b
, Dimension thickness
, int group
)
1485 LayerType
*SLayer
= LAYER_PTR (group
);
1488 if (showboxen
!= -1 && showboxen
!= group
)
1493 ddraw
->set_line_width (ar_gc
, thickness
);
1494 ddraw
->set_line_cap (ar_gc
, Trace_Cap
);
1495 ddraw
->set_color (ar_gc
, SLayer
->Color
);
1497 ddraw
->draw_line (ar_gc
, b
.X1
, b
.Y1
, b
.X2
, b
.Y1
);
1498 ddraw
->draw_line (ar_gc
, b
.X1
, b
.Y2
, b
.X2
, b
.Y2
);
1499 ddraw
->draw_line (ar_gc
, b
.X1
, b
.Y1
, b
.X1
, b
.Y2
);
1500 ddraw
->draw_line (ar_gc
, b
.X2
, b
.Y1
, b
.X2
, b
.Y2
);
1504 if (b
.Y1
== b
.Y2
|| b
.X1
== b
.X2
)
1506 line
= CreateNewLineOnLayer (LAYER_PTR (top_silk_layer
),
1507 b
.X1
, b
.Y1
, b
.X2
, b
.Y1
, thickness
, 0,
1509 AddObjectToCreateUndoList (LINE_TYPE
,
1510 LAYER_PTR (top_silk_layer
), line
,
1514 line
= CreateNewLineOnLayer (LAYER_PTR (top_silk_layer
),
1515 b
.X1
, b
.Y2
, b
.X2
, b
.Y2
, thickness
, 0,
1517 AddObjectToCreateUndoList (LINE_TYPE
,
1518 LAYER_PTR (bottom_silk_layer
),
1521 line
= CreateNewLineOnLayer (LAYER_PTR (top_silk_layer
),
1522 b
.X1
, b
.Y1
, b
.X1
, b
.Y2
, thickness
, 0,
1524 AddObjectToCreateUndoList (LINE_TYPE
,
1525 LAYER_PTR (top_silk_layer
), line
,
1529 line
= CreateNewLineOnLayer (LAYER_PTR (top_silk_layer
),
1530 b
.X2
, b
.Y1
, b
.X2
, b
.Y2
, thickness
, 0,
1532 AddObjectToCreateUndoList (LINE_TYPE
,
1533 LAYER_PTR (top_silk_layer
),
1540 #if defined(ROUTE_DEBUG)
1542 showedge (edge_t
* e
)
1544 BoxType
*b
= (BoxType
*) e
->rb
;
1549 ddraw
->set_line_cap (ar_gc
, Trace_Cap
);
1550 ddraw
->set_line_width (ar_gc
, 1);
1551 ddraw
->set_color (ar_gc
, Settings
.MaskColor
);
1553 switch (e
->expand_dir
)
1556 ddraw
->draw_line (ar_gc
, b
->X1
, b
->Y1
, b
->X2
, b
->Y1
);
1559 ddraw
->draw_line (ar_gc
, b
->X1
, b
->Y2
, b
->X2
, b
->Y2
);
1562 ddraw
->draw_line (ar_gc
, b
->X1
, b
->Y1
, b
->X1
, b
->Y2
);
1565 ddraw
->draw_line (ar_gc
, b
->X2
, b
->Y1
, b
->X2
, b
->Y2
);
1573 #if defined(ROUTE_DEBUG)
1575 showroutebox (routebox_t
* rb
)
1577 showbox (rb
->sbox
, rb
->flags
.source
? 20 : (rb
->flags
.target
? 10 : 1),
1578 rb
->flags
.is_via
? top_silk_layer
: rb
->group
);
1583 * \brief Return a "parent" of this edge which immediately precedes it
1587 route_parent (routebox_t
* rb
)
1589 while (rb
->flags
.homeless
&& !rb
->flags
.is_via
&& !rb
->flags
.is_thermal
)
1591 assert (rb
->type
== EXPANSION_AREA
);
1592 rb
= rb
->parent
.expansion_area
;
1599 path_conflicts (routebox_t
* rb
, routebox_t
* conflictor
, bool branch
)
1602 rb
->conflicts_with
= vector_duplicate (rb
->conflicts_with
);
1603 else if (!rb
->conflicts_with
)
1604 rb
->conflicts_with
= vector_create ();
1605 vector_append (rb
->conflicts_with
, conflictor
);
1606 return rb
->conflicts_with
;
1610 * \brief Touch everything (except fixed) on each net found
1611 * in the conflicts vector. If the vector is different
1612 * from the last one touched, untouch the last batch
1613 * and touch the new one. Always call with touch=1
1614 * (except for recursive call). Call with NULL, 1 to
1615 * clear the last batch touched.
1617 * Touched items become invisible to current path
1618 * so we don't encounter the same conflictor more
1622 touch_conflicts (vector_t
* conflicts
, int touch
)
1624 static vector_t
*last
= NULL
;
1625 static int last_size
= 0;
1630 if (last
&& conflicts
!= last
)
1631 touch_conflicts (last
, 0);
1637 n
= vector_size (conflicts
);
1640 routebox_t
*rb
= (routebox_t
*) vector_element (conflicts
, i
);
1642 LIST_LOOP (rb
, same_net
, p
);
1643 if (!p
->flags
.fixed
)
1644 p
->flags
.touched
= touch
;
1657 * \brief Return a "parent" of this edge which resides in a r-tree
1660 * Actually, this "parent" *may* be a via box, which doesn't live in
1664 nonhomeless_parent (routebox_t
* rb
)
1666 return route_parent (rb
);
1670 * \brief Some routines to find the minimum *cost* from a cost point to
1671 * a target (any target).
1673 struct mincost_target_closure
1675 const CheapPointType
*CostPoint
;
1676 Cardinal CostPointLayer
;
1677 routebox_t
*nearest
;
1678 cost_t nearest_cost
;
1681 __region_within_guess (const BoxType
* region
, void *cl
)
1683 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1684 cost_t cost_to_region
;
1685 if (mtc
->nearest
== NULL
)
1688 cost_to_layerless_box (mtc
->CostPoint
, mtc
->CostPointLayer
, region
);
1689 assert (cost_to_region
>= 0);
1690 /* if no guess yet, all regions are "close enough" */
1691 /* note that cost is *strictly more* than minimum distance, so we'll
1692 * always search a region large enough. */
1693 return (cost_to_region
< mtc
->nearest_cost
);
1696 __found_new_guess (const BoxType
* box
, void *cl
)
1698 struct mincost_target_closure
*mtc
= (struct mincost_target_closure
*) cl
;
1699 routebox_t
*guess
= (routebox_t
*) box
;
1700 cost_t cost_to_guess
=
1701 cost_to_routebox (mtc
->CostPoint
, mtc
->CostPointLayer
, guess
);
1702 assert (cost_to_guess
>= 0);
1703 /* if this is cheaper than previous guess... */
1704 if (cost_to_guess
< mtc
->nearest_cost
)
1706 mtc
->nearest
= guess
;
1707 mtc
->nearest_cost
= cost_to_guess
; /* this is our new guess! */
1711 return 0; /* not less expensive than our last guess */
1717 * \c target_guess is our guess at what the nearest target is, or
1718 * \c NULL if we just plum don't have a clue.
1721 mincost_target_to_point (const CheapPointType
* CostPoint
,
1722 Cardinal CostPointLayer
,
1723 rtree_t
* targets
, routebox_t
* target_guess
)
1725 struct mincost_target_closure mtc
;
1726 assert (target_guess
== NULL
|| target_guess
->flags
.target
); /* this is a target, right? */
1727 mtc
.CostPoint
= CostPoint
;
1728 mtc
.CostPointLayer
= CostPointLayer
;
1729 mtc
.nearest
= target_guess
;
1732 cost_to_routebox (mtc
.CostPoint
, mtc
.CostPointLayer
, mtc
.nearest
);
1734 mtc
.nearest_cost
= EXPENSIVE
;
1735 r_search (targets
, NULL
, __region_within_guess
, __found_new_guess
, &mtc
);
1736 assert (mtc
.nearest
!= NULL
&& mtc
.nearest_cost
>= 0);
1737 assert (mtc
.nearest
->flags
.target
); /* this is a target, right? */
1742 * \brief Create edge from field values.
1744 * mincost_target_guess can be \c NULL .
1747 CreateEdge (routebox_t
* rb
,
1748 Coord CostPointX
, Coord CostPointY
,
1749 cost_t cost_to_point
,
1750 routebox_t
* mincost_target_guess
,
1751 direction_t expand_dir
, rtree_t
* targets
)
1754 assert (__routebox_is_good (rb
));
1755 e
= (edge_t
*)malloc (sizeof (*e
));
1756 memset ((void *) e
, 0, sizeof (*e
));
1759 if (rb
->flags
.homeless
)
1761 e
->cost_point
.X
= CostPointX
;
1762 e
->cost_point
.Y
= CostPointY
;
1763 e
->cost_to_point
= cost_to_point
;
1764 e
->flags
.via_search
= 0;
1765 /* if this edge is created in response to a target, use it */
1768 mincost_target_to_point (&e
->cost_point
, rb
->group
,
1769 targets
, mincost_target_guess
);
1771 e
->mincost_target
= mincost_target_guess
;
1772 e
->expand_dir
= expand_dir
;
1773 assert (e
->rb
&& e
->mincost_target
); /* valid edge? */
1774 assert (!e
->flags
.is_via
|| e
->expand_dir
== ALL
);
1775 /* cost point should be on edge (unless this is a plane/via/conflict edge) */
1777 assert (rb
->type
== PLANE
|| rb
->conflicts_with
!= NULL
|| rb
->flags
.is_via
1778 || rb
->flags
.is_thermal
1779 || ((expand_dir
== NORTH
|| expand_dir
== SOUTH
) ? rb
->sbox
.X1
<=
1780 CostPointX
&& CostPointX
< rb
->sbox
.X2
1781 && CostPointY
== (expand_dir
==
1782 NORTH
? rb
->sbox
.Y1
: rb
->sbox
.Y2
- 1) :
1783 /* expand_dir==EAST || expand_dir==WEST */
1784 rb
->sbox
.Y1
<= CostPointY
&& CostPointY
< rb
->sbox
.Y2
&&
1785 CostPointX
== (expand_dir
==
1786 EAST
? rb
->sbox
.X2
- 1 : rb
->sbox
.X1
)));
1788 assert (__edge_is_good (e
));
1794 * \brief Create edge, using previous edge to fill in defaults.
1796 * Most of the work here is in determining a new cost point.
1799 CreateEdge2 (routebox_t
* rb
, direction_t expand_dir
,
1800 edge_t
* previous_edge
, rtree_t
* targets
, routebox_t
* guess
)
1803 CheapPointType thiscost
, prevcost
;
1806 assert (rb
&& previous_edge
);
1807 /* okay, find cheapest costpoint to costpoint of previous edge */
1808 thisbox
= edge_to_box (rb
, expand_dir
);
1809 prevcost
= previous_edge
->cost_point
;
1810 /* find point closest to target */
1811 thiscost
= closest_point_in_box (&prevcost
, &thisbox
);
1812 /* compute cost-to-point */
1813 d
= cost_to_point_on_layer (&prevcost
, &thiscost
, rb
->group
);
1814 /* add in jog penalty */
1815 if (previous_edge
->expand_dir
!= expand_dir
)
1816 d
+= AutoRouteParameters
.JogPenalty
;
1817 /* okay, new edge! */
1818 return CreateEdge (rb
, thiscost
.X
, thiscost
.Y
,
1819 previous_edge
->cost_to_point
+ d
,
1820 guess
? guess
: previous_edge
->mincost_target
,
1821 expand_dir
, targets
);
1825 * \brief Create via edge, using previous edge to fill in defaults.
1828 CreateViaEdge (const BoxType
* area
, Cardinal group
,
1829 routebox_t
* parent
, edge_t
* previous_edge
,
1830 conflict_t to_site_conflict
,
1831 conflict_t through_site_conflict
, rtree_t
* targets
)
1834 CheapPointType costpoint
;
1840 scale
[1] = AutoRouteParameters
.LastConflictPenalty
;
1841 scale
[2] = AutoRouteParameters
.ConflictPenalty
;
1843 assert (box_is_good (area
));
1844 assert (AutoRouteParameters
.with_conflicts
||
1845 (to_site_conflict
== NO_CONFLICT
&&
1846 through_site_conflict
== NO_CONFLICT
));
1847 rb
= CreateExpansionArea (area
, group
, parent
, true, previous_edge
);
1848 rb
->flags
.is_via
= 1;
1849 rb
->came_from
= ALL
;
1850 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES)
1852 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */
1853 /* for planes, choose a point near the target */
1854 if (previous_edge
->flags
.in_plane
)
1858 /* find a target near this via box */
1859 pnt
.X
= CENTER_X (*area
);
1860 pnt
.Y
= CENTER_Y (*area
);
1861 target
= mincost_target_to_point (&pnt
, rb
->group
,
1863 previous_edge
->mincost_target
);
1864 /* now find point near the target */
1865 pnt
.X
= CENTER_X (target
->box
);
1866 pnt
.Y
= CENTER_Y (target
->box
);
1867 costpoint
= closest_point_in_routebox (&pnt
, rb
);
1868 /* we moved from the previous cost point through the plane which is free travel */
1870 (scale
[through_site_conflict
] *
1871 cost_to_point (&costpoint
, group
, &costpoint
,
1872 previous_edge
->rb
->group
));
1874 CreateEdge (rb
, costpoint
.X
, costpoint
.Y
,
1875 previous_edge
->cost_to_point
+ d
, target
, ALL
, NULL
);
1876 ne
->mincost_target
= target
;
1881 target
= previous_edge
->mincost_target
;
1882 costpoint
= closest_point_in_routebox (&previous_edge
->cost_point
, rb
);
1884 (scale
[to_site_conflict
] *
1885 cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1886 previous_edge
->rb
->group
)) +
1887 (scale
[through_site_conflict
] *
1888 cost_to_point (&costpoint
, group
, &costpoint
,
1889 previous_edge
->rb
->group
));
1890 /* if the target is just this via away, then this via is cheaper */
1891 if (target
->group
== group
&&
1892 point_in_shrunk_box (target
, costpoint
.X
, costpoint
.Y
))
1893 d
-= AutoRouteParameters
.ViaCost
/ 2;
1895 CreateEdge (rb
, costpoint
.X
, costpoint
.Y
,
1896 previous_edge
->cost_to_point
+ d
,
1897 previous_edge
->mincost_target
, ALL
, targets
);
1899 ne
->flags
.is_via
= 1;
1900 ne
->flags
.via_conflict_level
= to_site_conflict
;
1901 assert (__edge_is_good (ne
));
1906 * \brief Create "interior" edge for routing with conflicts.
1908 * Presently once we "jump inside" the conflicting object
1909 * we consider it a routing highway to travel inside since
1910 * it will become available if the conflict is elliminated.
1911 * That is why we ignore the interior_edge argument.
1914 CreateEdgeWithConflicts (const BoxType
* interior_edge
,
1915 routebox_t
* container
, edge_t
* previous_edge
,
1916 cost_t cost_penalty_to_box
, rtree_t
* targets
)
1919 CheapPointType costpoint
;
1922 assert (interior_edge
&& container
&& previous_edge
&& targets
);
1923 assert (!container
->flags
.homeless
);
1924 assert (AutoRouteParameters
.with_conflicts
);
1925 assert (container
->flags
.touched
== 0);
1926 assert (previous_edge
->rb
->group
== container
->group
);
1927 /* use the caller's idea of what this box should be */
1929 CreateExpansionArea (interior_edge
, previous_edge
->rb
->group
,
1930 previous_edge
->rb
, true, previous_edge
);
1931 path_conflicts (rb
, container
, true); /* crucial! */
1933 closest_point_in_box (&previous_edge
->cost_point
, interior_edge
);
1935 cost_to_point_on_layer (&costpoint
, &previous_edge
->cost_point
,
1936 previous_edge
->rb
->group
);
1937 d
*= cost_penalty_to_box
;
1938 d
+= previous_edge
->cost_to_point
;
1939 ne
= CreateEdge (rb
, costpoint
.X
, costpoint
.Y
, d
, NULL
, ALL
, targets
);
1940 ne
->flags
.is_interior
= 1;
1941 assert (__edge_is_good (ne
));
1946 KillEdge (void *edge
)
1948 edge_t
*e
= (edge_t
*) edge
;
1950 if (e
->rb
->flags
.homeless
)
1951 RB_down_count (e
->rb
);
1952 if (e
->flags
.via_search
)
1953 mtsFreeWork (&e
->work
);
1958 DestroyEdge (edge_t
** e
)
1966 * \brief Cost function for an edge.
1969 edge_cost (const edge_t
* e
, const cost_t too_big
)
1971 cost_t penalty
= e
->cost_to_point
;
1972 if (e
->rb
->flags
.is_thermal
|| e
->rb
->type
== PLANE
)
1973 return penalty
; /* thermals are cheap */
1974 if (penalty
> too_big
)
1977 /* cost_to_routebox adds in our via correction, too. */
1979 cost_to_routebox (&e
->cost_point
, e
->rb
->group
, e
->mincost_target
);
1983 * \brief Given an edge of a box, return a box containing exactly the
1984 * points on that edge.
1986 * Note that the return box is treated as closed; that is, the bottom
1987 * and right "edges" consist of points (just barely) not in the
1991 edge_to_box (const routebox_t
* rb
, direction_t expand_dir
)
1993 BoxType b
= shrink_routebox (rb
);
1994 /* narrow box down to just the appropriate edge */
2018 BoxType left
, center
, right
;
2019 bool is_valid_left
, is_valid_center
, is_valid_right
;
2022 static struct broken_boxes
2023 break_box_edge (const BoxType
* original
, direction_t which_edge
,
2024 routebox_t
* breaker
)
2026 BoxType origbox
, breakbox
;
2027 struct broken_boxes result
;
2029 assert (original
&& breaker
);
2031 origbox
= *original
;
2032 breakbox
= bloat_routebox (breaker
);
2033 ROTATEBOX_TO_NORTH (origbox
, which_edge
);
2034 ROTATEBOX_TO_NORTH (breakbox
, which_edge
);
2035 result
.right
.Y1
= result
.center
.Y1
= result
.left
.Y1
= origbox
.Y1
;
2036 result
.right
.Y2
= result
.center
.Y2
= result
.left
.Y2
= origbox
.Y1
+ 1;
2037 /* validity of breaker is not important because the boxes are marked invalid */
2038 //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1);
2039 /* left edge piece */
2040 result
.left
.X1
= origbox
.X1
;
2041 result
.left
.X2
= breakbox
.X1
;
2042 /* center (ie blocked) edge piece */
2043 result
.center
.X1
= MAX (breakbox
.X1
, origbox
.X1
);
2044 result
.center
.X2
= MIN (breakbox
.X2
, origbox
.X2
);
2045 /* right edge piece */
2046 result
.right
.X1
= breakbox
.X2
;
2047 result
.right
.X2
= origbox
.X2
;
2049 result
.is_valid_left
= (result
.left
.X1
< result
.left
.X2
);
2050 result
.is_valid_center
= (result
.center
.X1
< result
.center
.X2
);
2051 result
.is_valid_right
= (result
.right
.X1
< result
.right
.X2
);
2053 ROTATEBOX_FROM_NORTH (result
.left
, which_edge
);
2054 ROTATEBOX_FROM_NORTH (result
.center
, which_edge
);
2055 ROTATEBOX_FROM_NORTH (result
.right
, which_edge
);
2062 share_edge (const BoxType
* child
, const BoxType
* parent
)
2065 (child
->X1
== parent
->X2
|| child
->X2
== parent
->X1
||
2066 child
->Y1
== parent
->Y2
|| child
->Y2
== parent
->Y1
) &&
2067 ((parent
->X1
<= child
->X1
&& child
->X2
<= parent
->X2
) ||
2068 (parent
->Y1
<= child
->Y1
&& child
->Y2
<= parent
->Y2
));
2071 edge_intersect (const BoxType
* child
, const BoxType
* parent
)
2074 (child
->X1
<= parent
->X2
) && (child
->X2
>= parent
->X1
) &&
2075 (child
->Y1
<= parent
->Y2
) && (child
->Y2
>= parent
->Y1
);
2080 * \brief Area is the expansion area, on layer group 'group'.
2082 * 'parent' is the immediately preceding expansion area, for backtracing.
2083 * 'lastarea' is the last expansion area created, we string these
2084 * together in a loop so we can remove them all easily at the end.
2087 CreateExpansionArea (const BoxType
* area
, Cardinal group
,
2088 routebox_t
* parent
,
2089 bool relax_edge_requirements
, edge_t
* src_edge
)
2091 routebox_t
*rb
= (routebox_t
*) malloc (sizeof (*rb
));
2092 memset ((void *) rb
, 0, sizeof (*rb
));
2093 assert (area
&& parent
);
2094 init_const_box (rb
, area
->X1
, area
->Y1
, area
->X2
, area
->Y2
, 0);
2096 rb
->type
= EXPANSION_AREA
;
2097 /* should always share edge or overlap with parent */
2098 assert (relax_edge_requirements
? box_intersect (&rb
->sbox
, &parent
->sbox
)
2099 : share_edge (&rb
->sbox
, &parent
->sbox
));
2100 rb
->parent
.expansion_area
= route_parent (parent
);
2102 closest_point_in_box (&rb
->parent
.expansion_area
->cost_point
, area
);
2104 rb
->parent
.expansion_area
->cost
+
2105 cost_to_point_on_layer (&rb
->parent
.expansion_area
->cost_point
,
2106 &rb
->cost_point
, rb
->group
);
2107 assert (relax_edge_requirements
? edge_intersect (&rb
->sbox
, &parent
->sbox
)
2108 : share_edge (&rb
->sbox
, &parent
->sbox
));
2109 if (rb
->parent
.expansion_area
->flags
.homeless
)
2110 RB_up_count (rb
->parent
.expansion_area
);
2111 rb
->flags
.homeless
= 1;
2112 rb
->flags
.nobloat
= 1;
2113 rb
->style
= AutoRouteParameters
.style
;
2114 rb
->conflicts_with
= parent
->conflicts_with
;
2115 /* we will never link an EXPANSION_AREA into the nets because they
2116 * are *ONLY* used for path searching. No need to call InitLists ()
2118 rb
->came_from
= src_edge
->expand_dir
;
2119 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
2121 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */
2125 /*------ Expand ------*/
2129 routebox_t
*n
, *e
, *s
, *w
;
2131 BoxType inflated
, orig
;
2136 * \brief Test method for Expand().
2138 * This routebox potentially is a blocker limiting expansion
2139 * if this is so, we limit the inflate box so another exactly
2140 * like it wouldn't be seen. We do this while keep the inflated
2141 * box as large as possible.
2144 __Expand_this_rect (const BoxType
* box
, void *cl
)
2146 struct E_result
*res
= (struct E_result
*) cl
;
2147 routebox_t
*rb
= (routebox_t
*) box
;
2149 Coord dn
, de
, ds
, dw
, bloat
;
2151 /* we don't see conflicts already encountered */
2152 if (rb
->flags
.touched
)
2155 /* The inflated box outer edges include its own
2156 * track width plus its own keepaway.
2158 * To check for intersection, we need to expand
2159 * anything with greater keepaway by its excess
2162 * If something has nobloat then we need to shrink
2163 * the inflated box back and see if it still touches.
2166 if (rb
->flags
.nobloat
)
2170 if (rbox
.X2
<= res
->inflated
.X1
+ bloat
||
2171 rbox
.X1
>= res
->inflated
.X2
- bloat
||
2172 rbox
.Y1
>= res
->inflated
.Y2
- bloat
||
2173 rbox
.Y2
<= res
->inflated
.Y1
+ bloat
)
2174 return 0; /* doesn't touch */
2178 if (rb
->style
->Keepaway
> res
->keep
)
2179 rbox
= bloat_box (&rb
->sbox
, rb
->style
->Keepaway
- res
->keep
);
2183 if (rbox
.X2
<= res
->inflated
.X1
|| rbox
.X1
>= res
->inflated
.X2
2184 || rbox
.Y1
>= res
->inflated
.Y2
|| rbox
.Y2
<= res
->inflated
.Y1
)
2185 return 0; /* doesn't touch */
2189 /* this is an intersecting box; it has to jump through a few more hoops */
2190 if (rb
== res
->parent
|| rb
->parent
.expansion_area
== res
->parent
)
2191 return 0; /* don't see what we came from */
2193 /* if we are expanding a source edge, don't let other sources
2194 * or their expansions stop us.
2197 if (res
->parent
->flags
.source
)
2198 if (rb
->flags
.source
2199 || (rb
->type
== EXPANSION_AREA
2200 && rb
->parent
.expansion_area
->flags
.source
))
2204 /* we ignore via expansion boxes because maybe its
2205 * cheaper to get there without the via through
2206 * the path we're exploring now.
2208 if (rb
->flags
.is_via
&& rb
->type
== EXPANSION_AREA
)
2211 if (rb
->type
== PLANE
) /* expanding inside a plane is not good */
2213 if (rbox
.X1
< res
->orig
.X1
&& rbox
.X2
> res
->orig
.X2
&&
2214 rbox
.Y1
< res
->orig
.Y1
&& rbox
.Y2
> res
->orig
.Y2
)
2216 res
->inflated
= bloat_box (&res
->orig
, res
->bloat
);
2220 /* calculate the distances from original box to this blocker */
2221 dn
= de
= ds
= dw
= 0;
2222 if (!(res
->done
& _NORTH
) && rbox
.Y1
<= res
->orig
.Y1
2223 && rbox
.Y2
> res
->inflated
.Y1
)
2224 dn
= res
->orig
.Y1
- rbox
.Y2
;
2225 if (!(res
->done
& _EAST
) && rbox
.X2
>= res
->orig
.X2
2226 && rbox
.X1
< res
->inflated
.X2
)
2227 de
= rbox
.X1
- res
->orig
.X2
;
2228 if (!(res
->done
& _SOUTH
) && rbox
.Y2
>= res
->orig
.Y2
2229 && rbox
.Y1
< res
->inflated
.Y2
)
2230 ds
= rbox
.Y1
- res
->orig
.Y2
;
2231 if (!(res
->done
& _WEST
) && rbox
.X1
<= res
->orig
.X1
2232 && rbox
.X2
> res
->inflated
.X1
)
2233 dw
= res
->orig
.X1
- rbox
.X2
;
2234 if (dn
<= 0 && de
<= 0 && ds
<= 0 && dw
<= 0)
2236 /* now shrink the inflated box to the largest blocking direction */
2237 if (dn
>= de
&& dn
>= ds
&& dn
>= dw
)
2239 res
->inflated
.Y1
= rbox
.Y2
- bloat
;
2242 else if (de
>= ds
&& de
>= dw
)
2244 res
->inflated
.X2
= rbox
.X1
+ bloat
;
2249 res
->inflated
.Y2
= rbox
.Y1
+ bloat
;
2254 res
->inflated
.X1
= rbox
.X2
- bloat
;
2261 boink_box (routebox_t
* rb
, struct E_result
*res
, direction_t dir
)
2264 if (rb
->style
->Keepaway
> res
->keep
)
2265 bloat
= res
->keep
- rb
->style
->Keepaway
;
2268 if (rb
->flags
.nobloat
)
2274 if (rb
->sbox
.X2
<= res
->inflated
.X1
+ bloat
2275 || rb
->sbox
.X1
>= res
->inflated
.X2
- bloat
)
2280 if (rb
->sbox
.Y1
>= res
->inflated
.Y2
- bloat
2281 || rb
->sbox
.Y2
<= res
->inflated
.Y1
+ bloat
)
2292 * \brief Main Expand routine.
2294 * The expansion probe edge includes the keepaway and half thickness
2295 * as the search is performed in order to see everything relevant.
2296 * The result is backed off by this amount before being returned.
2297 * Targets (and other no-bloat routeboxes) go all the way to touching.
2298 * This is accomplished by backing off the probe edge when checking
2299 * for touch against such an object. Usually the expanding edge
2300 * bumps into neighboring pins on the same device that require a
2301 * keepaway, preventing seeing a target immediately. Rather than await
2302 * another expansion to actually touch the target, the edge breaker code
2303 * looks past the keepaway to see these targets even though they
2304 * weren't actually touched in the expansion.
2307 Expand (rtree_t
* rtree
, edge_t
* e
, const BoxType
* box
)
2309 static struct E_result ans
;
2310 int noshrink
; /* bit field of which edges to not shrink */
2312 ans
.bloat
= AutoRouteParameters
.bloat
;
2314 ans
.n
= ans
.e
= ans
.s
= ans
.w
= NULL
;
2316 /* the inflated box must be bloated in all directions that it might
2317 * hit something in order to guarantee that we see object in the
2318 * tree it might hit. The tree holds objects bloated by their own
2319 * keepaway so we are guaranteed to honor that.
2321 switch (e
->expand_dir
)
2324 ans
.inflated
.X1
= (e
->rb
->came_from
== EAST
? ans
.orig
.X1
: 0);
2325 ans
.inflated
.Y1
= (e
->rb
->came_from
== SOUTH
? ans
.orig
.Y1
: 0);
2327 (e
->rb
->came_from
== WEST
? ans
.orig
.X2
: PCB
->MaxWidth
);
2329 (e
->rb
->came_from
== NORTH
? ans
.orig
.Y2
: PCB
->MaxHeight
);
2330 if (e
->rb
->came_from
== NORTH
)
2331 ans
.done
= noshrink
= _SOUTH
;
2332 else if (e
->rb
->came_from
== EAST
)
2333 ans
.done
= noshrink
= _WEST
;
2334 else if (e
->rb
->came_from
== SOUTH
)
2335 ans
.done
= noshrink
= _NORTH
;
2336 else if (e
->rb
->came_from
== WEST
)
2337 ans
.done
= noshrink
= _EAST
;
2339 ans
.done
= noshrink
= 0;
2342 ans
.done
= _SOUTH
+ _EAST
+ _WEST
;
2344 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2345 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2346 ans
.inflated
.Y2
= box
->Y2
;
2347 ans
.inflated
.Y1
= 0; /* far north */
2350 ans
.done
= _SOUTH
+ _WEST
;
2352 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2353 ans
.inflated
.X2
= PCB
->MaxWidth
;
2354 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2355 ans
.inflated
.Y1
= 0;
2358 ans
.done
= _NORTH
+ _SOUTH
+ _WEST
;
2360 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2361 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2362 ans
.inflated
.X1
= box
->X1
;
2363 ans
.inflated
.X2
= PCB
->MaxWidth
;
2366 ans
.done
= _NORTH
+ _WEST
;
2368 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2369 ans
.inflated
.X2
= PCB
->MaxWidth
;
2370 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2371 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2374 ans
.done
= _NORTH
+ _EAST
+ _WEST
;
2376 ans
.inflated
.X1
= box
->X1
- ans
.bloat
;
2377 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2378 ans
.inflated
.Y1
= box
->Y1
;
2379 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2382 ans
.done
= _NORTH
+ _EAST
;
2384 ans
.inflated
.X1
= 0;
2385 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2386 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2387 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2390 ans
.done
= _NORTH
+ _SOUTH
+ _EAST
;
2392 ans
.inflated
.Y1
= box
->Y1
- ans
.bloat
;
2393 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2394 ans
.inflated
.X1
= 0;
2395 ans
.inflated
.X2
= box
->X2
;
2398 ans
.done
= _SOUTH
+ _EAST
;
2400 ans
.inflated
.X1
= 0;
2401 ans
.inflated
.X2
= box
->X2
+ ans
.bloat
;
2402 ans
.inflated
.Y2
= box
->Y2
+ ans
.bloat
;
2403 ans
.inflated
.Y1
= 0;
2406 noshrink
= ans
.done
= 0;
2409 ans
.keep
= e
->rb
->style
->Keepaway
;
2410 ans
.parent
= nonhomeless_parent (e
->rb
);
2411 r_search (rtree
, &ans
.inflated
, NULL
, __Expand_this_rect
, &ans
);
2412 /* because the overlaping boxes are found in random order, some blockers
2413 * may have limited edges prematurely, so we check if the blockers realy
2414 * are blocking, and make another try if not
2416 if (ans
.n
&& !boink_box (ans
.n
, &ans
, NORTH
))
2417 ans
.inflated
.Y1
= 0;
2420 if (ans
.e
&& !boink_box (ans
.e
, &ans
, EAST
))
2421 ans
.inflated
.X2
= PCB
->MaxWidth
;
2424 if (ans
.s
&& !boink_box (ans
.s
, &ans
, SOUTH
))
2425 ans
.inflated
.Y2
= PCB
->MaxHeight
;
2428 if (ans
.w
&& !boink_box (ans
.w
, &ans
, WEST
))
2429 ans
.inflated
.X1
= 0;
2432 if (ans
.done
!= _NORTH
+ _EAST
+ _SOUTH
+ _WEST
)
2434 r_search (rtree
, &ans
.inflated
, NULL
, __Expand_this_rect
, &ans
);
2436 if ((noshrink
& _NORTH
) == 0)
2437 ans
.inflated
.Y1
+= ans
.bloat
;
2438 if ((noshrink
& _EAST
) == 0)
2439 ans
.inflated
.X2
-= ans
.bloat
;
2440 if ((noshrink
& _SOUTH
) == 0)
2441 ans
.inflated
.Y2
-= ans
.bloat
;
2442 if ((noshrink
& _WEST
) == 0)
2443 ans
.inflated
.X1
+= ans
.bloat
;
2448 * \brief \c blocker_to_heap puts the blockers into a heap so they
2449 * can be retrieved in clockwise order. If a blocker
2450 * is also a target, it gets put into the vector too.
2451 * It returns 1 for any fixed blocker that is not part
2452 * of this net and zero otherwise.
2455 blocker_to_heap (heap_t
* heap
, routebox_t
* rb
,
2456 BoxType
* box
, direction_t dir
)
2458 BoxType b
= rb
->sbox
;
2459 if (rb
->style
->Keepaway
> AutoRouteParameters
.style
->Keepaway
)
2462 rb
->style
->Keepaway
- AutoRouteParameters
.style
->Keepaway
);
2463 b
= clip_box (&b
, box
);
2464 assert (box_is_good (&b
));
2465 /* we want to look at the blockers clockwise around the box */
2468 /* we need to use the other coordinate fraction to resolve
2469 * ties since we want the shorter of the furthest
2473 heap_insert (heap
, b
.X1
- b
.X1
/ (b
.X2
+ 1.0), rb
);
2476 heap_insert (heap
, b
.Y1
- b
.Y1
/ (b
.Y2
+ 1.0), rb
);
2479 heap_insert (heap
, -(b
.X2
+ b
.X1
/ (b
.X2
+ 1.0)), rb
);
2482 heap_insert (heap
, -(b
.Y2
+ b
.Y1
/ (b
.Y2
+ 1.0)), rb
);
2487 if (rb
->flags
.fixed
&& !rb
->flags
.target
&& !rb
->flags
.source
)
2493 * \brief This creates an EXPANSION_AREA to bridge small gaps or,
2494 * (more commonly) create a supper-thin box to provide a
2495 * home for an expansion edge.
2498 CreateBridge (const BoxType
* area
, routebox_t
* parent
, direction_t dir
)
2500 routebox_t
*rb
= (routebox_t
*) malloc (sizeof (*rb
));
2501 memset ((void *) rb
, 0, sizeof (*rb
));
2502 assert (area
&& parent
);
2503 init_const_box (rb
, area
->X1
, area
->Y1
, area
->X2
, area
->Y2
, 0);
2504 rb
->group
= parent
->group
;
2505 rb
->type
= EXPANSION_AREA
;
2506 rb
->came_from
= dir
;
2507 rb
->cost_point
= closest_point_in_box (&parent
->cost_point
, area
);
2508 rb
->cost
= parent
->cost
+ cost_to_point_on_layer (&parent
->cost_point
,
2511 rb
->parent
.expansion_area
= route_parent (parent
);
2512 if (rb
->parent
.expansion_area
->flags
.homeless
)
2513 RB_up_count (rb
->parent
.expansion_area
);
2514 rb
->flags
.homeless
= 1;
2515 rb
->flags
.nobloat
= 1;
2516 rb
->style
= parent
->style
;
2517 rb
->conflicts_with
= parent
->conflicts_with
;
2518 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES)
2525 * \brief \c moveable_edge prepares the new search edges based on the
2526 * starting box, direction and blocker if any.
2529 moveable_edge (vector_t
* result
, const BoxType
* box
, direction_t dir
,
2531 routebox_t
* blocker
, edge_t
* e
, rtree_t
* targets
,
2532 struct routeone_state
*s
, rtree_t
* tree
, vector_t
* area_vec
)
2535 assert (box_is_good (box
));
2537 /* for the cardinal directions, move the box to overlap the
2538 * the parent by 1 unit. Corner expansions overlap more
2539 * and their starting boxes are pre-prepared.
2540 * Check if anything is headed off the board edges
2549 if (b
.Y1
<= AutoRouteParameters
.bloat
)
2550 return; /* off board edge */
2555 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
)
2556 return; /* off board edge */
2561 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
)
2562 return; /* off board edge */
2567 if (b
.X1
<= AutoRouteParameters
.bloat
)
2568 return; /* off board edge */
2571 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1
2572 && b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2573 return; /* off board edge */
2574 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1)
2575 dir
= EAST
; /* north off board edge */
2576 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2577 dir
= NORTH
; /* east off board edge */
2580 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1
2581 && b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2582 return; /* off board edge */
2583 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1)
2584 dir
= EAST
; /* south off board edge */
2585 if (b
.X2
>= PCB
->MaxWidth
- AutoRouteParameters
.bloat
- 1)
2586 dir
= SOUTH
; /* east off board edge */
2589 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1
2590 && b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2591 return; /* off board edge */
2592 if (b
.Y2
>= PCB
->MaxHeight
- AutoRouteParameters
.bloat
- 1)
2593 dir
= WEST
; /* south off board edge */
2594 if (b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2595 dir
= SOUTH
; /* west off board edge */
2598 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1
2599 && b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2600 return; /* off board edge */
2601 if (b
.Y1
<= AutoRouteParameters
.bloat
+ 1)
2602 dir
= WEST
; /* north off board edge */
2603 if (b
.X1
<= AutoRouteParameters
.bloat
+ 1)
2604 dir
= NORTH
; /* west off board edge */
2611 routebox_t
*nrb
= CreateBridge (&b
, rb
, dir
);
2612 /* move the cost point in corner expansions
2613 * these boxes are bigger, so move close to the target
2615 if (dir
== NE
|| dir
== SE
|| dir
== SW
|| dir
== NW
)
2619 closest_point_in_box (&nrb
->cost_point
, &e
->mincost_target
->sbox
);
2620 p
= closest_point_in_box (&p
, &b
);
2621 nrb
->cost
+= cost_to_point_on_layer (&p
, &nrb
->cost_point
,
2623 nrb
->cost_point
= p
;
2625 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
,
2626 nrb
->cost
, NULL
, dir
, targets
);
2627 vector_append (result
, ne
);
2629 else if (AutoRouteParameters
.with_conflicts
&& !blocker
->flags
.target
2630 && !blocker
->flags
.fixed
&& !blocker
->flags
.touched
&&
2631 !blocker
->flags
.source
&& blocker
->type
!= EXPANSION_AREA
)
2635 /* make a bridge to the edge of the blocker
2636 * in all directions from there
2641 b
.Y1
= blocker
->sbox
.Y2
- 1;
2644 b
.X2
= blocker
->sbox
.X1
+ 1;
2647 b
.Y2
= blocker
->sbox
.Y1
+ 1;
2650 b
.X1
= blocker
->sbox
.X2
- 1;
2655 if (!box_is_good (&b
))
2656 return; /* how did this happen ? */
2657 nrb
= CreateBridge (&b
, rb
, dir
);
2658 r_insert_entry (tree
, &nrb
->box
, 1);
2659 vector_append (area_vec
, nrb
);
2660 nrb
->flags
.homeless
= 0; /* not homeless any more */
2661 /* mark this one as conflicted */
2662 path_conflicts (nrb
, blocker
, true);
2663 /* and make an expansion edge */
2665 closest_point_in_box (&nrb
->cost_point
, &blocker
->sbox
);
2667 cost_to_point_on_layer (&nrb
->parent
.expansion_area
->cost_point
,
2669 nrb
->group
) * CONFLICT_PENALTY (blocker
);
2671 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
, nrb
->cost
,
2672 NULL
, ALL
, targets
);
2673 ne
->flags
.is_interior
= 1;
2674 vector_append (result
, ne
);
2677 else if (blocker
->type
== EXPANSION_AREA
)
2679 if (blocker
->cost
< rb
->cost
|| blocker
->cost
<= rb
->cost
+
2680 cost_to_point_on_layer (&blocker
->cost_point
, &rb
->cost_point
,
2683 if (blocker
->conflicts_with
|| rb
->conflicts_with
)
2685 /* does the blocker overlap this routebox ?? */
2686 /* does this re-parenting operation leave a memory leak? */
2687 if (blocker
->parent
.expansion_area
->flags
.homeless
)
2688 RB_down_count (blocker
->parent
.expansion_area
);
2689 blocker
->parent
.expansion_area
= rb
;
2693 else if (blocker
->flags
.target
)
2697 b
= bloat_box (&b
, 1);
2698 if (!box_intersect (&b
, &blocker
->sbox
))
2700 /* if the expansion edge stopped before touching, expand the bridge */
2704 b
.Y1
-= AutoRouteParameters
.bloat
+ 1;
2707 b
.X2
+= AutoRouteParameters
.bloat
+ 1;
2710 b
.Y2
+= AutoRouteParameters
.bloat
+ 1;
2713 b
.X1
-= AutoRouteParameters
.bloat
+ 1;
2719 assert (box_intersect (&b
, &blocker
->sbox
));
2720 b
= shrink_box (&b
, 1);
2721 nrb
= CreateBridge (&b
, rb
, dir
);
2722 r_insert_entry (tree
, &nrb
->box
, 1);
2723 vector_append (area_vec
, nrb
);
2724 nrb
->flags
.homeless
= 0; /* not homeless any more */
2725 ne
= CreateEdge (nrb
, nrb
->cost_point
.X
, nrb
->cost_point
.Y
,
2726 nrb
->cost
, blocker
, dir
, NULL
);
2727 best_path_candidate (s
, ne
, blocker
);
2742 __GatherBlockers (const BoxType
* box
, void *cl
)
2744 routebox_t
*rb
= (routebox_t
*) box
;
2745 struct break_info
*bi
= (struct break_info
*) cl
;
2748 if (bi
->parent
== rb
|| rb
->flags
.touched
||
2749 bi
->parent
->parent
.expansion_area
== rb
)
2751 if (rb
->flags
.source
&& bi
->ignore_source
)
2754 if (rb
->style
->Keepaway
> AutoRouteParameters
.style
->Keepaway
)
2757 rb
->style
->Keepaway
- AutoRouteParameters
.style
->Keepaway
);
2758 if (b
.X2
<= bi
->box
.X1
|| b
.X1
>= bi
->box
.X2
2759 || b
.Y1
>= bi
->box
.Y2
|| b
.Y2
<= bi
->box
.Y1
)
2761 return blocker_to_heap (bi
->heap
, rb
, &bi
->box
, bi
->dir
);
2765 * \brief Shrink the box to the last limit for the previous direction,
2766 * i.e. if dir is SOUTH, then this means fixing up an EAST leftover
2767 * edge, which would be the southern most edge for that example.
2769 static inline BoxType
2770 previous_edge (Coord last
, direction_t i
, const BoxType
* b
)
2785 Message ("previous edge bogus direction!");
2792 * \brief Break all the edges of the box that need breaking, handling
2793 * targets as they are found, and putting any moveable edges
2794 * in the return vector.
2797 BreakManyEdges (struct routeone_state
* s
, rtree_t
* targets
, rtree_t
* tree
,
2798 vector_t
* area_vec
, struct E_result
* ans
, routebox_t
* rb
,
2801 struct break_info bi
;
2809 edges
= vector_create ();
2810 bi
.ignore_source
= rb
->parent
.expansion_area
->flags
.source
;
2812 /* we add 2 to the bloat.
2813 * 1 will get us to the actual blocker that Expand() hit
2814 * but 1 more is needed because the new expansion edges
2815 * move out by 1 so they don't overlap their parents
2816 * this extra expansion could "trap" the edge if
2817 * there is a blocker 2 units from the original rb,
2818 * it is 1 unit from the new expansion edge which
2819 * would prevent expansion. So we want to break the
2820 * edge on it now to avoid the trap.
2823 bloat
= AutoRouteParameters
.bloat
+ 2;
2824 /* for corner expansion, we need to have a fake blocker
2825 * to prevent expansion back where we came from since
2826 * we still need to break portions of all 4 edges
2828 if (e
->expand_dir
== NE
|| e
->expand_dir
== SE
||
2829 e
->expand_dir
== SW
|| e
->expand_dir
== NW
)
2831 BoxType
*fb
= (BoxType
*) &fake
.sbox
;
2832 memset (&fake
, 0, sizeof (fake
));
2834 fake
.flags
.fixed
= 1; /* this stops expansion there */
2836 fake
.style
= AutoRouteParameters
.style
;
2838 /* the routbox_is_good checker wants a lot more! */
2839 fake
.flags
.inited
= 1;
2840 fb
= (BoxType
*) &fake
.box
;
2842 fake
.same_net
.next
= fake
.same_net
.prev
= &fake
;
2843 fake
.same_subnet
.next
= fake
.same_subnet
.prev
= &fake
;
2844 fake
.original_subnet
.next
= fake
.original_subnet
.prev
= &fake
;
2845 fake
.different_net
.next
= fake
.different_net
.prev
= &fake
;
2848 /* gather all of the blockers in heaps so they can be accessed
2849 * in clockwise order, which allows finding corners that can
2852 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
2854 /* don't break the edge we came from */
2855 if (e
->expand_dir
!= ((dir
+ 2) % 4))
2857 heap
[dir
] = heap_create ();
2858 bi
.box
= bloat_box (&rb
->sbox
, bloat
);
2859 bi
.heap
= heap
[dir
];
2861 /* convert to edge */
2865 bi
.box
.Y2
= bi
.box
.Y1
+ bloat
+ 1;
2866 /* for corner expansion, block the start edges and
2867 * limit the blocker search to only the new edge segment
2869 if (e
->expand_dir
== SE
|| e
->expand_dir
== SW
)
2870 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2871 if (e
->expand_dir
== SE
)
2872 bi
.box
.X1
= e
->rb
->sbox
.X2
;
2873 if (e
->expand_dir
== SW
)
2874 bi
.box
.X2
= e
->rb
->sbox
.X1
;
2875 rb
->n
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2878 bi
.box
.X1
= bi
.box
.X2
- bloat
- 1;
2879 /* corner, same as above */
2880 if (e
->expand_dir
== SW
|| e
->expand_dir
== NW
)
2881 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2882 if (e
->expand_dir
== SW
)
2883 bi
.box
.Y1
= e
->rb
->sbox
.Y2
;
2884 if (e
->expand_dir
== NW
)
2885 bi
.box
.Y2
= e
->rb
->sbox
.Y1
;
2886 rb
->e
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2889 bi
.box
.Y1
= bi
.box
.Y2
- bloat
- 1;
2890 /* corner, same as above */
2891 if (e
->expand_dir
== NE
|| e
->expand_dir
== NW
)
2892 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2893 if (e
->expand_dir
== NE
)
2894 bi
.box
.X1
= e
->rb
->sbox
.X2
;
2895 if (e
->expand_dir
== NW
)
2896 bi
.box
.X2
= e
->rb
->sbox
.X1
;
2897 rb
->s
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2900 bi
.box
.X2
= bi
.box
.X1
+ bloat
+ 1;
2901 /* corner, same as above */
2902 if (e
->expand_dir
== NE
|| e
->expand_dir
== SE
)
2903 blocker_to_heap (heap
[dir
], &fake
, &bi
.box
, dir
);
2904 if (e
->expand_dir
== SE
)
2905 bi
.box
.Y1
= e
->rb
->sbox
.Y2
;
2906 if (e
->expand_dir
== NE
)
2907 bi
.box
.Y2
= e
->rb
->sbox
.Y1
;
2908 rb
->w
= r_search (tree
, &bi
.box
, NULL
, __GatherBlockers
, &bi
);
2919 (rb
->n
+ rb
->e
+ rb
->s
+
2920 rb
->w
) * AutoRouteParameters
.CongestionPenalty
/ box_area (rb
->sbox
);
2922 /* now handle the blockers:
2923 * Go around the expansion area clockwise (North->East->South->West)
2924 * pulling blockers from the heap (which makes them come out in the right
2925 * order). Break the edges on the blocker and make the segments and corners
2926 * moveable as possible.
2929 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
2931 if (heap
[dir
] && !heap_is_empty (heap
[dir
]))
2933 /* pull the very first one out of the heap outside of the
2934 * heap loop because it is special; it can be part of a corner
2936 routebox_t
*blk
= (routebox_t
*) heap_remove_smallest (heap
[dir
]);
2937 BoxType b
= rb
->sbox
;
2938 struct broken_boxes broke
= break_box_edge (&b
, dir
, blk
);
2939 if (broke
.is_valid_left
)
2941 /* if last > 0, then the previous edge had a segment
2942 * joining this one, so it forms a valid corner expansion
2946 /* make a corner expansion */
2951 /* possible NE expansion */
2953 db
.Y2
= MIN (db
.Y2
, broke
.left
.Y2
);
2956 /* possible SE expansion */
2958 db
.X1
= MAX (db
.X1
, broke
.left
.X1
);
2961 /* possible SW expansion */
2963 db
.Y1
= MAX (db
.Y1
, broke
.left
.Y1
);
2969 moveable_edge (edges
, &db
, (direction_t
)(dir
+ 3), rb
, NULL
, e
, targets
,
2972 else if (dir
== NORTH
) /* north is start, so nothing "before" it */
2974 /* save for a possible corner once we've
2975 * finished circling the box
2977 first
= MAX (b
.X1
, broke
.left
.X2
);
2981 /* this is just a boring straight expansion
2982 * since the orthogonal segment was blocked
2984 moveable_edge (edges
, &broke
.left
, dir
, rb
, NULL
, e
,
2985 targets
, s
, NULL
, NULL
);
2987 } /* broke.is_valid_left */
2990 /* if the last one didn't become a corner,
2991 * we still want to expand it straight out
2992 * in the direction of the previous edge,
2993 * which it belongs to.
2995 BoxType db
= previous_edge (last
, dir
, &rb
->sbox
);
2996 moveable_edge (edges
, &db
, (direction_t
)(dir
- 1), rb
, NULL
, e
, targets
, s
,
2999 if (broke
.is_valid_center
&& !blk
->flags
.source
)
3000 moveable_edge (edges
, &broke
.center
, dir
, rb
, blk
, e
, targets
, s
,
3002 /* this is the heap extraction loop. We break out
3003 * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can
3004 * just leave stuff in the heap when it is destroyed
3006 while (broke
.is_valid_right
)
3008 /* move the box edge to the next potential free point */
3012 last
= b
.X1
= MAX (broke
.right
.X1
, b
.X1
);
3015 last
= b
.Y1
= MAX (broke
.right
.Y1
, b
.Y1
);
3018 last
= b
.X2
= MIN (broke
.right
.X2
, b
.X2
);
3021 last
= b
.Y2
= MIN (broke
.right
.Y2
, b
.Y2
);
3026 if (heap_is_empty (heap
[dir
]))
3028 blk
= (routebox_t
*)heap_remove_smallest (heap
[dir
]);
3029 broke
= break_box_edge (&b
, dir
, blk
);
3030 if (broke
.is_valid_left
)
3031 moveable_edge (edges
, &broke
.left
, dir
, rb
, NULL
, e
, targets
,
3033 if (broke
.is_valid_center
&& !blk
->flags
.source
)
3034 moveable_edge (edges
, &broke
.center
, dir
, rb
, blk
, e
, targets
,
3037 if (!broke
.is_valid_right
)
3040 else /* if (heap[dir]) */
3042 /* nothing touched this edge! Expand the whole edge unless
3043 * (1) it hit the board edge or (2) was the source of our expansion
3045 * for this case (of hitting nothing) we give up trying for corner
3046 * expansions because it is likely that they're not possible anyway
3048 if ((e
->expand_dir
== ALL
? e
->rb
->came_from
: e
->expand_dir
) !=
3051 /* ok, we are not going back on ourselves, and the whole edge seems free */
3052 moveable_edge (edges
, &rb
->sbox
, dir
, rb
, NULL
, e
, targets
, s
,
3058 /* expand the leftover from the prior direction */
3059 BoxType db
= previous_edge (last
, dir
, &rb
->sbox
);
3060 moveable_edge (edges
, &db
, (direction_t
)(dir
- 1), rb
, NULL
, e
, targets
, s
,
3066 /* finally, check for the NW corner now that we've come full circle */
3067 if (first
> 0 && last
> 0)
3069 BoxType db
= rb
->sbox
;
3072 moveable_edge (edges
, &db
, NW
, rb
, NULL
, e
, targets
, s
, NULL
, NULL
);
3078 BoxType db
= rb
->sbox
;
3080 moveable_edge (edges
, &db
, NORTH
, rb
, NULL
, e
, targets
, s
, NULL
,
3085 BoxType db
= rb
->sbox
;
3087 moveable_edge (edges
, &db
, WEST
, rb
, NULL
, e
, targets
, s
, NULL
,
3091 /* done with all expansion edges of this box */
3092 for (dir
= NORTH
; dir
<= WEST
; dir
= directionIncrement(dir
))
3095 heap_destroy (&heap
[dir
]);
3101 rb_source (routebox_t
* rb
)
3103 while (rb
&& !rb
->flags
.source
)
3105 assert (rb
->type
== EXPANSION_AREA
);
3106 rb
= rb
->parent
.expansion_area
;
3117 routebox_t
*intersect
;
3122 foib_rect_in_reg (const BoxType
* box
, void *cl
)
3124 struct foib_info
*foib
= (struct foib_info
*) cl
;
3126 routebox_t
*rb
= (routebox_t
*) box
;
3127 if (rb
->flags
.touched
)
3129 // if (rb->type == EXPANSION_AREA && !rb->flags.is_via)
3131 rbox
= bloat_routebox (rb
);
3132 if (!box_intersect (&rbox
, foib
->box
))
3134 /* this is an intersector! */
3135 foib
->intersect
= (routebox_t
*) box
;
3136 longjmp (foib
->env
, 1); /* skip to the end! */
3140 FindOneInBox (rtree_t
* rtree
, routebox_t
* rb
)
3142 struct foib_info foib
;
3147 foib
.intersect
= NULL
;
3149 if (setjmp (foib
.env
) == 0)
3150 r_search (rtree
, &r
, NULL
, foib_rect_in_reg
, &foib
);
3151 return foib
.intersect
;
3161 ftherm_rect_in_reg (const BoxType
* box
, void *cl
)
3163 routebox_t
*rbox
= (routebox_t
*) box
;
3164 struct therm_info
*ti
= (struct therm_info
*) cl
;
3167 if (rbox
->type
!= PIN
&& rbox
->type
!= VIA
&& rbox
->type
!= VIA_SHADOW
)
3169 if (rbox
->group
!= ti
->plane
->group
)
3172 sb
= shrink_routebox (rbox
);
3176 sq
= shrink_box (&ti
->query
, rbox
->parent
.pin
->Thickness
);
3177 if (!box_intersect (&sb
, &sq
))
3179 sb
.X1
= rbox
->parent
.pin
->X
;
3180 sb
.Y1
= rbox
->parent
.pin
->Y
;
3183 if (rbox
->flags
.fixed
)
3185 sq
= shrink_box (&ti
->query
, rbox
->parent
.via
->Thickness
);
3186 sb
.X1
= rbox
->parent
.pin
->X
;
3187 sb
.Y1
= rbox
->parent
.pin
->Y
;
3191 sq
= shrink_box (&ti
->query
, rbox
->style
->Diameter
);
3192 sb
.X1
= CENTER_X (sb
);
3193 sb
.Y1
= CENTER_Y (sb
);
3195 if (!box_intersect (&sb
, &sq
))
3199 sq
= shrink_box (&ti
->query
, rbox
->style
->Diameter
);
3200 if (!box_intersect (&sb
, &sq
))
3202 sb
.X1
= CENTER_X (sb
);
3203 sb
.Y1
= CENTER_Y (sb
);
3209 longjmp (ti
->env
, 1);
3214 * \brief Check for a pin or via target that a polygon can just use a
3215 * thermal to connect to.
3218 FindThermable (rtree_t
* rtree
, routebox_t
* rb
)
3220 struct therm_info info
;
3223 info
.query
= shrink_routebox (rb
);
3225 if (setjmp (info
.env
) == 0)
3227 r_search (rtree
, &info
.query
, NULL
, ftherm_rect_in_reg
, &info
);
3234 * \brief Route-tracing code: once we've got a path of expansion boxes,
3235 * trace a line through them to actually create the connection.
3238 RD_DrawThermal (routedata_t
* rd
, Coord X
, Coord Y
,
3239 Cardinal group
, Cardinal layer
, routebox_t
* subnet
,
3243 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3244 memset ((void *) rb
, 0, sizeof (*rb
));
3245 init_const_box (rb
, X
, Y
, X
+ 1, Y
+ 1, 0);
3248 rb
->flags
.fixed
= 0;
3249 rb
->flags
.is_bad
= is_bad
;
3250 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3251 rb
->flags
.circular
= 0;
3252 rb
->style
= AutoRouteParameters
.style
;
3255 MergeNets (rb
, subnet
, NET
);
3256 MergeNets (rb
, subnet
, SUBNET
);
3257 /* add it to the r-tree, this may be the whole route! */
3258 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3259 rb
->flags
.homeless
= 0;
3263 RD_DrawVia (routedata_t
* rd
, Coord X
, Coord Y
,
3264 Coord radius
, routebox_t
* subnet
, bool is_bad
)
3266 routebox_t
*rb
, *first_via
= NULL
;
3268 int ka
= AutoRouteParameters
.style
->Keepaway
;
3269 PinType
*live_via
= NULL
;
3271 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3273 live_via
= CreateNewVia (PCB
->Data
, X
, Y
, radius
* 2,
3274 2 * AutoRouteParameters
.style
->Keepaway
, 0,
3275 AutoRouteParameters
.style
->Hole
, NULL
,
3277 if (live_via
!= NULL
)
3281 /* a via cuts through every layer group */
3282 for (i
= 0; i
< max_group
; i
++)
3284 if (!is_layer_group_active
[i
])
3286 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3287 memset ((void *) rb
, 0, sizeof (*rb
));
3289 /*X1 */ X
- radius
, /*Y1 */ Y
- radius
,
3290 /*X2 */ X
+ radius
+ 1, /*Y2 */ Y
+ radius
+ 1, ka
);
3292 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
3293 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3294 rb
->flags
.is_bad
= is_bad
;
3295 rb
->came_from
= ALL
;
3296 rb
->flags
.circular
= true;
3297 rb
->style
= AutoRouteParameters
.style
;
3298 rb
->pass
= AutoRouteParameters
.pass
;
3299 if (first_via
== NULL
)
3302 rb
->parent
.via
= NULL
; /* indicates that not on PCB yet */
3304 /* only add the first via to mtspace, not the shadows too */
3305 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
3306 rb
->style
->Keepaway
);
3310 rb
->type
= VIA_SHADOW
;
3311 rb
->parent
.via_shadow
= first_via
;
3314 /* add these to proper subnet. */
3315 MergeNets (rb
, subnet
, NET
);
3316 MergeNets (rb
, subnet
, SUBNET
);
3317 assert (__routebox_is_good (rb
));
3318 /* and add it to the r-tree! */
3319 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3320 rb
->flags
.homeless
= 0; /* not homeless anymore */
3321 rb
->livedraw_obj
.via
= live_via
;
3325 RD_DrawLine (routedata_t
* rd
,
3326 Coord X1
, Coord Y1
, Coord X2
,
3327 Coord Y2
, Coord halfthick
, Cardinal group
,
3328 routebox_t
* subnet
, bool is_bad
, bool is_45
)
3330 /* we hold the line in a queue to concatenate segments that
3331 * ajoin one another. That reduces the number of things in
3332 * the trees and allows conflict boxes to be larger, both of
3333 * which are really useful.
3335 static Coord qX1
= -1, qY1
, qX2
, qY2
;
3336 static Coord qhthick
;
3337 static Cardinal qgroup
;
3338 static bool qis_45
, qis_bad
;
3339 static routebox_t
*qsn
;
3342 Coord ka
= AutoRouteParameters
.style
->Keepaway
;
3344 /* don't draw zero-length segments. */
3345 if (X1
== X2
&& Y1
== Y2
)
3347 if (qX1
== -1) /* first ever */
3353 qhthick
= halfthick
;
3360 /* Check if the lines concatenat. We only check the
3361 * normal expected nextpoint=lastpoint condition
3363 if (X1
== qX2
&& Y1
== qY2
&& qhthick
== halfthick
&& qgroup
== group
)
3365 if (qX1
== qX2
&& X1
== X2
) /* everybody on the same X here */
3370 if (qY1
== qY2
&& Y1
== Y2
) /* same Y all around */
3376 /* dump the queue, no match here */
3378 return; /* but not this! */
3379 rb
= (routebox_t
*) malloc (sizeof (*rb
));
3380 memset ((void *) rb
, 0, sizeof (*rb
));
3381 assert (is_45
? (ABS (qX2
- qX1
) == ABS (qY2
- qY1
)) /* line must be 45-degrees */
3382 : (qX1
== qX2
|| qY1
== qY2
) /* line must be ortho */ );
3384 /*X1 */ MIN (qX1
, qX2
) - qhthick
,
3385 /*Y1 */ MIN (qY1
, qY2
) - qhthick
,
3386 /*X2 */ MAX (qX1
, qX2
) + qhthick
+ 1,
3387 /*Y2 */ MAX (qY1
, qY2
) + qhthick
+ 1, ka
);
3390 rb
->parent
.line
= NULL
; /* indicates that not on PCB yet */
3391 rb
->flags
.fixed
= 0; /* indicates that not on PCB yet */
3392 rb
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
3393 rb
->flags
.is_bad
= qis_bad
;
3394 rb
->came_from
= ALL
;
3395 rb
->flags
.homeless
= 0; /* we're putting this in the tree */
3396 rb
->flags
.nonstraight
= qis_45
;
3397 rb
->flags
.bl_to_ur
= ((qX2
>= qX1
&& qY2
<= qY1
)
3398 || (qX2
<= qX1
&& qY2
>= qY1
));
3399 rb
->style
= AutoRouteParameters
.style
;
3400 rb
->pass
= AutoRouteParameters
.pass
;
3402 /* add these to proper subnet. */
3403 MergeNets (rb
, qsn
, NET
);
3404 MergeNets (rb
, qsn
, SUBNET
);
3405 assert (__routebox_is_good (rb
));
3406 /* and add it to the r-tree! */
3407 r_insert_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
, 1);
3409 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3411 LayerType
*layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[rb
->group
][0]);
3412 LineType
*line
= CreateNewLineOnLayer (layer
, qX1
, qY1
, qX2
, qY2
,
3413 2 * qhthick
, 0, MakeFlags (0));
3414 rb
->livedraw_obj
.line
= line
;
3416 DrawLine (layer
, line
);
3419 /* and to the via space structures */
3420 if (AutoRouteParameters
.use_vias
)
3421 mtspace_add (rd
->mtspace
, &rb
->box
, rb
->flags
.is_odd
? ODD
: EVEN
,
3422 rb
->style
->Keepaway
);
3423 usedGroup
[rb
->group
] = true;
3424 /* and queue this one */
3429 qhthick
= halfthick
;
3437 RD_DrawManhattanLine (routedata_t
* rd
,
3438 const BoxType
* box1
, const BoxType
* box2
,
3439 CheapPointType start
, CheapPointType end
,
3440 Coord halfthick
, Cardinal group
,
3441 routebox_t
* subnet
, bool is_bad
, bool last_was_x
)
3443 CheapPointType knee
= start
;
3444 if (end
.X
== start
.X
)
3446 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3447 subnet
, is_bad
, false);
3450 else if (end
.Y
== start
.Y
)
3452 RD_DrawLine (rd
, start
.X
, start
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3453 subnet
, is_bad
, false);
3456 /* find where knee belongs */
3457 if (point_in_box (box1
, end
.X
, start
.Y
)
3458 || point_in_box (box2
, end
.X
, start
.Y
))
3468 if ((knee
.X
== end
.X
&& !last_was_x
) &&
3469 (point_in_box (box1
, start
.X
, end
.Y
)
3470 || point_in_box (box2
, start
.X
, end
.Y
)))
3475 assert (AutoRouteParameters
.is_smoothing
3476 || point_in_closed_box (box1
, knee
.X
, knee
.Y
)
3477 || point_in_closed_box (box2
, knee
.X
, knee
.Y
));
3479 if (1 || !AutoRouteParameters
.is_smoothing
)
3481 /* draw standard manhattan paths */
3482 RD_DrawLine (rd
, start
.X
, start
.Y
, knee
.X
, knee
.Y
, halfthick
, group
,
3483 subnet
, is_bad
, false);
3484 RD_DrawLine (rd
, knee
.X
, knee
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3485 subnet
, is_bad
, false);
3489 /* draw 45-degree path across knee */
3490 Coord len45
= MIN (ABS (start
.X
- end
.X
), ABS (start
.Y
- end
.Y
));
3491 CheapPointType kneestart
= knee
, kneeend
= knee
;
3492 if (kneestart
.X
== start
.X
)
3493 kneestart
.Y
+= (kneestart
.Y
> start
.Y
) ? -len45
: len45
;
3495 kneestart
.X
+= (kneestart
.X
> start
.X
) ? -len45
: len45
;
3496 if (kneeend
.X
== end
.X
)
3497 kneeend
.Y
+= (kneeend
.Y
> end
.Y
) ? -len45
: len45
;
3499 kneeend
.X
+= (kneeend
.X
> end
.X
) ? -len45
: len45
;
3500 RD_DrawLine (rd
, start
.X
, start
.Y
, kneestart
.X
, kneestart
.Y
, halfthick
,
3501 group
, subnet
, is_bad
, false);
3502 RD_DrawLine (rd
, kneestart
.X
, kneestart
.Y
, kneeend
.X
, kneeend
.Y
,
3503 halfthick
, group
, subnet
, is_bad
, true);
3504 RD_DrawLine (rd
, kneeend
.X
, kneeend
.Y
, end
.X
, end
.Y
, halfthick
, group
,
3505 subnet
, is_bad
, false);
3507 return (knee
.X
!= end
.X
);
3510 /* for smoothing, don't pack traces to min clearance gratuitously */
3513 add_clearance (CheapPointType
* nextpoint
, const BoxType
* b
)
3515 if (nextpoint
->X
== b
->X1
)
3518 AutoRouteParameters
.style
->Keepaway
< (b
->X1
+ b
->X2
) / 2)
3519 nextpoint
->X
+= AutoRouteParameters
.style
->Keepaway
;
3521 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
3523 else if (nextpoint
->X
== b
->X2
)
3526 AutoRouteParameters
.style
->Keepaway
> (b
->X1
+ b
->X2
) / 2)
3527 nextpoint
->X
-= AutoRouteParameters
.style
->Keepaway
;
3529 nextpoint
->X
= (b
->X1
+ b
->X2
) / 2;
3531 else if (nextpoint
->Y
== b
->Y1
)
3534 AutoRouteParameters
.style
->Keepaway
< (b
->Y1
+ b
->Y2
) / 2)
3535 nextpoint
->Y
+= AutoRouteParameters
.style
->Keepaway
;
3537 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
3539 else if (nextpoint
->Y
== b
->Y2
)
3542 AutoRouteParameters
.style
->Keepaway
> (b
->Y1
+ b
->Y2
) / 2)
3543 nextpoint
->Y
-= AutoRouteParameters
.style
->Keepaway
;
3545 nextpoint
->Y
= (b
->Y1
+ b
->Y2
) / 2;
3551 * \brief This back-traces the expansion boxes along the best path
3552 * it draws the lines that will make the actual path.
3554 * During refinement passes, it should try to maximize the area
3555 * for other tracks so routing completion is easier.
3557 * During smoothing passes, it should try to make a better path,
3558 * possibly using diagonals, etc. The path boxes are larger on
3559 * average now so there is more possiblity to decide on a nice
3560 * path. Any combination of lines and arcs is possible, so long
3561 * as they don't poke more than half thick outside the path box.
3565 TracePath (routedata_t
* rd
, routebox_t
* path
, const routebox_t
* target
,
3566 routebox_t
* subnet
, bool is_bad
)
3568 bool last_x
= false;
3569 Coord halfwidth
= HALF_THICK (AutoRouteParameters
.style
->Thick
);
3570 Coord radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3571 CheapPointType lastpoint
, nextpoint
;
3572 routebox_t
*lastpath
;
3575 assert (subnet
->style
== AutoRouteParameters
.style
);
3576 /*XXX: because we round up odd thicknesses, there's the possibility that
3577 * a connecting line end-point might be 0.005 mil off the "real" edge.
3578 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */
3580 /* if we start with a thermal the target was a plane
3581 * or the target was a pin and the source a plane
3582 * in which case this thermal is the whole path
3584 if (path
->flags
.is_thermal
)
3586 /* the target was a plane, so we need to find a good spot for the via
3587 * now. It's logical to place it close to the source box which
3588 * is where we're utlimately headed on this path. However, it
3589 * must reside in the plane as well as the via area too.
3591 nextpoint
.X
= CENTER_X (path
->sbox
);
3592 nextpoint
.Y
= CENTER_Y (path
->sbox
);
3593 if (path
->parent
.expansion_area
->flags
.is_via
)
3595 TargetPoint (&nextpoint
, rb_source (path
));
3596 /* nextpoint is the middle of the source terminal now */
3597 b
= clip_box (&path
->sbox
, &path
->parent
.expansion_area
->sbox
);
3598 nextpoint
= closest_point_in_box (&nextpoint
, &b
);
3599 /* now it's in the via and plane near the source */
3601 else /* no via coming, target must have been a pin */
3603 assert (target
->type
== PIN
);
3604 TargetPoint (&nextpoint
, target
);
3606 assert (point_in_box (&path
->sbox
, nextpoint
.X
, nextpoint
.Y
));
3607 RD_DrawThermal (rd
, nextpoint
.X
, nextpoint
.Y
, path
->group
,
3608 path
->layer
, subnet
, is_bad
);
3612 /* start from best place of target box */
3613 lastpoint
.X
= CENTER_X (target
->sbox
);
3614 lastpoint
.Y
= CENTER_Y (target
->sbox
);
3615 TargetPoint (&lastpoint
, target
);
3616 if (AutoRouteParameters
.last_smooth
3617 && box_in_box (&path
->sbox
, &target
->sbox
))
3618 path
= path
->parent
.expansion_area
;
3620 if (path
->flags
.circular
)
3621 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
3622 nextpoint
= closest_point_in_box (&lastpoint
, &b
);
3623 if (AutoRouteParameters
.last_smooth
)
3624 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3625 halfwidth
, path
->group
, subnet
, is_bad
, TRUE
);
3627 last_x
= RD_DrawManhattanLine (rd
, &target
->sbox
, &path
->sbox
,
3628 lastpoint
, nextpoint
, halfwidth
,
3629 path
->group
, subnet
, is_bad
, last_x
);
3631 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3632 showroutebox (path
);
3633 #if defined(ROUTE_VERBOSE)
3634 pcb_printf ("TRACEPOINT start %#mD\n", nextpoint
.X
, nextpoint
.Y
);
3640 lastpoint
= nextpoint
;
3642 assert (path
->type
== EXPANSION_AREA
);
3643 path
= path
->parent
.expansion_area
;
3645 if (path
->flags
.circular
)
3646 b
= shrink_box (&b
, MIN (b
.X2
- b
.X1
, b
.Y2
- b
.Y1
) / 5);
3647 assert (b
.X1
!= b
.X2
&& b
.Y1
!= b
.Y2
); /* need someplace to put line! */
3648 /* find point on path perimeter closest to last point */
3649 /* if source terminal, try to hit a good place */
3650 nextpoint
= closest_point_in_box (&lastpoint
, &b
);
3652 /* leave more clearance if this is a smoothing pass */
3653 if (AutoRouteParameters
.is_smoothing
&&
3654 (nextpoint
.X
!= lastpoint
.X
|| nextpoint
.Y
!= lastpoint
.Y
))
3655 add_clearance (&nextpoint
, &b
);
3657 if (path
->flags
.source
&& path
->type
!= PLANE
)
3658 TargetPoint (&nextpoint
, path
);
3659 assert (point_in_box (&lastpath
->box
, lastpoint
.X
, lastpoint
.Y
));
3660 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
3661 #if defined(ROUTE_DEBUG_VERBOSE)
3662 printf ("TRACEPATH: ");
3663 DumpRouteBox (path
);
3664 pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n",
3665 lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3669 /* draw orthogonal lines from lastpoint to nextpoint */
3670 /* knee is placed in lastpath box */
3671 /* should never cause line to leave union of lastpath/path boxes */
3672 if (AutoRouteParameters
.last_smooth
)
3673 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
, nextpoint
.Y
,
3674 halfwidth
, path
->group
, subnet
, is_bad
, TRUE
);
3676 last_x
= RD_DrawManhattanLine (rd
, &lastpath
->sbox
, &path
->sbox
,
3677 lastpoint
, nextpoint
, halfwidth
,
3678 path
->group
, subnet
, is_bad
, last_x
);
3679 if (path
->flags
.is_via
)
3680 { /* if via, then add via */
3681 #ifdef ROUTE_VERBOSE
3684 assert (point_in_box (&path
->box
, nextpoint
.X
, nextpoint
.Y
));
3685 RD_DrawVia (rd
, nextpoint
.X
, nextpoint
.Y
, radius
, subnet
, is_bad
);
3688 assert (lastpath
->flags
.is_via
|| path
->group
== lastpath
->group
);
3690 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES)
3691 showroutebox (path
);
3692 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */
3693 /* if this is connected to a plane, draw the thermal */
3694 if (path
->flags
.is_thermal
|| path
->type
== PLANE
)
3695 RD_DrawThermal (rd
, lastpoint
.X
, lastpoint
.Y
, path
->group
,
3696 path
->layer
, subnet
, is_bad
);
3697 /* when one hop from the source, make an extra path in *this* box */
3698 if (path
->type
== EXPANSION_AREA
3699 && path
->parent
.expansion_area
->flags
.source
3700 && path
->parent
.expansion_area
->type
!= PLANE
)
3702 /* find special point on source (if it exists) */
3703 if (TargetPoint (&lastpoint
, path
->parent
.expansion_area
))
3705 lastpoint
= closest_point_in_routebox (&lastpoint
, path
);
3706 b
= shrink_routebox (path
);
3708 if (AutoRouteParameters
.is_smoothing
)
3709 add_clearance (&lastpoint
, &b
);
3711 if (AutoRouteParameters
.last_smooth
)
3712 RD_DrawLine (rd
, lastpoint
.X
, lastpoint
.Y
, nextpoint
.X
,
3713 nextpoint
.Y
, halfwidth
, path
->group
, subnet
,
3717 last_x
= RD_DrawManhattanLine (rd
, &b
, &b
,
3718 nextpoint
, lastpoint
,
3719 halfwidth
, path
->group
, subnet
,
3721 #if defined(ROUTE_DEBUG_VERBOSE)
3722 printf ("TRACEPATH: ");
3723 DumpRouteBox (path
);
3725 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n",
3726 nextpoint
.X
, nextpoint
.Y
, lastpoint
.X
, lastpoint
.Y
,
3730 nextpoint
= lastpoint
;
3734 while (!path
->flags
.source
);
3735 /* flush the line queue */
3736 RD_DrawLine (rd
, -1, 0, 0, 0, 0, 0, NULL
, false, false);
3738 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
3743 gui
->flush_debug_draw ();
3748 * \brief Create a fake "edge" used to defer via site searching.
3751 CreateSearchEdge (struct routeone_state
*s
, vetting_t
* work
, edge_t
* parent
,
3752 routebox_t
* rb
, conflict_t conflict
, rtree_t
* targets
,
3758 assert (__routebox_is_good (rb
));
3759 /* find the cheapest target */
3762 mincost_target_to_point (&parent
->cost_point
, max_group
+ 1, targets
,
3763 parent
->mincost_target
);
3765 target
= parent
->mincost_target
;
3767 b
= shrink_routebox (target
);
3769 parent
->cost_to_point
+ AutoRouteParameters
.ViaCost
+
3770 cost_to_layerless_box (&rb
->cost_point
, 0, &b
);
3771 if (cost
< s
->best_cost
)
3774 ne
= (edge_t
*)malloc (sizeof (*ne
));
3775 memset ((void *) ne
, 0, sizeof (*ne
));
3777 ne
->flags
.via_search
= 1;
3778 ne
->flags
.in_plane
= in_plane
;
3780 if (rb
->flags
.homeless
)
3783 ne
->mincost_target
= target
;
3784 ne
->flags
.via_conflict_level
= conflict
;
3785 ne
->cost_to_point
= parent
->cost_to_point
;
3786 ne
->cost_point
= parent
->cost_point
;
3788 heap_insert (s
->workheap
, ne
->cost
, ne
);
3792 mtsFreeWork (&work
);
3797 add_or_destroy_edge (struct routeone_state
*s
, edge_t
* e
)
3799 e
->cost
= edge_cost (e
, s
->best_cost
);
3800 assert (__edge_is_good (e
));
3801 assert (is_layer_group_active
[e
->rb
->group
]);
3802 if (e
->cost
< s
->best_cost
)
3803 heap_insert (s
->workheap
, e
->cost
, e
);
3809 best_path_candidate (struct routeone_state
*s
,
3810 edge_t
* e
, routebox_t
* best_target
)
3812 e
->cost
= edge_cost (e
, EXPENSIVE
);
3813 if (s
->best_path
== NULL
|| e
->cost
< s
->best_cost
)
3815 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE)
3816 printf ("New best path seen! cost = %f\n", e
->cost
);
3818 /* new best path! */
3819 if (s
->best_path
&& s
->best_path
->flags
.homeless
)
3820 RB_down_count (s
->best_path
);
3821 s
->best_path
= e
->rb
;
3822 s
->best_target
= best_target
;
3823 s
->best_cost
= e
->cost
;
3824 assert (s
->best_cost
>= 0);
3825 /* don't free this when we destroy edge! */
3826 if (s
->best_path
->flags
.homeless
)
3827 RB_up_count (s
->best_path
);
3833 * \brief Vectors for via site candidates (see mtspace.h).
3835 struct routeone_via_site_state
3837 vector_t
*free_space_vec
;
3838 vector_t
*lo_conflict_space_vec
;
3839 vector_t
*hi_conflict_space_vec
;
3843 add_via_sites (struct routeone_state
*s
,
3844 struct routeone_via_site_state
*vss
,
3845 mtspace_t
* mtspace
, routebox_t
* within
,
3846 conflict_t within_conflict_level
, edge_t
* parent_edge
,
3847 rtree_t
* targets
, Coord shrink
, bool in_plane
)
3849 Coord radius
, keepaway
;
3851 BoxType region
= shrink_routebox (within
);
3852 shrink_box (®ion
, shrink
);
3854 radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3855 keepaway
= AutoRouteParameters
.style
->Keepaway
;
3856 assert (AutoRouteParameters
.use_vias
);
3857 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when
3858 XXX: routing with conflicts may poke over edge. */
3860 /* ask for a via box near our cost_point first */
3861 work
= mtspace_query_rect (mtspace
, ®ion
, radius
, keepaway
,
3862 NULL
, vss
->free_space_vec
,
3863 vss
->lo_conflict_space_vec
,
3864 vss
->hi_conflict_space_vec
,
3865 AutoRouteParameters
.is_odd
,
3866 AutoRouteParameters
.with_conflicts
,
3867 &parent_edge
->cost_point
);
3870 CreateSearchEdge (s
, work
, parent_edge
, within
, within_conflict_level
,
3875 do_via_search (edge_t
* search
, struct routeone_state
*s
,
3876 struct routeone_via_site_state
*vss
, mtspace_t
* mtspace
,
3879 int i
, j
, count
= 0;
3880 Coord radius
, keepaway
;
3883 conflict_t within_conflict_level
;
3885 radius
= HALF_THICK (AutoRouteParameters
.style
->Diameter
);
3886 keepaway
= AutoRouteParameters
.style
->Keepaway
;
3887 work
= mtspace_query_rect (mtspace
, NULL
, 0, 0,
3888 search
->work
, vss
->free_space_vec
,
3889 vss
->lo_conflict_space_vec
,
3890 vss
->hi_conflict_space_vec
,
3891 AutoRouteParameters
.is_odd
,
3892 AutoRouteParameters
.with_conflicts
, NULL
);
3893 within
= search
->rb
;
3894 within_conflict_level
= search
->flags
.via_conflict_level
;
3895 for (i
= 0; i
< 3; i
++)
3898 (i
== NO_CONFLICT
? vss
->free_space_vec
:
3899 i
== LO_CONFLICT
? vss
->lo_conflict_space_vec
:
3900 i
== HI_CONFLICT
? vss
->hi_conflict_space_vec
: NULL
);
3902 while (!vector_is_empty (v
))
3905 BoxType
*area
= (BoxType
*)vector_remove_last (v
);
3906 if (!(i
== NO_CONFLICT
|| AutoRouteParameters
.with_conflicts
))
3911 /* answers are bloated by radius + keepaway */
3912 cliparea
= shrink_box (area
, radius
+ keepaway
);
3913 close_box (&cliparea
);
3915 assert (box_is_good (&cliparea
));
3917 for (j
= 0; j
< max_group
; j
++)
3920 if (j
== within
->group
|| !is_layer_group_active
[j
])
3922 ne
= CreateViaEdge (&cliparea
, j
, within
, search
,
3923 within_conflict_level
, (conflict_t
)i
, targets
);
3924 add_or_destroy_edge (s
, ne
);
3928 /* prevent freeing of work when this edge is destroyed */
3929 search
->flags
.via_search
= 0;
3932 CreateSearchEdge (s
, work
, search
, within
, within_conflict_level
, targets
,
3933 search
->flags
.in_plane
);
3934 assert (vector_is_empty (vss
->free_space_vec
));
3935 assert (vector_is_empty (vss
->lo_conflict_space_vec
));
3936 assert (vector_is_empty (vss
->hi_conflict_space_vec
));
3939 /* vector of expansion areas to be eventually removed from r-tree
3940 * this is a global for troubleshooting
3944 /* some routines for use in gdb while debugging */
3945 #if defined(ROUTE_DEBUG)
3947 list_conflicts (routebox_t
* rb
)
3950 if (!rb
->conflicts_with
)
3952 n
= vector_size (rb
->conflicts_with
);
3953 for (i
= 0; i
< n
; i
++)
3954 printf ("%p, ", vector_element (rb
->conflicts_with
, i
));
3958 show_area_vec (int lay
)
3966 for (n
= 0; n
< vector_size (area_vec
); n
++)
3968 routebox_t
*rb
= (routebox_t
*) vector_element (area_vec
, n
);
3975 net_id (routebox_t
* rb
, long int id
)
3978 LIST_LOOP (rb
, same_net
, p
);
3979 if (p
->flags
.source
&& p
->parent
.pad
->ID
== id
)
3986 trace_parents (routebox_t
* rb
)
3988 while (rb
&& rb
->type
== EXPANSION_AREA
)
3990 printf (" %p ->", rb
);
3991 rb
= rb
->parent
.expansion_area
;
3994 printf (" %p is source\n", rb
);
4000 show_one (routebox_t
* rb
)
4002 int save
= showboxen
;
4009 show_path (routebox_t
* rb
)
4011 while (rb
&& rb
->type
== EXPANSION_AREA
)
4014 rb
= rb
->parent
.expansion_area
;
4020 show_sources (routebox_t
* rb
)
4023 if (!rb
->flags
.source
&& !rb
->flags
.target
)
4025 printf ("start with a source or target please\n");
4028 LIST_LOOP (rb
, same_net
, p
);
4029 if (p
->flags
.source
)
4037 __conflict_source (const BoxType
* box
, void *cl
)
4039 routebox_t
*rb
= (routebox_t
*) box
;
4040 if (rb
->flags
.touched
|| rb
->flags
.fixed
)
4044 routebox_t
*dis
= (routebox_t
*) cl
;
4045 path_conflicts (dis
, rb
, false);
4046 touch_conflicts (dis
->conflicts_with
, 1);
4052 source_conflicts (rtree_t
* tree
, routebox_t
* rb
)
4054 if (!AutoRouteParameters
.with_conflicts
)
4056 r_search (tree
, &rb
->sbox
, NULL
, __conflict_source
, rb
);
4057 touch_conflicts (NULL
, 1);
4060 struct routeone_status
4063 int route_had_conflicts
;
4064 cost_t best_route_cost
;
4065 bool net_completely_routed
;
4069 static struct routeone_status
4070 RouteOne (routedata_t
* rd
, routebox_t
* from
, routebox_t
* to
, int max_edges
)
4072 struct routeone_status result
;
4075 const BoxType
**target_list
;
4078 /* vector of source edges for filtering */
4079 vector_t
*source_vec
;
4080 /* working vector */
4083 struct routeone_state s
;
4084 struct routeone_via_site_state vss
;
4086 assert (rd
&& from
);
4087 result
.route_had_conflicts
= 0;
4088 /* no targets on to/from net need keepaway areas */
4089 LIST_LOOP (from
, same_net
, p
);
4090 p
->flags
.nobloat
= 1;
4092 /* set 'source' flags */
4093 LIST_LOOP (from
, same_subnet
, p
);
4094 if (!p
->flags
.nonstraight
)
4095 p
->flags
.source
= 1;
4098 /* count up the targets */
4101 /* remove source/target flags from non-straight obstacles, because they
4102 * don't fill their bounding boxes and so connecting to them
4103 * after we've routed is problematic. Better solution? */
4105 { /* if we're routing to a specific target */
4106 if (!to
->flags
.source
)
4107 { /* not already connected */
4108 /* check that 'to' and 'from' are on the same net */
4111 LIST_LOOP (from
, same_net
, p
);
4116 assert (seen
); /* otherwise from and to are on different nets! */
4117 /* set target flags only on 'to's subnet */
4118 LIST_LOOP (to
, same_subnet
, p
);
4119 if (!p
->flags
.nonstraight
&& is_layer_group_active
[p
->group
])
4121 p
->flags
.target
= 1;
4129 /* all nodes on the net but not connected to from are targets */
4130 LIST_LOOP (from
, same_net
, p
);
4131 if (!p
->flags
.source
&& is_layer_group_active
[p
->group
]
4132 && !p
->flags
.nonstraight
)
4134 p
->flags
.target
= 1;
4140 /* if no targets, then net is done! reset flags and return. */
4141 if (num_targets
== 0)
4143 LIST_LOOP (from
, same_net
, p
);
4144 p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
4146 result
.found_route
= false;
4147 result
.net_completely_routed
= true;
4148 result
.best_route_cost
= 0;
4149 result
.route_had_conflicts
= 0;
4153 result
.net_completely_routed
= false;
4155 /* okay, there's stuff to route */
4156 assert (!from
->flags
.target
);
4157 assert (num_targets
> 0);
4158 /* create list of target pointers and from that a r-tree of targets */
4159 target_list
= (const BoxType
**)malloc (num_targets
* sizeof (*target_list
));
4161 LIST_LOOP (from
, same_net
, p
);
4162 if (p
->flags
.target
)
4164 target_list
[i
++] = &p
->box
;
4165 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS)
4170 targets
= r_create_tree ((const BoxType
**)target_list
, i
, 0);
4171 assert (i
<= num_targets
);
4174 source_vec
= vector_create ();
4175 /* touch the source subnet to prepare check for conflictors */
4176 LIST_LOOP (from
, same_subnet
, p
);
4177 p
->flags
.touched
= 1;
4179 LIST_LOOP (from
, same_subnet
, p
);
4181 /* we need the test for 'source' because this box may be nonstraight */
4182 if (p
->flags
.source
&& is_layer_group_active
[p
->group
])
4186 BoxType b
= shrink_routebox (p
);
4188 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES)
4191 /* may expand in all directions from source; center edge cost point. */
4192 /* note that planes shouldn't really expand, but we need an edge */
4194 cp
.X
= CENTER_X (b
);
4195 cp
.Y
= CENTER_Y (b
);
4196 e
= CreateEdge (p
, cp
.X
, cp
.Y
, 0, NULL
, ALL
, targets
);
4197 cp
= closest_point_in_box (&cp
, &e
->mincost_target
->sbox
);
4198 cp
= closest_point_in_box (&cp
, &b
);
4201 source_conflicts (rd
->layergrouptree
[p
->group
], p
);
4202 vector_append (source_vec
, e
);
4206 LIST_LOOP (from
, same_subnet
, p
);
4207 p
->flags
.touched
= 0;
4209 /* break source edges; some edges may be too near obstacles to be able
4212 /* okay, main expansion-search routing loop. */
4213 /* set up the initial activity heap */
4214 s
.workheap
= heap_create ();
4215 assert (s
.workheap
);
4216 while (!vector_is_empty (source_vec
))
4218 edge_t
*e
= (edge_t
*)vector_remove_last (source_vec
);
4219 assert (is_layer_group_active
[e
->rb
->group
]);
4220 e
->cost
= edge_cost (e
, EXPENSIVE
);
4221 heap_insert (s
.workheap
, e
->cost
, e
);
4223 vector_destroy (&source_vec
);
4224 /* okay, process items from heap until it is empty! */
4226 s
.best_cost
= EXPENSIVE
;
4227 area_vec
= vector_create ();
4228 edge_vec
= vector_create ();
4229 vss
.free_space_vec
= vector_create ();
4230 vss
.lo_conflict_space_vec
= vector_create ();
4231 vss
.hi_conflict_space_vec
= vector_create ();
4232 while (!heap_is_empty (s
.workheap
))
4234 edge_t
*e
= (edge_t
*)heap_remove_smallest (s
.workheap
);
4239 /* don't bother expanding this edge if the minimum possible edge cost
4240 * is already larger than the best edge cost we've found. */
4241 if (s
.best_path
&& e
->cost
>= s
.best_cost
)
4243 heap_free (s
.workheap
, KillEdge
);
4244 goto dontexpand
; /* skip this edge */
4246 /* surprisingly it helps to give up and not try too hard to find
4247 * a route! This is not only faster, but results in better routing.
4248 * who would have guessed?
4250 if (seen
++ > max_edges
)
4252 assert (__edge_is_good (e
));
4253 /* mark or unmark conflictors as needed */
4254 touch_conflicts (e
->rb
->conflicts_with
, 1);
4255 if (e
->flags
.via_search
)
4257 do_via_search (e
, &s
, &vss
, rd
->mtspace
, targets
);
4260 /* we should never add edges on inactive layer groups to the heap. */
4261 assert (is_layer_group_active
[e
->rb
->group
]);
4262 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES)
4265 if (e
->rb
->flags
.is_thermal
)
4267 best_path_candidate (&s
, e
, e
->mincost_target
);
4270 /* for a plane, look for quick connections with thermals or vias */
4271 if (e
->rb
->type
== PLANE
)
4273 routebox_t
*pin
= FindThermable (targets
, e
->rb
);
4276 BoxType b
= shrink_routebox (pin
);
4279 assert (pin
->flags
.target
);
4280 nrb
= CreateExpansionArea (&b
, e
->rb
->group
, e
->rb
, true, e
);
4281 nrb
->flags
.is_thermal
= 1;
4282 /* moving through the plane is free */
4283 e
->cost_point
.X
= b
.X1
;
4284 e
->cost_point
.Y
= b
.Y1
;
4285 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, pin
);
4286 best_path_candidate (&s
, ne
, pin
);
4291 /* add in possible via sites in plane */
4292 if (AutoRouteParameters
.use_vias
&&
4293 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
4295 /* we need a giant thermal */
4297 CreateExpansionArea (&e
->rb
->sbox
, e
->rb
->group
, e
->rb
,
4299 edge_t
*ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
,
4301 nrb
->flags
.is_thermal
= 1;
4302 add_via_sites (&s
, &vss
, rd
->mtspace
, nrb
, NO_CONFLICT
, ne
,
4303 targets
, e
->rb
->style
->Diameter
, true);
4306 goto dontexpand
; /* planes only connect via thermals */
4308 if (e
->flags
.is_via
)
4309 { /* special case via */
4310 routebox_t
*intersecting
;
4311 assert (AutoRouteParameters
.use_vias
);
4312 assert (e
->expand_dir
== ALL
);
4313 assert (vector_is_empty (edge_vec
));
4314 /* if there is already something here on this layer (like an
4315 * EXPANSION_AREA), then we don't want to expand from here
4316 * at least not inside the expansion area. A PLANE on the
4317 * other hand may be a target, or not.
4320 FindOneInBox (rd
->layergrouptree
[e
->rb
->group
], e
->rb
);
4322 if (intersecting
&& intersecting
->flags
.target
4323 && intersecting
->type
== PLANE
)
4325 /* we have hit a plane */
4328 BoxType b
= shrink_routebox (e
->rb
);
4329 /* limit via region to that inside the plane */
4330 clip_box (&b
, &intersecting
->sbox
);
4331 nrb
= CreateExpansionArea (&b
, e
->rb
->group
, e
->rb
, true, e
);
4332 nrb
->flags
.is_thermal
= 1;
4333 ne
= CreateEdge2 (nrb
, e
->expand_dir
, e
, NULL
, intersecting
);
4334 best_path_candidate (&s
, ne
, intersecting
);
4338 else if (intersecting
== NULL
)
4340 /* this via candidate is in an open area; add it to r-tree as
4341 * an expansion area */
4342 assert (e
->rb
->type
== EXPANSION_AREA
&& e
->rb
->flags
.is_via
);
4343 /*assert (!r_search (rd->layergrouptree[e->rb->group],
4344 &e->rb->box, NULL, no_planes,0));
4346 r_insert_entry (rd
->layergrouptree
[e
->rb
->group
], &e
->rb
->box
,
4348 e
->rb
->flags
.homeless
= 0; /* not homeless any more */
4349 /* add to vector of all expansion areas in r-tree */
4350 vector_append (area_vec
, e
->rb
);
4351 /* mark reset refcount to 0, since this is not homeless any more. */
4352 e
->rb
->refcount
= 0;
4353 /* go ahead and expand this edge! */
4358 { /* XXX: disabling this causes no via
4360 BoxType a
= bloat_routebox (intersecting
), b
;
4363 /* something intersects this via candidate. split via candidate
4364 * into pieces and add these pieces to the workheap. */
4365 for (i
= 0; i
< 3; i
++)
4367 for (j
= 0; j
< 3; j
++)
4369 b
= shrink_routebox (e
->rb
);
4373 b
.X2
= MIN (b
.X2
, a
.X1
);
4376 b
.X1
= MAX (b
.X1
, a
.X1
);
4377 b
.X2
= MIN (b
.X2
, a
.X2
);
4380 b
.X1
= MAX (b
.X1
, a
.X2
);
4388 b
.Y2
= MIN (b
.Y2
, a
.Y1
);
4391 b
.Y1
= MAX (b
.Y1
, a
.Y1
);
4392 b
.Y2
= MIN (b
.Y2
, a
.Y2
);
4395 b
.Y1
= MAX (b
.Y1
, a
.Y2
);
4400 /* skip if this box is not valid */
4401 if (!(b
.X1
< b
.X2
&& b
.Y1
< b
.Y2
))
4403 if (i
== 1 && j
== 1)
4405 /* this bit of the via space is obstructed. */
4406 if (intersecting
->type
== EXPANSION_AREA
4407 || intersecting
->flags
.fixed
)
4408 continue; /* skip this bit, it's already been done. */
4409 /* create an edge with conflicts, if enabled */
4410 if (!AutoRouteParameters
.with_conflicts
)
4412 ne
= CreateEdgeWithConflicts (&b
, intersecting
, e
, 1
4413 /*cost penalty to box */
4415 add_or_destroy_edge (&s
, ne
);
4419 /* if this is not the intersecting piece, create a new
4420 * (hopefully unobstructed) via edge and add it back to the
4423 CreateViaEdge (&b
, e
->rb
->group
,
4424 e
->rb
->parent
.expansion_area
, e
,
4425 e
->flags
.via_conflict_level
,
4427 /* value here doesn't matter */
4429 add_or_destroy_edge (&s
, ne
);
4435 /* between the time these edges are inserted and the
4436 * time they are processed, new expansion boxes (which
4437 * conflict with these edges) may be added to the graph!
4438 * w.o vias this isn't a problem because the broken box
4439 * is not homeless. */
4444 struct E_result
*ans
;
4447 if (e
->flags
.is_interior
)
4449 assert (AutoRouteParameters
.with_conflicts
); /* no interior edges unless
4450 routing with conflicts! */
4451 assert (e
->rb
->conflicts_with
);
4453 switch (e
->rb
->came_from
)
4457 b
.X1
= CENTER_X (b
);
4462 b
.Y1
= CENTER_Y (b
);
4467 b
.X1
= CENTER_X (b
);
4472 b
.Y1
= CENTER_Y (b
);
4479 /* sources may not expand to their own edges because of
4480 * adjacent blockers.
4482 else if (e
->rb
->flags
.source
)
4483 b
= box_center (&e
->rb
->sbox
);
4486 ans
= Expand (rd
->layergrouptree
[e
->rb
->group
], e
, &b
);
4487 if (!box_intersect (&ans
->inflated
, &ans
->orig
))
4490 /* skip if it didn't actually expand */
4491 if (ans
->inflated
.X1
>= e
->rb
->sbox
.X1
&&
4492 ans
->inflated
.X2
<= e
->rb
->sbox
.X2
&&
4493 ans
->inflated
.Y1
>= e
->rb
->sbox
.Y1
&&
4494 ans
->inflated
.Y2
<= e
->rb
->sbox
.Y2
)
4498 if (!box_is_good (&ans
->inflated
))
4500 nrb
= CreateExpansionArea (&ans
->inflated
, e
->rb
->group
, e
->rb
,
4502 r_insert_entry (rd
->layergrouptree
[nrb
->group
], &nrb
->box
, 1);
4503 vector_append (area_vec
, nrb
);
4504 nrb
->flags
.homeless
= 0; /* not homeless any more */
4506 BreakManyEdges (&s
, targets
, rd
->layergrouptree
[nrb
->group
],
4507 area_vec
, ans
, nrb
, e
);
4508 while (!vector_is_empty (broken
))
4510 edge_t
*ne
= (edge_t
*)vector_remove_last (broken
);
4511 add_or_destroy_edge (&s
, ne
);
4513 vector_destroy (&broken
);
4515 /* add in possible via sites in nrb */
4516 if (AutoRouteParameters
.use_vias
&& !e
->rb
->flags
.is_via
&&
4517 e
->cost
+ AutoRouteParameters
.ViaCost
< s
.best_cost
)
4518 add_via_sites (&s
, &vss
,
4519 rd
->mtspace
, nrb
, NO_CONFLICT
, e
, targets
, 0,
4526 touch_conflicts (NULL
, 1);
4527 heap_destroy (&s
.workheap
);
4528 r_destroy_tree (&targets
);
4529 assert (vector_is_empty (edge_vec
));
4530 vector_destroy (&edge_vec
);
4532 /* we should have a path in best_path now */
4536 #ifdef ROUTE_VERBOSE
4537 printf ("%d:%d RC %.0f", ro
++, seen
, s
.best_cost
);
4539 result
.found_route
= true;
4540 result
.best_route_cost
= s
.best_cost
;
4541 /* determine if the best path had conflicts */
4542 result
.route_had_conflicts
= 0;
4543 if (AutoRouteParameters
.with_conflicts
&& s
.best_path
->conflicts_with
)
4545 while (!vector_is_empty (s
.best_path
->conflicts_with
))
4547 rb
= (routebox_t
*)vector_remove_last (s
.best_path
->conflicts_with
);
4548 rb
->flags
.is_bad
= 1;
4549 result
.route_had_conflicts
++;
4552 #ifdef ROUTE_VERBOSE
4553 if (result
.route_had_conflicts
)
4554 printf (" (%d conflicts)", result
.route_had_conflicts
);
4556 if (result
.route_had_conflicts
< AutoRouteParameters
.hi_conflict
)
4558 /* back-trace the path and add lines/vias to r-tree */
4559 TracePath (rd
, s
.best_path
, s
.best_target
, from
,
4560 result
.route_had_conflicts
);
4561 MergeNets (from
, s
.best_target
, SUBNET
);
4565 #ifdef ROUTE_VERBOSE
4566 printf (" (too many in fact)");
4568 result
.found_route
= false;
4570 #ifdef ROUTE_VERBOSE
4576 #ifdef ROUTE_VERBOSE
4577 printf ("%d:%d NO PATH FOUND.\n", ro
++, seen
);
4579 result
.best_route_cost
= s
.best_cost
;
4580 result
.found_route
= false;
4582 /* now remove all expansion areas from the r-tree. */
4583 while (!vector_is_empty (area_vec
))
4585 routebox_t
*rb
= (routebox_t
*)vector_remove_last (area_vec
);
4586 assert (!rb
->flags
.homeless
);
4587 if (rb
->conflicts_with
4588 && rb
->parent
.expansion_area
->conflicts_with
!= rb
->conflicts_with
)
4589 vector_destroy (&rb
->conflicts_with
);
4590 r_delete_entry (rd
->layergrouptree
[rb
->group
], &rb
->box
);
4592 vector_destroy (&area_vec
);
4593 /* clean up; remove all 'source', 'target', and 'nobloat' flags */
4594 LIST_LOOP (from
, same_net
, p
);
4595 if (p
->flags
.source
&& p
->conflicts_with
)
4596 vector_destroy (&p
->conflicts_with
);
4597 p
->flags
.touched
= p
->flags
.source
= p
->flags
.target
= p
->flags
.nobloat
= 0;
4600 vector_destroy (&vss
.free_space_vec
);
4601 vector_destroy (&vss
.lo_conflict_space_vec
);
4602 vector_destroy (&vss
.hi_conflict_space_vec
);
4608 InitAutoRouteParameters (int pass
,
4609 RouteStyleType
* style
,
4610 bool with_conflicts
, bool is_smoothing
,
4615 AutoRouteParameters
.style
= style
;
4616 AutoRouteParameters
.bloat
= style
->Keepaway
+ HALF_THICK (style
->Thick
);
4618 AutoRouteParameters
.ViaCost
=
4619 INCH_TO_COORD (3.5) + style
->Diameter
* (is_smoothing
? 80 : 30);
4620 AutoRouteParameters
.LastConflictPenalty
=
4621 (400 * pass
/ passes
+ 2) / (pass
+ 1);
4622 AutoRouteParameters
.ConflictPenalty
=
4623 4 * AutoRouteParameters
.LastConflictPenalty
;
4624 AutoRouteParameters
.JogPenalty
= 1000 * (is_smoothing
? 20 : 4);
4625 AutoRouteParameters
.CongestionPenalty
= 1e6
;
4626 AutoRouteParameters
.MinPenalty
= EXPENSIVE
;
4627 for (i
= 0; i
< max_group
; i
++)
4629 if (is_layer_group_active
[i
])
4631 AutoRouteParameters
.MinPenalty
= MIN (x_cost
[i
],
4632 AutoRouteParameters
.
4634 AutoRouteParameters
.MinPenalty
=
4635 MIN (y_cost
[i
], AutoRouteParameters
.MinPenalty
);
4638 AutoRouteParameters
.NewLayerPenalty
= is_smoothing
?
4639 0.5 * EXPENSIVE
: 10 * AutoRouteParameters
.ViaCost
;
4641 AutoRouteParameters
.hi_conflict
= MAX (8 * (passes
- pass
+ 1), 6);
4642 AutoRouteParameters
.is_odd
= (pass
& 1);
4643 AutoRouteParameters
.with_conflicts
= with_conflicts
;
4644 AutoRouteParameters
.is_smoothing
= is_smoothing
;
4645 AutoRouteParameters
.rip_always
= is_smoothing
;
4646 AutoRouteParameters
.last_smooth
= 0; //lastpass;
4647 AutoRouteParameters
.pass
= pass
+ 1;
4652 bad_boy (const BoxType
* b
, void *cl
)
4654 routebox_t
*box
= (routebox_t
*) b
;
4655 if (box
->type
== EXPANSION_AREA
)
4661 no_expansion_boxes (routedata_t
* rd
)
4669 for (i
= 0; i
< max_group
; i
++)
4671 if (r_search (rd
->layergrouptree
[i
], &big
, NULL
, bad_boy
, NULL
))
4679 ripout_livedraw_obj (routebox_t
*rb
)
4681 if (rb
->type
== LINE
&& rb
->livedraw_obj
.line
)
4683 LayerType
*layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[rb
->group
][0]);
4684 EraseLine (rb
->livedraw_obj
.line
);
4685 DestroyObject (PCB
->Data
, LINE_TYPE
, layer
, rb
->livedraw_obj
.line
, NULL
);
4686 rb
->livedraw_obj
.line
= NULL
;
4688 if (rb
->type
== VIA
&& rb
->livedraw_obj
.via
)
4690 EraseVia (rb
->livedraw_obj
.via
);
4691 DestroyObject (PCB
->Data
, VIA_TYPE
, rb
->livedraw_obj
.via
, NULL
, NULL
);
4692 rb
->livedraw_obj
.via
= NULL
;
4697 ripout_livedraw_obj_cb (const BoxType
* b
, void *cl
)
4699 routebox_t
*box
= (routebox_t
*) b
;
4700 ripout_livedraw_obj (box
);
4704 struct routeall_status
4706 /* --- for completion rate statistics ---- */
4708 /* total subnets routed without conflicts */
4710 /* total subnets routed with conflicts */
4711 int conflict_subnets
;
4712 /* net failted entirely */
4714 /* net was ripped */
4716 int total_nets_routed
;
4720 calculate_progress (double this_heap_item
, double this_heap_size
,
4721 struct routeall_status
*ras
)
4723 double total_passes
= passes
+ smoothes
+ 1; /* + 1 is the refinement pass */
4724 double this_pass
= AutoRouteParameters
.pass
- 1; /* Number passes from zero */
4725 double heap_fraction
= (double)(ras
->routed_subnets
+ ras
->conflict_subnets
+ ras
->failed
) /
4726 (double)ras
->total_subnets
;
4727 double pass_fraction
= (this_heap_item
+ heap_fraction
) / this_heap_size
;
4728 double process_fraction
= (this_pass
+ pass_fraction
) / total_passes
;
4730 return process_fraction
;
4733 struct routeall_status
4734 RouteAll (routedata_t
* rd
)
4736 struct routeall_status ras
;
4737 struct routeone_status ros
;
4743 heap_t
*this_pass
, *next_pass
, *tmp
;
4744 routebox_t
*net
, *p
, *pp
;
4745 cost_t total_net_cost
, last_cost
= 0, this_cost
= 0;
4750 /* initialize heap for first pass;
4751 * do smallest area first; that makes
4752 * the subsequent costs more representative */
4753 this_pass
= heap_create ();
4754 next_pass
= heap_create ();
4756 net_heap
= heap_create ();
4758 LIST_LOOP (rd
->first_net
, different_net
, net
);
4761 BoxType bb
= shrink_routebox (net
);
4762 LIST_LOOP (net
, same_net
, p
);
4764 MAKEMIN (bb
.X1
, p
->sbox
.X1
);
4765 MAKEMIN (bb
.Y1
, p
->sbox
.Y1
);
4766 MAKEMAX (bb
.X2
, p
->sbox
.X2
);
4767 MAKEMAX (bb
.Y2
, p
->sbox
.Y2
);
4770 area
= (double) (bb
.X2
- bb
.X1
) * (bb
.Y2
- bb
.Y1
);
4771 heap_insert (this_pass
, area
, net
);
4775 ras
.total_nets_routed
= 0;
4776 /* refinement/finishing passes */
4777 for (i
= 0; i
<= passes
+ smoothes
; i
++)
4779 #ifdef ROUTE_VERBOSE
4780 if (i
> 0 && i
<= passes
)
4781 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i
);
4782 else if (i
> passes
)
4783 printf ("--------- STARTING SMOOTHING PASS %d -------------\n",
4786 ras
.total_subnets
= ras
.routed_subnets
= ras
.conflict_subnets
=
4787 ras
.failed
= ras
.ripped
= 0;
4788 assert (heap_is_empty (next_pass
));
4790 this_heap_size
= heap_size (this_pass
);
4791 for (this_heap_item
= 0; !heap_is_empty (this_pass
); this_heap_item
++)
4797 net
= (routebox_t
*) heap_remove_smallest (this_pass
);
4798 InitAutoRouteParameters (i
, net
->style
, i
< passes
, i
> passes
,
4799 i
== passes
+ smoothes
);
4802 /* rip up all unfixed traces in this net ? */
4803 if (AutoRouteParameters
.rip_always
)
4808 LIST_LOOP (net
, same_net
, p
);
4809 if (p
->flags
.is_bad
)
4817 LIST_LOOP (net
, same_net
, p
);
4818 p
->flags
.is_bad
= 0;
4819 if (!p
->flags
.fixed
)
4824 assert (!p
->flags
.homeless
);
4827 RemoveFromNet (p
, NET
);
4828 RemoveFromNet (p
, SUBNET
);
4830 if (AutoRouteParameters
.use_vias
&& p
->type
!= VIA_SHADOW
4831 && p
->type
!= PLANE
)
4833 mtspace_remove (rd
->mtspace
, &p
->box
,
4834 p
->flags
.is_odd
? ODD
: EVEN
,
4835 p
->style
->Keepaway
);
4837 mtspace_add (rd
->mtspace
, &p
->box
,
4838 p
->flags
.is_odd
? EVEN
: ODD
,
4839 p
->style
->Keepaway
);
4843 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
4844 ripout_livedraw_obj (p
);
4848 r_delete_entry (rd
->layergrouptree
[p
->group
],
4856 p
->flags
.is_odd
= AutoRouteParameters
.is_odd
;
4860 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
4862 /* reset to original connectivity */
4870 heap_insert (next_pass
, 0, net
);
4874 /* count number of subnets */
4875 FOREACH_SUBNET (net
, p
);
4876 ras
.total_subnets
++;
4877 END_FOREACH (net
, p
);
4878 /* the first subnet doesn't require routing. */
4879 ras
.total_subnets
--;
4882 /* only route that which isn't fully routed */
4884 if (ras
.total_subnets
== 0 || aabort
)
4886 if (ras
.total_subnets
== 0)
4889 heap_insert (next_pass
, 0, net
);
4893 /* the loop here ensures that we get to all subnets even if
4894 * some of them are unreachable from the first subnet. */
4895 LIST_LOOP (net
, same_net
, p
);
4898 BoxType b
= shrink_routebox (p
);
4899 /* using a heap allows us to start from smaller objects and
4900 * end at bigger ones. also prefer to start at planes, then pads */
4901 heap_insert (net_heap
, (float) (b
.X2
- b
.X1
) *
4902 #if defined(ROUTE_RANDOMIZED)
4903 (0.3 + rand () / (RAND_MAX
+ 1.0)) *
4905 (b
.Y2
- b
.Y1
) * (p
->type
== PLANE
?
4910 ros
.net_completely_routed
= 0;
4911 while (!heap_is_empty (net_heap
))
4913 p
= (routebox_t
*) heap_remove_smallest (net_heap
);
4915 if (!p
->flags
.fixed
|| p
->flags
.subnet_processed
||
4919 while (!ros
.net_completely_routed
)
4923 assert (no_expansion_boxes (rd
));
4924 /* FIX ME: the number of edges to examine should be in autoroute parameters
4925 * i.e. the 2000 and 800 hard-coded below should be controllable by the user
4928 RouteOne (rd
, p
, NULL
,
4929 ((AutoRouteParameters
.
4930 is_smoothing
? 2000 : 800) * (i
+
4933 total_net_cost
+= ros
.best_route_cost
;
4934 if (ros
.found_route
)
4936 if (ros
.route_had_conflicts
)
4937 ras
.conflict_subnets
++;
4940 ras
.routed_subnets
++;
4941 ras
.total_nets_routed
++;
4946 if (!ros
.net_completely_routed
)
4948 /* don't bother trying any other source in this subnet */
4949 LIST_LOOP (p
, same_subnet
, pp
);
4950 pp
->flags
.subnet_processed
= 1;
4954 /* note that we can infer nothing about ras.total_subnets based
4955 * on the number of calls to RouteOne, because we may be unable
4956 * to route a net from a particular starting point, but perfectly
4957 * able to route it from some other. */
4958 percent
= calculate_progress (this_heap_item
, this_heap_size
, &ras
);
4959 request_cancel
= gui
->progress (percent
* 100., 100,
4960 _("Autorouting tracks"));
4963 ras
.total_nets_routed
= 0;
4964 ras
.conflict_subnets
= 0;
4965 Message ("Autorouting cancelled\n");
4973 if (!ros
.net_completely_routed
)
4974 net
->flags
.is_bad
= 1; /* don't skip this the next round */
4976 /* Route easiest nets from this pass first on next pass.
4977 * This works best because it's likely that the hardest
4978 * is the last one routed (since it has the most obstacles)
4979 * but it will do no good to rip it up and try it again
4980 * without first changing any of the other routes
4982 heap_insert (next_pass
, total_net_cost
, net
);
4983 if (total_net_cost
< EXPENSIVE
)
4984 this_cost
+= total_net_cost
;
4985 /* reset subnet_processed flags */
4986 LIST_LOOP (net
, same_net
, p
);
4988 p
->flags
.subnet_processed
= 0;
4992 /* swap this_pass and next_pass and do it all over again! */
4994 assert (heap_is_empty (this_pass
));
4996 this_pass
= next_pass
;
4998 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE)
5000 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n",
5001 i
, ras
.routed_subnets
, ras
.total_subnets
, this_cost
,
5002 ras
.conflict_subnets
, ras
.failed
, ras
.ripped
);
5008 /* if no conflicts found, skip directly to smoothing pass! */
5009 if (ras
.conflict_subnets
== 0 && ras
.routed_subnets
== ras
.total_subnets
5011 i
= passes
- (smoothes
? 0 : 1);
5012 /* if no changes in a smoothing round, then we're done */
5013 if (this_cost
== last_cost
&& i
> passes
&& i
< passes
+ smoothes
)
5014 i
= passes
+ smoothes
- 1;
5015 last_cost
= this_cost
;
5019 Message ("%d of %d nets successfully routed.\n",
5020 ras
.routed_subnets
, ras
.total_subnets
);
5023 heap_destroy (&this_pass
);
5024 heap_destroy (&next_pass
);
5026 heap_destroy (&net_heap
);
5029 /* no conflicts should be left at the end of the process. */
5030 assert (ras
.conflict_subnets
== 0);
5043 fpin_rect (const BoxType
* b
, void *cl
)
5045 PinType
*pin
= (PinType
*) b
;
5046 struct fpin_info
*info
= (struct fpin_info
*) cl
;
5047 if (pin
->X
== info
->X
&& pin
->Y
== info
->Y
)
5049 info
->pin
= (PinType
*) b
;
5050 longjmp (info
->env
, 1);
5056 FindPin (const BoxType
* box
, PinType
** pin
)
5058 struct fpin_info info
;
5063 if (setjmp (info
.env
) == 0)
5064 r_search (PCB
->Data
->pin_tree
, box
, NULL
, fpin_rect
, &info
);
5070 if (setjmp (info
.env
) == 0)
5071 r_search (PCB
->Data
->via_tree
, box
, NULL
, fpin_rect
, &info
);
5083 * \brief Paths go on first 'on' layer in group.
5085 * Returns 'true' if any paths were added.
5088 IronDownAllUnfixedPaths (routedata_t
* rd
)
5090 bool changed
= false;
5092 routebox_t
*net
, *p
;
5094 LIST_LOOP (rd
->first_net
, different_net
, net
);
5096 LIST_LOOP (net
, same_net
, p
);
5098 if (!p
->flags
.fixed
)
5100 /* find first on layer in this group */
5101 assert (PCB
->LayerGroups
.Number
[p
->group
] > 0);
5102 assert (is_layer_group_active
[p
->group
]);
5103 for (i
= 0, layer
= NULL
; i
< PCB
->LayerGroups
.Number
[p
->group
];
5106 layer
= LAYER_PTR (PCB
->LayerGroups
.Entries
[p
->group
][i
]);
5110 assert (layer
&& layer
->On
); /*at least one layer must be on in this group! */
5111 assert (p
->type
!= EXPANSION_AREA
);
5112 if (p
->type
== LINE
)
5114 Coord halfwidth
= HALF_THICK (p
->style
->Thick
);
5115 double th
= halfwidth
* 2 + 1;
5117 assert (p
->parent
.line
== NULL
);
5118 /* orthogonal; thickness is 2*halfwidth */
5119 /* flip coordinates, if bl_to_ur */
5121 total_wire_length
+=
5122 sqrt ((b
.X2
- b
.X1
- th
) * (b
.X2
- b
.X1
- th
) +
5123 (b
.Y2
- b
.Y1
- th
) * (b
.Y2
- b
.Y1
- th
));
5124 b
= shrink_box (&b
, halfwidth
);
5125 if (b
.X2
== b
.X1
+ 1)
5127 if (b
.Y2
== b
.Y1
+ 1)
5129 if (p
->flags
.bl_to_ur
)
5136 /* using CreateDrawn instead of CreateNew concatenates sequential lines */
5137 p
->parent
.line
= CreateDrawnLineOnLayer
5138 (layer
, b
.X1
, b
.Y1
, b
.X2
, b
.Y2
,
5140 p
->style
->Keepaway
* 2,
5141 MakeFlags (AUTOFLAG
|
5142 (TEST_FLAG (CLEARNEWFLAG
, PCB
) ? CLEARLINEFLAG
:
5147 AddObjectToCreateUndoList (LINE_TYPE
, layer
,
5148 p
->parent
.line
, p
->parent
.line
);
5152 else if (p
->type
== VIA
|| p
->type
== VIA_SHADOW
)
5155 (p
->type
== VIA_SHADOW
) ? p
->parent
.via_shadow
: p
;
5156 Coord radius
= HALF_THICK (pp
->style
->Diameter
);
5157 BoxType b
= shrink_routebox (p
);
5159 assert (pp
->type
== VIA
);
5160 if (pp
->parent
.via
== NULL
)
5162 assert (b
.X1
+ radius
== b
.X2
- radius
);
5163 assert (b
.Y1
+ radius
== b
.Y2
- radius
);
5165 CreateNewVia (PCB
->Data
, b
.X1
+ radius
,
5167 pp
->style
->Diameter
,
5168 2 * pp
->style
->Keepaway
,
5169 0, pp
->style
->Hole
, NULL
,
5170 MakeFlags (AUTOFLAG
));
5171 assert (pp
->parent
.via
);
5174 AddObjectToCreateUndoList (VIA_TYPE
,
5181 assert (pp
->parent
.via
);
5182 if (p
->type
== VIA_SHADOW
)
5185 p
->parent
.via
= pp
->parent
.via
;
5188 else if (p
->type
== THERMAL
)
5189 /* nothing to do because, the via might not be there yet */ ;
5195 /* loop again to place all the thermals now that the vias are down */
5196 LIST_LOOP (net
, same_net
, p
);
5198 if (p
->type
== THERMAL
)
5200 PinType
*pin
= NULL
;
5201 /* thermals are alread a single point search, no need to shrink */
5202 int type
= FindPin (&p
->box
, &pin
);
5205 AddObjectToClearPolyUndoList (type
,
5206 pin
->Element
? pin
->Element
: pin
,
5208 RestoreToPolygon (PCB
->Data
, VIA_TYPE
, LAYER_PTR (p
->layer
),
5210 AddObjectToFlagUndoList (type
,
5211 pin
->Element
? pin
->Element
: pin
, pin
,
5213 ASSIGN_THERM (p
->layer
, PCB
->ThermStyle
, pin
);
5214 AddObjectToClearPolyUndoList (type
,
5215 pin
->Element
? pin
->Element
: pin
,
5217 ClearFromPolygon (PCB
->Data
, VIA_TYPE
, LAYER_PTR (p
->layer
),
5230 AutoRoute (bool selected
)
5232 bool changed
= false;
5236 total_wire_length
= 0;
5237 total_via_count
= 0;
5240 ddraw
= gui
->request_debug_draw ();
5243 ar_gc
= ddraw
->make_gc ();
5244 ddraw
->set_line_cap (ar_gc
, Round_Cap
);
5248 for (i
= 0; i
< NUM_STYLES
; i
++)
5250 if (PCB
->RouteStyle
[i
].Thick
== 0 ||
5251 PCB
->RouteStyle
[1].Diameter
== 0 ||
5252 PCB
->RouteStyle
[1].Hole
== 0 || PCB
->RouteStyle
[i
].Keepaway
== 0)
5254 Message ("You must define proper routing styles\n"
5255 "before auto-routing.\n");
5259 if (PCB
->Data
->RatN
== 0)
5261 rd
= CreateRouteData ();
5265 routebox_t
*net
, *rb
, *last
;
5267 /* count number of rats selected */
5268 RAT_LOOP (PCB
->Data
);
5270 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5274 #ifdef ROUTE_VERBOSE
5275 printf ("%d nets!\n", i
);
5278 goto donerouting
; /* nothing to do here */
5279 /* if only one rat selected, do things the quick way. =) */
5282 RAT_LOOP (PCB
->Data
);
5283 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5285 /* look up the end points of this rat line */
5287 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
5288 line
->Point1
.Y
, line
->group1
);
5290 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
5291 line
->Point2
.Y
, line
->group2
);
5293 /* If the rat starts or ends at a non-straight pad (i.e., at a
5294 * rotated SMD), a or b will be NULL since the autorouter can't
5297 if (a
!= NULL
&& b
!= NULL
)
5299 assert (a
->style
== b
->style
);
5300 /* route exactly one net, without allowing conflicts */
5301 InitAutoRouteParameters (0, a
->style
, false, true, true);
5302 /* hace planes work better as sources than targets */
5303 changed
= RouteOne (rd
, a
, b
, 150000).found_route
|| changed
;
5309 /* otherwise, munge the netlists so that only the selected rats
5311 /* first, separate all sub nets into separate nets */
5312 /* note that this code works because LIST_LOOP is clever enough not to
5313 * be fooled when the list is changing out from under it. */
5315 LIST_LOOP (rd
->first_net
, different_net
, net
);
5317 FOREACH_SUBNET (net
, rb
);
5321 last
->different_net
.next
= rb
;
5322 rb
->different_net
.prev
= last
;
5326 END_FOREACH (net
, rb
);
5327 LIST_LOOP (net
, same_net
, rb
);
5329 rb
->same_net
= rb
->same_subnet
;
5332 /* at this point all nets are equal to their subnets */
5337 last
->different_net
.next
= rd
->first_net
;
5338 rd
->first_net
->different_net
.prev
= last
;
5341 /* now merge only those subnets connected by a rat line */
5342 RAT_LOOP (PCB
->Data
);
5343 if (!selected
|| TEST_FLAG (SELECTEDFLAG
, line
))
5345 /* look up the end points of this rat line */
5349 FindRouteBoxOnLayerGroup (rd
, line
->Point1
.X
,
5350 line
->Point1
.Y
, line
->group1
);
5352 FindRouteBoxOnLayerGroup (rd
, line
->Point2
.X
,
5353 line
->Point2
.Y
, line
->group2
);
5356 #ifdef DEBUG_STALE_RATS
5357 AddObjectToFlagUndoList (RATLINE_TYPE
, line
, line
, line
);
5358 ASSIGN_FLAG (SELECTEDFLAG
, true, line
);
5360 #endif /* DEBUG_STALE_RATS */
5361 Message ("The rats nest is stale! Aborting autoroute...\n");
5364 /* merge subnets into a net! */
5365 MergeNets (a
, b
, NET
);
5368 /* now 'different_net' may point to too many different nets. Reset. */
5369 LIST_LOOP (rd
->first_net
, different_net
, net
);
5371 if (!net
->flags
.touched
)
5373 LIST_LOOP (net
, same_net
, rb
);
5374 rb
->flags
.touched
= 1;
5377 else /* this is not a "different net"! */
5378 RemoveFromNet (net
, DIFFERENT_NET
);
5381 /* reset "touched" flag */
5382 LIST_LOOP (rd
->first_net
, different_net
, net
);
5384 LIST_LOOP (net
, same_net
, rb
);
5386 assert (rb
->flags
.touched
);
5387 rb
->flags
.touched
= 0;
5393 /* okay, rd's idea of netlist now corresponds to what we want routed */
5394 /* auto-route all nets */
5395 changed
= (RouteAll (rd
).total_nets_routed
> 0) || changed
;
5397 gui
->progress (0, 0, NULL
);
5398 if (TEST_FLAG (LIVEROUTEFLAG
, PCB
))
5401 BoxType big
= {0, 0, MAX_COORD
, MAX_COORD
};
5402 for (i
= 0; i
< max_group
; i
++)
5404 r_search (rd
->layergrouptree
[i
], &big
, NULL
, ripout_livedraw_obj_cb
, NULL
);
5410 ddraw
->destroy_gc (ar_gc
);
5411 gui
->finish_debug_draw ();
5416 changed
= IronDownAllUnfixedPaths (rd
);
5417 Message ("Total added wire length = %$mS, %d vias added\n",
5418 (Coord
) total_wire_length
, total_via_count
);
5419 DestroyRouteData (&rd
);
5422 SaveUndoSerialNumber ();
5424 /* optimize rats, we've changed connectivity a lot. */
5425 DeleteRats (false /*all rats */ );
5426 RestoreUndoSerialNumber ();
5427 AddAllRats (false /*all rats */ , NULL
);
5428 RestoreUndoSerialNumber ();
5430 IncrementUndoSerialNumber ();
5434 #if defined (ROUTE_DEBUG)