egml_core/model/geometry/primitives/
surface.rs1use crate::Error;
2use crate::impl_has_geometry_type;
3use crate::model::common::{
4 ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
5};
6use crate::model::geometry::primitives::{
7 AbstractSurface, AbstractSurfacePatchKind, AsAbstractSurface, AsAbstractSurfaceMut,
8 TriangulatedSurface,
9};
10use crate::model::geometry::refs::AbstractGeometryKindRef;
11use crate::model::geometry::{DirectPosition, Envelope};
12use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
13
14#[derive(Debug, Clone, PartialEq)]
19pub struct Surface {
20 pub abstract_surface: AbstractSurface,
21 patches: Vec<AbstractSurfacePatchKind>,
22}
23
24impl Surface {
25 pub fn new(patches: Vec<AbstractSurfacePatchKind>) -> Self {
27 Surface {
28 abstract_surface: AbstractSurface::default(),
29 patches,
30 }
31 }
32
33 pub fn from_abstract_surface(
34 abstract_surface: AbstractSurface,
35 patches: Vec<AbstractSurfacePatchKind>,
36 ) -> Self {
37 Self {
38 abstract_surface,
39 patches,
40 }
41 }
42
43 pub fn patches(&self) -> &[AbstractSurfacePatchKind] {
44 &self.patches
45 }
46}
47
48pub trait AsSurface: AsAbstractSurface {
50 fn surface(&self) -> &Surface;
52
53 fn patches(&self) -> &[AbstractSurfacePatchKind] {
55 &self.surface().patches
56 }
57
58 fn patches_len(&self) -> usize {
59 self.patches().len()
60 }
61}
62
63pub trait AsSurfaceMut: AsSurface + AsAbstractSurfaceMut {
65 fn surface_mut(&mut self) -> &mut Surface;
67
68 fn patches_mut(&mut self) -> &mut Vec<AbstractSurfacePatchKind> {
69 &mut self.surface_mut().patches
70 }
71}
72
73impl AsSurface for Surface {
74 fn surface(&self) -> &Surface {
75 self
76 }
77}
78
79impl AsSurfaceMut for Surface {
80 fn surface_mut(&mut self) -> &mut Surface {
81 self
82 }
83}
84
85#[macro_export]
86macro_rules! impl_surface_traits {
87 ($type:ty) => {
88 $crate::impl_abstract_surface_traits!($type);
89
90 impl $crate::model::geometry::primitives::AsAbstractSurface for $type {
91 fn abstract_surface(&self) -> &$crate::model::geometry::primitives::AbstractSurface {
92 &<$type as $crate::model::geometry::primitives::AsSurface>::surface(self)
93 .abstract_surface
94 }
95 }
96 };
97}
98
99#[macro_export]
100macro_rules! impl_surface_mut_traits {
101 ($type:ty) => {
102 $crate::impl_abstract_surface_mut_traits!($type);
103
104 impl $crate::model::geometry::primitives::AsAbstractSurfaceMut for $type {
105 fn abstract_surface_mut(
106 &mut self,
107 ) -> &mut $crate::model::geometry::primitives::AbstractSurface {
108 &mut <$type as $crate::model::geometry::primitives::AsSurfaceMut>::surface_mut(self)
109 .abstract_surface
110 }
111 }
112 };
113}
114
115impl_surface_traits!(Surface);
116impl_surface_mut_traits!(Surface);
117impl_has_geometry_type!(Surface, Surface);
118
119impl Surface {
120 pub(crate) fn into_patches(self) -> Vec<AbstractSurfacePatchKind> {
121 self.patches
122 }
123
124 pub fn area_3d(&self) -> Result<f64, Error> {
125 self.patches
126 .iter()
127 .map(|p| p.area_3d())
128 .collect::<Result<Vec<f64>, Error>>()
129 .map(|area_3ds| area_3ds.into_iter().sum())
130 }
131
132 pub fn points(&self) -> Vec<&DirectPosition> {
134 self.patches.iter().flat_map(|p| p.points()).collect()
135 }
136}
137
138impl IterGeometries for Surface {
139 fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
140 Box::new(std::iter::once(self.into()))
141 }
142}
143
144impl ApplyTransform for Surface {
145 fn apply_transform(&mut self, transform: Transform3<f64>) {
146 self.patches
147 .iter_mut()
148 .for_each(|x| x.apply_transform(transform));
149 }
150
151 fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
152 self.patches
153 .iter_mut()
154 .for_each(|x| x.apply_isometry(isometry));
155 }
156
157 fn apply_translation(&mut self, vector: Vector3<f64>) {
158 self.patches
159 .iter_mut()
160 .for_each(|x| x.apply_translation(vector));
161 }
162
163 fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
164 self.patches
165 .iter_mut()
166 .for_each(|x| x.apply_rotation(rotation));
167 }
168
169 fn apply_scale(&mut self, scale: Scale3<f64>) {
170 self.patches.iter_mut().for_each(|x| x.apply_scale(scale));
171 }
172}
173
174impl ComputeEnvelope for Surface {
175 fn compute_envelope(&self) -> Option<Envelope> {
177 let envelopes: Vec<Envelope> = self
178 .patches
179 .iter()
180 .flat_map(|x| x.compute_envelope())
181 .collect();
182
183 Envelope::from_envelopes(&envelopes)
184 }
185}
186
187impl Triangulate for Surface {
188 fn triangulate(&self) -> Result<Triangulation, Error> {
196 let mut surfaces = Vec::new();
197 let mut skipped = Vec::new();
198
199 for patch in &self.patches {
200 match patch.triangulate() {
201 Ok(triangulation) => {
202 let (surface, nested_skipped) = triangulation.into_parts();
203 surfaces.push(surface);
204 skipped.extend(nested_skipped);
205 }
206 Err(error) => {
207 skipped.push(error);
208 }
209 }
210 }
211
212 let combined = TriangulatedSurface::from_triangulated_surfaces(surfaces)?;
213 Ok(Triangulation::new(combined, skipped))
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use crate::model::geometry::primitives::{
221 AbstractRingKind, AbstractSurfacePatchKind, LinearRing, PolygonPatch, Triangle,
222 };
223
224 fn pos(x: f64, y: f64, z: f64) -> DirectPosition {
225 DirectPosition::new(x, y, z).unwrap()
226 }
227
228 #[test]
229 fn points_collects_all_patches() {
230 let square = LinearRing::new([
231 pos(0., 0., 0.),
232 pos(1., 0., 0.),
233 pos(1., 1., 0.),
234 pos(0., 1., 0.),
235 ])
236 .unwrap();
237 let patch = PolygonPatch::new(Some(AbstractRingKind::LinearRing(square)), []);
238 let triangle =
239 Triangle::from_points(pos(0., 0., 1.), pos(1., 0., 1.), pos(0., 1., 1.)).unwrap();
240 let surface = Surface::new(vec![
241 AbstractSurfacePatchKind::PolygonPatch(patch),
242 AbstractSurfacePatchKind::Triangle(triangle),
243 ]);
244
245 let points = surface.points();
246 assert_eq!(points.len(), 7);
247 assert_eq!(points[0], &pos(0., 0., 0.));
248 assert_eq!(points[4], &pos(0., 0., 1.));
249 }
250}