egml_core/model/geometry/aggregates/
multi_surface.rs1use crate::error::Error;
2use crate::model::base::HasAssociationAttributes;
3use crate::model::common::{
4 ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
5};
6use crate::model::geometry::aggregates::{
7 AbstractGeometricAggregate, AsAbstractGeometricAggregate, AsAbstractGeometricAggregateMut,
8};
9use crate::model::geometry::primitives::AbstractSurfaceProperty;
10use crate::model::geometry::primitives::TriangulatedSurface;
11use crate::model::geometry::refs::AbstractGeometryKindRef;
12use crate::model::geometry::{DirectPosition, Envelope};
13use crate::{
14 impl_abstract_geometric_aggregate_mut_traits, impl_abstract_geometric_aggregate_traits,
15 impl_has_geometry_type,
16};
17use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
18use rayon::prelude::*;
19
20#[derive(Debug, Clone, PartialEq)]
24pub struct MultiSurface {
25 pub abstract_geometric_aggregate: AbstractGeometricAggregate,
26 surface_member: Vec<AbstractSurfaceProperty>,
27}
28
29impl MultiSurface {
30 pub fn new(members: impl IntoIterator<Item = AbstractSurfaceProperty>) -> Result<Self, Error> {
36 let members: Vec<AbstractSurfaceProperty> = members.into_iter().collect();
37 Self::validate(&members)?;
38
39 Ok(Self {
40 abstract_geometric_aggregate: AbstractGeometricAggregate::default(),
41 surface_member: members,
42 })
43 }
44
45 pub fn from_abstract_geometric_aggregate(
46 abstract_geometric_aggregate: AbstractGeometricAggregate,
47 members: impl IntoIterator<Item = AbstractSurfaceProperty>,
48 ) -> Result<Self, Error> {
49 let members: Vec<AbstractSurfaceProperty> = members.into_iter().collect();
50 Self::validate(&members)?;
51
52 Ok(Self {
53 abstract_geometric_aggregate,
54 surface_member: members,
55 })
56 }
57
58 fn validate(members: &[AbstractSurfaceProperty]) -> Result<(), Error> {
59 if members.is_empty() {
60 return Err(Error::TooFewElements {
61 geometry: "gml:MultiSurface",
62 minimum: 1,
63 spec: Some("OGC 07-036 §11.3.4.1"),
64 id: None,
65 detail: None,
66 });
67 }
68 Ok(())
69 }
70
71 pub fn surface_member(&self) -> &[AbstractSurfaceProperty] {
73 &self.surface_member
74 }
75
76 pub fn set_surface_member(&mut self, val: Vec<AbstractSurfaceProperty>) -> Result<(), Error> {
82 Self::validate(&val)?;
83
84 self.surface_member = val;
85 Ok(())
86 }
87
88 pub fn push_surface_member(&mut self, member: AbstractSurfaceProperty) {
89 self.surface_member.push(member);
90 }
91
92 pub fn extend_surface_members(
93 &mut self,
94 members: impl IntoIterator<Item = AbstractSurfaceProperty>,
95 ) {
96 self.surface_member.extend(members);
97 }
98}
99
100impl AsAbstractGeometricAggregate for MultiSurface {
101 fn abstract_geometric_aggregate(&self) -> &AbstractGeometricAggregate {
102 &self.abstract_geometric_aggregate
103 }
104}
105
106impl AsAbstractGeometricAggregateMut for MultiSurface {
107 fn abstract_geometric_aggregate_mut(&mut self) -> &mut AbstractGeometricAggregate {
108 &mut self.abstract_geometric_aggregate
109 }
110}
111
112impl_abstract_geometric_aggregate_traits!(MultiSurface);
113impl_abstract_geometric_aggregate_mut_traits!(MultiSurface);
114impl_has_geometry_type!(MultiSurface, MultiSurface);
115
116impl MultiSurface {
117 pub fn points(&self) -> Vec<&DirectPosition> {
118 self.surface_member
119 .iter()
120 .flat_map(|x| x.object())
121 .fold(Vec::new(), |mut acc, x| {
122 acc.extend(x.points().iter());
123 acc
124 })
125 }
126
127 pub fn area_3d(&self) -> Result<f64, Error> {
135 self.surface_member
136 .iter()
137 .map(|s| {
138 s.object()
139 .ok_or_else(|| Error::UnresolvedSurfaceReference {
140 href: s.href().as_ref().map(|h| h.to_string()),
141 })
142 .and_then(|kind| kind.area_3d())
143 })
144 .collect::<Result<Vec<f64>, Error>>()
145 .map(|area_3ds| area_3ds.into_iter().sum())
146 }
147}
148
149impl Triangulate for MultiSurface {
150 fn triangulate(&self) -> Result<Triangulation, Error> {
158 let mut surfaces = Vec::new();
159 let mut skipped = Vec::new();
160
161 for member in self.surface_member.iter().flat_map(|x| x.object()) {
162 match member.triangulate() {
163 Ok(triangulation) => {
164 let (surface, nested_skipped) = triangulation.into_parts();
165 surfaces.push(surface);
166 skipped.extend(nested_skipped);
167 }
168 Err(error) => {
169 skipped.push(error);
170 }
171 }
172 }
173
174 let combined = TriangulatedSurface::from_triangulated_surfaces(surfaces)?;
175 Ok(Triangulation::new(combined, skipped))
176 }
177}
178
179impl ApplyTransform for MultiSurface {
180 fn apply_transform(&mut self, transform: Transform3<f64>) {
181 self.surface_member.par_iter_mut().for_each(|p| {
182 if let Some(x) = p.object_mut() {
183 x.apply_transform(transform);
184 }
185 });
186 }
187
188 fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
189 self.surface_member.par_iter_mut().for_each(|p| {
190 if let Some(x) = p.object_mut() {
191 x.apply_isometry(isometry);
192 }
193 });
194 }
195
196 fn apply_translation(&mut self, vector: Vector3<f64>) {
197 self.surface_member.par_iter_mut().for_each(|p| {
198 if let Some(x) = p.object_mut() {
199 x.apply_translation(vector);
200 }
201 });
202 }
203
204 fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
205 self.surface_member.par_iter_mut().for_each(|p| {
206 if let Some(x) = p.object_mut() {
207 x.apply_rotation(rotation);
208 }
209 });
210 }
211
212 fn apply_scale(&mut self, scale: Scale3<f64>) {
213 self.surface_member.par_iter_mut().for_each(|p| {
214 if let Some(x) = p.object_mut() {
215 x.apply_scale(scale);
216 }
217 });
218 }
219}
220
221impl ComputeEnvelope for MultiSurface {
222 fn compute_envelope(&self) -> Option<Envelope> {
224 let envelopes: Vec<Envelope> = self
225 .surface_member
226 .iter()
227 .flat_map(|x| x.object())
228 .flat_map(|x| x.compute_envelope())
229 .collect();
230
231 Envelope::from_envelopes(&envelopes)
232 }
233}
234
235impl IterGeometries for MultiSurface {
236 fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
237 Box::new(
238 std::iter::once(self.into()).chain(
239 self.surface_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::Error;
252 use crate::model::geometry::DirectPosition;
253 use crate::model::geometry::primitives::{
254 AbstractRingKind, AbstractRingProperty, AbstractSurfaceKind, LinearRing,
255 };
256
257 fn unit_square_polygon(z: f64) -> AbstractSurfaceKind {
258 let ring = LinearRing::new([
259 DirectPosition::new(0.0, 0.0, z).unwrap(),
260 DirectPosition::new(1.0, 0.0, z).unwrap(),
261 DirectPosition::new(1.0, 1.0, z).unwrap(),
262 DirectPosition::new(0.0, 1.0, z).unwrap(),
263 ])
264 .unwrap();
265 let polygon = crate::model::geometry::primitives::Polygon::new(
266 Some(AbstractRingProperty::from_object(
267 AbstractRingKind::LinearRing(ring),
268 )),
269 vec![],
270 )
271 .unwrap();
272 AbstractSurfaceKind::Polygon(polygon)
273 }
274
275 #[test]
276 fn area_3d_two_unit_squares() {
277 let multi_surface = MultiSurface::new([
278 AbstractSurfaceProperty::from_object(unit_square_polygon(0.0)),
279 AbstractSurfaceProperty::from_object(unit_square_polygon(1.0)),
280 ])
281 .unwrap();
282 assert!((multi_surface.area_3d().unwrap() - 2.0).abs() < 1e-10);
283 }
284
285 #[test]
286 fn iter_geometries_yields_self_each_polygon_and_each_ring() {
287 let multi_surface = MultiSurface::new([
288 AbstractSurfaceProperty::from_object(unit_square_polygon(0.0)),
289 AbstractSurfaceProperty::from_object(unit_square_polygon(1.0)),
290 ])
291 .unwrap();
292
293 assert_eq!(multi_surface.iter_geometries().count(), 5);
295 }
296
297 #[test]
298 fn area_3d_unresolved_surface_reference() {
299 let multi_surface = MultiSurface::new([AbstractSurfaceProperty::from_href(
300 "urn:example:surface-1".into(),
301 )])
302 .unwrap();
303 assert_eq!(
304 multi_surface.area_3d(),
305 Err(Error::UnresolvedSurfaceReference {
306 href: Some("urn:example:surface-1".to_string())
307 })
308 );
309 }
310}