speed up true shadow computation. progressively compute shadow in all cases. hide ops on view change
This commit is contained in:
parent
230af26640
commit
7650ce0640
4 changed files with 73 additions and 64 deletions
|
|
@ -13,6 +13,8 @@ Full docs @ https://docs.grid.space/projects/kiri-moto
|
||||||
* `C` fix CAM output order for tool changes an spindle speed updates
|
* `C` fix CAM output order for tool changes an spindle speed updates
|
||||||
* `C` add CAM pocket operation using surface selection
|
* `C` add CAM pocket operation using surface selection
|
||||||
* `C` fix dogbones on outlines cut by tabs
|
* `C` fix dogbones on outlines cut by tabs
|
||||||
|
* `C` skip pockets that resolve to null
|
||||||
|
* `C` 10x speedup for true shadow generation
|
||||||
* `-` refactor cnc to use new core slicer engine
|
* `-` refactor cnc to use new core slicer engine
|
||||||
* `-` improve vertex replacement and widget update matrix tracking
|
* `-` improve vertex replacement and widget update matrix tracking
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ CAM.init = function(kiri, api) {
|
||||||
isAnimate = false;
|
isAnimate = false;
|
||||||
CAM.animate_clear(api);
|
CAM.animate_clear(api);
|
||||||
func.clearPops();
|
func.clearPops();
|
||||||
|
$('camops').style.display = isCamMode && isArrange ? 'flex' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
api.event.on("settings.saved", (settings) => {
|
api.event.on("settings.saved", (settings) => {
|
||||||
|
|
@ -271,7 +272,7 @@ CAM.init = function(kiri, api) {
|
||||||
});
|
});
|
||||||
|
|
||||||
api.event.on("cam.op.render", func.opRender = () => {
|
api.event.on("cam.op.render", func.opRender = () => {
|
||||||
$('camops').style.display = isCamMode && isArrange ? 'flex' : '';
|
// $('camops').style.display = isCamMode && isArrange ? 'flex' : '';
|
||||||
let oplist = current.process.ops;
|
let oplist = current.process.ops;
|
||||||
if (!(isCamMode && oplist)) return;
|
if (!(isCamMode && oplist)) return;
|
||||||
let mark = Date.now();
|
let mark = Date.now();
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ class OpRough extends CamOp {
|
||||||
let { op, state } = this;
|
let { op, state } = this;
|
||||||
let { settings, widget, slicer, sliceAll, unsafe, color } = state;
|
let { settings, widget, slicer, sliceAll, unsafe, color } = state;
|
||||||
let { updateToolDiams, thruHoles, tabs, cutTabs, cutPolys } = state;
|
let { updateToolDiams, thruHoles, tabs, cutTabs, cutPolys } = state;
|
||||||
let { tshadow, shadowTop, ztOff, zBottom, zMax } = state;
|
let { tshadow, shadowTop, ztOff, zBottom, zMax, shadowAt } = state;
|
||||||
let { process, stock } = settings;
|
let { process, stock } = settings;
|
||||||
|
|
||||||
if (op.down <= 0) {
|
if (op.down <= 0) {
|
||||||
|
|
@ -204,7 +204,8 @@ class OpRough extends CamOp {
|
||||||
// exclude flats injected to complete shadow
|
// exclude flats injected to complete shadow
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.shadow = trueShadow ? CAM.shadowAt(widget, data.z) : shadow.clone(true);
|
// data.shadow = trueShadow ? CAM.shadowAt(widget, data.z) : shadow.clone(true);
|
||||||
|
data.shadow = trueShadow ? shadowAt(data.z) : shadow.clone(true);
|
||||||
data.slice.shadow = data.shadow;
|
data.slice.shadow = data.shadow;
|
||||||
// data.slice.tops[0].inner = data.shadow;
|
// data.slice.tops[0].inner = data.shadow;
|
||||||
// data.slice.tops[0].inner = POLY.setZ(tshadow.clone(true), data.z);
|
// data.slice.tops[0].inner = POLY.setZ(tshadow.clone(true), data.z);
|
||||||
|
|
@ -926,7 +927,7 @@ class OpPocket extends CamOp {
|
||||||
let { op, state } = this;
|
let { op, state } = this;
|
||||||
let { tool, rate, down, plunge, expand } = op;
|
let { tool, rate, down, plunge, expand } = op;
|
||||||
let { settings, widget, sliceAll, zMax, zTop, zThru, tabs } = state;
|
let { settings, widget, sliceAll, zMax, zTop, zThru, tabs } = state;
|
||||||
let { updateToolDiams, cutTabs, cutPolys, healPolys } = state;
|
let { updateToolDiams, cutTabs, cutPolys, healPolys, shadowAt } = state;
|
||||||
let { process, stock } = settings;
|
let { process, stock } = settings;
|
||||||
// generate tracing offsets from chosen features
|
// generate tracing offsets from chosen features
|
||||||
let sliceOut = this.sliceOut = [];
|
let sliceOut = this.sliceOut = [];
|
||||||
|
|
@ -945,35 +946,13 @@ class OpPocket extends CamOp {
|
||||||
sliceOut.push(slice);
|
sliceOut.push(slice);
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
let shadows = {};
|
|
||||||
function genShadows(zs) {
|
|
||||||
for (let z of zs) {
|
|
||||||
if (shadows[z]) continue;
|
|
||||||
// find closest shadow above and use
|
|
||||||
let minzkey;
|
|
||||||
let zover = Object.keys(shadows).map(v => parseFloat(v)).filter(v => v > z);
|
|
||||||
for (let zkey of zover) {
|
|
||||||
if (minzkey && zkey < minzkey) {
|
|
||||||
minzkey = zkey;
|
|
||||||
} else {
|
|
||||||
minzkey = zkey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let shadow = CAM.shadowAt(widget, z + 0.001, minzkey);
|
|
||||||
if (minzkey) {
|
|
||||||
shadow = POLY.union([...shadow, ...shadows[minzkey]], undefined, true);
|
|
||||||
}
|
|
||||||
shadows[z] = POLY.setZ(shadow, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function clearZ(polys, z, down) {
|
function clearZ(polys, z, down) {
|
||||||
let zs = down ? base.util.lerp(zTop, z, down) : [ z ];
|
let zs = down ? base.util.lerp(zTop, z, down) : [ z ];
|
||||||
if (expand) polys = POLY.offset(polys, expand);
|
if (expand) polys = POLY.offset(polys, expand);
|
||||||
let zpro = 0, zinc = pinc / (polys.length * zs.length);
|
let zpro = 0, zinc = pinc / (polys.length * zs.length);
|
||||||
for (let poly of polys) {
|
for (let poly of polys) {
|
||||||
genShadows(zs);
|
|
||||||
for (let z of zs) {
|
for (let z of zs) {
|
||||||
let shadow = shadows[z];
|
let shadow = shadowAt(z);
|
||||||
let clip = [];
|
let clip = [];
|
||||||
POLY.subtract([ poly ], shadow, clip);
|
POLY.subtract([ poly ], shadow, clip);
|
||||||
let slice = newSliceOut(z);
|
let slice = newSliceOut(z);
|
||||||
|
|
@ -1016,6 +995,9 @@ class OpPocket extends CamOp {
|
||||||
outline = POLY.union(outline, 0.0001, true);
|
outline = POLY.union(outline, 0.0001, true);
|
||||||
outline = POLY.setWinding(outline, cutdir, false);
|
outline = POLY.setWinding(outline, cutdir, false);
|
||||||
outline = healPolys(outline);
|
outline = healPolys(outline);
|
||||||
|
if (outline.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (false) newSliceOut(zmin).output()
|
if (false) newSliceOut(zmin).output()
|
||||||
.setLayer("pocket area", {line: 0x1188ff}, false)
|
.setLayer("pocket area", {line: 0x1188ff}, false)
|
||||||
.addPolys(outline)
|
.addPolys(outline)
|
||||||
|
|
@ -1315,7 +1297,7 @@ class OpShadow extends CamOp {
|
||||||
|
|
||||||
slice(progress) {
|
slice(progress) {
|
||||||
let state = this.state;
|
let state = this.state;
|
||||||
let { ops, slicer, widget, unsafe, sliceAll } = state;
|
let { ops, slicer, widget, unsafe, sliceAll, shadowAt } = state;
|
||||||
|
|
||||||
let real = ops.map(rec => rec.op).filter(op => op);
|
let real = ops.map(rec => rec.op).filter(op => op);
|
||||||
let drill = real.filter(op => op.type === 'drill').length > 0;
|
let drill = real.filter(op => op.type === 'drill').length > 0;
|
||||||
|
|
@ -1341,8 +1323,9 @@ class OpShadow extends CamOp {
|
||||||
|
|
||||||
let lsz; // only shadow up to bottom of last shadow for progressive union
|
let lsz; // only shadow up to bottom of last shadow for progressive union
|
||||||
let terrain = slicer.slice(tzindex, { each: (data, index, total) => {
|
let terrain = slicer.slice(tzindex, { each: (data, index, total) => {
|
||||||
let shadowAt = trueShadow ? CAM.shadowAt(widget, data.z, lsz) : [];
|
// let shadow = trueShadow ? CAM.shadowAt(widget, data.z, lsz) : [];
|
||||||
tshadow = POLY.union(tshadow.slice().appendAll(data.tops).appendAll(shadowAt), 0.01, true);
|
let shadow = trueShadow ? shadowAt(data.z, lsz) : [];
|
||||||
|
tshadow = POLY.union(tshadow.slice().appendAll(data.tops).appendAll(shadow), 0.01, true);
|
||||||
tslices.push(data.slice);
|
tslices.push(data.slice);
|
||||||
data.slice.shadow = tshadow;
|
data.slice.shadow = tshadow;
|
||||||
if (false) {
|
if (false) {
|
||||||
|
|
@ -1373,8 +1356,8 @@ class OpShadow extends CamOp {
|
||||||
|
|
||||||
state.shadowTop = terrain[terrain.length - 1];
|
state.shadowTop = terrain[terrain.length - 1];
|
||||||
state.center = tshadow[0].bounds.center();
|
state.center = tshadow[0].bounds.center();
|
||||||
state.tshadow = tshadow;
|
state.tshadow = tshadow; // true shadow (bottom of part)
|
||||||
state.terrain = terrain;
|
state.terrain = terrain; // stack of shadow slices with tops
|
||||||
state.tslices = tslices;
|
state.tslices = tslices;
|
||||||
state.skipTerrain = skipTerrain;
|
state.skipTerrain = skipTerrain;
|
||||||
|
|
||||||
|
|
@ -1383,27 +1366,34 @@ class OpShadow extends CamOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// union triangles > z (opt cap < ztop) into polygon(s)
|
||||||
CAM.shadowAt = function(widget, z, ztop) {
|
CAM.shadowAt = function(widget, z, ztop) {
|
||||||
let geo = widget.cache.geo || new THREE.BufferGeometry()
|
const geo = widget.cache.geo || new THREE.BufferGeometry()
|
||||||
.setAttribute('position', new THREE.BufferAttribute(widget.vertices, 3));
|
.setAttribute('position', new THREE.BufferAttribute(widget.vertices, 3));
|
||||||
widget.cache.geo = geo;
|
widget.cache.geo = geo;
|
||||||
let rad = (Math.PI / 180);
|
const { position } = geo.attributes;
|
||||||
let deg = (180 / Math.PI);
|
const { itemSize, count, array } = position;
|
||||||
let angle = rad * 1;
|
// cache faces with normals up
|
||||||
let thresh = -Math.sin(angle);
|
if (!widget._shadow_faces) {
|
||||||
let found = [];
|
const faces = [];
|
||||||
let { position } = geo.attributes;
|
for (let i=0, ip=0; i<count; i += itemSize) {
|
||||||
let { itemSize, count, array } = position;
|
const a = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
||||||
if (widget._shadow_array) {
|
const b = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
||||||
array = widget._shadow_array;
|
const c = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
||||||
} else {
|
const n = THREE.computeFaceNormal(a,b,c);
|
||||||
array = widget._shadow_array = [...array].map(v => v.round(3));
|
if (n.z > 0.001) {
|
||||||
|
faces.push(a,b,c);
|
||||||
}
|
}
|
||||||
for (let i = 0; i<count; i += 3) {
|
}
|
||||||
let ip = i * itemSize;
|
widget._shadow_faces = faces;
|
||||||
let a = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
}
|
||||||
let b = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
const found = [];
|
||||||
let c = new THREE.Vector3(array[ip++], array[ip++], array[ip++]);
|
const faces = widget._shadow_faces;
|
||||||
|
const { checkOverUnderOn, intersectPoints } = self.kiri.cam_slicer;
|
||||||
|
for (let i=0; i<faces.length; ) {
|
||||||
|
const a = faces[i++];
|
||||||
|
const b = faces[i++];
|
||||||
|
const c = faces[i++];
|
||||||
let where = undefined;
|
let where = undefined;
|
||||||
if (ztop && a.z > ztop && b.z > ztop && c.z > ztop) {
|
if (ztop && a.z > ztop && b.z > ztop && c.z > ztop) {
|
||||||
// skip faces over top threshold
|
// skip faces over top threshold
|
||||||
|
|
@ -1413,19 +1403,10 @@ CAM.shadowAt = function(widget, z, ztop) {
|
||||||
// skip faces under threshold
|
// skip faces under threshold
|
||||||
continue;
|
continue;
|
||||||
} else if (a.z > z && b.z > z && c.z > z) {
|
} else if (a.z > z && b.z > z && c.z > z) {
|
||||||
// limit to selected faces over threshold
|
|
||||||
let norm = THREE.computeFaceNormal(a,b,c);
|
|
||||||
if (norm.z < thresh) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
found.push([a,b,c]);
|
found.push([a,b,c]);
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
// check faces straddling threshold
|
// check faces straddling threshold
|
||||||
where = {under: [], over: [], on: []};
|
const where = { under: [], over: [], on: [] };
|
||||||
}
|
|
||||||
if (where) {
|
|
||||||
let { checkOverUnderOn, intersectPoints } = self.kiri.cam_slicer;
|
|
||||||
checkOverUnderOn(newPoint(a.x, a.y, a.z), z, where);
|
checkOverUnderOn(newPoint(a.x, a.y, a.z), z, where);
|
||||||
checkOverUnderOn(newPoint(b.x, b.y, b.z), z, where);
|
checkOverUnderOn(newPoint(b.x, b.y, b.z), z, where);
|
||||||
checkOverUnderOn(newPoint(c.x, c.y, c.z), z, where);
|
checkOverUnderOn(newPoint(c.x, c.y, c.z), z, where);
|
||||||
|
|
@ -1445,11 +1426,7 @@ CAM.shadowAt = function(widget, z, ztop) {
|
||||||
console.log({msg: "invalid ips", line: line, where: where});
|
console.log({msg: "invalid ips", line: line, where: where});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
found.push([a,b,c]);
|
|
||||||
}
|
}
|
||||||
let polys = found.map(a => {
|
let polys = found.map(a => {
|
||||||
return newPolygon()
|
return newPolygon()
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,34 @@ CAM.slice = function(settings, widget, onupdate, ondone) {
|
||||||
maxToolDiam = Math.max(maxToolDiam, toolDiam);
|
maxToolDiam = Math.max(maxToolDiam, toolDiam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let shadows = {};
|
||||||
|
|
||||||
|
function shadowAt(z) {
|
||||||
|
let cached = shadows[z];
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
// find closest shadow above and use to speed up delta shadow gen
|
||||||
|
let minZabove;
|
||||||
|
let zover = Object.keys(shadows).map(v => parseFloat(v)).filter(v => v > z);
|
||||||
|
for (let zkey of zover) {
|
||||||
|
if (minZabove && zkey < minZabove) {
|
||||||
|
minZabove = zkey;
|
||||||
|
} else {
|
||||||
|
minZabove = zkey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let shadow = CAM.shadowAt(widget, z, minZabove);
|
||||||
|
if (minZabove) {
|
||||||
|
// const merge = shadow.length;
|
||||||
|
// const plus = shadows[minZabove].length;
|
||||||
|
// const mark = Date.now();
|
||||||
|
shadow = POLY.union([...shadow, ...shadows[minZabove]], 0.0011, true);
|
||||||
|
// console.log({merge, plus, equals: shadow.length, time: Date.now() - mark});
|
||||||
|
}
|
||||||
|
return shadows[z] = POLY.setZ(shadow, z);
|
||||||
|
}
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
settings,
|
settings,
|
||||||
widget,
|
widget,
|
||||||
|
|
@ -115,6 +143,7 @@ CAM.slice = function(settings, widget, onupdate, ondone) {
|
||||||
cutTabs,
|
cutTabs,
|
||||||
cutPolys,
|
cutPolys,
|
||||||
healPolys,
|
healPolys,
|
||||||
|
shadowAt,
|
||||||
slicer,
|
slicer,
|
||||||
sliceAll,
|
sliceAll,
|
||||||
updateToolDiams,
|
updateToolDiams,
|
||||||
|
|
@ -138,7 +167,7 @@ CAM.slice = function(settings, widget, onupdate, ondone) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let opSum = 0;
|
let opSum = 0;
|
||||||
let opTot = opList.map(op => op.weight()).reduce((a,v) => a + v);
|
let opTot = opList.length ? opList.map(op => op.weight()).reduce((a,v) => a + v) : 0;
|
||||||
|
|
||||||
for (let op of proc.ops.filter(op => !op.disabled)) {
|
for (let op of proc.ops.filter(op => !op.disabled)) {
|
||||||
let opfn = OPS[op.type];
|
let opfn = OPS[op.type];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue