egml_core/model/geometry/primitives/
shell.rs1use crate::model::common::{
2 ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
3};
4use crate::model::geometry::primitives::{
5 AbstractSurface, AbstractSurfaceProperty, AsAbstractSurface, AsAbstractSurfaceMut,
6 TriangulatedSurface,
7};
8use crate::model::geometry::refs::AbstractGeometryKindRef;
9use crate::model::geometry::{DirectPosition, Envelope};
10use crate::{
11 Error, impl_abstract_surface_mut_traits, impl_abstract_surface_traits, impl_has_geometry_type,
12};
13use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
14use rayon::iter::IntoParallelRefMutIterator;
15use rayon::iter::ParallelIterator;
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct Shell {
19 abstract_surface: AbstractSurface,
20 members: Vec<AbstractSurfaceProperty>,
21}
22
23impl Shell {
24 pub fn new(members: impl IntoIterator<Item = AbstractSurfaceProperty>) -> Result<Self, Error> {
25 let members: Vec<AbstractSurfaceProperty> = members.into_iter().collect();
26 Self::validate(&members)?;
27
28 Ok(Self {
29 abstract_surface: AbstractSurface::default(),
30 members,
31 })
32 }
33
34 pub fn from_abstract_surface(
35 abstract_surface: AbstractSurface,
36 members: impl IntoIterator<Item = AbstractSurfaceProperty>,
37 ) -> Result<Self, Error> {
38 let members: Vec<AbstractSurfaceProperty> = members.into_iter().collect();
39 Self::validate(&members)?;
40
41 Ok(Self {
42 abstract_surface,
43 members,
44 })
45 }
46
47 fn validate(members: &[AbstractSurfaceProperty]) -> Result<(), Error> {
48 if members.is_empty() {
49 return Err(Error::TooFewElements {
50 geometry: "gml:Solid",
51 minimum: 1,
52 spec: Some("OGC 07-036 §10.6.4"),
53 id: None,
54 detail: None,
55 });
56 }
57 Ok(())
58 }
59
60 pub fn members(&self) -> &[AbstractSurfaceProperty] {
62 &self.members
63 }
64
65 pub fn set_members(&mut self, val: Vec<AbstractSurfaceProperty>) -> Result<(), Error> {
71 Self::validate(&val)?;
72
73 self.members = val;
74 Ok(())
75 }
76
77 pub fn push_member(&mut self, member: AbstractSurfaceProperty) {
78 self.members.push(member);
79 }
80
81 pub fn extend_members(&mut self, members: impl IntoIterator<Item = AbstractSurfaceProperty>) {
82 self.members.extend(members);
83 }
84}
85
86impl AsAbstractSurface for Shell {
87 fn abstract_surface(&self) -> &AbstractSurface {
88 &self.abstract_surface
89 }
90}
91
92impl AsAbstractSurfaceMut for Shell {
93 fn abstract_surface_mut(&mut self) -> &mut AbstractSurface {
94 &mut self.abstract_surface
95 }
96}
97
98impl_abstract_surface_traits!(Shell);
99impl_abstract_surface_mut_traits!(Shell);
100impl_has_geometry_type!(Shell, Shell);
101
102impl IterGeometries for Shell {
103 fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
104 Box::new(
105 std::iter::once(self.into()).chain(
106 self.members
107 .iter()
108 .filter_map(|x| x.object())
109 .flat_map(|x| x.iter_geometries()),
110 ),
111 )
112 }
113}
114
115impl Shell {
116 pub fn points(&self) -> Vec<&DirectPosition> {
117 self.members
118 .iter()
119 .flat_map(|x| x.object())
120 .fold(Vec::new(), |mut acc, x| {
121 acc.extend(x.points().iter());
122 acc
123 })
124 }
125
126 pub fn volume_3d(&self) -> Result<f64, Error> {
135 let triangulation = self.triangulate()?;
136 let triangles = triangulation.surface().triangles();
137 let Some(first) = triangles.first() else {
138 return Ok(0.0);
139 };
140
141 let origin: Vector3<f64> = first.a().into();
144 let signed_vol: f64 = triangles
145 .iter()
146 .map(|t| {
147 let a: Vector3<f64> = Into::<Vector3<f64>>::into(t.a()) - origin;
148 let b: Vector3<f64> = Into::<Vector3<f64>>::into(t.b()) - origin;
149 let c: Vector3<f64> = Into::<Vector3<f64>>::into(t.c()) - origin;
150 a.dot(&b.cross(&c))
151 })
152 .sum();
153 Ok(signed_vol.abs() / 6.0)
154 }
155}
156
157impl ApplyTransform for Shell {
158 fn apply_transform(&mut self, transform: Transform3<f64>) {
159 self.members.par_iter_mut().for_each(|p| {
160 if let Some(x) = p.object_mut() {
161 x.apply_transform(transform);
162 }
163 });
164 }
165
166 fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
167 self.members.par_iter_mut().for_each(|p| {
168 if let Some(x) = p.object_mut() {
169 x.apply_isometry(isometry);
170 }
171 });
172 }
173
174 fn apply_translation(&mut self, vector: Vector3<f64>) {
175 self.members.par_iter_mut().for_each(|p| {
176 if let Some(x) = p.object_mut() {
177 x.apply_translation(vector);
178 }
179 });
180 }
181
182 fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
183 self.members.par_iter_mut().for_each(|p| {
184 if let Some(x) = p.object_mut() {
185 x.apply_rotation(rotation);
186 }
187 });
188 }
189
190 fn apply_scale(&mut self, scale: Scale3<f64>) {
191 self.members.par_iter_mut().for_each(|p| {
192 if let Some(x) = p.object_mut() {
193 x.apply_scale(scale);
194 }
195 });
196 }
197}
198
199impl ComputeEnvelope for Shell {
200 fn compute_envelope(&self) -> Option<Envelope> {
202 let envelopes: Vec<Envelope> = self
203 .members
204 .iter()
205 .flat_map(|x| x.object())
206 .flat_map(|x| x.compute_envelope())
207 .collect();
208
209 Envelope::from_envelopes(&envelopes)
210 }
211}
212
213impl Triangulate for Shell {
214 fn triangulate(&self) -> Result<Triangulation, Error> {
222 let mut surfaces = Vec::new();
223 let mut skipped = Vec::new();
224
225 for member in self.members.iter().flat_map(|x| x.object()) {
226 match member.triangulate() {
227 Ok(triangulation) => {
228 let (surface, nested_skipped) = triangulation.into_parts();
229 surfaces.push(surface);
230 skipped.extend(nested_skipped);
231 }
232 Err(error) => {
233 skipped.push(error);
234 }
235 }
236 }
237
238 let combined = TriangulatedSurface::from_triangulated_surfaces(surfaces)?;
239 Ok(Triangulation::new(combined, skipped))
240 }
241}