mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-12-23 11:33:49 +01:00
improved slicing algoritm
This commit is contained in:
parent
a70cf6325a
commit
5c413267d0
17
src/paths.js
17
src/paths.js
@ -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) {
|
||||||
|
303
src/slicer.js
303
src/slicer.js
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user