Skip to main content

ecitygml_core/model/core/
abstract_space.rs

1use crate::model::common::LevelOfDetail;
2use crate::model::core::{
3    AbstractCityObject, AsAbstractCityObjectMut, AsAbstractFeature, RelativeToTerrain,
4    RelativeToWater, SpaceType,
5};
6use crate::model::core::{AsAbstractCityObject, AsAbstractFeatureMut};
7use egml::model::geometry::Envelope;
8use egml::model::geometry::aggregates::{MultiCurve, MultiSurface};
9use egml::model::geometry::primitives::Solid;
10use nalgebra::Isometry3;
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, PartialEq)]
14pub struct AbstractSpace {
15    pub(crate) abstract_city_object: AbstractCityObject,
16
17    pub(crate) space_type: Option<SpaceType>,
18    pub(crate) relative_to_terrain: Option<RelativeToTerrain>,
19    pub(crate) relative_to_water: Option<RelativeToWater>,
20
21    pub(crate) lod1_solid: Option<Solid>,
22    pub(crate) lod2_solid: Option<Solid>,
23    pub(crate) lod3_solid: Option<Solid>,
24
25    pub(crate) lod0_multi_surface: Option<MultiSurface>,
26    pub(crate) lod2_multi_surface: Option<MultiSurface>,
27    pub(crate) lod3_multi_surface: Option<MultiSurface>,
28
29    pub(crate) lod0_multi_curve: Option<MultiCurve>,
30    pub(crate) lod2_multi_curve: Option<MultiCurve>,
31    pub(crate) lod3_multi_curve: Option<MultiCurve>,
32}
33
34impl AbstractSpace {
35    pub fn new(abstract_city_object: AbstractCityObject) -> Self {
36        Self {
37            abstract_city_object,
38            space_type: None,
39            relative_to_terrain: None,
40            relative_to_water: None,
41            lod1_solid: None,
42            lod2_solid: None,
43            lod3_solid: None,
44            lod0_multi_surface: None,
45            lod2_multi_surface: None,
46            lod3_multi_surface: None,
47            lod0_multi_curve: None,
48            lod2_multi_curve: None,
49            lod3_multi_curve: None,
50        }
51    }
52}
53
54pub trait AsAbstractSpace: AsAbstractCityObject {
55    fn abstract_space(&self) -> &AbstractSpace;
56
57    fn space_type(&self) -> Option<&SpaceType> {
58        self.abstract_space().space_type.as_ref()
59    }
60
61    fn relative_to_terrain(&self) -> Option<&RelativeToTerrain> {
62        self.abstract_space().relative_to_terrain.as_ref()
63    }
64
65    fn relative_to_water(&self) -> Option<&RelativeToWater> {
66        self.abstract_space().relative_to_water.as_ref()
67    }
68
69    fn lod1_solid(&self) -> Option<&Solid> {
70        self.abstract_space().lod1_solid.as_ref()
71    }
72
73    fn lod2_solid(&self) -> Option<&Solid> {
74        self.abstract_space().lod2_solid.as_ref()
75    }
76
77    fn lod3_solid(&self) -> Option<&Solid> {
78        self.abstract_space().lod3_solid.as_ref()
79    }
80
81    fn solids_by_lod(&self) -> HashMap<LevelOfDetail, &Solid> {
82        let mut map = HashMap::new();
83        if let Some(x) = self.lod1_solid() {
84            map.insert(LevelOfDetail::One, x);
85        }
86        if let Some(x) = self.lod2_solid() {
87            map.insert(LevelOfDetail::Two, x);
88        }
89        if let Some(x) = self.lod3_solid() {
90            map.insert(LevelOfDetail::Three, x);
91        }
92        map
93    }
94
95    fn lod0_multi_surface(&self) -> Option<&MultiSurface> {
96        self.abstract_space().lod0_multi_surface.as_ref()
97    }
98
99    fn lod2_multi_surface(&self) -> Option<&MultiSurface> {
100        self.abstract_space().lod2_multi_surface.as_ref()
101    }
102
103    fn lod3_multi_surface(&self) -> Option<&MultiSurface> {
104        self.abstract_space().lod3_multi_surface.as_ref()
105    }
106
107    fn multi_surfaces_by_lod(&self) -> HashMap<LevelOfDetail, &MultiSurface> {
108        let mut map = HashMap::new();
109        if let Some(x) = self.lod0_multi_surface() {
110            map.insert(LevelOfDetail::Zero, x);
111        }
112        if let Some(x) = self.lod2_multi_surface() {
113            map.insert(LevelOfDetail::Two, x);
114        }
115        if let Some(x) = self.lod3_multi_surface() {
116            map.insert(LevelOfDetail::Three, x);
117        }
118        map
119    }
120
121    fn lod0_multi_curve(&self) -> Option<&MultiCurve> {
122        self.abstract_space().lod0_multi_curve.as_ref()
123    }
124
125    fn lod2_multi_curve(&self) -> Option<&MultiCurve> {
126        self.abstract_space().lod2_multi_curve.as_ref()
127    }
128
129    fn lod3_multi_curve(&self) -> Option<&MultiCurve> {
130        self.abstract_space().lod3_multi_curve.as_ref()
131    }
132
133    fn multi_curves_by_lod(&self) -> HashMap<LevelOfDetail, &MultiCurve> {
134        let mut map = HashMap::new();
135        if let Some(x) = self.lod0_multi_curve() {
136            map.insert(LevelOfDetail::Zero, x);
137        }
138        if let Some(x) = self.lod2_multi_curve() {
139            map.insert(LevelOfDetail::Two, x);
140        }
141        if let Some(x) = self.lod3_multi_curve() {
142            map.insert(LevelOfDetail::Three, x);
143        }
144        map
145    }
146
147    fn compute_envelope(&self) -> Option<Envelope> {
148        let envelopes: Vec<Envelope> = vec![
149            self.lod1_solid().map(|x| x.compute_envelope()),
150            self.lod2_solid().map(|x| x.compute_envelope()),
151            self.lod3_solid().map(|x| x.compute_envelope()),
152            self.lod0_multi_surface().map(|x| x.compute_envelope()),
153            self.lod2_multi_surface().map(|x| x.compute_envelope()),
154            self.lod3_multi_surface().map(|x| x.compute_envelope()),
155            self.lod0_multi_curve().map(|x| x.compute_envelope()),
156            self.lod2_multi_curve().map(|x| x.compute_envelope()),
157            self.lod3_multi_curve().map(|x| x.compute_envelope()),
158        ]
159        .into_iter()
160        .flatten()
161        .collect();
162
163        Envelope::from_envelopes(&envelopes)
164    }
165}
166
167pub trait AsAbstractSpaceMut: AsAbstractCityObjectMut + AsAbstractSpace {
168    fn abstract_space_mut(&mut self) -> &mut AbstractSpace;
169
170    fn set_space_type(&mut self, value: Option<SpaceType>) {
171        self.abstract_space_mut().space_type = value;
172    }
173
174    fn set_relative_to_terrain(&mut self, value: Option<RelativeToTerrain>) {
175        self.abstract_space_mut().relative_to_terrain = value;
176    }
177
178    fn set_relative_to_water(&mut self, value: Option<RelativeToWater>) {
179        self.abstract_space_mut().relative_to_water = value;
180    }
181
182    fn set_lod1_solid(&mut self, value: Option<Solid>) {
183        self.abstract_space_mut().lod1_solid = value;
184    }
185
186    fn set_lod2_solid(&mut self, value: Option<Solid>) {
187        self.abstract_space_mut().lod2_solid = value;
188    }
189
190    fn set_lod3_solid(&mut self, value: Option<Solid>) {
191        self.abstract_space_mut().lod3_solid = value;
192    }
193
194    fn set_lod0_multi_surface(&mut self, value: Option<MultiSurface>) {
195        self.abstract_space_mut().lod0_multi_surface = value;
196    }
197
198    fn set_lod2_multi_surface(&mut self, value: Option<MultiSurface>) {
199        self.abstract_space_mut().lod2_multi_surface = value;
200    }
201
202    fn set_lod3_multi_surface(&mut self, value: Option<MultiSurface>) {
203        self.abstract_space_mut().lod3_multi_surface = value;
204    }
205
206    fn set_lod0_multi_curve(&mut self, value: Option<MultiCurve>) {
207        self.abstract_space_mut().lod0_multi_curve = value;
208    }
209
210    fn set_lod2_multi_curve(&mut self, value: Option<MultiCurve>) {
211        self.abstract_space_mut().lod2_multi_curve = value;
212    }
213
214    fn set_lod3_multi_curve(&mut self, value: Option<MultiCurve>) {
215        self.abstract_space_mut().lod3_multi_curve = value;
216    }
217
218    fn refresh_bounded_by(&mut self) {
219        let envelope = self.compute_envelope();
220        self.set_bounded_by(envelope);
221    }
222
223    fn apply_transform(&mut self, m: &Isometry3<f64>) {
224        if let Some(g) = &mut self.abstract_space_mut().lod1_solid {
225            g.apply_transform(m);
226        }
227        if let Some(g) = &mut self.abstract_space_mut().lod2_solid {
228            g.apply_transform(m);
229        }
230        if let Some(g) = &mut self.abstract_space_mut().lod3_solid {
231            g.apply_transform(m);
232        }
233
234        if let Some(g) = &mut self.abstract_space_mut().lod0_multi_surface {
235            g.apply_transform(m);
236        }
237        if let Some(g) = &mut self.abstract_space_mut().lod2_multi_surface {
238            g.apply_transform(m);
239        }
240        if let Some(g) = &mut self.abstract_space_mut().lod3_multi_surface {
241            g.apply_transform(m);
242        }
243
244        if let Some(g) = &mut self.abstract_space_mut().lod0_multi_curve {
245            g.apply_transform(m);
246        }
247        if let Some(g) = &mut self.abstract_space_mut().lod2_multi_curve {
248            g.apply_transform(m);
249        }
250        if let Some(g) = &mut self.abstract_space_mut().lod3_multi_curve {
251            g.apply_transform(m);
252        }
253    }
254}
255
256impl AsAbstractSpace for AbstractSpace {
257    fn abstract_space(&self) -> &AbstractSpace {
258        self
259    }
260}
261
262impl AsAbstractSpaceMut for AbstractSpace {
263    fn abstract_space_mut(&mut self) -> &mut AbstractSpace {
264        self
265    }
266}
267
268#[macro_export]
269macro_rules! impl_abstract_space_traits {
270    ($type:ty) => {
271        $crate::impl_abstract_city_object_traits!($type);
272
273        impl $crate::model::core::AsAbstractCityObject for $type {
274            fn abstract_city_object(&self) -> &$crate::model::core::AbstractCityObject {
275                use $crate::model::core::AsAbstractSpace;
276                &self.abstract_space().abstract_city_object
277            }
278        }
279
280        impl $crate::model::core::AsAbstractCityObjectMut for $type {
281            fn abstract_city_object_mut(&mut self) -> &mut $crate::model::core::AbstractCityObject {
282                use $crate::model::core::AsAbstractSpaceMut;
283                &mut self.abstract_space_mut().abstract_city_object
284            }
285        }
286    };
287}
288
289impl_abstract_space_traits!(AbstractSpace);
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294    use crate::model::core::{AbstractFeature, AbstractFeatureWithLifespan};
295    use egml::model::base::Id;
296
297    #[test]
298    fn trait_implementation_macro_test() {
299        let abstract_feature = AbstractFeature::new(Id::generate_uuid_v4());
300        let abstract_feature_with_lifespan = AbstractFeatureWithLifespan::new(abstract_feature);
301        let abstract_city_object = AbstractCityObject::new(abstract_feature_with_lifespan);
302        let space = AbstractSpace::new(abstract_city_object);
303
304        let a = space.bounded_by();
305    }
306}