mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-07 13:22:07 -05:00
Introduce Curve#isStraight() and use it in splitPath() and divide() to keep the result of splitting straight curves straight.
Do not use Curve#isLinear(), as that would include curves with collinear handles, and we don't want to set these straight.
This commit is contained in:
parent
605ceef94c
commit
9bd399b5b8
3 changed files with 46 additions and 32 deletions
|
@ -298,8 +298,22 @@ var Curve = Base.extend(/** @lends Curve# */{
|
||||||
* @see Path#hasHandles()
|
* @see Path#hasHandles()
|
||||||
*/
|
*/
|
||||||
hasHandles: function() {
|
hasHandles: function() {
|
||||||
return !this._segment1._handleOut.isZero()
|
return !this.isStraight();
|
||||||
|| !this._segment2._handleIn.isZero();
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* is within the valid range, {code null} otherwise.
|
||||||
*/
|
*/
|
||||||
// TODO: Rename to divideAt()?
|
// TODO: Rename to divideAt()?
|
||||||
divide: function(offset, isParameter, ignoreLinear) {
|
divide: function(offset, isParameter, ignoreStraight) {
|
||||||
var parameter = this._getParameter(offset, isParameter),
|
var parameter = this._getParameter(offset, isParameter),
|
||||||
tolerance = /*#=*/Numerical.TOLERANCE,
|
tolerance = /*#=*/Numerical.TOLERANCE,
|
||||||
res = null;
|
res = null;
|
||||||
// Only divide if not at the beginning or end.
|
// Only divide if not at the beginning or end.
|
||||||
if (parameter >= tolerance && parameter <= 1 - tolerance) {
|
if (parameter >= tolerance && parameter <= 1 - tolerance) {
|
||||||
var parts = Curve.subdivide(this.getValues(), parameter),
|
var parts = Curve.subdivide(this.getValues(), parameter),
|
||||||
isLinear = ignoreLinear ? false : this.isLinear(),
|
setHandles = ignoreStraight || this.hasHandles(),
|
||||||
left = parts[0],
|
left = parts[0],
|
||||||
right = parts[1];
|
right = parts[1];
|
||||||
|
|
||||||
// Write back the results:
|
// Write back the results:
|
||||||
if (!isLinear) {
|
if (setHandles) {
|
||||||
this._segment1._handleOut.set(left[2] - left[0],
|
this._segment1._handleOut.set(left[2] - left[0],
|
||||||
left[3] - left[1]);
|
left[3] - left[1]);
|
||||||
// segment2 is the end segment. By inserting newSegment
|
// 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:
|
// Create the new segment, convert absolute -> relative:
|
||||||
var x = left[6], y = left[7],
|
var x = left[6], y = left[7],
|
||||||
segment = new Segment(new Point(x, y),
|
segment = new Segment(new Point(x, y),
|
||||||
!isLinear && new Point(left[4] - x, left[5] - y),
|
setHandles && new Point(left[4] - x, left[5] - y),
|
||||||
!isLinear && new Point(right[2] - x, right[3] - y));
|
setHandles && new Point(right[2] - x, right[3] - y));
|
||||||
|
|
||||||
// Insert it in the segments list, if needed:
|
// Insert it in the segments list, if needed:
|
||||||
if (this._path) {
|
if (this._path) {
|
||||||
|
|
|
@ -191,14 +191,8 @@ PathItem.inject(new function() {
|
||||||
function splitPath(intersections) {
|
function splitPath(intersections) {
|
||||||
var tMin = /*#=*/Numerical.TOLERANCE,
|
var tMin = /*#=*/Numerical.TOLERANCE,
|
||||||
tMax = 1 - tMin,
|
tMax = 1 - tMin,
|
||||||
linearHandles;
|
isStraight = false,
|
||||||
|
straightSegments = [];
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = intersections.length - 1, curve, prev; i >= 0; i--) {
|
for (var i = intersections.length - 1, curve, prev; i >= 0; i--) {
|
||||||
var loc = intersections[i],
|
var loc = intersections[i],
|
||||||
|
@ -210,12 +204,7 @@ PathItem.inject(new function() {
|
||||||
t /= prev._parameter;
|
t /= prev._parameter;
|
||||||
} else {
|
} else {
|
||||||
curve = loc._curve;
|
curve = loc._curve;
|
||||||
if (linearHandles)
|
isStraight = curve.isStraight();
|
||||||
setLinear();
|
|
||||||
linearHandles = curve.isLinear() ? [
|
|
||||||
curve._segment1._handleOut,
|
|
||||||
curve._segment2._handleIn
|
|
||||||
] : null;
|
|
||||||
}
|
}
|
||||||
var segment;
|
var segment;
|
||||||
if (t < tMin) {
|
if (t < tMin) {
|
||||||
|
@ -223,22 +212,30 @@ PathItem.inject(new function() {
|
||||||
} else if (t > tMax) {
|
} else if (t > tMax) {
|
||||||
segment = curve._segment2;
|
segment = curve._segment2;
|
||||||
} else {
|
} else {
|
||||||
// Split the curve at t, while ignoring linearity of curves,
|
// Split the curve at t, passing true for ignoreStraight to not
|
||||||
// passing true for ignoreLinear as we don't want to have
|
// force the result of splitting straight curves straight.
|
||||||
// parametrically linear curves reset their handles.
|
|
||||||
var newCurve = curve.divide(t, true, true);
|
var newCurve = curve.divide(t, true, true);
|
||||||
segment = newCurve._segment1;
|
segment = newCurve._segment1;
|
||||||
curve = newCurve.getPrevious();
|
curve = newCurve.getPrevious();
|
||||||
if (linearHandles)
|
// Keep track of segments of once straight curves, so they can
|
||||||
linearHandles.push(segment._handleOut, segment._handleIn);
|
// be set back straight at the end.
|
||||||
|
if (isStraight)
|
||||||
|
straightSegments.push(segment);
|
||||||
}
|
}
|
||||||
// Link the new segment with the intersection on the other curve
|
// Link the new segment with the intersection on the other curve
|
||||||
segment._intersection = loc.getIntersection();
|
segment._intersection = loc.getIntersection();
|
||||||
loc._segment = segment;
|
loc._segment = segment;
|
||||||
prev = loc;
|
prev = loc;
|
||||||
}
|
}
|
||||||
if (linearHandles)
|
// Reset linear segments if they were part of a linear curve
|
||||||
setLinear();
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -241,12 +241,15 @@ var Segment = Base.extend(/** @lends Segment# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the segment is straight, meaning it has no curve
|
* Checks whether the segment is straight, meaning it has no curve handles
|
||||||
* handles defined.
|
* defined. If two straight segments follow each each other in a path, the
|
||||||
* If two straight segments are adjacent to each other, the curve between
|
* curve between them will appear as a straight line.
|
||||||
* them will be 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}
|
* @return {Boolean} {@true if the segment is straight}
|
||||||
|
* @see Curve#isStraight()
|
||||||
*/
|
*/
|
||||||
isStraight: function() {
|
isStraight: function() {
|
||||||
return this._handleIn.isZero() && this._handleOut.isZero();
|
return this._handleIn.isZero() && this._handleOut.isZero();
|
||||||
|
|
Loading…
Reference in a new issue