From 478023da6615acd308fda67836ac5faf9f44b6c2 Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Fri, 4 Apr 2025 21:42:27 -0400 Subject: [PATCH] Don't produce incorrect results when models extend beyond build volume --- Changelog.md | 4 ++++ slicer/src/slicer.rs | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Changelog.md b/Changelog.md index 554a843..7ee0eab 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ # Changelog +## v0.2.1 — Coming Soon? + +- Don't produce invalid results when models extend beyond build volume + ## v0.2.0 — Feb 19, 2025 - Convert slice operation window to a dockable panel diff --git a/slicer/src/slicer.rs b/slicer/src/slicer.rs index f4fdd7c..b9b1013 100644 --- a/slicer/src/slicer.rs +++ b/slicer/src/slicer.rs @@ -14,7 +14,7 @@ use common::{ use ordered_float::OrderedFloat; use rayon::iter::{IntoParallelIterator, ParallelIterator}; -use crate::{format::FormatSliceResult, mesh::Mesh, segments::Segments1D, Pos}; +use crate::{format::FormatSliceResult, mesh::Mesh, segments::Segments1D}; /// Used to slice a mesh. pub struct Slicer { @@ -40,14 +40,14 @@ pub struct ProgressInner { impl Slicer { /// Creates a new slicer given a slice config and list of models. pub fn new(slice_config: SliceConfig, models: Vec) -> Self { - let max = models.iter().fold(Pos::zeros(), |max, model| { - let f = model.vertices().iter().fold(Pos::zeros(), |max, &f| { - let f = model.transform(&f); - Pos::new(max.x.max(f.x), max.y.max(f.y), max.z.max(f.z)) - }); - Pos::new(max.x.max(f.x), max.y.max(f.y), max.z.max(f.z)) + let max_z = models.iter().fold(0_f32, |max, model| { + let verts = model.vertices().iter(); + let z = verts.fold(0_f32, |max, &f| max.max(model.transform(&f).z)); + max.max(z) }); - let layers = (max.z / slice_config.slice_height).ceil() as u32; + + let layers = (max_z / slice_config.slice_height).ceil() as u32; + let max_layers = (slice_config.platform_size.z / slice_config.slice_height).ceil() as u32; Self { slice_config, @@ -55,7 +55,7 @@ impl Slicer { progress: Progress { inner: Arc::new(ProgressInner { completed: AtomicU32::new(0), - total: layers, + total: layers.min(max_layers), notify: Condvar::new(), last_completed: Mutex::new(0), @@ -77,8 +77,8 @@ impl Slicer { /// Actually runs the slicing operation, it is multithreaded. pub fn slice(&self) -> SliceResult { - let pixels = (self.slice_config.platform_resolution.x - * self.slice_config.platform_resolution.y) as u64; + let platform_resolution = self.slice_config.platform_resolution; + let pixels = (platform_resolution.x * platform_resolution.y) as u64; // A segment contains a reference to all of the triangles it contains. By // splitting the mesh into segments, not all triangles need to be tested @@ -124,7 +124,7 @@ impl Slicer { // across and mark that as an intersection to then be run-length // encoded. There is probably a better polygon filling algo, but // this one works surprisingly fast. - for y in 0..self.slice_config.platform_resolution.y { + for y in 0..platform_resolution.y { let yf = y as f32; let mut intersections = segments .iter() @@ -155,14 +155,14 @@ impl Slicer { depth += (dir as i32) * 2 - 1; if (depth == 0) ^ (prev_depth == 0) { - filtered.push(pos); + filtered.push(pos.clamp(0.0, platform_resolution.x as f32)); } } // Convert the intersections into runs of white pixels to be // encoded into the layer for span in filtered.chunks_exact(2) { - let y_offset = (self.slice_config.platform_resolution.x * y) as u64; + let y_offset = (platform_resolution.x * y) as u64; let a = span[0].round() as u64; let b = span[1].round() as u64;