Skip to main content

egml_core/model/geometry/aggregates/
multi_geometry.rs

1use crate::model::common::{
2    ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
3};
4use crate::model::geometry::aggregates::{
5    AbstractGeometricAggregate, AsAbstractGeometricAggregate, AsAbstractGeometricAggregateMut,
6};
7use crate::model::geometry::primitives::TriangulatedSurface;
8use crate::model::geometry::refs::AbstractGeometryKindRef;
9use crate::model::geometry::{AbstractGeometryArrayProperty, AbstractGeometryProperty, Envelope};
10use crate::{
11    Error, impl_abstract_geometric_aggregate_mut_traits, impl_abstract_geometric_aggregate_traits,
12    impl_has_geometry_type,
13};
14use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
15use rayon::iter::ParallelIterator;
16use rayon::prelude::IntoParallelRefMutIterator;
17
18#[derive(Debug, Clone, PartialEq)]
19pub struct MultiGeometry {
20    pub abstract_geometric_aggregate: AbstractGeometricAggregate,
21    geometry_members: Option<AbstractGeometryArrayProperty>,
22    geometry_member: Vec<AbstractGeometryProperty>,
23}
24
25impl MultiGeometry {
26    pub fn new(geometry_members: Option<AbstractGeometryArrayProperty>) -> Result<Self, Error> {
27        Ok(Self {
28            abstract_geometric_aggregate: AbstractGeometricAggregate::default(),
29            geometry_members,
30            geometry_member: Vec::new(),
31        })
32    }
33
34    pub fn from_abstract_geometric_aggregate(
35        abstract_geometric_aggregate: AbstractGeometricAggregate,
36        geometry_members: Option<AbstractGeometryArrayProperty>,
37    ) -> Self {
38        Self {
39            abstract_geometric_aggregate,
40            geometry_members,
41            geometry_member: Vec::new(),
42        }
43    }
44
45    pub fn geometry_members(&self) -> Option<&AbstractGeometryArrayProperty> {
46        self.geometry_members.as_ref()
47    }
48
49    pub fn set_geometry_members(&mut self, val: AbstractGeometryArrayProperty) {
50        self.geometry_members = Some(val);
51    }
52
53    pub fn set_geometry_members_opt(&mut self, val: Option<AbstractGeometryArrayProperty>) {
54        self.geometry_members = val;
55    }
56
57    pub fn clear_geometry_members(&mut self) {
58        self.geometry_members = None;
59    }
60
61    pub fn geometry_member(&self) -> &[AbstractGeometryProperty] {
62        &self.geometry_member
63    }
64
65    pub fn set_geometry_member(&mut self, val: Vec<AbstractGeometryProperty>) {
66        self.geometry_member = val;
67    }
68
69    pub fn push_geometry_member(&mut self, member: AbstractGeometryProperty) {
70        self.geometry_member.push(member);
71    }
72
73    pub fn extend_geometry_members(
74        &mut self,
75        members: impl IntoIterator<Item = AbstractGeometryProperty>,
76    ) {
77        self.geometry_member.extend(members);
78    }
79}
80
81impl Triangulate for MultiGeometry {
82    /// Triangulates all surface members and merges them into a single [`TriangulatedSurface`].
83    ///
84    /// Members that fail to triangulate individually (e.g. a degenerate ring) are
85    /// skipped rather than failing the whole aggregate; see their errors via
86    /// [`Triangulation::skipped`].
87    ///
88    /// # Errors
89    ///
90    /// Returns [`Error::TooFewElements`] if no member could be triangulated.
91    fn triangulate(&self) -> Result<Triangulation, Error> {
92        let from_member = self.geometry_member.iter().flat_map(|x| x.object());
93        let from_members = self
94            .geometry_members
95            .iter()
96            .flat_map(|x| x.objects().iter());
97
98        let mut surfaces = Vec::new();
99        let mut skipped = Vec::new();
100
101        for member in from_member.chain(from_members) {
102            match member.triangulate() {
103                Ok(triangulation) => {
104                    let (surface, nested_skipped) = triangulation.into_parts();
105                    surfaces.push(surface);
106                    skipped.extend(nested_skipped);
107                }
108                Err(error) => {
109                    skipped.push(error);
110                }
111            }
112        }
113
114        let combined = TriangulatedSurface::from_triangulated_surfaces(surfaces)?;
115        Ok(Triangulation::new(combined, skipped))
116    }
117}
118
119impl ApplyTransform for MultiGeometry {
120    fn apply_transform(&mut self, transform: Transform3<f64>) {
121        if let Some(members) = &mut self.geometry_members {
122            members
123                .objects_mut()
124                .par_iter_mut()
125                .for_each(|p| p.apply_transform(transform));
126        }
127        self.geometry_member.par_iter_mut().for_each(|p| {
128            if let Some(object) = p.object_mut() {
129                object.apply_transform(transform);
130            }
131        });
132    }
133
134    fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
135        if let Some(members) = &mut self.geometry_members {
136            members
137                .objects_mut()
138                .par_iter_mut()
139                .for_each(|p| p.apply_isometry(isometry));
140        }
141        self.geometry_member.par_iter_mut().for_each(|p| {
142            if let Some(object) = p.object_mut() {
143                object.apply_isometry(isometry);
144            }
145        });
146    }
147
148    fn apply_translation(&mut self, vector: Vector3<f64>) {
149        if let Some(members) = &mut self.geometry_members {
150            members
151                .objects_mut()
152                .par_iter_mut()
153                .for_each(|p| p.apply_translation(vector));
154        }
155        self.geometry_member.par_iter_mut().for_each(|p| {
156            if let Some(object) = p.object_mut() {
157                object.apply_translation(vector);
158            }
159        });
160    }
161
162    fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
163        if let Some(members) = &mut self.geometry_members {
164            members
165                .objects_mut()
166                .par_iter_mut()
167                .for_each(|p| p.apply_rotation(rotation));
168        }
169        self.geometry_member.par_iter_mut().for_each(|p| {
170            if let Some(object) = p.object_mut() {
171                object.apply_rotation(rotation);
172            }
173        });
174    }
175
176    fn apply_scale(&mut self, scale: Scale3<f64>) {
177        if let Some(members) = &mut self.geometry_members {
178            members
179                .objects_mut()
180                .par_iter_mut()
181                .for_each(|p| p.apply_scale(scale));
182        }
183        self.geometry_member.par_iter_mut().for_each(|p| {
184            if let Some(object) = p.object_mut() {
185                object.apply_scale(scale);
186            }
187        });
188    }
189}
190
191impl ComputeEnvelope for MultiGeometry {
192    fn compute_envelope(&self) -> Option<Envelope> {
193        let from_member: Vec<Envelope> = self
194            .geometry_member
195            .iter()
196            .flat_map(|x| x.object())
197            .flat_map(|x| x.compute_envelope())
198            .collect();
199
200        let from_members: Vec<Envelope> = self
201            .geometry_members
202            .iter()
203            .flat_map(|x| x.objects().iter())
204            .flat_map(|x| x.compute_envelope())
205            .collect();
206
207        let envelopes: Vec<Envelope> = from_member.into_iter().chain(from_members).collect();
208        Envelope::from_envelopes(&envelopes)
209    }
210}
211
212impl AsAbstractGeometricAggregate for MultiGeometry {
213    fn abstract_geometric_aggregate(&self) -> &AbstractGeometricAggregate {
214        &self.abstract_geometric_aggregate
215    }
216}
217
218impl AsAbstractGeometricAggregateMut for MultiGeometry {
219    fn abstract_geometric_aggregate_mut(&mut self) -> &mut AbstractGeometricAggregate {
220        &mut self.abstract_geometric_aggregate
221    }
222}
223
224impl_abstract_geometric_aggregate_traits!(MultiGeometry);
225impl_abstract_geometric_aggregate_mut_traits!(MultiGeometry);
226impl_has_geometry_type!(MultiGeometry, MultiGeometry);
227
228impl IterGeometries for MultiGeometry {
229    fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
230        Box::new(
231            std::iter::once(self.into())
232                .chain(
233                    self.geometry_members
234                        .iter()
235                        .flat_map(|members| members.objects().iter())
236                        .flat_map(|x| x.iter_geometries()),
237                )
238                .chain(
239                    self.geometry_member
240                        .iter()
241                        .filter_map(|x| x.object())
242                        .flat_map(|x| x.iter_geometries()),
243                ),
244        )
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251    use crate::model::geometry::AbstractGeometryKind;
252    use crate::model::geometry::DirectPosition;
253    use crate::model::geometry::primitives::{
254        AbstractGeometricPrimitiveKind, AbstractRingKind, AbstractRingProperty,
255        AbstractSurfaceKind, AsSurface, LinearRing, Polygon,
256    };
257
258    fn unit_square_polygon_kind(z: f64) -> AbstractGeometryKind {
259        let ring = LinearRing::new([
260            DirectPosition::new(0.0, 0.0, z).unwrap(),
261            DirectPosition::new(1.0, 0.0, z).unwrap(),
262            DirectPosition::new(1.0, 1.0, z).unwrap(),
263            DirectPosition::new(0.0, 1.0, z).unwrap(),
264        ])
265        .unwrap();
266        let polygon = Polygon::new(
267            Some(AbstractRingProperty::from_object(
268                AbstractRingKind::LinearRing(ring),
269            )),
270            vec![],
271        )
272        .unwrap();
273        AbstractGeometryKind::AbstractGeometricPrimitiveKind(
274            AbstractGeometricPrimitiveKind::AbstractSurfaceKind(AbstractSurfaceKind::Polygon(
275                polygon,
276            )),
277        )
278    }
279
280    #[test]
281    fn triangulate_combines_geometry_member() {
282        let mut multi_geometry = MultiGeometry::new(None).unwrap();
283        multi_geometry.set_geometry_member(vec![
284            AbstractGeometryProperty::from_object(unit_square_polygon_kind(0.0)),
285            AbstractGeometryProperty::from_object(unit_square_polygon_kind(1.0)),
286        ]);
287
288        let triangulated = multi_geometry.triangulate().unwrap();
289
290        assert_eq!(triangulated.surface().patches().objects_len(), 4);
291    }
292
293    #[test]
294    fn triangulate_combines_geometry_members_array() {
295        let geometry_members = AbstractGeometryArrayProperty::from_objects(vec![
296            unit_square_polygon_kind(0.0),
297            unit_square_polygon_kind(1.0),
298        ]);
299        let multi_geometry = MultiGeometry::new(Some(geometry_members)).unwrap();
300
301        let triangulated = multi_geometry.triangulate().unwrap();
302
303        assert_eq!(triangulated.surface().patches().objects_len(), 4);
304    }
305
306    #[test]
307    fn triangulate_combines_both_member_and_members() {
308        let geometry_members =
309            AbstractGeometryArrayProperty::from_objects(vec![unit_square_polygon_kind(1.0)]);
310        let mut multi_geometry = MultiGeometry::new(Some(geometry_members)).unwrap();
311        multi_geometry.set_geometry_member(vec![AbstractGeometryProperty::from_object(
312            unit_square_polygon_kind(0.0),
313        )]);
314
315        let triangulated = multi_geometry.triangulate().unwrap();
316
317        assert_eq!(triangulated.surface().patches().objects_len(), 4);
318    }
319}