grid-apps-cmms/src/kiri/mode/cam/topo4.js

600 lines
21 KiB
JavaScript
Raw Normal View History

2023-01-16 13:56:08 -05:00
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { codec } from '../../core/codec.js';
import { newPoint } from '../../../geo/point.js';
import { newPolygon } from '../../../geo/polygon.js';
import { sliceConnect } from '../../../geo/slicer.js';
2025-07-12 15:43:51 -04:00
import { newSlice } from '../../core/slice.js';
import { Tool } from './tool.js';
import { Slicer as topo_slicer } from './slicer_topo.js';
2023-01-16 13:56:08 -05:00
const RAD2DEG = 180 / Math.PI;
2023-01-17 00:57:37 -05:00
const DEG2RAD = Math.PI / 180;
2023-01-16 13:56:08 -05:00
2023-02-14 00:15:40 -05:00
function scale(fn, factor = 1, base = 0) {
return (value, msg) => {
fn(base + value * factor, msg);
}
}
export class Topo {
2023-01-16 13:56:08 -05:00
constructor() { }
async generate(opt = {}) {
let { state, op, onupdate, ondone } = opt;
2025-11-07 00:06:40 -05:00
let { widget, settings, tabs, color } = state;
2023-01-16 13:56:08 -05:00
let { controller, process } = settings;
let { webGPU } = controller;
2023-01-16 13:56:08 -05:00
let axis = op.axis.toLowerCase(),
tool = new Tool(settings, op.tool),
2023-01-16 13:56:08 -05:00
bounds = widget.getBoundingBox().clone(),
density = parseInt(controller.animesh || 100) * 2500,
{ min, max } = bounds,
span = {
x: max.x - min.x,
y: max.y - min.y
},
contour = {
x: axis === "x",
y: axis === "y"
},
2023-01-16 23:33:24 -05:00
tolerance = op.tolerance,
resolution = (tolerance ? tolerance : 1 / Math.sqrt(density / (span.x * span.y))).round(5),
step = this.step = (tool.traceOffset() * 2) * op.step,
angle = this.angle = op.angle || 1;
2023-01-16 13:56:08 -05:00
2023-02-19 08:12:38 -05:00
if (tool.isTaperMill() && step === 0) {
step = this.step = op.step * tool.unitScale();
}
2023-01-16 13:56:08 -05:00
if (tolerance === 0) {
console.log(widget.id, 'topo4 auto tolerance', resolution.round(4));
}
2025-10-13 16:43:34 -04:00
this.zBottom = state.zBottom ?? 0;
2023-01-16 15:14:58 -05:00
this.resolution = resolution;
2023-02-19 08:12:38 -05:00
this.vertices = widget.getGeoVertices({ unroll: true, translate: true });
this.tabverts = widget.getTabVertices();
2023-01-16 23:33:24 -05:00
this.tool = tool.generateProfile(resolution).profile;
2023-02-13 23:10:42 -05:00
this.maxo = tool.profileDim.maxo * resolution;
this.diam = tool.fluteDiameter();
this.unit = tool.unitScale();
2025-11-04 18:34:32 -05:00
this.units = controller.units === 'in' ? 25.4 : 1
this.zoff = widget.track.top || 0;
this.leave = op.leave || 0;
2025-01-03 21:55:19 -05:00
this.linear = op.linear || false;
2025-11-07 00:06:40 -05:00
this.lineColor = color;//controller.dark ? 0xffff00 : 0x555500;
this.offStart = op.offStart ?? 0;
this.offEnd = op.offEnd ?? 0;
this.bounds = bounds;
this.gpu = webGPU ?? false;
2023-01-16 13:56:08 -05:00
onupdate(0, "lathe");
2023-01-16 18:27:38 -05:00
const parts = webGPU ? [ 0.8, 0.2 ] : [ 0.25, 0.75 ];
2023-01-16 23:33:24 -05:00
const range = this.range = { min: Infinity, max: -Infinity };
const slices = this.sliced = await this.slice(scale(onupdate, parts[0], 0));
2023-01-16 15:14:58 -05:00
for (let slice of slices) {
2023-01-16 23:33:24 -05:00
range.min = Math.min(range.min, slice.z);
range.max = Math.max(range.max, slice.z);
2023-01-16 15:14:58 -05:00
}
2023-01-16 13:56:08 -05:00
const lathe = await this.lathe(scale(onupdate, parts[1], parts[0]));
2023-01-16 18:27:38 -05:00
onupdate(1, "lathe");
2023-02-13 13:35:43 -05:00
ondone(lathe);
// ondone([...slices, ...lathe]);
return this;
2023-01-16 13:56:08 -05:00
}
2023-01-16 15:14:58 -05:00
async slice(onupdate) {
2025-11-04 18:34:32 -05:00
const { vertices, resolution, tabverts, zoff, offStart, offEnd, units } = this;
const { minions } = self.kiri_worker;
2023-01-16 15:14:58 -05:00
const range = this.range = { min: Infinity, max: -Infinity };
// swap XZ in shared array
2025-07-15 18:39:48 -04:00
for (let i = 0, l = vertices.length; i < l; i += 3) {
2023-01-16 15:14:58 -05:00
const x = vertices[i];
const z = vertices[i + 2] + zoff;
2023-01-16 15:14:58 -05:00
vertices[i] = z;
vertices[i + 2] = x;
range.min = Math.min(range.min, x);
range.max = Math.max(range.max, x);
}
// add tool diameter to slice min/max range to fully carve part
2025-11-04 18:34:32 -05:00
range.min += offStart * units;
range.max -= offEnd * units;
range.max += resolution * 2;
// merge in tab vertices here so they don't affect slice range / dimensions
2025-07-15 18:39:48 -04:00
for (let i = 0, l = tabverts.length; i < l; i += 3) {
const x = tabverts[i];
const z = tabverts[i + 2] + zoff;
tabverts[i] = z;
tabverts[i + 2] = x;
}
// re-create shared vertex array for workers
this.vertices = [].appendAll(vertices).appendAll(tabverts).toFloat32().toShared();
// rp.rasterizeMesh(vertices, resolution).then(rpo => console.log({ rpo }));
if (this.gpu) {
return await this.sliceGPU(onupdate);
}
const zSpan = range.max - range.min;
2023-01-16 15:14:58 -05:00
const shards = Math.ceil(Math.min(25, vertices.length / 27000));
const totalSteps = Math.ceil(zSpan / resolution);
const stardSteps = Math.ceil(totalSteps / shards);
const stepWidth = stardSteps * resolution;
2023-01-16 15:14:58 -05:00
let slices = this.slices = [];
for (let i=0; i<shards; i++) {
let s;
slices.push(s = {
min: range.min + i * stepWidth,
max: Math.min(range.max, range.min + (i+1) * stepWidth),
index: i * stardSteps
});
2023-01-16 15:14:58 -05:00
}
// console.log({
// shards,
// step: stepWidth,
// range,
// resolution,
// slices: slices.slice(),
// minions
// });
2025-07-12 15:43:51 -04:00
if (minions?.running > 1) {
2023-01-16 15:14:58 -05:00
return await this.sliceMinions(onupdate);
} else {
return await this.sliceWorker(onupdate);
}
}
async sliceGPU(onupdate) {
2025-12-10 18:48:51 -05:00
const { angle, diam, leave, linear, offStart, offEnd, resolution, tool, units, vertices, zBottom } = this;
// invert tool Z offset for gpu code
2025-11-04 18:34:32 -05:00
let toolBounds = new THREE.Box3()
.expandByPoint({ x: -this.diam/2, y: -diam/2, z: 0 })
.expandByPoint({ x: this.diam/2, y: diam/2, z: 0 });
2025-11-02 21:23:15 -05:00
let toolPos = tool.slice();
2025-11-04 18:34:32 -05:00
let minz = Infinity;
for (let i=0; i<toolPos.length; i += 3) {
// toolPos[i+2] = -toolPos[i+2];
toolBounds.expandByPoint({ x: 0, y: 0, z: toolPos[i+2] });
minz = Math.min(minz,toolPos[i+2]);
}
2025-11-02 21:23:15 -05:00
let toolData = { positions: toolPos, bounds: toolBounds };
2025-11-02 21:48:02 -05:00
// console.time('swap XZ vertices');
// swap XZ vertices for gpu code
for (let i=0; i<vertices.length; i+= 3) {
let tmp = vertices[i+2];
vertices[i+2] = vertices[i+0];
2025-11-10 00:15:41 -05:00
vertices[i+1] = -vertices[i+1];
vertices[i+0] = tmp;
}
2025-11-02 21:48:02 -05:00
// console.timeEnd('swap XZ vertices');
2025-11-02 21:23:15 -05:00
let gpu = await self.get_raster_gpu({
mode: "radial",
resolution,
2025-11-10 00:15:41 -05:00
rotationStep: angle,
radialRotationOffset: 90
2025-11-02 21:23:15 -05:00
});
2025-11-02 21:48:02 -05:00
let xStep = Math.max(1, Math.round(this.step / resolution));
2025-11-02 21:23:15 -05:00
let boundsOverride = this.bounds.clone();
2025-11-04 18:34:32 -05:00
boundsOverride.min.x += offStart * units;
boundsOverride.max.x -= offEnd * units;
2025-11-07 00:06:40 -05:00
await gpu.loadTool({
sparseData: toolData
});
await gpu.loadTerrain({
2025-11-02 21:23:15 -05:00
triangles: vertices,
boundsOverride,
onProgress(pct) { onupdate(pct/100) }
2025-11-02 21:23:15 -05:00
});
let output = await gpu.generateToolpaths({
2025-11-02 21:48:02 -05:00
xStep,
yStep: 1,
2025-11-02 21:23:15 -05:00
zFloor: zBottom,
onProgress(i,j) { onupdate(i/j) }
2025-11-02 21:23:15 -05:00
});
2025-11-04 18:34:32 -05:00
gpu.terminate();
2025-11-02 21:23:15 -05:00
2025-11-07 00:06:40 -05:00
let { numStrips, strips } = output;
let degPerRow = 360 / numStrips;
let slices = this.gpu_slices = [];
2025-11-02 21:48:02 -05:00
let xmult = resolution * xStep;
2025-11-07 00:06:40 -05:00
let xoff = boundsOverride.min.x;
let rows = [];
2025-11-07 00:06:40 -05:00
for (let i=0; i<numStrips; i++) {
2025-12-10 18:48:51 -05:00
let points = Array.from(strips[i].pathData).map((v,j) => newPoint(j * xmult + xoff, 0, v + leave).setA(-i * degPerRow));
rows.push(points);
}
if (linear) {
for (let i=0; i<rows.length; i++) {
let slice = newSlice(i);
slice.index = i;
slice.camLines = [ newPolygon(rows[i]).setOpen() ];
if (i % 2 === 1) slice.camLines[0].reverse();
slices.push(slice);
}
} else {
let { pointsPerLine } = strips[0];
for (let i=0; i<pointsPerLine; i++) {
let slice = newSlice(i);
let points = rows.map(row => row[i]);
points.push(points[0].clone().setA(-360));
if (i % 2 === 1) points.reverse();
slice.index = i;
slice.camLines = [ newPolygon(points).setOpen() ];
slices.push(slice);
}
}
for (let slice of slices) {
slice.output()
.setLayer("lathe", { line: this.lineColor })
.addPoly(slice.camLines[0].clone().applyRotations());
}
// console.log({ webGPU: output, slices });
return slices;
}
2023-01-16 15:14:58 -05:00
async sliceWorker(onupdate) {
const { vertices, slices, resolution } = this;
let output = [];
let complete = 0;
for (let slice of slices) {
const recs = new topo_slicer(slice.index)
2023-01-16 15:14:58 -05:00
.setFromArray(vertices, slice)
.slice(resolution)
.map(rec => {
const slice = newSlice(rec.z);
2023-01-16 15:14:58 -05:00
for (let line of rec.lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
if (!p2.swapped) { p2.swapXZ(); p2.swapped = true }
}
slice.index = rec.index;
slice.addTops(sliceConnect(rec.lines));
2023-01-16 18:27:38 -05:00
2025-07-15 18:39:48 -04:00
const points = codec.encodePointArray(rec.lines.map(l => [l.p1, l.p2]).flat());
2023-01-16 18:27:38 -05:00
const shared = new Float32Array(new SharedArrayBuffer(points.length * 4));
shared.set(points);
slice.shared = shared;
2023-01-16 15:14:58 -05:00
return slice;
});
output.appendAll(recs);
2025-07-15 18:39:48 -04:00
onupdate(++complete / slices.length);
2023-01-16 15:14:58 -05:00
}
return output;
}
async sliceMinions(onupdate) {
2023-01-16 23:33:24 -05:00
const { queue, putCache, clearCache } = this;
const { vertices, slices, resolution } = this;
putCache("vertices", vertices);
2023-01-16 15:14:58 -05:00
let complete = 0;
let promises = slices.map(slice => {
2023-01-16 23:33:24 -05:00
return queue("topo4_slice", {
resolution,
slice
}).then(data => {
onupdate(++complete / slices.length);
return data;
2023-01-16 15:14:58 -05:00
});
});
// merge boxes for all rasters for contouring clipping
const output = codec.decode(await Promise.all(promises))
.map(rec => rec.recs)
.flat()
2023-01-16 18:27:38 -05:00
.map(rec => newSlice(rec.z)
.addTops(rec.polys)
.setFields({ shared: rec.shared }))
2025-07-15 18:39:48 -04:00
.sort((a, b) => a.z - b.z);
2023-01-16 15:14:58 -05:00
2023-01-16 23:33:24 -05:00
clearCache();
2023-01-16 15:14:58 -05:00
return output;
}
2023-01-16 18:27:38 -05:00
async lathe(onupdate) {
2025-07-12 15:43:51 -04:00
const { minions } = self.kiri_worker;
if (this.gpu) {
return await this.latheGPU(onupdate);
} else if (minions?.running > 1) {
2023-01-16 18:27:38 -05:00
return await this.latheMinions(onupdate);
} else {
return await this.latheWorker(onupdate);
}
}
async latheGPU(onupdate) {
return this.gpu_slices;
}
2023-01-17 00:57:37 -05:00
lathePath(slices, tool) {
2023-02-13 23:10:42 -05:00
const { resolution, step, zBottom, maxo } = this;
2023-01-16 23:33:24 -05:00
const tlen = tool.length;
const slen = slices.length;
2023-01-17 00:57:37 -05:00
const heights = [];
// console.log({ tlen, slen, sinc, slices: slices.map(s => s.z) });
// cull slice lines to only the ones in range (~5x faster)
const oslices = [];
for (let slice of slices) {
const lines = slice.lines;
const plen = lines.length;
const rec = { z: slice.z, lines: [] };
2025-07-15 18:39:48 -04:00
for (let i = 0; i < plen;) {
++i; // skip x which should match slice.z
let py0 = lines[i++];
const pz0 = lines[i++];
++i; // skip x which should match slice.z
let py1 = lines[i++];
const pz1 = lines[i++];
if ((py0 < -maxo && py1 < -maxo) || (py0 > maxo && py1 > maxo)) {
continue;
}
rec.lines.push(0, py0, pz0, 0, py1, pz1);
}
oslices.push(rec);
}
2023-01-16 23:33:24 -05:00
// iterate over all slices (real x = z)
// find max real z using z ray intersect from tool point to slice lines + offset
let lz = 0;
for (let sz = 0; ; sz += step) {
let si = Math.ceil(sz / resolution);
if (si >= oslices.length) break;
const rx = oslices[si].z;
let mz = -Infinity;
2023-01-16 23:33:24 -05:00
// iterate over tool offsets
2025-07-15 18:39:48 -04:00
for (let ti = 0; ti < tlen;) {
2023-01-16 23:33:24 -05:00
// tool offset in grid units from present x (si)
const xo = tool[ti++]; // x grid offset (slice)
2023-01-17 00:57:37 -05:00
const yo = tool[ti++] * resolution; // y grid offset (mult rez to get real y)
2023-01-16 23:33:24 -05:00
const zo = tool[ti++]; // real z delta offset
// get slice index corresponding with offset
const ts = si + xo;
// outside of slice array, skip
if (ts < 0 || ts >= slen - 1) {
continue;
}
const slice = oslices[ts];
2023-01-16 23:33:24 -05:00
const lines = slice.lines;
const plen = lines.length;
2025-07-15 18:39:48 -04:00
for (let i = 0; i < plen;) {
2023-01-16 23:33:24 -05:00
++i; // skip x which should match slice.z
2023-01-17 06:41:37 -05:00
let py0 = lines[i++];
2023-01-16 23:33:24 -05:00
const pz0 = lines[i++];
++i; // skip x which should match slice.z
2023-01-17 06:41:37 -05:00
let py1 = lines[i++];
2023-01-16 23:33:24 -05:00
const pz1 = lines[i++];
2023-01-17 00:57:37 -05:00
if ((py0 <= yo && py1 >= yo) || (py1 <= yo && py0 >= yo)) {
2023-01-17 06:41:37 -05:00
const dz = pz1 - pz0;
2023-01-17 00:57:37 -05:00
const dy = Math.abs(py1 - py0);
if (dy === 0) continue;
2023-01-17 06:41:37 -05:00
const fr = Math.abs(yo - py0) / dy;
2023-01-17 00:57:37 -05:00
const lz = pz0 + dz * fr + zo;
2023-01-16 23:33:24 -05:00
// check z height
2023-01-17 00:57:37 -05:00
mz = Math.max(mz, lz);
2023-01-16 23:33:24 -05:00
}
}
if (mz === -Infinity && xo === 0 && yo === 0) {
// tool tip is off the model
// continue;
}
2023-01-16 23:33:24 -05:00
}
if (mz === -Infinity) {
2025-10-13 16:43:34 -04:00
mz = zBottom;
} else if (mz < zBottom) {
mz = zBottom;
}
heights.push(rx, 0, lz = mz);
2023-01-16 23:33:24 -05:00
}
2023-01-17 00:57:37 -05:00
return heights;
}
async latheWorker(onupdate) {
const { sliced, tool, zoff, leave, linear } = this;
2023-01-16 23:33:24 -05:00
const rota = this.angle * DEG2RAD;
const steps = (Math.PI * 2) / rota;
2023-01-17 00:57:37 -05:00
const axis = new THREE.Vector3(1, 0, 0);
const mrot = new THREE.Matrix4().makeRotationAxis(axis, rota);
2023-01-17 00:57:37 -05:00
const slices = sliced.map(s => { return { z: s.z, lines: s.shared } });
const paths = [];
const recs = [];
let angle = 0;
let count = 0;
// for each step angle, find Z spine heights, produce record
2023-01-17 00:57:37 -05:00
while (count++ < steps) {
const heights = this.lathePath(slices, tool, paths);
2023-02-13 13:35:43 -05:00
recs.push({ angle, heights, degrees: angle * RAD2DEG });
2023-01-17 00:57:37 -05:00
angle -= rota;
for (let lines of slices.map(s => s.lines)) {
rotatePoints(lines, mrot);
2023-01-17 00:57:37 -05:00
}
2023-02-14 00:15:40 -05:00
onupdate(count / steps);
2023-01-17 00:57:37 -05:00
}
count = linear ? recs.length : recs[0].heights.length / 3;
// count = recs[0].heights.length / 3;
2023-02-13 15:38:39 -05:00
while (count-- > 0) {
let slice = newSlice(count);
2025-07-15 18:39:48 -04:00
slice.camLines = [newPolygon().setOpen()];
2023-02-13 13:35:43 -05:00
paths.push(slice);
}
if (linear) {
2025-07-15 18:39:48 -04:00
recs.forEach((rec, i) => {
const { degrees, heights } = rec;
[...heights].group(3).forEach((a) => {
2025-07-15 18:39:48 -04:00
paths[i].camLines[0].push(newPoint(a[0], a[1], a[2] + leave).setA(degrees));
});
if (i % 2 === 1) {
paths[i].camLines[0].reverse();
}
});
} else {
for (let rec of recs) {
const { degrees, heights } = rec;
2025-07-15 18:39:48 -04:00
[...heights].group(3).forEach((a, i) => {
// progress each path 360 degrees to prevent A rolling backwards
2025-07-15 18:39:48 -04:00
paths[i].camLines[0].push(newPoint(a[0], a[1], a[2] + leave).setA(degrees + i * -360));
});
}
2023-02-13 13:35:43 -05:00
}
for (let slice of paths) {
const poly = slice.camLines[0];
if (!poly.length) {
2023-02-13 15:38:39 -05:00
console.log('empty', slice);
continue;
}
// repeat first point 360 degrees progressed
const repeat = poly.points[0];
slice.camLines[0].push(repeat.clone().setA(repeat.a - 360));
2023-01-17 00:57:37 -05:00
slice.output()
.setLayer("lathe", { line: this.lineColor })
2025-07-15 18:39:48 -04:00
.addPoly(poly.clone().applyRotations().move({ z: -zoff, x: 0, y: 0 }));
2023-01-17 00:57:37 -05:00
}
2023-02-13 13:35:43 -05:00
// console.log({ tool, slices, paths });
2023-01-17 00:57:37 -05:00
return paths;
2023-01-16 18:27:38 -05:00
}
async latheMinions(onupdate) {
2025-01-03 21:55:19 -05:00
const { sliced, tool, zoff, leave, maxo, zBottom, step, resolution, linear } = this;
2023-01-16 23:33:24 -05:00
const { putCache, clearCache, queue } = this;
2023-03-04 15:59:05 -05:00
const rota = this.angle * DEG2RAD;
const steps = (Math.PI * 2) / rota;
const slices = sliced.map(s => { return { z: s.z, lines: s.shared } });
const paths = [];
const recs = [];
2023-01-16 23:33:24 -05:00
putCache("lathe", {
2023-03-04 15:59:05 -05:00
maxo,
2023-01-16 23:33:24 -05:00
tool,
step,
2023-03-04 15:59:05 -05:00
slices,
zBottom,
2023-01-16 23:33:24 -05:00
resolution,
});
2023-01-16 18:27:38 -05:00
2023-03-04 15:59:05 -05:00
let done = 0;
let tangle = 0;
let count = 0;
let promises = [];
// for each step angle, find Z spine heights, produce record
while (count++ < steps) {
const angle = tangle;
let p = new Promise(resolve => {
queue("topo4_lathe", { angle }).then(data => {
// console.log({ angle, data });
recs.push({ angle, heights: data.heights, degrees: angle * RAD2DEG });
onupdate(++done / steps);
resolve();
2023-01-16 18:27:38 -05:00
});
2023-03-04 15:59:05 -05:00
});
// await p;
promises.push(p);
tangle -= rota;
}
2023-01-16 18:27:38 -05:00
2023-03-04 15:59:05 -05:00
await Promise.all(promises);
recs.sort((a, b) => { return b.angle - a.angle });
2023-03-04 15:59:05 -05:00
2025-01-03 21:55:19 -05:00
count = linear ? recs.length : recs[0].heights.length / 3;
2023-03-04 15:59:05 -05:00
while (count-- > 0) {
let slice = newSlice(count);
2025-07-15 18:39:48 -04:00
slice.camLines = [newPolygon().setOpen()];
2023-03-04 15:59:05 -05:00
paths.push(slice);
}
2025-01-03 21:55:19 -05:00
if (linear) {
2025-07-15 18:39:48 -04:00
recs.forEach((rec, i) => {
2025-01-03 21:55:19 -05:00
const { degrees, heights } = rec;
[...heights].group(3).forEach((a) => {
2025-07-15 18:39:48 -04:00
paths[i].camLines[0].push(newPoint(a[0], a[1], a[2] + leave).setA(degrees));
2025-01-03 21:55:19 -05:00
});
if (i % 2 === 1) {
paths[i].camLines[0].reverse();
}
2023-03-04 15:59:05 -05:00
});
2025-01-03 21:55:19 -05:00
} else {
for (let rec of recs) {
const { degrees, heights } = rec;
2025-07-15 18:39:48 -04:00
[...heights].group(3).forEach((a, i) => {
2025-01-03 21:55:19 -05:00
// progress each path 360 degrees to prevent A rolling backwards
2025-07-15 18:39:48 -04:00
paths[i].camLines[0].push(newPoint(a[0], a[1], a[2] + leave).setA(degrees + i * -360));
2025-01-03 21:55:19 -05:00
});
}
2023-03-04 15:59:05 -05:00
}
for (let slice of paths) {
const poly = slice.camLines[0];
if (!poly.length) {
console.log('empty', slice);
continue;
}
2025-01-03 21:55:19 -05:00
if (!linear) {
// repeat first point 360 degrees progressed
const repeat = poly.points[0];
slice.camLines[0].push(repeat.clone().setA(repeat.a - 360));
}
2023-03-04 15:59:05 -05:00
slice.output()
.setLayer("lathe", { line: this.lineColor })
2025-07-15 18:39:48 -04:00
.addPoly(poly.clone().applyRotations().move({ z: -zoff, x: 0, y: 0 }));
2023-03-04 15:59:05 -05:00
}
2023-01-16 18:27:38 -05:00
2023-03-04 15:59:05 -05:00
// console.log({ tool, slices, paths });
2023-01-16 23:33:24 -05:00
clearCache();
2023-03-04 15:59:05 -05:00
return paths;
2023-01-16 18:27:38 -05:00
}
2023-01-16 23:33:24 -05:00
putCache(key, data) {
2025-07-12 15:43:51 -04:00
const { dispatch } = self.kiri_worker;
dispatch.putCache({ key, data }, { done: data => { } });
2023-01-16 23:33:24 -05:00
}
clearCache() {
2025-07-12 15:43:51 -04:00
const { dispatch } = self.kiri_worker;
dispatch.clearCache({}, { done: data => { } });
2023-01-16 23:33:24 -05:00
}
queue(cmd, params) {
2025-07-12 15:43:51 -04:00
const { minions } = self.kiri_worker;
2023-01-16 23:33:24 -05:00
return new Promise(resolve => {
2025-07-12 15:43:51 -04:00
minions.queue({ cmd, ...params }, resolve);
2023-01-16 23:33:24 -05:00
});
}
2023-01-16 13:56:08 -05:00
}
2025-07-12 15:43:51 -04:00
export function rotatePoints(lines, rot) {
2023-01-17 00:57:37 -05:00
new THREE.BufferAttribute(lines, 3).applyMatrix4(rot);
}
export async function generate(opt) {
2025-07-12 15:43:51 -04:00
return new Topo().generate(opt);
2023-01-16 13:56:08 -05:00
};