diff --git a/src2/geo/point.js b/src2/geo/point.js index c59a0d39..a29b98c4 100644 --- a/src2/geo/point.js +++ b/src2/geo/point.js @@ -6,7 +6,7 @@ import { newSlope } from './slope.js'; const { Vector3 } = THREE; -export class Point { +class Point { constructor(x = 0, y = 0, z = 0, key) { this.x = x; this.y = y; @@ -39,7 +39,7 @@ export class Point { } toVector3() { - return new THREE.Vector3(this.x, this.y, this.z); + return new Vector3(this.x, this.y, this.z); } set(x, y, z) { @@ -436,6 +436,10 @@ export class Point { return this === p || (this.x === p.x && this.y === p.y && this.z === p.z); } + isEqual2D(p) { + return this === p || (this.x === p.x && this.y === p.y); + } + /** * returns true if points are close enough to be considered equivalent */ @@ -599,7 +603,6 @@ export class Point { } } -// Helper functions function dot(u, v) { return u.x * v.x + u.y * v.y; } @@ -609,22 +612,45 @@ function norm(v) { } function d(u, v) { - return Math.sqrt(sqr(u.x - v.x) + sqr(u.y - v.y)); + return norm({ + x: u.x - v.x, + y: u.y - v.y + }); } function p2l(p, l1, l2) { - let v = l2.clone().sub(l1); - let w = p.clone().sub(l1); - let proj = w.dot(v) / v.dot(v); - if (proj < 0) return w.length(); - if (proj > 1) return p.distTo(l2); - return w.sub(v.multiplyScalar(proj)).length(); + let v = { + x: l2.x - l1.x, + y: l2.y - l1.y + }; + let w = { + x: p.x - l1.x, + y: p.y - l1.y + }; + let c1 = dot(w, v); + let c2 = dot(v, v); + let b = c1 / c2; + if (isNaN(b)) { + // console.log('nan', {p, l1, l2, v, w, c1, c2}); + b = 0; + } + let pb = { + x: l1.x + b * v.x, + y: l1.y + b * v.y + }; + return d(p, pb); } -export function newPoint(x, y, z, key) { +function newPoint(x, y, z, key) { return new Point(x, y, z, key); } -export function pointFromClipper(cp, z) { +function pointFromClipper(cp, z) { return newPoint(cp.X / config.clipper, cp.Y / config.clipper, z); } + + export { + Point, + newPoint, + pointFromClipper +}; diff --git a/src2/kiri-mode/cam/client.js b/src2/kiri-mode/cam/client.js index a0c6fe31..15679976 100644 --- a/src2/kiri-mode/cam/client.js +++ b/src2/kiri-mode/cam/client.js @@ -9,6 +9,7 @@ import { animate2 as anim_3d, animate_clear2 as anim_3d_clear } from './anim-3d- import { space as SPACE } from '../../moto/space.js'; import { Layers } from '../../kiri/layers.js'; import { Stack } from '../../kiri/stack.js'; +import { Tool } from './tool.js'; import { CAM } from './driver-fe.js'; const { alerts, conf, noop, space } = api; @@ -435,7 +436,7 @@ func.traceAdd = (ev) => { let areas = (poppedRec.areas[widget.id] || []); let stack = new Stack(widget.mesh); widget.trace_stack = stack; - widget.traces.forEach(poly => { + widget.traces?.forEach(poly => { let match = areas.filter(arr => poly.matches(arr)); let layers = new Layers(); layers.setLayer("trace", {line: 0xaaaa55, fat:4, order:-10}, false).addPoly(poly); @@ -602,7 +603,7 @@ func.selectHoles = async function(individual){ * @param {Object} drill - {depth,selected} object of the hole * @returns {Mesh} the created mesh */ - function createHoleMesh(widget,drill){ + function createHoleMesh(widget,drill) { let {depth,selected, diam} = drill let color = selected ? 0xFF0000:0x39e366 let geo = new THREE.CylinderGeometry(diam/2,diam/2,depth,20); @@ -612,80 +613,92 @@ func.selectHoles = async function(individual){ mesh.position.z -= depth/2 mesh.rotation.x = Math.PI/2 drill.widgetID = widget.id - drill.meshId = mesh.id; //add pointers to both objects + drill.meshId = mesh.id; // add pointers to both objects mesh.hole = drill; mesh.parent = widget.mesh; widget.mesh.add(mesh); - widget.adds.push(mesh); //for click detection + widget.adds.push(mesh); // for click detection return mesh } - let meshesCached = widgets.every(widget=>poppedRec.drills[widget.id] != undefined) - if( individual && meshesCached ){ // if any widget already has cached holes + let meshesCached = widgets.every(widget => poppedRec.drills[widget.id] != undefined) + if (individual && meshesCached) { + // if any widget already has cached holes // console.log("already has cached holes",poppedRec.drills) - api.hide.alert(alert) + api.hide.alert(alert); api.widgets.for(widget => { - if(widget.adds){ - let drills = poppedRec.drills[widget.id] - let ids = drills - .map(hole => hole.meshId) - if(widget.adds.includes(mesh)){ - widget.adds.forEach(add=>{ - if(ids.includes(add.id)){ - add.visible = true + if (widget.adds) { + let drills = poppedRec.drills[widget.id]; + let ids = drills.map(hole => hole.meshId); + if (false && widget.adds.includes(mesh)) { + // mesh in the old code was a dead artifact + // so this code branch never actually ran + widget.adds.forEach(add => { + if (ids.includes(add.id)) { + add.visible = true; } }) - }else{ + } else { drills.forEach(drill => { - createHoleMesh(widget, drill) - }) + createHoleMesh(widget, drill); + }); } } }) - - }else{ // if no widget has cached holes - let alert = api.show.alert(""); - await CAM.holes( + } else { + // if no widget has cached holes + let alert2 = api.show.alert(""); + let found = await CAM.holes( individual, poppedRec, - (progress,msg)=>{ - alert[0]=msg - api.show.progress(progress,msg) - api.alerts.update() + (progress, msg) => { + alert2[0] = msg; + api.show.progress(progress,msg); + api.alerts.update(); }, async centers => { - api.show.progress(0) - if(! Array.isArray(centers) ){ - console.log("worker returned a malformed drills response") - return + api.show.progress(0); + if (!Array.isArray(centers)) { + console.log("worker returned a malformed drills response"); + return; } - let shadow = centers.some(c=>c.shadowed) - api.hide.alert(alert) - if(shadow){ - alert = api.show.alert("Some holes are shadowed by part and are not shown."); + if (centers.length === 0) { + console.log("no drill holes found"); + return; } - centers = centers ?? [] + let shadow = centers.some(c => c.shadowed); + api.hide.alert(alert2); + if (shadow) { + alert2 = api.show.alert("Some holes are shadowed by part and are not shown."); + } + centers = centers ?? []; // list of all hole centers and if they are selected api.widgets.for(widget => { - const {holes} = centers.find(center=>center.id == widget.id) + const { holes } = centers.find(center => center.id == widget.id); // console.log(holes) if (!holes.length) unselectHoles(holes); holes.forEach(hole => { - createHoleMesh(widget, hole) - }) + createHoleMesh(widget, hole); + }); //add hole data to record - poppedRec.drills = poppedRec.drills ?? {} - poppedRec.drills[widget.id] = holes + poppedRec.drills = poppedRec.drills ?? {}; + poppedRec.drills[widget.id] = holes; //give widget access to an array of drill records that refrence it //so that it can be cleared when widget is rotated or mirrored etc. - if(!widget.drills){widget.drills = []} - widget.drills.push(holes) + if(!widget.drills){widget.drills = []}; + widget.drills.push(holes); }) } ); + if (!found || found.length === 0) { + api.hide.alert(alert); + api.hide.alert(alert2); + api.show.alert("no drill holes found"); + return; + } } //hide the alert once hole meshes are calculated on the worker, and then added to the scene // api.hide.alert(alert); - let escAlert = api.show.alert("[esc] cancels drill editing",1000); + let escAlert = api.show.alert("[esc] cancels drill editing", 1000); setTimeout(() => { api.hide.alert(escAlert); }, 5000); @@ -1956,7 +1969,7 @@ function createPopOp(type, map) { api.util.ui2rec(op.rec, op.inputs); const settings = conf.get(); - const {tool} = new CAM.Tool(settings,op.rec.tool); //get tool by id + const {tool} = new Tool(settings,op.rec.tool); //get tool by id const opType = op.rec.type const drillOrRegister = opType == "drill" || opType == "register" diff --git a/src2/kiri-mode/cam/driver-be.js b/src2/kiri-mode/cam/driver-be.js index 2d4620be..5c9e85d3 100644 --- a/src2/kiri-mode/cam/driver-be.js +++ b/src2/kiri-mode/cam/driver-be.js @@ -81,10 +81,11 @@ function init(worker) { const widgets = Object.values(worker.cache); const fresh = []; - for (let [i,widget] of widgets.entries() ) { - if (await holes(settings, widget, indiv, rec, - ( prog, msg )=>{ send.data({progress: (i/widgets.length)+(prog/widgets.length),msg})} - )){ + for (let [i, widget] of widgets.entries()) { + let ret = await holes(settings, widget, indiv, rec, (prog, msg) => { + send.data({ progress: (i/widgets.length)+(prog/widgets.length), msg }); + }); + if (ret) { fresh.push(widget); } } @@ -93,7 +94,7 @@ function init(worker) { send.done(codec.encode(fresh.map(widget => { return { id: widget.id, holes: widget.drills, - shadowed:widget.shadowedDrills + shadowed: widget.shadowedDrills } } ))); } } diff --git a/src2/kiri-mode/cam/driver-fe.js b/src2/kiri-mode/cam/driver-fe.js index 2b6ce455..e5cf20c7 100644 --- a/src2/kiri-mode/cam/driver-fe.js +++ b/src2/kiri-mode/cam/driver-fe.js @@ -45,6 +45,7 @@ function traces(ondone, single) { const settings = api.conf.get(); const widgets = api.widgets.map(); api.client.send("cam_traces", { settings, single }, output => { + console.log({ output }); const ids = []; codec.decode(output).forEach(rec => { ids.push(rec.id); @@ -60,16 +61,16 @@ function traces_clear(ondone) { }); }; -function holes(indiv,rec,onProgress,onDone) { +function holes(indiv, rec, onProgress, onDone) { api.client.sync(); const settings = api.conf.get(); return new Promise((res,rej)=>{ api.client.send("cam_holes", { settings, rec, indiv }, output => { - let out = codec.decode(output) - if(out.progress != undefined){ + let out = codec.decode(output); + if (out.progress != undefined) { //if a progress message, onProgress(out.progress,out.msg) - }else{ + } else { api.hide.alert(alert); onDone(out); res(out); diff --git a/src2/kiri-mode/cam/op-contour.js b/src2/kiri-mode/cam/op-contour.js index 1801b95c..0fdeef35 100644 --- a/src2/kiri-mode/cam/op-contour.js +++ b/src2/kiri-mode/cam/op-contour.js @@ -2,6 +2,7 @@ import { CamOp } from './op.js'; import { Tool } from './tool.js'; +import { generate as Topo } from './topo3.js'; import { newPoint } from '../../geo/point.js'; import { tip2tipEmit } from '../../geo/paths.js'; diff --git a/src2/kiri-mode/cam/slice.js b/src2/kiri-mode/cam/slice.js index a3b49f08..ffa58f12 100644 --- a/src2/kiri-mode/cam/slice.js +++ b/src2/kiri-mode/cam/slice.js @@ -567,7 +567,7 @@ 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 = shadowAt(widget, slice.z, 0) + slice.shadow = computeShadowAt(widget, slice.z, 0) let inner = top.inner; if (!inner) { //no holes continue; diff --git a/src2/kiri-mode/cam/slicer2.js b/src2/kiri-mode/cam/slicer2.js index c0a99a15..5fb5c4a4 100644 --- a/src2/kiri-mode/cam/slicer2.js +++ b/src2/kiri-mode/cam/slicer2.js @@ -1,13 +1,12 @@ /** Copyright Stewart Allen -- All Rights Reserved */ -import { base } from '../../../geo/base.js'; -import { kiri } from '../../kiri.js'; -import { config, newOrderedLine, newPoint } from '../../../geo/base.js'; +import { base } from '../../geo/base.js'; +import { newPoint } from '../../geo/point.js'; +import { newOrderedLine } from '../../geo/line.js'; -const { base, kiri } = root; -const { config, newOrderedLine, newPoint } = base; +const { config } = base; -class Slicer { +export class Slicer { static intersectPoints = intersectPoints; static checkOverUnderOn = checkOverUnderOn; @@ -280,7 +279,7 @@ function removeDuplicateLines(lines, debug) { // find new endpoints that are not shared point let p1 = l1.p1 != point ? l1.p1 : l1.p2, p2 = l2.p1 != point ? l2.p1 : l2.p2, - newline = base.newOrderedLine(p1,p2); + newline = newOrderedLine(p1,p2); // remove deleted lines from associated points p1.group.remove(l1); p1.group.remove(l2); @@ -317,8 +316,3 @@ function removeDuplicateLines(lines, debug) { return output; } - -kiri.topo_slicer = Slicer; - - -export { checkOverUnderOn, intersectPoints, getCachedPoint, makeZLine, removeDuplicateLines, cachePoint, addLinesToPoint, min, max, len, pts, i, x0, y0, z0, x1, y1, z1, x2, y2, z2, minz, maxz, p0, p1, p2, ret, z, points, zMin, zMax, phash, lines, where, add2, line, delta, ip, j, cached, output, cp, l1, Slicer }; diff --git a/src2/kiri-mode/cam/topo3.js b/src2/kiri-mode/cam/topo3.js index 45c2e282..49b46a9d 100644 --- a/src2/kiri-mode/cam/topo3.js +++ b/src2/kiri-mode/cam/topo3.js @@ -1,19 +1,14 @@ /** Copyright Stewart Allen -- All Rights Reserved */ -import { base } from '../../../geo/base.js'; -import { kiri } from '../../kiri.js'; -import { moto } from '../../../moto.js'; -import { driver, newSlice } from '../../kiri.js'; -import { CAM } from './driver.js'; -import { polygons, newLine, newSlope, newPoint, newPolygon } from '../../../geo/base.js'; +import { broker } from '../../moto/broker.js'; +import { codec } from '../../kiri/codec.js'; +import { newPoint } from '../../geo/point.js'; +import { newPolygon } from '../../geo/polygon.js'; +import { newSlice } from '../../kiri/slice.js'; +import { Slicer as topo_slicer } from './slicer2.js'; +import { polygons as POLY } from '../../geo/polygons.js'; +import { Tool } from './tool.js'; -const { base, kiri, moto } = root; -const { driver, newSlice } = kiri; -const { CAM } = driver; -const { polygons, newLine, newSlope, newPoint, newPolygon } = base; - -const PRO = CAM.process; -const POLY = polygons; const RAD2DEG = 180 / Math.PI; const DEG2RAD = Math.PI / 180; @@ -44,7 +39,7 @@ class Topo { inside = contour.inside, density = 1 + (contour.reduction || 0), resolution = tolerance ? tolerance : 1/Math.sqrt(animesh/(boundsX * boundsY)), - tool = new CAM.Tool(settings, contour.tool), + tool = new Tool(settings, contour.tool), toolOffset = tool.generateProfile(resolution).profile, toolDiameter = tool.fluteDiameter(), toolStep = toolDiameter * contour.step, //tool.contourOffset(contour.step), @@ -197,7 +192,7 @@ class Topo { async raster(widget, params, onupdate) { const { resolution } = params; const { box } = params; - const { worker, minions } = kiri; + const { dispatch, minions } = self.kiri_worker; const vertices = widget.getGeoVertices({ unroll: true, translate: true }).toShared(); const range = { min: Infinity, max: -Infinity }; @@ -232,7 +227,7 @@ class Topo { // define sharded ranges if (minions.running > 1) { - worker.putCache({ key: widget.id, data: vertices }, { done: data => { + dispatch.putCache({ key: widget.id, data: vertices }, { done: data => { // console.log({ put_cache_done: data }); }}); @@ -262,7 +257,7 @@ class Topo { return box2; }); - worker.clearCache({}, { done: data => { + dispatch.clearCache({}, { done: data => { // console.log({ clear_cache_done: data }); }}); @@ -271,12 +266,12 @@ class Topo { // iterate over shards, merge output // const output = []; for (let slice of slices) { - new kiri.topo_slicer(slice.index) + new topo_slicer(slice.index) .setFromArray(vertices, slice) .slice(resolution) .map(rec => { - const slice = kiri.newSlice(rec.z); + const slice = newSlice(rec.z); slice.index = rec.index; slice.lines = rec.lines; for (let line of rec.lines) { @@ -302,7 +297,7 @@ class Topo { async contour(params, onupdate) { const trace = this.trace; - const concurrent = kiri.minions.running; + const concurrent = self.kiri_worker.minions.running; const { minX, maxX, minY, maxY, boundsX, boundsY, stepsX, stepsY } = params; const { gridDelta, resolution, density, partOff, toolStep, contourX, contourY } = params; @@ -589,7 +584,7 @@ class Trace { init(params) { this.cross = params; - const { minions } = kiri; + const { minions } = self.kiri_worker; const { clipTab, clipTabZ } = params; // because codec does not encode arbitrary fields @@ -601,7 +596,6 @@ class Trace { } if (minions && this.cross.concurrent) { - const { codec } = kiri; minions.broadcast("trace_init", codec.encode({ probe: this.probe.params, trace: this.params, @@ -611,7 +605,7 @@ class Trace { } cleanup() { - const { minions } = kiri; + const { minions } = self.kiri_worker; if (minions && this.cross.concurrent) { minions.broadcast("trace_cleanup"); @@ -619,14 +613,14 @@ class Trace { } crossY(params, then) { - const { minions } = kiri; + const { minions } = self.kiri_worker; if (minions && this.cross.concurrent) { minions.queue({ cmd: "trace_y", params }, data => { - then(kiri.codec.decode(data.slice)); + then(codec.decode(data.slice)); }); } else { this.crossY_sync(params, then); @@ -634,14 +628,14 @@ class Trace { } crossX(params, then) { - const { minions } = kiri; + const { minions } = self.kiri_worker; if (minions && this.cross.concurrent) { minions.queue({ cmd: "trace_x", params }, data => { - then(kiri.codec.decode(data.slice)); + then(codec.decode(data.slice)); }); } else { this.crossX_sync(params, then); @@ -817,11 +811,7 @@ function raster_slice(inputs) { return points; }; -CAM.Topo = async function(opt) { - return new Topo().generate(opt); -}; - -moto.broker.subscribe("minion.started", msg => { +broker.subscribe("minion.started", msg => { const { funcs, cache, reply, log } = msg; funcs.topo_raster = (data, seq) => { @@ -829,7 +819,7 @@ moto.broker.subscribe("minion.started", msg => { const { resolution } = params; const vertices = cache[id]; const box = new THREE.Box2(); - new kiri.topo_slicer(slice.index) + new topo_slicer(slice.index) .setFromArray(vertices, slice) .slice(resolution) .forEach(rec => { @@ -854,7 +844,6 @@ moto.broker.subscribe("minion.started", msg => { funcs.trace_init = data => { const { cache } = self; - const { codec } = kiri; data.cross.clipTo = codec.decode(data.cross.clipTo); data.cross.clipTab = codec.decode(data.cross.clipTab); const probe = new Probe(data.probe); @@ -871,7 +860,7 @@ moto.broker.subscribe("minion.started", msg => { const { cache } = self; const { trace } = cache.trace; trace.crossY_sync(data.params, slice => { - slice = kiri.codec.encode(slice); + slice = codec.encode(slice); reply({ seq, slice }); }); }; @@ -880,7 +869,7 @@ moto.broker.subscribe("minion.started", msg => { const { cache } = self; const { trace } = cache.trace; trace.crossX_sync(data.params, slice => { - slice = kiri.codec.encode(slice); + slice = codec.encode(slice); reply({ seq, slice }); }); }; @@ -890,5 +879,6 @@ moto.broker.subscribe("minion.started", msg => { }; }); - -export { raster_slice, PRO, POLY, RAD2DEG, DEG2RAD, ctab, debug, output, probe, trace, box, params, vertices, range, i, x, z, shards, step, slices, index, slice, complete, promises, concurrent, stepsTaken, pcount, slicesY, slicesX, promise, inc, dec, gridx, gridy, y, lines, points, toolAtZ, sx, tx, ty, tz, rx, ry, toolAtXY, zAtXY, ix, iy, newslice, newtrace, end_poly, log, push_point, newP, lastP, dl, dz, slope, dv, angle, object, poly, zok, checkr, tv, len, l1, tp, j, l2, p1, crossz, spansy, dy, nup, p2, Topo }; +export async function generate(opt) { + return new Topo().generate(opt); +} diff --git a/src2/kiri-run/worker.js b/src2/kiri-run/worker.js index 099bba08..11febd0f 100644 --- a/src2/kiri-run/worker.js +++ b/src2/kiri-run/worker.js @@ -287,7 +287,7 @@ const dispatch = { // current.snap = null; current.print = null; dispatch.group = wgroup = {}; - dispatch.cache = wcache = {}; + dispatch.cache = worker.cache = wcache = {}; Widget.Groups.clear(); send.done({ clear: true }); }, diff --git a/src2/kiri/widget.js b/src2/kiri/widget.js index 6415fbf0..625c31e8 100644 --- a/src2/kiri/widget.js +++ b/src2/kiri/widget.js @@ -15,6 +15,8 @@ let nextId = 0; function newWidget(id,group) { return new Widget(id,group) } +function catalog() { return self.kiri_catalog }; + function index() { return self.kiri_catalog.index } class Widget {