// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT //! Manages the comparison of detours between two ratlines, tracking their //! routing statuses and recording their lengths. use std::ops::ControlFlow; use petgraph::graph::EdgeIndex; use crate::{ board::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::{primitive::PrimitiveShape, shape::MeasureLength}, graph::MakeRef, router::{ navcord::NavcordStepper, navmesh::{Navmesh, NavvertexIndex}, }, stepper::Step, }; use super::{ autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper}, invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, remove_bands::RemoveBandsExecutionStepper, Autorouter, AutorouterError, AutorouterOptions, }; pub struct CompareDetoursExecutionStepper { autoroute: AutorouteExecutionStepper, next_autoroute: Option, ratline1: EdgeIndex, ratline2: EdgeIndex, total_length1: f64, total_length2: f64, done: bool, } impl CompareDetoursExecutionStepper { pub fn new( autorouter: &mut Autorouter, ratline1: EdgeIndex, ratline2: EdgeIndex, options: AutorouterOptions, ) -> Result { Ok(Self { autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], options)?, next_autoroute: Some(autorouter.autoroute_ratlines(vec![ratline2, ratline1], options)?), ratline1, ratline2, total_length1: 0.0, total_length2: 0.0, done: false, }) } } // XXX: Do we really need this to be a stepper? We don't use at the moment, as sorting functions // aren't steppable either. It may be useful for debugging later on tho. impl Step, (f64, f64)> for CompareDetoursExecutionStepper { type Error = AutorouterError; fn step( &mut self, autorouter: &mut Autorouter, ) -> Result, AutorouterError> { if self.done { return Ok(ControlFlow::Break((self.total_length1, self.total_length2))); } match self.autoroute.step(autorouter)? { ControlFlow::Continue(AutorouteContinueStatus::Running) => { Ok(ControlFlow::Continue(())) } ControlFlow::Continue(AutorouteContinueStatus::Routed(band_termseg)) => { let length = band_termseg .ref_(autorouter.board.layout().drawing()) .length(); if self.next_autoroute.is_some() { self.total_length1 += length; } else { self.total_length2 += length; } Ok(ControlFlow::Continue(())) } ControlFlow::Break(..) => { if let Some(next_autoroute) = self.next_autoroute.take() { autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?; self.autoroute = next_autoroute; Ok(ControlFlow::Continue(())) } else { self.done = true; autorouter.undo_autoroute_ratlines(vec![self.ratline2, self.ratline1])?; Ok(ControlFlow::Break((self.total_length1, self.total_length2))) } } } } } impl GetMaybeNavmesh for CompareDetoursExecutionStepper { fn maybe_navmesh(&self) -> Option<&Navmesh> { self.autoroute.maybe_navmesh() } } impl GetMaybeNavcord for CompareDetoursExecutionStepper { fn maybe_navcord(&self) -> Option<&NavcordStepper> { self.autoroute.maybe_navcord() } } impl GetGhosts for CompareDetoursExecutionStepper { fn ghosts(&self) -> &[PrimitiveShape] { self.autoroute.ghosts() } } impl GetObstacles for CompareDetoursExecutionStepper { fn obstacles(&self) -> &[PrimitiveIndex] { self.autoroute.obstacles() } } impl GetNavmeshDebugTexts for CompareDetoursExecutionStepper { fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { None } fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { None } }