mirror of https://codeberg.org/topola/topola.git
layout: implement removal of bands
This commit is contained in:
parent
2d5de212d2
commit
afe4c586b5
|
|
@ -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<ComponentWeight>;
|
|||
pub struct BandWeight {
|
||||
pub net: i64,
|
||||
pub width: f64,
|
||||
pub from: FixedDotIndex,
|
||||
}
|
||||
|
||||
impl GetNet for BandWeight {
|
||||
|
|
|
|||
|
|
@ -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<LooseBendIndex, LayoutException> {
|
||||
// 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;
|
||||
|
|
|
|||
26
src/loose.rs
26
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<LooseIndex>;
|
||||
fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex>;
|
||||
}
|
||||
|
||||
#[enum_dispatch(GetNodeIndex, MakePrimitive)]
|
||||
|
|
@ -55,26 +56,33 @@ impl<'a> Loose<'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 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<LooseIndex> {
|
||||
fn next_loose(&self, _maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
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 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<LooseIndex> {
|
||||
fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex> {
|
||||
let ends = self.ends();
|
||||
let Some(prev) = maybe_prev else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if ends.0.node_index() != prev.node_index() {
|
||||
Some(ends.0.into())
|
||||
} else {
|
||||
|
|
|
|||
26
src/main.rs
26
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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<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> {
|
||||
fn shape(&self) -> Shape {
|
||||
Shape::Dot(DotShape {
|
||||
|
|
@ -307,26 +322,26 @@ impl<'a> LooseDot<'a> {
|
|||
pub fn seg(&self) -> Option<SeqLooseSegIndex> {
|
||||
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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Mesh, RoutingError> {
|
||||
) -> Result<BandIndex, RoutingError> {
|
||||
// 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(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
#[derive(Debug)]
|
||||
pub struct Trace {
|
||||
pub path: Vec<VertexIndex>,
|
||||
head: Head,
|
||||
pub head: Head,
|
||||
}
|
||||
|
||||
pub struct Tracer<'a> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue