egml_io/geometry/
multi_surface.rs1use crate::error::Error;
2use quick_xml::de;
3use std::hash::{DefaultHasher, Hash, Hasher};
4
5use crate::geometry::polygon::GmlPolygon;
6use egml_core::model::base::{Gml, Id};
7use egml_core::model::geometry::{MultiSurface, Polygon};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
11#[serde(rename = "gml:MultiSurface")]
12struct GmlMultiSurface {
13 #[serde(rename = "@id", default)]
14 id: String,
15 #[serde(rename = "$value")]
16 members: Vec<GmlSurfaceMember>,
17}
18
19#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
20#[serde(rename = "gml:surfaceMember")]
21pub struct GmlSurfaceMember {
22 #[serde(rename = "@href", default)]
23 href: String,
24 #[serde(rename = "$value")]
25 pub polygon: Option<GmlPolygon>,
26}
27
28impl TryFrom<GmlMultiSurface> for MultiSurface {
29 type Error = Error;
30
31 fn try_from(value: GmlMultiSurface) -> Result<Self, Self::Error> {
32 let id: Id = value.id.clone().try_into().ok().unwrap_or_else(|| {
33 let mut hasher = DefaultHasher::new();
34 value.hash(&mut hasher);
35 Id::from_hashed_u64(hasher.finish())
36 });
37 let gml = Gml::new(id);
38
39 let polygons: Vec<Polygon> = value
40 .members
41 .into_iter()
42 .flat_map(|x| x.polygon)
43 .map(|x| x.try_into())
44 .collect::<Result<Vec<_>, _>>()?;
45
46 let multi_surface = MultiSurface::new(gml, polygons)?;
47 Ok(multi_surface)
48 }
49}
50
51pub fn parse_multi_surface(source_text: &str) -> Result<MultiSurface, Error> {
52 let parsed_geometry: GmlMultiSurface = de::from_str(source_text)?;
53 parsed_geometry.try_into()
54}
55
56#[cfg(test)]
57mod tests {
58 use crate::parse_multi_surface;
59
60 #[test]
61 fn parsing_multi_surface() {
62 let source_text = "<gml:MultiSurface gml:id=\"UUID_6b33ecfa-6e08-4e8e-a4b5-e1d06540faf0\">
63 <gml:surfaceMember>
64 <gml:Polygon gml:id=\"UUID_efb8f6a5-82fa-4b21-8709-c1d93ed1e595\">
65 <gml:exterior>
66 <gml:LinearRing>
67 <gml:posList srsDimension=\"3\">678009.7116291433 5403638.313338383 417.3480034550211 678012.5609078613 5403634.960884141 417.34658523466385 678013.7892528991 5403636.004867206 417.51938733855997 678010.9399743223 5403639.357321232 417.5208051908512 678009.7116291433 5403638.313338383 417.3480034550211</gml:posList>
68 </gml:LinearRing>
69 </gml:exterior>
70 </gml:Polygon>
71 </gml:surfaceMember>
72 </gml:MultiSurface>";
73
74 let _result = parse_multi_surface(source_text).unwrap();
75 }
76
77 #[test]
78 fn parsing_multi_surface_with_duplicate_elements() {
79 let source_text = "<gml:MultiSurface srsName=\"EPSG:25832\" srsDimension=\"3\">
80 <gml:surfaceMember>
81 <gml:Polygon gml:id=\"4018133_PG.3nRTCd4XPu47PsAAUyNv\">
82 <gml:exterior>
83 <gml:LinearRing gml:id=\"4018133_LR.lHfcvQUrKVl08ifcH6eO\">
84 <gml:posList>678105.792 5403815.554 369.98523 678105.792 5403815.555 367.67323 678106.047 5403815.125 367.67323 678106.047 5403815.125 367.67323 678106.047 5403815.125 367.67323 678106.047 5403815.124 369.98523 678105.792 5403815.554 369.98523</gml:posList>
85 </gml:LinearRing>
86 </gml:exterior>
87 </gml:Polygon>
88 </gml:surfaceMember>
89 </gml:MultiSurface>";
90
91 let _result = parse_multi_surface(source_text).unwrap();
92 }
93
94 #[test]
95 fn parsing_multi_surface_with_holes() {
96 let source_text = "
97 <gml:MultiSurface srsName=\"EPSG:25832\" srsDimension=\"3\">
98 <gml:surfaceMember>
99 <gml:Polygon gml:id=\"4018106_PG.dKY9ug9ol2tsxL5bLAPz\">
100 <gml:exterior>
101 <gml:LinearRing gml:id=\"4018106_LR.Wqmtl1E6Yz3eVJkuGjsK\">
102 <gml:posList>678097.805 5403801.433 367.40123 678092.938 5403810.139 367.40123 678092.938 5403810.139 370.87623 678092.032 5403811.76 370.87623 678092.032 5403811.76 377.09023 678097.805 5403801.433 377.09023 678097.805 5403801.433 367.40123</gml:posList>
103 </gml:LinearRing>
104 </gml:exterior>
105 <gml:interior>
106 <gml:LinearRing gml:id=\"4018106_LR.10JNDsQqif3fouy54mfv\">
107 <gml:posList>678096.88 5403803.088 374.90623 678097.403 5403802.152 374.90623 678097.403 5403802.152 376.19923 678096.88 5403803.088 376.19923 678096.88 5403803.088 374.90623</gml:posList>
108 </gml:LinearRing>
109 </gml:interior>
110 <gml:interior>
111 <gml:LinearRing gml:id=\"4018106_LR.yzLlZkAQX00eXb6Xi0DZ\">
112 <gml:posList>678096.154 5403804.386 376.19923 678096.154 5403804.386 374.90623 678096.677 5403803.45 374.90623 678096.677 5403803.45 376.19923 678096.154 5403804.386 376.19923</gml:posList>
113 </gml:LinearRing>
114 </gml:interior>
115 <gml:interior>
116 <gml:LinearRing gml:id=\"4018106_LR.MIkI0SEPyMQ4yblCNiF2\">
117 <gml:posList>678095.438 5403805.667 376.19923 678095.438 5403805.667 374.90623 678095.961 5403804.731 374.90623 678095.961 5403804.731 376.19923 678095.438 5403805.667 376.19923</gml:posList>
118 </gml:LinearRing>
119 </gml:interior>
120 <gml:interior>
121 <gml:LinearRing gml:id=\"4018106_LR.novU6ZVfhrtxrFFh7eYQ\">
122 <gml:posList>678097.403 5403802.152 372.05223 678097.403 5403802.152 373.34523 678096.88 5403803.088 373.34523 678096.88 5403803.088 372.05223 678097.403 5403802.152 372.05223</gml:posList>
123 </gml:LinearRing>
124 </gml:interior>
125 <gml:interior>
126 <gml:LinearRing gml:id=\"4018106_LR.XdJcfjsruS75wlUmTQdH\">
127 <gml:posList>678096.677 5403803.45 372.05223 678096.677 5403803.45 373.34523 678096.154 5403804.386 373.34523 678096.154 5403804.386 372.05223 678096.677 5403803.45 372.05223</gml:posList>
128 </gml:LinearRing>
129 </gml:interior>
130 <gml:interior>
131 <gml:LinearRing gml:id=\"4018106_LR.wzwxsPr4Ys8dTM1bzH8T\">
132 <gml:posList>678095.961 5403804.731 372.05223 678095.961 5403804.731 373.34523 678095.438 5403805.667 373.34523 678095.438 5403805.667 372.05223 678095.961 5403804.731 372.05223</gml:posList>
133 </gml:LinearRing>
134 </gml:interior>
135 <gml:interior>
136 <gml:LinearRing gml:id=\"4018106_LR.20P6FwXiq4ZJ4EAxdmJ0\">
137 <gml:posList>678093.838 5403808.528 374.89423 678094.361 5403807.593 374.89423 678094.361 5403807.593 376.18723 678093.838 5403808.528 376.18723 678093.838 5403808.528 374.89423</gml:posList>
138 </gml:LinearRing>
139 </gml:interior>
140 <gml:interior>
141 <gml:LinearRing gml:id=\"4018106_LR.saIYdVUNcoK3LJkC2LDw\">
142 <gml:posList>678093.645 5403808.873 374.89423 678093.645 5403808.873 376.18723 678093.122 5403809.809 376.18723 678093.122 5403809.809 374.89423 678093.645 5403808.873 374.89423</gml:posList>
143 </gml:LinearRing>
144 </gml:interior>
145 <gml:interior>
146 <gml:LinearRing gml:id=\"4018106_LR.yPDE98qtqfTYBziBsTpl\">
147 <gml:posList>678093.869 5403808.474 372.04523 678094.392 5403807.538 372.04523 678094.392 5403807.538 373.33823 678093.869 5403808.474 373.33823 678093.869 5403808.474 372.04523</gml:posList>
148 </gml:LinearRing>
149 </gml:interior>
150 <gml:interior>
151 <gml:LinearRing gml:id=\"4018106_LR.XaQt7QEqeVnG2PB8D6ad\">
152 <gml:posList>678093.153 5403809.755 373.33823 678093.153 5403809.755 372.04523 678093.676 5403808.819 372.04523 678093.676 5403808.819 373.33823 678093.153 5403809.755 373.33823</gml:posList>
153 </gml:LinearRing>
154 </gml:interior>
155 <gml:interior>
156 <gml:LinearRing gml:id=\"4018106_LR.kCEyyLA2tigxjpQY9cyU\">
157 <gml:posList>678092.933 5403810.148 372.04523 678092.933 5403810.148 373.32523 678092.126 5403811.591 373.32523 678092.126 5403811.591 372.04523 678092.933 5403810.148 372.04523</gml:posList>
158 </gml:LinearRing>
159 </gml:interior>
160 <gml:interior>
161 <gml:LinearRing gml:id=\"4018106_LR.Wq5AG6YS8zrN5HgtFQD8\">
162 <gml:posList>678092.126 5403811.591 376.18723 678092.126 5403811.591 374.89423 678092.933 5403810.148 374.89423 678092.933 5403810.148 376.18723 678092.126 5403811.591 376.18723</gml:posList>
163 </gml:LinearRing>
164 </gml:interior>
165 <gml:interior>
166 <gml:LinearRing gml:id=\"4018106_LR.aQFMEYkDQkns0ZoJ66pj\">
167 <gml:posList>678095.264 5403805.978 370.34223000000003 678095.264 5403805.978 370.79823 678093.197 5403809.675 370.79823 678093.197 5403809.675 370.34223000000003 678095.264 5403805.978 370.34223000000003</gml:posList>
168 </gml:LinearRing>
169 </gml:interior>
170 <gml:interior>
171 <gml:LinearRing gml:id=\"4018106_LR.tXljCrPP3Efr0mz83aTx\">
172 <gml:posList>678095.254 5403805.996 368.30523 678095.254 5403805.996 370.06923 678093.187 5403809.693 370.06923 678093.187 5403809.693 368.30523 678095.254 5403805.996 368.30523</gml:posList>
173 </gml:LinearRing>
174 </gml:interior>
175 <gml:interior>
176 <gml:LinearRing gml:id=\"4018106_LR.gLnR6siy7dPwvvNX2zz0\">
177 <gml:posList>678095.558 5403805.452 370.06723 678095.558 5403805.452 368.30323 678097.625 5403801.755 368.30323 678097.625 5403801.755 370.06723 678095.558 5403805.452 370.06723</gml:posList>
178 </gml:LinearRing>
179 </gml:interior>
180 <gml:interior>
181 <gml:LinearRing gml:id=\"4018106_LR.Iw6I84mlFFHQEPQCpApK\">
182 <gml:posList>678097.625 5403801.755 370.34223000000003 678097.625 5403801.755 370.79223 678095.558 5403805.452 370.79223 678095.558 5403805.452 370.34223000000003 678097.625 5403801.755 370.34223000000003</gml:posList>
183 </gml:LinearRing>
184 </gml:interior>
185 </gml:Polygon>
186 </gml:surfaceMember>
187 </gml:MultiSurface>";
188
189 let result = parse_multi_surface(source_text).unwrap();
190
191 assert_eq!(result.surface_member().len(), 1);
192 }
193
194 #[test]
195 fn parsing_multi_surface_without_id() {
196 let source_text = "<gml:MultiSurface>
197 <gml:surfaceMember>
198 <gml:Polygon>
199 <gml:exterior>
200 <gml:LinearRing>
201 <gml:posList srsDimension=\"3\">678009.7116291433 5403638.313338383 417.3480034550211 678012.5609078613 5403634.960884141 417.34658523466385 678013.7892528991 5403636.004867206 417.51938733855997 678010.9399743223 5403639.357321232 417.5208051908512 678009.7116291433 5403638.313338383 417.3480034550211</gml:posList>
202 </gml:LinearRing>
203 </gml:exterior>
204 </gml:Polygon>
205 </gml:surfaceMember>
206 </gml:MultiSurface>";
207
208 let result = parse_multi_surface(source_text).unwrap();
209
210 assert_eq!(result.surface_member().len(), 1);
211 }
212}