diff --git a/README.md b/README.md index 186d94f..06beefa 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,20 @@ This is an example of code. var localIp = "192.168.5.1"; var doodleBox = new D3D.Box(localIp); -var geometry = new THREE.BoxGeometry(20, 20, 20, 1, 1, 1); -var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}); -var mesh = new THREE.Mesh(geometry, material); -mesh.position.x = 100; -mesh.position.z = 100; -mesh.position.y = 10; - doodleBox.onload = function () { "use strict"; + + var printer = new D3D.Printer(printerSettings, userSettings); + + var geometry = new THREE.BoxGeometry(20, 20, 20, 1, 1, 1); + var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}); + var mesh = new THREE.Mesh(geometry, material); + mesh.position.x = 100; + mesh.position.z = 100; + mesh.position.y = 10; var slicer = new D3D.Slicer().setMesh(mesh); - var gcode = slicer.getGcode(doodleBox.printer); + var gcode = slicer.getGcode(printer); doodleBox.print(gcode); }; diff --git a/build/d3d.js b/build/d3d.js index 404f625..a6f5bde 100644 --- a/build/d3d.js +++ b/build/d3d.js @@ -11,16 +11,6 @@ var D3D = { "contact": "develop@doodle3d.com" }; -//add normal function to Three.js Vector class -THREE.Vector2.prototype.normal = function () { - "use strict"; - - var x = this.y; - var y = -this.x; - - return this.set(x, y); -}; - function sendAPI (url, data, callback) { "use strict"; @@ -69,18 +59,33 @@ function getAPI (url, callback) { }); } +function loadSettings (url, callback) { + "use strict"; + + $.ajax({ + url: url, + dataType: "json", + success: function (response) { + if (callback !== undefined) { + callback(response); + } + } + }); +} + function downloadFile (file, data) { "use strict"; - - $(document.createElement("a")).attr({ - download: file, - href: "data:text/plain," + data - })[0].click(); + + var blob = new Blob([data], {type:'text/plain'}); + + var button = document.createElement("a"); + button.download = file; + button.href = window.URL.createObjectURL(blob); + button.click(); } Array.prototype.clone = function () { "use strict"; - var array = []; for (var i = 0; i < this.length; i ++) { @@ -88,7 +93,7 @@ Array.prototype.clone = function () { } return array; -}; +} /****************************************************** * * Box @@ -114,6 +119,7 @@ D3D.Box = function (localIp) { this.api = "http://" + localIp + "/d3dapi/"; this.config = {}; + this.status = {}; this.printBatches = []; this.currentBatch = 0; @@ -123,7 +129,6 @@ D3D.Box = function (localIp) { this.getConfigAll(function (data) { self.updateConfig(data); - self.printer = new D3D.Printer(data); self.update(); self.loaded = true; @@ -136,9 +141,7 @@ D3D.Box.prototype.updateConfig = function (config) { "use strict"; for (var i in config) { - if (i.indexOf("doodle3d") === 0) { - this.config[i] = config[i]; - } + this.config[i] = config[i]; } return this; @@ -150,7 +153,7 @@ D3D.Box.prototype.update = function () { //Bij error wordt gelijk zelfde data opnieuw gestuurd //Als DoodleBox ontkoppeld wordt komt er een error in de loop waardoor pagina breekt en ververst moet worden - if (this.printBatches.length > 0 && (this.printer.status["buffered_lines"] + this.batchSize) <= this.maxBufferedLines) { + if (this.printBatches.length > 0 && (this.status["buffered_lines"] + this.batchSize) <= this.maxBufferedLines) { //if (this.printBatches.length > 0 ) { this.printBatch(); } @@ -164,7 +167,7 @@ D3D.Box.prototype.updateState = function () { var self = this; this.getInfoStatus(function (data) { - self.printer.status = data; + self.status = data; if (self.onupdate !== undefined) { self.onupdate(data); @@ -264,12 +267,10 @@ D3D.Box.prototype.setConfig = function (data, callback) { sendAPI(this.api + "config", data, function (response) { for (var i in response.validation) { - if (response.validation[i] !== "ok") { - delete data[i]; + if (response.validation[i] === "ok") { + self[i] = data[i]; } } - self.updateConfig(data); - self.printer.updateConfig(data); if (callback !== undefined) { callback(response); @@ -497,13 +498,13 @@ D3D.Box.prototype.setUpdateClear = function (callback) { * ******************************************************/ -D3D.Printer = function (config) { +D3D.Printer = function (printerSettings, userSettings) { "use strict"; - this.status = {}; this.config = {}; - this.updateConfig(config); + this.updateConfig(printerSettings); + this.updateConfig(userSettings); }; D3D.Printer.prototype.updateConfig = function (config) { "use strict"; @@ -793,8 +794,6 @@ D3D.Paths.prototype.draw = function (context, color) { D3D.Slicer = function () { "use strict"; - - this.lines = []; }; D3D.Slicer.prototype.setMesh = function (mesh) { "use strict"; @@ -823,7 +822,8 @@ D3D.Slicer.prototype.setMesh = function (mesh) { mesh.updateMatrix(); geometry.applyMatrix(mesh.matrix); geometry.computeFaceNormals(); - + geometry.computeBoundingBox(); + this.geometry = geometry; //get unique lines from geometry; @@ -841,7 +841,7 @@ D3D.Slicer.prototype.createLines = function () { function addLine (a, b) { //think lookup can only be b_a, a_b is only possible when face is flipped - var index = lineLookup[a + "_" + b] || lineLookup[b + "_" + a]; + var index = lineLookup[b + "_" + a] || lineLookup[a + "_" + b]; if (index === undefined) { index = self.lines.length; @@ -861,8 +861,8 @@ D3D.Slicer.prototype.createLines = function () { 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().set(face.normal.x, face.normal.z).normalize(); + if (face.normal.y !== 1 && face.normal.y !== -1) { + var normal = new THREE.Vector2().set(face.normal.z, face.normal.x).normalize(); //check for only adding unique lines //returns index of said line @@ -878,7 +878,7 @@ D3D.Slicer.prototype.createLines = function () { this.lines[a].normals.push(normal); this.lines[b].normals.push(normal); this.lines[c].normals.push(normal); - //} + } } }; D3D.Slicer.prototype.slice = function (height, step) { @@ -904,7 +904,10 @@ D3D.Slicer.prototype.slice = function (height, step) { var slices = []; + //still error in first layer, so remove first layer & last layer + //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 ++) { var layerIntersections = layersIntersections[layer]; var y = layer*step; @@ -917,11 +920,11 @@ D3D.Slicer.prototype.slice = function (height, step) { var x = line.end.x * alpha + line.start.x * (1 - alpha); var z = line.end.z * alpha + line.start.z * (1 - alpha); - intersections[index] = new THREE.Vector2(x, z); + intersections[index] = new THREE.Vector2(z, x); } var done = []; - var slice = new D3D.Paths([], true); + var slice = []; for (var i = 0; i < layerIntersections.length; i ++) { var index = layerIntersections[i]; @@ -940,7 +943,7 @@ D3D.Slicer.prototype.slice = function (height, step) { index = connects[j]; if (intersections[index] && done.indexOf(index) === -1) { - var a = new THREE.Vector2().set(intersection.x, intersection.y); + var a = new THREE.Vector2(intersection.x, intersection.y); var b = intersections[index]; var normal = a.sub(b).normal().normalize(); var faceNormal = faceNormals[Math.floor(j/2)]; @@ -1025,21 +1028,25 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) { var layerHeight = printer.config["printer.layerHeight"] * scale; var dimensionsZ = printer.config["printer.dimensions.z"] * scale; - var wallThickness = printer.config["printer.wallThickness"] * scale; + var wallThickness = printer.config["printer.wallThickness"] * scale / 2; var shellThickness = printer.config["printer.shellThickness"] * scale; var fillSize = printer.config["printer.fillSize"] * scale; var brimOffset = printer.config["printer.brimOffset"] * scale; - var skinCount = Math.ceil(shellThickness/layerHeight); + var bottomThickness = printer.config["printer.bottomThickness"] * scale; + var topThickness = printer.config["printer.topThickness"] * scale; + + var bottomSkinCount = Math.ceil(bottomThickness/layerHeight); + var topSkinCount = Math.ceil(topThickness/layerHeight); var start = new THREE.Vector2(0, 0); var data = []; var lowFillTemplate = this.getFillTemplate({ - left: 0, - top: 0, - right: dimensionsZ, - bottom: dimensionsZ + 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 }, fillSize, true, true); for (var layer = 0; layer < slices.length; layer ++) { @@ -1049,78 +1056,81 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) { data.push(layerData); var downSkin = new D3D.Paths([], true); - if (layer - skinCount >= 0) { - var downLayer = slices[layer - skinCount]; + 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 + skinCount < slices.length) { - var downLayer = slices[layer + skinCount]; + if (layer + topSkinCount < slices.length) { + var downLayer = slices[layer + topSkinCount]; for (var i = 0; i < downLayer.length; i ++) { upSkin.join(downLayer[i]); } } - var surroundingLayer = upSkin.intersect(downSkin).clone().scaleUp(scale); + var surroundingLayer = upSkin.intersect(downSkin).scaleUp(scale); var sliceData = []; for (var i = 0; i < slice.length; i ++) { var part = slice[i]; - var outerLayer = part.clone(); - outerLayer.scaleUp(scale); + //var outerLayer = part.clone(); + var outerLayer = part.clone().scaleUp(scale).offset(-wallThickness/2); - var insets = new D3D.Paths([], true); - for (var offset = wallThickness; offset <= shellThickness; offset += wallThickness) { - var inset = outerLayer.offset(-offset); + if (outerLayer.length > 0) { + var insets = new D3D.Paths([], true); + for (var offset = wallThickness; offset <= shellThickness; offset += wallThickness) { + var inset = outerLayer.offset(-offset); - insets.join(inset); - } + insets.join(inset); + } - var fillArea = (inset || outerLayer).offset(-wallThickness/2); - //var fillArea = (inset || outerLayer).clone(); + var fillArea = (inset || outerLayer).offset(-wallThickness/2); + //var fillArea = (inset || outerLayer).clone(); - var highFillArea = fillArea.difference(surroundingLayer); + var highFillArea = fillArea.difference(surroundingLayer); - var lowFillArea = fillArea.difference(highFillArea); + var lowFillArea = fillArea.difference(highFillArea); - var fill = new D3D.Paths([], false); + var fill = new D3D.Paths([], false); - if (lowFillTemplate.length > 0) { - fill.join(lowFillTemplate.intersect(lowFillArea)); - } + if (lowFillTemplate.length > 0) { + fill.join(lowFillTemplate.intersect(lowFillArea)); + } - if (highFillArea.length > 0) { - var bounds = highFillArea.bounds(); - var even = (layer % 2 === 0); - var highFillTemplate = this.getFillTemplate(bounds, wallThickness, even, !even); - fill.join(highFillTemplate.intersect(highFillArea)); + if (highFillArea.length > 0) { + var bounds = highFillArea.bounds(); + var even = (layer % 2 === 0); + var highFillTemplate = this.getFillTemplate(bounds, wallThickness, even, !even); + fill.join(highFillTemplate.intersect(highFillArea)); + } + + outerLayer = outerLayer.optimizePath(start); + if (insets.length > 0) { + insets = insets.optimizePath(outerLayer.lastPoint()); + fill = fill.optimizePath(insets.lastPoint()); + } + else { + fill = fill.optimizePath(outerLayer.lastPoint()); + } + + if (fill.length > 0) { + start = fill.lastPoint(); + } + else if (insets.length > 0) { + start = insets.lastPoint(); + } + else { + start = outerLayer.lastPoint(); + } + + layerData.push({ + outerLayer: outerLayer.scaleDown(scale), + fill: fill.scaleDown(scale), + insets: insets.scaleDown(scale) + }); } - - outerLayer = outerLayer.optimizePath(start); - if (insets.length > 0) { - insets = insets.optimizePath(outerLayer.lastPoint()); - fill = fill.optimizePath(insets.lastPoint()); - } - else { - fill = fill.optimizePath(outerLayer.lastPoint()); - } - if (fill.length > 0) { - start = fill.lastPoint(); - } - else if (insets.length > 0) { - start = insets.lastPoint(); - } - else { - start = outerLayer.lastPoint(); - } - - layerData.push({ - outerLayer: outerLayer.scaleDown(scale), - fill: fill.scaleDown(scale), - insets: insets.scaleDown(scale) - }); } } @@ -1132,12 +1142,12 @@ D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) { var paths = new D3D.Paths([], false); if (even) { - for (var length = Math.floor(bounds.left); length <= Math.ceil(bounds.right); length += size) { + for (var length = Math.floor(bounds.left/size)*size; length <= Math.ceil(bounds.right/size)*size; length += size) { paths.push([{X: length, Y: bounds.top}, {X: length, Y: bounds.bottom}]); } } if (uneven) { - for (var length = Math.floor(bounds.top); length <= Math.floor(bounds.bottom); length += size) { + for (var length = Math.floor(bounds.top/size)*size; length <= Math.floor(bounds.bottom/size)*size; length += size) { paths.push([{X: bounds.left, Y: length}, {X: bounds.right, Y: length}]); } } @@ -1201,8 +1211,8 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) { } } else { - var a = new THREE.Vector2().set(point.X, point.Y); - var b = new THREE.Vector2().set(previousPoint.X, previousPoint.Y); + var a = new THREE.Vector2(point.X, point.Y); + var b = new THREE.Vector2(previousPoint.X, previousPoint.Y); var lineLength = a.distanceTo(b); extruder += lineLength * wallThickness * layerHeight / filamentSurfaceArea * flowRate; @@ -1251,6 +1261,7 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) { } gcode = gcode.concat(printer.getEndCode()); + return gcode; }; //only for debug purposes @@ -1292,29 +1303,16 @@ D3D.Slicer.prototype.getGcode = function (printer) { var start = new Date().getTime(); var slices = this.slice(dimensionsZ, layerHeight); var end = new Date().getTime(); - console.log("Slicing: " + (end - start) + "ms"); - //still error in first layer, so remove first layer - //see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1 - var start = new Date().getTime(); var data = this.slicesToData(slices, printer); var end = new Date().getTime(); - console.log("Data: " + (end - start) + "ms"); - //return data; - - //TODO - //make the path more optimized for 3d printers - //make the printer follow the shortest path from line to line - //see https://github.com/Ultimaker/CuraEngine#gcode-generation - var start = new Date().getTime(); var gcode = this.dataToGcode(data, printer); var end = new Date().getTime(); - console.log("Gcode: " + (end - start) + "ms"); return gcode; diff --git a/build/d3d.min.js b/build/d3d.min.js index 9c55cb2..a450e98 100644 --- a/build/d3d.min.js +++ b/build/d3d.min.js @@ -1 +1 @@ -function sendAPI(t,e,i){"use strict";$.ajax({url:t,type:"POST",data:e,dataType:"json",timeout:1e4,success:function(t){"success"===t.status?void 0!==i&&i(t.data):console.warn(t.msg)}}).fail(function(){console.warn("Failed connecting to "+t),sendAPI(t,e,i)})}function getAPI(t,e){"use strict";$.ajax({url:t,dataType:"json",timeout:5e3,success:function(t){"success"===t.status?void 0!==e&&e(t.data):console.warn(t.msg)}}).fail(function(){console.warn("Failed connecting to "+t),getAPI(t,e)})}function downloadFile(t,e){"use strict";$(document.createElement("a")).attr({download:t,href:"data:text/plain,"+e})[0].click()}var D3D={version:"0.1",website:"http://www.doodle3d.com/",contact:"develop@doodle3d.com"};THREE.Vector2.prototype.normal=function(){"use strict";var t=this.y,e=-this.x;return this.set(t,e)},Array.prototype.clone=function(){"use strict";for(var t=[],e=0;e0&&this.printer.status.buffered_lines+this.batchSize<=this.maxBufferedLines?this.printBatch():this.updateState()},D3D.Box.prototype.updateState=function(){"use strict";var t=this;this.getInfoStatus(function(e){t.printer.status=e,void 0!==t.onupdate&&t.onupdate(e),t.update()})},D3D.Box.prototype.print=function(t){"use strict";for(this.currentBatch=0,t=t.clone();t.length>0;){var e=t.splice(0,Math.min(this.batchSize,t.length));this.printBatches.push(e)}return this},D3D.Box.prototype.printBatch=function(){"use strict";var t=this,e=this.printBatches.shift();this.setPrinterPrint({start:0===this.currentBatch?!0:!1,first:0===this.currentBatch?!0:!1,gcode:e.join("\n")},function(e){console.log("batch sent: "+t.currentBatch,e),t.printBatches.length>0&&t.currentBatch++,t.updateState()})},D3D.Box.prototype.stopPrint=function(){"use strict";this.printBatches=[],this.currentBatch=0;var t=["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)"];return this.setPrinterStop({gcode:t.join("\n")},function(t){console.log("Printer stop command sent")}),this},D3D.Box.prototype.getConfig=function(t,e){"use strict";return getAPI(this.api+"config/?"+t.join("=&")+"=",e),this},D3D.Box.prototype.getConfigAll=function(t){"use strict";return getAPI(this.api+"config/all",t),this},D3D.Box.prototype.setConfig=function(t,e){"use strict";var i=this;return sendAPI(this.api+"config",t,function(r){for(var n in r.validation)"ok"!==r.validation[n]&&delete t[n];i.updateConfig(t),i.printer.updateConfig(t),void 0!==e&&e(r)}),this},D3D.Box.prototype.getInfo=function(t){"use strict";return getAPI(this.api+"info",t),this},D3D.Box.prototype.getInfoStatus=function(t){"use strict";return getAPI(this.api+"info/status",t),this},D3D.Box.prototype.downloadInfoLogFiles=function(){"use strict";window.location=this.api+"info/logfiles"},D3D.Box.prototype.getInfoAcces=function(t){"use strict";return getAPI(this.api+"info/access",t),this},D3D.Box.prototype.getNetworkScan=function(t){"use strict";return getAPI(this.api+"network/scan",t),this},D3D.Box.prototype.getNetworkKnown=function(t){"use strict";return getAPI(this.api+"network/known",t),this},D3D.Box.prototype.getNetworkStatus=function(t){"use strict";return getAPI(this.api+"network/status",t),this},D3D.Box.prototype.setNetworkAssosiate=function(t,e){"use strict";return sendAPI(this.api+"network/associate",t,e),this},D3D.Box.prototype.setNetworkDisassosiate=function(t){"use strict";return sendAPI(this.api+"network/disassociate",{},t),this},D3D.Box.prototype.setNetworkOpenAP=function(t){"use strict";return sendAPI(this.api+"network/openap",{},t),this},D3D.Box.prototype.setNetworkRemove=function(t,e){"use strict";return sendAPI(this.api+"network/remove",{ssid:t},e),this},D3D.Box.prototype.getNetworkSignin=function(t){"use strict";return getAPI(this.api+"network/signin",t),this},D3D.Box.prototype.getNetworkAlive=function(t){"use strict";return getAPI(this.api+"network/alive",t),this},D3D.Box.prototype.getPrinterTemperature=function(t){"use strict";return getAPI(this.api+"printer/temperature",t),this},D3D.Box.prototype.getPrinterProgress=function(t){"use strict";return getAPI(this.api+"printer/progress",t),this},D3D.Box.prototype.getPrinterState=function(t){"use strict";return getAPI(this.api+"printer/state",t),this},D3D.Box.prototype.getPrinterListAll=function(t){"use strict";return getAPI(this.api+"printer/listall",t),this},D3D.Box.prototype.setPrinterHeatup=function(t){"use strict";return sendAPI(this.api+"printer/heatup",{},t),this},D3D.Box.prototype.setPrinterPrint=function(t,e){"use strict";return sendAPI(this.api+"printer/print",t,e),this},D3D.Box.prototype.setPrinterStop=function(t,e){"use strict";return sendAPI(this.api+"printer/stop",t,e),this},D3D.Box.prototype.getSketch=function(t,e){"use strict";return getAPI(this.api+"sketch/?id="+t,e),this},D3D.Box.prototype.setSketch=function(t,e){"use strict";return sendAPI(this.api+"sketch",{data:t},e),this},D3D.Box.prototype.getSketchStatus=function(t){"use strict";return getAPI(this.api+"sketch/status",t),this},D3D.Box.prototype.setSketchClear=function(t){"use strict";return sendAPI(this.api+"sketch/clear",t),this},D3D.Box.prototype.getSystemVersions=function(t){"use strict";return getAPI(this.api+"system/fwversions",t),this},D3D.Box.prototype.getUpdateStatus=function(t){"use strict";return getAPI(this.api+"update/status",t),this},D3D.Box.prototype.setUpdateDownload=function(t){"use strict";return sendAPI(this.api+"update/download",{},t),this},D3D.Box.prototype.setUpdateInstall=function(t){"use strict";return sendAPI(this.api+"update/install",{},t),this},D3D.Box.prototype.setUpdateClear=function(t){"use strict";return sendAPI(this.api+"update/clear",{},t),this},D3D.Printer=function(t){"use strict";this.status={},this.config={},this.updateConfig(t)},D3D.Printer.prototype.updateConfig=function(t){"use strict";for(var e in t)0===e.indexOf("printer")&&(this.config[e]=t[e]);return this},D3D.Printer.prototype.getStartCode=function(){"use strict";var t=this.config["printer.startcode"];return t=this.subsituteVariables(t),t.split("\n")},D3D.Printer.prototype.getEndCode=function(){"use strict";var t=this.config["printer.endcode"];return t=this.subsituteVariables(t),t.split("\n")},D3D.Printer.prototype.subsituteVariables=function(t){"use strict";var e=this.config["printer.temperature"],i=this.config["printer.bed.temperature"],r=this.config["printer.heatup.temperature"],n=this.config["printer.heatup.bed.temperature"],s=this.config["printer.type"],o=this.config["printer.heatedbed"];switch(s){case"makerbot_replicator2":s="r2";break;case"makerbot_replicator2x":s="r2x";break;case"makerbot_thingomatic":s="t6";break;case"makerbot_generic":s="r2";break;case"_3Dison_plus":s="r2"}var a=o?"":";";return t=t.replace(/{printingTemp}/gi,e),t=t.replace(/{printingBedTemp}/gi,i),t=t.replace(/{preheatTemp}/gi,r),t=t.replace(/{preheatBedTemp}/gi,n),t=t.replace(/{printerType}/gi,s),t=t.replace(/{if heatedBed}/gi,a)},D3D.Paths=function(t,e){"use strict";Array.call(this),this.setPaths(t||[]),this.closed=void 0!==e?e:!0},D3D.Paths.prototype=Object.create(Array.prototype),D3D.Paths.prototype.setPaths=function(t){"use strict";for(var e=0;e0&&this.push(i)}return this},D3D.Paths.prototype.clip=function(t,e){"use strict";var i=new ClipperLib.Paths,r=new ClipperLib.Clipper;return r.AddPaths(this,ClipperLib.PolyType.ptSubject,this.closed),r.AddPaths(t,ClipperLib.PolyType.ptClip,t.closed),r.Execute(e,i),new D3D.Paths(i,this.closed)},D3D.Paths.prototype.union=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctUnion)},D3D.Paths.prototype.difference=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctDifference)},D3D.Paths.prototype.intersect=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctIntersection)},D3D.Paths.prototype.xor=function(){"use strict";return this.clip(path,ClipperLib.ClipType.ctXor)},D3D.Paths.prototype.offset=function(t){"use strict";var e=new ClipperLib.Paths,i=new ClipperLib.ClipperOffset(1,1);return i.AddPaths(this,ClipperLib.JoinType.jtRound,ClipperLib.EndType.etClosedPolygon),i.Execute(e,t),new D3D.Paths(e)},D3D.Paths.prototype.scaleUp=function(t){"use strict";ClipperLib.JS.ScaleUpPaths(this,t);return this},D3D.Paths.prototype.scaleDown=function(t){"use strict";ClipperLib.JS.ScaleDownPaths(this,t);return this},D3D.Paths.prototype.lastPoint=function(){"use strict";var t=this[this.length-1],e=this.closed?t[0]:t[t.length-1];return new THREE.Vector2(e.X,e.Y)},D3D.Paths.prototype.optimizePath=function(t){"use strict";for(var e=new D3D.Paths([],this.closed),i=[];e.length!==this.length;){for(var r,n,s,o,a=!1,c=0;cl)&&(n=p,a=l,s=h,o=c)}else{var f=new THREE.Vector2(p[0].X,p[0].Y),l=f.sub(t).length();(a===!1||a>l)&&(n=p,a=l,r=!1,o=c);var g=new THREE.Vector2(p[p.length-1].X,p[p.length-1].Y),l=g.sub(t).length();a>l&&(n=p,a=l,r=!0,o=c)}}if(this.closed){n=n.concat(n.splice(0,s));var u=n[0]}else{r&&n.reverse();var u=n[n.length-1]}i.push(o),t=new THREE.Vector2(u.X,u.Y),e.push(n)}return e},D3D.Paths.prototype.tresholdArea=function(t){"use strict";for(var e=0;er&&(this.splice(e,1),e--)}return areas},D3D.Paths.prototype.join=function(t){"use strict";for(var e=0;es;s++){var o=r[s%r.length];t.lineTo(2*o.X,2*o.Y)}t.stroke()}},D3D.Slicer=function(){"use strict";this.lines=[]},D3D.Slicer.prototype.setMesh=function(t){"use strict";var e=t.geometry.clone();e instanceof THREE.BufferGeometry&&(e=(new THREE.Geometry).fromBufferGeometry(e));for(var i=0;i=a;a++)a>=0&&(void 0===i[a]&&(i[a]=[]),i[a].push(r));for(var c=[],p=1;p0)break;f=-1}else f=-1}P.length>0&&v.push(new D3D.Paths([P]))}}for(var k=[],r=0;r0){E.join(C),I=!0;break}}I||k.push(C)}if(!(k.length>0))break;c.push(k)}return c},D3D.Slicer.prototype.slicesToData=function(t,e){"use strict";for(var i=100,r=e.config["printer.layerHeight"]*i,n=e.config["printer.dimensions.z"]*i,s=e.config["printer.wallThickness"]*i,o=e.config["printer.shellThickness"]*i,a=e.config["printer.fillSize"]*i,c=(e.config["printer.brimOffset"]*i,Math.ceil(o/r)),p=new THREE.Vector2(0,0),h=[],u=this.getFillTemplate({left:0,top:0,right:n,bottom:n},a,!0,!0),l=0;l=0)for(var D=t[l-c],y=0;y=b;b+=s){var B=w.offset(-b);x.join(B)}var T=(B||w).offset(-s/2),A=T.difference(P),S=T.difference(A),k=new D3D.Paths([],!1);if(u.length>0&&k.join(u.intersect(S)),A.length>0){var C=A.bounds(),I=l%2===0,E=this.getFillTemplate(C,s,I,!I);k.join(E.intersect(A))}w=w.optimizePath(p),x.length>0?(x=x.optimizePath(w.lastPoint()),k=k.optimizePath(x.lastPoint())):k=k.optimizePath(w.lastPoint()),p=k.length>0?k.lastPoint():x.length>0?x.lastPoint():w.lastPoint(),g.push({outerLayer:w.scaleDown(i),fill:k.scaleDown(i),insets:x.scaleDown(i)})}}return h},D3D.Slicer.prototype.getFillTemplate=function(t,e,i,r){"use strict";var n=new D3D.Paths([],!1);if(i)for(var s=Math.floor(t.left);s<=Math.ceil(t.right);s+=e)n.push([{X:s,Y:t.top},{X:s,Y:t.bottom}]);if(r)for(var s=Math.floor(t.top);s<=Math.floor(t.bottom);s+=e)n.push([{X:t.left,Y:s},{X:t.right,Y:s}]);return n},D3D.Slicer.prototype.dataToGcode=function(t,e){"use strict";function i(t){for(var e=[],i=0;ia;a++){var p=s[a%s.length];if(0===a)D>f&&u&&e.push(["G0","E"+(D-g).toFixed(3),"F"+(60*l).toFixed(3)].join(" ")),e.push(["G0","X"+p.X.toFixed(3)+" Y"+p.Y.toFixed(3)+" Z"+x,"F"+60*c].join(" ")),D>f&&u&&e.push(["G0","E"+D.toFixed(3),"F"+(60*l).toFixed(3)].join(" "));else{var d=(new THREE.Vector2).set(p.X,p.Y),m=(new THREE.Vector2).set(n.X,n.Y),w=d.distanceTo(m);D+=w*h*r/v*P,e.push(["G1","X"+p.X.toFixed(3)+" Y"+p.Y.toFixed(3)+" Z"+x,"F"+y,"E"+D.toFixed(3)].join(" "))}n=p}return e}for(var r=e.config["printer.layerHeight"],n=e.config["printer.speed"],s=e.config["printer.bottomLayerSpeed"],o=e.config["printer.firstLayerSlow"],a=e.config["printer.bottomFlowRate"],c=e.config["printer.travelSpeed"],p=e.config["printer.filamentThickness"],h=e.config["printer.wallThickness"],u=(e.config["printer.enableTraveling"],e.config["printer.retraction.enabled"]),l=e.config["printer.retraction.speed"],f=e.config["printer.retraction.minDistance"],g=e.config["printer.retraction.amount"],d=e.getStartCode(),D=0,y=o?(60*s).toFixed(3):(60*n).toFixed(3),v=Math.pow(p/2,2)*Math.PI,P=a,m=0;mp;p++)for(var h=o[p%o.length],u=0;u0&&this.status.buffered_lines+this.batchSize<=this.maxBufferedLines?this.printBatch():this.updateState()},D3D.Box.prototype.updateState=function(){"use strict";var t=this;this.getInfoStatus(function(e){t.status=e,void 0!==t.onupdate&&t.onupdate(e),t.update()})},D3D.Box.prototype.print=function(t){"use strict";for(this.currentBatch=0,t=t.clone();t.length>0;){var e=t.splice(0,Math.min(this.batchSize,t.length));this.printBatches.push(e)}return this},D3D.Box.prototype.printBatch=function(){"use strict";var t=this,e=this.printBatches.shift();this.setPrinterPrint({start:0===this.currentBatch?!0:!1,first:0===this.currentBatch?!0:!1,gcode:e.join("\n")},function(e){console.log("batch sent: "+t.currentBatch,e),t.printBatches.length>0&&t.currentBatch++,t.updateState()})},D3D.Box.prototype.stopPrint=function(){"use strict";this.printBatches=[],this.currentBatch=0;var t=["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)"];return this.setPrinterStop({gcode:t.join("\n")},function(t){console.log("Printer stop command sent")}),this},D3D.Box.prototype.getConfig=function(t,e){"use strict";return getAPI(this.api+"config/?"+t.join("=&")+"=",e),this},D3D.Box.prototype.getConfigAll=function(t){"use strict";return getAPI(this.api+"config/all",t),this},D3D.Box.prototype.setConfig=function(t,e){"use strict";var i=this;return sendAPI(this.api+"config",t,function(r){for(var n in r.validation)"ok"===r.validation[n]&&(i[n]=t[n]);void 0!==e&&e(r)}),this},D3D.Box.prototype.getInfo=function(t){"use strict";return getAPI(this.api+"info",t),this},D3D.Box.prototype.getInfoStatus=function(t){"use strict";return getAPI(this.api+"info/status",t),this},D3D.Box.prototype.downloadInfoLogFiles=function(){"use strict";window.location=this.api+"info/logfiles"},D3D.Box.prototype.getInfoAcces=function(t){"use strict";return getAPI(this.api+"info/access",t),this},D3D.Box.prototype.getNetworkScan=function(t){"use strict";return getAPI(this.api+"network/scan",t),this},D3D.Box.prototype.getNetworkKnown=function(t){"use strict";return getAPI(this.api+"network/known",t),this},D3D.Box.prototype.getNetworkStatus=function(t){"use strict";return getAPI(this.api+"network/status",t),this},D3D.Box.prototype.setNetworkAssosiate=function(t,e){"use strict";return sendAPI(this.api+"network/associate",t,e),this},D3D.Box.prototype.setNetworkDisassosiate=function(t){"use strict";return sendAPI(this.api+"network/disassociate",{},t),this},D3D.Box.prototype.setNetworkOpenAP=function(t){"use strict";return sendAPI(this.api+"network/openap",{},t),this},D3D.Box.prototype.setNetworkRemove=function(t,e){"use strict";return sendAPI(this.api+"network/remove",{ssid:t},e),this},D3D.Box.prototype.getNetworkSignin=function(t){"use strict";return getAPI(this.api+"network/signin",t),this},D3D.Box.prototype.getNetworkAlive=function(t){"use strict";return getAPI(this.api+"network/alive",t),this},D3D.Box.prototype.getPrinterTemperature=function(t){"use strict";return getAPI(this.api+"printer/temperature",t),this},D3D.Box.prototype.getPrinterProgress=function(t){"use strict";return getAPI(this.api+"printer/progress",t),this},D3D.Box.prototype.getPrinterState=function(t){"use strict";return getAPI(this.api+"printer/state",t),this},D3D.Box.prototype.getPrinterListAll=function(t){"use strict";return getAPI(this.api+"printer/listall",t),this},D3D.Box.prototype.setPrinterHeatup=function(t){"use strict";return sendAPI(this.api+"printer/heatup",{},t),this},D3D.Box.prototype.setPrinterPrint=function(t,e){"use strict";return sendAPI(this.api+"printer/print",t,e),this},D3D.Box.prototype.setPrinterStop=function(t,e){"use strict";return sendAPI(this.api+"printer/stop",t,e),this},D3D.Box.prototype.getSketch=function(t,e){"use strict";return getAPI(this.api+"sketch/?id="+t,e),this},D3D.Box.prototype.setSketch=function(t,e){"use strict";return sendAPI(this.api+"sketch",{data:t},e),this},D3D.Box.prototype.getSketchStatus=function(t){"use strict";return getAPI(this.api+"sketch/status",t),this},D3D.Box.prototype.setSketchClear=function(t){"use strict";return sendAPI(this.api+"sketch/clear",t),this},D3D.Box.prototype.getSystemVersions=function(t){"use strict";return getAPI(this.api+"system/fwversions",t),this},D3D.Box.prototype.getUpdateStatus=function(t){"use strict";return getAPI(this.api+"update/status",t),this},D3D.Box.prototype.setUpdateDownload=function(t){"use strict";return sendAPI(this.api+"update/download",{},t),this},D3D.Box.prototype.setUpdateInstall=function(t){"use strict";return sendAPI(this.api+"update/install",{},t),this},D3D.Box.prototype.setUpdateClear=function(t){"use strict";return sendAPI(this.api+"update/clear",{},t),this},D3D.Printer=function(t,e){"use strict";this.config={},this.updateConfig(t),this.updateConfig(e)},D3D.Printer.prototype.updateConfig=function(t){"use strict";for(var e in t)0===e.indexOf("printer")&&(this.config[e]=t[e]);return this},D3D.Printer.prototype.getStartCode=function(){"use strict";var t=this.config["printer.startcode"];return t=this.subsituteVariables(t),t.split("\n")},D3D.Printer.prototype.getEndCode=function(){"use strict";var t=this.config["printer.endcode"];return t=this.subsituteVariables(t),t.split("\n")},D3D.Printer.prototype.subsituteVariables=function(t){"use strict";var e=this.config["printer.temperature"],i=this.config["printer.bed.temperature"],r=this.config["printer.heatup.temperature"],n=this.config["printer.heatup.bed.temperature"],s=this.config["printer.type"],o=this.config["printer.heatedbed"];switch(s){case"makerbot_replicator2":s="r2";break;case"makerbot_replicator2x":s="r2x";break;case"makerbot_thingomatic":s="t6";break;case"makerbot_generic":s="r2";break;case"_3Dison_plus":s="r2"}var a=o?"":";";return t=t.replace(/{printingTemp}/gi,e),t=t.replace(/{printingBedTemp}/gi,i),t=t.replace(/{preheatTemp}/gi,r),t=t.replace(/{preheatBedTemp}/gi,n),t=t.replace(/{printerType}/gi,s),t=t.replace(/{if heatedBed}/gi,a)},D3D.Paths=function(t,e){"use strict";Array.call(this),this.setPaths(t||[]),this.closed=void 0!==e?e:!0},D3D.Paths.prototype=Object.create(Array.prototype),D3D.Paths.prototype.setPaths=function(t){"use strict";for(var e=0;e0&&this.push(i)}return this},D3D.Paths.prototype.clip=function(t,e){"use strict";var i=new ClipperLib.Paths,r=new ClipperLib.Clipper;return r.AddPaths(this,ClipperLib.PolyType.ptSubject,this.closed),r.AddPaths(t,ClipperLib.PolyType.ptClip,t.closed),r.Execute(e,i),new D3D.Paths(i,this.closed)},D3D.Paths.prototype.union=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctUnion)},D3D.Paths.prototype.difference=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctDifference)},D3D.Paths.prototype.intersect=function(t){"use strict";return this.clip(t,ClipperLib.ClipType.ctIntersection)},D3D.Paths.prototype.xor=function(){"use strict";return this.clip(path,ClipperLib.ClipType.ctXor)},D3D.Paths.prototype.offset=function(t){"use strict";var e=new ClipperLib.Paths,i=new ClipperLib.ClipperOffset(1,1);return i.AddPaths(this,ClipperLib.JoinType.jtRound,ClipperLib.EndType.etClosedPolygon),i.Execute(e,t),new D3D.Paths(e)},D3D.Paths.prototype.scaleUp=function(t){"use strict";ClipperLib.JS.ScaleUpPaths(this,t);return this},D3D.Paths.prototype.scaleDown=function(t){"use strict";ClipperLib.JS.ScaleDownPaths(this,t);return this},D3D.Paths.prototype.lastPoint=function(){"use strict";var t=this[this.length-1],e=this.closed?t[0]:t[t.length-1];return new THREE.Vector2(e.X,e.Y)},D3D.Paths.prototype.optimizePath=function(t){"use strict";for(var e=new D3D.Paths([],this.closed),i=[];e.length!==this.length;){for(var r,n,s,o,a=!1,c=0;cl)&&(n=p,a=l,s=h,o=c)}else{var f=new THREE.Vector2(p[0].X,p[0].Y),l=f.sub(t).length();(a===!1||a>l)&&(n=p,a=l,r=!1,o=c);var g=new THREE.Vector2(p[p.length-1].X,p[p.length-1].Y),l=g.sub(t).length();a>l&&(n=p,a=l,r=!0,o=c)}}if(this.closed){n=n.concat(n.splice(0,s));var u=n[0]}else{r&&n.reverse();var u=n[n.length-1]}i.push(o),t=new THREE.Vector2(u.X,u.Y),e.push(n)}return e},D3D.Paths.prototype.tresholdArea=function(t){"use strict";for(var e=0;er&&(this.splice(e,1),e--)}return areas},D3D.Paths.prototype.join=function(t){"use strict";for(var e=0;es;s++){var o=r[s%r.length];t.lineTo(2*o.X,2*o.Y)}t.stroke()}},D3D.Slicer=function(){"use strict"},D3D.Slicer.prototype.setMesh=function(t){"use strict";var e=t.geometry.clone();e instanceof THREE.BufferGeometry&&(e=(new THREE.Geometry).fromBufferGeometry(e));for(var i=0;i=a;a++)a>=0&&(void 0===i[a]&&(i[a]=[]),i[a].push(r));for(var c=[],p=1;p0)break;f=-1}else f=-1}P.length>0&&v.push(new D3D.Paths([P]))}}for(var S=[],r=0;r0){E.join(C),I=!0;break}}I||S.push(C)}if(!(S.length>0))break;c.push(S)}return c},D3D.Slicer.prototype.slicesToData=function(t,e){"use strict";for(var i=100,r=e.config["printer.layerHeight"]*i,n=(e.config["printer.dimensions.z"]*i,e.config["printer.wallThickness"]*i/2),s=e.config["printer.shellThickness"]*i,o=e.config["printer.fillSize"]*i,a=(e.config["printer.brimOffset"]*i,e.config["printer.bottomThickness"]*i),c=e.config["printer.topThickness"]*i,p=Math.ceil(a/r),h=Math.ceil(c/r),u=new THREE.Vector2(0,0),l=[],f=this.getFillTemplate({left:this.geometry.boundingBox.min.z*i,top:this.geometry.boundingBox.min.x*i,right:this.geometry.boundingBox.max.z*i,bottom:this.geometry.boundingBox.max.x*i},o,!0,!0),g=0;g=0)for(var v=t[g-p],P=0;P0){for(var B=new D3D.Paths([],!0),T=n;s>=T;T+=n){var A=b.offset(-T);B.join(A)}var k=(A||b).offset(-n/2),S=k.difference(w),C=k.difference(S),I=new D3D.Paths([],!1);if(f.length>0&&I.join(f.intersect(C)),S.length>0){var E=S.bounds(),L=g%2===0,F=this.getFillTemplate(E,n,L,!L);I.join(F.intersect(S))}b=b.optimizePath(u),B.length>0?(B=B.optimizePath(b.lastPoint()),I=I.optimizePath(B.lastPoint())):I=I.optimizePath(b.lastPoint()),u=I.length>0?I.lastPoint():B.length>0?B.lastPoint():b.lastPoint(),D.push({outerLayer:b.scaleDown(i),fill:I.scaleDown(i),insets:B.scaleDown(i)})}}}return l},D3D.Slicer.prototype.getFillTemplate=function(t,e,i,r){"use strict";var n=new D3D.Paths([],!1);if(i)for(var s=Math.floor(t.left/e)*e;s<=Math.ceil(t.right/e)*e;s+=e)n.push([{X:s,Y:t.top},{X:s,Y:t.bottom}]);if(r)for(var s=Math.floor(t.top/e)*e;s<=Math.floor(t.bottom/e)*e;s+=e)n.push([{X:t.left,Y:s},{X:t.right,Y:s}]);return n},D3D.Slicer.prototype.dataToGcode=function(t,e){"use strict";function i(t){for(var e=[],i=0;ia;a++){var p=s[a%s.length];if(0===a)D>f&&u&&e.push(["G0","E"+(D-g).toFixed(3),"F"+(60*l).toFixed(3)].join(" ")),e.push(["G0","X"+p.X.toFixed(3)+" Y"+p.Y.toFixed(3)+" Z"+x,"F"+60*c].join(" ")),D>f&&u&&e.push(["G0","E"+D.toFixed(3),"F"+(60*l).toFixed(3)].join(" "));else{var d=new THREE.Vector2(p.X,p.Y),m=new THREE.Vector2(n.X,n.Y),w=d.distanceTo(m);D+=w*h*r/v*P,e.push(["G1","X"+p.X.toFixed(3)+" Y"+p.Y.toFixed(3)+" Z"+x,"F"+y,"E"+D.toFixed(3)].join(" "))}n=p}return e}for(var r=e.config["printer.layerHeight"],n=e.config["printer.speed"],s=e.config["printer.bottomLayerSpeed"],o=e.config["printer.firstLayerSlow"],a=e.config["printer.bottomFlowRate"],c=e.config["printer.travelSpeed"],p=e.config["printer.filamentThickness"],h=e.config["printer.wallThickness"],u=(e.config["printer.enableTraveling"],e.config["printer.retraction.enabled"]),l=e.config["printer.retraction.speed"],f=e.config["printer.retraction.minDistance"],g=e.config["printer.retraction.amount"],d=e.getStartCode(),D=0,y=o?(60*s).toFixed(3):(60*n).toFixed(3),v=Math.pow(p/2,2)*Math.PI,P=a,m=0;mp;p++)for(var h=o[p%o.length],u=0;u diff --git a/src/box.js b/src/box.js index 6a5751e..d5476fd 100644 --- a/src/box.js +++ b/src/box.js @@ -33,7 +33,6 @@ D3D.Box = function (localIp) { this.getConfigAll(function (data) { self.updateConfig(data); - self.printer = new D3D.Printer(data); self.update(); self.loaded = true; @@ -46,9 +45,7 @@ D3D.Box.prototype.updateConfig = function (config) { "use strict"; for (var i in config) { - if (i.indexOf("doodle3d") === 0) { - this.config[i] = config[i]; - } + this.config[i] = config[i]; } return this; @@ -174,12 +171,10 @@ D3D.Box.prototype.setConfig = function (data, callback) { sendAPI(this.api + "config", data, function (response) { for (var i in response.validation) { - if (response.validation[i] !== "ok") { - delete data[i]; + if (response.validation[i] === "ok") { + self[i] = data[i]; } } - self.updateConfig(data); - self.printer.updateConfig(data); if (callback !== undefined) { callback(response); diff --git a/src/printer.js b/src/printer.js index a3bdfd1..c581223 100644 --- a/src/printer.js +++ b/src/printer.js @@ -5,12 +5,13 @@ * ******************************************************/ -D3D.Printer = function (config) { +D3D.Printer = function (printerSettings, userSettings) { "use strict"; this.config = {}; - this.updateConfig(config); + this.updateConfig(printerSettings); + this.updateConfig(userSettings); }; D3D.Printer.prototype.updateConfig = function (config) { "use strict"; diff --git a/src/utils.js b/src/utils.js index 74dae39..9d5efd2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -59,6 +59,20 @@ function getAPI (url, callback) { }); } +function loadSettings (url, callback) { + "use strict"; + + $.ajax({ + url: url, + dataType: "json", + success: function (response) { + if (callback !== undefined) { + callback(response); + } + } + }); +} + function downloadFile (file, data) { "use strict";