refactor(autorouter): store edits in history entries

This commit is contained in:
Mikolaj Wielgus 2024-11-29 03:45:48 +01:00
parent e0de008f51
commit db9d897315
6 changed files with 47 additions and 31 deletions

View File

@ -9,6 +9,7 @@ use crate::{
board::mesadata::AccessMesadata,
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex},
geometry::primitive::PrimitiveShape,
layout::LayoutEdit,
router::{navcord::NavcordStepper, navmesh::Navmesh, route::RouteStepper, Router},
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
{
type Error = AutorouterError;
@ -79,14 +80,14 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (), AutorouteContinueStatus>
fn step(
&mut self,
autorouter: &mut Autorouter<M>,
) -> Result<ControlFlow<(), AutorouteContinueStatus>, AutorouterError> {
) -> Result<ControlFlow<Option<LayoutEdit>, AutorouteContinueStatus>, AutorouterError> {
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 {
// Shouldn't happen.
return Ok(ControlFlow::Break(()));
return Ok(ControlFlow::Break(None));
};
let (source, target) = autorouter.ratline_endpoints(curr_ratline);

View File

@ -79,7 +79,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (f64, f64)> for CompareDetoursExecut
Ok(ControlFlow::Continue(()))
}
ControlFlow::Break(()) => {
ControlFlow::Break(..) => {
if let Some(next_autoroute) = self.next_autoroute.take() {
autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?;
self.autoroute = next_autoroute;

View File

@ -3,7 +3,11 @@ use std::ops::ControlFlow;
use enum_dispatch::enum_dispatch;
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::{
autoroute::AutorouteExecutionStepper,
@ -40,34 +44,37 @@ impl ExecutionStepper {
fn step_catch_err<M: AccessMesadata>(
&mut self,
autorouter: &mut Autorouter<M>,
) -> Result<ControlFlow<String>, InvokerError> {
) -> Result<ControlFlow<(Option<LayoutEdit>, String)>, InvokerError> {
Ok(match self {
ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? {
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) => {
place_via.doit(autorouter)?;
ControlFlow::Break("finished placing via".to_string())
ControlFlow::Break((None, "finished placing via".to_string()))
}
ExecutionStepper::RemoveBands(remove_bands) => {
remove_bands.doit(autorouter)?;
ControlFlow::Break("finished removing bands".to_string())
ControlFlow::Break((None, "finished removing bands".to_string()))
}
ExecutionStepper::CompareDetours(compare_detours) => {
match compare_detours.step(autorouter)? {
ControlFlow::Continue(()) => ControlFlow::Continue(()),
ControlFlow::Break((total_length1, total_length2)) => {
ControlFlow::Break(format!(
ControlFlow::Break((total_length1, total_length2)) => ControlFlow::Break((
None,
format!(
"total detour lengths are {} and {}",
total_length1, total_length2
))
}
),
)),
}
}
ExecutionStepper::MeasureLength(measure_length) => {
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> {
match self.step_catch_err(&mut invoker.autorouter) {
Ok(ControlFlow::Continue(())) => Ok(ControlFlow::Continue(())),
Ok(ControlFlow::Break(msg)) => {
if let Some(command) = invoker.ongoing_command.take() {
invoker.history.do_(command);
Ok(ControlFlow::Break((maybe_edit, msg))) => {
if let (Some(command), Some(edit)) = (invoker.ongoing_command.take(), maybe_edit) {
invoker.history.do_(command, Some(edit));
}
Ok(ControlFlow::Break(msg))

View File

@ -6,7 +6,7 @@ use derive_getters::{Dissolve, Getters};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::autorouter::execution::Command;
use crate::{autorouter::execution::Command, layout::LayoutEdit};
#[derive(Error, Debug, Clone)]
pub enum HistoryError {
@ -16,10 +16,18 @@ pub enum HistoryError {
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)]
pub struct History {
done: Vec<Command>,
undone: Vec<Command>,
done: Vec<HistoryEntry>,
undone: Vec<HistoryEntry>,
}
impl History {
@ -27,8 +35,8 @@ impl History {
Self::default()
}
pub fn do_(&mut self, command: Command) {
self.done.push(command);
pub fn do_(&mut self, command: Command, edit: Option<LayoutEdit>) {
self.done.push(HistoryEntry { command, edit });
}
pub fn undo(&mut self) -> Result<(), HistoryError> {
@ -49,15 +57,15 @@ impl History {
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);
}
pub fn last_done(&self) -> Result<&Command, HistoryError> {
pub fn last_done(&self) -> Result<&HistoryEntry, HistoryError> {
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)
}
}

View File

@ -172,7 +172,7 @@ impl<M: AccessMesadata> Invoker<M> {
#[debug_requires(self.ongoing_command.is_none())]
/// Undo last command
pub fn undo(&mut self) -> Result<(), InvokerError> {
let command = self.history.last_done()?;
let command = self.history.last_done()?.command();
match command {
Command::Autoroute(ref selection, ..) => {
@ -194,7 +194,7 @@ impl<M: AccessMesadata> Invoker<M> {
//#[debug_requires(self.ongoing_command.is_none())]
/// Redo last command
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)?;
loop {
@ -214,8 +214,8 @@ impl<M: AccessMesadata> Invoker<M> {
pub fn replay(&mut self, history: History) {
let (done, undone) = history.dissolve();
for command in done {
self.execute(command);
for entry in done {
self.execute(entry.command().clone());
}
self.history.set_undone(undone.into_iter());

View File

@ -22,7 +22,7 @@ pub trait ApplyGeometryEdit<
fn apply(&mut self, edit: GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>);
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct GeometryEdit<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
DW: AccessDotWeight<PW> + GetLayer,