cjseq/
lib.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{json, Error, Value};
3use std::collections::HashMap;
4
5const DEFAULT_CRS_BASE_URL: &str = "https://www.opengis.net/def/crs";
6
7#[derive(Clone)]
8pub enum SortingStrategy {
9    Random,
10    Lexicographical,
11    Morton,  //-- TODO implement Morton sorting
12    Hilbert, //-- TODO implement Hilbert sorting
13}
14
15#[derive(Serialize, Deserialize, Debug, Clone)]
16pub struct CityJSON {
17    #[serde(rename = "type")]
18    pub thetype: String,
19    pub version: String,
20    pub transform: Transform,
21    #[serde(rename = "CityObjects")]
22    pub city_objects: HashMap<String, CityObject>,
23    pub vertices: Vec<Vec<i64>>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub metadata: Option<Metadata>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub appearance: Option<Appearance>,
28    #[serde(rename = "geometry-templates")]
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub geometry_templates: Option<GeometryTemplates>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub extensions: Option<Value>,
33    #[serde(flatten)]
34    pub other: serde_json::Value,
35    #[serde(skip)]
36    sorted_ids: Vec<String>,
37    #[serde(skip)]
38    transform_correction: Option<Transform>,
39}
40impl CityJSON {
41    /// Create a new CityJSON instance with default values.
42    pub fn new() -> Self {
43        let co: HashMap<String, CityObject> = HashMap::new();
44        let v: Vec<Vec<i64>> = Vec::new();
45        let tr = Transform::new();
46        CityJSON {
47            thetype: "CityJSON".to_string(),
48            version: "2.0".to_string(),
49            transform: tr,
50            city_objects: co,
51            vertices: v,
52            metadata: None,
53            appearance: None,
54            geometry_templates: None,
55            extensions: None,
56            other: json!(null),
57            sorted_ids: vec![],
58            transform_correction: None,
59        }
60    }
61    /// Create a new CityJSON instance from a string.
62    pub fn from_str(s: &str) -> Result<Self, Error> {
63        let mut cjj: CityJSON = serde_json::from_str(s)?;
64        //-- check if CO exists, then add them to the sorted_ids
65        for (key, co) in &cjj.city_objects {
66            if co.is_toplevel() {
67                cjj.sorted_ids.push(key.clone());
68            }
69        }
70        Ok(cjj)
71    }
72
73    /// Get the "first line" (aka metadata or header) of a CityJSONSeq
74    pub fn get_metadata(&self) -> Self {
75        let co: HashMap<String, CityObject> = HashMap::new();
76        let v: Vec<Vec<i64>> = Vec::new();
77        let mut cj0 = CityJSON {
78            thetype: self.thetype.clone(),
79            version: self.version.clone(),
80            transform: self.transform.clone(),
81            metadata: self.metadata.clone(),
82            city_objects: co,
83            vertices: v,
84            appearance: None,
85            geometry_templates: self.geometry_templates.clone(),
86            other: self.other.clone(),
87            extensions: self.extensions.clone(),
88            sorted_ids: vec![],
89            transform_correction: None,
90        };
91        //-- if geometry-templates have material/textures then these need to be
92        //-- added to 1st line (metadata)
93        match &self.geometry_templates {
94            Some(x) => {
95                let mut gts2: GeometryTemplates = x.clone();
96                let mut m_oldnew: HashMap<usize, usize> = HashMap::new();
97                let mut t_oldnew: HashMap<usize, usize> = HashMap::new();
98                let mut t_v_oldnew: HashMap<usize, usize> = HashMap::new();
99                for g in &mut gts2.templates {
100                    g.update_material(&mut m_oldnew);
101                    g.update_texture(&mut t_oldnew, &mut t_v_oldnew, 0);
102                }
103                //-- "slice" materials
104                if self.appearance.is_some() {
105                    let a = self.appearance.as_ref().unwrap();
106                    let mut acjf: Appearance = Appearance::new();
107                    acjf.default_theme_material = a.default_theme_material.clone();
108                    acjf.default_theme_texture = a.default_theme_texture.clone();
109                    if a.materials.is_some() {
110                        let am = a.materials.as_ref().unwrap();
111                        let mut mats2: Vec<Value> = Vec::new();
112                        mats2.resize(m_oldnew.len(), json!(null));
113                        for (old, new) in &m_oldnew {
114                            mats2[*new] = am[*old].clone();
115                        }
116                        acjf.materials = Some(mats2);
117                    }
118                    if a.textures.is_some() {
119                        let at = a.textures.as_ref().unwrap();
120                        let mut texs2: Vec<Value> = Vec::new();
121                        texs2.resize(t_oldnew.len(), json!(null));
122                        for (old, new) in &t_oldnew {
123                            texs2[*new] = at[*old].clone();
124                        }
125                        acjf.textures = Some(texs2);
126                    }
127                    if a.vertices_texture.is_some() {
128                        let atv = a.vertices_texture.as_ref().unwrap();
129                        let mut t_new_vertices: Vec<Vec<f64>> = Vec::new();
130                        t_new_vertices.resize(t_v_oldnew.len(), vec![]);
131                        for (old, new) in &t_v_oldnew {
132                            t_new_vertices[*new] = atv[*old].clone();
133                        }
134                        acjf.vertices_texture = Some(t_new_vertices);
135                    }
136                    cj0.appearance = Some(acjf);
137                }
138            }
139            None => (),
140        }
141        cj0
142    }
143    /// Getter for the features in a CityJSON dataset.
144    /// Starts at 0, and return Option::None if the index is out of bounds.
145    pub fn get_cjfeature(&self, i: usize) -> Option<CityJSONFeature> {
146        let i2 = self.sorted_ids.get(i);
147        if i2.is_none() {
148            return None;
149        }
150        let obj = self.city_objects.get(i2.unwrap());
151        if obj.is_none() {
152            return None;
153        }
154        let co = obj.unwrap();
155        //-- the other lines
156        let mut cjf = CityJSONFeature::new();
157        let mut co2: CityObject = co.clone();
158        let mut g_vi_oldnew: HashMap<usize, usize> = HashMap::new();
159        let mut m_oldnew: HashMap<usize, usize> = HashMap::new();
160        let mut t_oldnew: HashMap<usize, usize> = HashMap::new();
161        let mut t_v_oldnew: HashMap<usize, usize> = HashMap::new();
162        match &mut co2.geometry {
163            Some(x) => {
164                for g in x.iter_mut() {
165                    g.update_geometry_boundaries(&mut g_vi_oldnew);
166                    g.update_material(&mut m_oldnew);
167                    g.update_texture(&mut t_oldnew, &mut t_v_oldnew, 0);
168                }
169            }
170            None => (),
171        }
172        cjf.add_co(self.sorted_ids[i].clone(), co2);
173        cjf.id = self.sorted_ids[i].to_string();
174        //-- TODO: to fix: children-of-children?
175        //-- process all the children (only one-level lower)
176        for childkey in co.get_children_keys() {
177            let coc = self.city_objects.get(&childkey).unwrap();
178            let mut coc2: CityObject = coc.clone();
179            match &mut coc2.geometry {
180                Some(x) => {
181                    for g in x.iter_mut() {
182                        g.update_geometry_boundaries(&mut g_vi_oldnew);
183                        g.update_material(&mut m_oldnew);
184                        g.update_texture(&mut t_oldnew, &mut t_v_oldnew, 0);
185                    }
186                }
187                None => (),
188            }
189            cjf.add_co(childkey.clone(), coc2);
190        }
191        //-- "slice" geometry vertices
192        let allvertices = &self.vertices;
193        let mut g_new_vertices: Vec<Vec<i64>> = Vec::new();
194        g_new_vertices.resize(g_vi_oldnew.len(), vec![]);
195        for (old, new) in &g_vi_oldnew {
196            g_new_vertices[*new] = allvertices[*old].clone();
197        }
198        cjf.vertices = g_new_vertices;
199        //-- "slice" materials
200        if self.appearance.is_some() {
201            let a = self.appearance.as_ref().unwrap();
202            let mut acjf: Appearance = Appearance::new();
203            acjf.default_theme_material = a.default_theme_material.clone();
204            acjf.default_theme_texture = a.default_theme_texture.clone();
205            if a.materials.is_some() {
206                let am = a.materials.as_ref().unwrap();
207                let mut mats2: Vec<Value> = Vec::new();
208                mats2.resize(m_oldnew.len(), json!(null));
209                for (old, new) in &m_oldnew {
210                    mats2[*new] = am[*old].clone();
211                }
212                acjf.materials = Some(mats2);
213            }
214            if a.textures.is_some() {
215                let at = a.textures.as_ref().unwrap();
216                let mut texs2: Vec<Value> = Vec::new();
217                texs2.resize(t_oldnew.len(), json!(null));
218                for (old, new) in &t_oldnew {
219                    texs2[*new] = at[*old].clone();
220                }
221                acjf.textures = Some(texs2);
222            }
223            if a.vertices_texture.is_some() {
224                let atv = a.vertices_texture.as_ref().unwrap();
225                let mut t_new_vertices: Vec<Vec<f64>> = Vec::new();
226                t_new_vertices.resize(t_v_oldnew.len(), vec![]);
227                for (old, new) in &t_v_oldnew {
228                    t_new_vertices[*new] = atv[*old].clone();
229                }
230                acjf.vertices_texture = Some(t_new_vertices);
231            }
232            cjf.appearance = Some(acjf);
233        }
234        Some(cjf)
235    }
236    /// Used when many CityJSONSeq are used, the "transform" can
237    /// be modified (the new value is a "correction").
238    pub fn add_transform_correction(&mut self, t: Transform) {
239        self.transform_correction = Some(t);
240    }
241    pub fn add_cjfeature(&mut self, cjf: &mut CityJSONFeature) {
242        let mut m_oldnew: HashMap<usize, usize> = HashMap::new();
243        let mut t_oldnew: HashMap<usize, usize> = HashMap::new();
244        let mut t_v_oldnew: HashMap<usize, usize> = HashMap::new();
245        let g_offset = self.vertices.len();
246        let mut t_offset = 0;
247        if let Some(cjf_app) = &cjf.appearance {
248            if let Some(cjf_mat) = &cjf_app.materials {
249                for (i, m) in cjf_mat.iter().enumerate() {
250                    m_oldnew.insert(i, self.add_material(m.clone()));
251                }
252            }
253            if let Some(cjf_tex) = &cjf_app.textures {
254                for (i, m) in cjf_tex.iter().enumerate() {
255                    t_oldnew.insert(i, self.add_texture(m.clone()));
256                }
257            }
258            if let Some(cjf_v_tex) = &cjf_app.vertices_texture {
259                t_offset = cjf_v_tex.len();
260                self.add_vertices_texture(cjf_v_tex.clone());
261            }
262        }
263
264        for (key, co) in &mut cjf.city_objects {
265            //-- boundaries
266            if let Some(ref mut geoms) = &mut co.geometry {
267                for g in geoms.iter_mut() {
268                    //-- boundaries
269                    g.offset_geometry_boundaries(g_offset);
270                    // g.update_geometry_boundaries(&mut g_oldnew, g_offset);
271                    //-- material
272                    g.update_material(&mut m_oldnew);
273                    //-- texture
274                    g.update_texture(&mut t_oldnew, &mut t_v_oldnew, t_offset);
275                }
276            }
277            //-- update the collected json object by adding the CityObjects
278            self.add_co(key.to_string(), co.clone());
279        }
280        //-- add the new vertices
281        self.add_vertices(&mut cjf.vertices);
282        //-- add the CO id to the list
283        self.sorted_ids.push(cjf.id.clone());
284    }
285    pub fn remove_duplicate_vertices(&mut self) {
286        // let totalinput = self.vertices.len();
287        let mut h: HashMap<String, usize> = HashMap::new();
288        let mut newids: HashMap<usize, usize> = HashMap::new();
289        let mut newvertices: Vec<Vec<i64>> = Vec::new();
290        for (i, v) in self.vertices.iter().enumerate() {
291            // println!("{:?}", v);
292            let k = format!("{} {} {}", v[0], v[1], v[2]);
293            match h.get(&k) {
294                Some(x) => {
295                    let _ = newids.insert(i, *x);
296                }
297                None => {
298                    newids.insert(i, newvertices.len());
299                    h.insert(k.clone(), newvertices.len());
300                    newvertices.push(v.clone());
301                }
302            }
303        }
304        //-- update indices
305        let cos = &mut self.city_objects;
306        for (_key, co) in cos.iter_mut() {
307            match &mut co.geometry {
308                Some(x) => {
309                    for g in x.iter_mut() {
310                        g.update_geometry_boundaries(&mut newids);
311                    }
312                }
313                None => (),
314            }
315        }
316        //-- replace the vertices, innit?
317        self.vertices = newvertices;
318    }
319    pub fn update_geographicalextent(&mut self) {
320        if let Some(m) = &mut self.metadata {
321            if let Some(ref mut ge) = m.geographical_extent {
322                let mut mins: Vec<i64> = vec![i64::MAX, i64::MAX, i64::MAX];
323                let mut maxs: Vec<i64> = vec![i64::MIN, i64::MIN, i64::MIN];
324                for v in &self.vertices {
325                    for i in 0..3 {
326                        if v[i] < mins[i] {
327                            mins[i] = v[i];
328                        }
329                        if v[i] > maxs[i] {
330                            maxs[i] = v[i];
331                        }
332                    }
333                }
334                *ge = [
335                    mins[0] as f64 * self.transform.scale[0] + self.transform.translate[0],
336                    mins[1] as f64 * self.transform.scale[1] + self.transform.translate[1],
337                    mins[2] as f64 * self.transform.scale[2] + self.transform.translate[2],
338                    maxs[0] as f64 * self.transform.scale[0] + self.transform.translate[0],
339                    maxs[1] as f64 * self.transform.scale[1] + self.transform.translate[1],
340                    maxs[2] as f64 * self.transform.scale[2] + self.transform.translate[2],
341                ];
342            }
343        }
344    }
345    pub fn update_transform(&mut self) {
346        let mut newvertices: Vec<Vec<i64>> = Vec::new();
347        let mut mins: Vec<i64> = vec![i64::MAX, i64::MAX, i64::MAX];
348        //-- find min-xyz
349        for v in &self.vertices {
350            for i in 0..3 {
351                if v[i] < mins[i] {
352                    mins[i] = v[i];
353                }
354            }
355        }
356        //-- subtract the mins from each vertex
357        for v in &self.vertices {
358            let v: Vec<i64> = vec![v[0] - mins[0], v[1] - mins[1], v[2] - mins[2]];
359            newvertices.push(v);
360        }
361        //-- replace the vertices, innit?
362        self.vertices = newvertices;
363        //-- update the transform/translate
364        let ttx = (mins[0] as f64 * self.transform.scale[0]) + self.transform.translate[0];
365        let tty = (mins[1] as f64 * self.transform.scale[1]) + self.transform.translate[1];
366        let ttz = (mins[2] as f64 * self.transform.scale[2]) + self.transform.translate[2];
367        self.transform.translate = vec![ttx, tty, ttz];
368    }
369    pub fn number_of_city_objects(&self) -> usize {
370        let mut total: usize = 0;
371        for (_key, co) in &self.city_objects {
372            if co.is_toplevel() {
373                total += 1;
374            }
375        }
376        total
377    }
378    /// When getting the CityJSONFeatures, this controls the order in which
379    /// they are returned. By default they are returned in the order they were added.
380    pub fn sort_cjfeatures(&mut self, ss: SortingStrategy) {
381        self.sorted_ids.clear();
382        match ss {
383            SortingStrategy::Random => {
384                for (key, co) in &self.city_objects {
385                    if co.is_toplevel() {
386                        self.sorted_ids.push(key.clone());
387                    }
388                }
389            }
390            SortingStrategy::Lexicographical => {
391                for (key, co) in &self.city_objects {
392                    if co.is_toplevel() {
393                        self.sorted_ids.push(key.clone());
394                    }
395                }
396                self.sorted_ids.sort();
397            }
398            _ => todo!(),
399        }
400    }
401    fn add_co(&mut self, id: String, co: CityObject) {
402        self.city_objects.insert(id.clone(), co);
403    }
404    fn add_vertices(&mut self, vs: &mut Vec<Vec<i64>>) {
405        if self.transform_correction.is_none() {
406            self.vertices.append(vs);
407        } else {
408            //-- the transfrom correction needs to be applied
409            let c = self.transform_correction.as_ref().unwrap();
410            for v in vs {
411                let cx: i64 = (((v[0] as f64 * c.scale[0]) + c.translate[0]
412                    - self.transform.translate[0])
413                    / self.transform.scale[0])
414                    .round() as i64;
415                let cy: i64 = (((v[1] as f64 * c.scale[1]) + c.translate[1]
416                    - self.transform.translate[1])
417                    / self.transform.scale[1])
418                    .round() as i64;
419                let cz: i64 = (((v[2] as f64 * c.scale[2]) + c.translate[2]
420                    - self.transform.translate[2])
421                    / self.transform.scale[2])
422                    .round() as i64;
423                self.vertices.push(vec![cx, cy, cz]);
424            }
425        }
426    }
427    fn add_vertices_texture(&mut self, vs: Vec<Vec<f64>>) {
428        match &mut self.appearance {
429            Some(x) => x.add_vertices_texture(vs),
430            None => {
431                let mut a: Appearance = Appearance::new();
432                a.add_vertices_texture(vs);
433                self.appearance = Some(a);
434            }
435        };
436    }
437    fn add_material(&mut self, jm: Value) -> usize {
438        let re = match &mut self.appearance {
439            Some(x) => x.add_material(jm),
440            None => {
441                let mut a: Appearance = Appearance::new();
442                let re = a.add_material(jm);
443                self.appearance = Some(a);
444                re
445            }
446        };
447        re
448    }
449    fn add_texture(&mut self, jm: Value) -> usize {
450        let re = match &mut self.appearance {
451            Some(x) => x.add_texture(jm),
452            None => {
453                let mut a: Appearance = Appearance::new();
454                let re = a.add_texture(jm);
455                self.appearance = Some(a);
456                re
457            }
458        };
459        re
460    }
461}
462
463#[derive(Serialize, Deserialize, Debug, Clone)]
464pub struct CityJSONFeature {
465    #[serde(rename = "type")]
466    pub thetype: String,
467    pub id: String,
468    #[serde(rename = "CityObjects")]
469    pub city_objects: HashMap<String, CityObject>,
470    pub vertices: Vec<Vec<i64>>,
471    #[serde(skip_serializing_if = "Option::is_none")]
472    pub appearance: Option<Appearance>,
473}
474impl CityJSONFeature {
475    pub fn new() -> Self {
476        let co: HashMap<String, CityObject> = HashMap::new();
477        let v: Vec<Vec<i64>> = Vec::new();
478        CityJSONFeature {
479            thetype: "CityJSONFeature".to_string(),
480            id: "".to_string(),
481            city_objects: co,
482            vertices: v,
483            appearance: None,
484        }
485    }
486    pub fn from_str(s: &str) -> Result<Self, Error> {
487        let cjf: CityJSONFeature = serde_json::from_str(&s)?;
488        Ok(cjf)
489    }
490    pub fn add_co(&mut self, id: String, co: CityObject) {
491        self.city_objects.insert(id, co);
492    }
493    pub fn centroid(&self) -> Vec<f64> {
494        let mut totals: Vec<f64> = vec![0., 0., 0.];
495        for v in &self.vertices {
496            for i in 0..3 {
497                totals[i] += v[i] as f64;
498            }
499        }
500        for i in 0..3 {
501            totals[i] /= self.vertices.len() as f64;
502        }
503        return totals;
504    }
505}
506
507#[derive(Serialize, Deserialize, Debug, Clone)]
508pub struct CityObject {
509    #[serde(rename = "type")]
510    pub thetype: String,
511    #[serde(rename = "geographicalExtent")]
512    #[serde(skip_serializing_if = "Option::is_none")]
513    pub geographical_extent: Option<Vec<f64>>,
514    #[serde(skip_serializing_if = "Option::is_none")]
515    pub attributes: Option<Value>,
516    #[serde(skip_serializing_if = "Option::is_none")]
517    pub geometry: Option<Vec<Geometry>>,
518    #[serde(skip_serializing_if = "Option::is_none")]
519    pub children: Option<Vec<String>>,
520    #[serde(skip_serializing_if = "Option::is_none")]
521    pub parents: Option<Vec<String>>,
522    #[serde(flatten)]
523    other: serde_json::Value,
524}
525
526impl CityObject {
527    pub fn get_type(&self) -> String {
528        self.thetype.clone()
529    }
530    fn is_toplevel(&self) -> bool {
531        match &self.parents {
532            Some(x) => {
533                if x.is_empty() {
534                    return true;
535                } else {
536                    return false;
537                }
538            }
539            None => return true,
540        }
541    }
542    fn get_children_keys(&self) -> Vec<String> {
543        let mut re: Vec<String> = Vec::new();
544        match &self.children {
545            Some(x) => {
546                for each in x {
547                    re.push(each.to_string());
548                }
549            }
550            None => (),
551        }
552        re
553    }
554}
555
556#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
557pub enum GeometryType {
558    MultiPoint,
559    MultiLineString,
560    MultiSurface,
561    CompositeSurface,
562    Solid,
563    MultiSolid,
564    CompositeSolid,
565    GeometryInstance,
566}
567
568#[derive(Serialize, Deserialize, Debug, Clone)]
569pub struct Geometry {
570    #[serde(rename = "type")]
571    pub thetype: GeometryType,
572    #[serde(skip_serializing_if = "Option::is_none")]
573    pub lod: Option<String>,
574    pub boundaries: Value,
575    #[serde(skip_serializing_if = "Option::is_none")]
576    pub semantics: Option<Value>,
577    #[serde(skip_serializing_if = "Option::is_none")]
578    pub material: Option<HashMap<String, Material>>,
579    #[serde(skip_serializing_if = "Option::is_none")]
580    pub texture: Option<HashMap<String, Texture>>,
581    #[serde(skip_serializing_if = "Option::is_none")]
582    pub template: Option<usize>,
583    #[serde(rename = "transformationMatrix")]
584    #[serde(skip_serializing_if = "Option::is_none")]
585    pub transformation_matrix: Option<Value>,
586}
587impl Geometry {
588    fn update_geometry_boundaries(&mut self, violdnew: &mut HashMap<usize, usize>) {
589        match self.thetype {
590            GeometryType::MultiPoint => {
591                let a: Vec<usize> = serde_json::from_value(self.boundaries.clone()).unwrap();
592                let mut a2 = a.clone();
593                for (i, x) in a.iter().enumerate() {
594                    let kk = violdnew.get(&x);
595                    if kk.is_none() {
596                        let l = violdnew.len();
597                        violdnew.insert(*x, l);
598                        a2[i] = l;
599                    } else {
600                        let kk = kk.unwrap();
601                        a2[i] = *kk;
602                    }
603                }
604                self.boundaries = serde_json::to_value(&a2).unwrap();
605            }
606            GeometryType::MultiLineString => {
607                let a: Vec<Vec<usize>> = serde_json::from_value(self.boundaries.take()).unwrap();
608                let mut a2 = a.clone();
609                for (i, x) in a.iter().enumerate() {
610                    for (j, y) in x.iter().enumerate() {
611                        // r.push(z);
612                        let kk = violdnew.get(&y);
613                        if kk.is_none() {
614                            let l = violdnew.len();
615                            violdnew.insert(*y, l);
616                            a2[i][j] = l;
617                        } else {
618                            let kk = kk.unwrap();
619                            a2[i][j] = *kk;
620                        }
621                    }
622                }
623                self.boundaries = serde_json::to_value(&a2).unwrap();
624            }
625            GeometryType::MultiSurface | GeometryType::CompositeSurface => {
626                let a: Vec<Vec<Vec<usize>>> =
627                    serde_json::from_value(self.boundaries.take()).unwrap();
628                let mut a2 = a.clone();
629                for (i, x) in a.iter().enumerate() {
630                    for (j, y) in x.iter().enumerate() {
631                        for (k, z) in y.iter().enumerate() {
632                            let kk = violdnew.get(&z);
633                            if kk.is_none() {
634                                let l = violdnew.len();
635                                violdnew.insert(*z, l);
636                                a2[i][j][k] = l;
637                            } else {
638                                let kk = kk.unwrap();
639                                a2[i][j][k] = *kk;
640                            }
641                        }
642                    }
643                }
644                self.boundaries = serde_json::to_value(&a2).unwrap();
645            }
646            GeometryType::Solid => {
647                let a: Vec<Vec<Vec<Vec<usize>>>> =
648                    serde_json::from_value(self.boundaries.take()).unwrap();
649                let mut a2 = a.clone();
650                for (i, x) in a.iter().enumerate() {
651                    for (j, y) in x.iter().enumerate() {
652                        for (k, z) in y.iter().enumerate() {
653                            for (l, zz) in z.iter().enumerate() {
654                                let kk = violdnew.get(&zz);
655                                if kk.is_none() {
656                                    let l2 = violdnew.len();
657                                    violdnew.insert(*zz, l2);
658                                    a2[i][j][k][l] = l2;
659                                } else {
660                                    let kk = kk.unwrap();
661                                    a2[i][j][k][l] = *kk;
662                                }
663                            }
664                        }
665                    }
666                }
667                self.boundaries = serde_json::to_value(&a2).unwrap();
668            }
669            GeometryType::MultiSolid | GeometryType::CompositeSolid => {
670                let a: Vec<Vec<Vec<Vec<Vec<usize>>>>> =
671                    serde_json::from_value(self.boundaries.take()).unwrap();
672                let mut a2 = a.clone();
673                for (i, x) in a.iter().enumerate() {
674                    for (j, y) in x.iter().enumerate() {
675                        for (k, z) in y.iter().enumerate() {
676                            for (l, zz) in z.iter().enumerate() {
677                                for (m, zzz) in zz.iter().enumerate() {
678                                    let kk = violdnew.get(&zzz);
679                                    if kk.is_none() {
680                                        let l2 = violdnew.len();
681                                        violdnew.insert(*zzz, l2);
682                                        a2[i][j][k][l][m] = l2;
683                                    } else {
684                                        let kk = kk.unwrap();
685                                        a2[i][j][k][l][m] = *kk;
686                                    }
687                                }
688                            }
689                        }
690                    }
691                }
692                self.boundaries = serde_json::to_value(&a2).unwrap();
693            }
694            GeometryType::GeometryInstance => {
695                let a: Vec<usize> = serde_json::from_value(self.boundaries.clone()).unwrap();
696                let mut a2 = a.clone();
697                for (i, x) in a.iter().enumerate() {
698                    let kk = violdnew.get(&x);
699                    if kk.is_none() {
700                        let l = violdnew.len();
701                        violdnew.insert(*x, l);
702                        a2[i] = l;
703                    } else {
704                        let kk = kk.unwrap();
705                        a2[i] = *kk;
706                    }
707                }
708                self.boundaries = serde_json::to_value(&a2).unwrap();
709            }
710        }
711    }
712
713    fn offset_geometry_boundaries(&mut self, offset: usize) {
714        match self.thetype {
715            GeometryType::MultiPoint => {
716                let a: Vec<usize> = serde_json::from_value(self.boundaries.clone()).unwrap();
717                let mut a2 = a.clone();
718                for (i, x) in a.iter().enumerate() {
719                    a2[i] = *x + offset;
720                }
721                self.boundaries = serde_json::to_value(&a2).unwrap();
722            }
723            GeometryType::MultiLineString => {
724                let a: Vec<Vec<usize>> = serde_json::from_value(self.boundaries.take()).unwrap();
725                let mut a2 = a.clone();
726                for (i, x) in a.iter().enumerate() {
727                    for (j, y) in x.iter().enumerate() {
728                        // r.push(z);
729                        a2[i][j] = *y + offset;
730                    }
731                }
732                self.boundaries = serde_json::to_value(&a2).unwrap();
733            }
734            GeometryType::MultiSurface | GeometryType::CompositeSurface => {
735                let a: Vec<Vec<Vec<usize>>> =
736                    serde_json::from_value(self.boundaries.take()).unwrap();
737                let mut a2 = a.clone();
738                for (i, x) in a.iter().enumerate() {
739                    for (j, y) in x.iter().enumerate() {
740                        for (k, z) in y.iter().enumerate() {
741                            a2[i][j][k] = *z + offset;
742                        }
743                    }
744                }
745                self.boundaries = serde_json::to_value(&a2).unwrap();
746            }
747            GeometryType::Solid => {
748                let a: Vec<Vec<Vec<Vec<usize>>>> =
749                    serde_json::from_value(self.boundaries.take()).unwrap();
750                let mut a2 = a.clone();
751                for (i, x) in a.iter().enumerate() {
752                    for (j, y) in x.iter().enumerate() {
753                        for (k, z) in y.iter().enumerate() {
754                            for (l, zz) in z.iter().enumerate() {
755                                a2[i][j][k][l] = *zz + offset;
756                            }
757                        }
758                    }
759                }
760                self.boundaries = serde_json::to_value(&a2).unwrap();
761            }
762            GeometryType::MultiSolid | GeometryType::CompositeSolid => {
763                let a: Vec<Vec<Vec<Vec<Vec<usize>>>>> =
764                    serde_json::from_value(self.boundaries.take()).unwrap();
765                let mut a2 = a.clone();
766                for (i, x) in a.iter().enumerate() {
767                    for (j, y) in x.iter().enumerate() {
768                        for (k, z) in y.iter().enumerate() {
769                            for (l, zz) in z.iter().enumerate() {
770                                for (m, zzz) in zz.iter().enumerate() {
771                                    a2[i][j][k][l][m] = *zzz + offset;
772                                }
773                            }
774                        }
775                    }
776                }
777                self.boundaries = serde_json::to_value(&a2).unwrap();
778            }
779            GeometryType::GeometryInstance => {
780                let a: Vec<usize> = serde_json::from_value(self.boundaries.clone()).unwrap();
781                let mut a2 = a.clone();
782                for (i, x) in a.iter().enumerate() {
783                    a2[i] = *x + offset;
784                }
785                self.boundaries = serde_json::to_value(&a2).unwrap();
786            }
787        }
788    }
789
790    fn update_material(&mut self, m_oldnew: &mut HashMap<usize, usize>) {
791        match &mut self.material {
792            Some(x) => {
793                for (_key, mat) in &mut *x {
794                    //-- material.value
795                    if mat.value.is_some() {
796                        let thevalue: usize = mat.value.unwrap();
797                        let r = m_oldnew.get(&thevalue);
798                        if r.is_none() {
799                            let l = m_oldnew.len();
800                            m_oldnew.insert(thevalue, l);
801                            mat.value = Some(l);
802                        } else {
803                            let r2 = r.unwrap();
804                            mat.value = Some(*r2);
805                        }
806                        continue;
807                    }
808                    //-- else it's material.values (which differs per geom type)
809                    match self.thetype {
810                        GeometryType::MultiPoint | GeometryType::MultiLineString => (),
811                        GeometryType::MultiSurface | GeometryType::CompositeSurface => {
812                            if mat.values.is_some() {
813                                let a: Vec<Option<usize>> =
814                                    serde_json::from_value(mat.values.take().into()).unwrap();
815                                let mut a2 = a.clone();
816                                for (i, x) in a.iter().enumerate() {
817                                    if x.is_some() {
818                                        let y2 = m_oldnew.get(&x.unwrap());
819                                        if y2.is_none() {
820                                            let l = m_oldnew.len();
821                                            m_oldnew.insert(x.unwrap(), l);
822                                            a2[i] = Some(l);
823                                        } else {
824                                            let y2 = y2.unwrap();
825                                            a2[i] = Some(*y2);
826                                        }
827                                    }
828                                }
829                                mat.values = Some(serde_json::to_value(&a2).unwrap());
830                            }
831                        }
832                        GeometryType::Solid => {
833                            if mat.values.is_some() {
834                                let a: Vec<Vec<Option<usize>>> =
835                                    serde_json::from_value(mat.values.take().into()).unwrap();
836                                let mut a2 = a.clone();
837                                for (i, x) in a.iter().enumerate() {
838                                    for (j, y) in x.iter().enumerate() {
839                                        if y.is_some() {
840                                            let y2 = m_oldnew.get(&y.unwrap());
841                                            if y2.is_none() {
842                                                let l = m_oldnew.len();
843                                                m_oldnew.insert(y.unwrap(), l);
844                                                a2[i][j] = Some(l);
845                                            } else {
846                                                let y2 = y2.unwrap();
847                                                a2[i][j] = Some(*y2);
848                                            }
849                                        }
850                                    }
851                                }
852                                mat.values = Some(serde_json::to_value(&a2).unwrap());
853                            }
854                        }
855                        GeometryType::MultiSolid | GeometryType::CompositeSolid => {
856                            if mat.values.is_some() {
857                                let a: Vec<Vec<Vec<Option<usize>>>> =
858                                    serde_json::from_value(mat.values.take().into()).unwrap();
859                                let mut a2 = a.clone();
860                                for (i, x) in a.iter().enumerate() {
861                                    for (j, y) in x.iter().enumerate() {
862                                        for (k, z) in y.iter().enumerate() {
863                                            if z.is_some() {
864                                                let y2 = m_oldnew.get(&z.unwrap());
865                                                if y2.is_none() {
866                                                    let l = m_oldnew.len();
867                                                    m_oldnew.insert(z.unwrap(), l);
868                                                    a2[i][j][k] = Some(l);
869                                                } else {
870                                                    let y2 = y2.unwrap();
871                                                    a2[i][j][k] = Some(*y2);
872                                                }
873                                            }
874                                        }
875                                    }
876                                }
877                                mat.values = Some(serde_json::to_value(&a2).unwrap());
878                            }
879                        }
880                        GeometryType::GeometryInstance => todo!(),
881                    }
882                }
883                self.material = Some(x.clone());
884            }
885            None => (),
886        }
887    }
888    fn update_texture(
889        &mut self,
890        t_oldnew: &mut HashMap<usize, usize>,
891        t_v_oldnew: &mut HashMap<usize, usize>,
892        offset: usize,
893    ) {
894        match &mut self.texture {
895            Some(x) => {
896                for (_key, tex) in &mut *x {
897                    match self.thetype {
898                        GeometryType::MultiSurface | GeometryType::CompositeSurface => {
899                            let a: Vec<Vec<Vec<Option<usize>>>> =
900                                serde_json::from_value(tex.values.take().into()).unwrap();
901                            let mut a2 = a.clone();
902                            for (i, x) in a.iter().enumerate() {
903                                for (j, y) in x.iter().enumerate() {
904                                    for (k, z) in y.iter().enumerate() {
905                                        if z.is_some() {
906                                            let thevalue: usize = z.unwrap();
907                                            if k == 0 {
908                                                let y2 = t_oldnew.get(&thevalue);
909                                                if y2.is_none() {
910                                                    let l = t_oldnew.len();
911                                                    t_oldnew.insert(thevalue, l);
912                                                    a2[i][j][k] = Some(l);
913                                                } else {
914                                                    let y2 = y2.unwrap();
915                                                    a2[i][j][k] = Some(*y2);
916                                                }
917                                            } else {
918                                                let y2 = t_v_oldnew.get(&thevalue);
919                                                if y2.is_none() {
920                                                    let l = t_v_oldnew.len();
921                                                    t_v_oldnew.insert(thevalue, l + offset);
922                                                    a2[i][j][k] = Some(l);
923                                                } else {
924                                                    let y2 = y2.unwrap();
925                                                    a2[i][j][k] = Some(*y2);
926                                                }
927                                            }
928                                        }
929                                    }
930                                }
931                            }
932                            tex.values = Some(serde_json::to_value(&a2).unwrap());
933                        }
934                        GeometryType::Solid => {
935                            let a: Vec<Vec<Vec<Vec<Option<usize>>>>> =
936                                serde_json::from_value(tex.values.take().into()).unwrap();
937                            let mut a2 = a.clone();
938                            for (i, x) in a.iter().enumerate() {
939                                for (j, y) in x.iter().enumerate() {
940                                    for (k, z) in y.iter().enumerate() {
941                                        for (l, zz) in z.iter().enumerate() {
942                                            if zz.is_some() {
943                                                let thevalue: usize = zz.unwrap();
944                                                if l == 0 {
945                                                    let y2 = t_oldnew.get(&thevalue);
946                                                    if y2.is_none() {
947                                                        let l2 = t_oldnew.len();
948                                                        t_oldnew.insert(thevalue, l2);
949                                                        a2[i][j][k][l] = Some(l2);
950                                                    } else {
951                                                        let y2 = y2.unwrap();
952                                                        a2[i][j][k][l] = Some(*y2);
953                                                    }
954                                                } else {
955                                                    let y2 = t_v_oldnew.get(&thevalue);
956                                                    if y2.is_none() {
957                                                        let l2 = t_v_oldnew.len();
958                                                        t_v_oldnew.insert(thevalue, l2 + offset);
959                                                        a2[i][j][k][l] = Some(l2);
960                                                    } else {
961                                                        let y2 = y2.unwrap();
962                                                        a2[i][j][k][l] = Some(*y2);
963                                                    }
964                                                }
965                                            }
966                                        }
967                                    }
968                                }
969                            }
970                            tex.values = Some(serde_json::to_value(&a2).unwrap());
971                        }
972                        _ => todo!(),
973                    }
974                }
975            }
976            None => (),
977        }
978    }
979}
980
981#[derive(Serialize, Deserialize, Debug)]
982struct Vertex {
983    x: i64,
984    y: i64,
985    z: i64,
986}
987
988#[derive(Serialize, Deserialize, Debug, Clone)]
989pub struct Transform {
990    pub scale: Vec<f64>,
991    pub translate: Vec<f64>,
992}
993impl Transform {
994    fn new() -> Self {
995        Transform {
996            scale: vec![1.0, 1.0, 1.0],
997            translate: vec![0., 0., 0.],
998        }
999    }
1000}
1001
1002pub type GeographicalExtent = [f64; 6];
1003
1004#[derive(Serialize, Deserialize, Debug, Clone)]
1005pub struct Address {
1006    #[serde(rename = "thoroughfareNumber")]
1007    pub thoroughfare_number: i64,
1008    #[serde(rename = "thoroughfareName")]
1009    pub thoroughfare_name: String,
1010    pub locality: String,
1011    #[serde(rename = "postalCode")]
1012    pub postal_code: String,
1013    pub country: String,
1014}
1015
1016#[derive(Serialize, Deserialize, Debug, Clone)]
1017pub struct PointOfContact {
1018    #[serde(rename = "contactName")]
1019    pub contact_name: String,
1020    #[serde(rename = "contactType")]
1021    #[serde(skip_serializing_if = "Option::is_none")]
1022    pub contact_type: Option<String>,
1023    #[serde(rename = "role")]
1024    #[serde(skip_serializing_if = "Option::is_none")]
1025    pub role: Option<String>,
1026    #[serde(skip_serializing_if = "Option::is_none")]
1027    pub phone: Option<String>,
1028    #[serde(rename = "emailAddress")]
1029    pub email_address: String,
1030    #[serde(skip_serializing_if = "Option::is_none")]
1031    pub website: Option<String>,
1032    #[serde(skip_serializing_if = "Option::is_none")]
1033    pub address: Option<Address>,
1034}
1035
1036/// A reference system following the OGC Name Type Specification.
1037///
1038/// The format follows: `http://www.opengis.net/def/crs/{authority}/{version}/{code}`
1039/// where:
1040/// - `{authority}` designates the authority responsible for the definition of this CRS
1041///   (usually "EPSG" or "OGC")
1042/// - `{version}` designates the specific version of the CRS
1043///   (use "0" if there is no version)
1044/// - `{code}` is the identifier for the specific coordinate reference system
1045#[derive(Debug, Clone)]
1046pub struct ReferenceSystem {
1047    pub base_url: String,
1048    pub authority: String,
1049    pub version: String,
1050    pub code: String,
1051}
1052
1053impl ReferenceSystem {
1054    pub fn new(base_url: Option<String>, authority: String, version: String, code: String) -> Self {
1055        let base_url = base_url.unwrap_or(DEFAULT_CRS_BASE_URL.to_string());
1056        ReferenceSystem {
1057            base_url,
1058            authority,
1059            version,
1060            code,
1061        }
1062    }
1063
1064    pub fn to_url(&self) -> String {
1065        format!(
1066            "{}/{}/{}/{}",
1067            self.base_url, self.authority, self.version, self.code
1068        )
1069    }
1070
1071    // OGC Name Type Specification:
1072    // http://www.opengis.net/def/crs/{authority}/{version}/{code}
1073    // where {authority} designates the authority responsible for the definition of this CRS (usually "EPSG" or "OGC"), and where {version} designates the specific version of the CRS ("0" (zero) is used if there is no version).
1074    pub fn from_url(url: &str) -> Result<Self, &'static str> {
1075        if !url.contains("//www.opengis.net/def/crs") {
1076            return Err("Invalid reference system URL");
1077        }
1078
1079        let i = url.find("crs").unwrap();
1080        let s = &url[i + 4..];
1081
1082        let parts: Vec<&str> = s.split("/").collect();
1083        if parts.len() != 3 {
1084            return Err("Invalid reference system URL");
1085        }
1086
1087        Ok(ReferenceSystem {
1088            base_url: url[..i + 3].to_string(),
1089            authority: parts[0].to_string(),
1090            version: parts[1].to_string(),
1091            code: parts[2].to_string(),
1092        })
1093    }
1094}
1095
1096impl Serialize for ReferenceSystem {
1097    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1098    where
1099        S: serde::Serializer,
1100    {
1101        self.to_url().serialize(serializer)
1102    }
1103}
1104
1105impl<'de> Deserialize<'de> for ReferenceSystem {
1106    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1107    where
1108        D: serde::Deserializer<'de>,
1109    {
1110        let url = String::deserialize(deserializer)?;
1111        ReferenceSystem::from_url(&url).map_err(serde::de::Error::custom)
1112    }
1113}
1114
1115#[derive(Serialize, Deserialize, Debug, Clone)]
1116pub struct Metadata {
1117    #[serde(rename = "geographicalExtent")]
1118    #[serde(skip_serializing_if = "Option::is_none")]
1119    pub geographical_extent: Option<GeographicalExtent>,
1120    #[serde(skip_serializing_if = "Option::is_none")]
1121    pub identifier: Option<String>,
1122    #[serde(rename = "pointOfContact")]
1123    #[serde(skip_serializing_if = "Option::is_none")]
1124    pub point_of_contact: Option<PointOfContact>,
1125    #[serde(rename = "referenceDate")]
1126    #[serde(skip_serializing_if = "Option::is_none")]
1127    pub reference_date: Option<String>,
1128    #[serde(rename = "referenceSystem")]
1129    #[serde(skip_serializing_if = "Option::is_none")]
1130    pub reference_system: Option<ReferenceSystem>,
1131    #[serde(skip_serializing_if = "Option::is_none")]
1132    pub title: Option<String>,
1133}
1134
1135#[derive(Serialize, Deserialize, Debug, Clone)]
1136pub struct GeometryTemplates {
1137    pub templates: Vec<Geometry>,
1138    #[serde(rename = "vertices-templates")]
1139    pub vertices_templates: Value,
1140}
1141
1142#[derive(Serialize, Deserialize, Debug, Clone)]
1143pub struct Material {
1144    #[serde(skip_serializing_if = "Option::is_none")]
1145    pub values: Option<Value>,
1146    #[serde(skip_serializing_if = "Option::is_none")]
1147    pub value: Option<usize>,
1148}
1149
1150#[derive(Serialize, Deserialize, Debug, Clone)]
1151pub struct Texture {
1152    #[serde(skip_serializing_if = "Option::is_none")]
1153    pub values: Option<Value>,
1154}
1155
1156#[derive(Serialize, Deserialize, Debug, Clone)]
1157pub struct Appearance {
1158    #[serde(skip_serializing_if = "Option::is_none")]
1159    pub materials: Option<Vec<Value>>,
1160    #[serde(skip_serializing_if = "Option::is_none")]
1161    pub textures: Option<Vec<Value>>,
1162    #[serde(rename = "vertices-texture")]
1163    #[serde(skip_serializing_if = "Option::is_none")]
1164    pub vertices_texture: Option<Vec<Vec<f64>>>,
1165    #[serde(rename = "default-theme-texture")]
1166    #[serde(skip_serializing_if = "Option::is_none")]
1167    pub default_theme_texture: Option<String>,
1168    #[serde(rename = "default-theme-material")]
1169    #[serde(skip_serializing_if = "Option::is_none")]
1170    pub default_theme_material: Option<String>,
1171}
1172impl Appearance {
1173    fn new() -> Self {
1174        Appearance {
1175            materials: None,
1176            textures: None,
1177            vertices_texture: None,
1178            default_theme_texture: None,
1179            default_theme_material: None,
1180        }
1181    }
1182    fn add_material(&mut self, jm: Value) -> usize {
1183        let re = match &mut self.materials {
1184            Some(x) => match x.iter().position(|e| *e == jm) {
1185                Some(y) => y,
1186                None => {
1187                    x.push(jm);
1188                    x.len() - 1
1189                }
1190            },
1191            None => {
1192                let mut ls: Vec<Value> = Vec::new();
1193                ls.push(jm);
1194                self.materials = Some(ls);
1195                0
1196            }
1197        };
1198        re
1199    }
1200    fn add_texture(&mut self, jm: Value) -> usize {
1201        let re = match &mut self.textures {
1202            Some(x) => match x.iter().position(|e| *e == jm) {
1203                Some(y) => y,
1204                None => {
1205                    x.push(jm);
1206                    x.len() - 1
1207                }
1208            },
1209            None => {
1210                let mut ls: Vec<Value> = Vec::new();
1211                ls.push(jm);
1212                self.textures = Some(ls);
1213                0
1214            }
1215        };
1216        re
1217    }
1218    fn add_vertices_texture(&mut self, mut vs: Vec<Vec<f64>>) {
1219        match &mut self.vertices_texture {
1220            Some(x) => {
1221                x.append(&mut vs);
1222            }
1223            None => {
1224                let mut ls: Vec<Vec<f64>> = Vec::new();
1225                ls.append(&mut vs);
1226                self.vertices_texture = Some(ls);
1227            }
1228        };
1229    }
1230}
1231
1232/// Collects a base CityJSON metadata and a vector of CityJSONFeatures
1233/// into a complete CityJSON object
1234pub fn cjseq_to_cj(mut base_cj: CityJSON, features: Vec<CityJSONFeature>) -> CityJSON {
1235    for mut feature in features {
1236        base_cj.add_cjfeature(&mut feature);
1237    }
1238
1239    base_cj.remove_duplicate_vertices();
1240    base_cj.update_transform();
1241    base_cj.update_geographicalextent();
1242
1243    base_cj
1244}
1245
1246// WASM bindings module
1247#[cfg(target_arch = "wasm32")]
1248pub mod wasm;
1249
1250// Re-export WASM functions for convenience
1251#[cfg(target_arch = "wasm32")]
1252pub use wasm::*;