Doodle3D-Slicer/src/paths.js

237 lines
4.8 KiB
JavaScript
Raw Normal View History

2015-07-26 15:32:10 +02:00
import ClipperLib from 'clipper-lib';
import THREE from 'three.js';
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
export default class Paths extends Array {
constructor (paths = [], closed = true) {
super();
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
this.setPaths(paths);
this.closed = closed;
}
2015-07-26 15:32:10 +02:00
setPaths (paths) {
for (var path of paths) {
if (path.length > 0) {
this.push(path);
}
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
return this;
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
_clip (path, type) {
var solution = new ClipperLib.PolyTree();
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(type, solution);
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
if (this.closed) {
var paths = ClipperLib.Clipper.ClosedPathsFromPolyTree(solution);
}
else {
var paths = ClipperLib.Clipper.OpenPathsFromPolyTree(solution);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
return new Paths(paths, this.closed);
}
union (path) {
return this._clip(path, ClipperLib.ClipType.ctUnion);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
difference (path) {
return this._clip(path, ClipperLib.ClipType.ctDifference);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
intersect (path) {
return this._clip(path, ClipperLib.ClipType.ctIntersection);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
xor (path) {
return this._clip(path, ClipperLib.ClipType.ctXor);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
offset (offset) {
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(this, ClipperLib.JoinType.jtSquare, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, offset);
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
return new Paths(solution);
}
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
scaleUp (factor) {
ClipperLib.JS.ScaleUpPaths(this, factor);
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
return this;
}
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
scaleDown (factor) {
ClipperLib.JS.ScaleDownPaths(this, factor);
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
return this;
}
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
lastPoint () {
var lastPath = this[this.length - 1];
var lastPoint = this.closed ? lastPath[0] : lastPath[lastPath.length - 1];
return new THREE.Vector2(lastPoint.X, lastPoint.Y);
}
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
optimizePath (start) {
var optimizedPaths = new Paths([], this.closed);
var donePaths = [];
while (optimizedPaths.length !== this.length) {
var minLength = false;
var reverse;
var minPath;
var offset;
var pathIndex;
for (var i = 0; i < this.length; i += 1) {
var path = this[i];
if (donePaths.indexOf(i) === -1) {
if (this.closed) {
for (var j = 0; j < path.length; j += 1) {
var point = new THREE.Vector2(path[j].X, path[j].Y);
var length = point.sub(start).length();
if (minLength === false || length < minLength) {
minPath = path;
minLength = length;
offset = j;
pathIndex = i;
}
}
}
else {
var startPoint = new THREE.Vector2(path[0].X, path[0].Y);
var length = startPoint.sub(start).length();
2015-05-15 11:14:44 +02:00
if (minLength === false || length < minLength) {
minPath = path;
minLength = length;
2015-07-26 15:32:10 +02:00
reverse = false;
pathIndex = i;
}
var endPoint = new THREE.Vector2(path[path.length - 1].X, path[path.length - 1].Y);
var length = endPoint.sub(start).length();
if (length < minLength) {
minPath = path;
minLength = length;
reverse = true;
2015-05-15 11:14:44 +02:00
pathIndex = i;
}
}
}
}
2015-07-26 15:32:10 +02:00
if (this.closed) {
minPath = minPath.concat(minPath.splice(0, offset));
var point = minPath[0];
}
else {
if (reverse) {
minPath.reverse();
}
var point = minPath[minPath.length - 1];
2015-05-15 11:14:44 +02:00
}
2015-07-26 15:32:10 +02:00
donePaths.push(pathIndex);
start = new THREE.Vector2(point.X, point.Y);
optimizedPaths.push(minPath);
2015-05-15 11:14:44 +02:00
}
2015-07-26 15:32:10 +02:00
return optimizedPaths;
}
2015-06-09 21:58:22 +02:00
2015-07-26 15:32:10 +02:00
areas () {
var areas = [];
2015-06-09 21:58:22 +02:00
2015-07-26 15:32:10 +02:00
for (var shape of this) {
if (shape.closed) {
var area = Math.abs(ClipperLib.Clipper.Area(shape));
areas.push(area);
}
}
2015-06-09 21:58:22 +02:00
2015-07-26 15:32:10 +02:00
return areas;
2015-06-09 21:58:22 +02:00
}
2015-07-26 15:32:10 +02:00
area () {
var areas = this.areas();
var totalArea = 0;
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
for (area of areas) {
totalArea += area;
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
return totalArea;
}
tresholdArea (minArea) {
// code not tested yet
for (var shape of this) {
var area = ClipperLib.Clipper.Area(shape);
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
if (area < minArea) {
this.splice(i, 1);
i -= 1;
}
2015-05-13 12:12:15 +02:00
}
}
2015-07-26 15:32:10 +02:00
join (path) {
for (var i = 0; i < path.length; i += 1) {
this.push(path[i]);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
return this;
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
clone () {
return new Paths(ClipperLib.JS.Clone(this), this.closed);
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
bounds () {
return ClipperLib.Clipper.GetBounds(this);
}
2015-06-12 15:58:26 +02:00
2015-07-26 15:32:10 +02:00
clean (cleanDelta) {
return new Paths(ClipperLib.Clipper.CleanPolygons(this, cleanDelta), this.closed);
}
2015-07-26 15:32:10 +02:00
boundSize () {
var bounds = this.bounds();
2015-07-26 15:32:10 +02:00
var width = bounds.right - bounds.left;
var height = bounds.top - bounds.bottom;
2015-07-26 15:32:10 +02:00
return width * height;
}
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
draw (context, color) {
context.strokeStyle = color;
for (var i = 0; i < this.length; i += 1) {
var shape = this[i];
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
// var point = shape[0];
// context.fillText(i, point.X*2, point.Y*2);
2015-05-15 11:14:44 +02:00
2015-07-26 15:32:10 +02:00
context.beginPath();
for (var j = 0; j < shape.length; j += 1) {
var point = shape[j % shape.length];
2015-05-13 12:12:15 +02:00
2015-07-26 15:32:10 +02:00
context.lineTo(point.X * 2, point.Y * 2);
}
if (this.closed) {
context.closePath();
}
context.stroke();
}
2015-05-13 12:12:15 +02:00
}
2015-07-26 15:32:10 +02:00
}