use std::marker::PhantomData; use geo::{point, EuclideanDistance, Point}; use petgraph::visit; use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError}; use crate::graph::GetNodeIndex; pub trait GetVertexIndex { fn vertex_index(&self) -> I; } #[derive(Debug, Clone)] pub struct Triangulation + HasPosition> { triangulation: DelaunayTriangulation, vertex_to_handle: Vec>, index_marker: PhantomData, } impl + HasPosition> Triangulation { pub fn new(node_bound: usize) -> Self { let mut this = Self { triangulation: as spade::Triangulation>::new(), vertex_to_handle: Vec::new(), index_marker: PhantomData, }; this.vertex_to_handle.resize(node_bound, None); this } pub fn add_vertex(&mut self, weight: W) -> Result<(), InsertionError> { let index = weight.vertex_index().node_index().index(); self.vertex_to_handle[index] = Some(spade::Triangulation::insert( &mut self.triangulation, weight, )?); Ok(()) } pub fn weight(&self, vertex: I) -> &W { spade::Triangulation::s(&self.triangulation) .vertex_data(self.vertex_to_handle[vertex.node_index().index()].unwrap()) } 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_index() } 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); } #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub struct TriangulationEdgeWeight { length: f64, } impl + HasPosition> visit::Data for Triangulation { type NodeWeight = W; type EdgeWeight = TriangulationEdgeWeight; } #[derive(Debug, Clone, Copy, PartialEq)] pub struct TriangulationEdgeReference { from: I, to: I, weight: TriangulationEdgeWeight, } impl visit::EdgeRef for TriangulationEdgeReference { type NodeId = I; type EdgeId = (I, I); type Weight = TriangulationEdgeWeight; fn source(&self) -> Self::NodeId { self.from } fn target(&self) -> Self::NodeId { self.to } fn weight(&self) -> &Self::Weight { &self.weight } fn id(&self) -> Self::EdgeId { (self.from, self.to) } } 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::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| { let from = self.vertex(edge.from().fix()); let to = self.vertex(edge.to().fix()); TriangulationEdgeReference { from, to, weight: TriangulationEdgeWeight { length: self.position(from).euclidean_distance(&self.position(to)), }, } }), ) } } 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| { let from = self.vertex(edge.from().fix()); let to = self.vertex(edge.to().fix()); TriangulationEdgeReference { from, to, weight: TriangulationEdgeWeight { length: self.position(from).euclidean_distance(&self.position(to)), }, } }), ) } } impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex + HasPosition> visit::IntoNodeIdentifiers for &'a Triangulation { type NodeIdentifiers = Box + 'a>; fn node_identifiers(self) -> Self::NodeIdentifiers { Box::new( spade::Triangulation::fixed_vertices(&self.triangulation).map(|vertex| { spade::Triangulation::s(&self.triangulation) .vertex_data(vertex) .vertex_index() }), ) } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct TriangulationVertexReference<'a, I: Copy, W> { index: I, weight: &'a W, } impl<'a, I: Copy, W: Copy> visit::NodeRef for TriangulationVertexReference<'a, I, W> { type NodeId = I; type Weight = W; fn id(&self) -> Self::NodeId { self.index } fn weight(&self) -> &Self::Weight { self.weight } } impl< 'a, I: Copy + PartialEq + GetNodeIndex, W: Copy + GetVertexIndex + HasPosition, > visit::IntoNodeReferences for &'a Triangulation { type NodeRef = TriangulationVertexReference<'a, I, W>; type NodeReferences = Box> + 'a>; fn node_references(self) -> Self::NodeReferences { Box::new( spade::Triangulation::fixed_vertices(&self.triangulation).map(|vertex| { let weight = spade::Triangulation::s(&self.triangulation).vertex_data(vertex); TriangulationVertexReference { index: weight.vertex_index(), weight, } }), ) } } impl< 'a, I: Copy + PartialEq + GetNodeIndex + std::fmt::Debug, W: GetVertexIndex + HasPosition, > visit::NodeIndexable for &'a Triangulation { fn node_bound(&self) -> usize { //spade::Triangulation::num_vertices(&self.triangulation) self.vertex_to_handle.len() } fn to_index(&self, node: I) -> usize { node.node_index().index() } fn from_index(&self, index: usize) -> I { spade::Triangulation::s(&self.triangulation) .vertex_data(self.vertex_to_handle[index].unwrap()) .vertex_index() } }