2015-04-24 16:12:48 +02:00
|
|
|
/******************************************************
|
|
|
|
*
|
|
|
|
* 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
|
2015-04-30 18:26:34 +02:00
|
|
|
* 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))
|
2015-04-24 16:12:48 +02:00
|
|
|
*
|
|
|
|
******************************************************/
|
|
|
|
|
2015-04-28 14:11:41 +02:00
|
|
|
D3D.Slicer = function () {
|
2015-04-24 16:12:48 +02:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
this.lines = [];
|
|
|
|
};
|
2015-05-08 10:07:26 +02:00
|
|
|
D3D.Slicer.prototype.setGeometry = function (mesh) {
|
2015-04-28 14:11:41 +02:00
|
|
|
"use strict";
|
|
|
|
|
2015-05-08 10:07:26 +02:00
|
|
|
var geometry = mesh.geometry.clone();
|
|
|
|
geometry.mergeVertices();
|
|
|
|
geometry.applyMatrix(mesh.matrix);
|
|
|
|
|
2015-05-06 15:06:04 +02:00
|
|
|
if (geometry instanceof THREE.BufferGeometry) {
|
|
|
|
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
2015-05-08 10:07:26 +02:00
|
|
|
this.geometry = geometry;
|
2015-04-28 14:11:41 +02:00
|
|
|
|
|
|
|
this.createLines();
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
2015-05-01 16:44:05 +02:00
|
|
|
D3D.Slicer.prototype.createLines = function () {
|
2015-05-01 14:09:45 +02:00
|
|
|
"use strict";
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
this.lines = [];
|
|
|
|
var lineLookup = {};
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
var self = this;
|
|
|
|
function addLine (a, b) {
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
//think lookup can only be b_a, a_b is only possible when face is flipped
|
|
|
|
var index = lineLookup[a + "_" + b] || lineLookup[b + "_" + a];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
if (index === undefined) {
|
|
|
|
index = self.lines.length;
|
|
|
|
lineLookup[a + "_" + b] = index;
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
self.lines.push({
|
2015-05-07 14:09:36 +02:00
|
|
|
line: new THREE.Line3(self.geometry.vertices[a], self.geometry.vertices[b]),
|
|
|
|
connects: [],
|
2015-05-01 16:44:05 +02:00
|
|
|
normals: []
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
2015-05-07 11:04:48 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
for (var i = 0; i < this.geometry.faces.length; i ++) {
|
|
|
|
var face = this.geometry.faces[i];
|
2015-04-28 17:54:46 +02:00
|
|
|
var normal = new THREE.Vector2().set(face.normal.x, face.normal.z).normalize();
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
//check for only adding unique lines
|
|
|
|
//returns index of said line
|
2015-05-01 16:44:05 +02:00
|
|
|
var a = addLine(face.a, face.b);
|
|
|
|
var b = addLine(face.b, face.c);
|
|
|
|
var c = addLine(face.c, face.a);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
//set connecting lines (based on face)
|
|
|
|
this.lines[a].connects.push(b, c);
|
2015-04-28 17:54:46 +02:00
|
|
|
this.lines[b].connects.push(c, a);
|
2015-04-24 16:12:48 +02:00
|
|
|
this.lines[c].connects.push(a, b);
|
2015-04-28 17:54:46 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
this.lines[a].normals.push(normal);
|
|
|
|
this.lines[b].normals.push(normal);
|
|
|
|
this.lines[c].normals.push(normal);
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
D3D.Slicer.prototype.slice = function (height, step) {
|
|
|
|
"use strict";
|
|
|
|
|
2015-05-07 17:27:41 +02:00
|
|
|
var layersIntersections = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < this.lines.length; i ++) {
|
|
|
|
var line = this.lines[i];
|
|
|
|
|
|
|
|
var min = Math.ceil(Math.min(line.line.start.y, line.line.end.y) / step);
|
|
|
|
var max = Math.floor(Math.max(line.line.start.y, line.line.end.y) / step);
|
|
|
|
|
2015-05-07 17:43:27 +02:00
|
|
|
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
|
2015-05-07 17:27:41 +02:00
|
|
|
if (layerIndex >= 0) {
|
|
|
|
if (layersIntersections[layerIndex] === undefined) {
|
|
|
|
layersIntersections[layerIndex] = [];
|
|
|
|
}
|
|
|
|
layersIntersections[layerIndex].push(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-24 16:12:48 +02:00
|
|
|
var slices = [];
|
|
|
|
|
2015-05-07 17:27:41 +02:00
|
|
|
for (var layer = 1; layer < layersIntersections.length; layer ++) {
|
|
|
|
var layerIntersections = layersIntersections[layer];
|
2015-05-08 10:07:26 +02:00
|
|
|
var y = layer*step;
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
var intersections = [];
|
2015-05-07 17:27:41 +02:00
|
|
|
for (var i = 0; i < layerIntersections.length; i ++) {
|
|
|
|
var index = layerIntersections[i];
|
|
|
|
var line = this.lines[index].line;
|
2015-05-08 10:07:26 +02:00
|
|
|
|
|
|
|
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
|
|
|
|
var x = line.start.x * alpha + line.end.x * (1 - alpha);
|
|
|
|
var z = line.start.z * alpha + line.end.z * (1 - alpha);
|
|
|
|
|
|
|
|
//remove +100 when implimenting good stucture for creating geometry is complete
|
|
|
|
intersections[index] = new THREE.Vector2(x + 100, z + 100);
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var done = [];
|
2015-05-07 17:27:41 +02:00
|
|
|
var slice = [];
|
|
|
|
for (var i = 0; i < layerIntersections.length; i ++) {
|
|
|
|
var index = layerIntersections[i];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-05-07 17:27:41 +02:00
|
|
|
if (done.indexOf(index) === -1) {
|
2015-04-24 16:12:48 +02:00
|
|
|
var shape = [];
|
|
|
|
|
|
|
|
while (index !== -1) {
|
|
|
|
var intersection = intersections[index];
|
2015-04-30 18:26:34 +02:00
|
|
|
shape.push({X: intersection.x, Y: intersection.y});
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
done.push(index);
|
|
|
|
|
|
|
|
var connects = this.lines[index].connects;
|
2015-04-28 17:54:46 +02:00
|
|
|
var faceNormals = this.lines[index].normals;
|
2015-04-24 16:12:48 +02:00
|
|
|
for (var j = 0; j < connects.length; j ++) {
|
|
|
|
index = connects[j];
|
|
|
|
|
2015-04-28 14:11:41 +02:00
|
|
|
if (intersections[index] && done.indexOf(index) === -1) {
|
2015-04-30 20:34:57 +02:00
|
|
|
var a = new THREE.Vector2().set(intersection.x, intersection.y);
|
|
|
|
var b = intersections[index];
|
|
|
|
var normal = a.sub(b).normal().normalize();
|
2015-04-30 18:26:34 +02:00
|
|
|
var faceNormal = faceNormals[Math.floor(j/2)];
|
2015-04-28 17:54:46 +02:00
|
|
|
|
2015-04-28 18:10:16 +02:00
|
|
|
if (normal.dot(faceNormal) > 0) {
|
2015-04-28 17:54:46 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = -1;
|
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//think this check is not nescesary, always higher as 0
|
|
|
|
if (shape.length > 0) {
|
|
|
|
slice.push(shape);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-28 14:11:41 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
//stop when ther are no intersects
|
2015-04-28 14:11:41 +02:00
|
|
|
if (slice.length > 0) {
|
|
|
|
slices.push(slice);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return slices;
|
|
|
|
};
|
2015-04-30 18:26:34 +02:00
|
|
|
D3D.Slicer.prototype.getInset = function (slice, offset) {
|
2015-04-24 16:12:48 +02:00
|
|
|
"use strict";
|
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
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);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
return solution;
|
|
|
|
};
|
|
|
|
D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven) {
|
2015-04-30 20:34:57 +02:00
|
|
|
"use strict";
|
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
var paths = new ClipperLib.Paths();
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
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;
|
|
|
|
};
|
2015-05-01 10:06:52 +02:00
|
|
|
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
|
2015-04-30 20:34:57 +02:00
|
|
|
"use strict";
|
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
//scale because of clipper crap
|
|
|
|
var scale = 100;
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
var layerHeight = printer.config["printer.layerHeight"] * scale;
|
|
|
|
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
|
2015-05-01 11:03:07 +02:00
|
|
|
var wallThickness = printer.config["printer.wallThickness"] * scale;
|
|
|
|
var shellThickness = printer.config["printer.shellThickness"] * scale;
|
|
|
|
var fillSize = printer.config["printer.fillSize"] * scale;
|
|
|
|
var brimOffset = printer.config["printer.brimOffset"] * scale;
|
|
|
|
|
|
|
|
var data = [];
|
2015-04-30 18:26:34 +02:00
|
|
|
|
|
|
|
var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
for (var layer = 0; layer < slices.length; layer ++) {
|
|
|
|
var slice = slices[layer];
|
2015-05-01 11:03:07 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
//var outerLayer = ClipperLib.JS.Clean(slice, 1.0);
|
|
|
|
var outerLayer = slice.clone();
|
|
|
|
ClipperLib.JS.ScaleUpPaths(outerLayer, scale);
|
|
|
|
|
|
|
|
var innerLayer = [];
|
|
|
|
|
2015-05-01 11:03:07 +02:00
|
|
|
for (var i = wallThickness; i < shellThickness; i += wallThickness) {
|
2015-04-30 18:26:34 +02:00
|
|
|
var inset = this.getInset(outerLayer, i);
|
|
|
|
|
|
|
|
innerLayer = innerLayer.concat(inset);
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
|
2015-05-01 16:44:05 +02:00
|
|
|
//moet fillArea wel kleiner?
|
2015-05-06 15:06:04 +02:00
|
|
|
//var fillArea = this.getInset((inset || outerLayer), wallThickness);
|
|
|
|
var fillArea = (inset || outerLayer);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-05-01 14:59:39 +02:00
|
|
|
var fillAbove = false;
|
2015-05-01 12:15:46 +02:00
|
|
|
//for (var i = 1; i < shellThickness/layerHeight; i ++) {
|
2015-05-01 14:59:39 +02:00
|
|
|
for (var i = 1; i < shellThickness/layerHeight; i ++) {
|
2015-04-30 20:34:57 +02:00
|
|
|
var newLayer = ClipperLib.JS.Clone(slices[layer + i]);
|
2015-04-30 18:26:34 +02:00
|
|
|
ClipperLib.JS.ScaleUpPaths(newLayer, scale);
|
2015-04-30 20:34:57 +02:00
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
if (newLayer.length === 0 || (fillAbove && fillAbove.length === 0)) {
|
2015-04-30 20:34:57 +02:00
|
|
|
fillAbove = [];
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2015-05-01 14:59:39 +02:00
|
|
|
else if (fillAbove === false) {
|
2015-04-30 20:34:57 +02:00
|
|
|
fillAbove = newLayer;
|
|
|
|
}
|
|
|
|
else {
|
2015-05-01 11:03:07 +02:00
|
|
|
var c = new ClipperLib.Clipper();
|
|
|
|
var solution = new ClipperLib.Paths();
|
2015-05-01 14:59:39 +02:00
|
|
|
c.AddPaths(newLayer, ClipperLib.PolyType.ptSubject, true);
|
2015-05-01 11:03:07 +02:00
|
|
|
c.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
|
|
|
|
c.Execute(ClipperLib.ClipType.ctIntersection, solution);
|
|
|
|
|
|
|
|
fillAbove = solution;
|
2015-04-30 20:34:57 +02:00
|
|
|
}
|
|
|
|
}
|
2015-04-30 18:26:34 +02:00
|
|
|
//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
|
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
var clipper = new ClipperLib.Clipper();
|
2015-04-30 18:26:34 +02:00
|
|
|
var highFillArea = new ClipperLib.Paths();
|
2015-04-30 20:34:57 +02:00
|
|
|
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
|
|
|
|
clipper.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
|
|
|
|
clipper.Execute(ClipperLib.ClipType.ctDifference, highFillArea);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
var clipper = new ClipperLib.Clipper();
|
2015-04-30 18:26:34 +02:00
|
|
|
var lowFillArea = new ClipperLib.Paths();
|
2015-04-30 20:34:57 +02:00
|
|
|
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
|
|
|
|
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
|
|
|
|
clipper.Execute(ClipperLib.ClipType.ctDifference, lowFillArea);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
|
|
|
var fill = [];
|
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
var clipper = new ClipperLib.Clipper();
|
|
|
|
var lowFillStrokes = new ClipperLib.Paths();
|
|
|
|
clipper.AddPaths(lowFillTemplate, ClipperLib.PolyType.ptSubject, false);
|
|
|
|
clipper.AddPaths(lowFillArea, ClipperLib.PolyType.ptClip, true);
|
|
|
|
clipper.Execute(ClipperLib.ClipType.ctIntersection, lowFillStrokes);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
fill = fill.concat(lowFillStrokes);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-05-01 11:17:41 +02:00
|
|
|
//optimize
|
2015-05-01 12:15:46 +02:00
|
|
|
//make as big as bounding box of highFillArea
|
2015-05-01 11:17:41 +02:00
|
|
|
var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
|
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
var clipper = new ClipperLib.Clipper();
|
|
|
|
var highFillStrokes = new ClipperLib.Paths();
|
|
|
|
clipper.AddPaths(highFillTemplate, ClipperLib.PolyType.ptSubject, false);
|
|
|
|
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
|
|
|
|
clipper.Execute(ClipperLib.ClipType.ctIntersection, highFillStrokes);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-04-30 20:34:57 +02:00
|
|
|
fill = fill.concat(highFillStrokes);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
//create brim
|
2015-05-01 12:15:46 +02:00
|
|
|
/*if (layer === 0) {
|
2015-05-01 10:06:52 +02:00
|
|
|
var brim = this.getInset(outerLayer, -brimOffset);
|
|
|
|
outerLayer = brim.concat(outerLayer);
|
2015-05-01 12:15:46 +02:00
|
|
|
}*/
|
2015-05-01 10:06:52 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
ClipperLib.JS.ScaleDownPaths(outerLayer, scale);
|
|
|
|
ClipperLib.JS.ScaleDownPaths(innerLayer, scale);
|
|
|
|
ClipperLib.JS.ScaleDownPaths(fill, scale);
|
|
|
|
|
|
|
|
data.push({
|
2015-05-07 14:09:36 +02:00
|
|
|
outerLayer: outerLayer,
|
|
|
|
innerLayer: innerLayer,
|
2015-04-30 18:26:34 +02:00
|
|
|
fill: fill
|
2015-05-01 14:09:45 +02:00
|
|
|
});
|
2015-04-30 18:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
};
|
2015-05-01 10:06:52 +02:00
|
|
|
D3D.Slicer.prototype.dataToGcode = function (data, printer) {
|
2015-04-30 18:26:34 +02:00
|
|
|
"use strict";
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
var layerHeight = printer.config["printer.layerHeight"];
|
|
|
|
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 travelSpeed = printer.config["printer.travelSpeed"];
|
|
|
|
var filamentThickness = printer.config["printer.filamentThickness"];
|
|
|
|
var wallThickness = printer.config["printer.wallThickness"];
|
|
|
|
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"];
|
2015-05-06 15:06:04 +02:00
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
function sliceToGcode (slice) {
|
|
|
|
var gcode = [];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
for (var i = 0; i < slice.length; i ++) {
|
|
|
|
var shape = slice[i];
|
|
|
|
|
|
|
|
var previousPoint;
|
|
|
|
|
2015-05-06 15:06:04 +02:00
|
|
|
for (var j = 0; j < shape.length; j ++) {
|
|
|
|
var point = shape[j];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
|
|
|
if (j === 0) {
|
|
|
|
//TODO
|
|
|
|
//add retraction
|
2015-04-30 18:26:34 +02:00
|
|
|
if (extruder > retractionMinDistance && retractionEnabled) {
|
2015-04-24 16:12:48 +02:00
|
|
|
gcode.push([
|
|
|
|
"G0",
|
2015-05-07 14:09:36 +02:00
|
|
|
"E" + (extruder - retractionAmount).toFixed(3),
|
2015-04-24 21:32:39 +02:00
|
|
|
"F" + (retractionSpeed * 60).toFixed(3)
|
2015-04-24 16:12:48 +02:00
|
|
|
].join(" "));
|
|
|
|
}
|
|
|
|
|
|
|
|
gcode.push([
|
|
|
|
"G0",
|
2015-04-30 18:26:34 +02:00
|
|
|
"X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
|
2015-04-24 16:12:48 +02:00
|
|
|
"F" + (travelSpeed*60)
|
|
|
|
].join(" "));
|
|
|
|
|
2015-04-30 18:26:34 +02:00
|
|
|
if (extruder > retractionMinDistance && retractionEnabled) {
|
2015-04-24 16:12:48 +02:00
|
|
|
gcode.push([
|
|
|
|
"G0",
|
2015-05-07 14:09:36 +02:00
|
|
|
"E" + extruder.toFixed(3),
|
2015-04-24 21:32:39 +02:00
|
|
|
"F" + (retractionSpeed * 60).toFixed(3)
|
2015-04-24 16:12:48 +02:00
|
|
|
].join(" "));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-04-30 18:26:34 +02:00
|
|
|
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);
|
|
|
|
|
2015-04-24 16:12:48 +02:00
|
|
|
extruder += lineLength * wallThickness * layerHeight / filamentSurfaceArea * flowRate;
|
|
|
|
|
|
|
|
gcode.push([
|
|
|
|
"G1",
|
2015-04-30 18:26:34 +02:00
|
|
|
"X" + point.X.toFixed(3) + " Y" + point.Y.toFixed(3) + " Z" + z,
|
2015-04-24 16:12:48 +02:00
|
|
|
"F" + speed,
|
|
|
|
"E" + extruder.toFixed(3)
|
|
|
|
].join(" "));
|
|
|
|
}
|
|
|
|
|
|
|
|
previousPoint = point;
|
|
|
|
}
|
|
|
|
}
|
2015-04-30 18:26:34 +02:00
|
|
|
|
|
|
|
return gcode;
|
|
|
|
}
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
var gcode = printer.getStartCode();
|
2015-04-30 18:26:34 +02:00
|
|
|
|
|
|
|
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 ++) {
|
|
|
|
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));
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
gcode = gcode.concat(printer.getEndCode());
|
|
|
|
return gcode;
|
|
|
|
};
|
2015-05-01 12:15:46 +02:00
|
|
|
D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var layerHeight = printer.config["printer.layerHeight"];
|
|
|
|
var dimensionsZ = printer.config["printer.dimensions.z"];
|
|
|
|
|
2015-05-08 10:07:26 +02:00
|
|
|
function drawLines (paths, color) {
|
2015-05-01 12:15:46 +02:00
|
|
|
context.fillStyle = color;
|
|
|
|
context.strokeStyle = color;
|
|
|
|
context.beginPath();
|
|
|
|
|
|
|
|
for (var i = 0; i < paths.length; i ++) {
|
|
|
|
var path = paths[i];
|
|
|
|
|
2015-05-06 15:06:04 +02:00
|
|
|
context.moveTo((path[0].X * 2), (path[0].Y * 2));
|
2015-05-01 12:15:46 +02:00
|
|
|
|
|
|
|
for (var j = 0; j < path.length; j ++) {
|
|
|
|
var point = path[j];
|
2015-05-06 15:06:04 +02:00
|
|
|
context.lineTo((point.X * 2), (point.Y * 2));
|
2015-05-01 12:15:46 +02:00
|
|
|
}
|
2015-05-06 15:06:04 +02:00
|
|
|
//context.closePath();
|
2015-05-01 12:15:46 +02:00
|
|
|
}
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
|
2015-05-08 10:07:26 +02:00
|
|
|
function drawVertexes (paths, color) {
|
|
|
|
context.fillStyle = color;
|
|
|
|
context.strokeStyle = color;
|
|
|
|
|
|
|
|
for (var i = 0; i < paths.length; i ++) {
|
|
|
|
var path = paths[i];
|
|
|
|
|
|
|
|
for (var j = 0; j < path.length; j ++) {
|
|
|
|
var point = path[j];
|
|
|
|
context.beginPath();
|
|
|
|
context.arc(point.X * 2, point.Y * 2, 1, 0, Math.PI*2, false);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-01 12:15:46 +02:00
|
|
|
var slices = this.slice(dimensionsZ, layerHeight);
|
|
|
|
|
|
|
|
var data = this.slicesToData(slices, printer);
|
|
|
|
|
2015-05-01 14:09:45 +02:00
|
|
|
var canvas = document.createElement("canvas");
|
|
|
|
canvas.width = 400;
|
|
|
|
canvas.height = 400;
|
|
|
|
var context = canvas.getContext("2d");
|
|
|
|
|
2015-05-01 12:15:46 +02:00
|
|
|
for (var layer = min; layer < max; layer ++) {
|
|
|
|
var slice = data[layer % data.length];
|
|
|
|
|
2015-05-08 10:07:26 +02:00
|
|
|
drawLines(slice.outerLayer, "red");
|
|
|
|
//drawLines(slice.innerLayer, "green");
|
|
|
|
//drawLines(slice.fill, "blue");
|
|
|
|
|
|
|
|
drawVertexes(slice.outerLayer, "green");
|
2015-05-01 12:15:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return canvas;
|
|
|
|
};
|
2015-05-01 10:06:52 +02:00
|
|
|
D3D.Slicer.prototype.getGcode = function (printer) {
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var layerHeight = printer.config["printer.layerHeight"];
|
|
|
|
var dimensionsZ = printer.config["printer.dimensions.z"];
|
|
|
|
|
2015-05-07 18:14:10 +02:00
|
|
|
var start = new Date().getTime();
|
2015-05-01 10:06:52 +02:00
|
|
|
var slices = this.slice(dimensionsZ, layerHeight);
|
2015-05-07 18:14:10 +02:00
|
|
|
var end = new Date().getTime();
|
|
|
|
|
|
|
|
console.log("Slicing: " + (end - start) + "ms");
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
//still error in first layer, so remove first layer
|
|
|
|
//see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1
|
|
|
|
|
2015-05-07 18:14:10 +02:00
|
|
|
var start = new Date().getTime();
|
2015-05-01 10:06:52 +02:00
|
|
|
var data = this.slicesToData(slices, printer);
|
2015-05-07 18:14:10 +02:00
|
|
|
var end = new Date().getTime();
|
|
|
|
|
|
|
|
console.log("Data: " + (end - start) + "ms");
|
|
|
|
|
2015-05-01 10:06:52 +02:00
|
|
|
//return data;
|
|
|
|
|
|
|
|
//TODO
|
|
|
|
//make the path more optimized for 3d printers
|
|
|
|
//make the printer follow the shortest path from line to line
|
2015-05-01 14:09:45 +02:00
|
|
|
//see https://github.com/Ultimaker/CuraEngine#gcode-generation
|
2015-05-01 10:06:52 +02:00
|
|
|
|
2015-05-07 18:14:10 +02:00
|
|
|
var start = new Date().getTime();
|
2015-05-01 10:06:52 +02:00
|
|
|
var gcode = this.dataToGcode(data, printer);
|
2015-05-07 18:14:10 +02:00
|
|
|
var end = new Date().getTime();
|
|
|
|
|
|
|
|
console.log("Gcode: " + (end - start) + "ms");
|
|
|
|
|
2015-04-24 16:12:48 +02:00
|
|
|
return gcode;
|
|
|
|
};
|