Cleanup line supports
This commit is contained in:
@@ -1,13 +1,18 @@
|
|||||||
use egui::{Context, Ui};
|
use egui::{Context, Ui};
|
||||||
use slicer::supports::line::generate_line_supports;
|
use slicer::supports::line::LineSupportGenerator;
|
||||||
|
|
||||||
use crate::{app::App, ui::components::dragger};
|
use crate::{app::App, ui::components::dragger};
|
||||||
|
|
||||||
pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
||||||
if ui.button("Generate").clicked() {
|
if ui.button("Generate").clicked() {
|
||||||
app.state.line_support_debug = Vec::new();
|
app.state.line_support_debug = Vec::new();
|
||||||
|
let generator = LineSupportGenerator::new(
|
||||||
|
&app.state.line_support_config,
|
||||||
|
app.slice_config.platform_size,
|
||||||
|
);
|
||||||
|
|
||||||
for mesh in app.meshes.read().iter() {
|
for mesh in app.meshes.read().iter() {
|
||||||
let supports = generate_line_supports(&mesh.mesh, &app.state.line_support_config);
|
let supports = generator.generate_line_supports(&mesh.mesh);
|
||||||
app.state.line_support_debug.extend(supports);
|
app.state.line_support_debug.extend(supports);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,4 +40,11 @@ pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
|||||||
&mut app.state.line_support_config.min_angle,
|
&mut app.state.line_support_config.min_angle,
|
||||||
|x| x.speed(0.01),
|
|x| x.speed(0.01),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
dragger(
|
||||||
|
ui,
|
||||||
|
"Face Support Spacing",
|
||||||
|
&mut app.state.line_support_config.face_support_spacing,
|
||||||
|
|x| x.speed(0.1),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ use std::{fs::File, io::BufReader, path::Path};
|
|||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
|
|
||||||
use slicer::{mesh::load_mesh, segments::Segments};
|
use slicer::{mesh::load_mesh, segments::Segments1D};
|
||||||
|
|
||||||
pub fn bench(c: &mut Criterion) {
|
pub fn bench(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("Mesh Intersections");
|
let mut group = c.benchmark_group("Mesh Intersections");
|
||||||
@@ -11,7 +11,7 @@ pub fn bench(c: &mut Criterion) {
|
|||||||
for mesh_name in ["teapot.stl", "dragon.stl", "david.stl"] {
|
for mesh_name in ["teapot.stl", "dragon.stl", "david.stl"] {
|
||||||
let mut file = BufReader::new(File::open(parent.join(mesh_name)).unwrap());
|
let mut file = BufReader::new(File::open(parent.join(mesh_name)).unwrap());
|
||||||
let mesh = load_mesh(&mut file, "stl").unwrap();
|
let mesh = load_mesh(&mut file, "stl").unwrap();
|
||||||
let segments = Segments::from_mesh(&mesh, 100);
|
let segments = Segments1D::from_mesh(&mesh, 100);
|
||||||
|
|
||||||
group.bench_with_input(BenchmarkId::new("Linier", mesh_name), &mesh, |b, i| {
|
group.bench_with_input(BenchmarkId::new("Linier", mesh_name), &mesh, |b, i| {
|
||||||
b.iter(|| i.intersect_plane(0.0))
|
b.iter(|| i.intersect_plane(0.0))
|
||||||
|
3
slicer/src/segments/mod.rs
Normal file
3
slicer/src/segments/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod segments_1d;
|
||||||
|
|
||||||
|
pub use segments_1d::Segments1D;
|
@@ -6,7 +6,7 @@ use crate::mesh::Mesh;
|
|||||||
/// along the slicing axis and adding references to all the triangles that
|
/// along the slicing axis and adding references to all the triangles that
|
||||||
/// overlap each segment, to slice a layer, you don't need to loop through every
|
/// overlap each segment, to slice a layer, you don't need to loop through every
|
||||||
/// triangle in the mesh to find all intersecting faces.
|
/// triangle in the mesh to find all intersecting faces.
|
||||||
pub struct Segments {
|
pub struct Segments1D {
|
||||||
start_height: f32,
|
start_height: f32,
|
||||||
layer_height: f32,
|
layer_height: f32,
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ pub struct Segments {
|
|||||||
transformed_points: Vec<Vector3<f32>>,
|
transformed_points: Vec<Vector3<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segments {
|
impl Segments1D {
|
||||||
/// Creates a new Segments structure from a given mesh and segment count.
|
/// Creates a new Segments structure from a given mesh and segment count.
|
||||||
pub fn from_mesh(mesh: &Mesh, layer_count: usize) -> Self {
|
pub fn from_mesh(mesh: &Mesh, layer_count: usize) -> Self {
|
||||||
let (min, max) = mesh.minmax_point();
|
let (min, max) = mesh.minmax_point();
|
@@ -13,7 +13,7 @@ use common::{
|
|||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::{mesh::Mesh, segments::Segments, Pos};
|
use crate::{mesh::Mesh, segments::Segments1D, Pos};
|
||||||
|
|
||||||
/// Used to slice a mesh.
|
/// Used to slice a mesh.
|
||||||
pub struct Slicer {
|
pub struct Slicer {
|
||||||
@@ -80,7 +80,7 @@ impl Slicer {
|
|||||||
let segments = self
|
let segments = self
|
||||||
.models
|
.models
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| Segments::from_mesh(x, 100))
|
.map(|x| Segments1D::from_mesh(x, 100))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let layers = (0..self.progress.total)
|
let layers = (0..self.progress.total)
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
use std::{collections::HashSet, f32::consts::PI};
|
use std::{collections::HashSet, f32::consts::PI};
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
use crate::{half_edge::HalfEdgeMesh, mesh::Mesh};
|
use crate::{half_edge::HalfEdgeMesh, mesh::Mesh};
|
||||||
|
|
||||||
|
pub struct LineSupportGenerator<'a> {
|
||||||
|
config: &'a LineSupportConfig,
|
||||||
|
bed_size: Vector3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LineSupport {
|
pub struct LineSupport {
|
||||||
pub start: Vector3<f32>,
|
pub start: Vector3<f32>,
|
||||||
pub end: Vector3<f32>,
|
pub end: Vector3<f32>,
|
||||||
@@ -14,34 +19,30 @@ pub struct LineSupportConfig {
|
|||||||
pub max_origin_normal_z: f32,
|
pub max_origin_normal_z: f32,
|
||||||
pub max_neighbor_z_diff: f32,
|
pub max_neighbor_z_diff: f32,
|
||||||
pub min_angle: f32,
|
pub min_angle: f32,
|
||||||
|
pub face_support_spacing: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LineSupportConfig {
|
impl<'a> LineSupportGenerator<'a> {
|
||||||
fn default() -> Self {
|
pub fn new(config: &'a LineSupportConfig, bed_size: Vector3<f32>) -> Self {
|
||||||
Self {
|
Self { config, bed_size }
|
||||||
max_origin_normal_z: 0.0,
|
|
||||||
max_neighbor_z_diff: -0.01,
|
|
||||||
min_angle: PI / 4.0,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_line_supports(mesh: &Mesh, config: &LineSupportConfig) -> Vec<[Vector3<f32>; 2]> {
|
pub fn generate_line_supports(&self, mesh: &Mesh) -> Vec<[Vector3<f32>; 2]> {
|
||||||
// let half_edge_mesh = HalfEdgeMesh::new(mesh);
|
// let half_edge_mesh = HalfEdgeMesh::new(mesh);
|
||||||
|
|
||||||
// let points = detect_point_overhangs(mesh, &half_edge_mesh, config);
|
// let points = detect_point_overhangs(mesh, &half_edge_mesh, config);
|
||||||
let points = detect_face_overhangs(mesh, config);
|
let points = self.detect_face_overhangs(mesh);
|
||||||
println!("Found {} overhangs", points.len());
|
println!("Found {} overhangs", points.len());
|
||||||
|
|
||||||
points
|
points
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find all points that are both lower than their surrounding points and have down facing normals
|
/// Find all points that are both lower than their surrounding points and have down facing normals
|
||||||
fn detect_point_overhangs(
|
fn detect_point_overhangs(
|
||||||
|
&self,
|
||||||
mesh: &Mesh,
|
mesh: &Mesh,
|
||||||
half_edge: &HalfEdgeMesh,
|
half_edge: &HalfEdgeMesh,
|
||||||
config: &LineSupportConfig,
|
) -> Vec<[Vector3<f32>; 2]> {
|
||||||
) -> Vec<[Vector3<f32>; 2]> {
|
|
||||||
let mut overhangs = Vec::new();
|
let mut overhangs = Vec::new();
|
||||||
let mut seen = HashSet::new();
|
let mut seen = HashSet::new();
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ fn detect_point_overhangs(
|
|||||||
|
|
||||||
// Ignore points that are not on the bottom of the mesh
|
// Ignore points that are not on the bottom of the mesh
|
||||||
let origin_normal = mesh.transform_normal(&normals[origin.face as usize]);
|
let origin_normal = mesh.transform_normal(&normals[origin.face as usize]);
|
||||||
if origin_normal.z >= config.max_origin_normal_z {
|
if origin_normal.z >= self.config.max_origin_normal_z {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,37 +66,63 @@ fn detect_point_overhangs(
|
|||||||
let neighbors = half_edge.connected_vertices(edge as u32);
|
let neighbors = half_edge.connected_vertices(edge as u32);
|
||||||
if neighbors.iter().all(|connected| {
|
if neighbors.iter().all(|connected| {
|
||||||
(origin_pos.z - mesh.transform(&vertices[*connected as usize]).z)
|
(origin_pos.z - mesh.transform(&vertices[*connected as usize]).z)
|
||||||
<= config.max_neighbor_z_diff
|
<= self.config.max_neighbor_z_diff
|
||||||
}) {
|
}) {
|
||||||
overhangs.push([origin_pos, origin_normal]);
|
overhangs.push([origin_pos, origin_normal]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overhangs
|
overhangs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_face_overhangs(mesh: &Mesh, config: &LineSupportConfig) -> Vec<[Vector3<f32>; 2]> {
|
fn detect_face_overhangs(&self, mesh: &Mesh) -> Vec<[Vector3<f32>; 2]> {
|
||||||
let mut overhangs = Vec::new();
|
let mut overhangs = Vec::new();
|
||||||
|
|
||||||
let vertices = mesh.vertices();
|
let vertices = mesh.vertices();
|
||||||
for (face, normal) in mesh.faces().iter().zip(mesh.normals().iter()) {
|
let normals = mesh.normals();
|
||||||
|
|
||||||
|
for (face, normal) in normals.iter().enumerate() {
|
||||||
let normal = mesh.transform_normal(&normal);
|
let normal = mesh.transform_normal(&normal);
|
||||||
if normal.z >= config.max_origin_normal_z {
|
if normal.z >= self.config.max_origin_normal_z {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let angle = normal.angle(&Vector3::z());
|
let angle = normal.angle(&Vector3::z());
|
||||||
if angle < config.min_angle {
|
if angle < self.config.min_angle {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let center = face
|
overhangs.push(face);
|
||||||
.iter()
|
|
||||||
.fold(Vector3::zeros(), |acc, &v| acc + vertices[v as usize])
|
|
||||||
/ 3.0;
|
|
||||||
|
|
||||||
overhangs.push([center, normal]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overhangs
|
let x_count = (self.bed_size.x / self.config.face_support_spacing) as i32;
|
||||||
|
let y_count = (self.bed_size.y / self.config.face_support_spacing) as i32;
|
||||||
|
|
||||||
|
for x in 0..x_count {
|
||||||
|
for y in 0..y_count {
|
||||||
|
let pos = Vector2::new(
|
||||||
|
x as f32 * self.config.face_support_spacing,
|
||||||
|
y as f32 * self.config.face_support_spacing,
|
||||||
|
);
|
||||||
|
|
||||||
|
// intersect ray
|
||||||
|
// let intersections =
|
||||||
|
|
||||||
|
// if normal of intersection is facing down then add to overhangs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LineSupportConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
max_origin_normal_z: 0.0,
|
||||||
|
max_neighbor_z_diff: -0.01,
|
||||||
|
min_angle: PI / 4.0,
|
||||||
|
face_support_spacing: 10.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user