diff --git a/src/path/Curve.js b/src/path/Curve.js index 5f4e4d8e..80ed67e2 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -298,8 +298,22 @@ var Curve = Base.extend(/** @lends Curve# */{ * @see Path#hasHandles() */ hasHandles: function() { - return !this._segment1._handleOut.isZero() - || !this._segment2._handleIn.isZero(); + return !this.isStraight(); + }, + + /** + * Checks whether the curve is straight, meaning it has no curve handles + * defined and thus appears as a line. + * Note that this is not the same as {@link #isLinear()}, which performs a + * full linearity check that includes handles running collinear to the line + * direction. + * + * @return {Boolean} {@true if the curve is straight} + * @see Segment#isStraight() + */ + isStraight: function() { + return this._segment1._handleOut.isZero() + && this._segment2._handleIn.isZero(); }, /** @@ -378,19 +392,19 @@ var Curve = Base.extend(/** @lends Curve# */{ * is within the valid range, {code null} otherwise. */ // TODO: Rename to divideAt()? - divide: function(offset, isParameter, ignoreLinear) { + divide: function(offset, isParameter, ignoreStraight) { var parameter = this._getParameter(offset, isParameter), tolerance = /*#=*/Numerical.TOLERANCE, res = null; // Only divide if not at the beginning or end. if (parameter >= tolerance && parameter <= 1 - tolerance) { var parts = Curve.subdivide(this.getValues(), parameter), - isLinear = ignoreLinear ? false : this.isLinear(), + setHandles = ignoreStraight || this.hasHandles(), left = parts[0], right = parts[1]; // Write back the results: - if (!isLinear) { + if (setHandles) { this._segment1._handleOut.set(left[2] - left[0], left[3] - left[1]); // segment2 is the end segment. By inserting newSegment @@ -403,8 +417,8 @@ var Curve = Base.extend(/** @lends Curve# */{ // Create the new segment, convert absolute -> relative: var x = left[6], y = left[7], segment = new Segment(new Point(x, y), - !isLinear && new Point(left[4] - x, left[5] - y), - !isLinear && new Point(right[2] - x, right[3] - y)); + setHandles && new Point(left[4] - x, left[5] - y), + setHandles && new Point(right[2] - x, right[3] - y)); // Insert it in the segments list, if needed: if (this._path) { diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index 271fb2d5..589e1d24 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -191,14 +191,8 @@ PathItem.inject(new function() { function splitPath(intersections) { var tMin = /*#=*/Numerical.TOLERANCE, tMax = 1 - tMin, - linearHandles; - - function setLinear() { - // Reset linear segments if they were part of a linear curve - // and if we are done with the entire curve. - for (var i = 0, l = linearHandles.length; i < l; i++) - linearHandles[i].set(0, 0); - } + isStraight = false, + straightSegments = []; for (var i = intersections.length - 1, curve, prev; i >= 0; i--) { var loc = intersections[i], @@ -210,12 +204,7 @@ PathItem.inject(new function() { t /= prev._parameter; } else { curve = loc._curve; - if (linearHandles) - setLinear(); - linearHandles = curve.isLinear() ? [ - curve._segment1._handleOut, - curve._segment2._handleIn - ] : null; + isStraight = curve.isStraight(); } var segment; if (t < tMin) { @@ -223,22 +212,30 @@ PathItem.inject(new function() { } else if (t > tMax) { segment = curve._segment2; } else { - // Split the curve at t, while ignoring linearity of curves, - // passing true for ignoreLinear as we don't want to have - // parametrically linear curves reset their handles. + // Split the curve at t, passing true for ignoreStraight to not + // force the result of splitting straight curves straight. var newCurve = curve.divide(t, true, true); segment = newCurve._segment1; curve = newCurve.getPrevious(); - if (linearHandles) - linearHandles.push(segment._handleOut, segment._handleIn); + // Keep track of segments of once straight curves, so they can + // be set back straight at the end. + if (isStraight) + straightSegments.push(segment); } // Link the new segment with the intersection on the other curve segment._intersection = loc.getIntersection(); loc._segment = segment; prev = loc; } - if (linearHandles) - setLinear(); + // Reset linear segments if they were part of a linear curve + // and if we are done with the entire curve. + for (var i = 0, l = straightSegments.length; i < l; i++) { + var segment = straightSegments[i]; + // TODO: Implement Segment#makeStraight(), + // or #adjustHandles({ straight: true })) + segment._handleIn.set(0, 0); + segment._handleOut.set(0, 0); + } } /** diff --git a/src/path/Segment.js b/src/path/Segment.js index 967b29b9..4f0643df 100644 --- a/src/path/Segment.js +++ b/src/path/Segment.js @@ -241,12 +241,15 @@ var Segment = Base.extend(/** @lends Segment# */{ }, /** - * Checks whether the segment is straight, meaning it has no curve - * handles defined. - * If two straight segments are adjacent to each other, the curve between - * them will be a straight line. + * Checks whether the segment is straight, meaning it has no curve handles + * defined. If two straight segments follow each each other in a path, the + * curve between them will appear as a straight line. + * Note that this is not the same as {@link #isLinear()}, which performs a + * full linearity check that includes handles running collinear to the line + * direction. * * @return {Boolean} {@true if the segment is straight} + * @see Curve#isStraight() */ isStraight: function() { return this._handleIn.isZero() && this._handleOut.isZero();