diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..630296d --- /dev/null +++ b/src/constants.js @@ -0,0 +1,2 @@ +export const CLEAN_DELTA = 0.01; +export const PRECISION = 0.01; diff --git a/src/gcode.js b/src/gcode.js index 59b40a4..f21c4e6 100644 --- a/src/gcode.js +++ b/src/gcode.js @@ -1,5 +1,14 @@ import THREE from 'three.js'; +const G_COMMAND = 'G'; +const M_COMMAND = 'M'; +const FAN_SPEED = 'S'; +const SPEED = 'F'; +const EXTRUDER = 'E'; +const POSITION_X = 'X'; +const POSITION_Y = 'Y'; +const POSITION_Z = 'Z'; + export default class { constructor () { this.gcode = ''; @@ -23,15 +32,14 @@ export default class { str = action + value; first = false; - } - else if (currentValue !== value) { + } else if (currentValue !== value) { str += ` ${action}${value}`; this.current[action] = value; } } - this.gcode += str + '\n'; + this.gcode += `${str}\n`; } setSettings (settings) { @@ -43,13 +51,8 @@ export default class { turnFanOn (fanSpeed) { this.isFanOn = true; - var gcode = { - 'M': 106 - } - - if (fanSpeed !== undefined) { - gcode['S'] = fanSpeed; - } + const gcode = { [M_COMMAND]: 106 } + if (fanSpeed !== undefined) gcode[FAN_SPEED] = fanSpeed; this._addGCode(gcode); @@ -59,24 +62,24 @@ export default class { turnFanOff () { this.isFanOn = false; - this._addGCode({ - 'M': 107 - }); + this._addGCode({ [M_COMMAND]: 107 }); return this; } moveTo (x, y, layer) { - var layerHeight = this.settings.config['layerHeight']; - var travelSpeed = this.settings.config['travelSpeed']; + const layerHeight = this.settings.config['layerHeight']; + const travelSpeed = this.settings.config['travelSpeed']; - var z = (layer + 1) * layerHeight; - var speed = travelSpeed * 60; + const z = (layer + 1) * layerHeight; + const speed = travelSpeed * 60; this._addGCode({ - 'G': 0, - 'X': x.toFixed(3), 'Y': y.toFixed(3), 'Z': z.toFixed(3), - 'F': speed.toFixed(3) + [G_COMMAND]: 0, + [POSITION_X]: x.toFixed(3), + [POSITION_Y]: y.toFixed(3), + [POSITION_Z]: z.toFixed(3), + [SPEED]: speed.toFixed(3) }); this._nozzlePosition.set(x, y); @@ -85,29 +88,31 @@ export default class { } lineTo (x, y, layer, type) { - var newNozzlePosition = new THREE.Vector2(x, y); + const newNozzlePosition = new THREE.Vector2(x, y); - var layerHeight = this.settings.config['layerHeight']; - var nozzleDiameter = this.settings.config['nozzleDiameter']; - var filamentThickness = this.settings.config['filamentThickness']; - var travelSpeed = this.settings.config['travelSpeed']; + const layerHeight = this.settings.config['layerHeight']; + const nozzleDiameter = this.settings.config['nozzleDiameter']; + const filamentThickness = this.settings.config['filamentThickness']; + const travelSpeed = this.settings.config['travelSpeed']; - var profile = this.settings.config[(this.bottom ? 'bottom' : type)]; + const profile = this.settings.config[(this.bottom ? 'bottom' : type)]; - var speed = profile['speed'] * 60; - var flowRate = profile['flowRate']; - var z = (layer + 1) * layerHeight; + const speed = profile['speed'] * 60; + const flowRate = profile['flowRate']; + const z = (layer + 1) * layerHeight; - var lineLength = this._nozzlePosition.distanceTo(newNozzlePosition); + const lineLength = this._nozzlePosition.distanceTo(newNozzlePosition); - var filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI; + const filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI; this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate; this._addGCode({ - 'G': 1, - 'X': x.toFixed(3), 'Y': y.toFixed(3), 'Z': z.toFixed(3), - 'F': speed.toFixed(3), - 'E': this.extruder.toFixed(3) + [G_COMMAND]: 1, + [POSITION_X]: x.toFixed(3), + [POSITION_Y]: y.toFixed(3), + [POSITION_Z]: z.toFixed(3), + [SPEED]: speed.toFixed(3), + [EXTRUDER]: this.extruder.toFixed(3) }); this._nozzlePosition.copy(newNozzlePosition); @@ -116,20 +121,20 @@ export default class { } unRetract () { - var retractionEnabled = this.settings.config['retractionEnabled']; - var retractionMinDistance = this.settings.config['retractionMinDistance']; - var retractionSpeed = this.settings.config['retractionSpeed']; + const retractionEnabled = this.settings.config['retractionEnabled']; + const retractionMinDistance = this.settings.config['retractionMinDistance']; + const retractionSpeed = this.settings.config['retractionSpeed']; if (this.isRetracted && retractionEnabled) { this.isRetracted = false; - var speed = retractionSpeed * 60; + const speed = retractionSpeed * 60; if (this.extruder > retractionMinDistance) { this._addGCode({ - 'G': 0, - 'E': this.extruder.toFixed(3), - 'F': speed.toFixed(3) + [G_COMMAND]: 0, + [EXTRUDER]: this.extruder.toFixed(3), + [SPEED]: speed.toFixed(3) }); } } @@ -138,21 +143,21 @@ export default class { } retract () { - var retractionAmount = this.settings.config['retractionAmount']; - var retractionEnabled = this.settings.config['retractionEnabled']; - var retractionMinDistance = this.settings.config['retractionMinDistance']; - var retractionSpeed = this.settings.config['retractionSpeed']; + const retractionAmount = this.settings.config['retractionAmount']; + const retractionEnabled = this.settings.config['retractionEnabled']; + const retractionMinDistance = this.settings.config['retractionMinDistance']; + const retractionSpeed = this.settings.config['retractionSpeed']; if (!this.isRetracted && retractionEnabled) { this.isRetracted = true; - var speed = retractionSpeed * 60; + const speed = retractionSpeed * 60; if (this.extruder > retractionMinDistance && retractionEnabled) { this._addGCode({ - 'G': 0, - 'E': (this.extruder - retractionAmount).toFixed(3), - 'F': speed.toFixed(3) + [G_COMMAND]: 0, + [EXTRUDER]: (this.extruder - retractionAmount).toFixed(3), + [SPEED]: speed.toFixed(3) }); } } diff --git a/src/sliceActions/generateInfills.js b/src/sliceActions/generateInfills.js index abe796a..bc4ec1b 100644 --- a/src/sliceActions/generateInfills.js +++ b/src/sliceActions/generateInfills.js @@ -1,8 +1,7 @@ +import { PRECISION } from '../constants.js' import getFillTemplate from './getFillTemplate.js'; import Shape from 'Doodle3D/clipper-js'; -const scale = 100; - export default function generateInfills(slices, settings) { console.log('generating infills'); @@ -15,9 +14,9 @@ export default function generateInfills(slices, settings) { infillOverlap } = settings.config; - fillGridSize *= scale; - nozzleDiameter *= scale; - infillOverlap *= scale; + fillGridSize /= PRECISION; + nozzleDiameter /= PRECISION; + infillOverlap /= PRECISION; const bottomSkinCount = Math.ceil(bottomThickness/layerHeight); const topSkinCount = Math.ceil(topThickness/layerHeight); diff --git a/src/sliceActions/generateInnerLines.js b/src/sliceActions/generateInnerLines.js index 4d08e91..4979a65 100644 --- a/src/sliceActions/generateInnerLines.js +++ b/src/sliceActions/generateInnerLines.js @@ -1,4 +1,5 @@ -const scale = 100; +import { PRECISION } from '../constants.js' + const offsetOptions = { jointType: 'jtSquare', endType: 'etClosedPolygon', @@ -7,33 +8,32 @@ const offsetOptions = { }; export default function generateInnerLines(slices, settings) { - console.log("generating outer lines and inner lines"); + console.log('generating outer lines and inner lines'); // need to scale up everything because of clipper rounding errors let { layerHeight, nozzleDiameter, shellThickness } = settings.config; - nozzleDiameter *= scale; - shellThickness *= scale; - var nozzleRadius = nozzleDiameter / 2; - var shells = Math.round(shellThickness / nozzleDiameter); + nozzleDiameter /= PRECISION; + shellThickness /= PRECISION; + const nozzleRadius = nozzleDiameter / 2; + const shells = Math.round(shellThickness / nozzleDiameter); - for (var layer = 0; layer < slices.length; layer ++) { - var slice = slices[layer]; + for (let layer = 0; layer < slices.length; layer ++) { + const slice = slices[layer]; - for (var i = 0; i < slice.parts.length; i ++) { - var part = slice.parts[i]; + for (let i = 0; i < slice.parts.length; i ++) { + const part = slice.parts[i]; if (!part.shape.closed) continue; - // var outerLine = part.shape.clone().scaleUp(scale).offset(-nozzleRadius); - const outerLine = part.shape.scaleUp(scale).offset(-nozzleRadius, offsetOptions); + const outerLine = part.shape.scaleDown(PRECISION).offset(-nozzleRadius, offsetOptions); if (outerLine.paths.length > 0) { part.outerLine.join(outerLine); - for (var shell = 1; shell < shells; shell += 1) { - var offset = shell * nozzleDiameter; + for (let shell = 1; shell < shells; shell += 1) { + const offset = shell * nozzleDiameter; - var innerLine = outerLine.offset(-offset, offsetOptions); + const innerLine = outerLine.offset(-offset, offsetOptions); if (innerLine.paths.length > 0) { part.innerLines.push(innerLine); diff --git a/src/sliceActions/generateSupport.js b/src/sliceActions/generateSupport.js index 1c44374..8140e19 100644 --- a/src/sliceActions/generateSupport.js +++ b/src/sliceActions/generateSupport.js @@ -1,7 +1,6 @@ import getFillTemplate from './getFillTemplate.js'; import Shape from 'Doodle3D/clipper-js'; - -const scale = 100; +import { PRECISION } from '../constants.js'; export default function generateSupport(slices, settings) { console.log("generating support"); @@ -16,10 +15,10 @@ export default function generateSupport(slices, settings) { nozzleDiameter } = settings.config; - supportGridSize *= scale; - supportMargin *= scale; - plateSize *= scale; - nozzleDiameter *= scale; + supportGridSize /= PRECISION; + supportMargin /= PRECISION; + plateSize /= PRECISION; + nozzleDiameter /= PRECISION; var supportDistanceLayers = Math.max(Math.ceil(supportDistanceY / layerHeight), 1); var supportAreas = new Shape([], true); diff --git a/src/sliceActions/intersectionsToShapes.js b/src/sliceActions/intersectionsToShapes.js index a4742f3..0143cda 100644 --- a/src/sliceActions/intersectionsToShapes.js +++ b/src/sliceActions/intersectionsToShapes.js @@ -4,43 +4,39 @@ import Shape from 'Doodle3D/clipper-js'; export default function intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings) { console.log("generating slices"); - var layers = []; + const layers = []; - for (var layer = 1; layer < layerIntersectionIndexes.length; layer ++) { - var intersectionIndexes = layerIntersectionIndexes[layer]; - var intersectionPoints = layerIntersectionPoints[layer]; + for (let layer = 1; layer < layerIntersectionIndexes.length; layer ++) { + const intersectionIndexes = layerIntersectionIndexes[layer]; + const intersectionPoints = layerIntersectionPoints[layer]; - if (intersectionIndexes.length === 0) { - continue; - } + if (intersectionIndexes.length === 0) continue; - var closedShapes = []; - var openShapes = []; - for (var i = 0; i < intersectionIndexes.length; i ++) { - var index = intersectionIndexes[i]; + const closedShapes = []; + const openShapes = []; + for (let i = 0; i < intersectionIndexes.length; i ++) { + let index = intersectionIndexes[i]; - if (intersectionPoints[index] === undefined) { - continue; - } + if (intersectionPoints[index] === undefined) continue; - var firstPoints = [index]; - var isFirstPoint = true; - var closed = false; + const shape = []; - var shape = []; + const firstPoints = [index]; + let isFirstPoint = true; + let closed = false; while (index !== -1) { - var intersection = intersectionPoints[index]; + const intersection = intersectionPoints[index]; // uppercase X and Y because clipper vector shape.push(intersection); delete intersectionPoints[index]; - var connects = lines[index].connects; - var faceNormals = lines[index].normals; + const connects = lines[index].connects; + const faceNormals = lines[index].normals; - for (var j = 0; j < connects.length; j ++) { - var index = connects[j]; + for (let i = 0; i < connects.length; i ++) { + index = connects[i]; if (firstPoints.indexOf(index) !== -1 && shape.length > 2) { closed = true; @@ -50,10 +46,10 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt // Check if index has an intersection or is already used if (intersectionPoints[index] !== undefined) { - var faceNormal = faceNormals[Math.floor(j / 2)]; + const faceNormal = faceNormals[Math.floor(i / 2)]; - var a = new THREE.Vector2(intersection.x, intersection.y); - var b = new THREE.Vector2(intersectionPoints[index].x, intersectionPoints[index].y); + const a = new THREE.Vector2(intersection.x, intersection.y); + const b = new THREE.Vector2(intersectionPoints[index].x, intersectionPoints[index].y); // can't calculate normal between points if distance is smaller as 0.0001 if ((faceNormal.x === 0 && faceNormal.y === 0) || a.distanceTo(b) < 0.0001) { @@ -63,26 +59,23 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt delete intersectionPoints[index]; - connects = connects.concat(lines[index].connects); - faceNormals = faceNormals.concat(lines[index].normals); + connects.push(...lines[index].connects); + faceNormals.push(...lines[index].normals); index = -1; - } - else { + } else { // make sure the path goes the right direction // THREE.Vector2.normal is not yet implimented - // var normal = a.sub(b).normal().normalize(); - var normal = a.sub(b); + // const normal = a.sub(b).normal().normalize(); + const normal = a.sub(b); normal.set(-normal.y, normal.x).normalize(); if (normal.dot(faceNormal) > 0) { break; - } - else { + } else { index = -1; } } - } - else { + } else { index = -1; } } @@ -90,25 +83,24 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt } if (!closed) { - var index = firstPoints[0]; + index = firstPoints[0]; while (index !== -1) { if (firstPoints.indexOf(index) === -1) { - var intersection = intersectionPoints[index]; + const intersection = intersectionPoints[index]; shape.unshift(intersection); delete intersectionPoints[index]; } - var connects = lines[index].connects; + const connects = lines[index].connects; - for (var i = 0; i < connects.length; i ++) { - var index = connects[i]; + for (let i = 0; i < connects.length; i ++) { + index = connects[i]; if (intersectionPoints[index] !== undefined) { break; - } - else { + } else { index = -1; } } @@ -117,8 +109,7 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt if (closed) { closedShapes.push(shape); - } - else { + } else { openShapes.push(shape); } } diff --git a/src/sliceActions/optimizePaths.js b/src/sliceActions/optimizePaths.js index 7181f1f..2c873e5 100644 --- a/src/sliceActions/optimizePaths.js +++ b/src/sliceActions/optimizePaths.js @@ -1,4 +1,6 @@ import THREE from 'three.js'; +import { PRECISION } from '../constants.js'; + const offsetOptions = { jointType: 'jtSquare', endType: 'etClosedPolygon', @@ -9,15 +11,12 @@ const offsetOptions = { export default function optimizePaths(slices, settings) { console.log("opimize paths"); - // need to scale up everything because of clipper rounding errors - var scale = 100; + const brimOffset = settings.config["brimOffset"] / PRECISION; - var brimOffset = settings.config["brimOffset"] * scale; + const start = new THREE.Vector2(0, 0); - var start = new THREE.Vector2(0, 0); - - for (var layer = 0; layer < slices.length; layer ++) { - var slice = slices[layer]; + for (let layer = 0; layer < slices.length; layer ++) { + const slice = slices[layer]; if (layer === 0) { slice.brim = slice.getOutline().offset(brimOffset, offsetOptions); @@ -25,24 +24,24 @@ export default function optimizePaths(slices, settings) { // start = slice.optimizePaths(start); - for (var i = 0; i < slice.parts.length; i ++) { - var part = slice.parts[i]; + for (let i = 0; i < slice.parts.length; i ++) { + const part = slice.parts[i]; if (part.shape.closed) { - part.outerLine.scaleDown(scale); - for (var j = 0; j < part.innerLines.length; j ++) { - var innerLine = part.innerLines[j]; - innerLine.scaleDown(scale); + part.outerLine.scaleDown(1 / PRECISION); + for (let i = 0; i < part.innerLines.length; i ++) { + const innerLine = part.innerLines[i]; + innerLine.scaleDown(1 / PRECISION); } - part.fill.scaleDown(scale); + part.fill.scaleDown(1 / PRECISION); } } if (slice.support !== undefined) { - slice.support.scaleDown(scale); + slice.support.scaleDown(1 / PRECISION); } if (slice.brim !== undefined) { - slice.brim.scaleDown(scale); + slice.brim.scaleDown(1 / PRECISION); } } } diff --git a/src/sliceActions/shapesToSlices.js b/src/sliceActions/shapesToSlices.js index 36371f9..7be4a88 100644 --- a/src/sliceActions/shapesToSlices.js +++ b/src/sliceActions/shapesToSlices.js @@ -1,31 +1,34 @@ import Shape from 'Doodle3D/clipper-js'; import Slice from '../slice.js'; +import { CLEAN_DELTA } from '../constants.js'; + export default function shapesToSlices(shapes, settings) { const sliceLayers = []; - for (var layer = 0; layer < shapes.length; layer ++) { - var { closedShapes, openShapes } = shapes[layer]; + for (let layer = 0; layer < shapes.length; layer ++) { + let { closedShapes, openShapes } = shapes[layer]; closedShapes = new Shape(closedShapes, true, true) - .clean(0.01) + .clean(CLEAN_DELTA) .fixOrientation() .removeOverlap() .seperateShapes(); openShapes = new Shape(openShapes, false, true) - .clean(0.01); + .clean(CLEAN_DELTA); - var slice = new Slice(); + const slice = new Slice(); - for (var i = 0; i < closedShapes.length; i ++) { - var closedShape = closedShapes[i]; + for (let i = 0; i < closedShapes.length; i ++) { + const closedShape = closedShapes[i]; slice.add(closedShape); // if (openShapes.path.length > 0) { // openShapes = openShapes.difference(closedShape); // } } + if (openShapes.paths.length > 0) { slice.add(openShapes); }