diff --git a/examples/specctra.rs b/examples/specctra.rs index f316067..7993d9f 100644 --- a/examples/specctra.rs +++ b/examples/specctra.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::io::BufReader; use topola::autorouter::invoker::Invoker; use topola::autorouter::Autorouter; +use topola::layout::LayoutEdit; use topola::specctra::design::SpecctraDesign; 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 = 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()); diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 77f8951..d8e476a 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -8,7 +8,7 @@ use thiserror::Error; use crate::{ board::{mesadata::AccessMesadata, Board}, drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement}, - layout::via::ViaWeight, + layout::{via::ViaWeight, LayoutEdit}, router::{astar::AstarError, navmesh::NavmeshError, RouterOptions}, triangulation::GetTrianvertexNodeIndex, }; @@ -73,7 +73,7 @@ impl Autorouter { .node_index() { 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) @@ -82,7 +82,7 @@ impl Autorouter { pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> { self.board .layout_mut() - .remove_band(band) + .remove_band(&mut LayoutEdit::new(), band) .map_err(|_| AutorouterError::CouldNotRemoveBand(band)) } @@ -120,7 +120,7 @@ impl Autorouter { .unwrap(); self.board .layout_mut() - .remove_band(band) + .remove_band(&mut LayoutEdit::new(), band) .map_err(|_| AutorouterError::CouldNotRemoveBand(band))?; } @@ -191,7 +191,7 @@ impl Autorouter { .node_index() { 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 @@ -202,7 +202,7 @@ impl Autorouter { .node_index() { 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) diff --git a/src/autorouter/place_via.rs b/src/autorouter/place_via.rs index 30042fb..51df12e 100644 --- a/src/autorouter/place_via.rs +++ b/src/autorouter/place_via.rs @@ -6,7 +6,7 @@ use crate::{ board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, - layout::via::ViaWeight, + layout::{via::ViaWeight, LayoutEdit}, router::{navcord::NavcordStepper, navmesh::Navmesh}, }; @@ -35,7 +35,10 @@ impl PlaceViaExecutionStepper { ) -> Result<(), AutorouterError> { if !self.done { self.done = true; - autorouter.board.layout_mut().add_via(self.weight)?; + autorouter + .board + .layout_mut() + .add_via(&mut LayoutEdit::new(), self.weight)?; Ok(()) } else { Ok(()) diff --git a/src/autorouter/pointroute.rs b/src/autorouter/pointroute.rs index 74217e8..42b3f86 100644 --- a/src/autorouter/pointroute.rs +++ b/src/autorouter/pointroute.rs @@ -8,6 +8,7 @@ use crate::{ band::BandTermsegIndex, dot::{FixedDotIndex, FixedDotWeight}, }, + layout::LayoutEdit, math::Circle, router::{route::RouteStepper, Router}, stepper::Step, @@ -29,6 +30,7 @@ impl PointrouteExecutionStepper { options: AutorouterOptions, ) -> Result { let destination = autorouter.board.add_fixed_dot_infringably( + &mut LayoutEdit::new(), FixedDotWeight { circle: Circle { pos: point, diff --git a/src/autorouter/remove_bands.rs b/src/autorouter/remove_bands.rs index ece9b46..83214ef 100644 --- a/src/autorouter/remove_bands.rs +++ b/src/autorouter/remove_bands.rs @@ -4,6 +4,7 @@ use crate::{ board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, + layout::LayoutEdit, router::{navcord::NavcordStepper, navmesh::Navmesh}, }; @@ -36,7 +37,10 @@ impl RemoveBandsExecutionStepper { for selector in self.selection.selectors() { 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(()) } else { diff --git a/src/bin/topola-egui/workspace.rs b/src/bin/topola-egui/workspace.rs index 8d5e94d..b097716 100644 --- a/src/bin/topola-egui/workspace.rs +++ b/src/bin/topola-egui/workspace.rs @@ -9,6 +9,7 @@ use topola::{ activity::{ActivityContext, ActivityStepperWithStatus, InteractiveInput}, Interactor, }, + layout::LayoutEdit, specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, stepper::Step, }; @@ -30,7 +31,7 @@ pub struct Workspace { impl Workspace { pub fn new(design: SpecctraDesign, tr: &Translator) -> Result { - let board = design.make_board(); + let board = design.make_board(&mut LayoutEdit::new()); let layers = Layers::new(&board); let overlay = Overlay::new(&board).map_err(|err| { format!( diff --git a/src/bin/topola/main.rs b/src/bin/topola/main.rs index a781b76..ad5a7f9 100644 --- a/src/bin/topola/main.rs +++ b/src/bin/topola/main.rs @@ -7,6 +7,7 @@ use topola::autorouter::invoker::Invoker; use topola::autorouter::selection::PinSelection; use topola::autorouter::Autorouter; use topola::autorouter::AutorouterOptions; +use topola::layout::LayoutEdit; use topola::router::RouterOptions; use topola::specctra::design::SpecctraDesign; @@ -19,7 +20,7 @@ fn main() -> Result<(), std::io::Error> { let mut design_bufread = BufReader::new(design_file); 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 command_file = File::open(commands_filename)?; diff --git a/src/board/board.rs b/src/board/board.rs index 63764b9..ecad7d0 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -16,7 +16,7 @@ use crate::{ graph::GenericIndex, layout::{ poly::{GetMaybeApex, MakePolyShape, PolyWeight}, - Layout, NodeIndex, + Layout, LayoutEdit, NodeIndex, }, math::Circle, }; @@ -67,10 +67,11 @@ impl Board { /// 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, weight: FixedDotWeight, maybe_pin: Option, ) -> 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 { self.node_to_pinname @@ -85,10 +86,13 @@ impl Board { /// Adds the segment to the layout and maps the pin name to the created segment if provided. pub fn add_poly_fixed_dot_infringably( &mut self, + recorder: &mut LayoutEdit, weight: FixedDotWeight, poly: GenericIndex, ) -> 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())) { self.node_to_pinname @@ -103,12 +107,15 @@ impl Board { /// Adds the segment to the layout and updates the internal mapping if necessary. pub fn add_fixed_seg_infringably( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, maybe_pin: Option, ) -> 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 { self.node_to_pinname @@ -123,6 +130,7 @@ impl Board { /// Adds the segment to the layout and updates the internal mapping if necessary. pub fn add_poly_fixed_seg_infringably( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, @@ -130,7 +138,7 @@ impl Board { ) -> FixedSegIndex { let seg = self .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())) { self.node_to_pinname @@ -145,10 +153,11 @@ impl Board { /// 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( &mut self, + recorder: &mut LayoutEdit, weight: PolyWeight, maybe_pin: Option, ) -> GenericIndex { - let poly = self.layout.add_poly(weight); + let poly = self.layout.add_poly(recorder, weight); if let Some(pin) = maybe_pin { self.node_to_pinname @@ -161,11 +170,16 @@ impl Board { /// 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. - pub fn poly_apex(&mut self, poly: GenericIndex) -> FixedDotIndex { + pub fn poly_apex( + &mut self, + recorder: &mut LayoutEdit, + poly: GenericIndex, + ) -> FixedDotIndex { if let Some(apex) = self.layout.poly(poly).maybe_apex() { apex } else { self.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: self.layout.poly(poly).shape().center(), diff --git a/src/drawing/bend.rs b/src/drawing/bend.rs index 141b655..a8744cb 100644 --- a/src/drawing/bend.rs +++ b/src/drawing/bend.rs @@ -14,7 +14,7 @@ use crate::{ use petgraph::stable_graph::NodeIndex; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BendIndex { Fixed(FixedBendIndex), Loose(LooseBendIndex), diff --git a/src/drawing/dot.rs b/src/drawing/dot.rs index 152fa7d..a75e297 100644 --- a/src/drawing/dot.rs +++ b/src/drawing/dot.rs @@ -16,7 +16,7 @@ use crate::{ }; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum DotIndex { Fixed(FixedDotIndex), Loose(LooseDotIndex), diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index 5950aa8..306c1ec 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -7,9 +7,9 @@ use rstar::{RTree, AABB}; use thiserror::Error; use crate::geometry::{ - compound::ManageCompounds, primitive::{AccessPrimitiveShape, PrimitiveShape}, - with_rtree::{BboxedIndex, GeometryWithRtree}, + recording_with_rtree::{GeometryEdit, RecordingGeometryWithRtree}, + with_rtree::BboxedIndex, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, GetOffset, GetPos, GetWidth, }; @@ -65,9 +65,21 @@ pub struct Collision(pub PrimitiveShape, pub PrimitiveIndex); #[error("{1:?} is already connected to net {0}")] pub struct AlreadyConnected(pub usize, pub PrimitiveIndex); +pub type DrawingEdit = GeometryEdit< + PrimitiveWeight, + DotWeight, + SegWeight, + BendWeight, + CW, + PrimitiveIndex, + DotIndex, + SegIndex, + BendIndex, +>; + #[derive(Debug, Getters)] pub struct Drawing { - geometry_with_rtree: GeometryWithRtree< + recording_geometry_with_rtree: RecordingGeometryWithRtree< PrimitiveWeight, DotWeight, SegWeight, @@ -85,15 +97,20 @@ pub struct Drawing { impl Drawing { pub fn new(rules: R, layer_count: usize) -> Self { Self { - geometry_with_rtree: GeometryWithRtree::new(layer_count), + recording_geometry_with_rtree: RecordingGeometryWithRtree::new(layer_count), rules, } } - pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> { + pub fn remove_band( + &mut self, + recorder: &mut DrawingEdit, + band: BandTermsegIndex, + ) -> Result<(), DrawingException> { match band { 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) => { let mut dots = vec![]; @@ -110,7 +127,8 @@ impl Drawing { dots.push(dot); } LooseIndex::LoneSeg(seg) => { - self.geometry_with_rtree.remove_seg(seg.into()); + self.recording_geometry_with_rtree + .remove_seg(recorder, seg.into()); break; } LooseIndex::SeqSeg(seg) => { @@ -121,7 +139,7 @@ impl Drawing { if let Some(outer) = self.primitive(bend).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 Drawing { } 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 { - 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 // the shapes, which we first need unchanged to remove the segs and bends from the R-tree. 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 { - self.update_this_and_outward_bows(outer)?; + self.update_this_and_outward_bows(recorder, outer)?; } } } @@ -158,34 +179,44 @@ impl Drawing { #[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(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 { - self.add_dot_with_infringables(weight, Some(&[])) + pub fn add_fixed_dot( + &mut self, + recorder: &mut DrawingEdit, + weight: FixedDotWeight, + ) -> Result { + 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().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) { - self.geometry_with_rtree.remove_dot(dot.into()); + pub fn remove_fixed_dot(&mut self, recorder: &mut DrawingEdit, dot: FixedDotIndex) { + 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().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { - self.add_dot_infringably(weight) + pub fn add_fixed_dot_infringably( + &mut self, + recorder: &mut DrawingEdit, + 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_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] fn add_dot_with_infringables + GetLayer>( &mut self, + recorder: &mut DrawingEdit, weight: W, infringables: Option<&[PrimitiveIndex]>, ) -> Result, Infringement> where GenericIndex: Into + Copy, { - let dot = self.add_dot_infringably(weight); - self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; + let dot = self.add_dot_infringably(recorder, weight); + self.fail_and_remove_if_infringes_except(recorder, dot.into(), infringables)?; Ok(dot) } @@ -195,22 +226,24 @@ impl Drawing { #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn add_fixed_seg( &mut self, + recorder: &mut DrawingEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> Result { - 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().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] pub fn add_fixed_seg_infringably( &mut self, + recorder: &mut DrawingEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> 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))] @@ -219,11 +252,13 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { - 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) } @@ -233,11 +268,12 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { - 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) } @@ -247,6 +283,7 @@ impl Drawing { #[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 + GetLayer>( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, to: DotIndex, weight: W, @@ -255,8 +292,8 @@ impl Drawing { where GenericIndex: Into + Copy, { - let seg = self.add_seg_infringably(from, to, weight); - self.fail_and_remove_if_infringes_except(seg.into(), infringables)?; + let seg = self.add_seg_infringably(recorder, from, to, weight); + self.fail_and_remove_if_infringes_except(recorder, seg.into(), infringables)?; Ok(seg) } @@ -268,6 +305,7 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, from: LooseDotIndex, to: LooseDotIndex, around: GearIndex, @@ -294,13 +332,34 @@ impl Drawing { match around { 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), 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), 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), } } @@ -311,6 +370,7 @@ impl Drawing { #[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 + GetLayer>( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, to: DotIndex, core: FixedDotIndex, @@ -320,11 +380,11 @@ impl Drawing { where GenericIndex: Into + Copy, { - let bend = self - .geometry_with_rtree - .add_bend(from, to, core.into(), weight); + let bend = + self.recording_geometry_with_rtree + .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) } @@ -334,6 +394,7 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, from: LooseDotIndex, to: LooseDotIndex, inner: BendIndex, @@ -341,15 +402,15 @@ impl Drawing { infringables: Option<&[PrimitiveIndex]>, ) -> Result, Infringement> { let core = *self - .geometry_with_rtree + .recording_geometry_with_rtree .graph() .neighbors(inner.petgraph_index()) .filter(|ni| { matches!( - self.geometry_with_rtree + self.recording_geometry_with_rtree .graph() .edge_weight( - self.geometry_with_rtree + self.recording_geometry_with_rtree .graph() .find_edge(inner.petgraph_index(), *ni) .unwrap() @@ -363,29 +424,42 @@ impl Drawing { .first() .unwrap(); - let bend = self - .geometry_with_rtree - .add_bend(from.into(), to.into(), core.into(), weight); - self.geometry_with_rtree - .reattach_bend(bend.into(), Some(inner)); + let bend = self.recording_geometry_with_rtree.add_bend( + recorder, + from.into(), + to.into(), + 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) } #[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()))] - pub fn flip_bend(&mut self, bend: FixedBendIndex) { - self.geometry_with_rtree.flip_bend(bend.into()); + pub fn flip_bend(&mut self, recorder: &mut DrawingEdit, bend: FixedBendIndex) { + 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().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))] - fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option) { - self.geometry_with_rtree - .reattach_bend(bend.into(), maybe_new_inner.map(Into::into)); + fn reattach_bend( + &mut self, + recorder: &mut DrawingEdit, + bend: LooseBendIndex, + maybe_new_inner: Option, + ) { + 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))] @@ -394,6 +468,7 @@ impl Drawing { #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn insert_cane( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -403,6 +478,7 @@ impl Drawing { ) -> Result { let maybe_next_gear = around.ref_(self).next_gear(); let cane = self.add_cane_with_infringables( + recorder, from, around, dot_weight, @@ -413,21 +489,22 @@ impl Drawing { )?; 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() { - self.update_this_and_outward_bows(outer).map_err(|err| { - let joint = self.primitive(cane.bend).other_joint(cane.dot); - self.remove_cane(&cane, joint); - err - })?; + self.update_this_and_outward_bows(recorder, outer) + .map_err(|err| { + let joint = self.primitive(cane.bend).other_joint(cane.dot); + self.remove_cane(recorder, &cane, joint); + err + })?; } // Segs must not cross. if let Some(collision) = self.detect_collision(cane.seg.into()) { let joint = self.primitive(cane.bend).other_joint(cane.dot); - self.remove_cane(&cane, joint); + self.remove_cane(recorder, &cane, joint); Err(collision.into()) } else { Ok(cane) @@ -438,6 +515,7 @@ impl Drawing { #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] fn update_this_and_outward_bows( &mut self, + recorder: &mut DrawingEdit, around: LooseBendIndex, ) -> Result<(), DrawingException> { // FIXME: Fail gracefully on infringement. @@ -475,17 +553,20 @@ impl Drawing { ); self.move_dot_with_infringables( + recorder, joints.0.into(), from, Some(&self.collect().bend_outer_bows(rail)), )?; self.move_dot_with_infringables( + recorder, joints.1.into(), to, Some(&self.collect().bend_outer_bows(rail)), )?; self.shift_bend_with_infringables( + recorder, rail.into(), offset, Some(&self.collect().bend_outer_bows(rail)), @@ -517,17 +598,20 @@ impl Drawing { ); self.move_dot_with_infringables( + recorder, joints.0.into(), from, Some(&self.collect().bend_outer_bows(rail)), )?; self.move_dot_with_infringables( + recorder, joints.1.into(), to, Some(&self.collect().bend_outer_bows(rail)), )?; self.shift_bend_with_infringables( + recorder, rail.into(), offset, Some(&self.collect().bend_outer_bows(rail)), @@ -546,6 +630,7 @@ impl Drawing { #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn add_cane( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -554,6 +639,7 @@ impl Drawing { cw: bool, ) -> Result { self.add_cane_with_infringables( + recorder, from, around, dot_weight, @@ -570,6 +656,7 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -578,30 +665,43 @@ impl Drawing { cw: bool, infringables: Option<&[PrimitiveIndex]>, ) -> Result { - 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 - .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| { - self.geometry_with_rtree.remove_dot(seg_to.into()); + self.recording_geometry_with_rtree + .remove_dot(recorder, seg_to.into()); err })?; let to = self - .add_dot_with_infringables(dot_weight, infringables) + .add_dot_with_infringables(recorder, dot_weight, infringables) .map_err(|err| { - self.geometry_with_rtree.remove_seg(seg.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 })?; let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) }; 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| { - self.geometry_with_rtree.remove_dot(to.into()); - self.geometry_with_rtree.remove_seg(seg.into()); - self.geometry_with_rtree.remove_dot(seg_to.into()); + self.recording_geometry_with_rtree + .remove_dot(recorder, to.into()); + self.recording_geometry_with_rtree + .remove_seg(recorder, seg.into()); + self.recording_geometry_with_rtree + .remove_dot(recorder, seg_to.into()); err })?; @@ -613,25 +713,34 @@ impl Drawing { } #[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, + cane: &Cane, + face: LooseDotIndex, + ) { let maybe_outer = self.primitive(cane.bend).outer(); // Removing a loose bend affects its outer bends. 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.geometry_with_rtree.remove_seg(cane.seg.into()); + self.recording_geometry_with_rtree + .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 // 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.geometry_with_rtree.remove_dot(cane.dot.into()); + self.recording_geometry_with_rtree + .remove_dot(recorder, face.into()); + self.recording_geometry_with_rtree + .remove_dot(recorder, cane.dot.into()); 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 Drawing { #[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()))] - pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { + pub fn move_dot( + &mut self, + recorder: &mut DrawingEdit, + dot: DotIndex, + to: Point, + ) -> Result<(), Infringement> { match dot { - DotIndex::Fixed(..) => self.move_dot_with_infringables(dot, to, Some(&[])), - DotIndex::Loose(..) => 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(recorder, dot, to, Some(&[])), } } @@ -652,24 +766,32 @@ impl Drawing { #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] fn move_dot_with_infringables( &mut self, + recorder: &mut DrawingEdit, dot: DotIndex, to: Point, infringables: Option<&[PrimitiveIndex]>, ) -> Result<(), Infringement> { - let old_pos = self.geometry_with_rtree.geometry().dot_weight(dot).pos(); - self.geometry_with_rtree.move_dot(dot, to); + let old_pos = self + .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() { if let Some(infringement) = self.detect_infringement_except(limb, infringables) { // 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); } } if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) { // 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); } @@ -680,20 +802,23 @@ impl Drawing { #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] fn shift_bend_with_infringables( &mut self, + recorder: &mut DrawingEdit, bend: BendIndex, offset: f64, infringables: Option<&[PrimitiveIndex]>, ) -> Result<(), Infringement> { let old_offset = self - .geometry_with_rtree + .recording_geometry_with_rtree .geometry() .bend_weight(bend) .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) { // 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); } @@ -703,7 +828,7 @@ impl Drawing { fn detect_collision(&self, node: PrimitiveIndex) -> Option { let shape = node.primitive(self).shape(); - self.geometry_with_rtree + self.recording_geometry_with_rtree .rtree() .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) .filter_map(|wrapper| { @@ -724,18 +849,20 @@ impl Drawing { #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] fn add_dot_infringably + GetLayer>( &mut self, + recorder: &mut DrawingEdit, weight: W, ) -> GenericIndex where GenericIndex: Into + 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().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] fn add_seg_infringably + GetLayer>( &mut self, + recorder: &mut DrawingEdit, from: DotIndex, to: DotIndex, weight: W, @@ -743,7 +870,28 @@ impl Drawing { where GenericIndex: Into, { - 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, weight: CW) -> GenericIndex { + self.recording_geometry_with_rtree + .add_compound(recorder, weight) + } + + pub fn remove_compound(&mut self, recorder: &mut DrawingEdit, compound: GenericIndex) { + self.recording_geometry_with_rtree + .remove_compound(recorder, compound); + } + + pub fn add_to_compound( + &mut self, + recorder: &mut DrawingEdit, + primitive: GenericIndex, + compound: GenericIndex, + ) { + 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()))] @@ -751,16 +899,18 @@ impl Drawing { #[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( &mut self, + recorder: &mut DrawingEdit, node: PrimitiveIndex, maybe_except: Option<&[PrimitiveIndex]>, ) -> Result<(), Infringement> { if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { 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() { - self.geometry_with_rtree.remove_seg(seg); + self.recording_geometry_with_rtree.remove_seg(recorder, seg); } 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); } @@ -799,7 +949,7 @@ impl Drawing { .unwrap_or(0.0), ); - self.geometry_with_rtree + self.recording_geometry_with_rtree .rtree() .locate_in_envelope_intersecting( &limiting_shape.envelope_3d(0.0, node.primitive(self).layer()), @@ -832,7 +982,7 @@ impl Drawing { } pub fn primitive_nodes(&self) -> impl Iterator + '_ { - self.geometry_with_rtree + self.recording_geometry_with_rtree .rtree() .iter() .filter_map(|wrapper| { @@ -845,7 +995,7 @@ impl Drawing { } pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator + '_ { - self.geometry_with_rtree + self.recording_geometry_with_rtree .rtree() .locate_in_envelope_intersecting(&AABB::from_corners( [-f64::INFINITY, -f64::INFINITY, layer as f64], @@ -860,6 +1010,17 @@ impl Drawing { }) } + pub fn compound_weight(&self, compound: GenericIndex) -> CW { + self.recording_geometry_with_rtree.compound_weight(compound) + } + + pub fn compounds<'a, W: 'a>( + &'a self, + node: GenericIndex, + ) -> impl Iterator> + 'a { + self.recording_geometry_with_rtree.compounds(node) + } + fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { if let (Some(node1_net_id), Some(node2_net_id)) = ( node1.primitive(self).maybe_net(), @@ -884,11 +1045,11 @@ impl Drawing { SegIndex, BendIndex, > { - self.geometry_with_rtree.geometry() + self.recording_geometry_with_rtree.geometry() } pub fn rtree(&self) -> &RTree>>> { - 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()))] @@ -914,11 +1075,11 @@ impl Drawing { } 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 { - 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 { @@ -958,26 +1119,3 @@ impl Drawing { }) } } - -impl ManageCompounds> for Drawing { - fn add_compound(&mut self, weight: CW) -> GenericIndex { - self.geometry_with_rtree.add_compound(weight) - } - - fn remove_compound(&mut self, compound: GenericIndex) { - self.geometry_with_rtree.remove_compound(compound); - } - - fn add_to_compound(&mut self, primitive: GenericIndex, compound: GenericIndex) { - self.geometry_with_rtree - .add_to_compound(primitive, compound); - } - - fn compound_weight(&self, compound: GenericIndex) -> CW { - self.geometry_with_rtree.compound_weight(compound) - } - - fn compounds(&self, node: GenericIndex) -> impl Iterator> { - self.geometry_with_rtree.compounds(node) - } -} diff --git a/src/drawing/seg.rs b/src/drawing/seg.rs index a353f8c..261e405 100644 --- a/src/drawing/seg.rs +++ b/src/drawing/seg.rs @@ -14,7 +14,7 @@ use crate::{ use petgraph::stable_graph::NodeIndex; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SegIndex { Fixed(FixedSegIndex), LoneLoose(LoneLooseSegIndex), diff --git a/src/geometry/recording_with_rtree.rs b/src/geometry/recording_with_rtree.rs index 4da5203..7c22e0f 100644 --- a/src/geometry/recording_with_rtree.rs +++ b/src/geometry/recording_with_rtree.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, hash::Hash, marker::PhantomData}; use geo::Point; use petgraph::stable_graph::StableDiGraph; +use rstar::RTree; use crate::{ drawing::graph::{GetLayer, Retag}, @@ -9,10 +10,13 @@ use crate::{ }; use super::{ - compound::ManageCompounds, with_rtree::GeometryWithRtree, AccessBendWeight, AccessDotWeight, - AccessSegWeight, GenericNode, GeometryLabel, GetWidth, + compound::ManageCompounds, + with_rtree::{BboxedIndex, GeometryWithRtree}, + AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, + GetWidth, }; +#[derive(Debug)] pub struct GeometryEdit< PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, DW: AccessDotWeight + GetLayer, @@ -31,6 +35,30 @@ pub struct GeometryEdit< primitive_weight_marker: PhantomData, } +impl< + PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + GetLayer, + SW: AccessSegWeight + GetLayer, + BW: AccessBendWeight + GetLayer, + CW: Copy, + PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Hash + Copy, + DI: GetPetgraphIndex + Into + Eq + Hash + Copy, + SI: GetPetgraphIndex + Into + Eq + Hash + Copy, + BI: GetPetgraphIndex + Into + Eq + Hash + Copy, + > GeometryEdit +{ + 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< PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, DW: AccessDotWeight + GetLayer, @@ -57,6 +85,14 @@ impl< BI: GetPetgraphIndex + Into + Eq + Hash + Copy, > RecordingGeometryWithRtree { + pub fn new(layer_count: usize) -> Self { + Self { + geometry_with_rtree: GeometryWithRtree::::new( + layer_count, + ), + } + } + pub fn add_dot + GetLayer>( &mut self, recorder: &mut GeometryEdit, @@ -349,6 +385,18 @@ impl< self.geometry_with_rtree.compounds(node) } + pub fn geometry(&self) -> &Geometry { + self.geometry_with_rtree.geometry() + } + + pub fn rtree(&self) -> &RTree>>> { + self.geometry_with_rtree.rtree() + } + + pub fn layer_count(&self) -> usize { + *self.geometry_with_rtree.layer_count() + } + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { self.geometry_with_rtree.graph() } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 38aa264..b7cc30e 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -17,9 +17,9 @@ use crate::{ FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight, }, - Drawing, DrawingException, Infringement, + Drawing, DrawingEdit, DrawingException, Infringement, }, - geometry::{compound::ManageCompounds, GenericNode}, + geometry::GenericNode, graph::{GenericIndex, GetPetgraphIndex}, layout::{ poly::{Poly, PolyWeight}, @@ -39,6 +39,7 @@ pub enum CompoundWeight { /// The alias to differ node types pub type NodeIndex = GenericNode>; +pub type LayoutEdit = DrawingEdit; #[derive(Debug, Getters)] /// Structure for managing the Layout design @@ -54,46 +55,61 @@ impl Layout { /// Insert [`Cane`] object into the [`Layout`] pub fn insert_cane( &mut self, - from: DotIndex, + recorder: &mut LayoutEdit, + from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, cw: bool, ) -> Result { - self.drawing - .insert_cane(from, around, dot_weight, seg_weight, bend_weight, cw) + self.drawing.insert_cane( + recorder, + from, + around, + dot_weight, + seg_weight, + bend_weight, + cw, + ) } - + /// Remove [`Cane`] object from the [`Layout`] - pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) { - self.drawing.remove_cane(cane, face) + pub fn remove_cane(&mut self, recorder: &mut LayoutEdit, cane: &Cane, face: LooseDotIndex) { + 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_err() -> self.drawing.node_count() == old(self.drawing.node_count()))] /// Insert [`Via`] into the [`Layout`] - pub fn add_via(&mut self, weight: ViaWeight) -> Result, Infringement> { - let compound = self.drawing.add_compound(weight.into()); + pub fn add_via( + &mut self, + recorder: &mut LayoutEdit, + weight: ViaWeight, + ) -> Result, Infringement> { + let compound = self.drawing.add_compound(recorder, weight.into()); let mut dots = vec![]; for layer in weight.from_layer..=weight.to_layer { - match self.drawing.add_fixed_dot(FixedDotWeight { - circle: weight.circle, - layer, - maybe_net: weight.maybe_net, - }) { + match self.drawing.add_fixed_dot( + recorder, + FixedDotWeight { + circle: weight.circle, + layer, + maybe_net: weight.maybe_net, + }, + ) { Ok(dot) => { - self.drawing.add_to_compound(dot, compound); + self.drawing.add_to_compound(recorder, dot, compound); dots.push(dot); } Err(err) => { // Remove inserted dots. - self.drawing.remove_compound(compound); + self.drawing.remove_compound(recorder, compound); for dot in dots.iter().rev() { - self.drawing.remove_fixed_dot(*dot); + self.drawing.remove_fixed_dot(recorder, *dot); } return Err(err); @@ -104,24 +120,32 @@ impl Layout { Ok(GenericIndex::::new(compound.petgraph_index())) } - - pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result { - self.drawing.add_fixed_dot(weight) + pub fn add_fixed_dot( + &mut self, + recorder: &mut LayoutEdit, + weight: FixedDotWeight, + ) -> Result { + self.drawing.add_fixed_dot(recorder, weight) } - pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { - self.drawing.add_fixed_dot_infringably(weight) + pub fn add_fixed_dot_infringably( + &mut self, + recorder: &mut LayoutEdit, + weight: FixedDotWeight, + ) -> FixedDotIndex { + self.drawing.add_fixed_dot_infringably(recorder, weight) } pub fn add_poly_fixed_dot( &mut self, + recorder: &mut LayoutEdit, weight: FixedDotWeight, poly: GenericIndex, ) -> Result { - 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 { - self.drawing.add_to_compound(dot, poly.into()); + self.drawing.add_to_compound(recorder, dot, poly.into()); } maybe_dot @@ -129,43 +153,48 @@ impl Layout { pub fn add_poly_fixed_dot_infringably( &mut self, + recorder: &mut LayoutEdit, weight: FixedDotWeight, poly: GenericIndex, ) -> FixedDotIndex { - let dot = self.drawing.add_fixed_dot_infringably(weight); - self.drawing.add_to_compound(dot, poly.into()); + let dot = self.drawing.add_fixed_dot_infringably(recorder, weight); + self.drawing.add_to_compound(recorder, dot, poly.into()); dot } pub fn add_fixed_seg( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> Result { - self.drawing.add_fixed_seg(from, to, weight) + self.drawing.add_fixed_seg(recorder, from, to, weight) } pub fn add_fixed_seg_infringably( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> 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( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, poly: GenericIndex, ) -> Result { - 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 { - self.drawing.add_to_compound(seg, poly.into()); + self.drawing.add_to_compound(recorder, seg, poly.into()); } maybe_seg @@ -173,48 +202,64 @@ impl Layout { pub fn add_poly_fixed_seg_infringably( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, poly: GenericIndex, ) -> FixedSegIndex { - let seg = self.add_fixed_seg_infringably(from, to, weight); - self.drawing.add_to_compound(seg, poly.into()); + let seg = self.add_fixed_seg_infringably(recorder, from, to, weight); + self.drawing.add_to_compound(recorder, seg, poly.into()); seg } pub fn add_lone_loose_seg( &mut self, + recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { - 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( &mut self, + recorder: &mut LayoutEdit, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { - 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> { - self.drawing.move_dot(dot, to) + pub fn move_dot( + &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 { + pub fn add_poly( + &mut self, + recorder: &mut LayoutEdit, + weight: PolyWeight, + ) -> GenericIndex { GenericIndex::::new( self.drawing - .add_compound(CompoundWeight::Poly(weight)) + .add_compound(recorder, CompoundWeight::Poly(weight)) .petgraph_index(), ) } - pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> { - self.drawing.remove_band(band) + pub fn remove_band( + &mut self, + recorder: &mut LayoutEdit, + band: BandTermsegIndex, + ) -> Result<(), DrawingException> { + self.drawing.remove_band(recorder, band) } pub fn polys( diff --git a/src/layout/poly.rs b/src/layout/poly.rs index 5d0b410..d6e7818 100644 --- a/src/layout/poly.rs +++ b/src/layout/poly.rs @@ -12,7 +12,7 @@ use crate::{ rules::AccessRules, seg::SegIndex, }, - geometry::{compound::ManageCompounds, poly::PolyShape, GetPos}, + geometry::{poly::PolyShape, GetPos}, graph::{GenericIndex, GetPetgraphIndex}, layout::{CompoundWeight, Layout}, }; diff --git a/src/layout/via.rs b/src/layout/via.rs index 2ab7437..db7b177 100644 --- a/src/layout/via.rs +++ b/src/layout/via.rs @@ -4,10 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{ drawing::{graph::GetMaybeNet, primitive::MakePrimitiveShape, rules::AccessRules}, - geometry::{ - compound::ManageCompounds, - primitive::{DotShape, PrimitiveShape}, - }, + geometry::primitive::{DotShape, PrimitiveShape}, graph::{GenericIndex, GetPetgraphIndex}, layout::{CompoundWeight, Layout}, math::Circle, diff --git a/src/router/draw.rs b/src/router/draw.rs index aff3f20..d3f785a 100644 --- a/src/router/draw.rs +++ b/src/router/draw.rs @@ -16,7 +16,7 @@ use crate::{ seg::{LoneLooseSegWeight, SeqLooseSegWeight}, DrawingException, Infringement, }, - layout::Layout, + layout::{Layout, LayoutEdit}, math::{Circle, NoTangents}, }; @@ -66,6 +66,7 @@ impl<'a, R: AccessRules> Draw<'a, R> { DotIndex::Fixed(dot) => BandTermsegIndex::Straight( self.layout .add_lone_loose_seg( + &mut LayoutEdit::new(), dot, into, LoneLooseSegWeight { @@ -79,6 +80,7 @@ impl<'a, R: AccessRules> Draw<'a, R> { DotIndex::Loose(dot) => BandTermsegIndex::Bended( self.layout .add_seq_loose_seg( + &mut LayoutEdit::new(), into.into(), dot, 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()))] fn extend_head(&mut self, head: Head, to: Point) -> Result { 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)) } else { Ok(head) @@ -185,6 +188,7 @@ impl<'a, R: AccessRules> Draw<'a, R> { let layer = head.face().primitive(self.layout.drawing()).layer(); let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net(); let cane = self.layout.insert_cane( + &mut LayoutEdit::new(), head.face(), around, LooseDotWeight { @@ -227,7 +231,8 @@ impl<'a, R: AccessRules> Draw<'a, R> { .primitive(head.cane.seg) .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)) } diff --git a/src/specctra/design.rs b/src/specctra/design.rs index f77d8de..ae4b19f 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -16,7 +16,7 @@ use crate::{ Drawing, }, geometry::{primitive::PrimitiveShape, GetWidth}, - layout::{poly::SolidPolyWeight, Layout}, + layout::{poly::SolidPolyWeight, Layout, LayoutEdit}, math::{Circle, PointWithRotation}, specctra::{ mesadata::SpecctraMesadata, @@ -185,7 +185,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) -> Board { + pub fn make_board(&self, recorder: &mut LayoutEdit) -> Board { let mesadata = SpecctraMesadata::from_pcb(&self.pcb); let mut board = Board::new(Layout::new(Drawing::new( mesadata, @@ -210,11 +210,7 @@ impl SpecctraDesign { net_pin_assignments.pins.as_ref().and_then(|pins| { // take the list of pins // and for each pin output (pin name, net id) - Some(pins - .names - .iter() - .map(move |pinname| (pinname.clone(), net)) - ) + Some(pins.names.iter().map(move |pinname| (pinname.clone(), net))) }) }) // flatten the nested iters into a single stream of tuples @@ -248,6 +244,7 @@ impl SpecctraDesign { Shape::Circle(circle) => { let layer = get_layer(&board, &circle.layer); Self::add_circle( + recorder, &mut board, place.point_with_rotation(), pin.point_with_rotation(), @@ -260,6 +257,7 @@ impl SpecctraDesign { Shape::Rect(rect) => { let layer = get_layer(&board, &rect.layer); Self::add_rect( + recorder, &mut board, place.point_with_rotation(), pin.point_with_rotation(), @@ -275,6 +273,7 @@ impl SpecctraDesign { Shape::Path(path) => { let layer = get_layer(&board, &path.layer); Self::add_path( + recorder, &mut board, place.point_with_rotation(), pin.point_with_rotation(), @@ -288,6 +287,7 @@ impl SpecctraDesign { Shape::Polygon(polygon) => { let layer = get_layer(&board, &polygon.layer); Self::add_polygon( + recorder, &mut board, place.point_with_rotation(), pin.point_with_rotation(), @@ -305,11 +305,7 @@ impl SpecctraDesign { } for via in &self.pcb.wiring.vias { - let net = board - .layout() - .drawing() - .rules() - .netname_net(&via.net); + let net = board.layout().drawing().rules().netname_net(&via.net); let padstack = self.pcb.library.find_padstack_by_name(&via.name).unwrap(); @@ -322,6 +318,7 @@ impl SpecctraDesign { Shape::Circle(circle) => { let layer = get_layer(&board, &circle.layer); Self::add_circle( + recorder, &mut board, // TODO: refactor? // should this call take PointWithRotation? @@ -336,6 +333,7 @@ impl SpecctraDesign { Shape::Rect(rect) => { let layer = get_layer(&board, &rect.layer); Self::add_rect( + recorder, &mut board, PointWithRotation::from_xy(via.x, via.y), PointWithRotation::default(), @@ -351,6 +349,7 @@ impl SpecctraDesign { Shape::Path(path) => { let layer = get_layer(&board, &path.layer); Self::add_path( + recorder, &mut board, PointWithRotation::from_xy(via.x, via.y), PointWithRotation::default(), @@ -364,6 +363,7 @@ impl SpecctraDesign { Shape::Polygon(polygon) => { let layer = get_layer(&board, &polygon.layer); Self::add_polygon( + recorder, &mut board, PointWithRotation::from_xy(via.x, via.y), PointWithRotation::default(), @@ -385,13 +385,10 @@ impl SpecctraDesign { .rules() .layername_layer(&wire.path.layer) .unwrap(); - let net = board - .layout() - .drawing() - .rules() - .netname_net(&wire.net); + let net = board.layout().drawing().rules().netname_net(&wire.net); Self::add_path( + recorder, &mut board, PointWithRotation::default(), PointWithRotation::default(), @@ -427,6 +424,7 @@ impl SpecctraDesign { } fn add_circle( + recorder: &mut LayoutEdit, board: &mut Board, place: PointWithRotation, pin: PointWithRotation, @@ -441,6 +439,7 @@ impl SpecctraDesign { }; board.add_fixed_dot_infringably( + recorder, FixedDotWeight { circle, layer, @@ -451,6 +450,7 @@ impl SpecctraDesign { } fn add_rect( + recorder: &mut LayoutEdit, board: &mut Board, place: PointWithRotation, pin: PointWithRotation, @@ -463,16 +463,14 @@ impl SpecctraDesign { maybe_pin: Option, ) { let poly = board.add_poly( - SolidPolyWeight { - layer, - maybe_net, - } - .into(), + recorder, + SolidPolyWeight { layer, maybe_net }.into(), maybe_pin.clone(), ); // Corners. let dot_1_1 = board.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: Self::pos(place, pin, x1, y1), @@ -484,6 +482,7 @@ impl SpecctraDesign { poly, ); let dot_2_1 = board.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: Self::pos(place, pin, x2, y1), @@ -495,6 +494,7 @@ impl SpecctraDesign { poly, ); let dot_2_2 = board.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: Self::pos(place, pin, x2, y2), @@ -506,6 +506,7 @@ impl SpecctraDesign { poly, ); let dot_1_2 = board.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: Self::pos(place, pin, x1, y2), @@ -518,6 +519,7 @@ impl SpecctraDesign { ); // Sides. board.add_poly_fixed_seg_infringably( + recorder, dot_1_1, dot_2_1, FixedSegWeight { @@ -528,6 +530,7 @@ impl SpecctraDesign { poly, ); board.add_poly_fixed_seg_infringably( + recorder, dot_2_1, dot_2_2, FixedSegWeight { @@ -538,6 +541,7 @@ impl SpecctraDesign { poly, ); board.add_poly_fixed_seg_infringably( + recorder, dot_2_2, dot_1_2, FixedSegWeight { @@ -548,6 +552,7 @@ impl SpecctraDesign { poly, ); board.add_poly_fixed_seg_infringably( + recorder, dot_1_2, dot_1_1, FixedSegWeight { @@ -560,6 +565,7 @@ impl SpecctraDesign { } fn add_path( + recorder: &mut LayoutEdit, board: &mut Board, place: PointWithRotation, pin: PointWithRotation, @@ -572,6 +578,7 @@ impl SpecctraDesign { // 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_index = board.add_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: prev_pos, @@ -592,6 +599,7 @@ impl SpecctraDesign { } let index = board.add_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos, @@ -605,6 +613,7 @@ impl SpecctraDesign { // add a seg between the current and previous coords let _ = board.add_fixed_seg_infringably( + recorder, prev_index, index, FixedSegWeight { @@ -621,6 +630,7 @@ impl SpecctraDesign { } fn add_polygon( + recorder: &mut LayoutEdit, board: &mut Board, place: PointWithRotation, pin: PointWithRotation, @@ -631,16 +641,14 @@ impl SpecctraDesign { maybe_pin: Option, ) { let poly = board.add_poly( - SolidPolyWeight { - layer, - maybe_net, - } - .into(), + recorder, + SolidPolyWeight { layer, maybe_net }.into(), maybe_pin.clone(), ); // 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( + recorder, FixedDotWeight { circle: Circle { 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 for coord in coords.iter().skip(1) { let index = board.add_poly_fixed_dot_infringably( + recorder, FixedDotWeight { circle: Circle { pos: Self::pos(place, pin, coord.x, coord.y), @@ -671,6 +680,7 @@ impl SpecctraDesign { // add a seg between the current and previous coords let _ = board.add_poly_fixed_seg_infringably( + recorder, prev_index, index, FixedSegWeight { diff --git a/src/specctra/mesadata.rs b/src/specctra/mesadata.rs index a5abc4d..da0e6b7 100644 --- a/src/specctra/mesadata.rs +++ b/src/specctra/mesadata.rs @@ -86,11 +86,7 @@ impl SpecctraMesadata { .classes .iter() .flat_map(|class| &class.nets) - .chain( - pcb.network.nets - .iter() - .map(|net| &net.name) - ) + .chain(pcb.network.nets.iter().map(|net| &net.name)) .enumerate() .map(|(net, netname)| (net, netname.clone())), ); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 10a6150..1a722d1 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -11,6 +11,7 @@ use topola::{ drawing::graph::{GetLayer, GetMaybeNet}, geometry::shape::MeasureLength, graph::{GetPetgraphIndex, MakeRef}, + layout::LayoutEdit, specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, }; @@ -18,7 +19,8 @@ pub fn load_design_and_assert(filename: &str) -> Invoker { let design_file = File::open(filename).unwrap(); let design_bufread = BufReader::new(design_file); 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!( invoker.undo(),