#[cfg(feature = "write")]
use instant_xml::ToXml;
#[cfg(feature = "memory-optimized-read")]
use instant_xml::FromXml;
#[cfg(feature = "speed-optimized-read")]
use serde::Deserialize;
#[cfg(feature = "memory-optimized-read")]
use crate::core::constants;
use crate::{
core::{
beamlattice::BeamLattice,
triangle_set::TriangleSets,
types::{Double, OptionalResourceId, OptionalResourceIndex, ResourceId, ResourceIndex},
},
threemf_namespaces::{BEAM_LATTICE_NS, CORE_TRIANGLESET_NS, DISPLACEMENT_NS},
};
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "displacement2d"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(DISPLACEMENT_NS), rename = "displacement2d")
)]
pub struct Displacement2D {
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub id: ResourceId,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub path: String,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub channel: Option<ChannelName>,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub tilestyleu: Option<TileStyle>,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub tilestylev: Option<TileStyle>,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub filter: Option<Filter>,
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(from = "String"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(scalar, ns(DISPLACEMENT_NS))
)]
pub enum ChannelName {
R,
#[default]
G,
B,
A,
}
impl From<String> for ChannelName {
fn from(value: String) -> Self {
match value.as_str() {
"R" => Self::R,
"G" => Self::G,
"B" => Self::B,
"A" => Self::A,
_ => Self::G,
}
}
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(from = "String"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(scalar, ns(DISPLACEMENT_NS), rename_all = "lowercase")
)]
pub enum TileStyle {
#[default]
Wrap,
Mirror,
Clamp,
None,
}
impl From<String> for TileStyle {
fn from(value: String) -> Self {
match value.to_ascii_lowercase().as_str() {
"wrap" => Self::Wrap,
"mirror" => Self::Mirror,
"clamp" => Self::Clamp,
"none" => Self::None,
_ => Self::Wrap,
}
}
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(from = "String"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(scalar, ns(DISPLACEMENT_NS), rename_all = "lowercase")
)]
pub enum Filter {
#[default]
Auto,
Linear,
Nearest,
}
impl From<String> for Filter {
fn from(value: String) -> Self {
match value.to_ascii_lowercase().as_str() {
"auto" => Self::Auto,
"linear" => Self::Linear,
"nearest" => Self::Nearest,
_ => Self::Auto,
}
}
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "normvectorgroup"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(
feature = "write",
xml(ns(DISPLACEMENT_NS), rename = "normvectorgroup")
)]
pub struct NormVectorGroup {
#[cfg_attr(any(feature = "write"), xml(attribute))]
pub id: ResourceId,
#[cfg_attr(
feature = "speed-optimized-read",
serde(default, rename = "normvector")
)]
pub normvector: Vec<NormVector>,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for NormVectorGroup {
fn matches(id: instant_xml::Id<'_>, _field: Option<instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "normvectorgroup",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), instant_xml::Error> {
if into.is_some() {
return Err(instant_xml::Error::DuplicateValue(field));
}
let mut norm_id: u32 = 0;
let mut norm_vectors: Vec<NormVector> = Vec::with_capacity(constants::MAX_VERTEX_BUFFER);
while let Some(node) = deserializer.next()
&& let Ok(node) = node
{
match node {
instant_xml::de::Node::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
if id.name == "id" && !attr.value.is_empty() {
match lexical_core::parse::<u32>(attr.value.as_bytes()) {
Ok(value) => norm_id = value,
Err(_) => {
return Err(instant_xml::Error::MissingValue(
"Invalid values as id",
));
}
}
}
}
instant_xml::de::Node::Open(element) => {
let mut norm_vector_value: Option<NormVector> = None;
let mut nested = deserializer.nested(element);
if <NormVector as instant_xml::FromXml>::deserialize(
&mut norm_vector_value,
field,
&mut nested,
)
.is_ok()
&& let Some(vector) = norm_vector_value
{
norm_vectors.push(vector);
}
}
_ => {}
}
}
norm_vectors.shrink_to_fit();
*into = Some(Self {
id: norm_id,
normvector: norm_vectors,
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: instant_xml::Kind = instant_xml::Kind::Element;
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "normvector"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "write", xml(ns(DISPLACEMENT_NS), rename = "normvector"))]
pub struct NormVector {
#[cfg_attr(feature = "write", xml(attribute))]
pub x: Double,
#[cfg_attr(feature = "write", xml(attribute))]
pub y: Double,
#[cfg_attr(feature = "write", xml(attribute))]
pub z: Double,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for NormVector {
#[inline]
fn matches(id: ::instant_xml::Id<'_>, _: Option<::instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "normvector",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> ::std::result::Result<(), ::instant_xml::Error> {
use ::instant_xml::Error;
use ::instant_xml::de::Node;
let mut x: f64 = 0.0;
let mut y: f64 = 0.0;
let mut z: f64 = 0.0;
while let Some(node) = deserializer.next() {
let node = node?;
match node {
Node::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
match id.name.as_bytes().first() {
Some(b'x') => {
x = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
Some(b'y') => {
y = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
Some(b'z') => {
z = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
_ => {}
};
}
Node::Open(data) => {
let mut nested = deserializer.nested(data);
nested.ignore()?;
}
Node::Text(_) => {}
_ => {
return Err(Error::UnexpectedNode("Unexpected".to_owned()));
}
}
}
*into = Some(Self {
x: Double::new(x),
y: Double::new(y),
z: Double::new(z),
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "disp2dgroup"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(DISPLACEMENT_NS), rename = "disp2dgroup")
)]
pub struct Disp2DGroup {
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub id: ResourceId,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub dispid: ResourceId,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub nid: ResourceId,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub height: Double,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub offset: Option<Double>,
#[cfg_attr(
feature = "speed-optimized-read",
serde(default, rename = "disp2dcoord")
)]
pub disp2dcoord: Vec<Disp2DCoord>,
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "disp2dcoord"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(DISPLACEMENT_NS), rename = "disp2dcoord")
)]
pub struct Disp2DCoord {
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub u: Double,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub v: Double,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub n: ResourceIndex,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(attribute)
)]
pub f: Option<Double>,
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "displacementmesh"))]
#[cfg_attr(feature = "memory-optimized-read", derive(FromXml))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(DISPLACEMENT_NS, t = CORE_TRIANGLESET_NS, b = BEAM_LATTICE_NS), rename = "displacementmesh")
)]
pub struct DisplacementMesh {
pub vertices: Vertices,
pub triangles: Triangles,
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(CORE_TRIANGLESET_NS))
)]
pub trianglesets: Option<TriangleSets>,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(
any(feature = "write", feature = "memory-optimized-read"),
xml(ns(BEAM_LATTICE_NS))
)]
pub beamlattice: Option<BeamLattice>,
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "vertices"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "write", xml(ns(DISPLACEMENT_NS), rename = "vertices"))]
pub struct Vertices {
#[cfg_attr(feature = "speed-optimized-read", serde(default, rename = "vertex"))]
pub vertex: Vec<Vertex>,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for Vertices {
fn matches(id: instant_xml::Id<'_>, _field: Option<instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "vertices",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), instant_xml::Error> {
if into.is_some() {
return Err(instant_xml::Error::DuplicateValue(field));
}
let mut vertices: Vec<Vertex> = Vec::with_capacity(constants::MAX_VERTEX_BUFFER);
while let Some(node) = deserializer.next() {
if let Ok(n) = node
&& let instant_xml::de::Node::Open(element) = n
{
let mut vertex_value: Option<Vertex> = None;
let mut nested = deserializer.nested(element);
if <Vertex as instant_xml::FromXml>::deserialize(
&mut vertex_value,
"vertex",
&mut nested,
)
.is_ok()
&& let Some(vertex) = vertex_value
{
vertices.push(vertex);
};
}
}
vertices.shrink_to_fit();
*into = Some(Vertices { vertex: vertices });
Ok(())
}
type Accumulator = Option<Self>;
const KIND: instant_xml::Kind = instant_xml::Kind::Scalar;
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "vertex"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "write", xml(ns(DISPLACEMENT_NS), rename = "vertex"))]
pub struct Vertex {
#[cfg_attr(feature = "write", xml(attribute))]
pub x: Double,
#[cfg_attr(feature = "write", xml(attribute))]
pub y: Double,
#[cfg_attr(feature = "write", xml(attribute))]
pub z: Double,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for Vertex {
#[inline]
fn matches(id: ::instant_xml::Id<'_>, _: Option<::instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "vertex",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> ::std::result::Result<(), ::instant_xml::Error> {
use ::instant_xml::Error;
use ::instant_xml::de::Node;
let mut x: f64 = 0.0;
let mut y: f64 = 0.0;
let mut z: f64 = 0.0;
while let Some(node) = deserializer.next() {
let node = node?;
match node {
Node::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
match id.name.as_bytes().first() {
Some(b'x') => {
x = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
Some(b'y') => {
y = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
Some(b'z') => {
z = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default()
}
_ => {}
};
}
Node::Open(data) => {
let mut nested = deserializer.nested(data);
nested.ignore()?;
}
Node::Text(_) => {}
_ => {
return Err(Error::UnexpectedNode("Unexpected".to_owned()));
}
}
}
*into = Some(Self {
x: Double::new(x),
y: Double::new(y),
z: Double::new(z),
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "triangles"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "write", xml(ns(DISPLACEMENT_NS), rename = "triangles"))]
pub struct Triangles {
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(feature = "write", xml(attribute))]
pub did: OptionalResourceId,
#[cfg_attr(feature = "speed-optimized-read", serde(default, rename = "triangle"))]
pub triangle: Vec<Triangle>,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for Triangles {
fn matches(id: instant_xml::Id<'_>, _field: Option<instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "triangles",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), instant_xml::Error> {
if into.is_some() {
return Err(instant_xml::Error::DuplicateValue(field));
}
let mut did = OptionalResourceId::none();
let mut triangles: Vec<Triangle> = Vec::with_capacity(constants::MAX_TRIANGLE_BUFFER);
while let Some(node) = deserializer.next()
&& let Ok(node) = node
{
match node {
instant_xml::de::Node::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
if id.name == "did" && !attr.value.is_empty() {
did = attr.value.as_bytes().into();
}
}
instant_xml::de::Node::Open(element) => {
let mut triangle_value: Option<Triangle> = None;
let mut nested = deserializer.nested(element);
if <Triangle as instant_xml::FromXml>::deserialize(
&mut triangle_value,
field,
&mut nested,
)
.is_ok()
&& let Some(vertex) = triangle_value
{
triangles.push(vertex);
}
}
_ => {}
}
}
triangles.shrink_to_fit();
*into = Some(Triangles {
did,
triangle: triangles,
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: instant_xml::Kind = instant_xml::Kind::Element;
}
#[cfg_attr(feature = "speed-optimized-read", derive(Deserialize))]
#[cfg_attr(feature = "speed-optimized-read", serde(rename = "triangle"))]
#[cfg_attr(feature = "write", derive(ToXml))]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "write", xml(ns(DISPLACEMENT_NS), rename = "triangle"))]
pub struct Triangle {
#[cfg_attr(feature = "write", xml(attribute))]
pub v1: ResourceIndex,
#[cfg_attr(feature = "write", xml(attribute))]
pub v2: ResourceIndex,
#[cfg_attr(feature = "write", xml(attribute))]
pub v3: ResourceIndex,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(feature = "write", xml(attribute))]
pub d1: OptionalResourceIndex,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(feature = "write", xml(attribute))]
pub d2: OptionalResourceIndex,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(feature = "write", xml(attribute))]
pub d3: OptionalResourceIndex,
#[cfg_attr(feature = "speed-optimized-read", serde(default))]
#[cfg_attr(feature = "write", xml(attribute))]
pub did: OptionalResourceId,
#[cfg_attr(feature = "write", xml(attribute))]
#[cfg_attr(
feature = "speed-optimized-read",
serde(
default = "crate::core::types::opt_res_index_impl::default_none",
deserialize_with = "crate::core::types::opt_res_index_impl::deserialize"
)
)]
pub p1: OptionalResourceIndex,
#[cfg_attr(feature = "write", xml(attribute))]
#[cfg_attr(
feature = "speed-optimized-read",
serde(
default = "crate::core::types::opt_res_index_impl::default_none",
deserialize_with = "crate::core::types::opt_res_index_impl::deserialize"
)
)]
pub p2: OptionalResourceIndex,
#[cfg_attr(feature = "write", xml(attribute))]
#[cfg_attr(
feature = "speed-optimized-read",
serde(
default = "crate::core::types::opt_res_index_impl::default_none",
deserialize_with = "crate::core::types::opt_res_index_impl::deserialize"
)
)]
pub p3: OptionalResourceIndex,
#[cfg_attr(feature = "write", xml(attribute))]
#[cfg_attr(
feature = "speed-optimized-read",
serde(
default = "crate::core::types::opt_res_id_impl::default_none",
deserialize_with = "crate::core::types::opt_res_id_impl::deserialize"
)
)]
pub pid: OptionalResourceId,
}
#[cfg(feature = "memory-optimized-read")]
impl<'xml> FromXml<'xml> for Triangle {
#[inline]
fn matches(id: ::instant_xml::Id<'_>, _: Option<::instant_xml::Id<'_>>) -> bool {
id == ::instant_xml::Id {
ns: DISPLACEMENT_NS,
name: "triangle",
}
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> ::std::result::Result<(), ::instant_xml::Error> {
use ::instant_xml::Error;
use ::instant_xml::de::Node;
let mut v1: ResourceIndex = 0;
let mut v2: ResourceIndex = 0;
let mut v3: ResourceIndex = 0;
let mut d1: OptionalResourceIndex = OptionalResourceIndex::none();
let mut d2: OptionalResourceIndex = OptionalResourceIndex::none();
let mut d3: OptionalResourceIndex = OptionalResourceIndex::none();
let mut did: OptionalResourceId = OptionalResourceId::none();
let mut p1: OptionalResourceIndex = OptionalResourceIndex::none();
let mut p2: OptionalResourceIndex = OptionalResourceIndex::none();
let mut p3: OptionalResourceIndex = OptionalResourceIndex::none();
let mut pid: OptionalResourceId = OptionalResourceId::none();
while let Some(node) = deserializer.next() {
let node = node?;
match node {
Node::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
match id.name {
"v1" => v1 = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default(),
"v2" => v2 = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default(),
"v3" => v3 = lexical_core::parse(attr.value.as_bytes()).unwrap_or_default(),
"d1" => d1 = attr.value.as_bytes().into(),
"d2" => d2 = attr.value.as_bytes().into(),
"d3" => d3 = attr.value.as_bytes().into(),
"did" => did = attr.value.as_bytes().into(),
"p1" => p1 = attr.value.as_bytes().into(),
"p2" => p2 = attr.value.as_bytes().into(),
"p3" => p3 = attr.value.as_bytes().into(),
"pid" => pid = attr.value.as_bytes().into(),
_ => {}
};
}
Node::Open(data) => {
let mut nested = deserializer.nested(data);
nested.ignore()?;
}
Node::Text(_) => {}
_ => {
return Err(Error::UnexpectedNode("Unexpected".to_owned()));
}
}
}
*into = Some(Self {
v1,
v2,
v3,
d1,
d2,
d3,
did,
p1,
p2,
p3,
pid,
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
}
#[cfg(test)]
mod tests {
use super::{ChannelName, Filter};
#[test]
fn channel_name_default_is_g() {
assert_eq!(ChannelName::default(), ChannelName::G);
}
#[test]
fn channel_name_from_string_r() {
assert_eq!(ChannelName::from(String::from("R")), ChannelName::R);
}
#[test]
fn channel_name_from_string_g() {
assert_eq!(ChannelName::from(String::from("G")), ChannelName::G);
}
#[test]
fn channel_name_from_string_b() {
assert_eq!(ChannelName::from(String::from("B")), ChannelName::B);
}
#[test]
fn channel_name_from_string_a() {
assert_eq!(ChannelName::from(String::from("A")), ChannelName::A);
}
#[test]
fn channel_name_from_unknown_defaults_to_g() {
assert_eq!(ChannelName::from(String::from("X")), ChannelName::G);
}
use super::TileStyle;
#[test]
fn tile_style_default_is_wrap() {
assert_eq!(TileStyle::default(), TileStyle::Wrap);
}
#[test]
fn tile_style_from_string_wrap() {
assert_eq!(TileStyle::from(String::from("wrap")), TileStyle::Wrap);
}
#[test]
fn tile_style_from_string_mirror() {
assert_eq!(TileStyle::from(String::from("mirror")), TileStyle::Mirror);
}
#[test]
fn tile_style_from_string_clamp() {
assert_eq!(TileStyle::from(String::from("clamp")), TileStyle::Clamp);
}
#[test]
fn tile_style_from_string_none() {
assert_eq!(TileStyle::from(String::from("none")), TileStyle::None);
}
#[test]
fn tile_style_from_uppercase() {
assert_eq!(TileStyle::from(String::from("MIRROR")), TileStyle::Mirror);
}
#[test]
fn tile_style_from_unknown_defaults_to_wrap() {
assert_eq!(TileStyle::from(String::from("invalid")), TileStyle::Wrap);
}
#[test]
fn displacement_filter_default_is_auto() {
assert_eq!(Filter::default(), Filter::Auto);
}
#[test]
fn displacement_filter_from_string_auto() {
assert_eq!(Filter::from(String::from("auto")), Filter::Auto);
}
#[test]
fn displacement_filter_from_string_linear() {
assert_eq!(Filter::from(String::from("linear")), Filter::Linear);
}
#[test]
fn displacement_filter_from_string_nearest() {
assert_eq!(Filter::from(String::from("nearest")), Filter::Nearest);
}
#[test]
fn displacement_filter_from_uppercase() {
assert_eq!(Filter::from(String::from("LINEAR")), Filter::Linear);
}
#[test]
fn displacement_filter_from_unknown_defaults_to_auto() {
assert_eq!(Filter::from(String::from("invalid")), Filter::Auto);
}
}
#[cfg(feature = "write")]
#[cfg(test)]
mod write_tests {
use instant_xml::to_string;
use pretty_assertions::assert_eq;
use crate::threemf_namespaces::{
BEAM_LATTICE_PREFIX, CORE_TRIANGLESET_PREFIX, DISPLACEMENT_NS,
};
use super::*;
#[test]
fn toxml_displacement2d_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"1\" path=\"/3D/Textures/displacement.png\" />",
DISPLACEMENT_NS
);
let displacement2d = Displacement2D {
id: 1,
path: "/3D/Textures/displacement.png".to_owned(),
channel: None,
tilestyleu: None,
tilestylev: None,
filter: None,
};
let xml_output = to_string(&displacement2d).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_displacement2d_with_options_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"2\" path=\"/textures/disp.png\" channel=\"R\" tilestyleu=\"mirror\" tilestylev=\"clamp\" filter=\"linear\" />",
DISPLACEMENT_NS
);
let displacement2d = Displacement2D {
id: 2,
path: "/textures/disp.png".to_owned(),
channel: Some(ChannelName::R),
tilestyleu: Some(TileStyle::Mirror),
tilestylev: Some(TileStyle::Clamp),
filter: Some(Filter::Linear),
};
let xml_output = to_string(&displacement2d).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_channel_name_test() {
let xml_string = "R".to_owned();
let color = ChannelName::R;
let xml_output = to_string(&color).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_tile_style_test() {
let xml_string = "mirror".to_owned();
let tilestyle = TileStyle::Mirror;
let xml_output = to_string(&tilestyle).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_displacement_filter_test() {
let xml_string = "linear".to_owned();
let filter = Filter::Linear;
let xml_output = to_string(&filter).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_norm_vector_group_test() {
let xml_string = format!(
"<normvectorgroup xmlns=\"{}\" id=\"1\"><normvector x=\"0\" y=\"0\" z=\"1\" /><normvector x=\"0\" y=\"1\" z=\"0\" /></normvectorgroup>",
DISPLACEMENT_NS
);
let group = NormVectorGroup {
id: 1,
normvector: vec![
NormVector {
x: 0.0.into(),
y: 0.0.into(),
z: 1.0.into(),
},
NormVector {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
};
let xml_output = to_string(&group).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_disp2d_group_test() {
let xml_string = format!(
"<disp2dgroup xmlns=\"{}\" id=\"1\" dispid=\"2\" nid=\"3\" height=\"0.5\" offset=\"0.1\"><disp2dcoord u=\"0\" v=\"0\" n=\"0\" /><disp2dcoord u=\"1\" v=\"1\" n=\"1\" f=\"0.3\" /></disp2dgroup>",
DISPLACEMENT_NS
);
let group = Disp2DGroup {
id: 1,
dispid: 2,
nid: 3,
height: 0.5.into(),
offset: Some(0.1.into()),
disp2dcoord: vec![
Disp2DCoord {
u: 0.0.into(),
v: 0.0.into(),
n: 0,
f: None,
},
Disp2DCoord {
u: 1.0.into(),
v: 1.0.into(),
n: 1,
f: Some(0.3.into()),
},
],
};
let xml_output = to_string(&group).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_displacement_vertices_test() {
let xml_string = format!(
"<vertices xmlns=\"{}\"><vertex x=\"0\" y=\"0\" z=\"0\" /><vertex x=\"1\" y=\"0\" z=\"0\" /></vertices>",
DISPLACEMENT_NS
);
let vertices = Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
],
};
let xml_output = to_string(&vertices).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_displacement_triangles_test() {
let xml_string = format!(
"<triangles xmlns=\"{}\" did=\"5\"><triangle v1=\"0\" v2=\"1\" v3=\"2\" d1=\"0\" d2=\"1\" d3=\"2\" /></triangles>",
DISPLACEMENT_NS
);
let triangles = Triangles {
did: OptionalResourceId::new(5),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::new(0),
d2: OptionalResourceIndex::new(1),
d3: OptionalResourceIndex::new(2),
did: OptionalResourceId::none(),
p1: OptionalResourceIndex::none(),
p2: OptionalResourceIndex::none(),
p3: OptionalResourceIndex::none(),
pid: OptionalResourceId::none(),
}],
};
let xml_output = to_string(&triangles).unwrap();
assert_eq!(xml_output, xml_string);
}
#[test]
fn toxml_displacement_mesh_test() {
let mesh_string = format!(
r##"<displacementmesh xmlns="{}" xmlns:{}="{}" xmlns:{}="{}"><vertices><vertex x="0" y="0" z="0" /><vertex x="1" y="0" z="0" /><vertex x="0" y="1" z="0" /></vertices><triangles><triangle v1="0" v2="1" v3="2" /></triangles></displacementmesh>"##,
DISPLACEMENT_NS,
BEAM_LATTICE_PREFIX,
BEAM_LATTICE_NS,
CORE_TRIANGLESET_PREFIX,
CORE_TRIANGLESET_NS,
);
let mesh = DisplacementMesh {
vertices: Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
},
triangles: Triangles {
did: OptionalResourceId::none(),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::none(),
d2: OptionalResourceIndex::none(),
d3: OptionalResourceIndex::none(),
did: OptionalResourceId::none(),
p1: OptionalResourceIndex::none(),
p2: OptionalResourceIndex::none(),
p3: OptionalResourceIndex::none(),
pid: OptionalResourceId::none(),
}],
},
trianglesets: None,
beamlattice: None,
};
let xml_output = to_string(&mesh).unwrap();
assert_eq!(xml_output, mesh_string);
}
}
#[cfg(feature = "memory-optimized-read")]
#[cfg(test)]
mod memory_optimized_read_tests {
use instant_xml::from_str;
use pretty_assertions::assert_eq;
use crate::threemf_namespaces::DISPLACEMENT_NS;
use super::*;
#[test]
fn fromxml_displacement2d_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"1\" path=\"/3D/Textures/displacement.png\" />",
DISPLACEMENT_NS
);
let displacement2d = from_str::<Displacement2D>(&xml_string).unwrap();
assert_eq!(
displacement2d,
Displacement2D {
id: 1,
path: "/3D/Textures/displacement.png".to_owned(),
channel: None,
tilestyleu: None,
tilestylev: None,
filter: None,
}
);
}
#[test]
fn fromxml_displacement2d_with_options_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"2\" path=\"/textures/disp.png\" channel=\"R\" tilestyleu=\"mirror\" tilestylev=\"clamp\" filter=\"linear\" />",
DISPLACEMENT_NS
);
let displacement2d = from_str::<Displacement2D>(&xml_string).unwrap();
assert_eq!(displacement2d.id, 2);
assert_eq!(displacement2d.path, "/textures/disp.png");
}
#[test]
fn fromxml_channel_name_test() {
for (xml, expected) in [
("R", ChannelName::R),
("G", ChannelName::G),
("B", ChannelName::B),
("A", ChannelName::A),
] {
let xml_string = format!("<color xmlns=\"{}\">{}</color>", DISPLACEMENT_NS, xml);
let color: ChannelName = from_str(&xml_string).unwrap();
assert_eq!(color, expected);
}
}
#[test]
fn fromxml_tile_style_test() {
for (xml, expected) in [
("wrap", TileStyle::Wrap),
("mirror", TileStyle::Mirror),
("clamp", TileStyle::Clamp),
("none", TileStyle::None),
] {
let xml_string = format!(
"<tilestyle xmlns=\"{}\">{}</tilestyle>",
DISPLACEMENT_NS, xml
);
let tilestyle: TileStyle = from_str(&xml_string).unwrap();
assert_eq!(tilestyle, expected);
}
}
#[test]
fn fromxml_displacement_filter_test() {
for (xml, expected) in [
("auto", Filter::Auto),
("linear", Filter::Linear),
("nearest", Filter::Nearest),
] {
let xml_string = format!("<filter xmlns=\"{}\">{}</filter>", DISPLACEMENT_NS, xml);
let filter: Filter = from_str(&xml_string).unwrap();
assert_eq!(filter, expected);
}
}
#[test]
fn fromxml_norm_vector_group_test() {
let xml_string = format!(
"<normvectorgroup xmlns=\"{}\" id=\"1\"><normvector x=\"0\" y=\"0\" z=\"1\" /><normvector x=\"0\" y=\"1\" z=\"0\" /></normvectorgroup>",
DISPLACEMENT_NS
);
let group = from_str::<NormVectorGroup>(&xml_string).unwrap();
assert_eq!(
group,
NormVectorGroup {
id: 1,
normvector: vec![
NormVector {
x: 0.0.into(),
y: 0.0.into(),
z: 1.0.into(),
},
NormVector {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
}
);
}
#[test]
fn fromxml_disp2d_group_test() {
let xml_string = format!(
"<disp2dgroup xmlns=\"{}\" id=\"1\" dispid=\"2\" nid=\"3\" height=\"0.5\" offset=\"0.1\"><disp2dcoord u=\"0\" v=\"0\" n=\"0\" /><disp2dcoord u=\"1\" v=\"1\" n=\"1\" f=\"0.3\" /></disp2dgroup>",
DISPLACEMENT_NS
);
let group = from_str::<Disp2DGroup>(&xml_string).unwrap();
assert_eq!(
group,
Disp2DGroup {
id: 1,
dispid: 2,
nid: 3,
height: 0.5.into(),
offset: Some(0.1.into()),
disp2dcoord: vec![
Disp2DCoord {
u: 0.0.into(),
v: 0.0.into(),
n: 0,
f: None,
},
Disp2DCoord {
u: 1.0.into(),
v: 1.0.into(),
n: 1,
f: Some(0.3.into()),
},
],
}
);
}
#[test]
fn fromxml_displacement_vertices_test() {
let xml_string = format!(
"<vertices xmlns=\"{}\"><vertex x=\"0\" y=\"0\" z=\"0\" /><vertex x=\"1\" y=\"0\" z=\"0\" /></vertices>",
DISPLACEMENT_NS
);
let vertices = from_str::<Vertices>(&xml_string).unwrap();
assert_eq!(
vertices,
Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
],
}
);
}
#[test]
fn fromxml_displacement_triangles_test() {
let xml_string = format!(
"<triangles xmlns=\"{}\" did=\"5\"><triangle v1=\"0\" v2=\"1\" v3=\"2\" d1=\"0\" d2=\"1\" d3=\"2\" did=\"6\" p1=\"0\" p2=\"1\" p3=\"2\" pid=\"6\" /></triangles>",
DISPLACEMENT_NS
);
let triangles = from_str::<Triangles>(&xml_string).unwrap();
assert_eq!(
triangles,
Triangles {
did: OptionalResourceId::new(5),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::new(0),
d2: OptionalResourceIndex::new(1),
d3: OptionalResourceIndex::new(2),
did: OptionalResourceId::new(6),
p1: OptionalResourceIndex::new(0),
p2: OptionalResourceIndex::new(1),
p3: OptionalResourceIndex::new(2),
pid: OptionalResourceId::new(6),
}],
}
);
}
#[test]
fn fromxml_displacement_mesh_test() {
let xml_string = format!(
"<displacementmesh xmlns=\"{}\"><vertices><vertex x=\"0.0\" y=\"0.0\" z=\"0.0\" /><vertex x=\"1.0\" y=\"0.0\" z=\"0.0\" /><vertex x=\"0.0\" y=\"1.0\" z=\"0.0\" /></vertices><triangles><triangle v1=\"0\" v2=\"1\" v3=\"2\" /></triangles></displacementmesh>",
DISPLACEMENT_NS
);
let mesh = from_str::<DisplacementMesh>(&xml_string).unwrap();
assert_eq!(
mesh,
DisplacementMesh {
vertices: Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
},
triangles: Triangles {
did: OptionalResourceId::none(),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::none(),
d2: OptionalResourceIndex::none(),
d3: OptionalResourceIndex::none(),
did: OptionalResourceId::none(),
p1: OptionalResourceIndex::none(),
p2: OptionalResourceIndex::none(),
p3: OptionalResourceIndex::none(),
pid: OptionalResourceId::none(),
}],
},
trianglesets: None,
beamlattice: None,
}
);
}
}
#[cfg(feature = "speed-optimized-read")]
#[cfg(test)]
mod speed_optimized_read_tests {
use pretty_assertions::assert_eq;
use serde_roxmltree::from_str;
use crate::threemf_namespaces::DISPLACEMENT_NS;
use super::*;
#[test]
fn fromxml_displacement2d_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"1\" path=\"/3D/Textures/displacement.png\" />",
DISPLACEMENT_NS
);
let displacement2d = from_str::<Displacement2D>(&xml_string).unwrap();
assert_eq!(
displacement2d,
Displacement2D {
id: 1,
path: "/3D/Textures/displacement.png".to_owned(),
channel: None,
tilestyleu: None,
tilestylev: None,
filter: None,
}
);
}
#[test]
fn fromxml_displacement2d_with_options_test() {
let xml_string = format!(
"<displacement2d xmlns=\"{}\" id=\"2\" path=\"/textures/disp.png\" channel=\"R\" tilestyleu=\"mirror\" tilestylev=\"clamp\" filter=\"linear\" />",
DISPLACEMENT_NS
);
let displacement2d = from_str::<Displacement2D>(&xml_string).unwrap();
assert_eq!(displacement2d.id, 2);
assert_eq!(displacement2d.path, "/textures/disp.png");
}
#[test]
fn fromxml_channel_name_test() {
for (xml, expected) in [
("R", ChannelName::R),
("G", ChannelName::G),
("B", ChannelName::B),
("A", ChannelName::A),
] {
let xml_string = format!("<color xmlns=\"{}\">{}</color>", DISPLACEMENT_NS, xml);
let color: ChannelName = from_str(&xml_string).unwrap();
assert_eq!(color, expected);
}
}
#[test]
fn fromxml_tile_style_test() {
for (xml, expected) in [
("wrap", TileStyle::Wrap),
("mirror", TileStyle::Mirror),
("clamp", TileStyle::Clamp),
("none", TileStyle::None),
] {
let xml_string = format!(
"<tilestyle xmlns=\"{}\">{}</tilestyle>",
DISPLACEMENT_NS, xml
);
let tilestyle: TileStyle = from_str(&xml_string).unwrap();
assert_eq!(tilestyle, expected);
}
}
#[test]
fn fromxml_displacement_filter_test() {
for (xml, expected) in [
("auto", Filter::Auto),
("linear", Filter::Linear),
("nearest", Filter::Nearest),
] {
let xml_string = format!("<filter xmlns=\"{}\">{}</filter>", DISPLACEMENT_NS, xml);
let filter: Filter = from_str(&xml_string).unwrap();
assert_eq!(filter, expected);
}
}
#[test]
fn fromxml_norm_vector_group_test() {
let xml_string = format!(
"<normvectorgroup xmlns=\"{}\" id=\"1\"><normvector x=\"0\" y=\"0\" z=\"1\" /><normvector x=\"0\" y=\"1\" z=\"0\" /></normvectorgroup>",
DISPLACEMENT_NS
);
let group = from_str::<NormVectorGroup>(&xml_string).unwrap();
assert_eq!(
group,
NormVectorGroup {
id: 1,
normvector: vec![
NormVector {
x: 0.0.into(),
y: 0.0.into(),
z: 1.0.into(),
},
NormVector {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
}
);
}
#[test]
fn fromxml_disp2d_group_test() {
let xml_string = format!(
"<disp2dgroup xmlns=\"{}\" id=\"1\" dispid=\"2\" nid=\"3\" height=\"0.5\" offset=\"0.1\"><disp2dcoord u=\"0\" v=\"0\" n=\"0\" /><disp2dcoord u=\"1\" v=\"1\" n=\"1\" f=\"0.3\" /></disp2dgroup>",
DISPLACEMENT_NS
);
let group = from_str::<Disp2DGroup>(&xml_string).unwrap();
assert_eq!(
group,
Disp2DGroup {
id: 1,
dispid: 2,
nid: 3,
height: 0.5.into(),
offset: Some(0.1.into()),
disp2dcoord: vec![
Disp2DCoord {
u: 0.0.into(),
v: 0.0.into(),
n: 0,
f: None,
},
Disp2DCoord {
u: 1.0.into(),
v: 1.0.into(),
n: 1,
f: Some(0.3.into()),
},
],
}
);
}
#[test]
fn fromxml_displacement_vertices_test() {
let xml_string = format!(
"<vertices xmlns=\"{}\"><vertex x=\"0\" y=\"0\" z=\"0\" /><vertex x=\"1\" y=\"0\" z=\"0\" /></vertices>",
DISPLACEMENT_NS
);
let vertices = from_str::<Vertices>(&xml_string).unwrap();
assert_eq!(
vertices,
Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
],
}
);
}
#[test]
fn fromxml_displacement_triangles_test() {
let xml_string = format!(
"<triangles xmlns=\"{}\" did=\"5\"><triangle v1=\"0\" v2=\"1\" v3=\"2\" d1=\"0\" d2=\"1\" d3=\"2\" /></triangles>",
DISPLACEMENT_NS
);
let triangles = from_str::<Triangles>(&xml_string).unwrap();
assert_eq!(
triangles,
Triangles {
did: OptionalResourceId::new(5),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::new(0),
d2: OptionalResourceIndex::new(1),
d3: OptionalResourceIndex::new(2),
did: OptionalResourceId::none(),
p1: OptionalResourceIndex::none(),
p2: OptionalResourceIndex::none(),
p3: OptionalResourceIndex::none(),
pid: OptionalResourceId::none(),
}],
}
);
}
#[test]
fn fromxml_displacement_mesh_test() {
let xml_string = format!(
"<displacementmesh xmlns=\"{}\"><vertices><vertex x=\"0.0\" y=\"0.0\" z=\"0.0\" /><vertex x=\"1.0\" y=\"0.0\" z=\"0.0\" /><vertex x=\"0.0\" y=\"1.0\" z=\"0.0\" /></vertices><triangles><triangle v1=\"0\" v2=\"1\" v3=\"2\" /></triangles></displacementmesh>",
DISPLACEMENT_NS
);
let mesh = from_str::<DisplacementMesh>(&xml_string).unwrap();
assert_eq!(
mesh,
DisplacementMesh {
vertices: Vertices {
vertex: vec![
Vertex {
x: 0.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 1.0.into(),
y: 0.0.into(),
z: 0.0.into(),
},
Vertex {
x: 0.0.into(),
y: 1.0.into(),
z: 0.0.into(),
},
],
},
triangles: Triangles {
did: OptionalResourceId::none(),
triangle: vec![Triangle {
v1: 0,
v2: 1,
v3: 2,
d1: OptionalResourceIndex::none(),
d2: OptionalResourceIndex::none(),
d3: OptionalResourceIndex::none(),
did: OptionalResourceId::none(),
p1: OptionalResourceIndex::none(),
p2: OptionalResourceIndex::none(),
p3: OptionalResourceIndex::none(),
pid: OptionalResourceId::none(),
}],
},
trianglesets: None,
beamlattice: None,
}
);
}
}