egml_core/model/geometry/aggregates/
multi_geometry.rs1use 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 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}