feat(autorouter/anterouter): As second choice, anteroute fanouts in ordinal directions

This commit is contained in:
Mikolaj Wielgus 2025-10-10 18:03:50 +02:00
parent 43f8d69281
commit 60cf00e014
2 changed files with 136 additions and 45 deletions

View File

@ -11,7 +11,11 @@ use serde::{Deserialize, Serialize};
use specctra_core::mesadata::AccessMesadata; use specctra_core::mesadata::AccessMesadata;
use crate::{ use crate::{
autorouter::{compass_direction::CardinalDirection, ratline::RatlineIndex, Autorouter}, autorouter::{
compass_direction::{CardinalDirection, CompassDirection, OrdinalDirection},
ratline::RatlineIndex,
Autorouter,
},
board::edit::BoardEdit, board::edit::BoardEdit,
drawing::{ drawing::{
dot::FixedDotIndex, dot::FixedDotIndex,
@ -157,7 +161,7 @@ impl Anterouter {
source_dot, source_dot,
small_bbox, small_bbox,
target_layer, target_layer,
CardinalDirection::nearest_to_vector(ratline_delta), CardinalDirection::nearest_from_vector(ratline_delta),
options, options,
) )
.is_ok() .is_ok()
@ -190,7 +194,37 @@ impl Anterouter {
source_dot, source_dot,
large_bbox, large_bbox,
target_layer, target_layer,
CardinalDirection::nearest_to_vector(ratline_delta), CardinalDirection::nearest_from_vector(ratline_delta),
options,
)
.is_ok()
{
return;
}
if self
.anteroute_fanout_on_bbox(
autorouter,
ratvertex,
source_dot,
small_bbox,
target_layer,
OrdinalDirection::nearest_from_vector(ratline_delta),
options,
)
.is_ok()
{
return;
}
if self
.anteroute_fanout_on_bbox(
autorouter,
ratvertex,
source_dot,
large_bbox,
target_layer,
OrdinalDirection::nearest_from_vector(ratline_delta),
options, options,
) )
.is_ok() .is_ok()
@ -208,17 +242,17 @@ impl Anterouter {
source_dot: FixedDotIndex, source_dot: FixedDotIndex,
bbox: AABB<[f64; 2]>, bbox: AABB<[f64; 2]>,
target_layer: usize, target_layer: usize,
preferred_cardinal_direction: CardinalDirection, preferred_compass_direction: impl CompassDirection,
options: &AnterouterOptions, options: &AnterouterOptions,
) -> Result<(), ()> { ) -> Result<(), ()> {
if self if self
.anteroute_fanout_on_bbox_in_cardinal_direction( .anteroute_fanout_on_bbox_in_direction(
autorouter, autorouter,
ratvertex, ratvertex,
source_dot, source_dot,
bbox, bbox,
target_layer, target_layer,
preferred_cardinal_direction, preferred_compass_direction,
options, options,
) )
.is_ok() .is_ok()
@ -226,15 +260,15 @@ impl Anterouter {
return Ok(()); return Ok(());
} }
let mut counterclockwise_turning_cardinal_direction = preferred_cardinal_direction; let mut counterclockwise_turning_cardinal_direction = preferred_compass_direction;
let mut clockwise_turning_cardinal_direction = preferred_cardinal_direction; let mut clockwise_turning_cardinal_direction = preferred_compass_direction;
loop { loop {
counterclockwise_turning_cardinal_direction = counterclockwise_turning_cardinal_direction =
counterclockwise_turning_cardinal_direction.turn_counterclockwise(); counterclockwise_turning_cardinal_direction.turn_counterclockwise();
if self if self
.anteroute_fanout_on_bbox_in_cardinal_direction( .anteroute_fanout_on_bbox_in_direction(
autorouter, autorouter,
ratvertex, ratvertex,
source_dot, source_dot,
@ -252,7 +286,7 @@ impl Anterouter {
clockwise_turning_cardinal_direction.turn_clockwise(); clockwise_turning_cardinal_direction.turn_clockwise();
if self if self
.anteroute_fanout_on_bbox_in_cardinal_direction( .anteroute_fanout_on_bbox_in_direction(
autorouter, autorouter,
ratvertex, ratvertex,
source_dot, source_dot,
@ -266,31 +300,31 @@ impl Anterouter {
return Ok(()); return Ok(());
} }
if counterclockwise_turning_cardinal_direction == preferred_cardinal_direction if counterclockwise_turning_cardinal_direction == preferred_compass_direction
|| clockwise_turning_cardinal_direction == preferred_cardinal_direction || clockwise_turning_cardinal_direction == preferred_compass_direction
{ {
return Err(()); return Err(());
} }
} }
} }
fn anteroute_fanout_on_bbox_in_cardinal_direction( fn anteroute_fanout_on_bbox_in_direction(
&mut self, &mut self,
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratvertex: NodeIndex<usize>, ratvertex: NodeIndex<usize>,
source_dot: FixedDotIndex, source_dot: FixedDotIndex,
bbox: AABB<[f64; 2]>, bbox: AABB<[f64; 2]>,
target_layer: usize, target_layer: usize,
cardinal_direction: CardinalDirection, direction: impl Into<Point>,
options: &AnterouterOptions, options: &AnterouterOptions,
) -> Result<(), ()> { ) -> Result<(), ()> {
let (_, dots) = self.place_fanout_via_on_bbox_in_cardinal_direction( let (_, dots) = self.place_fanout_via_on_bbox_in_direction(
autorouter, autorouter,
ratvertex, ratvertex,
source_dot, source_dot,
bbox, bbox,
target_layer, target_layer,
cardinal_direction, direction,
options, options,
)?; )?;
@ -326,14 +360,14 @@ impl Anterouter {
Ok(()) Ok(())
} }
fn place_fanout_via_on_bbox_in_cardinal_direction( fn place_fanout_via_on_bbox_in_direction(
&mut self, &mut self,
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratvertex: NodeIndex<usize>, ratvertex: NodeIndex<usize>,
source_dot: FixedDotIndex, source_dot: FixedDotIndex,
bbox: AABB<[f64; 2]>, bbox: AABB<[f64; 2]>,
target_layer: usize, target_layer: usize,
cardinal_direction: CardinalDirection, direction: impl Into<Point>,
options: &AnterouterOptions, options: &AnterouterOptions,
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), ()> { ) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), ()> {
let source_layer = autorouter let source_layer = autorouter
@ -357,7 +391,7 @@ impl Anterouter {
.shape() .shape()
.center(); .center();
let cardinal_direction_vector = Point::from(cardinal_direction); let cardinal_direction_vector = direction.into();
let bbox_anchor = point! { let bbox_anchor = point! {
x: (bbox.upper()[0] - bbox.lower()[0]) / 2.0 * cardinal_direction_vector.x(), x: (bbox.upper()[0] - bbox.lower()[0]) / 2.0 * cardinal_direction_vector.x(),

View File

@ -4,6 +4,12 @@
use geo::Point; use geo::Point;
pub trait CompassDirection: Copy + PartialEq + Into<Point> {
fn nearest_from_vector(vector: Point) -> Self;
fn turn_clockwise(self) -> Self;
fn turn_counterclockwise(self) -> Self;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CardinalDirection { pub enum CardinalDirection {
North, North,
@ -13,8 +19,8 @@ pub enum CardinalDirection {
} }
impl From<CardinalDirection> for Point { impl From<CardinalDirection> for Point {
fn from(compass_direction: CardinalDirection) -> Point { fn from(cardinal_direction: CardinalDirection) -> Point {
match compass_direction { match cardinal_direction {
CardinalDirection::North => [0.0, -1.0].into(), CardinalDirection::North => [0.0, -1.0].into(),
CardinalDirection::West => [-1.0, 0.0].into(), CardinalDirection::West => [-1.0, 0.0].into(),
CardinalDirection::South => [0.0, 1.0].into(), CardinalDirection::South => [0.0, 1.0].into(),
@ -23,8 +29,8 @@ impl From<CardinalDirection> for Point {
} }
} }
impl CardinalDirection { impl CompassDirection for CardinalDirection {
pub fn nearest_to_vector(vector: Point) -> Self { fn nearest_from_vector(vector: Point) -> Self {
if vector.x().abs() > vector.y().abs() { if vector.x().abs() > vector.y().abs() {
if vector.x() > 0.0 { if vector.x() > 0.0 {
Self::East Self::East
@ -40,7 +46,16 @@ impl CardinalDirection {
} }
} }
pub fn turn_counterclockwise(self) -> Self { fn turn_clockwise(self) -> Self {
match self {
Self::North => Self::East,
Self::East => Self::South,
Self::South => Self::West,
Self::West => Self::North,
}
}
fn turn_counterclockwise(self) -> Self {
match self { match self {
Self::North => Self::West, Self::North => Self::West,
Self::West => Self::South, Self::West => Self::South,
@ -48,13 +63,55 @@ impl CardinalDirection {
Self::East => Self::North, Self::East => Self::North,
} }
} }
}
pub fn turn_clockwise(self) -> Self { #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OrdinalDirection {
NorthWest,
SouthWest,
SouthEast,
NorthEast,
}
impl From<OrdinalDirection> for Point {
fn from(ordinal_direction: OrdinalDirection) -> Point {
match ordinal_direction {
OrdinalDirection::NorthWest => [-1.0, -1.0].into(),
OrdinalDirection::SouthWest => [-1.0, 1.0].into(),
OrdinalDirection::SouthEast => [1.0, 1.0].into(),
OrdinalDirection::NorthEast => [1.0, -1.0].into(),
}
}
}
impl CompassDirection for OrdinalDirection {
fn nearest_from_vector(vector: Point) -> Self {
if vector.x() > 0.0 && vector.y() > 0.0 {
Self::SouthEast
} else if vector.x() > 0.0 && vector.y() < 0.0 {
Self::NorthEast
} else if vector.x() < 0.0 && vector.y() < 0.0 {
Self::NorthWest
} else {
Self::NorthEast
}
}
fn turn_clockwise(self) -> Self {
match self { match self {
Self::North => Self::East, Self::NorthWest => Self::SouthWest,
Self::East => Self::South, Self::SouthWest => Self::SouthEast,
Self::South => Self::West, Self::SouthEast => Self::SouthWest,
Self::West => Self::North, Self::NorthEast => Self::NorthWest,
}
}
fn turn_counterclockwise(self) -> Self {
match self {
Self::NorthWest => Self::SouthWest,
Self::SouthWest => Self::SouthEast,
Self::SouthEast => Self::NorthEast,
Self::NorthEast => Self::NorthWest,
} }
} }
} }
@ -86,8 +143,8 @@ impl From<PrincipalWind> for Point {
} }
} }
impl PrincipalWind { impl CompassDirection for PrincipalWind {
pub fn nearest_to_vector(vector: Point) -> Self { fn nearest_from_vector(vector: Point) -> Self {
if vector.x() == 0.0 && vector.y() == 0.0 { if vector.x() == 0.0 && vector.y() == 0.0 {
panic!("Zero vector has no direction"); panic!("Zero vector has no direction");
} }
@ -110,20 +167,7 @@ impl PrincipalWind {
} }
} }
pub fn turn_counterclockwise(self) -> Self { fn turn_clockwise(self) -> Self {
match self {
Self::North => Self::NorthWest,
Self::NorthWest => Self::West,
Self::West => Self::SouthWest,
Self::SouthWest => Self::South,
Self::South => Self::SouthEast,
Self::SouthEast => Self::East,
Self::East => Self::NorthEast,
Self::NorthEast => Self::North,
}
}
pub fn turn_clockwise(self) -> Self {
match self { match self {
Self::North => Self::NorthEast, Self::North => Self::NorthEast,
Self::NorthEast => Self::East, Self::NorthEast => Self::East,
@ -135,4 +179,17 @@ impl PrincipalWind {
Self::NorthWest => Self::North, Self::NorthWest => Self::North,
} }
} }
fn turn_counterclockwise(self) -> Self {
match self {
Self::North => Self::NorthWest,
Self::NorthWest => Self::West,
Self::West => Self::SouthWest,
Self::SouthWest => Self::South,
Self::South => Self::SouthEast,
Self::SouthEast => Self::East,
Self::East => Self::NorthEast,
Self::NorthEast => Self::North,
}
}
} }