fix arc.flat() bug, migrate 3d/4d topo for minions

This commit is contained in:
Stewart Allen 2025-07-08 21:26:52 -04:00
commit 3a71c93752
7 changed files with 135 additions and 155 deletions

View file

@ -8,7 +8,7 @@ if (!AP.flat) {
try { try {
return [].concat.apply([], this); return [].concat.apply([], this);
} catch (e) { } catch (e) {
// console.log({flat_error: e}); // console.log({ flat_error: e, array: this });
let out = []; let out = [];
for (let e of this.slice()) { for (let e of this.slice()) {
out.push(...e); out.push(...e);

View file

@ -27,7 +27,7 @@ export function init(worker) {
// destructure arcs into path points // destructure arcs into path points
path = path.map(o => path = path.map(o =>
o.arcPoints ? [ ...o.arcPoints.map(point => ({ ...o, point })), o ] : o o.arcPoints ? [ ...o.arcPoints.map(point => ({ ...o, point })), o ] : [ o ]
).flat(); ).flat();
const step = rez; const step = rez;

View file

@ -3,6 +3,7 @@
// WORKER BACK END ANIMATION CODE for 3D (indexed) // WORKER BACK END ANIMATION CODE for 3D (indexed)
import { CSG } from '../../geo/csg.js'; import { CSG } from '../../geo/csg.js';
import { Tool } from './tool.js';
let nextMeshID = 1; let nextMeshID = 1;
let stock, center, rez; let stock, center, rez;
@ -269,7 +270,7 @@ function toolUpdate(toolid, send) {
if (tool) { if (tool) {
send.data({ mesh_del: toolID }); send.data({ mesh_del: toolID });
} }
tool = new CAM.Tool({ tools }, toolid); tool = new Tool({ tools }, toolid);
const Instance = CSG.Instance(); const Instance = CSG.Instance();
const slen = tool.shaftLength() || 15; const slen = tool.shaftLength() || 15;
const srad = tool.shaftDiameter() / 2; const srad = tool.shaftDiameter() / 2;

View file

@ -246,7 +246,7 @@ const opDel = (rec) => {
}; };
export function opRender() { export function opRender() {
let oplist = env.current.process.ops; let oplist = env.current?.process?.ops;
if (!(env.isCamMode && oplist)) { if (!(env.isCamMode && oplist)) {
return; return;
} }

View file

@ -1,6 +1,5 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */ /** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { broker } from '../../moto/broker.js';
import { codec } from '../../kiri/codec.js'; import { codec } from '../../kiri/codec.js';
import { newPoint } from '../../geo/point.js'; import { newPoint } from '../../geo/point.js';
import { newPolygon } from '../../geo/polygon.js'; import { newPolygon } from '../../geo/polygon.js';
@ -422,7 +421,7 @@ class Topo {
} }
class Probe { export class Probe {
constructor(params) { constructor(params) {
@ -478,7 +477,7 @@ class Probe {
} }
class Trace { export class Trace {
constructor(probe, params) { constructor(probe, params) {
@ -584,7 +583,7 @@ class Trace {
init(params) { init(params) {
this.cross = params; this.cross = params;
const { minions } = self.kiri_worker; const { minions } = self.kiri_worker ?? {};
const { clipTab, clipTabZ } = params; const { clipTab, clipTabZ } = params;
// because codec does not encode arbitrary fields // because codec does not encode arbitrary fields
@ -720,7 +719,7 @@ class Trace {
} }
} }
function raster_slice(inputs) { export function raster_slice(inputs) {
const { lines, data, box, resolution, curvesOnly } = inputs; const { lines, data, box, resolution, curvesOnly } = inputs;
const { flatness, zMin, minY, maxY, stepsY, gridx } = inputs; const { flatness, zMin, minY, maxY, stepsY, gridx } = inputs;
const { slice } = inputs; const { slice } = inputs;
@ -811,74 +810,6 @@ function raster_slice(inputs) {
return points; return points;
}; };
broker.subscribe("minion.started", msg => {
const { funcs, cache, reply, log } = msg;
funcs.topo_raster = (data, seq) => {
const { id, slice, params } = data;
const { resolution } = params;
const vertices = cache[id];
const box = new THREE.Box2();
new topo_slicer(slice.index)
.setFromArray(vertices, slice)
.slice(resolution)
.forEach(rec => {
const { z, index, lines } = rec;
for (let line of lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
if (!p2.swapped) { p2.swapXZ(); p2.swapped = true }
}
raster_slice({
...params,
box,
lines,
gridx: index
});
});
// only pass back bounds of rasters to be merged
reply({ seq, box });
};
funcs.trace_init = data => {
const { cache } = self;
data.cross.clipTo = codec.decode(data.cross.clipTo);
data.cross.clipTab = codec.decode(data.cross.clipTab);
const probe = new Probe(data.probe);
const trace = new Trace(probe, data.trace);
cache.trace = {
probe,
trace,
cross: data.cross
};
trace.init(data.cross);
};
funcs.trace_y = (data, seq) => {
const { cache } = self;
const { trace } = cache.trace;
trace.crossY_sync(data.params, slice => {
slice = codec.encode(slice);
reply({ seq, slice });
});
};
funcs.trace_x = (data, seq) => {
const { cache } = self;
const { trace } = cache.trace;
trace.crossX_sync(data.params, slice => {
slice = codec.encode(slice);
reply({ seq, slice });
});
};
funcs.trace_cleanup = () => {
delete cache.trace;
};
});
export async function generate(opt) { export async function generate(opt) {
return new Topo().generate(opt); return new Topo().generate(opt);
} }

View file

@ -1,22 +1,12 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */ /** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { base } from '../geo/base.js'; import { codec } from '../../kiri/codec.js';
import { line } from '../geo/line.js'; import { newPoint } from '../../geo/point.js';
import { point } from '../geo/point.js'; import { newPolygon } from '../../geo/polygon.js';
import { polygon } from '../geo/polygon.js'; import { sliceConnect } from '../../geo/slicer.js';
import { polygons } from '../geo/polygons.js'; import { Tool } from './tool.js';
import { broker } from '../moto/broker.js'; import { Slicer as topo_slicer } from './slicer2.js';
import { slice } from '../kiri/slice.js';
import { driver } from '../kiri-mode/cam/driver.js';
import { slicer2 } from '../kiri-mode/cam/slicer2.js';
const { base, kiri, moto } = root;
const { driver, newSlice } = kiri;
const { CAM } = driver;
const { polygons, newPoint, newPolygon, sliceConnect } = base;
const PRO = CAM.process;
const POLY = polygons;
const RAD2DEG = 180 / Math.PI; const RAD2DEG = 180 / Math.PI;
const DEG2RAD = Math.PI / 180; const DEG2RAD = Math.PI / 180;
@ -35,7 +25,7 @@ class Topo4 {
let { controller, process } = settings; let { controller, process } = settings;
let axis = op.axis.toLowerCase(), let axis = op.axis.toLowerCase(),
tool = new CAM.Tool(settings, op.tool), tool = new Tool(settings, op.tool),
bounds = widget.getBoundingBox().clone(), bounds = widget.getBoundingBox().clone(),
density = parseInt(controller.animesh || 100) * 2500, density = parseInt(controller.animesh || 100) * 2500,
{ min, max } = bounds, { min, max } = bounds,
@ -151,16 +141,15 @@ class Topo4 {
async sliceWorker(onupdate) { async sliceWorker(onupdate) {
const { vertices, slices, resolution } = this; const { vertices, slices, resolution } = this;
const { codec } = kiri;
let output = []; let output = [];
let complete = 0; let complete = 0;
for (let slice of slices) { for (let slice of slices) {
const recs = new kiri.topo_slicer(slice.index) const recs = new topo_slicer(slice.index)
.setFromArray(vertices, slice) .setFromArray(vertices, slice)
.slice(resolution) .slice(resolution)
.map(rec => { .map(rec => {
const slice = kiri.newSlice(rec.z); const slice = newSlice(rec.z);
for (let line of rec.lines) { for (let line of rec.lines) {
const { p1, p2 } = line; const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true } if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
@ -184,7 +173,6 @@ class Topo4 {
} }
async sliceMinions(onupdate) { async sliceMinions(onupdate) {
const { codec } = kiri;
const { queue, putCache, clearCache } = this; const { queue, putCache, clearCache } = this;
const { vertices, slices, resolution } = this; const { vertices, slices, resolution } = this;
putCache("vertices", vertices); putCache("vertices", vertices);
@ -474,61 +462,6 @@ function rotatePoints(lines, rot) {
new THREE.BufferAttribute(lines, 3).applyMatrix4(rot); new THREE.BufferAttribute(lines, 3).applyMatrix4(rot);
} }
CAM.Topo4 = function(opt) { export function Topo4(opt) {
return new Topo4().generate(opt); return new Topo4().generate(opt);
}; };
moto.broker.subscribe("minion.started", msg => {
const { funcs, cache, reply, log } = msg;
const { codec } = kiri;
funcs.topo4_slice = (data, seq) => {
const { slice, resolution } = data;
const vertices = cache.vertices;
const recs = new kiri.topo_slicer(slice.index)
.setFromArray(vertices, slice)
.slice(resolution)
.map(rec => {
const { z, index, lines } = rec;
for (let line of lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
if (!p2.swapped) { p2.swapXZ(); p2.swapped = true }
}
const points = codec.encodePointArray(lines.map(l => [ l.p1, l.p2 ]).flat());
const shared = new Float32Array(new SharedArrayBuffer(points.length * 4));
shared.set(points);
return {
z, index, shared,
polys: codec.encode(sliceConnect(lines)),
};
});
// only pass back bounds of rasters to be merged
reply({ seq, recs });
};
funcs.topo4_lathe = (data, seq) => {
const { angle } = data;
const { slices, tool } = cache.lathe;
const axis = new THREE.Vector3(1, 0, 0);
const mrot = new THREE.Matrix4().makeRotationAxis(axis, -angle);
const stmp = slices.map(s => {
const lines = s.lines.slice();
rotatePoints(lines, mrot);
return { z: s.z, lines }
});
const topo4 = Object.assign(new Topo4(), cache.lathe);
const heights = topo4.lathePath(stmp, tool);
reply({ seq, heights });
}
});
export { scale, rotatePoints, PRO, POLY, RAD2DEG, DEG2RAD, axis, range, slices, lathe, box, i, x, z, shards, step, index, slice, output, complete, recs, points, shared, promises, tlen, slen, sinc, heights, oslices, lines, plen, rec, py0, pz0, py1, pz1, lz, si, rx, mz, ti, xo, yo, zo, ts, dz, dy, fr, rota, steps, mrot, paths, angle, count, poly, repeat, done, tangle, p, linear, vertices, stmp, topo4, Topo4 };

View file

@ -13,6 +13,8 @@ import { newPoint } from '../geo/point.js';
import { polygons as POLY } from '../geo/polygons.js'; import { polygons as POLY } from '../geo/polygons.js';
import { sliceZ } from '../geo/slicer.js'; import { sliceZ } from '../geo/slicer.js';
import { Slicer as cam_slicer } from '../kiri-mode/cam/slicer.js'; import { Slicer as cam_slicer } from '../kiri-mode/cam/slicer.js';
import { Slicer as topo_slicer } from '../kiri-mode/cam/slicer2.js';
import { Probe, Trace, raster_slice } from '../kiri-mode/cam/topo3.js';
import { wasm_ctrl } from '../geo/wasm.js'; import { wasm_ctrl } from '../geo/wasm.js';
const clib = self.ClipperLib; const clib = self.ClipperLib;
@ -175,6 +177,8 @@ const funcs = self.minion = {
} }
}, },
// CAM slice support
cam_slice_init() { cam_slice_init() {
cache.slicer = new cam_slicer(); cache.slicer = new cam_slicer();
}, },
@ -198,4 +202,115 @@ const funcs = self.minion = {
reply({ seq, slices: data }); reply({ seq, slices: data });
}); });
}, },
// CAM Topo3 support
topo_raster(data, seq) {
const { id, slice, params } = data;
const { resolution } = params;
const vertices = cache[id];
const box = new THREE.Box2();
new topo_slicer(slice.index)
.setFromArray(vertices, slice)
.slice(resolution)
.forEach(rec => {
const { z, index, lines } = rec;
for (let line of lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
if (!p2.swapped) { p2.swapXZ(); p2.swapped = true }
}
raster_slice({
...params,
box,
lines,
gridx: index
});
});
// only pass back bounds of rasters to be merged
reply({ seq, box });
},
trace_init(data) {
data.cross.clipTo = codec.decode(data.cross.clipTo);
data.cross.clipTab = codec.decode(data.cross.clipTab);
const probe = new Probe(data.probe);
const trace = new Trace(probe, data.trace);
cache.trace = {
probe,
trace,
cross: data.cross
};
trace.init(data.cross);
},
trace_y(data, seq) {
const { trace } = cache.trace;
trace.crossY_sync(data.params, slice => {
slice = codec.encode(slice);
reply({ seq, slice });
});
},
trace_x(data, seq) {
const { trace } = cache.trace;
trace.crossX_sync(data.params, slice => {
slice = codec.encode(slice);
reply({ seq, slice });
});
},
trace_cleanup() {
delete cache.trace;
},
// CAM Topo4 support
topo4_slice(data, seq) {
const { slice, resolution } = data;
const vertices = cache.vertices;
const recs = new kiri.topo_slicer(slice.index)
.setFromArray(vertices, slice)
.slice(resolution)
.map(rec => {
const { z, index, lines } = rec;
for (let line of lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
if (!p2.swapped) { p2.swapXZ(); p2.swapped = true }
}
const points = codec.encodePointArray(lines.map(l => [ l.p1, l.p2 ]).flat());
const shared = new Float32Array(new SharedArrayBuffer(points.length * 4));
shared.set(points);
return {
z, index, shared,
polys: codec.encode(sliceConnect(lines)),
};
});
// only pass back bounds of rasters to be merged
reply({ seq, recs });
},
topo4_lathe(data, seq) {
const { angle } = data;
const { slices, tool } = cache.lathe;
const axis = new THREE.Vector3(1, 0, 0);
const mrot = new THREE.Matrix4().makeRotationAxis(axis, -angle);
const stmp = slices.map(s => {
const lines = s.lines.slice();
rotatePoints(lines, mrot);
return { z: s.z, lines }
});
const topo4 = Object.assign(new Topo4(), cache.lathe);
const heights = topo4.lathePath(stmp, tool);
reply({ seq, heights });
}
}; };