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 {
return [].concat.apply([], this);
} catch (e) {
// console.log({flat_error: e});
// console.log({ flat_error: e, array: this });
let out = [];
for (let e of this.slice()) {
out.push(...e);

View file

@ -27,7 +27,7 @@ export function init(worker) {
// destructure arcs into path points
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();
const step = rez;

View file

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

View file

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

View file

@ -1,6 +1,5 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { broker } from '../../moto/broker.js';
import { codec } from '../../kiri/codec.js';
import { newPoint } from '../../geo/point.js';
import { newPolygon } from '../../geo/polygon.js';
@ -422,7 +421,7 @@ class Topo {
}
class Probe {
export class Probe {
constructor(params) {
@ -478,7 +477,7 @@ class Probe {
}
class Trace {
export class Trace {
constructor(probe, params) {
@ -584,7 +583,7 @@ class Trace {
init(params) {
this.cross = params;
const { minions } = self.kiri_worker;
const { minions } = self.kiri_worker ?? {};
const { clipTab, clipTabZ } = params;
// 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 { flatness, zMin, minY, maxY, stepsY, gridx } = inputs;
const { slice } = inputs;
@ -811,74 +810,6 @@ function raster_slice(inputs) {
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) {
return new Topo().generate(opt);
}

View file

@ -1,22 +1,12 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { base } from '../geo/base.js';
import { line } from '../geo/line.js';
import { point } from '../geo/point.js';
import { polygon } from '../geo/polygon.js';
import { polygons } from '../geo/polygons.js';
import { broker } from '../moto/broker.js';
import { slice } from '../kiri/slice.js';
import { driver } from '../kiri-mode/cam/driver.js';
import { slicer2 } from '../kiri-mode/cam/slicer2.js';
import { codec } from '../../kiri/codec.js';
import { newPoint } from '../../geo/point.js';
import { newPolygon } from '../../geo/polygon.js';
import { sliceConnect } from '../../geo/slicer.js';
import { Tool } from './tool.js';
import { Slicer as topo_slicer } from './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 DEG2RAD = Math.PI / 180;
@ -35,7 +25,7 @@ class Topo4 {
let { controller, process } = settings;
let axis = op.axis.toLowerCase(),
tool = new CAM.Tool(settings, op.tool),
tool = new Tool(settings, op.tool),
bounds = widget.getBoundingBox().clone(),
density = parseInt(controller.animesh || 100) * 2500,
{ min, max } = bounds,
@ -151,16 +141,15 @@ class Topo4 {
async sliceWorker(onupdate) {
const { vertices, slices, resolution } = this;
const { codec } = kiri;
let output = [];
let complete = 0;
for (let slice of slices) {
const recs = new kiri.topo_slicer(slice.index)
const recs = new topo_slicer(slice.index)
.setFromArray(vertices, slice)
.slice(resolution)
.map(rec => {
const slice = kiri.newSlice(rec.z);
const slice = newSlice(rec.z);
for (let line of rec.lines) {
const { p1, p2 } = line;
if (!p1.swapped) { p1.swapXZ(); p1.swapped = true }
@ -184,7 +173,6 @@ class Topo4 {
}
async sliceMinions(onupdate) {
const { codec } = kiri;
const { queue, putCache, clearCache } = this;
const { vertices, slices, resolution } = this;
putCache("vertices", vertices);
@ -474,61 +462,6 @@ function rotatePoints(lines, rot) {
new THREE.BufferAttribute(lines, 3).applyMatrix4(rot);
}
CAM.Topo4 = function(opt) {
export function Topo4(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 { sliceZ } from '../geo/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';
const clib = self.ClipperLib;
@ -175,6 +177,8 @@ const funcs = self.minion = {
}
},
// CAM slice support
cam_slice_init() {
cache.slicer = new cam_slicer();
},
@ -198,4 +202,115 @@ const funcs = self.minion = {
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 });
}
};