use enum_dispatch::enum_dispatch; use fixedbitset::FixedBitSet; use geo::{point, Point}; use petgraph::stable_graph::NodeIndex; use petgraph::visit::{self, NodeIndexable}; use spade::{ handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError, Point2, Triangulation, }; use crate::{ graph::{FixedBendIndex, FixedDotIndex, GetNodeIndex, Index, LooseBendIndex}, layout::Layout, }; use crate::{primitive::MakeShape, shape::ShapeTrait}; #[derive(Debug, Clone)] struct Vertex { graph_index: VertexIndex, x: f64, y: f64, } #[enum_dispatch(GetNodeIndex)] #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] pub enum VertexIndex { FixedDot(FixedDotIndex), FixedBend(FixedBendIndex), LooseBend(LooseBendIndex), } impl HasPosition for Vertex { type Scalar = f64; fn position(&self) -> Point2 { Point2::new(self.x, self.y) } } #[derive(Debug, Clone)] pub struct Mesh { triangulation: DelaunayTriangulation, vertex_to_handle: Vec>, } impl Mesh { pub fn new() -> Self { Self { triangulation: DelaunayTriangulation::new(), vertex_to_handle: Vec::new(), } } pub fn triangulate(&mut self, layout: &Layout) -> Result<(), InsertionError> { self.triangulation.clear(); self.vertex_to_handle = Vec::new(); self.vertex_to_handle .resize(layout.graph.node_bound(), None); for node in layout.nodes() { if let Index::FixedDot(dot) = node { let center = layout.primitive(dot).shape().center(); self.vertex_to_handle[dot.node_index().index()] = Some(self.triangulation.insert(Vertex { graph_index: dot.into(), x: center.x(), y: center.y(), })?); } } Ok(()) } pub fn vertex(&self, handle: FixedVertexHandle) -> VertexIndex { self.triangulation.vertex(handle).as_ref().graph_index } pub fn handle(&self, graph_index: VertexIndex) -> FixedVertexHandle { self.vertex_to_handle[graph_index.node_index().index()].unwrap() } pub fn position(&self, vertex: VertexIndex) -> Point { let position = self.triangulation.vertex(self.handle(vertex)).position(); point! {x: position.x, y: position.y} } } impl visit::GraphBase for Mesh { type NodeId = VertexIndex; type EdgeId = (VertexIndex, VertexIndex); } pub struct MeshVisitMap { fixedbitset: FixedBitSet, } impl MeshVisitMap { pub fn with_capacity(bits: usize) -> Self { Self { fixedbitset: FixedBitSet::with_capacity(bits), } } pub fn clear(&mut self) { self.fixedbitset.clear(); } pub fn grow(&mut self, bits: usize) { self.fixedbitset.grow(bits); } } impl visit::VisitMap for MeshVisitMap { fn visit(&mut self, a: T) -> bool { !self.fixedbitset.put(a.node_index().index()) } fn is_visited(&self, a: &T) -> bool { self.fixedbitset.contains(a.node_index().index()) } } impl visit::Visitable for Mesh { type Map = MeshVisitMap; fn visit_map(&self) -> Self::Map { // FIXME: This seems wrong, but pathfinding works for some reason. Investigate. MeshVisitMap::with_capacity(self.triangulation.num_vertices()) } fn reset_map(&self, map: &mut Self::Map) { map.clear(); map.grow(self.triangulation.num_vertices()); } } impl visit::Data for Mesh { type NodeWeight = (); type EdgeWeight = (); } #[derive(Clone, Copy)] pub struct MeshEdgeReference { from: VertexIndex, to: VertexIndex, } impl<'a> visit::EdgeRef for MeshEdgeReference { type NodeId = VertexIndex; type EdgeId = (VertexIndex, VertexIndex); type Weight = (); fn source(&self) -> Self::NodeId { self.from } fn target(&self) -> Self::NodeId { self.to } fn weight(&self) -> &Self::Weight { &() } fn id(&self) -> Self::EdgeId { (self.from, self.to) } } impl<'a> visit::IntoEdgeReferences for &'a Mesh { type EdgeRef = MeshEdgeReference; type EdgeReferences = Box + 'a>; fn edge_references(self) -> Self::EdgeReferences { Box::new( self.triangulation .directed_edges() .map(|edge| MeshEdgeReference { from: self.vertex(edge.from().fix()), to: self.vertex(edge.to().fix()), }), ) } } impl<'a> visit::IntoNeighbors for &'a Mesh { type Neighbors = Box + 'a>; fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors { Box::new( self.triangulation .vertex(self.handle(vertex)) .out_edges() .map(|handle| self.vertex(handle.to().fix())), ) } } impl<'a> visit::IntoEdges for &'a Mesh { type Edges = Box + 'a>; fn edges(self, a: Self::NodeId) -> Self::Edges { Box::new( self.triangulation .vertex(self.handle(a)) .out_edges() .map(|edge| MeshEdgeReference { from: self.vertex(edge.from().fix()), to: self.vertex(edge.to().fix()), }), ) } }