egml_io/geometry/
solid.rs

1use quick_xml::de;
2use std::hash::{DefaultHasher, Hash, Hasher};
3
4use crate::error::Error;
5use crate::error::Error::MissingElements;
6use crate::GmlSurfaceMember;
7use egml_core::model::base::{Gml, Id};
8use egml_core::model::geometry::{LinearRing, Solid};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
12#[serde(rename = "gml:Solid")]
13struct GmlSolid {
14    #[serde(rename = "@id", default)]
15    id: String,
16    // #[serde(rename = "$value")]
17    // members: Vec<SurfaceMemberElement>,
18    #[serde(rename = "$value")]
19    exterior: Option<GmlShellProperty>,
20}
21
22#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
23#[serde(rename = "gml:exterior")]
24struct GmlShellProperty {
25    #[serde(rename = "$value")]
26    shell: Option<GmlShell>,
27}
28
29#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
30#[serde(rename = "gml:Shell")]
31struct GmlShell {
32    #[serde(rename = "$value")]
33    members: Vec<GmlSurfaceMember>,
34}
35
36impl TryFrom<GmlSolid> for Solid {
37    type Error = Error;
38
39    fn try_from(value: GmlSolid) -> Result<Self, Self::Error> {
40        let id: Id = value.id.clone().try_into().ok().unwrap_or_else(|| {
41            let mut hasher = DefaultHasher::new();
42            value.hash(&mut hasher);
43            Id::from_hashed_u64(hasher.finish())
44        });
45        let gml = Gml::new(id);
46
47        let linear_rings: Vec<LinearRing> = value
48            .exterior
49            .ok_or(MissingElements())?
50            .shell
51            .ok_or(MissingElements())?
52            .members
53            .into_iter()
54            .flat_map(|x| x.polygon)
55            .map(|x| x.exterior)
56            .flat_map(|x| x.linear_ring)
57            .map(|x| x.try_into().unwrap())
58            .collect();
59
60        let solid = Solid::new(gml, linear_rings)?;
61        Ok(solid)
62    }
63}
64
65pub fn parse_solid(source_text: &str) -> Result<Solid, Error> {
66    let parsed_geometry: GmlSolid = de::from_str(source_text)?;
67    parsed_geometry.try_into()
68}
69
70#[cfg(test)]
71mod tests {
72    use crate::geometry::solid::parse_solid;
73
74    #[test]
75    fn parsing_solid() {
76        let source_text = "\
77        <gml:Solid gml:id=\"UUID_9c9c6a8e-4704-4675-b3c0-e8f8c9dc4522\">
78          <gml:exterior>
79            <gml:Shell>
80              <gml:surfaceMember>
81                <gml:Polygon gml:id=\"UUID_bdc0d140-fb3a-4f9e-aaaf-90c9d3c4f37e\">
82                  <gml:exterior>
83                    <gml:LinearRing>
84                      <gml:posList srsDimension=\"3\">677996.9921558445 5403654.972995559 414.84686725860973 677996.9730161787 5403654.969217261 414.84686725860973 677996.9538875414 5403654.973051003 414.84686725860973 677996.9376820943 5403654.983913131 414.84686725860973 677996.9268669697 5403655.000149984 414.84686725860973 677996.9230886723 5403655.01928965 414.84686725860973 677996.9269224138 5403655.038418287 414.84686725860973 677996.9377845416 5403655.054623734 414.84686725860973 677996.9540213953 5403655.065438859 414.84686725860973 677996.9731610611 5403655.069217157 414.84686725860973 677996.9922896983 5403655.065383415 414.84686725860973 677997.0084951455 5403655.054521287 414.84686725860973 677997.0193102701 5403655.038284434 414.84686725860973 677997.0230885674 5403655.019144768 414.84686725860973 677997.019254826 5403655.0000161305 414.84686725860973 677997.0083926981 5403654.983810684 414.84686725860973 677996.9921558445 5403654.972995559 414.84686725860973</gml:posList>
85                    </gml:LinearRing>
86                  </gml:exterior>
87                </gml:Polygon>
88              </gml:surfaceMember>
89              <gml:surfaceMember>
90                <gml:Polygon gml:id=\"UUID_b4e59597-63a3-46a0-a91b-91689cf63b7d\">
91                  <gml:exterior>
92                    <gml:LinearRing>
93                      <gml:posList srsDimension=\"3\">677997.0083926981 5403654.983810684 418.08686725860974 677997.019254826 5403655.0000161305 418.08686725860974 677997.0230885674 5403655.019144768 418.08686725860974 677997.0193102701 5403655.038284434 418.08686725860974 677997.0084951455 5403655.054521287 418.08686725860974 677996.9922896983 5403655.065383415 418.08686725860974 677996.9731610611 5403655.069217157 418.08686725860974 677996.9540213953 5403655.065438859 418.08686725860974 677996.9377845416 5403655.054623734 418.08686725860974 677996.9269224138 5403655.038418287 418.08686725860974 677996.9230886723 5403655.01928965 418.08686725860974 677996.9268669697 5403655.000149984 418.08686725860974 677996.9376820943 5403654.983913131 418.08686725860974 677996.9538875414 5403654.973051003 418.08686725860974 677996.9730161787 5403654.969217261 418.08686725860974 677996.9921558445 5403654.972995559 418.08686725860974 677997.0083926981 5403654.983810684 418.08686725860974</gml:posList>
94                    </gml:LinearRing>
95                  </gml:exterior>
96                </gml:Polygon>
97              </gml:surfaceMember>
98            </gml:Shell>
99          </gml:exterior>
100        </gml:Solid>";
101
102        let solid_geometry = parse_solid(source_text).unwrap();
103
104        assert_eq!(solid_geometry.members().len(), 2);
105    }
106
107    #[test]
108    fn parsing_solid_without_ids() {
109        let source_text = "\
110        <gml:Solid>
111          <gml:exterior>
112            <gml:Shell>
113              <gml:surfaceMember>
114                <gml:Polygon>
115                  <gml:exterior>
116                    <gml:LinearRing>
117                      <gml:posList srsDimension=\"3\">677996.9921558445 5403654.972995559 414.84686725860973 677996.9730161787 5403654.969217261 414.84686725860973 677996.9538875414 5403654.973051003 414.84686725860973 677996.9376820943 5403654.983913131 414.84686725860973 677996.9268669697 5403655.000149984 414.84686725860973 677996.9230886723 5403655.01928965 414.84686725860973 677996.9269224138 5403655.038418287 414.84686725860973 677996.9377845416 5403655.054623734 414.84686725860973 677996.9540213953 5403655.065438859 414.84686725860973 677996.9731610611 5403655.069217157 414.84686725860973 677996.9922896983 5403655.065383415 414.84686725860973 677997.0084951455 5403655.054521287 414.84686725860973 677997.0193102701 5403655.038284434 414.84686725860973 677997.0230885674 5403655.019144768 414.84686725860973 677997.019254826 5403655.0000161305 414.84686725860973 677997.0083926981 5403654.983810684 414.84686725860973 677996.9921558445 5403654.972995559 414.84686725860973</gml:posList>
118                    </gml:LinearRing>
119                  </gml:exterior>
120                </gml:Polygon>
121              </gml:surfaceMember>
122              <gml:surfaceMember>
123                <gml:Polygon>
124                  <gml:exterior>
125                    <gml:LinearRing>
126                      <gml:posList srsDimension=\"3\">677997.0083926981 5403654.983810684 418.08686725860974 677997.019254826 5403655.0000161305 418.08686725860974 677997.0230885674 5403655.019144768 418.08686725860974 677997.0193102701 5403655.038284434 418.08686725860974 677997.0084951455 5403655.054521287 418.08686725860974 677996.9922896983 5403655.065383415 418.08686725860974 677996.9731610611 5403655.069217157 418.08686725860974 677996.9540213953 5403655.065438859 418.08686725860974 677996.9377845416 5403655.054623734 418.08686725860974 677996.9269224138 5403655.038418287 418.08686725860974 677996.9230886723 5403655.01928965 418.08686725860974 677996.9268669697 5403655.000149984 418.08686725860974 677996.9376820943 5403654.983913131 418.08686725860974 677996.9538875414 5403654.973051003 418.08686725860974 677996.9730161787 5403654.969217261 418.08686725860974 677996.9921558445 5403654.972995559 418.08686725860974 677997.0083926981 5403654.983810684 418.08686725860974</gml:posList>
127                    </gml:LinearRing>
128                  </gml:exterior>
129                </gml:Polygon>
130              </gml:surfaceMember>
131            </gml:Shell>
132          </gml:exterior>
133        </gml:Solid>";
134
135        let solid_geometry = parse_solid(source_text).unwrap();
136
137        assert_eq!(solid_geometry.members().len(), 2);
138    }
139
140    #[test]
141    fn parsing_solid_with_xlinks_only() {
142        // TODO
143        let source_text = "\
144        <gml:Solid srsDimension=\"3\">
145          <gml:exterior>
146            <gml:Shell>
147              <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_a8f507d0-7f89-4966-8f8d-0ffa02508922_poly\"/>
148              <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_d2691fca-4e89-404c-80f8-fc90794581d8_poly\"/>
149              <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_f3d48f8e-6ae2-49ea-9dd8-4f08af06a738_poly\"/>
150              <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_1dea43d2-0e28-4010-9297-606eb7abcc42_poly\"/>
151            </gml:Shell>
152          </gml:exterior>
153        </gml:Solid>";
154
155        //let solid_geometry = parse_solid(source_text).unwrap();
156
157        //assert_eq!(solid_geometry.members().len(), 4);
158    }
159}