lib3mf_core/writer/
displacement_writer.rs1use crate::error::Result;
2use crate::model::{Channel, Displacement2D, DisplacementMesh, FilterMode, TileStyle};
3use crate::writer::xml_writer::XmlWriter;
4use std::io::Write;
5
6pub fn write_displacement_mesh<W: Write>(
8 writer: &mut XmlWriter<W>,
9 mesh: &DisplacementMesh,
10) -> Result<()> {
11 writer.start_element("d:displacementmesh").write_start()?;
12
13 writer.start_element("d:vertices").write_start()?;
15 for v in &mesh.vertices {
16 writer
17 .start_element("d:vertex")
18 .attr("x", &v.x.to_string())
19 .attr("y", &v.y.to_string())
20 .attr("z", &v.z.to_string())
21 .write_empty()?;
22 }
23 writer.end_element("d:vertices")?;
24
25 writer.start_element("d:triangles").write_start()?;
27 for t in &mesh.triangles {
28 let mut builder = writer
29 .start_element("d:triangle")
30 .attr("v1", &t.v1.to_string())
31 .attr("v2", &t.v2.to_string())
32 .attr("v3", &t.v3.to_string());
33
34 if let Some(d1) = t.d1 {
36 builder = builder.attr("d1", &d1.to_string());
37 }
38 if let Some(d2) = t.d2 {
39 builder = builder.attr("d2", &d2.to_string());
40 }
41 if let Some(d3) = t.d3 {
42 builder = builder.attr("d3", &d3.to_string());
43 }
44
45 if let Some(p1) = t.p1 {
47 builder = builder.attr("p1", &p1.to_string());
48 }
49 if let Some(p2) = t.p2 {
50 builder = builder.attr("p2", &p2.to_string());
51 }
52 if let Some(p3) = t.p3 {
53 builder = builder.attr("p3", &p3.to_string());
54 }
55 if let Some(pid) = t.pid {
56 builder = builder.attr("pid", &pid.to_string());
57 }
58
59 builder.write_empty()?;
60 }
61 writer.end_element("d:triangles")?;
62
63 writer.start_element("d:normvectors").write_start()?;
65 for n in &mesh.normals {
66 writer
67 .start_element("d:normvector")
68 .attr("nx", &n.nx.to_string())
69 .attr("ny", &n.ny.to_string())
70 .attr("nz", &n.nz.to_string())
71 .write_empty()?;
72 }
73 writer.end_element("d:normvectors")?;
74
75 if let Some(gradients) = &mesh.gradients {
77 writer.start_element("d:disp2dgroups").write_start()?;
78 writer.start_element("d:disp2dgroup").write_start()?;
79 for g in gradients {
80 writer
81 .start_element("d:tex2dcoord")
82 .attr("gu", &g.gu.to_string())
83 .attr("gv", &g.gv.to_string())
84 .write_empty()?;
85 }
86 writer.end_element("d:disp2dgroup")?;
87 writer.end_element("d:disp2dgroups")?;
88 }
89
90 writer.end_element("d:displacementmesh")?;
91 Ok(())
92}
93
94pub fn write_displacement_2d<W: Write>(
96 writer: &mut XmlWriter<W>,
97 res: &Displacement2D,
98) -> Result<()> {
99 let mut builder = writer
100 .start_element("d:displacement2d")
101 .attr("id", &res.id.0.to_string())
102 .attr("path", &res.path);
103
104 if res.channel != Channel::G {
106 builder = builder.attr("channel", channel_to_str(res.channel));
107 }
108
109 if res.tile_style != TileStyle::Wrap {
111 builder = builder.attr("tilestyle", tile_style_to_str(res.tile_style));
112 }
113
114 if res.filter != FilterMode::Linear {
116 builder = builder.attr("filter", filter_mode_to_str(res.filter));
117 }
118
119 builder = builder.attr("height", &res.height.to_string());
121
122 if res.offset != 0.0 {
124 builder = builder.attr("offset", &res.offset.to_string());
125 }
126
127 builder.write_empty()?;
128 Ok(())
129}
130
131fn channel_to_str(c: Channel) -> &'static str {
133 match c {
134 Channel::R => "R",
135 Channel::G => "G",
136 Channel::B => "B",
137 Channel::A => "A",
138 }
139}
140
141fn tile_style_to_str(ts: TileStyle) -> &'static str {
143 match ts {
144 TileStyle::Wrap => "wrap",
145 TileStyle::Mirror => "mirror",
146 TileStyle::Clamp => "clamp",
147 TileStyle::None => "none",
148 }
149}
150
151fn filter_mode_to_str(fm: FilterMode) -> &'static str {
153 match fm {
154 FilterMode::Linear => "linear",
155 FilterMode::Nearest => "nearest",
156 }
157}