1use crate::cityjson::core::appearance::ThemeName;
2use crate::error::{Error, Result};
3use crate::raw::{CityModelRawAccessor, DenseIndexRemap};
4use crate::resources::storage::OwnedStringStorage;
5use crate::symbols::SymbolStorageOptions;
6use crate::v2_0::appearance::material::Material;
7use crate::v2_0::appearance::texture::Texture;
8use crate::v2_0::attributes::{AttributeValue, Attributes};
9use crate::v2_0::boundary::Boundary;
10use crate::v2_0::cityobject::{CityObject, CityObjectType};
11use crate::v2_0::geometry::semantic::{Semantic, SemanticType};
12use crate::v2_0::geometry::{
13 AffineTransform3D, Geometry, GeometryType, LoD, StoredGeometryInstance, StoredGeometryParts,
14};
15use crate::v2_0::metadata::{BBox, CRS, CityModelIdentifier, Contact, ContactRole, ContactType};
16use crate::v2_0::vertex::VertexIndex;
17use crate::v2_0::{
18 CityModelCapacities, Extension, MaterialMap, Metadata, OwnedCityModel, RealWorldCoordinate,
19 SemanticMap, UVCoordinate, WrapMode,
20};
21use crate::{CityModelType, resources::mapping::textures::TextureMap as PublicTextureMap};
22use std::collections::HashMap;
23use std::str::FromStr;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
26pub struct SymbolId(pub u32);
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
29pub struct CityObjectId(pub u32);
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
32pub struct GeometryId(pub u32);
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
35pub struct GeometryTemplateId(pub u32);
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
38pub struct SemanticId(pub u32);
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
41pub struct MaterialId(pub u32);
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
44pub struct TextureId(pub u32);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
47pub struct VertexId(pub u32);
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
50pub struct UvVertexId(pub u32);
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
53pub struct AttributeNodeId(pub u32);
54
55macro_rules! impl_dense_id {
56 ($name:ident) => {
57 impl $name {
58 #[allow(dead_code)]
59 fn index(self) -> usize {
60 usize::try_from(self.0).unwrap_or(usize::MAX)
61 }
62 }
63 };
64}
65
66impl_dense_id!(SymbolId);
67impl_dense_id!(CityObjectId);
68impl_dense_id!(GeometryId);
69impl_dense_id!(GeometryTemplateId);
70impl_dense_id!(SemanticId);
71impl_dense_id!(MaterialId);
72impl_dense_id!(TextureId);
73impl_dense_id!(VertexId);
74impl_dense_id!(UvVertexId);
75impl_dense_id!(AttributeNodeId);
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum AttributeNodeType {
79 Null,
80 Bool,
81 Unsigned,
82 Integer,
83 Float,
84 String,
85 Array,
86 Object,
87 GeometryRef,
88}
89
90#[derive(Debug, Clone, Default)]
91pub struct SymbolTableOwned {
92 pub values: Vec<String>,
93}
94
95#[derive(Debug, Clone, Default)]
96pub struct VertexTableOwned {
97 pub x: Vec<f64>,
98 pub y: Vec<f64>,
99 pub z: Vec<f64>,
100}
101
102impl VertexTableOwned {
103 #[must_use]
104 pub fn len(&self) -> usize {
105 self.x.len()
106 }
107
108 #[must_use]
109 pub fn is_empty(&self) -> bool {
110 self.x.is_empty()
111 }
112}
113
114#[derive(Debug, Clone, Default)]
115pub struct UvVertexTableOwned {
116 pub u: Vec<f64>,
117 pub v: Vec<f64>,
118}
119
120impl UvVertexTableOwned {
121 #[must_use]
122 pub fn len(&self) -> usize {
123 self.u.len()
124 }
125
126 #[must_use]
127 pub fn is_empty(&self) -> bool {
128 self.u.is_empty()
129 }
130}
131
132#[derive(Debug, Clone, Default)]
133pub struct CityObjectTableOwned {
134 pub ids: Vec<CityObjectId>,
135 pub external_id_symbols: Vec<SymbolId>,
136 pub object_type_symbols: Vec<SymbolId>,
137 pub parent_start: Vec<u32>,
138 pub parent_len: Vec<u32>,
139 pub parents: Vec<CityObjectId>,
140 pub child_start: Vec<u32>,
141 pub child_len: Vec<u32>,
142 pub children: Vec<CityObjectId>,
143 pub geometry_start: Vec<u32>,
144 pub geometry_len: Vec<u32>,
145 pub geometries: Vec<GeometryId>,
146 pub attribute_root: Vec<Option<AttributeNodeId>>,
147 pub bbox_min_x: Vec<Option<f64>>,
148 pub bbox_min_y: Vec<Option<f64>>,
149 pub bbox_min_z: Vec<Option<f64>>,
150 pub bbox_max_x: Vec<Option<f64>>,
151 pub bbox_max_y: Vec<Option<f64>>,
152 pub bbox_max_z: Vec<Option<f64>>,
153}
154
155impl CityObjectTableOwned {
156 #[must_use]
157 pub fn len(&self) -> usize {
158 self.ids.len()
159 }
160
161 #[must_use]
162 pub fn is_empty(&self) -> bool {
163 self.ids.is_empty()
164 }
165}
166
167#[derive(Debug, Clone, Default)]
168pub struct SemanticTableOwned {
169 pub ids: Vec<SemanticId>,
170 pub semantic_type_symbols: Vec<SymbolId>,
171 pub parent: Vec<Option<SemanticId>>,
172 pub child_start: Vec<u32>,
173 pub child_len: Vec<u32>,
174 pub children: Vec<SemanticId>,
175 pub attribute_root: Vec<Option<AttributeNodeId>>,
176}
177
178impl SemanticTableOwned {
179 #[must_use]
180 pub fn len(&self) -> usize {
181 self.ids.len()
182 }
183
184 #[must_use]
185 pub fn is_empty(&self) -> bool {
186 self.ids.is_empty()
187 }
188}
189
190#[derive(Debug, Clone, Default)]
191pub struct MaterialTableOwned {
192 pub ids: Vec<MaterialId>,
193 pub name_symbols: Vec<SymbolId>,
194 pub ambient_intensity: Vec<Option<f32>>,
195 pub diffuse_color: Vec<Option<[f32; 3]>>,
196 pub emissive_color: Vec<Option<[f32; 3]>>,
197 pub specular_color: Vec<Option<[f32; 3]>>,
198 pub shininess: Vec<Option<f32>>,
199 pub transparency: Vec<Option<f32>>,
200 pub is_smooth: Vec<Option<bool>>,
201}
202
203impl MaterialTableOwned {
204 #[must_use]
205 pub fn len(&self) -> usize {
206 self.ids.len()
207 }
208
209 #[must_use]
210 pub fn is_empty(&self) -> bool {
211 self.ids.is_empty()
212 }
213}
214
215#[derive(Debug, Clone, Default)]
216pub struct TextureTableOwned {
217 pub ids: Vec<TextureId>,
218 pub image_uri_symbols: Vec<SymbolId>,
219 pub texture_type_symbols: Vec<Option<SymbolId>>,
220 pub wrap_mode_symbols: Vec<Option<SymbolId>>,
221 pub image_type_symbols: Vec<SymbolId>,
222 pub border_color: Vec<Option<[f32; 4]>>,
223}
224
225impl TextureTableOwned {
226 #[must_use]
227 pub fn len(&self) -> usize {
228 self.ids.len()
229 }
230
231 #[must_use]
232 pub fn is_empty(&self) -> bool {
233 self.ids.is_empty()
234 }
235}
236
237#[derive(Debug, Clone, Default)]
238pub struct GeometryMaterialThemeOwned {
239 pub geometry: GeometryId,
240 pub theme_symbol: SymbolId,
241 pub point_start: u32,
242 pub point_len: u32,
243 pub linestring_start: u32,
244 pub linestring_len: u32,
245 pub surface_start: u32,
246 pub surface_len: u32,
247}
248
249#[derive(Debug, Clone, Default)]
250pub struct GeometryTextureThemeOwned {
251 pub geometry: GeometryId,
252 pub theme_symbol: SymbolId,
253 pub vertex_start: u32,
254 pub vertex_len: u32,
255 pub ring_start: u32,
256 pub ring_len: u32,
257 pub ring_texture_start: u32,
258 pub ring_texture_len: u32,
259}
260
261#[derive(Debug, Clone, Default)]
262pub struct GeometryTableOwned {
263 pub ids: Vec<GeometryId>,
264 pub geometry_type_symbols: Vec<SymbolId>,
265 pub lod_symbols: Vec<Option<SymbolId>>,
266 pub boundary_vertex_start: Vec<u32>,
267 pub boundary_vertex_len: Vec<u32>,
268 pub boundary_ring_start: Vec<u32>,
269 pub boundary_ring_len: Vec<u32>,
270 pub boundary_surface_start: Vec<u32>,
271 pub boundary_surface_len: Vec<u32>,
272 pub boundary_shell_start: Vec<u32>,
273 pub boundary_shell_len: Vec<u32>,
274 pub boundary_solid_start: Vec<u32>,
275 pub boundary_solid_len: Vec<u32>,
276 pub semantic_point_start: Vec<u32>,
277 pub semantic_point_len: Vec<u32>,
278 pub semantic_linestring_start: Vec<u32>,
279 pub semantic_linestring_len: Vec<u32>,
280 pub semantic_surface_start: Vec<u32>,
281 pub semantic_surface_len: Vec<u32>,
282 pub material_theme_start: Vec<u32>,
283 pub material_theme_len: Vec<u32>,
284 pub texture_theme_start: Vec<u32>,
285 pub texture_theme_len: Vec<u32>,
286 pub template_ref: Vec<Option<GeometryTemplateId>>,
287 pub reference_point: Vec<Option<VertexId>>,
288 pub transform_matrix: Vec<[f64; 16]>,
289 pub boundary_vertices: Vec<VertexId>,
290 pub boundary_rings: Vec<u32>,
291 pub boundary_surfaces: Vec<u32>,
292 pub boundary_shells: Vec<u32>,
293 pub boundary_solids: Vec<u32>,
294 pub semantic_points: Vec<Option<SemanticId>>,
295 pub semantic_linestrings: Vec<Option<SemanticId>>,
296 pub semantic_surfaces: Vec<Option<SemanticId>>,
297 pub material_themes: Vec<GeometryMaterialThemeOwned>,
298 pub material_points: Vec<Option<MaterialId>>,
299 pub material_linestrings: Vec<Option<MaterialId>>,
300 pub material_surfaces: Vec<Option<MaterialId>>,
301 pub texture_themes: Vec<GeometryTextureThemeOwned>,
302 pub texture_vertex_refs: Vec<Option<VertexId>>,
303 pub texture_rings: Vec<u32>,
304 pub texture_ring_textures: Vec<Option<TextureId>>,
305}
306
307impl GeometryTableOwned {
308 #[must_use]
309 pub fn len(&self) -> usize {
310 self.ids.len()
311 }
312
313 #[must_use]
314 pub fn is_empty(&self) -> bool {
315 self.ids.is_empty()
316 }
317}
318
319#[derive(Debug, Clone, Default)]
320pub struct AttributeArenaOwned {
321 pub node_type: Vec<AttributeNodeType>,
322 pub key_symbol: Vec<Option<SymbolId>>,
323 pub string_value_symbol: Vec<Option<SymbolId>>,
324 pub bool_value: Vec<Option<bool>>,
325 pub unsigned_value: Vec<Option<u64>>,
326 pub int_value: Vec<Option<i64>>,
327 pub float_value: Vec<Option<f64>>,
328 pub geometry_value: Vec<Option<GeometryId>>,
329 pub first_child_offset: Vec<u32>,
330 pub child_len: Vec<u32>,
331 pub child_nodes: Vec<AttributeNodeId>,
332}
333
334impl AttributeArenaOwned {
335 #[must_use]
336 pub fn len(&self) -> usize {
337 self.node_type.len()
338 }
339
340 #[must_use]
341 pub fn is_empty(&self) -> bool {
342 self.node_type.is_empty()
343 }
344}
345
346#[derive(Debug, Clone, Default)]
347pub struct ExtensionTableOwned {
348 pub name_symbols: Vec<SymbolId>,
349 pub url_symbols: Vec<SymbolId>,
350 pub version_symbols: Vec<SymbolId>,
351}
352
353impl ExtensionTableOwned {
354 #[must_use]
355 pub fn len(&self) -> usize {
356 self.name_symbols.len()
357 }
358
359 #[must_use]
360 pub fn is_empty(&self) -> bool {
361 self.name_symbols.is_empty()
362 }
363}
364
365#[derive(Debug, Clone, Default)]
366pub struct ContactOwned {
367 pub name_symbol: SymbolId,
368 pub email_symbol: SymbolId,
369 pub role_symbol: Option<SymbolId>,
370 pub website_symbol: Option<SymbolId>,
371 pub contact_type_symbol: Option<SymbolId>,
372 pub address_root: Option<AttributeNodeId>,
373 pub phone_symbol: Option<SymbolId>,
374 pub organization_symbol: Option<SymbolId>,
375}
376
377#[derive(Debug, Clone, Default)]
378pub struct MetadataOwned {
379 pub geographical_extent: Option<[f64; 6]>,
380 pub identifier_symbol: Option<SymbolId>,
381 pub reference_date_symbol: Option<SymbolId>,
382 pub reference_system_symbol: Option<SymbolId>,
383 pub title_symbol: Option<SymbolId>,
384 pub extra_root: Option<AttributeNodeId>,
385 pub point_of_contact: Option<ContactOwned>,
386}
387
388#[derive(Debug, Clone, Copy, Default)]
389pub struct TransformOwned {
390 pub scale: [f64; 3],
391 pub translate: [f64; 3],
392}
393
394#[derive(Debug, Clone, Default)]
395pub struct DefaultThemeOwned {
396 pub material_theme_symbol: Option<SymbolId>,
397 pub texture_theme_symbol: Option<SymbolId>,
398}
399
400pub struct SymbolTableView<'a> {
401 pub values: &'a [String],
402}
403
404impl SymbolTableView<'_> {
405 #[must_use]
406 pub fn len(&self) -> usize {
407 self.values.len()
408 }
409
410 #[must_use]
411 pub fn is_empty(&self) -> bool {
412 self.values.is_empty()
413 }
414}
415
416pub struct VertexTableView<'a> {
417 pub x: &'a [f64],
418 pub y: &'a [f64],
419 pub z: &'a [f64],
420}
421
422impl VertexTableView<'_> {
423 #[must_use]
424 pub fn len(&self) -> usize {
425 self.x.len()
426 }
427
428 #[must_use]
429 pub fn is_empty(&self) -> bool {
430 self.x.is_empty()
431 }
432}
433
434pub struct UvVertexTableView<'a> {
435 pub u: &'a [f64],
436 pub v: &'a [f64],
437}
438
439impl UvVertexTableView<'_> {
440 #[must_use]
441 pub fn len(&self) -> usize {
442 self.u.len()
443 }
444
445 #[must_use]
446 pub fn is_empty(&self) -> bool {
447 self.u.is_empty()
448 }
449}
450
451pub type CityObjectTableView<'a> = &'a CityObjectTableOwned;
452pub type GeometryTableView<'a> = &'a GeometryTableOwned;
453pub type SemanticTableView<'a> = &'a SemanticTableOwned;
454pub type MaterialTableView<'a> = &'a MaterialTableOwned;
455pub type TextureTableView<'a> = &'a TextureTableOwned;
456pub type AttributeArenaView<'a> = &'a AttributeArenaOwned;
457pub type ExtensionTableView<'a> = &'a ExtensionTableOwned;
458pub type MetadataView<'a> = &'a MetadataOwned;
459pub type TransformView<'a> = &'a TransformOwned;
460pub type DefaultThemeView<'a> = &'a DefaultThemeOwned;
461
462#[derive(Debug, Clone)]
463pub struct ModelRelationalView<'a> {
464 model: &'a OwnedCityModel,
465 cityobject_remap: DenseIndexRemap,
466 geometry_remap: DenseIndexRemap,
467 geometry_template_remap: DenseIndexRemap,
468 semantic_remap: DenseIndexRemap,
469 material_remap: DenseIndexRemap,
470 texture_remap: DenseIndexRemap,
471}
472
473impl<'a> ModelRelationalView<'a> {
474 #[must_use]
475 pub const fn model(&self) -> &'a OwnedCityModel {
476 self.model
477 }
478
479 #[must_use]
480 pub fn raw(&self) -> CityModelRawAccessor<'a, u32, OwnedStringStorage> {
481 self.model.raw()
482 }
483
484 #[must_use]
485 pub fn cityobjects(&self) -> &'a crate::v2_0::OwnedCityObjects {
486 self.model.cityobjects()
487 }
488
489 #[must_use]
490 pub fn cityobject_remap(&self) -> &DenseIndexRemap {
491 &self.cityobject_remap
492 }
493
494 #[must_use]
495 pub fn geometry_remap(&self) -> &DenseIndexRemap {
496 &self.geometry_remap
497 }
498
499 #[must_use]
500 pub fn geometry_template_remap(&self) -> &DenseIndexRemap {
501 &self.geometry_template_remap
502 }
503
504 #[must_use]
505 pub fn semantic_remap(&self) -> &DenseIndexRemap {
506 &self.semantic_remap
507 }
508
509 #[must_use]
510 pub fn material_remap(&self) -> &DenseIndexRemap {
511 &self.material_remap
512 }
513
514 #[must_use]
515 pub fn texture_remap(&self) -> &DenseIndexRemap {
516 &self.texture_remap
517 }
518
519 #[must_use]
520 pub fn feature_root(&self) -> Option<CityObjectId> {
521 self.model
522 .id()
523 .and_then(|handle| {
524 self.cityobject_remap
525 .get(usize::try_from(slot(handle)).unwrap_or(usize::MAX))
526 })
527 .and_then(|dense| u32::try_from(dense).ok())
528 .map(CityObjectId)
529 }
530
531 #[must_use]
532 pub fn snapshot(&self) -> OwnedRelationalSnapshot {
533 build_relational_snapshot(self.model)
534 }
535}
536
537#[derive(Debug, Clone, Default)]
538pub struct OwnedRelationalSnapshot {
539 symbols: SymbolTableOwned,
540 vertices: VertexTableOwned,
541 template_vertices: VertexTableOwned,
542 uv_vertices: UvVertexTableOwned,
543 cityobjects: CityObjectTableOwned,
544 geometries: GeometryTableOwned,
545 geometry_templates: GeometryTableOwned,
546 semantics: SemanticTableOwned,
547 materials: MaterialTableOwned,
548 textures: TextureTableOwned,
549 attributes: AttributeArenaOwned,
550 metadata: Option<MetadataOwned>,
551 transform: Option<TransformOwned>,
552 defaults: DefaultThemeOwned,
553 extensions: ExtensionTableOwned,
554 feature_root: Option<CityObjectId>,
555}
556
557impl OwnedRelationalSnapshot {
558 #[must_use]
559 pub fn symbol_table(&self) -> &SymbolTableOwned {
560 &self.symbols
561 }
562
563 #[must_use]
564 pub fn symbols(&self) -> SymbolTableView<'_> {
565 SymbolTableView {
566 values: &self.symbols.values,
567 }
568 }
569
570 #[must_use]
571 pub fn vertex_table(&self) -> &VertexTableOwned {
572 &self.vertices
573 }
574
575 #[must_use]
576 pub fn vertices(&self) -> VertexTableView<'_> {
577 VertexTableView {
578 x: &self.vertices.x,
579 y: &self.vertices.y,
580 z: &self.vertices.z,
581 }
582 }
583
584 #[must_use]
585 pub fn template_vertices(&self) -> VertexTableView<'_> {
586 VertexTableView {
587 x: &self.template_vertices.x,
588 y: &self.template_vertices.y,
589 z: &self.template_vertices.z,
590 }
591 }
592
593 #[must_use]
594 pub fn template_vertex_table(&self) -> &VertexTableOwned {
595 &self.template_vertices
596 }
597
598 #[must_use]
599 pub fn uv_vertex_table(&self) -> &UvVertexTableOwned {
600 &self.uv_vertices
601 }
602
603 #[must_use]
604 pub fn uv_vertices(&self) -> UvVertexTableView<'_> {
605 UvVertexTableView {
606 u: &self.uv_vertices.u,
607 v: &self.uv_vertices.v,
608 }
609 }
610
611 #[must_use]
612 pub fn cityobjects(&self) -> CityObjectTableView<'_> {
613 &self.cityobjects
614 }
615
616 #[must_use]
617 pub fn geometries(&self) -> GeometryTableView<'_> {
618 &self.geometries
619 }
620
621 #[must_use]
622 pub fn geometry_templates(&self) -> GeometryTableView<'_> {
623 &self.geometry_templates
624 }
625
626 #[must_use]
627 pub fn semantics(&self) -> SemanticTableView<'_> {
628 &self.semantics
629 }
630
631 #[must_use]
632 pub fn materials(&self) -> MaterialTableView<'_> {
633 &self.materials
634 }
635
636 #[must_use]
637 pub fn textures(&self) -> TextureTableView<'_> {
638 &self.textures
639 }
640
641 #[must_use]
642 pub fn attributes(&self) -> AttributeArenaView<'_> {
643 &self.attributes
644 }
645
646 #[must_use]
647 pub fn metadata(&self) -> Option<MetadataView<'_>> {
648 self.metadata.as_ref()
649 }
650
651 #[must_use]
652 pub fn transform(&self) -> Option<TransformView<'_>> {
653 self.transform.as_ref()
654 }
655
656 #[must_use]
657 pub fn defaults(&self) -> DefaultThemeView<'_> {
658 &self.defaults
659 }
660
661 #[must_use]
662 pub fn extensions(&self) -> ExtensionTableView<'_> {
663 &self.extensions
664 }
665
666 #[must_use]
667 pub fn metadata_owned(&self) -> Option<&MetadataOwned> {
668 self.metadata.as_ref()
669 }
670
671 #[must_use]
672 pub fn transform_owned(&self) -> Option<&TransformOwned> {
673 self.transform.as_ref()
674 }
675
676 #[must_use]
677 pub fn defaults_owned(&self) -> &DefaultThemeOwned {
678 &self.defaults
679 }
680
681 #[must_use]
682 pub fn feature_root(&self) -> Option<CityObjectId> {
683 self.feature_root
684 }
685
686 fn symbol(&self, id: SymbolId) -> Result<&str> {
687 self.symbols
688 .values
689 .get(id.index())
690 .map(String::as_str)
691 .ok_or_else(|| Error::Import(format!("missing symbol {}", id.0)))
692 }
693}
694
695pub trait RelationalAccess {
696 fn relational(&self) -> ModelRelationalView<'_>;
697 fn relational_snapshot(&self) -> OwnedRelationalSnapshot;
698}
699
700impl RelationalAccess for OwnedCityModel {
701 fn relational(&self) -> ModelRelationalView<'_> {
702 ModelRelationalView {
703 model: self,
704 cityobject_remap: dense_cityobject_remap(self),
705 geometry_remap: self.raw().geometries().dense_index_remap(),
706 geometry_template_remap: dense_geometry_template_remap(self),
707 semantic_remap: self.raw().semantics().dense_index_remap(),
708 material_remap: self.raw().materials().dense_index_remap(),
709 texture_remap: self.raw().textures().dense_index_remap(),
710 }
711 }
712
713 fn relational_snapshot(&self) -> OwnedRelationalSnapshot {
714 build_relational_snapshot(self)
715 }
716}
717
718#[derive(Debug, Clone)]
719pub struct RelationalImportOptions {
720 pub symbol_storage: SymbolStorageOptions,
721 pub validate_default_themes: bool,
722 pub validate_references: bool,
723}
724
725impl Default for RelationalImportOptions {
726 fn default() -> Self {
727 Self {
728 symbol_storage: SymbolStorageOptions::default(),
729 validate_default_themes: true,
730 validate_references: true,
731 }
732 }
733}
734
735#[derive(Debug, Clone, Default)]
736pub struct RelationalCapacities {
737 pub symbols: usize,
738 pub cityobjects: usize,
739 pub geometries: usize,
740 pub geometry_templates: usize,
741 pub vertices: usize,
742 pub template_vertices: usize,
743 pub uv_vertices: usize,
744 pub semantics: usize,
745 pub materials: usize,
746 pub textures: usize,
747 pub attribute_nodes: usize,
748 pub extensions: usize,
749}
750
751#[derive(Debug, Default)]
752pub struct RelationalModelBuilder {
753 model_type: CityModelType,
754 options: RelationalImportOptions,
755 symbols: Option<SymbolTableOwned>,
756 cityobjects: Option<CityObjectTableOwned>,
757 geometries: Option<GeometryTableOwned>,
758 geometry_templates: Option<GeometryTableOwned>,
759 vertices: Option<VertexTableOwned>,
760 template_vertices: Option<VertexTableOwned>,
761 uv_vertices: Option<UvVertexTableOwned>,
762 semantics: Option<SemanticTableOwned>,
763 materials: Option<MaterialTableOwned>,
764 textures: Option<TextureTableOwned>,
765 attributes: Option<AttributeArenaOwned>,
766 metadata: Option<MetadataOwned>,
767 transform: Option<TransformOwned>,
768 defaults: Option<DefaultThemeOwned>,
769 extensions: Option<ExtensionTableOwned>,
770 feature_root: Option<CityObjectId>,
771}
772
773#[allow(clippy::missing_errors_doc)]
774impl RelationalModelBuilder {
775 #[must_use]
776 pub fn new(model_type: CityModelType, options: RelationalImportOptions) -> Self {
777 Self {
778 model_type,
779 options,
780 ..Self::default()
781 }
782 }
783
784 pub fn reserve(&mut self, _capacities: RelationalCapacities) -> Result<()> {
785 Ok(())
786 }
787
788 pub fn push_symbols(&mut self, table: SymbolTableOwned) -> Result<()> {
789 self.symbols = Some(table);
790 Ok(())
791 }
792
793 pub fn push_vertices(&mut self, table: VertexTableOwned) -> Result<()> {
794 self.vertices = Some(table);
795 Ok(())
796 }
797
798 pub fn push_template_vertices(&mut self, table: VertexTableOwned) -> Result<()> {
799 self.template_vertices = Some(table);
800 Ok(())
801 }
802
803 pub fn push_uv_vertices(&mut self, table: UvVertexTableOwned) -> Result<()> {
804 self.uv_vertices = Some(table);
805 Ok(())
806 }
807
808 pub fn push_semantics(&mut self, table: SemanticTableOwned) -> Result<()> {
809 self.semantics = Some(table);
810 Ok(())
811 }
812
813 pub fn push_materials(&mut self, table: MaterialTableOwned) -> Result<()> {
814 self.materials = Some(table);
815 Ok(())
816 }
817
818 pub fn push_textures(&mut self, table: TextureTableOwned) -> Result<()> {
819 self.textures = Some(table);
820 Ok(())
821 }
822
823 pub fn push_attributes(&mut self, table: AttributeArenaOwned) -> Result<()> {
824 self.attributes = Some(table);
825 Ok(())
826 }
827
828 pub fn push_cityobjects(&mut self, table: CityObjectTableOwned) -> Result<()> {
829 self.cityobjects = Some(table);
830 Ok(())
831 }
832
833 pub fn push_geometries(&mut self, table: GeometryTableOwned) -> Result<()> {
834 self.geometries = Some(table);
835 Ok(())
836 }
837
838 pub fn push_geometry_templates(&mut self, table: GeometryTableOwned) -> Result<()> {
839 self.geometry_templates = Some(table);
840 Ok(())
841 }
842
843 pub fn push_metadata(&mut self, view: Option<MetadataOwned>) -> Result<()> {
844 self.metadata = view;
845 Ok(())
846 }
847
848 pub fn push_transform(&mut self, view: Option<TransformOwned>) -> Result<()> {
849 self.transform = view;
850 Ok(())
851 }
852
853 pub fn push_defaults(&mut self, view: DefaultThemeOwned) -> Result<()> {
854 self.defaults = Some(view);
855 Ok(())
856 }
857
858 pub fn push_extensions(&mut self, table: ExtensionTableOwned) -> Result<()> {
859 self.extensions = Some(table);
860 Ok(())
861 }
862
863 pub fn push_feature_root(&mut self, feature_root: Option<CityObjectId>) -> Result<()> {
864 self.feature_root = feature_root;
865 Ok(())
866 }
867
868 pub fn finish(self) -> Result<OwnedCityModel> {
869 let view = OwnedRelationalSnapshot {
870 symbols: self
871 .symbols
872 .ok_or_else(|| Error::Import("missing symbol table".to_string()))?,
873 vertices: self.vertices.unwrap_or_default(),
874 template_vertices: self.template_vertices.unwrap_or_default(),
875 uv_vertices: self.uv_vertices.unwrap_or_default(),
876 cityobjects: self.cityobjects.unwrap_or_default(),
877 geometries: self.geometries.unwrap_or_default(),
878 geometry_templates: self.geometry_templates.unwrap_or_default(),
879 semantics: self.semantics.unwrap_or_default(),
880 materials: self.materials.unwrap_or_default(),
881 textures: self.textures.unwrap_or_default(),
882 attributes: self.attributes.unwrap_or_default(),
883 metadata: self.metadata,
884 transform: self.transform,
885 defaults: self.defaults.unwrap_or_default(),
886 extensions: self.extensions.unwrap_or_default(),
887 feature_root: self.feature_root,
888 };
889
890 build_model_from_relational(self.model_type, &self.options, &view)
891 }
892}
893
894#[derive(Default)]
895struct SymbolCollector {
896 ids_by_value: HashMap<String, SymbolId>,
897 values: Vec<String>,
898}
899
900impl SymbolCollector {
901 fn intern(&mut self, value: &str) -> SymbolId {
902 if let Some(id) = self.ids_by_value.get(value) {
903 return *id;
904 }
905
906 let id = SymbolId(u32::try_from(self.values.len()).unwrap_or(u32::MAX));
907 let owned = value.to_string();
908 self.values.push(owned.clone());
909 self.ids_by_value.insert(owned, id);
910 id
911 }
912}
913
914fn build_relational_snapshot(model: &OwnedCityModel) -> OwnedRelationalSnapshot {
915 let mut symbols = SymbolCollector::default();
916 let mut attributes = AttributeArenaOwned::default();
917
918 let cityobject_ids = dense_cityobject_ids(model);
919 let geometry_ids = dense_geometry_ids(model);
920 let geometry_template_ids = dense_geometry_template_ids(model);
921 let semantic_ids = dense_semantic_ids(model);
922 let material_ids = dense_material_ids(model);
923 let texture_ids = dense_texture_ids(model);
924
925 let vertices = encode_vertex_table(model.vertices().as_slice());
926 let template_vertices = encode_vertex_table(model.template_vertices().as_slice());
927 let uv_vertices = encode_uv_table(model.vertices_texture().as_slice());
928
929 let cityobjects = encode_cityobjects(
930 model,
931 &cityobject_ids,
932 &geometry_ids,
933 &mut symbols,
934 &mut attributes,
935 );
936 let semantics = encode_semantics(model, &semantic_ids, &mut symbols, &mut attributes);
937 let materials = encode_materials(model, &material_ids, &mut symbols);
938 let textures = encode_textures(model, &texture_ids, &mut symbols);
939 let geometries = encode_geometries(
940 model
941 .iter_geometries()
942 .map(|(id, geometry)| (GeometryId(geometry_ids[&slot(id)]), geometry)),
943 &semantic_ids,
944 &material_ids,
945 &texture_ids,
946 &geometry_template_ids,
947 &mut symbols,
948 );
949 let geometry_templates = encode_geometries(
950 model
951 .iter_geometry_templates()
952 .map(|(id, geometry)| (GeometryId(geometry_template_ids[&slot(id)]), geometry)),
953 &semantic_ids,
954 &material_ids,
955 &texture_ids,
956 &geometry_template_ids,
957 &mut symbols,
958 );
959 let metadata = encode_metadata(
960 model.metadata(),
961 &geometry_ids,
962 &mut symbols,
963 &mut attributes,
964 );
965 let transform = model.transform().map(|transform| TransformOwned {
966 scale: transform.scale(),
967 translate: transform.translate(),
968 });
969 let defaults = DefaultThemeOwned {
970 material_theme_symbol: model
971 .default_material_theme()
972 .map(|theme| symbols.intern(theme.as_ref())),
973 texture_theme_symbol: model
974 .default_texture_theme()
975 .map(|theme| symbols.intern(theme.as_ref())),
976 };
977 let extensions = encode_extensions(model.extensions(), &mut symbols);
978 let feature_root = model.id().map(|id| CityObjectId(cityobject_ids[&slot(id)]));
979
980 OwnedRelationalSnapshot {
981 symbols: SymbolTableOwned {
982 values: symbols.values,
983 },
984 vertices,
985 template_vertices,
986 uv_vertices,
987 cityobjects,
988 geometries,
989 geometry_templates,
990 semantics,
991 materials,
992 textures,
993 attributes,
994 metadata,
995 transform,
996 defaults,
997 extensions,
998 feature_root,
999 }
1000}
1001
1002#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
1003fn build_model_from_relational(
1004 model_type: CityModelType,
1005 options: &RelationalImportOptions,
1006 relational: &OwnedRelationalSnapshot,
1007) -> Result<OwnedCityModel> {
1008 let capacities = CityModelCapacities {
1009 cityobjects: relational.cityobjects.len(),
1010 vertices: relational.vertices.len(),
1011 semantics: relational.semantics.len(),
1012 materials: relational.materials.len(),
1013 textures: relational.textures.len(),
1014 geometries: relational.geometries.len(),
1015 template_vertices: relational.template_vertices.len(),
1016 template_geometries: relational.geometry_templates.len(),
1017 uv_coordinates: relational.uv_vertices.len(),
1018 };
1019
1020 let mut model = OwnedCityModel::with_capacities(model_type, capacities);
1021
1022 for i in 0..relational.vertices.len() {
1023 model.add_vertex(RealWorldCoordinate::new(
1024 relational.vertices.x[i],
1025 relational.vertices.y[i],
1026 relational.vertices.z[i],
1027 ))?;
1028 }
1029
1030 for i in 0..relational.template_vertices.len() {
1031 model.add_template_vertex(RealWorldCoordinate::new(
1032 relational.template_vertices.x[i],
1033 relational.template_vertices.y[i],
1034 relational.template_vertices.z[i],
1035 ))?;
1036 }
1037
1038 for i in 0..relational.uv_vertices.len() {
1039 model.add_uv_coordinate(UVCoordinate::new(
1040 relational.uv_vertices.u[i] as f32,
1041 relational.uv_vertices.v[i] as f32,
1042 ))?;
1043 }
1044
1045 let mut semantic_handles = Vec::with_capacity(relational.semantics.len());
1046 for i in 0..relational.semantics.len() {
1047 let semantic = Semantic::new(parse_semantic_type(
1048 relational.symbol(relational.semantics.semantic_type_symbols[i])?,
1049 ));
1050 semantic_handles.push(model.add_semantic(semantic)?);
1051 }
1052 for i in 0..relational.semantics.len() {
1053 if let Some(root) = relational.semantics.attribute_root[i] {
1054 let attrs = decode_attributes(
1055 &relational.attributes,
1056 &relational.symbols.values,
1057 root,
1058 None,
1059 )?
1060 .ok_or_else(|| {
1061 Error::Import("semantic attribute root was not an object".to_string())
1062 })?;
1063 model
1064 .get_semantic_mut(semantic_handles[i])
1065 .ok_or_else(|| Error::Import("missing semantic during import".to_string()))?
1066 .attributes_mut()
1067 .clone_from(&attrs);
1068 }
1069 if let Some(parent) = relational.semantics.parent[i] {
1070 model
1071 .get_semantic_mut(semantic_handles[i])
1072 .ok_or_else(|| Error::Import("missing semantic parent target".to_string()))?
1073 .set_parent(semantic_handles[parent.index()]);
1074 }
1075 let start = usize::try_from(relational.semantics.child_start[i]).unwrap_or(usize::MAX);
1076 let len = usize::try_from(relational.semantics.child_len[i]).unwrap_or(usize::MAX);
1077 for child in &relational.semantics.children[start..start + len] {
1078 model
1079 .get_semantic_mut(semantic_handles[i])
1080 .ok_or_else(|| Error::Import("missing semantic child target".to_string()))?
1081 .children_mut()
1082 .push(semantic_handles[child.index()]);
1083 }
1084 }
1085
1086 let mut material_handles = Vec::with_capacity(relational.materials.len());
1087 for i in 0..relational.materials.len() {
1088 let mut material = Material::new(
1089 relational
1090 .symbol(relational.materials.name_symbols[i])?
1091 .to_string(),
1092 );
1093 material.set_ambient_intensity(relational.materials.ambient_intensity[i]);
1094 material.set_diffuse_color(relational.materials.diffuse_color[i].map(Into::into));
1095 material.set_emissive_color(relational.materials.emissive_color[i].map(Into::into));
1096 material.set_specular_color(relational.materials.specular_color[i].map(Into::into));
1097 material.set_shininess(relational.materials.shininess[i]);
1098 material.set_transparency(relational.materials.transparency[i]);
1099 material.set_is_smooth(relational.materials.is_smooth[i]);
1100 material_handles.push(model.add_material(material)?);
1101 }
1102
1103 let mut texture_handles = Vec::with_capacity(relational.textures.len());
1104 for i in 0..relational.textures.len() {
1105 let mut texture = Texture::new(
1106 relational
1107 .symbol(relational.textures.image_uri_symbols[i])?
1108 .to_string(),
1109 parse_image_type(relational.symbol(relational.textures.image_type_symbols[i])?),
1110 );
1111 texture.set_texture_type(
1112 relational.textures.texture_type_symbols[i]
1113 .map(|id| parse_texture_type(relational.symbol(id).unwrap_or("unknown"))),
1114 );
1115 texture.set_wrap_mode(
1116 relational.textures.wrap_mode_symbols[i]
1117 .map(|id| parse_wrap_mode(relational.symbol(id).unwrap_or("none"))),
1118 );
1119 texture.set_border_color(relational.textures.border_color[i].map(Into::into));
1120 texture_handles.push(model.add_texture(texture)?);
1121 }
1122
1123 let mut template_handles = Vec::with_capacity(relational.geometry_templates.len());
1124 for i in 0..relational.geometry_templates.len() {
1125 let geometry = decode_geometry(
1126 &relational.geometry_templates,
1127 i,
1128 &template_handles,
1129 &semantic_handles,
1130 &material_handles,
1131 &texture_handles,
1132 true,
1133 relational,
1134 )?;
1135 template_handles.push(model.add_geometry_template_unchecked(geometry)?);
1136 }
1137
1138 let mut geometry_handles = Vec::with_capacity(relational.geometries.len());
1139 for i in 0..relational.geometries.len() {
1140 let geometry = decode_geometry(
1141 &relational.geometries,
1142 i,
1143 &template_handles,
1144 &semantic_handles,
1145 &material_handles,
1146 &texture_handles,
1147 false,
1148 relational,
1149 )?;
1150 geometry_handles.push(model.add_geometry_unchecked(geometry)?);
1151 }
1152
1153 let mut cityobject_handles = Vec::with_capacity(relational.cityobjects.len());
1154 for i in 0..relational.cityobjects.len() {
1155 let mut object = CityObject::new(
1156 crate::v2_0::CityObjectIdentifier::new(
1157 relational
1158 .symbol(relational.cityobjects.external_id_symbols[i])?
1159 .to_string(),
1160 ),
1161 parse_cityobject_type(
1162 relational.symbol(relational.cityobjects.object_type_symbols[i])?,
1163 )?,
1164 );
1165 if let Some(root) = relational.cityobjects.attribute_root[i] {
1166 let attrs = decode_attributes(
1167 &relational.attributes,
1168 &relational.symbols.values,
1169 root,
1170 Some(&geometry_handles),
1171 )?
1172 .ok_or_else(|| {
1173 Error::Import("cityobject attribute root was not an object".to_string())
1174 })?;
1175 *object.attributes_mut() = attrs;
1176 }
1177 if let Some(min_x) = relational.cityobjects.bbox_min_x[i] {
1178 object.set_geographical_extent(Some(BBox::new(
1179 min_x,
1180 relational.cityobjects.bbox_min_y[i].unwrap_or_default(),
1181 relational.cityobjects.bbox_min_z[i].unwrap_or_default(),
1182 relational.cityobjects.bbox_max_x[i].unwrap_or_default(),
1183 relational.cityobjects.bbox_max_y[i].unwrap_or_default(),
1184 relational.cityobjects.bbox_max_z[i].unwrap_or_default(),
1185 )));
1186 }
1187 let start = usize::try_from(relational.cityobjects.geometry_start[i]).unwrap_or(usize::MAX);
1188 let len = usize::try_from(relational.cityobjects.geometry_len[i]).unwrap_or(usize::MAX);
1189 for geometry in &relational.cityobjects.geometries[start..start + len] {
1190 object.add_geometry(geometry_handles[geometry.index()]);
1191 }
1192 cityobject_handles.push(model.cityobjects_mut().add(object)?);
1193 }
1194
1195 for i in 0..relational.cityobjects.len() {
1196 let parents_start =
1197 usize::try_from(relational.cityobjects.parent_start[i]).unwrap_or(usize::MAX);
1198 let parents_len =
1199 usize::try_from(relational.cityobjects.parent_len[i]).unwrap_or(usize::MAX);
1200 for parent in &relational.cityobjects.parents[parents_start..parents_start + parents_len] {
1201 model
1202 .cityobjects_mut()
1203 .get_mut(cityobject_handles[i])
1204 .ok_or_else(|| {
1205 Error::Import("missing cityobject during parent import".to_string())
1206 })?
1207 .add_parent(cityobject_handles[parent.index()]);
1208 }
1209 let children_start =
1210 usize::try_from(relational.cityobjects.child_start[i]).unwrap_or(usize::MAX);
1211 let children_len =
1212 usize::try_from(relational.cityobjects.child_len[i]).unwrap_or(usize::MAX);
1213 for child in &relational.cityobjects.children[children_start..children_start + children_len]
1214 {
1215 model
1216 .cityobjects_mut()
1217 .get_mut(cityobject_handles[i])
1218 .ok_or_else(|| Error::Import("missing cityobject during child import".to_string()))?
1219 .add_child(cityobject_handles[child.index()]);
1220 }
1221 }
1222
1223 if let Some(feature_root) = relational.feature_root {
1224 model.set_id(Some(cityobject_handles[feature_root.index()]));
1225 }
1226
1227 if let Some(metadata) = relational.metadata() {
1228 let target = model.metadata_mut();
1229 if let Some(extent) = metadata.geographical_extent {
1230 target.set_geographical_extent(BBox::new(
1231 extent[0], extent[1], extent[2], extent[3], extent[4], extent[5],
1232 ));
1233 }
1234 if let Some(id) = metadata.identifier_symbol {
1235 target.set_identifier(CityModelIdentifier::new(relational.symbol(id)?.to_string()));
1236 }
1237 if let Some(date) = metadata.reference_date_symbol {
1238 target.set_reference_date(crate::v2_0::Date::new(relational.symbol(date)?.to_string()));
1239 }
1240 if let Some(crs) = metadata.reference_system_symbol {
1241 target.set_reference_system(CRS::new(relational.symbol(crs)?.to_string()));
1242 }
1243 if let Some(title) = metadata.title_symbol {
1244 target.set_title(relational.symbol(title)?.to_string());
1245 }
1246 if let Some(extra_root) = metadata.extra_root {
1247 let attrs = decode_attributes(
1248 &relational.attributes,
1249 &relational.symbols.values,
1250 extra_root,
1251 Some(&geometry_handles),
1252 )?
1253 .ok_or_else(|| Error::Import("metadata extra root was not an object".to_string()))?;
1254 target.set_extra(Some(attrs));
1255 }
1256 if let Some(contact) = &metadata.point_of_contact {
1257 let mut target_contact = Contact::new();
1258 target_contact.set_contact_name(relational.symbol(contact.name_symbol)?.to_string());
1259 target_contact.set_email_address(relational.symbol(contact.email_symbol)?.to_string());
1260 target_contact.set_role(
1261 contact
1262 .role_symbol
1263 .map(|id| parse_contact_role(relational.symbol(id).unwrap_or("Author"))),
1264 );
1265 target_contact.set_website(
1266 contact
1267 .website_symbol
1268 .map(|id| relational.symbol(id).unwrap_or_default().to_string()),
1269 );
1270 target_contact.set_contact_type(
1271 contact
1272 .contact_type_symbol
1273 .map(|id| parse_contact_type(relational.symbol(id).unwrap_or("Individual"))),
1274 );
1275 target_contact.set_phone(
1276 contact
1277 .phone_symbol
1278 .map(|id| relational.symbol(id).unwrap_or_default().to_string()),
1279 );
1280 target_contact.set_organization(
1281 contact
1282 .organization_symbol
1283 .map(|id| relational.symbol(id).unwrap_or_default().to_string()),
1284 );
1285 if let Some(address_root) = contact.address_root {
1286 let attrs = decode_attributes(
1287 &relational.attributes,
1288 &relational.symbols.values,
1289 address_root,
1290 Some(&geometry_handles),
1291 )?
1292 .ok_or_else(|| {
1293 Error::Import("contact address root was not an object".to_string())
1294 })?;
1295 target_contact.set_address(Some(attrs));
1296 }
1297 target.set_point_of_contact(Some(target_contact));
1298 }
1299 }
1300
1301 if let Some(transform) = relational.transform() {
1302 model.transform_mut().set_scale(transform.scale);
1303 model.transform_mut().set_translate(transform.translate);
1304 }
1305
1306 if let Some(theme) = relational.defaults.material_theme_symbol {
1307 model.set_default_material_theme(Some(ThemeName::new(
1308 relational.symbol(theme)?.to_string(),
1309 )));
1310 }
1311 if let Some(theme) = relational.defaults.texture_theme_symbol {
1312 model
1313 .set_default_texture_theme(Some(ThemeName::new(relational.symbol(theme)?.to_string())));
1314 }
1315
1316 for i in 0..relational.extensions.len() {
1317 model.extensions_mut().add(Extension::new(
1318 relational
1319 .symbol(relational.extensions.name_symbols[i])?
1320 .to_string(),
1321 relational
1322 .symbol(relational.extensions.url_symbols[i])?
1323 .to_string(),
1324 relational
1325 .symbol(relational.extensions.version_symbols[i])?
1326 .to_string(),
1327 ));
1328 }
1329
1330 if options.validate_default_themes {
1331 model.validate_default_themes()?;
1332 }
1333
1334 Ok(model)
1335}
1336
1337fn encode_vertex_table(vertices: &[RealWorldCoordinate]) -> VertexTableOwned {
1338 let mut table = VertexTableOwned::default();
1339 table.x.reserve(vertices.len());
1340 table.y.reserve(vertices.len());
1341 table.z.reserve(vertices.len());
1342 for vertex in vertices {
1343 table.x.push(vertex.x());
1344 table.y.push(vertex.y());
1345 table.z.push(vertex.z());
1346 }
1347 table
1348}
1349
1350fn encode_uv_table(vertices: &[UVCoordinate]) -> UvVertexTableOwned {
1351 let mut table = UvVertexTableOwned::default();
1352 table.u.reserve(vertices.len());
1353 table.v.reserve(vertices.len());
1354 for vertex in vertices {
1355 table.u.push(f64::from(vertex.u()));
1356 table.v.push(f64::from(vertex.v()));
1357 }
1358 table
1359}
1360
1361fn encode_cityobjects(
1362 model: &OwnedCityModel,
1363 cityobject_ids: &HashMap<u32, u32>,
1364 geometry_ids: &HashMap<u32, u32>,
1365 symbols: &mut SymbolCollector,
1366 attributes: &mut AttributeArenaOwned,
1367) -> CityObjectTableOwned {
1368 let mut table = CityObjectTableOwned::default();
1369
1370 for (dense_index, (handle, object)) in model.cityobjects().iter().enumerate() {
1371 table
1372 .ids
1373 .push(CityObjectId(u32::try_from(dense_index).unwrap_or(u32::MAX)));
1374 table.external_id_symbols.push(symbols.intern(object.id()));
1375 table
1376 .object_type_symbols
1377 .push(symbols.intern(&cityobject_type_name(object.type_cityobject())));
1378
1379 let parent_start = table.parents.len();
1380 for parent in object.parents().into_iter().flatten() {
1381 table.parents.push(CityObjectId(
1382 *cityobject_ids.get(&slot(*parent)).unwrap_or(&u32::MAX),
1383 ));
1384 }
1385 table
1386 .parent_start
1387 .push(u32::try_from(parent_start).unwrap_or(u32::MAX));
1388 table
1389 .parent_len
1390 .push(u32::try_from(table.parents.len() - parent_start).unwrap_or(u32::MAX));
1391
1392 let child_start = table.children.len();
1393 for child in object.children().into_iter().flatten() {
1394 table.children.push(CityObjectId(
1395 *cityobject_ids.get(&slot(*child)).unwrap_or(&u32::MAX),
1396 ));
1397 }
1398 table
1399 .child_start
1400 .push(u32::try_from(child_start).unwrap_or(u32::MAX));
1401 table
1402 .child_len
1403 .push(u32::try_from(table.children.len() - child_start).unwrap_or(u32::MAX));
1404
1405 let geometry_start = table.geometries.len();
1406 for geometry in object.geometry().into_iter().flatten() {
1407 table.geometries.push(GeometryId(
1408 *geometry_ids.get(&slot(*geometry)).unwrap_or(&u32::MAX),
1409 ));
1410 }
1411 table
1412 .geometry_start
1413 .push(u32::try_from(geometry_start).unwrap_or(u32::MAX));
1414 table
1415 .geometry_len
1416 .push(u32::try_from(table.geometries.len() - geometry_start).unwrap_or(u32::MAX));
1417
1418 table.attribute_root.push(
1419 object
1420 .attributes()
1421 .map(|values| encode_attributes(values, geometry_ids, symbols, attributes)),
1422 );
1423
1424 if let Some(bbox) = object.geographical_extent() {
1425 let values: [f64; 6] = (*bbox).into();
1426 table.bbox_min_x.push(Some(values[0]));
1427 table.bbox_min_y.push(Some(values[1]));
1428 table.bbox_min_z.push(Some(values[2]));
1429 table.bbox_max_x.push(Some(values[3]));
1430 table.bbox_max_y.push(Some(values[4]));
1431 table.bbox_max_z.push(Some(values[5]));
1432 } else {
1433 table.bbox_min_x.push(None);
1434 table.bbox_min_y.push(None);
1435 table.bbox_min_z.push(None);
1436 table.bbox_max_x.push(None);
1437 table.bbox_max_y.push(None);
1438 table.bbox_max_z.push(None);
1439 }
1440
1441 let _ = handle;
1442 }
1443
1444 table
1445}
1446
1447fn encode_semantics(
1448 model: &OwnedCityModel,
1449 semantic_ids: &HashMap<u32, u32>,
1450 symbols: &mut SymbolCollector,
1451 attributes: &mut AttributeArenaOwned,
1452) -> SemanticTableOwned {
1453 let mut table = SemanticTableOwned::default();
1454
1455 for (dense_index, (_handle, semantic)) in model.iter_semantics().enumerate() {
1456 table
1457 .ids
1458 .push(SemanticId(u32::try_from(dense_index).unwrap_or(u32::MAX)));
1459 table
1460 .semantic_type_symbols
1461 .push(symbols.intern(&semantic_type_name(semantic.type_semantic())));
1462 table.parent.push(
1463 semantic
1464 .parent()
1465 .map(|parent| SemanticId(*semantic_ids.get(&slot(parent)).unwrap_or(&u32::MAX))),
1466 );
1467 let child_start = table.children.len();
1468 for child in semantic.children().into_iter().flatten() {
1469 table.children.push(SemanticId(
1470 *semantic_ids.get(&slot(*child)).unwrap_or(&u32::MAX),
1471 ));
1472 }
1473 table
1474 .child_start
1475 .push(u32::try_from(child_start).unwrap_or(u32::MAX));
1476 table
1477 .child_len
1478 .push(u32::try_from(table.children.len() - child_start).unwrap_or(u32::MAX));
1479 table.attribute_root.push(
1480 semantic
1481 .attributes()
1482 .map(|values| encode_attributes(values, &HashMap::new(), symbols, attributes)),
1483 );
1484 }
1485
1486 table
1487}
1488
1489fn encode_materials(
1490 model: &OwnedCityModel,
1491 _material_ids: &HashMap<u32, u32>,
1492 symbols: &mut SymbolCollector,
1493) -> MaterialTableOwned {
1494 let mut table = MaterialTableOwned::default();
1495 for (dense_index, (_handle, material)) in model.iter_materials().enumerate() {
1496 table
1497 .ids
1498 .push(MaterialId(u32::try_from(dense_index).unwrap_or(u32::MAX)));
1499 table.name_symbols.push(symbols.intern(material.name()));
1500 table.ambient_intensity.push(material.ambient_intensity());
1501 table
1502 .diffuse_color
1503 .push(material.diffuse_color().map(Into::into));
1504 table
1505 .emissive_color
1506 .push(material.emissive_color().map(Into::into));
1507 table
1508 .specular_color
1509 .push(material.specular_color().map(Into::into));
1510 table.shininess.push(material.shininess());
1511 table.transparency.push(material.transparency());
1512 table.is_smooth.push(material.is_smooth());
1513 }
1514 table
1515}
1516
1517fn encode_textures(
1518 model: &OwnedCityModel,
1519 _texture_ids: &HashMap<u32, u32>,
1520 symbols: &mut SymbolCollector,
1521) -> TextureTableOwned {
1522 let mut table = TextureTableOwned::default();
1523 for (dense_index, (_handle, texture)) in model.iter_textures().enumerate() {
1524 table
1525 .ids
1526 .push(TextureId(u32::try_from(dense_index).unwrap_or(u32::MAX)));
1527 table
1528 .image_uri_symbols
1529 .push(symbols.intern(texture.image()));
1530 table.texture_type_symbols.push(
1531 texture
1532 .texture_type()
1533 .map(|value| symbols.intern(&value.to_string())),
1534 );
1535 table.wrap_mode_symbols.push(
1536 texture
1537 .wrap_mode()
1538 .map(|value| symbols.intern(&value.to_string())),
1539 );
1540 table
1541 .image_type_symbols
1542 .push(symbols.intern(&texture.image_type().to_string()));
1543 table
1544 .border_color
1545 .push(texture.border_color().map(Into::into));
1546 }
1547 table
1548}
1549
1550#[allow(clippy::too_many_lines)]
1551fn encode_geometries<'a>(
1552 items: impl Iterator<
1553 Item = (
1554 GeometryId,
1555 &'a Geometry<u32, crate::resources::storage::OwnedStringStorage>,
1556 ),
1557 >,
1558 semantic_ids: &HashMap<u32, u32>,
1559 material_ids: &HashMap<u32, u32>,
1560 texture_ids: &HashMap<u32, u32>,
1561 geometry_template_ids: &HashMap<u32, u32>,
1562 symbols: &mut SymbolCollector,
1563) -> GeometryTableOwned {
1564 let mut table = GeometryTableOwned::default();
1565
1566 for (dense_id, geometry) in items {
1567 table.ids.push(dense_id);
1568 table
1569 .geometry_type_symbols
1570 .push(symbols.intern(&geometry.type_geometry().to_string()));
1571 table
1572 .lod_symbols
1573 .push(geometry.lod().map(|lod| symbols.intern(&lod.to_string())));
1574
1575 if let Some(boundary) = geometry.boundaries() {
1576 push_boundary(boundary, &mut table);
1577 } else {
1578 push_empty_boundary(&mut table);
1579 }
1580
1581 if let Some(semantics) = geometry.semantics() {
1582 push_semantic_assignments(semantics, semantic_ids, &mut table);
1583 } else {
1584 push_empty_semantic_assignments(&mut table);
1585 }
1586
1587 let material_start = table.material_themes.len();
1588 if let Some(materials) = geometry.raw().materials() {
1589 for (theme, mapping) in materials {
1590 let theme_row_start_points = table.material_points.len();
1591 table
1592 .material_points
1593 .extend(mapping.points().iter().map(|value| {
1594 value.map(|id| {
1595 MaterialId(*material_ids.get(&id.index()).unwrap_or(&u32::MAX))
1596 })
1597 }));
1598 let theme_row_start_linestrings = table.material_linestrings.len();
1599 table
1600 .material_linestrings
1601 .extend(mapping.linestrings().iter().map(|value| {
1602 value.map(|id| {
1603 MaterialId(*material_ids.get(&id.index()).unwrap_or(&u32::MAX))
1604 })
1605 }));
1606 let theme_row_start_surfaces = table.material_surfaces.len();
1607 table
1608 .material_surfaces
1609 .extend(mapping.surfaces().iter().map(|value| {
1610 value.map(|id| {
1611 MaterialId(*material_ids.get(&id.index()).unwrap_or(&u32::MAX))
1612 })
1613 }));
1614 table.material_themes.push(GeometryMaterialThemeOwned {
1615 geometry: dense_id,
1616 theme_symbol: symbols.intern(theme.as_ref()),
1617 point_start: u32::try_from(theme_row_start_points).unwrap_or(u32::MAX),
1618 point_len: u32::try_from(table.material_points.len() - theme_row_start_points)
1619 .unwrap_or(u32::MAX),
1620 linestring_start: u32::try_from(theme_row_start_linestrings)
1621 .unwrap_or(u32::MAX),
1622 linestring_len: u32::try_from(
1623 table.material_linestrings.len() - theme_row_start_linestrings,
1624 )
1625 .unwrap_or(u32::MAX),
1626 surface_start: u32::try_from(theme_row_start_surfaces).unwrap_or(u32::MAX),
1627 surface_len: u32::try_from(
1628 table.material_surfaces.len() - theme_row_start_surfaces,
1629 )
1630 .unwrap_or(u32::MAX),
1631 });
1632 }
1633 }
1634 table
1635 .material_theme_start
1636 .push(u32::try_from(material_start).unwrap_or(u32::MAX));
1637 table
1638 .material_theme_len
1639 .push(u32::try_from(table.material_themes.len() - material_start).unwrap_or(u32::MAX));
1640
1641 let texture_start = table.texture_themes.len();
1642 if let Some(textures) = geometry.raw().textures() {
1643 for (theme, mapping) in textures {
1644 let vertex_start = table.texture_vertex_refs.len();
1645 table.texture_vertex_refs.extend(
1646 mapping
1647 .vertices()
1648 .iter()
1649 .map(|value| value.map(|vertex| VertexId(vertex.value()))),
1650 );
1651 let ring_start = table.texture_rings.len();
1652 table
1653 .texture_rings
1654 .extend(mapping.rings().iter().map(crate::v2_0::VertexIndex::value));
1655 let ring_texture_start = table.texture_ring_textures.len();
1656 table
1657 .texture_ring_textures
1658 .extend(mapping.ring_textures().iter().copied().map(|value| {
1659 value
1660 .map(|id| TextureId(*texture_ids.get(&id.index()).unwrap_or(&u32::MAX)))
1661 }));
1662 table.texture_themes.push(GeometryTextureThemeOwned {
1663 geometry: dense_id,
1664 theme_symbol: symbols.intern(theme.as_ref()),
1665 vertex_start: u32::try_from(vertex_start).unwrap_or(u32::MAX),
1666 vertex_len: u32::try_from(table.texture_vertex_refs.len() - vertex_start)
1667 .unwrap_or(u32::MAX),
1668 ring_start: u32::try_from(ring_start).unwrap_or(u32::MAX),
1669 ring_len: u32::try_from(table.texture_rings.len() - ring_start)
1670 .unwrap_or(u32::MAX),
1671 ring_texture_start: u32::try_from(ring_texture_start).unwrap_or(u32::MAX),
1672 ring_texture_len: u32::try_from(
1673 table.texture_ring_textures.len() - ring_texture_start,
1674 )
1675 .unwrap_or(u32::MAX),
1676 });
1677 }
1678 }
1679 table
1680 .texture_theme_start
1681 .push(u32::try_from(texture_start).unwrap_or(u32::MAX));
1682 table
1683 .texture_theme_len
1684 .push(u32::try_from(table.texture_themes.len() - texture_start).unwrap_or(u32::MAX));
1685
1686 if let Some(instance) = geometry.instance() {
1687 table.template_ref.push(Some(GeometryTemplateId(
1688 *geometry_template_ids
1689 .get(&slot(instance.template()))
1690 .unwrap_or(&u32::MAX),
1691 )));
1692 table
1693 .reference_point
1694 .push(Some(VertexId(instance.reference_point().value())));
1695 table
1696 .transform_matrix
1697 .push(instance.transformation().into_array());
1698 } else {
1699 table.template_ref.push(None);
1700 table.reference_point.push(None);
1701 table
1702 .transform_matrix
1703 .push(AffineTransform3D::identity().into_array());
1704 }
1705 }
1706
1707 table
1708}
1709
1710fn encode_extensions(
1711 extensions: Option<&crate::v2_0::Extensions<crate::resources::storage::OwnedStringStorage>>,
1712 symbols: &mut SymbolCollector,
1713) -> ExtensionTableOwned {
1714 let mut table = ExtensionTableOwned::default();
1715 if let Some(extensions) = extensions {
1716 for extension in extensions {
1717 table.name_symbols.push(symbols.intern(extension.name()));
1718 table.url_symbols.push(symbols.intern(extension.url()));
1719 table
1720 .version_symbols
1721 .push(symbols.intern(extension.version()));
1722 }
1723 }
1724 table
1725}
1726
1727fn encode_metadata(
1728 metadata: Option<&Metadata<crate::resources::storage::OwnedStringStorage>>,
1729 geometry_ids: &HashMap<u32, u32>,
1730 symbols: &mut SymbolCollector,
1731 attributes: &mut AttributeArenaOwned,
1732) -> Option<MetadataOwned> {
1733 metadata.map(|metadata| MetadataOwned {
1734 geographical_extent: metadata.geographical_extent().map(|bbox| (*bbox).into()),
1735 identifier_symbol: metadata
1736 .identifier()
1737 .map(|value| symbols.intern(&value.to_string())),
1738 reference_date_symbol: metadata
1739 .reference_date()
1740 .map(|value| symbols.intern(&value.to_string())),
1741 reference_system_symbol: metadata
1742 .reference_system()
1743 .map(|value| symbols.intern(&value.to_string())),
1744 title_symbol: metadata.title().map(|value| symbols.intern(value)),
1745 extra_root: metadata
1746 .extra()
1747 .map(|value| encode_attributes(value, geometry_ids, symbols, attributes)),
1748 point_of_contact: metadata.point_of_contact().map(|contact| ContactOwned {
1749 name_symbol: symbols.intern(contact.contact_name()),
1750 email_symbol: symbols.intern(contact.email_address()),
1751 role_symbol: contact.role().map(|role| symbols.intern(&role.to_string())),
1752 website_symbol: contact
1753 .website()
1754 .as_ref()
1755 .map(|value| symbols.intern(value)),
1756 contact_type_symbol: contact
1757 .contact_type()
1758 .map(|value| symbols.intern(&value.to_string())),
1759 address_root: contact
1760 .address()
1761 .map(|value| encode_attributes(value, geometry_ids, symbols, attributes)),
1762 phone_symbol: contact.phone().as_ref().map(|value| symbols.intern(value)),
1763 organization_symbol: contact
1764 .organization()
1765 .as_ref()
1766 .map(|value| symbols.intern(value)),
1767 }),
1768 })
1769}
1770
1771fn encode_attributes(
1772 attributes_map: &Attributes<crate::resources::storage::OwnedStringStorage>,
1773 geometry_ids: &HashMap<u32, u32>,
1774 symbols: &mut SymbolCollector,
1775 arena: &mut AttributeArenaOwned,
1776) -> AttributeNodeId {
1777 encode_attribute_value(
1778 &AttributeValue::Map(
1779 attributes_map
1780 .iter()
1781 .map(|(key, value)| (key.clone(), value.clone()))
1782 .collect(),
1783 ),
1784 None,
1785 geometry_ids,
1786 symbols,
1787 arena,
1788 )
1789}
1790
1791fn encode_attribute_value(
1792 value: &AttributeValue<crate::resources::storage::OwnedStringStorage>,
1793 key: Option<SymbolId>,
1794 geometry_ids: &HashMap<u32, u32>,
1795 symbols: &mut SymbolCollector,
1796 arena: &mut AttributeArenaOwned,
1797) -> AttributeNodeId {
1798 let id = AttributeNodeId(u32::try_from(arena.node_type.len()).unwrap_or(u32::MAX));
1799 arena.key_symbol.push(key);
1800 arena.string_value_symbol.push(None);
1801 arena.bool_value.push(None);
1802 arena.unsigned_value.push(None);
1803 arena.int_value.push(None);
1804 arena.float_value.push(None);
1805 arena.geometry_value.push(None);
1806 arena
1807 .first_child_offset
1808 .push(u32::try_from(arena.child_nodes.len()).unwrap_or(u32::MAX));
1809 arena.child_len.push(0);
1810
1811 match value {
1812 AttributeValue::Null => arena.node_type.push(AttributeNodeType::Null),
1813 AttributeValue::Bool(value) => {
1814 arena.node_type.push(AttributeNodeType::Bool);
1815 arena.bool_value[id.index()] = Some(*value);
1816 }
1817 AttributeValue::Unsigned(value) => {
1818 arena.node_type.push(AttributeNodeType::Unsigned);
1819 arena.unsigned_value[id.index()] = Some(*value);
1820 }
1821 AttributeValue::Integer(value) => {
1822 arena.node_type.push(AttributeNodeType::Integer);
1823 arena.int_value[id.index()] = Some(*value);
1824 }
1825 AttributeValue::Float(value) => {
1826 arena.node_type.push(AttributeNodeType::Float);
1827 arena.float_value[id.index()] = Some(*value);
1828 }
1829 AttributeValue::String(value) => {
1830 arena.node_type.push(AttributeNodeType::String);
1831 arena.string_value_symbol[id.index()] = Some(symbols.intern(value));
1832 }
1833 AttributeValue::Geometry(handle) => {
1834 arena.node_type.push(AttributeNodeType::GeometryRef);
1835 arena.geometry_value[id.index()] = Some(GeometryId(
1836 *geometry_ids.get(&slot(*handle)).unwrap_or(&u32::MAX),
1837 ));
1838 }
1839 AttributeValue::Vec(values) => {
1840 arena.node_type.push(AttributeNodeType::Array);
1841 let start = arena.child_nodes.len();
1842 for child in values {
1843 let child_id = encode_attribute_value(child, None, geometry_ids, symbols, arena);
1844 arena.child_nodes.push(child_id);
1845 }
1846 arena.first_child_offset[id.index()] = u32::try_from(start).unwrap_or(u32::MAX);
1847 arena.child_len[id.index()] =
1848 u32::try_from(arena.child_nodes.len() - start).unwrap_or(u32::MAX);
1849 }
1850 AttributeValue::Map(values) => {
1851 arena.node_type.push(AttributeNodeType::Object);
1852 let mut ordered = values.iter().collect::<Vec<_>>();
1853 ordered.sort_by(|(left, _), (right, _)| left.as_str().cmp(right.as_str()));
1854 let start = arena.child_nodes.len();
1855 for (child_key, child_value) in ordered {
1856 let child_id = encode_attribute_value(
1857 child_value,
1858 Some(symbols.intern(child_key)),
1859 geometry_ids,
1860 symbols,
1861 arena,
1862 );
1863 arena.child_nodes.push(child_id);
1864 }
1865 arena.first_child_offset[id.index()] = u32::try_from(start).unwrap_or(u32::MAX);
1866 arena.child_len[id.index()] =
1867 u32::try_from(arena.child_nodes.len() - start).unwrap_or(u32::MAX);
1868 }
1869 }
1870
1871 id
1872}
1873
1874#[allow(clippy::too_many_arguments)]
1875fn decode_geometry(
1876 table: &GeometryTableOwned,
1877 index: usize,
1878 template_handles: &[crate::resources::handles::GeometryTemplateHandle],
1879 semantic_handles: &[crate::resources::handles::SemanticHandle],
1880 material_handles: &[crate::resources::handles::MaterialHandle],
1881 texture_handles: &[crate::resources::handles::TextureHandle],
1882 template_vertices: bool,
1883 relational: &OwnedRelationalSnapshot,
1884) -> Result<Geometry<u32, crate::resources::storage::OwnedStringStorage>> {
1885 let boundary = decode_boundary(table, index)?;
1886 let semantics = decode_semantic_map(table, index, semantic_handles);
1887 let materials = decode_material_maps(table, index, material_handles, relational)?;
1888 let textures = decode_texture_maps(table, index, texture_handles, relational)?;
1889 let instance = match (table.template_ref[index], table.reference_point[index]) {
1890 (Some(template), Some(reference_point)) => Some(StoredGeometryInstance {
1891 template: template_handles[template.index()],
1892 reference_point: VertexIndex::new(reference_point.0),
1893 transformation: AffineTransform3D::new(table.transform_matrix[index]),
1894 }),
1895 _ => None,
1896 };
1897
1898 let _ = template_vertices;
1899
1900 Ok(Geometry::from_stored_parts(StoredGeometryParts {
1901 type_geometry: parse_geometry_type(relational.symbol(table.geometry_type_symbols[index])?),
1902 lod: table.lod_symbols[index]
1903 .map(|symbol| parse_lod(relational.symbol(symbol).unwrap_or("0"))),
1904 boundaries: boundary,
1905 semantics,
1906 materials,
1907 textures,
1908 instance,
1909 }))
1910}
1911
1912fn decode_boundary(table: &GeometryTableOwned, index: usize) -> Result<Option<Boundary<u32>>> {
1913 let vertices: Vec<VertexIndex<u32>> = slice_u32(
1914 &table.boundary_vertices,
1915 table.boundary_vertex_start[index],
1916 table.boundary_vertex_len[index],
1917 )?
1918 .iter()
1919 .map(|value| VertexIndex::new(value.0))
1920 .collect();
1921 let rings: Vec<VertexIndex<u32>> = slice_copy(
1922 &table.boundary_rings,
1923 table.boundary_ring_start[index],
1924 table.boundary_ring_len[index],
1925 )?
1926 .into_iter()
1927 .map(VertexIndex::new)
1928 .collect();
1929 let surfaces: Vec<VertexIndex<u32>> = slice_copy(
1930 &table.boundary_surfaces,
1931 table.boundary_surface_start[index],
1932 table.boundary_surface_len[index],
1933 )?
1934 .into_iter()
1935 .map(VertexIndex::new)
1936 .collect();
1937 let shells: Vec<VertexIndex<u32>> = slice_copy(
1938 &table.boundary_shells,
1939 table.boundary_shell_start[index],
1940 table.boundary_shell_len[index],
1941 )?
1942 .into_iter()
1943 .map(VertexIndex::new)
1944 .collect();
1945 let solids: Vec<VertexIndex<u32>> = slice_copy(
1946 &table.boundary_solids,
1947 table.boundary_solid_start[index],
1948 table.boundary_solid_len[index],
1949 )?
1950 .into_iter()
1951 .map(VertexIndex::new)
1952 .collect();
1953
1954 if vertices.is_empty()
1955 && rings.is_empty()
1956 && surfaces.is_empty()
1957 && shells.is_empty()
1958 && solids.is_empty()
1959 {
1960 return Ok(None);
1961 }
1962
1963 Ok(Some(Boundary::from_parts(
1964 vertices, rings, surfaces, shells, solids,
1965 )?))
1966}
1967
1968fn decode_semantic_map(
1969 table: &GeometryTableOwned,
1970 index: usize,
1971 semantic_handles: &[crate::resources::handles::SemanticHandle],
1972) -> Option<SemanticMap<u32>> {
1973 let points = slice_copy(
1974 &table.semantic_points,
1975 table.semantic_point_start[index],
1976 table.semantic_point_len[index],
1977 )
1978 .ok()?;
1979 let linestrings = slice_copy(
1980 &table.semantic_linestrings,
1981 table.semantic_linestring_start[index],
1982 table.semantic_linestring_len[index],
1983 )
1984 .ok()?;
1985 let surfaces = slice_copy(
1986 &table.semantic_surfaces,
1987 table.semantic_surface_start[index],
1988 table.semantic_surface_len[index],
1989 )
1990 .ok()?;
1991
1992 if points.is_empty() && linestrings.is_empty() && surfaces.is_empty() {
1993 return None;
1994 }
1995
1996 let mut map = SemanticMap::new();
1997 for value in points {
1998 map.add_point(value.map(|id| semantic_handles[id.index()]));
1999 }
2000 for value in linestrings {
2001 map.add_linestring(value.map(|id| semantic_handles[id.index()]));
2002 }
2003 for value in surfaces {
2004 map.add_surface(value.map(|id| semantic_handles[id.index()]));
2005 }
2006 Some(map)
2007}
2008
2009#[allow(clippy::type_complexity)]
2010fn decode_material_maps(
2011 table: &GeometryTableOwned,
2012 index: usize,
2013 material_handles: &[crate::resources::handles::MaterialHandle],
2014 relational: &OwnedRelationalSnapshot,
2015) -> Result<
2016 Option<
2017 Vec<(
2018 ThemeName<crate::resources::storage::OwnedStringStorage>,
2019 MaterialMap<u32>,
2020 )>,
2021 >,
2022> {
2023 let start = usize::try_from(table.material_theme_start[index]).unwrap_or(usize::MAX);
2024 let len = usize::try_from(table.material_theme_len[index]).unwrap_or(usize::MAX);
2025 if len == 0 {
2026 return Ok(None);
2027 }
2028
2029 let mut items = Vec::with_capacity(len);
2030 for row in &table.material_themes[start..start + len] {
2031 let mut map = MaterialMap::new();
2032 for value in slice_copy(&table.material_points, row.point_start, row.point_len)? {
2033 map.add_point(value.map(|id| material_handles[id.index()]));
2034 }
2035 for value in slice_copy(
2036 &table.material_linestrings,
2037 row.linestring_start,
2038 row.linestring_len,
2039 )? {
2040 map.add_linestring(value.map(|id| material_handles[id.index()]));
2041 }
2042 for value in slice_copy(&table.material_surfaces, row.surface_start, row.surface_len)? {
2043 map.add_surface(value.map(|id| material_handles[id.index()]));
2044 }
2045 items.push((
2046 ThemeName::new(relational.symbol(row.theme_symbol)?.to_string()),
2047 map,
2048 ));
2049 }
2050
2051 Ok(Some(items))
2052}
2053
2054#[allow(clippy::type_complexity)]
2055fn decode_texture_maps(
2056 table: &GeometryTableOwned,
2057 index: usize,
2058 texture_handles: &[crate::resources::handles::TextureHandle],
2059 relational: &OwnedRelationalSnapshot,
2060) -> Result<
2061 Option<
2062 Vec<(
2063 ThemeName<crate::resources::storage::OwnedStringStorage>,
2064 PublicTextureMap<u32>,
2065 )>,
2066 >,
2067> {
2068 let start = usize::try_from(table.texture_theme_start[index]).unwrap_or(usize::MAX);
2069 let len = usize::try_from(table.texture_theme_len[index]).unwrap_or(usize::MAX);
2070 if len == 0 {
2071 return Ok(None);
2072 }
2073
2074 let mut items = Vec::with_capacity(len);
2075 for row in &table.texture_themes[start..start + len] {
2076 let mut map = PublicTextureMap::new();
2077 for value in slice_copy(&table.texture_vertex_refs, row.vertex_start, row.vertex_len)? {
2078 map.add_vertex(value.map(|id| VertexIndex::new(id.0)));
2079 }
2080 for value in slice_copy(&table.texture_rings, row.ring_start, row.ring_len)? {
2081 map.add_ring(VertexIndex::new(value));
2082 }
2083 for value in slice_copy(
2084 &table.texture_ring_textures,
2085 row.ring_texture_start,
2086 row.ring_texture_len,
2087 )? {
2088 map.add_ring_texture(value.map(|id| texture_handles[id.index()]));
2089 }
2090 items.push((
2091 ThemeName::new(relational.symbol(row.theme_symbol)?.to_string()),
2092 map,
2093 ));
2094 }
2095
2096 Ok(Some(items))
2097}
2098
2099fn decode_attributes(
2100 arena: &AttributeArenaOwned,
2101 symbols: &[String],
2102 root: AttributeNodeId,
2103 geometry_handles: Option<&[crate::resources::handles::GeometryHandle]>,
2104) -> Result<Option<Attributes<crate::resources::storage::OwnedStringStorage>>> {
2105 match decode_attribute_value(arena, symbols, root, geometry_handles)? {
2106 AttributeValue::Map(values) => Ok(Some(Attributes::from(values))),
2107 _ => Ok(None),
2108 }
2109}
2110
2111fn decode_attribute_value(
2112 arena: &AttributeArenaOwned,
2113 symbols: &[String],
2114 id: AttributeNodeId,
2115 geometry_handles: Option<&[crate::resources::handles::GeometryHandle]>,
2116) -> Result<AttributeValue<crate::resources::storage::OwnedStringStorage>> {
2117 let index = id.index();
2118 let kind = arena
2119 .node_type
2120 .get(index)
2121 .copied()
2122 .ok_or_else(|| Error::Import(format!("missing attribute node {}", id.0)))?;
2123
2124 Ok(match kind {
2125 AttributeNodeType::Null => AttributeValue::Null,
2126 AttributeNodeType::Bool => AttributeValue::Bool(arena.bool_value[index].unwrap_or(false)),
2127 AttributeNodeType::Unsigned => {
2128 AttributeValue::Unsigned(arena.unsigned_value[index].unwrap_or_default())
2129 }
2130 AttributeNodeType::Integer => {
2131 AttributeValue::Integer(arena.int_value[index].unwrap_or_default())
2132 }
2133 AttributeNodeType::Float => {
2134 AttributeValue::Float(arena.float_value[index].unwrap_or_default())
2135 }
2136 AttributeNodeType::String => AttributeValue::String(
2137 arena
2138 .string_value_symbol
2139 .get(index)
2140 .copied()
2141 .flatten()
2142 .and_then(|symbol| symbols.get(symbol.index()).cloned())
2143 .unwrap_or_default(),
2144 ),
2145 AttributeNodeType::GeometryRef => AttributeValue::Geometry(
2146 arena.geometry_value[index]
2147 .and_then(|geometry| {
2148 geometry_handles.and_then(|handles| handles.get(geometry.index()).copied())
2149 })
2150 .unwrap_or_default(),
2151 ),
2152 AttributeNodeType::Array => {
2153 let mut values = Vec::new();
2154 let start = usize::try_from(arena.first_child_offset[index]).unwrap_or(usize::MAX);
2155 let len = usize::try_from(arena.child_len[index]).unwrap_or(usize::MAX);
2156 for child in &arena.child_nodes[start..start + len] {
2157 values.push(decode_attribute_value(
2158 arena,
2159 symbols,
2160 *child,
2161 geometry_handles,
2162 )?);
2163 }
2164 AttributeValue::Vec(values)
2165 }
2166 AttributeNodeType::Object => {
2167 let mut values = HashMap::new();
2168 let start = usize::try_from(arena.first_child_offset[index]).unwrap_or(usize::MAX);
2169 let len = usize::try_from(arena.child_len[index]).unwrap_or(usize::MAX);
2170 for child in &arena.child_nodes[start..start + len] {
2171 let child_index = child.index();
2172 let key = arena.key_symbol[child_index]
2173 .and_then(|symbol| symbols.get(symbol.index()).cloned())
2174 .unwrap_or_default();
2175 values.insert(
2176 key,
2177 decode_attribute_value(arena, symbols, *child, geometry_handles)?,
2178 );
2179 }
2180 AttributeValue::Map(values)
2181 }
2182 })
2183}
2184
2185fn dense_cityobject_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2186 model
2187 .cityobjects()
2188 .iter()
2189 .enumerate()
2190 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2191 .collect()
2192}
2193
2194fn dense_cityobject_remap(model: &OwnedCityModel) -> DenseIndexRemap {
2195 dense_remap_from_slots(model.cityobjects().iter().map(|(handle, _)| slot(handle)))
2196}
2197
2198fn dense_geometry_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2199 model
2200 .iter_geometries()
2201 .enumerate()
2202 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2203 .collect()
2204}
2205
2206fn dense_geometry_template_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2207 model
2208 .iter_geometry_templates()
2209 .enumerate()
2210 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2211 .collect()
2212}
2213
2214fn dense_geometry_template_remap(model: &OwnedCityModel) -> DenseIndexRemap {
2215 dense_remap_from_slots(
2216 model
2217 .iter_geometry_templates()
2218 .map(|(handle, _)| slot(handle)),
2219 )
2220}
2221
2222fn dense_semantic_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2223 model
2224 .iter_semantics()
2225 .enumerate()
2226 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2227 .collect()
2228}
2229
2230fn dense_material_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2231 model
2232 .iter_materials()
2233 .enumerate()
2234 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2235 .collect()
2236}
2237
2238fn dense_texture_ids(model: &OwnedCityModel) -> HashMap<u32, u32> {
2239 model
2240 .iter_textures()
2241 .enumerate()
2242 .map(|(dense, (handle, _))| (slot(handle), u32::try_from(dense).unwrap_or(u32::MAX)))
2243 .collect()
2244}
2245
2246fn dense_remap_from_slots(slots: impl Iterator<Item = u32>) -> DenseIndexRemap {
2247 let occupied = slots
2248 .map(|slot| usize::try_from(slot).unwrap_or(usize::MAX))
2249 .collect::<Vec<_>>();
2250 let capacity = occupied.iter().copied().max().map_or(0, |max| max + 1);
2251 DenseIndexRemap::from_occupied_indices(capacity, occupied)
2252}
2253
2254fn slot<H>(handle: H) -> u32
2255where
2256 H: Copy,
2257 H: crate::resources::handles::HandleType,
2258{
2259 handle.to_raw().index()
2260}
2261
2262fn push_boundary(boundary: &Boundary<u32>, table: &mut GeometryTableOwned) {
2263 let vertex_start = table.boundary_vertices.len();
2264 table.boundary_vertices.extend(
2265 boundary
2266 .vertices()
2267 .iter()
2268 .map(|value| VertexId(value.value())),
2269 );
2270 table
2271 .boundary_vertex_start
2272 .push(u32::try_from(vertex_start).unwrap_or(u32::MAX));
2273 table
2274 .boundary_vertex_len
2275 .push(u32::try_from(table.boundary_vertices.len() - vertex_start).unwrap_or(u32::MAX));
2276
2277 let ring_start = table.boundary_rings.len();
2278 table
2279 .boundary_rings
2280 .extend(boundary.rings_raw().iter().copied());
2281 table
2282 .boundary_ring_start
2283 .push(u32::try_from(ring_start).unwrap_or(u32::MAX));
2284 table
2285 .boundary_ring_len
2286 .push(u32::try_from(table.boundary_rings.len() - ring_start).unwrap_or(u32::MAX));
2287
2288 let surface_start = table.boundary_surfaces.len();
2289 table
2290 .boundary_surfaces
2291 .extend(boundary.surfaces_raw().iter().copied());
2292 table
2293 .boundary_surface_start
2294 .push(u32::try_from(surface_start).unwrap_or(u32::MAX));
2295 table
2296 .boundary_surface_len
2297 .push(u32::try_from(table.boundary_surfaces.len() - surface_start).unwrap_or(u32::MAX));
2298
2299 let shell_start = table.boundary_shells.len();
2300 table
2301 .boundary_shells
2302 .extend(boundary.shells_raw().iter().copied());
2303 table
2304 .boundary_shell_start
2305 .push(u32::try_from(shell_start).unwrap_or(u32::MAX));
2306 table
2307 .boundary_shell_len
2308 .push(u32::try_from(table.boundary_shells.len() - shell_start).unwrap_or(u32::MAX));
2309
2310 let solid_start = table.boundary_solids.len();
2311 table
2312 .boundary_solids
2313 .extend(boundary.solids_raw().iter().copied());
2314 table
2315 .boundary_solid_start
2316 .push(u32::try_from(solid_start).unwrap_or(u32::MAX));
2317 table
2318 .boundary_solid_len
2319 .push(u32::try_from(table.boundary_solids.len() - solid_start).unwrap_or(u32::MAX));
2320}
2321
2322fn push_empty_boundary(table: &mut GeometryTableOwned) {
2323 table
2324 .boundary_vertex_start
2325 .push(u32::try_from(table.boundary_vertices.len()).unwrap_or(u32::MAX));
2326 table.boundary_vertex_len.push(0);
2327 table
2328 .boundary_ring_start
2329 .push(u32::try_from(table.boundary_rings.len()).unwrap_or(u32::MAX));
2330 table.boundary_ring_len.push(0);
2331 table
2332 .boundary_surface_start
2333 .push(u32::try_from(table.boundary_surfaces.len()).unwrap_or(u32::MAX));
2334 table.boundary_surface_len.push(0);
2335 table
2336 .boundary_shell_start
2337 .push(u32::try_from(table.boundary_shells.len()).unwrap_or(u32::MAX));
2338 table.boundary_shell_len.push(0);
2339 table
2340 .boundary_solid_start
2341 .push(u32::try_from(table.boundary_solids.len()).unwrap_or(u32::MAX));
2342 table.boundary_solid_len.push(0);
2343}
2344
2345fn push_semantic_assignments(
2346 semantics: crate::v2_0::geometry::SemanticMapView<'_, u32>,
2347 semantic_ids: &HashMap<u32, u32>,
2348 table: &mut GeometryTableOwned,
2349) {
2350 let point_start = table.semantic_points.len();
2351 table
2352 .semantic_points
2353 .extend(semantics.points().iter().map(|value| {
2354 value.map(|id| SemanticId(*semantic_ids.get(&slot(id)).unwrap_or(&u32::MAX)))
2355 }));
2356 table
2357 .semantic_point_start
2358 .push(u32::try_from(point_start).unwrap_or(u32::MAX));
2359 table
2360 .semantic_point_len
2361 .push(u32::try_from(table.semantic_points.len() - point_start).unwrap_or(u32::MAX));
2362
2363 let linestring_start = table.semantic_linestrings.len();
2364 table
2365 .semantic_linestrings
2366 .extend(semantics.linestrings().iter().map(|value| {
2367 value.map(|id| SemanticId(*semantic_ids.get(&slot(id)).unwrap_or(&u32::MAX)))
2368 }));
2369 table
2370 .semantic_linestring_start
2371 .push(u32::try_from(linestring_start).unwrap_or(u32::MAX));
2372 table.semantic_linestring_len.push(
2373 u32::try_from(table.semantic_linestrings.len() - linestring_start).unwrap_or(u32::MAX),
2374 );
2375
2376 let surface_start = table.semantic_surfaces.len();
2377 table
2378 .semantic_surfaces
2379 .extend(semantics.surfaces().iter().map(|value| {
2380 value.map(|id| SemanticId(*semantic_ids.get(&slot(id)).unwrap_or(&u32::MAX)))
2381 }));
2382 table
2383 .semantic_surface_start
2384 .push(u32::try_from(surface_start).unwrap_or(u32::MAX));
2385 table
2386 .semantic_surface_len
2387 .push(u32::try_from(table.semantic_surfaces.len() - surface_start).unwrap_or(u32::MAX));
2388}
2389
2390fn push_empty_semantic_assignments(table: &mut GeometryTableOwned) {
2391 table
2392 .semantic_point_start
2393 .push(u32::try_from(table.semantic_points.len()).unwrap_or(u32::MAX));
2394 table.semantic_point_len.push(0);
2395 table
2396 .semantic_linestring_start
2397 .push(u32::try_from(table.semantic_linestrings.len()).unwrap_or(u32::MAX));
2398 table.semantic_linestring_len.push(0);
2399 table
2400 .semantic_surface_start
2401 .push(u32::try_from(table.semantic_surfaces.len()).unwrap_or(u32::MAX));
2402 table.semantic_surface_len.push(0);
2403}
2404
2405fn slice_copy<T: Copy>(items: &[T], start: u32, len: u32) -> Result<Vec<T>> {
2406 let start = usize::try_from(start).unwrap_or(usize::MAX);
2407 let len = usize::try_from(len).unwrap_or(usize::MAX);
2408 items
2409 .get(start..start + len)
2410 .map(<[T]>::to_vec)
2411 .ok_or_else(|| Error::Import("invalid relational slice".to_string()))
2412}
2413
2414fn slice_u32(items: &[VertexId], start: u32, len: u32) -> Result<&[VertexId]> {
2415 let start = usize::try_from(start).unwrap_or(usize::MAX);
2416 let len = usize::try_from(len).unwrap_or(usize::MAX);
2417 items
2418 .get(start..start + len)
2419 .ok_or_else(|| Error::Import("invalid relational vertex slice".to_string()))
2420}
2421
2422fn cityobject_type_name(
2423 value: &CityObjectType<crate::resources::storage::OwnedStringStorage>,
2424) -> String {
2425 value.to_string()
2426}
2427
2428fn semantic_type_name(
2429 value: &SemanticType<crate::resources::storage::OwnedStringStorage>,
2430) -> String {
2431 match value {
2432 SemanticType::Extension(value) => value.clone(),
2433 _ => format!("{value:?}"),
2434 }
2435}
2436
2437fn parse_cityobject_type(
2438 value: &str,
2439) -> Result<CityObjectType<crate::resources::storage::OwnedStringStorage>> {
2440 CityObjectType::from_str(value)
2441}
2442
2443fn parse_geometry_type(value: &str) -> GeometryType {
2444 GeometryType::from_str(value).unwrap_or(GeometryType::MultiPoint)
2445}
2446
2447fn parse_semantic_type(value: &str) -> SemanticType<crate::resources::storage::OwnedStringStorage> {
2448 match value {
2449 "Default" => SemanticType::Default,
2450 "RoofSurface" => SemanticType::RoofSurface,
2451 "GroundSurface" => SemanticType::GroundSurface,
2452 "WallSurface" => SemanticType::WallSurface,
2453 "ClosureSurface" => SemanticType::ClosureSurface,
2454 "OuterCeilingSurface" => SemanticType::OuterCeilingSurface,
2455 "OuterFloorSurface" => SemanticType::OuterFloorSurface,
2456 "Window" => SemanticType::Window,
2457 "Door" => SemanticType::Door,
2458 "InteriorWallSurface" => SemanticType::InteriorWallSurface,
2459 "CeilingSurface" => SemanticType::CeilingSurface,
2460 "FloorSurface" => SemanticType::FloorSurface,
2461 "WaterSurface" => SemanticType::WaterSurface,
2462 "WaterGroundSurface" => SemanticType::WaterGroundSurface,
2463 "WaterClosureSurface" => SemanticType::WaterClosureSurface,
2464 "TrafficArea" => SemanticType::TrafficArea,
2465 "AuxiliaryTrafficArea" => SemanticType::AuxiliaryTrafficArea,
2466 "TransportationMarking" => SemanticType::TransportationMarking,
2467 "TransportationHole" => SemanticType::TransportationHole,
2468 other => SemanticType::Extension(other.to_string()),
2469 }
2470}
2471
2472fn parse_lod(value: &str) -> LoD {
2473 match value {
2474 "0.0" => LoD::LoD0_0,
2475 "0.1" => LoD::LoD0_1,
2476 "0.2" => LoD::LoD0_2,
2477 "0.3" => LoD::LoD0_3,
2478 "1" => LoD::LoD1,
2479 "1.0" => LoD::LoD1_0,
2480 "1.1" => LoD::LoD1_1,
2481 "1.2" => LoD::LoD1_2,
2482 "1.3" => LoD::LoD1_3,
2483 "2" => LoD::LoD2,
2484 "2.0" => LoD::LoD2_0,
2485 "2.1" => LoD::LoD2_1,
2486 "2.2" => LoD::LoD2_2,
2487 "2.3" => LoD::LoD2_3,
2488 "3" => LoD::LoD3,
2489 "3.0" => LoD::LoD3_0,
2490 "3.1" => LoD::LoD3_1,
2491 "3.2" => LoD::LoD3_2,
2492 "3.3" => LoD::LoD3_3,
2493 _ => LoD::LoD0,
2494 }
2495}
2496
2497fn parse_image_type(value: &str) -> crate::v2_0::ImageType {
2498 match value {
2499 "JPG" => crate::v2_0::ImageType::Jpg,
2500 _ => crate::v2_0::ImageType::Png,
2501 }
2502}
2503
2504fn parse_wrap_mode(value: &str) -> WrapMode {
2505 match value {
2506 "wrap" => WrapMode::Wrap,
2507 "mirror" => WrapMode::Mirror,
2508 "clamp" => WrapMode::Clamp,
2509 "border" => WrapMode::Border,
2510 _ => WrapMode::None,
2511 }
2512}
2513
2514fn parse_texture_type(value: &str) -> crate::v2_0::TextureType {
2515 match value {
2516 "specific" => crate::v2_0::TextureType::Specific,
2517 "typical" => crate::v2_0::TextureType::Typical,
2518 _ => crate::v2_0::TextureType::Unknown,
2519 }
2520}
2521
2522fn parse_contact_role(value: &str) -> ContactRole {
2523 match value {
2524 "CoAuthor" => ContactRole::CoAuthor,
2525 "Processor" => ContactRole::Processor,
2526 "PointOfContact" => ContactRole::PointOfContact,
2527 "Owner" => ContactRole::Owner,
2528 "User" => ContactRole::User,
2529 "Distributor" => ContactRole::Distributor,
2530 "Originator" => ContactRole::Originator,
2531 "Custodian" => ContactRole::Custodian,
2532 "ResourceProvider" => ContactRole::ResourceProvider,
2533 "RightsHolder" => ContactRole::RightsHolder,
2534 "Sponsor" => ContactRole::Sponsor,
2535 "PrincipalInvestigator" => ContactRole::PrincipalInvestigator,
2536 "Stakeholder" => ContactRole::Stakeholder,
2537 "Publisher" => ContactRole::Publisher,
2538 _ => ContactRole::Author,
2539 }
2540}
2541
2542fn parse_contact_type(value: &str) -> ContactType {
2543 match value {
2544 "Organization" => ContactType::Organization,
2545 _ => ContactType::Individual,
2546 }
2547}
2548
2549#[cfg(test)]
2550mod tests {
2551 use super::{RelationalAccess, RelationalImportOptions, RelationalModelBuilder};
2552 use crate::CityModelType;
2553 use crate::query::summary;
2554 use crate::v2_0::geometry::semantic::SemanticType;
2555 use crate::v2_0::{
2556 CityObject, CityObjectType, Extension, GeometryDraft, ImageType, Material,
2557 OwnedAttributeValue, OwnedCityModel, RingDraft, Semantic, SurfaceDraft, Texture, ThemeName,
2558 };
2559
2560 #[allow(clippy::too_many_lines)]
2561 #[test]
2562 fn owned_model_roundtrips_through_relational_builder() {
2563 let mut model = OwnedCityModel::new(CityModelType::CityJSONFeature);
2564
2565 let roof_semantic = model
2566 .add_semantic(Semantic::new(SemanticType::RoofSurface))
2567 .unwrap();
2568 let roof_material = model
2569 .add_material(Material::new("roof".to_string()))
2570 .unwrap();
2571 let roof_texture = model
2572 .add_texture(Texture::new("roof.png".to_string(), ImageType::Png))
2573 .unwrap();
2574
2575 let geometry = GeometryDraft::multi_surface(
2576 None,
2577 [SurfaceDraft::new(
2578 RingDraft::new([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]).with_texture(
2579 "tex".to_string(),
2580 roof_texture,
2581 [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]],
2582 ),
2583 [],
2584 )
2585 .with_semantic(roof_semantic)
2586 .with_material("mat".to_string(), roof_material)],
2587 )
2588 .insert_into(&mut model)
2589 .unwrap();
2590
2591 let mut building = CityObject::new(
2592 crate::v2_0::CityObjectIdentifier::new("building-1".to_string()),
2593 CityObjectType::Building,
2594 );
2595 building.add_geometry(geometry);
2596 building.attributes_mut().insert(
2597 "name".to_string(),
2598 OwnedAttributeValue::String("demo".to_string()),
2599 );
2600 let building_handle = model.cityobjects_mut().add(building).unwrap();
2601 model.set_id(Some(building_handle));
2602 model.metadata_mut().set_title("demo dataset".to_string());
2603 model.metadata_mut().extra_mut().insert(
2604 "source".to_string(),
2605 OwnedAttributeValue::String("unit-test".to_string()),
2606 );
2607 model.set_default_material_theme(Some(ThemeName::new("mat".to_string())));
2608 model.set_default_texture_theme(Some(ThemeName::new("tex".to_string())));
2609 model.extensions_mut().add(Extension::new(
2610 "noise".to_string(),
2611 "https://example.com/noise.json".to_string(),
2612 "1.0".to_string(),
2613 ));
2614
2615 let relational = model.relational_snapshot();
2616 let baseline = summary(&model);
2617
2618 assert_eq!(relational.cityobjects().len(), 1);
2619 assert_eq!(relational.geometries().len(), 1);
2620 assert!(relational.symbols().len() >= 6);
2621
2622 let mut builder =
2623 RelationalModelBuilder::new(model.type_citymodel(), RelationalImportOptions::default());
2624 builder
2625 .push_symbols(relational.symbol_table().clone())
2626 .unwrap();
2627 builder
2628 .push_vertices(relational.vertex_table().clone())
2629 .unwrap();
2630 builder
2631 .push_template_vertices(relational.template_vertex_table().clone())
2632 .unwrap();
2633 builder
2634 .push_uv_vertices(relational.uv_vertex_table().clone())
2635 .unwrap();
2636 builder
2637 .push_semantics(relational.semantics().clone())
2638 .unwrap();
2639 builder
2640 .push_materials(relational.materials().clone())
2641 .unwrap();
2642 builder
2643 .push_textures(relational.textures().clone())
2644 .unwrap();
2645 builder
2646 .push_attributes(relational.attributes().clone())
2647 .unwrap();
2648 builder
2649 .push_cityobjects(relational.cityobjects().clone())
2650 .unwrap();
2651 builder
2652 .push_geometries(relational.geometries().clone())
2653 .unwrap();
2654 builder
2655 .push_geometry_templates(relational.geometry_templates().clone())
2656 .unwrap();
2657 builder
2658 .push_metadata(relational.metadata_owned().cloned())
2659 .unwrap();
2660 builder
2661 .push_transform(relational.transform_owned().copied())
2662 .unwrap();
2663 builder
2664 .push_defaults(relational.defaults_owned().clone())
2665 .unwrap();
2666 builder
2667 .push_extensions(relational.extensions().clone())
2668 .unwrap();
2669 builder
2670 .push_feature_root(relational.feature_root())
2671 .unwrap();
2672
2673 let rebuilt = builder.finish().unwrap();
2674 let rebuilt_summary = summary(&rebuilt);
2675
2676 assert_eq!(rebuilt_summary.cityobject_count, baseline.cityobject_count);
2677 assert_eq!(rebuilt_summary.geometry_count, baseline.geometry_count);
2678 assert_eq!(rebuilt_summary.semantic_count, baseline.semantic_count);
2679 assert_eq!(rebuilt_summary.material_count, baseline.material_count);
2680 assert_eq!(rebuilt_summary.texture_count, baseline.texture_count);
2681 assert_eq!(
2682 rebuilt.id().unwrap(),
2683 rebuilt.cityobjects().first().unwrap().0
2684 );
2685 assert_eq!(rebuilt.metadata().unwrap().title(), Some("demo dataset"));
2686 assert!(rebuilt.has_material_theme("mat"));
2687 assert!(rebuilt.has_texture_theme("tex"));
2688 assert_eq!(rebuilt.extensions().unwrap().len(), 1);
2689 assert_eq!(
2690 rebuilt
2691 .cityobjects()
2692 .first()
2693 .unwrap()
2694 .1
2695 .attributes()
2696 .unwrap()
2697 .get("name"),
2698 Some(&OwnedAttributeValue::String("demo".to_string()))
2699 );
2700 }
2701}