// SPDX-FileCopyrightText: 2025 Topola contributors // // SPDX-License-Identifier: MIT use std::ops::ControlFlow; use serde::{Deserialize, Serialize}; use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ anterouter::{Anterouter, AnterouterOptions, AnterouterPlan}, invoker::GetDebugOverlayData, planar_reconfigurator::{PlanarAutorouteReconfigurator, PlanarReconfiguratorStatus}, ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, }, board::edit::BoardEdit, drawing::graph::PrimitiveIndex, geometry::{edit::Edit, primitive::PrimitiveShape}, router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper}, stepper::{Abort, EstimateProgress, ReconfiguratorStatus, Reconfigure, Step}, }; #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct MultilayerAutorouteOptions { pub anterouter: AnterouterOptions, pub planar: PlanarAutorouteOptions, } pub struct MultilayerAutorouteExecutionStepper { planar: PlanarAutorouteReconfigurator, anteroute_edit: BoardEdit, options: MultilayerAutorouteOptions, } impl MultilayerAutorouteExecutionStepper { pub fn new( autorouter: &mut Autorouter, ratlines: Vec, plan: AnterouterPlan, options: MultilayerAutorouteOptions, ) -> Result { let mut anterouter = Anterouter::new(plan); let mut anteroute_edit = BoardEdit::new(); anterouter.anteroute(autorouter, &mut anteroute_edit, &options.anterouter); Ok(Self { planar: PlanarAutorouteReconfigurator::new(autorouter, ratlines, options.planar)?, anteroute_edit, options: options.clone(), }) } } impl Step, Option, PlanarReconfiguratorStatus> for MultilayerAutorouteExecutionStepper { type Error = AutorouterError; fn step( &mut self, autorouter: &mut Autorouter, ) -> Result, PlanarReconfiguratorStatus>, AutorouterError> { match self.planar.step(autorouter) { Ok(ControlFlow::Break(Some(edit))) => { self.anteroute_edit.merge(edit); // FIXME: Unnecessary large clone. Ok(ControlFlow::Break(Some(self.anteroute_edit.clone()))) } Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(result))) => Ok( ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(result)), ), x => x, } } } impl Abort> for MultilayerAutorouteExecutionStepper { fn abort(&mut self, autorouter: &mut Autorouter) { self.planar.abort(autorouter) } } impl Reconfigure> for MultilayerAutorouteExecutionStepper { type Configuration = AnterouterPlan; type Output = Result<(), AutorouterError>; fn reconfigure( &mut self, autorouter: &mut Autorouter, plan: AnterouterPlan, ) -> Result<(), AutorouterError> { self.planar.abort(autorouter); autorouter.board.apply_edit(&self.anteroute_edit.reverse()); let mut anterouter = Anterouter::new(plan); let mut anteroute_edit = BoardEdit::new(); anterouter.anteroute(autorouter, &mut anteroute_edit, &self.options.anterouter); Ok(()) } } impl EstimateProgress for MultilayerAutorouteExecutionStepper { type Value = f64; fn estimate_progress_value(&self) -> f64 { self.planar.estimate_progress_value() } fn estimate_progress_maximum(&self) -> f64 { self.planar.estimate_progress_maximum() } } impl GetDebugOverlayData for MultilayerAutorouteExecutionStepper { fn maybe_thetastar(&self) -> Option<&ThetastarStepper> { self.planar.maybe_thetastar() } fn maybe_navcord(&self) -> Option<&Navcord> { self.planar.maybe_navcord() } fn ghosts(&self) -> &[PrimitiveShape] { self.planar.ghosts() } fn obstacles(&self) -> &[PrimitiveIndex] { self.planar.obstacles() } }