Cleanup line supports
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
use egui::{Context, Ui};
|
||||
use slicer::supports::line::generate_line_supports;
|
||||
use slicer::supports::line::LineSupportGenerator;
|
||||
|
||||
use crate::{app::App, ui::components::dragger};
|
||||
|
||||
pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
||||
if ui.button("Generate").clicked() {
|
||||
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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -35,4 +40,11 @@ pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
||||
&mut app.state.line_support_config.min_angle,
|
||||
|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 slicer::{mesh::load_mesh, segments::Segments};
|
||||
use slicer::{mesh::load_mesh, segments::Segments1D};
|
||||
|
||||
pub fn bench(c: &mut Criterion) {
|
||||
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"] {
|
||||
let mut file = BufReader::new(File::open(parent.join(mesh_name)).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| {
|
||||
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
|
||||
/// overlap each segment, to slice a layer, you don't need to loop through every
|
||||
/// triangle in the mesh to find all intersecting faces.
|
||||
pub struct Segments {
|
||||
pub struct Segments1D {
|
||||
start_height: f32,
|
||||
layer_height: f32,
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct Segments {
|
||||
transformed_points: Vec<Vector3<f32>>,
|
||||
}
|
||||
|
||||
impl Segments {
|
||||
impl Segments1D {
|
||||
/// Creates a new Segments structure from a given mesh and segment count.
|
||||
pub fn from_mesh(mesh: &Mesh, layer_count: usize) -> Self {
|
||||
let (min, max) = mesh.minmax_point();
|
@@ -13,7 +13,7 @@ use common::{
|
||||
use ordered_float::OrderedFloat;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::{mesh::Mesh, segments::Segments, Pos};
|
||||
use crate::{mesh::Mesh, segments::Segments1D, Pos};
|
||||
|
||||
/// Used to slice a mesh.
|
||||
pub struct Slicer {
|
||||
@@ -80,7 +80,7 @@ impl Slicer {
|
||||
let segments = self
|
||||
.models
|
||||
.iter()
|
||||
.map(|x| Segments::from_mesh(x, 100))
|
||||
.map(|x| Segments1D::from_mesh(x, 100))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let layers = (0..self.progress.total)
|
||||
|
@@ -1,9 +1,14 @@
|
||||
use std::{collections::HashSet, f32::consts::PI};
|
||||
|
||||
use nalgebra::Vector3;
|
||||
use nalgebra::{Vector2, Vector3};
|
||||
|
||||
use crate::{half_edge::HalfEdgeMesh, mesh::Mesh};
|
||||
|
||||
pub struct LineSupportGenerator<'a> {
|
||||
config: &'a LineSupportConfig,
|
||||
bed_size: Vector3<f32>,
|
||||
}
|
||||
|
||||
pub struct LineSupport {
|
||||
pub start: Vector3<f32>,
|
||||
pub end: Vector3<f32>,
|
||||
@@ -14,6 +19,101 @@ pub struct LineSupportConfig {
|
||||
pub max_origin_normal_z: f32,
|
||||
pub max_neighbor_z_diff: f32,
|
||||
pub min_angle: f32,
|
||||
pub face_support_spacing: f32,
|
||||
}
|
||||
|
||||
impl<'a> LineSupportGenerator<'a> {
|
||||
pub fn new(config: &'a LineSupportConfig, bed_size: Vector3<f32>) -> Self {
|
||||
Self { config, bed_size }
|
||||
}
|
||||
|
||||
pub fn generate_line_supports(&self, mesh: &Mesh) -> Vec<[Vector3<f32>; 2]> {
|
||||
// let half_edge_mesh = HalfEdgeMesh::new(mesh);
|
||||
|
||||
// let points = detect_point_overhangs(mesh, &half_edge_mesh, config);
|
||||
let points = self.detect_face_overhangs(mesh);
|
||||
println!("Found {} overhangs", points.len());
|
||||
|
||||
points
|
||||
}
|
||||
|
||||
/// Find all points that are both lower than their surrounding points and have down facing normals
|
||||
fn detect_point_overhangs(
|
||||
&self,
|
||||
mesh: &Mesh,
|
||||
half_edge: &HalfEdgeMesh,
|
||||
) -> Vec<[Vector3<f32>; 2]> {
|
||||
let mut overhangs = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
let vertices = mesh.vertices();
|
||||
let normals = mesh.normals();
|
||||
|
||||
for edge in 0..half_edge.half_edge_count() {
|
||||
let origin = half_edge.get_edge(edge as u32);
|
||||
if !seen.insert(origin.origin_vertex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore points that are not on the bottom of the mesh
|
||||
let origin_normal = mesh.transform_normal(&normals[origin.face as usize]);
|
||||
if origin_normal.z >= self.config.max_origin_normal_z {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only add to overhangs if the original point is lower than all connected points by one layer
|
||||
let origin_pos = mesh.transform(&vertices[origin.origin_vertex as usize]);
|
||||
let neighbors = half_edge.connected_vertices(edge as u32);
|
||||
if neighbors.iter().all(|connected| {
|
||||
(origin_pos.z - mesh.transform(&vertices[*connected as usize]).z)
|
||||
<= self.config.max_neighbor_z_diff
|
||||
}) {
|
||||
overhangs.push([origin_pos, origin_normal]);
|
||||
}
|
||||
}
|
||||
|
||||
overhangs
|
||||
}
|
||||
|
||||
fn detect_face_overhangs(&self, mesh: &Mesh) -> Vec<[Vector3<f32>; 2]> {
|
||||
let mut overhangs = Vec::new();
|
||||
|
||||
let vertices = mesh.vertices();
|
||||
let normals = mesh.normals();
|
||||
|
||||
for (face, normal) in normals.iter().enumerate() {
|
||||
let normal = mesh.transform_normal(&normal);
|
||||
if normal.z >= self.config.max_origin_normal_z {
|
||||
continue;
|
||||
}
|
||||
|
||||
let angle = normal.angle(&Vector3::z());
|
||||
if angle < self.config.min_angle {
|
||||
continue;
|
||||
}
|
||||
|
||||
overhangs.push(face);
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -22,80 +122,7 @@ impl Default for LineSupportConfig {
|
||||
max_origin_normal_z: 0.0,
|
||||
max_neighbor_z_diff: -0.01,
|
||||
min_angle: PI / 4.0,
|
||||
face_support_spacing: 10.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_line_supports(mesh: &Mesh, config: &LineSupportConfig) -> Vec<[Vector3<f32>; 2]> {
|
||||
// let half_edge_mesh = HalfEdgeMesh::new(mesh);
|
||||
|
||||
// let points = detect_point_overhangs(mesh, &half_edge_mesh, config);
|
||||
let points = detect_face_overhangs(mesh, config);
|
||||
println!("Found {} overhangs", points.len());
|
||||
|
||||
points
|
||||
}
|
||||
|
||||
/// Find all points that are both lower than their surrounding points and have down facing normals
|
||||
fn detect_point_overhangs(
|
||||
mesh: &Mesh,
|
||||
half_edge: &HalfEdgeMesh,
|
||||
config: &LineSupportConfig,
|
||||
) -> Vec<[Vector3<f32>; 2]> {
|
||||
let mut overhangs = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
let vertices = mesh.vertices();
|
||||
let normals = mesh.normals();
|
||||
|
||||
for edge in 0..half_edge.half_edge_count() {
|
||||
let origin = half_edge.get_edge(edge as u32);
|
||||
if !seen.insert(origin.origin_vertex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore points that are not on the bottom of the mesh
|
||||
let origin_normal = mesh.transform_normal(&normals[origin.face as usize]);
|
||||
if origin_normal.z >= config.max_origin_normal_z {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only add to overhangs if the original point is lower than all connected points by one layer
|
||||
let origin_pos = mesh.transform(&vertices[origin.origin_vertex as usize]);
|
||||
let neighbors = half_edge.connected_vertices(edge as u32);
|
||||
if neighbors.iter().all(|connected| {
|
||||
(origin_pos.z - mesh.transform(&vertices[*connected as usize]).z)
|
||||
<= config.max_neighbor_z_diff
|
||||
}) {
|
||||
overhangs.push([origin_pos, origin_normal]);
|
||||
}
|
||||
}
|
||||
|
||||
overhangs
|
||||
}
|
||||
|
||||
fn detect_face_overhangs(mesh: &Mesh, config: &LineSupportConfig) -> Vec<[Vector3<f32>; 2]> {
|
||||
let mut overhangs = Vec::new();
|
||||
|
||||
let vertices = mesh.vertices();
|
||||
for (face, normal) in mesh.faces().iter().zip(mesh.normals().iter()) {
|
||||
let normal = mesh.transform_normal(&normal);
|
||||
if normal.z >= config.max_origin_normal_z {
|
||||
continue;
|
||||
}
|
||||
|
||||
let angle = normal.angle(&Vector3::z());
|
||||
if angle < config.min_angle {
|
||||
continue;
|
||||
}
|
||||
|
||||
let center = face
|
||||
.iter()
|
||||
.fold(Vector3::zeros(), |acc, &v| acc + vertices[v as usize])
|
||||
/ 3.0;
|
||||
|
||||
overhangs.push([center, normal]);
|
||||
}
|
||||
|
||||
overhangs
|
||||
}
|
||||
|
Reference in New Issue
Block a user