mirror of
https://github.com/Theaninova/Bampy.git
synced 2025-12-11 03:56:17 +00:00
feat: testing some stuff
This commit is contained in:
@@ -1,11 +1,14 @@
|
|||||||
|
use std::iter::empty;
|
||||||
|
|
||||||
use approx::relative_eq;
|
use approx::relative_eq;
|
||||||
use nalgebra::{vector, Vector3};
|
use nalgebra::{vector, SimdBool, Vector3};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use slicer::{line::Line3, slice_rings::slice_rings};
|
||||||
use tsify::Tsify;
|
use tsify::Tsify;
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
use crate::slicer::{
|
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,
|
trace_surface::trace_surface, triangle::Triangle, FloatValue, SlicerOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,6 +39,10 @@ pub enum Slice {
|
|||||||
#[tsify(type = "Float32Array")]
|
#[tsify(type = "Float32Array")]
|
||||||
position: Vec<f32>,
|
position: Vec<f32>,
|
||||||
},
|
},
|
||||||
|
Path {
|
||||||
|
#[tsify(type = "Float32Array")]
|
||||||
|
position: Vec<f32>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Tsify, Serialize, Deserialize)]
|
#[derive(Tsify, Serialize, Deserialize)]
|
||||||
@@ -95,12 +102,47 @@ pub fn slice(
|
|||||||
let slicer_options = SlicerOptions { layer_height };
|
let slicer_options = SlicerOptions { layer_height };
|
||||||
|
|
||||||
console_log!("Creating Surfaces");
|
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");
|
console_log!("Computing BVH");
|
||||||
let slicable = Mesh::from(slicable_triangles);
|
let slicable = Mesh::from(slicable_triangles);
|
||||||
console_log!("Creating Slices");
|
console_log!("Creating Slices");
|
||||||
let mut slices = create_slices(&slicer_options, &slicable);
|
let slices = slice_rings(2, &slicer_options, &slicable);
|
||||||
|
|
||||||
/*console_log!("Tracing Surfaces");
|
/*console_log!("Tracing Surfaces");
|
||||||
let a = max_angle.tan();
|
let a = max_angle.tan();
|
||||||
@@ -114,16 +156,23 @@ pub fn slice(
|
|||||||
|
|
||||||
console_log!("Done");
|
console_log!("Done");
|
||||||
SliceResult {
|
SliceResult {
|
||||||
slices: slices
|
slices: surfaces
|
||||||
.into_iter()
|
|
||||||
.map(|slice| Slice::Ring {
|
.map(|slice| Slice::Ring {
|
||||||
position: slice
|
position: slice
|
||||||
.points
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|point| [point.x as f32, point.y as f32, point.z as f32])
|
.flat_map(|point| [point.x as f32, point.y as f32, point.z as f32])
|
||||||
.collect(),
|
.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 {
|
Slice::Surface {
|
||||||
position: surface
|
position: surface
|
||||||
.triangles
|
.triangles
|
||||||
@@ -143,7 +192,7 @@ pub fn slice(
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}))
|
}))*/
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
use super::{
|
use super::{line::Line3, mesh::Mesh, FloatValue, SlicerOptions};
|
||||||
line::Line3,
|
use crate::console_log;
|
||||||
mesh::Mesh,
|
|
||||||
slice_rings::{find_slice_rings, SliceRing},
|
|
||||||
FloatValue, SlicerOptions,
|
|
||||||
};
|
|
||||||
use bvh::bvh::BvhNode;
|
use bvh::bvh::BvhNode;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BaseSlice {
|
pub struct BaseSlice {
|
||||||
pub z: FloatValue,
|
pub d: FloatValue,
|
||||||
pub lines: Vec<Line3>,
|
pub lines: Vec<Line3>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates base slices from the geometry, excluding surfaces.
|
/// Creates base slices from the geometry
|
||||||
/// The slicse are not sorted or separated into rings.
|
pub fn create_base_slices<'a>(
|
||||||
pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing> {
|
axis: usize,
|
||||||
let layer_count = (slicable.aabb.max.z / options.layer_height).floor() as usize;
|
options: &'a SlicerOptions,
|
||||||
let mut rings = vec![];
|
slicable: &'a Mesh,
|
||||||
let mut layer_index = 0;
|
) -> 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 {
|
(0..layer_count).map(move |i| {
|
||||||
let layer = i as FloatValue * options.layer_height;
|
let layer = i as FloatValue * options.layer_height + slicable.aabb.min[axis];
|
||||||
let mut base_slice = BaseSlice {
|
let mut base_slice = BaseSlice {
|
||||||
z: layer,
|
d: layer,
|
||||||
lines: vec![],
|
lines: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,12 +35,12 @@ pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing>
|
|||||||
child_r_index,
|
child_r_index,
|
||||||
child_r_aabb,
|
child_r_aabb,
|
||||||
} => {
|
} => {
|
||||||
assert!(child_l_aabb.min.z <= child_l_aabb.max.z);
|
assert!(child_l_aabb.min[axis] <= child_l_aabb.max[axis]);
|
||||||
assert!(child_r_aabb.min.z <= child_r_aabb.max.z);
|
assert!(child_r_aabb.min[axis] <= child_r_aabb.max[axis]);
|
||||||
if layer >= child_l_aabb.min.z && layer <= child_l_aabb.max.z {
|
if layer >= child_l_aabb.min[axis] && layer <= child_l_aabb.max[axis] {
|
||||||
stack.push(child_l_index);
|
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);
|
stack.push(child_r_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +49,7 @@ pub fn create_slices(options: &SlicerOptions, slicable: &Mesh) -> Vec<SliceRing>
|
|||||||
shape_index,
|
shape_index,
|
||||||
} => {
|
} => {
|
||||||
slicable.triangles[shape_index]
|
slicable.triangles[shape_index]
|
||||||
.intersect_z(layer)
|
.intersect(layer, axis)
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
base_slice.lines.push(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));
|
base_slice
|
||||||
}
|
})
|
||||||
|
|
||||||
rings
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,68 +3,72 @@ use nalgebra::Vector3;
|
|||||||
|
|
||||||
use crate::console_log;
|
use crate::console_log;
|
||||||
|
|
||||||
use super::{base_slices::BaseSlice, FloatValue};
|
use super::{
|
||||||
|
base_slices::{create_base_slices, BaseSlice},
|
||||||
|
mesh::Mesh,
|
||||||
|
FloatValue, SlicerOptions,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SliceRing {
|
pub struct SliceRing {
|
||||||
pub z: FloatValue,
|
pub d: FloatValue,
|
||||||
/// The points of the ring, in clockwise order.
|
/// The points of the ring, in clockwise order.
|
||||||
pub points: Vec<Vector3<FloatValue>>,
|
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![];
|
let mut rings = vec![];
|
||||||
while let Some(line) = slice.lines.pop() {
|
while let Some(line) = slice.lines.pop() {
|
||||||
if relative_eq!(line.start, line.end) {
|
if relative_eq!(line.start, line.end) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut ring = SliceRing {
|
let mut right = vec![line.end];
|
||||||
z: slice.z,
|
let mut left = vec![line.start];
|
||||||
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 previous_len = usize::MAX;
|
let mut previous_len = usize::MAX;
|
||||||
let mut done = false;
|
let mut closed = false;
|
||||||
|
|
||||||
while !done {
|
while !closed {
|
||||||
if previous_len == slice.lines.len() {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
previous_len = slice.lines.len();
|
previous_len = slice.lines.len();
|
||||||
|
|
||||||
slice.lines.retain_mut(|line| {
|
slice.lines.retain_mut(|line| {
|
||||||
if done {
|
if closed {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! add {
|
let test = |side: &mut Vec<Vector3<FloatValue>>| {
|
||||||
( $point:expr ) => {
|
let last = side.last().unwrap();
|
||||||
if !relative_eq!($point, right_start) {
|
let s = relative_eq!(line.start, last);
|
||||||
right_start = right;
|
let e = relative_eq!(line.end, last);
|
||||||
right = $point;
|
if s && !e {
|
||||||
ring.points.push(right);
|
side.push(line.end);
|
||||||
sum_of_edges = (right.x - right_start.x) * (right.y + right_start.y);
|
} else if !s && e {
|
||||||
done = relative_eq!(ring.points[0], right);
|
side.push(line.start);
|
||||||
}
|
}
|
||||||
};
|
s || e
|
||||||
}
|
};
|
||||||
|
|
||||||
let s = relative_eq!(line.start, right);
|
if test(&mut left) || test(&mut right) {
|
||||||
let e = relative_eq!(line.end, right);
|
closed = relative_eq!(left.last().unwrap(), right.last().unwrap());
|
||||||
if s && !e {
|
|
||||||
add!(line.end);
|
|
||||||
false
|
|
||||||
} else if e && !s {
|
|
||||||
add!(line.start);
|
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
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.
|
left.reverse();
|
||||||
if sum_of_edges < 0.0 {
|
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();
|
ring.points.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
rings.push(ring);
|
rings.push(ring);
|
||||||
*layer_index += 1;
|
*layer_index += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,26 +73,24 @@ impl Triangle {
|
|||||||
a && b || a && c || b && c
|
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 intersection = Vec::<Vector3<FloatValue>>::with_capacity(3);
|
||||||
let mut last = &self.c;
|
let mut last = &self.c;
|
||||||
for point in [self.a, self.b, self.c].iter() {
|
for point in [self.a, self.b, self.c].iter() {
|
||||||
if relative_eq!(point.z, z) {
|
if relative_eq!(point[axis], value) {
|
||||||
intersection.push(Vector3::new(point.x, point.y, z));
|
let mut new_point = *point;
|
||||||
} else if last.z < z && point.z > z {
|
new_point[axis] = value;
|
||||||
let ratio = (z - last.z) / (point.z - last.z);
|
intersection.push(new_point);
|
||||||
intersection.push(Vector3::new(
|
} else if last[axis] < value && point[axis] > value {
|
||||||
last.x + (point.x - last.x) * ratio,
|
let ratio = (value - last[axis]) / (point[axis] - last[axis]);
|
||||||
last.y + (point.y - last.y) * ratio,
|
let mut new_point = last + (point - last) * ratio;
|
||||||
z,
|
new_point[axis] = value;
|
||||||
))
|
intersection.push(new_point);
|
||||||
} else if last.z > z && point.z < z {
|
} else if last[axis] > value && point[axis] < value {
|
||||||
let ratio = (z - point.z) / (last.z - point.z);
|
let ratio = (value - point[axis]) / (last[axis] - point[axis]);
|
||||||
intersection.push(Vector3::new(
|
let mut new_point = point + (last - point) * ratio;
|
||||||
point.x + (last.x - point.x) * ratio,
|
new_point[axis] = value;
|
||||||
point.y + (last.y - point.y) * ratio,
|
intersection.push(new_point);
|
||||||
z,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
last = point;
|
last = point;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,4 +37,3 @@
|
|||||||
"vite-plugin-wasm": "^3.3.0"
|
"vite-plugin-wasm": "^3.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { T, type AsyncWritable } from '@threlte/core';
|
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 { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
|
||||||
import { useLoader } from '@threlte/core';
|
import { useLoader } from '@threlte/core';
|
||||||
import {
|
import {
|
||||||
@@ -9,9 +9,7 @@
|
|||||||
Vector3,
|
Vector3,
|
||||||
DoubleSide,
|
DoubleSide,
|
||||||
Color,
|
Color,
|
||||||
BufferGeometryLoader,
|
BufferGeometryLoader
|
||||||
TubeGeometry,
|
|
||||||
CatmullRomCurve3
|
|
||||||
} from 'three';
|
} from 'three';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
@@ -38,15 +36,12 @@
|
|||||||
case 'layer': {
|
case 'layer': {
|
||||||
layers.update((layers) => {
|
layers.update((layers) => {
|
||||||
const layer = event.data.data;
|
const layer = event.data.data;
|
||||||
if (layer.type === 'ring') {
|
if (layer.type === 'ring' || layer.type === 'path') {
|
||||||
const curve = new CatmullRomCurve3(
|
layers.push(
|
||||||
Array.from({ length: layer.position.length / 3 }, (_, i) =>
|
Array.from({ length: layer.position.length / 3 }, (_, i) =>
|
||||||
new Vector3().fromArray(layer.position, i * 3)
|
new Vector3().fromArray(layer.position, i * 3)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const geometry = new TubeGeometry(curve, undefined, 0.1);
|
|
||||||
|
|
||||||
layers.push(geometry);
|
|
||||||
} else if (layer.type === 'surface') {
|
} else if (layer.type === 'surface') {
|
||||||
}
|
}
|
||||||
return layers;
|
return layers;
|
||||||
@@ -72,7 +67,7 @@
|
|||||||
export let maxNonPlanarAngle = MathUtils.degToRad(20);
|
export let maxNonPlanarAngle = MathUtils.degToRad(20);
|
||||||
export let bedNormal = new Vector3(0, 0, 1);
|
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');
|
const stl: AsyncWritable<BufferGeometry> = useLoader(STLLoader).load('/benchy.stl');
|
||||||
|
|
||||||
@@ -107,12 +102,13 @@
|
|||||||
gridSize={[buildSurface[0], buildSurface[1]]}
|
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 visible = maxZ !== 0 ? i === maxZ : showSlices >= i / $layers.length}
|
||||||
{@const color = new Color(Math.random() * 0xffffff)}
|
{@const color = new Color(Math.random() * 0xffffff)}
|
||||||
<!---{@const color = new Color(0, i / $layers.length, 0.2)}-->
|
<!---{@const color = new Color(0, i / $layers.length, 0.2)}-->
|
||||||
<T.Mesh {geometry} {visible}>
|
<T.Mesh {visible}>
|
||||||
<T.MeshMatcapMaterial {color} side={DoubleSide} />
|
<MeshLineGeometry {points} />
|
||||||
|
<MeshLineMaterial width={layerHeight / 6} {color} />
|
||||||
</T.Mesh>
|
</T.Mesh>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user