mesh: fix finding neighbors and edges from non-triangulation vertices

This fixes a panic caused by lack of implementation of handling of these.
This commit is contained in:
Mikolaj Wielgus 2023-12-19 21:24:11 +00:00
parent 84d5f9c49e
commit 9a755059c0
1 changed files with 103 additions and 34 deletions

View File

@ -3,7 +3,7 @@ use std::iter;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use geo::Point; use geo::Point;
use itertools::Itertools; use itertools::Itertools;
use petgraph::visit; use petgraph::visit::{self, NodeIndexable};
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef}; use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
use spade::{HasPosition, InsertionError, Point2}; use spade::{HasPosition, InsertionError, Point2};
@ -25,15 +25,31 @@ pub enum VertexIndex {
LooseBend(LooseBendIndex), LooseBend(LooseBendIndex),
} }
#[enum_dispatch(GetNodeIndex, MakePrimitive)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
pub enum TriangulationVertexIndex {
FixedDot(FixedDotIndex),
FixedBend(FixedBendIndex),
}
impl From<TriangulationVertexIndex> for VertexIndex {
fn from(vertex: TriangulationVertexIndex) -> Self {
match vertex {
TriangulationVertexIndex::FixedDot(dot) => VertexIndex::FixedDot(dot),
TriangulationVertexIndex::FixedBend(bend) => VertexIndex::FixedBend(bend),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TriangulationWeight { struct TriangulationWeight {
vertex: VertexIndex, vertex: TriangulationVertexIndex,
rails: Vec<LooseBendIndex>, rails: Vec<LooseBendIndex>,
pos: Point, pos: Point,
} }
impl GetVertexIndex<VertexIndex> for TriangulationWeight { impl GetVertexIndex<TriangulationVertexIndex> for TriangulationWeight {
fn vertex(&self) -> VertexIndex { fn vertex(&self) -> TriangulationVertexIndex {
self.vertex self.vertex
} }
} }
@ -47,14 +63,19 @@ impl HasPosition for TriangulationWeight {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mesh { pub struct Mesh {
triangulation: Triangulation<VertexIndex, TriangulationWeight>, triangulation: Triangulation<TriangulationVertexIndex, TriangulationWeight>,
vertex_to_triangulation_vertex: Vec<Option<TriangulationVertexIndex>>,
} }
impl Mesh { impl Mesh {
pub fn new(layout: &Layout) -> Self { pub fn new(layout: &Layout) -> Self {
Self { let mut this = Self {
triangulation: Triangulation::new(layout), triangulation: Triangulation::new(layout),
} vertex_to_triangulation_vertex: Vec::new(),
};
this.vertex_to_triangulation_vertex
.resize(layout.graph.node_bound(), None);
this
} }
pub fn generate(&mut self, layout: &Layout) -> Result<(), InsertionError> { pub fn generate(&mut self, layout: &Layout) -> Result<(), InsertionError> {
@ -62,16 +83,16 @@ impl Mesh {
let center = node.primitive(layout).shape().center(); let center = node.primitive(layout).shape().center();
match node { match node {
Index::FixedDot(fixed_dot) => { Index::FixedDot(dot) => {
self.triangulation.add_vertex(TriangulationWeight { self.triangulation.add_vertex(TriangulationWeight {
vertex: fixed_dot.into(), vertex: dot.into(),
rails: vec![], rails: vec![],
pos: center, pos: center,
})?; })?;
} }
Index::FixedBend(fixed_bend) => { Index::FixedBend(bend) => {
self.triangulation.add_vertex(TriangulationWeight { self.triangulation.add_vertex(TriangulationWeight {
vertex: fixed_bend.into(), vertex: bend.into(),
rails: vec![], rails: vec![],
pos: center, pos: center,
})?; })?;
@ -81,12 +102,15 @@ impl Mesh {
} }
for node in layout.nodes() { for node in layout.nodes() {
// Add rails as vertices. This is how the mesh differs from the triangulation.
match node { match node {
Index::LooseBend(loose_bend) => { Index::LooseBend(bend) => {
self.triangulation self.triangulation
.weight_mut(layout.primitive(loose_bend).core().into()) .weight_mut(layout.primitive(bend).core().into())
.rails .rails
.push(loose_bend.into()); .push(bend.into());
self.vertex_to_triangulation_vertex[bend.node_index().index()] =
Some(layout.primitive(bend).core().into());
} }
_ => (), _ => (),
} }
@ -94,6 +118,16 @@ impl Mesh {
Ok(()) Ok(())
} }
pub fn triangulation_vertex(&self, vertex: VertexIndex) -> TriangulationVertexIndex {
match vertex {
VertexIndex::FixedDot(dot) => TriangulationVertexIndex::FixedDot(dot),
VertexIndex::FixedBend(bend) => TriangulationVertexIndex::FixedBend(bend),
VertexIndex::LooseBend(bend) => {
self.vertex_to_triangulation_vertex[bend.node_index().index()].unwrap()
}
}
}
} }
impl visit::GraphBase for Mesh { impl visit::GraphBase for Mesh {
@ -138,23 +172,29 @@ impl<'a> visit::IntoNeighbors for &'a Mesh {
type Neighbors = Box<dyn Iterator<Item = VertexIndex> + 'a>; type Neighbors = Box<dyn Iterator<Item = VertexIndex> + 'a>;
fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors { fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors {
Box::new(self.triangulation.neighbors(vertex).flat_map(|neighbor| { Box::new(
iter::once(neighbor).chain( self.triangulation
.neighbors(self.triangulation_vertex(vertex))
.flat_map(|neighbor| {
iter::once(neighbor.into()).chain(
self.triangulation self.triangulation
.weight(neighbor) .weight(neighbor)
.rails .rails
.iter() .iter()
.map(|index| VertexIndex::from(*index)), .map(|index| VertexIndex::from(*index)),
) )
})) }),
)
} }
} }
fn edges( fn edge_with_near_edges(
triangulation: &Triangulation<VertexIndex, TriangulationWeight>, triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>,
edge: TriangulationEdgeReference<VertexIndex>, edge: TriangulationEdgeReference<TriangulationVertexIndex>,
) -> impl Iterator<Item = MeshEdgeReference> { ) -> impl Iterator<Item = MeshEdgeReference> {
let mut from_vertices = vec![edge.source()]; let mut from_vertices = vec![edge.source().into()];
// Append rails to the source.
from_vertices.extend( from_vertices.extend(
triangulation triangulation
.weight(edge.source()) .weight(edge.source())
@ -163,7 +203,9 @@ fn edges(
.map(|bend| VertexIndex::from(*bend)), .map(|bend| VertexIndex::from(*bend)),
); );
let mut to_vertices = vec![edge.target()]; let mut to_vertices = vec![edge.target().into()];
// Append rails to the target.
to_vertices.extend( to_vertices.extend(
triangulation triangulation
.weight(edge.target()) .weight(edge.target())
@ -172,12 +214,13 @@ fn edges(
.map(|bend| VertexIndex::from(*bend)), .map(|bend| VertexIndex::from(*bend)),
); );
// Return cartesian product.
from_vertices from_vertices
.into_iter() .into_iter()
.cartesian_product(to_vertices.into_iter()) .cartesian_product(to_vertices.into_iter())
.map(|pair| MeshEdgeReference { .map(|pair| MeshEdgeReference {
from: pair.0, from: pair.0,
to: pair.1, to: pair.1.into(),
}) })
} }
@ -189,20 +232,46 @@ impl<'a> visit::IntoEdgeReferences for &'a Mesh {
Box::new( Box::new(
self.triangulation self.triangulation
.edge_references() .edge_references()
.flat_map(move |edge| edges(&self.triangulation, edge)), .flat_map(move |edge| edge_with_near_edges(&self.triangulation, edge)),
) )
} }
} }
fn vertex_edges(
triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>,
from: VertexIndex,
to: TriangulationVertexIndex,
) -> impl Iterator<Item = MeshEdgeReference> {
let from_vertices = vec![from];
let mut to_vertices = vec![to.into()];
// Append rails to the target.
to_vertices.extend(
triangulation
.weight(to)
.rails
.iter()
.map(|bend| VertexIndex::from(*bend)),
);
// Return cartesian product.
from_vertices
.into_iter()
.cartesian_product(to_vertices.into_iter())
.map(|pair| MeshEdgeReference {
from: pair.0,
to: pair.1,
})
}
impl<'a> visit::IntoEdges for &'a Mesh { impl<'a> visit::IntoEdges for &'a Mesh {
type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>; type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
fn edges(self, node: Self::NodeId) -> Self::Edges { fn edges(self, vertex: Self::NodeId) -> Self::Edges {
Box::new( Box::new(
self.triangulation self.triangulation
// FIXME: node has to be converted to triangulation vertex (?) .edges(self.triangulation_vertex(vertex))
.edges(node) .flat_map(move |edge| vertex_edges(&self.triangulation, vertex, edge.target())),
.flat_map(move |edge| edges(&self.triangulation, edge)),
) )
} }
} }