Skip to main content

egml_core/model/geometry/primitives/
triangulated_surface.rs

1use crate::error::Error;
2use crate::impl_surface_traits;
3use crate::model::geometry::Envelope;
4use crate::model::geometry::primitives::surface_patch_kind::SurfacePatchKind;
5use crate::model::geometry::primitives::{
6    AsSurface, AsSurfaceMut, Surface, SurfacePatchArrayProperty, Triangle,
7};
8use nalgebra::Isometry3;
9
10/// A 2-D surface composed exclusively of [`Triangle`] patches.
11///
12/// Corresponds to `gml:TriangulatedSurface` in [OGC 07-036 §10.5.11.4](https://docs.ogc.org/is/07-036/07-036.pdf).
13/// This type is the primary output of triangulation operations.
14#[derive(Debug, Clone, PartialEq)]
15pub struct TriangulatedSurface {
16    pub(crate) surface: Surface,
17}
18
19impl TriangulatedSurface {
20    /// Creates a new `TriangulatedSurface` from an existing [`Surface`].
21    pub fn new(surface: Surface) -> Result<Self, Error> {
22        Ok(TriangulatedSurface { surface })
23    }
24
25    pub fn surface(&self) -> &Surface {
26        &self.surface
27    }
28}
29
30impl TriangulatedSurface {
31    /// Creates a `TriangulatedSurface` from a flat list of triangles.
32    ///
33    /// # Errors
34    ///
35    /// Returns [`Error::TooFewElements`] if `triangles` is empty.
36    pub fn from_triangles(triangles: Vec<Triangle>) -> Result<Self, Error> {
37        if triangles.is_empty() {
38            return Err(Error::TooFewElements {
39                geometry: "gml:TriangulatedSurface",
40                minimum: 1,
41                spec: Some("OGC 07-036 §10.5.11.4"),
42                id: None,
43                detail: None,
44            });
45        }
46
47        let patches: Vec<SurfacePatchKind> = triangles
48            .into_iter()
49            .map(SurfacePatchKind::Triangle)
50            .collect();
51        let surface_patch_array_property: SurfacePatchArrayProperty =
52            SurfacePatchArrayProperty::new(patches);
53
54        Self::new(Surface::new(surface_patch_array_property))
55    }
56
57    /// Merges multiple triangulated surfaces into one by combining all their patches.
58    ///
59    /// # Errors
60    ///
61    /// Returns [`Error::TooFewElements`] if `surfaces` is empty.
62    pub fn from_triangulated_surfaces(surfaces: Vec<TriangulatedSurface>) -> Result<Self, Error> {
63        if surfaces.is_empty() {
64            return Err(Error::TooFewElements {
65                geometry: "TriangulatedSurface::from_triangulated_surfaces",
66                minimum: 1,
67                spec: None,
68                id: None,
69                detail: None,
70            });
71        }
72
73        let patches: Vec<SurfacePatchKind> = surfaces
74            .into_iter()
75            .flat_map(|surface| surface.surface.into_patches().patches)
76            .collect();
77
78        let surface_patch_array_property: SurfacePatchArrayProperty =
79            SurfacePatchArrayProperty::new(patches);
80
81        let surface = Surface::new(surface_patch_array_property);
82        Ok(TriangulatedSurface { surface })
83    }
84
85    /// Returns references to all [`Triangle`] patches in this surface.
86    pub fn triangles(&self) -> Vec<&Triangle> {
87        self.surface
88            .patches()
89            .patches()
90            .iter()
91            .filter_map(|patch| match patch {
92                SurfacePatchKind::Triangle(triangle) => Some(triangle),
93                _ => None,
94            })
95            .collect()
96    }
97
98    pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
99        self.surface.apply_transform(m);
100    }
101
102    /// Returns the axis-aligned bounding box of all triangles.
103    pub fn compute_envelope(&self) -> Option<Envelope> {
104        self.surface.compute_envelope()
105    }
106}
107
108impl AsSurface for TriangulatedSurface {
109    fn surface(&self) -> &Surface {
110        &self.surface
111    }
112}
113
114impl AsSurfaceMut for TriangulatedSurface {
115    fn surface_mut(&mut self) -> &mut Surface {
116        &mut self.surface
117    }
118}
119
120impl_surface_traits!(TriangulatedSurface);