Cleanup line supports

This commit is contained in:
Connor Slade
2024-08-03 22:15:34 -04:00
parent 1b72a6ea52
commit c7c8cf0e2e
6 changed files with 125 additions and 83 deletions

View File

@@ -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),
);
}

View File

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

View File

@@ -0,0 +1,3 @@
pub mod segments_1d;
pub use segments_1d::Segments1D;

View File

@@ -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();

View File

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

View File

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