improved slicing algoritm

This commit is contained in:
casperlamboo 2015-07-29 11:18:18 +02:00
parent bde4a8a907
commit adafc44dc1
2 changed files with 182 additions and 138 deletions

View File

@ -10,7 +10,9 @@ export default class Paths extends Array {
} }
setPaths (paths) { setPaths (paths) {
for (var path of paths) { for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
if (path.length > 0) { if (path.length > 0) {
this.push(path); this.push(path);
} }
@ -75,6 +77,10 @@ export default class Paths extends Array {
} }
lastPoint () { lastPoint () {
if (this.length === 0) {
return new THREE.Vector2();
}
var lastPath = this[this.length - 1]; var lastPath = this[this.length - 1];
var lastPoint = this.closed ? lastPath[0] : lastPath[lastPath.length - 1]; var lastPoint = this.closed ? lastPath[0] : lastPath[lastPath.length - 1];
return new THREE.Vector2(lastPoint.X, lastPoint.Y); return new THREE.Vector2(lastPoint.X, lastPoint.Y);
@ -151,7 +157,8 @@ export default class Paths extends Array {
areas () { areas () {
var areas = []; var areas = [];
for (var shape of this) { for (var i = 0; i < this.length; i ++) {
var shape = this[i];
if (shape.closed) { if (shape.closed) {
var area = Math.abs(ClipperLib.Clipper.Area(shape)); var area = Math.abs(ClipperLib.Clipper.Area(shape));
areas.push(area); areas.push(area);
@ -165,7 +172,8 @@ export default class Paths extends Array {
var areas = this.areas(); var areas = this.areas();
var totalArea = 0; var totalArea = 0;
for (area of areas) { for (var i = 0; i < areas.length; i ++) {
var area = areas[i];
totalArea += area; totalArea += area;
} }
@ -174,7 +182,8 @@ export default class Paths extends Array {
tresholdArea (minArea) { tresholdArea (minArea) {
// code not tested yet // code not tested yet
for (var shape of this) { for (var i = 0; i < this.length; i ++) {
var shape = this[i];
var area = ClipperLib.Clipper.Area(shape); var area = ClipperLib.Clipper.Area(shape);
if (area < minArea) { if (area < minArea) {

View File

@ -7,7 +7,9 @@ export default class {
constructor () { constructor () {
this.progress = { this.progress = {
createdLines: false, createdLines: false,
calculatedLayerIntersections: false,
sliced: false, sliced: false,
generatedSlices: false,
generatedInnerLines: false, generatedInnerLines: false,
generatedInfills: false, generatedInfills: false,
generatedSupport: false, generatedSupport: false,
@ -52,10 +54,14 @@ export default class {
slice (settings) { slice (settings) {
var supportEnabled = settings.config['supportEnabled']; var supportEnabled = settings.config['supportEnabled'];
//get unique lines from geometry; // get unique lines from geometry;
var lines = this._createLines(settings); var lines = this._createLines(settings);
var slices = this._slice(lines, settings); var {layersIntersectionIndexes, layersIntersectionPoints} = this._calculateLayersIntersections(lines, settings);
var shapes = this._intersectionsToShapes(layersIntersectionIndexes, layersIntersectionPoints, lines, settings);
var slices = this._shapesToSlices(shapes, settings);
this._generateInnerLines(slices, settings); this._generateInnerLines(slices, settings);
@ -99,7 +105,8 @@ export default class {
return index; return index;
} }
for (var face of this.geometry.faces) { 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) { if (face.normal.y !== 1 && face.normal.y !== -1) {
var normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize(); var normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
@ -126,17 +133,19 @@ export default class {
return lines; return lines;
} }
_slice (lines, settings) { _calculateLayersIntersections (lines, settings) {
console.log("generating slices"); console.log('calculating layer intersections');
var layerHeight = settings.config["layerHeight"]; var layerHeight = settings.config["layerHeight"];
var height = settings.config["dimensionsZ"]; var height = settings.config["dimensionsZ"];
var numLayers = height / layerHeight; var numLayers = height / layerHeight;
var layersIntersections = []; var layersIntersectionIndexes = [];
var layersIntersectionPoints = [];
for (var layer = 0; layer < numLayers; layer ++) { for (var layer = 0; layer < numLayers; layer ++) {
layersIntersections[layer] = []; layersIntersectionIndexes[layer] = [];
layersIntersectionPoints[layer] = [];
} }
for (var lineIndex = 0; lineIndex < lines.length; lineIndex ++) { for (var lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
@ -147,23 +156,10 @@ export default class {
for (var layerIndex = min; layerIndex <= max; layerIndex ++) { for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0 && layerIndex < numLayers) { if (layerIndex >= 0 && layerIndex < numLayers) {
layersIntersections[layerIndex].push(lineIndex);
}
}
}
var slices = []; layersIntersectionIndexes[layerIndex].push(lineIndex);
for (var layer = 1; layer < layersIntersections.length; layer ++) { var y = layerIndex * layerHeight;
var layerIntersections = layersIntersections[layer];
if (layerIntersections.length > 0) {
var y = layer * layerHeight;
var intersections = [];
for (var index of layerIntersections) {
var line = lines[index].line;
if (line.start.y === line.end.y) { if (line.start.y === line.end.y) {
var x = line.start.x; var x = line.start.x;
@ -174,152 +170,191 @@ export default class {
var x = line.end.x * alpha + line.start.x * (1 - alpha); var x = line.end.x * alpha + line.start.x * (1 - alpha);
var z = line.end.z * alpha + line.start.z * (1 - alpha); var z = line.end.z * alpha + line.start.z * (1 - alpha);
} }
intersections[index] = new THREE.Vector2(z, x);
layersIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
}
}
}
this.progress.calculatedLayerIntersections = true;
this._updateProgress(settings);
return {
layersIntersectionIndexes,
layersIntersectionPoints
};
}
_intersectionsToShapes (layersIntersectionIndexes, layersIntersectionPoints, lines, settings) {
console.log("generating slices");
var layerHeight = settings.config["layerHeight"];
var shapes = [];
for (var layer = 1; layer < layersIntersectionIndexes.length; layer ++) {
var layerIntersectionIndexes = layersIntersectionIndexes[layer];
var layerIntersectionPoints = layersIntersectionPoints[layer];
if (layerIntersectionIndexes.length === 0) {
continue;
}
var shapeParts = [];
for (var i = 0; i < layerIntersectionIndexes.length; i ++) {
var index = layerIntersectionIndexes[i];
if (layerIntersectionPoints[index] === undefined) {
continue;
} }
var done = []; var firstPoint = index;
var sliceParts = []; var closed = false;
for (var index of layerIntersections) {
var firstPoint = index;
var closed = false;
if (done.indexOf(index) === -1) { var shape = [];
var shape = [];
while (index !== -1) { while (index !== -1) {
done.push(index); var intersection = layerIntersectionPoints[index];
//uppercase X and Y because clipper vector
shape.push({X: intersection.x, Y: intersection.y});
var intersection = intersections[index]; delete layerIntersectionPoints[index];
//uppercase X and Y because clipper vector
shape.push({X: intersection.x, Y: intersection.y});
var connects = lines[index].connects.map((value) => value); var connects = lines[index].connects;
var faceNormals = lines[index].normals.map((value) => value); var faceNormals = lines[index].normals;
for (var i = 0; i < connects.length; i ++) { for (var j = 0; j < connects.length; j ++) {
var index = connects[i]; var index = connects[j];
if (shape.length > 2 && index === firstPoint) { if (index === firstPoint && shape.length > 2) {
closed = true; closed = true;
index = -1;
break;
}
// Check if index has an intersection or is already used
if (layerIntersectionPoints[index] !== undefined) {
var faceNormal = faceNormals[Math.floor(j / 2)];
var a = new THREE.Vector2(intersection.x, intersection.y);
var b = new THREE.Vector2(layerIntersectionPoints[index].x, layerIntersectionPoints[index].y);
//threejs can't calculate normal if distance is smaller as 0.0001
if ((faceNormal.x === 0 && faceNormal.y === 0) || a.distanceTo(b) < 0.0001) {
delete layerIntersectionPoints[index];
connects = connects.concat(lines[index].connects);
faceNormals = faceNormals.concat(lines[index].normals);
index = -1;
}
else {
// 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; break;
} }
//check if index is already used
if (done.indexOf(index) === -1) {
//check if index has an intersection
if (intersections[index] !== undefined) {
var faceNormal = faceNormals[Math.floor(i / 2)];
var a = new THREE.Vector2(intersection.x, intersection.y);
var b = new THREE.Vector2(intersections[index].x, intersections[index].y);
if (a.distanceTo(b) < 0.0001 || (faceNormal.x === 0 && faceNormal.y === 0)) {
done.push(index);
connects = connects.concat(lines[index].connects);
faceNormals = faceNormals.concat(lines[index].normals);
index = -1;
}
else {
// 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;
}
}
}
else {
done.push(index);
index = -1;
}
}
else { else {
index = -1; index = -1;
} }
} }
} }
else {
if (!closed) { index = -1;
var index = firstPoint;
while (index !== -1) {
if (index !== firstPoint) {
done.push(index);
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});
}
var connects = lines[index].connects;
for (var index of connects) {
if (done.indexOf(index) === -1) {
if (intersections[index] !== undefined) {
break;
}
else {
done.push(index);
index = -1;
}
}
else {
index = -1;
}
}
}
}
if (shape.length > 0) {
var part = new Paths([shape], closed).clean(0.01);
sliceParts.push(part);
} }
} }
} }
sliceParts.sort((a, b) => { if (!closed) {
return b.boundSize() - a.boundSize(); var index = firstPoint;
});
var slice = new Slice(); while (index !== -1) {
if (index !== firstPoint) {
var intersection = layerIntersectionPoints[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});
for (var slicePart1 of sliceParts) { delete layerIntersectionPoints[index];
if (slicePart1.closed) { }
var merge = false;
for (var slicePart2 of slice.parts) { var connects = lines[index].connects;
if (slicePart2.closed && slicePart2.intersect(slicePart1).length > 0) {
slicePart2.join(slicePart1); for (var i = 0; i < connects.length; i ++) {
merge = true; var index = connects[i];
if (layerIntersectionPoints[index] !== undefined) {
break; break;
} }
else {
delete layerIntersectionPoints[index];
index = -1;
}
} }
if (!merge) {
slice.add(slicePart1);
}
}
else {
slice.add(slicePart1);
} }
} }
slices.push(slice); // don't think this check is nessecary
if (shape.length > 0) {
var part = new Paths([shape], closed).clean(0.01);
shapeParts.push(part);
}
} }
shapes.push(shapeParts);
} }
this.progress.sliced = true; this.progress.sliced = true;
this._updateProgress(settings); this._updateProgress(settings);
return shapes;
}
_shapesToSlices (shapes, settings) {
var slices = [];
for (var layer = 0; layer < shapes.length; layer ++) {
var shapeParts = shapes[layer];
shapeParts.sort((a, b) => {
return a.boundSize() - b.boundSize();
});
var slice = new Slice();
for (var i = 0; i < shapeParts.length; i ++) {
var shapePart1 = shapeParts[i];
if (shapePart1.closed) {
var merge = false;
for (var j = 0; j < slice.parts.length; j ++) {
var shapePart2 = slice.parts[j].intersect;
if (shapePart2.closed && shapePart2.intersect(shapePart1).length > 0) {
shapePart2.join(shapePart1);
merge = true;
break;
}
}
if (!merge) {
slice.add(shapePart1);
}
}
else {
slice.add(shapePart1);
}
}
slices.push(slice);
}
this.progress.generatedSlices = true;
this._updateProgress(settings);
return slices; return slices;
} }