From 7645f34e504e5a8a3361b2dec47d87e0738aff7a Mon Sep 17 00:00:00 2001 From: Adam Getchell Date: Sun, 17 Dec 2023 17:08:01 -0800 Subject: [PATCH] Tds add function and dimensionality constraints Tds::add to add one vertex to the triangulation data structure. Set the dimensionality of the Tds using CGAL conventions: -1 if no vertices are present 0 for a single vertex 1 for two vertices (edge) 2 for three vertices (face) Up to D for D+1 vertices or greater Where D is the extrinsic dimensionality (i.e. number of coordinates of a point). --- README.md | 5 +- src/delaunay_core/cell.rs | 2 +- .../triangulation_data_structure.rs | 95 ++++++++++++++++++- 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ef55613..99a188d 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ D-dimensional Delaunay triangulations in Rust, inspired by [CGAL]. ## Introduction -This library implements d-dimensional Delaunay triangulations and CGAL-like features in Rust. It is inspired by the [CGAL] library, which is a C++ library for computational geometry; and [Spade], a Rust library implementing 2D Delaunay triangulations, Constrained Delaunay triangulations, and Voronoi diagrams. The eventual goal of this library is to provide a lightweight Rust alternative to [CGAL]. +This library implements d-dimensional Delaunay triangulations in [Rust]. It is inspired by the [CGAL] library, which is a C++ library for computational geometry; and [Spade], a Rust library implementing 2D Delaunay triangulations, Constrained Delaunay triangulations, and Voronoi diagrams. The eventual goal of this library is to provide a lightweight [Rust] alternative to [CGAL]. -At some point I may merge it into another library, such as [Spade], or [delaunay], but for now I am developing this without trying to figure out how to fit into the coding style and standards of another library. +At some point I may merge it into another library, such as [Spade], or [delaunay], but for now I am developing this library without trying to figure out how to fit into other coding styles and standards. +[Rust]: https://rust-lang.org [CGAL]: https://www.cgal.org/ [Spade]: https://github.com/Stoeoef/spade [delaunay]: https://crates.io/crates/delaunay diff --git a/src/delaunay_core/cell.rs b/src/delaunay_core/cell.rs index 770e0bb..5069299 100644 --- a/src/delaunay_core/cell.rs +++ b/src/delaunay_core/cell.rs @@ -2,7 +2,7 @@ use uuid::Uuid; use super::{utilities::make_uuid, vertex::Vertex}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Cell { pub vertices: Vec>, pub uuid: Uuid, diff --git a/src/delaunay_core/triangulation_data_structure.rs b/src/delaunay_core/triangulation_data_structure.rs index a4401fe..5d569a3 100644 --- a/src/delaunay_core/triangulation_data_structure.rs +++ b/src/delaunay_core/triangulation_data_structure.rs @@ -1,8 +1,9 @@ use super::{cell::Cell, point::Point, vertex::Vertex}; -use std::collections::HashMap; +use std::cmp::PartialEq; +use std::{cmp::min, collections::HashMap}; use uuid::Uuid; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Tds { pub vertices: HashMap>, pub cells: HashMap>, @@ -14,6 +15,34 @@ impl Tds { let cells = HashMap::new(); Self { vertices, cells } } + + pub fn add(&mut self, vertex: Vertex) -> Result<(), &'static str> + where + T: PartialEq, + { + // Don't add if vertex with that point already exists + for val in self.vertices.values() { + if val.point.coords == vertex.point.coords { + return Err("Vertex already exists"); + } + } + + let result = self.vertices.insert(vertex.uuid, vertex); + match result { + Some(_) => Err("Uuid already exists"), + None => Ok(()), + } + } + + pub fn number_of_vertices(&self) -> usize { + self.vertices.len() + } + + pub fn dim(&self) -> i32 { + let len = self.vertices.len() as i32; + + min(len - 1, D as i32) + } } pub fn start() -> i32 { @@ -27,7 +56,7 @@ mod tests { use super::*; #[test] - fn make_tds() { + fn tds_new() { let points = vec![ Point::new([1.0, 2.0, 3.0]), Point::new([4.0, 5.0, 6.0]), @@ -39,8 +68,68 @@ mod tests { assert_eq!(tds.vertices.len(), 4); assert_eq!(tds.cells.len(), 0); + assert_eq!(tds.dim(), 3); // Human readable output for cargo test -- --nocapture println!("{:?}", tds); } + + #[test] + fn tds_add_dim() { + let points: Vec> = Vec::new(); + + let mut tds: Tds = Tds::new(points); + + assert_eq!(tds.vertices.len(), 0); + assert_eq!(tds.cells.len(), 0); + assert_eq!(tds.dim(), -1); + + let new_vertex1: Vertex = Vertex::new(Point::new([1.0, 2.0, 3.0])); + let _ = tds.add(new_vertex1); + assert_eq!(tds.vertices.len(), 1); + assert_eq!(tds.dim(), 0); + + let new_vertex2: Vertex = Vertex::new(Point::new([4.0, 5.0, 6.0])); + let _ = tds.add(new_vertex2); + assert_eq!(tds.vertices.len(), 2); + assert_eq!(tds.dim(), 1); + + let new_vertex3: Vertex = Vertex::new(Point::new([7.0, 8.0, 9.0])); + let _ = tds.add(new_vertex3); + assert_eq!(tds.vertices.len(), 3); + assert_eq!(tds.dim(), 2); + + let new_vertex4: Vertex = Vertex::new(Point::new([10.0, 11.0, 12.0])); + let _ = tds.add(new_vertex4); + assert_eq!(tds.vertices.len(), 4); + assert_eq!(tds.dim(), 3); + + let new_vertex5: Vertex = Vertex::new(Point::new([13.0, 14.0, 15.0])); + let _ = tds.add(new_vertex5); + assert_eq!(tds.vertices.len(), 5); + assert_eq!(tds.dim(), 3); + } + + #[test] + fn tds_no_add() { + let points = vec![ + Point::new([1.0, 2.0, 3.0]), + Point::new([4.0, 5.0, 6.0]), + Point::new([7.0, 8.0, 9.0]), + Point::new([10.0, 11.0, 12.0]), + ]; + + let mut tds: Tds = Tds::new(points); + + assert_eq!(tds.vertices.len(), 4); + assert_eq!(tds.cells.len(), 0); + assert_eq!(tds.dim(), 3); + + let new_vertex1: Vertex = Vertex::new(Point::new([1.0, 2.0, 3.0])); + let result = tds.add(new_vertex1); + assert_eq!(tds.vertices.len(), 4); + assert_eq!(tds.dim(), 3); + + assert!(result.is_err()); + } }