use std::marker::PhantomData; use geo::{point, Point}; use petgraph::visit::{self, NodeIndexable}; use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError}; use crate::{graph::GetNodeIndex, layout::Layout}; pub trait GetVertexIndex { fn vertex(&self) -> I; } #[derive(Debug, Clone)] pub struct Triangulation + HasPosition> { triangulation: DelaunayTriangulation, vertex_to_handle: Vec>, index_marker: PhantomData, } impl + HasPosition> Triangulation { pub fn new(layout: &Layout) -> Self { let mut this = Self { triangulation: as spade::Triangulation>::new(), vertex_to_handle: Vec::new(), index_marker: PhantomData, }; this.vertex_to_handle .resize(layout.graph.node_bound(), None); this } pub fn add_vertex(&mut self, weight: W) -> Result<(), InsertionError> { let index = weight.vertex().node_index().index(); self.vertex_to_handle[index] = Some(spade::Triangulation::insert( &mut self.triangulation, weight, )?); Ok(()) } pub fn weight_mut(&mut self, vertex: I) -> &mut W { spade::Triangulation::vertex_data_mut( &mut self.triangulation, self.vertex_to_handle[vertex.node_index().index()].unwrap(), ) } pub fn position(&self, vertex: I) -> Point { let position = spade::Triangulation::vertex(&self.triangulation, self.handle(vertex)).position(); point! {x: position.x, y: position.y} } fn vertex(&self, handle: FixedVertexHandle) -> I { spade::Triangulation::vertex(&self.triangulation, handle) .as_ref() .vertex() } fn handle(&self, vertex: I) -> FixedVertexHandle { self.vertex_to_handle[vertex.node_index().index()].unwrap() } } impl + HasPosition> visit::GraphBase for Triangulation { type NodeId = I; type EdgeId = (I, I); } impl + HasPosition> visit::Data for Triangulation { type NodeWeight = (); type EdgeWeight = (); } #[derive(Debug, Clone, Copy, PartialEq)] pub struct TriangulationEdgeReference { from: I, to: I, } impl visit::EdgeRef for TriangulationEdgeReference { type NodeId = I; type EdgeId = (I, I); 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, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex + HasPosition> visit::IntoEdgeReferences for &'a Triangulation { type EdgeRef = TriangulationEdgeReference; type EdgeReferences = Box> + 'a>; fn edge_references(self) -> Self::EdgeReferences { Box::new( spade::Triangulation::directed_edges(&self.triangulation).map(|edge| { TriangulationEdgeReference { from: self.vertex(edge.from().fix()), to: self.vertex(edge.to().fix()), } }), ) } } impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex + HasPosition> visit::IntoNeighbors for &'a Triangulation { type Neighbors = Box + 'a>; fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors { Box::new( spade::Triangulation::vertex(&self.triangulation, self.handle(vertex)) .out_edges() .map(|handle| self.vertex(handle.to().fix())), ) } } impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex + HasPosition> visit::IntoEdges for &'a Triangulation { type Edges = Box> + 'a>; fn edges(self, node: Self::NodeId) -> Self::Edges { Box::new( spade::Triangulation::vertex(&self.triangulation, self.handle(node)) .out_edges() .map(|edge| TriangulationEdgeReference { from: self.vertex(edge.from().fix()), to: self.vertex(edge.to().fix()), }), ) } }