add curves-only support to gpu contour, merge co-planar point runs
This commit is contained in:
parent
14def831cd
commit
f4d7a37265
7 changed files with 84 additions and 39 deletions
|
|
@ -127,6 +127,12 @@ class Point {
|
|||
return p;
|
||||
}
|
||||
|
||||
// annotate instance with other field data (see clone())
|
||||
annotate(obj = {}) {
|
||||
Object.assign(this, obj);
|
||||
return this;
|
||||
}
|
||||
|
||||
slopeTo(p) {
|
||||
return newSlope(this, p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -908,6 +908,7 @@ export class Polygon {
|
|||
* todo make more efficient
|
||||
*
|
||||
* @param {Boolean} deep
|
||||
* @param {String[]} fields to copy beyond class fields
|
||||
* @returns {Polygon}
|
||||
*/
|
||||
clone(deep, fields) {
|
||||
|
|
@ -2145,6 +2146,7 @@ export class Polygon {
|
|||
return null;
|
||||
}
|
||||
|
||||
// annotate instance with other field data (see clone())
|
||||
annotate(obj = {}) {
|
||||
Object.assign(this, obj);
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ export function cam_export(print, online) {
|
|||
const widget = print.widgets[0];
|
||||
if (!widget) return;
|
||||
|
||||
console.log({ cam_export: print });
|
||||
|
||||
const { settings } = print;
|
||||
const { device, tools } = settings;
|
||||
const { device } = settings;
|
||||
|
||||
let i,
|
||||
time = 0,
|
||||
|
|
@ -169,7 +167,6 @@ export function cam_export(print, online) {
|
|||
function moveTo(out, opt = {}) {
|
||||
let laser = out.type === 'laser';
|
||||
let newpos = out.point;
|
||||
console.log(mode.type, out.point);
|
||||
|
||||
// no point == dwell
|
||||
// out.speed = time to dwell in ms
|
||||
|
|
|
|||
|
|
@ -113,11 +113,11 @@ class OpContour extends CamOp {
|
|||
|
||||
prepare(ops, progress) {
|
||||
let { op, state, sliceOut } = this;
|
||||
let { settings, widget } = state;
|
||||
let { settings } = state;
|
||||
let { process } = settings;
|
||||
|
||||
let { setTolerance, setTool, setSpindle, setPrintPoint } = ops;
|
||||
let { camOut, polyEmit, newLayer, printPoint, lastPoint } = ops;
|
||||
let { camOut, newLayer, printPoint, lastPoint } = ops;
|
||||
let { bounds, zmax } = ops;
|
||||
|
||||
let toolDiam = this.toolDiam;
|
||||
|
|
@ -136,9 +136,9 @@ class OpContour extends CamOp {
|
|||
if (!slice.camLines) {
|
||||
continue;
|
||||
}
|
||||
let polys = [], poly, emit;
|
||||
let polys = [], poly;
|
||||
slice.camLines.forEach(function (poly) {
|
||||
if (depthFirst) poly = poly.clone(true);
|
||||
if (depthFirst) poly = poly.clone(true).annotate({ slice: slice.index + 1 });
|
||||
polys.push({ first: poly.first(), last: poly.last(), poly: poly });
|
||||
});
|
||||
if (depthFirst) {
|
||||
|
|
@ -150,7 +150,7 @@ class OpContour extends CamOp {
|
|||
poly.reverse();
|
||||
}
|
||||
poly.forEachPoint(function (point, pidx) {
|
||||
camOut(point.clone(), pidx > 0, stepover);
|
||||
camOut(point.clone(), pidx > 0, { moveLen: stepover });
|
||||
}, false);
|
||||
});
|
||||
newLayer();
|
||||
|
|
@ -164,7 +164,7 @@ class OpContour extends CamOp {
|
|||
poly.reverse();
|
||||
}
|
||||
poly.forEachPoint(function (point, pidx) {
|
||||
camOut(point.clone(), pidx > 0, stepover);
|
||||
camOut(point.clone().annotate({ slice: poly.slice }), pidx > 0, { moveLen: stepover });
|
||||
}, false);
|
||||
newLayer();
|
||||
return lastPoint();
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
stockz = stock.z * (isIndexed ? 0.5 : 1),
|
||||
outer = settings.bounds || widget.getPositionBox(),
|
||||
outerz = outer.max.z,
|
||||
// slices = widget.slices,
|
||||
zclear = (process.camZClearance || 1),
|
||||
zmax_force = process.camForceZMax || false,
|
||||
zmax_outer = stockz + zclear,
|
||||
|
|
@ -81,7 +80,6 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
originx = (startCenter ? 0 : -stock.x / 2) + (process.camOriginOffX || 0),
|
||||
originy = (startCenter ? 0 : -stock.y / 2) + (process.camOriginOffY || 0),
|
||||
origin = newPoint(originx + wmx, originy + wmy, zmax),
|
||||
// output = print.output,
|
||||
easeDown = process.camEaseDown,
|
||||
easeAngle = process.camEaseAngle,
|
||||
depthFirst = process.camDepthFirst,
|
||||
|
|
@ -99,7 +97,6 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
newOutput = print.output || [],
|
||||
layerOut = [],
|
||||
printPoint,
|
||||
// isNewMode,
|
||||
isPocket,
|
||||
isContour,
|
||||
isRough,
|
||||
|
|
@ -263,8 +260,8 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
*/
|
||||
function layerPush(point, emit, speed, tool, options) {
|
||||
const { type, center, arcPoints } = options ?? {};
|
||||
const dz = (point && lastPush && lastPush.point) ? point.z - lastPush.point.z : 0;
|
||||
if (dz < 0 && speed > plungeRate) {
|
||||
const dz = (point && lastPush?.point) ? point.z - lastPush.point.z : 0;
|
||||
if (dz < -0.05 && speed > plungeRate) {
|
||||
speed = plungeRate;
|
||||
}
|
||||
// if (options?.type !== 'lerp') console.log( point, currentOp.type );
|
||||
|
|
@ -320,7 +317,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
p.x + wmx,
|
||||
p.y + wmy,
|
||||
p.z + zadd
|
||||
).setA(p.a ?? lastPoint?.a);
|
||||
).setA(p.a ?? lastPoint?.a).annotate({ slice: p.slice });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -359,14 +356,12 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
factor = 1,
|
||||
} = opts ?? {}
|
||||
|
||||
// console.log({radius})
|
||||
const isArc = emit == 2 || emit == 3;
|
||||
const pointA = point.a;
|
||||
|
||||
// apply widget movement pos
|
||||
const pointA = point.a;
|
||||
point = applyWidgetMovement(point);
|
||||
|
||||
// console.log(point.z);
|
||||
if (nextIsMove) {
|
||||
emit = 0;
|
||||
nextIsMove = false;
|
||||
|
|
@ -429,6 +424,9 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
return;
|
||||
}
|
||||
|
||||
// no jump moves in contour mode to adjacent slice points
|
||||
let steady = lastPoint && currentOp.type === 'contour' && Math.abs(point.slice - lastPoint.slice) < 4;
|
||||
|
||||
// convert short planar moves to cuts in some cases
|
||||
if (hasDelta && !isArc && isMove && deltaXY <= moveLen && deltaZ <= 0 && !lasering) {
|
||||
let iscontour = tolerance > 0;
|
||||
|
|
@ -438,7 +436,6 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
emit = 1;
|
||||
isMove = false;
|
||||
} else if (deltaZ <= -tolerance) {
|
||||
console.log({ deltaZ, tolerance, iscontour });
|
||||
// move over before descending
|
||||
layerPush(point.clone().setZ(lastPoint.z), 0, 0, tool);
|
||||
// new pos for plunge calc
|
||||
|
|
@ -450,7 +447,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
} else if (point.z < lastPoint.z) {
|
||||
layerPush(point.clone().setZ(lastPoint.z), 0, 0, tool);
|
||||
}
|
||||
} else if (isMove) {
|
||||
} else if (isMove && !steady) {
|
||||
// for longer moves, check the terrain to see if we need to go up and over
|
||||
const bigXY = (deltaXY > moveLen && !lasering);
|
||||
const bigZ = (deltaZ > toolDiam / 2 && deltaXY > tolerance);
|
||||
|
|
@ -497,13 +494,15 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
}
|
||||
|
||||
// set new plunge rate
|
||||
let tmprate;
|
||||
if (false)
|
||||
if (!lasering && !isLathe && deltaZ < -tolerance) {
|
||||
let threshold = Math.min(deltaXY / 2, absDeltaZ),
|
||||
modifier = threshold / absDeltaZ;
|
||||
if (synthPlunge && threshold && modifier && deltaXY > tolerance) {
|
||||
// use modifier to speed up long XY move plunge rates
|
||||
// console.log('modifier', modifier);
|
||||
rate = Math.max(
|
||||
tmprate = Math.max(
|
||||
plungeRate,
|
||||
Math.round(plungeRate + ((feedRate - plungeRate) * modifier))
|
||||
);
|
||||
|
|
@ -511,7 +510,8 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
let L = Math.hypot(deltaXY, absDeltaZ);
|
||||
let limXY = feedRate * L / deltaXY;
|
||||
let limZ = plungeRate * L / Math.abs(deltaZ);
|
||||
rate = Math.min(feedRate, limXY, limZ);
|
||||
tmprate = Math.min(feedRate, limXY, limZ);
|
||||
console.log({ rate_override: rate, was: rate });
|
||||
// let zps = len / absDeltaZ;
|
||||
// rate = Math.max(
|
||||
// plungeRate,
|
||||
|
|
@ -527,7 +527,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
lastPoint = layerPush(
|
||||
point,
|
||||
clockwise ? 2 : 3,
|
||||
rate,
|
||||
tmprate ?? rate,
|
||||
tool,
|
||||
{
|
||||
center,
|
||||
|
|
@ -542,7 +542,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
lastPoint = layerPush(
|
||||
point,
|
||||
emit,
|
||||
rate,
|
||||
tmprate ?? rate,
|
||||
tool
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { newSlice } from '../../core/slice.js';
|
|||
import { Slicer as topo_slicer } from './slicer_topo.js';
|
||||
import { polygons as POLY } from '../../../geo/polygons.js';
|
||||
import { Tool } from './tool.js';
|
||||
import { poly2polyEmit } from '../../../geo/paths.js';
|
||||
|
||||
const RAD2DEG = 180 / Math.PI;
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
|
|
@ -42,7 +43,7 @@ export class Topo {
|
|||
tool = new Tool(settings, contour.tool),
|
||||
toolOffset = tool.generateProfile(resolution).profile,
|
||||
toolDiameter = tool.fluteDiameter(),
|
||||
toolStep = toolDiameter * contour.step, //tool.contourOffset(contour.step),
|
||||
toolStep = toolDiameter * contour.step,
|
||||
leave = contour.leave || 0,
|
||||
maxangle = contour.angle,
|
||||
curvesOnly = contour.curves,
|
||||
|
|
@ -75,12 +76,7 @@ export class Topo {
|
|||
clipTo = inside ? shadow : POLY.expand(shadow, toolDiameter / 2 + resolution * 3),
|
||||
partOff = inside ? 0 : toolDiameter / 2 + resolution,
|
||||
gridDelta = Math.floor(partOff / resolution),
|
||||
debug = false,
|
||||
debug_clips = debug && true,
|
||||
debug_topo = debug && true,
|
||||
debug_topo_lines = debug && true,
|
||||
debug_topo_shells = debug && true,
|
||||
time = Date.now;
|
||||
debug_clips = false;
|
||||
|
||||
if (tolerance === 0 && !topoCache) {
|
||||
console.log(widget.id, 'topo auto tolerance', resolution.round(4));
|
||||
|
|
@ -142,7 +138,7 @@ export class Topo {
|
|||
});
|
||||
let xStep = density;
|
||||
let yStep = Math.ceil(toolStep / resolution);
|
||||
let epsilon = 10e-5;
|
||||
let epsilon = 10e-4;
|
||||
await gpu.loadTool({
|
||||
sparseData: toolData
|
||||
});
|
||||
|
|
@ -180,7 +176,7 @@ export class Topo {
|
|||
;
|
||||
let slice = newSlice(i);
|
||||
let poly = newPolygon().setOpen();
|
||||
let lines = slice.camLines = [ ];
|
||||
let lines = [ ];
|
||||
let skip = 0;
|
||||
let lp;
|
||||
for (let p of points) {
|
||||
|
|
@ -216,9 +212,11 @@ export class Topo {
|
|||
poly.push(lp = p);
|
||||
skip = 0;
|
||||
}
|
||||
// require two points or more
|
||||
if (poly.length > 1) {
|
||||
lines.push(poly);
|
||||
}
|
||||
// raize output points when inside tab boundaries
|
||||
if (!inside && tabsOn && clipTab.length)
|
||||
for (let poly of lines) {
|
||||
for (let p of poly.points) {
|
||||
|
|
@ -230,6 +228,49 @@ export class Topo {
|
|||
}
|
||||
}
|
||||
}
|
||||
// drop interior points along a continuous slope
|
||||
for (let poly of lines) {
|
||||
let { points } = poly;
|
||||
let merged = [ points[0] ];
|
||||
let lp = points[1];
|
||||
let dz = points[0].z - lp.z;
|
||||
for (let i=2; i<points.length; i++) {
|
||||
let np = points[i];
|
||||
let ndz = np.z - lp.z;
|
||||
if (Math.abs(dz - ndz) > epsilon) {
|
||||
// slope changed
|
||||
merged.push(lp);
|
||||
dz = ndz;
|
||||
} else if (curvesOnly && Math.abs(ndz) < epsilon) {
|
||||
// add empty points as path separators
|
||||
merged.push(undefined);
|
||||
}
|
||||
lp = np;
|
||||
}
|
||||
if (merged.peek() !== lp) {
|
||||
merged.push(lp);
|
||||
}
|
||||
poly.points = merged;
|
||||
}
|
||||
// drop flat regions when enabled
|
||||
if (curvesOnly) {
|
||||
let nulines = [];
|
||||
for (let poly of lines) {
|
||||
let { points } = poly;
|
||||
let newp = [];
|
||||
for (let p of points) {
|
||||
if (p) {
|
||||
newp.push(p);
|
||||
} else if (newp.length) {
|
||||
nulines.push(newPolygon(newp).setOpen());
|
||||
newp = [];
|
||||
}
|
||||
}
|
||||
nulines.push(newPolygon(newp).setOpen());
|
||||
}
|
||||
lines = nulines.filter(p => p.perimeter() > toolStep);
|
||||
}
|
||||
slice.camLines = lines;
|
||||
slices.push(slice);
|
||||
if (inside) {
|
||||
onupdate(i, numScanlines);
|
||||
|
|
@ -659,9 +700,9 @@ export class Trace {
|
|||
console.log(...arguments);
|
||||
}
|
||||
|
||||
const push_point = this.push_point = function (x, y, z) {
|
||||
this.push_point = function (x, y, z) {
|
||||
const newP = newPoint(x, y, z);
|
||||
const lastP = lastPP;//trace.last();
|
||||
const lastP = lastPP;
|
||||
|
||||
if (lastP) {
|
||||
const dl = (x - lastP.x) || (y - lastP.y);
|
||||
|
|
@ -678,7 +719,6 @@ export class Trace {
|
|||
}
|
||||
if (curvesOnly) {
|
||||
const dv = contourX ? Math.abs(lastP.x - x) : Math.abs(lastP.y - y);
|
||||
// const dz = lastPP.z - z;
|
||||
const angle = Math.atan2(Math.abs(dz), dv) * RAD2DEG;
|
||||
if (angle > maxangle) {
|
||||
end_poly();
|
||||
|
|
|
|||
|
|
@ -321,10 +321,10 @@ self.lang['en-us'] = {
|
|||
pt_heal_l: ["attempt to heal non-manifold meshes during slicing. may increase slicing time. enables a warning when non-manifold geometries are detected."],
|
||||
pt_thrd_s: "threaded",
|
||||
pt_thrd_l: ["use parallel processing when browser supports nested workers. may increase memory pressure on larger models. disable if you are getting out of memory errors"],
|
||||
pt_assy_s: "assembly",
|
||||
pt_assy_s: "web asm",
|
||||
pt_assy_l: ["use web assembly when supported by browser. if you experience artifacts or memory errors, try disabling this."],
|
||||
pt_wgpu_s: "web gpu",
|
||||
pt_wgpu_l: ["use web gpu when supported by browser"],
|
||||
pt_wgpu_l: ["use web gpu when supported by browser. if you experience artifacts or memory errors, try disabling this."],
|
||||
|
||||
xp_menu: "exports",
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue