mesh: Split out `Mesh` into a new `Triangulation` struct

It will be possible for the mesh to contain additional vertices that
aren't part of the Delaunay triangulation. `Mesh` is now a wrapper over
`Triangulation` that implements the same traits, and will be later
adding its own vertices in addition to the ones from triangulation.
This commit is contained in:
Mikolaj Wielgus 2023-11-04 18:36:41 +00:00
parent 66d5b3e605
commit 8379470bb1
4 changed files with 153 additions and 79 deletions

View File

@ -23,6 +23,7 @@ mod segbend;
mod shape;
mod tracer;
mod traverser;
mod triangulation;
use geo::point;
use graph::{FixedDotIndex, FixedSegWeight, LooseDotIndex};

View File

@ -1,25 +1,16 @@
use enum_dispatch::enum_dispatch;
use fixedbitset::FixedBitSet;
use geo::{point, Point};
use geo::Point;
use petgraph::stable_graph::NodeIndex;
use petgraph::visit::{self, NodeIndexable};
use spade::{
handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError, Point2,
Triangulation,
};
use petgraph::visit;
use spade::InsertionError;
use crate::{
graph::{FixedBendIndex, FixedDotIndex, GetNodeIndex, Index, LooseBendIndex},
layout::Layout,
primitive::MakeShape,
shape::ShapeTrait,
triangulation::Triangulation,
};
use crate::{primitive::MakeShape, shape::ShapeTrait};
#[derive(Debug, Clone)]
struct Vertex {
graph_index: VertexIndex,
x: f64,
y: f64,
}
#[enum_dispatch(GetNodeIndex)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
@ -29,60 +20,32 @@ pub enum VertexIndex {
LooseBend(LooseBendIndex),
}
impl HasPosition for Vertex {
type Scalar = f64;
fn position(&self) -> Point2<Self::Scalar> {
Point2::new(self.x, self.y)
}
}
#[derive(Debug, Clone)]
pub struct Mesh {
triangulation: DelaunayTriangulation<Vertex>,
vertex_to_handle: Vec<Option<FixedVertexHandle>>,
triangulation: Triangulation,
}
impl Mesh {
pub fn new() -> Self {
pub fn new(layout: &Layout) -> Self {
Self {
triangulation: DelaunayTriangulation::new(),
vertex_to_handle: Vec::new(),
triangulation: Triangulation::new(layout),
}
}
pub fn triangulate(&mut self, layout: &Layout) -> Result<(), InsertionError> {
self.triangulation.clear();
self.vertex_to_handle = Vec::new();
self.vertex_to_handle
.resize(layout.graph.node_bound(), None);
pub fn generate(&mut self, layout: &Layout) -> Result<(), InsertionError> {
for node in layout.nodes() {
if let Index::FixedDot(dot) = node {
let center = layout.primitive(dot).shape().center();
self.vertex_to_handle[dot.node_index().index()] =
Some(self.triangulation.insert(Vertex {
graph_index: dot.into(),
x: center.x(),
y: center.y(),
})?);
self.triangulation
.add_vertex(dot.into(), center.x(), center.y());
}
}
Ok(())
}
pub fn vertex(&self, handle: FixedVertexHandle) -> VertexIndex {
self.triangulation.vertex(handle).as_ref().graph_index
}
pub fn handle(&self, graph_index: VertexIndex) -> FixedVertexHandle {
self.vertex_to_handle[graph_index.node_index().index()].unwrap()
}
pub fn position(&self, vertex: VertexIndex) -> Point {
let position = self.triangulation.vertex(self.handle(vertex)).position();
point! {x: position.x, y: position.y}
self.triangulation.position(vertex)
}
}
@ -98,8 +61,8 @@ impl visit::Data for Mesh {
#[derive(Clone, Copy)]
pub struct MeshEdgeReference {
from: VertexIndex,
to: VertexIndex,
pub from: VertexIndex,
pub to: VertexIndex,
}
impl<'a> visit::EdgeRef for MeshEdgeReference {
@ -129,14 +92,7 @@ impl<'a> visit::IntoEdgeReferences for &'a Mesh {
type EdgeReferences = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
fn edge_references(self) -> Self::EdgeReferences {
Box::new(
self.triangulation
.directed_edges()
.map(|edge| MeshEdgeReference {
from: self.vertex(edge.from().fix()),
to: self.vertex(edge.to().fix()),
}),
)
Box::new(self.triangulation.edge_references())
}
}
@ -144,27 +100,14 @@ impl<'a> visit::IntoNeighbors for &'a Mesh {
type Neighbors = Box<dyn Iterator<Item = VertexIndex> + 'a>;
fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors {
Box::new(
self.triangulation
.vertex(self.handle(vertex))
.out_edges()
.map(|handle| self.vertex(handle.to().fix())),
)
self.triangulation.neighbors(vertex)
}
}
impl<'a> visit::IntoEdges for &'a Mesh {
type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
Box::new(
self.triangulation
.vertex(self.handle(a))
.out_edges()
.map(|edge| MeshEdgeReference {
from: self.vertex(edge.from().fix()),
to: self.vertex(edge.to().fix()),
}),
)
fn edges(self, node: Self::NodeId) -> Self::Edges {
Box::new(self.triangulation.edges(node))
}
}

View File

@ -90,8 +90,8 @@ impl Router {
// XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look
// right.
//self.mesh.triangulate(&self.layout)?;
let mut mesh = Mesh::new();
mesh.triangulate(&self.layout)?;
let mut mesh = Mesh::new(&self.layout);
mesh.generate(&self.layout)?;
let mut tracer = self.tracer(&mesh);
let trace = tracer.start(from);
@ -129,7 +129,7 @@ impl Router {
};
self.enroute(from, to_dot, observer)*/
Ok(Mesh::new())
Ok(Mesh::new(&self.layout))
}
/*pub fn squeeze_around_dot(

130
src/triangulation.rs Normal file
View File

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