diff --git a/src/components/operation-diagram.js b/src/components/operation-diagram.js index 0593f1cd..21f2d2b7 100644 --- a/src/components/operation-diagram.js +++ b/src/components/operation-diagram.js @@ -45,6 +45,7 @@ const hide = [ const types = { 'Laser Cut': { show: ['LaserCut'] }, + 'Laser Cut (unoptimized)': { show: ['LaserCut'] }, 'Laser Cut Inside': { show: ['LaserCutInside', 'laserDia'] }, 'Laser Cut Outside': { show: ['LaserCutOutside', 'laserDia'] }, 'Laser Fill Path': { show: ['LaserFill', 'lineSpace'] }, diff --git a/src/components/operation.js b/src/components/operation.js index 6c504236..f0a97ddf 100644 --- a/src/components/operation.js +++ b/src/components/operation.js @@ -581,6 +581,7 @@ const tabFields = [ export const OPERATION_TYPES = { 'Laser Cut': { allowTabs: true, tabFields: false, fields: ['name', 'filterFillColor', 'filterStrokeColor', 'laserPower', 'passes', 'passDepth', 'startHeight', 'cutRate', 'useA', 'aAxisDiameter', 'useBlower', 'segmentLength', ...OPERATION_GROUPS.Macros.fields] }, + 'Laser Cut (unoptimized)': { allowTabs: true, tabFields: false, fields: ['name', 'filterFillColor', 'filterStrokeColor', 'laserPower', 'passes', 'passDepth', 'startHeight', 'cutRate', 'useA', 'aAxisDiameter', 'useBlower', 'segmentLength', ...OPERATION_GROUPS.Macros.fields] }, 'Laser Cut Inside': { allowTabs: true, tabFields: false, fields: ['name', 'filterFillColor', 'filterStrokeColor', 'laserDiameter', 'laserPower', 'margin', 'passes', 'passDepth', 'startHeight', 'cutRate', 'useA', 'aAxisDiameter', 'useBlower', 'segmentLength', ...OPERATION_GROUPS.Macros.fields] }, 'Laser Cut Outside': { allowTabs: true, tabFields: false, fields: ['name', 'filterFillColor', 'filterStrokeColor', 'laserDiameter', 'laserPower', 'margin', 'passes', 'passDepth', 'startHeight', 'cutRate', 'useA', 'aAxisDiameter', 'useBlower', 'segmentLength', ...OPERATION_GROUPS.Macros.fields] }, 'Laser Fill Path': { allowTabs: false, tabFields: false, fields: ['name', 'filterFillColor', 'filterStrokeColor', 'lineDistance', 'lineAngle', 'laserPower', 'margin', 'passes', 'passDepth', 'startHeight', 'cutRate', 'useA', 'aAxisDiameter', 'useBlower', ...OPERATION_GROUPS.Macros.fields] }, diff --git a/src/lib/cam-gcode-laser-cut.js b/src/lib/cam-gcode-laser-cut.js index ed7e02fe..2816fc4a 100644 --- a/src/lib/cam-gcode-laser-cut.js +++ b/src/lib/cam-gcode-laser-cut.js @@ -164,7 +164,7 @@ export function getLaserCutGcode(props) { export function getLaserCutGcodeFromOp(settings, opIndex, op, geometry, openGeometry, tabGeometry, showAlert, done, progress) { let ok = true; - if (op.type !== 'Laser Cut' && op.type !== 'Laser Fill Path') { + if (op.type !== 'Laser Cut' && op.type !== 'Laser Cut (unoptimized)' && op.type !== 'Laser Fill Path') { if (op.laserDiameter <= 0) { showAlert("Laser Diameter must be greater than 0", "danger"); ok = false; @@ -209,6 +209,8 @@ export function getLaserCutGcodeFromOp(settings, opIndex, op, geometry, openGeom let camPaths = []; if (op.type === 'Laser Cut') { camPaths = cut(geometry, openGeometry, false); + } else if (op.type === 'Laser Cut (unoptimized)') { + camPaths = cut(geometry, openGeometry, false, false); } else if (op.type === 'Laser Cut Inside') { if (op.margin) geometry = offset(geometry, -op.margin * mmToClipperScale); diff --git a/src/lib/cam-gcode.js b/src/lib/cam-gcode.js index 18f0b143..5b8ef5b8 100644 --- a/src/lib/cam-gcode.js +++ b/src/lib/cam-gcode.js @@ -144,7 +144,7 @@ export function getGcode(settings, documents, operations, documentCacheHolder, s .then((preflight) => { let { geometry, openGeometry, tabGeometry, filteredDocIds, docsWithImages } = preflight; console.log('Queueing Worker: ' + op.type + "->" + opIndex); - if (op.type === 'Laser Cut' || op.type === 'Laser Cut Inside' || op.type === 'Laser Cut Outside' || op.type === 'Laser Fill Path') { + if (op.type === 'Laser Cut' || op.type === 'Laser Cut (unoptimized)' || op.type === 'Laser Cut Inside' || op.type === 'Laser Cut Outside' || op.type === 'Laser Fill Path') { laserOps = true; if (startCode === "") startCode = settings.gcodeStart; if (endCode === "") endCode = settings.gcodeEnd; diff --git a/src/lib/cam.js b/src/lib/cam.js index 4893ef4d..0b016bbf 100644 --- a/src/lib/cam.js +++ b/src/lib/cam.js @@ -71,7 +71,7 @@ function closeClipperPaths(paths) { // Try to merge paths. A merged path doesn't cross outside of bounds. Returns array of CamPath. // If paths contains both open and closed paths, then the closed paths must be before the open // paths within the array. -function mergePaths(bounds, paths) { +function mergePaths(bounds, paths, optimized) { if (paths.length === 0) return []; @@ -117,13 +117,13 @@ function mergePaths(bounds, paths) { paths[closestPathIndex] = []; numLeft -= 1; let needNew; - if (pathIsClosed(path)) { + if (pathIsClosed(path) && optimized) { needNew = crosses(bounds, currentPoint, path[closestPointIndex]); path = path.slice(closestPointIndex, path.length).concat(path.slice(1, closestPointIndex)); path.push(path[0]); } else { needNew = true; - if (closestReverse) { + if (closestReverse && optimized) { path = path.slice(); path.reverse(); } @@ -225,7 +225,7 @@ export function insideOutside(geometry, cutterDia, isInside, width, stepover, cl // Compute paths for cut operation on Clipper geometry. Returns array // of CamPath. -export function cut(geometry, openGeometry, climb) { +export function cut(geometry, openGeometry, climb, optimized = true) { let allPaths = []; for (let i = 0; i < geometry.length; ++i) { let path = geometry[i].slice(0); @@ -236,7 +236,9 @@ export function cut(geometry, openGeometry, climb) { } for (let path of openGeometry) allPaths.push(path.slice()); - let result = mergePaths(null, allPaths); + + let result = mergePaths(null, allPaths, optimized); + for (let i = 0; i < result.length; ++i) result[i].safeToClose = pathIsClosed(result[i].path); return result; diff --git a/src/reducers/operation.js b/src/reducers/operation.js index 97f1521e..f7f79245 100644 --- a/src/reducers/operation.js +++ b/src/reducers/operation.js @@ -2,7 +2,7 @@ import { getParentIds, object, objectArray } from '../reducers/object' -import arrayMove from 'array-move' +import { arrayMoveImmutable } from 'array-move' import { GlobalStore } from '../index'; @@ -147,7 +147,7 @@ export const operations = (state, action) => { newIndex = 0; if (newIndex > state.length - 1) newIndex = state.length - 1; - return arrayMove(state.slice(), index, newIndex); + return arrayMoveImmutable(state.slice(), index, newIndex); case 'OPERATION_SET_ATTRS': if (action.payload.attrs.expanded) state = state.map(op => ({ ...op, expanded: op.id === action.payload.id }));