use crate::Error;
use crate::gml::codec::core::basic_types::GmlIntegerBetween0And3;
use crate::gml::codec::core::{
deserialize_abstract_space_boundary, serialize_abstract_space_boundary,
};
use crate::gml::codec::relief::abstract_relief_component_property::{
deserialize_abstract_relief_component_property, serialize_abstract_relief_component_property,
};
use crate::gml::util::CityGmlElement;
use ecitygml_core::model::core::AsAbstractSpaceBoundary;
use ecitygml_core::model::relief::ReliefFeature;
use egml::io::util::collect_children;
use egml::io::util::{
Formatting, XmlNode, XmlNodeContent, extract_xml_element_spans, serialize_inner,
};
use quick_xml::de;
use serde::{Deserialize, Serialize};
pub fn deserialize_relief_feature(xml_document: &[u8]) -> Result<ReliefFeature, Error> {
let spans = extract_xml_element_spans(xml_document)?;
let mut abstract_space_boundary_result = None;
let mut parsed_result = None;
let mut relief_components_result = None;
rayon::scope(|s| {
s.spawn(|_| {
abstract_space_boundary_result =
Some(deserialize_abstract_space_boundary(xml_document, &spans));
});
s.spawn(|_| {
parsed_result =
Some(de::from_reader::<_, GmlReliefFeature>(xml_document).map_err(Error::from));
});
s.spawn(|_| {
relief_components_result = Some(collect_children(
xml_document,
&spans,
CityGmlElement::AbstractReliefComponentProperty.into(),
deserialize_abstract_relief_component_property,
));
});
});
let abstract_space_boundary =
abstract_space_boundary_result.expect("rayon::scope guarantees all spawns complete")?;
let parsed: GmlReliefFeature =
parsed_result.expect("rayon::scope guarantees all spawns complete")?;
let relief_components =
relief_components_result.expect("rayon::scope guarantees all spawns complete")?;
let mut relief_feature =
ReliefFeature::from_abstract_space_boundary(abstract_space_boundary, parsed.lod.into());
relief_feature.set_relief_components(relief_components);
Ok(relief_feature)
}
pub fn serialize_relief_feature(
relief_feature: &ReliefFeature,
formatting: Formatting,
) -> Result<XmlNode, Error> {
let mut parts =
serialize_abstract_space_boundary(relief_feature.abstract_space_boundary(), formatting)?;
if let Some(raw) = serialize_inner(GmlReliefFeature::from(relief_feature), formatting)? {
parts.content.push(XmlNodeContent::Raw(raw));
}
for component in relief_feature.relief_components() {
parts.content.push(XmlNodeContent::Child(
serialize_abstract_relief_component_property(component, formatting)?,
));
}
Ok(XmlNode::new(CityGmlElement::ReliefFeature.into(), parts))
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct GmlReliefFeature {
#[serde(rename(serialize = "dem:lod", deserialize = "lod"))]
pub lod: GmlIntegerBetween0And3,
}
impl From<&ReliefFeature> for GmlReliefFeature {
fn from(item: &ReliefFeature) -> Self {
Self {
lod: item.lod().into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use ecitygml_core::model::common::LevelOfDetail;
use ecitygml_core::model::core::AsAbstractFeature;
use egml::model::base::Id;
#[test]
fn test_deserialize_tin_relief() {
let xml_document = "
<dem:ReliefFeature gml:id=\"ID_7a8b707e-f87c-35f3-8e3c-254427e59493\">
<dem:lod>2</dem:lod>
<dem:reliefComponent>
<dem:TINRelief gml:id=\"abc\">
<dem:lod>3</dem:lod>
<dem:tin>
<gml:TriangulatedSurface gml:id=\"ground\">
<gml:patches>
<gml:Triangle>
<gml:exterior>
<gml:LinearRing gml:id=\"Geo28109128\">
<gml:posList>513037.352708 5403284.890495 247.27 513034.424098 5403297.424959 247.19 513034.423981 5403287.429362 247.3 513037.352708 5403284.890495 247.27</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Triangle>
</gml:patches>
</gml:TriangulatedSurface>
</dem:tin>
</dem:TINRelief>
</dem:reliefComponent>
</dem:ReliefFeature>";
let relief_feature =
deserialize_relief_feature(xml_document.as_bytes()).expect("should work");
assert_eq!(
relief_feature.feature_id(),
&Id::try_from("ID_7a8b707e-f87c-35f3-8e3c-254427e59493").unwrap()
);
assert_eq!(relief_feature.lod(), LevelOfDetail::Two);
assert_eq!(relief_feature.num_relief_components(), 1);
let abstract_relief_component_property = relief_feature
.relief_components()
.first()
.to_owned()
.unwrap();
assert!(abstract_relief_component_property.object().is_some());
let relief_component = abstract_relief_component_property.object().unwrap();
assert_eq!(relief_component.feature_id(), &Id::try_from("abc").unwrap());
}
}