mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-05 20:32:00 -05:00
Clean up computeBoolean().
Work in progress.
This commit is contained in:
parent
d014ed3c68
commit
1031f4ecfb
1 changed files with 70 additions and 79 deletions
|
@ -104,133 +104,124 @@ PathItem.inject(new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeBoolean(path1, path2, operator, subtract, _cache) {
|
function computeBoolean(path1, path2, operator, subtract, _cache) {
|
||||||
var _path1, _path2, path1Clockwise, path2Clockwise;
|
|
||||||
var ixs, path1Id, path2Id;
|
var ixs, path1Id, path2Id;
|
||||||
// We do not modify the operands themselves
|
// We do not modify the operands themselves
|
||||||
// The result might not belong to the same type
|
// The result might not belong to the same type
|
||||||
// i.e. subtraction(A:Path, B:Path):CompoundPath etc.
|
// i.e. subtraction(A:Path, B:Path):CompoundPath etc.
|
||||||
_path1 = path1.clone();
|
var _path1 = path1.clone(),
|
||||||
_path2 = path2.clone();
|
_path2 = path2.clone(),
|
||||||
_path1.style = _path2.style = null;
|
path1Id = _path1.id,
|
||||||
_path1.selected = _path2.selected = false;
|
path2Id = _path2.id,
|
||||||
path1Clockwise = reorientCompoundPath(_path1);
|
path1Clockwise = reorientCompoundPath(_path1),
|
||||||
path2Clockwise = reorientCompoundPath(_path2);
|
path2Clockwise = reorientCompoundPath(_path2),
|
||||||
path1Id = _path1.id;
|
|
||||||
path2Id = _path2.id;
|
|
||||||
// Calculate all the intersections
|
// Calculate all the intersections
|
||||||
ixs = _cache && _cache.intersections || _path1.getIntersections(_path2);
|
intersections = _cache && _cache.intersections
|
||||||
// if we have a empty _cache object as an operand,
|
|| _path1.getIntersections(_path2);
|
||||||
// skip calculating boolean and cache the intersections
|
// if we have a empty _cache object as an operand, skip calculating
|
||||||
if (_cache && !_cache.intersections)
|
// boolean and cache the intersections
|
||||||
return _cache.intersections = ixs;
|
if (_cache && !_cache.intersections) {
|
||||||
splitPath(splitPath(ixs, true));
|
// TODO: Don't we need to clear up and remove _path1 & _path2 again?
|
||||||
path1Id = _path1.id;
|
return _cache.intersections = intersections;
|
||||||
path2Id = _path2.id;
|
}
|
||||||
|
// Now split intersections on both curves, by asking the first call to
|
||||||
|
// collect the 'other' intersections for us and passing that on to the
|
||||||
|
// second call.
|
||||||
|
splitPath(splitPath(intersections, true));
|
||||||
// Do operator specific calculations before we begin
|
// Do operator specific calculations before we begin
|
||||||
if (subtract) {
|
if (subtract) {
|
||||||
_path2.reverse();
|
_path2.reverse();
|
||||||
path2Clockwise = !path2Clockwise;
|
path2Clockwise = !path2Clockwise;
|
||||||
}
|
}
|
||||||
|
|
||||||
var i, j, len, path, crv;
|
var paths = [],
|
||||||
var paths = [];
|
nodes = [],
|
||||||
|
result = new CompoundPath(),
|
||||||
|
push = paths.push;
|
||||||
if (_path1 instanceof CompoundPath) {
|
if (_path1 instanceof CompoundPath) {
|
||||||
paths = paths.concat(_path1.children);
|
push.apply(paths, _path1._children);
|
||||||
} else {
|
} else {
|
||||||
paths = [ _path1 ];
|
paths.push(_path1);
|
||||||
}
|
}
|
||||||
if (_path2 instanceof CompoundPath) {
|
if (_path2 instanceof CompoundPath) {
|
||||||
paths = paths.concat(_path2.children);
|
push.apply(paths, _path2._children);
|
||||||
} else {
|
} else {
|
||||||
paths.push(_path2);
|
paths.push(_path2);
|
||||||
}
|
}
|
||||||
// step 1: discard invalid links according to the boolean operator
|
// Step 1: Discard invalid links according to the boolean operator
|
||||||
var lastNode, firstNode, nextNode, midPoint, insidePath1, insidePath2;
|
for (var i = 0, l = paths.length; i < l; i++) {
|
||||||
var thisId, thisWinding, contains;
|
var path = paths[i],
|
||||||
for (i = 0, len = paths.length; i < len; i++) {
|
insidePath1 = false,
|
||||||
insidePath1 = insidePath2 = false;
|
insidePath2 = false,
|
||||||
path = paths[i];
|
thisId = path.parent instanceof CompoundPath
|
||||||
thisId = (path.parent instanceof CompoundPath)? path.parent.id : path.id;
|
? path.parent.id : path.id,
|
||||||
thisWinding = path.clockwise;
|
clockwise = path.isClockwise(),
|
||||||
lastNode = path.lastSegment;
|
segments = path._segments;
|
||||||
firstNode = path.firstSegment;
|
for (var j = 0, k = segments.length; j < k; j++) {
|
||||||
nextNode = null;
|
var segment = segments[j],
|
||||||
while (nextNode !== firstNode) {
|
curve = segment.getCurve(),
|
||||||
nextNode = (nextNode)? nextNode.previous: lastNode;
|
midPoint = curve.getPoint(0.5);
|
||||||
crv = nextNode.curve;
|
|
||||||
midPoint = crv.getPoint(0.5);
|
|
||||||
if (thisId !== path1Id) {
|
if (thisId !== path1Id) {
|
||||||
contains = _path1.
|
insidePath1 = _path1.contains(midPoint)
|
||||||
contains(midPoint);
|
&& (clockwise === path1Clockwise || subtract
|
||||||
insidePath1 = thisWinding === path1Clockwise || subtract
|
|| !testOnCurve(_path1, midPoint));
|
||||||
? contains
|
|
||||||
: contains && !testOnCurve(_path1, midPoint);
|
|
||||||
}
|
}
|
||||||
if (thisId !== path2Id) {
|
if (thisId !== path2Id) {
|
||||||
contains = _path2.contains(midPoint);
|
insidePath2 = _path2.contains(midPoint)
|
||||||
insidePath2 = thisWinding === path2Clockwise
|
&& (clockwise === path2Clockwise
|
||||||
? contains
|
|| !testOnCurve(_path2, midPoint));
|
||||||
: contains && !testOnCurve(_path2, midPoint);
|
|
||||||
}
|
}
|
||||||
if (operator(thisId === path1Id, insidePath1, insidePath2)) {
|
if (operator(thisId === path1Id, insidePath1, insidePath2)) {
|
||||||
crv._INVALID = true;
|
curve._INVALID = true;
|
||||||
// markPoint(midPoint, '+');
|
// markPoint(midPoint, '+');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nodes = nodes.concat(path._segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final step: Retrieve the resulting paths from the graph
|
// Step 2: Retrieve the resulting paths from the graph
|
||||||
var boolResult = new CompoundPath();
|
for (var i = 0, l = nodes.length; i < l; i++) {
|
||||||
var node, nuNode, nuPath, nodeList = [], handle;
|
var node = nodes[i];
|
||||||
for (i = 0, len = paths.length; i < len; i++) {
|
|
||||||
nodeList = nodeList.concat(paths[i].segments);
|
|
||||||
}
|
|
||||||
for (i = 0, len = nodeList.length; i < len; i++) {
|
|
||||||
node = nodeList[i];
|
|
||||||
if (node.curve._INVALID || node._visited) { continue; }
|
if (node.curve._INVALID || node._visited) { continue; }
|
||||||
path = node.path;
|
var path = node.path,
|
||||||
thisId = (path.parent instanceof CompoundPath)? path.parent.id : path.id;
|
thisId = (path.parent instanceof CompoundPath)? path.parent.id : path.id,
|
||||||
thisWinding = path.clockwise;
|
nuPath = new Path(),
|
||||||
nuPath = new Path();
|
firstNode = null,
|
||||||
firstNode = null;
|
|
||||||
firstNode_ix = null;
|
firstNode_ix = null;
|
||||||
if (node.previous.curve._INVALID) {
|
if (node.previous.curve._INVALID) {
|
||||||
node.handleIn = (node._ixPair)?
|
node.setHandleIn(node._ixPair
|
||||||
node._ixPair.getIntersection().__segment.handleIn : [ 0, 0 ];
|
? node._ixPair.getIntersection().__segment._handleIn
|
||||||
|
: Point.create(0, 0));
|
||||||
}
|
}
|
||||||
while (node && !node._visited && (node !== firstNode && node !== firstNode_ix)) {
|
while (node && !node._visited && (node !== firstNode && node !== firstNode_ix)) {
|
||||||
node._visited = true;
|
node._visited = true;
|
||||||
firstNode = (firstNode)? firstNode: node;
|
firstNode = firstNode || node;
|
||||||
firstNode_ix = (!firstNode_ix && firstNode._ixPair)?
|
firstNode_ix = !firstNode_ix && firstNode._ixPair
|
||||||
firstNode._ixPair.getIntersection().__segment: firstNode_ix;
|
? firstNode._ixPair.getIntersection().__segment
|
||||||
|
: firstNode_ix;
|
||||||
// node._ixPair is this node's intersection CurveLocation object
|
// node._ixPair is this node's intersection CurveLocation object
|
||||||
// node._ixPair.getIntersection() is the other CurveLocation object this node intersects with
|
// node._ixPair.getIntersection() is the other CurveLocation object this node intersects with
|
||||||
nextNode = (node._ixPair && node.curve._INVALID)? node._ixPair.getIntersection().__segment : node;
|
var nextNode = (node._ixPair && node.curve._INVALID)? node._ixPair.getIntersection().__segment : node;
|
||||||
if (node._ixPair) {
|
if (node._ixPair) {
|
||||||
nextNode._visited = true;
|
nextNode._visited = true;
|
||||||
nuNode = new Segment(node.point, node.handleIn, nextNode.handleOut);
|
nuPath.add(new Segment(node._point, node._handleIn,
|
||||||
nuPath.add(nuNode);
|
nextNode._handleOut));
|
||||||
node = nextNode;
|
node = nextNode;
|
||||||
path = node.path;
|
|
||||||
thisWinding = path.clockwise;
|
|
||||||
} else {
|
} else {
|
||||||
nuPath.add(node);
|
nuPath.add(node);
|
||||||
}
|
}
|
||||||
node = node.next;
|
node = node.next;
|
||||||
}
|
}
|
||||||
if (nuPath.segments.length > 1) {
|
// Avoid stray segments and incomplete paths
|
||||||
// avoid stray segments and incomplete paths
|
|
||||||
if (nuPath.segments.length > 2 || !nuPath.curves[0].isLinear()) {
|
if (nuPath.segments.length > 2 || !nuPath.curves[0].isLinear()) {
|
||||||
nuPath.closed = true;
|
nuPath.closed = true;
|
||||||
boolResult.addChild(nuPath, true);
|
result.addChild(nuPath, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Delete the proxies
|
// Delete the proxies
|
||||||
_path1.remove();
|
_path1.remove();
|
||||||
_path2.remove();
|
_path2.remove();
|
||||||
// And then, we are done.
|
// And then, we are done.
|
||||||
return boolResult.reduce();
|
return result.reduce();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testOnCurve(path, point) {
|
function testOnCurve(path, point) {
|
||||||
|
|
Loading…
Reference in a new issue