refactor(autorouter/planar_autoroute): Wrap ratline vec in new "configuration" struct

This will be useful later.
This commit is contained in:
Mikolaj Wielgus 2025-10-22 18:27:23 +02:00
parent 58e366ab0f
commit 630c3f0202
5 changed files with 70 additions and 58 deletions

View File

@ -14,6 +14,7 @@ use crate::{
autorouter::{ autorouter::{
multilayer_autoroute::MultilayerAutorouteOptions, multilayer_autoroute::MultilayerAutorouteOptions,
multilayer_reconfigurator::MultilayerAutorouteReconfigurator, multilayer_reconfigurator::MultilayerAutorouteReconfigurator,
planar_autoroute::PlanarAutorouteConfiguration,
planar_reconfigurator::PlanarAutorouteReconfigurator, ratsnests::Ratsnests, planar_reconfigurator::PlanarAutorouteReconfigurator, ratsnests::Ratsnests,
}, },
board::{AccessMesadata, Board}, board::{AccessMesadata, Board},
@ -132,7 +133,9 @@ impl<M: AccessMesadata> Autorouter<M> {
) -> Result<PlanarAutorouteReconfigurator, AutorouterError> { ) -> Result<PlanarAutorouteReconfigurator, AutorouterError> {
PlanarAutorouteReconfigurator::new( PlanarAutorouteReconfigurator::new(
self, self,
self.selected_planar_ratlines(selection, options.principal_layer), PlanarAutorouteConfiguration {
ratlines: self.selected_planar_ratlines(selection, options.principal_layer),
},
options, options,
) )
} }

View File

@ -11,6 +11,7 @@ use crate::{
autorouter::{ autorouter::{
anterouter::{Anterouter, AnterouterOptions, AnterouterPlan}, anterouter::{Anterouter, AnterouterOptions, AnterouterPlan},
invoker::GetDebugOverlayData, invoker::GetDebugOverlayData,
planar_autoroute::PlanarAutorouteConfiguration,
planar_reconfigurator::{PlanarAutorouteReconfigurator, PlanarReconfiguratorStatus}, planar_reconfigurator::{PlanarAutorouteReconfigurator, PlanarReconfiguratorStatus},
ratline::RatlineUid, ratline::RatlineUid,
Autorouter, AutorouterError, PlanarAutorouteOptions, Autorouter, AutorouterError, PlanarAutorouteOptions,
@ -46,7 +47,11 @@ impl MultilayerAutorouteExecutionStepper {
anterouter.anteroute(autorouter, &mut anteroute_edit, &options.anterouter); anterouter.anteroute(autorouter, &mut anteroute_edit, &options.anterouter);
Ok(Self { Ok(Self {
planar: PlanarAutorouteReconfigurator::new(autorouter, ratlines, options.planar)?, planar: PlanarAutorouteReconfigurator::new(
autorouter,
PlanarAutorouteConfiguration { ratlines },
options.planar,
)?,
anteroute_edit, anteroute_edit,
options: options.clone(), options: options.clone(),
}) })

View File

@ -59,8 +59,8 @@ pub enum PlanarAutorouteContinueStatus {
/// Manages the autorouting process across multiple ratlines. /// Manages the autorouting process across multiple ratlines.
#[derive(Getters)] #[derive(Getters)]
pub struct PlanarAutorouteExecutionStepper { pub struct PlanarAutorouteExecutionStepper {
/// The ratlines which we are routing. /// The stepper configuration, including the ratlines which we are routing.
ratlines: Vec<RatlineUid>, configuration: PlanarAutorouteConfiguration,
/// Keeps track of the current ratline being routed, if one is active. /// Keeps track of the current ratline being routed, if one is active.
curr_ratline_index: usize, curr_ratline_index: usize,
/// Stores the current route being processed, if any. /// Stores the current route being processed, if any.
@ -74,25 +74,22 @@ pub struct PlanarAutorouteExecutionStepper {
} }
impl PlanarAutorouteExecutionStepper { impl PlanarAutorouteExecutionStepper {
/// Initializes a new [`AutorouteExecutionStepper`] instance.
///
/// This method sets up the routing process by accepting the execution properties.
/// It prepares the first ratline to route
/// and stores the associated data for future routing steps.
pub fn new( pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineUid>, configuration: PlanarAutorouteConfiguration,
options: PlanarAutorouteOptions, options: PlanarAutorouteOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
if ratlines.is_empty() { if configuration.ratlines.is_empty() {
return Err(AutorouterError::NothingToRoute); return Err(AutorouterError::NothingToRoute);
}; };
let (origin, destination) = ratlines[0].ref_(autorouter).terminating_dots(); let (origin, destination) = configuration.ratlines[0]
.ref_(autorouter)
.terminating_dots();
let mut router = Router::new(autorouter.board.layout_mut(), options.router); let mut router = Router::new(autorouter.board.layout_mut(), options.router);
Ok(Self { Ok(Self {
ratlines, configuration,
curr_ratline_index: 0, curr_ratline_index: 0,
route: Some(router.route( route: Some(router.route(
LayoutEdit::new(), LayoutEdit::new(),
@ -124,7 +121,9 @@ impl PlanarAutorouteExecutionStepper {
autorouter.board.apply_edit(&board_edit.reverse()); autorouter.board.apply_edit(&board_edit.reverse());
let (origin, destination) = self.ratlines[index].ref_(autorouter).terminating_dots(); let (origin, destination) = self.configuration.ratlines[index]
.ref_(autorouter)
.terminating_dots();
let mut router = Router::new(autorouter.board.layout_mut(), self.options.router); let mut router = Router::new(autorouter.board.layout_mut(), self.options.router);
self.route = Some(router.route( self.route = Some(router.route(
@ -158,7 +157,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
{ {
// TODO: Use a proper state machine here for better readability? // TODO: Use a proper state machine here for better readability?
if self.curr_ratline_index >= self.ratlines.len() { if self.curr_ratline_index >= self.configuration().ratlines.len() {
self.dissolve_route_stepper_and_push_layout_edit(); self.dissolve_route_stepper_and_push_layout_edit();
return Ok(ControlFlow::Break(Some(BoardEdit::new_from_edits( return Ok(ControlFlow::Break(Some(BoardEdit::new_from_edits(
@ -170,15 +169,15 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
)))); ))));
} }
let (origin, destination) = self.configuration().ratlines[self.curr_ratline_index]
.ref_(autorouter)
.terminating_dots();
let Some(ref mut route) = self.route else { let Some(ref mut route) = self.route else {
// May happen if stepper was aborted. // May happen if stepper was aborted.
return Ok(ControlFlow::Break(None)); return Ok(ControlFlow::Break(None));
}; };
let (origin, destination) = self.ratlines[self.curr_ratline_index]
.ref_(autorouter)
.terminating_dots();
let ret = if let Some(band_termseg) = let ret = if let Some(band_termseg) =
autorouter.board.band_between_nodes(origin, destination) autorouter.board.band_between_nodes(origin, destination)
{ {
@ -206,7 +205,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
.ratsnests .ratsnests
.on_principal_layer_mut(self.options.principal_layer) .on_principal_layer_mut(self.options.principal_layer)
.assign_band_termseg_to_ratline( .assign_band_termseg_to_ratline(
self.ratlines[self.curr_ratline_index].index, self.configuration().ratlines[self.curr_ratline_index].index,
band_termseg, band_termseg,
); );
@ -226,7 +225,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
self.curr_ratline_index += 1; self.curr_ratline_index += 1;
if let Some(new_ratline) = self.ratlines.get(self.curr_ratline_index) { if let Some(new_ratline) = self.configuration.ratlines.get(self.curr_ratline_index) {
let (origin, destination) = new_ratline.ref_(autorouter).terminating_dots(); let (origin, destination) = new_ratline.ref_(autorouter).terminating_dots();
let mut router = Router::new(autorouter.board.layout_mut(), self.options.router); let mut router = Router::new(autorouter.board.layout_mut(), self.options.router);
@ -248,31 +247,30 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
impl<M: AccessMesadata> Abort<Autorouter<M>> for PlanarAutorouteExecutionStepper { impl<M: AccessMesadata> Abort<Autorouter<M>> for PlanarAutorouteExecutionStepper {
fn abort(&mut self, autorouter: &mut Autorouter<M>) { fn abort(&mut self, autorouter: &mut Autorouter<M>) {
self.backtrace_to_index(autorouter, 0); self.backtrace_to_index(autorouter, 0);
self.curr_ratline_index = self.ratlines.len(); self.curr_ratline_index = self.configuration.ratlines.len();
} }
} }
impl<M: AccessMesadata> Reconfigure<Autorouter<M>> for PlanarAutorouteExecutionStepper { impl<M: AccessMesadata> Reconfigure<Autorouter<M>> for PlanarAutorouteExecutionStepper {
type Configuration = Vec<RatlineUid>; type Configuration = PlanarAutorouteConfiguration;
type Output = Result<PlanarAutorouteConfigurationResult, AutorouterError>; type Output = Result<PlanarAutorouteConfigurationResult, AutorouterError>;
fn reconfigure( fn reconfigure(
&mut self, &mut self,
autorouter: &mut Autorouter<M>, autorouter: &mut Autorouter<M>,
permutation: Vec<RatlineUid>, new_configuration: PlanarAutorouteConfiguration,
) -> Result<PlanarAutorouteConfigurationResult, AutorouterError> { ) -> Result<PlanarAutorouteConfigurationResult, AutorouterError> {
let Some(new_index) = permutation let Some(new_index) = new_configuration
.ratlines
.iter() .iter()
.zip(self.ratlines.iter()) .zip(self.configuration.ratlines.iter())
.position(|(permuted, original)| *permuted != *original) .position(|(permuted, original)| *permuted != *original)
else { else {
return Err(AutorouterError::NothingToUndoForReconfiguration); return Err(AutorouterError::NothingToUndoForReconfiguration);
}; };
let result = PlanarAutorouteConfigurationResult { let result = PlanarAutorouteConfigurationResult {
configuration: PlanarAutorouteConfiguration { configuration: std::mem::replace(&mut self.configuration, new_configuration),
ratlines: std::mem::replace(&mut self.ratlines, permutation),
},
costs: PlanarAutorouteCosts { costs: PlanarAutorouteCosts {
lengths: vec![], // TODO. lengths: vec![], // TODO.
}, },
@ -294,7 +292,7 @@ impl EstimateProgress for PlanarAutorouteExecutionStepper {
} }
fn estimate_progress_maximum(&self) -> f64 { fn estimate_progress_maximum(&self) -> f64 {
self.ratlines.len() as f64 self.configuration().ratlines.len() as f64
} }
} }

View File

@ -10,12 +10,11 @@ use crate::{
autorouter::{ autorouter::{
invoker::GetDebugOverlayData, invoker::GetDebugOverlayData,
planar_autoroute::{ planar_autoroute::{
PlanarAutorouteConfigurationResult, PlanarAutorouteContinueStatus, PlanarAutorouteConfiguration, PlanarAutorouteConfigurationResult,
PlanarAutorouteExecutionStepper, PlanarAutorouteContinueStatus, PlanarAutorouteExecutionStepper,
}, },
planar_reconfigurer::{PermuteRatlines, PlanarReconfigurer}, planar_reconfigurer::{PermuteRatlines, PlanarReconfigurer},
presorter::{PresortParams, PresortRatlines, SccIntersectionsAndLengthPresorter}, presorter::{PresortParams, PresortRatlines, SccIntersectionsAndLengthPresorter},
ratline::RatlineUid,
Autorouter, AutorouterError, PlanarAutorouteOptions, Autorouter, AutorouterError, PlanarAutorouteOptions,
}, },
board::edit::BoardEdit, board::edit::BoardEdit,
@ -36,30 +35,26 @@ pub struct PlanarAutorouteReconfigurator {
impl PlanarAutorouteReconfigurator { impl PlanarAutorouteReconfigurator {
pub fn new( pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineUid>, input_configuration: PlanarAutorouteConfiguration,
options: PlanarAutorouteOptions, options: PlanarAutorouteOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
let presorter = SccIntersectionsAndLengthPresorter::new( let presorter = SccIntersectionsAndLengthPresorter::new(
autorouter, autorouter,
&ratlines, &input_configuration.ratlines,
&PresortParams { &PresortParams {
intersector_count_weight: 1.0, intersector_count_weight: 1.0,
length_weight: 0.001, length_weight: 0.001,
}, },
&options, &options,
); );
let initially_sorted_ratlines = presorter.presort_ratlines(autorouter, &ratlines); let preconfiguration = PlanarAutorouteConfiguration {
/*let permuter = RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new( ratlines: presorter.presort_ratlines(autorouter, &input_configuration.ratlines),
autorouter, ratlines, presorter, &options, };
));*/ let reconfigurer =
let reconfigurer = PlanarReconfigurer::new(autorouter, ratlines, presorter, &options); PlanarReconfigurer::new(autorouter, input_configuration, presorter, &options);
Ok(Self { Ok(Self {
stepper: PlanarAutorouteExecutionStepper::new( stepper: PlanarAutorouteExecutionStepper::new(autorouter, preconfiguration, options)?,
autorouter,
initially_sorted_ratlines,
options,
)?,
// Note: I assume here that the first permutation is the same as the original order. // Note: I assume here that the first permutation is the same as the original order.
reconfigurer, reconfigurer,
options, options,
@ -94,7 +89,12 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarReconfigura
return Ok(ControlFlow::Break(None)); return Ok(ControlFlow::Break(None));
}; };
match self.stepper.reconfigure(autorouter, permutation) { match self.stepper.reconfigure(
autorouter,
PlanarAutorouteConfiguration {
ratlines: permutation,
},
) {
Ok(result) => { Ok(result) => {
return Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured( return Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(
result, result,

View File

@ -10,9 +10,11 @@ use specctra_core::mesadata::AccessMesadata;
use crate::{ use crate::{
autorouter::{ autorouter::{
planar_autoroute::PlanarAutorouteExecutionStepper, planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineUid, scc::Scc, Autorouter, presorter::SccIntersectionsAndLengthPresorter,
PlanarAutorouteOptions, ratline::RatlineUid,
scc::Scc,
Autorouter, PlanarAutorouteOptions,
}, },
drawing::graph::MakePrimitiveRef, drawing::graph::MakePrimitiveRef,
geometry::{GenericNode, GetLayer}, geometry::{GenericNode, GetLayer},
@ -37,12 +39,15 @@ pub enum PlanarReconfigurer {
impl PlanarReconfigurer { impl PlanarReconfigurer {
pub fn new( pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineUid>, input_configuration: PlanarAutorouteConfiguration,
presorter: SccIntersectionsAndLengthPresorter, presorter: SccIntersectionsAndLengthPresorter,
options: &PlanarAutorouteOptions, options: &PlanarAutorouteOptions,
) -> Self { ) -> Self {
PlanarReconfigurer::SccPermutations(SccPermutationsPlanarReconfigurer::new( PlanarReconfigurer::SccPermutations(SccPermutationsPlanarReconfigurer::new(
autorouter, ratlines, presorter, options, autorouter,
input_configuration,
presorter,
options,
)) ))
/*RatlinesPermuter::RatlineCuts(RatlineCutsRatlinePermuter::new( /*RatlinesPermuter::RatlineCuts(RatlineCutsRatlinePermuter::new(
autorouter, ratlines, presorter, options, autorouter, ratlines, presorter, options,
@ -52,13 +57,13 @@ impl PlanarReconfigurer {
pub struct SccPermutationsPlanarReconfigurer { pub struct SccPermutationsPlanarReconfigurer {
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Scc>>>, sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Scc>>>,
original_ratlines: Vec<RatlineUid>, input_configuration: PlanarAutorouteConfiguration,
} }
impl SccPermutationsPlanarReconfigurer { impl SccPermutationsPlanarReconfigurer {
pub fn new( pub fn new(
_autorouter: &mut Autorouter<impl AccessMesadata>, _autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineUid>, input_configuration: PlanarAutorouteConfiguration,
presorter: SccIntersectionsAndLengthPresorter, presorter: SccIntersectionsAndLengthPresorter,
_options: &PlanarAutorouteOptions, _options: &PlanarAutorouteOptions,
) -> Self { ) -> Self {
@ -69,7 +74,7 @@ impl SccPermutationsPlanarReconfigurer {
Self { Self {
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1), sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1),
original_ratlines: ratlines, input_configuration,
} }
} }
} }
@ -84,7 +89,7 @@ impl PermuteRatlines for SccPermutationsPlanarReconfigurer {
let mut ratlines = vec![]; let mut ratlines = vec![];
for scc in scc_permutation { for scc in scc_permutation {
for ratline in self.original_ratlines.iter() { for ratline in self.input_configuration.ratlines.iter() {
if scc.node_indices().contains( if scc.node_indices().contains(
&autorouter &autorouter
.ratsnests() .ratsnests()
@ -135,7 +140,7 @@ impl PermuteRatlines for RatlineCutsPlanarReconfigurer {
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
stepper: &PlanarAutorouteExecutionStepper, stepper: &PlanarAutorouteExecutionStepper,
) -> Option<Vec<RatlineUid>> { ) -> Option<Vec<RatlineUid>> {
let curr_ratline = stepper.ratlines()[*stepper.curr_ratline_index()]; let curr_ratline = stepper.configuration().ratlines[*stepper.curr_ratline_index()];
let terminating_dots = curr_ratline.ref_(autorouter).terminating_dots(); let terminating_dots = curr_ratline.ref_(autorouter).terminating_dots();
let bands_cut_by_ratline: Vec<_> = autorouter let bands_cut_by_ratline: Vec<_> = autorouter
.board() .board()
@ -152,7 +157,8 @@ impl PermuteRatlines for RatlineCutsPlanarReconfigurer {
// Find the first ratline corresponding to a band that is cut. // Find the first ratline corresponding to a band that is cut.
let first_cut_ratline_index = stepper let first_cut_ratline_index = stepper
.ratlines() .configuration()
.ratlines
.iter() .iter()
.position(|ratline| { .position(|ratline| {
for (band_uid, _) in &bands_cut_by_ratline { for (band_uid, _) in &bands_cut_by_ratline {
@ -169,7 +175,7 @@ impl PermuteRatlines for RatlineCutsPlanarReconfigurer {
// Swap the first ratline corresponding to a band that is cut with the // Swap the first ratline corresponding to a band that is cut with the
// ratline that we have failed routing. // ratline that we have failed routing.
let mut ratlines = stepper.ratlines().clone(); let mut ratlines = stepper.configuration().ratlines.clone();
ratlines.swap(*stepper.curr_ratline_index(), first_cut_ratline_index); ratlines.swap(*stepper.curr_ratline_index(), first_cut_ratline_index);
Some(ratlines) Some(ratlines)