Slice into generic image buffer
While it does compile, as all images are stored before being encoded, slicing a 600 layer model would use about 25 gb of memory. I'll fix that in the next commit.
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -1033,6 +1033,9 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"nalgebra",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
@@ -2408,13 +2411,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nalgebra-macros"
|
name = "nalgebra-macros"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998"
|
checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
3
TODO.md
3
TODO.md
@@ -27,8 +27,7 @@
|
|||||||
- [ ] 0-pad slice preview layer display so its width doesn't change as you move the slider
|
- [ ] 0-pad slice preview layer display so its width doesn't change as you move the slider
|
||||||
- [ ] Preload layer 1 in slice preview
|
- [ ] Preload layer 1 in slice preview
|
||||||
- [x] Better camera movement (left click to orbit, right click to change orbit point)
|
- [x] Better camera movement (left click to orbit, right click to change orbit point)
|
||||||
- [ ] Don't crash when object is outside bounds
|
- [ ] Don't crash when slicing an object outside of bounds
|
||||||
- [ ] Change centerpoint of model to be at z=0
|
|
||||||
- [x] Add support for loading .obj files
|
- [x] Add support for loading .obj files
|
||||||
- [x] Move call to slicer into app from top_bar
|
- [x] Move call to slicer into app from top_bar
|
||||||
- [ ] Determine which side is the front of the printer
|
- [ ] Determine which side is the front of the printer
|
||||||
|
@@ -6,3 +6,4 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
nalgebra = "0.32.6"
|
||||||
|
109
common/src/image.rs
Normal file
109
common/src/image.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use nalgebra::Vector2;
|
||||||
|
|
||||||
|
use crate::misc::Run;
|
||||||
|
|
||||||
|
/// A fast grayscale image buffer
|
||||||
|
pub struct Image {
|
||||||
|
size: Vector2<usize>,
|
||||||
|
data: Vec<u8>,
|
||||||
|
idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn blank(width: usize, height: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
size: Vector2::new(width, height),
|
||||||
|
data: vec![0; width * height],
|
||||||
|
idx: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_run(&mut self, length: usize, value: u8) {
|
||||||
|
self.data[self.idx..self.idx + length].fill(value);
|
||||||
|
self.idx += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pixel(&self, x: usize, y: usize) -> u8 {
|
||||||
|
let idx = self.size.x * y + x;
|
||||||
|
self.data[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pixel(&mut self, x: usize, y: usize, val: u8) {
|
||||||
|
let idx = self.size.x * y + x;
|
||||||
|
self.data[idx] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blur(&mut self, sigma: f32) {
|
||||||
|
// Generate kernel
|
||||||
|
let kernel_size = (4.0 * sigma) as usize;
|
||||||
|
let half_kernel_size = kernel_size / 2;
|
||||||
|
|
||||||
|
let mut kernel = vec![0.0; kernel_size];
|
||||||
|
for x in 0..kernel_size {
|
||||||
|
kernel[x] = gaussian((x - half_kernel_size) as f32, sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blur image horizontally
|
||||||
|
for y in 0..self.size.y {
|
||||||
|
for x in 0..self.size.x {
|
||||||
|
let sum = (x.saturating_sub(half_kernel_size)
|
||||||
|
..(x + half_kernel_size).min(self.size.x))
|
||||||
|
.map(|i| self.get_pixel(i, y) as f32 * kernel[i + half_kernel_size])
|
||||||
|
.sum::<f32>();
|
||||||
|
self.set_pixel(x, y, (sum / kernel_size as f32) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blur image vertically
|
||||||
|
for x in 0..self.size.x {
|
||||||
|
for y in 0..self.size.y {
|
||||||
|
let sum = (y.saturating_sub(half_kernel_size)
|
||||||
|
..(y + half_kernel_size).min(self.size.y))
|
||||||
|
.map(|i| self.get_pixel(i, y) as f32 * kernel[i + half_kernel_size])
|
||||||
|
.sum::<f32>();
|
||||||
|
self.set_pixel(x, y, (sum / kernel_size as f32) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Turn into iterator
|
||||||
|
pub fn runs(&self) -> Vec<Run> {
|
||||||
|
let mut last = (self.data[0], 0);
|
||||||
|
let mut runs = Vec::new();
|
||||||
|
|
||||||
|
let size = (self.size.x * self.size.y) as u64;
|
||||||
|
for i in 0..size {
|
||||||
|
let val = self.data[i as usize];
|
||||||
|
|
||||||
|
if val != last.0 {
|
||||||
|
runs.push(Run {
|
||||||
|
length: i - last.1,
|
||||||
|
value: last.0,
|
||||||
|
});
|
||||||
|
last = (val, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if last.1 + 1 != size {
|
||||||
|
runs.push(Run {
|
||||||
|
length: size - last.1,
|
||||||
|
value: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
runs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&self) -> &[u8] {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(self) -> Vec<u8> {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gaussian(x: f32, sigma: f32) -> f32 {
|
||||||
|
const ROOT_TWO_PI: f32 = 2.50662827463100050242;
|
||||||
|
(x.powi(2) / (2.0 * sigma.powi(2))).exp() / (sigma * ROOT_TWO_PI)
|
||||||
|
}
|
@@ -1 +1,4 @@
|
|||||||
|
pub mod config;
|
||||||
|
pub mod image;
|
||||||
|
pub mod misc;
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
|
11
common/src/misc.rs
Normal file
11
common/src/misc.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use crate::{config::SliceConfig, image::Image};
|
||||||
|
|
||||||
|
pub struct SliceResult<'a> {
|
||||||
|
pub layers: Vec<Image>,
|
||||||
|
pub slice_config: &'a SliceConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Run {
|
||||||
|
pub length: u64,
|
||||||
|
pub value: u8,
|
||||||
|
}
|
@@ -1,3 +1,5 @@
|
|||||||
|
use common::misc::Run;
|
||||||
|
|
||||||
use crate::layer_content::calculate_checksum;
|
use crate::layer_content::calculate_checksum;
|
||||||
|
|
||||||
pub struct LayerEncoder {
|
pub struct LayerEncoder {
|
||||||
@@ -11,11 +13,6 @@ pub struct LayerDecoder<'a> {
|
|||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Run {
|
|
||||||
pub length: u64,
|
|
||||||
pub value: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayerEncoder {
|
impl LayerEncoder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
|
|
||||||
use common::serde::{Deserializer, Serializer};
|
use common::{
|
||||||
|
misc::SliceResult,
|
||||||
|
serde::{Deserializer, Serializer},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{HeaderInfo, LayerContent, ENDING_STRING};
|
use crate::{HeaderInfo, LayerContent, LayerEncoder, ENDING_STRING};
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub header: HeaderInfo,
|
pub header: HeaderInfo,
|
||||||
@@ -13,6 +16,81 @@ impl File {
|
|||||||
pub fn new(header: HeaderInfo, layers: Vec<LayerContent>) -> Self {
|
pub fn new(header: HeaderInfo, layers: Vec<LayerContent>) -> Self {
|
||||||
Self { header, layers }
|
Self { header, layers }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_slice_result(result: SliceResult) -> Self {
|
||||||
|
let slice_config = result.slice_config;
|
||||||
|
let layers = result
|
||||||
|
.layers
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, layer)| {
|
||||||
|
let mut encoder = LayerEncoder::new();
|
||||||
|
|
||||||
|
for run in layer.runs() {
|
||||||
|
encoder.add_run(run.length, run.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (data, checksum) = encoder.finish();
|
||||||
|
let layer_exposure = if (idx as u32) < slice_config.first_layers {
|
||||||
|
&slice_config.first_exposure_config
|
||||||
|
} else {
|
||||||
|
&slice_config.exposure_config
|
||||||
|
};
|
||||||
|
|
||||||
|
LayerContent {
|
||||||
|
data,
|
||||||
|
checksum,
|
||||||
|
layer_position_z: slice_config.slice_height * (idx + 1) as f32,
|
||||||
|
|
||||||
|
layer_exposure_time: layer_exposure.exposure_time,
|
||||||
|
lift_distance: layer_exposure.lift_distance,
|
||||||
|
lift_speed: layer_exposure.lift_speed,
|
||||||
|
retract_distance: layer_exposure.retract_distance,
|
||||||
|
retract_speed: layer_exposure.retract_speed,
|
||||||
|
pause_position_z: slice_config.platform_size.z,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let layer_time = slice_config.exposure_config.exposure_time
|
||||||
|
+ slice_config.exposure_config.lift_distance / slice_config.exposure_config.lift_speed;
|
||||||
|
let bottom_layer_time = slice_config.first_exposure_config.exposure_time
|
||||||
|
+ slice_config.first_exposure_config.lift_distance
|
||||||
|
/ slice_config.first_exposure_config.lift_speed;
|
||||||
|
let total_time = (layers.len() as u32 - slice_config.first_layers) as f32 * layer_time
|
||||||
|
+ slice_config.first_layers as f32 * bottom_layer_time;
|
||||||
|
|
||||||
|
Self::new(
|
||||||
|
HeaderInfo {
|
||||||
|
x_resolution: slice_config.platform_resolution.x as u16,
|
||||||
|
y_resolution: slice_config.platform_resolution.y as u16,
|
||||||
|
x_size: slice_config.platform_size.x,
|
||||||
|
y_size: slice_config.platform_size.y,
|
||||||
|
|
||||||
|
layer_count: layers.len() as u32,
|
||||||
|
printing_time: total_time as u32,
|
||||||
|
layer_thickness: slice_config.slice_height,
|
||||||
|
bottom_layers: slice_config.first_layers,
|
||||||
|
transition_layers: slice_config.first_layers as u16 + 1,
|
||||||
|
|
||||||
|
exposure_time: slice_config.exposure_config.exposure_time,
|
||||||
|
lift_distance: slice_config.exposure_config.lift_distance,
|
||||||
|
lift_speed: slice_config.exposure_config.lift_speed,
|
||||||
|
retract_distance: slice_config.exposure_config.retract_distance,
|
||||||
|
retract_speed: slice_config.exposure_config.retract_speed,
|
||||||
|
|
||||||
|
bottom_exposure_time: slice_config.first_exposure_config.exposure_time,
|
||||||
|
bottom_lift_distance: slice_config.first_exposure_config.lift_distance,
|
||||||
|
bottom_lift_speed: slice_config.first_exposure_config.lift_speed,
|
||||||
|
bottom_retract_distance: slice_config.first_exposure_config.retract_distance,
|
||||||
|
bottom_retract_speed: slice_config.first_exposure_config.retract_speed,
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
layers,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
|
@@ -5,7 +5,7 @@ mod header_info;
|
|||||||
mod layer_content;
|
mod layer_content;
|
||||||
mod preview_image;
|
mod preview_image;
|
||||||
|
|
||||||
pub use encoded_layer::{LayerDecoder, LayerEncoder, Run};
|
pub use encoded_layer::{LayerDecoder, LayerEncoder};
|
||||||
pub use file::File;
|
pub use file::File;
|
||||||
pub use header_info::HeaderInfo;
|
pub use header_info::HeaderInfo;
|
||||||
pub use layer_content::LayerContent;
|
pub use layer_content::LayerContent;
|
||||||
|
@@ -6,7 +6,8 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use goo_format::{File, LayerDecoder, PreviewImage, Run};
|
use common::misc::Run;
|
||||||
|
use goo_format::{File, LayerDecoder, PreviewImage};
|
||||||
use image::RgbImage;
|
use image::RgbImage;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
bytemuck = "1.16.1"
|
bytemuck = "1.16.1"
|
||||||
|
clone-macro = "0.1.0"
|
||||||
eframe = { version = "0.27.2", features = ["wgpu"] }
|
eframe = { version = "0.27.2", features = ["wgpu"] }
|
||||||
egui = "0.27.2"
|
egui = "0.27.2"
|
||||||
egui-wgpu = "0.27.2"
|
egui-wgpu = "0.27.2"
|
||||||
@@ -18,4 +19,3 @@ wgpu = "0.19.4"
|
|||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
goo_format = { path = "../goo_format" }
|
goo_format = { path = "../goo_format" }
|
||||||
slicer = { path = "../slicer" }
|
slicer = { path = "../slicer" }
|
||||||
clone-macro = "0.1.0"
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Mutex, RwLock}, thread, time::Instant
|
sync::{Arc, Mutex, RwLock},
|
||||||
|
thread,
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clone_macro::clone;
|
use clone_macro::clone;
|
||||||
@@ -7,8 +9,8 @@ use egui::{CentralPanel, Frame, Sense};
|
|||||||
use egui_wgpu::Callback;
|
use egui_wgpu::Callback;
|
||||||
use nalgebra::{Vector2, Vector3};
|
use nalgebra::{Vector2, Vector3};
|
||||||
use slicer::{
|
use slicer::{
|
||||||
config::{ExposureConfig, SliceConfig},
|
slicer::{Progress as SliceProgress, Slicer},
|
||||||
slicer::{Progress as SliceProgress, Slicer}, Pos,
|
Pos,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -18,6 +20,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
windows::{self, Windows},
|
windows::{self, Windows},
|
||||||
};
|
};
|
||||||
|
use common::config::{ExposureConfig, SliceConfig};
|
||||||
use goo_format::File as GooFile;
|
use goo_format::File as GooFile;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@@ -81,7 +84,7 @@ impl App {
|
|||||||
self.slice_progress = Some(slicer.progress());
|
self.slice_progress = Some(slicer.progress());
|
||||||
|
|
||||||
thread::spawn(clone!([{ self.slice_result } as slice_result], move || {
|
thread::spawn(clone!([{ self.slice_result } as slice_result], move || {
|
||||||
let goo = slicer.slice();
|
let goo = GooFile::from_slice_result(slicer.slice());
|
||||||
slice_result.lock().unwrap().replace(SliceResult {
|
slice_result.lock().unwrap().replace(SliceResult {
|
||||||
goo,
|
goo,
|
||||||
slice_preview_layer: 0,
|
slice_preview_layer: 0,
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
use eframe::Frame;
|
use eframe::Frame;
|
||||||
use egui::{Context, DragValue, Grid, Ui, Window};
|
use egui::{Context, DragValue, Grid, Ui, Window};
|
||||||
use slicer::config::ExposureConfig;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
components::{vec2_dragger, vec3_dragger},
|
components::{vec2_dragger, vec3_dragger},
|
||||||
};
|
};
|
||||||
|
use common::config::ExposureConfig;
|
||||||
|
|
||||||
pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) {
|
pub fn ui(app: &mut App, ctx: &Context, _frame: &mut Frame) {
|
||||||
Window::new("Slice Config")
|
Window::new("Slice Config")
|
||||||
|
@@ -8,10 +8,10 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
nalgebra = "0.32.6"
|
nalgebra = "0.32.6"
|
||||||
|
obj-rs = "0.7.1"
|
||||||
ordered-float = "4.2.0"
|
ordered-float = "4.2.0"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
stl_io = "0.7.0"
|
stl_io = "0.7.0"
|
||||||
|
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
goo_format = { path = "../goo_format" }
|
goo_format = { path = "../goo_format" }
|
||||||
obj-rs = "0.7.1"
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
pub mod config;
|
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod slicer;
|
pub mod slicer;
|
||||||
|
|
||||||
|
@@ -6,15 +6,14 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::serde::DynamicSerializer;
|
|
||||||
use nalgebra::{Vector2, Vector3};
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
use slicer::{
|
use common::{
|
||||||
config::{ExposureConfig, SliceConfig},
|
config::{ExposureConfig, SliceConfig},
|
||||||
mesh::load_mesh,
|
serde::DynamicSerializer,
|
||||||
slicer::Slicer,
|
|
||||||
Pos,
|
|
||||||
};
|
};
|
||||||
|
use goo_format::File as GooFile;
|
||||||
|
use slicer::{mesh::load_mesh, slicer::Slicer, Pos};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
const FILE_PATH: &str = "teapot.stl";
|
const FILE_PATH: &str = "teapot.stl";
|
||||||
@@ -67,7 +66,7 @@ fn main() -> Result<()> {
|
|||||||
let slicer = Slicer::new(slice_config.clone(), mesh);
|
let slicer = Slicer::new(slice_config.clone(), mesh);
|
||||||
let progress = slicer.progress();
|
let progress = slicer.progress();
|
||||||
|
|
||||||
let goo = thread::spawn(move || slicer.slice());
|
let goo = thread::spawn(move || GooFile::from_slice_result(slicer.slice()));
|
||||||
|
|
||||||
let mut completed = 0;
|
let mut completed = 0;
|
||||||
while completed < progress.total() {
|
while completed < progress.total() {
|
||||||
|
@@ -24,6 +24,7 @@ impl Mesh {
|
|||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
|
|
||||||
for face in &self.faces {
|
for face in &self.faces {
|
||||||
|
// todo: just transform the plane with the inverse transformation matrix
|
||||||
let v0 = self.transform(&self.vertices[face[0] as usize]);
|
let v0 = self.transform(&self.vertices[face[0] as usize]);
|
||||||
let v1 = self.transform(&self.vertices[face[1] as usize]);
|
let v1 = self.transform(&self.vertices[face[1] as usize]);
|
||||||
let v2 = self.transform(&self.vertices[face[2] as usize]);
|
let v2 = self.transform(&self.vertices[face[2] as usize]);
|
||||||
|
@@ -6,11 +6,11 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use common::{config::SliceConfig, image::Image, misc::SliceResult};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::{config::SliceConfig, mesh::Mesh, Pos};
|
use crate::{mesh::Mesh, Pos};
|
||||||
use goo_format::{File as GooFile, HeaderInfo, LayerContent, LayerEncoder};
|
|
||||||
|
|
||||||
pub struct Slicer {
|
pub struct Slicer {
|
||||||
slice_config: SliceConfig,
|
slice_config: SliceConfig,
|
||||||
@@ -58,7 +58,7 @@ impl Slicer {
|
|||||||
self.progress.clone()
|
self.progress.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice(&self) -> GooFile {
|
pub fn slice(&self) -> SliceResult {
|
||||||
let (slice_config, model) = (&self.slice_config, &self.model);
|
let (slice_config, model) = (&self.slice_config, &self.model);
|
||||||
let layers = (0..self.progress.total)
|
let layers = (0..self.progress.total)
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
@@ -98,83 +98,30 @@ impl Slicer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut encoder = LayerEncoder::new();
|
let mut image = Image::blank(
|
||||||
|
self.slice_config.platform_resolution.x as usize,
|
||||||
|
self.slice_config.platform_resolution.y as usize,
|
||||||
|
);
|
||||||
|
|
||||||
let mut last = 0;
|
let mut last = 0;
|
||||||
for (start, end) in out {
|
for (start, end) in out {
|
||||||
if start > last {
|
if start > last {
|
||||||
encoder.add_run(start - last, 0);
|
image.add_run((start - last) as usize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(end >= start, "End precedes start in layer {layer}");
|
assert!(end >= start, "End precedes start in layer {layer}");
|
||||||
encoder.add_run(end - start, 255);
|
image.add_run((end - start) as usize, 255);
|
||||||
last = end;
|
last = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
let image_size = slice_config.platform_resolution.x as u64
|
image
|
||||||
* slice_config.platform_resolution.y as u64;
|
|
||||||
encoder.add_run(image_size - last, 0);
|
|
||||||
|
|
||||||
let (data, checksum) = encoder.finish();
|
|
||||||
let layer_exposure = if layer < slice_config.first_layers {
|
|
||||||
&slice_config.first_exposure_config
|
|
||||||
} else {
|
|
||||||
&slice_config.exposure_config
|
|
||||||
};
|
|
||||||
|
|
||||||
LayerContent {
|
|
||||||
data,
|
|
||||||
checksum,
|
|
||||||
layer_position_z: slice_config.slice_height * (layer + 1) as f32,
|
|
||||||
|
|
||||||
layer_exposure_time: layer_exposure.exposure_time,
|
|
||||||
lift_distance: layer_exposure.lift_distance,
|
|
||||||
lift_speed: layer_exposure.lift_speed,
|
|
||||||
retract_distance: layer_exposure.retract_distance,
|
|
||||||
retract_speed: layer_exposure.retract_speed,
|
|
||||||
pause_position_z: slice_config.platform_size.z,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let layer_time = slice_config.exposure_config.exposure_time
|
SliceResult {
|
||||||
+ slice_config.exposure_config.lift_distance / slice_config.exposure_config.lift_speed;
|
|
||||||
let bottom_layer_time = slice_config.first_exposure_config.exposure_time
|
|
||||||
+ slice_config.first_exposure_config.lift_distance
|
|
||||||
/ slice_config.first_exposure_config.lift_speed;
|
|
||||||
let total_time = (layers.len() as u32 - slice_config.first_layers) as f32 * layer_time
|
|
||||||
+ slice_config.first_layers as f32 * bottom_layer_time;
|
|
||||||
|
|
||||||
GooFile::new(
|
|
||||||
HeaderInfo {
|
|
||||||
x_resolution: slice_config.platform_resolution.x as u16,
|
|
||||||
y_resolution: slice_config.platform_resolution.y as u16,
|
|
||||||
x_size: slice_config.platform_size.x,
|
|
||||||
y_size: slice_config.platform_size.y,
|
|
||||||
|
|
||||||
layer_count: layers.len() as u32,
|
|
||||||
printing_time: total_time as u32,
|
|
||||||
layer_thickness: slice_config.slice_height,
|
|
||||||
bottom_layers: slice_config.first_layers,
|
|
||||||
transition_layers: slice_config.first_layers as u16 + 1,
|
|
||||||
|
|
||||||
exposure_time: slice_config.exposure_config.exposure_time,
|
|
||||||
lift_distance: slice_config.exposure_config.lift_distance,
|
|
||||||
lift_speed: slice_config.exposure_config.lift_speed,
|
|
||||||
retract_distance: slice_config.exposure_config.retract_distance,
|
|
||||||
retract_speed: slice_config.exposure_config.retract_speed,
|
|
||||||
|
|
||||||
bottom_exposure_time: slice_config.first_exposure_config.exposure_time,
|
|
||||||
bottom_lift_distance: slice_config.first_exposure_config.lift_distance,
|
|
||||||
bottom_lift_speed: slice_config.first_exposure_config.lift_speed,
|
|
||||||
bottom_retract_distance: slice_config.first_exposure_config.retract_distance,
|
|
||||||
bottom_retract_speed: slice_config.first_exposure_config.retract_speed,
|
|
||||||
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
layers,
|
layers,
|
||||||
)
|
slice_config: &self.slice_config,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user