logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//! Incremental polygonal mesh construction.
//!
//! This module provides traits for incrementally constructing mesh data
//! structures. This API allows for meshes to be constructed in a way that is
//! agnostic to the specific data structure used to represent the mesh.
//!
//! [`Buildable`] is the primary trait of this API. It is implemented by mesh
//! data structures and exposes various associated types for their associated
//! data.  [`Buildable`] exposes a builder type via its
//! [`builder`][`Buildable::builder`] function. This builder type in turn
//! provides additional builders that can be used to construct a mesh from
//! _surfaces_ and _facets_.
//!
//! # Examples
//!
//! A function that generates a triangle from point geometry using builders:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! #
//! use nalgebra::Point2;
//! use plexus::buffer::MeshBuffer3;
//! use plexus::builder::Buildable;
//! use plexus::geometry::FromGeometry;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//!
//! type E2 = Point2<f64>;
//!
//! fn trigon<B, T>(points: [T; 3]) -> Result<B, B::Error>
//! where
//!     B: Buildable,
//!     B::Vertex: FromGeometry<T>,
//! {
//!     let mut builder = B::builder();
//!     builder.surface_with(|builder| {
//!         let [a, b, c] = points;
//!         let a = builder.insert_vertex(a)?;
//!         let b = builder.insert_vertex(b)?;
//!         let c = builder.insert_vertex(c)?;
//!         builder.facets_with(|builder| builder.insert_facet(&[a, b, c], B::Facet::default()))
//!     })?;
//!     builder.build()
//! }
//!
//! // `MeshBuffer` and `MeshGraph` implement the `Buildable` trait.
//! let graph: MeshGraph<E2> = trigon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)]).unwrap();
//! let buffer: MeshBuffer3<usize, E2> = trigon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)]).unwrap();
//! ```
//!
//! [`Buildable::builder`]: crate::builder::Buildable::builder
//! [`Buildable`]: crate::builder::Buildable

// TODO: Is it useful to use a separate `FacetBuilder` type?
// TODO: Keys are not opaque. Especially for `MeshBuffer`, it may be possible to
//       "forge" keys. This could be prevented by using a wrapper type that is
//       not exported, but would introduce a performance cost to map and collect
//       slices of keys.

use std::fmt::Debug;
use std::hash::Hash;

use crate::geometry::FromGeometry;
use crate::transact::ClosedInput;

/// Polygonal mesh data structure that can be built incrementally.
///
/// This trait is the primary entrypoint into the builder API. Types that
/// implement this trait expose a [`MeshBuilder`] that can be used to construct
/// an instance of the type from surfaces and facets.
///
/// [`MeshBuilder`]: crate::builder::MeshBuilder
pub trait Buildable: Sized {
    type Builder: MeshBuilder<
        Commit = Self,
        Error = Self::Error,
        Vertex = Self::Vertex,
        Facet = Self::Facet,
    >;
    type Error: Debug;

    /// Vertex data.
    ///
    /// This type represents the data associated with vertices in the mesh.
    /// This typically includes positional data, but no data is required and
    /// this type may be the unit type `()`.
    ///
    /// Each builder trait also exposes such an associated type which is
    /// constrained by the `Builder` type.
    type Vertex;
    /// Facet data.
    ///
    /// This type represents the data associated with facets in the mesh. No
    /// data is required and this type may be the unit type `()`.
    ///
    /// Each builder trait also exposes such an associated type which is
    /// constrained by the `Builder` type.
    type Facet: Default;

    fn builder() -> Self::Builder;
}

/// Incremental polygonal mesh builder.
///
/// This trait exposes types that allow for mesh data structures to be
/// constructed incrementally from _surfaces_ and _facets_. A _surface_ is a
/// collection of vertices and facets connecting those vertices and typically
/// describes a _manifold_. A _facet_ is the connectivity between vertices in a
/// surface. Facets may also include associated data.
///
/// Construction is hierarchical, beginning with a surface and its vertices and
/// then facets. The association between a surface, its vertices, and facets is
/// enforced by the API, which accepts functions that operate on increasingly
/// specific builder types. The [`build`][`MeshBuilder::build`] function is used
/// to complete the construction of a mesh.
///
/// Builders may emit errors at any stage and errors depend on the
/// implementation of the builder types (and by extension the details of the
/// underlying data structure).
///
/// [`MeshBuilder::build`]: crate::builder::MeshBuilder::build
pub trait MeshBuilder: ClosedInput {
    type Builder: SurfaceBuilder<Error = Self::Error, Vertex = Self::Vertex, Facet = Self::Facet>;

    type Vertex;
    type Facet: Default;

    /// Constructs a surface.
    ///
    /// The given function is invoked with a [`SurfaceBuilder`], which can be
    /// used to insert vertices and construct facets.
    ///
    /// [`SurfaceBuilder`]: crate::builder::SurfaceBuilder
    fn surface_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>
    where
        Self::Error: From<E>,
        F: FnOnce(&mut Self::Builder) -> Result<T, E>;

    /// Builds the mesh.
    ///
    /// The builder is consumed and a mesh with the constructed surfaces and
    /// facets is produced.
    ///
    /// # Errors
    ///
    /// Returns a latent error if the constructed surfaces and facets are
    /// incompatible with the underlying data structure. May return other
    /// errors depending on the details of the implementation.
    fn build(self) -> Result<Self::Commit, Self::Error> {
        self.commit().map_err(|(_, error)| error)
    }
}

pub trait SurfaceBuilder: ClosedInput {
    type Builder: FacetBuilder<Self::Key, Error = Self::Error, Facet = Self::Facet>;
    /// Vertex key.
    ///
    /// Each vertex is associated with a key of this type. This key is used to
    /// reference a given vertex and is required to insert faces with a
    /// [`FacetBuilder`].
    ///
    /// [`FacetBuilder`]: crate::builder::FacetBuilder
    type Key: Copy + Eq + Hash;

    type Vertex;
    type Facet: Default;

    /// Constructs facets in the surface.
    ///
    /// The given function is invoked with a [`FacetBuilder`], which can be used
    /// to insert facets.
    ///
    /// [`FacetBuilder`]: crate::builder::FacetBuilder
    fn facets_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>
    where
        Self::Error: From<E>,
        F: FnOnce(&mut Self::Builder) -> Result<T, E>;

    /// Inserts a vertex into the surface.
    ///
    /// Returns a key that refers to the inserted vertex. This key can be used
    /// to insert facets with a [`FacetBuilder`].
    ///
    /// [`FacetBuilder`]: crate::builder::FacetBuilder
    fn insert_vertex<T>(&mut self, data: T) -> Result<Self::Key, Self::Error>
    where
        Self::Vertex: FromGeometry<T>;
}

pub trait FacetBuilder<K>: ClosedInput
where
    K: Eq + Hash,
{
    /// Facet key.
    ///
    /// Each facet is associated with a key of this type.
    type Key: Copy + Eq + Hash;

    type Facet: Default;

    /// Inserts a facet into the associated surface.
    ///
    /// A facet is formed from connectivity between vertices represented by an
    /// ordered slice of vertex keys from the associated [`SurfaceBuilder`].
    ///
    /// Returns a key that refers to the inserted facet.
    ///
    /// [`SurfaceBuilder`]: crate::builder::SurfaceBuilder
    fn insert_facet<T, U>(&mut self, keys: T, data: U) -> Result<Self::Key, Self::Error>
    where
        Self::Facet: FromGeometry<U>,
        T: AsRef<[K]>;
}