layout: implement removal of bands

This commit is contained in:
Mikolaj Wielgus 2024-01-18 00:43:32 +00:00
parent 2d5de212d2
commit afe4c586b5
7 changed files with 167 additions and 46 deletions

View File

@ -1,7 +1,7 @@
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use petgraph::stable_graph::StableDiGraph; use petgraph::stable_graph::StableDiGraph;
use crate::graph::GenericIndex; use crate::{geometry::FixedDotIndex, graph::GenericIndex};
#[enum_dispatch] #[enum_dispatch]
pub trait GetNet { pub trait GetNet {
@ -34,6 +34,7 @@ pub type ComponentIndex = GenericIndex<ComponentWeight>;
pub struct BandWeight { pub struct BandWeight {
pub net: i64, pub net: i64,
pub width: f64, pub width: f64,
pub from: FixedDotIndex,
} }
impl GetNet for BandWeight { impl GetNet for BandWeight {

View File

@ -20,6 +20,7 @@ use crate::geometry::{
}; };
use crate::graph::{GenericIndex, GetNodeIndex}; use crate::graph::{GenericIndex, GetNodeIndex};
use crate::guide::Guide; use crate::guide::Guide;
use crate::loose::{GetNextLoose, Loose, LooseIndex};
use crate::math::NoTangents; use crate::math::NoTangents;
use crate::primitive::{ use crate::primitive::{
GenericPrimitive, GetConnectable, GetCore, GetEnds, GetInnerOuter, GetOtherEnd, GetWeight, 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))] #[debug_ensures(self.geometry.node_count() == old(self.geometry.node_count() - 4))]
pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) {
let maybe_outer = self.primitive(segbend.bend).outer(); let maybe_outer = self.primitive(segbend.bend).outer();
@ -126,6 +183,7 @@ impl Layout {
.add_node(ConnectivityWeight::Band(BandWeight { .add_node(ConnectivityWeight::Band(BandWeight {
width, width,
net: self.primitive(from).net(), net: self.primitive(from).net(),
from,
})), })),
) )
} }
@ -547,11 +605,7 @@ impl Layout {
infringables: &[GeometryIndex], infringables: &[GeometryIndex],
) -> Result<LooseBendIndex, LayoutException> { ) -> Result<LooseBendIndex, LayoutException> {
// It makes no sense to wrap something around or under one of its connectables. // It makes no sense to wrap something around or under one of its connectables.
let net = self let net = self.band_weight(weight.band).net();
.connectivity
.node_weight(weight.band.node_index())
.unwrap()
.net();
// //
if net == around.primitive(self).net() { if net == around.primitive(self).net() {
return Err(AlreadyConnected(net, around.into()).into()); 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.node_count() == old(self.geometry.node_count()))]
#[debug_ensures(self.geometry.edge_count() == old(self.geometry.edge_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) 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 { fn test_envelopes(&self) -> bool {
!self.rtree.iter().any(|wrapper| { !self.rtree.iter().any(|wrapper| {
let node = wrapper.data; let node = wrapper.data;

View File

@ -11,8 +11,9 @@ use crate::{
primitive::{GetEnds, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg}, primitive::{GetEnds, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg},
}; };
#[enum_dispatch]
pub trait GetNextLoose { pub trait GetNextLoose {
fn next(&self, prev: GeometryIndex) -> Option<LooseIndex>; fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex>;
} }
#[enum_dispatch(GetNodeIndex, MakePrimitive)] #[enum_dispatch(GetNodeIndex, MakePrimitive)]
@ -55,26 +56,33 @@ impl<'a> Loose<'a> {
} }
impl<'a> GetNextLoose for LooseDot<'a> { impl<'a> GetNextLoose for LooseDot<'a> {
fn next(&self, prev: GeometryIndex) -> Option<LooseIndex> { fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
let bend = self.bend(); let bend = self.bend();
let Some(prev) = maybe_prev else {
unreachable!();
};
if bend.node_index() != prev.node_index() { if bend.node_index() != prev.node_index() {
self.seg().map(Into::into)
} else {
Some(bend.into()) Some(bend.into())
} else {
self.seg().map(Into::into)
} }
} }
} }
impl<'a> GetNextLoose for LoneLooseSeg<'a> { impl<'a> GetNextLoose for LoneLooseSeg<'a> {
fn next(&self, _prev: GeometryIndex) -> Option<LooseIndex> { fn next_loose(&self, _maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
None None
} }
} }
impl<'a> GetNextLoose for SeqLooseSeg<'a> { impl<'a> GetNextLoose for SeqLooseSeg<'a> {
fn next(&self, prev: GeometryIndex) -> Option<LooseIndex> { fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
let ends = self.ends(); let ends = self.ends();
let Some(prev) = maybe_prev else {
return Some(ends.1.into());
};
if ends.0.node_index() != prev.node_index() { if ends.0.node_index() != prev.node_index() {
match ends.0 { match ends.0 {
DotIndex::Fixed(..) => None, DotIndex::Fixed(..) => None,
@ -87,8 +95,12 @@ impl<'a> GetNextLoose for SeqLooseSeg<'a> {
} }
impl<'a> GetNextLoose for LooseBend<'a> { impl<'a> GetNextLoose for LooseBend<'a> {
fn next(&self, prev: GeometryIndex) -> Option<LooseIndex> { fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
let ends = self.ends(); let ends = self.ends();
let Some(prev) = maybe_prev else {
unreachable!();
};
if ends.0.node_index() != prev.node_index() { if ends.0.node_index() != prev.node_index() {
Some(ends.0.into()) Some(ends.0.into())
} else { } else {

View File

@ -494,7 +494,7 @@ fn main() -> Result<(), anyhow::Error> {
-1, -1,
);*/ );*/
let _ = router.enroute( let _ = router.route_band(
dot_start, dot_start,
dot_end, dot_end,
&mut EmptyRouterObserver, &mut EmptyRouterObserver,
@ -527,7 +527,7 @@ fn main() -> Result<(), anyhow::Error> {
-1, -1,
);*/ );*/
let _ = router.enroute( let band2 = router.route_band(
dot_start2, dot_start2,
dot_end2, dot_end2,
&mut EmptyRouterObserver, &mut EmptyRouterObserver,
@ -549,10 +549,11 @@ fn main() -> Result<(), anyhow::Error> {
-1, -1,
); );
let _ = router.enroute( let band3 = router.route_band(
dot_start3, dot_start3,
dot_end3, 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( render_times(
@ -570,6 +571,23 @@ fn main() -> Result<(), anyhow::Error> {
-1, -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(()) Ok(())
} }

View File

@ -4,16 +4,16 @@ use enum_dispatch::enum_dispatch;
use petgraph::stable_graph::NodeIndex; use petgraph::stable_graph::NodeIndex;
use petgraph::Direction::{Incoming, Outgoing}; use petgraph::Direction::{Incoming, Outgoing};
use crate::connectivity::GetNet; use crate::connectivity::{BandIndex, GetNet};
use crate::geometry::{ use crate::geometry::{
DotIndex, FixedBendWeight, FixedDotIndex, FixedDotWeight, FixedSegWeight, GeometryIndex, DotIndex, FixedBendWeight, FixedDotIndex, FixedDotWeight, FixedSegWeight, GeometryIndex,
GeometryLabel, GeometryWeight, GetBandIndex, GetComponentIndex, GetOffset, GetWidth, GeometryLabel, GeometryWeight, GetBandIndex, GetComponentIndex, GetOffset, GetWidth,
LoneLooseSegWeight, LooseBendIndex, LooseBendWeight, LooseDotIndex, LooseDotWeight, LoneLooseSegIndex, LoneLooseSegWeight, LooseBendIndex, LooseBendWeight, LooseDotIndex,
MakePrimitive, Retag, SeqLooseSegIndex, SeqLooseSegWeight, LooseDotWeight, MakePrimitive, Retag, SeqLooseSegIndex, SeqLooseSegWeight,
}; };
use crate::graph::{GenericIndex, GetNodeIndex}; use crate::graph::{GenericIndex, GetNodeIndex};
use crate::layout::Layout; use crate::layout::Layout;
use crate::loose::Loose; use crate::loose::{Loose, LooseIndex};
use crate::math::{self, Circle}; use crate::math::{self, Circle};
use crate::shape::{BendShape, DotShape, SegShape, Shape, ShapeTrait}; use crate::shape::{BendShape, DotShape, SegShape, Shape, ShapeTrait};
@ -66,21 +66,21 @@ pub trait GetFirstRail: GetLayout + GetNodeIndex {
self.layout() self.layout()
.geometry() .geometry()
.neighbors_directed(self.node_index(), Incoming) .neighbors_directed(self.node_index(), Incoming)
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout() self.layout()
.geometry() .geometry()
.edge_weight( .edge_weight(
self.layout() self.layout()
.geometry() .geometry()
.find_edge(*ni, self.node_index()) .find_edge(*node, self.node_index())
.unwrap() .unwrap()
) )
.unwrap(), .unwrap(),
GeometryLabel::Core GeometryLabel::Core
) )
}) })
.map(|ni| LooseBendIndex::new(ni)) .map(|node| LooseBendIndex::new(node))
.next() .next()
} }
} }
@ -90,21 +90,21 @@ pub trait GetCore: GetLayout + GetNodeIndex {
self.layout() self.layout()
.geometry() .geometry()
.neighbors(self.node_index()) .neighbors(self.node_index())
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout() self.layout()
.geometry() .geometry()
.edge_weight( .edge_weight(
self.layout() self.layout()
.geometry() .geometry()
.find_edge(self.node_index(), *ni) .find_edge(self.node_index(), *node)
.unwrap() .unwrap()
) )
.unwrap(), .unwrap(),
GeometryLabel::Core GeometryLabel::Core
) )
}) })
.map(|ni| FixedDotIndex::new(ni)) .map(|node| FixedDotIndex::new(node))
.next() .next()
.unwrap() .unwrap()
} }
@ -115,21 +115,21 @@ pub trait GetInnerOuter: GetLayout + GetNodeIndex {
self.layout() self.layout()
.geometry() .geometry()
.neighbors_directed(self.node_index(), Incoming) .neighbors_directed(self.node_index(), Incoming)
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout() self.layout()
.geometry() .geometry()
.edge_weight( .edge_weight(
self.layout() self.layout()
.geometry() .geometry()
.find_edge(*ni, self.node_index()) .find_edge(*node, self.node_index())
.unwrap() .unwrap()
) )
.unwrap(), .unwrap(),
GeometryLabel::Outer GeometryLabel::Outer
) )
}) })
.map(|ni| LooseBendIndex::new(ni)) .map(|node| LooseBendIndex::new(node))
.next() .next()
} }
@ -137,21 +137,21 @@ pub trait GetInnerOuter: GetLayout + GetNodeIndex {
self.layout() self.layout()
.geometry() .geometry()
.neighbors_directed(self.node_index(), Outgoing) .neighbors_directed(self.node_index(), Outgoing)
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout() self.layout()
.geometry() .geometry()
.edge_weight( .edge_weight(
self.layout() self.layout()
.geometry() .geometry()
.find_edge(self.node_index(), *ni) .find_edge(self.node_index(), *node)
.unwrap() .unwrap()
) )
.unwrap(), .unwrap(),
GeometryLabel::Outer GeometryLabel::Outer
) )
}) })
.map(|ni| LooseBendIndex::new(ni)) .map(|node| LooseBendIndex::new(node))
.next() .next()
} }
} }
@ -236,14 +236,14 @@ impl<'a, W> GenericPrimitive<'a, W> {
self.layout self.layout
.geometry() .geometry()
.neighbors_undirected(self.index.node_index()) .neighbors_undirected(self.index.node_index())
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout self.layout
.geometry() .geometry()
.edge_weight( .edge_weight(
self.layout self.layout
.geometry() .geometry()
.find_edge_undirected(self.index.node_index(), *ni) .find_edge_undirected(self.index.node_index(), *node)
.unwrap() .unwrap()
.0, .0,
) )
@ -291,6 +291,21 @@ where
pub type FixedDot<'a> = GenericPrimitive<'a, FixedDotWeight>; pub type FixedDot<'a> = GenericPrimitive<'a, FixedDotWeight>;
impl_fixed_primitive!(FixedDot, FixedDotWeight); impl_fixed_primitive!(FixedDot, FixedDotWeight);
impl<'a> FixedDot<'a> {
pub fn first_loose(&self, band: BandIndex) -> Option<LooseIndex> {
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> { impl<'a> MakeShape for FixedDot<'a> {
fn shape(&self) -> Shape { fn shape(&self) -> Shape {
Shape::Dot(DotShape { Shape::Dot(DotShape {
@ -307,26 +322,26 @@ impl<'a> LooseDot<'a> {
pub fn seg(&self) -> Option<SeqLooseSegIndex> { pub fn seg(&self) -> Option<SeqLooseSegIndex> {
self.adjacents() self.adjacents()
.into_iter() .into_iter()
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout.geometry().node_weight(*ni).unwrap(), self.layout.geometry().node_weight(*node).unwrap(),
GeometryWeight::SeqLooseSeg(..) GeometryWeight::SeqLooseSeg(..)
) )
}) })
.map(|ni| SeqLooseSegIndex::new(ni)) .map(|node| SeqLooseSegIndex::new(node))
.next() .next()
} }
pub fn bend(&self) -> LooseBendIndex { pub fn bend(&self) -> LooseBendIndex {
self.adjacents() self.adjacents()
.into_iter() .into_iter()
.filter(|ni| { .filter(|node| {
matches!( matches!(
self.layout.geometry().node_weight(*ni).unwrap(), self.layout.geometry().node_weight(*node).unwrap(),
GeometryWeight::LooseBend(..) GeometryWeight::LooseBend(..)
) )
}) })
.map(|ni| LooseBendIndex::new(ni)) .map(|node| LooseBendIndex::new(node))
.next() .next()
.unwrap() .unwrap()
} }

View File

@ -4,8 +4,10 @@ use spade::InsertionError;
use thiserror::Error; use thiserror::Error;
use crate::astar::{astar, AstarStrategy, PathTracker}; use crate::astar::{astar, AstarStrategy, PathTracker};
use crate::connectivity::BandIndex;
use crate::draw::DrawException; use crate::draw::DrawException;
use crate::geometry::FixedDotIndex; use crate::geometry::FixedDotIndex;
use crate::guide::HeadTrait;
use crate::layout::Layout; use crate::layout::Layout;
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex}; use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
@ -111,12 +113,12 @@ impl Router {
} }
} }
pub fn enroute( pub fn route_band(
&mut self, &mut self,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
observer: &mut impl RouterObserver, observer: &mut impl RouterObserver,
) -> Result<Mesh, RoutingError> { ) -> Result<BandIndex, RoutingError> {
// XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look // XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look
// right. // right.
//self.mesh.triangulate(&self.layout)?; //self.mesh.triangulate(&self.layout)?;
@ -129,6 +131,7 @@ impl Router {
let mut tracer = self.tracer(&mesh); let mut tracer = self.tracer(&mesh);
let trace = tracer.start(from, 3.0); let trace = tracer.start(from, 3.0);
let band = trace.head.band();
let (_cost, _path) = astar( let (_cost, _path) = astar(
&mesh, &mesh,
@ -141,7 +144,7 @@ impl Router {
source: RoutingErrorKind::AStar, source: RoutingErrorKind::AStar,
})?; })?;
Ok(mesh) Ok(band)
} }
pub fn reroute( pub fn reroute(

View File

@ -12,7 +12,7 @@ use crate::{
#[derive(Debug)] #[derive(Debug)]
pub struct Trace { pub struct Trace {
pub path: Vec<VertexIndex>, pub path: Vec<VertexIndex>,
head: Head, pub head: Head,
} }
pub struct Tracer<'a> { pub struct Tracer<'a> {