egml_core/model/geometry/primitives/
polygon_patch.rs1use 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#[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}