Merge branch 'webworker'

This commit is contained in:
casperlamboo 2015-06-10 18:26:32 +02:00
commit dd41e6d3e7
25 changed files with 7324 additions and 1621 deletions

1319
build/d3d.js vendored

File diff suppressed because it is too large Load Diff

1
build/d3d.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,27 +0,0 @@
'use strict';
var gulp = require('gulp');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var watch = require('gulp-watch');
var files = [
"src/utils.js",
"src/box.js",
"src/printer.js",
"src/paths.js",
"src/slicer.js"
];
var destination = 'build/';
gulp.task('default', function () {
return gulp.src(files)
// .pipe(watch(files))
.pipe(concat('d3d.js'))
.pipe(gulp.dest(destination))
.pipe(uglify())
.pipe(rename({extname: '.min.js'}))
.pipe(gulp.dest(destination));
});

View File

@ -20,9 +20,15 @@ $(document).ready(function () {
var listDoodle = $("#printers-doodle"); var listDoodle = $("#printers-doodle");
var listSliceTest = $("#printers-slicetest"); var listSliceTest = $("#printers-slicetest");
var listSliceWebworker = $("#printers-webworker");
listDoodle.append("<li><a href='doodle.html#192.168.5.1'>Wired Printer</a></li>"); listDoodle.append("<li><a href='doodle.html#192.168.5.1'>Wired Printer</a></li>");
listSliceTest.append("<li><a href='slice_test.html#192.168.5.1'>Wired Printer</a></li>"); listSliceTest.append("<li><a href='slice_test.html#192.168.5.1'>Wired Printer</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#192.168.5.1'>Wired Printer</a></li>");
listDoodle.append("<li><a href='doodle.html#" + window.location.host + ":3000'>Node Server</a></li>");
listSliceTest.append("<li><a href='slice_test.html#" + window.location.host + ":3000'>Node Server</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#" + window.location.host + ":3000'>Node Server</a></li>");
/* /*
printers.push({ printers.push({
@ -44,6 +50,7 @@ $(document).ready(function () {
listDoodle.append("<li><a href='doodle.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>"); listDoodle.append("<li><a href='doodle.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
listSliceTest.append("<li><a href='slice_test.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>"); listSliceTest.append("<li><a href='slice_test.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
} }
}); });
}); });
@ -54,6 +61,10 @@ $(document).ready(function () {
<p>Slice Test</p> <p>Slice Test</p>
<ul id="printers-slicetest"></ul> <ul id="printers-slicetest"></ul>
<p>Webworkers</p>
<ul id="printers-webworker"></ul>
<!-- <!--
<table> <table>
<tr> <tr>

3919
library/benchmark.js Normal file

File diff suppressed because it is too large Load Diff

2329
library/cal.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9342,6 +9342,21 @@ THREE.BufferGeometry.prototype = {
this.dispatchEvent( { type: 'dispose' } ); this.dispatchEvent( { type: 'dispose' } );
},
getBuffers: function () {
var buffers = [];
for ( var i = 0; i < this.attributesKeys.length; i ++ ) {
var key = this.attributesKeys[ i ];
buffers.push( this.attributes[ key ].array.buffer );
}
return buffers;
} }
}; };

BIN
models/dom.stl Normal file

Binary file not shown.

BIN
models/support_test.stl Normal file

Binary file not shown.

BIN
models/ultimaker_robot.stl Executable file

Binary file not shown.

View File

@ -5,7 +5,7 @@
"printer.dimensions.y": 200, "printer.dimensions.y": 200,
"printer.dimensions.z": 200, "printer.dimensions.z": 200,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)", "printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.89, "printer.filamentThickness": 2.85,
"printer.heatedbed": false, "printer.heatedbed": false,
"printer.heatup.bed.temperature": 70, "printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true, "printer.heatup.enabled": true,
@ -13,5 +13,35 @@
"printer.nozzleDiameter": 0.4, "printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (default)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG91 ;relative positioning\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG92 E0 ;zero the extruded length again\nG1 F9000\nG90 ;absolute positioning\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)", "printer.startcode": ";Generated with Doodle3D (default)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG91 ;relative positioning\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG92 E0 ;zero the extruded length again\nG1 F9000\nG90 ;absolute positioning\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker" "printer.type": "ultimaker"
},
"ultimaker2": {
"printer.baudrate": "115200",
"printer.dimensions.x": 223,
"printer.dimensions.y": 223,
"printer.dimensions.z": 205,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+5.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 ;home the printer\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.85,
"printer.heatedbed": true,
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (ultimaker2)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nG28 ; home to endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker2"
},
"ultimaker2go": {
"printer.baudrate": "115200",
"printer.dimensions.x": 120,
"printer.dimensions.y": 120,
"printer.dimensions.z": 115,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+5.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 ;home the printer\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.85,
"printer.heatedbed": false,
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (ultimaker2)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nG28 ; home to endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker2g0"
} }
} }

View File

@ -1,18 +1,24 @@
{ {
"printer.normalFlowRate": 1.0, "printer.normalFlowRate": 1.0,
"printer.bottomFlowRate": 2.0, "printer.bottomFlowRate": 2.0,
"printer.bottomLayerSpeed": 35, "printer.bottomLayerSpeed": 35.0,
"printer.bottomThickness": 0.4, "printer.bottomThickness": 0.4,
"printer.fillSize": 5, "printer.fillSize": 5.0,
"printer.firstLayerSlow": true, "printer.firstLayerSlow": true,
"printer.layerHeight": 0.2, "printer.layerHeight": 0.2,
"printer.retraction.amount": 3, "printer.retraction.amount": 3.0,
"printer.retraction.enabled": true, "printer.retraction.enabled": true,
"printer.retraction.speed": 50, "printer.retraction.speed": 50,
"printer.retraction.minDistance": 5, "printer.retraction.minDistance": 5.0,
"printer.shellThickness": 0.4, "printer.shellThickness": 0.4,
"printer.speed": 50, "printer.speed": 50.0,
"printer.temperature": 230, "printer.temperature": 210.0,
"printer.topThickness": 0.8, "printer.topThickness": 0.8,
"printer.travelSpeed": 200 "printer.travelSpeed": 200.0,
"printer.support.accaptanceSize": 1.5,
"printer.support.distanceY": 0.4,
"printer.support.use": true,
"printer.support.gritSize": 6.0,
"printer.support.margin": 2.0,
"printer.support.plateSize": 4.0
} }

View File

@ -12,11 +12,9 @@
<script src="src/box.js"></script> <script src="src/box.js"></script>
<script src="src/printer.js"></script> <script src="src/printer.js"></script>
<script src="src/paths.js"></script> <script src="src/paths.js"></script>
<script src="src/gcode.js"></script>
<script src="src/slicer.js"></script> <script src="src/slicer.js"></script>
<script src="gcode/testgcode.js"></script>
<script src="gcode/easterbunny.js"></script>
<style> <style>
canvas {border: 1px solid black;} canvas {border: 1px solid black;}
</style> </style>
@ -33,12 +31,12 @@ function init () {
var scene = createScene(); var scene = createScene();
var localIp = location.hash.substring(1); var localIp = location.hash.substring(1);
doodleBox = new D3D.Box(localIp); //doodleBox = new D3D.Box(localIp);
var printer = new D3D.Printer(USER_SETTINGS, PRINTER_SETTINGS["ultimaker"]); var printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS["ultimaker"]);
var loader = new THREE.STLLoader(); var loader = new THREE.STLLoader();
loader.load("models/pokemon/pikachu.stl", function (geometry) { loader.load('models/support_test.stl', function (geometry) {
//var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1); //var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1);
//var geometry = new THREE.SphereGeometry(10, 20, 10); //var geometry = new THREE.SphereGeometry(10, 20, 10);
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30); //var geometry = new THREE.TorusGeometry(20, 10, 30, 30);
@ -72,23 +70,23 @@ function init () {
mesh.rotation.x = -Math.PI/2; mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1; mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;
mesh.position.x = 100; mesh.position.y = -0.1;
mesh.position.z = 100; mesh.position.x = 60;
mesh.position.z = 60;
//scene.add(mesh); mesh.updateMatrix();
var slicer = new D3D.Slicer().setMesh(mesh);
var mesh = new THREE.Mesh(slicer.geometry, material);
scene.add(mesh); scene.add(mesh);
var canvas = document.getElementById("canvas"); var slicer = new D3D.Slicer().setMesh(mesh.geometry, mesh.matrix);
var context = canvas.getContext("2d");
var img = slicer.drawPaths(printer, 0, 1); //var canvas = document.getElementById("canvas");
context.drawImage(img, 0, 0); //var context = canvas.getContext("2d");
gcode = slicer.getGcode(printer); //var img = slicer.drawPaths(printer, 0, 1);
//context.drawImage(img, 0, 0);
gcode = slicer.getGCode(printer);
}); });
} }

View File

@ -14,7 +14,7 @@
D3D.Box = function (localIp) { D3D.Box = function (localIp) {
"use strict"; "use strict";
var self = this; var scope = this;
this.batchSize = 512; this.batchSize = 512;
this.maxBufferedLines = 4096; this.maxBufferedLines = 4096;
@ -31,13 +31,13 @@ D3D.Box = function (localIp) {
this.loaded = false; this.loaded = false;
this.getConfigAll(function (data) { this.getConfigAll(function (data) {
self.updateConfig(data); scope.updateConfig(data);
self.update(); scope.update();
self.loaded = true; scope.loaded = true;
if (self.onload !== undefined) { if (scope.onload !== undefined) {
self.onload(); scope.onload();
} }
}); });
}; };
@ -52,6 +52,7 @@ D3D.Box.prototype.updateConfig = function (config) {
}; };
D3D.Box.prototype.update = function () { D3D.Box.prototype.update = function () {
"use strict"; "use strict";
var scope = this;
//TODO //TODO
//Code is zo op gezet dat maar api call te gelijk is //Code is zo op gezet dat maar api call te gelijk is
//Bij error wordt gelijk zelfde data opnieuw gestuurd //Bij error wordt gelijk zelfde data opnieuw gestuurd
@ -62,22 +63,24 @@ D3D.Box.prototype.update = function () {
this.printBatch(); this.printBatch();
} }
else { else {
this.updateState(); setTimeout(function () {
scope.updateState();
}, 1000);
} }
}; };
D3D.Box.prototype.updateState = function () { D3D.Box.prototype.updateState = function () {
//que api calls so they don't overload the d3d box //que api calls so they don't overload the d3d box
"use strict"; "use strict";
var self = this; var scope = this;
this.getInfoStatus(function (data) { this.getInfoStatus(function (data) {
self.status = data; scope.status = data;
if (self.onupdate !== undefined) { if (scope.onupdate !== undefined) {
self.onupdate(data); scope.onupdate(data);
} }
self.update(); scope.update();
}); });
}; };
D3D.Box.prototype.print = function (gcode) { D3D.Box.prototype.print = function (gcode) {
@ -98,50 +101,37 @@ D3D.Box.prototype.print = function (gcode) {
}; };
D3D.Box.prototype.printBatch = function () { D3D.Box.prototype.printBatch = function () {
"use strict"; "use strict";
var self = this; var scope = this;
var gcode = this.printBatches.shift(); var gcode = this.printBatches.shift();
this.setPrinterPrint({ this.setPrinterPrint({
"start": ((this.currentBatch === 0) ? true : false), "start": ((this.currentBatch === 0) ? true : false),
"first": ((this.currentBatch === 0) ? true : false), "first": ((this.currentBatch === 0) ? true : false),
"gcode": gcode.join("\n") "gcode": gcode.join("\n"),
"last": ((this.printBatches.length === 0) ? true : false) //only for debug purposes
}, function (data) { }, function (data) {
console.log("batch sent: " + self.currentBatch, data); console.log("batch sent: " + scope.currentBatch, data);
if (self.printBatches.length > 0) { if (scope.printBatches.length > 0) {
//sent new batch //sent new batch
self.currentBatch ++; scope.currentBatch ++;
} }
else { else {
//finish sending //finish sending
} }
self.updateState(); scope.updateState();
}); });
}; };
D3D.Box.prototype.stopPrint = function () { D3D.Box.prototype.stopPrint = function (printer) {
"use strict"; "use strict";
this.printBatches = []; this.printBatches = [];
this.currentBatch = 0; this.currentBatch = 0;
var finishMove = [
"M107 ;fan off",
"G91 ;relative positioning",
"G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure",
"G1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more",
"G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way",
"M84 ;disable axes / steppers",
"G90 ;absolute positioning",
"M104 S180",
";M140 S70",
"M117 Done ;display message (20 characters to clear whole screen)"
];
this.setPrinterStop({ this.setPrinterStop({
//"gcode": {} "gcode": printer.getEndCode().join("\n")
"gcode": finishMove.join("\n")
}, function (data) { }, function (data) {
console.log("Printer stop command sent"); console.log("Printer stop command sent");
}); });
@ -167,12 +157,12 @@ D3D.Box.prototype.getConfigAll = function (callback) {
}; };
D3D.Box.prototype.setConfig = function (data, callback) { D3D.Box.prototype.setConfig = function (data, callback) {
"use strict"; "use strict";
var self = this; var scope = this;
sendAPI(this.api + "config", data, function (response) { sendAPI(this.api + "config", data, function (response) {
for (var i in response.validation) { for (var i in response.validation) {
if (response.validation[i] === "ok") { if (response.validation[i] === "ok") {
self[i] = data[i]; scope[i] = data[i];
} }
} }

184
src/gcode.js Normal file
View File

@ -0,0 +1,184 @@
/******************************************************
*
* GCode
*
* Manages the gcode
* Also handles different flavours of gcode
* TODO
* calculate extrusion length and total time
*
******************************************************/
D3D.GCode = function () {
"use strict";
this.gcode = [];
this.current = {};
this.extruder = 0.0;
this.bottom = true;
this.isRetracted = false;
this.isFanOn = false;
this.nozzlePosition = new THREE.Vector2(0, 0);
};
D3D.GCode.prototype.addGCode = function (command) {
"use strict";
var str = [];
for (var i in command) {
if (i === "G") {
str.push(i + command[i]);
}
else if (this.current[i] !== command[i]) {
str.push(i + command[i]);
this.current[i] = command[i];
}
}
str = str.join(" ");
if (str.length > 0) {
this.gcode.push(str);
}
};
D3D.GCode.prototype.setSettings = function (printer) {
"use strict";
this.settings = printer;
return this;
};
D3D.GCode.prototype.turnFanOn = function (fanSpeed) {
"use strict";
this.isFanOn = true;
var gcode = {
"M": 106
};
if (fanSpeed !== undefined) {
gcode["S"] = fanSpeed;
}
this.addGCode(gcode);
return this;
};
D3D.GCode.prototype.turnFanOff = function () {
"use strict";
this.isFanOn = false;
this.addGCode({
"M": 107
});
return this;
};
D3D.GCode.prototype.moveTo = function (extrude, x, y, layer) {
"use strict";
var layerHeight = this.settings.config["printer.layerHeight"];
var firstLayerSlow = this.settings.config["printer.firstLayerSlow"];
var normalSpeed = this.settings.config["printer.speed"];
var bottomSpeed = this.settings.config["printer.bottomLayerSpeed"];
var normalSpeed = this.settings.config["printer.speed"];
var bottomSpeed = this.settings.config["printer.bottomLayerSpeed"];
var nozzleDiameter = this.settings.config["printer.nozzleDiameter"];
var filamentThickness = this.settings.config["printer.filamentThickness"];
var bottomFlowRate = this.settings.config["printer.bottomFlowRate"];
var normalFlowRate = this.settings.config["printer.normalFlowRate"];
var travelSpeed = this.settings.config["printer.travelSpeed"];
if (this.bottom) {
var speed = bottomSpeed * 60;
var flowRate = bottomFlowRate;
}
else {
var speed = normalSpeed * 60;
var flowRate = normalFlowRate;
}
var z = (layer + 1) * layerHeight;
if (extrude) {
var lineLength = this.nozzlePosition.distanceTo(new THREE.Vector2(x, y));
var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
this.addGCode({
"G": 1,
"X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
"F": speed.toFixed(3),
"E": this.extruder.toFixed(3)
});
}
else {
var speed = travelSpeed * 60;
this.addGCode({
"G": 0,
"X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
"F": speed.toFixed(3)
});
}
this.nozzlePosition = new THREE.Vector2(x, y);
return this;
};
D3D.GCode.prototype.unRetract = function () {
"use strict";
if (this.isRetracted) {
this.isRetracted = false;
var retractionAmount = this.settings.config["printer.retraction.amount"];
var retractionEnabled = this.settings.config["printer.retraction.enabled"];
var retractionMinDistance = this.settings.config["printer.retraction.minDistance"];
var retractionSpeed = this.settings.config["printer.retraction.speed"];
var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) {
this.addGCode({
"G": 0,
"E": this.extruder.toFixed(3),
"F": speed.toFixed(3)
});
}
return this;
}
};
D3D.GCode.prototype.retract = function () {
"use strict";
if (!this.isRetracted) {
this.isRetracted = true;
var retractionAmount = this.settings.config["printer.retraction.amount"];
var retractionEnabled = this.settings.config["printer.retraction.enabled"];
var retractionMinDistance = this.settings.config["printer.retraction.minDistance"];
var retractionSpeed = this.settings.config["printer.retraction.speed"];
var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) {
this.addGCode({
"G": 0,
"E": (this.extruder - retractionAmount).toFixed(3),
"F": speed.toFixed(3)
});
}
return this;
}
};
D3D.GCode.prototype.getGCode = function () {
"use strict";
return this.settings.getStartCode().concat(this.gcode, this.settings.getEndCode());
};

View File

@ -160,6 +160,20 @@ D3D.Paths.prototype.optimizePath = function (start) {
return optimizedPaths; return optimizedPaths;
}; };
D3D.Paths.prototype.areas = function () {
"use strict";
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;
};
D3D.Paths.prototype.tresholdArea = function (minArea) { D3D.Paths.prototype.tresholdArea = function (minArea) {
//code not tested yet //code not tested yet
"use strict"; "use strict";
@ -196,6 +210,16 @@ D3D.Paths.prototype.bounds = function () {
return ClipperLib.Clipper.GetBounds(this); return ClipperLib.Clipper.GetBounds(this);
}; };
D3D.Paths.prototype.boundSize = function () {
"use strict";
var bounds = this.bounds();
var width = bounds.right - bounds.left;
var height = bounds.top - bounds.bottom;
return width * height;
};
D3D.Paths.prototype.draw = function (context, color) { D3D.Paths.prototype.draw = function (context, color) {
"use strict"; "use strict";

View File

@ -5,13 +5,10 @@
* *
******************************************************/ ******************************************************/
D3D.Printer = function (printerSettings, userSettings) { D3D.Printer = function () {
"use strict"; "use strict";
this.config = {}; this.config = {};
this.updateConfig(printerSettings);
this.updateConfig(userSettings);
}; };
D3D.Printer.prototype.updateConfig = function (config) { D3D.Printer.prototype.updateConfig = function (config) {
"use strict"; "use strict";
@ -36,6 +33,7 @@ D3D.Printer.prototype.getEndCode = function () {
"use strict"; "use strict";
var gcode = this.config["printer.endcode"]; var gcode = this.config["printer.endcode"];
gcode = this.subsituteVariables(gcode); gcode = this.subsituteVariables(gcode);
return gcode.split("\n"); return gcode.split("\n");

View File

@ -2,48 +2,46 @@
* *
* Slicer * Slicer
* *
* TODO (optimalisatie)
* sorteer lijnen op laagste hoogte -> stop loop wanneer hij een lijn zonder intersectie heeft gevonden
* verwijder lijnen die ooit interactie gehad hebben, maar nu niet meer
* helft van lijnen toevoegen omdat 4face altijd recht is, en 3face dus te veel data bevat
*
* omliggende lagen -> difference && sum omliggende lijnen
* voor laag 5 = 5 diff (3 && 4 && 6 && 7))
*
******************************************************/ ******************************************************/
D3D.Slicer = function () { D3D.Slicer = function () {
"use strict"; "use strict";
this.progress = {
totalFaces: 0,
currentFace: 0,
totalLayers: 0,
sliceLayer: 0,
dataLayer: 0,
gcodeLayer: 0
}; };
D3D.Slicer.prototype.setMesh = function (mesh) { };
D3D.Slicer.prototype.setMesh = function (geometry, matrix) {
"use strict"; "use strict";
//convert buffergeometry to geometry; //convert buffergeometry to geometry;
var geometry = mesh.geometry.clone();
if (geometry instanceof THREE.BufferGeometry) { if (geometry instanceof THREE.BufferGeometry) {
geometry = new THREE.Geometry().fromBufferGeometry(geometry); geometry = new THREE.Geometry().fromBufferGeometry(geometry);
} }
//remove duplicate vertices;
for (var i = 0; i < geometry.vertices.length; i ++) {
var vertexA = geometry.vertices[i];
for (var j = i + 1; j < geometry.vertices.length; j ++) {
var vertexB = geometry.vertices[j];
if (vertexA.equals(vertexB)) {
geometry.vertices[j] = vertexA;
}
}
}
geometry.mergeVertices();
//apply mesh matrix on geometry; //apply mesh matrix on geometry;
mesh.updateMatrix(); geometry.applyMatrix(matrix);
geometry.applyMatrix(mesh.matrix); geometry.mergeVertices();
geometry.computeFaceNormals(); geometry.computeFaceNormals();
geometry.computeBoundingBox(); geometry.computeBoundingBox();
/*
for (var i = 0; i < geometry.faces.length; i ++) {
var face = geometry.faces[i];
var normal = face.normal;
if (normal.x === 0 && normal.y === 0 && normal.z === 0) {
geometry.faces.splice(i, 1);
i --;
}
}
*/
this.geometry = geometry; this.geometry = geometry;
//get unique lines from geometry; //get unique lines from geometry;
@ -51,17 +49,32 @@ D3D.Slicer.prototype.setMesh = function (mesh) {
return this; return this;
}; };
D3D.Slicer.prototype.updateProgress = function () {
'use strict';
var faces = this.progress.currentFace / (this.progress.totalFaces - 1);
var slice = this.progress.sliceLayer / (this.progress.totalLayers - 1);
var data = this.progress.dataLayer / (this.progress.totalLayers - 2);
var gcode = this.progress.gcodeLayer / (this.progress.totalLayers - 2);
this.progress.procent = (faces + slice + data + gcode) / 4;
if (this.onProgress !== undefined) {
this.onProgress(this.progress);
}
};
D3D.Slicer.prototype.createLines = function () { D3D.Slicer.prototype.createLines = function () {
"use strict"; "use strict";
this.progress.totalFaces = this.geometry.faces.length;
this.lines = []; this.lines = [];
var lineLookup = {}; var lineLookup = {};
var self = this; var self = this;
function addLine (a, b) { function addLine (a, b) {
var index = lineLookup[b + "_" + a];
//think lookup can only be b_a, a_b is only possible when face is flipped
var index = lineLookup[b + "_" + a] || lineLookup[a + "_" + b];
if (index === undefined) { if (index === undefined) {
index = self.lines.length; index = self.lines.length;
@ -70,8 +83,7 @@ D3D.Slicer.prototype.createLines = function () {
self.lines.push({ self.lines.push({
line: new THREE.Line3(self.geometry.vertices[a], self.geometry.vertices[b]), line: new THREE.Line3(self.geometry.vertices[a], self.geometry.vertices[b]),
connects: [], connects: [],
normals: [], normals: []
ignore: 0
}); });
} }
@ -99,10 +111,14 @@ D3D.Slicer.prototype.createLines = function () {
this.lines[b].normals.push(normal); this.lines[b].normals.push(normal);
this.lines[c].normals.push(normal); this.lines[c].normals.push(normal);
} }
this.progress.currentFace = i;
this.updateProgress();
} }
}; };
D3D.Slicer.prototype.slice = function (layerHeight, height) { D3D.Slicer.prototype.slice = function (layerHeight, height) {
"use strict"; "use strict";
var numLayers = height / layerHeight;
var layersIntersections = []; var layersIntersections = [];
@ -113,7 +129,7 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var max = Math.floor(Math.max(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 ++) { for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0) { if (layerIndex >= 0 && layerIndex < numLayers) {
if (layersIntersections[layerIndex] === undefined) { if (layersIntersections[layerIndex] === undefined) {
layersIntersections[layerIndex] = []; layersIntersections[layerIndex] = [];
} }
@ -126,21 +142,28 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
//still error in first layer, so remove first layer & last layer //still error in first layer, so remove first layer & last layer
//see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1 //see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1
for (var layer = 1; layer < layersIntersections.length-1; layer ++) { for (var layer = 0; layer < layersIntersections.length; layer ++) {
//for (var layer = 0; layer < layersIntersections.length; layer ++) {
var layerIntersections = layersIntersections[layer]; var layerIntersections = layersIntersections[layer];
var y = layer * layerHeight; var y = layer * layerHeight;
var intersections = []; var intersections = [];
var log = [];
for (var i = 0; i < layerIntersections.length; i ++) { for (var i = 0; i < layerIntersections.length; i ++) {
var index = layerIntersections[i]; var index = layerIntersections[i];
var line = this.lines[index].line; var line = this.lines[index].line;
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 alpha = (y - line.start.y) / (line.end.y - line.start.y);
var x = line.end.x * alpha + line.start.x * (1 - alpha); var x = line.end.x * alpha + line.start.x * (1 - alpha);
var z = line.end.z * alpha + line.start.z * (1 - alpha); var z = line.end.z * alpha + line.start.z * (1 - alpha);
}
intersections[index] = new THREE.Vector2(z, x); intersections[index] = new THREE.Vector2(z, x);
log.push({x: z, y: x, index: index, connects: this.lines[index].connects});
} }
var done = []; var done = [];
@ -155,26 +178,35 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var intersection = intersections[index]; var intersection = intersections[index];
shape.push({X: intersection.x, Y: intersection.y}); shape.push({X: intersection.x, Y: intersection.y});
done.push(index);
var connects = this.lines[index].connects; var connects = this.lines[index].connects;
var faceNormals = this.lines[index].normals; var faceNormals = this.lines[index].normals;
for (var j = 0; j < connects.length; j ++) { for (var j = 0; j < connects.length; j ++) {
index = connects[j]; index = connects[j];
if (intersections[index] && done.indexOf(index) === -1) { if (intersections[index] !== undefined && done.indexOf(index) === -1) {
done.push(index);
var a = new THREE.Vector2(intersection.x, intersection.y); var a = new THREE.Vector2(intersection.x, intersection.y);
var b = intersections[index]; var b = intersections[index];
if (a.distanceTo(b) === 0) {
connects = connects.concat(this.lines[index].connects);
faceNormals = faceNormals.concat(this.lines[index].normals);
index = -1;
}
else {
var normal = a.sub(b).normal().normalize(); var normal = a.sub(b).normal().normalize();
var faceNormal = faceNormals[Math.floor(j/2)]; var faceNormal = faceNormals[Math.floor(j/2)];
if (normal.dot(faceNormal) > 0) { if (normal.dot(faceNormal) >= 0) {
//if (true) {
break; break;
} }
else { else {
index = -1; index = -1;
} }
} }
}
else { else {
index = -1; index = -1;
} }
@ -205,11 +237,12 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
//think this check is not nescesary, always higher as 0 //think this check is not nescesary, always higher as 0
if (shape.length > 0) { if (shape.length > 0) {
slice.push(new D3D.Paths([shape])); slice.push(new D3D.Paths([shape], true));
} }
} }
} }
var layerParts = []; var layerParts = [];
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
@ -237,8 +270,10 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
else { else {
break; break;
} }
}
this.progress.sliceLayer = layer;
this.updateProgress();
}
return slices; return slices;
}; };
D3D.Slicer.prototype.slicesToData = function (slices, printer) { D3D.Slicer.prototype.slicesToData = function (slices, printer) {
@ -246,23 +281,25 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) {
var scale = 100; var scale = 100;
var layerHeight = printer.config["printer.layerHeight"] * scale; var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
var nozzleDiameter = printer.config["printer.nozzleDiameter"] * scale; var nozzleDiameter = printer.config["printer.nozzleDiameter"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale; var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale; var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale; var brimOffset = printer.config["printer.brimOffset"] * scale;
var bottomThickness = printer.config["printer.bottomThickness"] * scale; var bottomThickness = printer.config["printer.bottomThickness"];
var topThickness = printer.config["printer.topThickness"] * scale; var topThickness = printer.config["printer.topThickness"];
var useSupport = printer.config["printer.support.use"];
var supportGritSize = printer.config["printer.support.gritSize"] * scale;
var supportAccaptanceSize = printer.config["printer.support.accaptanceSize"] * scale;
var supportMargin = printer.config["printer.support.margin"] * scale;
var plateSize = printer.config["printer.support.plateSize"] * scale;
var supportDistanceY = printer.config["printer.support.distanceY"];
var supportDistanceLayers = Math.ceil(supportDistanceY / layerHeight);
var bottomSkinCount = Math.ceil(bottomThickness/layerHeight); var bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
var topSkinCount = Math.ceil(topThickness/layerHeight); var topSkinCount = Math.ceil(topThickness/layerHeight);
var nozzleRadius = nozzleDiameter / 2; var nozzleRadius = nozzleDiameter / 2;
var start = new THREE.Vector2(0, 0);
var data = [];
var lowFillTemplate = this.getFillTemplate({ var lowFillTemplate = this.getFillTemplate({
left: this.geometry.boundingBox.min.z * scale, left: this.geometry.boundingBox.min.z * scale,
top: this.geometry.boundingBox.min.x * scale, top: this.geometry.boundingBox.min.x * scale,
@ -270,45 +307,64 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) {
bottom: this.geometry.boundingBox.max.x * scale bottom: this.geometry.boundingBox.max.x * scale
}, fillSize, true, true); }, fillSize, true, true);
var data = [];
//generate outerLayer and insets
for (var layer = 0; layer < slices.length; layer ++) { for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer]; var slice = slices[layer];
var layerData = []; var layerData = [];
data.push(layerData); data.push(layerData);
var downSkin = new D3D.Paths([], true);
if (layer - bottomSkinCount >= 0) {
var downLayer = slices[layer - bottomSkinCount];
for (var i = 0; i < downLayer.length; i ++) {
downSkin.join(downLayer[i]);
}
}
var upSkin = new D3D.Paths([], true);
if (layer + topSkinCount < slices.length) {
var upLayer = slices[layer + topSkinCount];
for (var i = 0; i < upLayer.length; i ++) {
upSkin.join(upLayer[i]);
}
}
var surroundingLayer = upSkin.intersect(downSkin).scaleUp(scale);
var sliceData = [];
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
var part = slice[i]; var part = slice[i];
//var outerLayer = part.clone();
var outerLayer = part.clone().scaleUp(scale).offset(-nozzleRadius); var outerLayer = part.clone().scaleUp(scale).offset(-nozzleRadius);
if (outerLayer.length > 0) {
var insets = new D3D.Paths([], true); var insets = new D3D.Paths([], true);
if (outerLayer.length > 0) {
for (var offset = nozzleDiameter; offset <= shellThickness; offset += nozzleDiameter) { for (var offset = nozzleDiameter; offset <= shellThickness; offset += nozzleDiameter) {
var inset = outerLayer.offset(-offset); var inset = outerLayer.offset(-offset);
insets.join(inset); insets.join(inset);
} }
var fillArea = (inset || outerLayer).offset(-nozzleRadius); layerData.push({
//var fillArea = (inset || outerLayer).clone(); outerLayer: outerLayer,
insets: insets
});
}
}
}
//generate infills
for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer];
var downSkin = new D3D.Paths([], true);
if (layer - bottomSkinCount >= 0) {
var downLayer = data[layer - bottomSkinCount];
for (var i = 0; i < downLayer.length; i ++) {
downSkin.join(downLayer[i].outerLayer);
}
}
var upSkin = new D3D.Paths([], true);
if (layer + topSkinCount < data.length) {
var upLayer = data[layer + topSkinCount];
for (var i = 0; i < upLayer.length; i ++) {
upSkin.join(upLayer[i].outerLayer);
}
}
var surroundingLayer = upSkin.intersect(downSkin);
var sliceData = [];
for (var i = 0; i < slice.length; i ++) {
var part = slice[i];
var outerLayer = part.outerLayer;
var insets = part.insets;
if (outerLayer.length > 0) {
var fillArea = ((insets.length > 0) ? insets : outerLayer).offset(-nozzleRadius);
var highFillArea = fillArea.difference(surroundingLayer); var highFillArea = fillArea.difference(surroundingLayer);
var lowFillArea = fillArea.difference(highFillArea); var lowFillArea = fillArea.difference(highFillArea);
@ -325,36 +381,107 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) {
fill.join(highFillTemplate.intersect(highFillArea)); fill.join(highFillTemplate.intersect(highFillArea));
} }
outerLayer = outerLayer.optimizePath(start); part.fill = fill;
if (insets.length > 0) {
insets = insets.optimizePath(outerLayer.lastPoint());
fill = fill.optimizePath(insets.lastPoint());
} }
else {
fill = fill.optimizePath(outerLayer.lastPoint());
} }
if (fill.length > 0) { this.progress.dataLayer = layer;
start = fill.lastPoint(); this.updateProgress();
}
else if (insets.length > 0) {
start = insets.lastPoint();
}
else {
start = outerLayer.lastPoint();
} }
layerData.push({ //generate support
outerLayer: outerLayer.scaleDown(scale), if (useSupport) {
fill: fill.scaleDown(scale), var supportTemplate = this.getFillTemplate({
insets: insets.scaleDown(scale) left: this.geometry.boundingBox.min.z * scale,
}); top: this.geometry.boundingBox.min.x * scale,
right: this.geometry.boundingBox.max.z * scale,
bottom: this.geometry.boundingBox.max.x * scale
}, supportGritSize, true, true);
var supportAreas = new D3D.Paths([], true);
for (var layer = data.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
if (supportAreas.length > 0) {
if (layer >= supportDistanceLayers) {
var sliceSkin = new D3D.Paths([], true);
var slice = data[layer - supportDistanceLayers];
for (var i = 0; i < slice.length; i ++) {
sliceSkin.join(slice[i].outerLayer);
}
sliceSkin = sliceSkin.offset(supportMargin);
supportAreas = supportAreas.difference(sliceSkin);
}
var currentSlice = data[layer];
if (layer === 0) {
supportAreas = supportAreas.offset(plateSize).difference(sliceSkin);
var template = this.getFillTemplate(supportAreas.bounds(), nozzleDiameter, true, false);
currentSlice[0].support = template.intersect(supportAreas);
}
else {
currentSlice[0].support = supportTemplate.intersect(supportAreas).join(supportAreas.clone());
}
}
var supportSlice = data[layer + supportDistanceLayers - 1];
var supportSkin = new D3D.Paths([], true);
for (var i = 0; i < supportSlice.length; i ++) {
//supportSkin = supportSkin.union(supportSlice[i].outerLayer);
supportSkin.join(supportSlice[i].outerLayer);
}
var slice = data[layer + supportDistanceLayers];
for (var i = 0; i < slice.length; i ++) {
var slicePart = slice[i];
var outerLayer = slicePart.outerLayer;
var overlap = supportSkin.offset(supportAccaptanceSize).intersect(outerLayer);
var overhang = outerLayer.difference(overlap);
if (overlap.length === 0 || overhang.length > 0) {
var supportArea = outerLayer.difference(supportSkin.intersect(outerLayer));
supportAreas = supportAreas.union(supportArea);
}
}
}
}
//finalize paths
var start = new THREE.Vector2(0, 0);
var order = ["outerLayer", "insets", "fill", "support"];
for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer];
for (var i = 0; i < slice.length; i ++) {
var part = slice[i];
for (var j = 0; j < order.length; j ++) {
var property = order[j];
if (part[property] !== undefined && part[property].length > 0) {
part[property] = part[property].optimizePath(start);
start = part[property].lastPoint();
}
}
part.outerLayer.scaleDown(100);
part.insets.scaleDown(100);
part.fill.scaleDown(100);
if (part.support !== undefined) {
part.support.scaleDown(100);
} }
} }
} }
return data; return data;
}; };
D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) { D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) {
"use strict"; "use strict";
@ -374,154 +501,74 @@ D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) {
//return paths; //return paths;
return paths; return paths;
}; };
D3D.Slicer.prototype.dataToGcode = function (data, printer) { D3D.Slicer.prototype.dataToGCode = function (data, printer) {
"use strict"; "use strict";
var layerHeight = printer.config["printer.layerHeight"]; var gcode = new D3D.GCode().setSettings(printer);
var normalSpeed = printer.config["printer.speed"];
var bottomSpeed = printer.config["printer.bottomLayerSpeed"];
var firstLayerSlow = printer.config["printer.firstLayerSlow"];
var bottomFlowRate = printer.config["printer.bottomFlowRate"];
var normalFlowRate = printer.config["printer.normalFlowRate"];
var travelSpeed = printer.config["printer.travelSpeed"];
var filamentThickness = printer.config["printer.filamentThickness"];
var nozzleDiameter = printer.config["printer.nozzleDiameter"];
var enableTraveling = printer.config["printer.enableTraveling"];
var retractionEnabled = printer.config["printer.retraction.enabled"];
var retractionSpeed = printer.config["printer.retraction.speed"];
var retractionMinDistance = printer.config["printer.retraction.minDistance"];
var retractionAmount = printer.config["printer.retraction.amount"];
function sliceToGcode (path) {
var gcode = [];
function sliceToGCode (path, retract, unRetract) {
for (var i = 0; i < path.length; i ++) { for (var i = 0; i < path.length; i ++) {
var shape = path[i]; var shape = path[i];
var previousPoint;
var length = path.closed ? (shape.length + 1) : shape.length; var length = path.closed ? (shape.length + 1) : shape.length;
for (var j = 0; j < length; j ++) { for (var j = 0; j < length; j ++) {
var point = shape[j % shape.length]; var point = shape[j % shape.length];
if (j === 0) { if (j === 0) {
//TODO gcode.moveTo(false, point.X, point.Y, layer);
//add retraction
gcode.push([ if (unRetract) {
"G0", gcode.unRetract();
"X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
"F" + (travelSpeed * 60)
].join(" "));
if (extruder > retractionMinDistance && retractionEnabled && j === 0) {
gcode.push([
"G0",
"E" + extruder.toFixed(3),
"F" + (retractionSpeed * 60).toFixed(3)
].join(" "));
} }
} }
else { else {
var a = new THREE.Vector2(point.X, point.Y); gcode.moveTo(true, point.X, point.Y, layer);
var b = new THREE.Vector2(previousPoint.X, previousPoint.Y);
var lineLength = a.distanceTo(b);
extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
gcode.push([
"G1",
"X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
"F" + speed,
"E" + extruder.toFixed(3)
].join(" "));
} }
previousPoint = point;
} }
} }
if (extruder > retractionMinDistance && retractionEnabled) { if (retract) {
gcode.push([ gcode.retract();
"G0",
"E" + (extruder - retractionAmount).toFixed(3),
"F" + (retractionSpeed * 60).toFixed(3)
].join(" "));
} }
return gcode;
} }
var gcode = printer.getStartCode();
var extruder = 0.0;
var speed = firstLayerSlow ? (bottomSpeed*60).toFixed(3) : (normalSpeed*60).toFixed(3);
var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
var flowRate = bottomFlowRate;
for (var layer = 0; layer < data.length; layer ++) { for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer]; var slice = data[layer];
//turn on fan on layer 1
if (layer === 1) { if (layer === 1) {
gcode.push("M106"); gcode.turnFanOn();
speed = (normalSpeed*60).toFixed(3); gcode.bottom = false;
flowRate = normalFlowRate;
} }
var z = ((layer + 1) * layerHeight).toFixed(3);
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
var layerPart = slice[i]; var layerPart = slice[i];
gcode = gcode.concat(sliceToGcode(layerPart.outerLayer)); sliceToGCode(layerPart.outerLayer, false, true);
gcode = gcode.concat(sliceToGcode(layerPart.insets)); sliceToGCode(layerPart.insets, false, false);
gcode = gcode.concat(sliceToGcode(layerPart.fill)); sliceToGCode(layerPart.fill, true, false);
if (layerPart.support !== undefined) {
sliceToGCode(layerPart.support, true, true);
} }
} }
gcode = gcode.concat(printer.getEndCode()); this.progress.gcodeLayer = layer;
this.updateProgress();
}
return gcode; return gcode.getGCode();
}; };
//only for debug purposes D3D.Slicer.prototype.getGCode = function (printer) {
D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
"use strict"; "use strict";
var layerHeight = printer.config["printer.layerHeight"]; var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"]; var dimensionsZ = printer.config["printer.dimensions.z"];
var slices = this.slice(layerHeight, dimensionsZ); this.progress.totalLayers = Math.floor(Math.min(this.geometry.boundingBox.max.y, dimensionsZ) / layerHeight);
this.progress.sliceLayer = 0;
var data = this.slicesToData(slices, printer); this.progress.dataLayer = 0;
this.progress.gcodeLayer = 0;
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 400;
var context = canvas.getContext("2d");
for (var layer = min; layer < max; layer ++) {
var slice = data[layer % data.length];
for (var i = 0; i < slice.length; i ++) {
var layerPart = slice[i];
layerPart.insets.draw(context, "blue");
layerPart.outerLayer.draw(context, "green");
layerPart.fill.draw(context, "red");
}
}
return canvas;
};
D3D.Slicer.prototype.getGcode = function (printer) {
"use strict";
var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"];
var start = new Date().getTime(); var start = new Date().getTime();
var slices = this.slice(layerHeight, dimensionsZ); var slices = this.slice(layerHeight, dimensionsZ);
@ -534,7 +581,7 @@ D3D.Slicer.prototype.getGcode = function (printer) {
console.log("Data: " + (end - start) + "ms"); console.log("Data: " + (end - start) + "ms");
start = new Date().getTime(); start = new Date().getTime();
var gcode = this.dataToGcode(data, printer); var gcode = this.dataToGCode(data, printer);
end = new Date().getTime(); end = new Date().getTime();
console.log("Gcode: " + (end - start) + "ms"); console.log("Gcode: " + (end - start) + "ms");

78
src/slicerworker.js Normal file
View File

@ -0,0 +1,78 @@
D3D.SlicerWorker = function () {
'use strict';
this.worker = new Worker('webworker/worker.js');
var scope = this;
this.worker.addEventListener('message', function (event) {
switch (event.data['cmd']) {
case 'PROGRESS':
if (scope.onprogress !== undefined) {
var progress = event.data['progress'];
scope.onprogress(progress);
}
break;
case 'GCODE':
if (scope.onfinish !== undefined) {
var gcode = event.data['gcode'];
scope.onfinish(gcode);
}
break;
}
}, false);
}
D3D.SlicerWorker.prototype.setSettings = function (USER_SETTINGS, PRINTER_SETTINGS) {
'use strict';
this.worker.postMessage({
'cmd': 'SET_SETTINGS',
'USER_SETTINGS': USER_SETTINGS,
'PRINTER_SETTINGS': PRINTER_SETTINGS
});
};
D3D.SlicerWorker.prototype.setMesh = function (mesh) {
'use strict';
if (mesh.geometry instanceof THREE.Geometry) {
var geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);
}
else {
var geometry = mesh.geometry.clone();
}
var buffers = [];
for (var i = 0; i < geometry.attributesKeys.length; i ++) {
var key = geometry.attributesKeys[i];
buffers.push(geometry.attributes[key].array.buffer);
}
mesh.updateMatrix();
this.worker.postMessage({
'cmd': 'SET_MESH',
'geometry': {
'attributes': geometry.attributes,
'attributesKeys': geometry.attributesKeys
},
'matrix': mesh.matrix.toArray()
}, buffers);
};
D3D.SlicerWorker.prototype.slice = function () {
'use strict';
this.worker.postMessage({
'cmd': 'SLICE'
});
};
D3D.SlicerWorker.prototype.close = function () {
'use strict';
this.worker.postMessage({
'cmd': 'CLOSE'
});
};

View File

@ -1,7 +1,7 @@
/****************************************************** /******************************************************
* *
* Utils * Utils
* requires jQuery, Three.js * dependices Three.js
* *
******************************************************/ ******************************************************/
@ -14,6 +14,37 @@ var D3D = {
function sendAPI (url, data, callback) { function sendAPI (url, data, callback) {
"use strict"; "use strict";
/*
var form = new FormData();
for (var i in data) {
form.append(i, JSON.stringify(data[i]));
}
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.send(data);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.log(request);
console.warn("Failed connecting to " + url);
//sendAPI(url, data, callback);
}
};
*/
$.ajax({ $.ajax({
url: url, url: url,
type: "POST", type: "POST",
@ -38,6 +69,29 @@ function sendAPI (url, data, callback) {
function getAPI (url, callback) { function getAPI (url, callback) {
"use strict"; "use strict";
/*
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.send();
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.warn("Failed connecting to " + url);
sendAPI(url, callback);
}
};*/
$.ajax({ $.ajax({
url: url, url: url,
@ -57,6 +111,7 @@ function getAPI (url, callback) {
console.warn("Failed connecting to " + url); console.warn("Failed connecting to " + url);
getAPI(url, callback); getAPI(url, callback);
}); });
} }
function loadSettings (url, callback) { function loadSettings (url, callback) {

9
webworker/benchmark.js Normal file
View File

@ -0,0 +1,9 @@
self.addEventListener("message", function (event) {
"use strict";
//console.log(event.data);
if (event.data === "close") {
self.close();
}
});

57
webworker/worker.js Normal file
View File

@ -0,0 +1,57 @@
importScripts("../library/three.js");
importScripts("../library/clipper.js");
importScripts("../src/utils.js");
importScripts("../src/printer.js");
importScripts("../src/paths.js");
importScripts("../src/slicer.js");
importScripts("../src/gcode.js");
var printer = new D3D.Printer();
var slicer = new D3D.Slicer();
slicer.onProgress = function (progress) {
"use strict";
self.postMessage({
"cmd": "PROGRESS",
"progress": progress
});
};
self.addEventListener("message", function (event) {
"use strict";
switch (event.data["cmd"]) {
case "SET_MESH":
//hack...
//because boundings loses functions when converting
event.data["geometry"].boundingBox = event.data["geometry"].boundingSphere = null;
var geometry = new THREE.Geometry().fromBufferGeometry(event.data["geometry"]);
var matrix = new THREE.Matrix4().fromArray(event.data["matrix"]);
slicer.setMesh(geometry, matrix);
break;
case "SET_SETTINGS":
printer.updateConfig(event.data["USER_SETTINGS"]);
printer.updateConfig(event.data["PRINTER_SETTINGS"]);
break;
case "SLICE":
var gcode = slicer.getGCode(printer);
self.postMessage({
"cmd": "GCODE",
"gcode": gcode
});
break;
case "CLOSE":
self.close();
break;
}
});

74
webworker_benchmark.html Normal file
View File

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<script src="library/benchmark.js"></script>
<script src="library/three.js"></script>
<title>Doedel Drie Dee || Webworker Benchmark</title>
<style>
</style>
</head>
<body>
<script>
var worker = new Worker('webworker/benchmark.js');
var geometry = new THREE.BoxGeometry(10, 30, 10).clone();
//var geometry = new THREE.TorusKnotGeometry(10, 3, 200, 200).clone();
new Benchmark.Suite().add('Buffer Geometry', function () {
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);
worker.postMessage(bufferGeometry);
//this happens in the worker
var workerGeometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
workerGeometry.mergeVertices();
}).add('Buffer Geometry Transferrable Object', function () {
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);
var buffers = [];
for (var i = 0; i < bufferGeometry.attributesKeys.length; i ++) {
var key = bufferGeometry.attributesKeys[i];
buffers.push(bufferGeometry.attributes[key].array.buffer);
}
worker.postMessage(bufferGeometry, buffers);
//this happens in the worker
//this is redundant...
//buffers are transferred to worker so the do not exist in this part of the script
//[TEST NOT VIABLE]
var workerGeometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
workerGeometry.mergeVertices();
}).add('Geometry JSON', function () {
var json = geometry.toJSON().data;
worker.postMessage(json);
//worker.postMessage(geometry);
//this happens in the worker
var loader = new THREE.JSONLoader();
var workerGeometry = loader.parse(json).geometry;
workerGeometry.mergeVertices();
}).on('cycle', function (event) {
document.body.innerHTML += "<p>" + String(event.target) + "</p>";
}).on('complete', function () {
document.body.innerHTML += "<p>" + 'Fastest is "' + this.filter('fastest').pluck('name') + '"' + "</p>";
}).run({
'async': true
});
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
----------- RESULTATEN TORUS KNOT --------------
Buffer Geometry x 0.53 ops/sec ±134.70% (8 runs sampled)
Buffer Geometry Transferrable Object x 63.04 ops/sec ±2.19% (67 runs sampled)
Geometry JSON x 0.50 ops/sec ±6.55% (6 runs sampled)
Fastest is "Buffer Geometry Transferrable Object"
----------- RESULTATEN KUBUS --------------
Buffer Geometry x 5,360 ops/sec ±19.42% (85 runs sampled)
Buffer Geometry Transferrable Object x 1,535 ops/sec ±10.17% (35 runs sampled)
Geometry JSON x 3,831 ops/sec ±2.52% (82 runs sampled)
Fastest is "Buffer Geometry"

207
webworker_test.html Normal file
View File

@ -0,0 +1,207 @@
<!DOCTYPE HTML>
<html lang='en'>
<head>
<script src='library/jquery.js'></script>
<script src='library/three.js'></script>
<script src='library/stl_loader.js'></script>
<script src='src/utils.js'></script>
<script src='src/box.js'></script>
<script src='src/printer.js'></script>
<script src='src/slicerworker.js'></script>
<title>Doedel Drie Dee || Webworker Test</title>
<style>
canvas {border: 1px solid black;}
#progress {height: 20px; width: 200px; border: 1px solid black; overflow: hidden;}
#progress_bar {height: 20px; background-color: lightblue; width: 0%;}
.block {border: 1px solid black; width: 400px; height: 400px; display: inline-block;}
#start_print, #download {display: none;}
</style>
</head>
<body>
<canvas id='3d-preview' height='400' width='400'></canvas>
<div class='block'>
<p>State: <span id='state'></span></p>
<p>Bed Temp: <span id='bed_temp'></span></p>
<p>Bed Target Temp: <span id='bed_target_temp'></span></p>
<p>Nozzle Temp: <span id='nozzle_temp'></span></p>
<p>Nozzle Target Temp: <span id='nozzle_target_temp'></span></p>
<p>Current Line: <span id='current_line'></span></p>
<p>Buffered Lines: <span id='buffered_lines'></span></p>
<p>Total Lines: <span id='total_lines'></span></p>
<p>Batches To Send: <span id='print_batches'></span></p>
<div id='progress'><div id='progress_bar'></div></div>
<button id="stop_print">Stop Print</button>
<button id="start_print">Start Print</button>
<button id="download">Download Gcode</button>
</div>
<script>
var USER_SETTINGS, PRINTER_SETTINGS, doodleBox, gcode, slicerWorker, printer;
function init () {
'use strict';
var scene = createScene();
var localIp = location.hash.substring(1);
doodleBox = new D3D.Box(localIp);
doodleBox.onupdate = function (data) {
document.getElementById('state').innerHTML = data.state;
document.getElementById('bed_temp').innerHTML = data.bed;
document.getElementById('bed_target_temp').innerHTML = data.bed_target;
document.getElementById('nozzle_temp').innerHTML = data.hotend;
document.getElementById('nozzle_target_temp').innerHTML = data.hotend_target;
document.getElementById('current_line').innerHTML = data.current_line;
document.getElementById('buffered_lines').innerHTML = data.buffered_lines;
document.getElementById('total_lines').innerHTML = data.total_lines;
document.getElementById('print_batches').innerHTML = doodleBox.printBatches.length;
};
printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS['ultimaker2go']);
document.getElementById('stop_print').onclick = function () {
doodleBox.stopPrint(printer);
};
var slicer = new D3D.SlicerWorker();
slicer.setSettings(USER_SETTINGS, PRINTER_SETTINGS['ultimaker2go']);
var progressBar = document.getElementById('progress_bar');
slicer.onprogress = function (progress) {
progressBar.style.width = progress.procent * 100 + '%';
};
slicer.onfinish = function (_gcode) {
gcode = _gcode;
var startPrintButton = document.getElementById('start_print');
var downloadButton = document.getElementById('download');
startPrintButton.style.display = 'initial';
startPrintButton.onclick = function () {
doodleBox.print(gcode);
};
downloadButton.style.display = 'initial';
downloadButton.onclick = function () {
downloadFile("gcode.gcode", gcode.join('\n'));
};
};
var loader = new THREE.STLLoader();
loader.load('models/robot.stl', function (geometry) {
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30).clone();
var material = new THREE.MeshPhongMaterial({color: 0x00ff00, wireframe: false});
//var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;
mesh.position.y = -0.1;
mesh.position.x = 60;
mesh.position.z = 60;
scene.add(mesh);
slicer.setMesh(mesh);
slicer.slice();
slicer.close();
});
}
function createScene () {
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: document.getElementById('3d-preview'), antialias: true});
renderer.setClearColor(0xffffff, 1);
var camera = new THREE.PerspectiveCamera(75, renderer.domElement.width/renderer.domElement.height, 1, 10000);
scene.add(camera);
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
var directionalLight = new THREE.PointLight(0xffffff, 0.5);
camera.add(directionalLight);
applyMouseControls(renderer, camera, new THREE.Vector3(50, 0, 50), 1000);
function applyMouseControls (renderer, camera, center, maxDistance) {
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on('mousedown', function (e) {
moveCamera = true;
}).on('wheel', function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on('mouseup', function (e) {
moveCamera = false;
}).on('mousemove', function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
(function animate () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
})();
return scene;
}
(function () {
'use strict';
var loadedItems = 0;
function loaded () {
loadedItems ++;
if (loadedItems === 2) {
init();
}
}
loadSettings('settings/user_settings.json', function (data) {
USER_SETTINGS = data;
loaded();
});
loadSettings('settings/printer_settings.json', function (data) {
PRINTER_SETTINGS = data;
loaded();
});
})();
</script>
</body>
</html>