mirror of https://codeberg.org/topola/topola.git
autorouter: add new compare command to be used for sorting later
This commit is contained in:
parent
43b48e78e3
commit
b2c9305cea
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod autoroute;
|
||||
mod autorouter;
|
||||
pub mod compare;
|
||||
pub mod history;
|
||||
pub mod invoker;
|
||||
pub mod place_via;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)?));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue