egml_io/geometry/
solid.rs1use quick_xml::de;
2use std::hash::{DefaultHasher, Hash, Hasher};
3
4use crate::GmlSurfaceMember;
5use crate::error::Error;
6use crate::error::Error::MissingElements;
7use egml_core::model::base::{AbstractGml, Id};
8use egml_core::model::geometry::{Solid, SurfaceProperty};
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")]
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 abstract_gml = AbstractGml::new(id);
46
47 let surface_properties: Vec<SurfaceProperty> = value
48 .exterior
49 .ok_or(MissingElements())?
50 .shell
51 .ok_or(MissingElements())?
52 .members
53 .into_iter()
54 .map(|x| x.try_into())
55 .collect::<Result<Vec<_>, _>>()?;
56
57 let solid = Solid::new(abstract_gml, surface_properties)?;
58 Ok(solid)
59 }
60}
61
62pub fn parse_solid(source_text: &str) -> Result<Solid, Error> {
63 let parsed_geometry: GmlSolid = de::from_str(source_text)?;
64 parsed_geometry.try_into()
65}
66
67#[cfg(test)]
68mod tests {
69 use crate::geometry::solid::parse_solid;
70
71 #[test]
72 fn parsing_solid() {
73 let source_text = "\
74 <gml:Solid gml:id=\"UUID_9c9c6a8e-4704-4675-b3c0-e8f8c9dc4522\">
75 <gml:exterior>
76 <gml:Shell>
77 <gml:surfaceMember>
78 <gml:Polygon gml:id=\"UUID_bdc0d140-fb3a-4f9e-aaaf-90c9d3c4f37e\">
79 <gml:exterior>
80 <gml:LinearRing>
81 <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>
82 </gml:LinearRing>
83 </gml:exterior>
84 </gml:Polygon>
85 </gml:surfaceMember>
86 <gml:surfaceMember>
87 <gml:Polygon gml:id=\"UUID_b4e59597-63a3-46a0-a91b-91689cf63b7d\">
88 <gml:exterior>
89 <gml:LinearRing>
90 <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>
91 </gml:LinearRing>
92 </gml:exterior>
93 </gml:Polygon>
94 </gml:surfaceMember>
95 </gml:Shell>
96 </gml:exterior>
97 </gml:Solid>";
98
99 let solid_geometry = parse_solid(source_text).unwrap();
100
101 assert_eq!(solid_geometry.members().len(), 2);
102 }
103
104 #[test]
105 fn parsing_solid_xlink_members() {
106 let source_text = "\
107 <gml:Solid srsDimension=\"3\">
108 <gml:exterior>
109 <gml:Shell>
110 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_59772_4becb506-d53b-44ca-a483-e6a3d238b4c2_2_poly\"/>
111 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_59772_be3462c3-9865-467b-829d-76e6b9b692e7_2_poly\"/>
112 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_59772_c0aae462-3f4b-4062-80bb-8cd04768ab1a_2_poly\"/>
113 </gml:Shell>
114 </gml:exterior>
115 </gml:Solid>";
116
117 let solid_geometry = parse_solid(source_text).unwrap();
118
119 assert_eq!(solid_geometry.members().len(), 3);
120 }
121
122 #[test]
123 fn parsing_solid_without_ids() {
124 let source_text = "\
125 <gml:Solid>
126 <gml:exterior>
127 <gml:Shell>
128 <gml:surfaceMember>
129 <gml:Polygon>
130 <gml:exterior>
131 <gml:LinearRing>
132 <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>
133 </gml:LinearRing>
134 </gml:exterior>
135 </gml:Polygon>
136 </gml:surfaceMember>
137 <gml:surfaceMember>
138 <gml:Polygon>
139 <gml:exterior>
140 <gml:LinearRing>
141 <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>
142 </gml:LinearRing>
143 </gml:exterior>
144 </gml:Polygon>
145 </gml:surfaceMember>
146 </gml:Shell>
147 </gml:exterior>
148 </gml:Solid>";
149
150 let solid_geometry = parse_solid(source_text).unwrap();
151
152 assert_eq!(solid_geometry.members().len(), 2);
153 }
154
155 #[test]
156 fn parsing_solid_with_xlinks_only() {
157 let source_text = "\
159 <gml:Solid srsDimension=\"3\">
160 <gml:exterior>
161 <gml:Shell>
162 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_a8f507d0-7f89-4966-8f8d-0ffa02508922_poly\"/>
163 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_d2691fca-4e89-404c-80f8-fc90794581d8_poly\"/>
164 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_f3d48f8e-6ae2-49ea-9dd8-4f08af06a738_poly\"/>
165 <gml:surfaceMember xlink:href=\"#DEBY_LOD2_4905373_1dea43d2-0e28-4010-9297-606eb7abcc42_poly\"/>
166 </gml:Shell>
167 </gml:exterior>
168 </gml:Solid>";
169
170 }
174}