refactor(autorouter/ratsnest): Split out ratline code to new file, ratline.rs

This commit is contained in:
Mikolaj Wielgus 2025-07-12 02:28:13 +02:00 committed by mikolaj
parent bf44fe1e71
commit 0752817538
8 changed files with 141 additions and 66 deletions

View File

@ -7,12 +7,11 @@
use std::ops::ControlFlow;
use petgraph::graph::EdgeIndex;
use crate::{
board::AccessMesadata,
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex, Collect},
geometry::primitive::PrimitiveShape,
graph::MakeRef,
layout::LayoutEdit,
router::{
navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper, RouteStepper, Router,
@ -20,7 +19,10 @@ use crate::{
stepper::{EstimateProgress, Step},
};
use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError, AutorouterOptions};
use super::{
invoker::GetDebugOverlayData, ratline::RatlineIndex, Autorouter, AutorouterError,
AutorouterOptions,
};
/// Represents the current status of the autoroute operation.
pub enum AutorouteContinueStatus {
@ -35,7 +37,7 @@ pub enum AutorouteContinueStatus {
/// Manages the autorouting process across multiple ratlines.
pub struct AutorouteExecutionStepper {
/// The ratlines which we are routing.
ratlines: Vec<EdgeIndex<usize>>,
ratlines: Vec<RatlineIndex>,
/// Keeps track of the current ratline being routed, if one is active.
curr_ratline_index: usize,
/// Stores the current route being processed, if any.
@ -52,14 +54,14 @@ impl AutorouteExecutionStepper {
/// and stores the associated data for future routing steps.
pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<EdgeIndex<usize>>,
ratlines: Vec<RatlineIndex>,
options: AutorouterOptions,
) -> Result<Self, AutorouterError> {
if ratlines.is_empty() {
return Err(AutorouterError::NothingToRoute);
};
let (origin, destination) = autorouter.ratline_endpoints(ratlines[0]);
let (origin, destination) = ratlines[0].ref_(autorouter).endpoint_dots();
let mut router = Router::new(autorouter.board.layout_mut(), options.router_options);
Ok(Self {
@ -101,7 +103,9 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
return Ok(ControlFlow::Break(None));
};
let (source, target) = autorouter.ratline_endpoints(self.ratlines[self.curr_ratline_index]);
let (source, target) = self.ratlines[self.curr_ratline_index]
.ref_(autorouter)
.endpoint_dots();
let ret = if let Some(band_termseg) = autorouter.board.band_between_nodes(source, target) {
AutorouteContinueStatus::Skipped(band_termseg[false])
@ -138,7 +142,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
self.curr_ratline_index += 1;
if let Some(new_ratline) = self.ratlines.get(self.curr_ratline_index) {
let (source, target) = autorouter.ratline_endpoints(*new_ratline);
let (source, target) = new_ratline.ref_(autorouter).endpoint_dots();
let mut router =
Router::new(autorouter.board.layout_mut(), self.options.router_options);

View File

@ -4,7 +4,7 @@
use derive_getters::Getters;
use geo::Point;
use petgraph::graph::{EdgeIndex, NodeIndex};
use petgraph::graph::NodeIndex;
use serde::{Deserialize, Serialize};
use spade::InsertionError;
use std::collections::BTreeSet;
@ -25,6 +25,7 @@ use super::{
measure_length::MeasureLengthExecutionStepper,
place_via::PlaceViaExecutionStepper,
pointroute::PointrouteExecutionStepper,
ratline::RatlineIndex,
ratsnest::{Ratsnest, RatvertexIndex},
remove_bands::RemoveBandsExecutionStepper,
selection::{BandSelection, PinSelection},
@ -104,7 +105,7 @@ impl<M: AccessMesadata> Autorouter<M> {
pub(super) fn autoroute_ratlines(
&mut self,
ratlines: Vec<EdgeIndex<usize>>,
ratlines: Vec<RatlineIndex>,
options: AutorouterOptions,
) -> Result<AutorouteExecutionStepper, AutorouterError> {
AutorouteExecutionStepper::new(self, ratlines, options)
@ -116,7 +117,7 @@ impl<M: AccessMesadata> Autorouter<M> {
pub(super) fn undo_autoroute_ratlines(
&mut self,
ratlines: Vec<EdgeIndex<usize>>,
ratlines: Vec<RatlineIndex>,
) -> Result<(), AutorouterError> {
for ratline in ratlines.iter() {
let band = self
@ -157,7 +158,7 @@ impl<M: AccessMesadata> Autorouter<M> {
pub(super) fn topo_autoroute_ratlines(
&mut self,
ratlines: Vec<EdgeIndex<usize>>,
ratlines: Vec<RatlineIndex>,
allowed_edges: BTreeSet<ng::PieEdgeIndex>,
active_layer: usize,
width: f64,
@ -187,7 +188,7 @@ impl<M: AccessMesadata> Autorouter<M> {
active_layer,
allowed_edges,
ratlines.into_iter().filter_map(|ratline| {
let (source, target) = self.ratline_endpoints(ratline);
let (source, target) = ratline.ref_(self).endpoint_dots();
if navmesh
.as_ref()
@ -260,8 +261,8 @@ impl<M: AccessMesadata> Autorouter<M> {
pub(super) fn compare_detours_ratlines(
&mut self,
ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>,
ratline1: RatlineIndex,
ratline2: RatlineIndex,
options: AutorouterOptions,
) -> Result<CompareDetoursExecutionStepper, AutorouterError> {
CompareDetoursExecutionStepper::new(self, ratline1, ratline2, options)
@ -274,35 +275,7 @@ impl<M: AccessMesadata> Autorouter<M> {
MeasureLengthExecutionStepper::new(selection)
}
pub fn ratline_endpoints(&self, ratline: EdgeIndex<usize>) -> (FixedDotIndex, FixedDotIndex) {
let (source, target) = self.ratsnest.graph().edge_endpoints(ratline).unwrap();
let source_dot = match self
.ratsnest
.graph()
.node_weight(source)
.unwrap()
.node_index()
{
RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(),
};
let target_dot = match self
.ratsnest
.graph()
.node_weight(target)
.unwrap()
.node_index()
{
RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(),
};
(source_dot, target_dot)
}
pub(super) fn selected_ratlines(&self, selection: &PinSelection) -> Vec<EdgeIndex<usize>> {
pub(super) fn selected_ratlines(&self, selection: &PinSelection) -> Vec<RatlineIndex> {
self.ratsnest
.graph()
.edge_indices()

View File

@ -7,8 +7,6 @@
use std::ops::ControlFlow;
use petgraph::graph::EdgeIndex;
use crate::{
board::AccessMesadata,
drawing::graph::PrimitiveIndex,
@ -21,14 +19,15 @@ use crate::{
use super::{
autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper},
invoker::GetDebugOverlayData,
ratline::RatlineIndex,
Autorouter, AutorouterError, AutorouterOptions,
};
pub struct CompareDetoursExecutionStepper {
autoroute: AutorouteExecutionStepper,
next_autoroute: Option<AutorouteExecutionStepper>,
ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>,
ratline1: RatlineIndex,
ratline2: RatlineIndex,
total_length1: f64,
total_length2: f64,
done: bool,
@ -37,8 +36,8 @@ pub struct CompareDetoursExecutionStepper {
impl CompareDetoursExecutionStepper {
pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>,
ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>,
ratline1: RatlineIndex,
ratline2: RatlineIndex,
options: AutorouterOptions,
) -> Result<Self, AutorouterError> {
Ok(Self {

View File

@ -13,6 +13,7 @@ pub mod invoker;
pub mod measure_length;
pub mod place_via;
pub mod pointroute;
pub mod ratline;
pub mod ratsnest;
pub mod remove_bands;
pub mod selection;

103
src/autorouter/ratline.rs Normal file
View File

@ -0,0 +1,103 @@
// SPDX-FileCopyrightText: 2025 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use geo::{Distance, Euclidean};
use petgraph::graph::EdgeIndex;
use specctra_core::mesadata::AccessMesadata;
use crate::{
drawing::{band::BandTermsegIndex, dot::FixedDotIndex},
geometry::shape::MeasureLength,
graph::MakeRef,
triangulation::GetTrianvertexNodeIndex,
};
use super::{ratsnest::RatvertexIndex, Autorouter};
pub type RatlineIndex = EdgeIndex<usize>;
#[derive(Debug, Default, Clone, Copy)]
pub struct RatlineWeight {
pub band_termseg: Option<BandTermsegIndex>,
}
impl<'a, M: AccessMesadata + 'a> MakeRef<'a, Autorouter<M>> for RatlineIndex {
type Output = RatlineRef<'a, M>;
fn ref_(&self, autorouter: &'a Autorouter<M>) -> RatlineRef<'a, M> {
RatlineRef::new(*self, autorouter)
}
}
pub struct RatlineRef<'a, M: AccessMesadata> {
index: RatlineIndex,
autorouter: &'a Autorouter<M>,
}
impl<'a, M: AccessMesadata> RatlineRef<'a, M> {
pub fn new(index: RatlineIndex, autorouter: &'a Autorouter<M>) -> Self {
Self { index, autorouter }
}
pub fn endpoint_dots(&self) -> (FixedDotIndex, FixedDotIndex) {
let (source, target) = self
.autorouter
.ratsnest
.graph()
.edge_endpoints(self.index)
.unwrap();
let source_dot = match self
.autorouter
.ratsnest
.graph()
.node_weight(source)
.unwrap()
.node_index()
{
RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(),
};
let target_dot = match self
.autorouter
.ratsnest
.graph()
.node_weight(target)
.unwrap()
.node_index()
{
RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(),
};
(source_dot, target_dot)
}
}
impl<'a, M: AccessMesadata> MeasureLength for RatlineRef<'a, M> {
fn length(&self) -> f64 {
let (ratvertex0, ratvertex1) = self
.autorouter
.ratsnest
.graph()
.edge_endpoints(self.index)
.unwrap();
let ratvertex0_pos = self
.autorouter
.ratsnest
.graph()
.node_weight(ratvertex0)
.unwrap()
.pos;
let ratvertex1_pos = self
.autorouter
.ratsnest
.graph()
.node_weight(ratvertex1)
.unwrap()
.pos;
Euclidean::distance(&ratvertex0_pos, &ratvertex1_pos)
}
}

View File

@ -13,7 +13,7 @@ use enum_dispatch::enum_dispatch;
use geo::Point;
use petgraph::{
data::Element,
graph::{EdgeIndex, NodeIndex, UnGraph},
graph::{NodeIndex, UnGraph},
unionfind::UnionFind,
visit::{EdgeRef, IntoEdgeReferences, NodeIndexable},
};
@ -36,6 +36,8 @@ use crate::{
triangulation::{GetTrianvertexNodeIndex, Triangulation},
};
use super::ratline::{RatlineIndex, RatlineWeight};
#[enum_dispatch(GetPetgraphIndex)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RatvertexIndex {
@ -71,11 +73,6 @@ impl HasPosition for RatvertexWeight {
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct RatlineWeight {
pub band_termseg: Option<BandTermsegIndex>,
}
pub struct Ratsnest {
graph: UnGraph<RatvertexWeight, RatlineWeight, usize>,
}
@ -161,7 +158,7 @@ impl Ratsnest {
pub fn assign_band_termseg_to_ratline(
&mut self,
ratline: EdgeIndex<usize>,
ratline: RatlineIndex,
termseg: BandTermsegIndex,
) {
self.graph.edge_weight_mut(ratline).unwrap().band_termseg = Some(termseg);

View File

@ -11,8 +11,7 @@ use petgraph::{
graph::UnGraph,
stable_graph::NodeIndex,
visit::{
Data, EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges, IntoNeighbors,
IntoNodeIdentifiers, NodeIndexable,
Data, EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNodeIdentifiers,
},
};
use spade::InsertionError;
@ -23,21 +22,19 @@ use crate::{
bend::{FixedBendIndex, LooseBendIndex},
dot::FixedDotIndex,
gear::{GearIndex, GetNextGear},
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex},
graph::{MakePrimitive, PrimitiveIndex},
primitive::Primitive,
rules::AccessRules,
Drawing,
},
geometry::GetLayer,
graph::{GetPetgraphIndex, MakeRef},
layout::Layout,
math::RotationSense,
router::thetastar::MakeEdgeRef,
triangulation::Triangulation,
};
use super::{
prenavmesh::{Prenavmesh, PrenavmeshConstraint, PrenavmeshNodeIndex, PrenavmeshWeight},
prenavmesh::{Prenavmesh, PrenavmeshNodeIndex},
RouterOptions,
};

View File

@ -83,7 +83,8 @@ pub fn assert_navnode_count(
.collect::<Vec<_>>()
.iter()
.find_map(|ratline| {
let (candidate_origin, candidate_destination) = autorouter.ratline_endpoints(*ratline);
let (candidate_origin, candidate_destination) =
autorouter.ratline_endpoint_dots(*ratline);
let candidate_origin_pin = autorouter
.board()
.node_pinname(&GenericNode::Primitive(candidate_origin.into()))
@ -121,7 +122,7 @@ pub fn assert_single_layer_groundless_autoroute(
let unionfind = unionfind(autorouter);
for ratline in autorouter.ratsnest().graph().edge_indices() {
let (origin_dot, destination_dot) = autorouter.ratline_endpoints(ratline);
let (origin_dot, destination_dot) = autorouter.ratline_endpoint_dots(ratline);
let origin_layer = autorouter
.board()
@ -219,7 +220,7 @@ fn unionfind(autorouter: &mut Autorouter<impl AccessMesadata>) -> UnionFind<Node
for ratline in autorouter.ratsnest().graph().edge_indices() {
// Accessing endpoints may create new dots because apex construction is lazy, so we access
// tem all before starting unionfind, as it requires a constant index bound.
let _ = autorouter.ratline_endpoints(ratline);
let _ = autorouter.ratline_endpoint_dots(ratline);
}
let mut unionfind = UnionFind::new(