egml_core/model/geometry/complexes/
composite_surface.rs1use crate::model::base::HasAssociationAttributes;
2use crate::model::common::{
3 ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
4};
5use crate::model::geometry::aggregates::AggregationType;
6use crate::model::geometry::primitives::{
7 AbstractSurface, AbstractSurfaceProperty, AsAbstractSurface, AsAbstractSurfaceMut,
8 TriangulatedSurface,
9};
10use crate::model::geometry::refs::AbstractGeometryKindRef;
11use crate::model::geometry::{DirectPosition, Envelope};
12use crate::{
13 Error, impl_abstract_surface_mut_traits, impl_abstract_surface_traits, impl_has_geometry_type,
14};
15use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
16use rayon::iter::IntoParallelRefMutIterator;
17use rayon::iter::ParallelIterator;
18
19#[derive(Debug, Clone, PartialEq)]
26pub struct CompositeSurface {
27 pub abstract_surface: AbstractSurface,
28 surface_member: Vec<AbstractSurfaceProperty>,
29 aggregation_type: AggregationType,
30}
31
32impl CompositeSurface {
33 pub fn new(
39 surface_member: impl IntoIterator<Item = AbstractSurfaceProperty>,
40 aggregation_type: AggregationType,
41 ) -> Result<Self, Error> {
42 let surface_member: Vec<AbstractSurfaceProperty> = surface_member.into_iter().collect();
43 Self::validate(&surface_member)?;
44
45 Ok(CompositeSurface {
46 abstract_surface: AbstractSurface::default(),
47 surface_member,
48 aggregation_type,
49 })
50 }
51
52 pub fn from_abstract_surface(
53 abstract_surface: AbstractSurface,
54 surface_member: impl IntoIterator<Item = AbstractSurfaceProperty>,
55 aggregation_type: AggregationType,
56 ) -> Result<Self, Error> {
57 let surface_member: Vec<AbstractSurfaceProperty> = surface_member.into_iter().collect();
58 Self::validate(&surface_member)?;
59
60 Ok(Self {
61 abstract_surface,
62 surface_member,
63 aggregation_type,
64 })
65 }
66
67 fn validate(members: &[AbstractSurfaceProperty]) -> Result<(), Error> {
68 if members.is_empty() {
69 return Err(Error::TooFewElements {
70 geometry: "gml:CompositeSurface",
71 minimum: 1,
72 spec: Some("OGC 07-036 §10.5.11.4"),
73 id: None,
74 detail: None,
75 });
76 }
77 Ok(())
78 }
79
80 pub fn surface_member(&self) -> &[AbstractSurfaceProperty] {
82 &self.surface_member
83 }
84
85 pub fn set_surface_member(
91 &mut self,
92 surface_members: Vec<AbstractSurfaceProperty>,
93 ) -> Result<(), Error> {
94 Self::validate(&surface_members)?;
95 self.surface_member = surface_members;
96 Ok(())
97 }
98
99 pub fn push_surface_member(&mut self, member: AbstractSurfaceProperty) {
100 self.surface_member.push(member);
101 }
102
103 pub fn extend_surface_members(
104 &mut self,
105 members: impl IntoIterator<Item = AbstractSurfaceProperty>,
106 ) {
107 self.surface_member.extend(members);
108 }
109
110 pub fn aggregation_type(&self) -> AggregationType {
112 self.aggregation_type
113 }
114
115 pub fn set_aggregation_type(&mut self, aggregation_type: AggregationType) {
116 self.aggregation_type = aggregation_type;
117 }
118}
119
120impl AsAbstractSurface for CompositeSurface {
121 fn abstract_surface(&self) -> &AbstractSurface {
122 &self.abstract_surface
123 }
124}
125
126impl AsAbstractSurfaceMut for CompositeSurface {
127 fn abstract_surface_mut(&mut self) -> &mut AbstractSurface {
128 &mut self.abstract_surface
129 }
130}
131
132impl_abstract_surface_traits!(CompositeSurface);
133impl_abstract_surface_mut_traits!(CompositeSurface);
134impl_has_geometry_type!(CompositeSurface, CompositeSurface);
135
136impl CompositeSurface {
137 pub fn surface_member_count(&self) -> usize {
139 self.surface_member.len()
140 }
141
142 pub fn area_3d(&self) -> Result<f64, Error> {
143 self.surface_member
144 .iter()
145 .map(|s| {
146 s.object()
147 .ok_or_else(|| Error::UnresolvedSurfaceReference {
148 href: s.href().map(|h| h.to_string()),
149 })
150 .and_then(|kind| kind.area_3d())
151 })
152 .collect::<Result<Vec<f64>, Error>>()
153 .map(|area_3ds| area_3ds.into_iter().sum())
154 }
155
156 pub fn points(&self) -> Vec<&DirectPosition> {
160 self.surface_member
161 .iter()
162 .flat_map(|s| s.object())
163 .flat_map(|kind| kind.points())
164 .collect()
165 }
166}
167
168impl ApplyTransform for CompositeSurface {
169 fn apply_transform(&mut self, transform: Transform3<f64>) {
170 self.surface_member
171 .par_iter_mut()
172 .flat_map(|x| x.object_mut())
173 .for_each(|x| x.apply_transform(transform));
174 }
175
176 fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
177 self.surface_member
178 .par_iter_mut()
179 .flat_map(|x| x.object_mut())
180 .for_each(|x| x.apply_isometry(isometry));
181 }
182
183 fn apply_translation(&mut self, vector: Vector3<f64>) {
184 self.surface_member
185 .par_iter_mut()
186 .flat_map(|x| x.object_mut())
187 .for_each(|x| x.apply_translation(vector));
188 }
189
190 fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
191 self.surface_member
192 .par_iter_mut()
193 .flat_map(|x| x.object_mut())
194 .for_each(|x| x.apply_rotation(rotation));
195 }
196
197 fn apply_scale(&mut self, scale: Scale3<f64>) {
198 self.surface_member
199 .par_iter_mut()
200 .flat_map(|x| x.object_mut())
201 .for_each(|x| x.apply_scale(scale));
202 }
203}
204
205impl ComputeEnvelope for CompositeSurface {
206 fn compute_envelope(&self) -> Option<Envelope> {
208 let envelopes: Vec<Envelope> = self
209 .surface_member
210 .iter()
211 .flat_map(|x| x.object())
212 .flat_map(|x| x.compute_envelope())
213 .collect::<Vec<_>>();
214
215 Envelope::from_envelopes(&envelopes)
216 }
217}
218
219impl IterGeometries for CompositeSurface {
220 fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
221 Box::new(
222 std::iter::once(self.into()).chain(
223 self.surface_member
224 .iter()
225 .filter_map(|x| x.object())
226 .flat_map(|x| x.iter_geometries()),
227 ),
228 )
229 }
230}
231
232impl Triangulate for CompositeSurface {
233 fn triangulate(&self) -> Result<Triangulation, Error> {
241 let mut surfaces = Vec::new();
242 let mut skipped = Vec::new();
243
244 for member in self.surface_member.iter().flat_map(|x| x.object()) {
245 match member.triangulate() {
246 Ok(triangulation) => {
247 let (surface, nested_skipped) = triangulation.into_parts();
248 surfaces.push(surface);
249 skipped.extend(nested_skipped);
250 }
251 Err(error) => {
252 skipped.push(error);
253 }
254 }
255 }
256
257 let combined = TriangulatedSurface::from_triangulated_surfaces(surfaces)?;
258 Ok(Triangulation::new(combined, skipped))
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use crate::model::geometry::primitives::{
266 AbstractRingKind, AbstractSurfaceKind, LinearRing, Polygon,
267 };
268
269 fn unit_square(z: f64) -> AbstractSurfaceProperty {
270 let ring = LinearRing::new([
271 DirectPosition::new(0.0, 0.0, z).unwrap(),
272 DirectPosition::new(1.0, 0.0, z).unwrap(),
273 DirectPosition::new(1.0, 1.0, z).unwrap(),
274 DirectPosition::new(0.0, 1.0, z).unwrap(),
275 ])
276 .unwrap();
277 let polygon = Polygon::new(Some(AbstractRingKind::LinearRing(ring)), []).unwrap();
278 AbstractSurfaceProperty::from_object(AbstractSurfaceKind::Polygon(polygon))
279 }
280
281 #[test]
282 fn points_collects_all_members() {
283 let composite =
284 CompositeSurface::new([unit_square(0.0), unit_square(1.0)], AggregationType::Set)
285 .unwrap();
286 let points = composite.points();
287 assert_eq!(points.len(), 8);
288 assert_eq!(points[4], &DirectPosition::new(0.0, 0.0, 1.0).unwrap());
289 }
290
291 #[test]
292 fn points_skips_unresolved_members() {
293 let composite = CompositeSurface::new(
294 [
295 unit_square(0.0),
296 AbstractSurfaceProperty::from_href("urn:example:surface-1".into()),
297 ],
298 AggregationType::Set,
299 )
300 .unwrap();
301 assert_eq!(composite.points().len(), 4);
302 }
303}