Skip to main content

egml_core/model/geometry/primitives/
polygon_patch.rs

1use crate::Error;
2use crate::model::base::HasAssociationAttributes;
3use crate::model::common::{ApplyTransform, ComputeEnvelope, Triangulate, Triangulation};
4use crate::model::geometry::Envelope;
5use crate::model::geometry::primitives::surface_interpolation::SurfaceInterpolation;
6use crate::model::geometry::primitives::{
7    AbstractRingProperty, AbstractSurfacePatch, AsAbstractSurfacePatch, AsAbstractSurfacePatchMut,
8};
9use crate::util::triangulate::triangulate;
10use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
11use rayon::iter::IntoParallelRefMutIterator;
12use rayon::iter::ParallelIterator;
13
14/// A planar polygon used as a surface patch inside a [`Surface`](crate::model::geometry::primitives::Surface).
15///
16/// `PolygonPatch` has the same geometry as [`Polygon`](crate::model::geometry::primitives::Polygon)
17/// but is used exclusively as a building block of a patched surface rather than
18/// as a standalone geometry element.  Corresponds to `gml:PolygonPatch` in [OGC 07-036 ยง10.5.12.4](https://docs.ogc.org/is/07-036/07-036.pdf).
19#[derive(Debug, Clone, PartialEq)]
20pub struct PolygonPatch {
21    pub abstract_surface_patch: AbstractSurfacePatch,
22    exterior: Option<AbstractRingProperty>,
23    interior: Vec<AbstractRingProperty>,
24    interpolation: SurfaceInterpolation,
25}
26
27impl PolygonPatch {
28    pub fn new(
29        exterior: Option<AbstractRingProperty>,
30        interior: impl IntoIterator<Item = AbstractRingProperty>,
31    ) -> Self {
32        Self {
33            abstract_surface_patch: AbstractSurfacePatch::default(),
34            exterior,
35            interior: interior.into_iter().collect(),
36            interpolation: SurfaceInterpolation::Planar,
37        }
38    }
39
40    pub fn from_abstract_surface_patch(
41        abstract_surface_patch: AbstractSurfacePatch,
42        exterior: Option<AbstractRingProperty>,
43        interior: impl IntoIterator<Item = AbstractRingProperty>,
44    ) -> Self {
45        Self {
46            abstract_surface_patch,
47            exterior,
48            interior: interior.into_iter().collect(),
49            interpolation: SurfaceInterpolation::Planar,
50        }
51    }
52
53    pub fn exterior(&self) -> Option<&AbstractRingProperty> {
54        self.exterior.as_ref()
55    }
56
57    pub fn set_exterior(&mut self, exterior: AbstractRingProperty) {
58        self.exterior = Some(exterior);
59    }
60
61    pub fn set_exterior_opt(&mut self, exterior: Option<AbstractRingProperty>) {
62        self.exterior = exterior;
63    }
64
65    pub fn clear_exterior(&mut self) {
66        self.exterior = None;
67    }
68
69    pub fn interior(&self) -> &[AbstractRingProperty] {
70        &self.interior
71    }
72
73    pub fn set_interior(&mut self, interior: Vec<AbstractRingProperty>) {
74        self.interior = interior;
75    }
76
77    pub fn push_interior(&mut self, ring: AbstractRingProperty) {
78        self.interior.push(ring);
79    }
80
81    pub fn extend_interiors(&mut self, rings: impl IntoIterator<Item = AbstractRingProperty>) {
82        self.interior.extend(rings);
83    }
84
85    pub fn interpolation(&self) -> SurfaceInterpolation {
86        self.interpolation
87    }
88}
89
90impl AsAbstractSurfacePatch for PolygonPatch {
91    fn abstract_surface_patch(&self) -> &AbstractSurfacePatch {
92        &self.abstract_surface_patch
93    }
94}
95
96impl AsAbstractSurfacePatchMut for PolygonPatch {
97    fn abstract_surface_patch_mut(&mut self) -> &mut AbstractSurfacePatch {
98        &mut self.abstract_surface_patch
99    }
100}
101
102impl PolygonPatch {
103    pub fn area_3d(&self) -> Result<f64, Error> {
104        let exterior_ring = self.exterior.as_ref().ok_or(Error::MissingExteriorRing)?;
105        let exterior = exterior_ring
106            .object()
107            .ok_or_else(|| Error::UnresolvedRingReference {
108                href: exterior_ring.href().map(|h| h.to_string()),
109            })?
110            .area_3d();
111
112        let holes = self
113            .interior
114            .iter()
115            .map(|r| {
116                r.object()
117                    .ok_or_else(|| Error::UnresolvedRingReference {
118                        href: r.href().map(|h| h.to_string()),
119                    })
120                    .map(|ring| ring.area_3d())
121            })
122            .collect::<Result<Vec<f64>, Error>>()?
123            .into_iter()
124            .sum::<f64>();
125
126        Ok(exterior - holes)
127    }
128}
129
130impl ApplyTransform for PolygonPatch {
131    fn apply_transform(&mut self, transform: Transform3<f64>) {
132        if let Some(exterior) = &mut self.exterior
133            && let Some(object) = exterior.object_mut()
134        {
135            object.apply_transform(transform);
136        }
137
138        self.interior.par_iter_mut().for_each(|p| {
139            if let Some(object) = p.object_mut() {
140                object.apply_transform(transform);
141            }
142        });
143    }
144
145    fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
146        if let Some(exterior) = &mut self.exterior
147            && let Some(object) = exterior.object_mut()
148        {
149            object.apply_isometry(isometry);
150        }
151
152        self.interior.par_iter_mut().for_each(|p| {
153            if let Some(object) = p.object_mut() {
154                object.apply_isometry(isometry);
155            }
156        });
157    }
158
159    fn apply_translation(&mut self, vector: Vector3<f64>) {
160        if let Some(exterior) = &mut self.exterior
161            && let Some(object) = exterior.object_mut()
162        {
163            object.apply_translation(vector);
164        }
165
166        self.interior.par_iter_mut().for_each(|p| {
167            if let Some(object) = p.object_mut() {
168                object.apply_translation(vector);
169            }
170        });
171    }
172
173    fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
174        if let Some(exterior) = &mut self.exterior
175            && let Some(object) = exterior.object_mut()
176        {
177            object.apply_rotation(rotation);
178        }
179
180        self.interior.par_iter_mut().for_each(|p| {
181            if let Some(object) = p.object_mut() {
182                object.apply_rotation(rotation);
183            }
184        });
185    }
186
187    fn apply_scale(&mut self, scale: Scale3<f64>) {
188        if let Some(exterior) = &mut self.exterior
189            && let Some(object) = exterior.object_mut()
190        {
191            object.apply_scale(scale);
192        }
193
194        self.interior.par_iter_mut().for_each(|p| {
195            if let Some(object) = p.object_mut() {
196                object.apply_scale(scale);
197            }
198        });
199    }
200}
201
202impl ComputeEnvelope for PolygonPatch {
203    fn compute_envelope(&self) -> Option<Envelope> {
204        if let Some(exterior) = &self.exterior
205            && let Some(object) = exterior.object()
206            && let Some(e) = object.compute_envelope()
207        {
208            return Some(e);
209        }
210
211        let envelopes = self
212            .interior
213            .iter()
214            .filter_map(|x| x.object())
215            .filter_map(|x| x.compute_envelope())
216            .collect::<Vec<_>>();
217
218        Envelope::from_envelopes(&envelopes)
219    }
220}
221
222impl Triangulate for PolygonPatch {
223    fn triangulate(&self) -> Result<Triangulation, Error> {
224        let exterior = match self.exterior.clone() {
225            Some(x) => x,
226            None => {
227                todo!("triangulate polygon patch with no exterior ring needs to be implemented")
228            }
229        };
230
231        let surface = triangulate(Some(exterior), self.interior.clone())?;
232        Ok(Triangulation::new(surface, Vec::new()))
233    }
234}