From 4ad9ca1c80fffc8668ea278970752cd73049d42c Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Wed, 11 Mar 2020 12:57:34 -0400 Subject: [PATCH] fix and cleanup linear finishing. add latent points to merge collinear --- js/kiri-driver-cam.js | 203 ++++++++++++++++++++++-------------------- js/kiri-slicer.js | 59 +++++++----- 2 files changed, 139 insertions(+), 123 deletions(-) diff --git a/js/kiri-driver-cam.js b/js/kiri-driver-cam.js index a7bc1617..e4217427 100644 --- a/js/kiri-driver-cam.js +++ b/js/kiri-driver-cam.js @@ -190,31 +190,32 @@ let gs_kiri_cam = exports; let dy = y - ly; while (i < profile.length) { + // tool profile point x, y, and z offsets let tx = profile[i++]; let ty = profile[i++]; let tz = profile[i++]; - + // only check points in the direction of travel if (dx == -1 && tx > 0) continue; if (dx == 1 && tx < 0) continue; if (dy == -1 && ty > 0) continue; if (dy == 1 && ty < 0) continue; - + // update with tool profile point offset tx += x; ty += y; - // if outside max topo steps, skip if (tx < 0 || tx >= sx || ty < 0 || ty >= sy) { continue; } - // lookup grid value @ tx, ty gv = topo.data[tx * sy + ty]; // outside the topo if (gv === undefined) { + console.log("outside"); continue; } // inside the topo but off the part if (floormax && gv === 0) { + // console.log("off topo"); // return topo.bounds.max.z; gv = topo.bounds.max.z; } @@ -224,7 +225,7 @@ let gs_kiri_cam = exports; lastTopo.lx = x; lastTopo.ly = y; - lastTopo.lr = mz >= 0.0 ? mz : topo.bounds.max.z; + lastTopo.lr = Math.max(mz,0);//mz >= 0.0 ? mz : topo.bounds.max.z; return lastTopo.lr; }; @@ -346,85 +347,6 @@ let gs_kiri_cam = exports; }); } - /** - * merge collinear points - * remove floor lead-in, lead-out - * remove collinear points (todo) - */ - function cleanupTopoSlice(slice, diameter, curvesOnly) { - let poly = slice.tops[0].traces[0], - nupoly = newPolygon().setOpen(), - points = poly.points, - start = 0, - end = points.length - 1, - latent, point, last, i; - - // find start - for (i = start; i < points.length; i++) - if (points[i].z > 0) { start = i; break; } - // find end - for (i = end; i > 0; i--) - if (points[i].z > 0) { end = i; break; } - // merge collinear - for (i = start; i <= end; i++) { - point = points[i]; - if (last) { - if (last.z === point.z && (last.x === point.x || last.y === point.y)) { - latent = point; - continue - } else { - if (latent) { - nupoly.push(latent); - latent = null; - } - } - } - nupoly.push(point); - last = point; - } - if (latent) nupoly.push(latent); - - if (nupoly.length < 2) return false; - - // limit cleanup to curved features - let traces = [], - trace = newPolygon().setOpen(); - - slice.tops[0].traces = traces; - points = nupoly.points; - last = points[0]; - latent = null; - for (i = 1; i < points.length; i++) { - point = points[i]; - let use = curvesOnly ? - (last.z != point.z && (last.x !== point.x || last.y !== point.y)) : - last.z && point.z; - if (use) { - // join to previous trace if not too far away - if (trace.length === 0 && traces.length > 0 && point.distTo3D(traces.peek().last()) <= diameter) { - trace = traces.peek(); - } - if (latent !== last) trace.push(last); - trace.push(point); - latent = point; - } else { - if (trace.length > 1) { - // don't re-push a joined trace - if (traces.length === 0 || traces.peek() !== trace) traces.push(trace); - trace = newPolygon().setOpen(); - latent = null; - } else if (trace.length === 1) { - trace = newPolygon().setOpen(); - } - } - last = point; - } - - if (trace.length > 1) traces.push(trace); - - return traces.length > 0; - } - /** * @param {Widget} widget * @param {Object} settings @@ -478,26 +400,22 @@ let gs_kiri_cam = exports; gridv, // value miny = bounds.min.y, maxy = bounds.max.y, - maxx = bounds.max.x, zMin = MAX(bounds.min.z, outp.camZBottom) + 0.0001, x, y, tv, ltv; // for each Y slice, find z grid value (x/z swapped) for (let j=0; j zMin || p2.z > zMin) && // one endpoint above 0 (p1.z > gridv || p2.z > gridv) && // one endpoint above gridv @@ -508,7 +426,9 @@ let gs_kiri_cam = exports; dz = p1.z - p2.z, pct = (p1.y - y) / dy, nz = p1.z - (dz * pct); - if (nz > gridv) gridv = lodata[gridi] = Math.max(nz, zMin); + if (nz > gridv) { + gridv = data[gridi] = Math.max(nz, zMin); + } } } gridy++; @@ -529,9 +449,32 @@ let gs_kiri_cam = exports; slice.lines = newlines = []; newtop = slice.addTop(newPolygon().setOpen()).poly; newtrace = newPolygon().setOpen(); - slice.tops[0].traces = [ newtrace ]; + let sliceout = slice.tops[0].traces = [ ]; + let latent; for (y = bounds.min.y; y < bounds.max.y; y += resolution) { gridv = data[gridx * stepsy + gridy]; + if (gridv === undefined) { + // off topo (why?) + gridy++; + continue; + } + if (gridv === 0) { + // off part + if (latent) { + newtrace.push(latent); + } + if (newtrace.length > 0) { + sliceout.push(newtrace); + newtrace = newPolygon().setOpen(); + latent = null; + ly = 0; + } + gridy++; + continue; + } + if (gridy === 0 || newtrace.length === 0) { + ltv = undefined; + } tv = maxzat(gridx, gridy); if (ly) { if (mesh) newlines.push(newLine( @@ -541,6 +484,10 @@ let gs_kiri_cam = exports; let ang = Math.abs((Math.atan2(ltv - tv, resolution) * R2A) % 90); // over max angle, turn into square edge (up or down) if (ang > maxangle) { + if (latent) { + newtrace.push(latent); + latent = null; + } if (ltv > tv) { // down = forward,down newtrace.push(newPoint(x,y,ltv)); @@ -550,13 +497,27 @@ let gs_kiri_cam = exports; } } } - newtrace.push(newPoint(x,y,tv)); + if (tv === ltv) { + latent = newPoint(x,y,tv); + } else { + if (latent) { + newtrace.push(latent); + latent = null; + } + newtrace.push(newPoint(x,y,tv)); + } ly = y; lv = gridv; ltv = tv; gridy++; } - if (cleanupTopoSlice(slice,diameter,curvesOnly)) { + if (latent) { + newtrace.push(latent); + } + if (newtrace.length > 0) { + sliceout.push(newtrace); + } + if (sliceout.length > 0) { newslices.push(slice); } gridx = Math.round(((x - bounds.min.x + toolStep) / boundsX) * stepsx); @@ -576,10 +537,33 @@ let gs_kiri_cam = exports; slice.lines = newlines = []; newtop = slice.addTop(newPolygon().setOpen()).poly; newtrace = newPolygon().setOpen(); - slice.tops[0].traces = [ newtrace ]; + let sliceout = slice.tops[0].traces = [ ]; + let latent; for (x = bounds.min.x; x <= bounds.max.x; x += resolution) { gridv = data[gridx * stepsy + gridy]; + if (gridv === undefined) { + // off topo (why?) + gridx++; + continue; + } + if (gridv === 0) { + // off part + if (latent) { + newtrace.push(latent); + } + if (newtrace.length > 0) { + sliceout.push(newtrace); + newtrace = newPolygon().setOpen(); + latent = null; + lx = 0; + } + gridx++; + continue; + } tv = maxzat(gridx, gridy); + if (gridx === 0 || newtrace.length === 0) { + ltv = undefined; + } if (lx) { if (mesh) newlines.push(newLine( newPoint(lx,y,lv), @@ -588,6 +572,10 @@ let gs_kiri_cam = exports; let ang = Math.abs((Math.atan2(ltv - tv, resolution) * R2A) % 90); // over max angle, turn into square edge (up or down) if (ang > maxangle) { + if (latent) { + newtrace.push(latent); + latent = null; + } if (ltv > tv) { // down = forward,down newtrace.push(newPoint(x,y,ltv)); @@ -597,14 +585,29 @@ let gs_kiri_cam = exports; } } } - newtrace.push(newPoint(x,y,tv)); + if (tv === ltv) { + latent = newPoint(x,y,tv); + } else { + if (latent) { + newtrace.push(latent); + latent = null; + } + newtrace.push(newPoint(x,y,tv)); + } lx = x; lv = gridv; ltv = tv; gridx++; } - if (cleanupTopoSlice(slice,diameter,curvesOnly)) { + if (latent) { + newtrace.push(latent); + } + if (newtrace.length > 0) { + sliceout.push(newtrace); + } + if (sliceout.length > 0) { newslices.push(slice); + // console.log(sliceout.map(v => v.length)) } gridy = Math.round(((y - bounds.min.y + toolStep) / boundsY) * stepsy); onupdate(0.85 + (gridy/stepsy) * 0.15, "linear y"); @@ -1407,7 +1410,9 @@ let gs_kiri_cam = exports; let linearxy = [].appendAll(depthData.linearx).appendAll(depthData.lineary); printPoint = tip2tipEmit(linearxy, printPoint, function(el, point, count) { let poly = el.poly; - if (poly.last() === point) poly.reverse(); + if (poly.last() === point) { + poly.reverse(); + } poly.forEachPoint(function(point, pidx) { camOut(point.clone(), pidx > 0); }, false); diff --git a/js/kiri-slicer.js b/js/kiri-slicer.js index 5f97a3f0..d4f82774 100644 --- a/js/kiri-slicer.js +++ b/js/kiri-slicer.js @@ -50,13 +50,14 @@ var gs_kiri_slicer = exports; function slice(points, bounds, options, ondone, onupdate) { var topoMode = options.topo, simpleMode = options.simple, + swap = options.swapX || options.swapY, ox = 0, oy = 0; // handle rotating meshes for CAM finishing. // slicer expects things just so, so we alter // geometry to satisfy - if (options.swapX || options.swapY) { + if (swap) { points = points.slice(); var btmp = new THREE.Box3(), @@ -149,7 +150,7 @@ var gs_kiri_slicer = exports; } else { zFlat[zkey] += area; } - } else if (false) { + } else if (options.trace) { // detect zLines (curved region tops/bottoms) // mark these layers for ball mills only if (p1.z === p2.z && p1.z > bounds.min.z) { @@ -171,26 +172,30 @@ var gs_kiri_slicer = exports; } } - // translate zLines to zFlats - if (options.cam) { - let zlk, zlv; - Object.entries(zLines) - .map(v => [v[0], v[1], parseFloat(v[0])]) - .sort((a,b) => { - return a[2] - b[2] - }) - .forEach(zl => { - if (zlk) { - if (zlv != zl[1]) { - zFlat[zlk] = zlv; - zlv = zl[1]; - } - zlk = zl[0]; - } else { - zlk = zl[0]; - zlv = zl[1]; + // find slice candidates to trace for ballmills and tapermills + if (options.trace) { + let zl = {}; + let le; + let zs = Object.entries(zLines).map(oe => { + return oe.map(v => parseFloat(v)); + }).sort((a,b) => { + return b[0] - a[0]; + }).forEach((e,i) => { + // console.log(e) + if (i > 0) { + let zd = le[0]-e[0]; + // console.log(e[0], zd); + if (zd > 0.1 && e[1] > 100) { + // zl.push(e) + zl[e[0].toFixed(5)] = e[1]; + zFlat[e[0].toFixed(5)] = e[1]; } - }); + } + if (e[1] > 10) { + le = e; + } + }); + zLines = zl; } /** bucket polygons into z-bounded groups */ @@ -247,9 +252,13 @@ var gs_kiri_slicer = exports; } for (key in zFlat) { // todo make threshold for flat detection configurable - if (!zFlat.hasOwnProperty(key) || zFlat[key] < 10) continue; + if (!zFlat.hasOwnProperty(key) || zFlat[key] < 10){ + continue; + } key = parseFloat(key); - if (!zIndexes.contains(key) && key >= zMin) zIndexes.push(key); + if (!zIndexes.contains(key) && key >= zMin) { + zIndexes.push(key); + } } // sort top down zIndexes.sort(function(a,b) { @@ -411,7 +420,9 @@ var gs_kiri_slicer = exports; function sliceZ(z, height) { var phash = {}, lines = [], - onflat = zFlat[z.toFixed(5)] > 0, + zkey = z.toFixed(5), + onflat = zFlat[zkey] > 0, + online = zLines[zkey] > 0, slice = newSlice(z, options.view ? options.view.newGroup() : null), bucket = bucketCount == 1 ? points : buckets[Math.floor(z * zScale)];