conspire/geometry/mesh/tessellation/write/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 geometry::{
6 Coordinate, Direction,
7 mesh::{
8 Connectivity,
9 tessellation::{D, Tessellation},
10 },
11 },
12 io::Write,
13 math::Tensor,
14};
15use std::{
16 fs::File,
17 io::{BufWriter, Error as ErrorIO, Write as WriteIO},
18 path::Path,
19};
20
21pub enum Stl<P>
22where
23 P: AsRef<Path>,
24{
25 Ascii(P),
26 Binary(P),
27}
28
29impl<P> AsRef<Path> for Stl<P>
30where
31 P: AsRef<Path>,
32{
33 fn as_ref(&self) -> &Path {
34 match self {
35 Stl::Ascii(path) => path.as_ref(),
36 Stl::Binary(path) => path.as_ref(),
37 }
38 }
39}
40
41impl<P> Write<Stl<P>> for Tessellation
42where
43 P: AsRef<Path>,
44{
45 type Error = ErrorIO;
46 fn write(&self, output: Stl<P>) -> Result<(), Self::Error> {
47 match output {
48 Stl::Ascii(path) => self.write_stl_ascii(path)?,
49 Stl::Binary(path) => self.write_stl_binary(path)?,
50 }
51 Ok(())
52 }
53}
54
55impl Tessellation {
56 fn for_each_facet<F>(&self, mut facet: F) -> Result<(), ErrorIO>
57 where
58 F: FnMut(&Direction<D>, [&Coordinate<D>; D]) -> Result<(), ErrorIO>,
59 {
60 self.mesh
61 .connectivities()
62 .iter()
63 .zip(self.normals.iter())
64 .try_for_each(|(connectivity, normals)| match connectivity {
65 Connectivity::Triangular(triangles) => triangles
66 .iter()
67 .zip(normals.iter())
68 .try_for_each(|(nodes, normal)| {
69 facet(normal, nodes.map(|node| &self.mesh.coordinates()[node]))
70 }),
71 _ => panic!("STL only supports triangular blocks"),
72 })
73 }
74 fn write_stl_binary<P>(&self, path: P) -> Result<(), ErrorIO>
75 where
76 P: AsRef<Path>,
77 {
78 let mut writer = BufWriter::new(File::create(path)?);
79 writer.write_all(&[0_u8; 80])?;
80 writer.write_all(&(self.mesh.number_of_elements() as u32).to_le_bytes())?;
81 self.for_each_facet(|normal, vertices| {
82 normal.iter().try_for_each(|&component| {
83 writer.write_all(&(component.value() as f32).to_le_bytes())
84 })?;
85 vertices.iter().try_for_each(|vertex| {
86 vertex.iter().try_for_each(|&coordinate| {
87 writer.write_all(&(coordinate.value() as f32).to_le_bytes())
88 })
89 })?;
90 writer.write_all(&0_u16.to_le_bytes())
91 })?;
92 writer.flush()
93 }
94 fn write_stl_ascii<P>(&self, path: P) -> Result<(), ErrorIO>
95 where
96 P: AsRef<Path>,
97 {
98 let mut writer = BufWriter::new(File::create(path)?);
99 writer.write_all(b"solid conspire\n")?;
100 self.for_each_facet(|normal, vertices| {
101 writeln!(
102 writer,
103 " facet normal {} {} {}\n outer loop",
104 normal[0].value() as f32,
105 normal[1].value() as f32,
106 normal[2].value() as f32
107 )?;
108 vertices.iter().try_for_each(|vertex| {
109 writeln!(
110 writer,
111 " vertex {} {} {}",
112 vertex[0].value() as f32,
113 vertex[1].value() as f32,
114 vertex[2].value() as f32
115 )
116 })?;
117 writer.write_all(b" endloop\n endfacet\n")
118 })?;
119 writer.write_all(b"endsolid conspire\n")?;
120 writer.flush()
121 }
122}