mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-22 21:47:59 +01:00
Merge branch 'restructure' into develop
This commit is contained in:
commit
d016aa345b
95
config.js
95
config.js
@ -1,95 +0,0 @@
|
|||||||
System.config({
|
|
||||||
baseURL: "/",
|
|
||||||
defaultJSExtensions: true,
|
|
||||||
transpiler: "babel",
|
|
||||||
babelOptions: {
|
|
||||||
"optional": [
|
|
||||||
"runtime"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
paths: {
|
|
||||||
"github:*": "jspm_packages/github/*",
|
|
||||||
"npm:*": "jspm_packages/npm/*"
|
|
||||||
},
|
|
||||||
bundles: {
|
|
||||||
"bundle.js": []
|
|
||||||
},
|
|
||||||
|
|
||||||
map: {
|
|
||||||
"babel": "npm:babel-core@5.8.21",
|
|
||||||
"babel-runtime": "npm:babel-runtime@5.8.20",
|
|
||||||
"clipper-lib": "npm:clipper-lib@1.0.0",
|
|
||||||
"core-js": "npm:core-js@0.9.18",
|
|
||||||
"json": "github:systemjs/plugin-json@0.1.0",
|
|
||||||
"nodeca/js-yaml": "github:nodeca/js-yaml@3.3.1",
|
|
||||||
"read-yaml": "npm:read-yaml@1.0.0",
|
|
||||||
"systemjs/plugin-json": "github:systemjs/plugin-json@0.1.0",
|
|
||||||
"three.js": "github:mrdoob/three.js@r72",
|
|
||||||
"github:jspm/nodelibs-assert@0.1.0": {
|
|
||||||
"assert": "npm:assert@1.3.0"
|
|
||||||
},
|
|
||||||
"github:jspm/nodelibs-path@0.1.0": {
|
|
||||||
"path-browserify": "npm:path-browserify@0.0.0"
|
|
||||||
},
|
|
||||||
"github:jspm/nodelibs-process@0.1.1": {
|
|
||||||
"process": "npm:process@0.10.1"
|
|
||||||
},
|
|
||||||
"github:jspm/nodelibs-util@0.1.0": {
|
|
||||||
"util": "npm:util@0.10.3"
|
|
||||||
},
|
|
||||||
"npm:argparse@1.0.2": {
|
|
||||||
"assert": "github:jspm/nodelibs-assert@0.1.0",
|
|
||||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
|
||||||
"lodash": "npm:lodash@3.10.1",
|
|
||||||
"path": "github:jspm/nodelibs-path@0.1.0",
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1",
|
|
||||||
"sprintf-js": "npm:sprintf-js@1.0.3",
|
|
||||||
"util": "github:jspm/nodelibs-util@0.1.0"
|
|
||||||
},
|
|
||||||
"npm:assert@1.3.0": {
|
|
||||||
"util": "npm:util@0.10.3"
|
|
||||||
},
|
|
||||||
"npm:babel-runtime@5.8.20": {
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
},
|
|
||||||
"npm:clipper-lib@1.0.0": {
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
},
|
|
||||||
"npm:core-js@0.9.18": {
|
|
||||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1",
|
|
||||||
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
|
|
||||||
},
|
|
||||||
"npm:esprima@2.2.0": {
|
|
||||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
},
|
|
||||||
"npm:inherits@2.0.1": {
|
|
||||||
"util": "github:jspm/nodelibs-util@0.1.0"
|
|
||||||
},
|
|
||||||
"npm:js-yaml@3.3.1": {
|
|
||||||
"argparse": "npm:argparse@1.0.2",
|
|
||||||
"esprima": "npm:esprima@2.2.0",
|
|
||||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
|
||||||
"path": "github:jspm/nodelibs-path@0.1.0",
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1",
|
|
||||||
"systemjs-json": "github:systemjs/plugin-json@0.1.0",
|
|
||||||
"util": "github:jspm/nodelibs-util@0.1.0"
|
|
||||||
},
|
|
||||||
"npm:lodash@3.10.1": {
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
},
|
|
||||||
"npm:path-browserify@0.0.0": {
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
},
|
|
||||||
"npm:read-yaml@1.0.0": {
|
|
||||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
|
||||||
"js-yaml": "npm:js-yaml@3.3.1",
|
|
||||||
"xtend": "npm:xtend@4.0.0"
|
|
||||||
},
|
|
||||||
"npm:util@0.10.3": {
|
|
||||||
"inherits": "npm:inherits@2.0.1",
|
|
||||||
"process": "github:jspm/nodelibs-process@0.1.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,19 +1,17 @@
|
|||||||
import THREE from 'three.js';
|
import THREE from 'three.js';
|
||||||
import PRINTER_SETTINGS from 'settings/printer_settings.json!';
|
|
||||||
import USER_SETTINGS from 'settings/user_settings.json!';
|
|
||||||
import * as SLICER from 'src/index';
|
import * as SLICER from 'src/index';
|
||||||
|
|
||||||
var settings = new SLICER.Settings();
|
const settings = new SLICER.Settings({
|
||||||
settings.updateConfig(PRINTER_SETTINGS["ultimaker2go"]);
|
...SLICER.printerSettings['ultimaker2go'],
|
||||||
settings.updateConfig(USER_SETTINGS);
|
...SLICER.userSettings
|
||||||
|
});
|
||||||
|
|
||||||
var geometry = new THREE.TorusGeometry(20, 10, 30, 30);
|
const geometry = new THREE.TorusGeometry(20, 10, 30, 30);
|
||||||
|
|
||||||
var slicer = new SLICER.Slicer();
|
const slicer = new SLICER.Slicer();
|
||||||
//var slicer = new SLICER.SlicerWorker();
|
|
||||||
|
|
||||||
slicer.setGeometry(geometry.clone());
|
slicer.setGeometry(geometry);
|
||||||
slicer.onfinish = function (gCode) {
|
slicer.addEventListener('finish', ({ gcode }) => {
|
||||||
document.getElementById('gcode').innerHTML = gCode.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
document.getElementById('gcode').innerHTML = gcode.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
||||||
};
|
});
|
||||||
slicer.slice(settings);
|
slicer.slice(settings);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript" src="../jspm_packages/system.js"></script>
|
<script type="text/javascript" src="../jspm_packages/system.js"></script>
|
||||||
<script type="text/javascript" src="../config.js"></script>
|
<script type="text/javascript" src="../jspm.config.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
System.import('example/app.js');
|
System.import('example/app.js');
|
||||||
|
70
jspm.config.js
Normal file
70
jspm.config.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
SystemJS.config({
|
||||||
|
paths: {
|
||||||
|
"github:": "jspm_packages/github/",
|
||||||
|
"npm:": "jspm_packages/npm/",
|
||||||
|
"slicer/": "src/"
|
||||||
|
},
|
||||||
|
browserConfig: {
|
||||||
|
"baseURL": "/"
|
||||||
|
},
|
||||||
|
devConfig: {
|
||||||
|
"map": {
|
||||||
|
"babel-runtime": "npm:babel-runtime@5.8.38",
|
||||||
|
"core-js": "npm:core-js@0.9.18",
|
||||||
|
"process": "github:jspm/nodelibs-process@0.2.0-alpha",
|
||||||
|
"fs": "github:jspm/nodelibs-fs@0.2.0-alpha",
|
||||||
|
"plugin-babel": "npm:systemjs-plugin-babel@0.0.12"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"npm:babel-runtime@5.8.38": {
|
||||||
|
"map": {}
|
||||||
|
},
|
||||||
|
"npm:core-js@0.9.18": {
|
||||||
|
"map": {
|
||||||
|
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
transpiler: "plugin-babel",
|
||||||
|
babelOptions: {
|
||||||
|
"optional": [
|
||||||
|
"runtime"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
packages: {
|
||||||
|
"slicer": {
|
||||||
|
"main": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bundles: {
|
||||||
|
"bundle.js": []
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
"babel": "npm:babel-core@5.8.38"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SystemJS.config({
|
||||||
|
packageConfigPaths: [
|
||||||
|
"npm:@*/*.json",
|
||||||
|
"npm:*.json",
|
||||||
|
"github:*/*.json"
|
||||||
|
],
|
||||||
|
map: {
|
||||||
|
"json": "github:systemjs/plugin-json@0.1.2",
|
||||||
|
"Doodle3D/clipper-js": "github:Doodle3D/clipper-js@master",
|
||||||
|
"casperlamboo/EventDispatcher": "github:casperlamboo/EventDispatcher@master",
|
||||||
|
"three.js": "github:mrdoob/three.js@r72"
|
||||||
|
},
|
||||||
|
packages: {
|
||||||
|
"github:Doodle3D/clipper-js@master": {
|
||||||
|
"map": {
|
||||||
|
"clipper-lib": "npm:clipper-lib@1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npm:clipper-lib@1.0.0": {
|
||||||
|
"map": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
25
package.json
25
package.json
@ -1,20 +1,31 @@
|
|||||||
{
|
{
|
||||||
"jspm": {
|
"jspm": {
|
||||||
"main": "index",
|
"name": "slicer",
|
||||||
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
"lib": "src"
|
"lib": "src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clipper-lib": "npm:clipper-lib@^1.0.0",
|
"Doodle3D/clipper-js": "github:Doodle3D/clipper-js@master",
|
||||||
"nodeca/js-yaml": "github:nodeca/js-yaml@^3.3.1",
|
"casperlamboo/EventDispatcher": "github:casperlamboo/EventDispatcher@master",
|
||||||
"read-yaml": "npm:read-yaml@^1.0.0",
|
"json": "github:systemjs/plugin-json@^0.1.2",
|
||||||
"systemjs/plugin-json": "github:systemjs/plugin-json@^0.1.0",
|
|
||||||
"three.js": "github:mrdoob/three.js@r72"
|
"three.js": "github:mrdoob/three.js@r72"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel": "npm:babel-core@^5.1.13",
|
|
||||||
"babel-runtime": "npm:babel-runtime@^5.1.13",
|
"babel-runtime": "npm:babel-runtime@^5.1.13",
|
||||||
"core-js": "npm:core-js@^0.9.4"
|
"core-js": "npm:core-js@^0.9.4",
|
||||||
|
"fs": "github:jspm/nodelibs-fs@^0.2.0-alpha",
|
||||||
|
"plugin-babel": "npm:systemjs-plugin-babel@^0.0.12",
|
||||||
|
"process": "github:jspm/nodelibs-process@^0.2.0-alpha"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"npm:babel-runtime@5.8.38": {
|
||||||
|
"main": false,
|
||||||
|
"dependencies": {},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"core-js": "^1.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
src/constants.js
Normal file
2
src/constants.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const CLEAN_DELTA = 0.01;
|
||||||
|
export const PRECISION = 0.01;
|
155
src/gcode.js
155
src/gcode.js
@ -1,7 +1,16 @@
|
|||||||
import THREE from 'three.js';
|
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 {
|
export default class {
|
||||||
constructor () {
|
constructor(settings) {
|
||||||
this.gcode = '';
|
this.gcode = '';
|
||||||
this.current = {};
|
this.current = {};
|
||||||
|
|
||||||
@ -10,71 +19,73 @@ export default class {
|
|||||||
this.isRetracted = false;
|
this.isRetracted = false;
|
||||||
this.isFanOn = false;
|
this.isFanOn = false;
|
||||||
this._nozzlePosition = new THREE.Vector2(0, 0);
|
this._nozzlePosition = new THREE.Vector2(0, 0);
|
||||||
|
|
||||||
|
if (settings !== undefined) {
|
||||||
|
this.setSettings(settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_addGCode (command) {
|
_addGCode(command) {
|
||||||
var str = '';
|
let str = '';
|
||||||
var first = true;
|
let first = true;
|
||||||
|
|
||||||
for (var i in command) {
|
for (const action in command) {
|
||||||
|
const value = command[action];
|
||||||
|
const currentValue = this.current[action];
|
||||||
if (first) {
|
if (first) {
|
||||||
str = i + command[i];
|
str = action + value;
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
}
|
} else if (currentValue !== value) {
|
||||||
else if (this.current[i] !== command[i]) {
|
str += ` ${action}${value}`;
|
||||||
str += ' ' + i + command[i];
|
|
||||||
|
|
||||||
this.current[i] = command[i];
|
this.current[action] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gcode += str + '\n';
|
this.gcode += `${str}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSettings (settings) {
|
setSettings(settings) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
turnFanOn (fanSpeed) {
|
turnFanOn(fanSpeed) {
|
||||||
this.isFanOn = true;
|
this.isFanOn = true;
|
||||||
|
|
||||||
var gcode = {
|
const gcode = { [M_COMMAND]: 106 }
|
||||||
'M': 106
|
if (fanSpeed !== undefined) gcode[FAN_SPEED] = fanSpeed;
|
||||||
}
|
|
||||||
|
|
||||||
if (fanSpeed !== undefined) {
|
|
||||||
gcode['S'] = fanSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._addGCode(gcode);
|
this._addGCode(gcode);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
turnFanOff () {
|
turnFanOff() {
|
||||||
this.isFanOn = false;
|
this.isFanOn = false;
|
||||||
|
|
||||||
this._addGCode({
|
this._addGCode({ [M_COMMAND]: 107 });
|
||||||
'M': 107
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTo (x, y, layer) {
|
moveTo(x, y, layer) {
|
||||||
var layerHeight = this.settings.config['layerHeight'];
|
const {
|
||||||
var travelSpeed = this.settings.config['travelSpeed'];
|
layerHeight,
|
||||||
|
travelSpeed
|
||||||
|
} = this.settings.config;
|
||||||
|
|
||||||
var z = (layer + 1) * layerHeight;
|
const z = (layer + 1) * layerHeight;
|
||||||
var speed = travelSpeed * 60;
|
const speed = travelSpeed * 60;
|
||||||
|
|
||||||
this._addGCode({
|
this._addGCode({
|
||||||
'G': 0,
|
[G_COMMAND]: 0,
|
||||||
'X': x.toFixed(3), 'Y': y.toFixed(3), 'Z': z.toFixed(3),
|
[POSITION_X]: x.toFixed(3),
|
||||||
'F': speed.toFixed(3)
|
[POSITION_Y]: y.toFixed(3),
|
||||||
|
[POSITION_Z]: z.toFixed(3),
|
||||||
|
[SPEED]: speed.toFixed(3)
|
||||||
});
|
});
|
||||||
|
|
||||||
this._nozzlePosition.set(x, y);
|
this._nozzlePosition.set(x, y);
|
||||||
@ -82,30 +93,38 @@ export default class {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineTo (x, y, layer, type) {
|
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'];
|
const {
|
||||||
var nozzleDiameter = this.settings.config['nozzleDiameter'];
|
layerHeight,
|
||||||
var filamentThickness = this.settings.config['filamentThickness'];
|
nozzleDiameter,
|
||||||
var travelSpeed = this.settings.config['travelSpeed'];
|
filamentThickness,
|
||||||
|
travelSpeed
|
||||||
|
} = this.settings.config;
|
||||||
|
|
||||||
var profile = this.settings.config[(this.bottom ? 'bottom' : type)];
|
const profile = this.settings.config[(this.bottom ? 'bottom' : type)];
|
||||||
|
|
||||||
var speed = profile['speed'] * 60;
|
let {
|
||||||
var flowRate = profile['flowRate'];
|
speed,
|
||||||
var z = (layer + 1) * layerHeight;
|
flowRate
|
||||||
|
} = profile;
|
||||||
|
|
||||||
var lineLength = this._nozzlePosition.distanceTo(newNozzlePosition);
|
speed *= 60;
|
||||||
|
const z = (layer + 1) * layerHeight;
|
||||||
|
|
||||||
var filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI;
|
const lineLength = this._nozzlePosition.distanceTo(newNozzlePosition);
|
||||||
|
|
||||||
|
const filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI;
|
||||||
this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
|
this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
|
||||||
|
|
||||||
this._addGCode({
|
this._addGCode({
|
||||||
'G': 1,
|
[G_COMMAND]: 1,
|
||||||
'X': x.toFixed(3), 'Y': y.toFixed(3), 'Z': z.toFixed(3),
|
[POSITION_X]: x.toFixed(3),
|
||||||
'F': speed.toFixed(3),
|
[POSITION_Y]: y.toFixed(3),
|
||||||
'E': this.extruder.toFixed(3)
|
[POSITION_Z]: z.toFixed(3),
|
||||||
|
[SPEED]: speed.toFixed(3),
|
||||||
|
[EXTRUDER]: this.extruder.toFixed(3)
|
||||||
});
|
});
|
||||||
|
|
||||||
this._nozzlePosition.copy(newNozzlePosition);
|
this._nozzlePosition.copy(newNozzlePosition);
|
||||||
@ -113,21 +132,23 @@ export default class {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
unRetract () {
|
unRetract() {
|
||||||
var retractionEnabled = this.settings.config['retractionEnabled'];
|
const {
|
||||||
var retractionMinDistance = this.settings.config['retractionMinDistance'];
|
retractionEnabled,
|
||||||
var retractionSpeed = this.settings.config['retractionSpeed'];
|
retractionMinDistance,
|
||||||
|
retractionSpeed
|
||||||
|
} = this.settings.config;
|
||||||
|
|
||||||
if (this.isRetracted && retractionEnabled) {
|
if (this.isRetracted && retractionEnabled) {
|
||||||
this.isRetracted = false;
|
this.isRetracted = false;
|
||||||
|
|
||||||
var speed = retractionSpeed * 60;
|
const speed = retractionSpeed * 60;
|
||||||
|
|
||||||
if (this.extruder > retractionMinDistance) {
|
if (this.extruder > retractionMinDistance) {
|
||||||
this._addGCode({
|
this._addGCode({
|
||||||
'G': 0,
|
[G_COMMAND]: 0,
|
||||||
'E': this.extruder.toFixed(3),
|
[EXTRUDER]: this.extruder.toFixed(3),
|
||||||
'F': speed.toFixed(3)
|
[SPEED]: speed.toFixed(3)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,22 +156,24 @@ export default class {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
retract () {
|
retract() {
|
||||||
var retractionAmount = this.settings.config['retractionAmount'];
|
const {
|
||||||
var retractionEnabled = this.settings.config['retractionEnabled'];
|
retractionAmount,
|
||||||
var retractionMinDistance = this.settings.config['retractionMinDistance'];
|
retractionEnabled,
|
||||||
var retractionSpeed = this.settings.config['retractionSpeed'];
|
retractionMinDistance,
|
||||||
|
retractionSpeed
|
||||||
|
} = this.settings.config;
|
||||||
|
|
||||||
if (!this.isRetracted && retractionEnabled) {
|
if (!this.isRetracted && retractionEnabled) {
|
||||||
this.isRetracted = true;
|
this.isRetracted = true;
|
||||||
|
|
||||||
var speed = retractionSpeed * 60;
|
const speed = retractionSpeed * 60;
|
||||||
|
|
||||||
if (this.extruder > retractionMinDistance && retractionEnabled) {
|
if (this.extruder > retractionMinDistance && retractionEnabled) {
|
||||||
this._addGCode({
|
this._addGCode({
|
||||||
'G': 0,
|
[G_COMMAND]: 0,
|
||||||
'E': (this.extruder - retractionAmount).toFixed(3),
|
[EXTRUDER]: (this.extruder - retractionAmount).toFixed(3),
|
||||||
'F': speed.toFixed(3)
|
[SPEED]: speed.toFixed(3)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +181,7 @@ export default class {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGCode () {
|
getGCode() {
|
||||||
return this.settings.startCode() + this.gcode + this.settings.endCode();
|
return this.settings.startCode() + this.gcode + this.settings.endCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/getFillTemplate.js
Normal file
31
src/getFillTemplate.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
|
||||||
|
export default function getFillTemplate(bounds, size, even, uneven) {
|
||||||
|
const paths = [];
|
||||||
|
|
||||||
|
const left = Math.floor(bounds.left / size) * size;
|
||||||
|
const right = Math.ceil(bounds.right / size) * size;
|
||||||
|
const top = Math.floor(bounds.top / size) * size;
|
||||||
|
const bottom = Math.ceil(bounds.bottom / size) * size;
|
||||||
|
|
||||||
|
const width = right - left;
|
||||||
|
|
||||||
|
if (even) {
|
||||||
|
for (let y = top; y <= bottom + width; y += size) {
|
||||||
|
paths.push([
|
||||||
|
{ x: left, y },
|
||||||
|
{ x: right, y: y - width }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uneven) {
|
||||||
|
for (let y = top - width; y <= bottom; y += size) {
|
||||||
|
paths.push([
|
||||||
|
{ x: left, y },
|
||||||
|
{ x: right, y: y + width }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Shape(paths, false, true);
|
||||||
|
}
|
10
src/index.js
10
src/index.js
@ -1,10 +1,6 @@
|
|||||||
import Slicer from './slicer.js';
|
import Slicer from './slicer.js';
|
||||||
import SlicerWorker from './slicerworker.js';
|
|
||||||
import Settings from './settings.js';
|
import Settings from './settings.js';
|
||||||
import ClipperLib from 'clipper-lib';
|
import printerSettings from './settings/printer_settings.json!json';
|
||||||
|
import userSettings from './settings/user_settings.json!json';
|
||||||
|
|
||||||
ClipperLib.Error = function (message) {
|
export { Slicer, Settings, printerSettings, userSettings };
|
||||||
console.error(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {Slicer, SlicerWorker, Settings};
|
|
||||||
|
252
src/paths.js
252
src/paths.js
@ -1,252 +0,0 @@
|
|||||||
import ClipperLib from 'clipper-lib';
|
|
||||||
import THREE from 'three.js';
|
|
||||||
|
|
||||||
export default class Paths extends Array {
|
|
||||||
constructor (paths = [], closed = true) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.setPaths(paths);
|
|
||||||
this.closed = closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPaths (paths) {
|
|
||||||
for (var i = 0; i < paths.length; i ++) {
|
|
||||||
var path = paths[i];
|
|
||||||
|
|
||||||
if (path.length > 0) {
|
|
||||||
this.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
_clip (path, type) {
|
|
||||||
var solution = new ClipperLib.PolyTree();
|
|
||||||
|
|
||||||
var clipper = new ClipperLib.Clipper();
|
|
||||||
clipper.AddPaths(this, ClipperLib.PolyType.ptSubject, this.closed);
|
|
||||||
clipper.AddPaths(path, ClipperLib.PolyType.ptClip, path.closed);
|
|
||||||
clipper.Execute(type, solution);
|
|
||||||
|
|
||||||
if (this.closed) {
|
|
||||||
var paths = ClipperLib.Clipper.ClosedPathsFromPolyTree(solution);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var paths = ClipperLib.Clipper.OpenPathsFromPolyTree(solution);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Paths(paths, this.closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
union (path) {
|
|
||||||
return this._clip(path, ClipperLib.ClipType.ctUnion);
|
|
||||||
}
|
|
||||||
|
|
||||||
difference (path) {
|
|
||||||
return this._clip(path, ClipperLib.ClipType.ctDifference);
|
|
||||||
}
|
|
||||||
|
|
||||||
intersect (path) {
|
|
||||||
return this._clip(path, ClipperLib.ClipType.ctIntersection);
|
|
||||||
}
|
|
||||||
|
|
||||||
xor (path) {
|
|
||||||
return this._clip(path, ClipperLib.ClipType.ctXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset (offset) {
|
|
||||||
var solution = new ClipperLib.Paths();
|
|
||||||
var co = new ClipperLib.ClipperOffset(1, 1);
|
|
||||||
co.AddPaths(this, ClipperLib.JoinType.jtSquare, ClipperLib.EndType.etClosedPolygon);
|
|
||||||
co.Execute(solution, offset);
|
|
||||||
|
|
||||||
return new Paths(solution);
|
|
||||||
}
|
|
||||||
|
|
||||||
scaleUp (factor) {
|
|
||||||
ClipperLib.JS.ScaleUpPaths(this, factor);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
scaleDown (factor) {
|
|
||||||
ClipperLib.JS.ScaleDownPaths(this, factor);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPoint () {
|
|
||||||
if (this.length === 0) {
|
|
||||||
return new THREE.Vector2();
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastPath = this[this.length - 1];
|
|
||||||
var lastPoint = this.closed ? lastPath[0] : lastPath[lastPath.length - 1];
|
|
||||||
return new THREE.Vector2(lastPoint.X, lastPoint.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
optimizePath (start) {
|
|
||||||
var optimizedPaths = new Paths([], this.closed);
|
|
||||||
var donePaths = [];
|
|
||||||
|
|
||||||
while (optimizedPaths.length !== this.length) {
|
|
||||||
var minLength = false;
|
|
||||||
var reverse;
|
|
||||||
var minPath;
|
|
||||||
var offset;
|
|
||||||
var pathIndex;
|
|
||||||
|
|
||||||
for (var i = 0; i < this.length; i += 1) {
|
|
||||||
var path = this[i];
|
|
||||||
|
|
||||||
if (donePaths.indexOf(i) === -1) {
|
|
||||||
|
|
||||||
if (this.closed) {
|
|
||||||
for (var j = 0; j < path.length; j += 1) {
|
|
||||||
var point = new THREE.Vector2(path[j].X, path[j].Y);
|
|
||||||
var length = point.sub(start).length();
|
|
||||||
if (minLength === false || length < minLength) {
|
|
||||||
minPath = path;
|
|
||||||
minLength = length;
|
|
||||||
offset = j;
|
|
||||||
pathIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var startPoint = new THREE.Vector2(path[0].X, path[0].Y);
|
|
||||||
var length = startPoint.sub(start).length();
|
|
||||||
if (minLength === false || length < minLength) {
|
|
||||||
minPath = path;
|
|
||||||
minLength = length;
|
|
||||||
reverse = false;
|
|
||||||
pathIndex = i;
|
|
||||||
}
|
|
||||||
var endPoint = new THREE.Vector2(path[path.length - 1].X, path[path.length - 1].Y);
|
|
||||||
var length = endPoint.sub(start).length();
|
|
||||||
if (length < minLength) {
|
|
||||||
minPath = path;
|
|
||||||
minLength = length;
|
|
||||||
reverse = true;
|
|
||||||
pathIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.closed) {
|
|
||||||
minPath = minPath.concat(minPath.splice(0, offset));
|
|
||||||
var point = minPath[0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (reverse) {
|
|
||||||
minPath.reverse();
|
|
||||||
}
|
|
||||||
var point = minPath[minPath.length - 1];
|
|
||||||
}
|
|
||||||
donePaths.push(pathIndex);
|
|
||||||
start = new THREE.Vector2(point.X, point.Y);
|
|
||||||
|
|
||||||
optimizedPaths.push(minPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return optimizedPaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
areas () {
|
|
||||||
var areas = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < this.length; i ++) {
|
|
||||||
var shape = this[i];
|
|
||||||
var area = Math.abs(ClipperLib.Clipper.Area(shape));
|
|
||||||
areas.push(area);
|
|
||||||
}
|
|
||||||
|
|
||||||
return areas;
|
|
||||||
}
|
|
||||||
|
|
||||||
area () {
|
|
||||||
var areas = this.areas();
|
|
||||||
var totalArea = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < areas.length; i ++) {
|
|
||||||
var area = areas[i];
|
|
||||||
totalArea += area;
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
tresholdArea (minArea) {
|
|
||||||
// code not tested yet
|
|
||||||
for (var i = 0; i < this.length; i ++) {
|
|
||||||
var shape = this[i];
|
|
||||||
var area = ClipperLib.Clipper.Area(shape);
|
|
||||||
|
|
||||||
if (area < minArea) {
|
|
||||||
this.splice(i, 1);
|
|
||||||
i -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
join (path) {
|
|
||||||
for (var i = 0; i < path.length; i += 1) {
|
|
||||||
this.push(path[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone () {
|
|
||||||
return new Paths(ClipperLib.JS.Clone(this), this.closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
bounds () {
|
|
||||||
return ClipperLib.Clipper.GetBounds(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
clean (cleanDelta) {
|
|
||||||
return new Paths(ClipperLib.Clipper.CleanPolygons(this, cleanDelta), this.closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
isHole () {
|
|
||||||
return !ClipperLib.Clipper.Orientation(this[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointCollision (point) {
|
|
||||||
var collision = ClipperLib.Clipper.PointInPolygon(point, this[0]);
|
|
||||||
return ClipperLib.Clipper.PointInPolygon(point, this[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
boundSize () {
|
|
||||||
var bounds = this.bounds();
|
|
||||||
|
|
||||||
var width = bounds.right - bounds.left;
|
|
||||||
var height = bounds.bottom - bounds.top;
|
|
||||||
|
|
||||||
return width * height;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw (context, color) {
|
|
||||||
context.strokeStyle = color;
|
|
||||||
for (var i = 0; i < this.length; i += 1) {
|
|
||||||
var shape = this[i];
|
|
||||||
|
|
||||||
// var point = shape[0];
|
|
||||||
// context.fillText(i, point.X*2, point.Y*2);
|
|
||||||
|
|
||||||
context.beginPath();
|
|
||||||
for (var j = 0; j < shape.length; j += 1) {
|
|
||||||
var point = shape[j % shape.length];
|
|
||||||
|
|
||||||
context.lineTo(point.X * 2, point.Y * 2);
|
|
||||||
}
|
|
||||||
if (this.closed) {
|
|
||||||
context.closePath();
|
|
||||||
}
|
|
||||||
context.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +1,49 @@
|
|||||||
export default class {
|
export default class {
|
||||||
constructor () {
|
constructor(config = {}) {
|
||||||
this.config = {};
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
updateConfig(config) {
|
||||||
updateConfig (config) {
|
this.config = { ...this.config, ...config };
|
||||||
for (var i in config) {
|
|
||||||
this.config[i] = config[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
startCode() {
|
||||||
startCode () {
|
const { startCode } = this.config;
|
||||||
var gcode = this.config["startCode"];
|
const gcode = this._subsituteVariables(startCode);
|
||||||
|
|
||||||
gcode = this._subsituteVariables(gcode);
|
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
endCode() {
|
||||||
endCode () {
|
const { endCode } = this.config;
|
||||||
var gcode = this.config["endCode"];
|
const gcode = this._subsituteVariables(endCode);
|
||||||
|
|
||||||
gcode = this._subsituteVariables(gcode);
|
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
_subsituteVariables(gcode) {
|
||||||
|
let {
|
||||||
|
temperature,
|
||||||
|
bedTemperature,
|
||||||
|
heatTemperature,
|
||||||
|
heatBedTemperature,
|
||||||
|
travelSpeed,
|
||||||
|
printerType,
|
||||||
|
heatedbed
|
||||||
|
} = this.config;
|
||||||
|
|
||||||
_subsituteVariables (gcode) {
|
travelSpeed *= 60;
|
||||||
var temperature = this.config["temperature"];
|
|
||||||
var bedTemperature = this.config["bedTemperature"];
|
|
||||||
var preheatTemperature = this.config["heatupTemperature"];
|
|
||||||
var preheatBedTemperature = this.config["heatupBedTemperature"];
|
|
||||||
var travelSpeed = this.config["travelSpeed"] * 60;
|
|
||||||
var printerType = this.config["type"];
|
|
||||||
var heatedbed = this.config["heatedbed"];
|
|
||||||
|
|
||||||
switch (printerType) {
|
switch (printerType) {
|
||||||
case "makerbot_replicator2": printerType = "r2"; break;
|
case 'makerbot_replicator2': printerType = 'r2'; break;
|
||||||
case "makerbot_replicator2x": printerType = "r2x"; break;
|
case 'makerbot_replicator2x': printerType = 'r2x'; break;
|
||||||
case "makerbot_thingomatic": printerType = "t6"; break;
|
case 'makerbot_thingomatic': printerType = 't6'; break;
|
||||||
case "makerbot_generic": printerType = "r2"; break;
|
case 'makerbot_generic': printerType = 'r2'; break;
|
||||||
case "_3Dison_plus": printerType = "r2"; break;
|
case '_3Dison_plus': printerType = 'r2'; break;
|
||||||
}
|
}
|
||||||
var heatedBedReplacement = heatedbed ? "" : ";";
|
|
||||||
|
const heatedBedReplacement = heatedbed ? '' : ';';
|
||||||
|
|
||||||
gcode = gcode.replace(/{printingTemp}/gi, temperature);
|
gcode = gcode.replace(/{printingTemp}/gi, temperature);
|
||||||
gcode = gcode.replace(/{printingBedTemp}/gi, bedTemperature);
|
gcode = gcode.replace(/{printingBedTemp}/gi, bedTemperature);
|
||||||
gcode = gcode.replace(/{preheatTemp}/gi, preheatTemperature);
|
gcode = gcode.replace(/{preheatTemp}/gi, heatTemperature);
|
||||||
gcode = gcode.replace(/{preheatBedTemp}/gi, preheatBedTemperature);
|
gcode = gcode.replace(/{preheatBedTemp}/gi, heatBedTemperature);
|
||||||
gcode = gcode.replace(/{printerType}/gi, printerType);
|
gcode = gcode.replace(/{printerType}/gi, printerType);
|
||||||
gcode = gcode.replace(/{travelSpeed}/gi, travelSpeed);
|
gcode = gcode.replace(/{travelSpeed}/gi, travelSpeed);
|
||||||
gcode = gcode.replace(/{if heatedBed}/gi, heatedBedReplacement);
|
gcode = gcode.replace(/{if heatedBed}/gi, heatedBedReplacement);
|
||||||
|
131
src/slice.js
131
src/slice.js
@ -1,134 +1,31 @@
|
|||||||
import Paths from './paths.js';
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
constructor () {
|
constructor() {
|
||||||
this.parts = [];
|
this.parts = [];
|
||||||
}
|
}
|
||||||
|
getOutline() {
|
||||||
|
const outLines = new Shape([], true);
|
||||||
|
|
||||||
removeSelfIntersect () {
|
for (let i = 0; i < this.parts.length; i ++) {
|
||||||
for (var i = 0; i < this.parts.length; i ++) {
|
const part = this.parts[i];
|
||||||
var part1 = this.parts[i].intersect;
|
|
||||||
|
|
||||||
if (!part1.closed) {
|
if (part.shape.closed) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var j = i + 1; j < this.parts.length; j ++) {
|
|
||||||
var part2 = this.parts[j].intersect;
|
|
||||||
|
|
||||||
if (!part2.closed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part2.intersect(part1).length > 0) {
|
|
||||||
part1 = this.parts[i].intersect = part1.union(part2);
|
|
||||||
|
|
||||||
this.parts.splice(j, 1);
|
|
||||||
j --;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
optimizePaths (start) {
|
|
||||||
if (this.brim !== undefined && this.brim.length > 0) {
|
|
||||||
this.brim = this.brim.optimizePath(start);
|
|
||||||
start = this.brim.lastPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
var parts = [];
|
|
||||||
|
|
||||||
while (this.parts.length > 0) {
|
|
||||||
|
|
||||||
var closestDistance = Infinity;
|
|
||||||
var closestPart;
|
|
||||||
|
|
||||||
for (var i = 0; i < this.parts.length; i ++) {
|
|
||||||
var part = this.parts[i];
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
var bounds = part.outerLine.bounds();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var bounds = part.intersect.bounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
var top = bounds.top - start.y;
|
|
||||||
var bottom = start.y - bounds.bottom;
|
|
||||||
var left = bounds.left - start.x;
|
|
||||||
var right = start.x - bounds.right;
|
|
||||||
|
|
||||||
var distance = Math.max(top, bottom, left, right);
|
|
||||||
|
|
||||||
if (distance < closestDistance) {
|
|
||||||
closestDistance = distance;
|
|
||||||
closestPart = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = this.parts.splice(closestPart, 1)[0];
|
|
||||||
parts.push(part);
|
|
||||||
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
if (part.outerLine.length > 0) {
|
|
||||||
part.outerLine = part.outerLine.optimizePath(start);
|
|
||||||
start = part.outerLine.lastPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
||||||
var innerLine = part.innerLines[j];
|
|
||||||
if (innerLine.length > 0) {
|
|
||||||
part.innerLines[j] = innerLine.optimizePath(start);
|
|
||||||
start = part.innerLines[j].lastPoint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part.fill.length > 0) {
|
|
||||||
part.fill = part.fill.optimizePath(start);
|
|
||||||
start = part.fill.lastPoint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
part.intersect.optimizePath(start);
|
|
||||||
start = part.intersect.lastPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parts = parts;
|
|
||||||
|
|
||||||
if (this.support !== undefined && this.support.length > 0) {
|
|
||||||
this.support = this.support.optimizePath(start);
|
|
||||||
start = this.support.lastPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOutline () {
|
|
||||||
var outLines = new Paths([], true);
|
|
||||||
|
|
||||||
for (var i = 0; i < this.parts.length; i ++) {
|
|
||||||
var part = this.parts[i];
|
|
||||||
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
outLines.join(this.parts[i].outerLine);
|
outLines.join(this.parts[i].outerLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return outLines;
|
return outLines;
|
||||||
}
|
}
|
||||||
|
add(shape) {
|
||||||
|
const part = { shape };
|
||||||
|
|
||||||
add (intersect) {
|
if (shape.closed) {
|
||||||
var parts = {
|
part.innerLines = [];
|
||||||
intersect
|
part.outerLine = new Shape([], true);
|
||||||
};
|
part.fill = new Shape([], false);
|
||||||
|
|
||||||
if (intersect.closed) {
|
|
||||||
parts.innerLines = [];
|
|
||||||
parts.outerLine = new Paths([], true);
|
|
||||||
parts.fill = new Paths([], false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parts.push(parts);
|
this.parts.push(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
19
src/sliceActions/addBrim.js
Normal file
19
src/sliceActions/addBrim.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
import { PRECISION } from '../constants.js';
|
||||||
|
|
||||||
|
const offsetOptions = {
|
||||||
|
jointType: 'jtSquare',
|
||||||
|
endType: 'etClosedPolygon',
|
||||||
|
miterLimit: 2.0,
|
||||||
|
roundPrecision: 0.25
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function addBrim(slices, settings) {
|
||||||
|
console.log('add brim');
|
||||||
|
|
||||||
|
let { brimOffset } = settings.config;
|
||||||
|
brimOffset /= PRECISION;
|
||||||
|
|
||||||
|
const fistLayer = slices[0];
|
||||||
|
fistLayer.brim = fistLayer.getOutline().offset(brimOffset, offsetOptions);
|
||||||
|
}
|
22
src/sliceActions/applyPrecision.js
Normal file
22
src/sliceActions/applyPrecision.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { PRECISION } from '../constants.js'
|
||||||
|
|
||||||
|
export default function applyPrecision(shapes) {
|
||||||
|
for (let i = 0; i < shapes.length; i ++) {
|
||||||
|
const { closedShapes, openShapes } = shapes[i];
|
||||||
|
|
||||||
|
scaleUpShape(closedShapes);
|
||||||
|
scaleUpShape(openShapes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scaleUpShape(shape) {
|
||||||
|
for (let i = 0; i < shape.length; i ++) {
|
||||||
|
const path = shape[i];
|
||||||
|
|
||||||
|
for (let i = 0; i < path.length; i ++) {
|
||||||
|
const point = path[i];
|
||||||
|
|
||||||
|
point.copy(point.divideScalar(PRECISION));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/sliceActions/calculateLayersIntersections.js
Normal file
47
src/sliceActions/calculateLayersIntersections.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
|
||||||
|
export default function calculateLayersIntersections(lines, settings) {
|
||||||
|
console.log('calculating layer intersections');
|
||||||
|
|
||||||
|
const { layerHeight, dimensionsZ } = settings.config;
|
||||||
|
|
||||||
|
const numLayers = Math.floor(dimensionsZ / layerHeight);
|
||||||
|
|
||||||
|
const layerIntersectionIndexes = [];
|
||||||
|
const layerIntersectionPoints = [];
|
||||||
|
for (let layer = 0; layer < numLayers; layer ++) {
|
||||||
|
layerIntersectionIndexes[layer] = [];
|
||||||
|
layerIntersectionPoints[layer] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
||||||
|
const line = lines[lineIndex].line;
|
||||||
|
|
||||||
|
const min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
|
||||||
|
const max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
|
||||||
|
|
||||||
|
for (let layerIndex = min; layerIndex <= max; layerIndex ++) {
|
||||||
|
if (layerIndex >= 0 && layerIndex < numLayers) {
|
||||||
|
|
||||||
|
layerIntersectionIndexes[layerIndex].push(lineIndex);
|
||||||
|
|
||||||
|
const y = layerIndex * layerHeight;
|
||||||
|
let x, z;
|
||||||
|
|
||||||
|
if (line.start.y === line.end.y) {
|
||||||
|
x = line.start.x;
|
||||||
|
z = line.start.z;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const alpha = (y - line.start.y) / (line.end.y - line.start.y);
|
||||||
|
x = line.end.x * alpha + line.start.x * (1 - alpha);
|
||||||
|
z = line.end.z * alpha + line.start.z * (1 - alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
layerIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { layerIntersectionIndexes, layerIntersectionPoints };
|
||||||
|
}
|
49
src/sliceActions/createLines.js
Normal file
49
src/sliceActions/createLines.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
|
||||||
|
function addLine(geometry, lineLookup, lines, a, b) {
|
||||||
|
const index = lines.length;
|
||||||
|
lineLookup[`${a}_${b}`] = index;
|
||||||
|
|
||||||
|
lines.push({
|
||||||
|
line: new THREE.Line3(geometry.vertices[a], geometry.vertices[b]),
|
||||||
|
connects: [],
|
||||||
|
normals: []
|
||||||
|
});
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function createLines(geometry, settings) {
|
||||||
|
console.log('constructing unique lines from geometry');
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
const lineLookup = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < geometry.faces.length; i ++) {
|
||||||
|
const face = geometry.faces[i];
|
||||||
|
if (face.normal.y !== 1 && face.normal.y !== -1) {
|
||||||
|
const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
|
||||||
|
|
||||||
|
const lookupA = lineLookup[`${face.b}_${face.a}`];
|
||||||
|
const lookupB = lineLookup[`${face.c}_${face.b}`];
|
||||||
|
const lookupC = lineLookup[`${face.a}_${face.c}`];
|
||||||
|
|
||||||
|
// only add unique lines
|
||||||
|
// returns index of said line
|
||||||
|
const indexA = lookupA !== undefined ? lookupA : addLine(geometry, lineLookup, lines, face.a, face.b);
|
||||||
|
const indexB = lookupB !== undefined ? lookupB : addLine(geometry, lineLookup, lines, face.b, face.c);
|
||||||
|
const indexC = lookupC !== undefined ? lookupC : addLine(geometry, lineLookup, lines, face.c, face.a);
|
||||||
|
|
||||||
|
// set connecting lines (based on face)
|
||||||
|
lines[indexA].connects.push(indexB, indexC);
|
||||||
|
lines[indexB].connects.push(indexC, indexA);
|
||||||
|
lines[indexC].connects.push(indexA, indexB);
|
||||||
|
|
||||||
|
lines[indexA].normals.push(normal);
|
||||||
|
lines[indexB].normals.push(normal);
|
||||||
|
lines[indexC].normals.push(normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
81
src/sliceActions/generateInfills.js
Normal file
81
src/sliceActions/generateInfills.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { PRECISION } from '../constants.js'
|
||||||
|
import getFillTemplate from '../getFillTemplate.js';
|
||||||
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
|
||||||
|
export default function generateInfills(slices, settings) {
|
||||||
|
console.log('generating infills');
|
||||||
|
|
||||||
|
let {
|
||||||
|
layerHeight,
|
||||||
|
fillGridSize,
|
||||||
|
bottomThickness,
|
||||||
|
topThickness,
|
||||||
|
nozzleDiameter,
|
||||||
|
infillOverlap
|
||||||
|
} = settings.config;
|
||||||
|
|
||||||
|
fillGridSize /= PRECISION;
|
||||||
|
nozzleDiameter /= PRECISION;
|
||||||
|
infillOverlap /= PRECISION;
|
||||||
|
|
||||||
|
const bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
|
||||||
|
const topSkinCount = Math.ceil(topThickness/layerHeight);
|
||||||
|
const nozzleRadius = nozzleDiameter / 2;
|
||||||
|
const hightemplateSize = Math.sqrt(2 * Math.pow(nozzleDiameter, 2));
|
||||||
|
|
||||||
|
for (let layer = 0; layer < slices.length; layer ++) {
|
||||||
|
const slice = slices[layer];
|
||||||
|
|
||||||
|
let surroundingLayer;
|
||||||
|
if (layer - bottomSkinCount >= 0 && layer + topSkinCount < slices.length) {
|
||||||
|
const downSkin = slices[layer - bottomSkinCount].getOutline();
|
||||||
|
const upSkin = slices[layer + topSkinCount].getOutline();
|
||||||
|
surroundingLayer = upSkin.intersect(downSkin);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < slice.parts.length; i ++) {
|
||||||
|
const part = slice.parts[i];
|
||||||
|
|
||||||
|
if (!part.shape.closed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const outerLine = part.outerLine;
|
||||||
|
|
||||||
|
if (outerLine.paths.length > 0) {
|
||||||
|
const inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
|
||||||
|
|
||||||
|
const fillArea = inset.offset(-nozzleRadius);
|
||||||
|
let lowFillArea;
|
||||||
|
let highFillArea;
|
||||||
|
if (surroundingLayer) {
|
||||||
|
highFillArea = fillArea.difference(surroundingLayer);
|
||||||
|
|
||||||
|
if (infillOverlap > 0) {
|
||||||
|
highFillArea = highFillArea.offset(infillOverlap);
|
||||||
|
}
|
||||||
|
|
||||||
|
highFillArea = highFillArea.intersect(fillArea);
|
||||||
|
lowFillArea = fillArea.difference(highFillArea);
|
||||||
|
} else {
|
||||||
|
highFillArea = fillArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowFillArea && lowFillArea.paths.length > 0) {
|
||||||
|
const bounds = lowFillArea.shapeBounds();
|
||||||
|
const lowFillTemplate = getFillTemplate(bounds, fillGridSize, true, true);
|
||||||
|
|
||||||
|
part.fill.join(lowFillTemplate.intersect(lowFillArea));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highFillArea.paths.length > 0) {
|
||||||
|
const bounds = highFillArea.shapeBounds();
|
||||||
|
const even = (layer % 2 === 0);
|
||||||
|
const highFillTemplate = getFillTemplate(bounds, hightemplateSize, even, !even);
|
||||||
|
|
||||||
|
part.fill.join(highFillTemplate.intersect(highFillArea));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/sliceActions/generateInnerLines.js
Normal file
48
src/sliceActions/generateInnerLines.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { PRECISION } from '../constants.js'
|
||||||
|
|
||||||
|
const offsetOptions = {
|
||||||
|
jointType: 'jtSquare',
|
||||||
|
endType: 'etClosedPolygon',
|
||||||
|
miterLimit: 2.0,
|
||||||
|
roundPrecision: 0.25
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function generateInnerLines(slices, settings) {
|
||||||
|
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 /= PRECISION;
|
||||||
|
shellThickness /= PRECISION;
|
||||||
|
const nozzleRadius = nozzleDiameter / 2;
|
||||||
|
const shells = Math.round(shellThickness / nozzleDiameter);
|
||||||
|
|
||||||
|
for (let layer = 0; layer < slices.length; layer ++) {
|
||||||
|
const slice = slices[layer];
|
||||||
|
|
||||||
|
for (let i = 0; i < slice.parts.length; i ++) {
|
||||||
|
const part = slice.parts[i];
|
||||||
|
|
||||||
|
if (!part.shape.closed) continue;
|
||||||
|
|
||||||
|
const outerLine = part.shape.offset(-nozzleRadius, offsetOptions);
|
||||||
|
|
||||||
|
if (outerLine.paths.length > 0) {
|
||||||
|
part.outerLine.join(outerLine);
|
||||||
|
|
||||||
|
for (let shell = 1; shell < shells; shell += 1) {
|
||||||
|
const offset = shell * nozzleDiameter;
|
||||||
|
|
||||||
|
const innerLine = outerLine.offset(-offset, offsetOptions);
|
||||||
|
|
||||||
|
if (innerLine.paths.length > 0) {
|
||||||
|
part.innerLines.push(innerLine);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/sliceActions/generateSupport.js
Normal file
77
src/sliceActions/generateSupport.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import getFillTemplate from '../getFillTemplate.js';
|
||||||
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
import { PRECISION } from '../constants.js';
|
||||||
|
|
||||||
|
export default function generateSupport(slices, settings) {
|
||||||
|
console.log('generating support');
|
||||||
|
|
||||||
|
if (!settings.config.supportEnabled) return;
|
||||||
|
|
||||||
|
let {
|
||||||
|
layerHeight,
|
||||||
|
supportGridSize,
|
||||||
|
supportAcceptanceMargin,
|
||||||
|
supportPlateSize: plateSize,
|
||||||
|
supportDistanceY,
|
||||||
|
nozzleDiameter
|
||||||
|
} = settings.config;
|
||||||
|
|
||||||
|
supportGridSize /= PRECISION;
|
||||||
|
supportMargin /= PRECISION;
|
||||||
|
plateSize /= PRECISION;
|
||||||
|
nozzleDiameter /= PRECISION;
|
||||||
|
var supportDistanceLayers = Math.max(Math.ceil(supportDistanceY / layerHeight), 1);
|
||||||
|
|
||||||
|
var supportAreas = new Shape([], true);
|
||||||
|
|
||||||
|
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
|
||||||
|
var currentSlice = slices[layer];
|
||||||
|
|
||||||
|
if (supportAreas.length > 0) {
|
||||||
|
|
||||||
|
if (layer >= supportDistanceLayers) {
|
||||||
|
var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
|
||||||
|
sliceSkin = sliceSkin;
|
||||||
|
|
||||||
|
var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin));
|
||||||
|
if (supportAreasSlimmed.area() < 100.0) {
|
||||||
|
supportAreas = supportAreas.difference(sliceSkin);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
supportAreas = supportAreasSlimmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var supportTemplate = getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
|
||||||
|
var supportFill = supportTemplate.intersect(supportAreas);
|
||||||
|
if (supportFill.length === 0) {
|
||||||
|
currentSlice.support = supportAreas.clone();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentSlice.support = supportFill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
|
||||||
|
|
||||||
|
var slice = slices[layer + supportDistanceLayers];
|
||||||
|
for (var i = 0; i < slice.parts.length; i ++) {
|
||||||
|
var slicePart = slice.parts[i];
|
||||||
|
|
||||||
|
if (slicePart.intersect.closed) {
|
||||||
|
var outerLine = slicePart.outerLine;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var outerLine = slicePart.intersect.offset(supportAcceptanceMargin);
|
||||||
|
}
|
||||||
|
|
||||||
|
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
|
||||||
|
var overhang = outerLine.difference(overlap);
|
||||||
|
|
||||||
|
if (overlap.length === 0 || overhang.length > 0) {
|
||||||
|
supportAreas = supportAreas.join(overhang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
src/sliceActions/intersectionsToShapes.js
Normal file
121
src/sliceActions/intersectionsToShapes.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
|
||||||
|
export default function intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings) {
|
||||||
|
console.log('generating slices');
|
||||||
|
|
||||||
|
const layers = [];
|
||||||
|
|
||||||
|
for (let layer = 1; layer < layerIntersectionIndexes.length; layer ++) {
|
||||||
|
const intersectionIndexes = layerIntersectionIndexes[layer];
|
||||||
|
const intersectionPoints = layerIntersectionPoints[layer];
|
||||||
|
|
||||||
|
if (intersectionIndexes.length === 0) continue;
|
||||||
|
|
||||||
|
const closedShapes = [];
|
||||||
|
const openShapes = [];
|
||||||
|
for (let i = 0; i < intersectionIndexes.length; i ++) {
|
||||||
|
let index = intersectionIndexes[i];
|
||||||
|
|
||||||
|
if (intersectionPoints[index] === undefined) continue;
|
||||||
|
|
||||||
|
const shape = [];
|
||||||
|
|
||||||
|
const firstPoints = [index];
|
||||||
|
let isFirstPoint = true;
|
||||||
|
let closed = false;
|
||||||
|
|
||||||
|
while (index !== -1) {
|
||||||
|
const intersection = intersectionPoints[index];
|
||||||
|
// uppercase X and Y because clipper vector
|
||||||
|
shape.push(intersection);
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
|
||||||
|
const connects = lines[index].connects;
|
||||||
|
const faceNormals = lines[index].normals;
|
||||||
|
|
||||||
|
for (let i = 0; i < connects.length; i ++) {
|
||||||
|
index = connects[i];
|
||||||
|
|
||||||
|
if (firstPoints.indexOf(index) !== -1 && shape.length > 2) {
|
||||||
|
closed = true;
|
||||||
|
index = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if index has an intersection or is already used
|
||||||
|
if (intersectionPoints[index] !== undefined) {
|
||||||
|
const faceNormal = faceNormals[Math.floor(i / 2)];
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (isFirstPoint) {
|
||||||
|
firstPoints.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
|
||||||
|
connects.push(...lines[index].connects);
|
||||||
|
faceNormals.push(...lines[index].normals);
|
||||||
|
index = -1;
|
||||||
|
} else {
|
||||||
|
// make sure the path goes the right direction
|
||||||
|
// THREE.Vector2.normal is not yet implimented
|
||||||
|
// 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 {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isFirstPoint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closed) {
|
||||||
|
index = firstPoints[0];
|
||||||
|
|
||||||
|
while (index !== -1) {
|
||||||
|
if (firstPoints.indexOf(index) === -1) {
|
||||||
|
const intersection = intersectionPoints[index];
|
||||||
|
shape.unshift(intersection);
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const connects = lines[index].connects;
|
||||||
|
|
||||||
|
for (let i = 0; i < connects.length; i ++) {
|
||||||
|
index = connects[i];
|
||||||
|
|
||||||
|
if (intersectionPoints[index] !== undefined) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
closedShapes.push(shape);
|
||||||
|
} else {
|
||||||
|
openShapes.push(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layers.push({ closedShapes, openShapes });
|
||||||
|
}
|
||||||
|
|
||||||
|
return layers;
|
||||||
|
}
|
152
src/sliceActions/optimizePaths.js
Normal file
152
src/sliceActions/optimizePaths.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
import Shape from 'Doodle3D/clipper-js';
|
||||||
|
|
||||||
|
export default function optimizePaths(slices, settings) {
|
||||||
|
console.log('optimize paths');
|
||||||
|
|
||||||
|
const start = new THREE.Vector2(0, 0);
|
||||||
|
|
||||||
|
for (let layer = 0; layer < slices.length; layer ++) {
|
||||||
|
const slice = slices[layer];
|
||||||
|
|
||||||
|
if (slice.brim !== undefined && slice.brim.paths.length > 0) {
|
||||||
|
slice.brim = optimizeShape(slice.brim, start);
|
||||||
|
start.copy(slice.brim.lastPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = [];
|
||||||
|
|
||||||
|
while (slice.parts.length > 0) {
|
||||||
|
let closestDistance = Infinity;
|
||||||
|
let closestPart;
|
||||||
|
|
||||||
|
for (let i = 0; i < slice.parts.length; i ++) {
|
||||||
|
const part = slice.parts[i];
|
||||||
|
|
||||||
|
let bounds;
|
||||||
|
if (part.shape.closed) {
|
||||||
|
bounds = part.outerLine.shapeBounds();
|
||||||
|
} else {
|
||||||
|
bounds = part.shape.shapeBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
const top = bounds.top - start.y;
|
||||||
|
const bottom = start.y - bounds.bottom;
|
||||||
|
const left = bounds.left - start.x;
|
||||||
|
const right = start.x - bounds.right;
|
||||||
|
|
||||||
|
const distance = Math.max(top, bottom, left, right);
|
||||||
|
|
||||||
|
if (distance < closestDistance) {
|
||||||
|
closestDistance = distance;
|
||||||
|
closestPart = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const part = slice.parts.splice(closestPart, 1)[0];
|
||||||
|
parts.push(part);
|
||||||
|
|
||||||
|
if (part.shape.closed) {
|
||||||
|
if (part.outerLine.paths.length > 0) {
|
||||||
|
part.outerLine = optimizeShape(part.outerLine, start);
|
||||||
|
start.copy(part.outerLine.lastPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < part.innerLines.length; i ++) {
|
||||||
|
const innerLine = part.innerLines[i];
|
||||||
|
|
||||||
|
if (innerLine.paths.length > 0) {
|
||||||
|
part.innerLines[i] = optimizeShape(innerLine, start);
|
||||||
|
start.copy(part.innerLines[i].lastPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.fill.paths.length > 0) {
|
||||||
|
part.fill = optimizeShape(part.fill, start);
|
||||||
|
start.copy(part.fill.lastPoint());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
part.shape = optimizeShape(part.shape, start);
|
||||||
|
start.copy(part.shape.lastPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice.parts = parts;
|
||||||
|
|
||||||
|
if (slice.support !== undefined && slice.support.length > 0) {
|
||||||
|
slice.support = optimizeShape(slice.support, start);
|
||||||
|
start.copy(slice.support.lastPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optimizeShape(shape, start) {
|
||||||
|
start = start.clone();
|
||||||
|
|
||||||
|
const inputPaths = shape.mapToLower();
|
||||||
|
const optimizedPaths = [];
|
||||||
|
const donePaths = [];
|
||||||
|
|
||||||
|
while (optimizedPaths.length !== inputPaths.length) {
|
||||||
|
let minLength = false;
|
||||||
|
let reverse;
|
||||||
|
let minPath;
|
||||||
|
let offset;
|
||||||
|
let pathIndex;
|
||||||
|
|
||||||
|
for (let i = 0; i < inputPaths.length; i ++) {
|
||||||
|
if (donePaths.indexOf(i) !== -1) continue;
|
||||||
|
|
||||||
|
const path = inputPaths[i];
|
||||||
|
|
||||||
|
if (shape.closed) {
|
||||||
|
for (let j = 0; j < path.length; j += 1) {
|
||||||
|
const point = new THREE.Vector2().copy(path[j]);
|
||||||
|
const length = point.sub(start).length();
|
||||||
|
if (minLength === false || length < minLength) {
|
||||||
|
minPath = path;
|
||||||
|
minLength = length;
|
||||||
|
offset = j;
|
||||||
|
pathIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const startPoint = new THREE.Vector2().copy(path[0]);
|
||||||
|
const lengthToStart = startPoint.sub(start).length();
|
||||||
|
if (minLength === false || lengthToStart < minLength) {
|
||||||
|
minPath = path;
|
||||||
|
minLength = lengthToStart;
|
||||||
|
reverse = false;
|
||||||
|
pathIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
const endPoint = new THREE.Vector2().copy(path[path.length - 1]);
|
||||||
|
const lengthToEnd = endPoint.sub(start).length();
|
||||||
|
if (lengthToEnd < minLength) {
|
||||||
|
minPath = path;
|
||||||
|
minLength = lengthToEnd;
|
||||||
|
reverse = true;
|
||||||
|
pathIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let point;
|
||||||
|
if (shape.closed) {
|
||||||
|
minPath = minPath.concat(minPath.splice(0, offset));
|
||||||
|
point = minPath[0];
|
||||||
|
} else {
|
||||||
|
if (reverse) {
|
||||||
|
minPath.reverse();
|
||||||
|
}
|
||||||
|
point = minPath[minPath.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
donePaths.push(pathIndex);
|
||||||
|
start.copy(point);
|
||||||
|
|
||||||
|
optimizedPaths.push(minPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Shape(optimizedPaths, shape.closed, true);
|
||||||
|
}
|
32
src/sliceActions/removePrecision.js
Normal file
32
src/sliceActions/removePrecision.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
import { PRECISION } from '../constants.js';
|
||||||
|
|
||||||
|
export default function removePrecision(slices) {
|
||||||
|
console.log('remove precision');
|
||||||
|
|
||||||
|
const start = new THREE.Vector2(0, 0);
|
||||||
|
|
||||||
|
for (let layer = 0; layer < slices.length; layer ++) {
|
||||||
|
const slice = slices[layer];
|
||||||
|
|
||||||
|
for (let i = 0; i < slice.parts.length; i ++) {
|
||||||
|
const part = slice.parts[i];
|
||||||
|
|
||||||
|
if (part.shape.closed) {
|
||||||
|
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(1 / PRECISION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.support !== undefined) {
|
||||||
|
slice.support.scaleDown(1 / PRECISION);
|
||||||
|
}
|
||||||
|
if (slice.brim !== undefined) {
|
||||||
|
slice.brim.scaleDown(1 / PRECISION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/sliceActions/shapesToSlices.js
Normal file
40
src/sliceActions/shapesToSlices.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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 (let layer = 0; layer < shapes.length; layer ++) {
|
||||||
|
let { closedShapes, openShapes } = shapes[layer];
|
||||||
|
|
||||||
|
closedShapes = new Shape(closedShapes, true, true)
|
||||||
|
.clean(CLEAN_DELTA)
|
||||||
|
.fixOrientation()
|
||||||
|
.removeOverlap()
|
||||||
|
.seperateShapes();
|
||||||
|
|
||||||
|
openShapes = new Shape(openShapes, false, true)
|
||||||
|
.clean(CLEAN_DELTA);
|
||||||
|
|
||||||
|
const slice = new Slice();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceLayers.push(slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sliceLayers;
|
||||||
|
}
|
71
src/sliceActions/slicesToGCode.js
Normal file
71
src/sliceActions/slicesToGCode.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import GCode from '../gcode.js';
|
||||||
|
|
||||||
|
export default function slicesToGCode(slices, settings) {
|
||||||
|
console.log('slices to gcode');
|
||||||
|
|
||||||
|
const gcode = new GCode(settings);
|
||||||
|
|
||||||
|
for (let layer = 0; layer < slices.length; layer ++) {
|
||||||
|
const slice = slices[layer];
|
||||||
|
|
||||||
|
if (layer === 1) {
|
||||||
|
gcode.turnFanOn();
|
||||||
|
gcode.bottom = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.brim !== undefined) {
|
||||||
|
pathToGCode(gcode, slice.brim, true, true, layer, 'brim');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < slice.parts.length; i ++) {
|
||||||
|
const part = slice.parts[i];
|
||||||
|
|
||||||
|
if (part.shape.closed) {
|
||||||
|
pathToGCode(gcode, part.outerLine, false, true, layer, 'outerLine');
|
||||||
|
|
||||||
|
for (let i = 0; i < part.innerLines.length; i ++) {
|
||||||
|
const innerLine = part.innerLines[i];
|
||||||
|
pathToGCode(gcode, innerLine, false, false, layer, 'innerLine');
|
||||||
|
}
|
||||||
|
|
||||||
|
pathToGCode(gcode, part.fill, true, false, layer, 'fill');
|
||||||
|
} else {
|
||||||
|
const retract = !(slice.parts.length === 1 && slice.support === undefined);
|
||||||
|
pathToGCode(gcode, part.shape, retract, retract, layer, 'outerLine');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.support !== undefined) {
|
||||||
|
pathToGCode(gcode, slice.support, true, true, layer, 'support');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gcode.getGCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathToGCode(gcode, shape, retract, unRetract, layer, type) {
|
||||||
|
for (let i = 0; i < shape.paths.length; i ++) {
|
||||||
|
const line = shape.paths[i];
|
||||||
|
|
||||||
|
const length = shape.closed ? (line.length + 1) : line.length;
|
||||||
|
for (let i = 0; i < length; i ++) {
|
||||||
|
const point = line[i % line.length];
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
// TODO
|
||||||
|
// moveTo should impliment combing
|
||||||
|
gcode.moveTo(point.X, point.Y, layer);
|
||||||
|
|
||||||
|
if (unRetract) {
|
||||||
|
gcode.unRetract();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gcode.lineTo(point.X, point.Y, layer, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retract) {
|
||||||
|
gcode.retract();
|
||||||
|
}
|
||||||
|
}
|
760
src/slicer.js
760
src/slicer.js
@ -1,41 +1,33 @@
|
|||||||
import THREE from 'three.js';
|
import THREE from 'three.js';
|
||||||
import Paths from './paths.js';
|
import EventDispatcher from 'casperlamboo/EventDispatcher';
|
||||||
import Slice from './slice.js';
|
import calculateLayersIntersections from './sliceActions/calculateLayersIntersections.js';
|
||||||
import GCode from './gcode.js';
|
import createLines from './sliceActions/createLines.js';
|
||||||
|
import generateInfills from './sliceActions/generateInfills.js';
|
||||||
|
import generateInnerLines from './sliceActions/generateInnerLines.js';
|
||||||
|
import generateSupport from './sliceActions/generateSupport.js';
|
||||||
|
import intersectionsToShapes from './sliceActions/intersectionsToShapes.js';
|
||||||
|
import addBrim from './sliceActions/addBrim.js';
|
||||||
|
import optimizePaths from './sliceActions/optimizePaths.js';
|
||||||
|
import shapesToSlices from './sliceActions/shapesToSlices.js';
|
||||||
|
import slicesToGCode from './sliceActions/slicesToGCode.js';
|
||||||
|
import applyPrecision from './sliceActions/applyPrecision.js';
|
||||||
|
import removePrecision from './sliceActions/removePrecision.js';
|
||||||
|
|
||||||
export default class {
|
export default class extends EventDispatcher {
|
||||||
constructor () {
|
setMesh(mesh) {
|
||||||
this.progress = {
|
|
||||||
createdLines: false,
|
|
||||||
calculatedLayerIntersections: false,
|
|
||||||
sliced: false,
|
|
||||||
generatedSlices: false,
|
|
||||||
generatedInnerLines: false,
|
|
||||||
generatedInfills: false,
|
|
||||||
generatedSupport: false,
|
|
||||||
optimizedPaths: false,
|
|
||||||
generatedGCode: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setMesh (mesh) {
|
|
||||||
mesh.updateMatrix();
|
mesh.updateMatrix();
|
||||||
|
|
||||||
this.setGeometry(mesh.geometry, mesh.matrix);
|
this.setGeometry(mesh.geometry, mesh.matrix);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
setGeometry(geometry, matrix) {
|
||||||
setGeometry (geometry, matrix) {
|
if (geometry instanceof THREE.BufferGeometry) {
|
||||||
if (geometry.type === 'BufferGeometry') {
|
|
||||||
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
|
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
|
||||||
}
|
} else if (geometry instanceof THREE.Geometry) {
|
||||||
else if (geometry.type.endsWith('Geometry')) {
|
|
||||||
geometry = geometry.clone();
|
geometry = geometry.clone();
|
||||||
}
|
} else {
|
||||||
else {
|
throw 'Geometry is not an instance of BufferGeometry or Geometry';
|
||||||
console.warn('Geometry is not an instance of BufferGeometry or Geometry');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matrix instanceof THREE.Matrix4) {
|
if (matrix instanceof THREE.Matrix4) {
|
||||||
@ -49,711 +41,31 @@ export default class {
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
slice(settings) {
|
||||||
slice (settings) {
|
|
||||||
var supportEnabled = settings.config['supportEnabled'];
|
|
||||||
|
|
||||||
// get unique lines from geometry;
|
// get unique lines from geometry;
|
||||||
var lines = this._createLines(settings);
|
const lines = createLines(this.geometry, settings);
|
||||||
|
|
||||||
var {layerIntersectionIndexes, layerIntersectionPoints} = this._calculateLayersIntersections(lines, settings);
|
const {
|
||||||
|
|
||||||
var shapes = this._intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
|
|
||||||
|
|
||||||
var slices = this._shapesToSlices(shapes, settings);
|
|
||||||
|
|
||||||
this._generateInnerLines(slices, settings);
|
|
||||||
|
|
||||||
this._generateInfills(slices, settings);
|
|
||||||
|
|
||||||
if (supportEnabled) {
|
|
||||||
this._generateSupport(slices, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._optimizePaths(slices, settings);
|
|
||||||
|
|
||||||
var gcode = this._slicesToGCode(slices, settings);
|
|
||||||
|
|
||||||
if (this.onfinish !== undefined) {
|
|
||||||
this.onfinish(gcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return gcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
_createLines (settings) {
|
|
||||||
console.log('constructing unique lines from geometry');
|
|
||||||
|
|
||||||
var lines = [];
|
|
||||||
var lineLookup = {};
|
|
||||||
|
|
||||||
var addLine = (a, b) => {
|
|
||||||
var index = lineLookup[b + '_' + a];
|
|
||||||
|
|
||||||
if (index === undefined) {
|
|
||||||
index = lines.length;
|
|
||||||
lineLookup[a + '_' + b] = index;
|
|
||||||
|
|
||||||
lines.push({
|
|
||||||
line: new THREE.Line3(this.geometry.vertices[a], this.geometry.vertices[b]),
|
|
||||||
connects: [],
|
|
||||||
normals: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < this.geometry.faces.length; i ++) {
|
|
||||||
var face = this.geometry.faces[i];
|
|
||||||
if (face.normal.y !== 1 && face.normal.y !== -1) {
|
|
||||||
var normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
|
|
||||||
|
|
||||||
// check for only adding unique lines
|
|
||||||
// returns index of said line
|
|
||||||
var a = addLine(face.a, face.b);
|
|
||||||
var b = addLine(face.b, face.c);
|
|
||||||
var c = addLine(face.c, face.a);
|
|
||||||
|
|
||||||
// set connecting lines (based on face)
|
|
||||||
lines[a].connects.push(b, c);
|
|
||||||
lines[b].connects.push(c, a);
|
|
||||||
lines[c].connects.push(a, b);
|
|
||||||
|
|
||||||
lines[a].normals.push(normal);
|
|
||||||
lines[b].normals.push(normal);
|
|
||||||
lines[c].normals.push(normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.createdLines = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
_calculateLayersIntersections (lines, settings) {
|
|
||||||
console.log('calculating layer intersections');
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var height = settings.config["dimensionsZ"];
|
|
||||||
|
|
||||||
var numLayers = Math.floor(height / layerHeight);
|
|
||||||
|
|
||||||
var layerIntersectionIndexes = [];
|
|
||||||
var layerIntersectionPoints = [];
|
|
||||||
for (var layer = 0; layer < numLayers; layer ++) {
|
|
||||||
layerIntersectionIndexes[layer] = [];
|
|
||||||
layerIntersectionPoints[layer] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
|
||||||
var line = lines[lineIndex].line;
|
|
||||||
|
|
||||||
var min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
|
|
||||||
var max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
|
|
||||||
|
|
||||||
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
|
|
||||||
if (layerIndex >= 0 && layerIndex < numLayers) {
|
|
||||||
|
|
||||||
layerIntersectionIndexes[layerIndex].push(lineIndex);
|
|
||||||
|
|
||||||
var y = layerIndex * layerHeight;
|
|
||||||
|
|
||||||
if (line.start.y === line.end.y) {
|
|
||||||
var x = line.start.x;
|
|
||||||
var z = line.start.z;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
|
|
||||||
var x = line.end.x * alpha + line.start.x * (1 - alpha);
|
|
||||||
var z = line.end.z * alpha + line.start.z * (1 - alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
layerIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.calculatedLayerIntersections = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return {
|
|
||||||
layerIntersectionIndexes,
|
layerIntersectionIndexes,
|
||||||
layerIntersectionPoints
|
layerIntersectionPoints
|
||||||
};
|
} = calculateLayersIntersections(lines, settings);
|
||||||
}
|
|
||||||
|
|
||||||
_intersectionsToShapes (layerIntersectionIndexes, layerIntersectionPoints, lines, settings) {
|
const shapes = intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
|
||||||
console.log("generating slices");
|
|
||||||
|
|
||||||
var shapes = [];
|
applyPrecision(shapes);
|
||||||
|
|
||||||
for (var layer = 1; layer < layerIntersectionIndexes.length; layer ++) {
|
const slices = shapesToSlices(shapes, settings);
|
||||||
var intersectionIndexes = layerIntersectionIndexes[layer];
|
|
||||||
var intersectionPoints = layerIntersectionPoints[layer];
|
|
||||||
|
|
||||||
if (intersectionIndexes.length === 0) {
|
generateInnerLines(slices, settings);
|
||||||
continue;
|
generateInfills(slices, settings);
|
||||||
}
|
generateSupport(slices, settings);
|
||||||
|
addBrim(slices, settings);
|
||||||
|
optimizePaths(slices, settings);
|
||||||
|
removePrecision(slices);
|
||||||
|
|
||||||
var shapeParts = [];
|
const gcode = slicesToGCode(slices, settings);
|
||||||
for (var i = 0; i < intersectionIndexes.length; i ++) {
|
|
||||||
var index = intersectionIndexes[i];
|
|
||||||
|
|
||||||
if (intersectionPoints[index] === undefined) {
|
this.dispatchEvent({ type: 'finish', gcode });
|
||||||
continue;
|
return gcode;
|
||||||
}
|
|
||||||
|
|
||||||
var firstPoints = [index];
|
|
||||||
var isFirstPoint = true;
|
|
||||||
var closed = false;
|
|
||||||
|
|
||||||
var shape = [];
|
|
||||||
|
|
||||||
while (index !== -1) {
|
|
||||||
var intersection = intersectionPoints[index];
|
|
||||||
// uppercase X and Y because clipper vector
|
|
||||||
shape.push({X: intersection.x, Y: intersection.y});
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
|
|
||||||
var connects = lines[index].connects;
|
|
||||||
var faceNormals = lines[index].normals;
|
|
||||||
|
|
||||||
for (var j = 0; j < connects.length; j ++) {
|
|
||||||
var index = connects[j];
|
|
||||||
|
|
||||||
if (firstPoints.indexOf(index) !== -1 && shape.length > 2) {
|
|
||||||
closed = true;
|
|
||||||
index = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if index has an intersection or is already used
|
|
||||||
if (intersectionPoints[index] !== undefined) {
|
|
||||||
var faceNormal = faceNormals[Math.floor(j / 2)];
|
|
||||||
|
|
||||||
var a = new THREE.Vector2(intersection.x, intersection.y);
|
|
||||||
var 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) {
|
|
||||||
if (isFirstPoint) {
|
|
||||||
firstPoints.push(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
|
|
||||||
connects = connects.concat(lines[index].connects);
|
|
||||||
faceNormals = faceNormals.concat(lines[index].normals);
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
normal.set(-normal.y, normal.x).normalize();
|
|
||||||
|
|
||||||
if (normal.dot(faceNormal) > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isFirstPoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!closed) {
|
|
||||||
var index = firstPoints[0];
|
|
||||||
|
|
||||||
while (index !== -1) {
|
|
||||||
if (firstPoints.indexOf(index) === -1) {
|
|
||||||
var intersection = intersectionPoints[index];
|
|
||||||
shape.unshift({X: intersection.x, Y: intersection.y});
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
var connects = lines[index].connects;
|
|
||||||
|
|
||||||
for (var i = 0; i < connects.length; i ++) {
|
|
||||||
var index = connects[i];
|
|
||||||
|
|
||||||
if (intersectionPoints[index] !== undefined) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = new Paths([shape], closed).clean(0.01);
|
|
||||||
if (part.length > 0) {
|
|
||||||
shapeParts.push(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shapes.push(shapeParts);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.sliced = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return shapes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_shapesToSlices (shapes, settings) {
|
|
||||||
var slices = [];
|
|
||||||
|
|
||||||
for (var layer = 0; layer < shapes.length; layer ++) {
|
|
||||||
var shapeParts = shapes[layer];
|
|
||||||
|
|
||||||
var slice = new Slice();
|
|
||||||
|
|
||||||
var holes = [];
|
|
||||||
var outlines = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < shapeParts.length; i ++) {
|
|
||||||
var shape = shapeParts[i];
|
|
||||||
|
|
||||||
if (!shape.closed) {
|
|
||||||
slice.add(shape);
|
|
||||||
}
|
|
||||||
else if (shape.isHole()) {
|
|
||||||
holes.push(shape);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
slice.add(shape);
|
|
||||||
outlines.push(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outlines.sort((a, b) => {
|
|
||||||
return a.boundSize() - b.boundSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('test');
|
|
||||||
|
|
||||||
if (holes.length > outlines.length) {
|
|
||||||
[holes, outlines] = [outlines, holes];
|
|
||||||
}
|
|
||||||
else if (holes.length === outlines.length) {
|
|
||||||
holes.sort((a, b) => {
|
|
||||||
return a.boundSize() - b.boundSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (holes[0].boundSize > outlines[0].boundSize()) {
|
|
||||||
[holes, outlines] = [outlines, holes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < holes.length; i ++) {
|
|
||||||
var hole = holes[i];
|
|
||||||
|
|
||||||
for (var j = 0; j < outlines.length; j ++) {
|
|
||||||
var outline = outlines[j];
|
|
||||||
|
|
||||||
if (outline.pointCollision(hole[0][0])) {
|
|
||||||
outline.join(hole);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slice.removeSelfIntersect();
|
|
||||||
|
|
||||||
slices.push(slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedSlices = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return slices;
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateInnerLines (slices, settings) {
|
|
||||||
console.log("generating outer lines and inner lines");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
||||||
var shellThickness = settings.config["shellThickness"] * scale;
|
|
||||||
var nozzleRadius = nozzleDiameter / 2;
|
|
||||||
var shells = Math.round(shellThickness / nozzleDiameter);
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (!part.intersect.closed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// var outerLine = part.intersect.clone().scaleUp(scale).offset(-nozzleRadius);
|
|
||||||
var outerLine = part.intersect.scaleUp(scale).offset(-nozzleRadius);
|
|
||||||
|
|
||||||
if (outerLine.length > 0) {
|
|
||||||
part.outerLine = outerLine;
|
|
||||||
|
|
||||||
for (var shell = 1; shell < shells; shell += 1) {
|
|
||||||
var offset = shell * nozzleDiameter;
|
|
||||||
|
|
||||||
var innerLine = outerLine.offset(-offset);
|
|
||||||
|
|
||||||
if (innerLine.length > 0) {
|
|
||||||
part.innerLines.push(innerLine);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedInnerLines = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateInfills (slices, settings) {
|
|
||||||
console.log("generating infills");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var fillGridSize = settings.config["fillGridSize"] * scale;
|
|
||||||
var bottomThickness = settings.config["bottomThickness"];
|
|
||||||
var topThickness = settings.config["topThickness"];
|
|
||||||
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
||||||
var infillOverlap = settings.config["infillOverlap"] * scale;
|
|
||||||
|
|
||||||
var bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
|
|
||||||
var topSkinCount = Math.ceil(topThickness/layerHeight);
|
|
||||||
var nozzleRadius = nozzleDiameter / 2;
|
|
||||||
var hightemplateSize = Math.sqrt(2 * Math.pow(nozzleDiameter, 2));
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
if (layer - bottomSkinCount >= 0 && layer + topSkinCount < slices.length) {
|
|
||||||
var downSkin = slices[layer - bottomSkinCount].getOutline();
|
|
||||||
var upSkin = slices[layer + topSkinCount].getOutline();
|
|
||||||
var surroundingLayer = upSkin.intersect(downSkin);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var surroundingLayer = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (!part.intersect.closed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outerLine = part.outerLine;
|
|
||||||
|
|
||||||
if (outerLine.length > 0) {
|
|
||||||
var inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
|
|
||||||
|
|
||||||
var fillArea = inset.offset(-nozzleRadius);
|
|
||||||
var lowFillArea = false;
|
|
||||||
if (surroundingLayer) {
|
|
||||||
var highFillArea = fillArea.difference(surroundingLayer);
|
|
||||||
|
|
||||||
if (infillOverlap > 0) {
|
|
||||||
highFillArea = highFillArea.offset(infillOverlap);
|
|
||||||
}
|
|
||||||
|
|
||||||
highFillArea = highFillArea.intersect(fillArea);
|
|
||||||
|
|
||||||
var lowFillArea = fillArea.difference(highFillArea);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var highFillArea = fillArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fill = new Paths([], false);
|
|
||||||
|
|
||||||
if (lowFillArea && lowFillArea.length > 0) {
|
|
||||||
var bounds = lowFillArea.bounds();
|
|
||||||
var lowFillTemplate = this._getFillTemplate(bounds, fillGridSize, true, true);
|
|
||||||
|
|
||||||
part.fill.join(lowFillTemplate.intersect(lowFillArea));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highFillArea.length > 0) {
|
|
||||||
var bounds = highFillArea.bounds();
|
|
||||||
var even = (layer % 2 === 0);
|
|
||||||
var highFillTemplate = this._getFillTemplate(bounds, hightemplateSize, even, !even);
|
|
||||||
|
|
||||||
part.fill.join(highFillTemplate.intersect(highFillArea));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedInfills = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateSupport (slices, settings) {
|
|
||||||
console.log("generating support");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var supportGridSize = settings.config["supportGridSize"] * scale;
|
|
||||||
var supportAcceptanceMargin = settings.config["supportAcceptanceMargin"] * scale;
|
|
||||||
var supportMargin = settings.config["supportMargin"] * scale;
|
|
||||||
var plateSize = settings.config["supportPlateSize"] * scale;
|
|
||||||
var supportDistanceY = settings.config["supportDistanceY"];
|
|
||||||
var supportDistanceLayers = Math.max(Math.ceil(supportDistanceY / layerHeight), 1);
|
|
||||||
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
||||||
|
|
||||||
var supportAreas = new Paths([], true);
|
|
||||||
|
|
||||||
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
|
|
||||||
var currentSlice = slices[layer];
|
|
||||||
|
|
||||||
if (supportAreas.length > 0) {
|
|
||||||
|
|
||||||
if (layer >= supportDistanceLayers) {
|
|
||||||
var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
|
|
||||||
sliceSkin = sliceSkin;
|
|
||||||
|
|
||||||
var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin));
|
|
||||||
if (supportAreasSlimmed.area() < 100.0) {
|
|
||||||
supportAreas = supportAreas.difference(sliceSkin);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
supportAreas = supportAreasSlimmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var supportTemplate = this._getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
|
|
||||||
var supportFill = supportTemplate.intersect(supportAreas);
|
|
||||||
if (supportFill.length === 0) {
|
|
||||||
currentSlice.support = supportAreas.clone();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentSlice.support = supportFill;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
|
|
||||||
|
|
||||||
var slice = slices[layer + supportDistanceLayers];
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var slicePart = slice.parts[i];
|
|
||||||
|
|
||||||
if (slicePart.intersect.closed) {
|
|
||||||
var outerLine = slicePart.outerLine;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var outerLine = slicePart.intersect.offset(supportAcceptanceMargin);
|
|
||||||
}
|
|
||||||
|
|
||||||
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
|
|
||||||
var overhang = outerLine.difference(overlap);
|
|
||||||
|
|
||||||
if (overlap.length === 0 || overhang.length > 0) {
|
|
||||||
supportAreas = supportAreas.join(overhang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedSupport = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_optimizePaths (slices, settings) {
|
|
||||||
console.log("opimize paths");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var brimOffset = settings.config["brimOffset"] * scale;
|
|
||||||
|
|
||||||
var start = new THREE.Vector2(0, 0);
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
if (layer === 0) {
|
|
||||||
slice.brim = slice.getOutline().offset(brimOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = slice.optimizePaths(start);
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
part.outerLine.scaleDown(scale);
|
|
||||||
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
||||||
var innerLine = part.innerLines[j];
|
|
||||||
innerLine.scaleDown(scale);
|
|
||||||
}
|
|
||||||
part.fill.scaleDown(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.support !== undefined) {
|
|
||||||
slice.support.scaleDown(scale);
|
|
||||||
}
|
|
||||||
if (slice.brim !== undefined) {
|
|
||||||
slice.brim.scaleDown(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.optimizedPaths = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_getFillTemplate (bounds, size, even, uneven) {
|
|
||||||
var paths = new Paths([], false);
|
|
||||||
|
|
||||||
var left = Math.floor(bounds.left / size) * size;
|
|
||||||
var right = Math.ceil(bounds.right / size) * size;
|
|
||||||
var top = Math.floor(bounds.top / size) * size;
|
|
||||||
var bottom = Math.ceil(bounds.bottom / size) * size;
|
|
||||||
|
|
||||||
var width = right - left;
|
|
||||||
|
|
||||||
if (even) {
|
|
||||||
for (var y = top; y <= bottom + width; y += size) {
|
|
||||||
paths.push([
|
|
||||||
{X: left, Y: y},
|
|
||||||
{X: right, Y: y - width}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (uneven) {
|
|
||||||
for (var y = top - width; y <= bottom; y += size) {
|
|
||||||
paths.push([
|
|
||||||
{X: left, Y: y},
|
|
||||||
{X: right, Y: y + width}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
_slicesToGCode (slices, settings) {
|
|
||||||
var gcode = new GCode().setSettings(settings);
|
|
||||||
|
|
||||||
function pathToGCode (path, retract, unRetract, type) {
|
|
||||||
|
|
||||||
for (var i = 0; i < path.length; i ++) {
|
|
||||||
var shape = path[i];
|
|
||||||
|
|
||||||
var length = path.closed ? (shape.length + 1) : shape.length;
|
|
||||||
|
|
||||||
for (var j = 0; j < length; j ++) {
|
|
||||||
var point = shape[j % shape.length];
|
|
||||||
|
|
||||||
if (j === 0) {
|
|
||||||
// TODO
|
|
||||||
// moveTo should impliment combing
|
|
||||||
gcode.moveTo(point.X, point.Y, layer);
|
|
||||||
|
|
||||||
if (unRetract) {
|
|
||||||
gcode.unRetract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gcode.lineTo(point.X, point.Y, layer, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retract) {
|
|
||||||
gcode.retract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
if (layer === 1) {
|
|
||||||
gcode.turnFanOn();
|
|
||||||
gcode.bottom = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.brim !== undefined) {
|
|
||||||
pathToGCode(slice.brim, true, true, "brim");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
pathToGCode(part.outerLine, false, true, "outerLine");
|
|
||||||
|
|
||||||
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
||||||
var innerLine = part.innerLines[j];
|
|
||||||
pathToGCode(innerLine, false, false, "innerLine");
|
|
||||||
}
|
|
||||||
|
|
||||||
pathToGCode(part.fill, true, false, "fill");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var retract = !(slice.parts.length === 1 && slice.support === undefined);
|
|
||||||
pathToGCode(part.intersect, retract, retract, "outerLine");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.support !== undefined) {
|
|
||||||
pathToGCode(slice.support, true, true, "support");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedGCode = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return gcode.getGCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateProgress (settings) {
|
|
||||||
if (this.onprogress !== undefined) {
|
|
||||||
var supportEnabled = settings.config["supportEnabled"];
|
|
||||||
|
|
||||||
var progress = {};
|
|
||||||
|
|
||||||
var procent = 0;
|
|
||||||
var length = 0;
|
|
||||||
for (var i in this.progress) {
|
|
||||||
if (!(!supportEnabled && i === "generatedSupport")) {
|
|
||||||
progress[i] = this.progress[i];
|
|
||||||
if (progress[i]) {
|
|
||||||
procent += 1;
|
|
||||||
}
|
|
||||||
length += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
progress.procent = procent / length;
|
|
||||||
|
|
||||||
this.onprogress(progress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
import THREE from 'three.js';
|
|
||||||
import Settings from './settings.js';
|
|
||||||
|
|
||||||
export default class {
|
|
||||||
constructor () {
|
|
||||||
this.worker = new Worker('./worker.js');
|
|
||||||
|
|
||||||
this.worker.addEventListener('message', (event) => {
|
|
||||||
switch (event.data['cmd']) {
|
|
||||||
case 'PROGRESS':
|
|
||||||
|
|
||||||
if (this.onprogress !== undefined) {
|
|
||||||
var progress = event.data['progress'];
|
|
||||||
|
|
||||||
this.onprogress(progress);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'GCODE':
|
|
||||||
if (this.onfinish !== undefined) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.addEventListener("loadend", () => {
|
|
||||||
var gcode = reader.result;
|
|
||||||
this.onfinish(gcode);
|
|
||||||
});
|
|
||||||
reader.readAsBinaryString(event.data['gcode']);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
this.worker.onerror = function (error) {
|
|
||||||
console.warn(error);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setMesh (mesh) {
|
|
||||||
mesh.updateMatrix();
|
|
||||||
|
|
||||||
this.setGeometry(mesh.geometry, mesh.matrix);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setGeometry (geometry, matrix) {
|
|
||||||
if (geometry.type === 'Geometry') {
|
|
||||||
geometry = new THREE.BufferGeometry().fromGeometry(geometry);
|
|
||||||
}
|
|
||||||
else if (geometry.type === 'BufferGeometry') {
|
|
||||||
geometry = geometry.clone();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.warn('Geometry is not an instance of BufferGeometry or Geometry');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(matrix instanceof THREE.Matrix4)) {
|
|
||||||
matrix = new THREE.Matrix4();
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffers = [];
|
|
||||||
for (var i = 0; i < geometry.attributesKeys.length; i ++) {
|
|
||||||
var key = geometry.attributesKeys[i];
|
|
||||||
buffers.push(geometry.attributes[key].array.buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete geometry.boundingBox;
|
|
||||||
delete geometry.boundingSphere;
|
|
||||||
|
|
||||||
this.worker.postMessage({
|
|
||||||
'cmd': 'SET_MESH',
|
|
||||||
'geometry': {
|
|
||||||
'attributes': geometry.attributes,
|
|
||||||
'attributesKeys': geometry.attributesKeys
|
|
||||||
},
|
|
||||||
'matrix': matrix.toArray()
|
|
||||||
}, buffers);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
slice (settings) {
|
|
||||||
this.worker.postMessage({
|
|
||||||
'cmd': 'SLICE',
|
|
||||||
'settings': settings.config
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
close () {
|
|
||||||
this.worker.postMessage({
|
|
||||||
'cmd': 'CLOSE'
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
importScripts('../jspm_packages/system.js');
|
|
||||||
importScripts('../config.js');
|
|
||||||
|
|
||||||
var Slicer, Settings, THREE;
|
|
||||||
|
|
||||||
function init () {
|
|
||||||
var slicer = new Slicer();
|
|
||||||
slicer.onProgress = function (progress) {
|
|
||||||
self.postMessage({
|
|
||||||
'cmd': 'PROGRESS',
|
|
||||||
'progress': progress
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
self.addEventListener('message', function (event) {
|
|
||||||
switch (event.data['cmd']) {
|
|
||||||
case 'SET_MESH':
|
|
||||||
var geometry = new THREE.Geometry().fromBufferGeometry(event.data['geometry']);
|
|
||||||
var matrix = new THREE.Matrix4().fromArray(event.data['matrix']);
|
|
||||||
|
|
||||||
slicer.setGeometry(geometry, matrix);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SLICE':
|
|
||||||
var settings = new Settings().updateConfig(event.data['settings']);
|
|
||||||
|
|
||||||
var gcode = slicer.slice(settings);
|
|
||||||
var blob = new Blob([gcode], {type: 'text/plain'});
|
|
||||||
|
|
||||||
self.postMessage({
|
|
||||||
'cmd': 'GCODE',
|
|
||||||
'gcode': blob
|
|
||||||
});
|
|
||||||
|
|
||||||
//self.close();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'CLOSE':
|
|
||||||
self.close();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all([
|
|
||||||
System.import('./slicer'),
|
|
||||||
System.import('./settings'),
|
|
||||||
System.import('three.js')
|
|
||||||
]).then(function(modules) {
|
|
||||||
Slicer = modules[0].default;
|
|
||||||
Settings = modules[1].default;
|
|
||||||
THREE = modules[2];
|
|
||||||
|
|
||||||
init();
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user