mirror of https://codeberg.org/topola/topola.git
refactor(autorouter): store edits in history entries
This commit is contained in:
parent
e0de008f51
commit
db9d897315
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
board::mesadata::AccessMesadata,
|
board::mesadata::AccessMesadata,
|
||||||
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex},
|
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex},
|
||||||
geometry::primitive::PrimitiveShape,
|
geometry::primitive::PrimitiveShape,
|
||||||
|
layout::LayoutEdit,
|
||||||
router::{navcord::NavcordStepper, navmesh::Navmesh, route::RouteStepper, Router},
|
router::{navcord::NavcordStepper, navmesh::Navmesh, route::RouteStepper, Router},
|
||||||
stepper::Step,
|
stepper::Step,
|
||||||
};
|
};
|
||||||
|
|
@ -71,7 +72,7 @@ impl AutorouteExecutionStepper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: AccessMesadata> Step<Autorouter<M>, (), AutorouteContinueStatus>
|
impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinueStatus>
|
||||||
for AutorouteExecutionStepper
|
for AutorouteExecutionStepper
|
||||||
{
|
{
|
||||||
type Error = AutorouterError;
|
type Error = AutorouterError;
|
||||||
|
|
@ -79,14 +80,14 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (), AutorouteContinueStatus>
|
||||||
fn step(
|
fn step(
|
||||||
&mut self,
|
&mut self,
|
||||||
autorouter: &mut Autorouter<M>,
|
autorouter: &mut Autorouter<M>,
|
||||||
) -> Result<ControlFlow<(), AutorouteContinueStatus>, AutorouterError> {
|
) -> Result<ControlFlow<Option<LayoutEdit>, AutorouteContinueStatus>, AutorouterError> {
|
||||||
let Some(curr_ratline) = self.curr_ratline else {
|
let Some(curr_ratline) = self.curr_ratline else {
|
||||||
return Ok(ControlFlow::Break(()));
|
return Ok(ControlFlow::Break(None));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(ref mut route) = self.route else {
|
let Some(ref mut route) = self.route else {
|
||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
return Ok(ControlFlow::Break(()));
|
return Ok(ControlFlow::Break(None));
|
||||||
};
|
};
|
||||||
|
|
||||||
let (source, target) = autorouter.ratline_endpoints(curr_ratline);
|
let (source, target) = autorouter.ratline_endpoints(curr_ratline);
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (f64, f64)> for CompareDetoursExecut
|
||||||
|
|
||||||
Ok(ControlFlow::Continue(()))
|
Ok(ControlFlow::Continue(()))
|
||||||
}
|
}
|
||||||
ControlFlow::Break(()) => {
|
ControlFlow::Break(..) => {
|
||||||
if let Some(next_autoroute) = self.next_autoroute.take() {
|
if let Some(next_autoroute) = self.next_autoroute.take() {
|
||||||
autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?;
|
autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?;
|
||||||
self.autoroute = next_autoroute;
|
self.autoroute = next_autoroute;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ use std::ops::ControlFlow;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{board::mesadata::AccessMesadata, layout::via::ViaWeight, stepper::Step};
|
use crate::{
|
||||||
|
board::mesadata::AccessMesadata,
|
||||||
|
layout::{via::ViaWeight, LayoutEdit},
|
||||||
|
stepper::Step,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
autoroute::AutorouteExecutionStepper,
|
autoroute::AutorouteExecutionStepper,
|
||||||
|
|
@ -40,34 +44,37 @@ impl ExecutionStepper {
|
||||||
fn step_catch_err<M: AccessMesadata>(
|
fn step_catch_err<M: AccessMesadata>(
|
||||||
&mut self,
|
&mut self,
|
||||||
autorouter: &mut Autorouter<M>,
|
autorouter: &mut Autorouter<M>,
|
||||||
) -> Result<ControlFlow<String>, InvokerError> {
|
) -> Result<ControlFlow<(Option<LayoutEdit>, String)>, InvokerError> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? {
|
ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? {
|
||||||
ControlFlow::Continue(..) => ControlFlow::Continue(()),
|
ControlFlow::Continue(..) => ControlFlow::Continue(()),
|
||||||
ControlFlow::Break(..) => ControlFlow::Break("finished autorouting".to_string()),
|
ControlFlow::Break(edit) => {
|
||||||
|
ControlFlow::Break((edit, "finished autorouting".to_string()))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ExecutionStepper::PlaceVia(place_via) => {
|
ExecutionStepper::PlaceVia(place_via) => {
|
||||||
place_via.doit(autorouter)?;
|
place_via.doit(autorouter)?;
|
||||||
ControlFlow::Break("finished placing via".to_string())
|
ControlFlow::Break((None, "finished placing via".to_string()))
|
||||||
}
|
}
|
||||||
ExecutionStepper::RemoveBands(remove_bands) => {
|
ExecutionStepper::RemoveBands(remove_bands) => {
|
||||||
remove_bands.doit(autorouter)?;
|
remove_bands.doit(autorouter)?;
|
||||||
ControlFlow::Break("finished removing bands".to_string())
|
ControlFlow::Break((None, "finished removing bands".to_string()))
|
||||||
}
|
}
|
||||||
ExecutionStepper::CompareDetours(compare_detours) => {
|
ExecutionStepper::CompareDetours(compare_detours) => {
|
||||||
match compare_detours.step(autorouter)? {
|
match compare_detours.step(autorouter)? {
|
||||||
ControlFlow::Continue(()) => ControlFlow::Continue(()),
|
ControlFlow::Continue(()) => ControlFlow::Continue(()),
|
||||||
ControlFlow::Break((total_length1, total_length2)) => {
|
ControlFlow::Break((total_length1, total_length2)) => ControlFlow::Break((
|
||||||
ControlFlow::Break(format!(
|
None,
|
||||||
|
format!(
|
||||||
"total detour lengths are {} and {}",
|
"total detour lengths are {} and {}",
|
||||||
total_length1, total_length2
|
total_length1, total_length2
|
||||||
))
|
),
|
||||||
}
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExecutionStepper::MeasureLength(measure_length) => {
|
ExecutionStepper::MeasureLength(measure_length) => {
|
||||||
let length = measure_length.doit(autorouter)?;
|
let length = measure_length.doit(autorouter)?;
|
||||||
ControlFlow::Break(format!("Total length of selected bands: {}", length))
|
ControlFlow::Break((None, format!("Total length of selected bands: {}", length)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -79,9 +86,9 @@ impl<M: AccessMesadata> Step<Invoker<M>, String> for ExecutionStepper {
|
||||||
fn step(&mut self, invoker: &mut Invoker<M>) -> Result<ControlFlow<String>, InvokerError> {
|
fn step(&mut self, invoker: &mut Invoker<M>) -> Result<ControlFlow<String>, InvokerError> {
|
||||||
match self.step_catch_err(&mut invoker.autorouter) {
|
match self.step_catch_err(&mut invoker.autorouter) {
|
||||||
Ok(ControlFlow::Continue(())) => Ok(ControlFlow::Continue(())),
|
Ok(ControlFlow::Continue(())) => Ok(ControlFlow::Continue(())),
|
||||||
Ok(ControlFlow::Break(msg)) => {
|
Ok(ControlFlow::Break((maybe_edit, msg))) => {
|
||||||
if let Some(command) = invoker.ongoing_command.take() {
|
if let (Some(command), Some(edit)) = (invoker.ongoing_command.take(), maybe_edit) {
|
||||||
invoker.history.do_(command);
|
invoker.history.do_(command, Some(edit));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ControlFlow::Break(msg))
|
Ok(ControlFlow::Break(msg))
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use derive_getters::{Dissolve, Getters};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::autorouter::execution::Command;
|
use crate::{autorouter::execution::Command, layout::LayoutEdit};
|
||||||
|
|
||||||
#[derive(Error, Debug, Clone)]
|
#[derive(Error, Debug, Clone)]
|
||||||
pub enum HistoryError {
|
pub enum HistoryError {
|
||||||
|
|
@ -16,10 +16,18 @@ pub enum HistoryError {
|
||||||
NoNextCommand,
|
NoNextCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Getters, Serialize, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct HistoryEntry {
|
||||||
|
command: Command,
|
||||||
|
#[serde(skip)]
|
||||||
|
edit: Option<LayoutEdit>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)]
|
||||||
pub struct History {
|
pub struct History {
|
||||||
done: Vec<Command>,
|
done: Vec<HistoryEntry>,
|
||||||
undone: Vec<Command>,
|
undone: Vec<HistoryEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl History {
|
impl History {
|
||||||
|
|
@ -27,8 +35,8 @@ impl History {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_(&mut self, command: Command) {
|
pub fn do_(&mut self, command: Command, edit: Option<LayoutEdit>) {
|
||||||
self.done.push(command);
|
self.done.push(HistoryEntry { command, edit });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self) -> Result<(), HistoryError> {
|
pub fn undo(&mut self) -> Result<(), HistoryError> {
|
||||||
|
|
@ -49,15 +57,15 @@ impl History {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_undone(&mut self, iter: impl IntoIterator<Item = Command>) {
|
pub fn set_undone(&mut self, iter: impl IntoIterator<Item = HistoryEntry>) {
|
||||||
self.undone = Vec::from_iter(iter);
|
self.undone = Vec::from_iter(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_done(&self) -> Result<&Command, HistoryError> {
|
pub fn last_done(&self) -> Result<&HistoryEntry, HistoryError> {
|
||||||
self.done.last().ok_or(HistoryError::NoPreviousCommand)
|
self.done.last().ok_or(HistoryError::NoPreviousCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_undone(&self) -> Result<&Command, HistoryError> {
|
pub fn last_undone(&self) -> Result<&HistoryEntry, HistoryError> {
|
||||||
self.undone.last().ok_or(HistoryError::NoNextCommand)
|
self.undone.last().ok_or(HistoryError::NoNextCommand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ impl<M: AccessMesadata> Invoker<M> {
|
||||||
#[debug_requires(self.ongoing_command.is_none())]
|
#[debug_requires(self.ongoing_command.is_none())]
|
||||||
/// Undo last command
|
/// Undo last command
|
||||||
pub fn undo(&mut self) -> Result<(), InvokerError> {
|
pub fn undo(&mut self) -> Result<(), InvokerError> {
|
||||||
let command = self.history.last_done()?;
|
let command = self.history.last_done()?.command();
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
Command::Autoroute(ref selection, ..) => {
|
Command::Autoroute(ref selection, ..) => {
|
||||||
|
|
@ -194,7 +194,7 @@ impl<M: AccessMesadata> Invoker<M> {
|
||||||
//#[debug_requires(self.ongoing_command.is_none())]
|
//#[debug_requires(self.ongoing_command.is_none())]
|
||||||
/// Redo last command
|
/// Redo last command
|
||||||
pub fn redo(&mut self) -> Result<(), InvokerError> {
|
pub fn redo(&mut self) -> Result<(), InvokerError> {
|
||||||
let command = self.history.last_undone()?.clone();
|
let command = self.history.last_undone()?.command().clone();
|
||||||
let mut execute = self.execute_stepper(command)?;
|
let mut execute = self.execute_stepper(command)?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -214,8 +214,8 @@ impl<M: AccessMesadata> Invoker<M> {
|
||||||
pub fn replay(&mut self, history: History) {
|
pub fn replay(&mut self, history: History) {
|
||||||
let (done, undone) = history.dissolve();
|
let (done, undone) = history.dissolve();
|
||||||
|
|
||||||
for command in done {
|
for entry in done {
|
||||||
self.execute(command);
|
self.execute(entry.command().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.history.set_undone(undone.into_iter());
|
self.history.set_undone(undone.into_iter());
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub trait ApplyGeometryEdit<
|
||||||
fn apply(&mut self, edit: GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>);
|
fn apply(&mut self, edit: GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct GeometryEdit<
|
pub struct GeometryEdit<
|
||||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||||
DW: AccessDotWeight<PW> + GetLayer,
|
DW: AccessDotWeight<PW> + GetLayer,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue