triangulation: Parameterize to make independent from `Mesh`

This commit is contained in:
Mikolaj Wielgus 2023-11-05 20:19:18 +00:00
parent 961fc02678
commit d6163d3d44
2 changed files with 130 additions and 67 deletions

View File

@ -1,15 +1,15 @@
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use geo::Point; use geo::Point;
use petgraph::stable_graph::NodeIndex;
use petgraph::visit; use petgraph::visit;
use spade::InsertionError; use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
use spade::{HasPosition, InsertionError, Point2};
use crate::{ use crate::{
graph::{FixedBendIndex, FixedDotIndex, GetNodeIndex, Index, LooseBendIndex, MakePrimitive}, graph::{FixedBendIndex, FixedDotIndex, GetNodeIndex, Index, LooseBendIndex, MakePrimitive},
layout::Layout, layout::Layout,
primitive::{GetCore, MakeShape}, primitive::MakeShape,
shape::ShapeTrait, shape::ShapeTrait,
triangulation::Triangulation, triangulation::{GetVertexIndex, Triangulation},
}; };
#[enum_dispatch(GetNodeIndex)] #[enum_dispatch(GetNodeIndex)]
@ -20,9 +20,28 @@ pub enum VertexIndex {
LooseBend(LooseBendIndex), LooseBend(LooseBendIndex),
} }
#[derive(Debug, Clone)]
struct TriangulationWeight {
vertex: VertexIndex,
pos: Point,
}
impl GetVertexIndex<VertexIndex> for TriangulationWeight {
fn vertex(&self) -> VertexIndex {
self.vertex
}
}
impl HasPosition for TriangulationWeight {
type Scalar = f64;
fn position(&self) -> Point2<Self::Scalar> {
Point2::new(self.pos.x(), self.pos.y())
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mesh { pub struct Mesh {
triangulation: Triangulation, triangulation: Triangulation<VertexIndex, TriangulationWeight>,
} }
impl Mesh { impl Mesh {
@ -38,12 +57,16 @@ impl Mesh {
match node { match node {
Index::FixedDot(fixed_dot) => { Index::FixedDot(fixed_dot) => {
self.triangulation self.triangulation.add_vertex(TriangulationWeight {
.add_vertex(fixed_dot.into(), center.x(), center.y())?; vertex: fixed_dot.into(),
pos: center,
})?;
} }
Index::FixedBend(fixed_bend) => { Index::FixedBend(fixed_bend) => {
self.triangulation self.triangulation.add_vertex(TriangulationWeight {
.add_vertex(fixed_bend.into(), center.x(), center.y())?; vertex: fixed_bend.into(),
pos: center,
})?;
} }
/*Index::LooseBend(loose_bend) => { /*Index::LooseBend(loose_bend) => {
self.triangulation.add_bend( self.triangulation.add_bend(
@ -72,13 +95,13 @@ impl visit::Data for Mesh {
type EdgeWeight = (); type EdgeWeight = ();
} }
#[derive(Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct MeshEdgeReference { pub struct MeshEdgeReference {
pub from: VertexIndex, from: VertexIndex,
pub to: VertexIndex, to: VertexIndex,
} }
impl<'a> visit::EdgeRef for MeshEdgeReference { impl visit::EdgeRef for MeshEdgeReference {
type NodeId = VertexIndex; type NodeId = VertexIndex;
type EdgeId = (VertexIndex, VertexIndex); type EdgeId = (VertexIndex, VertexIndex);
type Weight = (); type Weight = ();
@ -105,7 +128,14 @@ impl<'a> visit::IntoEdgeReferences for &'a Mesh {
type EdgeReferences = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>; type EdgeReferences = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
fn edge_references(self) -> Self::EdgeReferences { fn edge_references(self) -> Self::EdgeReferences {
Box::new(self.triangulation.edge_references()) Box::new(
self.triangulation
.edge_references()
.map(|edge| MeshEdgeReference {
from: edge.source(),
to: edge.target(),
}),
)
} }
} }
@ -121,6 +151,13 @@ impl<'a> visit::IntoEdges for &'a Mesh {
type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>; type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
fn edges(self, node: Self::NodeId) -> Self::Edges { fn edges(self, node: Self::NodeId) -> Self::Edges {
Box::new(self.triangulation.edges(node)) Box::new(
self.triangulation
.edges(node)
.map(|edge| MeshEdgeReference {
from: edge.source(),
to: edge.target(),
}),
)
} }
} }

View File

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