mirror of https://codeberg.org/topola/topola.git
feat(autorouter/autoroute): Record band assigns so undo actually works
Aborting the autoroute stepper was unimplemented and it would make the autorouting job finish instead. This is fixed now.
This commit is contained in:
parent
1cc75a79e8
commit
d7129354a1
|
|
@ -12,7 +12,7 @@ use topola::autorouter::selection::PinSelection;
|
|||
use topola::autorouter::Autorouter;
|
||||
use topola::autorouter::AutorouterOptions;
|
||||
use topola::autorouter::PresortBy;
|
||||
use topola::layout::LayoutEdit;
|
||||
use topola::board::edit::BoardEdit;
|
||||
use topola::router::RouterOptions;
|
||||
use topola::specctra::design::SpecctraDesign;
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||
let design =
|
||||
SpecctraDesign::load(design_bufread).expect("File failed to parse as Specctra DSN");
|
||||
|
||||
let board = design.make_board(&mut LayoutEdit::new());
|
||||
let board = design.make_board(&mut BoardEdit::new());
|
||||
|
||||
let history = if let Some(commands_filename) = args.commands {
|
||||
let command_file = File::open(commands_filename)?;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ use std::{
|
|||
|
||||
use topola::{
|
||||
autorouter::{execution::Command, history::History},
|
||||
board::edit::BoardEdit,
|
||||
interactor::{
|
||||
activity::{InteractiveEvent, InteractiveEventKind, InteractiveInput},
|
||||
Interactor,
|
||||
},
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
layout::via::ViaWeight,
|
||||
math::Circle,
|
||||
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
||||
};
|
||||
|
|
@ -40,7 +41,7 @@ pub struct Workspace {
|
|||
|
||||
impl Workspace {
|
||||
pub fn new(design: SpecctraDesign, tr: &Translator) -> Result<Self, String> {
|
||||
let board = design.make_board(&mut LayoutEdit::new());
|
||||
let board = design.make_board(&mut BoardEdit::new());
|
||||
let appearance_panel = AppearancePanel::new(&board);
|
||||
let overlay = Overlay::new(&board).map_err(|err| {
|
||||
format!(
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::{
|
||||
board::AccessMesadata,
|
||||
board::{
|
||||
edit::{BoardDataEdit, BoardEdit},
|
||||
AccessMesadata,
|
||||
},
|
||||
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex, Collect},
|
||||
geometry::{edit::ApplyGeometryEdit, primitive::PrimitiveShape},
|
||||
geometry::primitive::PrimitiveShape,
|
||||
graph::MakeRef,
|
||||
layout::LayoutEdit,
|
||||
router::{
|
||||
|
|
@ -42,6 +45,9 @@ pub struct AutorouteExecutionStepper {
|
|||
curr_ratline_index: usize,
|
||||
/// Stores the current route being processed, if any.
|
||||
route: Option<RouteStepper>,
|
||||
/// Records the changes to the board data (changes to layout data are
|
||||
/// recorded in navcord in route stepper).
|
||||
data_edit: BoardDataEdit,
|
||||
/// The options for the autorouting process, defining how routing should be carried out.
|
||||
options: AutorouterOptions,
|
||||
}
|
||||
|
|
@ -73,12 +79,22 @@ impl AutorouteExecutionStepper {
|
|||
destination,
|
||||
options.router_options.routed_band_width,
|
||||
)?),
|
||||
data_edit: BoardDataEdit::new(),
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
fn dissolve_route_stepper_into_layout_edit(&mut self) -> LayoutEdit {
|
||||
if let Some(taken_route) = self.route.take() {
|
||||
let (_thetastar, navcord, ..) = taken_route.dissolve();
|
||||
navcord.recorder
|
||||
} else {
|
||||
LayoutEdit::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinueStatus>
|
||||
impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinueStatus>
|
||||
for AutorouteExecutionStepper
|
||||
{
|
||||
type Error = AutorouterError;
|
||||
|
|
@ -86,20 +102,17 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
|
|||
fn step(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<Option<LayoutEdit>, AutorouteContinueStatus>, AutorouterError> {
|
||||
) -> Result<ControlFlow<Option<BoardEdit>, AutorouteContinueStatus>, AutorouterError> {
|
||||
if self.curr_ratline_index >= self.ratlines.len() {
|
||||
let recorder = if let Some(taken_route) = self.route.take() {
|
||||
let (_thetastar, navcord, ..) = taken_route.dissolve();
|
||||
navcord.recorder
|
||||
} else {
|
||||
LayoutEdit::new()
|
||||
};
|
||||
|
||||
return Ok(ControlFlow::Break(Some(recorder)));
|
||||
let recorder = self.dissolve_route_stepper_into_layout_edit();
|
||||
return Ok(ControlFlow::Break(Some(BoardEdit::new_from_edits(
|
||||
self.data_edit.clone(),
|
||||
recorder,
|
||||
))));
|
||||
}
|
||||
|
||||
let Some(ref mut route) = self.route else {
|
||||
// Shouldn't happen.
|
||||
// May happen if stepper was aborted.
|
||||
return Ok(ControlFlow::Break(None));
|
||||
};
|
||||
|
||||
|
|
@ -134,7 +147,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
|
|||
|
||||
autorouter
|
||||
.board
|
||||
.try_set_band_between_nodes(source, target, band);
|
||||
.try_set_band_between_nodes(&mut self.data_edit, source, target, band);
|
||||
|
||||
AutorouteContinueStatus::Routed(band_termseg)
|
||||
};
|
||||
|
|
@ -145,13 +158,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
|
|||
let (source, target) = new_ratline.ref_(autorouter).endpoint_dots();
|
||||
let mut router =
|
||||
Router::new(autorouter.board.layout_mut(), self.options.router_options);
|
||||
|
||||
let recorder = if let Some(taken_route) = self.route.take() {
|
||||
let (_thetastar, navcord, ..) = taken_route.dissolve();
|
||||
navcord.recorder
|
||||
} else {
|
||||
LayoutEdit::new()
|
||||
};
|
||||
let recorder = self.dissolve_route_stepper_into_layout_edit();
|
||||
|
||||
self.route = Some(router.route(
|
||||
recorder,
|
||||
|
|
@ -167,12 +174,13 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
|
|||
|
||||
impl<M: AccessMesadata> Abort<Autorouter<M>> for AutorouteExecutionStepper {
|
||||
fn abort(&mut self, autorouter: &mut Autorouter<M>) {
|
||||
if let Some(ref route) = self.route {
|
||||
autorouter.board.apply(&route.navcord().recorder.reverse());
|
||||
let layout_edit = self.dissolve_route_stepper_into_layout_edit();
|
||||
let board_edit = BoardEdit::new_from_edits(self.data_edit.clone(), layout_edit);
|
||||
|
||||
autorouter.board.apply_edit(&board_edit.reverse());
|
||||
self.curr_ratline_index = self.ratlines.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for AutorouteExecutionStepper {
|
||||
type Value = f64;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use enum_dispatch::enum_dispatch;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
board::AccessMesadata,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
board::{edit::BoardEdit, AccessMesadata},
|
||||
layout::via::ViaWeight,
|
||||
router::ng,
|
||||
stepper::{Abort, EstimateProgress, Step},
|
||||
};
|
||||
|
|
@ -57,7 +57,7 @@ impl<M: AccessMesadata + Clone> ExecutionStepper<M> {
|
|||
fn step_catch_err(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<(Option<LayoutEdit>, String)>, InvokerError> {
|
||||
) -> Result<ControlFlow<(Option<BoardEdit>, String)>, InvokerError> {
|
||||
Ok(match self {
|
||||
ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? {
|
||||
ControlFlow::Continue(..) => ControlFlow::Continue(()),
|
||||
|
|
@ -74,9 +74,12 @@ impl<M: AccessMesadata + Clone> ExecutionStepper<M> {
|
|||
ControlFlow::Break(true) => {
|
||||
for (ep, band) in &autoroute.last_bands {
|
||||
let (source, target) = ep.end_points.into();
|
||||
autorouter
|
||||
.board
|
||||
.try_set_band_between_nodes(source, target, *band);
|
||||
autorouter.board.try_set_band_between_nodes(
|
||||
&mut autoroute.last_recorder.data_edit,
|
||||
source,
|
||||
target,
|
||||
*band,
|
||||
);
|
||||
}
|
||||
|
||||
let topo_navmesh = autoroute.maybe_topo_navmesh().unwrap().to_owned();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use derive_getters::{Dissolve, Getters};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{autorouter::execution::Command, layout::LayoutEdit};
|
||||
use crate::{autorouter::execution::Command, board::edit::BoardEdit};
|
||||
|
||||
#[derive(Error, Debug, Clone)]
|
||||
pub enum HistoryError {
|
||||
|
|
@ -25,7 +25,7 @@ pub enum HistoryError {
|
|||
pub struct HistoryEntry {
|
||||
command: Command,
|
||||
#[serde(skip)]
|
||||
edit: Option<LayoutEdit>,
|
||||
edit: Option<BoardEdit>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)]
|
||||
|
|
@ -39,7 +39,7 @@ impl History {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn do_(&mut self, command: Command, edit: Option<LayoutEdit>) {
|
||||
pub fn do_(&mut self, command: Command, edit: Option<BoardEdit>) {
|
||||
self.done.push(HistoryEntry { command, edit });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use thiserror::Error;
|
|||
use crate::{
|
||||
board::AccessMesadata,
|
||||
drawing::graph::PrimitiveIndex,
|
||||
geometry::{edit::ApplyGeometryEdit, primitive::PrimitiveShape, shape::MeasureLength},
|
||||
geometry::{primitive::PrimitiveShape, shape::MeasureLength},
|
||||
graph::{GenericIndex, MakeRef},
|
||||
layout::poly::PolyWeight,
|
||||
router::{
|
||||
|
|
@ -256,7 +256,7 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
|
|||
let last_done = self.history.last_done()?;
|
||||
|
||||
if let Some(edit) = last_done.edit() {
|
||||
self.autorouter.board.apply(&edit.reverse());
|
||||
self.autorouter.board.apply_edit(&edit.reverse());
|
||||
}
|
||||
|
||||
Ok(self.history.undo()?)
|
||||
|
|
@ -268,7 +268,7 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
|
|||
let last_undone = self.history.last_undone()?;
|
||||
|
||||
if let Some(edit) = last_undone.edit() {
|
||||
self.autorouter.board.apply(edit);
|
||||
self.autorouter.board.apply_edit(edit);
|
||||
}
|
||||
|
||||
Ok(self.history.redo()?)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@
|
|||
//! checks if the via has already been placed.
|
||||
|
||||
use crate::{
|
||||
board::AccessMesadata,
|
||||
board::{
|
||||
edit::{BoardDataEdit, BoardEdit},
|
||||
AccessMesadata,
|
||||
},
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
stepper::EstimateProgress,
|
||||
};
|
||||
|
|
@ -31,16 +34,19 @@ impl PlaceViaExecutionStepper {
|
|||
pub fn doit(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
) -> Result<Option<LayoutEdit>, AutorouterError> {
|
||||
) -> Result<Option<BoardEdit>, AutorouterError> {
|
||||
if !self.done {
|
||||
self.done = true;
|
||||
|
||||
let mut edit = LayoutEdit::new();
|
||||
let mut layout_edit = LayoutEdit::new();
|
||||
autorouter
|
||||
.board
|
||||
.layout_mut()
|
||||
.add_via(&mut edit, self.weight)?;
|
||||
Ok(Some(edit))
|
||||
.add_via(&mut layout_edit, self.weight)?;
|
||||
Ok(Some(BoardEdit::new_from_edits(
|
||||
BoardDataEdit::new(),
|
||||
layout_edit,
|
||||
)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::ops::ControlFlow;
|
|||
use geo::Point;
|
||||
|
||||
use crate::{
|
||||
board::AccessMesadata,
|
||||
board::{edit::BoardEdit, AccessMesadata},
|
||||
drawing::{
|
||||
band::BandTermsegIndex,
|
||||
dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight},
|
||||
|
|
@ -33,7 +33,7 @@ impl PointrouteExecutionStepper {
|
|||
options: AutorouterOptions,
|
||||
) -> Result<Self, AutorouterError> {
|
||||
let destination = autorouter.board.add_fixed_dot_infringably(
|
||||
&mut LayoutEdit::new(),
|
||||
&mut BoardEdit::new(), // TODO?
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
pos: point,
|
||||
|
|
@ -49,7 +49,7 @@ impl PointrouteExecutionStepper {
|
|||
|
||||
Ok(Self {
|
||||
route: router.route(
|
||||
LayoutEdit::new(),
|
||||
LayoutEdit::new(), // TODO?
|
||||
origin,
|
||||
destination,
|
||||
options.router_options.routed_band_width,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
//! Provides functionality to remove bands from the layout.
|
||||
|
||||
use crate::{board::AccessMesadata, layout::LayoutEdit, stepper::EstimateProgress};
|
||||
use crate::{
|
||||
board::{edit::BoardEdit, AccessMesadata},
|
||||
stepper::EstimateProgress,
|
||||
};
|
||||
|
||||
use super::{invoker::GetDebugOverlayData, selection::BandSelection, Autorouter, AutorouterError};
|
||||
|
||||
|
|
@ -25,11 +28,12 @@ impl RemoveBandsExecutionStepper {
|
|||
pub fn doit(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
) -> Result<Option<LayoutEdit>, AutorouterError> {
|
||||
) -> Result<Option<BoardEdit>, AutorouterError> {
|
||||
if !self.done {
|
||||
self.done = true;
|
||||
|
||||
let mut edit = LayoutEdit::new();
|
||||
let mut edit = BoardEdit::new();
|
||||
|
||||
for selector in self.selection.selectors() {
|
||||
let band = *autorouter.board.bandname_band(&selector.band).unwrap();
|
||||
autorouter
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// SPDX-FileCopyrightText: 2025 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{drawing::band::BandUid, layout::LayoutEdit};
|
||||
|
||||
use super::BandName;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoardDataEdit {
|
||||
pub(super) bands: BTreeMap<BandName, (Option<BandUid>, Option<BandUid>)>,
|
||||
}
|
||||
|
||||
impl BoardDataEdit {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bands: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoardEdit {
|
||||
pub data_edit: BoardDataEdit,
|
||||
pub layout_edit: LayoutEdit,
|
||||
}
|
||||
|
||||
impl BoardEdit {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data_edit: BoardDataEdit::new(),
|
||||
layout_edit: LayoutEdit::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_edits(data_edit: BoardDataEdit, layout_edit: LayoutEdit) -> Self {
|
||||
Self {
|
||||
data_edit,
|
||||
layout_edit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse_inplace(&mut self) {
|
||||
self.data_edit
|
||||
.bands
|
||||
.values_mut()
|
||||
.for_each(Self::swap_tuple_inplace);
|
||||
self.layout_edit.reverse_inplace();
|
||||
}
|
||||
|
||||
fn swap_tuple_inplace<D>(x: &mut (D, D)) {
|
||||
core::mem::swap(&mut x.0, &mut x.1);
|
||||
}
|
||||
|
||||
pub fn reverse(&self) -> Self {
|
||||
let mut rev = self.clone();
|
||||
rev.reverse_inplace();
|
||||
rev
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Provides the functionality to create and manage relationships
|
||||
//! between nodes, pins, and bands, as well as handle metadata and geometric data
|
||||
//! for layout construction.
|
||||
//! Manages relationship between pins and bands and the primitives and compounds
|
||||
//! that consitutite them on the layout. And some more.
|
||||
|
||||
pub mod edit;
|
||||
|
||||
use edit::{BoardDataEdit, BoardEdit};
|
||||
pub use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use bimap::BiBTreeMap;
|
||||
|
|
@ -16,15 +18,14 @@ use std::collections::BTreeMap;
|
|||
use crate::{
|
||||
drawing::{
|
||||
band::BandUid,
|
||||
bend::{BendIndex, BendWeight},
|
||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight},
|
||||
dot::{FixedDotIndex, FixedDotWeight},
|
||||
graph::PrimitiveIndex,
|
||||
seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight},
|
||||
seg::{FixedSegIndex, FixedSegWeight},
|
||||
Collect, DrawingException,
|
||||
},
|
||||
geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer},
|
||||
graph::{GenericIndex, MakeRef},
|
||||
layout::{poly::PolyWeight, CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit, NodeIndex},
|
||||
layout::{poly::PolyWeight, CompoundWeight, Layout, NodeIndex},
|
||||
router::ng::EtchedPath,
|
||||
};
|
||||
|
||||
|
|
@ -109,11 +110,13 @@ impl<M: AccessMesadata> Board<M> {
|
|||
/// Inserts the dot into the layout and, if a pin name is provided, maps it to the created dot's node.
|
||||
pub fn add_fixed_dot_infringably(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
weight: FixedDotWeight,
|
||||
maybe_pin: Option<String>,
|
||||
) -> FixedDotIndex {
|
||||
let dot = self.layout.add_fixed_dot_infringably(recorder, weight);
|
||||
let dot = self
|
||||
.layout
|
||||
.add_fixed_dot_infringably(&mut recorder.layout_edit, weight);
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
self.node_to_pinname
|
||||
|
|
@ -128,15 +131,15 @@ impl<M: AccessMesadata> Board<M> {
|
|||
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
||||
pub fn add_fixed_seg_infringably(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
from: FixedDotIndex,
|
||||
to: FixedDotIndex,
|
||||
weight: FixedSegWeight,
|
||||
maybe_pin: Option<String>,
|
||||
) -> FixedSegIndex {
|
||||
let seg = self
|
||||
.layout
|
||||
.add_fixed_seg_infringably(recorder, from, to, weight);
|
||||
let seg =
|
||||
self.layout
|
||||
.add_fixed_seg_infringably(&mut recorder.layout_edit, from, to, weight);
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
self.node_to_pinname
|
||||
|
|
@ -151,12 +154,14 @@ impl<M: AccessMesadata> Board<M> {
|
|||
/// Inserts the polygon into the layout and, if a pin name is provided, maps it to the created polygon's node.
|
||||
pub fn add_poly_with_nodes(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
weight: PolyWeight,
|
||||
maybe_pin: Option<String>,
|
||||
nodes: &[PrimitiveIndex],
|
||||
) -> GenericIndex<PolyWeight> {
|
||||
let (poly, apex) = self.layout.add_poly_with_nodes(recorder, weight, nodes);
|
||||
let (poly, apex) =
|
||||
self.layout
|
||||
.add_poly_with_nodes(&mut recorder.layout_edit, weight, nodes);
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
for i in nodes {
|
||||
|
|
@ -203,6 +208,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
/// Creates band between the two nodes
|
||||
pub fn try_set_band_between_nodes(
|
||||
&mut self,
|
||||
recorder: &mut BoardDataEdit,
|
||||
source: FixedDotIndex,
|
||||
target: FixedDotIndex,
|
||||
band: BandUid,
|
||||
|
|
@ -216,6 +222,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
.unwrap()
|
||||
.to_string();
|
||||
let bandname = BandName::from((source_pinname, target_pinname));
|
||||
|
||||
if self.band_bandname.get_by_right(&bandname).is_some() {
|
||||
false
|
||||
} else {
|
||||
|
|
@ -223,7 +230,9 @@ impl<M: AccessMesadata> Board<M> {
|
|||
end_points: (source, target).into(),
|
||||
};
|
||||
self.bands_by_id.insert(ep, band);
|
||||
self.band_bandname.insert(band, bandname);
|
||||
self.band_bandname.insert(band, bandname.clone());
|
||||
|
||||
recorder.bands.insert(bandname, (None, Some(band)));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -242,10 +251,10 @@ impl<M: AccessMesadata> Board<M> {
|
|||
self.band_between_pins(source_pinname, target_pinname)
|
||||
}
|
||||
|
||||
/// Removes the band between the two nodes
|
||||
/// Removes the band between the two nodes.
|
||||
pub fn remove_band_between_nodes(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
source: FixedDotIndex,
|
||||
target: FixedDotIndex,
|
||||
) -> Result<(), DrawingException> {
|
||||
|
|
@ -260,25 +269,35 @@ impl<M: AccessMesadata> Board<M> {
|
|||
.node_pinname(&GenericNode::Primitive(target.into()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
self.band_bandname
|
||||
.remove_by_right(&BandName::from((source_pinname, target_pinname)));
|
||||
|
||||
let bandname = BandName::from((source_pinname, target_pinname));
|
||||
let maybe_band = self.band_bandname.get_by_right(&bandname).cloned();
|
||||
self.band_bandname.remove_by_right(&bandname);
|
||||
|
||||
if let Some((_, uid)) = self.bands_by_id.remove_by_left(&ep) {
|
||||
let (from, _) = uid.into();
|
||||
self.layout.remove_band(recorder, from)?;
|
||||
self.layout.remove_band(&mut recorder.layout_edit, from)?;
|
||||
}
|
||||
|
||||
recorder
|
||||
.data_edit
|
||||
.bands
|
||||
.insert(bandname, (maybe_band, None));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the band between two nodes given by [`BandUid`]
|
||||
/// Removes the band between two nodes given by [`BandUid`].
|
||||
pub fn remove_band_by_id(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
uid: BandUid,
|
||||
) -> Result<(), DrawingException> {
|
||||
if let Some(ep) = self.bands_by_id.get_by_right(&uid) {
|
||||
let (source, target) = ep.end_points.into();
|
||||
self.remove_band_between_nodes(recorder, source, target)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -293,26 +312,24 @@ impl<M: AccessMesadata> Board<M> {
|
|||
.copied()
|
||||
}
|
||||
|
||||
pub fn apply_edit(&mut self, edit: &BoardEdit) {
|
||||
for (bandname, (maybe_old_band_uid, ..)) in &edit.data_edit.bands {
|
||||
if maybe_old_band_uid.is_some() {
|
||||
self.band_bandname.remove_by_right(bandname);
|
||||
}
|
||||
}
|
||||
|
||||
self.layout_mut().apply(&edit.layout_edit);
|
||||
|
||||
for (bandname, (.., maybe_new_band_uid)) in &edit.data_edit.bands {
|
||||
if let Some(band_uid) = maybe_new_band_uid {
|
||||
self.band_bandname.insert(*band_uid, bandname.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the mesadata associated with the layout's drawing rules.
|
||||
pub fn mesadata(&self) -> &M {
|
||||
self.layout.drawing().rules()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: AccessMesadata>
|
||||
ApplyGeometryEdit<
|
||||
DotWeight,
|
||||
SegWeight,
|
||||
BendWeight,
|
||||
CompoundWeight,
|
||||
CompoundEntryLabel,
|
||||
PrimitiveIndex,
|
||||
DotIndex,
|
||||
SegIndex,
|
||||
BendIndex,
|
||||
> for Board<M>
|
||||
{
|
||||
fn apply(&mut self, edit: &LayoutEdit) {
|
||||
self.layout.apply(edit);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,12 @@ impl AstarContext {
|
|||
}
|
||||
}
|
||||
|
||||
let fin = layout.finish_in_dot(&mut recorder, sub.active_head, prim, width)?;
|
||||
let fin = layout.finish_in_dot(
|
||||
&mut recorder.layout_edit,
|
||||
sub.active_head,
|
||||
prim,
|
||||
width,
|
||||
)?;
|
||||
length += sub
|
||||
.active_head
|
||||
.maybe_cane()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
board::Board,
|
||||
board::{edit::BoardEdit, Board},
|
||||
drawing::{
|
||||
band::BandUid,
|
||||
bend::BendIndex,
|
||||
|
|
@ -34,7 +34,7 @@ use crate::{
|
|||
GenericNode,
|
||||
},
|
||||
graph::GetPetgraphIndex as _,
|
||||
layout::{Layout, LayoutEdit},
|
||||
layout::Layout,
|
||||
math::{CachedPolyExt, RotationSense},
|
||||
router::draw::{Draw, DrawException},
|
||||
};
|
||||
|
|
@ -122,7 +122,7 @@ pub struct Common<R> {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct AstarContext {
|
||||
/// TODO: make sure we can trust the `LayoutEdit`
|
||||
pub recorder: LayoutEdit,
|
||||
pub recorder: BoardEdit,
|
||||
|
||||
pub bands: BTreeMap<EtchedPath, BandUid>,
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ pub struct AstarContext {
|
|||
impl AstarContext {
|
||||
pub fn last_layout<R: AccessRules + Clone>(&self, common: &Common<R>) -> Layout<R> {
|
||||
let mut layout = common.layout.clone();
|
||||
layout.apply(&self.recorder);
|
||||
layout.apply(&self.recorder.layout_edit);
|
||||
layout
|
||||
}
|
||||
}
|
||||
|
|
@ -557,7 +557,7 @@ impl SubContext {
|
|||
|
||||
fn cane_around<R: AccessRules>(
|
||||
layout: &mut Layout<R>,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
route_length: &mut f64,
|
||||
old_head: Head,
|
||||
core: FixedDotIndex,
|
||||
|
|
@ -574,7 +574,7 @@ fn cane_around<R: AccessRules>(
|
|||
);
|
||||
|
||||
let ret = match inner {
|
||||
None => layout.cane_around_dot(recorder, old_head, core, sense, width),
|
||||
None => layout.cane_around_dot(&mut recorder.layout_edit, old_head, core, sense, width),
|
||||
Some(inner) => {
|
||||
// now, inner is expected to be a bend.
|
||||
// TODO: handle the case that the same path wraps multiple times around the same core
|
||||
|
|
@ -595,7 +595,13 @@ fn cane_around<R: AccessRules>(
|
|||
})
|
||||
.next();
|
||||
if let Some(inner_bend) = inner_bend {
|
||||
layout.cane_around_bend(recorder, old_head, inner_bend.into(), sense, width)
|
||||
layout.cane_around_bend(
|
||||
&mut recorder.layout_edit,
|
||||
old_head,
|
||||
inner_bend.into(),
|
||||
sense,
|
||||
width,
|
||||
)
|
||||
} else {
|
||||
return Err(EvalException::BendNotFound {
|
||||
core: core,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use geo::Point;
|
|||
use specctra_core::rules::AccessRules;
|
||||
|
||||
use crate::{
|
||||
board::edit::BoardEdit,
|
||||
drawing::{
|
||||
band::BandUid,
|
||||
dot::FixedDotIndex,
|
||||
|
|
@ -15,7 +16,7 @@ use crate::{
|
|||
},
|
||||
geometry::{compound::ManageCompounds, shape::AccessShape as _, GetSetPos as _},
|
||||
graph::{GenericIndex, GetPetgraphIndex as _},
|
||||
layout::{poly::PolyWeight, CompoundEntryLabel, Layout, LayoutEdit},
|
||||
layout::{poly::PolyWeight, CompoundEntryLabel, Layout},
|
||||
math::{is_poly_convex_hull_cw, CachedPolyExt, RotationSense},
|
||||
router::ng::{
|
||||
pie::{mayrev, utils::rotate_iter},
|
||||
|
|
@ -112,7 +113,7 @@ impl PolygonRouting {
|
|||
fn route_next<R: AccessRules>(
|
||||
&self,
|
||||
layout: &mut Layout<R>,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
route_length: &mut f64,
|
||||
old_head: Head,
|
||||
ext_core: FixedDotIndex,
|
||||
|
|
@ -133,7 +134,7 @@ impl PolygonRouting {
|
|||
pub fn route_to_entry<R: AccessRules>(
|
||||
&self,
|
||||
layout: &mut Layout<R>,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
old_head: Head,
|
||||
entry_point: FixedDotIndex,
|
||||
width: f64,
|
||||
|
|
@ -153,7 +154,7 @@ impl PolygonRouting {
|
|||
pub fn route_to_exit<R: AccessRules>(
|
||||
&self,
|
||||
layout: &mut Layout<R>,
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
mut active_head: Head,
|
||||
exit: FixedDotIndex,
|
||||
width: f64,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ use std::{
|
|||
|
||||
use crate::{
|
||||
autorouter::invoker::GetDebugOverlayData,
|
||||
board::edit::BoardEdit,
|
||||
drawing::{band::BandUid, dot::FixedDotIndex, graph::PrimitiveIndex, rules::AccessRules},
|
||||
geometry::primitive::PrimitiveShape,
|
||||
graph::GenericIndex,
|
||||
layout::{poly::PolyWeight, Layout, LayoutEdit},
|
||||
layout::{poly::PolyWeight, Layout},
|
||||
stepper::{Abort, EstimateProgress},
|
||||
};
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ pub struct AutorouteExecutionStepper<R> {
|
|||
original_edge_paths: Box<[EdgePaths<EtchedPath, ()>]>,
|
||||
|
||||
pub last_layout: Layout<R>,
|
||||
pub last_recorder: LayoutEdit,
|
||||
pub last_recorder: BoardEdit,
|
||||
pub last_edge_paths: Box<[EdgePaths<EtchedPath, ()>]>,
|
||||
pub last_bands: BTreeMap<EtchedPath, BandUid>,
|
||||
|
||||
|
|
@ -90,7 +91,7 @@ impl<R: Clone> AutorouteExecutionStepper<R> {
|
|||
impl<M: Clone + std::panic::RefUnwindSafe> Abort<()> for AutorouteExecutionStepper<M> {
|
||||
fn abort(&mut self, _: &mut ()) {
|
||||
self.last_layout = self.common.layout.clone();
|
||||
self.last_recorder = LayoutEdit::new();
|
||||
self.last_recorder = BoardEdit::new();
|
||||
self.last_edge_paths = self.original_edge_paths.clone();
|
||||
self.last_bands = BTreeMap::new();
|
||||
self.finish();
|
||||
|
|
@ -121,7 +122,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> AutorouteExecutionStepp
|
|||
}
|
||||
|
||||
let context = AstarContext {
|
||||
recorder: LayoutEdit::new(),
|
||||
recorder: BoardEdit::new(),
|
||||
bands,
|
||||
length: 0.0,
|
||||
sub: None,
|
||||
|
|
@ -154,7 +155,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> AutorouteExecutionStepp
|
|||
common,
|
||||
original_edge_paths: navmesh.edge_paths.clone(),
|
||||
last_layout: layout.clone(),
|
||||
last_recorder: LayoutEdit::new(),
|
||||
last_recorder: BoardEdit::new(),
|
||||
last_edge_paths: navmesh.edge_paths.clone(),
|
||||
last_bands: context.bands.clone(),
|
||||
active_polygons: Vec::new(),
|
||||
|
|
@ -204,7 +205,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> AutorouteExecutionStepp
|
|||
// no valid result found
|
||||
ControlFlow::Break(None) => {
|
||||
self.last_layout = self.common.layout.clone();
|
||||
self.last_recorder = LayoutEdit::new();
|
||||
self.last_recorder = BoardEdit::new();
|
||||
self.last_edge_paths = self.original_edge_paths.clone();
|
||||
self.last_bands = BTreeMap::new();
|
||||
self.finish();
|
||||
|
|
@ -286,7 +287,7 @@ pub struct ManualrouteExecutionStepper<R> {
|
|||
|
||||
// results
|
||||
pub last_layout: Layout<R>,
|
||||
pub last_recorder: LayoutEdit,
|
||||
pub last_recorder: BoardEdit,
|
||||
|
||||
// visualization / debug
|
||||
pub active_polygons: Vec<GenericIndex<PolyWeight>>,
|
||||
|
|
@ -321,7 +322,7 @@ impl<M: Clone> ManualrouteExecutionStepper<M> {
|
|||
impl<M: Clone + std::panic::RefUnwindSafe> Abort<()> for ManualrouteExecutionStepper<M> {
|
||||
fn abort(&mut self, _: &mut ()) {
|
||||
self.last_layout = self.common.layout.clone();
|
||||
self.last_recorder = LayoutEdit::new();
|
||||
self.last_recorder = BoardEdit::new();
|
||||
self.context.bands = BTreeMap::new();
|
||||
self.finish();
|
||||
self.aborted = true;
|
||||
|
|
@ -365,7 +366,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> ManualrouteExecutionSte
|
|||
}
|
||||
|
||||
let context = AstarContext {
|
||||
recorder: LayoutEdit::new(),
|
||||
recorder: BoardEdit::new(),
|
||||
bands,
|
||||
length: 0.0,
|
||||
sub: None,
|
||||
|
|
@ -382,7 +383,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> ManualrouteExecutionSte
|
|||
original_edge_paths: tmp_navmesh_edge_paths,
|
||||
|
||||
last_layout: layout.clone(),
|
||||
last_recorder: LayoutEdit::new(),
|
||||
last_recorder: BoardEdit::new(),
|
||||
active_polygons: Vec::new(),
|
||||
ghosts: Vec::new(),
|
||||
polygonal_blockers: Vec::new(),
|
||||
|
|
@ -514,7 +515,7 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> ManualrouteExecutionSte
|
|||
|
||||
// no valid result found
|
||||
self.last_layout = self.common.layout.clone();
|
||||
self.last_recorder = LayoutEdit::new();
|
||||
self.last_recorder = BoardEdit::new();
|
||||
self.context.bands = BTreeMap::new();
|
||||
self.finish();
|
||||
ControlFlow::Break(false)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap};
|
|||
use geo::{point, Point, Rotate};
|
||||
|
||||
use crate::{
|
||||
board::{AccessMesadata, Board},
|
||||
board::{edit::BoardEdit, AccessMesadata, Board},
|
||||
drawing::{
|
||||
dot::{FixedDotWeight, GeneralDotWeight},
|
||||
graph::{GetMaybeNet, MakePrimitive},
|
||||
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
Drawing,
|
||||
},
|
||||
geometry::{primitive::PrimitiveShape, GetLayer, GetWidth},
|
||||
layout::{poly::SolidPolyWeight, Layout, LayoutEdit},
|
||||
layout::{poly::SolidPolyWeight, Layout},
|
||||
math::{Circle, PointWithRotation},
|
||||
specctra::{
|
||||
mesadata::SpecctraMesadata,
|
||||
|
|
@ -179,7 +179,7 @@ impl SpecctraDesign {
|
|||
/// which is used for layout and routing operations. The board is initialized with [`SpecctraMesadata`],
|
||||
/// which includes layer and net mappings, and is populated with components, pins, vias, and wires
|
||||
/// from the PCB definition.
|
||||
pub fn make_board(&self, recorder: &mut LayoutEdit) -> Board<SpecctraMesadata> {
|
||||
pub fn make_board(&self, recorder: &mut BoardEdit) -> Board<SpecctraMesadata> {
|
||||
let mesadata = SpecctraMesadata::from_pcb(&self.pcb);
|
||||
let mut board = Board::new(Layout::new(Drawing::new(
|
||||
mesadata,
|
||||
|
|
@ -424,7 +424,7 @@ impl SpecctraDesign {
|
|||
}
|
||||
|
||||
fn add_circle(
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
board: &mut Board<SpecctraMesadata>,
|
||||
place: PointWithRotation,
|
||||
pin: PointWithRotation,
|
||||
|
|
@ -450,7 +450,7 @@ impl SpecctraDesign {
|
|||
}
|
||||
|
||||
fn add_rect(
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
board: &mut Board<SpecctraMesadata>,
|
||||
place: PointWithRotation,
|
||||
pin: PointWithRotation,
|
||||
|
|
@ -575,7 +575,7 @@ impl SpecctraDesign {
|
|||
}
|
||||
|
||||
fn add_path(
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
board: &mut Board<SpecctraMesadata>,
|
||||
place: PointWithRotation,
|
||||
pin: PointWithRotation,
|
||||
|
|
@ -640,7 +640,7 @@ impl SpecctraDesign {
|
|||
}
|
||||
|
||||
fn add_polygon(
|
||||
recorder: &mut LayoutEdit,
|
||||
recorder: &mut BoardEdit,
|
||||
board: &mut Board<SpecctraMesadata>,
|
||||
place: PointWithRotation,
|
||||
pin: PointWithRotation,
|
||||
|
|
|
|||
Loading…
Reference in New Issue