Merge branch 'rel-4.3' of https://github.com/GridSpace/grid-apps into drill-optimization
This commit is contained in:
commit
cd462709d7
37 changed files with 955 additions and 223 deletions
|
|
@ -1,7 +1,7 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../core/api.js';
|
||||
import { env, opRender } from './client.js';
|
||||
import { env, opAdd, opRender } from './client.js';
|
||||
import { CAM } from './driver-fe.js';
|
||||
import { clearTabs, restoreTabs } from './cl-tab.js';
|
||||
import { updateStock } from './cl-stock.js';
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export function createTabBox(iw, ic, n) {
|
|||
const { camZBottom, camStockIndexed } = process;
|
||||
const sz = stock.z || bounds.max.z;
|
||||
const zto = sz - iw.track.top;
|
||||
const zp = (env.camZBottom || camStockIndexed ? env.camZBottom : sz - track.box.d - zto) + (camTabsMidline ? 0 : camTabsHeight / 2);
|
||||
const zp = (camZBottom || camStockIndexed ? camZBottom : sz - track.box.d - zto) + (camTabsMidline ? 0 : camTabsHeight / 2);
|
||||
ic.x += n.x * camTabsDepth / 2; // offset from part
|
||||
ic.z -= n.y * camTabsDepth / 2; // offset swap z,y
|
||||
ic.y = zp; // offset swap in world space y,z
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ const traceClear = () => {
|
|||
api.conf.save();
|
||||
};
|
||||
|
||||
const opAdd = (rec) => {
|
||||
export const opAdd = (rec) => {
|
||||
if (!env.isCamMode) return;
|
||||
clearPops();
|
||||
let oplist = env.current.process.ops;
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ export function cam_export(print, online) {
|
|||
lasering = false,
|
||||
laserOp,
|
||||
stock = settings.stock || {},
|
||||
ztOff = stock.z - widget.track.top,
|
||||
bounds = widget.getBoundingBox(),
|
||||
zmax = stock.z,
|
||||
runbox = {
|
||||
max: { x: -Infinity, y: -Infinity, z: -Infinity },
|
||||
|
|
@ -234,7 +232,7 @@ export function cam_export(print, online) {
|
|||
// speed: Infinity,
|
||||
tool: out.tool,
|
||||
point: { x: newpos.x, y: newpos.y, z: newpos.z, a: pos.a },
|
||||
emit: 1,
|
||||
emit: out.emit,
|
||||
}, {
|
||||
dx: 1, dy: 1, dz: 0, time: 0
|
||||
});
|
||||
|
|
@ -251,7 +249,7 @@ export function cam_export(print, online) {
|
|||
// speed: Infinity,
|
||||
tool: out.tool,
|
||||
point: { x: newpos.x, y: newpos.y, z: newpos.z, a: newpos.a },
|
||||
emit: 1
|
||||
emit: out.emit
|
||||
}, {
|
||||
dx: 0, dy: 0, dz: 1, time: 0
|
||||
});
|
||||
|
|
@ -274,6 +272,9 @@ export function cam_export(print, online) {
|
|||
dist = Math.sqrt(dx * dx + dy * dy + dz * dz),
|
||||
newFeed = feed && feed !== pos.f;
|
||||
|
||||
// catch NaN in debugging
|
||||
// if (nl.length === 0 || nl[0] === undefined)
|
||||
// console.log(out, nl.length, ...nl);
|
||||
|
||||
// drop dup points (all deltas are 0)
|
||||
if (!arc && !(dx || dy || dz || da)) {
|
||||
|
|
@ -408,7 +409,7 @@ export function cam_export(print, online) {
|
|||
|
||||
// collect tool info to add to header
|
||||
let toolz = {}, ctool;
|
||||
const isOffset = offset && (offset.x || offset.y);
|
||||
const isOffset = offset && (offset.x || offset.y || offset.z);
|
||||
// remap points as necessary for origins, offsets, inversions
|
||||
print.output.forEach(layer => {
|
||||
if (!Array.isArray(layer)) {
|
||||
|
|
@ -427,8 +428,9 @@ export function cam_export(print, online) {
|
|||
// ensure not point is modified twice
|
||||
point.mod = 1;
|
||||
if (isOffset) {
|
||||
point.x += offset.x;
|
||||
point.y += offset.y;
|
||||
point.x += offset.x ?? 0;
|
||||
point.y += offset.y ?? 0;
|
||||
point.z -= offset.z ?? 0;
|
||||
}
|
||||
if (scale) {
|
||||
point.x *= scale.x;
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ export function menu() {
|
|||
camConventional: newBoolean(LANG.ou_conv_s, onBooleanClick, {title:LANG.ou_conv_l}),
|
||||
camEaseDown: newBoolean(LANG.cr_ease_s, onBooleanClick, {title:LANG.cr_ease_l}),
|
||||
camDepthFirst: newBoolean(LANG.ou_depf_s, onBooleanClick, {title:LANG.ou_depf_l}),
|
||||
camInnerFirst: newBoolean(LANG.ou_inrf_s, onBooleanClick, {title:LANG.ou_inrf_l}),
|
||||
camToolInit: newBoolean(LANG.ou_toin_s, onBooleanClick, {title:LANG.ou_toin_l}),
|
||||
separator: newBlank({ class:"set-sep", driven }),
|
||||
camFirstZMax: newBoolean(LANG.ou_z1st_s, onBooleanClick, {title:LANG.ou_z1st_l}),
|
||||
|
|
|
|||
|
|
@ -100,6 +100,11 @@ class OpOutline extends CamOp {
|
|||
// extend cut thru (only when z bottom is 0)
|
||||
if (workarea.bottom_z < 0) {
|
||||
let last = slices[slices.length-1];
|
||||
// when step down > full cut depth, clear slices and
|
||||
// leave only the cut-thru pass(es)
|
||||
if (op.down > workarea.top_stock - workarea.bottom_part) {
|
||||
slices.length = 0;
|
||||
}
|
||||
for (let zneg of base_util.lerp(0, -workarea.bottom_cut, op.down)) {
|
||||
if (!last) continue;
|
||||
let add = last.clone(true);
|
||||
|
|
@ -225,7 +230,7 @@ class OpOutline extends CamOp {
|
|||
|
||||
let easeDown = process.camEaseDown;
|
||||
let toolDiam = this.toolDiam;
|
||||
let cutdir = op.ov_conv;//process.camConventional;
|
||||
let cutdir = op.ov_conv;
|
||||
let depthFirst = process.camDepthFirst;
|
||||
let depthData = [];
|
||||
|
||||
|
|
@ -251,9 +256,9 @@ class OpOutline extends CamOp {
|
|||
});
|
||||
|
||||
// set cut direction on outer polys
|
||||
POLY.setWinding(t, cutdir);
|
||||
POLY.setWinding(t, !cutdir);
|
||||
// set cut direction on inner polys
|
||||
POLY.setWinding(c, !cutdir);
|
||||
POLY.setWinding(c, cutdir);
|
||||
|
||||
if (depthFirst) {
|
||||
depthData.push(polys);
|
||||
|
|
@ -269,9 +274,11 @@ class OpOutline extends CamOp {
|
|||
let polyLast;
|
||||
// console.log({order, orderPolys});
|
||||
printPoint = poly2polyEmit(orderPolys, printPoint, function(poly, index, count) {
|
||||
|
||||
polyLast = polyEmit(poly, index, count, polyLast);
|
||||
}, { swapdir: false });
|
||||
}, {
|
||||
swapdir: false,
|
||||
weight: process.camInnerFirst
|
||||
});
|
||||
})
|
||||
newLayer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Tool } from './tool.js';
|
|||
import { newPolygon } from '../../../geo/polygon.js';
|
||||
import { newSlice } from '../../core/slice.js';
|
||||
import { newPoint } from '../../../geo/point.js';
|
||||
import { util as base_util } from '../../../geo/base.js';
|
||||
import { util } from '../../../geo/base.js';
|
||||
|
||||
class OpRegister extends CamOp {
|
||||
constructor(state, op) {
|
||||
|
|
@ -88,7 +88,7 @@ class OpRegister extends CamOp {
|
|||
step = -step;
|
||||
}
|
||||
}
|
||||
for (let z of base.util.lerp(startZ, endZ, op.down)) {
|
||||
for (let z of util.lerp(startZ, endZ, op.down)) {
|
||||
let slice = newSlice(z);
|
||||
addSlices(slice);
|
||||
sliceOut.push(slice);
|
||||
|
|
|
|||
|
|
@ -32,11 +32,12 @@ class OpRough extends CamOp {
|
|||
let roughStock = op.all && isIndexed;
|
||||
let toolDiam = new Tool(settings, op.tool).fluteDiameter();
|
||||
let trueShadow = process.camTrueShadow === true;
|
||||
let cutThruBypass = op.down > workarea.top_stock - workarea.bottom_part;
|
||||
|
||||
updateToolDiams(toolDiam);
|
||||
|
||||
// clear the stock above the area to be roughed out
|
||||
if (workarea.top_z > workarea.top_part) {
|
||||
if (workarea.top_z > workarea.top_part && !cutThruBypass) {
|
||||
let shadow = state.shadow.base.clone();
|
||||
let step = toolDiam * op.step;
|
||||
let inset = roughStock ?
|
||||
|
|
@ -55,9 +56,16 @@ class OpRough extends CamOp {
|
|||
for (let z = zstart; zsteps > 0; zsteps--) {
|
||||
let slice = newSlice();
|
||||
slice.z = z;
|
||||
slice.camLines = POLY.setZ(facing.clone(true), slice.z + roughLeaveZ);
|
||||
let polys = POLY.setZ(facing.clone(true), slice.z + roughLeaveZ);
|
||||
if (tabs) {
|
||||
tabs.forEach(tab => {
|
||||
tab.off = POLY.expand([tab.poly], toolDiam / 2).flat();
|
||||
});
|
||||
polys = cutTabs(tabs, polys, slice.z);
|
||||
}
|
||||
slice.camLines = polys;
|
||||
slice.output()
|
||||
.setLayer("face", {face: color, line: color})
|
||||
.setLayer("roughing", {face: color, line: color})
|
||||
.addPolys(slice.camLines);
|
||||
addSlices(slice);
|
||||
camFaces.push(slice);
|
||||
|
|
@ -251,6 +259,12 @@ class OpRough extends CamOp {
|
|||
|
||||
let last = slices[slices.length-1];
|
||||
|
||||
// when step down > full cut depth, clear slices and
|
||||
// leave only the cut-thru pass(es)
|
||||
if (cutThruBypass) {
|
||||
slices.length = 0;
|
||||
}
|
||||
// add cut thru passes
|
||||
if (workarea.bottom_z < 0)
|
||||
for (let zneg of base_util.lerp(0, -workarea.bottom_cut, op.down)) {
|
||||
if (!last) continue;
|
||||
|
|
@ -302,7 +316,9 @@ class OpRough extends CamOp {
|
|||
// set winding specified in output
|
||||
POLY.setWinding(level, cutdir, false);
|
||||
poly2polyEmit(level, printPoint, (poly, index, count) => {
|
||||
printPoint = polyEmit(poly, index, count, printPoint);
|
||||
printPoint = polyEmit(poly, index, count, printPoint, {cutFromLast: true});
|
||||
}, {
|
||||
weight: process.camInnerFirst
|
||||
});
|
||||
newLayer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class OpTrace extends CamOp {
|
|||
let cutdir = ov_conv;
|
||||
let polys = [];
|
||||
let reContour = false;
|
||||
let canRecontour = offset !== 'none' && down === 0;
|
||||
let canRecontour = offset !== 'none' && down < 0;
|
||||
let stockRect = stock.center && stock.x && stock.y ?
|
||||
newPolygon().centerRectangle({x:0,y:0}, stock.x, stock.y) : undefined;
|
||||
updateToolDiams(toolDiam);
|
||||
|
|
@ -57,6 +57,7 @@ class OpTrace extends CamOp {
|
|||
let max = Math.max(...zs);
|
||||
if (max - min > 0.0001 && canRecontour) {
|
||||
reContour = true;
|
||||
down = 0;
|
||||
}
|
||||
}
|
||||
if (false) newSliceOut(0).output()
|
||||
|
|
@ -89,6 +90,7 @@ class OpTrace extends CamOp {
|
|||
if (reContour) {
|
||||
state.contourPolys(widget, slice.camLines);
|
||||
}
|
||||
POLY.setWinding(slice.camLines, offset === "outside" ? !cutdir : cutdir, false);
|
||||
slice.output()
|
||||
.setLayer("trace follow", {line: color}, false)
|
||||
.addPolys(slice.camLines)
|
||||
|
|
@ -144,7 +146,7 @@ class OpTrace extends CamOp {
|
|||
} else {
|
||||
slice.camLines = POLY.flatten(slice.camLines, null, true);
|
||||
}
|
||||
POLY.setWinding(slice.camLines, cutdir, false);
|
||||
POLY.setWinding(slice.camLines, offset === "outside" ? !cutdir : cutdir, false);
|
||||
if (debug && shadow) slice.output()
|
||||
.setLayer("trace shadow", {line: 0xff8811}, false)
|
||||
.addPolys(shadow)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
easeDown = process.camEaseDown,
|
||||
easeAngle = process.camEaseAngle,
|
||||
depthFirst = process.camDepthFirst,
|
||||
innerFirst = process.camInnerFirst,
|
||||
engageFactor = process.camFullEngage,
|
||||
arcTolerance = process.camArcTolerance,
|
||||
arcRes = toRadians(process.camArcResolution),
|
||||
|
|
@ -243,7 +244,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
camOut(point.clone().setZ(zmax_outer));
|
||||
camOut(point.clone().setZ(zmax_outer), 0);
|
||||
points.forEach(function (point, index) {
|
||||
camOut(point, 1);
|
||||
if (index > 0 && index < points.length - 1) {
|
||||
|
|
@ -331,7 +332,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
* @param {number} opts.moveLen typically = tool diameter used to trigger terrain detection
|
||||
* @param {number} opts.factor speed scale factor
|
||||
*/
|
||||
function camOut(point, emit, opts) {
|
||||
function camOut(point, emit = 1, opts) {
|
||||
// console.trace({point, emit, opts})
|
||||
let {
|
||||
center = {},
|
||||
|
|
@ -392,8 +393,18 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
let deltaXY = lastPoint.distTo2D(point),
|
||||
deltaZ = point.z - lastPoint.z,
|
||||
absDeltaZ = Math.abs(deltaZ),
|
||||
hasDelta = deltaXY >= 0.001 && absDeltaZ >= 0,
|
||||
isMove = emit == 0;
|
||||
|
||||
// when rapid pluge could cut thru stock, rapid to just above stock
|
||||
// then continue plunge as a plunge cut
|
||||
if (deltaZ < 0 && lastPoint.z > stockz && point.z < stockz && emit === 0) {
|
||||
// console.log('detected plunge cut as rapid move', lastPoint.z, stockz, point.z);
|
||||
layerPush(point.clone().setZ(stockz + 1), 0, 0, tool);
|
||||
// change to cutting move for remainder of plunge
|
||||
emit = 1;
|
||||
}
|
||||
|
||||
// drop points too close together
|
||||
if (!isLathe && !isArc && deltaXY < 0.001 && point.z === lastPoint.z) {
|
||||
// console.trace(["drop dup",lastPoint,point]);
|
||||
|
|
@ -401,7 +412,7 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
}
|
||||
|
||||
// convert short planar moves to cuts in some cases
|
||||
if (!isRough && !isArc && isMove && deltaXY <= moveLen && deltaZ <= 0 && !lasering) {
|
||||
if (hasDelta && !isRough && !isArc && isMove && deltaXY <= moveLen && deltaZ <= 0 && !lasering) {
|
||||
let iscontour = tolerance > 0;
|
||||
let isflat = absDeltaZ < 0.001;
|
||||
// restrict this to contouring
|
||||
|
|
@ -455,6 +466,11 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
layerPush(point.clone().setZ(zClearance), 0, 0, tool);
|
||||
// new pos for plunge calc
|
||||
deltaXY = 0;
|
||||
// if plunge goes below stock, convert to cut
|
||||
if (emit === 0 && point.z < stockz) {
|
||||
lastPoint = layerPush(point.clone().setZ(stockz + 1), 0, 0, tool);
|
||||
emit = 1;
|
||||
}
|
||||
}
|
||||
} else if (isRough && deltaZ < 0) {
|
||||
layerPush(point.clone().setZ(lastPoint.z), 0, 0, tool);
|
||||
|
|
@ -717,9 +733,10 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
function emitTrace(slice) {
|
||||
let { tool, rate, plunge } = slice.camTrace;
|
||||
setTool(tool, rate, plunge);
|
||||
let traceTool = new Tool(settings, tool);
|
||||
let traceToolDiam = traceTool.fluteDiameter();
|
||||
printPoint = poly2polyEmit(slice.camLines, printPoint, polyEmit, { swapdir: false });
|
||||
printPoint = poly2polyEmit(slice.camLines, printPoint, polyEmit, {
|
||||
swapdir: false,
|
||||
weight: innerFirst
|
||||
});
|
||||
newLayer();
|
||||
}
|
||||
|
||||
|
|
@ -736,10 +753,15 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
* @param {number} index - unused
|
||||
* @param {number} count - 1 to set engage factor
|
||||
* @param {Point} fromPoint - the point to rapid move from
|
||||
* @param {Object} camOutOpts - optional parameters to pass to camOut
|
||||
* @param {boolean} ops.cutFromLast - whether to emit a 1 when moving from last point. Defaults to false
|
||||
* @returns {Point} - the last point of the polygon
|
||||
*/
|
||||
function polyEmit(poly, index, count, fromPoint) {
|
||||
function polyEmit(poly, index, count, fromPoint, ops) {
|
||||
let {
|
||||
cutFromLast,
|
||||
} = ops ?? {
|
||||
cutFromLast: false
|
||||
};
|
||||
let arcQ = [],
|
||||
arcMax = Infinity, // no max arc radius
|
||||
lineTolerance = 0.001, // do not consider points under 0.001mm for arcs
|
||||
|
|
@ -775,7 +797,8 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
// if(offset == 0) console.log("forEachPoint",point,pidx,points)
|
||||
// console.log({pointA, pointB, indexA, indexB,startIndex})
|
||||
if (indexA == startIndex) {
|
||||
camOut(pointA.clone(), 0, { factor: engageFactor });
|
||||
//if cutFromLast is true, emit a 1 for a cutting move
|
||||
camOut(pointA.clone(), cutFromLast ? 1 : 0, { factor: engageFactor });
|
||||
// if first point, move to and call export function
|
||||
if (arcEnabled) arcQ.push(pointA);
|
||||
}
|
||||
|
|
@ -845,7 +868,6 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
radFault = Math.abs(angle) > arcRes
|
||||
if (radFault) {
|
||||
// if so, remove first point
|
||||
|
||||
console.log("secondary radfault,",structuredClone(arcQ),{angle,arcRes,a,b})
|
||||
camOut(arcQ.shift(), 1)
|
||||
}
|
||||
|
|
@ -1062,7 +1084,10 @@ export function prepEach(widget, settings, print, firstPoint, update) {
|
|||
fromPoint = depthOutlinePath(fromPoint, depth + 1, levels, radius, emitter, dir, ease);
|
||||
fromPoint = depthOutlinePath(fromPoint, depth + 1, levels, radius, emitter, !dir, ease);
|
||||
return fromPoint;
|
||||
}, { weight: false, swapdir: false });
|
||||
}, {
|
||||
weight: innerFirst,
|
||||
swapdir: false
|
||||
});
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
@ -1098,10 +1123,10 @@ function getZClearPath(terrain, x1, y1, x2, y2, z, zadd, off, over) {
|
|||
}
|
||||
}
|
||||
check.reverse();
|
||||
let p1 = newPoint(x1, y1);
|
||||
let p2 = newPoint(x2, y2);
|
||||
for (let i = 0; i < check.length; i++) {
|
||||
let data = check[i];
|
||||
let p1 = newPoint(x1, y1);
|
||||
let p2 = newPoint(x2, y2);
|
||||
let int = data.tops.map(p => p.intersections(p1, p2, true)).flat();
|
||||
if (int.length) {
|
||||
maxz = Math.max(maxz, data.z + zadd + over);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { base, util } from '../../../geo/base.js';
|
|||
import { newLine } from '../../../geo/line.js';
|
||||
import { newPoint } from '../../../geo/point.js';
|
||||
import { newPolygon } from '../../../geo/polygon.js';
|
||||
import { newSlopeFromAngle } from '../../../geo/slope.js';
|
||||
import { polygons as POLY } from '../../../geo/polygons.js';
|
||||
import { setSliceTracker } from '../../core/slice.js';
|
||||
import { ops as OPS } from './ops.js';
|
||||
|
|
@ -86,6 +87,8 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
|
|||
bottom_z, bottom_cut
|
||||
}, 3);
|
||||
|
||||
// console.log({ track, bounds, stock, workarea });
|
||||
|
||||
return structuredClone(workarea);
|
||||
};
|
||||
|
||||
|
|
@ -383,11 +386,11 @@ export function addDogbones(poly, dist, reverse) {
|
|||
let bdiff = ((adiff < 0 ? (180 - adiff) : (180 + adiff)) / 2) + 180;
|
||||
if (!open || (i > 1 && i < length)) {
|
||||
if (isCW && adiff > 45) {
|
||||
let newa = base.newSlopeFromAngle(lastsl.angle + bdiff);
|
||||
let newa = newSlopeFromAngle(lastsl.angle + bdiff);
|
||||
newpts.push(lastpt.projectOnSlope(newa, dist));
|
||||
newpts.push(lastpt.clone());
|
||||
} else if (!isCW && adiff < -45) {
|
||||
let newa = base.newSlopeFromAngle(lastsl.angle - bdiff);
|
||||
let newa = newSlopeFromAngle(lastsl.angle - bdiff);
|
||||
newpts.push(lastpt.projectOnSlope(newa, dist));
|
||||
newpts.push(lastpt.clone());
|
||||
}
|
||||
|
|
@ -657,9 +660,9 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
// keeps the z bottom relative to the part when z align changes
|
||||
zBottom = isIndexed ? camZBottom : camZBottom - zbOff;
|
||||
|
||||
let slicerOpts = { flatoff: 0.001 }
|
||||
let slicerOpts = { flatoff: 0.001 };
|
||||
let slicer = new cam_slicer(widget, slicerOpts);
|
||||
let zFlats = Object.keys(slicer.zFlat).map(Number).map(z => [z, z - 0.002]).flat()
|
||||
let zFlats = Object.keys(slicer.zFlat).map(Number).map(z => [z, z - 0.002]).flat();
|
||||
|
||||
precision = Math.max(0, precision)
|
||||
let intervals = (precision == 0) ? [] : slicer.interval(
|
||||
|
|
@ -669,11 +672,11 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
}
|
||||
)
|
||||
|
||||
let zees = [...zFlats, ...intervals]
|
||||
let zees = [...zFlats, ...intervals];
|
||||
let indices = [...new Set(zees
|
||||
.map(kv => parseFloat(kv).round(5))
|
||||
.filter(z => z !== null)
|
||||
)]
|
||||
)];
|
||||
let centerDiff = diam * 0.1,
|
||||
area = (diam / 2) * (diam / 2) * Math.PI,
|
||||
circles = [],
|
||||
|
|
@ -689,19 +692,20 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
for (let [i, slice] of slices.entries()) {
|
||||
for (let top of slice.tops) {
|
||||
// console.log("slicing",slice.z,top)
|
||||
slice.shadow = computeShadowAt(widget, slice.z, 0)
|
||||
slice.shadow = computeShadowAt(widget, slice.z, 0);
|
||||
let inner = top.inner;
|
||||
if (!inner) { //no holes
|
||||
continue;
|
||||
}
|
||||
for (let poly of inner) {
|
||||
if (poly.points.length < 7) continue;
|
||||
|
||||
let center = poly.calcCircleCenter();
|
||||
center.area = poly.area();
|
||||
center.overlapping = [center]
|
||||
center.overlapping = [center];
|
||||
center.depth = 0;
|
||||
// console.log("center",center)
|
||||
if (poly.circularity() < 0.985) {
|
||||
if (poly.circularity() < 0.98) {
|
||||
// if not circular, don't add to holes
|
||||
continue;
|
||||
}
|
||||
|
|
@ -712,7 +716,7 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
}
|
||||
let overlap = false;
|
||||
for (let [i, circle] of circles.entries()) {
|
||||
let dist = circle.distTo2D(center)
|
||||
let dist = circle.distTo2D(center);
|
||||
|
||||
// //if on the same xy point,
|
||||
if (dist <= centerDiff) {
|
||||
|
|
@ -726,19 +730,19 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
if (!overlap) circles.push(center);
|
||||
}
|
||||
}
|
||||
onProgress(0.5 + (i / slices.length * 0.25), "recognize circles")
|
||||
onProgress(0.5 + (i / slices.length * 0.25), "recognize circles");
|
||||
}
|
||||
|
||||
let drills = []
|
||||
let drills = [];
|
||||
|
||||
for (let [i, c] of circles.entries()) {
|
||||
let overlapping = c.overlapping
|
||||
let overlapping = c.overlapping;
|
||||
|
||||
let last = overlapping.shift();
|
||||
while (overlapping.length) {
|
||||
let circ = overlapping.shift();
|
||||
let aveArea = (circ.area + last.area) / 2;
|
||||
let areaDelta = Math.abs(circ.area - last.area)
|
||||
let areaDelta = Math.abs(circ.area - last.area);
|
||||
if (areaDelta < aveArea * 0.05) { // if area delta less than 5% of average area
|
||||
//keep top circle selected
|
||||
last.depth = last.z - circ.z;
|
||||
|
|
@ -748,24 +752,25 @@ export async function holes(settings, widget, individual, rec, onProgress) {
|
|||
last = circ;
|
||||
}
|
||||
}
|
||||
if (last.depth != 0) drills.push(last) //add last circle
|
||||
onProgress(0.75 + (i / circles.length * 0.25), "assemble holes")
|
||||
if (last.depth != 0) drills.push(last); // add last circle
|
||||
onProgress(0.75 + (i / circles.length * 0.25), "assemble holes");
|
||||
}
|
||||
drills.forEach(h => {
|
||||
if (rec.fromTop) {
|
||||
// set z top if selected
|
||||
h.depth += wztop - h.z
|
||||
h.z = wztop
|
||||
h.depth += wztop - h.z;
|
||||
h.z = wztop;
|
||||
}
|
||||
delete h.overlapping //for encoding
|
||||
h.diam = toolDiam // for mesh generation
|
||||
h.selected = (!individual && Math.abs(h.area - area) <= area * 0.05); //for same size selection
|
||||
delete h.overlapping; //for encoding
|
||||
h.diam = toolDiam; // for mesh generation
|
||||
h.selected = (!individual && Math.abs(h.area - area) <= area * 0.05); // for same size selection
|
||||
})
|
||||
|
||||
// console.log("unfiltered circles",circles)
|
||||
// console.log("drills",drills)
|
||||
drills = drills.filter(drill => drill.depth > 0)
|
||||
widget.shadowedDrills = shadowedDrills
|
||||
console.log("unfiltered circles",circles);
|
||||
console.log("drills",drills);
|
||||
|
||||
drills = drills.filter(drill => drill.depth > 0);
|
||||
widget.shadowedDrills = shadowedDrills;
|
||||
widget.drills = drills;
|
||||
return drills;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { $ } from '../../../moto/webui.js';
|
|||
import { api } from '../../core/api.js';
|
||||
import { consts } from '../../core/consts.js';
|
||||
import { settings as setconf } from '../../core/settings.js';
|
||||
import { calcTaperLength, calcTaperAngle } from './tool.js';
|
||||
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ function selectTool(tool) {
|
|||
ui.toolMetric.checked = tool.metric;
|
||||
ui.toolType.selectedIndex = toolNames.indexOf(tool.type);
|
||||
if (tool === 'tapermill') {
|
||||
ui.toolTaperAngle.value = kiri.driver.CAM.calcTaperAngle(
|
||||
ui.toolTaperAngle.value = calcTaperAngle(
|
||||
(tool.flute_diam - tool.taper_tip) / 2, tool.flute_len
|
||||
).round(1);
|
||||
} else if(tool === 'drill'){
|
||||
|
|
@ -208,16 +209,15 @@ export function updateTool(ev) {
|
|||
selectedTool.metric = ui.toolMetric.checked;
|
||||
selectedTool.type = toolNames[ui.toolType.selectedIndex];
|
||||
if (selectedTool.type === 'tapermill') {
|
||||
const CAM = kiri.driver.CAM;
|
||||
const rad = (selectedTool.flute_diam - selectedTool.taper_tip) / 2;
|
||||
if (ev && ev.target === ui.toolTaperAngle) {
|
||||
const angle = parseFloat(ev.target.value);
|
||||
const len = CAM.calcTaperLength(rad, angle * DEG2RAD);
|
||||
const len = calcTaperLength(rad, angle * DEG2RAD);
|
||||
selectedTool.flute_len = len;
|
||||
ui.toolTaperAngle.value = angle.round(1);
|
||||
ui.toolFluteLen.value = selectedTool.flute_len.round(4);
|
||||
} else {
|
||||
ui.toolTaperAngle.value = CAM.calcTaperAngle(rad, selectedTool.flute_len).round(1);
|
||||
ui.toolTaperAngle.value = calcTaperAngle(rad, selectedTool.flute_len).round(1);
|
||||
}
|
||||
} else {
|
||||
ui.toolTaperAngle.value = 0;
|
||||
|
|
@ -318,7 +318,7 @@ function _showTools() {
|
|||
return;
|
||||
}
|
||||
const record = {
|
||||
version: kiri.version,
|
||||
version: api.version,
|
||||
tools: api.conf.get().tools,
|
||||
time: Date.now()
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue