egml_io/geometry/
point.rs

1use crate::error::Error;
2use crate::error::Error::{MissingElements, Only3DSupported};
3use egml_core::model::geometry::DirectPosition;
4use quick_xml::de;
5use serde::{Deserialize, Serialize};
6use std::io::BufRead;
7
8#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
9#[serde(rename = "gml:Point")]
10struct GmlPoint {
11    #[serde(rename = "@id", default)]
12    id: String,
13    pos: GmlPos,
14}
15
16#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
17#[serde(rename = "gml:pos")]
18struct GmlPos {
19    #[serde(rename = "@srsDimension")]
20    srs_dimension: Option<u32>,
21    #[serde(rename = "$value")]
22    value: String,
23}
24
25impl TryFrom<GmlPos> for DirectPosition {
26    type Error = Error;
27
28    fn try_from(value: GmlPos) -> Result<Self, Self::Error> {
29        if value.srs_dimension.unwrap_or(3) != 3 {
30            return Err(Only3DSupported());
31        }
32
33        let parsed_values: Vec<f64> = value
34            .value
35            .split_whitespace()
36            .map(|s| s.parse().unwrap())
37            .collect();
38        if !parsed_values.len().is_multiple_of(3) {
39            return Err(MissingElements());
40        }
41
42        let position = DirectPosition::new(parsed_values[0], parsed_values[1], parsed_values[2])?;
43        Ok(position)
44    }
45}
46
47pub fn parse_point<T: BufRead>(source: T) -> Result<DirectPosition, Error> {
48    let parsed_point: GmlPoint = de::from_reader(source)?;
49    parsed_point.pos.try_into()
50}
51
52#[cfg(test)]
53mod tests {
54    use crate::parse_point;
55
56    #[test]
57    fn parsing_point() {
58        let source_text = "<gml:Point>
59              <gml:pos srsDimension=\"3\" gml:id=\"UUID_6b33ecfa-6e08-4e8e-a4b5-e1d06540faf0\">678000.9484065345 5403659.060043676 417.3802376791456</gml:pos>
60            </gml:Point>";
61
62        let result = parse_point(source_text.as_ref()).unwrap();
63
64        assert_eq!(result.x(), 678000.9484065345);
65        assert_eq!(result.y(), 5403659.060043676);
66        assert_eq!(result.z(), 417.3802376791456);
67    }
68
69    #[test]
70    fn parsing_point_without_id() {
71        let source_text = "<gml:Point>
72              <gml:pos srsDimension=\"3\">678000.9484065345 5403659.060043676 417.3802376791456</gml:pos>
73            </gml:Point>";
74
75        let result = parse_point(source_text.as_ref()).unwrap();
76
77        assert_eq!(result.x(), 678000.9484065345);
78        assert_eq!(result.y(), 5403659.060043676);
79        assert_eq!(result.z(), 417.3802376791456);
80    }
81}