1use crate::*;
2use bytemuck::{Pod, Zeroable};
3use rustc_hash::FxHashMap as HashMap;
4use std::io::{BufRead, BufReader, Lines, Read, Write};
5
6const FACESIZE: usize = size_of::<StlFace>();
7const CHUNKSIZE: usize = FACESIZE + 2;
8
9type Vertex = StandardVertex;
10type Result<T> = std::result::Result<T, errors::Error>;
11
12fn syntax_error() -> std::io::Error {
13 std::io::Error::new(std::io::ErrorKind::InvalidData, "syntax error")
14}
15
16#[repr(C)]
18#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Pod, Zeroable)]
19pub struct StlFace {
20 pub normal: [f32; 3],
22 pub vertices: [[f32; 3]; 3],
24}
25
26impl StlFace {
27 #[inline(always)]
28 fn is_empty(&self) -> bool { self == &StlFace::default() }
29}
30
31#[derive(Debug)]
33pub enum StlReader<R: Read> {
34 #[doc(hidden)]
35 Ascii(Lines<BufReader<R>>),
36 #[doc(hidden)]
37 Binary(R, usize),
38}
39
40#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
42pub enum StlType {
43 #[default]
53 Automatic,
54 Ascii,
56 Binary,
58}
59
60impl<R: Read> StlReader<R> {
61 #[inline(always)]
62 fn text_reader(reader: R) -> StlReader<R> { StlReader::Ascii(BufReader::new(reader).lines()) }
63 fn binary_reader(mut reader: R, header_judge: bool) -> Result<StlReader<R>> {
64 let mut header = [0; 5];
65 reader.read_exact(&mut header)?;
66 if header_judge && &header == b"solid" {
67 return Ok(Self::text_reader(reader));
68 }
69 let mut header = [0; 75];
70 reader.read_exact(&mut header)?;
71 let mut length_bytes = [0; 4];
72 reader.read_exact(&mut length_bytes)?;
73 let length = u32::from_le_bytes(length_bytes) as usize;
74 Ok(StlReader::Binary(reader, length))
75 }
76 #[inline(always)]
78 pub fn new(reader: R, stl_type: StlType) -> Result<Self> {
79 match stl_type {
80 StlType::Automatic => Self::binary_reader(reader, true),
81 StlType::Binary => Self::binary_reader(reader, false),
82 StlType::Ascii => Ok(Self::text_reader(reader)),
83 }
84 }
85 #[inline(always)]
87 pub fn stl_type(&self) -> StlType {
88 match self {
89 StlReader::Ascii(_) => StlType::Ascii,
90 StlReader::Binary(_, _) => StlType::Binary,
91 }
92 }
93}
94
95impl<R: Read> Iterator for StlReader<R> {
96 type Item = Result<StlFace>;
97 fn next(&mut self) -> Option<Self::Item> {
98 let res = match self {
99 StlReader::Binary(reader, length) => {
100 if *length == 0 {
101 Ok(None)
102 } else {
103 *length -= 1;
104 binary_one_read(reader)
105 }
106 }
107 StlReader::Ascii(lines) => ascii_one_read(lines),
108 };
109 match res {
110 Ok(Some(got)) => Some(Ok(got)),
111 Ok(None) => None,
112 Err(error) => Some(Err(error)),
113 }
114 }
115}
116
117fn ascii_one_read<R: BufRead>(lines: &mut Lines<R>) -> Result<Option<StlFace>> {
118 let mut face = StlFace::default();
119 let mut num_ver = 0;
120 loop {
121 let line = match lines.next() {
122 Some(got) => got?,
123 None => match face.is_empty() {
124 true => return Ok(None),
125 false => return Err(syntax_error().into()),
126 },
127 };
128 let line = line.trim();
129 if line.len() < 8 {
130 continue;
131 } else if &line[0..5] == "facet" {
132 let args: Vec<_> = line.split_whitespace().collect();
133 face.normal = array![i => args[i + 2].parse::<f32>()?; 3];
134 } else if &line[0..6] == "vertex" {
135 let args: Vec<_> = line.split_whitespace().collect();
136 if num_ver > 2 {
137 return Err(syntax_error().into());
138 }
139 face.vertices[num_ver] = array![i => args[i + 1].parse::<f32>()?; 3];
140 num_ver += 1;
141 } else if &line[0..8] == "endfacet" {
142 if num_ver != 3 {
143 return Err(syntax_error().into());
144 }
145 return Ok(Some(face));
146 }
147 }
148}
149
150fn binary_one_read<R: Read>(reader: &mut R) -> Result<Option<StlFace>> {
151 let mut chunk = [0; CHUNKSIZE];
152 let size = reader.read(&mut chunk)?;
153 if size == CHUNKSIZE {
154 let mut buf = [0; FACESIZE];
155 buf.copy_from_slice(&chunk[..FACESIZE]);
156 Ok(Some(bytemuck::cast(buf)))
157 } else {
158 Err(syntax_error().into())
159 }
160}
161
162#[inline(always)]
166pub fn write<I: IntoStlIterator, W: Write>(
167 iter: I,
168 writer: &mut W,
169 stl_type: StlType,
170) -> Result<()> {
171 match stl_type {
172 StlType::Ascii => write_ascii(iter, writer),
173 _ => write_binary(iter, writer),
174 }
175}
176
177fn write_ascii<I: IntoStlIterator, W: Write>(iter: I, writer: &mut W) -> Result<()> {
179 let mut iter = iter.into_iter();
180 writer.write_all(b"solid\n")?;
181 iter.try_for_each::<_, Result<()>>(|face| {
182 writer.write_fmt(format_args!(
183 " facet normal {:e} {:e} {:e}\n",
184 face.normal[0], face.normal[1], face.normal[2]
185 ))?;
186 writer.write_all(b" outer loop\n")?;
187 face.vertices.iter().try_for_each(|pt| {
188 writer.write_fmt(format_args!(
189 " vertex {:e} {:e} {:e}\n",
190 pt[0], pt[1], pt[2]
191 ))
192 })?;
193 writer.write_all(b" endloop\n endfacet\n")?;
194 Ok(())
195 })?;
196 writer.write_all(b"endsolid\n")?;
197 Ok(())
198}
199
200#[inline(always)]
202fn write_binary<I: IntoStlIterator, W: Write>(iter: I, writer: &mut W) -> Result<()> {
203 let mut iter = iter.into_iter();
204 let len = iter.len() as u32;
205 writer.write_all(&[0u8; 80])?;
206 writer.write_all(&len.to_le_bytes())?;
207 iter.try_for_each(|face| {
208 writer.write_all(bytemuck::cast_slice(&[face]))?;
209 writer.write_all(&[0u8, 0u8])?;
210 Ok(())
211 })
212}
213
214pub trait IntoStlIterator {
219 type IntoIter: ExactSizeIterator<Item = StlFace>;
221 fn into_iter(self) -> Self::IntoIter;
223}
224
225#[derive(Debug)]
227pub struct PolygonMeshStlFaceIterator<'a> {
228 positions: &'a Vec<Point3>,
229 faces: faces::TriangleIterator<'a, Vertex>,
230 len: usize,
231}
232
233impl<'a> Iterator for PolygonMeshStlFaceIterator<'a> {
234 type Item = StlFace;
235 fn next(&mut self) -> Option<StlFace> {
236 self.faces.next().map(|face| {
237 let p = array![i => self.positions[face[i].pos]; 3];
238 let n = (p[1] - p[0]).cross(p[2] - p[0]).normalize();
239 let normal = n.cast().unwrap().into();
240 let vertices = array![i => p[i].cast().unwrap().into(); 3];
241 StlFace { normal, vertices }
242 })
243 }
244 #[inline(always)]
245 fn size_hint(&self) -> (usize, Option<usize>) { (self.len, Some(self.len)) }
246}
247
248impl<'a> ExactSizeIterator for PolygonMeshStlFaceIterator<'a> {}
249
250impl<'a> IntoStlIterator for &'a PolygonMesh {
251 type IntoIter = PolygonMeshStlFaceIterator<'a>;
252 fn into_iter(self) -> Self::IntoIter {
253 let iter = self.faces().triangle_iter();
254 Self::IntoIter {
255 positions: self.positions(),
256 len: iter.len(),
257 faces: iter,
258 }
259 }
260}
261
262impl<I> IntoStlIterator for I
263where
264 I: IntoIterator<Item = StlFace>,
265 I::IntoIter: ExactSizeIterator,
266{
267 type IntoIter = I::IntoIter;
268 fn into_iter(self) -> I::IntoIter { self.into_iter() }
269}
270
271fn signup_vector(vector: [f32; 3], map: &mut HashMap<[i64; 3], usize>) -> usize {
272 let vector = array![i =>
273 ((vector[i] as f64 + TOLERANCE * 0.25) / (TOLERANCE * 0.5)) as i64; 3];
274 let len = map.len();
275 *map.entry(vector).or_insert_with(|| len)
276}
277
278fn decode_vector<T: From<[f64; 3]>>((code, _): ([i64; 3], usize)) -> T {
279 array![i => code[i] as f64 * TOLERANCE * 0.5; 3].into()
280}
281
282impl FromIterator<StlFace> for PolygonMesh {
283 fn from_iter<I: IntoIterator<Item = StlFace>>(iter: I) -> PolygonMesh {
284 let mut positions = HashMap::<[i64; 3], usize>::default();
285 let mut normals = HashMap::<[i64; 3], usize>::default();
286 let closure = |face: StlFace| {
287 let n = signup_vector(face.normal, &mut normals);
288 let p = array![i => signup_vector(face.vertices[i], &mut positions); 3];
289 array![i => (p[i], None, Some(n)).into(); 3]
290 };
291 let faces: Vec<[Vertex; 3]> = iter.into_iter().map(closure).collect();
292 let faces = Faces::from_tri_and_quad_faces(faces, Vec::new());
293 let mut positions: Vec<([i64; 3], usize)> = positions.into_iter().collect();
294 positions.sort_by(|a, b| a.1.cmp(&b.1));
295 let positions: Vec<Point3> = positions.into_iter().map(decode_vector).collect();
296 let mut normals: Vec<([i64; 3], usize)> = normals.into_iter().collect();
297 normals.sort_by(|a, b| a.1.cmp(&b.1));
298 let normals: Vec<Vector3> = normals.into_iter().map(decode_vector).collect();
299 PolygonMesh::debug_new(
300 StandardAttributes {
301 positions,
302 uv_coords: Vec::new(),
303 normals,
304 },
305 faces,
306 )
307 }
308}
309
310#[inline(always)]
312pub fn read<R: Read>(reader: R, stl_type: StlType) -> Result<PolygonMesh> {
313 StlReader::new(reader, stl_type)?.collect()
314}