created abstraction for clipper js

This commit is contained in:
casperlamboo 2015-05-12 11:29:01 +02:00
parent c63f50075f
commit 9740c254c2
11 changed files with 528 additions and 507 deletions

5
.gitignore vendored
View File

@ -15,4 +15,7 @@ src/script/.DS_Store
src/.DS_Store
bower_components/
bower_components/
src/oldcode.js
test.html

445
build/d3d.js vendored
View File

@ -89,61 +89,6 @@ Array.prototype.clone = function () {
return array;
};
function applyMouseControls (renderer, camera, center, maxDistance) {
"use strict";
//TODO
//impliment touch controls
//windows mouse wheel fix
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on("mousedown", function (e) {
moveCamera = true;
}).on("wheel", function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on("mouseup", function (e) {
moveCamera = false;
}).on("mousemove", function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
var requestAnimFrame = (function () {
"use strict";
return requestAnimationFrame || webkitRequestAnimationFrame || mozRequestAnimationFrame || function (callback) {
setTimeout(callback, 1000/60);
};
})();
/******************************************************
*
* Box
@ -617,6 +562,159 @@ D3D.Printer.prototype.subsituteVariables = function (gcode) {
};
/******************************************************
*
* Path
*
* Abstraction layer for annoying clipper js
*
******************************************************/
D3D.Path = function (path, closed) {
"use strict";
this.path = path || [];
this.closed = (closed !== undefined) ? closed : true;
};
D3D.Path.prototype.setPath = function (path) {
"use strict";
this.path = path;
return this;
};
D3D.Path.prototype.union = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctUnion, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.difference = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctDifference, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.intersect = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctIntersection, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.xor = function () {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctXor, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.offset = function (offset) {
"use strict";
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(this.path, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, offset);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.scaleUp = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleUpPaths(this.path, factor);
return this;
};
D3D.Path.prototype.scaleDown = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleDownPaths(this.path, factor);
return this;
};
D3D.Path.prototype.tresholdArea = function (minArea) {
"use strict";
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
var area = ClipperLib.Clipper.Area(shape);
if (area < minArea) {
this.path.splice(i, 1);
i --;
}
}
return areas;
};
D3D.Path.prototype.area = function () {
"use strict";
var areas = [];
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
areas.push(ClipperLib.Clipper.Area(shape))
}
return areas;
};
D3D.Path.prototype.join = function (path) {
"use strict";
this.path = this.path.concat(path.path);
return this;
}
D3D.Path.prototype.clone = function () {
"use strict";
var path = ClipperLib.JS.Clone(this.path);
return new D3D.Path(path, this.closed);
}
D3D.Path.prototype.draw = function (context, color) {
"use strict";
context.strokeStyle = color;
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
context.beginPath();
var length = this.closed ? (shape.length + 1) : shape.length;
for (var j = 0; j < length; j ++) {
var point = shape[j % shape.length];
context.lineTo(point.X*2, point.Y*2);
}
context.stroke();
}
};
/******************************************************
*
* Slicer
*
* TODO (optimalisatie)
@ -732,8 +830,8 @@ D3D.Slicer.prototype.slice = function (height, step) {
var line = this.lines[index].line;
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
var x = line.start.x * alpha + line.end.x * (1 - alpha);
var z = line.start.z * alpha + line.end.z * (1 - alpha);
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(x, z);
}
@ -807,7 +905,8 @@ D3D.Slicer.prototype.slice = function (height, step) {
//stop when ther are no intersects
if (slice.length > 0) {
slices.push(slice);
slices.push(new D3D.Path(slice, true));
//slices.push(slice);
}
else {
break;
@ -816,20 +915,64 @@ D3D.Slicer.prototype.slice = function (height, step) {
return slices;
};
D3D.Slicer.prototype.getInset = function (slice, offset) {
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
"use strict";
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(slice, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, -offset);
var scale = 100;
return solution;
var layerHeight = printer.config["printer.layerHeight"] * scale;
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
var wallThickness = printer.config["printer.wallThickness"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale;
var skinCount = Math.ceil(shellThickness/layerHeight);
var data = [];
var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
var outerLayer = slice.clone();
outerLayer.scaleUp(scale);
var insets = new D3D.Path();
for (var offset = wallThickness; offset <= shellThickness; offset += wallThickness) {
var inset = outerLayer.offset(-offset);
insets.join(inset);
}
var fillArea = (inset || outerLayer).offset(-wallThickness/2);
var downFill = (layer - skinCount >= 0) ? slices[layer - skinCount] : new D3D.Path();
var upFill = (layer + skinCount < slices.length) ? slices[layer + skinCount] : new D3D.Path();
var highFillArea = fillArea.difference(downFill.intersect(upFill).scaleUp(scale));
var lowFillArea = fillArea.difference(highFillArea);
var fill = new D3D.Path([], false);
fill.join(lowFillTemplate.intersect(lowFillArea));
if (highFillArea.path.length > 0) {
var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
fill.join(highFillTemplate.intersect(highFillArea));
}
data.push({
outerLayer: outerLayer.scaleDown(scale),
insets: insets.scaleDown(scale),
fill: fill.scaleDown(scale)
});
}
return data;
};
D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven) {
"use strict";
var paths = new ClipperLib.Paths();
var paths = [];
if (even) {
for (var length = 0; length <= dimension; length += size) {
@ -842,125 +985,8 @@ D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven)
}
}
return paths;
};
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
"use strict";
//scale because of clipper crap
var scale = 100;
var layerHeight = printer.config["printer.layerHeight"] * scale;
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
var wallThickness = printer.config["printer.wallThickness"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale;
var data = [];
var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
//var outerLayer = ClipperLib.JS.Clean(slice, 1.0);
var outerLayer = slice.clone();
ClipperLib.JS.ScaleUpPaths(outerLayer, scale);
var innerLayer = [];
for (var i = wallThickness; i < shellThickness; i += wallThickness) {
var inset = this.getInset(outerLayer, i);
innerLayer = innerLayer.concat(inset);
}
//moet fillArea wel kleiner?
//var fillArea = this.getInset((inset || outerLayer), wallThickness);
var fillArea = (inset || outerLayer);
var fillAbove = false;
//for (var i = 1; i < shellThickness/layerHeight; i ++) {
for (var i = 1; i < shellThickness/layerHeight; i ++) {
var newLayer = ClipperLib.JS.Clone(slices[layer + i]);
ClipperLib.JS.ScaleUpPaths(newLayer, scale);
if (newLayer.length === 0 || (fillAbove && fillAbove.length === 0)) {
fillAbove = [];
break;
}
else if (fillAbove === false) {
fillAbove = newLayer;
}
else {
var c = new ClipperLib.Clipper();
var solution = new ClipperLib.Paths();
c.AddPaths(newLayer, ClipperLib.PolyType.ptSubject, true);
c.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
c.Execute(ClipperLib.ClipType.ctIntersection, solution);
fillAbove = solution;
}
}
//kijkt alleen nog naar boven
//omliggende lagen hebben inhoud van lowFill;
//inset moet opgevult worden;
//verschill tussen lowFill en inset moet vol, rest is raster
var clipper = new ClipperLib.Clipper();
var highFillArea = new ClipperLib.Paths();
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
clipper.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctDifference, highFillArea);
var clipper = new ClipperLib.Clipper();
var lowFillArea = new ClipperLib.Paths();
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctDifference, lowFillArea);
var fill = [];
var clipper = new ClipperLib.Clipper();
var lowFillStrokes = new ClipperLib.Paths();
clipper.AddPaths(lowFillTemplate, ClipperLib.PolyType.ptSubject, false);
clipper.AddPaths(lowFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctIntersection, lowFillStrokes);
fill = fill.concat(lowFillStrokes);
//optimize
//make as big as bounding box of highFillArea
var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
var clipper = new ClipperLib.Clipper();
var highFillStrokes = new ClipperLib.Paths();
clipper.AddPaths(highFillTemplate, ClipperLib.PolyType.ptSubject, false);
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctIntersection, highFillStrokes);
fill = fill.concat(highFillStrokes);
//create brim
/*if (layer === 0) {
var brim = this.getInset(outerLayer, -brimOffset);
outerLayer = brim.concat(outerLayer);
}*/
ClipperLib.JS.ScaleDownPaths(outerLayer, scale);
ClipperLib.JS.ScaleDownPaths(innerLayer, scale);
ClipperLib.JS.ScaleDownPaths(fill, scale);
data.push({
outerLayer: outerLayer,
innerLayer: innerLayer,
fill: fill
});
}
return data;
//return paths;
return new D3D.Path(paths, false);
};
D3D.Slicer.prototype.dataToGcode = function (data, printer) {
"use strict";
@ -982,8 +1008,8 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
function sliceToGcode (slice) {
var gcode = [];
for (var i = 0; i < slice.length; i ++) {
var shape = slice[i];
for (var i = 0; i < slice.path.length; i ++) {
var shape = slice.path[i];
var previousPoint;
@ -1057,54 +1083,20 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
var z = ((layer + 1) * layerHeight).toFixed(3);
gcode = gcode.concat(sliceToGcode(slice.outerLayer));
gcode = gcode.concat(sliceToGcode(slice.innerLayer));
gcode = gcode.concat(sliceToGcode(slice.insets));
gcode = gcode.concat(sliceToGcode(slice.fill));
}
gcode = gcode.concat(printer.getEndCode());
return gcode;
};
//only for debug purposes
D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
"use strict";
var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"];
function drawLines (paths, color) {
context.fillStyle = color;
context.strokeStyle = color;
context.beginPath();
for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
context.moveTo((path[0].X * 2), (path[0].Y * 2));
for (var j = 0; j < path.length; j ++) {
var point = path[j];
context.lineTo((point.X * 2), (point.Y * 2));
}
//context.closePath();
}
context.stroke();
}
function drawVertexes (paths, color) {
context.fillStyle = color;
context.strokeStyle = color;
for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
for (var j = 0; j < path.length; j ++) {
var point = path[j];
context.beginPath();
context.arc(point.X * 2, point.Y * 2, 1, 0, Math.PI*2, false);
context.stroke();
}
}
}
var slices = this.slice(dimensionsZ, layerHeight);
var data = this.slicesToData(slices, printer);
@ -1114,14 +1106,13 @@ D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
canvas.height = 400;
var context = canvas.getContext("2d");
for (var layer = min; layer < max; layer ++) {
var slice = data[layer % data.length];
drawLines(slice.outerLayer, "red");
drawLines(slice.innerLayer, "green");
drawLines(slice.fill, "blue");
drawVertexes(slice.outerLayer, "green");
slice.insets.draw(context, "blue");
slice.outerLayer.draw(context, "green");
slice.fill.draw(context, "red");
}
return canvas;

2
build/d3d.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@ var files = [
"src/utils.js",
"src/box.js",
"src/printer.js",
"src/path.js",
"src/slicer.js"
];

BIN
models/cubes.stl Normal file

Binary file not shown.

BIN
models/overhang_test.stl Normal file

Binary file not shown.

View File

@ -11,6 +11,7 @@
<script src="src/utils.js"></script>
<script src="src/box.js"></script>
<script src="src/printer.js"></script>
<script src="src/path.js"></script>
<script src="src/slicer.js"></script>
<script src="gcode/testgcode.js"></script>
@ -43,9 +44,8 @@ var printerConfig = {
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.layerHeight": 0.3,
"printer.retraction.amount": 3,
"printer.retraction.enabled": true,
"printer.retraction.enabled": false,
"printer.retraction.minDistance": 5,
"printer.retraction.speed": 50,
"printer.screenToMillimeterScale": 0.3, //????
@ -55,13 +55,16 @@ var printerConfig = {
"printer.travelSpeed": 200,
"printer.type": "ultimaker",
"printer.useSubLayers": true, //wat is dit?
"printer.wallThickness": 0.4,
"printer.wallThickness": 0.4, //nozzle
"printer.layerHeight": 0.3,
//variabele toevoegen;
//-snelheid, retraction etc voor verschillende types (outerlayer, innerlayer, fill)
"printer.shellThickness": 0.8,
"printer.shellThickness": 0.4,
"printer.fillSize": 5, //dit is het raster aan de binnen kant van de geometry
"printer.brimOffset": 5
"printer.brimOffset": 5,
"printer.bottomTopThickness": 0.8
};
var printer = new D3D.Printer(printerConfig);
@ -104,53 +107,30 @@ var geometry = (function () {
var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30);
var geometry = new THREE.BoxGeometry(20, 20, 20, 1, 1, 1);
var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1);
//var geometry = new THREE.SphereGeometry(10, 10, 10);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 100;
mesh.position.z = 100;
scene.add(mesh);
//scene.add(mesh);
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var slicer = new D3D.Slicer().setMesh(mesh);
gcode = slicer.getGcode(printer);
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var layer = 0;
var img = slicer.drawPaths(printer, layer, layer + 1);
context.drawImage(img, 0, 0);
/*
var loader = new THREE.STLLoader();
loader.load('stl/overhang_test.stl', function (geometry) {
var matrix = new THREE.Matrix4();
matrix.makeRotationX(Math.PI*1.5);
geometry.applyMatrix(matrix);
var material = new THREE.MeshLambertMaterial({color: 0x000000, wireframe: true});
loader.load("models/cubes.stl", function (geometry) {
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 100;
mesh.position.z = 100;
mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 3;
//mesh is lifted a little bit...
mesh.position.y = -0.6552429199218741;
scene.add(mesh);
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var slicer = new D3D.Slicer().setMesh(mesh);
var slicer = new D3D.Slicer().setMesh(geometry);
var layer = 149;
var img = slicer.drawPaths(printer, layer, layer + 1);
context.drawImage(img, 0, 0);
var gcode = slicer.getGcode(printer);
console.log(gcode);
gcode = slicer.getGcode(printer);
});
*/
(function animate () {
"use strict";
@ -158,6 +138,53 @@ loader.load('stl/overhang_test.stl', function (geometry) {
requestAnimationFrame(animate);
renderer.render(scene, camera);
})();
function applyMouseControls (renderer, camera, center, maxDistance) {
"use strict";
//TODO
//impliment touch controls
//windows mouse wheel fix
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on("mousedown", function (e) {
moveCamera = true;
}).on("wheel", function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on("mouseup", function (e) {
moveCamera = false;
}).on("mousemove", function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
</script>
</body>

153
src/path.js Normal file
View File

@ -0,0 +1,153 @@
/******************************************************
*
* Path
*
* Abstraction layer for annoying clipper js
*
******************************************************/
D3D.Path = function (path, closed) {
"use strict";
this.path = path || [];
this.closed = (closed !== undefined) ? closed : true;
};
D3D.Path.prototype.setPath = function (path) {
"use strict";
this.path = path;
return this;
};
D3D.Path.prototype.union = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctUnion, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.difference = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctDifference, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.intersect = function (path) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctIntersection, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.xor = function () {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this.path, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path.path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(ClipperLib.ClipType.ctXor, solution);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.offset = function (offset) {
"use strict";
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(this.path, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, offset);
return new D3D.Path(solution, this.closed);
};
D3D.Path.prototype.scaleUp = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleUpPaths(this.path, factor);
return this;
};
D3D.Path.prototype.scaleDown = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleDownPaths(this.path, factor);
return this;
};
D3D.Path.prototype.tresholdArea = function (minArea) {
"use strict";
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
var area = ClipperLib.Clipper.Area(shape);
if (area < minArea) {
this.path.splice(i, 1);
i --;
}
}
return areas;
};
D3D.Path.prototype.area = function () {
"use strict";
var areas = [];
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
areas.push(ClipperLib.Clipper.Area(shape))
}
return areas;
};
D3D.Path.prototype.join = function (path) {
"use strict";
this.path = this.path.concat(path.path);
return this;
}
D3D.Path.prototype.clone = function () {
"use strict";
var path = ClipperLib.JS.Clone(this.path);
return new D3D.Path(path, this.closed);
}
D3D.Path.prototype.draw = function (context, color) {
"use strict";
context.strokeStyle = color;
for (var i = 0; i < this.path.length; i ++) {
var shape = this.path[i];
context.beginPath();
var length = this.closed ? (shape.length + 1) : shape.length;
for (var j = 0; j < length; j ++) {
var point = shape[j % shape.length];
context.lineTo(point.X*2, point.Y*2);
}
context.stroke();
}
};

View File

@ -23,12 +23,11 @@ D3D.Slicer.prototype.setMesh = function (mesh) {
mesh.updateMatrix();
var geometry = mesh.geometry.clone();
geometry.mergeVertices();
geometry.applyMatrix(mesh.matrix);
if (geometry instanceof THREE.BufferGeometry) {
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
}
geometry.mergeVertices();
geometry.applyMatrix(mesh.matrix);
this.geometry = geometry;
@ -55,7 +54,8 @@ D3D.Slicer.prototype.createLines = function () {
self.lines.push({
line: new THREE.Line3(self.geometry.vertices[a], self.geometry.vertices[b]),
connects: [],
normals: []
normals: [],
ignore: 0
});
}
@ -80,6 +80,12 @@ D3D.Slicer.prototype.createLines = function () {
this.lines[a].normals.push(normal);
this.lines[b].normals.push(normal);
this.lines[c].normals.push(normal);
if (face.normal.y === 1 || face.normal.y === -1) {
this.lines[a].ignore ++;
this.lines[b].ignore ++;
this.lines[c].ignore ++;
}
}
};
D3D.Slicer.prototype.slice = function (height, step) {
@ -93,12 +99,14 @@ D3D.Slicer.prototype.slice = function (height, step) {
var min = Math.ceil(Math.min(line.line.start.y, line.line.end.y) / step);
var max = Math.floor(Math.max(line.line.start.y, line.line.end.y) / step);
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0) {
if (layersIntersections[layerIndex] === undefined) {
layersIntersections[layerIndex] = [];
if (line.ignore < 2) {
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0) {
if (layersIntersections[layerIndex] === undefined) {
layersIntersections[layerIndex] = [];
}
layersIntersections[layerIndex].push(i);
}
layersIntersections[layerIndex].push(i);
}
}
}
@ -115,8 +123,8 @@ D3D.Slicer.prototype.slice = function (height, step) {
var line = this.lines[index].line;
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
var x = line.start.x * alpha + line.end.x * (1 - alpha);
var z = line.start.z * alpha + line.end.z * (1 - alpha);
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(x, z);
}
@ -190,7 +198,8 @@ D3D.Slicer.prototype.slice = function (height, step) {
//stop when ther are no intersects
if (slice.length > 0) {
slices.push(slice);
slices.push(new D3D.Path(slice, true));
//slices.push(slice);
}
else {
break;
@ -199,20 +208,65 @@ D3D.Slicer.prototype.slice = function (height, step) {
return slices;
};
D3D.Slicer.prototype.getInset = function (slice, offset) {
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
"use strict";
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(slice, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, -offset);
var scale = 100;
return solution;
var layerHeight = printer.config["printer.layerHeight"] * scale;
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
var wallThickness = printer.config["printer.wallThickness"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale;
var skinCount = Math.ceil(shellThickness/layerHeight);
var data = [];
var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
var outerLayer = slice.clone();
outerLayer.scaleUp(scale);
var insets = new D3D.Path();
for (var offset = wallThickness; offset <= shellThickness; offset += wallThickness) {
var inset = outerLayer.offset(-offset);
insets.join(inset);
}
var fillArea = (inset || outerLayer).offset(-wallThickness/2);
var downFill = (layer - skinCount >= 0) ? slices[layer - skinCount] : new D3D.Path();
var upFill = (layer + skinCount < slices.length) ? slices[layer + skinCount] : new D3D.Path();
var highFillArea = fillArea.difference(downFill.intersect(upFill).scaleUp(scale));
var lowFillArea = fillArea.difference(highFillArea);
var fill = new D3D.Path([], false);
fill.join(lowFillTemplate.intersect(lowFillArea));
if (highFillArea.path.length > 0) {
var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
var highFillStrokes = highFillArea;
fill.join(highFillTemplate.intersect(highFillStrokes));
}
data.push({
outerLayer: outerLayer.scaleDown(scale),
insets: insets.scaleDown(scale),
fill: fill.scaleDown(scale)
});
}
return data;
};
D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven) {
"use strict";
var paths = new ClipperLib.Paths();
var paths = [];
if (even) {
for (var length = 0; length <= dimension; length += size) {
@ -225,125 +279,8 @@ D3D.Slicer.prototype.getFillTemplate = function (dimension, size, even, uneven)
}
}
return paths;
};
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
"use strict";
//scale because of clipper crap
var scale = 100;
var layerHeight = printer.config["printer.layerHeight"] * scale;
var dimensionsZ = printer.config["printer.dimensions.z"] * scale;
var wallThickness = printer.config["printer.wallThickness"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale;
var data = [];
var lowFillTemplate = this.getFillTemplate(dimensionsZ, fillSize, true, true);
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
//var outerLayer = ClipperLib.JS.Clean(slice, 1.0);
var outerLayer = slice.clone();
ClipperLib.JS.ScaleUpPaths(outerLayer, scale);
var innerLayer = [];
for (var i = wallThickness; i < shellThickness; i += wallThickness) {
var inset = this.getInset(outerLayer, i);
innerLayer = innerLayer.concat(inset);
}
//moet fillArea wel kleiner?
//var fillArea = this.getInset((inset || outerLayer), wallThickness);
var fillArea = (inset || outerLayer);
var fillAbove = false;
//for (var i = 1; i < shellThickness/layerHeight; i ++) {
for (var i = 1; i < shellThickness/layerHeight; i ++) {
var newLayer = ClipperLib.JS.Clone(slices[layer + i]);
ClipperLib.JS.ScaleUpPaths(newLayer, scale);
if (newLayer.length === 0 || (fillAbove && fillAbove.length === 0)) {
fillAbove = [];
break;
}
else if (fillAbove === false) {
fillAbove = newLayer;
}
else {
var c = new ClipperLib.Clipper();
var solution = new ClipperLib.Paths();
c.AddPaths(newLayer, ClipperLib.PolyType.ptSubject, true);
c.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
c.Execute(ClipperLib.ClipType.ctIntersection, solution);
fillAbove = solution;
}
}
//kijkt alleen nog naar boven
//omliggende lagen hebben inhoud van lowFill;
//inset moet opgevult worden;
//verschill tussen lowFill en inset moet vol, rest is raster
var clipper = new ClipperLib.Clipper();
var highFillArea = new ClipperLib.Paths();
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
clipper.AddPaths(fillAbove, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctDifference, highFillArea);
var clipper = new ClipperLib.Clipper();
var lowFillArea = new ClipperLib.Paths();
clipper.AddPaths(fillArea, ClipperLib.PolyType.ptSubject, true);
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctDifference, lowFillArea);
var fill = [];
var clipper = new ClipperLib.Clipper();
var lowFillStrokes = new ClipperLib.Paths();
clipper.AddPaths(lowFillTemplate, ClipperLib.PolyType.ptSubject, false);
clipper.AddPaths(lowFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctIntersection, lowFillStrokes);
fill = fill.concat(lowFillStrokes);
//optimize
//make as big as bounding box of highFillArea
var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
var clipper = new ClipperLib.Clipper();
var highFillStrokes = new ClipperLib.Paths();
clipper.AddPaths(highFillTemplate, ClipperLib.PolyType.ptSubject, false);
clipper.AddPaths(highFillArea, ClipperLib.PolyType.ptClip, true);
clipper.Execute(ClipperLib.ClipType.ctIntersection, highFillStrokes);
fill = fill.concat(highFillStrokes);
//create brim
/*if (layer === 0) {
var brim = this.getInset(outerLayer, -brimOffset);
outerLayer = brim.concat(outerLayer);
}*/
ClipperLib.JS.ScaleDownPaths(outerLayer, scale);
ClipperLib.JS.ScaleDownPaths(innerLayer, scale);
ClipperLib.JS.ScaleDownPaths(fill, scale);
data.push({
outerLayer: outerLayer,
innerLayer: innerLayer,
fill: fill
});
}
return data;
//return paths;
return new D3D.Path(paths, false);
};
D3D.Slicer.prototype.dataToGcode = function (data, printer) {
"use strict";
@ -365,8 +302,8 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
function sliceToGcode (slice) {
var gcode = [];
for (var i = 0; i < slice.length; i ++) {
var shape = slice[i];
for (var i = 0; i < slice.path.length; i ++) {
var shape = slice.path[i];
var previousPoint;
@ -440,54 +377,20 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
var z = ((layer + 1) * layerHeight).toFixed(3);
gcode = gcode.concat(sliceToGcode(slice.outerLayer));
gcode = gcode.concat(sliceToGcode(slice.innerLayer));
gcode = gcode.concat(sliceToGcode(slice.insets));
gcode = gcode.concat(sliceToGcode(slice.fill));
}
gcode = gcode.concat(printer.getEndCode());
return gcode;
};
//only for debug purposes
D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
"use strict";
var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"];
function drawLines (paths, color) {
context.fillStyle = color;
context.strokeStyle = color;
context.beginPath();
for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
context.moveTo((path[0].X * 2), (path[0].Y * 2));
for (var j = 0; j < path.length; j ++) {
var point = path[j];
context.lineTo((point.X * 2), (point.Y * 2));
}
//context.closePath();
}
context.stroke();
}
function drawVertexes (paths, color) {
context.fillStyle = color;
context.strokeStyle = color;
for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
for (var j = 0; j < path.length; j ++) {
var point = path[j];
context.beginPath();
context.arc(point.X * 2, point.Y * 2, 1, 0, Math.PI*2, false);
context.stroke();
}
}
}
var slices = this.slice(dimensionsZ, layerHeight);
var data = this.slicesToData(slices, printer);
@ -500,11 +403,9 @@ D3D.Slicer.prototype.drawPaths = function (printer, min, max) {
for (var layer = min; layer < max; layer ++) {
var slice = data[layer % data.length];
drawLines(slice.outerLayer, "red");
drawLines(slice.innerLayer, "green");
drawLines(slice.fill, "blue");
drawVertexes(slice.outerLayer, "green");
slice.insets.draw(context, "blue");
slice.outerLayer.draw(context, "green");
slice.fill.draw(context, "red");
}
return canvas;

View File

@ -88,59 +88,4 @@ Array.prototype.clone = function () {
}
return array;
};
function applyMouseControls (renderer, camera, center, maxDistance) {
"use strict";
//TODO
//impliment touch controls
//windows mouse wheel fix
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on("mousedown", function (e) {
moveCamera = true;
}).on("wheel", function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on("mouseup", function (e) {
moveCamera = false;
}).on("mousemove", function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
var requestAnimFrame = (function () {
"use strict";
return requestAnimationFrame || webkitRequestAnimationFrame || mozRequestAnimationFrame || function (callback) {
setTimeout(callback, 1000/60);
};
})();
};

Binary file not shown.