From afe4c586b52c691d1c580beac51839a7a6d8926d Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Thu, 18 Jan 2024 00:43:32 +0000 Subject: [PATCH] layout: implement removal of bands --- src/connectivity.rs | 3 +- src/layout.rs | 84 +++++++++++++++++++++++++++++++++++++++++---- src/loose.rs | 26 ++++++++++---- src/main.rs | 26 +++++++++++--- src/primitive.rs | 63 +++++++++++++++++++++------------- src/router.rs | 9 +++-- src/tracer.rs | 2 +- 7 files changed, 167 insertions(+), 46 deletions(-) diff --git a/src/connectivity.rs b/src/connectivity.rs index 79cfef8..138032f 100644 --- a/src/connectivity.rs +++ b/src/connectivity.rs @@ -1,7 +1,7 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::StableDiGraph; -use crate::graph::GenericIndex; +use crate::{geometry::FixedDotIndex, graph::GenericIndex}; #[enum_dispatch] pub trait GetNet { @@ -34,6 +34,7 @@ pub type ComponentIndex = GenericIndex; pub struct BandWeight { pub net: i64, pub width: f64, + pub from: FixedDotIndex, } impl GetNet for BandWeight { diff --git a/src/layout.rs b/src/layout.rs index 048c0be..c9d4f3a 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -20,6 +20,7 @@ use crate::geometry::{ }; use crate::graph::{GenericIndex, GetNodeIndex}; use crate::guide::Guide; +use crate::loose::{GetNextLoose, Loose, LooseIndex}; use crate::math::NoTangents; use crate::primitive::{ GenericPrimitive, GetConnectable, GetCore, GetEnds, GetInnerOuter, GetOtherEnd, GetWeight, @@ -75,6 +76,62 @@ impl Layout { } } + pub fn remove_band(&mut self, band: BandIndex) { + let mut dots = vec![]; + let mut segs = vec![]; + let mut bends = vec![]; + let mut outers = vec![]; + + let from = self.band_weight(band).from; + let mut maybe_loose = self.primitive(from).first_loose(band); + let mut prev = None; + + while let Some(loose) = maybe_loose { + match loose { + LooseIndex::Dot(dot) => { + dots.push(dot); + } + LooseIndex::LoneSeg(..) => { + unreachable!(); + } + LooseIndex::SeqSeg(seg) => { + segs.push(seg); + } + LooseIndex::Bend(bend) => { + bends.push(bend); + + if let Some(outer) = self.primitive(bend).outer() { + outers.push(outer); + self.reattach_bend(outer, self.primitive(bend).inner()); + } + } + } + + let prev_prev = prev; + prev = maybe_loose; + maybe_loose = self.loose(loose).next_loose(prev_prev); + } + + for bend in bends { + self.remove(bend.into()); + } + + for seg in segs { + self.remove(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.remove(dot.into()); + } + + for outer in outers { + self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. + } + } + #[debug_ensures(self.geometry.node_count() == old(self.geometry.node_count() - 4))] pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { let maybe_outer = self.primitive(segbend.bend).outer(); @@ -126,6 +183,7 @@ impl Layout { .add_node(ConnectivityWeight::Band(BandWeight { width, net: self.primitive(from).net(), + from, })), ) } @@ -547,11 +605,7 @@ impl Layout { infringables: &[GeometryIndex], ) -> Result { // It makes no sense to wrap something around or under one of its connectables. - let net = self - .connectivity - .node_weight(weight.band.node_index()) - .unwrap() - .net(); + let net = self.band_weight(weight.band).net(); // if net == around.primitive(self).net() { return Err(AlreadyConnected(net, around.into()).into()); @@ -841,10 +895,28 @@ impl Layout { #[debug_ensures(self.geometry.node_count() == old(self.geometry.node_count()))] #[debug_ensures(self.geometry.edge_count() == old(self.geometry.edge_count()))] - pub fn wraparoundable(&self, node: WraparoundableIndex) -> Wraparoundable { + fn wraparoundable(&self, node: WraparoundableIndex) -> Wraparoundable { Wraparoundable::new(node, self) } + #[debug_ensures(self.geometry.node_count() == old(self.geometry.node_count()))] + #[debug_ensures(self.geometry.edge_count() == old(self.geometry.edge_count()))] + fn loose(&self, node: LooseIndex) -> Loose { + Loose::new(node, self) + } + + #[debug_ensures(self.geometry.node_count() == old(self.geometry.node_count()))] + #[debug_ensures(self.geometry.edge_count() == old(self.geometry.edge_count()))] + fn band_weight(&self, band: BandIndex) -> BandWeight { + if let Some(ConnectivityWeight::Band(band_weight)) = + self.connectivity.node_weight(band.node_index()) + { + *band_weight + } else { + unreachable!() + } + } + fn test_envelopes(&self) -> bool { !self.rtree.iter().any(|wrapper| { let node = wrapper.data; diff --git a/src/loose.rs b/src/loose.rs index 052b6eb..5c0a155 100644 --- a/src/loose.rs +++ b/src/loose.rs @@ -11,8 +11,9 @@ use crate::{ primitive::{GetEnds, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg}, }; +#[enum_dispatch] pub trait GetNextLoose { - fn next(&self, prev: GeometryIndex) -> Option; + fn next_loose(&self, maybe_prev: Option) -> Option; } #[enum_dispatch(GetNodeIndex, MakePrimitive)] @@ -55,26 +56,33 @@ impl<'a> Loose<'a> { } impl<'a> GetNextLoose for LooseDot<'a> { - fn next(&self, prev: GeometryIndex) -> Option { + fn next_loose(&self, maybe_prev: Option) -> Option { let bend = self.bend(); + let Some(prev) = maybe_prev else { + unreachable!(); + }; if bend.node_index() != prev.node_index() { - self.seg().map(Into::into) - } else { Some(bend.into()) + } else { + self.seg().map(Into::into) } } } impl<'a> GetNextLoose for LoneLooseSeg<'a> { - fn next(&self, _prev: GeometryIndex) -> Option { + fn next_loose(&self, _maybe_prev: Option) -> Option { None } } impl<'a> GetNextLoose for SeqLooseSeg<'a> { - fn next(&self, prev: GeometryIndex) -> Option { + fn next_loose(&self, maybe_prev: Option) -> Option { let ends = self.ends(); + let Some(prev) = maybe_prev else { + return Some(ends.1.into()); + }; + if ends.0.node_index() != prev.node_index() { match ends.0 { DotIndex::Fixed(..) => None, @@ -87,8 +95,12 @@ impl<'a> GetNextLoose for SeqLooseSeg<'a> { } impl<'a> GetNextLoose for LooseBend<'a> { - fn next(&self, prev: GeometryIndex) -> Option { + fn next_loose(&self, maybe_prev: Option) -> Option { let ends = self.ends(); + let Some(prev) = maybe_prev else { + unreachable!(); + }; + if ends.0.node_index() != prev.node_index() { Some(ends.0.into()) } else { diff --git a/src/main.rs b/src/main.rs index 6c870dc..e41aa4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -494,7 +494,7 @@ fn main() -> Result<(), anyhow::Error> { -1, );*/ - let _ = router.enroute( + let _ = router.route_band( dot_start, dot_end, &mut EmptyRouterObserver, @@ -527,7 +527,7 @@ fn main() -> Result<(), anyhow::Error> { -1, );*/ - let _ = router.enroute( + let band2 = router.route_band( dot_start2, dot_end2, &mut EmptyRouterObserver, @@ -549,10 +549,11 @@ fn main() -> Result<(), anyhow::Error> { -1, ); - let _ = router.enroute( + let band3 = router.route_band( dot_start3, dot_end3, - &mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context), + &mut EmptyRouterObserver, + //&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context), )?; render_times( @@ -570,6 +571,23 @@ fn main() -> Result<(), anyhow::Error> { -1, ); + router.layout.remove_band(band3); + + render_times( + &mut event_pump, + &window, + &mut renderer, + &font_context, + RouterOrLayout::Layout(&router.layout), + None, + None, + None, + &[], + &[], + &[], + -1, + ); + Ok(()) } diff --git a/src/primitive.rs b/src/primitive.rs index 649501c..54a3812 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -4,16 +4,16 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; use petgraph::Direction::{Incoming, Outgoing}; -use crate::connectivity::GetNet; +use crate::connectivity::{BandIndex, GetNet}; use crate::geometry::{ DotIndex, FixedBendWeight, FixedDotIndex, FixedDotWeight, FixedSegWeight, GeometryIndex, GeometryLabel, GeometryWeight, GetBandIndex, GetComponentIndex, GetOffset, GetWidth, - LoneLooseSegWeight, LooseBendIndex, LooseBendWeight, LooseDotIndex, LooseDotWeight, - MakePrimitive, Retag, SeqLooseSegIndex, SeqLooseSegWeight, + LoneLooseSegIndex, LoneLooseSegWeight, LooseBendIndex, LooseBendWeight, LooseDotIndex, + LooseDotWeight, MakePrimitive, Retag, SeqLooseSegIndex, SeqLooseSegWeight, }; use crate::graph::{GenericIndex, GetNodeIndex}; use crate::layout::Layout; -use crate::loose::Loose; +use crate::loose::{Loose, LooseIndex}; use crate::math::{self, Circle}; use crate::shape::{BendShape, DotShape, SegShape, Shape, ShapeTrait}; @@ -66,21 +66,21 @@ pub trait GetFirstRail: GetLayout + GetNodeIndex { self.layout() .geometry() .neighbors_directed(self.node_index(), Incoming) - .filter(|ni| { + .filter(|node| { matches!( self.layout() .geometry() .edge_weight( self.layout() .geometry() - .find_edge(*ni, self.node_index()) + .find_edge(*node, self.node_index()) .unwrap() ) .unwrap(), GeometryLabel::Core ) }) - .map(|ni| LooseBendIndex::new(ni)) + .map(|node| LooseBendIndex::new(node)) .next() } } @@ -90,21 +90,21 @@ pub trait GetCore: GetLayout + GetNodeIndex { self.layout() .geometry() .neighbors(self.node_index()) - .filter(|ni| { + .filter(|node| { matches!( self.layout() .geometry() .edge_weight( self.layout() .geometry() - .find_edge(self.node_index(), *ni) + .find_edge(self.node_index(), *node) .unwrap() ) .unwrap(), GeometryLabel::Core ) }) - .map(|ni| FixedDotIndex::new(ni)) + .map(|node| FixedDotIndex::new(node)) .next() .unwrap() } @@ -115,21 +115,21 @@ pub trait GetInnerOuter: GetLayout + GetNodeIndex { self.layout() .geometry() .neighbors_directed(self.node_index(), Incoming) - .filter(|ni| { + .filter(|node| { matches!( self.layout() .geometry() .edge_weight( self.layout() .geometry() - .find_edge(*ni, self.node_index()) + .find_edge(*node, self.node_index()) .unwrap() ) .unwrap(), GeometryLabel::Outer ) }) - .map(|ni| LooseBendIndex::new(ni)) + .map(|node| LooseBendIndex::new(node)) .next() } @@ -137,21 +137,21 @@ pub trait GetInnerOuter: GetLayout + GetNodeIndex { self.layout() .geometry() .neighbors_directed(self.node_index(), Outgoing) - .filter(|ni| { + .filter(|node| { matches!( self.layout() .geometry() .edge_weight( self.layout() .geometry() - .find_edge(self.node_index(), *ni) + .find_edge(self.node_index(), *node) .unwrap() ) .unwrap(), GeometryLabel::Outer ) }) - .map(|ni| LooseBendIndex::new(ni)) + .map(|node| LooseBendIndex::new(node)) .next() } } @@ -236,14 +236,14 @@ impl<'a, W> GenericPrimitive<'a, W> { self.layout .geometry() .neighbors_undirected(self.index.node_index()) - .filter(|ni| { + .filter(|node| { matches!( self.layout .geometry() .edge_weight( self.layout .geometry() - .find_edge_undirected(self.index.node_index(), *ni) + .find_edge_undirected(self.index.node_index(), *node) .unwrap() .0, ) @@ -291,6 +291,21 @@ where pub type FixedDot<'a> = GenericPrimitive<'a, FixedDotWeight>; impl_fixed_primitive!(FixedDot, FixedDotWeight); +impl<'a> FixedDot<'a> { + pub fn first_loose(&self, band: BandIndex) -> Option { + self.adjacents().into_iter().find_map(|node| { + let weight = self.layout.geometry().node_weight(node).unwrap(); + if matches!(weight, GeometryWeight::LoneLooseSeg(..)) { + Some(LoneLooseSegIndex::new(node).into()) + } else if matches!(weight, GeometryWeight::SeqLooseSeg(..)) { + Some(SeqLooseSegIndex::new(node).into()) + } else { + None + } + }) + } +} + impl<'a> MakeShape for FixedDot<'a> { fn shape(&self) -> Shape { Shape::Dot(DotShape { @@ -307,26 +322,26 @@ impl<'a> LooseDot<'a> { pub fn seg(&self) -> Option { self.adjacents() .into_iter() - .filter(|ni| { + .filter(|node| { matches!( - self.layout.geometry().node_weight(*ni).unwrap(), + self.layout.geometry().node_weight(*node).unwrap(), GeometryWeight::SeqLooseSeg(..) ) }) - .map(|ni| SeqLooseSegIndex::new(ni)) + .map(|node| SeqLooseSegIndex::new(node)) .next() } pub fn bend(&self) -> LooseBendIndex { self.adjacents() .into_iter() - .filter(|ni| { + .filter(|node| { matches!( - self.layout.geometry().node_weight(*ni).unwrap(), + self.layout.geometry().node_weight(*node).unwrap(), GeometryWeight::LooseBend(..) ) }) - .map(|ni| LooseBendIndex::new(ni)) + .map(|node| LooseBendIndex::new(node)) .next() .unwrap() } diff --git a/src/router.rs b/src/router.rs index 5c23ed1..7cec5d2 100644 --- a/src/router.rs +++ b/src/router.rs @@ -4,8 +4,10 @@ use spade::InsertionError; use thiserror::Error; use crate::astar::{astar, AstarStrategy, PathTracker}; +use crate::connectivity::BandIndex; use crate::draw::DrawException; use crate::geometry::FixedDotIndex; +use crate::guide::HeadTrait; use crate::layout::Layout; use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex}; @@ -111,12 +113,12 @@ impl Router { } } - pub fn enroute( + pub fn route_band( &mut self, from: FixedDotIndex, to: FixedDotIndex, observer: &mut impl RouterObserver, - ) -> Result { + ) -> Result { // XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look // right. //self.mesh.triangulate(&self.layout)?; @@ -129,6 +131,7 @@ impl Router { let mut tracer = self.tracer(&mesh); let trace = tracer.start(from, 3.0); + let band = trace.head.band(); let (_cost, _path) = astar( &mesh, @@ -141,7 +144,7 @@ impl Router { source: RoutingErrorKind::AStar, })?; - Ok(mesh) + Ok(band) } pub fn reroute( diff --git a/src/tracer.rs b/src/tracer.rs index 80a008e..3f15201 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -12,7 +12,7 @@ use crate::{ #[derive(Debug)] pub struct Trace { pub path: Vec, - head: Head, + pub head: Head, } pub struct Tracer<'a> {