diff --git a/src/clipper.js b/library/clipper.js
similarity index 99%
rename from src/clipper.js
rename to library/clipper.js
index 22aa676..5fb0652 100755
--- a/src/clipper.js
+++ b/library/clipper.js
@@ -3100,7 +3100,7 @@
if (this.m_ExecuteLocked)
return false;
if (this.m_HasOpenPaths)
- ClipperLib.Error("Error: PolyTree struct is need for open path clipping.");
+ //ClipperLib.Error("Error: PolyTree struct is need for open path clipping.");
this.m_ExecuteLocked = true;
ClipperLib.Clear(solution);
this.m_SubjFillType = subjFillType;
diff --git a/slice_test.html b/slice_test.html
index 4d31074..d159749 100644
--- a/slice_test.html
+++ b/slice_test.html
@@ -6,6 +6,7 @@
+
@@ -27,22 +28,46 @@ canvas {border: 1px solid black;}
var localIp = location.hash.substring(1);
var doodleBox = new D3D.Box(localIp);
+var gcode;
doodleBox.onload = function () {
- "use strict";
+ doodleBox.printer.config["printer.bottomFlowRate"] = 1.0;
+ doodleBox.printer.config["printer.layerHeight"] = 0.3;
+ doodleBox.printer.config["printer.retraction.enabled"] = false;
- /*var gcode = slicer.getGcode(doodleBox.printer);
+ gcode = slicer.getGcode(doodleBox.printer.config);
- var print = $(document.createElement("a")).html("Print").on("click", function () {
- doodleBox.print(gcode);
- });
- var stop = $(document.createElement("a")).html("Stop").on("click", function () {
- doodleBox.stop();
- });
- var download = $(document.createElement("a")).html("Download").attr({
- download: "test.gcode",
- href: "data:text/plain," + encodeURIComponent(gcode.join("\n"))
- });
- $("body").append(print, stop, download);*/
+ var canvas = document.getElementById("canvas");
+ var context = canvas.getContext("2d");
+
+ function drawPolygons (paths, color) {
+ context.fillStyle = color;
+ context.strokeStyle = color;
+ context.beginPath();
+
+ for (var i = 0; i < paths.length; i ++) {
+ var path = paths[i];
+
+ context.moveTo((path[0].X- 100) * 8.0 + 200, (path[0].Y- 100) * 8.0 + 200);
+
+ for (var j = 0; j < path.length; j ++) {
+ var point = path[j];
+ context.lineTo((point.X- 100) * 8.0 + 200, (point.Y- 100) * 8.0 + 200);
+ }
+ context.closePath();
+ }
+ context.stroke();
+ }
+
+ //for (var layer = 0; layer < gcode.length; layer ++) {
+ var layer = 0;
+ var slice = gcode[layer];
+
+ console.log(gcode.length);
+
+ drawPolygons(slice.outerLayer, "red");
+ drawPolygons(slice.innerLayer, "green");
+ drawPolygons(slice.fill, "blue");
+ //}*/
};
var scene = new THREE.Scene();
@@ -54,35 +79,69 @@ var camera = new THREE.PerspectiveCamera(75, renderer.domElement.width/renderer.
applyMouseControls(renderer, camera, 1000);
+var geometry = (function () {
+ var circle = new THREE.Shape();
+ circle.absarc(0, 0, 20, 0, Math.PI*2, false);
+
+ var hole = new THREE.Path();
+ hole.absarc(0, 0, 10, 0, Math.PI*2, true );
+
+ circle.holes.push(hole);
+
+ var matrix = new THREE.Matrix4();
+ matrix.makeRotationX(Math.PI*1.5);
+
+ var geometry = new THREE.ExtrudeGeometry(circle, {
+ amount: 1,
+ bevelEnabled: false,
+ steps: 1
+ });
+ geometry.applyMatrix(matrix);
+
+ return geometry;
+})();
+
var material = new THREE.MeshLambertMaterial({color: 0x000000, wireframe: true});
-var geometry = new THREE.TorusGeometry(20, 10, 10, 10);
+//var geometry = new THREE.TorusGeometry(40, 20, 10, 10);
//var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1);
-//var geometry = new THREE.SphereGeometry(40, 10, 10);
+//var geometry = new THREE.SphereGeometry(10, 10, 10);
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
+var slicer = new D3D.Slicer().setGeometry(geometry);
+
+var canvas = document.getElementById("canvas");
+var context = canvas.getContext("2d");
+
+var slicer = new D3D.Slicer().setGeometry(geometry);
+//slicer.draw(1, context);
+
+/*
(function () {
var slicer = new D3D.Slicer().setGeometry(geometry);
var slices = slicer.slice(200, 0.2);
+ slices.shift();
//var slices = slicer.slice(1, 1);
CAL.Scene.setCanvas(document.getElementById("canvas"));
//error at layer 0;
//maybe because of geomety
- var layer = 4;
+ var layer = 0;
var shapes = [];
var slice = slices[layer];
+ //downloadFile("slice.json", JSON.stringify(slice));
+
for (var i = 0; i < slice.length; i ++) {
var shape = new CAL.Shape({shapeColor: false});
shapes.push(shape);
for (var j = 0; j < slice[i].length; j ++) {
var point = slice[i][j];
- shape.addPoint(new CAL.Vector((point.x-100) * 5 + 200, (point.y-100) * 5 + 200));
+ shape.addPoint(new CAL.Vector(point.X, point.Y));
}
}
@@ -100,6 +159,7 @@ scene.add(mesh);
}
}
})();
+*/
(function animate () {
requestAnimationFrame(animate);
diff --git a/src/box.js b/src/box.js
index 55cdddb..2706725 100644
--- a/src/box.js
+++ b/src/box.js
@@ -20,6 +20,8 @@ D3D.Box = function (localIp) {
this.localIp = localIp;
this.api = "http://" + localIp + "/d3dapi/";
+ this.config = {};
+
this.printBatches = [];
this.currentBatch = 0;
@@ -31,7 +33,7 @@ D3D.Box = function (localIp) {
for (var i in data) {
if (i.indexOf("doodle3d") === 0) {
- self[i] = data[i];
+ self.config[i] = data[i];
}
}
@@ -65,7 +67,7 @@ D3D.Box.prototype.updateState = function () {
//que api calls so they don't overload the d3d box
getAPI(this.api + "info/status", function (data) {
- self.printer.data = data;
+ self.printer.status = data;
self.update();
});
diff --git a/src/printer.js b/src/printer.js
index 49eaf9b..882c240 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -8,18 +8,19 @@
D3D.Printer = function (config) {
"use strict";
- this.data = {};
+ this.status = {};
+ this.config = {};
for (var i in config) {
if (i.indexOf("printer") === 0) {
- this[i] = config[i];
+ this.config[i] = config[i];
}
}
};
D3D.Printer.prototype.getStartCode = function () {
"use strict";
- var gcode = this["printer.startcode"];
+ var gcode = this.config["printer.startcode"];
gcode = this.subsituteVariables(gcode);
return gcode.split("\n");
@@ -27,7 +28,7 @@ D3D.Printer.prototype.getStartCode = function () {
D3D.Printer.prototype.getEndCode = function () {
"use strict";
- var gcode = this["printer.endcode"];
+ var gcode = this.config["printer.endcode"];
gcode = this.subsituteVariables(gcode);
return gcode.split("\n");
@@ -35,12 +36,12 @@ D3D.Printer.prototype.getEndCode = function () {
D3D.Printer.prototype.subsituteVariables = function (gcode) {
"use strict";
- var temperature = this["printer.temperature"];
- var bedTemperature = this["printer.bed.temperature"];
- var preheatTemperature = this["printer.heatup.temperature"];
- var preheatBedTemperature = this["printer.heatup.bed.temperature"];
- var printerType = this["printer.type"];
- var heatedbed = this["printer.heatedbed"];
+ var temperature = this.config["printer.temperature"];
+ var bedTemperature = this.config["printer.bed.temperature"];
+ var preheatTemperature = this.config["printer.heatup.temperature"];
+ var preheatBedTemperature = this.config["printer.heatup.bed.temperature"];
+ var printerType = this.config["printer.type"];
+ var heatedbed = this.config["printer.heatedbed"];
switch (printerType) {
case "makerbot_replicator2": printerType = "r2"; break;
diff --git a/src/slicer.js b/src/slicer.js
index 3e1811d..3a473f1 100644
--- a/src/slicer.js
+++ b/src/slicer.js
@@ -5,8 +5,13 @@
* 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))
*
******************************************************/
+var use_deprecated = true;
D3D.Slicer = function () {
"use strict";
@@ -69,9 +74,9 @@ D3D.Slicer.prototype.createLines = function () {
this.lines[b].connects.push(c, a);
this.lines[c].connects.push(a, b);
- this.lines[a].normals.push(normal, normal);
- this.lines[b].normals.push(normal, normal);
- this.lines[c].normals.push(normal, normal);
+ this.lines[a].normals.push(normal);
+ this.lines[b].normals.push(normal);
+ this.lines[c].normals.push(normal);
}
//sort lines on min height
@@ -119,7 +124,7 @@ D3D.Slicer.prototype.slice = function (height, step) {
while (index !== -1) {
var intersection = intersections[index];
- shape.push(intersection);
+ shape.push({X: intersection.x, Y: intersection.y});
done.push(index);
@@ -130,7 +135,7 @@ D3D.Slicer.prototype.slice = function (height, step) {
if (intersections[index] && done.indexOf(index) === -1) {
var normal = new THREE.Vector2().copy(intersection).sub(intersections[index]).normal().normalize();
- var faceNormal = faceNormals[j];
+ var faceNormal = faceNormals[Math.floor(j/2)];
if (normal.dot(faceNormal) > 0) {
break;
@@ -152,6 +157,7 @@ D3D.Slicer.prototype.slice = function (height, step) {
}
}
+ //stop when ther are no intersects
if (slice.length > 0) {
slices.push(slice);
}
@@ -162,44 +168,128 @@ D3D.Slicer.prototype.slice = function (height, step) {
return slices;
};
-D3D.Slicer.prototype.getGcode = function (printer) {
+D3D.Slicer.prototype.getInset = function (slice, offset) {
"use strict";
- var normalSpeed = doodleBox.printer["printer.speed"];
- var bottomSpeed = doodleBox.printer["printer.bottomLayerSpeed"];
- var firstLayerSlow = doodleBox.printer["printer.firstLayerSlow"];
- var bottomFlowRate = doodleBox.printer["printer.bottomFlowRate"];
- var travelSpeed = doodleBox.printer["printer.travelSpeed"];
- var filamentThickness = doodleBox.printer["printer.filamentThickness"];
- var wallThickness = doodleBox.printer["printer.wallThickness"];
- var layerHeight = doodleBox.printer["printer.layerHeight"];
- var enableTraveling = doodleBox.printer["printer.enableTraveling"];
- var retractionEnabled = doodleBox.printer["printer.retraction.enabled"];
- var retractionSpeed = doodleBox.printer["printer.retraction.speed"];
- var retractionminDistance = doodleBox.printer["printer.retraction.minDistance"];
- var retractionAmount = doodleBox.printer["printer.retraction.amount"];
- var dimensionsZ = doodleBox.printer["printer.dimensions.z"];
+ var solution = new ClipperLib.Paths();
+ var co = new ClipperLib.ClipperOffset(1, 1);
+ co.AddPaths(slice, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
+ co.Execute(solution, -offset);
- var gcode = doodleBox.printer.getStartCode();
+ return solution;
+};
+D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven) {
+ var paths = new ClipperLib.Paths();
- var extruder = 0.0;
- var speed = firstLayerSlow ? (bottomSpeed*60).toFixed(3) : (normalSpeed*60).toFixed(3);
- var flowRate = bottomFlowRate;
- var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
+ if (even) {
+ for (var length = 0; length <= dimension; length += size) {
+ paths.push([{X: length, Y: 0}, {X: length, Y: dimension}]);
+ }
+ }
+ if (uneven) {
+ for (var length = 0; length <= dimension; length += size) {
+ paths.push([{X: 0, Y: length}, {X: dimension, Y: length}]);
+ }
+ }
+
+ return paths;
+};
+D3D.Slicer.prototype.slicesToData = function (slices, config) {
+ var data = [];
- var slices = this.slice(dimensionsZ, layerHeight);
+ //scale because of clipper crap
+ var scale = 100;
+
+ var layerHeight = config["printer.layerHeight"] * scale;
+ var dimensionsZ = config["printer.dimensions.z"] * scale;
+ //should come from config???
+ //aan rick voorleggen
+ var nozzleSize = 0.4 * scale;
+ var shellThickness = 0.8 * scale;
+ var fillSize = 5 * scale;
+
+ var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
+
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
+ var highFillTemplate = this.getFillTemplate(dimensionsZ, nozzleSize*2, (layer % 2 === 0), (layer % 2 === 1));
- //turn on fan on layer 2
- if (layer === 2) {
- gcode.push("M106");
- speed = (normalSpeed*60).toFixed(3);
- flowRate = 1;
+ //var outerLayer = ClipperLib.JS.Clean(slice, 1.0);
+ var outerLayer = slice.clone();
+ ClipperLib.JS.ScaleUpPaths(outerLayer, scale);
+
+ var innerLayer = [];
+
+ for (var i = nozzleSize; i < shellThickness; i += nozzleSize) {
+ var inset = this.getInset(outerLayer, i);
+
+ innerLayer = innerLayer.concat(inset);
}
- var z = ((layer + 1) * layerHeight).toFixed(3);
+ var fillArea = this.getInset((inset || outerLayer), nozzleSize);
+
+ var highFill;
+
+ var fillAbove;
+ //for (var i = 1; i < shellThickness/layerHeight; i ++) {
+ var newLayer = ClipperLib.JS.Clone(slices[layer + 1] || []);
+ ClipperLib.JS.ScaleUpPaths(newLayer, scale);
+ fillAbove = newLayer;
+ //}
+ //kijkt alleen nog naar boven
+ //omliggende lagen hebben inhoud van lowFill;
+ //inset moet opgevult worden;
+ //verschill tussen lowFill en inset moet vol, rest is raster
+
+ var c = new ClipperLib.Clipper();
+ var highFillArea = new ClipperLib.Paths();
+ c.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
+ c.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
+ c.Execute(ClipperLib.ClipType.ctDifference, highFillArea);
+
+ var c = new ClipperLib.Clipper();
+ var lowFillArea = new ClipperLib.Paths();
+ c.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
+ c.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
+ c.Execute(ClipperLib.ClipType.ctDifference, lowFillArea);
+
+ var fill = [];
+
+ var c = new ClipperLib.Clipper();
+ var solution = new ClipperLib.Paths();
+ c.AddPaths(lowFillTemplate, ClipperLib.PolyType.ptSubject, false);
+ c.AddPaths(lowFillArea, ClipperLib.PolyType.ptClip, true);
+ c.Execute(ClipperLib.ClipType.ctIntersection, solution);
+
+ fill = fill.concat(solution);
+
+ var c = new ClipperLib.Clipper();
+ var solution = new ClipperLib.Paths();
+ c.AddPaths(highFillTemplate, ClipperLib.PolyType.ptSubject, false);
+ c.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
+ c.Execute(ClipperLib.ClipType.ctIntersection, solution);
+
+ fill = fill.concat(solution);
+
+ ClipperLib.JS.ScaleDownPaths(outerLayer, scale);
+ ClipperLib.JS.ScaleDownPaths(innerLayer, scale);
+ ClipperLib.JS.ScaleDownPaths(fill, scale);
+
+ data.push({
+ outerLayer: outerLayer,
+ innerLayer: innerLayer,
+ fill: fill
+ })
+ }
+
+ return data;
+};
+D3D.Slicer.prototype.getGcode = function (config) {
+ "use strict";
+
+ function sliceToGcode (slice) {
+ var gcode = [];
for (var i = 0; i < slice.length; i ++) {
var shape = slice[i];
@@ -213,7 +303,7 @@ D3D.Slicer.prototype.getGcode = function (printer) {
if (j === 0) {
//TODO
//add retraction
- if (extruder > retractionAmount && retractionEnabled) {
+ if (extruder > retractionMinDistance && retractionEnabled) {
gcode.push([
"G0",
"E" + (extruder - retractionAmount).toFixed(3),
@@ -223,11 +313,11 @@ D3D.Slicer.prototype.getGcode = function (printer) {
gcode.push([
"G0",
- "X" + point.x.toFixed(3) + " Y" + point.y.toFixed(3) + " Z" + z,
+ "X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
"F" + (travelSpeed*60)
].join(" "));
- if (extruder > retractionAmount && retractionEnabled) {
+ if (extruder > retractionMinDistance && retractionEnabled) {
gcode.push([
"G0",
"E" + extruder.toFixed(3),
@@ -236,12 +326,15 @@ D3D.Slicer.prototype.getGcode = function (printer) {
}
}
else {
- var lineLength = new THREE.Vector2().copy(point).sub(previousPoint).length();
+ var a = new THREE.Vector2().set(point.X, point.Y);
+ var b = new THREE.Vector2().set(previousPoint.X, previousPoint.Y);
+ var lineLength = a.distanceTo(b);
+
extruder += lineLength * wallThickness * layerHeight / filamentSurfaceArea * flowRate;
gcode.push([
"G1",
- "X" + point.x.toFixed(3) + " Y" + point.y.toFixed(3) + " Z" + z,
+ "X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
"F" + speed,
"E" + extruder.toFixed(3)
].join(" "));
@@ -250,6 +343,60 @@ D3D.Slicer.prototype.getGcode = function (printer) {
previousPoint = point;
}
}
+
+ return gcode;
+ }
+
+ var normalSpeed = config["printer.speed"];
+ var bottomSpeed = config["printer.bottomLayerSpeed"];
+ var firstLayerSlow = config["printer.firstLayerSlow"];
+ var bottomFlowRate = config["printer.bottomFlowRate"];
+ var travelSpeed = config["printer.travelSpeed"];
+ var filamentThickness = config["printer.filamentThickness"];
+ var wallThickness = config["printer.wallThickness"];
+ var layerHeight = config["printer.layerHeight"];
+ var enableTraveling = config["printer.enableTraveling"];
+ var retractionEnabled = config["printer.retraction.enabled"];
+ var retractionSpeed = config["printer.retraction.speed"];
+ var retractionMinDistance = config["printer.retraction.minDistance"];
+ var retractionAmount = config["printer.retraction.amount"];
+ var dimensionsZ = config["printer.dimensions.z"];
+
+ var gcode = doodleBox.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;
+
+ var slices = [];
+
+ var slices = this.slice(dimensionsZ, layerHeight);
+ //still error in first layer, so remove first layer
+ //see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1
+ slices.shift();
+
+ //code for only printing the first layer
+ //var slices = [slices.shift()];
+
+ var data = this.slicesToData(slices, config);
+ //return data;
+
+ for (var layer = 0; layer < data.length; layer ++) {
+ var slice = data[layer];
+
+ //turn on fan on layer 2
+ if (layer === 2) {
+ gcode.push("M106");
+ speed = (normalSpeed*60).toFixed(3);
+ flowRate = 1;
+ }
+
+ var z = ((layer + 1) * layerHeight).toFixed(3);
+
+ gcode = gcode.concat(sliceToGcode(slice.outerLayer));
+ gcode = gcode.concat(sliceToGcode(slice.innerLayer));
+ gcode = gcode.concat(sliceToGcode(slice.fill));
}
gcode = gcode.concat(doodleBox.printer.getEndCode());