diff --git a/mods/devel/init.js b/mods/devel/init.js index 3a0ab317..35907126 100644 --- a/mods/devel/init.js +++ b/mods/devel/init.js @@ -1,9 +1,9 @@ // back end for device export in dev mode module.exports = function(server) { - server.inject("kiri", "kiri.js"); if (!server.env.debug) { return; } + server.inject("kiri", "kiri.js"); const fs = require('fs'); server.api.postDevice = (req, res, next) => { server.handler.decodePost(req, res, () => { @@ -16,7 +16,7 @@ module.exports = function(server) { } const { mode } = device; const { deviceName } = device; - const path = `${server.const.rootdir}/src/kiri-dev/${mode.toLowerCase()}/${deviceName.replace(/\ /g,'.')}`; + const path = `${server.const.rootdir}/src/kiri/dev/${mode.toLowerCase()}/${deviceName.replace(/\ /g,'.')}`; // console.log({ mode, device, process, path }); fs.writeFileSync(path, JSON.stringify(device, undefined, 4)); res.end('profile saved'); diff --git a/mods/devel/kiri.js b/mods/devel/kiri.js index 6ec2c57e..a4562540 100644 --- a/mods/devel/kiri.js +++ b/mods/devel/kiri.js @@ -4,7 +4,7 @@ self.kiri.load(api => { let deviceExport = api.device.export; api.device.export = (exp, name, opt = {}) => { const { event, record } = opt; - if (event && event.shiftKey & api.const.LOCAL) { + if (event && event.shiftKey) { const { code, process, profiles } = record; fetch("/api/postDevice", { method: "POST", @@ -12,7 +12,7 @@ self.kiri.load(api => { }) .then(r => r.text()) .then(t => { - // console.log({server_said: t}); + console.log({server_said: t}); api.show.alert('profile saved to server'); }); } else { diff --git a/src/geo/polygon.js b/src/geo/polygon.js index 952a0474..f834776a 100644 --- a/src/geo/polygon.js +++ b/src/geo/polygon.js @@ -70,6 +70,18 @@ export class Polygon { return bounds; } + getBounds3D(bounds = new THREE.Box3()) { + for (let point of this.points) { + bounds.expandByPoint(point); + } + if (this.inner) { + for (let i of this.inner) { + i.getBounds3D(bounds); + } + } + return bounds; + } + toPath2D(offset) { return paths.pointsToPath(this.points, offset, this.open); } @@ -985,7 +997,13 @@ export class Polygon { } minZ() { - return Math.min(...this.points.map(p => p.z)); + let minZ = Math.min(...this.points.map(p => p.z)); + if (this.inner) { + for (let i of this.inner) { + minZ = Math.min(minZ, i.minZ()); + } + } + return minZ; } avgZ() { diff --git a/src/kiri/core/api.js b/src/kiri/core/api.js index 76f00517..a12e4718 100644 --- a/src/kiri/core/api.js +++ b/src/kiri/core/api.js @@ -73,6 +73,9 @@ let UC = UI.prefix('kiri').inputAction(settings.conf.update), redo: noop // do.js }, devel = { + get enabled() { + return settings.ctrl().devel; + }, xray(layers, raw) { let proc = api.conf.get().process, size = proc.sliceHeight || proc.slaSlice || 1, diff --git a/src/kiri/core/conf.js b/src/kiri/core/conf.js index 04a0f130..86f10e4e 100644 --- a/src/kiri/core/conf.js +++ b/src/kiri/core/conf.js @@ -423,6 +423,20 @@ export const conf = { camArcEnabled: false, camArcResolution: 5, camArcTolerance: 0.15, + camAreaSpindle: 1000, + camAreaTool: 1000, + camAreaMode: "clear", + camAreaTrace: "none", + camAreaSurface: "linear", + camAreaAngle: 0, + camAreaOver: 0.4, + camAreaDown: 1, + camAreaSpeed: 1000, + camAreaPlunge: 100, + camAreaExpand: 0, + camAreaSmooth: 1, + camAreaRefine: 0, + camAreaOutline: false, camContourAngle: 85, camContourBottom: false, camContourBridge: 0, diff --git a/src/kiri/core/consts.js b/src/kiri/core/consts.js index 0f6e9ff7..ca4ec075 100644 --- a/src/kiri/core/consts.js +++ b/src/kiri/core/consts.js @@ -121,6 +121,15 @@ const LISTS = { { name: "adaptive" }, { name: "legacy 1" }, { name: "legacy 2" } + ], + opmode: [ + { name: "clear" }, + { name: "trace" }, + { name: "surface" } + ], + surftyp: [ + { name: "linear" }, + { name: "offset" }, ] }; diff --git a/src/kiri/core/init.js b/src/kiri/core/init.js index a8968d1a..bf47547a 100644 --- a/src/kiri/core/init.js +++ b/src/kiri/core/init.js @@ -1579,16 +1579,6 @@ function init_two() { api.event.emit('load.lib', lib); }); - // load CSS extensions - if (SETUP.ss) SETUP.ss.forEach(function(style) { - style = style.charAt(0) === '/' ? style : `/kiri/style-${style}`; - let ss = DOC.createElement('link'); - ss.setAttribute("type", "text/css"); - ss.setAttribute("rel", "stylesheet"); - ss.setAttribute("href", `${style}.css?${version}`); - DOC.body.appendChild(ss); - }); - // override stored settings if (SETUP.v) SETUP.v.forEach(function(kv) { kv = kv.split('='); diff --git a/src/kiri/core/tools.js b/src/kiri/core/tools.js index 8b8062b4..6802b718 100644 --- a/src/kiri/core/tools.js +++ b/src/kiri/core/tools.js @@ -54,7 +54,7 @@ function onLeftySelect() { let projectedNormal = new Vector3(lastface.normal.x, lastface.normal.y, 0).normalize(); // Target direction on XY plane (negative Y axis) - let targetDir = new Vector3(0, -1, 0); + let targetDir = new Vector3(-1, 0, 0); // Calculate angle between projected normal and target let angle = Math.atan2( diff --git a/src/kiri/core/widget.js b/src/kiri/core/widget.js index 85b16879..f72115da 100644 --- a/src/kiri/core/widget.js +++ b/src/kiri/core/widget.js @@ -332,6 +332,10 @@ class Widget { moto.space.refresh(); } + isSynth() { + return this.track.synth ?? false; + } + isVisible() { return this.getMaterial().visible; } diff --git a/src/kiri/dev/fdm/Creality.Ender.7 b/src/kiri/dev/fdm/Creality.Ender.7 new file mode 100644 index 00000000..f7401222 --- /dev/null +++ b/src/kiri/dev/fdm/Creality.Ender.7 @@ -0,0 +1,166 @@ +{ + "mode": "FDM", + "internal": 0, + "bedHeight": 2.5, + "bedWidth": 252, + "bedDepth": 252, + "bedRound": false, + "bedBelt": false, + "deviceZMax": 0, + "gcodeTime": 1, + "maxHeight": 302, + "originCenter": false, + "gcodeFan": [ + "M106 S{fan_speed}" + ], + "gcodeFeature": [], + "gcodeTrack": [], + "gcodeLayer": [], + "gcodePre": [ + "M140 S{bed_temp}", + "M105", + "M190 S{bed_temp}", + "M104 S{temp}", + "M105", + "M109 S{temp}", + "M82 ; absolute extrusion mode", + "G28 ; Home", + "G92 E0 ; Reset Extruder", + "G1 Z2.0 F3000 ; Move Z Axis up", + "G1 X10.1 Y20 Z0.28 F5000.0 ; Move to start position", + "G1 X10.1 Y200.0 Z0.28 F1500.0 E15 ; Draw the first line", + "G1 X10.4 Y200.0 Z0.28 F5000.0 ; Move to side a little", + "G1 X10.4 Y20 Z0.28 F1500.0 E30 ; Draw the second line", + "G92 E0 ; Reset Extruder", + "G1 Z2.0 F3000 ; Move Z Axis up" + ], + "gcodePost": [ + "G91 ; Relative positionning", + "G1 E-2 F2700 ; Retract a bit", + "G1 E-2 Z0.2 F2400 ; Retract and raise Z", + "G1 X5 Y5 F3000 ; Wipe out", + "G1 Z10 ; Raise Z more", + "G90 ; Absolute positionning", + "G28 X Y ; Present print", + "M106 S0 ; Turn-off fan", + "M104 S0 ; Turn-off hotend", + "M140 S0 ; Turn-off bed", + "M84 X Y E ; Disable all steppers but Z" + ], + "gcodeProc": "", + "gcodeChange": [], + "gcodeFExt": "gcode", + "extruders": [ + { + "extFilament": 1.75, + "extNozzle": 0.4, + "extOffsetX": 0, + "extOffsetY": 0 + }, + { + "extFilament": 1.75, + "extNozzle": 0.4, + "extOffsetX": 0, + "extOffsetY": 0 + } + ], + "new": false, + "deviceName": "Creality.Ender.7", + "imageURL": "", + "fwRetract": false, + "filamentSource": "direct", + "profiles": [ + { + "antiBacklash": 0, + "arcTolerance": 0, + "firstLayerBedTemp": 60, + "firstLayerBeltBump": 0, + "firstLayerBeltLead": 3, + "firstLayerBeltFact": 1, + "firstLayerBrim": 0, + "firstLayerBrimGap": 0, + "firstLayerBrimIn": 0, + "firstLayerBrimTrig": 0, + "firstLayerFanSpeed": 0, + "firstLayerFillRate": 35, + "firstLayerFlatten": 0, + "firstLayerNozzleTemp": 210, + "firstLayerRate": 30, + "firstLayerYOffset": 0, + "firstSliceHeight": 0.25, + "outputAlternating": false, + "outputAvoidGaps": true, + "outputBedTemp": 65, + "outputBeltFirst": false, + "outputBrimCount": 2, + "outputBrimOffset": 2, + "outputCoastDist": 0, + "outputDraftShield": false, + "outputFanLayer": 1, + "outputFanSpeed": 255, + "outputFeedrate": 50, + "outputFillMult": 1.25, + "outputFinishrate": 50, + "outputInvertX": false, + "outputInvertY": false, + "outputLayerRetract": false, + "outputLoops": 0, + "outputMaxFlowrate": 15, + "outputMinLayerTime": 10, + "outputMinSpeed": 5, + "outputPurgeTower": 0, + "outputRaft": false, + "outputRaftSpacing": 0.2, + "outputRetractDist": 10, + "outputRetractDwell": 20, + "outputRetractSpeed": 40, + "outputRetractWipe": 0, + "outputScarfLength": 0, + "outputSeekrate": 250, + "outputShellMult": 1.25, + "outputShortPoly": 0, + "outputSparseMult": 1.25, + "outputTemp": 220, + "processName": "Ender 7 PLA", + "ranges": [], + "sliceAdaptive": false, + "sliceAngle": 45, + "sliceBottomLayers": 3, + "sliceCompInner": 0, + "sliceCompOuter": 0, + "sliceDetectThin": "basic", + "sliceFillAngle": 45, + "sliceFillGrow": 0, + "sliceFillOverlap": 0.35, + "sliceFillRepeat": 1, + "sliceFillSparse": 0.25, + "sliceFillType": "hex", + "sliceFillWidth": 1, + "sliceHeight": 0.25, + "sliceLayerStart": "last", + "sliceLayerStartX": 0, + "sliceLayerStartY": 0, + "sliceLineWidth": 0, + "sliceMinHeight": 0, + "sliceShellOrder": "in-out", + "sliceShells": 3, + "sliceSolidMinArea": 1, + "sliceSupportAngle": 50, + "sliceSupportArea": 0.1, + "sliceSupportDensity": 0.1, + "sliceSupportEnable": true, + "sliceSupportExtra": 0, + "sliceSupportGap": 1, + "sliceSupportGrow": 0, + "sliceSupportNozzle": 0, + "sliceSupportOffset": 1, + "sliceSupportOutline": true, + "sliceSupportSize": 5, + "sliceSupportSpan": 5, + "sliceTopLayers": 3, + "sliceZInterleave": false, + "zHopDistance": 0.2 + } + ], + "extras": {} +} \ No newline at end of file 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/cl-ops.js b/src/kiri/mode/cam/cl-ops.js index 4cefd5d0..80555902 100644 --- a/src/kiri/mode/cam/cl-ops.js +++ b/src/kiri/mode/cam/cl-ops.js @@ -15,7 +15,9 @@ const { MODES } = api.const; const { uc: UC } = api; const { alerts, conf } = api; const { current: LANG } = api.language; +const { toInt, toFloat } = UC; +const units = true; let seed = Date.now(); function hasIndexing() { @@ -205,12 +207,12 @@ export function createPopOps() { }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0) }), - stepz: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true, bound: UC.bound(0, 100.0) }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), - down: UC.newInput(LANG.cc_loff_s, { title: LANG.cc_loff_l, convert: UC.toFloat, units: true }), - inset: UC.newInput(LANG.cc_lxyo_s, { title: LANG.cc_lxyo_l, convert: UC.toFloat, units: true, show: () => !env.popOp.level.rec.stock }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }), + stepz: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units, bound: UC.bound(0, 100.0) }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + down: UC.newInput(LANG.cc_loff_s, { title: LANG.cc_loff_l, convert: toFloat, units }), + inset: UC.newInput(LANG.cc_lxyo_s, { title: LANG.cc_lxyo_l, convert: toFloat, units, show: () => !env.popOp.level.rec.stock }), sep: UC.newBlank({ class: "pop-sep" }), stock: UC.newBoolean(LANG.cc_lsto_s, undefined, { title: LANG.cc_lsto_l }), }; @@ -235,14 +237,14 @@ export function createPopOps() { }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), sep: UC.newBlank({ class: "pop-sep" }), - down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0) }), - leave: UC.newInput(LANG.cr_lsto_s, { title: LANG.cr_lsto_l, convert: UC.toFloat, units: true }), - leavez: UC.newInput(LANG.cr_lstz_s, { title: LANG.cr_lstz_l, convert: UC.toFloat, bound: UC.bound(0, 10), units: true }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }), + leave: UC.newInput(LANG.cr_lsto_s, { title: LANG.cr_lsto_l, convert: toFloat, units }), + leavez: UC.newInput(LANG.cr_lstz_s, { title: LANG.cr_lstz_l, convert: toFloat, bound: UC.bound(0, 10), units }), sep: UC.newBlank({ class: "pop-sep" }), all: UC.newBoolean(LANG.cr_clst_s, undefined, { title: LANG.cr_clst_l, show: hasIndexing }), voids: UC.newBoolean(LANG.cr_clrp_s, undefined, { title: LANG.cr_clrp_l }), @@ -251,8 +253,8 @@ export function createPopOps() { omitthru: UC.newBoolean(LANG.co_omit_s, undefined, { title: LANG.co_omit_l }), sep: UC.newBlank({ class: "pop-sep" }), exp: UC.newExpand("overrides"), - ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: UC.toFloat, units: true }), - ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: UC.toFloat, units: true }), + ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: toFloat, units }), + ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: toFloat, units }), ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, { title: LANG.ou_conv_l }), exp_end: UC.endExpand(), }; @@ -278,12 +280,12 @@ export function createPopOps() { }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }), - down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0), show: () => env.popOp.outline.rec.wide }), - steps: UC.newInput(LANG.cc_sovc_s, { title: LANG.cc_sovc_l, convert: UC.toInt, bound: UC.bound(1, 500), show: () => env.popOp.outline.rec.wide }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: () => env.popOp.outline.rec.wide }), + steps: UC.newInput(LANG.cc_sovc_s, { title: LANG.cc_sovc_l, convert: toInt, bound: UC.bound(1, 500), show: () => env.popOp.outline.rec.wide }), sep: UC.newBlank({ class: "pop-sep" }), top: UC.newBoolean(LANG.co_clrt_s, undefined, { title: LANG.co_clrt_l }), inside: UC.newBoolean(LANG.co_olin_s, undefined, { title: LANG.co_olin_l, show: (op) => { return !op.inputs.outside.checked } }), @@ -295,8 +297,8 @@ export function createPopOps() { dogbones: UC.newBoolean(LANG.co_dogb_s, undefined, { title: LANG.co_dogb_l, show: (op) => { return !op.inputs.wide.checked } }), sep: UC.newBlank({ class: "pop-sep" }), exp: UC.newExpand("overrides"), - ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: UC.toFloat, units: true }), - ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: UC.toFloat, units: true }), + ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: toFloat, units }), + ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: toFloat, units }), ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, { title: LANG.ou_conv_l }), exp_end: UC.endExpand(), }; @@ -323,17 +325,17 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), axis: UC.newSelect(LANG.cd_axis, {}, "xyaxis"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), sep: UC.newBlank({ class: "pop-sep" }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 10.0) }), - leave: UC.newInput(LANG.cf_leav_s, { title: LANG.cf_leav_l, convert: UC.toFloat, bound: UC.bound(0, 100) }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 10.0) }), + leave: UC.newInput(LANG.cf_leav_s, { title: LANG.cf_leav_l, convert: toFloat, bound: UC.bound(0, 100) }), sep: UC.newBlank({ class: "pop-sep" }), - angle: UC.newInput(LANG.cf_angl_s, { title: LANG.cf_angl_l, convert: UC.toFloat, bound: UC.bound(45, 90), show: (op) => op.inputs.curves.checked }), - flatness: UC.newInput(LANG.ou_flat_s, { title: LANG.ou_flat_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), units: false, round: 4 }), - tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: UC.toFloat, bound: UC.bound(0, 10.0), units: true, round: 4 }), - reduction: UC.newInput(LANG.ou_redu_s, { title: LANG.ou_redu_l, convert: UC.toInt, bound: UC.bound(0, 10), units: false }), - // bridging: UC.newInput(LANG.ou_brdg_s, {title:LANG.ou_brdg_l, convert:UC.toFloat, bound:UC.bound(0,1000.0), units:true, round:4, show:(op) => op.inputs.curves.checked}), + angle: UC.newInput(LANG.cf_angl_s, { title: LANG.cf_angl_l, convert: toFloat, bound: UC.bound(45, 90), show: (op) => op.inputs.curves.checked }), + flatness: UC.newInput(LANG.ou_flat_s, { title: LANG.ou_flat_l, convert: toFloat, bound: UC.bound(0, 1.0), units: false, round: 4 }), + tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: toFloat, bound: UC.bound(0, 10.0), units, round: 4 }), + reduction: UC.newInput(LANG.ou_redu_s, { title: LANG.ou_redu_l, convert: toInt, bound: UC.bound(0, 10), units: false }), + // bridging: UC.newInput(LANG.ou_brdg_s, {title:LANG.ou_brdg_l, convert:toFloat, bound:UC.bound(0,1000.0), units:true, round:4, show:(op) => op.inputs.curves.checked}), sep: UC.newBlank({ class: "pop-sep" }), curves: UC.newBoolean(LANG.cf_curv_s, undefined, { title: LANG.cf_curv_l }), inside: UC.newBoolean(LANG.cf_olin_s, undefined, { title: LANG.cf_olin_l }), @@ -357,17 +359,17 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), // axis: UC.newSelect(LANG.cd_axis, {}, "xyaxis"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), sep: UC.newBlank({ class: "pop-sep" }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 100.0) }), - angle: UC.newInput(LANG.cc_sang_s, { title: LANG.cc_sang_l, convert: UC.toFloat, bound: UC.bound(0.01, 180.0) }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 100.0) }), + angle: UC.newInput(LANG.cc_sang_s, { title: LANG.cc_sang_l, convert: toFloat, bound: UC.bound(0.01, 180.0) }), sep: UC.newBlank({ class: "pop-sep" }), - offStart: UC.newInput(LANG.ci_laso_s, { title: LANG.ci_laso_l, convert: UC.toFloat}), - offEnd: UC.newInput(LANG.ci_laeo_s, { title: LANG.ci_laeo_l, convert: UC.toFloat}), + offStart: UC.newInput(LANG.ci_laso_s, { title: LANG.ci_laso_l, convert: toFloat}), + offEnd: UC.newInput(LANG.ci_laeo_s, { title: LANG.ci_laeo_l, convert: toFloat}), sep: UC.newBlank({ class: "pop-sep" }), - tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: UC.toFloat, bound: UC.bound(0, 10.0), units: true, round: 4 }), - leave: UC.newInput(LANG.cf_leav_s, { title: LANG.cf_leav_l, convert: UC.toFloat, bound: UC.bound(0, 100) }), + tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: toFloat, bound: UC.bound(0, 10.0), units, round: 4 }), + leave: UC.newInput(LANG.cf_leav_s, { title: LANG.cf_leav_l, convert: toFloat, bound: UC.bound(0, 100) }), sep: UC.newBlank({ class: "pop-sep" }), linear: UC.newBoolean(LANG.ci_line_s, undefined, { title: LANG.ci_line_l }), // filter: UC.newRow([ UC.newButton(LANG.filter, contourFilter) ], {class:"ext-buttons f-row"}) @@ -408,22 +410,22 @@ export function createPopOps() { mode: UC.newSelect(LANG.cu_type_s, { title: LANG.cu_type_l }, "trace"), offset: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: () => (env.poppedRec.mode === 'follow') }, "traceoff"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), sep: UC.newBlank({ class: "pop-sep" }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0), show: (op) => env.popOp.trace.rec.mode === "clear" }), - down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }), - thru: UC.newInput(LANG.cc_thru_s, { title: LANG.cc_thru_l, convert: UC.toFloat, units: true }), - offover: UC.newInput(LANG.cc_offd_s, { title: LANG.cc_offd_l, convert: UC.toFloat, units: true, show: () => env.poppedRec.offset !== "none" || env.poppedRec.mode === "clear" }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: (op) => env.popOp.trace.rec.mode === "clear" }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), + thru: UC.newInput(LANG.cc_thru_s, { title: LANG.cc_thru_l, convert: toFloat, units }), + offover: UC.newInput(LANG.cc_offd_s, { title: LANG.cc_offd_l, convert: toFloat, units, show: () => env.poppedRec.offset !== "none" || env.poppedRec.mode === "clear" }), sep: UC.newBlank({ class: "pop-sep", modes: MODES.CAM, xshow: zDogSep }), merge: UC.newBoolean(LANG.co_merg_s, undefined, { title: LANG.co_merg_l, show: () => !env.popOp.trace.rec.down }), dogbone: UC.newBoolean(LANG.co_dogb_s, undefined, { title: LANG.co_dogb_l, show: canDogBones }), revbone: UC.newBoolean(LANG.co_dogr_s, undefined, { title: LANG.co_dogr_l, show: canDogBonesRev }), exp: UC.newExpand("overrides"), sep: UC.newBlank({ class: "pop-sep" }), - ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: UC.toFloat, units: true }), - ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: UC.toFloat, units: true }), + ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: toFloat, units }), + ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: toFloat, units }), ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, { title: LANG.ou_conv_l }), exp_end: UC.endExpand(), sep: UC.newBlank({ class: "pop-sep" }), @@ -451,26 +453,26 @@ export function createPopOps() { }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), sep: UC.newBlank({ class: "pop-sep" }), - step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0) }), - down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.contour }), + step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units, show: () => !env.poppedRec.contour }), sep: UC.newBlank({ class: "pop-sep" }), - expand: UC.newInput(LANG.cp_xpnd_s, { title: LANG.cp_xpnd_l, convert: UC.toFloat, units: true, xshow: () => !env.poppedRec.contour }), - refine: UC.newInput(LANG.cp_refi_s, { title: LANG.cp_refi_l, convert: UC.toInt, show: () => env.poppedRec.contour }), - smooth: UC.newInput(LANG.cp_smoo_s, { title: LANG.cp_smoo_l, convert: UC.toInt }), - tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: UC.toFloat, bound: UC.bound(0, 10.0), units: true, round: 4, show: () => env.poppedRec.contour }), - follow: UC.newInput(LANG.cp_foll_s, { title: LANG.cp_foll_l, convert: UC.toFloat }), + expand: UC.newInput(LANG.cp_xpnd_s, { title: LANG.cp_xpnd_l, convert: toFloat, units, xshow: () => !env.poppedRec.contour }), + refine: UC.newInput(LANG.cp_refi_s, { title: LANG.cp_refi_l, convert: toInt, show: () => env.poppedRec.contour }), + smooth: UC.newInput(LANG.cp_smoo_s, { title: LANG.cp_smoo_l, convert: toInt }), + tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: toFloat, bound: UC.bound(0, 10.0), units, round: 4, show: () => env.poppedRec.contour }), + follow: UC.newInput(LANG.cp_foll_s, { title: LANG.cp_foll_l, convert: toFloat }), sep: UC.newBlank({ class: "pop-sep" }), contour: UC.newBoolean(LANG.cp_cont_s, undefined, { title: LANG.cp_cont_s }), engrave: UC.newBoolean(LANG.cp_engr_s, undefined, { title: LANG.cp_engr_l, show: () => env.poppedRec.contour }), outline: UC.newBoolean(LANG.cp_outl_s, undefined, { title: LANG.cp_outl_l }), exp: UC.newExpand("overrides"), sep: UC.newBlank({ class: "pop-sep" }), - ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: UC.toFloat, units: true }), - ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: UC.toFloat, units: true }), + ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: toFloat, units }), + ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: toFloat, units }), ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, { title: LANG.ou_conv_l }), exp_end: UC.endExpand(), sep: UC.newBlank({ class: "pop-sep" }), @@ -491,16 +493,16 @@ export function createPopOps() { }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }), - down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }), - dwell: UC.newInput(LANG.cd_dwll_s, { title: LANG.cd_dwll_l, convert: UC.toFloat }), - lift: UC.newInput(LANG.cd_lift_s, { title: LANG.cd_lift_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), + dwell: UC.newInput(LANG.cd_dwll_s, { title: LANG.cd_dwll_l, convert: toFloat }), + lift: UC.newInput(LANG.cd_lift_s, { title: LANG.cd_lift_l, convert: toFloat, units, show: () => !env.poppedRec.mark }), mark: UC.newBoolean(LANG.cd_mark_s, undefined, { title: LANG.cd_mark_l, show: () => !env.poppedRec.fromTop }), fromTop: UC.newBoolean(LANG.cd_ftop_s, undefined, { title: LANG.cd_ftop_l, show: () => !env.poppedRec.mark }), sep: UC.newBlank({ class: "pop-sep" }), - thru: UC.newInput(LANG.cd_dtru_s, { title: LANG.cd_dtru_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }), - precision: UC.newInput(LANG.cd_prcn_s, { title: LANG.cd_prcn_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }), + thru: UC.newInput(LANG.cd_dtru_s, { title: LANG.cd_dtru_l, convert: toFloat, units, show: () => !env.poppedRec.mark }), + precision: UC.newInput(LANG.cd_prcn_s, { title: LANG.cd_prcn_l, convert: toFloat, units, show: () => !env.poppedRec.mark }), sep: UC.newBlank({ class: "pop-sep", }), actions: UC.newRow([ UC.newButton(LANG.select, () => selectHoles(true), { title: LANG.cd_seli_l }), @@ -523,16 +525,16 @@ export function createPopOps() { axis: UC.newSelect(LANG.cd_axis, {}, "regaxis"), points: UC.newSelect(LANG.cd_points, {show:() => env.poppedRec.axis !== '-'}, "regpoints"), sep: UC.newBlank({class:"pop-sep"}), - spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}), - rate: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toInt, units:true}), - feed: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true, show:() => env.poppedRec.axis === '-'}), + spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:toInt, show:hasSpindle}), + rate: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:toInt, units:true}), + feed: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:toInt, units:true, show:() => env.poppedRec.axis === '-'}), sep: UC.newBlank({class:"pop-sep"}), - down: UC.newInput(LANG.cc_sdwn_s, {title:LANG.cc_sdwn_l, convert:UC.toFloat, units:true}), - dwell: UC.newInput(LANG.cd_dwll_s, {title:LANG.cd_dwll_l, convert:UC.toFloat, show:() => env.poppedRec.axis !== '-'}), - lift: UC.newInput(LANG.cd_lift_s, {title:LANG.cd_lift_l, convert:UC.toFloat, units:true, show:() => env.poppedRec.axis !== '-'}), + down: UC.newInput(LANG.cc_sdwn_s, {title:LANG.cc_sdwn_l, convert:toFloat, units:true}), + dwell: UC.newInput(LANG.cd_dwll_s, {title:LANG.cd_dwll_l, convert:toFloat, show:() => env.poppedRec.axis !== '-'}), + lift: UC.newInput(LANG.cd_lift_s, {title:LANG.cd_lift_l, convert:toFloat, units:true, show:() => env.poppedRec.axis !== '-'}), sep: UC.newBlank({class:"pop-sep"}), - offset: UC.newInput(LANG.cd_rego_s, {title:LANG.cd_rego_l, convert:UC.toFloat, units:true, }), - thru: UC.newInput(LANG.cd_thru_s, {title:LANG.cd_thru_l, convert:UC.toFloat, units:true}), + offset: UC.newInput(LANG.cd_rego_s, {title:LANG.cd_rego_l, convert:toFloat, units:true, }), + thru: UC.newInput(LANG.cd_thru_s, {title:LANG.cd_thru_l, convert:toFloat, units:true}), }; createPopOp('helical', { @@ -556,15 +558,15 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), offset: UC.newSelect(LANG.cc_offs_s, {title: LANG.cc_offs_l,}, "helicaloff"), sep: UC.newBlank({class:"pop-sep"}), - spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}), - rate: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toFloat, units:true}), - feed: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toFloat, units:true}), - down: UC.newInput(LANG.ch_sdwn_s, {title:LANG.ch_sdwn_l, convert:UC.toFloat, units:true}), + spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:toInt, show:hasSpindle}), + rate: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:toFloat, units:true}), + feed: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:toFloat, units:true}), + down: UC.newInput(LANG.ch_sdwn_s, {title:LANG.ch_sdwn_l, convert:toFloat, units:true}), startAng: UC.newInput(LANG.ch_stra_s, {title:LANG.ch_stra_l, convert:UC.toDegsFloat, bound:UC.bound(-360,360),show:() => env.poppedRec.forceStartAng}), - offOver: UC.newInput(LANG.cc_offd_s, {title:LANG.cc_offd_l, convert:UC.toFloat, units:true, bound:UC.bound(0,Infinity)}), + offOver: UC.newInput(LANG.cc_offd_s, {title:LANG.cc_offd_l, convert:toFloat, units:true, bound:UC.bound(0,Infinity)}), sep: UC.newBlank({class:"pop-sep"}), entry: UC.newBoolean(LANG.ch_entr_s,undefined, {title:LANG.ch_entr_l}), - entryOffset: UC.newInput(LANG.ch_ento_s, {title:LANG.ch_ento_l, convert:UC.toFloat, units:true, show:() => env.poppedRec.entry}), + entryOffset: UC.newInput(LANG.ch_ento_s, {title:LANG.ch_ento_l, convert:toFloat, units:true, show:() => env.poppedRec.entry}), reverse: UC.newBoolean(LANG.ch_rvrs_s,undefined, {title:LANG.ch_rvrs_l}), clockwise:UC.newBoolean(LANG.ch_clkw_s,undefined, {title:LANG.ch_clkw_l}), sep: UC.newBlank({class:"pop-sep"}), @@ -572,7 +574,7 @@ export function createPopOps() { forceStartAng: UC.newBoolean(LANG.ch_fsta_s, undefined, {title:LANG.ch_fsta_l }), fromTop: UC.newBoolean(LANG.cd_ftop_s,undefined, {title:LANG.cd_ftop_l}), sep: UC.newBlank({class:"pop-sep"}), - thru: UC.newInput(LANG.cd_thru_s, {title:LANG.cd_thru_l, convert:UC.toFloat, units:true}), + thru: UC.newInput(LANG.cd_thru_s, {title:LANG.cd_thru_l, convert:toFloat, units:true}), actions: UC.newRow([ UC.newButton(LANG.select, selectHelical, {title:LANG.cd_seli_l}), ], {class:"ext-buttons f-col"}) @@ -603,7 +605,7 @@ export function createPopOps() { degrees: 'camIndexAxis', absolute: 'camIndexAbs' }).inputs = { - degrees: UC.newInput(LANG.ci_degr_s, { title: LANG.ci_degr_l, convert: UC.toFloat, bound: UC.bound(-360, 360.0) }), + degrees: UC.newInput(LANG.ci_degr_s, { title: LANG.ci_degr_l, convert: toFloat, bound: UC.bound(-360, 360.0) }), absolute: UC.newBoolean(LANG.ci_abso_s, undefined, { title: LANG.ci_abso_l }), select: UC.newRow([UC.newButton(LANG.ci_face_s, angleTowardZUp)], { class: "ext-buttons f-row" }) }; @@ -630,12 +632,12 @@ export function createPopOps() { on: UC.newRow([UC.newButton(LANG.on, editOn)], { class: "ext-buttons f-row" }), off: UC.newRow([UC.newButton(LANG.off, editOff)], { class: "ext-buttons f-row" }), sep: UC.newBlank({ class: "pop-sep" }), - power: UC.newInput(LANG.cl_powr_s, { title: LANG.cl_powr_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => !env.poppedRec.adapt }), - maxp: UC.newInput(LANG.cl_maxp_s, { title: LANG.cl_maxp_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }), - minp: UC.newInput(LANG.cl_minp_s, { title: LANG.cl_minp_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }), - maxz: UC.newInput(LANG.cl_maxz_s, { title: LANG.cl_maxz_l, convert: UC.toFloat, show: () => env.poppedRec.adapt }), - minz: UC.newInput(LANG.cl_minz_s, { title: LANG.cl_minz_l, convert: UC.toFloat, show: () => env.poppedRec.adapt }), - flatz: UC.newInput(LANG.cl_flaz_s, { title: LANG.cl_flaz_l, convert: UC.toFloat, show: () => env.poppedRec.flat }), + power: UC.newInput(LANG.cl_powr_s, { title: LANG.cl_powr_l, convert: toFloat, bound: UC.bound(0, 1.0), show: () => !env.poppedRec.adapt }), + maxp: UC.newInput(LANG.cl_maxp_s, { title: LANG.cl_maxp_l, convert: toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }), + minp: UC.newInput(LANG.cl_minp_s, { title: LANG.cl_minp_l, convert: toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }), + maxz: UC.newInput(LANG.cl_maxz_s, { title: LANG.cl_maxz_l, convert: toFloat, show: () => env.poppedRec.adapt }), + minz: UC.newInput(LANG.cl_minz_s, { title: LANG.cl_minz_l, convert: toFloat, show: () => env.poppedRec.adapt }), + flatz: UC.newInput(LANG.cl_flaz_s, { title: LANG.cl_flaz_l, convert: toFloat, show: () => env.poppedRec.flat }), sep: UC.newBlank({ class: "pop-sep" }), adapt: UC.newBoolean(LANG.cl_adap_s, undefined, { title: LANG.cl_adap_l }), adaptrp: UC.newBoolean(LANG.cl_adrp_s, undefined, { title: LANG.cl_adrp_l, show: () => env.poppedRec.adapt }), @@ -651,4 +653,75 @@ export function createPopOps() { }; createPopOp('|', {}).inputs = {}; + + function isClear() { + return env.poppedRec.mode === 'clear'; + } + + function isTrace() { + return env.poppedRec.mode === 'trace'; + } + + function isSurface() { + return env.poppedRec.mode === 'surface'; + } + + function isSurfaceLinear() { + return env.poppedRec.mode === 'surface' && env.poppedRec.sr_type === 'linear'; + } + + createPopOp('area', { + spindle: 'camAreaSpindle', + tool: 'camAreaTool', + mode: 'camAreaMode', + tr_type: 'camAreaTrace', + sr_type: 'camAreaSurface', + sr_angle: 'camAreaAngle', + over: 'camAreaOver', + down: 'camAreaDown', + rate: 'camAreaSpeed', + plunge: 'camAreaPlunge', + expand: 'camAreaExpand', + smooth: 'camAreaSmooth', + refine: 'camAreaRefine', + outline: 'camAreaOutline', + ov_topz: 0, + ov_botz: 0, + ov_conv: '~camConventional', + tolerance: 'camTolerance', + }).inputs = { + tool: UC.newSelect(LANG.cc_tool, {}, "tools"), + mode: UC.newSelect(LANG.mo_menu, {}, "opmode"), + tr_type: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: isTrace }, "traceoff"), + sr_type: UC.newSelect("pattern", { title: "pattern", show: isSurface }, "surftyp"), + sep: UC.newBlank({ class: "pop-sep" }), + menu: UC.newRow([ + UC.newButton("edge", traceAdd), + UC.newButton("surface", surfaceAdd), + ], { class: "ext-buttons f-row" }), + outline: UC.newBoolean(LANG.cp_outl_s, undefined, { title: LANG.cp_outl_l }), + expand: UC.newInput(LANG.cp_xpnd_s, { title: LANG.cp_xpnd_l, convert: toFloat, units }), + sep: UC.newBlank({ class: "pop-sep" }), + sr_angle: UC.newInput("step angle", { title: "step angle", convert: toFloat, bound: UC.bound(0, 360), show: isSurfaceLinear }), + over: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.001, 100.0), show: () => isClear() || isSurface() }), + down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, bound: UC.bound(0, 100.0), units, show: () => isClear() || isTrace() }), + sep: UC.newBlank({ class: "pop-sep", show: isSurface }), + refine: UC.newInput(LANG.cp_refi_s, { title: LANG.cp_refi_l, convert: toInt, show: isSurface }), + smooth: UC.newInput(LANG.cp_smoo_s, { title: LANG.cp_smoo_l, convert: toInt, show: isSurface }), + tolerance: UC.newInput(LANG.ou_toll_s, { title: LANG.ou_toll_l, convert: toFloat, bound: UC.bound(0, 10.0), units, round: 4, show: isSurface }), + sep: UC.newBlank({ class: "pop-sep" }), + exp: UC.newExpand("feeds & speeds"), + sep: UC.newBlank({ class: "pop-sep" }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + exp_end: UC.endExpand(), + exp: UC.newExpand("overrides"), + sep: UC.newBlank({ class: "pop-sep" }), + ov_topz: UC.newInput(LANG.ou_ztop_s, { title: LANG.ou_ztop_l, convert: toFloat, units }), + ov_botz: UC.newInput(LANG.ou_zbot_s, { title: LANG.ou_zbot_l, convert: toFloat, units }), + ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, { title: LANG.ou_conv_l }), + exp_end: UC.endExpand(), + }; + } diff --git a/src/kiri/mode/cam/cl-surface.js b/src/kiri/mode/cam/cl-surface.js index bdbbbcae..baf6a2cc 100644 --- a/src/kiri/mode/cam/cl-surface.js +++ b/src/kiri/mode/cam/cl-surface.js @@ -16,9 +16,10 @@ export function surfaceAdd(ev) { return surfaceDone(); } clearPops(); + let { surfaces, follow } = env.poppedRec; + let { edgeangle } = api.conf.get().controller; alert = api.show.alert("analyzing surfaces...", 1000); - let surfaces = env.poppedRec.surfaces; - let radians = env.poppedRec.follow * DEG2RAD; + let radians = (follow ?? edgeangle) * DEG2RAD; CAM.surface_prep(env.currentIndex * RAD2DEG, () => { api.hide.alert(alert); alert = api.show.alert("[esc] cancels surface selection"); diff --git a/src/kiri/mode/cam/cl-tab.js b/src/kiri/mode/cam/cl-tab.js index 0cda4f12..9abcd4af 100644 --- a/src/kiri/mode/cam/cl-tab.js +++ b/src/kiri/mode/cam/cl-tab.js @@ -87,6 +87,12 @@ export function addWidgetTab(widget, rec) { } } +export function recreateTabs() { + let widgets = api.widgets.all(); + for (let w of widgets) clearTabs(w, true); + restoreTabs(widgets); +} + export function restoreTabs(widgets) { widgets.forEach(widget => { const tabs = api.widgets.annotate(widget.id).tab || []; diff --git a/src/kiri/mode/cam/client.js b/src/kiri/mode/cam/client.js index 65eba6db..245210b3 100644 --- a/src/kiri/mode/cam/client.js +++ b/src/kiri/mode/cam/client.js @@ -16,6 +16,11 @@ import { holeSelOn, selectHolesDone, clearHolesRec } from './cl-hole.js'; import { surfaceOn, surfaceDone } from './cl-surface.js'; import { helicalOn, helicalDone } from './cl-helical.js'; import { originSelectDone } from './cl-origin.js'; +import { Widget, newWidget } from '../../core/widget.js'; +import { space } from '../../../moto/space.js'; +import { recreateTabs } from './cl-tab.js'; + +const { BufferGeometryUtils } = THREE; const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; @@ -184,6 +189,15 @@ const opAddHelical = () => { opAdd(rec); }; +const opAddArea = () => { + traceDone(); + surfaceDone(); + let rec = env.popOp.area.new(); + rec.areas = { /* widget.id: [ polygons... ] */ }; + rec.surfaces = { /* widget.id: [ faces... ] */ }; + opAdd(rec); +}; + const opAddContour = (axis) => { let rec = env.popOp.contour.new(); rec.axis = axis.toUpperCase(); @@ -273,7 +287,7 @@ export function opRender() { oplist.forEach((rec, i) => { let title = ''; let clock = rec.type === '|'; - let label = clock ? `` : rec.type; + let label = clock ? `` : rec.mode ?? rec.type; let clazz = notime ? ["draggable", "notime"] : ["draggable"]; let notable = rec.note ? rec.note.split(' ').filter(v => v.charAt(0) === '#') : undefined; if (clock) { clazz.push('clock'); title = ` title="end of ops chain\ndrag/drop like an op\nops after this are disabled"` } @@ -512,6 +526,10 @@ export function opRender() { export function init() { + if (api.devel.enabled) { + $('op:area').classList.remove('hide'); + } + api.event.on('tool.mesh.face-normal', normal => { // console.log({ env.poppedRec }); env.poppedRec.degrees = (Math.atan2(normal.y, normal.z) * RAD2DEG).round(2); @@ -606,6 +624,20 @@ export function init() { updateStock(); opRender(); api.uc.setVisible($('layer-animate'), env.isAnimate && env.isCamMode); + + if (!env.isCamMode) { + return; + } + + // remove tab synth + api.widgets.filter((widget) => { + if (widget.track.synth) { + space.world.remove(widget.mesh); + Widget.Groups.remove(widget); + } + return !widget.track.synth + }); + }); api.event.on("settings.saved", (settings) => { @@ -745,6 +777,7 @@ export function init() { case "trace": return opAddTrace(); case "pocket": return opAddPocket(); case "helical": return opAddHelical(); + case "area": return opAddArea(); case "flip": // only one flip op permitted for (let op of env.current.process.ops) { @@ -786,8 +819,27 @@ export function init() { // COMMON TAB/TRACE EVENT HANDLERS api.event.on("slice.begin", () => { - if (env.isCamMode) { - clearPops(); + if (!env.isCamMode) { + return; + } + clearPops(); + recreateTabs(); + for (let group of Widget.Groups.list()) { + let root = group[0]; + if (root.tabs) + for (let tab of Object.values(root.tabs)) { + let geo = tab.box.geometry.clone(); + if (geo.index) geo = geo.toNonIndexed(); + geo.translate(tab.x, tab.y, tab.z); + let bbg = BufferGeometryUtils.mergeGeometries([ geo ]); + let sw = newWidget(null, group); + let fwp = group[0].track.pos; + sw.loadGeometry(bbg); + sw._move(fwp.x, fwp.y, fwp.z); + api.widgets.add(sw); + sw.track.synth = true; + sw.track.indexed = root.track.indexed; + } } }); 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-area.js b/src/kiri/mode/cam/op-area.js new file mode 100644 index 00000000..7ead88f1 --- /dev/null +++ b/src/kiri/mode/cam/op-area.js @@ -0,0 +1,398 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +import { CamOp } from './op.js'; +import { Tool } from './tool.js'; +import { newSlice } from '../../core/slice.js'; +import { newPoint } from '../../../geo/point.js'; +import { newPolygon } from '../../../geo/polygon.js'; +import { polygons as POLY } from '../../../geo/polygons.js'; +import { util as base_util } from '../../../geo/base.js'; +import { CAM } from './driver-be.js'; + +const DEG2RAD = Math.PI / 180; +const clib = self.ClipperLib; +const ctyp = clib.ClipType; +const ptyp = clib.PolyType; +const cfil = clib.PolyFillType; + +class OpArea extends CamOp { + constructor(state, op) { + super(state, op); + } + + async slice(progress) { + let { op, state } = this; + let { tool, mode, down, over, follow, expand, outline, refine, smooth } = op; + let { ov_topz, ov_botz, ov_conv } = op; + let { settings, widget, tabs, color } = state; + let { addSlices, setToolDiam, cutTabs, healPolys, shadowAt, workarea } = state; + + let areaTool = new Tool(settings, tool); + let toolDiam = areaTool.fluteDiameter(); + let toolOver = areaTool.hasTaper() ? over : toolDiam * over; + let zTop = ov_topz ? workarea.bottom_stock + ov_topz : workarea.top_stock; + let zBottom = ov_botz ? workarea.bottom_stock + ov_botz : workarea.bottom_part; + + // also updates tab offsets + setToolDiam(toolDiam); + + // selected area polygons: surfaces and edges + let { devel, edgeangle } = settings.controller; + let stack = []; + let surfaces = this.surfaces = []; + let areas = this.areas = [ stack ]; + let polys = []; + + function newArea() { + if (stack.length) { + stack = []; + areas.push(stack); + } + } + + function newLayer() { + stack.push(newSlice()); + return stack.peek(); + } + + // gather area selections + for (let arr of (op.areas[widget.id] ?? [])) { + polys.push(newPolygon().fromArray(arr)); + } + + // connect open poly edge segments into closed loops (when possible) + // surface and edge selections produce open polygons by default + polys = POLY.nest(healPolys(polys)); + + // gather surface selections + let vert = widget.getGeoVertices({ unroll: true, translate: true }).map(v => v.round(4)); + let faces = CAM.surface_find(widget, (op.surfaces[widget.id] ?? []), (follow ?? edgeangle ?? 5) * DEG2RAD); + let fpoly = []; + let fminz = Infinity; + for (let face of faces) { + let i = face * 9; + fpoly.push(newPolygon() + .add(vert[i++], vert[i++], fminz = Math.min(fminz, vert[i++])) + .add(vert[i++], vert[i++], fminz = Math.min(fminz, vert[i++])) + .add(vert[i++], vert[i++], fminz = Math.min(fminz, vert[i++])) + ); + } + // remove invalid edges (eg. when vertical walls are the only selection) + fpoly = fpoly.filter(p => p.area() > 0.001); + + // add in unioned surface areas + polys.push(...POLY.setZ(POLY.union(fpoly, 0.00001, true), fminz)); + + // todo: implement `refine` and `smooth` + + // expand selections (flattens z variable polys) + if (Math.abs(expand) > 0) { + let nupolys = polys.filter(p => p.open); // set aside open + for (let p of polys.filter(p => !p.open)) { + let expanded = POLY.expand([ p ], expand); + if (expanded) { + POLY.setZ(expanded, p.minZ()); + nupolys.push(...expanded.flat()); + } + } + polys = nupolys; + } + + // process each area separately + let proc = 0; + let pinc = 1 / polys.length; + for (let area of polys) { + let bounds = area.getBounds3D(); + + if (devel) newLayer().output() + .setLayer("area", { line: 0xff8800 }, false) + .addPolys([ area ]); + + newArea(); + + if (outline) { + // remove inner voids when processing outline only + area.inner = undefined; + } + + if (mode === 'clear') { + let zs = down ? base_util.lerp(zTop, zBottom, down) : [ bounds.min.z ]; + let zroc = 0; + let zinc = 1 / zs.length; + let lzo; + outer: for (;;) + for (let z of zs) { + let slice = newLayer(); + let layers = slice.output(); + let outs = []; + let clip = []; + let shadow = shadowAt(z); + POLY.subtract([ area ], shadow, clip, undefined, undefined, 0); + POLY.offset(clip, [ -toolDiam / 2, -toolOver ], { + count: 999, outs, flat: true, z, minArea: 0 + }); + if (outs.length === 0) { + if (bounds && lzo > bounds.min.z) { + // try a bottom layer matching bottom of selection + zs = [ bounds.min.z ]; + bounds = undefined; + continue outer; + } + // terminate z descent when no further output possible + break outer; + } + // cut tabs when present + if (tabs) outs = cutTabs(tabs, outs); + slice.camLines = outs; + zroc += zinc; + lzo = z; + progress(proc + (pinc * zroc), 'clear'); + if (devel) layers + .setLayer("shadow", { line: 0x0088ff }, false) + .addPolys(shadow); + layers + .setLayer("clear", { line: 0x88ff00 }, false) + .addPolys(outs); + // of the last output still cuts, we need an escape + if (z === zs.peek()) { + break outer; + } + } + proc += pinc; + progress(proc, 'clear'); + } else + if (mode === 'trace') { + let { tr_type } = op; + let zs = down ? base_util.lerp(zTop, bounds.min.z, down) : [ bounds.min.z ]; + let zroc = 0; + let zinc = 1 / zs.length; + let lzo; + for (let z of zs) { + let slice = newLayer(); + let layers = slice.output(); + let outs = []; + if (tr_type === 'none') { + area = area.clone(true); + outs = [ zs.length > 1 ? area.setZ(z) : area ]; + } else { + POLY.offset([ area ], tr_type === 'inside' ? [ -toolDiam / 2 ] : [ toolDiam / 2 ], { + count: 1, outs, flat: true, z, minArea: 0 + }); + } + if (outs.length === 0) { + // terminate z descent when no further output possible + break; + } + // cut tabs when present + if (tabs) outs = cutTabs(tabs, outs); + slice.camLines = outs; + zroc += zinc; + lzo = z; + progress(proc + (pinc * zroc), 'trace'); + layers + .setLayer("trace", { line: 0x88ff00 }, false) + .addPolys(outs); + } + proc += pinc; + progress(proc, 'trace'); + } else + if (mode === 'surface') { + let { sr_type, sr_angle, tolerance } = op; + + let resolution = tolerance || 0.05; + let raster = await self.get_raster_gpu({ mode: "tracing", resolution }); + let surface = []; + let paths = []; + + // prepare paths + if (sr_type === 'linear') { + // scan the area bounding box with rays at defined angle + let scan = scanBoxAtAngle(bounds, sr_angle * DEG2RAD, toolOver); + let lines = scan.map(line => { + let { a, b } = line; + return [ newPoint(a.x, a.y, 0).toClipper(), newPoint(b.x, b.y, 0).toClipper() ] + }); + // use clipper to clip lines to the area polygon + let clip = new clib.Clipper(); + let ctre = new clib.PolyTree(); + clip.AddPaths(lines, ptyp.ptSubject, false); + clip.AddPaths(POLY.toClipper([ area ]), ptyp.ptClip, true); + if (clip.Execute(ctyp.ctIntersection, ctre, cfil.pftNonZero, cfil.pftEvenOdd)) { + for (let node of ctre.m_AllPolys) { + paths.push(POLY.fromClipperNode(node, 0)); + } + } + // convert resulting poly lines to raster float32 array groups + paths = paths.map(poly => poly.points.map(p => [ p.x, p.y ]).flat().toFloat32()); + } else + if (sr_type === 'offset') { + // todo: progressive inset from perimeter + console.log({ sr_offset: toolOver }); + } + + // prepare tool mesh points + let toolBounds = new THREE.Box3() + .expandByPoint({ x: -toolDiam/2, y: -toolDiam/2, z: 0 }) + .expandByPoint({ x: toolDiam/2, y: toolDiam/2, z: 0 }); + let toolPos = areaTool.generateProfile(resolution).profile.slice(); + for (let i=0; i { return { + el: poly, + first: poly.first(), + last: poly.last() + } }); + tip2tipEmit(array, printPoint, (next, first, count) => { + printPoint = polyEmit(next.el, 0, 1, printPoint, {}); + newLayer(); + }); + } + + // skip areas when processing surfaces + if (surfaces.length) { + return; + } + + // process areas as pockets + while (areas?.length) { + let min = { + dist: Infinity, + area: undefined + }; + for (let area of areas.filter(p => !p.used)) { + // skip devel / debug only areas + let topPolys = area[0].camLines; + if (!topPolys) continue; + // select poly with largest area + let poly = topPolys.slice().sort((a,b) => b.area() - a.area())[0]; + if (!poly) continue; + // compute move distance to top poly for efficient routing + let find = poly.findClosestPointTo(printPoint); + if (find.distance < min.dist) { + min.area = area; + min.dist = find.distance; + } + } + // if we have a next-closest top poly, pocket that + if (min.area) { + min.area.used = true; + pocket({ + cutdir: op.ov_conv, + depthFirst: process.camDepthFirst, + easeDown: op.down && process.easeDown ? op.down : 0, + progress: (n,m) => progress(n/m, "area"), + slices: min.area.filter(slice => slice.camLines) + }); + } else { + break; + } + } + } +} + +// box2: THREE.Box2 +// angle: radians (direction of each scan ray) +// step: spacing between parallel rays (world units) +function scanBoxAtAngle(box2, angle, step) { + const cx = (box2.min.x + box2.max.x) * 0.5; + const cy = (box2.min.y + box2.max.y) * 0.5; + const w = box2.max.x - box2.min.x; + const h = box2.max.y - box2.min.y; + + // ray direction + const dx = Math.cos(angle); + const dy = Math.sin(angle); + + // normal between rays (perpendicular to ray dir) + const nx = -dy; + const ny = dx; + + // extent of the box along the normal + const extentN = Math.abs(nx) * w + Math.abs(ny) * h; + + // length of each ray across the box (along ray dir) + const extentD = Math.abs(dx) * w + Math.abs(dy) * h; + + // how many rays to cover the box; +1 so edges are covered + const count = Math.max(1, Math.ceil(extentN / step) + 1); + + const halfSpan = step * (count - 1) * 0.5; + const halfD = extentD * 0.5; + const rays = []; + + for (let i = 0; i < count; i++) { + // offset along normal + const o = -halfSpan + i * step; + const ox = cx + nx * o; + const oy = cy + ny * o; + + // segment endpoints for this ray inside (or slightly outside) the box + const ax = ox - dx * halfD; + const ay = oy - dy * halfD; + const bx = ox + dx * halfD; + const by = oy + dy * halfD; + + rays.push({ + a: new THREE.Vector2(ax, ay), + b: new THREE.Vector2(bx, by), + }); + } + + return rays; +} + +export { OpArea }; 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/op-index.js b/src/kiri/mode/cam/op-index.js index 1b1fd92a..c9fd55fa 100644 --- a/src/kiri/mode/cam/op-index.js +++ b/src/kiri/mode/cam/op-index.js @@ -17,7 +17,7 @@ export class OpIndex extends CamOp { throw 'index op requires indexed stock'; } let { widget, updateSlicer, computeShadows, setAxisIndex } = state; - this.degrees = setAxisIndex(op.degrees, op.absolute); + this.degrees = await setAxisIndex(op.degrees, op.absolute); // force recompute of topo widget.topo = undefined; updateSlicer(); diff --git a/src/kiri/mode/cam/ops.js b/src/kiri/mode/cam/ops.js index 003a7dcc..79e4c7f0 100644 --- a/src/kiri/mode/cam/ops.js +++ b/src/kiri/mode/cam/ops.js @@ -1,39 +1,41 @@ /** Copyright Stewart Allen -- All Rights Reserved */ -import { OpXRay } from './op-xray.js'; -import { OpShadow } from './op-shadow.js'; -import { OpLevel } from './op-level.js'; -import { OpRough } from './op-rough.js'; -import { OpOutline } from './op-outline.js'; -import { OpContour } from './op-contour.js'; -import { OpPocket } from './op-pocket.js'; -import { OpLathe } from './op-lathe.js'; -import { OpTrace } from './op-trace.js'; -import { OpDrill } from './op-drill.js'; -import { OpRegister } from './op-register.js'; -import { OpLaserOn } from './op-laser-on.js'; -import { OpLaserOff } from './op-laser-off.js'; -import { OpGCode } from './op-gcode.js'; -import { OpIndex } from './op-index.js'; import { CamOp } from './op.js'; +import { OpArea } from './op-area.js'; +import { OpContour } from './op-contour.js'; +import { OpDrill } from './op-drill.js'; +import { OpGCode } from './op-gcode.js'; import { OpHelical } from './op-helical.js'; +import { OpIndex } from './op-index.js'; +import { OpLaserOff } from './op-laser-off.js'; +import { OpLaserOn } from './op-laser-on.js'; +import { OpLathe } from './op-lathe.js'; +import { OpLevel } from './op-level.js'; +import { OpOutline } from './op-outline.js'; +import { OpPocket } from './op-pocket.js'; +import { OpRegister } from './op-register.js'; +import { OpRough } from './op-rough.js'; +import { OpShadow } from './op-shadow.js'; +import { OpTrace } from './op-trace.js'; +import { OpXRay } from './op-xray.js'; export const ops = { - "xray": OpXRay, - "shadow": OpShadow, - "level": OpLevel, - "rough": OpRough, - "outline": OpOutline, + "area": OpArea, "contour": OpContour, - "pocket": OpPocket, - "lathe": OpLathe, - "trace": OpTrace, "drill": OpDrill, - "register": OpRegister, - "helical": OpHelical, - "laser on": OpLaserOn, - "laser off": OpLaserOff, + "flip": CamOp, "gcode": OpGCode, + "helical": OpHelical, "index": OpIndex, - "flip": CamOp + "laser off": OpLaserOff, + "laser on": OpLaserOn, + "lathe": OpLathe, + "level": OpLevel, + "outline": OpOutline, + "pocket": OpPocket, + "register": OpRegister, + "rough": OpRough, + "shadow": OpShadow, + "trace": OpTrace, + "xray": OpXRay }; diff --git a/src/kiri/mode/cam/prepare.js b/src/kiri/mode/cam/prepare.js index 1bc4c4b7..079cc378 100644 --- a/src/kiri/mode/cam/prepare.js +++ b/src/kiri/mode/cam/prepare.js @@ -26,7 +26,7 @@ export async function cam_prepare(widall, settings, update) { print.output = []; let point; - widgets.forEach((widget, index) => { + widgets.filter(w => !w.isSynth()).forEach((widget, index) => { point = prepEach(widget, settings, print, point, (progress, msg) => { update((index * weight + progress * weight) * 0.75, msg || "prepare"); }); @@ -337,7 +337,7 @@ export function prepEach(widget, settings, print, firstPoint, update) { // 1. move to safe z of current point preserving angle // 2. move to safe z of new point preserving old angle // 3. move to safe z of new point with new angle - if (lop && lop !== currentOp && lastPoint) { + if (lop !== currentOp && lastPoint) { // compensate for applyWidgetMovement() applied to lastPoint let lpo = lastPoint.clone().move({ x: -wmx, y: -wmy, z: -zadd }); camOut(lpo.clone().setZ(zsafe).setA(lastPoint.a), 0); diff --git a/src/kiri/mode/cam/slice.js b/src/kiri/mode/cam/slice.js index ed3a541c..06174696 100644 --- a/src/kiri/mode/cam/slice.js +++ b/src/kiri/mode/cam/slice.js @@ -20,6 +20,10 @@ import { CAM } from './driver-be.js'; * @param {Function} output */ export async function cam_slice(settings, widget, onupdate, ondone) { + if (widget.track.synth) return ondone(); + + let tabW = widget.group.filter(w => w != widget); + let proc = settings.process, sliceAll = widget.slices = [], camOps = widget.camops = [], @@ -87,7 +91,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); }; @@ -95,26 +99,6 @@ export async function cam_slice(settings, widget, onupdate, ondone) { // initial setup var_compute(); - if (tabs) { - // make tab polygons - tabs.forEach(tab => { - let zero = newPoint(0, 0, 0), - point = newPoint(tab.pos.x, tab.pos.y, tab.pos.z), - poly = newPolygon().centerRectangle(zero, tab.dim.x, tab.dim.y), - [rx, ry, rz, rw] = tab.rot, - m4 = new THREE.Matrix4().makeRotationFromQuaternion( - new THREE.Quaternion(rx, ry, rz, rw) - ); - poly.points = poly.points - .map(p => new THREE.Vector3(p.x, p.y, p.z).applyMatrix4(m4)) - .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); - }); - } - function error(msg) { ondone(msg); } @@ -155,7 +139,6 @@ export async function cam_slice(settings, widget, onupdate, ondone) { alert(`invalid z bottom ${(zMin / units).round(3)} >= bounds z max ${(zMax / units).round(3)}`); } - let mark = Date.now(); let opList = []; let opSum = 0; let opTot = 0; @@ -174,6 +157,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) { isIndexed, ops: opList, setAxisIndex, + setToolDiam, settings, shadowAt, slicer, @@ -190,6 +174,30 @@ export async function cam_slice(settings, widget, onupdate, ondone) { }; let tracker = setSliceTracker({ rotation: 0 }); + async function updateTab(tab) { + tab.setAxisIndex(isIndexed ? -axisIndex : 0) + let ts = new cam_slicer(tab); + let si = Object.keys(ts.zList).map(k => parseFloat(k)); + si = [ ...si.map(v => v-0.01), ...si.map(v => v+0.01) ]; + let zt = Math.max(...si); + let zb = Math.min(...si); + let shadow; + await ts.slice(si, { each: data => { + if (shadow) { + shadow = POLY.union([...shadow, ...data.polys]); + } else { + shadow = data.polys; + } + }}); + return { + top: zt, + poly: shadow[0], + pos: { z: (zt+zb)/2 }, + dim: { z: (zt-zb) }, + NEW: true + } + } + function updateSlicer() { slicer = state.slicer = new cam_slicer(widget); } @@ -201,6 +209,15 @@ export async function cam_slice(settings, widget, onupdate, ondone) { }); } + function setToolDiam(toolDiam) { + updateToolDiams(toolDiam); + if (tabs) { + tabs.forEach(tab => { + tab.off = POLY.expand([ tab.poly ], toolDiam / 2).flat(); + }); + } + } + function updateToolDiams(toolDiam) { minToolDiam = Math.min(minToolDiam, toolDiam); maxToolDiam = Math.max(maxToolDiam, toolDiam); @@ -212,30 +229,23 @@ export async function cam_slice(settings, widget, onupdate, ondone) { return cached; } // find closest shadow above and use to speed up delta shadow gen - let minZabove; let zover = Object.keys(shadows).map(v => parseFloat(v)).filter(v => v > z); - for (let zkey of zover) { - if (minZabove && zkey < minZabove) { - minZabove = zkey; - } else { - minZabove = zkey; - } - } + let minZabove = Math.min(Infinity, ...zover); let shadow = computeShadowAt(widget, z, minZabove); - if (minZabove) { - // const merge = shadow.length; - // const plus = shadows[minZabove].length; - // const mark = Date.now(); + if (minZabove < Infinity) { shadow = POLY.union([...shadow, ...shadows[minZabove]], 0.001, true); - // console.log({merge, plus, equals: shadow.length, time: Date.now() - mark}); } return shadows[z] = POLY.setZ(shadow, z); } - function setAxisIndex(degrees = 0, absolute = true) { + async function setAxisIndex(degrees = 0, absolute = true) { axisIndex = absolute ? degrees : (axisIndex || 0) + degrees; axisRotation = (Math.PI / 180) * axisIndex; widget.setAxisIndex(isIndexed ? -axisIndex : 0); + state.tabs = tabs = []; + for (let tab of tabW) { + tabs.push(await updateTab(tab)); + } return isIndexed ? -axisIndex : 0; } @@ -300,7 +310,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) { } // call slice() function on all ops in order - setAxisIndex(); + await setAxisIndex(); updateSlicer(); for (let op of opList) { let weight = op.weight(); @@ -326,12 +336,6 @@ export async function cam_slice(settings, widget, onupdate, ondone) { zTop, workarea: workover }); - // console.log({ - // op, - // workover, - // bounds: structuredClone(bounds), - // stock: structuredClone(stock) - // }); await op.slice((progress, message) => { onupdate((opSum + (progress * weight)) / opTot, message || op.type()); }); @@ -595,7 +599,7 @@ export function cylinder_poly_find(widget, face) { let zmid = (zmin + zmax) / 2; let cylVerts = new Float32Array(faces.length * 9); let opts = { - dedup: false, + dedup: true, edges: false, over: true }; @@ -648,7 +652,7 @@ export function cylinder_poly_find(widget, face) { */ export async function holes(settings, widget, individual, rec, onProgress) { - let { tool, mark, precision } = rec //TODO: display some visual difference if mark is selected + let { tool, precision } = rec //TODO: display some visual difference if mark is selected let toolDiam = new Tool(settings, tool).fluteDiameter() let diam = individual ? 1 : toolDiam; // sets default diameter when select individual used diff --git a/src/kiri/mode/cam/topo3.js b/src/kiri/mode/cam/topo3.js index e42f31ef..28fd488b 100644 --- a/src/kiri/mode/cam/topo3.js +++ b/src/kiri/mode/cam/topo3.js @@ -222,7 +222,7 @@ export class Topo { if (poly.length > 1) { lines.push(poly); } - // raize output points when inside tab boundaries + // raise output points when inside tab boundaries if (!inside && tabsOn && clipTab.length) for (let poly of lines) { for (let p of poly.points) { diff --git a/web/kiri/index.css b/web/kiri/index.css index bf495bae..390e24ea 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -2024,6 +2024,18 @@ details[open] summary::after { width: 100%; /* background-color: #f8f8f8; */ } +#device-action { + align-items: center; +} +#device-action a { + right: 0; + position: absolute; + border-bottom: 1px dotted; +} +#device-action a:hover { + color: #888; + border-bottom: 1px transparent; +} #device-action button, #tool-action button { flex-direction: column; justify-content: center; diff --git a/web/kiri/index.html b/web/kiri/index.html index 7ba7dfc2..6d45ea5e 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -461,6 +461,7 @@
contour
pocket
helical
+
area
@@ -545,6 +546,7 @@
+ gcode macro docs diff --git a/web/kiri/style-alt.css b/web/kiri/style-alt.css deleted file mode 100644 index 24c7da31..00000000 --- a/web/kiri/style-alt.css +++ /dev/null @@ -1,114 +0,0 @@ -/** atom3dp css */ - -button { - color: #000; - border: 1px solid rgba(20,20,20,0.5); - background-color: rgba(210,210,210,0.8); - padding: 2px 7px 3px 7px; - margin-bottom: 2px !important; -} -button:hover { - border-color: #000; - background-color: #fff; -} -label { - border-bottom: 1px solid rgba(220,220,225,1); -} -.dialog { - background-color: rgba(220,220,220,0.75); - border-color: #bbb; - color: #000; -} - -#device-cols > div { - background-color: rgba(250,250,250,0.75); -} -#device-list select { - color: #000; -} -#device-list option[local="1"] { - color: #00f; -} -#device-labels span { - background-color: rgba(170,221,255,0.75); - border: 1px dashed #aaa; - color: black; -} - -#tool-cols > div { - background-color: rgba(250,250,250,0.75); -} -#tool-list select { - color: #000; -} -#tool-list option[local="1"] { - color: #00f; -} -#tool-labels span { - background-color: rgba(170,221,255,0.75); - border: 1px dashed #aaa; - color: black; -} - -#catalog span { - margin-left: 0; - margin-right: 0; - background-color: rgba(170,221,255,0.75); - border: 1px dashed #aaa; - color: black; -} -#catalog button { - background-color: rgba(250,250,250,0.8); -} -#catalog button:hover { - background-color: rgba(200,200,200,0.8); -} - -#settings span { - margin-left: 0; - margin-right: 0; - background-color: rgba(170,221,255,0.75); - border: 1px dashed #aaa; - color: black; -} -#settings button { - background-color: rgba(250,250,250,0.8); -} -#settings button:hover { - background-color: rgba(200,200,200,0.8); -} - -.grouphead { - color: black; - border-top-left-radius: 3px; - border-top-right-radius: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 0; - border: 1px dashed #aaa; - margin-top: 5px; - margin-bottom: 3px; - padding: 3px 2px 2px 3px; - background-color: rgba(170,221,255,0.75); - font-weight: bold; - font-size: 12px; -} -#control-left { - border-top: 0; - border-bottom: 0; - background-color: rgba(220,220,225,0.25); -} -#control-right { - color: #000; - border-top: 0; - border-bottom: 0; - background-color: rgba(220,220,225,0.25); -} -#appid span { - x-background-color: rgba(220,220,225,0.5) !important; -} -#selection span { - background-color: rgba(220,220,225,0.5) !important; -} -#layer-view span { - background-color: rgba(220,220,225,0.5) !important; -} diff --git a/web/kiri/style-atom3dp.css b/web/kiri/style-atom3dp.css deleted file mode 100644 index bce791fc..00000000 --- a/web/kiri/style-atom3dp.css +++ /dev/null @@ -1,32 +0,0 @@ -/** atom3dp css */ - -button { - color: #000; - border: 1px solid rgba(20,20,20,0.5); -} -label { - border-bottom: 1px solid rgba(200,200,0,0.75); -} -.grouphead { - color: white; - background-color: rgba(0,0,0,0.85); -} -#control-left { - background-color: rgba(240,240,20,0.5); -} -#control-right { - color: #000; - background-color: rgba(240,240,20,0.5); -} -#appid span { - background-color: rgba(240,240,20,0.5) !important; -} -#selection span { - background-color: rgba(240,240,20,0.5) !important; -} -#layer-view span { - background-color: rgba(240,240,20,0.5) !important; -} -#modeCAM { - display: none !important; -}