mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-20 22:39:50 -05:00
Merge PathItem#getIntersections() and #getSelfIntersections()
This commit is contained in:
parent
e11b6138bd
commit
4ec3daf4d1
2 changed files with 53 additions and 71 deletions
|
@ -78,16 +78,16 @@ PathItem.inject(new function() {
|
||||||
// We call reduce() on both cloned paths to simplify compound paths and
|
// We call reduce() on both cloned paths to simplify compound paths and
|
||||||
// remove empty curves. We also apply matrices to both paths in case
|
// remove empty curves. We also apply matrices to both paths in case
|
||||||
// they were transformed.
|
// they were transformed.
|
||||||
var singlePathOp = path1 === path2;
|
var selfOp = path1 === path2;
|
||||||
path1 = reorientPath(path1.clone(false).reduce().applyMatrix());
|
path1 = reorientPath(path1.clone(false).reduce().applyMatrix());
|
||||||
if (!singlePathOp)
|
path2 = selfOp ? path1
|
||||||
path2 = reorientPath(path2.clone(false).reduce().applyMatrix());
|
: reorientPath(path2.clone(false).reduce().applyMatrix());
|
||||||
// Do operator specific calculations before we begin
|
// Do operator specific calculations before we begin
|
||||||
// Make both paths at clockwise orientation, except when @subtract = true
|
// Make both paths at clockwise orientation, except when @subtract = true
|
||||||
// We need both paths at opposit orientation for subtraction
|
// We need both paths at opposit orientation for subtraction
|
||||||
if (!path1.isClockwise())
|
if (!path1.isClockwise())
|
||||||
path1.reverse();
|
path1.reverse();
|
||||||
if (!singlePathOp && !(subtract ^ path2.isClockwise()))
|
if (!selfOp && !(subtract ^ path2.isClockwise()))
|
||||||
path2.reverse();
|
path2.reverse();
|
||||||
var i, j, l, lj, segment, wind,
|
var i, j, l, lj, segment, wind,
|
||||||
point, startSeg, crv, length, parent, v, horizontal,
|
point, startSeg, crv, length, parent, v, horizontal,
|
||||||
|
@ -101,13 +101,12 @@ PathItem.inject(new function() {
|
||||||
monoCurves = [],
|
monoCurves = [],
|
||||||
result = new CompoundPath(),
|
result = new CompoundPath(),
|
||||||
tolerance = /*#=*/ Numerical.TOLERANCE,
|
tolerance = /*#=*/ Numerical.TOLERANCE,
|
||||||
intersections = singlePathOp ? path1.getSelfIntersections(true)
|
intersections = path1.getIntersections(path2, true);
|
||||||
: path1.getIntersections(path2, true);
|
|
||||||
// Split curves at intersections on both paths.
|
// Split curves at intersections on both paths.
|
||||||
PathItem._splitPath(intersections);
|
PathItem._splitPath(intersections);
|
||||||
// Collect all sub paths and segments
|
// Collect all sub paths and segments
|
||||||
paths.push.apply(paths, path1._children || [path1]);
|
paths.push.apply(paths, path1._children || [path1]);
|
||||||
if (!singlePathOp)
|
if (!selfOp)
|
||||||
paths.push.apply(paths, path2._children || [path2]);
|
paths.push.apply(paths, path2._children || [path2]);
|
||||||
|
|
||||||
for (i = 0, l = paths.length; i < l; i++) {
|
for (i = 0, l = paths.length; i < l; i++) {
|
||||||
|
@ -186,7 +185,7 @@ PathItem.inject(new function() {
|
||||||
result.addChild(paths[i], true);
|
result.addChild(paths[i], true);
|
||||||
// Delete the proxies
|
// Delete the proxies
|
||||||
path1.remove();
|
path1.remove();
|
||||||
if (!singlePathOp)
|
if (!selfOp)
|
||||||
path2.remove();
|
path2.remove();
|
||||||
// And then, we are done.
|
// And then, we are done.
|
||||||
return result.reduce();
|
return result.reduce();
|
||||||
|
|
|
@ -65,85 +65,68 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
getIntersections: function(path, _expand) {
|
getIntersections: function(path, _expand) {
|
||||||
// First check the bounds of the two paths. If they don't intersect,
|
// First check the bounds of the two paths. If they don't intersect,
|
||||||
// we don't need to iterate through their curves.
|
// we don't need to iterate through their curves.
|
||||||
if (!this.getBounds().touches(path.getBounds()))
|
var selfOp = this === path;
|
||||||
|
if (!selfOp && !this.getBounds().touches(path.getBounds()))
|
||||||
return [];
|
return [];
|
||||||
var locations = [],
|
var locations = [],
|
||||||
|
locs = [],
|
||||||
curves1 = this.getCurves(),
|
curves1 = this.getCurves(),
|
||||||
curves2 = path.getCurves(),
|
curves2 = selfOp ? curves1 : path.getCurves(),
|
||||||
matrix1 = this._matrix.orNullIfIdentity(),
|
matrix1 = this._matrix.orNullIfIdentity(),
|
||||||
matrix2 = path._matrix.orNullIfIdentity(),
|
matrix2 = selfOp ? matrix1 : path._matrix.orNullIfIdentity(),
|
||||||
length1 = curves1.length,
|
length1 = curves1.length,
|
||||||
length2 = curves2.length,
|
length2 = selfOp ? length1 : curves2.length,
|
||||||
values2 = [];
|
values2 = [],
|
||||||
|
ZERO = /*#=*/ Numerical.EPSILON,
|
||||||
|
ONE = 1 - /*#=*/ Numerical.EPSILON;
|
||||||
for (var i = 0; i < length2; i++)
|
for (var i = 0; i < length2; i++)
|
||||||
values2[i] = curves2[i].getValues(matrix2);
|
values2[i] = curves2[i].getValues(matrix2);
|
||||||
for (var i = 0; i < length1; i++) {
|
for (var i = 0; i < length1; i++) {
|
||||||
var curve1 = curves1[i],
|
var curve1 = curves1[i],
|
||||||
values1 = curve1.getValues(matrix1);
|
values1 = selfOp ? values2[i] : curve1.getValues(matrix1);
|
||||||
for (var j = 0; j < length2; j++)
|
if (selfOp) {
|
||||||
Curve.getIntersections(values1, values2[j], curve1, curves2[j],
|
// First check for self-intersections within the same curve
|
||||||
locations);
|
var seg1 = curve1.getSegment1(),
|
||||||
}
|
seg2 = curve1.getSegment2(),
|
||||||
|
h1 = seg1._handleOut,
|
||||||
return PathItem._filterIntersections(locations, _expand);
|
h2 = seg2._handleIn;
|
||||||
},
|
// Check if extended handles of endpoints of this curve
|
||||||
|
// intersects each other. We cannot have a self intersection
|
||||||
getSelfIntersections: function(_expand) {
|
// within this curve if they don't intersect due to convex-hull
|
||||||
var locations = [],
|
// property.
|
||||||
locs = [],
|
if (new Line(seg1._point.subtract(h1), h1, true).intersect(
|
||||||
curves = this.getCurves(),
|
new Line(seg2._point.subtract(h2), h2, true), false)) {
|
||||||
length = curves.length - 1,
|
locs.length = 0;
|
||||||
matrix = this._matrix.orNullIfIdentity(),
|
var parts = Curve.subdivide(values1);
|
||||||
values = [],
|
Curve.getIntersections(parts[0], parts[1], curve1, curve1,
|
||||||
curve1, values1, parts, i, j, k, ix, from, to, param, v1, v2,
|
locs);
|
||||||
EPSILON = /*#=*/ Numerical.EPSILON,
|
for (var j = locs.length - 1; j >= 0; j--) {
|
||||||
EPSILON1s = 1 - EPSILON;
|
var loc = locs[j];
|
||||||
for (i = 0; i <= length; i++)
|
if (loc._parameter <= ONE) {
|
||||||
values[i] = curves[i].getValues(matrix);
|
loc._parameter /= 2;
|
||||||
for (i = 0; i <= length; i++) {
|
loc._parameter2 = (loc._parameter2 + 1) / 2;
|
||||||
curve1 = curves[i];
|
locations.push(loc);
|
||||||
values1 = values[i];
|
break;
|
||||||
// First check for self-intersections within the same curve
|
}
|
||||||
from = curve1.getSegment1();
|
|
||||||
to = curve1.getSegment2();
|
|
||||||
v1 = from._handleOut;
|
|
||||||
v2 = to._handleIn;
|
|
||||||
// Check if extended handles of endpoints of this curve intersects
|
|
||||||
// each other. We cannot have a self intersection within this curve
|
|
||||||
// if they don't intersect due to convex-hull property.
|
|
||||||
ix = new Line(from._point.subtract(v1), v1.multiply(2), true)
|
|
||||||
.intersect(new Line(to._point.subtract(v2),
|
|
||||||
v2.multiply(2), true), false);
|
|
||||||
if (ix) {
|
|
||||||
parts = paper.Curve.subdivide(values1);
|
|
||||||
locs.length = 0;
|
|
||||||
Curve.getIntersections(parts[0], parts[1], curve1, curve1, locs);
|
|
||||||
for (j = locs.length - 1; j >= 0; j--) {
|
|
||||||
ix = locs[j];
|
|
||||||
if (ix._parameter <= EPSILON1s) {
|
|
||||||
ix._parameter = ix._parameter * 0.5;
|
|
||||||
ix._parameter2 = 0.5 + ix._parameter2 * 0.5;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (j >= 0)
|
|
||||||
locations.push(ix);
|
|
||||||
}
|
}
|
||||||
// Check for intersections with other curves
|
// Check for intersections with other curves
|
||||||
for (j = i + 1; j <= length; j++) {
|
for (var j = selfOp ? i + 1 : 0; j < length2; j++) {
|
||||||
// Avoid end point intersections on consecutive curves
|
// Avoid end point intersections on consecutive curves
|
||||||
if (j === i + 1 || (j === length && i === 0)) {
|
if (selfOp && (j === i + 1 || (j === length2 - 1 && i === 0))) {
|
||||||
locs.length = 0;
|
locs.length = 0;
|
||||||
Curve.getIntersections(values1, values[j], curve1,
|
Curve.getIntersections(values1, values2[j], curve1,
|
||||||
curves[j], locs);
|
curves2[j], locs);
|
||||||
for (k = locs.length - 1; k >= 0; k--) {
|
for (var k = locs.length - 1; k >= 0; k--) {
|
||||||
param = locs[k].getParameter();
|
var loc = locs[k],
|
||||||
if (param < EPSILON1s && param > EPSILON)
|
t = loc.getParameter();
|
||||||
locations.push(locs[k]);
|
if (t > ZERO && t < ONE)
|
||||||
|
locations.push(loc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
paper.Curve.getIntersections(values1, values[j], curve1,
|
Curve.getIntersections(values1, values2[j], curve1,
|
||||||
curves[j], locations);
|
curves2[j], locations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,7 +420,7 @@ statics: {
|
||||||
// Values for getTangentAt() that are almost 0 and 1.
|
// Values for getTangentAt() that are almost 0 and 1.
|
||||||
// TODO: Correctly support getTangentAt(0) / (1)?
|
// TODO: Correctly support getTangentAt(0) / (1)?
|
||||||
ZERO = 1e-3,
|
ZERO = 1e-3,
|
||||||
ONE = 1 - ZERO;
|
ONE = 1 - 1e-3;
|
||||||
for (var i = 0, seg, startSeg, l = segments.length; i < l; i++) {
|
for (var i = 0, seg, startSeg, l = segments.length; i < l; i++) {
|
||||||
seg = startSeg = segments[i];
|
seg = startSeg = segments[i];
|
||||||
if (seg._visited || !operator(seg._winding))
|
if (seg._visited || !operator(seg._winding))
|
||||||
|
|
Loading…
Reference in a new issue