spade/lib.rs
1//! # Spade
2//!
3//! Delaunay triangulations for the rust ecosystem.
4//!
5//! # Features
6//! * A 2D Delaunay triangulation: [DelaunayTriangulation]
7//! * Uses exact geometric predicate evaluation, preventing construction errors due to precision loss.
8//! * A 2D constrained Delaunay triangulation: [ConstrainedDelaunayTriangulation]
9//! * Supports vertex removal
10//! * Serde support with the `serde` feature.
11//! * `no_std` support with `default-features = false`
12//! * Natural neighbor interpolation: [NaturalNeighbor]
13//!
14//! # Cargo features
15//!
16//! These features are disabled by default and need to be enabled in your `Cargo.toml`:
17//! - `serde`: Enable (de)serialization of (constrained) Delaunay triangulations with the
18//! [Serde](https://docs.rs/serde/latest/serde/) crate
19//! - `mint`: Enables rudimentary [mint](https://docs.rs/mint/latest/mint/) interoperability by
20//! implementing the `From` and `Into` conversion traits between `spade::Point2` and
21//! `mint::Point2`. Also implements [HasPosition] for `mint::Point2`.
22
23#![no_std]
24#![forbid(unsafe_code)]
25#![warn(clippy::all)]
26#![deny(rustdoc::broken_intra_doc_links)]
27#![cfg_attr(not(fuzzing), warn(missing_docs))]
28#![cfg_attr(fuzzing, allow(unused_imports))]
29
30#[cfg(feature = "std")]
31extern crate std;
32
33extern crate alloc;
34
35mod cdt;
36mod delaunay_core;
37mod delaunay_triangulation;
38mod flood_fill_iterator;
39mod intersection_iterator;
40mod point;
41
42mod triangulation;
43
44pub use crate::cdt::{CdtEdge, ConstrainedDelaunayTriangulation};
45pub use crate::delaunay_triangulation::DelaunayTriangulation;
46pub use crate::point::{HasPosition, Point2, SpadeNum};
47
48pub use crate::delaunay_core::math::{
49 mitigate_underflow, validate_coordinate, validate_vertex, InsertionError, PointProjection,
50 MAX_ALLOWED_VALUE, MIN_ALLOWED_VALUE,
51};
52
53pub use delaunay_core::{
54 AngleLimit, HierarchyHintGenerator, HierarchyHintGeneratorWithBranchFactor, HintGenerator,
55 LastUsedVertexHintGenerator, RefinementParameters, RefinementResult,
56};
57
58pub use crate::delaunay_core::interpolation::{Barycentric, NaturalNeighbor};
59pub use delaunay_core::LineSideInfo;
60pub use intersection_iterator::{Intersection, LineIntersectionIterator};
61pub use triangulation::{FloatTriangulation, PositionInTriangulation, Triangulation};
62
63#[cfg(not(fuzzing))]
64pub(crate) use delaunay_core::TriangulationExt;
65
66#[cfg(fuzzing)]
67pub use delaunay_core::TriangulationExt;
68
69pub(crate) use delaunay_core::RemovalResult;
70
71#[cfg(feature = "mint")]
72mod mint_support;
73#[cfg(test)]
74mod test_utilities;
75
76/// Handle types used for traversal and modification of triangulations.
77///
78/// A handle can either be a "reference handle" or a "fixed handle". Reference handles are
79/// used for immutable access to a triangulation. Fixed handles allow mutation but have a
80/// more limited API.
81///
82/// # Reference handles
83///
84/// Reference handles come in one of four variants:
85/// * [FaceHandle](handles::FaceHandle)s refer to a single face (triangle) of the triangulation.
86/// They are used get the triangle's adjacent vertices and edges. They also may refer to
87/// the single outer face.
88/// * [VertexHandle](handles::VertexHandle)s refer to a single vertex of the triangulation. They
89/// allow to retrieve the vertex position and its outgoing edges.
90/// * [DirectedEdgeHandle](handles::DirectedEdgeHandle)s refer to a single directed edge. They
91/// allow to retrieve the edges origin and destination vertex, its adjacent face as well as
92/// its previous and next edge.
93/// * [UndirectedEdgeHandle](handles::UndirectedEdgeHandle)s refer to an edge without specifying its
94/// direction.
95///
96/// All handles also allow to set and retrieve arbitrary additional data associated with that
97/// element. Refer to the type parameters of [Triangulation] for more details.
98///
99/// # Fixed handles
100/// Reference handles all hold an immutable reference to the underlying triangulation.
101/// This reference is used to implement a feature rich and intuitive API. However,
102/// due to Rust's ownership semantics, modification of a triangulation
103/// can not be done using these handles as that would require a mutable reference. This is
104/// required in some cases, e.g. whenever traversal of the triangulation is mixed with insertion
105/// operations or when attempting to remove vertices.
106/// As a solution, Spade relies on _fixed_ handles for mutation: These are created from normal
107/// handles by calling `some_handle.fix()` and do not keep a reference to the triangulation.
108///
109/// Internally, fixed handles are implemented as indices into a `Vec`. **Removing elements from
110/// the triangulation can possibly invalidate any fixed handle**. Attempting to resolve an invalid
111/// handle may either refer to a different element or panic at run time. It is the callers
112/// responsibility to make sure that fixed handles are not used anymore after a removal operation
113/// has taken place.
114///
115/// Fixed handles also come in four variants, depending on which element they refer to:
116/// * [FixedVertexHandle](handles::FixedVertexHandle)
117/// * [FixedFaceHandle](handles::FixedFaceHandle)
118/// * [FixedDirectedEdgeHandle](handles::FixedDirectedEdgeHandle)
119/// * [FixedUndirectedEdgeHandle](handles::FixedUndirectedEdgeHandle)
120///
121/// # Retrieving handles by iteration
122///
123/// The [Triangulation] trait defines iterators for all handle types:
124///
125/// | | Vertices | Directed Edges | Undirected Edges | Faces |
126/// |----------------|----------|-----------------|------------------|-------|
127/// | **Reference** | [vertices()](Triangulation::vertices()) | [directed_edges()](Triangulation::directed_edges) | [undirected_edges()](Triangulation::undirected_edges()) | [inner_faces()](Triangulation::inner_faces())<br>[all_faces()](Triangulation::all_faces()) |
128/// | **Fixed** | [fixed_vertices()](Triangulation::fixed_vertices()) | [fixed_directed_edges()](Triangulation::fixed_directed_edges()) | [fixed_undirected_edges()](Triangulation::fixed_undirected_edges()) | [fixed_inner_faces()](Triangulation::fixed_inner_faces())<br> [fixed_faces()](Triangulation::fixed_inner_faces()) |
129///
130/// # Creating handles directly
131///
132/// In some cases it may be desirable to create vertex handles artificially by providing the index
133/// manually. This can be done by calling [handles::FixedVertexHandle::from_index](from_index(usize)).
134/// Make sure that the provided index is smaller than the number of vertices in the triangulation.
135///
136/// # Converting between reference and fixed handles
137///
138/// Converting a reference handle into its fixed counterpart is performed via the
139/// `fix()` method (defined on any handle type).
140///
141/// Converting a fixed handle type back into a reference handle requires calling either
142/// [Triangulation::vertex], [Triangulation::face],
143/// [Triangulation::directed_edge] or [Triangulation::undirected_edge].
144///
145/// # Example: Using handles
146/// This example implements a nearest neighbor algorithm on a delaunay triangulation. Starting
147/// from an arbitrary start vertex, it greedily walks to the closes vertex until arriving at a
148/// local minimum. Due to the special properties of Delaunay triangulations, this is also the
149/// global nearest neighbor.
150///
151/// _Note: Spade already implements this method, see [DelaunayTriangulation::nearest_neighbor]_
152/// ```
153/// use spade::handles::VertexHandle;
154/// use spade::{DelaunayTriangulation, Point2, Triangulation};
155///
156/// fn nearest_neighbor(
157/// triangulation: &DelaunayTriangulation<Point2<f64>>,
158/// target_point: Point2<f64>,
159/// ) -> VertexHandle<Point2<f64>> {
160/// let mut current = triangulation.vertices().next().unwrap();
161/// let mut best_distance = current.position().distance_2(target_point);
162/// loop {
163/// let mut closer = None;
164/// for neighbor in current.out_edges().map(|edge| edge.to()) {
165/// let neighbor_distance = neighbor.position().distance_2(target_point);
166/// if neighbor_distance < best_distance {
167/// best_distance = neighbor_distance;
168/// closer = Some(neighbor);
169/// break;
170/// }
171/// }
172///
173/// if let Some(closer) = closer {
174/// current = closer;
175/// } else {
176/// return current;
177/// }
178/// }
179/// }
180///
181/// # fn try_main() -> Result<(), spade::InsertionError> {
182///
183/// let vertices = vec![
184/// Point2::new(0.0, 1.0),
185/// Point2::new(1.0, 1.0),
186/// Point2::new(0.0, 0.0),
187/// Point2::new(1.0, 0.0),
188/// ];
189/// let triangulation: DelaunayTriangulation<Point2<f64>> = Triangulation::bulk_load(vertices)?;
190///
191/// // Check that everything works!
192/// for vertex in triangulation.vertices() {
193/// let nearest_neighbor = nearest_neighbor(&triangulation, vertex.position());
194/// assert_eq!(nearest_neighbor, vertex);
195/// }
196/// # Ok(()) }
197/// # fn main() { try_main().unwrap() }
198/// ```
199pub mod handles {
200 pub use crate::delaunay_core::{
201 DirectedEdgeHandle, DirectedVoronoiEdge, FaceHandle, FixedDirectedEdgeHandle,
202 FixedFaceHandle, FixedUndirectedEdgeHandle, FixedVertexHandle, InnerTag, PossiblyOuterTag,
203 UndirectedEdgeHandle, UndirectedVoronoiEdge, VertexHandle, VoronoiFace, VoronoiVertex,
204 OUTER_FACE,
205 };
206}
207
208/// Iterators over various elements of Delaunay triangulations.
209pub mod iterators {
210 pub use crate::delaunay_core::iterators::{
211 DirectedEdgeIterator, DirectedVoronoiEdgeIterator, FaceIterator, FixedDirectedEdgeIterator,
212 FixedFaceIterator, FixedInnerFaceIterator, FixedUndirectedEdgeIterator,
213 FixedVertexIterator, InnerFaceIterator, UndirectedEdgeIterator,
214 UndirectedVoronoiEdgeIterator, VertexIterator, VoronoiFaceIterator,
215 };
216 pub use crate::flood_fill_iterator::{
217 CircleMetric, EdgesInShapeIterator, RectangleMetric, VerticesInShapeIterator,
218 };
219}
220
221/// Internals that must be published due to technical reasons. This is not the place you are
222/// looking for. A change to these items is not considered to be a breaking change.
223pub mod internals {
224 pub use crate::delaunay_core::{DynamicHandleImpl, FixedHandleImpl};
225}