ecitygml_core/model/core/
abstract_space.rs1use 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}