ecitygml-io 0.0.2-alpha.5

IO operations for processing CityGML data.
Documentation
use crate::Error;
use crate::gml::codec::appearance::abstract_surface_data::{
    deserialize_abstract_surface_data, serialize_abstract_surface_data,
};
use crate::gml::codec::appearance::basic_types::{GmlColor, GmlGeometryReference};
use crate::gml::codec::core::basic_types::GmlDoubleBetween0And1;
use crate::gml::util::CityGmlElement;
use ecitygml_core::model::appearance::{AsAbstractSurfaceData, X3DMaterial};
use egml::io::util::{
    Formatting, XmlNode, XmlNodeContent, extract_xml_element_spans, serialize_inner,
};
use quick_xml::de;
use serde::{Deserialize, Serialize};

pub fn deserialize_x3d_material(xml_document: &[u8]) -> Result<X3DMaterial, Error> {
    let spans = extract_xml_element_spans(xml_document)?;
    let (abstract_surface_data_result, parsed_result) = rayon::join(
        || deserialize_abstract_surface_data(xml_document, &spans),
        || de::from_reader::<_, GmlX3DMaterial>(xml_document).map_err(Error::from),
    );
    let abstract_surface_data = abstract_surface_data_result?;
    let parsed = parsed_result?;

    let mut x3d_material = X3DMaterial::from_abstract_surface_data(abstract_surface_data);
    x3d_material.set_ambient_intensity_opt(
        parsed
            .ambient_intensity
            .map(TryInto::try_into)
            .transpose()?,
    );
    x3d_material.set_diffuse_color_opt(parsed.diffuse_color.map(TryInto::try_into).transpose()?);
    x3d_material.set_emissive_color_opt(parsed.emissive_color.map(TryInto::try_into).transpose()?);
    x3d_material.set_specular_color_opt(parsed.specular_color.map(TryInto::try_into).transpose()?);
    x3d_material.set_shininess_opt(parsed.shininess.map(TryInto::try_into).transpose()?);
    x3d_material.set_transparency_opt(parsed.transparency.map(TryInto::try_into).transpose()?);
    x3d_material.set_is_smooth(parsed.is_smooth);
    x3d_material.set_targets(parsed.targets.into_iter().map(Into::into).collect());

    Ok(x3d_material)
}

pub fn serialize_x3d_material(
    x3d_material: &X3DMaterial,
    formatting: Formatting,
) -> Result<XmlNode, Error> {
    let mut xml_node_parts =
        serialize_abstract_surface_data(x3d_material.abstract_surface_data(), formatting)?;

    if let Some(raw) = serialize_inner(GmlX3DMaterial::from(x3d_material), formatting)? {
        xml_node_parts.content.push(XmlNodeContent::Raw(raw));
    }

    Ok(XmlNode::new(
        CityGmlElement::X3DMaterial.into(),
        xml_node_parts,
    ))
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GmlX3DMaterial {
    #[serde(
        rename(serialize = "app:ambientIntensity", deserialize = "ambientIntensity"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub ambient_intensity: Option<GmlDoubleBetween0And1>,

    #[serde(
        rename(serialize = "app:diffuseColor", deserialize = "diffuseColor"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub diffuse_color: Option<GmlColor>,

    #[serde(
        rename(serialize = "app:emissiveColor", deserialize = "emissiveColor"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub emissive_color: Option<GmlColor>,

    #[serde(
        rename(serialize = "app:specularColor", deserialize = "specularColor"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub specular_color: Option<GmlColor>,

    #[serde(
        rename(serialize = "app:shininess", deserialize = "shininess"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub shininess: Option<GmlDoubleBetween0And1>,

    #[serde(
        rename(serialize = "app:transparency", deserialize = "transparency"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub transparency: Option<GmlDoubleBetween0And1>,

    #[serde(
        rename(serialize = "app:isSmooth", deserialize = "isSmooth"),
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub is_smooth: Option<bool>,

    #[serde(rename(serialize = "app:target", deserialize = "target"), default)]
    pub targets: Vec<GmlGeometryReference>,
}

impl From<&X3DMaterial> for GmlX3DMaterial {
    fn from(item: &X3DMaterial) -> Self {
        Self {
            ambient_intensity: item.ambient_intensity().map(Into::into),
            diffuse_color: item.diffuse_color().map(Into::into),
            emissive_color: item.emissive_color().map(Into::into),
            specular_color: item.specular_color().map(Into::into),
            shininess: item.shininess().map(Into::into),
            transparency: item.transparency().map(Into::into),
            is_smooth: item.is_smooth(),
            targets: item.targets().iter().map(Into::into).collect(),
        }
    }
}