Skip to main content

egml_core/model/geometry/primitives/
surface.rs

1use crate::Error;
2use crate::model::geometry::primitives::{
3    AbstractSurface, AsAbstractSurface, AsAbstractSurfaceMut, SurfacePatchArrayProperty,
4    TriangulatedSurface,
5};
6use crate::model::geometry::{DirectPosition, Envelope};
7use nalgebra::Isometry3;
8
9/// A 2-D geometry composed of one or more surface patches.
10///
11/// Corresponds to `gml:Surface` in [OGC 07-036 ยง10.5.10](https://docs.ogc.org/is/07-036/07-036.pdf).  Patches are stored as
12/// a [`SurfacePatchArrayProperty`] and may be of mixed kinds (polygons, triangles).
13#[derive(Debug, Clone, PartialEq)]
14pub struct Surface {
15    pub(crate) abstract_surface: AbstractSurface,
16    patches: SurfacePatchArrayProperty,
17}
18
19impl Surface {
20    /// Creates a new `Surface` from a patch array.
21    pub fn new(patches: SurfacePatchArrayProperty) -> Self {
22        Surface {
23            abstract_surface: AbstractSurface::default(),
24            patches,
25        }
26    }
27
28    pub fn patches(&self) -> &SurfacePatchArrayProperty {
29        &self.patches
30    }
31}
32
33impl Surface {
34    pub(crate) fn into_patches(self) -> SurfacePatchArrayProperty {
35        self.patches
36    }
37
38    /// Decomposes this surface into a [`TriangulatedSurface`] by triangulating each patch.
39    ///
40    /// # Errors
41    ///
42    /// Returns [`Error::TriangulationFailed`] if any patch cannot be triangulated.
43    pub fn triangulate(&self) -> Result<TriangulatedSurface, Error> {
44        let a = self.patches.patches.iter().map(|patch| patch.triangulate());
45        let b = a.collect::<Result<Vec<TriangulatedSurface>, Error>>()?;
46        TriangulatedSurface::from_triangulated_surfaces(b)
47    }
48
49    /// Returns the union of the bounding boxes of all patches.
50    pub fn compute_envelope(&self) -> Option<Envelope> {
51        self.patches.compute_envelope()
52    }
53
54    pub fn area_3d(&self) -> Result<f64, Error> {
55        self.patches.area_3d()
56    }
57
58    pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
59        self.patches.apply_transform(m)
60    }
61
62    pub fn points(&self) -> Vec<&DirectPosition> {
63        todo!("needs to be implemented")
64    }
65}
66
67/// Object-safe read accessor for [`Surface`] data.
68pub trait AsSurface: AsAbstractSurface {
69    /// Returns a reference to the underlying [`Surface`].
70    fn surface(&self) -> &Surface;
71
72    /// Returns the patch array of this surface.
73    fn patches(&self) -> &SurfacePatchArrayProperty {
74        &self.surface().patches
75    }
76
77    fn patches_len(&self) -> usize {
78        self.patches().patches_len()
79    }
80}
81
82/// Mutable companion to [`AsSurface`].
83pub trait AsSurfaceMut: AsSurface + AsAbstractSurfaceMut {
84    /// Returns a mutable reference to the underlying [`Surface`].
85    fn surface_mut(&mut self) -> &mut Surface;
86
87    fn patches_mut(&mut self) -> &mut SurfacePatchArrayProperty {
88        &mut self.surface_mut().patches
89    }
90}
91
92impl AsSurface for Surface {
93    fn surface(&self) -> &Surface {
94        self
95    }
96}
97
98impl AsSurfaceMut for Surface {
99    fn surface_mut(&mut self) -> &mut Surface {
100        self
101    }
102}
103
104#[doc(hidden)]
105#[macro_export]
106macro_rules! impl_surface_traits {
107    ($type:ty) => {
108        $crate::impl_abstract_surface_traits!($type);
109
110        impl $crate::model::geometry::primitives::AsAbstractSurface for $type {
111            fn abstract_surface(&self) -> &$crate::model::geometry::primitives::AbstractSurface {
112                use $crate::model::geometry::primitives::AsSurface;
113                &self.surface().abstract_surface
114            }
115        }
116
117        impl $crate::model::geometry::primitives::AsAbstractSurfaceMut for $type {
118            fn abstract_surface_mut(
119                &mut self,
120            ) -> &mut $crate::model::geometry::primitives::AbstractSurface {
121                use $crate::model::geometry::primitives::AsSurfaceMut;
122                &mut self.surface_mut().abstract_surface
123            }
124        }
125    };
126}
127
128impl_surface_traits!(Surface);