mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-12-23 19:43:48 +01:00
separate into actions into different files
This commit is contained in:
parent
7ae57e0bda
commit
3db03cd873
50
src/sliceActions/calculateLayersIntersections.js
Normal file
50
src/sliceActions/calculateLayersIntersections.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
|
||||||
|
export default function calculateLayersIntersections(lines, settings) {
|
||||||
|
console.log('calculating layer intersections');
|
||||||
|
|
||||||
|
var layerHeight = settings.config["layerHeight"];
|
||||||
|
var height = settings.config["dimensionsZ"];
|
||||||
|
|
||||||
|
var numLayers = Math.floor(height / layerHeight);
|
||||||
|
|
||||||
|
var layerIntersectionIndexes = [];
|
||||||
|
var layerIntersectionPoints = [];
|
||||||
|
for (var layer = 0; layer < numLayers; layer ++) {
|
||||||
|
layerIntersectionIndexes[layer] = [];
|
||||||
|
layerIntersectionPoints[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) {
|
||||||
|
|
||||||
|
layerIntersectionIndexes[layerIndex].push(lineIndex);
|
||||||
|
|
||||||
|
var y = layerIndex * layerHeight;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
layerIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
layerIntersectionIndexes,
|
||||||
|
layerIntersectionPoints
|
||||||
|
};
|
||||||
|
}
|
49
src/sliceActions/createLines.js
Normal file
49
src/sliceActions/createLines.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
|
||||||
|
export default function createLines(geometry, settings) {
|
||||||
|
console.log('constructing unique lines from geometry');
|
||||||
|
|
||||||
|
var lines = [];
|
||||||
|
var lineLookup = {};
|
||||||
|
|
||||||
|
var addLine = (a, b) => {
|
||||||
|
var index = lineLookup[b + '_' + a];
|
||||||
|
|
||||||
|
if (index === undefined) {
|
||||||
|
index = lines.length;
|
||||||
|
lineLookup[a + '_' + b] = index;
|
||||||
|
|
||||||
|
lines.push({
|
||||||
|
line: new THREE.Line3(geometry.vertices[a], geometry.vertices[b]),
|
||||||
|
connects: [],
|
||||||
|
normals: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < geometry.faces.length; i ++) {
|
||||||
|
var face = geometry.faces[i];
|
||||||
|
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);
|
||||||
|
|
||||||
|
// set connecting lines (based on face)
|
||||||
|
lines[a].connects.push(b, c);
|
||||||
|
lines[b].connects.push(c, a);
|
||||||
|
lines[c].connects.push(a, b);
|
||||||
|
|
||||||
|
lines[a].normals.push(normal);
|
||||||
|
lines[b].normals.push(normal);
|
||||||
|
lines[c].normals.push(normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
82
src/sliceActions/generateInfills.js
Normal file
82
src/sliceActions/generateInfills.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import getFillTemplate from './getFillTemplate.js';
|
||||||
|
import Paths from '../paths.js';
|
||||||
|
|
||||||
|
export default function generateInfills(slices, settings) {
|
||||||
|
console.log("generating infills");
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outerLine = part.outerLine;
|
||||||
|
|
||||||
|
if (outerLine.length > 0) {
|
||||||
|
var inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
|
||||||
|
|
||||||
|
var fillArea = inset.offset(-nozzleRadius);
|
||||||
|
var lowFillArea = false;
|
||||||
|
if (surroundingLayer) {
|
||||||
|
var highFillArea = fillArea.difference(surroundingLayer);
|
||||||
|
|
||||||
|
if (infillOverlap > 0) {
|
||||||
|
highFillArea = highFillArea.offset(infillOverlap);
|
||||||
|
}
|
||||||
|
|
||||||
|
highFillArea = highFillArea.intersect(fillArea);
|
||||||
|
|
||||||
|
var lowFillArea = fillArea.difference(highFillArea);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var highFillArea = fillArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fill = new Paths([], false);
|
||||||
|
|
||||||
|
if (lowFillArea && lowFillArea.length > 0) {
|
||||||
|
var bounds = lowFillArea.bounds();
|
||||||
|
var lowFillTemplate = getFillTemplate(bounds, fillGridSize, true, true);
|
||||||
|
|
||||||
|
part.fill.join(lowFillTemplate.intersect(lowFillArea));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highFillArea.length > 0) {
|
||||||
|
var bounds = highFillArea.bounds();
|
||||||
|
var even = (layer % 2 === 0);
|
||||||
|
var highFillTemplate = getFillTemplate(bounds, hightemplateSize, even, !even);
|
||||||
|
|
||||||
|
part.fill.join(highFillTemplate.intersect(highFillArea));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/sliceActions/generateInnerLines.js
Normal file
44
src/sliceActions/generateInnerLines.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
export default function generateInnerLines(slices, settings) {
|
||||||
|
console.log("generating outer lines and inner lines");
|
||||||
|
|
||||||
|
// need to scale up everything because of clipper rounding errors
|
||||||
|
var scale = 100;
|
||||||
|
|
||||||
|
var layerHeight = settings.config["layerHeight"];
|
||||||
|
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
||||||
|
var shellThickness = settings.config["shellThickness"] * scale;
|
||||||
|
var nozzleRadius = nozzleDiameter / 2;
|
||||||
|
var shells = Math.round(shellThickness / nozzleDiameter);
|
||||||
|
|
||||||
|
for (var layer = 0; layer < slices.length; layer ++) {
|
||||||
|
var slice = slices[layer];
|
||||||
|
|
||||||
|
for (var i = 0; i < slice.parts.length; i ++) {
|
||||||
|
var part = slice.parts[i];
|
||||||
|
|
||||||
|
if (!part.intersect.closed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// var outerLine = part.intersect.clone().scaleUp(scale).offset(-nozzleRadius);
|
||||||
|
var outerLine = part.intersect.scaleUp(scale).offset(-nozzleRadius);
|
||||||
|
|
||||||
|
if (outerLine.length > 0) {
|
||||||
|
part.outerLine = outerLine;
|
||||||
|
|
||||||
|
for (var shell = 1; shell < shells; shell += 1) {
|
||||||
|
var offset = shell * nozzleDiameter;
|
||||||
|
|
||||||
|
var innerLine = outerLine.offset(-offset);
|
||||||
|
|
||||||
|
if (innerLine.length > 0) {
|
||||||
|
part.innerLines.push(innerLine);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
src/sliceActions/generateSupport.js
Normal file
71
src/sliceActions/generateSupport.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import getFillTemplate from './getFillTemplate.js';
|
||||||
|
import Paths from '../paths.js';
|
||||||
|
|
||||||
|
export default function generateSupport(slices, settings) {
|
||||||
|
console.log("generating support");
|
||||||
|
|
||||||
|
// need to scale up everything because of clipper rounding errors
|
||||||
|
var scale = 100;
|
||||||
|
|
||||||
|
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.max(Math.ceil(supportDistanceY / layerHeight), 1);
|
||||||
|
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
||||||
|
|
||||||
|
var supportAreas = new Paths([], true);
|
||||||
|
|
||||||
|
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
|
||||||
|
var currentSlice = slices[layer];
|
||||||
|
|
||||||
|
if (supportAreas.length > 0) {
|
||||||
|
|
||||||
|
if (layer >= supportDistanceLayers) {
|
||||||
|
var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
|
||||||
|
sliceSkin = sliceSkin;
|
||||||
|
|
||||||
|
var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin));
|
||||||
|
if (supportAreasSlimmed.area() < 100.0) {
|
||||||
|
supportAreas = supportAreas.difference(sliceSkin);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
supportAreas = supportAreasSlimmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var supportTemplate = getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
|
||||||
|
var supportFill = supportTemplate.intersect(supportAreas);
|
||||||
|
if (supportFill.length === 0) {
|
||||||
|
currentSlice.support = supportAreas.clone();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentSlice.support = supportFill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
|
||||||
|
|
||||||
|
var slice = slices[layer + supportDistanceLayers];
|
||||||
|
for (var i = 0; i < slice.parts.length; i ++) {
|
||||||
|
var slicePart = slice.parts[i];
|
||||||
|
|
||||||
|
if (slicePart.intersect.closed) {
|
||||||
|
var outerLine = slicePart.outerLine;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var outerLine = slicePart.intersect.offset(supportAcceptanceMargin);
|
||||||
|
}
|
||||||
|
|
||||||
|
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
|
||||||
|
var overhang = outerLine.difference(overlap);
|
||||||
|
|
||||||
|
if (overlap.length === 0 || overhang.length > 0) {
|
||||||
|
supportAreas = supportAreas.join(overhang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
src/sliceActions/getFillTemplate.js
Normal file
31
src/sliceActions/getFillTemplate.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import Paths from '../paths.js';
|
||||||
|
|
||||||
|
export default function getFillTemplate(bounds, size, even, uneven) {
|
||||||
|
var paths = new Paths([], false);
|
||||||
|
|
||||||
|
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.ceil(bounds.bottom / size) * size;
|
||||||
|
|
||||||
|
var width = right - left;
|
||||||
|
|
||||||
|
if (even) {
|
||||||
|
for (var y = top; y <= bottom + width; y += size) {
|
||||||
|
paths.push([
|
||||||
|
{X: left, Y: y},
|
||||||
|
{X: right, Y: y - width}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uneven) {
|
||||||
|
for (var y = top - width; y <= bottom; y += size) {
|
||||||
|
paths.push([
|
||||||
|
{X: left, Y: y},
|
||||||
|
{X: right, Y: y + width}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
127
src/sliceActions/intersectionsToShapes.js
Normal file
127
src/sliceActions/intersectionsToShapes.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
import Paths from '../paths.js';
|
||||||
|
|
||||||
|
export default function intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings) {
|
||||||
|
console.log("generating slices");
|
||||||
|
|
||||||
|
var shapes = [];
|
||||||
|
|
||||||
|
for (var layer = 1; layer < layerIntersectionIndexes.length; layer ++) {
|
||||||
|
var intersectionIndexes = layerIntersectionIndexes[layer];
|
||||||
|
var intersectionPoints = layerIntersectionPoints[layer];
|
||||||
|
|
||||||
|
if (intersectionIndexes.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shapeParts = [];
|
||||||
|
for (var i = 0; i < intersectionIndexes.length; i ++) {
|
||||||
|
var index = intersectionIndexes[i];
|
||||||
|
|
||||||
|
if (intersectionPoints[index] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstPoints = [index];
|
||||||
|
var isFirstPoint = true;
|
||||||
|
var closed = false;
|
||||||
|
|
||||||
|
var shape = [];
|
||||||
|
|
||||||
|
while (index !== -1) {
|
||||||
|
var intersection = intersectionPoints[index];
|
||||||
|
// uppercase X and Y because clipper vector
|
||||||
|
shape.push({X: intersection.x, Y: intersection.y});
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
|
||||||
|
var connects = lines[index].connects;
|
||||||
|
var faceNormals = lines[index].normals;
|
||||||
|
|
||||||
|
for (var j = 0; j < connects.length; j ++) {
|
||||||
|
var index = connects[j];
|
||||||
|
|
||||||
|
if (firstPoints.indexOf(index) !== -1 && shape.length > 2) {
|
||||||
|
closed = true;
|
||||||
|
index = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if index has an intersection or is already used
|
||||||
|
if (intersectionPoints[index] !== undefined) {
|
||||||
|
var faceNormal = faceNormals[Math.floor(j / 2)];
|
||||||
|
|
||||||
|
var a = new THREE.Vector2(intersection.x, intersection.y);
|
||||||
|
var b = new THREE.Vector2(intersectionPoints[index].x, intersectionPoints[index].y);
|
||||||
|
|
||||||
|
// can't calculate normal between points if distance is smaller as 0.0001
|
||||||
|
if ((faceNormal.x === 0 && faceNormal.y === 0) || a.distanceTo(b) < 0.0001) {
|
||||||
|
if (isFirstPoint) {
|
||||||
|
firstPoints.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
|
||||||
|
connects = connects.concat(lines[index].connects);
|
||||||
|
faceNormals = faceNormals.concat(lines[index].normals);
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// make sure the path goes the right direction
|
||||||
|
// 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 {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isFirstPoint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closed) {
|
||||||
|
var index = firstPoints[0];
|
||||||
|
|
||||||
|
while (index !== -1) {
|
||||||
|
if (firstPoints.indexOf(index) === -1) {
|
||||||
|
var intersection = intersectionPoints[index];
|
||||||
|
shape.unshift({X: intersection.x, Y: intersection.y});
|
||||||
|
|
||||||
|
delete intersectionPoints[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
var connects = lines[index].connects;
|
||||||
|
|
||||||
|
for (var i = 0; i < connects.length; i ++) {
|
||||||
|
var index = connects[i];
|
||||||
|
|
||||||
|
if (intersectionPoints[index] !== undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var part = new Paths([shape], closed).clean(0.01);
|
||||||
|
if (part.length > 0) {
|
||||||
|
shapeParts.push(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shapes.push(shapeParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shapes;
|
||||||
|
}
|
42
src/sliceActions/optimizePaths.js
Normal file
42
src/sliceActions/optimizePaths.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import THREE from 'three.js';
|
||||||
|
|
||||||
|
export default function optimizePaths(slices, settings) {
|
||||||
|
console.log("opimize paths");
|
||||||
|
|
||||||
|
// need to scale up everything because of clipper rounding errors
|
||||||
|
var scale = 100;
|
||||||
|
|
||||||
|
var brimOffset = settings.config["brimOffset"] * scale;
|
||||||
|
|
||||||
|
var start = new THREE.Vector2(0, 0);
|
||||||
|
|
||||||
|
for (var layer = 0; layer < slices.length; layer ++) {
|
||||||
|
var slice = slices[layer];
|
||||||
|
|
||||||
|
if (layer === 0) {
|
||||||
|
slice.brim = slice.getOutline().offset(brimOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = slice.optimizePaths(start);
|
||||||
|
|
||||||
|
for (var i = 0; i < slice.parts.length; i ++) {
|
||||||
|
var part = slice.parts[i];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.support !== undefined) {
|
||||||
|
slice.support.scaleDown(scale);
|
||||||
|
}
|
||||||
|
if (slice.brim !== undefined) {
|
||||||
|
slice.brim.scaleDown(scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
src/sliceActions/shapesToSlices.js
Normal file
65
src/sliceActions/shapesToSlices.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import Slice from '../slice.js';
|
||||||
|
|
||||||
|
export default function shapesToSlices(shapes, settings) {
|
||||||
|
var slices = [];
|
||||||
|
|
||||||
|
for (var layer = 0; layer < shapes.length; layer ++) {
|
||||||
|
var shapeParts = shapes[layer];
|
||||||
|
|
||||||
|
var slice = new Slice();
|
||||||
|
|
||||||
|
var holes = [];
|
||||||
|
var outlines = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < shapeParts.length; i ++) {
|
||||||
|
var shape = shapeParts[i];
|
||||||
|
|
||||||
|
if (!shape.closed) {
|
||||||
|
slice.add(shape);
|
||||||
|
}
|
||||||
|
else if (shape.isHole()) {
|
||||||
|
holes.push(shape);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
slice.add(shape);
|
||||||
|
outlines.push(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outlines.sort((a, b) => {
|
||||||
|
return a.boundSize() - b.boundSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (holes.length > outlines.length) {
|
||||||
|
[holes, outlines] = [outlines, holes];
|
||||||
|
}
|
||||||
|
else if (holes.length === outlines.length) {
|
||||||
|
holes.sort((a, b) => {
|
||||||
|
return a.boundSize() - b.boundSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (holes[0].boundSize > outlines[0].boundSize()) {
|
||||||
|
[holes, outlines] = [outlines, holes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < holes.length; i ++) {
|
||||||
|
var hole = holes[i];
|
||||||
|
|
||||||
|
for (var j = 0; j < outlines.length; j ++) {
|
||||||
|
var outline = outlines[j];
|
||||||
|
|
||||||
|
if (outline.pointCollision(hole[0][0])) {
|
||||||
|
outline.join(hole);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice.removeSelfIntersect();
|
||||||
|
|
||||||
|
slices.push(slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return slices;
|
||||||
|
}
|
73
src/sliceActions/slicesToGCode.js
Normal file
73
src/sliceActions/slicesToGCode.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import GCode from '../gcode.js';
|
||||||
|
|
||||||
|
export default function slicesToGCode(slices, settings) {
|
||||||
|
var gcode = new GCode().setSettings(settings);
|
||||||
|
|
||||||
|
function pathToGCode (path, retract, unRetract, type) {
|
||||||
|
|
||||||
|
for (var i = 0; i < path.length; i ++) {
|
||||||
|
var shape = path[i];
|
||||||
|
|
||||||
|
var length = path.closed ? (shape.length + 1) : shape.length;
|
||||||
|
|
||||||
|
for (var j = 0; j < length; j ++) {
|
||||||
|
var point = shape[j % shape.length];
|
||||||
|
|
||||||
|
if (j === 0) {
|
||||||
|
// TODO
|
||||||
|
// moveTo should impliment combing
|
||||||
|
gcode.moveTo(point.X, point.Y, layer);
|
||||||
|
|
||||||
|
if (unRetract) {
|
||||||
|
gcode.unRetract();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gcode.lineTo(point.X, point.Y, layer, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retract) {
|
||||||
|
gcode.retract();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var layer = 0; layer < slices.length; layer ++) {
|
||||||
|
var slice = slices[layer];
|
||||||
|
|
||||||
|
if (layer === 1) {
|
||||||
|
gcode.turnFanOn();
|
||||||
|
gcode.bottom = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.brim !== undefined) {
|
||||||
|
pathToGCode(slice.brim, true, true, "brim");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < slice.parts.length; i ++) {
|
||||||
|
var part = slice.parts[i];
|
||||||
|
|
||||||
|
if (part.intersect.closed) {
|
||||||
|
pathToGCode(part.outerLine, false, true, "outerLine");
|
||||||
|
|
||||||
|
for (var j = 0; j < part.innerLines.length; j ++) {
|
||||||
|
var innerLine = part.innerLines[j];
|
||||||
|
pathToGCode(innerLine, false, false, "innerLine");
|
||||||
|
}
|
||||||
|
|
||||||
|
pathToGCode(part.fill, true, false, "fill");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var retract = !(slice.parts.length === 1 && slice.support === undefined);
|
||||||
|
pathToGCode(part.intersect, retract, retract, "outerLine");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.support !== undefined) {
|
||||||
|
pathToGCode(slice.support, true, true, "support");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gcode.getGCode();
|
||||||
|
}
|
700
src/slicer.js
700
src/slicer.js
@ -1,7 +1,13 @@
|
|||||||
import THREE from 'three.js';
|
import THREE from 'three.js';
|
||||||
import Paths from './paths.js';
|
import calculateLayersIntersections from './sliceActions/calculateLayersIntersections.js';
|
||||||
import Slice from './slice.js';
|
import createLines from './sliceActions/createLines.js';
|
||||||
import GCode from './gcode.js';
|
import generateInfills from './sliceActions/generateInfills.js';
|
||||||
|
import generateInnerLines from './sliceActions/generateInnerLines.js';
|
||||||
|
import generateSupport from './sliceActions/generateSupport.js';
|
||||||
|
import intersectionsToShapes from './sliceActions/intersectionsToShapes.js';
|
||||||
|
import optimizePaths from './sliceActions/optimizePaths.js';
|
||||||
|
import shapesToSlices from './sliceActions/shapesToSlices.js';
|
||||||
|
import slicesToGCode from './sliceActions/slicesToGCode.js';
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
constructor () {
|
constructor () {
|
||||||
@ -54,25 +60,43 @@ export default class {
|
|||||||
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 = createLines(this.geometry, settings);
|
||||||
|
this.progress.createdLines = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
var {layerIntersectionIndexes, layerIntersectionPoints} = this._calculateLayersIntersections(lines, settings);
|
var {layerIntersectionIndexes, layerIntersectionPoints} = calculateLayersIntersections(lines, settings);
|
||||||
|
this.progress.calculatedLayerIntersections = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
var shapes = this._intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
|
var shapes = intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
|
||||||
|
this.progress.sliced = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
var slices = this._shapesToSlices(shapes, settings);
|
var slices = shapesToSlices(shapes, settings);
|
||||||
|
this.progress.generatedSlices = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
this._generateInnerLines(slices, settings);
|
generateInnerLines(slices, settings);
|
||||||
|
this.progress.generatedInnerLines = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
this._generateInfills(slices, settings);
|
generateInfills(slices, settings);
|
||||||
|
this.progress.generatedInfills = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
if (supportEnabled) {
|
if (supportEnabled) {
|
||||||
this._generateSupport(slices, settings);
|
generateSupport(slices, settings);
|
||||||
|
this.progress.generatedSupport = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._optimizePaths(slices, settings);
|
optimizePaths(slices, settings);
|
||||||
|
this.progress.optimizedPaths = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
var gcode = this._slicesToGCode(slices, settings);
|
var gcode = slicesToGCode(slices, settings);
|
||||||
|
this.progress.generatedGCode = true;
|
||||||
|
this._updateProgress(settings);
|
||||||
|
|
||||||
if (this.onfinish !== undefined) {
|
if (this.onfinish !== undefined) {
|
||||||
this.onfinish(gcode);
|
this.onfinish(gcode);
|
||||||
@ -81,658 +105,6 @@ export default class {
|
|||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
_createLines (settings) {
|
|
||||||
console.log('constructing unique lines from geometry');
|
|
||||||
|
|
||||||
var lines = [];
|
|
||||||
var lineLookup = {};
|
|
||||||
|
|
||||||
var addLine = (a, b) => {
|
|
||||||
var index = lineLookup[b + '_' + a];
|
|
||||||
|
|
||||||
if (index === undefined) {
|
|
||||||
index = lines.length;
|
|
||||||
lineLookup[a + '_' + b] = index;
|
|
||||||
|
|
||||||
lines.push({
|
|
||||||
line: new THREE.Line3(this.geometry.vertices[a], this.geometry.vertices[b]),
|
|
||||||
connects: [],
|
|
||||||
normals: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
// set connecting lines (based on face)
|
|
||||||
lines[a].connects.push(b, c);
|
|
||||||
lines[b].connects.push(c, a);
|
|
||||||
lines[c].connects.push(a, b);
|
|
||||||
|
|
||||||
lines[a].normals.push(normal);
|
|
||||||
lines[b].normals.push(normal);
|
|
||||||
lines[c].normals.push(normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.createdLines = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
_calculateLayersIntersections (lines, settings) {
|
|
||||||
console.log('calculating layer intersections');
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var height = settings.config["dimensionsZ"];
|
|
||||||
|
|
||||||
var numLayers = Math.floor(height / layerHeight);
|
|
||||||
|
|
||||||
var layerIntersectionIndexes = [];
|
|
||||||
var layerIntersectionPoints = [];
|
|
||||||
for (var layer = 0; layer < numLayers; layer ++) {
|
|
||||||
layerIntersectionIndexes[layer] = [];
|
|
||||||
layerIntersectionPoints[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) {
|
|
||||||
|
|
||||||
layerIntersectionIndexes[layerIndex].push(lineIndex);
|
|
||||||
|
|
||||||
var y = layerIndex * layerHeight;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
layerIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.calculatedLayerIntersections = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return {
|
|
||||||
layerIntersectionIndexes,
|
|
||||||
layerIntersectionPoints
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_intersectionsToShapes (layerIntersectionIndexes, layerIntersectionPoints, lines, settings) {
|
|
||||||
console.log("generating slices");
|
|
||||||
|
|
||||||
var shapes = [];
|
|
||||||
|
|
||||||
for (var layer = 1; layer < layerIntersectionIndexes.length; layer ++) {
|
|
||||||
var intersectionIndexes = layerIntersectionIndexes[layer];
|
|
||||||
var intersectionPoints = layerIntersectionPoints[layer];
|
|
||||||
|
|
||||||
if (intersectionIndexes.length === 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var shapeParts = [];
|
|
||||||
for (var i = 0; i < intersectionIndexes.length; i ++) {
|
|
||||||
var index = intersectionIndexes[i];
|
|
||||||
|
|
||||||
if (intersectionPoints[index] === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstPoints = [index];
|
|
||||||
var isFirstPoint = true;
|
|
||||||
var closed = false;
|
|
||||||
|
|
||||||
var shape = [];
|
|
||||||
|
|
||||||
while (index !== -1) {
|
|
||||||
var intersection = intersectionPoints[index];
|
|
||||||
// uppercase X and Y because clipper vector
|
|
||||||
shape.push({X: intersection.x, Y: intersection.y});
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
|
|
||||||
var connects = lines[index].connects;
|
|
||||||
var faceNormals = lines[index].normals;
|
|
||||||
|
|
||||||
for (var j = 0; j < connects.length; j ++) {
|
|
||||||
var index = connects[j];
|
|
||||||
|
|
||||||
if (firstPoints.indexOf(index) !== -1 && shape.length > 2) {
|
|
||||||
closed = true;
|
|
||||||
index = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if index has an intersection or is already used
|
|
||||||
if (intersectionPoints[index] !== undefined) {
|
|
||||||
var faceNormal = faceNormals[Math.floor(j / 2)];
|
|
||||||
|
|
||||||
var a = new THREE.Vector2(intersection.x, intersection.y);
|
|
||||||
var b = new THREE.Vector2(intersectionPoints[index].x, intersectionPoints[index].y);
|
|
||||||
|
|
||||||
// can't calculate normal between points if distance is smaller as 0.0001
|
|
||||||
if ((faceNormal.x === 0 && faceNormal.y === 0) || a.distanceTo(b) < 0.0001) {
|
|
||||||
if (isFirstPoint) {
|
|
||||||
firstPoints.push(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
|
|
||||||
connects = connects.concat(lines[index].connects);
|
|
||||||
faceNormals = faceNormals.concat(lines[index].normals);
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// make sure the path goes the right direction
|
|
||||||
// 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 {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isFirstPoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!closed) {
|
|
||||||
var index = firstPoints[0];
|
|
||||||
|
|
||||||
while (index !== -1) {
|
|
||||||
if (firstPoints.indexOf(index) === -1) {
|
|
||||||
var intersection = intersectionPoints[index];
|
|
||||||
shape.unshift({X: intersection.x, Y: intersection.y});
|
|
||||||
|
|
||||||
delete intersectionPoints[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
var connects = lines[index].connects;
|
|
||||||
|
|
||||||
for (var i = 0; i < connects.length; i ++) {
|
|
||||||
var index = connects[i];
|
|
||||||
|
|
||||||
if (intersectionPoints[index] !== undefined) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = new Paths([shape], closed).clean(0.01);
|
|
||||||
if (part.length > 0) {
|
|
||||||
shapeParts.push(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shapes.push(shapeParts);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.sliced = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return shapes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_shapesToSlices (shapes, settings) {
|
|
||||||
var slices = [];
|
|
||||||
|
|
||||||
for (var layer = 0; layer < shapes.length; layer ++) {
|
|
||||||
var shapeParts = shapes[layer];
|
|
||||||
|
|
||||||
var slice = new Slice();
|
|
||||||
|
|
||||||
var holes = [];
|
|
||||||
var outlines = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < shapeParts.length; i ++) {
|
|
||||||
var shape = shapeParts[i];
|
|
||||||
|
|
||||||
if (!shape.closed) {
|
|
||||||
slice.add(shape);
|
|
||||||
}
|
|
||||||
else if (shape.isHole()) {
|
|
||||||
holes.push(shape);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
slice.add(shape);
|
|
||||||
outlines.push(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outlines.sort((a, b) => {
|
|
||||||
return a.boundSize() - b.boundSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('test');
|
|
||||||
|
|
||||||
if (holes.length > outlines.length) {
|
|
||||||
[holes, outlines] = [outlines, holes];
|
|
||||||
}
|
|
||||||
else if (holes.length === outlines.length) {
|
|
||||||
holes.sort((a, b) => {
|
|
||||||
return a.boundSize() - b.boundSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (holes[0].boundSize > outlines[0].boundSize()) {
|
|
||||||
[holes, outlines] = [outlines, holes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < holes.length; i ++) {
|
|
||||||
var hole = holes[i];
|
|
||||||
|
|
||||||
for (var j = 0; j < outlines.length; j ++) {
|
|
||||||
var outline = outlines[j];
|
|
||||||
|
|
||||||
if (outline.pointCollision(hole[0][0])) {
|
|
||||||
outline.join(hole);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slice.removeSelfIntersect();
|
|
||||||
|
|
||||||
slices.push(slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedSlices = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return slices;
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateInnerLines (slices, settings) {
|
|
||||||
console.log("generating outer lines and inner lines");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var layerHeight = settings.config["layerHeight"];
|
|
||||||
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
||||||
var shellThickness = settings.config["shellThickness"] * scale;
|
|
||||||
var nozzleRadius = nozzleDiameter / 2;
|
|
||||||
var shells = Math.round(shellThickness / nozzleDiameter);
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (!part.intersect.closed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// var outerLine = part.intersect.clone().scaleUp(scale).offset(-nozzleRadius);
|
|
||||||
var outerLine = part.intersect.scaleUp(scale).offset(-nozzleRadius);
|
|
||||||
|
|
||||||
if (outerLine.length > 0) {
|
|
||||||
part.outerLine = outerLine;
|
|
||||||
|
|
||||||
for (var shell = 1; shell < shells; shell += 1) {
|
|
||||||
var offset = shell * nozzleDiameter;
|
|
||||||
|
|
||||||
var innerLine = outerLine.offset(-offset);
|
|
||||||
|
|
||||||
if (innerLine.length > 0) {
|
|
||||||
part.innerLines.push(innerLine);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedInnerLines = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateInfills (slices, settings) {
|
|
||||||
console.log("generating infills");
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outerLine = part.outerLine;
|
|
||||||
|
|
||||||
if (outerLine.length > 0) {
|
|
||||||
var inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
|
|
||||||
|
|
||||||
var fillArea = inset.offset(-nozzleRadius);
|
|
||||||
var lowFillArea = false;
|
|
||||||
if (surroundingLayer) {
|
|
||||||
var highFillArea = fillArea.difference(surroundingLayer);
|
|
||||||
|
|
||||||
if (infillOverlap > 0) {
|
|
||||||
highFillArea = highFillArea.offset(infillOverlap);
|
|
||||||
}
|
|
||||||
|
|
||||||
highFillArea = highFillArea.intersect(fillArea);
|
|
||||||
|
|
||||||
var lowFillArea = fillArea.difference(highFillArea);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var highFillArea = fillArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fill = new Paths([], false);
|
|
||||||
|
|
||||||
if (lowFillArea && lowFillArea.length > 0) {
|
|
||||||
var bounds = lowFillArea.bounds();
|
|
||||||
var lowFillTemplate = this._getFillTemplate(bounds, fillGridSize, true, true);
|
|
||||||
|
|
||||||
part.fill.join(lowFillTemplate.intersect(lowFillArea));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highFillArea.length > 0) {
|
|
||||||
var bounds = highFillArea.bounds();
|
|
||||||
var even = (layer % 2 === 0);
|
|
||||||
var highFillTemplate = this._getFillTemplate(bounds, hightemplateSize, even, !even);
|
|
||||||
|
|
||||||
part.fill.join(highFillTemplate.intersect(highFillArea));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedInfills = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateSupport (slices, settings) {
|
|
||||||
console.log("generating support");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
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.max(Math.ceil(supportDistanceY / layerHeight), 1);
|
|
||||||
var nozzleDiameter = settings.config["nozzleDiameter"] * scale;
|
|
||||||
|
|
||||||
var supportAreas = new Paths([], true);
|
|
||||||
|
|
||||||
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
|
|
||||||
var currentSlice = slices[layer];
|
|
||||||
|
|
||||||
if (supportAreas.length > 0) {
|
|
||||||
|
|
||||||
if (layer >= supportDistanceLayers) {
|
|
||||||
var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
|
|
||||||
sliceSkin = sliceSkin;
|
|
||||||
|
|
||||||
var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin));
|
|
||||||
if (supportAreasSlimmed.area() < 100.0) {
|
|
||||||
supportAreas = supportAreas.difference(sliceSkin);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
supportAreas = supportAreasSlimmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var supportTemplate = this._getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
|
|
||||||
var supportFill = supportTemplate.intersect(supportAreas);
|
|
||||||
if (supportFill.length === 0) {
|
|
||||||
currentSlice.support = supportAreas.clone();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentSlice.support = supportFill;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
|
|
||||||
|
|
||||||
var slice = slices[layer + supportDistanceLayers];
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var slicePart = slice.parts[i];
|
|
||||||
|
|
||||||
if (slicePart.intersect.closed) {
|
|
||||||
var outerLine = slicePart.outerLine;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var outerLine = slicePart.intersect.offset(supportAcceptanceMargin);
|
|
||||||
}
|
|
||||||
|
|
||||||
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
|
|
||||||
var overhang = outerLine.difference(overlap);
|
|
||||||
|
|
||||||
if (overlap.length === 0 || overhang.length > 0) {
|
|
||||||
supportAreas = supportAreas.join(overhang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedSupport = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_optimizePaths (slices, settings) {
|
|
||||||
console.log("opimize paths");
|
|
||||||
|
|
||||||
// need to scale up everything because of clipper rounding errors
|
|
||||||
var scale = 100;
|
|
||||||
|
|
||||||
var brimOffset = settings.config["brimOffset"] * scale;
|
|
||||||
|
|
||||||
var start = new THREE.Vector2(0, 0);
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
if (layer === 0) {
|
|
||||||
slice.brim = slice.getOutline().offset(brimOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = slice.optimizePaths(start);
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.support !== undefined) {
|
|
||||||
slice.support.scaleDown(scale);
|
|
||||||
}
|
|
||||||
if (slice.brim !== undefined) {
|
|
||||||
slice.brim.scaleDown(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.optimizedPaths = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
_getFillTemplate (bounds, size, even, uneven) {
|
|
||||||
var paths = new Paths([], false);
|
|
||||||
|
|
||||||
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.ceil(bounds.bottom / size) * size;
|
|
||||||
|
|
||||||
var width = right - left;
|
|
||||||
|
|
||||||
if (even) {
|
|
||||||
for (var y = top; y <= bottom + width; y += size) {
|
|
||||||
paths.push([
|
|
||||||
{X: left, Y: y},
|
|
||||||
{X: right, Y: y - width}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (uneven) {
|
|
||||||
for (var y = top - width; y <= bottom; y += size) {
|
|
||||||
paths.push([
|
|
||||||
{X: left, Y: y},
|
|
||||||
{X: right, Y: y + width}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
_slicesToGCode (slices, settings) {
|
|
||||||
var gcode = new GCode().setSettings(settings);
|
|
||||||
|
|
||||||
function pathToGCode (path, retract, unRetract, type) {
|
|
||||||
|
|
||||||
for (var i = 0; i < path.length; i ++) {
|
|
||||||
var shape = path[i];
|
|
||||||
|
|
||||||
var length = path.closed ? (shape.length + 1) : shape.length;
|
|
||||||
|
|
||||||
for (var j = 0; j < length; j ++) {
|
|
||||||
var point = shape[j % shape.length];
|
|
||||||
|
|
||||||
if (j === 0) {
|
|
||||||
// TODO
|
|
||||||
// moveTo should impliment combing
|
|
||||||
gcode.moveTo(point.X, point.Y, layer);
|
|
||||||
|
|
||||||
if (unRetract) {
|
|
||||||
gcode.unRetract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gcode.lineTo(point.X, point.Y, layer, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retract) {
|
|
||||||
gcode.retract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var layer = 0; layer < slices.length; layer ++) {
|
|
||||||
var slice = slices[layer];
|
|
||||||
|
|
||||||
if (layer === 1) {
|
|
||||||
gcode.turnFanOn();
|
|
||||||
gcode.bottom = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.brim !== undefined) {
|
|
||||||
pathToGCode(slice.brim, true, true, "brim");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < slice.parts.length; i ++) {
|
|
||||||
var part = slice.parts[i];
|
|
||||||
|
|
||||||
if (part.intersect.closed) {
|
|
||||||
pathToGCode(part.outerLine, false, true, "outerLine");
|
|
||||||
|
|
||||||
for (var j = 0; j < part.innerLines.length; j ++) {
|
|
||||||
var innerLine = part.innerLines[j];
|
|
||||||
pathToGCode(innerLine, false, false, "innerLine");
|
|
||||||
}
|
|
||||||
|
|
||||||
pathToGCode(part.fill, true, false, "fill");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var retract = !(slice.parts.length === 1 && slice.support === undefined);
|
|
||||||
pathToGCode(part.intersect, retract, retract, "outerLine");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice.support !== undefined) {
|
|
||||||
pathToGCode(slice.support, true, true, "support");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.progress.generatedGCode = true;
|
|
||||||
this._updateProgress(settings);
|
|
||||||
|
|
||||||
return gcode.getGCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateProgress (settings) {
|
_updateProgress (settings) {
|
||||||
if (this.onprogress !== undefined) {
|
if (this.onprogress !== undefined) {
|
||||||
var supportEnabled = settings.config["supportEnabled"];
|
var supportEnabled = settings.config["supportEnabled"];
|
||||||
|
Loading…
Reference in New Issue
Block a user