Merge PathItem#getIntersections() and #getSelfIntersections()

This commit is contained in:
Jürg Lehni 2014-02-20 16:26:47 +01:00
parent e11b6138bd
commit 4ec3daf4d1
2 changed files with 53 additions and 71 deletions

View file

@ -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();

View file

@ -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))