From b2c9305cea3b56a10a80174a140d66efb2e32166 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Mon, 5 Aug 2024 04:33:51 +0200 Subject: [PATCH] autorouter: add new compare command to be used for sorting later --- src/autorouter/autoroute.rs | 36 +++++++---- src/autorouter/autorouter.rs | 54 ++++++++++------ src/autorouter/compare.rs | 120 +++++++++++++++++++++++++++++++++++ src/autorouter/invoker.rs | 27 +++++--- src/autorouter/mod.rs | 1 + src/bin/topola-egui/top.rs | 15 ++--- 6 files changed, 206 insertions(+), 47 deletions(-) create mode 100644 src/autorouter/compare.rs diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index 577f2b7..eced645 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -10,9 +10,26 @@ use crate::{ use super::{ invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles}, - Autorouter, AutorouterError, AutorouterStatus, + Autorouter, AutorouterError, }; +pub enum AutorouteStatus { + Running, + Routed(BandTermsegIndex), + Finished, +} + +impl TryInto<()> for AutorouteStatus { + type Error = (); + fn try_into(self) -> Result<(), ()> { + match self { + AutorouteStatus::Running => Err(()), + AutorouteStatus::Routed(..) => Err(()), + AutorouteStatus::Finished => Ok(()), + } + } +} + pub struct Autoroute { ratlines_iter: Box>>, route: Option, @@ -43,18 +60,15 @@ impl Autoroute { } } -impl Step, AutorouterStatus, AutorouterError, ()> for Autoroute { - fn step( - &mut self, - autorouter: &mut Autorouter, - ) -> Result { +impl Step, AutorouteStatus, AutorouterError, ()> for Autoroute { + fn step(&mut self, autorouter: &mut Autorouter) -> Result { let Some(ref mut route) = self.route else { // Shouldn't happen. - return Ok(AutorouterStatus::Finished); + return Ok(AutorouteStatus::Finished); }; let Some(curr_ratline) = self.curr_ratline else { - return Ok(AutorouterStatus::Finished); + return Ok(AutorouteStatus::Finished); }; let (source, target) = autorouter.ratline_endpoints(curr_ratline); @@ -63,7 +77,7 @@ impl Step, AutorouterStatus, AutorouterError, ( let mut router = Router::new(autorouter.board.layout_mut()); let RouterStatus::Finished(band_termseg) = route.step(&mut router)? else { - return Ok(AutorouterStatus::Running); + return Ok(AutorouteStatus::Running); }; band_termseg }; @@ -85,7 +99,7 @@ impl Step, AutorouterStatus, AutorouterError, ( let Some(new_ratline) = self.ratlines_iter.next() else { self.curr_ratline = None; - return Ok(AutorouterStatus::Finished); + return Ok(AutorouteStatus::Finished); }; let (source, target) = autorouter.ratline_endpoints(new_ratline); @@ -94,7 +108,7 @@ impl Step, AutorouterStatus, AutorouterError, ( self.curr_ratline = Some(new_ratline); self.route = Some(router.route(source, target, 100.0)?); - Ok(AutorouterStatus::Routed(band_termseg)) + Ok(AutorouteStatus::Routed(band_termseg)) } } diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 1219f73..938c386 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -4,7 +4,7 @@ use thiserror::Error; use crate::{ board::{mesadata::AccessMesadata, Board}, - drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement}, + drawing::{dot::FixedDotIndex, Infringement}, layout::via::ViaWeight, router::{navmesh::NavmeshError, RouterError}, triangulation::GetTrianvertexNodeIndex, @@ -12,6 +12,7 @@ use crate::{ use super::{ autoroute::Autoroute, + compare::Compare, place_via::PlaceVia, ratsnest::{Ratsnest, RatvertexIndex}, remove_bands::RemoveBands, @@ -28,23 +29,8 @@ pub enum AutorouterError { Router(#[from] RouterError), #[error("could not place via")] CouldNotPlaceVia(#[from] Infringement), -} - -pub enum AutorouterStatus { - Running, - Routed(BandTermsegIndex), - Finished, -} - -impl TryInto<()> for AutorouterStatus { - type Error = (); - fn try_into(self) -> Result<(), ()> { - match self { - AutorouterStatus::Running => Err(()), - AutorouterStatus::Routed(..) => Err(()), - AutorouterStatus::Finished => Ok(()), - } - } + #[error("need exactly two ratlines")] + NeedExactlyTwoRatlines, } pub struct Autorouter { @@ -59,11 +45,22 @@ impl Autorouter { } pub fn autoroute(&mut self, selection: &PinSelection) -> Result { - Autoroute::new(self, self.selected_ratlines(selection)) + self.autoroute_ratlines(self.selected_ratlines(selection)) + } + + pub(super) fn autoroute_ratlines( + &mut self, + ratlines: Vec>, + ) -> Result { + Autoroute::new(self, ratlines) } pub fn undo_autoroute(&mut self, selection: &PinSelection) { - for ratline in self.selected_ratlines(selection).iter() { + self.undo_autoroute_ratlines(self.selected_ratlines(selection)) + } + + pub(super) fn undo_autoroute_ratlines(&mut self, ratlines: Vec>) { + for ratline in ratlines.iter() { let band = self .ratsnest .graph() @@ -91,6 +88,23 @@ impl Autorouter { todo!(); } + pub fn compare(&mut self, selection: &PinSelection) -> Result { + self.compare_ratlines(self.selected_ratlines(selection)) + } + + fn compare_ratlines( + &mut self, + ratlines: Vec>, + ) -> Result { + let ratline1 = *ratlines + .get(0) + .ok_or(AutorouterError::NeedExactlyTwoRatlines)?; + let ratline2 = *ratlines + .get(1) + .ok_or(AutorouterError::NeedExactlyTwoRatlines)?; + Compare::new(self, ratline1, ratline2) + } + pub fn ratline_endpoints( &mut self, ratline: EdgeIndex, diff --git a/src/autorouter/compare.rs b/src/autorouter/compare.rs new file mode 100644 index 0000000..06c694a --- /dev/null +++ b/src/autorouter/compare.rs @@ -0,0 +1,120 @@ +use petgraph::graph::EdgeIndex; + +use crate::{ + board::mesadata::AccessMesadata, + drawing::graph::PrimitiveIndex, + geometry::{primitive::PrimitiveShape, shape::MeasureLength}, + graph::MakeRef, + router::{navmesh::Navmesh, trace::Trace}, + step::Step, +}; + +use super::{ + autoroute::{Autoroute, AutorouteStatus}, + invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles}, + Autorouter, AutorouterError, +}; + +pub enum CompareStatus { + Running, + Finished(f64), +} + +impl TryInto for CompareStatus { + type Error = (); + fn try_into(self) -> Result { + match self { + CompareStatus::Running => Err(()), + CompareStatus::Finished(delta) => Ok(delta), + } + } +} + +pub struct Compare { + autoroute: Autoroute, + next_autoroute: Option, + ratline1: EdgeIndex, + ratline2: EdgeIndex, + total_length1: Option, + total_length2: Option, +} + +impl Compare { + pub fn new( + autorouter: &mut Autorouter, + ratline1: EdgeIndex, + ratline2: EdgeIndex, + ) -> Result { + Ok(Self { + autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2])?, + next_autoroute: Some(autorouter.autoroute_ratlines(vec![ratline2, ratline1])?), + ratline1, + ratline2, + total_length1: None, + total_length2: None, + }) + } +} + +// 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, CompareStatus, AutorouterError, f64> for Compare { + fn step(&mut self, autorouter: &mut Autorouter) -> Result { + match self.autoroute.step(autorouter)? { + AutorouteStatus::Running => Ok(CompareStatus::Running), + AutorouteStatus::Routed(band_termseg) => { + let length = band_termseg + .ref_(autorouter.board.layout().drawing()) + .length(); + + if self.total_length1.is_none() { + self.total_length1 = Some(length); + } else if self.total_length2.is_none() { + self.total_length2 = Some(length); + } else { + panic!(); + } + + Ok(CompareStatus::Running) + } + AutorouteStatus::Finished => { + if let Some(next_autoroute) = self.next_autoroute.take() { + autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2]); + self.autoroute = next_autoroute; + + Ok(CompareStatus::Running) + } else { + autorouter.undo_autoroute_ratlines(vec![self.ratline2, self.ratline1]); + + Ok(CompareStatus::Finished( + self.total_length1.unwrap() - self.total_length2.unwrap(), + )) + } + } + } + } +} + +impl GetMaybeNavmesh for Compare { + fn maybe_navmesh(&self) -> Option<&Navmesh> { + self.autoroute.maybe_navmesh() + } +} + +impl GetMaybeTrace for Compare { + fn maybe_trace(&self) -> Option<&Trace> { + self.autoroute.maybe_trace() + } +} + +impl GetGhosts for Compare { + fn ghosts(&self) -> &[PrimitiveShape] { + self.autoroute.ghosts() + } +} + +impl GetObstacles for Compare { + fn obstacles(&self) -> &[PrimitiveIndex] { + self.autoroute.obstacles() + } +} diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 311fa2c..a56d285 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -13,12 +13,13 @@ use crate::{ }; use super::{ - autoroute::Autoroute, + autoroute::{Autoroute, AutorouteStatus}, + compare::{Compare, CompareStatus}, history::{History, HistoryError}, place_via::PlaceVia, remove_bands::RemoveBands, selection::{BandSelection, PinSelection}, - Autorouter, AutorouterError, AutorouterStatus, + Autorouter, AutorouterError, }; #[enum_dispatch] @@ -70,6 +71,7 @@ pub enum Command { Autoroute(PinSelection), PlaceVia(ViaWeight), RemoveBands(BandSelection), + Compare(PinSelection), } #[enum_dispatch(GetMaybeNavmesh, GetMaybeTrace, GetGhosts, GetObstacles)] @@ -77,6 +79,7 @@ pub enum Execute { Autoroute(Autoroute), PlaceVia(PlaceVia), RemoveBands(RemoveBands), + Compare(Compare), } impl Execute { @@ -86,9 +89,9 @@ impl Execute { ) -> Result { match self { Execute::Autoroute(autoroute) => match autoroute.step(&mut invoker.autorouter)? { - AutorouterStatus::Running => Ok(InvokerStatus::Running), - AutorouterStatus::Routed(..) => Ok(InvokerStatus::Running), - AutorouterStatus::Finished => Ok(InvokerStatus::Finished), + AutorouteStatus::Running => Ok(InvokerStatus::Running), + AutorouteStatus::Routed(..) => Ok(InvokerStatus::Running), + AutorouteStatus::Finished => Ok(InvokerStatus::Finished), }, Execute::PlaceVia(place_via) => { place_via.doit(&mut invoker.autorouter)?; @@ -98,6 +101,10 @@ impl Execute { remove_bands.doit(&mut invoker.autorouter)?; Ok(InvokerStatus::Finished) } + Execute::Compare(compare) => match compare.step(&mut invoker.autorouter)? { + CompareStatus::Running => Ok(InvokerStatus::Running), + CompareStatus::Finished(delta) => Ok(InvokerStatus::Finished), + }, } } } @@ -197,7 +204,7 @@ impl Invoker { //#[debug_requires(self.ongoing_command.is_none())] pub fn execute(&mut self, command: Command) -> Result<(), InvokerError> { - let mut execute = self.execute_walk(command)?; + let mut execute = self.execute_stepper(command)?; loop { let status = match execute.step(self) { @@ -213,7 +220,7 @@ impl Invoker { } #[debug_requires(self.ongoing_command.is_none())] - pub fn execute_walk(&mut self, command: Command) -> Result { + pub fn execute_stepper(&mut self, command: Command) -> Result { let execute = self.dispatch_command(&command); self.ongoing_command = Some(command); execute @@ -231,6 +238,9 @@ impl Invoker { Command::RemoveBands(selection) => Ok::(Execute::RemoveBands( self.autorouter.remove_bands(selection)?, )), + Command::Compare(selection) => { + Ok::(Execute::Compare(self.autorouter.compare(selection)?)) + } } } @@ -242,6 +252,7 @@ impl Invoker { Command::Autoroute(ref selection) => self.autorouter.undo_autoroute(selection), Command::PlaceVia(weight) => self.autorouter.undo_place_via(*weight), Command::RemoveBands(ref selection) => self.autorouter.undo_remove_bands(selection), + Command::Compare(..) => (), } Ok::<(), InvokerError>(self.history.undo()?) @@ -250,7 +261,7 @@ impl Invoker { //#[debug_requires(self.ongoing.is_none())] pub fn redo(&mut self) -> Result<(), InvokerError> { let command = self.history.last_undone()?.clone(); - let mut execute = self.execute_walk(command)?; + let mut execute = self.execute_stepper(command)?; loop { let status = match execute.step(self) { diff --git a/src/autorouter/mod.rs b/src/autorouter/mod.rs index 03e299d..94c5d81 100644 --- a/src/autorouter/mod.rs +++ b/src/autorouter/mod.rs @@ -1,5 +1,6 @@ pub mod autoroute; mod autorouter; +pub mod compare; pub mod history; pub mod invoker; pub mod place_via; diff --git a/src/bin/topola-egui/top.rs b/src/bin/topola-egui/top.rs index 4aab9b4..831093d 100644 --- a/src/bin/topola-egui/top.rs +++ b/src/bin/topola-egui/top.rs @@ -213,10 +213,10 @@ impl Top { ) { let selection = overlay.selection().clone(); overlay.clear_selection(); - maybe_execute.insert(ExecuteWithStatus::new( - invoker - .execute_walk(Command::Autoroute(selection.pin_selection))?, - )); + maybe_execute + .insert(ExecuteWithStatus::new(invoker.execute_stepper( + Command::Autoroute(selection.pin_selection), + )?)); } } } else if place_via.consume_key_enabled(ctx, ui, &mut self.is_placing_via) { @@ -230,10 +230,9 @@ impl Top { ) { let selection = overlay.selection().clone(); overlay.clear_selection(); - maybe_execute - .insert(ExecuteWithStatus::new(invoker.execute_walk( - Command::RemoveBands(selection.band_selection), - )?)); + maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper( + Command::RemoveBands(selection.band_selection), + )?)); } } } else if undo.consume_key_triggered(ctx, ui) {