// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT use std::{cmp::Ordering, marker::PhantomData}; use geo::algorithm::line_measures::{Distance, Euclidean}; use geo::{point, Point}; use petgraph::visit; use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError}; use crate::graph::GetPetgraphIndex; pub trait GetTrianvertexNodeIndex { fn node_index(&self) -> I; } #[derive(Debug, Clone)] pub struct Triangulation + HasPosition, EW: Default> { triangulation: DelaunayTriangulation, trianvertex_to_handle: Box<[Option]>, index_marker: PhantomData, } impl + HasPosition, EW: Default> Triangulation { pub fn new(node_bound: usize) -> Self { Self { triangulation: as spade::Triangulation>::new(), trianvertex_to_handle: vec![None; node_bound].into_boxed_slice(), index_marker: PhantomData, } } pub fn add_vertex(&mut self, weight: VW) -> Result<(), InsertionError> { let index = weight.node_index().petgraph_index().index(); self.trianvertex_to_handle[index] = Some(spade::Triangulation::insert( &mut self.triangulation, weight, )?); Ok(()) } pub fn weight(&self, vertex: I) -> &VW { spade::Triangulation::s(&self.triangulation) .vertex_data(self.trianvertex_to_handle[vertex.petgraph_index().index()].unwrap()) } pub fn weight_mut(&mut self, vertex: I) -> &mut VW { spade::Triangulation::vertex_data_mut( &mut self.triangulation, self.trianvertex_to_handle[vertex.petgraph_index().index()].unwrap(), ) } fn vertex(&self, handle: FixedVertexHandle) -> I { spade::Triangulation::vertex(&self.triangulation, handle) .as_ref() .node_index() } fn handle(&self, vertex: I) -> FixedVertexHandle { self.trianvertex_to_handle[vertex.petgraph_index().index()].unwrap() } pub fn position(&self, vertex: I) -> Point<::Scalar> where ::Scalar: geo::CoordNum, { let position = spade::Triangulation::vertex(&self.triangulation, self.handle(vertex)).position(); point! {x: position.x, y: position.y} } } impl< I: Copy + PartialEq + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Default, > visit::GraphBase for Triangulation { type NodeId = I; type EdgeId = (I, I); } #[derive(Debug, Clone, Copy)] pub struct TriangulationEdgeWeightWrapper { length: f64, pub weight: EW, } impl PartialEq for TriangulationEdgeWeightWrapper { fn eq(&self, other: &Self) -> bool { self.length.eq(&other.length) } } impl PartialOrd for TriangulationEdgeWeightWrapper { fn partial_cmp(&self, other: &Self) -> Option { self.length.partial_cmp(&other.length) } } impl< I: Copy + PartialEq + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Copy + Default, > visit::Data for Triangulation { type NodeWeight = VW; type EdgeWeight = TriangulationEdgeWeightWrapper; } #[derive(Debug, Clone, Copy, PartialEq)] pub struct TriangulationEdgeReference { from: I, to: I, weight: TriangulationEdgeWeightWrapper, } impl visit::EdgeRef for TriangulationEdgeReference { type NodeId = I; type EdgeId = (I, I); type Weight = TriangulationEdgeWeightWrapper; 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 + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Default, > 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 + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Copy + Default, > 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: TriangulationEdgeWeightWrapper { length: Euclidean::distance(&self.position(from), &self.position(to)), weight: *edge.data(), }, } }), ) } } impl< 'a, I: Copy + PartialEq + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Copy + Default, > 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: TriangulationEdgeWeightWrapper { length: Euclidean::distance(&self.position(from), &self.position(to)), weight: *edge.data(), }, } }), ) } } impl< 'a, I: Copy + PartialEq + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Default, > 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) .node_index() }), ) } } #[derive(Debug, PartialEq)] pub struct TriangulationVertexReference<'a, I, VW> { index: I, weight: &'a VW, } impl Clone for TriangulationVertexReference<'_, I, VW> { fn clone(&self) -> Self { Self { index: self.index.clone(), weight: self.weight, } } } impl Copy for TriangulationVertexReference<'_, I, VW> {} impl visit::NodeRef for TriangulationVertexReference<'_, I, VW> { type NodeId = I; type Weight = VW; fn id(&self) -> Self::NodeId { self.index } fn weight(&self) -> &Self::Weight { self.weight } } impl< 'a, I: Copy + PartialEq + GetPetgraphIndex, VW: GetTrianvertexNodeIndex + HasPosition, EW: Copy + Default, > visit::IntoNodeReferences for &'a Triangulation { type NodeRef = TriangulationVertexReference<'a, I, VW>; 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.node_index(), weight, } }), ) } } impl< I: Copy + PartialEq + GetPetgraphIndex + std::fmt::Debug, VW: GetTrianvertexNodeIndex + HasPosition, EW: Default, > visit::NodeIndexable for &Triangulation { fn node_bound(&self) -> usize { //spade::Triangulation::num_vertices(&self.triangulation) self.trianvertex_to_handle.len() } fn to_index(&self, node: I) -> usize { node.petgraph_index().index() } fn from_index(&self, index: usize) -> I { spade::Triangulation::s(&self.triangulation) .vertex_data(self.trianvertex_to_handle[index].unwrap()) .node_index() } }