feat(board,layout,drawing): implement edit recording

Not stored in the undo/redo objects yet.
This commit is contained in:
Mikolaj Wielgus 2024-10-29 16:58:59 +01:00 committed by mikolaj
parent ad1b43b806
commit d6fe67a373
20 changed files with 490 additions and 223 deletions

View File

@ -2,6 +2,7 @@ use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use topola::autorouter::invoker::Invoker; use topola::autorouter::invoker::Invoker;
use topola::autorouter::Autorouter; use topola::autorouter::Autorouter;
use topola::layout::LayoutEdit;
use topola::specctra::design::SpecctraDesign; use topola::specctra::design::SpecctraDesign;
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
@ -9,7 +10,7 @@ fn main() -> Result<(), std::io::Error> {
let design_bufread = BufReader::new(design_file); let design_bufread = BufReader::new(design_file);
let design = SpecctraDesign::load(design_bufread).unwrap(); let design = SpecctraDesign::load(design_bufread).unwrap();
let board = design.make_board(); let board = design.make_board(&mut LayoutEdit::new());
let invoker = Invoker::new(Autorouter::new(board).unwrap()); let invoker = Invoker::new(Autorouter::new(board).unwrap());

View File

@ -8,7 +8,7 @@ use thiserror::Error;
use crate::{ use crate::{
board::{mesadata::AccessMesadata, Board}, board::{mesadata::AccessMesadata, Board},
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement}, drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement},
layout::via::ViaWeight, layout::{via::ViaWeight, LayoutEdit},
router::{astar::AstarError, navmesh::NavmeshError, RouterOptions}, router::{astar::AstarError, navmesh::NavmeshError, RouterOptions},
triangulation::GetTrianvertexNodeIndex, triangulation::GetTrianvertexNodeIndex,
}; };
@ -73,7 +73,7 @@ impl<M: AccessMesadata> Autorouter<M> {
.node_index() .node_index()
{ {
RatvertexIndex::FixedDot(dot) => dot, RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly), RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
}; };
PointrouteExecutionStepper::new(self, origin_dot, point, options) PointrouteExecutionStepper::new(self, origin_dot, point, options)
@ -82,7 +82,7 @@ impl<M: AccessMesadata> Autorouter<M> {
pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> { pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> {
self.board self.board
.layout_mut() .layout_mut()
.remove_band(band) .remove_band(&mut LayoutEdit::new(), band)
.map_err(|_| AutorouterError::CouldNotRemoveBand(band)) .map_err(|_| AutorouterError::CouldNotRemoveBand(band))
} }
@ -120,7 +120,7 @@ impl<M: AccessMesadata> Autorouter<M> {
.unwrap(); .unwrap();
self.board self.board
.layout_mut() .layout_mut()
.remove_band(band) .remove_band(&mut LayoutEdit::new(), band)
.map_err(|_| AutorouterError::CouldNotRemoveBand(band))?; .map_err(|_| AutorouterError::CouldNotRemoveBand(band))?;
} }
@ -191,7 +191,7 @@ impl<M: AccessMesadata> Autorouter<M> {
.node_index() .node_index()
{ {
RatvertexIndex::FixedDot(dot) => dot, RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly), RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
}; };
let target_dot = match self let target_dot = match self
@ -202,7 +202,7 @@ impl<M: AccessMesadata> Autorouter<M> {
.node_index() .node_index()
{ {
RatvertexIndex::FixedDot(dot) => dot, RatvertexIndex::FixedDot(dot) => dot,
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly), RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
}; };
(source_dot, target_dot) (source_dot, target_dot)

View File

@ -6,7 +6,7 @@ use crate::{
board::mesadata::AccessMesadata, board::mesadata::AccessMesadata,
drawing::graph::PrimitiveIndex, drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape, geometry::primitive::PrimitiveShape,
layout::via::ViaWeight, layout::{via::ViaWeight, LayoutEdit},
router::{navcord::NavcordStepper, navmesh::Navmesh}, router::{navcord::NavcordStepper, navmesh::Navmesh},
}; };
@ -35,7 +35,10 @@ impl PlaceViaExecutionStepper {
) -> Result<(), AutorouterError> { ) -> Result<(), AutorouterError> {
if !self.done { if !self.done {
self.done = true; self.done = true;
autorouter.board.layout_mut().add_via(self.weight)?; autorouter
.board
.layout_mut()
.add_via(&mut LayoutEdit::new(), self.weight)?;
Ok(()) Ok(())
} else { } else {
Ok(()) Ok(())

View File

@ -8,6 +8,7 @@ use crate::{
band::BandTermsegIndex, band::BandTermsegIndex,
dot::{FixedDotIndex, FixedDotWeight}, dot::{FixedDotIndex, FixedDotWeight},
}, },
layout::LayoutEdit,
math::Circle, math::Circle,
router::{route::RouteStepper, Router}, router::{route::RouteStepper, Router},
stepper::Step, stepper::Step,
@ -29,6 +30,7 @@ impl PointrouteExecutionStepper {
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
let destination = autorouter.board.add_fixed_dot_infringably( let destination = autorouter.board.add_fixed_dot_infringably(
&mut LayoutEdit::new(),
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: point, pos: point,

View File

@ -4,6 +4,7 @@ use crate::{
board::mesadata::AccessMesadata, board::mesadata::AccessMesadata,
drawing::graph::PrimitiveIndex, drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape, geometry::primitive::PrimitiveShape,
layout::LayoutEdit,
router::{navcord::NavcordStepper, navmesh::Navmesh}, router::{navcord::NavcordStepper, navmesh::Navmesh},
}; };
@ -36,7 +37,10 @@ impl RemoveBandsExecutionStepper {
for selector in self.selection.selectors() { for selector in self.selection.selectors() {
let band = autorouter.board.bandname_band(&selector.band).unwrap().0; let band = autorouter.board.bandname_band(&selector.band).unwrap().0;
autorouter.board.layout_mut().remove_band(band); autorouter
.board
.layout_mut()
.remove_band(&mut LayoutEdit::new(), band);
} }
Ok(()) Ok(())
} else { } else {

View File

@ -9,6 +9,7 @@ use topola::{
activity::{ActivityContext, ActivityStepperWithStatus, InteractiveInput}, activity::{ActivityContext, ActivityStepperWithStatus, InteractiveInput},
Interactor, Interactor,
}, },
layout::LayoutEdit,
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
stepper::Step, stepper::Step,
}; };
@ -30,7 +31,7 @@ pub struct Workspace {
impl Workspace { impl Workspace {
pub fn new(design: SpecctraDesign, tr: &Translator) -> Result<Self, String> { pub fn new(design: SpecctraDesign, tr: &Translator) -> Result<Self, String> {
let board = design.make_board(); let board = design.make_board(&mut LayoutEdit::new());
let layers = Layers::new(&board); let layers = Layers::new(&board);
let overlay = Overlay::new(&board).map_err(|err| { let overlay = Overlay::new(&board).map_err(|err| {
format!( format!(

View File

@ -7,6 +7,7 @@ use topola::autorouter::invoker::Invoker;
use topola::autorouter::selection::PinSelection; use topola::autorouter::selection::PinSelection;
use topola::autorouter::Autorouter; use topola::autorouter::Autorouter;
use topola::autorouter::AutorouterOptions; use topola::autorouter::AutorouterOptions;
use topola::layout::LayoutEdit;
use topola::router::RouterOptions; use topola::router::RouterOptions;
use topola::specctra::design::SpecctraDesign; use topola::specctra::design::SpecctraDesign;
@ -19,7 +20,7 @@ fn main() -> Result<(), std::io::Error> {
let mut design_bufread = BufReader::new(design_file); let mut design_bufread = BufReader::new(design_file);
let design = SpecctraDesign::load(design_bufread).unwrap(); let design = SpecctraDesign::load(design_bufread).unwrap();
let board = design.make_board(); let board = design.make_board(&mut LayoutEdit::new());
let history = if let Some(commands_filename) = args.commands { let history = if let Some(commands_filename) = args.commands {
let command_file = File::open(commands_filename)?; let command_file = File::open(commands_filename)?;

View File

@ -16,7 +16,7 @@ use crate::{
graph::GenericIndex, graph::GenericIndex,
layout::{ layout::{
poly::{GetMaybeApex, MakePolyShape, PolyWeight}, poly::{GetMaybeApex, MakePolyShape, PolyWeight},
Layout, NodeIndex, Layout, LayoutEdit, NodeIndex,
}, },
math::Circle, math::Circle,
}; };
@ -67,10 +67,11 @@ 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. /// 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( pub fn add_fixed_dot_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight, weight: FixedDotWeight,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) -> FixedDotIndex { ) -> FixedDotIndex {
let dot = self.layout.add_fixed_dot_infringably(weight); let dot = self.layout.add_fixed_dot_infringably(recorder, weight);
if let Some(ref pin) = maybe_pin { if let Some(ref pin) = maybe_pin {
self.node_to_pinname self.node_to_pinname
@ -85,10 +86,13 @@ impl<M: AccessMesadata> Board<M> {
/// Adds the segment to the layout and maps the pin name to the created segment if provided. /// Adds the segment to the layout and maps the pin name to the created segment if provided.
pub fn add_poly_fixed_dot_infringably( pub fn add_poly_fixed_dot_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight, weight: FixedDotWeight,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
) -> FixedDotIndex { ) -> FixedDotIndex {
let dot = self.layout.add_poly_fixed_dot_infringably(weight, poly); let dot = self
.layout
.add_poly_fixed_dot_infringably(recorder, weight, poly);
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) { if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
self.node_to_pinname self.node_to_pinname
@ -103,12 +107,15 @@ impl<M: AccessMesadata> Board<M> {
/// Adds the segment to the layout and updates the internal mapping if necessary. /// Adds the segment to the layout and updates the internal mapping if necessary.
pub fn add_fixed_seg_infringably( pub fn add_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) -> FixedSegIndex { ) -> FixedSegIndex {
let seg = self.layout.add_fixed_seg_infringably(from, to, weight); let seg = self
.layout
.add_fixed_seg_infringably(recorder, from, to, weight);
if let Some(pin) = maybe_pin { if let Some(pin) = maybe_pin {
self.node_to_pinname self.node_to_pinname
@ -123,6 +130,7 @@ impl<M: AccessMesadata> Board<M> {
/// Adds the segment to the layout and updates the internal mapping if necessary. /// Adds the segment to the layout and updates the internal mapping if necessary.
pub fn add_poly_fixed_seg_infringably( pub fn add_poly_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
@ -130,7 +138,7 @@ impl<M: AccessMesadata> Board<M> {
) -> FixedSegIndex { ) -> FixedSegIndex {
let seg = self let seg = self
.layout .layout
.add_poly_fixed_seg_infringably(from, to, weight, poly); .add_poly_fixed_seg_infringably(recorder, from, to, weight, poly);
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) { if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
self.node_to_pinname self.node_to_pinname
@ -145,10 +153,11 @@ 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. /// 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( pub fn add_poly(
&mut self, &mut self,
recorder: &mut LayoutEdit,
weight: PolyWeight, weight: PolyWeight,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) -> GenericIndex<PolyWeight> { ) -> GenericIndex<PolyWeight> {
let poly = self.layout.add_poly(weight); let poly = self.layout.add_poly(recorder, weight);
if let Some(pin) = maybe_pin { if let Some(pin) = maybe_pin {
self.node_to_pinname self.node_to_pinname
@ -161,11 +170,16 @@ impl<M: AccessMesadata> Board<M> {
/// Retrieves or creates the apex (top point) of a polygon in the layout. /// Retrieves or creates the apex (top point) of a polygon in the layout.
/// ///
/// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex. /// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex.
pub fn poly_apex(&mut self, poly: GenericIndex<PolyWeight>) -> FixedDotIndex { pub fn poly_apex(
&mut self,
recorder: &mut LayoutEdit,
poly: GenericIndex<PolyWeight>,
) -> FixedDotIndex {
if let Some(apex) = self.layout.poly(poly).maybe_apex() { if let Some(apex) = self.layout.poly(poly).maybe_apex() {
apex apex
} else { } else {
self.add_poly_fixed_dot_infringably( self.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: self.layout.poly(poly).shape().center(), pos: self.layout.poly(poly).shape().center(),

View File

@ -14,7 +14,7 @@ use crate::{
use petgraph::stable_graph::NodeIndex; use petgraph::stable_graph::NodeIndex;
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BendIndex { pub enum BendIndex {
Fixed(FixedBendIndex), Fixed(FixedBendIndex),
Loose(LooseBendIndex), Loose(LooseBendIndex),

View File

@ -16,7 +16,7 @@ use crate::{
}; };
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DotIndex { pub enum DotIndex {
Fixed(FixedDotIndex), Fixed(FixedDotIndex),
Loose(LooseDotIndex), Loose(LooseDotIndex),

View File

@ -7,9 +7,9 @@ use rstar::{RTree, AABB};
use thiserror::Error; use thiserror::Error;
use crate::geometry::{ use crate::geometry::{
compound::ManageCompounds,
primitive::{AccessPrimitiveShape, PrimitiveShape}, primitive::{AccessPrimitiveShape, PrimitiveShape},
with_rtree::{BboxedIndex, GeometryWithRtree}, recording_with_rtree::{GeometryEdit, RecordingGeometryWithRtree},
with_rtree::BboxedIndex,
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
GetOffset, GetPos, GetWidth, GetOffset, GetPos, GetWidth,
}; };
@ -65,9 +65,21 @@ pub struct Collision(pub PrimitiveShape, pub PrimitiveIndex);
#[error("{1:?} is already connected to net {0}")] #[error("{1:?} is already connected to net {0}")]
pub struct AlreadyConnected(pub usize, pub PrimitiveIndex); pub struct AlreadyConnected(pub usize, pub PrimitiveIndex);
pub type DrawingEdit<CW: Copy> = GeometryEdit<
PrimitiveWeight,
DotWeight,
SegWeight,
BendWeight,
CW,
PrimitiveIndex,
DotIndex,
SegIndex,
BendIndex,
>;
#[derive(Debug, Getters)] #[derive(Debug, Getters)]
pub struct Drawing<CW: Copy, R: AccessRules> { pub struct Drawing<CW: Copy, R: AccessRules> {
geometry_with_rtree: GeometryWithRtree< recording_geometry_with_rtree: RecordingGeometryWithRtree<
PrimitiveWeight, PrimitiveWeight,
DotWeight, DotWeight,
SegWeight, SegWeight,
@ -85,15 +97,20 @@ pub struct Drawing<CW: Copy, R: AccessRules> {
impl<CW: Copy, R: AccessRules> Drawing<CW, R> { impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
pub fn new(rules: R, layer_count: usize) -> Self { pub fn new(rules: R, layer_count: usize) -> Self {
Self { Self {
geometry_with_rtree: GeometryWithRtree::new(layer_count), recording_geometry_with_rtree: RecordingGeometryWithRtree::new(layer_count),
rules, rules,
} }
} }
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> { pub fn remove_band(
&mut self,
recorder: &mut DrawingEdit<CW>,
band: BandTermsegIndex,
) -> Result<(), DrawingException> {
match band { match band {
BandTermsegIndex::Straight(seg) => { BandTermsegIndex::Straight(seg) => {
self.geometry_with_rtree.remove_seg(seg.into()); self.recording_geometry_with_rtree
.remove_seg(recorder, seg.into());
} }
BandTermsegIndex::Bended(first_loose_seg) => { BandTermsegIndex::Bended(first_loose_seg) => {
let mut dots = vec![]; let mut dots = vec![];
@ -110,7 +127,8 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
dots.push(dot); dots.push(dot);
} }
LooseIndex::LoneSeg(seg) => { LooseIndex::LoneSeg(seg) => {
self.geometry_with_rtree.remove_seg(seg.into()); self.recording_geometry_with_rtree
.remove_seg(recorder, seg.into());
break; break;
} }
LooseIndex::SeqSeg(seg) => { LooseIndex::SeqSeg(seg) => {
@ -121,7 +139,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
if let Some(outer) = self.primitive(bend).outer() { if let Some(outer) = self.primitive(bend).outer() {
outers.push(outer); outers.push(outer);
self.reattach_bend(outer, self.primitive(bend).inner()); self.reattach_bend(recorder, outer, self.primitive(bend).inner());
} }
} }
} }
@ -132,22 +150,25 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
} }
for bend in bends { for bend in bends {
self.geometry_with_rtree.remove_bend(bend.into()); self.recording_geometry_with_rtree
.remove_bend(recorder, bend.into());
} }
for seg in segs { for seg in segs {
self.geometry_with_rtree.remove_seg(seg.into()); self.recording_geometry_with_rtree
.remove_seg(recorder, seg.into());
} }
// We must remove the dots only after the segs and bends because we need dots to calculate // We must remove the dots only after the segs and bends because we need dots to calculate
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree. // the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
for dot in dots { for dot in dots {
self.geometry_with_rtree.remove_dot(dot.into()); self.recording_geometry_with_rtree
.remove_dot(recorder, dot.into());
} }
for outer in outers { for outer in outers {
self.update_this_and_outward_bows(outer)?; self.update_this_and_outward_bows(recorder, outer)?;
} }
} }
} }
@ -158,34 +179,44 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> { pub fn add_fixed_dot(
self.add_dot_with_infringables(weight, Some(&[])) &mut self,
recorder: &mut DrawingEdit<CW>,
weight: FixedDotWeight,
) -> Result<FixedDotIndex, Infringement> {
self.add_dot_with_infringables(recorder, weight, Some(&[]))
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) { pub fn remove_fixed_dot(&mut self, recorder: &mut DrawingEdit<CW>, dot: FixedDotIndex) {
self.geometry_with_rtree.remove_dot(dot.into()); self.recording_geometry_with_rtree
.remove_dot(recorder, dot.into());
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { pub fn add_fixed_dot_infringably(
self.add_dot_infringably(weight) &mut self,
recorder: &mut DrawingEdit<CW>,
weight: FixedDotWeight,
) -> FixedDotIndex {
self.add_dot_infringably(recorder, weight)
} }
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
fn add_dot_with_infringables<W: AccessDotWeight<PrimitiveWeight> + GetLayer>( fn add_dot_with_infringables<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
weight: W, weight: W,
infringables: Option<&[PrimitiveIndex]>, infringables: Option<&[PrimitiveIndex]>,
) -> Result<GenericIndex<W>, Infringement> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let dot = self.add_dot_infringably(weight); let dot = self.add_dot_infringably(recorder, weight);
self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, dot.into(), infringables)?;
Ok(dot) Ok(dot)
} }
@ -195,22 +226,24 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_fixed_seg( pub fn add_fixed_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> Result<FixedSegIndex, Infringement> { ) -> Result<FixedSegIndex, Infringement> {
self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[])) self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[]))
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
pub fn add_fixed_seg_infringably( pub fn add_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> FixedSegIndex { ) -> FixedSegIndex {
self.add_seg_infringably(from.into(), to.into(), weight) self.add_seg_infringably(recorder, from.into(), to.into(), weight)
} }
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
@ -219,11 +252,13 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_lone_loose_seg( pub fn add_lone_loose_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: LoneLooseSegWeight, weight: LoneLooseSegWeight,
) -> Result<LoneLooseSegIndex, Infringement> { ) -> Result<LoneLooseSegIndex, Infringement> {
let seg = self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[]))?; let seg =
self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[]))?;
Ok(seg) Ok(seg)
} }
@ -233,11 +268,12 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_seq_loose_seg( pub fn add_seq_loose_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
to: LooseDotIndex, to: LooseDotIndex,
weight: SeqLooseSegWeight, weight: SeqLooseSegWeight,
) -> Result<SeqLooseSegIndex, Infringement> { ) -> Result<SeqLooseSegIndex, Infringement> {
let seg = self.add_seg_with_infringables(from, to.into(), weight, Some(&[]))?; let seg = self.add_seg_with_infringables(recorder, from, to.into(), weight, Some(&[]))?;
Ok(seg) Ok(seg)
} }
@ -247,6 +283,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_seg_with_infringables<W: AccessSegWeight<PrimitiveWeight> + GetLayer>( fn add_seg_with_infringables<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
weight: W, weight: W,
@ -255,8 +292,8 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let seg = self.add_seg_infringably(from, to, weight); let seg = self.add_seg_infringably(recorder, from, to, weight);
self.fail_and_remove_if_infringes_except(seg.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, seg.into(), infringables)?;
Ok(seg) Ok(seg)
} }
@ -268,6 +305,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_loose_bend_with_infringables( fn add_loose_bend_with_infringables(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: LooseDotIndex, from: LooseDotIndex,
to: LooseDotIndex, to: LooseDotIndex,
around: GearIndex, around: GearIndex,
@ -294,13 +332,34 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
match around { match around {
GearIndex::FixedDot(core) => self GearIndex::FixedDot(core) => self
.add_core_bend_with_infringables(from.into(), to.into(), core, weight, infringables) .add_core_bend_with_infringables(
recorder,
from.into(),
to.into(),
core,
weight,
infringables,
)
.map_err(Into::into), .map_err(Into::into),
GearIndex::FixedBend(around) => self GearIndex::FixedBend(around) => self
.add_outer_bend_with_infringables(from, to, around.into(), weight, infringables) .add_outer_bend_with_infringables(
recorder,
from,
to,
around.into(),
weight,
infringables,
)
.map_err(Into::into), .map_err(Into::into),
GearIndex::LooseBend(around) => self GearIndex::LooseBend(around) => self
.add_outer_bend_with_infringables(from, to, around.into(), weight, infringables) .add_outer_bend_with_infringables(
recorder,
from,
to,
around.into(),
weight,
infringables,
)
.map_err(Into::into), .map_err(Into::into),
} }
} }
@ -311,6 +370,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_core_bend_with_infringables<W: AccessBendWeight<PrimitiveWeight> + GetLayer>( fn add_core_bend_with_infringables<W: AccessBendWeight<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
core: FixedDotIndex, core: FixedDotIndex,
@ -320,11 +380,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let bend = self let bend =
.geometry_with_rtree self.recording_geometry_with_rtree
.add_bend(from, to, core.into(), weight); .add_bend(recorder, from, to, core.into(), weight);
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?;
Ok(bend) Ok(bend)
} }
@ -334,6 +394,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_outer_bend_with_infringables( fn add_outer_bend_with_infringables(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: LooseDotIndex, from: LooseDotIndex,
to: LooseDotIndex, to: LooseDotIndex,
inner: BendIndex, inner: BendIndex,
@ -341,15 +402,15 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
infringables: Option<&[PrimitiveIndex]>, infringables: Option<&[PrimitiveIndex]>,
) -> Result<GenericIndex<LooseBendWeight>, Infringement> { ) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
let core = *self let core = *self
.geometry_with_rtree .recording_geometry_with_rtree
.graph() .graph()
.neighbors(inner.petgraph_index()) .neighbors(inner.petgraph_index())
.filter(|ni| { .filter(|ni| {
matches!( matches!(
self.geometry_with_rtree self.recording_geometry_with_rtree
.graph() .graph()
.edge_weight( .edge_weight(
self.geometry_with_rtree self.recording_geometry_with_rtree
.graph() .graph()
.find_edge(inner.petgraph_index(), *ni) .find_edge(inner.petgraph_index(), *ni)
.unwrap() .unwrap()
@ -363,29 +424,42 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
.first() .first()
.unwrap(); .unwrap();
let bend = self let bend = self.recording_geometry_with_rtree.add_bend(
.geometry_with_rtree recorder,
.add_bend(from.into(), to.into(), core.into(), weight); from.into(),
self.geometry_with_rtree to.into(),
.reattach_bend(bend.into(), Some(inner)); core.into(),
weight,
);
self.recording_geometry_with_rtree
.reattach_bend(recorder, bend.into(), Some(inner));
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?;
Ok(bend) Ok(bend)
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn flip_bend(&mut self, bend: FixedBendIndex) { pub fn flip_bend(&mut self, recorder: &mut DrawingEdit<CW>, bend: FixedBendIndex) {
self.geometry_with_rtree.flip_bend(bend.into()); self.recording_geometry_with_rtree
.flip_bend(recorder, bend.into());
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()) #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count())
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1) || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1)
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))] || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))]
fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option<LooseBendIndex>) { fn reattach_bend(
self.geometry_with_rtree &mut self,
.reattach_bend(bend.into(), maybe_new_inner.map(Into::into)); recorder: &mut DrawingEdit<CW>,
bend: LooseBendIndex,
maybe_new_inner: Option<LooseBendIndex>,
) {
self.recording_geometry_with_rtree.reattach_bend(
recorder,
bend.into(),
maybe_new_inner.map(Into::into),
);
} }
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))]
@ -394,6 +468,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn insert_cane( pub fn insert_cane(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -403,6 +478,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
let maybe_next_gear = around.ref_(self).next_gear(); let maybe_next_gear = around.ref_(self).next_gear();
let cane = self.add_cane_with_infringables( let cane = self.add_cane_with_infringables(
recorder,
from, from,
around, around,
dot_weight, dot_weight,
@ -413,21 +489,22 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
)?; )?;
if let Some(next_gear) = maybe_next_gear { if let Some(next_gear) = maybe_next_gear {
self.reattach_bend(next_gear, Some(cane.bend)); self.reattach_bend(recorder, next_gear, Some(cane.bend));
} }
if let Some(outer) = self.primitive(cane.bend).outer() { if let Some(outer) = self.primitive(cane.bend).outer() {
self.update_this_and_outward_bows(outer).map_err(|err| { self.update_this_and_outward_bows(recorder, outer)
let joint = self.primitive(cane.bend).other_joint(cane.dot); .map_err(|err| {
self.remove_cane(&cane, joint); let joint = self.primitive(cane.bend).other_joint(cane.dot);
err self.remove_cane(recorder, &cane, joint);
})?; err
})?;
} }
// Segs must not cross. // Segs must not cross.
if let Some(collision) = self.detect_collision(cane.seg.into()) { if let Some(collision) = self.detect_collision(cane.seg.into()) {
let joint = self.primitive(cane.bend).other_joint(cane.dot); let joint = self.primitive(cane.bend).other_joint(cane.dot);
self.remove_cane(&cane, joint); self.remove_cane(recorder, &cane, joint);
Err(collision.into()) Err(collision.into())
} else { } else {
Ok(cane) Ok(cane)
@ -438,6 +515,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn update_this_and_outward_bows( fn update_this_and_outward_bows(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
around: LooseBendIndex, around: LooseBendIndex,
) -> Result<(), DrawingException> { ) -> Result<(), DrawingException> {
// FIXME: Fail gracefully on infringement. // FIXME: Fail gracefully on infringement.
@ -475,17 +553,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
); );
self.move_dot_with_infringables( self.move_dot_with_infringables(
recorder,
joints.0.into(), joints.0.into(),
from, from,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
)?; )?;
self.move_dot_with_infringables( self.move_dot_with_infringables(
recorder,
joints.1.into(), joints.1.into(),
to, to,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
)?; )?;
self.shift_bend_with_infringables( self.shift_bend_with_infringables(
recorder,
rail.into(), rail.into(),
offset, offset,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
@ -517,17 +598,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
); );
self.move_dot_with_infringables( self.move_dot_with_infringables(
recorder,
joints.0.into(), joints.0.into(),
from, from,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
)?; )?;
self.move_dot_with_infringables( self.move_dot_with_infringables(
recorder,
joints.1.into(), joints.1.into(),
to, to,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
)?; )?;
self.shift_bend_with_infringables( self.shift_bend_with_infringables(
recorder,
rail.into(), rail.into(),
offset, offset,
Some(&self.collect().bend_outer_bows(rail)), Some(&self.collect().bend_outer_bows(rail)),
@ -546,6 +630,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn add_cane( pub fn add_cane(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -554,6 +639,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
cw: bool, cw: bool,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
self.add_cane_with_infringables( self.add_cane_with_infringables(
recorder,
from, from,
around, around,
dot_weight, dot_weight,
@ -570,6 +656,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_cane_with_infringables( fn add_cane_with_infringables(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -578,30 +665,43 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
cw: bool, cw: bool,
infringables: Option<&[PrimitiveIndex]>, infringables: Option<&[PrimitiveIndex]>,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
let seg_to = self.add_dot_with_infringables(dot_weight, infringables)?; let seg_to = self.add_dot_with_infringables(recorder, dot_weight, infringables)?;
let seg = self let seg = self
.add_seg_with_infringables(from, seg_to.into(), seg_weight, infringables) .add_seg_with_infringables(recorder, from, seg_to.into(), seg_weight, infringables)
.map_err(|err| { .map_err(|err| {
self.geometry_with_rtree.remove_dot(seg_to.into()); self.recording_geometry_with_rtree
.remove_dot(recorder, seg_to.into());
err err
})?; })?;
let to = self let to = self
.add_dot_with_infringables(dot_weight, infringables) .add_dot_with_infringables(recorder, dot_weight, infringables)
.map_err(|err| { .map_err(|err| {
self.geometry_with_rtree.remove_seg(seg.into()); self.recording_geometry_with_rtree
self.geometry_with_rtree.remove_dot(seg_to.into()); .remove_seg(recorder, seg.into());
self.recording_geometry_with_rtree
.remove_dot(recorder, seg_to.into());
err err
})?; })?;
let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) }; let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) };
let bend = self let bend = self
.add_loose_bend_with_infringables(bend_from, bend_to, around, bend_weight, infringables) .add_loose_bend_with_infringables(
recorder,
bend_from,
bend_to,
around,
bend_weight,
infringables,
)
.map_err(|err| { .map_err(|err| {
self.geometry_with_rtree.remove_dot(to.into()); self.recording_geometry_with_rtree
self.geometry_with_rtree.remove_seg(seg.into()); .remove_dot(recorder, to.into());
self.geometry_with_rtree.remove_dot(seg_to.into()); self.recording_geometry_with_rtree
.remove_seg(recorder, seg.into());
self.recording_geometry_with_rtree
.remove_dot(recorder, seg_to.into());
err err
})?; })?;
@ -613,25 +713,34 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))]
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) { pub fn remove_cane(
&mut self,
recorder: &mut DrawingEdit<CW>,
cane: &Cane,
face: LooseDotIndex,
) {
let maybe_outer = self.primitive(cane.bend).outer(); let maybe_outer = self.primitive(cane.bend).outer();
// Removing a loose bend affects its outer bends. // Removing a loose bend affects its outer bends.
if let Some(outer) = maybe_outer { if let Some(outer) = maybe_outer {
self.reattach_bend(outer, self.primitive(cane.bend).inner()); self.reattach_bend(recorder, outer, self.primitive(cane.bend).inner());
} }
self.geometry_with_rtree.remove_bend(cane.bend.into()); self.recording_geometry_with_rtree
self.geometry_with_rtree.remove_seg(cane.seg.into()); .remove_bend(recorder, cane.bend.into());
self.recording_geometry_with_rtree
.remove_seg(recorder, cane.seg.into());
// We must remove the dots only after the segs and bends because we need dots to calculate // We must remove the dots only after the segs and bends because we need dots to calculate
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree. // the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
self.geometry_with_rtree.remove_dot(face.into()); self.recording_geometry_with_rtree
self.geometry_with_rtree.remove_dot(cane.dot.into()); .remove_dot(recorder, face.into());
self.recording_geometry_with_rtree
.remove_dot(recorder, cane.dot.into());
if let Some(outer) = maybe_outer { if let Some(outer) = maybe_outer {
self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. self.update_this_and_outward_bows(recorder, outer).unwrap(); // Must never fail.
} }
} }
@ -641,10 +750,15 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { pub fn move_dot(
&mut self,
recorder: &mut DrawingEdit<CW>,
dot: DotIndex,
to: Point,
) -> Result<(), Infringement> {
match dot { match dot {
DotIndex::Fixed(..) => self.move_dot_with_infringables(dot, to, Some(&[])), DotIndex::Fixed(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])),
DotIndex::Loose(..) => self.move_dot_with_infringables(dot, to, Some(&[])), DotIndex::Loose(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])),
} }
} }
@ -652,24 +766,32 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn move_dot_with_infringables( fn move_dot_with_infringables(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
dot: DotIndex, dot: DotIndex,
to: Point, to: Point,
infringables: Option<&[PrimitiveIndex]>, infringables: Option<&[PrimitiveIndex]>,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
let old_pos = self.geometry_with_rtree.geometry().dot_weight(dot).pos(); let old_pos = self
self.geometry_with_rtree.move_dot(dot, to); .recording_geometry_with_rtree
.geometry()
.dot_weight(dot)
.pos();
self.recording_geometry_with_rtree
.move_dot(recorder, dot, to);
for limb in dot.primitive(self).limbs() { for limb in dot.primitive(self).limbs() {
if let Some(infringement) = self.detect_infringement_except(limb, infringables) { if let Some(infringement) = self.detect_infringement_except(limb, infringables) {
// Restore original state. // Restore original state.
self.geometry_with_rtree.move_dot(dot, old_pos); self.recording_geometry_with_rtree
.move_dot(recorder, dot, old_pos);
return Err(infringement); return Err(infringement);
} }
} }
if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) { if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) {
// Restore original state. // Restore original state.
self.geometry_with_rtree.move_dot(dot, old_pos); self.recording_geometry_with_rtree
.move_dot(recorder, dot, old_pos);
return Err(infringement); return Err(infringement);
} }
@ -680,20 +802,23 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn shift_bend_with_infringables( fn shift_bend_with_infringables(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
bend: BendIndex, bend: BendIndex,
offset: f64, offset: f64,
infringables: Option<&[PrimitiveIndex]>, infringables: Option<&[PrimitiveIndex]>,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
let old_offset = self let old_offset = self
.geometry_with_rtree .recording_geometry_with_rtree
.geometry() .geometry()
.bend_weight(bend) .bend_weight(bend)
.offset(); .offset();
self.geometry_with_rtree.shift_bend(bend, offset); self.recording_geometry_with_rtree
.shift_bend(recorder, bend, offset);
if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) { if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) {
// Restore original state. // Restore original state.
self.geometry_with_rtree.shift_bend(bend, old_offset); self.recording_geometry_with_rtree
.shift_bend(recorder, bend, old_offset);
return Err(infringement); return Err(infringement);
} }
@ -703,7 +828,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
fn detect_collision(&self, node: PrimitiveIndex) -> Option<Collision> { fn detect_collision(&self, node: PrimitiveIndex) -> Option<Collision> {
let shape = node.primitive(self).shape(); let shape = node.primitive(self).shape();
self.geometry_with_rtree self.recording_geometry_with_rtree
.rtree() .rtree()
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
.filter_map(|wrapper| { .filter_map(|wrapper| {
@ -724,18 +849,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>( fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
weight: W, weight: W,
) -> GenericIndex<W> ) -> GenericIndex<W>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
self.geometry_with_rtree.add_dot(weight) self.recording_geometry_with_rtree.add_dot(recorder, weight)
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>( fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
weight: W, weight: W,
@ -743,7 +870,28 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
where where
GenericIndex<W>: Into<PrimitiveIndex>, GenericIndex<W>: Into<PrimitiveIndex>,
{ {
self.geometry_with_rtree.add_seg(from, to, weight) self.recording_geometry_with_rtree
.add_seg(recorder, from, to, weight)
}
pub fn add_compound(&mut self, recorder: &mut DrawingEdit<CW>, weight: CW) -> GenericIndex<CW> {
self.recording_geometry_with_rtree
.add_compound(recorder, weight)
}
pub fn remove_compound(&mut self, recorder: &mut DrawingEdit<CW>, compound: GenericIndex<CW>) {
self.recording_geometry_with_rtree
.remove_compound(recorder, compound);
}
pub fn add_to_compound<W>(
&mut self,
recorder: &mut DrawingEdit<CW>,
primitive: GenericIndex<W>,
compound: GenericIndex<CW>,
) {
self.recording_geometry_with_rtree
.add_to_compound(recorder, primitive, compound);
} }
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
@ -751,16 +899,18 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
fn fail_and_remove_if_infringes_except( fn fail_and_remove_if_infringes_except(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW>,
node: PrimitiveIndex, node: PrimitiveIndex,
maybe_except: Option<&[PrimitiveIndex]>, maybe_except: Option<&[PrimitiveIndex]>,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { if let Some(infringement) = self.detect_infringement_except(node, maybe_except) {
if let Ok(dot) = node.try_into() { if let Ok(dot) = node.try_into() {
self.geometry_with_rtree.remove_dot(dot); self.recording_geometry_with_rtree.remove_dot(recorder, dot);
} else if let Ok(seg) = node.try_into() { } else if let Ok(seg) = node.try_into() {
self.geometry_with_rtree.remove_seg(seg); self.recording_geometry_with_rtree.remove_seg(recorder, seg);
} else if let Ok(bend) = node.try_into() { } else if let Ok(bend) = node.try_into() {
self.geometry_with_rtree.remove_bend(bend); self.recording_geometry_with_rtree
.remove_bend(recorder, bend);
} }
return Err(infringement); return Err(infringement);
} }
@ -799,7 +949,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
.unwrap_or(0.0), .unwrap_or(0.0),
); );
self.geometry_with_rtree self.recording_geometry_with_rtree
.rtree() .rtree()
.locate_in_envelope_intersecting( .locate_in_envelope_intersecting(
&limiting_shape.envelope_3d(0.0, node.primitive(self).layer()), &limiting_shape.envelope_3d(0.0, node.primitive(self).layer()),
@ -832,7 +982,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
} }
pub fn primitive_nodes(&self) -> impl Iterator<Item = PrimitiveIndex> + '_ { pub fn primitive_nodes(&self) -> impl Iterator<Item = PrimitiveIndex> + '_ {
self.geometry_with_rtree self.recording_geometry_with_rtree
.rtree() .rtree()
.iter() .iter()
.filter_map(|wrapper| { .filter_map(|wrapper| {
@ -845,7 +995,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
} }
pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator<Item = PrimitiveIndex> + '_ { pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator<Item = PrimitiveIndex> + '_ {
self.geometry_with_rtree self.recording_geometry_with_rtree
.rtree() .rtree()
.locate_in_envelope_intersecting(&AABB::from_corners( .locate_in_envelope_intersecting(&AABB::from_corners(
[-f64::INFINITY, -f64::INFINITY, layer as f64], [-f64::INFINITY, -f64::INFINITY, layer as f64],
@ -860,6 +1010,17 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
}) })
} }
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
self.recording_geometry_with_rtree.compound_weight(compound)
}
pub fn compounds<'a, W: 'a>(
&'a self,
node: GenericIndex<W>,
) -> impl Iterator<Item = GenericIndex<CW>> + 'a {
self.recording_geometry_with_rtree.compounds(node)
}
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
if let (Some(node1_net_id), Some(node2_net_id)) = ( if let (Some(node1_net_id), Some(node2_net_id)) = (
node1.primitive(self).maybe_net(), node1.primitive(self).maybe_net(),
@ -884,11 +1045,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
SegIndex, SegIndex,
BendIndex, BendIndex,
> { > {
self.geometry_with_rtree.geometry() self.recording_geometry_with_rtree.geometry()
} }
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PrimitiveIndex, GenericIndex<CW>>>> { pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PrimitiveIndex, GenericIndex<CW>>>> {
self.geometry_with_rtree.rtree() self.recording_geometry_with_rtree.rtree()
} }
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
@ -914,11 +1075,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
} }
pub fn layer_count(&self) -> usize { pub fn layer_count(&self) -> usize {
*self.geometry_with_rtree.layer_count() self.recording_geometry_with_rtree.layer_count()
} }
pub fn node_count(&self) -> usize { pub fn node_count(&self) -> usize {
self.geometry_with_rtree.graph().node_count() self.recording_geometry_with_rtree.graph().node_count()
} }
fn test_if_looses_dont_infringe_each_other(&self) -> bool { fn test_if_looses_dont_infringe_each_other(&self) -> bool {
@ -958,26 +1119,3 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
}) })
} }
} }
impl<CW: Copy, R: AccessRules> ManageCompounds<CW, GenericIndex<CW>> for Drawing<CW, R> {
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
self.geometry_with_rtree.add_compound(weight)
}
fn remove_compound(&mut self, compound: GenericIndex<CW>) {
self.geometry_with_rtree.remove_compound(compound);
}
fn add_to_compound<W>(&mut self, primitive: GenericIndex<W>, compound: GenericIndex<CW>) {
self.geometry_with_rtree
.add_to_compound(primitive, compound);
}
fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
self.geometry_with_rtree.compound_weight(compound)
}
fn compounds<W>(&self, node: GenericIndex<W>) -> impl Iterator<Item = GenericIndex<CW>> {
self.geometry_with_rtree.compounds(node)
}
}

View File

@ -14,7 +14,7 @@ use crate::{
use petgraph::stable_graph::NodeIndex; use petgraph::stable_graph::NodeIndex;
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SegIndex { pub enum SegIndex {
Fixed(FixedSegIndex), Fixed(FixedSegIndex),
LoneLoose(LoneLooseSegIndex), LoneLoose(LoneLooseSegIndex),

View File

@ -2,6 +2,7 @@ use std::{collections::HashMap, hash::Hash, marker::PhantomData};
use geo::Point; use geo::Point;
use petgraph::stable_graph::StableDiGraph; use petgraph::stable_graph::StableDiGraph;
use rstar::RTree;
use crate::{ use crate::{
drawing::graph::{GetLayer, Retag}, drawing::graph::{GetLayer, Retag},
@ -9,10 +10,13 @@ use crate::{
}; };
use super::{ use super::{
compound::ManageCompounds, with_rtree::GeometryWithRtree, AccessBendWeight, AccessDotWeight, compound::ManageCompounds,
AccessSegWeight, GenericNode, GeometryLabel, GetWidth, with_rtree::{BboxedIndex, GeometryWithRtree},
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
GetWidth,
}; };
#[derive(Debug)]
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,
@ -31,6 +35,30 @@ pub struct GeometryEdit<
primitive_weight_marker: PhantomData<PW>, primitive_weight_marker: PhantomData<PW>,
} }
impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
DW: AccessDotWeight<PW> + GetLayer,
SW: AccessSegWeight<PW> + GetLayer,
BW: AccessBendWeight<PW> + GetLayer,
CW: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
> GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>
{
pub fn new() -> Self {
Self {
dots: HashMap::new(),
segs: HashMap::new(),
bends: HashMap::new(),
compounds: HashMap::new(),
primitive_weight_marker: PhantomData,
}
}
}
#[derive(Debug)]
pub struct RecordingGeometryWithRtree< pub struct RecordingGeometryWithRtree<
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,
@ -57,6 +85,14 @@ impl<
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy, BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
> RecordingGeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI> > RecordingGeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
{ {
pub fn new(layer_count: usize) -> Self {
Self {
geometry_with_rtree: GeometryWithRtree::<PW, DW, SW, BW, CW, PI, DI, SI, BI>::new(
layer_count,
),
}
}
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>( pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(
&mut self, &mut self,
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>, recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
@ -349,6 +385,18 @@ impl<
self.geometry_with_rtree.compounds(node) self.geometry_with_rtree.compounds(node)
} }
pub fn geometry(&self) -> &Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
self.geometry_with_rtree.geometry()
}
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PI, GenericIndex<CW>>>> {
self.geometry_with_rtree.rtree()
}
pub fn layer_count(&self) -> usize {
*self.geometry_with_rtree.layer_count()
}
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize> { pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize> {
self.geometry_with_rtree.graph() self.geometry_with_rtree.graph()
} }

View File

@ -17,9 +17,9 @@ use crate::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
SeqLooseSegWeight, SeqLooseSegWeight,
}, },
Drawing, DrawingException, Infringement, Drawing, DrawingEdit, DrawingException, Infringement,
}, },
geometry::{compound::ManageCompounds, GenericNode}, geometry::GenericNode,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
layout::{ layout::{
poly::{Poly, PolyWeight}, poly::{Poly, PolyWeight},
@ -39,6 +39,7 @@ pub enum CompoundWeight {
/// The alias to differ node types /// The alias to differ node types
pub type NodeIndex = GenericNode<PrimitiveIndex, GenericIndex<CompoundWeight>>; pub type NodeIndex = GenericNode<PrimitiveIndex, GenericIndex<CompoundWeight>>;
pub type LayoutEdit = DrawingEdit<CompoundWeight>;
#[derive(Debug, Getters)] #[derive(Debug, Getters)]
/// Structure for managing the Layout design /// Structure for managing the Layout design
@ -54,46 +55,61 @@ impl<R: AccessRules> Layout<R> {
/// Insert [`Cane`] object into the [`Layout`] /// Insert [`Cane`] object into the [`Layout`]
pub fn insert_cane( pub fn insert_cane(
&mut self, &mut self,
from: DotIndex, recorder: &mut LayoutEdit,
from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
seg_weight: SeqLooseSegWeight, seg_weight: SeqLooseSegWeight,
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
cw: bool, cw: bool,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
self.drawing self.drawing.insert_cane(
.insert_cane(from, around, dot_weight, seg_weight, bend_weight, cw) recorder,
from,
around,
dot_weight,
seg_weight,
bend_weight,
cw,
)
} }
/// Remove [`Cane`] object from the [`Layout`] /// Remove [`Cane`] object from the [`Layout`]
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) { pub fn remove_cane(&mut self, recorder: &mut LayoutEdit, cane: &Cane, face: LooseDotIndex) {
self.drawing.remove_cane(cane, face) self.drawing.remove_cane(recorder, cane, face)
} }
#[debug_ensures(ret.is_ok() -> self.drawing.node_count() == old(self.drawing.node_count()) + weight.to_layer - weight.from_layer + 2)] #[debug_ensures(ret.is_ok() -> self.drawing.node_count() == old(self.drawing.node_count()) + weight.to_layer - weight.from_layer + 2)]
#[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))] #[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))]
/// Insert [`Via`] into the [`Layout`] /// Insert [`Via`] into the [`Layout`]
pub fn add_via(&mut self, weight: ViaWeight) -> Result<GenericIndex<ViaWeight>, Infringement> { pub fn add_via(
let compound = self.drawing.add_compound(weight.into()); &mut self,
recorder: &mut LayoutEdit,
weight: ViaWeight,
) -> Result<GenericIndex<ViaWeight>, Infringement> {
let compound = self.drawing.add_compound(recorder, weight.into());
let mut dots = vec![]; let mut dots = vec![];
for layer in weight.from_layer..=weight.to_layer { for layer in weight.from_layer..=weight.to_layer {
match self.drawing.add_fixed_dot(FixedDotWeight { match self.drawing.add_fixed_dot(
circle: weight.circle, recorder,
layer, FixedDotWeight {
maybe_net: weight.maybe_net, circle: weight.circle,
}) { layer,
maybe_net: weight.maybe_net,
},
) {
Ok(dot) => { Ok(dot) => {
self.drawing.add_to_compound(dot, compound); self.drawing.add_to_compound(recorder, dot, compound);
dots.push(dot); dots.push(dot);
} }
Err(err) => { Err(err) => {
// Remove inserted dots. // Remove inserted dots.
self.drawing.remove_compound(compound); self.drawing.remove_compound(recorder, compound);
for dot in dots.iter().rev() { for dot in dots.iter().rev() {
self.drawing.remove_fixed_dot(*dot); self.drawing.remove_fixed_dot(recorder, *dot);
} }
return Err(err); return Err(err);
@ -104,24 +120,32 @@ impl<R: AccessRules> Layout<R> {
Ok(GenericIndex::<ViaWeight>::new(compound.petgraph_index())) Ok(GenericIndex::<ViaWeight>::new(compound.petgraph_index()))
} }
pub fn add_fixed_dot(
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> { &mut self,
self.drawing.add_fixed_dot(weight) recorder: &mut LayoutEdit,
weight: FixedDotWeight,
) -> Result<FixedDotIndex, Infringement> {
self.drawing.add_fixed_dot(recorder, weight)
} }
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { pub fn add_fixed_dot_infringably(
self.drawing.add_fixed_dot_infringably(weight) &mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight,
) -> FixedDotIndex {
self.drawing.add_fixed_dot_infringably(recorder, weight)
} }
pub fn add_poly_fixed_dot( pub fn add_poly_fixed_dot(
&mut self, &mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight, weight: FixedDotWeight,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
) -> Result<FixedDotIndex, Infringement> { ) -> Result<FixedDotIndex, Infringement> {
let maybe_dot = self.drawing.add_fixed_dot(weight); let maybe_dot = self.drawing.add_fixed_dot(recorder, weight);
if let Ok(dot) = maybe_dot { if let Ok(dot) = maybe_dot {
self.drawing.add_to_compound(dot, poly.into()); self.drawing.add_to_compound(recorder, dot, poly.into());
} }
maybe_dot maybe_dot
@ -129,43 +153,48 @@ impl<R: AccessRules> Layout<R> {
pub fn add_poly_fixed_dot_infringably( pub fn add_poly_fixed_dot_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight, weight: FixedDotWeight,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
) -> FixedDotIndex { ) -> FixedDotIndex {
let dot = self.drawing.add_fixed_dot_infringably(weight); let dot = self.drawing.add_fixed_dot_infringably(recorder, weight);
self.drawing.add_to_compound(dot, poly.into()); self.drawing.add_to_compound(recorder, dot, poly.into());
dot dot
} }
pub fn add_fixed_seg( pub fn add_fixed_seg(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> Result<FixedSegIndex, Infringement> { ) -> Result<FixedSegIndex, Infringement> {
self.drawing.add_fixed_seg(from, to, weight) self.drawing.add_fixed_seg(recorder, from, to, weight)
} }
pub fn add_fixed_seg_infringably( pub fn add_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> FixedSegIndex { ) -> FixedSegIndex {
self.drawing.add_fixed_seg_infringably(from, to, weight) self.drawing
.add_fixed_seg_infringably(recorder, from, to, weight)
} }
pub fn add_poly_fixed_seg( pub fn add_poly_fixed_seg(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
) -> Result<FixedSegIndex, Infringement> { ) -> Result<FixedSegIndex, Infringement> {
let maybe_seg = self.add_fixed_seg(from, to, weight); let maybe_seg = self.add_fixed_seg(recorder, from, to, weight);
if let Ok(seg) = maybe_seg { if let Ok(seg) = maybe_seg {
self.drawing.add_to_compound(seg, poly.into()); self.drawing.add_to_compound(recorder, seg, poly.into());
} }
maybe_seg maybe_seg
@ -173,48 +202,64 @@ impl<R: AccessRules> Layout<R> {
pub fn add_poly_fixed_seg_infringably( pub fn add_poly_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
) -> FixedSegIndex { ) -> FixedSegIndex {
let seg = self.add_fixed_seg_infringably(from, to, weight); let seg = self.add_fixed_seg_infringably(recorder, from, to, weight);
self.drawing.add_to_compound(seg, poly.into()); self.drawing.add_to_compound(recorder, seg, poly.into());
seg seg
} }
pub fn add_lone_loose_seg( pub fn add_lone_loose_seg(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: LoneLooseSegWeight, weight: LoneLooseSegWeight,
) -> Result<LoneLooseSegIndex, Infringement> { ) -> Result<LoneLooseSegIndex, Infringement> {
self.drawing.add_lone_loose_seg(from, to, weight) self.drawing.add_lone_loose_seg(recorder, from, to, weight)
} }
pub fn add_seq_loose_seg( pub fn add_seq_loose_seg(
&mut self, &mut self,
recorder: &mut LayoutEdit,
from: DotIndex, from: DotIndex,
to: LooseDotIndex, to: LooseDotIndex,
weight: SeqLooseSegWeight, weight: SeqLooseSegWeight,
) -> Result<SeqLooseSegIndex, Infringement> { ) -> Result<SeqLooseSegIndex, Infringement> {
self.drawing.add_seq_loose_seg(from, to, weight) self.drawing.add_seq_loose_seg(recorder, from, to, weight)
} }
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { pub fn move_dot(
self.drawing.move_dot(dot, to) &mut self,
recorder: &mut LayoutEdit,
dot: DotIndex,
to: Point,
) -> Result<(), Infringement> {
self.drawing.move_dot(recorder, dot, to)
} }
pub fn add_poly(&mut self, weight: PolyWeight) -> GenericIndex<PolyWeight> { pub fn add_poly(
&mut self,
recorder: &mut LayoutEdit,
weight: PolyWeight,
) -> GenericIndex<PolyWeight> {
GenericIndex::<PolyWeight>::new( GenericIndex::<PolyWeight>::new(
self.drawing self.drawing
.add_compound(CompoundWeight::Poly(weight)) .add_compound(recorder, CompoundWeight::Poly(weight))
.petgraph_index(), .petgraph_index(),
) )
} }
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> { pub fn remove_band(
self.drawing.remove_band(band) &mut self,
recorder: &mut LayoutEdit,
band: BandTermsegIndex,
) -> Result<(), DrawingException> {
self.drawing.remove_band(recorder, band)
} }
pub fn polys<W: 'static>( pub fn polys<W: 'static>(

View File

@ -12,7 +12,7 @@ use crate::{
rules::AccessRules, rules::AccessRules,
seg::SegIndex, seg::SegIndex,
}, },
geometry::{compound::ManageCompounds, poly::PolyShape, GetPos}, geometry::{poly::PolyShape, GetPos},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
layout::{CompoundWeight, Layout}, layout::{CompoundWeight, Layout},
}; };

View File

@ -4,10 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
drawing::{graph::GetMaybeNet, primitive::MakePrimitiveShape, rules::AccessRules}, drawing::{graph::GetMaybeNet, primitive::MakePrimitiveShape, rules::AccessRules},
geometry::{ geometry::primitive::{DotShape, PrimitiveShape},
compound::ManageCompounds,
primitive::{DotShape, PrimitiveShape},
},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
layout::{CompoundWeight, Layout}, layout::{CompoundWeight, Layout},
math::Circle, math::Circle,

View File

@ -16,7 +16,7 @@ use crate::{
seg::{LoneLooseSegWeight, SeqLooseSegWeight}, seg::{LoneLooseSegWeight, SeqLooseSegWeight},
DrawingException, Infringement, DrawingException, Infringement,
}, },
layout::Layout, layout::{Layout, LayoutEdit},
math::{Circle, NoTangents}, math::{Circle, NoTangents},
}; };
@ -66,6 +66,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
DotIndex::Fixed(dot) => BandTermsegIndex::Straight( DotIndex::Fixed(dot) => BandTermsegIndex::Straight(
self.layout self.layout
.add_lone_loose_seg( .add_lone_loose_seg(
&mut LayoutEdit::new(),
dot, dot,
into, into,
LoneLooseSegWeight { LoneLooseSegWeight {
@ -79,6 +80,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
DotIndex::Loose(dot) => BandTermsegIndex::Bended( DotIndex::Loose(dot) => BandTermsegIndex::Bended(
self.layout self.layout
.add_seq_loose_seg( .add_seq_loose_seg(
&mut LayoutEdit::new(),
into.into(), into.into(),
dot, dot,
SeqLooseSegWeight { SeqLooseSegWeight {
@ -164,7 +166,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
#[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> { fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> {
if let Head::Cane(head) = head { if let Head::Cane(head) = head {
self.layout.move_dot(head.face.into(), to)?; self.layout
.move_dot(&mut LayoutEdit::new(), head.face.into(), to)?;
Ok(Head::Cane(head)) Ok(Head::Cane(head))
} else { } else {
Ok(head) Ok(head)
@ -185,6 +188,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
let layer = head.face().primitive(self.layout.drawing()).layer(); let layer = head.face().primitive(self.layout.drawing()).layer();
let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net(); let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net();
let cane = self.layout.insert_cane( let cane = self.layout.insert_cane(
&mut LayoutEdit::new(),
head.face(), head.face(),
around, around,
LooseDotWeight { LooseDotWeight {
@ -227,7 +231,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.primitive(head.cane.seg) .primitive(head.cane.seg)
.other_joint(head.cane.dot.into()); .other_joint(head.cane.dot.into());
self.layout.remove_cane(&head.cane, head.face); self.layout
.remove_cane(&mut LayoutEdit::new(), &head.cane, head.face);
Some(self.guide().head(prev_dot)) Some(self.guide().head(prev_dot))
} }

View File

@ -16,7 +16,7 @@ use crate::{
Drawing, Drawing,
}, },
geometry::{primitive::PrimitiveShape, GetWidth}, geometry::{primitive::PrimitiveShape, GetWidth},
layout::{poly::SolidPolyWeight, Layout}, layout::{poly::SolidPolyWeight, Layout, LayoutEdit},
math::{Circle, PointWithRotation}, math::{Circle, PointWithRotation},
specctra::{ specctra::{
mesadata::SpecctraMesadata, mesadata::SpecctraMesadata,
@ -185,7 +185,7 @@ impl SpecctraDesign {
/// which is used for layout and routing operations. The board is initialized with [`SpecctraMesadata`], /// 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 /// which includes layer and net mappings, and is populated with components, pins, vias, and wires
/// from the PCB definition. /// from the PCB definition.
pub fn make_board(&self) -> Board<SpecctraMesadata> { pub fn make_board(&self, recorder: &mut LayoutEdit) -> Board<SpecctraMesadata> {
let mesadata = SpecctraMesadata::from_pcb(&self.pcb); let mesadata = SpecctraMesadata::from_pcb(&self.pcb);
let mut board = Board::new(Layout::new(Drawing::new( let mut board = Board::new(Layout::new(Drawing::new(
mesadata, mesadata,
@ -210,11 +210,7 @@ impl SpecctraDesign {
net_pin_assignments.pins.as_ref().and_then(|pins| { net_pin_assignments.pins.as_ref().and_then(|pins| {
// take the list of pins // take the list of pins
// and for each pin output (pin name, net id) // and for each pin output (pin name, net id)
Some(pins Some(pins.names.iter().map(move |pinname| (pinname.clone(), net)))
.names
.iter()
.map(move |pinname| (pinname.clone(), net))
)
}) })
}) })
// flatten the nested iters into a single stream of tuples // flatten the nested iters into a single stream of tuples
@ -248,6 +244,7 @@ impl SpecctraDesign {
Shape::Circle(circle) => { Shape::Circle(circle) => {
let layer = get_layer(&board, &circle.layer); let layer = get_layer(&board, &circle.layer);
Self::add_circle( Self::add_circle(
recorder,
&mut board, &mut board,
place.point_with_rotation(), place.point_with_rotation(),
pin.point_with_rotation(), pin.point_with_rotation(),
@ -260,6 +257,7 @@ impl SpecctraDesign {
Shape::Rect(rect) => { Shape::Rect(rect) => {
let layer = get_layer(&board, &rect.layer); let layer = get_layer(&board, &rect.layer);
Self::add_rect( Self::add_rect(
recorder,
&mut board, &mut board,
place.point_with_rotation(), place.point_with_rotation(),
pin.point_with_rotation(), pin.point_with_rotation(),
@ -275,6 +273,7 @@ impl SpecctraDesign {
Shape::Path(path) => { Shape::Path(path) => {
let layer = get_layer(&board, &path.layer); let layer = get_layer(&board, &path.layer);
Self::add_path( Self::add_path(
recorder,
&mut board, &mut board,
place.point_with_rotation(), place.point_with_rotation(),
pin.point_with_rotation(), pin.point_with_rotation(),
@ -288,6 +287,7 @@ impl SpecctraDesign {
Shape::Polygon(polygon) => { Shape::Polygon(polygon) => {
let layer = get_layer(&board, &polygon.layer); let layer = get_layer(&board, &polygon.layer);
Self::add_polygon( Self::add_polygon(
recorder,
&mut board, &mut board,
place.point_with_rotation(), place.point_with_rotation(),
pin.point_with_rotation(), pin.point_with_rotation(),
@ -305,11 +305,7 @@ impl SpecctraDesign {
} }
for via in &self.pcb.wiring.vias { for via in &self.pcb.wiring.vias {
let net = board let net = board.layout().drawing().rules().netname_net(&via.net);
.layout()
.drawing()
.rules()
.netname_net(&via.net);
let padstack = self.pcb.library.find_padstack_by_name(&via.name).unwrap(); let padstack = self.pcb.library.find_padstack_by_name(&via.name).unwrap();
@ -322,6 +318,7 @@ impl SpecctraDesign {
Shape::Circle(circle) => { Shape::Circle(circle) => {
let layer = get_layer(&board, &circle.layer); let layer = get_layer(&board, &circle.layer);
Self::add_circle( Self::add_circle(
recorder,
&mut board, &mut board,
// TODO: refactor? // TODO: refactor?
// should this call take PointWithRotation? // should this call take PointWithRotation?
@ -336,6 +333,7 @@ impl SpecctraDesign {
Shape::Rect(rect) => { Shape::Rect(rect) => {
let layer = get_layer(&board, &rect.layer); let layer = get_layer(&board, &rect.layer);
Self::add_rect( Self::add_rect(
recorder,
&mut board, &mut board,
PointWithRotation::from_xy(via.x, via.y), PointWithRotation::from_xy(via.x, via.y),
PointWithRotation::default(), PointWithRotation::default(),
@ -351,6 +349,7 @@ impl SpecctraDesign {
Shape::Path(path) => { Shape::Path(path) => {
let layer = get_layer(&board, &path.layer); let layer = get_layer(&board, &path.layer);
Self::add_path( Self::add_path(
recorder,
&mut board, &mut board,
PointWithRotation::from_xy(via.x, via.y), PointWithRotation::from_xy(via.x, via.y),
PointWithRotation::default(), PointWithRotation::default(),
@ -364,6 +363,7 @@ impl SpecctraDesign {
Shape::Polygon(polygon) => { Shape::Polygon(polygon) => {
let layer = get_layer(&board, &polygon.layer); let layer = get_layer(&board, &polygon.layer);
Self::add_polygon( Self::add_polygon(
recorder,
&mut board, &mut board,
PointWithRotation::from_xy(via.x, via.y), PointWithRotation::from_xy(via.x, via.y),
PointWithRotation::default(), PointWithRotation::default(),
@ -385,13 +385,10 @@ impl SpecctraDesign {
.rules() .rules()
.layername_layer(&wire.path.layer) .layername_layer(&wire.path.layer)
.unwrap(); .unwrap();
let net = board let net = board.layout().drawing().rules().netname_net(&wire.net);
.layout()
.drawing()
.rules()
.netname_net(&wire.net);
Self::add_path( Self::add_path(
recorder,
&mut board, &mut board,
PointWithRotation::default(), PointWithRotation::default(),
PointWithRotation::default(), PointWithRotation::default(),
@ -427,6 +424,7 @@ impl SpecctraDesign {
} }
fn add_circle( fn add_circle(
recorder: &mut LayoutEdit,
board: &mut Board<SpecctraMesadata>, board: &mut Board<SpecctraMesadata>,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -441,6 +439,7 @@ impl SpecctraDesign {
}; };
board.add_fixed_dot_infringably( board.add_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle, circle,
layer, layer,
@ -451,6 +450,7 @@ impl SpecctraDesign {
} }
fn add_rect( fn add_rect(
recorder: &mut LayoutEdit,
board: &mut Board<SpecctraMesadata>, board: &mut Board<SpecctraMesadata>,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -463,16 +463,14 @@ impl SpecctraDesign {
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
let poly = board.add_poly( let poly = board.add_poly(
SolidPolyWeight { recorder,
layer, SolidPolyWeight { layer, maybe_net }.into(),
maybe_net,
}
.into(),
maybe_pin.clone(), maybe_pin.clone(),
); );
// Corners. // Corners.
let dot_1_1 = board.add_poly_fixed_dot_infringably( let dot_1_1 = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x1, y1), pos: Self::pos(place, pin, x1, y1),
@ -484,6 +482,7 @@ impl SpecctraDesign {
poly, poly,
); );
let dot_2_1 = board.add_poly_fixed_dot_infringably( let dot_2_1 = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x2, y1), pos: Self::pos(place, pin, x2, y1),
@ -495,6 +494,7 @@ impl SpecctraDesign {
poly, poly,
); );
let dot_2_2 = board.add_poly_fixed_dot_infringably( let dot_2_2 = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x2, y2), pos: Self::pos(place, pin, x2, y2),
@ -506,6 +506,7 @@ impl SpecctraDesign {
poly, poly,
); );
let dot_1_2 = board.add_poly_fixed_dot_infringably( let dot_1_2 = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x1, y2), pos: Self::pos(place, pin, x1, y2),
@ -518,6 +519,7 @@ impl SpecctraDesign {
); );
// Sides. // Sides.
board.add_poly_fixed_seg_infringably( board.add_poly_fixed_seg_infringably(
recorder,
dot_1_1, dot_1_1,
dot_2_1, dot_2_1,
FixedSegWeight { FixedSegWeight {
@ -528,6 +530,7 @@ impl SpecctraDesign {
poly, poly,
); );
board.add_poly_fixed_seg_infringably( board.add_poly_fixed_seg_infringably(
recorder,
dot_2_1, dot_2_1,
dot_2_2, dot_2_2,
FixedSegWeight { FixedSegWeight {
@ -538,6 +541,7 @@ impl SpecctraDesign {
poly, poly,
); );
board.add_poly_fixed_seg_infringably( board.add_poly_fixed_seg_infringably(
recorder,
dot_2_2, dot_2_2,
dot_1_2, dot_1_2,
FixedSegWeight { FixedSegWeight {
@ -548,6 +552,7 @@ impl SpecctraDesign {
poly, poly,
); );
board.add_poly_fixed_seg_infringably( board.add_poly_fixed_seg_infringably(
recorder,
dot_1_2, dot_1_2,
dot_1_1, dot_1_1,
FixedSegWeight { FixedSegWeight {
@ -560,6 +565,7 @@ impl SpecctraDesign {
} }
fn add_path( fn add_path(
recorder: &mut LayoutEdit,
board: &mut Board<SpecctraMesadata>, board: &mut Board<SpecctraMesadata>,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -572,6 +578,7 @@ impl SpecctraDesign {
// add the first coordinate in the wire path as a dot and save its index // add the first coordinate in the wire path as a dot and save its index
let mut prev_pos = Self::pos(place, pin, coords[0].x, coords[0].y); let mut prev_pos = Self::pos(place, pin, coords[0].x, coords[0].y);
let mut prev_index = board.add_fixed_dot_infringably( let mut prev_index = board.add_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: prev_pos, pos: prev_pos,
@ -592,6 +599,7 @@ impl SpecctraDesign {
} }
let index = board.add_fixed_dot_infringably( let index = board.add_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos, pos,
@ -605,6 +613,7 @@ impl SpecctraDesign {
// add a seg between the current and previous coords // add a seg between the current and previous coords
let _ = board.add_fixed_seg_infringably( let _ = board.add_fixed_seg_infringably(
recorder,
prev_index, prev_index,
index, index,
FixedSegWeight { FixedSegWeight {
@ -621,6 +630,7 @@ impl SpecctraDesign {
} }
fn add_polygon( fn add_polygon(
recorder: &mut LayoutEdit,
board: &mut Board<SpecctraMesadata>, board: &mut Board<SpecctraMesadata>,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -631,16 +641,14 @@ impl SpecctraDesign {
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
let poly = board.add_poly( let poly = board.add_poly(
SolidPolyWeight { recorder,
layer, SolidPolyWeight { layer, maybe_net }.into(),
maybe_net,
}
.into(),
maybe_pin.clone(), maybe_pin.clone(),
); );
// add the first coordinate in the wire path as a dot and save its index // add the first coordinate in the wire path as a dot and save its index
let mut prev_index = board.add_poly_fixed_dot_infringably( let mut prev_index = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, coords[0].x, coords[0].y), pos: Self::pos(place, pin, coords[0].x, coords[0].y),
@ -657,6 +665,7 @@ impl SpecctraDesign {
// iterate through path coords starting from the second // iterate through path coords starting from the second
for coord in coords.iter().skip(1) { for coord in coords.iter().skip(1) {
let index = board.add_poly_fixed_dot_infringably( let index = board.add_poly_fixed_dot_infringably(
recorder,
FixedDotWeight { FixedDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, coord.x, coord.y), pos: Self::pos(place, pin, coord.x, coord.y),
@ -671,6 +680,7 @@ impl SpecctraDesign {
// add a seg between the current and previous coords // add a seg between the current and previous coords
let _ = board.add_poly_fixed_seg_infringably( let _ = board.add_poly_fixed_seg_infringably(
recorder,
prev_index, prev_index,
index, index,
FixedSegWeight { FixedSegWeight {

View File

@ -86,11 +86,7 @@ impl SpecctraMesadata {
.classes .classes
.iter() .iter()
.flat_map(|class| &class.nets) .flat_map(|class| &class.nets)
.chain( .chain(pcb.network.nets.iter().map(|net| &net.name))
pcb.network.nets
.iter()
.map(|net| &net.name)
)
.enumerate() .enumerate()
.map(|(net, netname)| (net, netname.clone())), .map(|(net, netname)| (net, netname.clone())),
); );

View File

@ -11,6 +11,7 @@ use topola::{
drawing::graph::{GetLayer, GetMaybeNet}, drawing::graph::{GetLayer, GetMaybeNet},
geometry::shape::MeasureLength, geometry::shape::MeasureLength,
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},
layout::LayoutEdit,
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
}; };
@ -18,7 +19,8 @@ pub fn load_design_and_assert(filename: &str) -> Invoker<SpecctraMesadata> {
let design_file = File::open(filename).unwrap(); let design_file = File::open(filename).unwrap();
let design_bufread = BufReader::new(design_file); let design_bufread = BufReader::new(design_file);
let design = SpecctraDesign::load(design_bufread).unwrap(); let design = SpecctraDesign::load(design_bufread).unwrap();
let mut invoker = Invoker::new(Autorouter::new(design.make_board()).unwrap()); let mut invoker =
Invoker::new(Autorouter::new(design.make_board(&mut LayoutEdit::new())).unwrap());
assert!(matches!( assert!(matches!(
invoker.undo(), invoker.undo(),