egml_core/model/geometry/aggregates/
multi_surface.rs1use crate::error::Error;
2use crate::impl_abstract_geometric_aggregate_traits;
3use crate::model::geometry::aggregates::{
4 AbstractGeometricAggregate, AsAbstractGeometricAggregate, AsAbstractGeometricAggregateMut,
5};
6use crate::model::geometry::primitives::SurfaceProperty;
7use crate::model::geometry::primitives::TriangulatedSurface;
8use crate::model::geometry::{DirectPosition, Envelope};
9use nalgebra::Isometry3;
10use rayon::prelude::*;
11
12#[derive(Debug, Clone, PartialEq)]
16pub struct MultiSurface {
17 pub(crate) abstract_geometric_aggregate: AbstractGeometricAggregate,
18 surface_member: Vec<SurfaceProperty>,
19}
20
21impl MultiSurface {
22 pub fn new(members: impl IntoIterator<Item = SurfaceProperty>) -> Result<Self, Error> {
28 let members: Vec<SurfaceProperty> = members.into_iter().collect();
29 if members.is_empty() {
30 return Err(Error::TooFewElements {
31 geometry: "gml:MultiSurface",
32 minimum: 1,
33 spec: Some("OGC 07-036 §11.3.4.1"),
34 id: None,
35 detail: None,
36 });
37 }
38
39 Ok(Self {
40 abstract_geometric_aggregate: AbstractGeometricAggregate::default(),
41 surface_member: members,
42 })
43 }
44
45 pub fn surface_member(&self) -> &[SurfaceProperty] {
47 &self.surface_member
48 }
49
50 pub fn set_surface_member(&mut self, val: Vec<SurfaceProperty>) -> Result<(), Error> {
56 if val.is_empty() {
57 return Err(Error::TooFewElements {
58 geometry: "gml:MultiSurface",
59 minimum: 1,
60 spec: Some("OGC 07-036 §11.3.4.1"),
61 id: None,
62 detail: None,
63 });
64 }
65 self.surface_member = val;
66 Ok(())
67 }
68
69 pub fn push_surface_member(&mut self, member: SurfaceProperty) {
70 self.surface_member.push(member);
71 }
72
73 pub fn extend_surface_members(&mut self, members: impl IntoIterator<Item = SurfaceProperty>) {
74 self.surface_member.extend(members);
75 }
76}
77
78impl MultiSurface {
79 pub fn triangulate(&self) -> Result<TriangulatedSurface, Error> {
85 let triangulated_surfaces: Vec<TriangulatedSurface> = self
86 .surface_member
87 .iter()
88 .flat_map(|x| x.object.as_ref())
89 .map(|x| x.triangulate())
90 .collect::<Result<Vec<TriangulatedSurface>, Error>>()?;
91
92 let combined_triangulated_surface =
93 TriangulatedSurface::from_triangulated_surfaces(triangulated_surfaces)?;
94 Ok(combined_triangulated_surface)
95 }
96
97 pub fn points(&self) -> Vec<&DirectPosition> {
98 self.surface_member
99 .iter()
100 .flat_map(|x| x.object.as_ref())
101 .fold(Vec::new(), |mut acc, x| {
102 acc.extend(x.points().iter());
103 acc
104 })
105 }
106
107 pub fn area_3d(&self) -> Result<f64, Error> {
115 self.surface_member
116 .iter()
117 .map(|s| {
118 s.object
119 .as_ref()
120 .ok_or_else(|| Error::UnresolvedSurfaceReference {
121 href: s.href.clone(),
122 })
123 .and_then(|kind| kind.area_3d())
124 })
125 .collect::<Result<Vec<f64>, Error>>()
126 .map(|area_3ds| area_3ds.into_iter().sum())
127 }
128
129 pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
130 self.surface_member.par_iter_mut().for_each(|p| {
131 if let Some(x) = p.object.as_mut() {
132 x.apply_transform(m);
133 }
134 });
135 }
136
137 pub fn compute_envelope(&self) -> Option<Envelope> {
139 let envelopes: Vec<Envelope> = self
140 .surface_member
141 .iter()
142 .flat_map(|x| x.object.as_ref())
143 .flat_map(|x| x.compute_envelope())
144 .collect();
145
146 Envelope::from_envelopes(&envelopes)
147 }
148}
149
150impl AsAbstractGeometricAggregate for MultiSurface {
151 fn abstract_geometric_aggregate(&self) -> &AbstractGeometricAggregate {
152 &self.abstract_geometric_aggregate
153 }
154}
155
156impl AsAbstractGeometricAggregateMut for MultiSurface {
157 fn abstract_geometric_aggregate_mut(&mut self) -> &mut AbstractGeometricAggregate {
158 &mut self.abstract_geometric_aggregate
159 }
160}
161
162impl_abstract_geometric_aggregate_traits!(MultiSurface);
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::Error;
168 use crate::model::geometry::DirectPosition;
169 use crate::model::geometry::primitives::{LinearRing, RingKind, RingProperty, SurfaceKind};
170
171 fn unit_square_polygon(z: f64) -> SurfaceKind {
172 let ring = LinearRing::new([
173 DirectPosition::new(0.0, 0.0, z).unwrap(),
174 DirectPosition::new(1.0, 0.0, z).unwrap(),
175 DirectPosition::new(1.0, 1.0, z).unwrap(),
176 DirectPosition::new(0.0, 1.0, z).unwrap(),
177 ])
178 .unwrap();
179 let polygon = crate::model::geometry::primitives::Polygon::new(
180 Some(RingProperty::new(RingKind::LinearRing(ring))),
181 vec![],
182 )
183 .unwrap();
184 SurfaceKind::Polygon(polygon)
185 }
186
187 #[test]
188 fn area_3d_two_unit_squares() {
189 let multi_surface = MultiSurface::new([
190 SurfaceProperty::new(unit_square_polygon(0.0)),
191 SurfaceProperty::new(unit_square_polygon(1.0)),
192 ])
193 .unwrap();
194 assert!((multi_surface.area_3d().unwrap() - 2.0).abs() < 1e-10);
195 }
196
197 #[test]
198 fn area_3d_unresolved_surface_reference() {
199 let multi_surface = MultiSurface::new([SurfaceProperty::new_href(
200 "urn:example:surface-1".to_string(),
201 )])
202 .unwrap();
203 assert_eq!(
204 multi_surface.area_3d(),
205 Err(Error::UnresolvedSurfaceReference {
206 href: Some("urn:example:surface-1".to_string())
207 })
208 );
209 }
210}