From c20c3ae7e5275b92177602fd5eff93572c87b1c8 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Wed, 26 Nov 2025 12:58:46 -0500 Subject: [PATCH] reformat helical --- src/kiri/mode/cam/cl-helical.js | 3 + src/kiri/mode/cam/driver-fe.js | 1 - src/kiri/mode/cam/op-helical.js | 513 ++++++++++++++++---------------- src/kiri/mode/cam/slice.js | 7 +- 4 files changed, 262 insertions(+), 262 deletions(-) diff --git a/src/kiri/mode/cam/cl-helical.js b/src/kiri/mode/cam/cl-helical.js index f8102e94..bf64098e 100644 --- a/src/kiri/mode/cam/cl-helical.js +++ b/src/kiri/mode/cam/cl-helical.js @@ -3,7 +3,9 @@ import { CAM } from "./driver-fe.js"; import { clearPops, env } from "./client.js"; let alert, lastWidget; + export let helicalOn = false; + export function selectHelical() { if (helicalOn) { return helicalDone(); @@ -25,6 +27,7 @@ export function selectHelical() { } } }); + helicalOn = env.hoveredOp; helicalOn.classList.add("editing"); api.feature.on_mouse_up = (obj, ev) => { diff --git a/src/kiri/mode/cam/driver-fe.js b/src/kiri/mode/cam/driver-fe.js index dbb02a0e..9f123c16 100644 --- a/src/kiri/mode/cam/driver-fe.js +++ b/src/kiri/mode/cam/driver-fe.js @@ -104,7 +104,6 @@ function cylinderShow(onProgress,onDone){ cyls[face] = faces; CAM.cylinder_show(widget); } - onDone({faces:Object.keys(cyls).map(v => parseInt(v)),error}); }); } diff --git a/src/kiri/mode/cam/op-helical.js b/src/kiri/mode/cam/op-helical.js index a8f19e78..4d6e2719 100644 --- a/src/kiri/mode/cam/op-helical.js +++ b/src/kiri/mode/cam/op-helical.js @@ -7,278 +7,277 @@ import { newPoint } from "../../../geo/point.js"; import { newSlice } from "../../core/slice.js"; export class OpHelical extends CamOp { - constructor(state, op) { - super(state, op); - } - async slice(progress) { - let { op, state } = this; - let { settings, addSlices, widget, updateToolDiams, slicer } = state; - let { color } = state; - let { - cylinders, - forceStartAng, - startAng, - fromTop, - offOver, - offset, - down, - thru, - finish, - clockwise, - reverse, - entry, - entryOffset, - } = op; - let {stock} = settings + constructor(state, op) { + super(state, op); + } - let tool = new Tool(settings, op.tool), - toolDiam = tool.fluteDiameter(), - sliceOut = (this.sliceOut = []), - startAngle = forceStartAng ? startAng : 0; - - updateToolDiams(toolDiam); - // console.log({cylinders}) - let faces = cylinders[widget.id] ?? []; - if (faces.faces) faces = faces.faces; - let polys = []; - - //iterate over selected faces - for (let [i,face] of faces.entries()) { - //get poly info for the cylinder - let res - try{ - res = cylinder_poly_find( - widget, - face - ); - }catch(error){ - // don't quit if a cylinder errors out, just skip - console.error(error) - continue - } - let { zmin, zmax, diam, center, interior, faces } = res; - // console.log({ zmin, zmax, diam, center, interior }); - let radius = diam /2; - zmax = fromTop ? stock.z: zmax; - - let radAdd, - zBottom = zmin - thru, - numSegs = faces.length / 2, - poly = newPolygon().setOpen(); - - if (offOver) { - //apply offset override - if (offset == "auto") { - radAdd = interior ? -offOver : offOver; - } else if (offset == "inside") { - radAdd = -offOver; - } else if (offset == "outside") { - radAdd = offOver; - } - } else { - //otherwise, calculate based on offset type - if (offset == "auto") { - radAdd = (interior ? -toolDiam : toolDiam) / 2; - } else if (offset == "inside") { - radAdd = -toolDiam / 2; - } else if (offset == "outside") { - radAdd = toolDiam / 2; - } - } - radius += radAdd; - - if( radius <= 0 ){ - //if negative radius, skip this cylinder - console.log('negative radius', radius); - continue - } - - let startPoint = center - .clone() - .setZ(zmax) - .add( - newPoint( - Math.cos(startAngle) * radius, - Math.sin(startAngle) * radius, - 0 - ) - ); - - let currentZ = zmax; - for (;;) { - let bottom = currentZ - down; - if ( bottom > zBottom ) { - //if not at the bottom, do a whole helix - let start = startPoint.setZ(currentZ), - end = startPoint.clone().setZ(bottom); - // console.log(currentZ, bottom, [start.z, end.z]); - let path = arcToPath(start, end, numSegs, { + async slice(progress) { + let { op, state } = this; + let { settings, addSlices, widget, updateToolDiams } = state; + let { + cylinders, + forceStartAng, + startAng, + fromTop, + offOver, + offset, + down, + thru, + finish, clockwise, - radius, - center, - }); - // console.log({ path, start, end, radius, center }); - poly.addPoints(path); - } else { - //if at the bottom, do a partial helix - let toBottom = currentZ - zBottom, - ofFull = toBottom / down, - ofCircle = ofFull * (2 * Math.PI), - cwMultiplier = clockwise ? -1 : 1, - finalAngle = startAngle + (ofCircle*cwMultiplier), - finalEnd = center - .clone() - .setZ(zBottom) - .add( - newPoint( - Math.cos(finalAngle) * radius, - Math.sin(finalAngle) * radius, - 0 - ) - ); - // console.log({down,toBottom,ofFull,ofCircle,startAngle,finalAngle,finalEnd}); + reverse, + entry, + entryOffset, + } = op; + let { color } = state; + let { stock } = settings - //if not already very close to final point - if( ofCircle >= 0.001 ){ - //circle down to final point - poly.addPoints( - arcToPath(startPoint.setZ(currentZ), finalEnd, numSegs , { - clockwise, - radius, - center, - }) - ); - } + let tool = new Tool(settings, op.tool), + toolDiam = tool.fluteDiameter(), + sliceOut = (this.sliceOut = []), + startAngle = forceStartAng ? startAng : 0; - //if starting at the bottom, reverse poly - if ( reverse ){ - poly.reverse(); - } + updateToolDiams(toolDiam); + // console.log({cylinders}); + let faces = cylinders[widget.id] ?? []; + if (faces.faces) faces = faces.faces; + let polys = []; - if ( entry ){ - //get first z of poly to use for entry - let firstZ = poly.first().z; - //create new pointArray - let entry =[newPoint(0,0,0)]; - //add center point - let entryCenter = center.clone().setZ(firstZ) - - //if doing a curved enter, add more - if ( entryOffset > 0 ){ - if ( entryOffset > radius ){ - console.error("entryOffset must be less than radius of helix"); - }else{ - //calculate entry center - let lineOut = radius - entryOffset; - let centerOffset = (entryOffset**2 + 2*entryOffset*lineOut) / (2*(entryOffset + lineOut)); - //add entry points - entry.push( - newPoint(0,-lineOut,0), - ...arcToPath( - newPoint(0,-lineOut,0), - newPoint(radius,0,0), - 128, - { - clockwise:false, - radius:lineOut, - center:newPoint(centerOffset,0,0) - } - ), - newPoint(radius,0,0), - ) - } + //iterate over selected faces + for (let [i, face] of faces.entries()) { + //get poly info for the cylinder + let res + try { + res = cylinder_poly_find( + widget, + face + ); + } catch (error) { + // don't quit if a cylinder errors out, just skip + console.error(error) + continue } - //for each point - //rotate by start angle - // add to hole center - let invert = ((clockwise && !reverse ) || (!clockwise && reverse) ) ? -1 : 1 - let entryAngle = reverse ? finalAngle : startAngle - entry = entry.map(p => { - // TODO: there's totally a way to do this with a matrix - // logical XOR - p.y *= invert - p.rotate(entryAngle) - return p.add(entryCenter) - }) - //append to start of poly - poly = newPolygon().setOpen().addPoints(entry).addPoints(poly.points); - } - //if doing a finish pass, do a full circle at the bottom - if ( finish && !reverse ){ - poly.addPoints( - arcToPath(finalEnd, finalEnd, numSegs, { - clockwise, - radius, - center, - }), - ); - poly.append( - finalEnd.clone().setZ(zBottom), - ) - } - break; - } - currentZ = bottom; - } + let { zmin, zmax, diam, center, interior, faces } = res; + // console.log({ zmin, zmax, diam, center, interior }); + let radius = diam / 2; + zmax = fromTop ? stock.z : zmax; - progress(i/faces.length, "Helical intrerpolation"); - polys.push(poly); + let radAdd, + zBottom = zmin - thru, + numSegs = faces.length / 2, + poly = newPolygon().setOpen(); + + if (offOver) { + //apply offset override + if (offset == "auto") { + radAdd = interior ? -offOver : offOver; + } else if (offset == "inside") { + radAdd = -offOver; + } else if (offset == "outside") { + radAdd = offOver; + } + } else { + //otherwise, calculate based on offset type + if (offset == "auto") { + radAdd = (interior ? -toolDiam : toolDiam) / 2; + } else if (offset == "inside") { + radAdd = -toolDiam / 2; + } else if (offset == "outside") { + radAdd = toolDiam / 2; + } + } + radius += radAdd; + + if (radius <= 0) { + //if negative radius, skip this cylinder + console.log('negative radius', radius); + continue + } + + let startPoint = center + .clone() + .setZ(zmax) + .add( + newPoint( + Math.cos(startAngle) * radius, + Math.sin(startAngle) * radius, + 0 + ) + ); + + let currentZ = zmax; + for (; ;) { + let bottom = currentZ - down; + if (bottom > zBottom) { + //if not at the bottom, do a whole helix + let start = startPoint.setZ(currentZ), + end = startPoint.clone().setZ(bottom); + // console.log(currentZ, bottom, [start.z, end.z]); + let path = arcToPath(start, end, numSegs, { + clockwise, + radius, + center, + }); + // console.log({ path, start, end, radius, center }); + poly.addPoints(path); + } else { + //if at the bottom, do a partial helix + let toBottom = currentZ - zBottom, + ofFull = toBottom / down, + ofCircle = ofFull * (2 * Math.PI), + cwMultiplier = clockwise ? -1 : 1, + finalAngle = startAngle + (ofCircle * cwMultiplier), + finalEnd = center + .clone() + .setZ(zBottom) + .add( + newPoint( + Math.cos(finalAngle) * radius, + Math.sin(finalAngle) * radius, + 0 + ) + ); + + // console.log({down,toBottom,ofFull,ofCircle,startAngle,finalAngle,finalEnd}); + //if not already very close to final point + if (ofCircle >= 0.001) { + //circle down to final point + poly.addPoints( + arcToPath(startPoint.setZ(currentZ), finalEnd, numSegs, { + clockwise, + radius, + center, + }) + ); + } + + //if starting at the bottom, reverse poly + if (reverse) { + poly.reverse(); + } + + if (entry) { + //get first z of poly to use for entry + let firstZ = poly.first().z; + //create new pointArray + let entry = [newPoint(0, 0, 0)]; + //add center point + let entryCenter = center.clone().setZ(firstZ) + + //if doing a curved enter, add more + if (entryOffset > 0) { + if (entryOffset > radius) { + console.error("entryOffset must be less than radius of helix"); + } else { + //calculate entry center + let lineOut = radius - entryOffset; + let centerOffset = (entryOffset ** 2 + 2 * entryOffset * lineOut) / (2 * (entryOffset + lineOut)); + //add entry points + entry.push( + newPoint(0, -lineOut, 0), + ...arcToPath( + newPoint(0, -lineOut, 0), + newPoint(radius, 0, 0), + 128, + { + clockwise: false, + radius: lineOut, + center: newPoint(centerOffset, 0, 0) + } + ), + newPoint(radius, 0, 0), + ) + } + } + //for each point + //rotate by start angle + // add to hole center + let invert = ((clockwise && !reverse) || (!clockwise && reverse)) ? -1 : 1 + let entryAngle = reverse ? finalAngle : startAngle + entry = entry.map(p => { + // TODO: there's totally a way to do this with a matrix + // logical XOR + p.y *= invert + p.rotate(entryAngle) + return p.add(entryCenter) + }) + //append to start of poly + poly = newPolygon().setOpen().addPoints(entry).addPoints(poly.points); + } + //if doing a finish pass, do a full circle at the bottom + if (finish && !reverse) { + poly.addPoints( + arcToPath(finalEnd, finalEnd, numSegs, { + clockwise, + radius, + center, + }), + ); + poly.append( + finalEnd.clone().setZ(zBottom), + ) + } + break; + } + currentZ = bottom; + } + + progress(i / faces.length, "Helical intrerpolation"); + polys.push(poly); + } + + let slice = newSlice(0); + slice.camTrace = { tool: op.tool, rate: op.feed, plunge: op.rate }; + slice.camLines = polys; + + slice + .output() + .setLayer("Helical", { face: color, line: color }) + .addPolys(slice.camLines); + + addSlices(slice); + sliceOut.push(slice); } - let slice = newSlice(0); + async prepare(ops, progress) { + let { + setTool, + setSpindle, + polyEmit, + setPrintPoint, + getPrintPoint, + } = ops; + let { tool, spindle, rate, feed } = this.op; - slice.camTrace = { tool: op.tool, rate: op.feed, plunge: op.rate }; - slice.camLines = polys; + setTool(tool, feed, rate); + setSpindle(spindle); - slice - .output() - .setLayer("Helical", { face: color, line: color }) - .addPolys(slice.camLines); - addSlices(slice); - sliceOut.push(slice); - } + let [polys] = this.sliceOut.map((s) => s.camLines); + let pp = getPrintPoint(); + polys = polys.slice(); - async prepare(ops, progress) { - let { op, state } = this; - let { settings, widget, addSlices, updateToolDiams } = state; - let { - setTool, - setSpindle, - polyEmit, - camOut, - setPrintPoint, - getPrintPoint, - } = ops; - let { tool, spindle, rate, feed } = op; - setTool(tool, feed, rate); - setSpindle(spindle); + for (;;) { + let closestDist = Infinity, + closestI, + closest = null, + dist, + poly; - let [polys] = this.sliceOut.map((s) => s.camLines); - let pp = getPrintPoint(); + for (let i = 0; i < polys.length; i++) { + if (!polys[i]) continue; + if ((dist = polys[i].first().distTo2D(pp)) < closestDist) { + closestDist = dist; + closest = polys[i]; + closestI = i; + } + } - polys = polys.slice(); - for (;;) { - let closestDist = Infinity, - closestI, - closest = null, - dist, - poly; - - for (let i = 0; i < polys.length; i++) { - if (!polys[i]) continue; - if ((dist = polys[i].first().distTo2D(pp)) < closestDist) { - closestDist = dist; - closest = polys[i]; - closestI = i; + if (!closest) break; + poly = polys[closestI] + polys[closestI] = null; + pp = polyEmit(poly, 0, 1, poly.points[0]) } - } - if (!closest) break; - poly = polys[closestI] - polys[closestI] = null; - //emit - pp = polyEmit(poly,0,1,poly.points[0]) + setPrintPoint(pp); } - setPrintPoint(pp); - } } diff --git a/src/kiri/mode/cam/slice.js b/src/kiri/mode/cam/slice.js index ed3a541c..f011808d 100644 --- a/src/kiri/mode/cam/slice.js +++ b/src/kiri/mode/cam/slice.js @@ -87,7 +87,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) { bottom_z, bottom_cut }, 3); - // console.log({ track, bounds, stock, workarea }); + // console.log({ bounds, stock, track, workarea }); return structuredClone(workarea); }; @@ -96,7 +96,8 @@ export async function cam_slice(settings, widget, onupdate, ondone) { var_compute(); if (tabs) { - // make tab polygons + // create tab polygons. defer offset to each op + // since it's dependent on selected tool diameter tabs.forEach(tab => { let zero = newPoint(0, 0, 0), point = newPoint(tab.pos.x, tab.pos.y, tab.pos.z), @@ -110,8 +111,6 @@ export async function cam_slice(settings, widget, onupdate, ondone) { .map(v => newPoint(v.x, v.y, v.z)); poly.move(point); tab.poly = poly; - // tslice.output().setLayer("tabs", 0xff0000).addPoly(poly); - // sliceAll.push(tslice); }); }