autorouter: add new compare command to be used for sorting later

This commit is contained in:
Mikolaj Wielgus 2024-08-05 04:33:51 +02:00
parent 43b48e78e3
commit b2c9305cea
6 changed files with 206 additions and 47 deletions

View File

@ -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<dyn Iterator<Item = EdgeIndex<usize>>>,
route: Option<Route>,
@ -43,18 +60,15 @@ impl Autoroute {
}
}
impl<M: AccessMesadata> Step<Autorouter<M>, AutorouterStatus, AutorouterError, ()> for Autoroute {
fn step(
&mut self,
autorouter: &mut Autorouter<M>,
) -> Result<AutorouterStatus, AutorouterError> {
impl<M: AccessMesadata> Step<Autorouter<M>, AutorouteStatus, AutorouterError, ()> for Autoroute {
fn step(&mut self, autorouter: &mut Autorouter<M>) -> Result<AutorouteStatus, AutorouterError> {
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<M: AccessMesadata> Step<Autorouter<M>, 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<M: AccessMesadata> Step<Autorouter<M>, 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<M: AccessMesadata> Step<Autorouter<M>, 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))
}
}

View File

@ -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<M: AccessMesadata> {
@ -59,11 +45,22 @@ impl<M: AccessMesadata> Autorouter<M> {
}
pub fn autoroute(&mut self, selection: &PinSelection) -> Result<Autoroute, AutorouterError> {
Autoroute::new(self, self.selected_ratlines(selection))
self.autoroute_ratlines(self.selected_ratlines(selection))
}
pub(super) fn autoroute_ratlines(
&mut self,
ratlines: Vec<EdgeIndex<usize>>,
) -> Result<Autoroute, AutorouterError> {
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<EdgeIndex<usize>>) {
for ratline in ratlines.iter() {
let band = self
.ratsnest
.graph()
@ -91,6 +88,23 @@ impl<M: AccessMesadata> Autorouter<M> {
todo!();
}
pub fn compare(&mut self, selection: &PinSelection) -> Result<Compare, AutorouterError> {
self.compare_ratlines(self.selected_ratlines(selection))
}
fn compare_ratlines(
&mut self,
ratlines: Vec<EdgeIndex<usize>>,
) -> Result<Compare, AutorouterError> {
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<usize>,

120
src/autorouter/compare.rs Normal file
View File

@ -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<f64> for CompareStatus {
type Error = ();
fn try_into(self) -> Result<f64, ()> {
match self {
CompareStatus::Running => Err(()),
CompareStatus::Finished(delta) => Ok(delta),
}
}
}
pub struct Compare {
autoroute: Autoroute,
next_autoroute: Option<Autoroute>,
ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>,
total_length1: Option<f64>,
total_length2: Option<f64>,
}
impl Compare {
pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>,
ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>,
) -> Result<Self, AutorouterError> {
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<M: AccessMesadata> Step<Autorouter<M>, CompareStatus, AutorouterError, f64> for Compare {
fn step(&mut self, autorouter: &mut Autorouter<M>) -> Result<CompareStatus, AutorouterError> {
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()
}
}

View File

@ -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<InvokerStatus, InvokerError> {
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<M: AccessMesadata> Invoker<M> {
//#[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<M: AccessMesadata> Invoker<M> {
}
#[debug_requires(self.ongoing_command.is_none())]
pub fn execute_walk(&mut self, command: Command) -> Result<Execute, InvokerError> {
pub fn execute_stepper(&mut self, command: Command) -> Result<Execute, InvokerError> {
let execute = self.dispatch_command(&command);
self.ongoing_command = Some(command);
execute
@ -231,6 +238,9 @@ impl<M: AccessMesadata> Invoker<M> {
Command::RemoveBands(selection) => Ok::<Execute, InvokerError>(Execute::RemoveBands(
self.autorouter.remove_bands(selection)?,
)),
Command::Compare(selection) => {
Ok::<Execute, InvokerError>(Execute::Compare(self.autorouter.compare(selection)?))
}
}
}
@ -242,6 +252,7 @@ impl<M: AccessMesadata> Invoker<M> {
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<M: AccessMesadata> Invoker<M> {
//#[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) {

View File

@ -1,5 +1,6 @@
pub mod autoroute;
mod autorouter;
pub mod compare;
pub mod history;
pub mod invoker;
pub mod place_via;

View File

@ -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,8 +230,7 @@ impl Top {
) {
let selection = overlay.selection().clone();
overlay.clear_selection();
maybe_execute
.insert(ExecuteWithStatus::new(invoker.execute_walk(
maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper(
Command::RemoveBands(selection.band_selection),
)?));
}