mirror of https://codeberg.org/topola/topola.git
157 lines
4.6 KiB
Rust
157 lines
4.6 KiB
Rust
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<I> {
|
|
fn vertex(&self) -> I;
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Triangulation<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition> {
|
|
triangulation: DelaunayTriangulation<W>,
|
|
vertex_to_handle: Vec<Option<FixedVertexHandle>>,
|
|
index_marker: PhantomData<I>,
|
|
}
|
|
|
|
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
|
|
Triangulation<I, W>
|
|
{
|
|
pub fn new(layout: &Layout) -> Self {
|
|
let mut this = Self {
|
|
triangulation: <DelaunayTriangulation<W> 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<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
|
|
visit::GraphBase for Triangulation<I, W>
|
|
{
|
|
type NodeId = I;
|
|
type EdgeId = (I, I);
|
|
}
|
|
|
|
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
|
|
visit::Data for Triangulation<I, W>
|
|
{
|
|
type NodeWeight = ();
|
|
type EdgeWeight = ();
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub struct TriangulationEdgeReference<I> {
|
|
from: I,
|
|
to: I,
|
|
}
|
|
|
|
impl<I: Copy> visit::EdgeRef for TriangulationEdgeReference<I> {
|
|
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<I> + HasPosition<Scalar = f64>>
|
|
visit::IntoEdgeReferences for &'a Triangulation<I, W>
|
|
{
|
|
type EdgeRef = TriangulationEdgeReference<I>;
|
|
type EdgeReferences = Box<dyn Iterator<Item = TriangulationEdgeReference<I>> + '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<I> + HasPosition<Scalar = f64>>
|
|
visit::IntoNeighbors for &'a Triangulation<I, W>
|
|
{
|
|
type Neighbors = Box<dyn Iterator<Item = I> + '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<I> + HasPosition<Scalar = f64>>
|
|
visit::IntoEdges for &'a Triangulation<I, W>
|
|
{
|
|
type Edges = Box<dyn Iterator<Item = TriangulationEdgeReference<I>> + '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()),
|
|
}),
|
|
)
|
|
}
|
|
}
|