2015-07-26 15:32:10 +02:00
|
|
|
import THREE from 'three.js';
|
|
|
|
import Paths from './paths.js';
|
|
|
|
import Slice from './slice.js';
|
|
|
|
import GCode from './gcode.js';
|
|
|
|
|
|
|
|
export default class {
|
|
|
|
constructor () {
|
|
|
|
this.progress = {
|
|
|
|
createdLines: false,
|
|
|
|
sliced: false,
|
|
|
|
generatedInnerLines: false,
|
|
|
|
generatedInfills: false,
|
|
|
|
generatedSupport: false,
|
|
|
|
optimizedPaths: false,
|
|
|
|
generatedGCode: false
|
|
|
|
};
|
2015-06-16 01:25:06 +02:00
|
|
|
}
|
2015-06-16 07:23:31 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
setMesh (mesh) {
|
|
|
|
mesh.updateMatrix();
|
2015-06-11 10:28:21 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.setGeometry(mesh.geometry, mesh.matrix);
|
2015-04-28 14:11:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return this;
|
|
|
|
}
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
setGeometry (geometry, matrix) {
|
|
|
|
//convert buffergeometry to geometry;
|
|
|
|
if (geometry.type === 'BufferGeometry') {
|
|
|
|
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
|
|
|
|
}
|
|
|
|
else if (geometry.type === 'Geometry') {
|
|
|
|
geometry = geometry.clone();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.warn('Geometry is not an instance of BufferGeometry or Geometry');
|
|
|
|
return;
|
|
|
|
}
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (matrix instanceof THREE.Matrix4) {
|
|
|
|
geometry.applyMatrix(matrix);
|
|
|
|
}
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
geometry.computeBoundingBox();
|
|
|
|
geometry.computeFaceNormals();
|
|
|
|
geometry.mergeVertices();
|
2015-07-10 15:06:51 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.geometry = geometry;
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return this;
|
2015-06-16 10:28:26 +02:00
|
|
|
}
|
2015-07-10 15:06:51 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
slice (settings) {
|
|
|
|
var supportEnabled = settings.config['supportEnabled'];
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//get unique lines from geometry;
|
|
|
|
var lines = this._createLines(settings);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var slices = this._slice(lines, settings);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this._generateInnerLines(slices, settings);
|
|
|
|
|
|
|
|
this._generateInfills(slices, settings);
|
|
|
|
|
|
|
|
if (supportEnabled) {
|
|
|
|
this._generateSupport(slices, settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._optimizePaths(slices, settings);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var gcode = this._slicesToGCode(slices, settings);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (this.onfinish !== undefined) {
|
|
|
|
this.onfinish(gcode);
|
2015-05-01 16:44:05 +02:00
|
|
|
}
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return gcode;
|
2015-05-07 11:04:48 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_createLines (settings) {
|
|
|
|
console.log('constructing lines from geometry');
|
|
|
|
|
|
|
|
var lines = [];
|
|
|
|
var lineLookup = {};
|
2015-05-13 12:12:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var addLine = (a, b) => {
|
|
|
|
var index = lineLookup[b + '_' + a];
|
2015-05-13 12:12:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (index === undefined) {
|
|
|
|
index = lines.length;
|
|
|
|
lineLookup[a + '_' + b] = index;
|
2015-05-13 12:12:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
lines.push({
|
|
|
|
line: new THREE.Line3(this.geometry.vertices[a], this.geometry.vertices[b]),
|
|
|
|
connects: [],
|
|
|
|
normals: []
|
|
|
|
});
|
|
|
|
}
|
2015-05-13 12:12:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return index;
|
2015-05-17 19:58:44 +02:00
|
|
|
}
|
2015-07-01 14:51:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var face of this.geometry.faces) {
|
|
|
|
if (face.normal.y !== 1 && face.normal.y !== -1) {
|
|
|
|
var normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
|
|
|
|
|
|
|
|
//check for only adding unique lines
|
|
|
|
//returns index of said line
|
|
|
|
var a = addLine(face.a, face.b);
|
|
|
|
var b = addLine(face.b, face.c);
|
|
|
|
var c = addLine(face.c, face.a);
|
2015-07-10 12:59:50 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//set connecting lines (based on face)
|
|
|
|
lines[a].connects.push(b, c);
|
|
|
|
lines[b].connects.push(c, a);
|
|
|
|
lines[c].connects.push(a, b);
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
lines[a].normals.push(normal);
|
|
|
|
lines[b].normals.push(normal);
|
|
|
|
lines[c].normals.push(normal);
|
|
|
|
}
|
|
|
|
}
|
2015-07-10 09:16:03 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.createdLines = true;
|
|
|
|
this._updateProgress(settings);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return lines;
|
2015-06-12 15:58:26 +02:00
|
|
|
}
|
2015-07-10 15:06:51 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_slice (lines, settings) {
|
|
|
|
console.log("generating slices");
|
2015-05-07 17:27:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var layerHeight = settings.config["layerHeight"];
|
|
|
|
var height = settings.config["dimensionsZ"];
|
2015-05-07 17:27:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var numLayers = height / layerHeight;
|
|
|
|
|
|
|
|
var layersIntersections = [];
|
|
|
|
for (var layer = 0; layer < numLayers; layer ++) {
|
|
|
|
layersIntersections[layer] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
|
|
|
var line = lines[lineIndex].line;
|
|
|
|
|
|
|
|
var min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
|
|
|
|
var max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
|
|
|
|
|
|
|
|
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
|
|
|
|
if (layerIndex >= 0 && layerIndex < numLayers) {
|
|
|
|
layersIntersections[layerIndex].push(lineIndex);
|
|
|
|
}
|
2015-05-07 17:27:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var slices = [];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var layer = 1; layer < layersIntersections.length; layer ++) {
|
|
|
|
var layerIntersections = layersIntersections[layer];
|
2015-06-12 15:58:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (layerIntersections.length > 0) {
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var y = layer * layerHeight;
|
2015-05-08 10:07:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var intersections = [];
|
|
|
|
for (var index of layerIntersections) {
|
|
|
|
var line = lines[index].line;
|
2015-06-12 15:58:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (line.start.y === line.end.y) {
|
|
|
|
var x = line.start.x;
|
|
|
|
var z = line.start.z;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
|
|
|
|
var x = line.end.x * alpha + line.start.x * (1 - alpha);
|
|
|
|
var z = line.end.z * alpha + line.start.z * (1 - alpha);
|
|
|
|
}
|
|
|
|
intersections[index] = new THREE.Vector2(z, x);
|
2015-06-12 21:19:56 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var done = [];
|
|
|
|
var sliceParts = [];
|
|
|
|
for (var index of layerIntersections) {
|
|
|
|
var firstPoint = index;
|
|
|
|
var closed = false;
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (done.indexOf(index) === -1) {
|
|
|
|
var shape = [];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
while (index !== -1) {
|
|
|
|
done.push(index);
|
2015-06-17 09:36:01 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var intersection = intersections[index];
|
|
|
|
//uppercase X and Y because clipper vector
|
|
|
|
shape.push({X: intersection.x, Y: intersection.y});
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var connects = lines[index].connects.map((value) => value);
|
|
|
|
var faceNormals = lines[index].normals.map((value) => value);
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < connects.length; i ++) {
|
|
|
|
var index = connects[i];
|
2015-06-09 11:08:06 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (shape.length > 2 && index === firstPoint) {
|
|
|
|
closed = true;
|
|
|
|
break;
|
|
|
|
}
|
2015-07-26 15:24:35 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//check if index is already used
|
|
|
|
if (done.indexOf(index) === -1) {
|
2015-04-28 17:54:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//check if index has an intersection
|
|
|
|
if (intersections[index] !== undefined) {
|
2015-06-11 10:28:21 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var faceNormal = faceNormals[Math.floor(i / 2)];
|
2015-06-09 11:08:06 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var a = new THREE.Vector2(intersection.x, intersection.y);
|
|
|
|
var b = new THREE.Vector2(intersections[index].x, intersections[index].y);
|
2015-06-15 17:22:36 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (a.distanceTo(b) < 0.0001 || (faceNormal.x === 0 && faceNormal.y === 0)) {
|
|
|
|
done.push(index);
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
connects = connects.concat(lines[index].connects);
|
|
|
|
faceNormals = faceNormals.concat(lines[index].normals);
|
|
|
|
index = -1;
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-07-26 15:32:10 +02:00
|
|
|
// THREE.Vector2.normal is not yet implimented
|
|
|
|
// var normal = a.sub(b).normal().normalize();
|
|
|
|
var normal = a.sub(b);
|
|
|
|
normal.set(-normal.y, normal.x).normalize();
|
|
|
|
|
|
|
|
if (normal.dot(faceNormal) > 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = -1;
|
|
|
|
}
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
else {
|
|
|
|
done.push(index);
|
|
|
|
index = -1;
|
|
|
|
}
|
2015-06-09 11:08:06 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-07-10 18:04:10 +02:00
|
|
|
index = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-12 21:19:56 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (!closed) {
|
|
|
|
var index = firstPoint;
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
while (index !== -1) {
|
|
|
|
if (index !== firstPoint) {
|
|
|
|
done.push(index);
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var intersection = intersections[index];
|
|
|
|
// PERFORMACE
|
|
|
|
// maybe performance can be increased by unshifting to sepperate
|
|
|
|
// array and to later concat the original en the new array
|
|
|
|
shape.unshift({X: intersection.x, Y: intersection.y});
|
|
|
|
}
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var connects = lines[index].connects;
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var index of connects) {
|
|
|
|
index = connects[j];
|
2015-07-10 18:04:10 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (done.indexOf(index) === -1) {
|
|
|
|
if (intersections[index] !== undefined) {
|
|
|
|
break;
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-07-26 15:32:10 +02:00
|
|
|
done.push(index);
|
|
|
|
index = -1;
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
2015-06-17 09:36:01 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = -1;
|
|
|
|
}
|
2015-06-09 11:08:06 +02:00
|
|
|
}
|
2015-06-12 21:19:56 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (shape.length > 0) {
|
|
|
|
var part = new Paths([shape], closed).clean(0.01);
|
|
|
|
sliceParts.push(part);
|
|
|
|
}
|
2015-06-12 21:19:56 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
}
|
2015-04-28 14:11:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
sliceParts.sort(function (a, b) {
|
|
|
|
return b.area() - a.area();
|
|
|
|
});
|
2015-06-09 11:08:06 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var slice = new Slice();
|
2015-05-13 13:18:37 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < sliceParts.length; i ++) {
|
|
|
|
var slicePart1 = sliceParts[i];
|
|
|
|
if (slicePart1.closed) {
|
|
|
|
var merge = false;
|
2015-05-13 17:37:52 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var j = 0; j < slice.parts.length; j ++) {
|
|
|
|
var slicePart2 = slice.parts[j].intersect;
|
|
|
|
|
|
|
|
if (slicePart2.closed && slicePart2.intersect(slicePart1).length > 0) {
|
|
|
|
slicePart2.join(slicePart1);
|
|
|
|
merge = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!merge) {
|
|
|
|
slice.add(slicePart1);
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
else {
|
2015-07-10 18:04:10 +02:00
|
|
|
slice.add(slicePart1);
|
2015-06-12 21:19:56 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-13 17:37:52 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
slices.push(slice);
|
|
|
|
}
|
2015-06-12 21:19:56 +02:00
|
|
|
}
|
2015-06-15 17:22:36 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.sliced = true;
|
|
|
|
this._updateProgress(settings);
|
2015-06-15 17:22:36 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return slices;
|
|
|
|
}
|
2015-04-30 20:34:57 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_generateInnerLines (slices, settings) {
|
|
|
|
console.log("generating outer lines and inner lines");
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//need to scale up everything because of clipper rounding errors
|
|
|
|
var scale = 100;
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var layerHeight = settings.config["layerHeight"];
|
|
|
|
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
|
|
var shellThickness = settings.config["shellThickness"] * scale;
|
|
|
|
var nozzleRadius = nozzleDiameter / 2;
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var layer = 0; layer < slices.length; layer ++) {
|
|
|
|
var slice = slices[layer];
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < slice.parts.length; i ++) {
|
|
|
|
var part = slice.parts[i];
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (!part.intersect.closed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//var outerLine = part.intersect.clone().scaleUp(scale).offset(-nozzleRadius);
|
|
|
|
var outerLine = part.intersect.scaleUp(scale).offset(-nozzleRadius);
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
if (outerLine.length > 0) {
|
|
|
|
part.outerLine = outerLine;
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
for (var offset = nozzleDiameter; offset <= shellThickness; offset += nozzleDiameter) {
|
|
|
|
var innerLine = outerLine.offset(-offset);
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
if (innerLine.length > 0) {
|
|
|
|
part.innerLines.push(innerLine);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
2015-06-11 14:34:30 +02:00
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
|
|
|
|
this.progress.generatedInnerLines = true;
|
|
|
|
this._updateProgress(settings);
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-07-01 14:51:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_generateInfills (slices, settings) {
|
|
|
|
console.log("generating infills");
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//need to scale up everything because of clipper rounding errors
|
|
|
|
var scale = 100;
|
|
|
|
|
|
|
|
var layerHeight = settings.config["layerHeight"];
|
|
|
|
var fillGridSize = settings.config["fillGridSize"] * scale;
|
|
|
|
var bottomThickness = settings.config["bottomThickness"];
|
|
|
|
var topThickness = settings.config["topThickness"];
|
|
|
|
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
|
|
var infillOverlap = settings.config["infillOverlap"] * scale;
|
|
|
|
|
|
|
|
var bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
|
|
|
|
var topSkinCount = Math.ceil(topThickness/layerHeight);
|
|
|
|
var nozzleRadius = nozzleDiameter / 2;
|
|
|
|
var hightemplateSize = Math.sqrt(2 * Math.pow(nozzleDiameter, 2));
|
|
|
|
|
|
|
|
for (var layer = 0; layer < slices.length; layer ++) {
|
|
|
|
var slice = slices[layer];
|
|
|
|
|
|
|
|
if (layer - bottomSkinCount >= 0 && layer + topSkinCount < slices.length) {
|
|
|
|
var downSkin = slices[layer - bottomSkinCount].getOutline();
|
|
|
|
var upSkin = slices[layer + topSkinCount].getOutline();
|
|
|
|
var surroundingLayer = upSkin.intersect(downSkin);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var surroundingLayer = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < slice.parts.length; i ++) {
|
|
|
|
var part = slice.parts[i];
|
|
|
|
|
|
|
|
if (!part.intersect.closed) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
var outerLine = part.outerLine;
|
|
|
|
|
|
|
|
if (outerLine.length > 0) {
|
2015-07-26 15:32:10 +02:00
|
|
|
var inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
var fillArea = inset.offset(-nozzleRadius);
|
|
|
|
if (surroundingLayer) {
|
2015-07-26 15:32:10 +02:00
|
|
|
|
|
|
|
var highFillArea = fillArea.difference(surroundingLayer);
|
|
|
|
|
|
|
|
if (infillOverlap > 0) {
|
|
|
|
highFillArea = highFillArea.offset(infillOverlap);
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
|
|
|
|
highFillArea = highFillArea.intersect(fillArea);
|
|
|
|
|
|
|
|
var lowFillArea = fillArea.difference(highFillArea);
|
2015-07-10 12:59:50 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-07-10 18:04:10 +02:00
|
|
|
var highFillArea = fillArea;
|
2015-07-10 12:59:50 +02:00
|
|
|
}
|
2015-04-30 20:34:57 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var fill = new Paths([], false);
|
2015-05-13 12:12:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (lowFillArea !== undefined && lowFillArea.length > 0) {
|
2015-07-10 18:04:10 +02:00
|
|
|
var bounds = lowFillArea.bounds();
|
|
|
|
var lowFillTemplate = this._getFillTemplate(bounds, fillGridSize, true, true);
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
part.fill.join(lowFillTemplate.intersect(lowFillArea));
|
|
|
|
}
|
2015-04-30 20:34:57 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
if (highFillArea.length > 0) {
|
|
|
|
var bounds = highFillArea.bounds();
|
|
|
|
var even = (layer % 2 === 0);
|
|
|
|
var highFillTemplate = this._getFillTemplate(bounds, hightemplateSize, even, !even);
|
2015-06-15 10:21:05 +02:00
|
|
|
|
2015-07-10 18:04:10 +02:00
|
|
|
part.fill.join(highFillTemplate.intersect(highFillArea));
|
|
|
|
}
|
2015-05-18 13:53:49 +02:00
|
|
|
}
|
2015-05-15 17:35:18 +02:00
|
|
|
}
|
2015-04-30 20:34:57 +02:00
|
|
|
}
|
2015-07-01 14:51:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.generatedInfills = true;
|
|
|
|
this._updateProgress(settings);
|
|
|
|
}
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_generateSupport (slices, settings) {
|
|
|
|
console.log("generating support");
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//need to scale up everything because of clipper rounding errors
|
|
|
|
var scale = 100;
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var layerHeight = settings.config["layerHeight"];
|
|
|
|
var supportGridSize = settings.config["supportGridSize"] * scale;
|
|
|
|
var supportAcceptanceMargin = settings.config["supportAcceptanceMargin"] * scale;
|
|
|
|
var supportMargin = settings.config["supportMargin"] * scale;
|
|
|
|
var plateSize = settings.config["supportPlateSize"] * scale;
|
|
|
|
var supportDistanceY = settings.config["supportDistanceY"];
|
|
|
|
var supportDistanceLayers = Math.ceil(supportDistanceY / layerHeight);
|
|
|
|
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var supportAreas = new Paths([], true);
|
2015-05-12 11:29:01 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
|
|
|
|
if (supportAreas.length > 0) {
|
2015-06-10 18:25:49 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (layer >= supportDistanceLayers) {
|
|
|
|
//var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
|
|
|
|
var sliceSkin = slices[layer].getOutline();
|
|
|
|
sliceSkin = sliceSkin.offset(supportMargin);
|
2015-06-10 18:25:49 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
supportAreas = supportAreas.difference(sliceSkin);
|
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var currentSlice = slices[layer];
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (layer === 0) {
|
|
|
|
supportAreas = supportAreas.offset(plateSize).difference(sliceSkin);
|
2015-05-13 17:37:52 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var template = this._getFillTemplate(supportAreas.bounds(), nozzleDiameter, true, false);
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
currentSlice.support = template.intersect(supportAreas);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var supportTemplate = this._getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
|
2015-06-15 10:21:05 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
currentSlice.support = supportTemplate.intersect(supportAreas).join(supportAreas.clone());
|
|
|
|
}
|
2015-06-10 18:25:49 +02:00
|
|
|
}
|
2015-04-24 16:12:48 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
|
2015-05-26 11:44:15 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var slice = slices[layer + supportDistanceLayers];
|
|
|
|
for (var i = 0; i < slice.parts.length; i ++) {
|
|
|
|
var slicePart = slice.parts[i];
|
|
|
|
var outerLine = slicePart.outerLine;
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
|
|
|
|
var overhang = outerLine.difference(overlap);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (overlap.length === 0 || overhang.length > 0) {
|
|
|
|
supportAreas = supportAreas.union(overhang.offset(supportAcceptanceMargin).intersect(outerLine));
|
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-01 14:51:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.generatedSupport = true;
|
|
|
|
this._updateProgress(settings);
|
|
|
|
}
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_optimizePaths (slices, settings) {
|
|
|
|
console.log("opimize paths");
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
//need to scale up everything because of clipper rounding errors
|
|
|
|
var scale = 100;
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var brimOffset = settings.config["brimOffset"] * scale;
|
2015-06-16 10:28:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var start = new THREE.Vector2(0, 0);
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var layer = 0; layer < slices.length; layer ++) {
|
|
|
|
var slice = slices[layer];
|
2015-04-30 18:26:34 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (layer === 0) {
|
|
|
|
slice.brim = slice.getOutline().offset(brimOffset);
|
|
|
|
}
|
2015-05-13 17:37:52 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
start = slice.optimizePaths(start);
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < slice.parts.length; i ++) {
|
|
|
|
var part = slice.parts[i];
|
2015-05-29 13:51:18 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (part.intersect.closed) {
|
|
|
|
part.outerLine.scaleDown(scale);
|
|
|
|
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
|
|
var innerLine = part.innerLines[j];
|
|
|
|
innerLine.scaleDown(scale);
|
|
|
|
}
|
|
|
|
part.fill.scaleDown(scale);
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (slice.support !== undefined) {
|
|
|
|
slice.support.scaleDown(scale);
|
|
|
|
}
|
|
|
|
if (slice.brim !== undefined) {
|
|
|
|
slice.brim.scaleDown(scale);
|
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-07-01 14:51:41 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.optimizedPaths = true;
|
|
|
|
this._updateProgress(settings);
|
|
|
|
}
|
2015-05-19 19:04:20 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_getFillTemplate (bounds, size, even, uneven) {
|
|
|
|
var paths = new Paths([], false);
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var left = Math.floor(bounds.left / size) * size;
|
|
|
|
var right = Math.ceil(bounds.right / size) * size;
|
|
|
|
var top = Math.floor(bounds.top / size) * size;
|
|
|
|
var bottom = Math.floor(bounds.bottom / size) * size;
|
2015-06-16 01:25:06 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var width = right - left;
|
2015-06-16 01:25:06 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (even) {
|
|
|
|
for (var y = top; y <= bottom + width; y += size) {
|
|
|
|
paths.push([
|
|
|
|
{X: left, Y: y},
|
|
|
|
{X: right, Y: y - width}
|
|
|
|
]);
|
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
if (uneven) {
|
|
|
|
for (var y = top - width; y <= bottom; y += size) {
|
|
|
|
paths.push([
|
|
|
|
{X: left, Y: y},
|
|
|
|
{X: right, Y: y + width}
|
|
|
|
]);
|
|
|
|
}
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
|
|
|
|
return paths;
|
2015-06-09 21:58:22 +02:00
|
|
|
}
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_slicesToGCode (slices, settings) {
|
|
|
|
var gcode = new GCode().setSettings(settings);
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
function pathToGCode (path, retract, unRetract, type) {
|
2015-06-12 15:58:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < path.length; i ++) {
|
|
|
|
var shape = path[i];
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var length = path.closed ? (shape.length + 1) : shape.length;
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var j = 0; j < length; j ++) {
|
|
|
|
var point = shape[j % shape.length];
|
2015-05-01 14:09:45 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (j === 0) {
|
|
|
|
//TODO
|
|
|
|
//moveTo should impliment combing
|
|
|
|
gcode.moveTo(point.X, point.Y, layer);
|
2015-06-05 09:56:58 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (unRetract) {
|
|
|
|
gcode.unRetract();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gcode.lineTo(point.X, point.Y, layer, type);
|
2015-06-05 09:56:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
|
|
|
|
if (retract) {
|
|
|
|
gcode.retract();
|
|
|
|
}
|
2015-06-05 09:56:58 +02:00
|
|
|
}
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var layer = 0; layer < slices.length; layer ++) {
|
|
|
|
var slice = slices[layer];
|
2015-06-05 09:56:58 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (layer === 1) {
|
|
|
|
gcode.turnFanOn();
|
|
|
|
gcode.bottom = false;
|
|
|
|
}
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (slice.brim !== undefined) {
|
|
|
|
pathToGCode(slice.brim, true, true, "brim");
|
|
|
|
}
|
2015-05-13 17:37:52 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var i = 0; i < slice.parts.length; i ++) {
|
|
|
|
var part = slice.parts[i];
|
2015-06-09 21:58:22 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (part.intersect.closed) {
|
|
|
|
pathToGCode(part.outerLine, false, true, "outerLine");
|
2015-06-12 15:58:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
|
|
var innerLine = part.innerLines[j];
|
|
|
|
pathToGCode(innerLine, false, false, "innerLine");
|
|
|
|
}
|
2015-06-12 15:58:26 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
pathToGCode(part.fill, true, false, "fill");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var retract = !(slice.parts.length === 1 && slice.support === undefined);
|
|
|
|
pathToGCode(part.intersect, retract, retract, "outerLine");
|
|
|
|
}
|
2015-07-10 18:04:10 +02:00
|
|
|
}
|
2015-06-11 14:34:30 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
if (slice.support !== undefined) {
|
|
|
|
pathToGCode(slice.support, true, true, "support");
|
|
|
|
}
|
2015-05-13 17:37:52 +02:00
|
|
|
}
|
2015-05-01 12:15:46 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.progress.generatedGCode = true;
|
|
|
|
this._updateProgress(settings);
|
2015-07-01 14:51:41 +02:00
|
|
|
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
return gcode.getGCode();
|
|
|
|
}
|
2015-07-10 12:59:50 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
_updateProgress (settings) {
|
|
|
|
if (this.onprogress !== undefined) {
|
|
|
|
var supportEnabled = settings.config["supportEnabled"];
|
2015-07-10 12:59:50 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var progress = {};
|
2015-07-10 12:59:50 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
var procent = 0;
|
|
|
|
var length = 0;
|
|
|
|
for (var i in this.progress) {
|
|
|
|
if (!(!supportEnabled && i === "generatedSupport")) {
|
|
|
|
progress[i] = this.progress[i];
|
|
|
|
if (progress[i]) {
|
|
|
|
procent += 1;
|
|
|
|
}
|
|
|
|
length += 1;
|
2015-07-10 12:59:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
progress.procent = procent / length;
|
2015-07-10 12:59:50 +02:00
|
|
|
|
2015-07-26 15:32:10 +02:00
|
|
|
this.onprogress(progress);
|
|
|
|
}
|
2015-07-10 12:59:50 +02:00
|
|
|
}
|
2015-07-26 15:32:10 +02:00
|
|
|
}
|