feat: testing some stuff

This commit is contained in:
2024-07-17 01:08:23 +02:00
parent 44b792cc58
commit 0e8479af91
6 changed files with 158 additions and 105 deletions

View File

@@ -1,11 +1,14 @@
use std::iter::empty;
use approx::relative_eq;
use nalgebra::{vector, Vector3};
use nalgebra::{vector, SimdBool, Vector3};
use serde::{Deserialize, Serialize};
use slicer::{line::Line3, slice_rings::slice_rings};
use tsify::Tsify;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::slicer::{
base_slices::create_slices, mesh::Mesh, split_surface::split_surface,
base_slices::create_base_slices, mesh::Mesh, split_surface::split_surface,
trace_surface::trace_surface, triangle::Triangle, FloatValue, SlicerOptions,
};
@@ -36,6 +39,10 @@ pub enum Slice {
#[tsify(type = "Float32Array")]
position: Vec<f32>,
},
Path {
#[tsify(type = "Float32Array")]
position: Vec<f32>,
},
}
#[derive(Tsify, Serialize, Deserialize)]
@@ -95,12 +102,47 @@ pub fn slice(
let slicer_options = SlicerOptions { layer_height };
console_log!("Creating Surfaces");
let surfaces = split_surface(surface_triangles);
let surfaces = split_surface(surface_triangles).into_iter().map(|mesh| {
slice_rings(1, &slicer_options, &mesh)
.flat_map(|mut rings| {
/*let mut rings = rings
.into_iter()
.map(|mut ring| {
ring.points.sort_unstable_by(|a, b| {
a[0].partial_cmp(&b[0]).unwrap_or(std::cmp::Ordering::Equal)
});
ring
})
.collect::<Vec<_>>();*/
rings.sort_unstable_by(|a, b| {
a.points
.first()
.unwrap()
.partial_cmp(b.points.first().unwrap())
.unwrap_or(std::cmp::Ordering::Equal)
});
rings
})
.fold(Vec::<Vector3<FloatValue>>::new(), |mut acc, mut curr| {
if acc
.last()
.zip(curr.points.first())
.zip(curr.points.last())
.map_or(false, |((last, start), end)| {
start.metric_distance(last) > end.metric_distance(last)
})
{
curr.points.reverse();
}
acc.extend(curr.points);
acc
})
});
console_log!("Computing BVH");
let slicable = Mesh::from(slicable_triangles);
console_log!("Creating Slices");
let mut slices = create_slices(&slicer_options, &slicable);
let slices = slice_rings(2, &slicer_options, &slicable);
/*console_log!("Tracing Surfaces");
let a = max_angle.tan();
@@ -114,16 +156,23 @@ pub fn slice(
console_log!("Done");
SliceResult {
slices: slices
.into_iter()
slices: surfaces
.map(|slice| Slice::Ring {
position: slice
.points
.into_iter()
.flat_map(|point| [point.x as f32, point.y as f32, point.z as f32])
.collect(),
})
.chain(surfaces.into_iter().map(|surface| {
/*.chain(slices.flatten().map(|slice| {
Slice::Ring {
position: slice
.points
.into_iter()
.flat_map(|point| [point.x as f32, point.y as f32, point.z as f32])
.collect(),
}
}))*/
/*.chain(surfaces.into_iter().map(|surface| {
Slice::Surface {
position: surface
.triangles
@@ -143,7 +192,7 @@ pub fn slice(
})
.collect(),
}
}))
}))*/
.collect(),
}
}

View File

@@ -1,28 +1,26 @@
use super::{
line::Line3,
mesh::Mesh,
slice_rings::{find_slice_rings, SliceRing},
FloatValue, SlicerOptions,
};
use super::{line::Line3, mesh::Mesh, FloatValue, SlicerOptions};
use crate::console_log;
use bvh::bvh::BvhNode;
#[derive(Debug)]
pub struct BaseSlice {
pub z: FloatValue,
pub d: FloatValue,
pub lines: Vec<Line3>,
}
/// Creates base slices from the geometry, excluding surfaces.
/// The slicse are not sorted or separated into rings.
pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing> {
let layer_count = (slicable.aabb.max.z / options.layer_height).floor() as usize;
let mut rings = vec![];
let mut layer_index = 0;
/// Creates base slices from the geometry
pub fn create_base_slices<'a>(
axis: usize,
options: &'a SlicerOptions,
slicable: &'a Mesh,
) -> impl Iterator<Item = BaseSlice> + 'a {
let layer_count = ((slicable.aabb.max[axis] - slicable.aabb.min[axis]) / options.layer_height)
.floor() as usize;
for i in 0..layer_count {
let layer = i as FloatValue * options.layer_height;
(0..layer_count).map(move |i| {
let layer = i as FloatValue * options.layer_height + slicable.aabb.min[axis];
let mut base_slice = BaseSlice {
z: layer,
d: layer,
lines: vec![],
};
@@ -37,12 +35,12 @@ pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing>
child_r_index,
child_r_aabb,
} => {
assert!(child_l_aabb.min.z <= child_l_aabb.max.z);
assert!(child_r_aabb.min.z <= child_r_aabb.max.z);
if layer >= child_l_aabb.min.z && layer <= child_l_aabb.max.z {
assert!(child_l_aabb.min[axis] <= child_l_aabb.max[axis]);
assert!(child_r_aabb.min[axis] <= child_r_aabb.max[axis]);
if layer >= child_l_aabb.min[axis] && layer <= child_l_aabb.max[axis] {
stack.push(child_l_index);
}
if layer >= child_r_aabb.min.z && layer <= child_r_aabb.max.z {
if layer >= child_r_aabb.min[axis] && layer <= child_r_aabb.max[axis] {
stack.push(child_r_index);
}
}
@@ -51,7 +49,7 @@ pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing>
shape_index,
} => {
slicable.triangles[shape_index]
.intersect_z(layer)
.intersect(layer, axis)
.map(|line| {
base_slice.lines.push(line);
});
@@ -59,8 +57,6 @@ pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing>
}
}
rings.append(&mut find_slice_rings(base_slice, &mut layer_index));
}
rings
base_slice
})
}

View File

@@ -3,68 +3,72 @@ use nalgebra::Vector3;
use crate::console_log;
use super::{base_slices::BaseSlice, FloatValue};
use super::{
base_slices::{create_base_slices, BaseSlice},
mesh::Mesh,
FloatValue, SlicerOptions,
};
#[derive(Debug)]
pub struct SliceRing {
pub z: FloatValue,
pub d: FloatValue,
/// The points of the ring, in clockwise order.
pub points: Vec<Vector3<FloatValue>>,
pub closed: bool,
}
pub fn find_slice_rings(mut slice: BaseSlice, layer_index: &mut u32) -> Vec<SliceRing> {
pub fn slice_rings<'a>(
axis: usize,
options: &'a SlicerOptions,
slicable: &'a Mesh,
) -> impl Iterator<Item = Vec<SliceRing>> + 'a {
let mut layer_index = 0;
create_base_slices(axis, options, slicable)
.map(move |slice| find_slice_rings(axis, slice, &mut layer_index))
}
pub fn find_slice_rings(
axis: usize,
mut slice: BaseSlice,
layer_index: &mut u32,
) -> Vec<SliceRing> {
let axis_a = (axis + 1) % 3;
let axis_b = (axis + 2) % 3;
let mut rings = vec![];
while let Some(line) = slice.lines.pop() {
if relative_eq!(line.start, line.end) {
continue;
}
let mut ring = SliceRing {
z: slice.z,
points: vec![line.start, line.end],
};
let mut right_start = ring.points[0];
let mut right = ring.points[1];
let mut sum_of_edges = (right.x - right_start.x) * (right.y + right_start.y);
let mut right = vec![line.end];
let mut left = vec![line.start];
let mut previous_len = usize::MAX;
let mut done = false;
let mut closed = false;
while !done {
while !closed {
if previous_len == slice.lines.len() {
console_log!(
"Error: Could not close ring {}, d = {}, {} items left.",
layer_index,
ring.points[0].metric_distance(&right),
slice.lines.len()
);
break;
}
previous_len = slice.lines.len();
slice.lines.retain_mut(|line| {
if done {
if closed {
return true;
}
macro_rules! add {
( $point:expr ) => {
if !relative_eq!($point, right_start) {
right_start = right;
right = $point;
ring.points.push(right);
sum_of_edges = (right.x - right_start.x) * (right.y + right_start.y);
done = relative_eq!(ring.points[0], right);
}
};
}
let test = |side: &mut Vec<Vector3<FloatValue>>| {
let last = side.last().unwrap();
let s = relative_eq!(line.start, last);
let e = relative_eq!(line.end, last);
if s && !e {
side.push(line.end);
} else if !s && e {
side.push(line.start);
}
s || e
};
let s = relative_eq!(line.start, right);
let e = relative_eq!(line.end, right);
if s && !e {
add!(line.end);
false
} else if e && !s {
add!(line.start);
if test(&mut left) || test(&mut right) {
closed = relative_eq!(left.last().unwrap(), right.last().unwrap());
false
} else {
true
@@ -72,10 +76,21 @@ pub fn find_slice_rings(mut slice: BaseSlice, layer_index: &mut u32) -> Vec<Slic
})
}
// The end point is duplicate, so not part of the winding order calculation.
if sum_of_edges < 0.0 {
left.reverse();
left.extend(right);
let mut ring = SliceRing {
d: slice.d,
closed,
points: left,
};
if ring.points.windows(2).fold(0.0, |acc, curr| {
acc + (curr[1][axis_a] - curr[0][axis_a]) * (curr[1][axis_b] + curr[0][axis_b])
}) < 0.0
{
ring.points.reverse();
}
rings.push(ring);
*layer_index += 1;
}

View File

@@ -73,26 +73,24 @@ impl Triangle {
a && b || a && c || b && c
}
pub fn intersect_z(&self, z: FloatValue) -> Option<Line3> {
pub fn intersect(&self, value: FloatValue, axis: usize) -> Option<Line3> {
let mut intersection = Vec::<Vector3<FloatValue>>::with_capacity(3);
let mut last = &self.c;
for point in [self.a, self.b, self.c].iter() {
if relative_eq!(point.z, z) {
intersection.push(Vector3::new(point.x, point.y, z));
} else if last.z < z && point.z > z {
let ratio = (z - last.z) / (point.z - last.z);
intersection.push(Vector3::new(
last.x + (point.x - last.x) * ratio,
last.y + (point.y - last.y) * ratio,
z,
))
} else if last.z > z && point.z < z {
let ratio = (z - point.z) / (last.z - point.z);
intersection.push(Vector3::new(
point.x + (last.x - point.x) * ratio,
point.y + (last.y - point.y) * ratio,
z,
))
if relative_eq!(point[axis], value) {
let mut new_point = *point;
new_point[axis] = value;
intersection.push(new_point);
} else if last[axis] < value && point[axis] > value {
let ratio = (value - last[axis]) / (point[axis] - last[axis]);
let mut new_point = last + (point - last) * ratio;
new_point[axis] = value;
intersection.push(new_point);
} else if last[axis] > value && point[axis] < value {
let ratio = (value - point[axis]) / (last[axis] - point[axis]);
let mut new_point = point + (last - point) * ratio;
new_point[axis] = value;
intersection.push(new_point);
}
last = point;
}

View File

@@ -37,4 +37,3 @@
"vite-plugin-wasm": "^3.3.0"
}
}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { T, type AsyncWritable } from '@threlte/core';
import { Gizmo, Grid, MeshLineGeometry, MeshLineMaterial, OrbitControls } from '@threlte/extras';
import { Gizmo, Grid, OrbitControls, MeshLineGeometry, MeshLineMaterial } from '@threlte/extras';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { useLoader } from '@threlte/core';
import {
@@ -9,9 +9,7 @@
Vector3,
DoubleSide,
Color,
BufferGeometryLoader,
TubeGeometry,
CatmullRomCurve3
BufferGeometryLoader
} from 'three';
import { writable } from 'svelte/store';
import { onDestroy, onMount } from 'svelte';
@@ -38,15 +36,12 @@
case 'layer': {
layers.update((layers) => {
const layer = event.data.data;
if (layer.type === 'ring') {
const curve = new CatmullRomCurve3(
if (layer.type === 'ring' || layer.type === 'path') {
layers.push(
Array.from({ length: layer.position.length / 3 }, (_, i) =>
new Vector3().fromArray(layer.position, i * 3)
)
);
const geometry = new TubeGeometry(curve, undefined, 0.1);
layers.push(geometry);
} else if (layer.type === 'surface') {
}
return layers;
@@ -72,7 +67,7 @@
export let maxNonPlanarAngle = MathUtils.degToRad(20);
export let bedNormal = new Vector3(0, 0, 1);
let layers = writable<Layer[]>([]);
let layers = writable<Vector3[][]>([]);
const stl: AsyncWritable<BufferGeometry> = useLoader(STLLoader).load('/benchy.stl');
@@ -107,12 +102,13 @@
gridSize={[buildSurface[0], buildSurface[1]]}
/>
{#each $layers as geometry, i}
{#each $layers as points, i}
{@const visible = maxZ !== 0 ? i === maxZ : showSlices >= i / $layers.length}
{@const color = new Color(Math.random() * 0xffffff)}
<!---{@const color = new Color(0, i / $layers.length, 0.2)}-->
<T.Mesh {geometry} {visible}>
<T.MeshMatcapMaterial {color} side={DoubleSide} />
<T.Mesh {visible}>
<MeshLineGeometry {points} />
<MeshLineMaterial width={layerHeight / 6} {color} />
</T.Mesh>
{/each}