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

View File

@ -4,6 +4,12 @@
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)]
pub enum CardinalDirection {
North,
@ -13,8 +19,8 @@ pub enum CardinalDirection {
}
impl From<CardinalDirection> for Point {
fn from(compass_direction: CardinalDirection) -> Point {
match compass_direction {
fn from(cardinal_direction: CardinalDirection) -> Point {
match cardinal_direction {
CardinalDirection::North => [0.0, -1.0].into(),
CardinalDirection::West => [-1.0, 0.0].into(),
CardinalDirection::South => [0.0, 1.0].into(),
@ -23,8 +29,8 @@ impl From<CardinalDirection> for Point {
}
}
impl CardinalDirection {
pub fn nearest_to_vector(vector: Point) -> Self {
impl CompassDirection for CardinalDirection {
fn nearest_from_vector(vector: Point) -> Self {
if vector.x().abs() > vector.y().abs() {
if vector.x() > 0.0 {
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 {
Self::North => Self::West,
Self::West => Self::South,
@ -48,13 +63,55 @@ impl CardinalDirection {
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 {
Self::North => Self::East,
Self::East => Self::South,
Self::South => Self::West,
Self::West => Self::North,
Self::NorthWest => Self::SouthWest,
Self::SouthWest => Self::SouthEast,
Self::SouthEast => Self::SouthWest,
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 {
pub fn nearest_to_vector(vector: Point) -> Self {
impl CompassDirection for PrincipalWind {
fn nearest_from_vector(vector: Point) -> Self {
if vector.x() == 0.0 && vector.y() == 0.0 {
panic!("Zero vector has no direction");
}
@ -110,20 +167,7 @@ impl PrincipalWind {
}
}
pub 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,
}
}
pub fn turn_clockwise(self) -> Self {
fn turn_clockwise(self) -> Self {
match self {
Self::North => Self::NorthEast,
Self::NorthEast => Self::East,
@ -135,4 +179,17 @@ impl PrincipalWind {
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,
}
}
}