mirror of
https://github.com/Theaninova/Bampy.git
synced 2025-12-10 11:36:18 +00:00
feat: testing some stuff
This commit is contained in:
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -37,4 +37,3 @@
|
||||
"vite-plugin-wasm": "^3.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user