mirror of
https://github.com/Theaninova/Bampy.git
synced 2025-12-11 03:56:17 +00:00
120 lines
3.0 KiB
Svelte
120 lines
3.0 KiB
Svelte
<script lang="ts">
|
|
import { T, type AsyncWritable } from '@threlte/core';
|
|
import { Gizmo, Grid, OrbitControls, MeshLineGeometry, MeshLineMaterial } from '@threlte/extras';
|
|
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
|
|
import { useLoader } from '@threlte/core';
|
|
import {
|
|
BufferGeometry,
|
|
MathUtils,
|
|
Vector3,
|
|
DoubleSide,
|
|
Color,
|
|
BufferGeometryLoader
|
|
} from 'three';
|
|
import { writable } from 'svelte/store';
|
|
import { onDestroy, onMount } from 'svelte';
|
|
import SliceWorker from '$lib/slicer/worker.js?worker';
|
|
import {
|
|
LayerType,
|
|
type WorkerMessage,
|
|
type Layer,
|
|
type SliceEvent
|
|
} from '$lib/slicer/worker-data';
|
|
|
|
let sliceWorker: Worker;
|
|
|
|
onMount(() => {
|
|
const geometryLoader = new BufferGeometryLoader();
|
|
sliceWorker = new SliceWorker();
|
|
sliceWorker.addEventListener('message', (event: MessageEvent<WorkerMessage>) => {
|
|
switch (event.data.type) {
|
|
case 'progress': {
|
|
progress.set(event.data.percent);
|
|
progressLayer.set(event.data.layer);
|
|
break;
|
|
}
|
|
case 'layer': {
|
|
layers.update((layers) => {
|
|
const layer = event.data.data;
|
|
if (layer.type === 'ring' || layer.type === 'path') {
|
|
layers.push(
|
|
Array.from({ length: layer.position.length / 3 }, (_, i) =>
|
|
new Vector3().fromArray(layer.position, i * 3)
|
|
)
|
|
);
|
|
} else if (layer.type === 'surface') {
|
|
}
|
|
return layers;
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
onDestroy(() => {
|
|
sliceWorker?.terminate();
|
|
});
|
|
|
|
export let buildSurface = [300, 300, 300];
|
|
export let layerHeight = 0.2;
|
|
export let tolerance = 0.005;
|
|
export let progress = writable<number | undefined>(undefined);
|
|
export let progressLayer = writable(0);
|
|
export let showSlices = 1;
|
|
export let maxZ = 0;
|
|
|
|
export let maxNonPlanarAngle = MathUtils.degToRad(20);
|
|
export let bedNormal = new Vector3(0, 0, 1);
|
|
|
|
let layers = writable<Vector3[][]>([]);
|
|
|
|
const stl: AsyncWritable<BufferGeometry> = useLoader(STLLoader).load('/benchy.stl');
|
|
|
|
$: if ($stl) {
|
|
sliceWorker.postMessage({
|
|
type: 'slice',
|
|
data: {
|
|
stl: $stl.toJSON(),
|
|
layerHeight,
|
|
tolerance,
|
|
maxNonPlanarAngle,
|
|
bedNormal: bedNormal.toArray()
|
|
}
|
|
} satisfies SliceEvent);
|
|
}
|
|
</script>
|
|
|
|
<T.PerspectiveCamera makeDefault position={buildSurface} fov={60} up={[0, 0, 1]}>
|
|
<OrbitControls enableDamping target.y={1.5} />
|
|
</T.PerspectiveCamera>
|
|
|
|
<Gizmo />
|
|
|
|
<Grid
|
|
position.y={-0.001}
|
|
cellColor="#ffffff"
|
|
sectionColor="#ff1111"
|
|
fadeDistance={buildSurface[0] * 2}
|
|
cellSize={10}
|
|
sectionSize={0}
|
|
plane="xy"
|
|
gridSize={[buildSurface[0], buildSurface[1]]}
|
|
/>
|
|
|
|
{#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 {visible}>
|
|
<MeshLineGeometry {points} />
|
|
<MeshLineMaterial width={layerHeight / 6} {color} />
|
|
</T.Mesh>
|
|
{/each}
|
|
|
|
{#if $stl}
|
|
<T.Mesh geometry={$stl} position.y={40}>
|
|
<T.MeshNormalMaterial />
|
|
</T.Mesh>
|
|
{/if}
|