Don't produce incorrect results when models extend beyond build volume

This commit is contained in:
Connor Slade
2025-04-04 21:42:27 -04:00
parent 5fc58dc767
commit 478023da66
2 changed files with 18 additions and 14 deletions

View File

@@ -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

View File

@@ -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<Mesh>) -> 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<Layer: EncodableLayer>(&self) -> SliceResult<Layer::Output> {
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;