Merge branch 'rel-4.5' of https://github.com/GridSpace/grid-apps into drill-optimization
This commit is contained in:
commit
ce8cbc2c5c
27 changed files with 1190 additions and 581 deletions
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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('=');
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -332,6 +332,10 @@ class Widget {
|
|||
moto.space.refresh();
|
||||
}
|
||||
|
||||
isSynth() {
|
||||
return this.track.synth ?? false;
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
return this.getMaterial().visible;
|
||||
}
|
||||
|
|
|
|||
166
src/kiri/dev/fdm/Creality.Ender.7
Normal file
166
src/kiri/dev/fdm/Creality.Ender.7
Normal file
|
|
@ -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": {}
|
||||
}
|
||||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 || [];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
398
src/kiri/mode/cam/op-area.js
Normal file
398
src/kiri/mode/cam/op-area.js
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- 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<toolPos.length; i+= 3) {
|
||||
toolBounds.expandByPoint({ x: toolPos[i], y: toolPos[i+1], z: toolPos[i+2] });
|
||||
}
|
||||
let toolData = { positions: toolPos, bounds: toolBounds };
|
||||
|
||||
// prepare terrain and raster paths over terrain
|
||||
let vertices = widget.getGeoVertices({ unroll: true, translate: true });
|
||||
let wbounds = bounds.clone().expandByVector({ x: toolDiam/2, y: toolDiam/2, z: 0 });
|
||||
wbounds.min.z = zBottom;
|
||||
wbounds.max.z = zTop;
|
||||
await raster.loadTool({
|
||||
sparseData: toolData
|
||||
});
|
||||
await raster.loadTerrain({
|
||||
triangles: vertices,
|
||||
boundsOverride: wbounds
|
||||
});
|
||||
let output = await raster.generateToolpaths({
|
||||
paths,
|
||||
step: toolOver / 2,
|
||||
zFloor: zBottom - 1,
|
||||
onProgress(pct) { console.log({ pct }); onupdate(pct/100, 100) }
|
||||
});
|
||||
raster.terminate();
|
||||
|
||||
// todo: port clever bits from topo3 for inside/outside detection and tab clipping
|
||||
|
||||
// convert terrain raster output back to open polylines
|
||||
for (let path of output.paths) {
|
||||
path = newPolygon().fromArray([1, ...path]);
|
||||
surface.push(path);
|
||||
newLayer().output()
|
||||
.setLayer("linear", { line: 0x00ff00 }, false)
|
||||
.addPolys([ path ]);
|
||||
}
|
||||
|
||||
// output this surface
|
||||
surfaces.push(surface);
|
||||
}
|
||||
}
|
||||
|
||||
addSlices(areas.flat());
|
||||
}
|
||||
|
||||
prepare(ops, progress) {
|
||||
let { op, state, areas, surfaces } = this;
|
||||
let { getPrintPoint, newLayer, pocket, polyEmit, setTool, setSpindle, tip2tipEmit } = ops;
|
||||
let { process } = state.settings;
|
||||
|
||||
setTool(op.tool, op.rate);
|
||||
setSpindle(op.spindle);
|
||||
|
||||
let printPoint = getPrintPoint();
|
||||
|
||||
// process surface paths
|
||||
for (let surface of surfaces) {
|
||||
let array = surface.map(poly => { 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 };
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1,39 +1,41 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- 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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@
|
|||
<div title="2.5D tracing along X or Y axis used for complex part features">contour</div>
|
||||
<div title="clear areas above selected surfaces">pocket</div>
|
||||
<div title="follow a helix around circular paths">helical</div>
|
||||
<div title="perform configurable operations on selected areas" id="op:area" class="hide">area</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -545,6 +546,7 @@
|
|||
<div class="grow"></div>
|
||||
<button id="device-save" lk="save">save</button>
|
||||
<div class="grow"></div>
|
||||
<a href="https://docs.grid.space/kiri-moto/gcode-macros" target="docs">gcode macro docs</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue