1use std::io::{BufRead, BufReader, Read, Write};
22
23#[cfg(feature = "bytemuck")]
24use bytemuck::{Pod, Zeroable};
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Deserializer, Serialize, Serializer};
28
29const F32_SIZE: usize = std::mem::size_of::<f32>();
30
31const TRIANGLE_BINARY_SIZE: usize = 50;
43
44const HEADER_BINARY_SIZE: usize = 80;
48
49#[repr(C)]
51#[derive(Default, Debug, Copy, Clone, PartialEq)]
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53pub struct Triangle {
54 pub v1: [f32; 3],
55 pub v2: [f32; 3],
56 pub v3: [f32; 3],
57}
58
59#[cfg(feature = "bytemuck")]
60unsafe impl Pod for Triangle {}
61#[cfg(feature = "bytemuck")]
62unsafe impl Zeroable for Triangle {}
63
64pub type Result<T> = std::result::Result<T, Error>;
65
66impl From<&[u8]> for Triangle {
67 fn from(buffer: &[u8]) -> Self {
68 const N_FLOAT_VALUES: usize = 9; let mut values = [0.0; N_FLOAT_VALUES];
70 for (value, bytes) in values
71 .iter_mut()
72 .zip(buffer[0..(N_FLOAT_VALUES * F32_SIZE)].chunks_exact(F32_SIZE))
73 {
74 let mut buf = [0; F32_SIZE];
75 buf.copy_from_slice(bytes);
76 *value = f32::from_le_bytes(buf);
77 }
78
79 let mut facet = Triangle::default();
80 facet.v1.copy_from_slice(&values[0..3]);
81 facet.v2.copy_from_slice(&values[3..6]);
82 facet.v3.copy_from_slice(&values[6..9]);
83 facet
84 }
85}
86
87impl Triangle {
88 #[must_use]
90 fn calculate_normals(&self) -> [f32; 3] {
91 let u = [
92 self.v2[0] - self.v1[0],
93 self.v2[1] - self.v1[1],
94 self.v2[2] - self.v1[2],
95 ];
96 let v = [
97 self.v3[0] - self.v1[0],
98 self.v3[1] - self.v1[1],
99 self.v3[2] - self.v1[2],
100 ];
101
102 let mut normal = [
103 u[1] * v[2] - u[2] * v[1],
104 u[2] * v[0] - u[0] * v[2],
105 u[0] * v[1] - u[1] * v[0],
106 ];
107
108 let len = (normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]).sqrt();
109 normal[0] /= len;
110 normal[1] /= len;
111 normal[2] /= len;
112 normal
113 }
114
115 #[must_use]
117 fn check_and_fix_normals(&self, normal: [f32; 3]) -> [f32; 3] {
118 const NORMAL_LENGTH_DEVIATION_LIMIT: f32 = 0.001;
119
120 let normal = if normal.iter().all(|i| *i == 0.0) {
121 self.calculate_normals()
122 } else {
123 normal
124 };
125
126 let len = (normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]).sqrt();
127 if (len - 1.0).abs() > NORMAL_LENGTH_DEVIATION_LIMIT {
128 return self.calculate_normals();
129 }
130 normal
131 }
132}
133
134#[derive(Debug)]
136pub enum Error {
137 MissingData,
140 Unexpected(usize),
142 Parse(usize),
144 TooManyFacets(<u32 as std::convert::TryFrom<usize>>::Error),
146 TryFromInt(std::num::TryFromIntError),
148 Io(std::io::Error),
150}
151
152impl From<std::io::Error> for Error {
153 fn from(e: std::io::Error) -> Self {
154 Self::Io(e)
155 }
156}
157
158impl From<std::num::TryFromIntError> for Error {
159 fn from(e: std::num::TryFromIntError) -> Self {
160 Self::TryFromInt(e)
161 }
162}
163
164impl std::fmt::Display for Error {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 match self {
167 Error::MissingData => write!(
168 f,
169 "STL data ended unexpectely and is incomplete or otherwise broken."
170 ),
171 Error::Unexpected(line) => {
172 write!(
173 f,
174 "Found an unexpected keyword or token in an ASCII STL file on line {line}."
175 )
176 }
177 Error::Parse(line) => write!(f, "Bad Vertex or Normal on line {line}."),
178 Error::TooManyFacets(e) => {
179 write!(f, "{e:?}")
180 }
181 Error::Io(e) => write!(f, "{e:?}"),
182 Error::TryFromInt(e) => write!(f, "{e:?}"),
183 }
184 }
185}
186
187fn parse_triplet(str: &str, line: usize) -> Result<[f32; 3]> {
191 let mut result = [0.0; 3];
192 let mut count = 0;
193 for (r, v) in result.iter_mut().zip(str.split_whitespace()) {
194 if let Ok(v) = v.parse() {
195 *r = v;
196 } else {
197 return Err(Error::Parse(line));
198 }
199 count += 1;
200 }
201 if count != 3 {
202 return Err(Error::Parse(line));
203 }
204 Ok(result)
205}
206
207#[derive(Debug, Copy, Clone, PartialEq, Eq)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209pub enum Encoding {
211 Binary,
212 Ascii,
213}
214
215#[cfg(feature = "serde")]
216fn header_serialize<S: Serializer>(
217 header: &Option<[u8; 80]>,
218 s: S,
219) -> std::result::Result<S::Ok, S::Error> {
220 s.serialize_bytes(header.unwrap_or([0; 80]).as_slice())
221}
222
223#[cfg(feature = "serde")]
224fn header_deserialize<'de, D>(d: D) -> std::result::Result<Option<[u8; 80]>, D::Error>
225where
226 D: Deserializer<'de>,
227{
228 let mut res = [0; 80];
229 res.copy_from_slice(<&[u8]>::deserialize(d)?);
230 Ok(Some(res))
231}
232
233#[derive(Default, Debug, Clone, PartialEq)]
235#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
236pub struct StlData {
237 pub triangles: Vec<Triangle>,
239 pub normals: Vec<[f32; 3]>,
240 pub name: String,
241 #[cfg_attr(feature = "serde", serde(serialize_with = "header_serialize"))]
242 #[cfg_attr(feature = "serde", serde(deserialize_with = "header_deserialize"))]
243 pub header: Option<[u8; HEADER_BINARY_SIZE]>,
244 pub encoding: Option<Encoding>,
245 pub force_normals: bool,
250 pub disable_normals: bool,
254 pub nullify_normals: bool,
257}
258
259impl StlData {
260 pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
262 fn read_file_path(path: &std::path::Path) -> Result<StlData> {
265 let mut res = StlData::default();
266 res.set_from_file(path)?;
267 Ok(res)
268 }
269 read_file_path(path.as_ref())
270 }
271
272 pub fn read_buffer(reader: impl BufRead) -> Result<Self> {
274 let mut res = Self::default();
275 res.set_from_buffer(reader)?;
276 Ok(res)
277 }
278
279 pub fn set_from_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<()> {
283 self.set_from_file_path(path.as_ref())
284 }
285
286 fn set_from_file_path(&mut self, path: &std::path::Path) -> Result<()> {
289 let file = std::fs::File::open(path)?;
290 let reader = BufReader::new(file);
291 self.set_from_buffer(reader)?;
292 Ok(())
293 }
294
295 pub fn set_from_buffer(&mut self, mut reader: impl BufRead) -> Result<()> {
299 self.clear();
300 let buffer = reader.fill_buf()?;
301 if buffer.len() < 5 {
302 return Err(Error::MissingData);
303 }
304 if buffer[0..5] == *b"solid" {
305 let set = self.read_ascii_buffer(reader);
306 if set.is_err() {
307 self.clear();
308 return set;
309 }
310 self.encoding = Some(Encoding::Ascii);
311 } else {
312 let set = self.read_binary_buffer(reader);
313 if set.is_err() {
314 self.clear();
315 return set;
316 }
317 self.encoding = Some(Encoding::Binary);
318 }
319 Ok(())
320 }
321
322 pub fn clear(&mut self) {
324 self.triangles.clear();
325 self.name.clear();
326 self.header = None;
327 self.encoding = None;
328 }
329
330 fn read_ascii_buffer(&mut self, reader: impl BufRead) -> Result<()> {
333 let mut active_solid = false;
335 let mut active_facet = false;
336 let mut active_loop = false;
337 let mut solid_count = 0;
338 let mut loop_count = 0;
339 let mut vertex_count = 0;
340
341 let mut n = [0.0; 3];
342 let mut v = [0.0; 9];
343
344 for (line_number, line) in reader.lines().enumerate() {
346 let line_number = line_number + 1; let line = line?;
348 if line.trim().starts_with("solid") {
349 if active_solid || solid_count != 0 {
350 return Err(Error::Unexpected(line_number));
351 }
352 active_solid = true;
353 if line.trim().len() > 5 {
354 self.name = (line["solid".len()..].trim()).to_string();
355 }
356 }
357 if line.trim().starts_with("endsolid") {
358 if !active_solid || active_facet || active_loop {
359 return Err(Error::Unexpected(line_number));
360 }
361 active_solid = false;
362 solid_count += 1;
363 }
364 if line.trim().starts_with("facet normal") {
365 if !active_solid || active_loop || active_facet {
366 return Err(Error::Unexpected(line_number));
367 }
368 active_facet = true;
369 n = parse_triplet(line.trim()["facet normal".len()..].trim(), line_number)?;
370 }
371 if line.trim().starts_with("endfacet") {
372 if !active_solid || active_loop || !active_facet || loop_count != 1 {
373 return Err(Error::Unexpected(line_number));
374 }
375 active_facet = false;
376 loop_count = 0;
377 let mut facet = Triangle::default();
378 facet.v1.copy_from_slice(&v[0..3]);
379 facet.v2.copy_from_slice(&v[3..6]);
380 facet.v3.copy_from_slice(&v[6..9]);
381
382 let normal = if self.force_normals && !self.disable_normals {
383 facet.calculate_normals()
384 } else if !self.disable_normals {
385 facet.check_and_fix_normals(n)
386 } else {
387 n
388 };
389
390 self.normals.push(normal);
391 self.triangles.push(facet);
392 }
393 if line.trim().starts_with("outer loop") {
394 if !active_solid || !active_facet || active_loop {
395 return Err(Error::Unexpected(line_number));
396 }
397 active_loop = true;
398 }
399 if line.trim().starts_with("endloop") {
400 if !active_solid || !active_facet || !active_loop || vertex_count != 3 {
401 return Err(Error::Unexpected(line_number));
402 }
403 active_loop = false;
404 loop_count += 1;
405 vertex_count = 0;
406 }
407 if line.trim().starts_with("vertex") {
408 if !active_solid || !active_facet || !active_loop || vertex_count >= 3 {
409 return Err(Error::Unexpected(line_number));
410 }
411 let triplet = parse_triplet(line.trim()["vertex".len()..].trim(), line_number)?;
412 v[vertex_count * 3] = triplet[0];
413 v[vertex_count * 3 + 1] = triplet[1];
414 v[vertex_count * 3 + 2] = triplet[2];
415
416 vertex_count += 1;
417 }
418 }
419
420 if active_solid || active_facet || active_loop || solid_count == 0 {
421 return Err(Error::MissingData);
422 }
423
424 Ok(())
425 }
426
427 fn read_binary_buffer(&mut self, mut reader: impl BufRead) -> Result<()> {
430 let mut buffer = vec![0; HEADER_BINARY_SIZE];
431
432 let mut header_reader = (&mut reader).take(u64::try_from(HEADER_BINARY_SIZE)?);
433 let header_bytes_read = header_reader.read_to_end(&mut buffer)?;
434 if header_bytes_read != HEADER_BINARY_SIZE {
435 return Err(Error::MissingData);
436 }
437
438 let mut header_buffer = [0; HEADER_BINARY_SIZE];
439 header_buffer.copy_from_slice(&buffer[0..HEADER_BINARY_SIZE]);
440 self.header = Some(header_buffer);
441 buffer.clear();
442
443 let mut facet_count_reader = (&mut reader).take(4);
444 let facet_count_bytes_read = facet_count_reader.read_to_end(&mut buffer)?;
445 if facet_count_bytes_read != 4 {
446 return Err(Error::MissingData);
447 }
448 let mut facet_count_buf = [0; 4];
449 facet_count_buf.copy_from_slice(&buffer[0..4]);
450
451 let facet_count = u32::from_le_bytes(facet_count_buf);
452 if facet_count == 0 {
453 return Err(Error::MissingData);
454 }
455 buffer.clear();
456
457 for _ in 0..facet_count {
458 let mut facet_reader = (&mut reader).take(u64::try_from(TRIANGLE_BINARY_SIZE)?);
459 let facet_buffer_bytes_read = facet_reader.read_to_end(&mut buffer)?;
460 if facet_buffer_bytes_read != TRIANGLE_BINARY_SIZE {
461 return Err(Error::MissingData);
462 }
463 let (normal_buffer, vertex_buffer) = buffer.split_at(F32_SIZE * 3);
464 let facet = Triangle::from(vertex_buffer);
465 let mut n = [0.0; 3];
466 for (n, chunk) in n.iter_mut().zip(normal_buffer.chunks_exact(F32_SIZE)) {
467 let mut bytes = [0; 4];
468 bytes.copy_from_slice(chunk);
469 *n = f32::from_le_bytes(bytes);
470 }
471 let normal = if self.force_normals && !self.disable_normals {
472 facet.calculate_normals()
473 } else if !self.disable_normals {
474 facet.check_and_fix_normals(n)
475 } else {
476 n
477 };
478 self.normals.push(normal);
479 self.triangles.push(facet);
480 buffer.clear();
481 }
482 Ok(())
483 }
484
485 pub fn write_binary_buffer(&self, mut writer: impl Write) -> Result<()> {
487 writer.write_all(self.header.unwrap_or([0; HEADER_BINARY_SIZE]).as_slice())?;
488 let n_triangles = u32::try_from(self.triangles.len())?;
489 writer.write_all(n_triangles.to_le_bytes().as_slice())?;
490 let null_bytes = [0; 12];
491
492 for (&Triangle { v1, v2, v3 }, &normal) in self.triangles.iter().zip(self.normals.iter()) {
493 if self.nullify_normals {
494 writer.write_all(&null_bytes)?;
495 } else {
496 for n in normal {
497 writer.write_all(n.to_le_bytes().as_slice())?;
498 }
499 }
500
501 for vertex in [v1, v2, v3] {
502 for v in vertex {
503 writer.write_all(v.to_le_bytes().as_slice())?;
504 }
505 }
506
507 writer.write_all(&[0; 2])?;
508 }
509
510 Ok(())
511 }
512
513 pub fn write_ascii_buffer(&self, mut writer: impl Write) -> Result<()> {
515 writeln!(writer, "solid {}", self.name)?;
516 for (&Triangle { v1, v2, v3 }, &normal) in self.triangles.iter().zip(self.normals.iter()) {
517 if self.nullify_normals {
518 writeln!(writer, " facet normal 0 0 0")?;
519 } else {
520 let [n0, n1, n2] = normal;
521 writeln!(writer, " facet normal {n0} {n1} {n2}")?;
522 };
523 writeln!(writer, " outer loop")?;
524 for v in [v1, v2, v3] {
525 let [v0, v1, v2] = v;
526 writeln!(writer, " vertex {v0} {v1} {v2}")?;
527 }
528 writeln!(writer, " endloop")?;
529 writeln!(writer, " endfacet")?;
530 }
531 writeln!(writer, "endsolid")?;
532 Ok(())
533 }
534
535 pub fn write_ascii_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
539 self.write_ascii_file_path(path.as_ref())
540 }
541
542 fn write_ascii_file_path(&self, path: &std::path::Path) -> Result<()> {
545 let file = std::fs::OpenOptions::new()
546 .write(true)
547 .create(true)
548 .open(path)?;
549 let writer = std::io::BufWriter::new(file);
550 self.write_ascii_buffer(writer)?;
551 Ok(())
552 }
553
554 pub fn write_binary_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
558 self.write_binary_file_path(path.as_ref())
559 }
560
561 fn write_binary_file_path(&self, path: &std::path::Path) -> Result<()> {
564 let file = std::fs::OpenOptions::new()
565 .write(true)
566 .create(true)
567 .open(path)?;
568 let writer = std::io::BufWriter::new(file);
569 self.write_binary_buffer(writer)?;
570 Ok(())
571 }
572}