Remove #isStraight() in favor of #hasHandles() and implement #clearHandles()

Relates to #652
This commit is contained in:
Jürg Lehni 2015-09-06 12:47:35 +02:00
parent bfbe0b3147
commit 8b67d8a1dc
5 changed files with 47 additions and 51 deletions

View file

@ -120,11 +120,11 @@ var Curve = Base.extend(/** @lends Curve# */{
}, },
_serialize: function(options) { _serialize: function(options) {
// If it is straight, only serialize point, otherwise handles too. // If it has no handles, only serialize points, otherwise handles too.
return Base.serialize(this.isStraight() return Base.serialize(this.hasHandles()
? [this.getPoint1(), this.getPoint2()] ? [this.getPoint1(), this.getHandle1(), this.getHandle2(),
: [this.getPoint1(), this.getHandle1(), this.getHandle2(), this.getPoint2()]
this.getPoint2()], : [this.getPoint1(), this.getPoint2()],
options, true); options, true);
}, },
@ -329,22 +329,17 @@ var Curve = Base.extend(/** @lends Curve# */{
* @see Path#hasHandles() * @see Path#hasHandles()
*/ */
hasHandles: function() { hasHandles: function() {
return !this.isStraight(); return !this._segment1._handleOut.isZero()
|| !this._segment2._handleIn.isZero();
}, },
/** /**
* Checks whether the curve is straight, meaning it has no curve handles * Clears the curve's handles by setting their coordinates to zero,
* defined and thus appears as a line. * turning the curve into 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 curve is straight}
* @see Segment#isStraight()
*/ */
isStraight: function() { clearHandles: function() {
return this._segment1._handleOut.isZero() this._segment1._handleOut.set(0, 0);
&& this._segment2._handleIn.isZero(); this._segment2._handleIn.set(0, 0);
}, },
/** /**

View file

@ -402,6 +402,16 @@ var Path = PathItem.extend(/** @lends Path# */{
return false; return false;
}, },
/**
* Clears the path's handles by setting their coordinates to zero,
* turning the path into a polygon (or a polyline if it isn't closed).
*/
clearHandles: function() {
var segments = this._segments;
for (var i = 0, l = segments.length; i < l; i++)
segments[i].clearHandles();
},
_transformContent: function(matrix) { _transformContent: function(matrix) {
var coords = new Array(6); var coords = new Array(6);
for (var i = 0, l = this._segments.length; i < l; i++) for (var i = 0, l = this._segments.length; i < l; i++)

View file

@ -242,8 +242,8 @@ PathItem.inject(new function() {
// TODO: Make public in API, since useful! // TODO: Make public in API, since useful!
var tMin = /*#=*/Numerical.TOLERANCE, var tMin = /*#=*/Numerical.TOLERANCE,
tMax = 1 - tMin, tMax = 1 - tMin,
isStraight = false, noHandles = false,
straightSegments = []; clearSegments = [];
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],
@ -255,7 +255,7 @@ PathItem.inject(new function() {
t /= prev._parameter; t /= prev._parameter;
} else { } else {
curve = loc._curve; curve = loc._curve;
isStraight = curve.isStraight(); noHandles = !curve.hasHandles();
} }
var segment; var segment;
if (t < tMin) { if (t < tMin) {
@ -270,22 +270,18 @@ PathItem.inject(new function() {
curve = newCurve.getPrevious(); curve = newCurve.getPrevious();
// Keep track of segments of once straight curves, so they can // Keep track of segments of once straight curves, so they can
// be set back straight at the end. // be set back straight at the end.
if (isStraight) if (noHandles)
straightSegments.push(segment); clearSegments.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;
} }
// Reset linear segments if they were part of a linear curve // Clear segment handles if they were part of a curve with no handles,
// and if we are done with the entire curve. // once we are done with the entire curve.
for (var i = 0, l = straightSegments.length; i < l; i++) { for (var i = 0, l = clearSegments.length; i < l; i++) {
var segment = straightSegments[i]; clearSegments[i].clearHandles();
// TODO: Implement Segment#makeStraight(),
// or #adjustHandles({ straight: true }))
segment._handleIn.set(0, 0);
segment._handleOut.set(0, 0);
} }
} }

View file

@ -145,9 +145,10 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
_serialize: function(options) { _serialize: function(options) {
// If it is straight, only serialize point, otherwise handles too. // If it is has no handles, only serialize point, otherwise handles too.
return Base.serialize(this.isStraight() ? this._point return Base.serialize(this.hasHandles()
: [this._point, this._handleIn, this._handleOut], ? [this._point, this._handleIn, this._handleOut]
: this._point,
options, true); options, true);
}, },
@ -237,22 +238,16 @@ var Segment = Base.extend(/** @lends Segment# */{
* @see Path#hasHandles() * @see Path#hasHandles()
*/ */
hasHandles: function() { hasHandles: function() {
return !this.isStraight(); return !this._handleIn.isZero() || !this._handleOut.isZero();
}, },
/** /**
* Checks whether the segment is straight, meaning it has no curve handles * Clears the segment's handles by setting their coordinates to zero,
* defined. If two straight segments follow each each other in a path, the * turning the segment into a corner.
* 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() { clearHandles: function() {
return this._handleIn.isZero() && this._handleOut.isZero(); this._handleIn.set(0, 0);
this._handleOut.set(0, 0);
}, },
/** /**
@ -579,7 +574,7 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
isCollinear: function(seg1, seg2, seg3, seg4) { isCollinear: function(seg1, seg2, seg3, seg4) {
// TODO: This assumes isStraight(), while isLinear() allows handles! // TODO: This assumes !hasHandles(), while isLinear() allows handles!
return seg1._handleOut.isZero() && seg2._handleIn.isZero() return seg1._handleOut.isZero() && seg2._handleIn.isZero()
&& seg3._handleOut.isZero() && seg4._handleIn.isZero() && seg3._handleOut.isZero() && seg4._handleIn.isZero()
&& seg2._point.subtract(seg1._point).isCollinear( && seg2._point.subtract(seg1._point).isCollinear(
@ -587,7 +582,7 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
isOrthogonal: function(seg1, seg2, seg3) { isOrthogonal: function(seg1, seg2, seg3) {
// TODO: This assumes isStraight(), while isLinear() allows handles! // TODO: This assumes !hasHandles(), while isLinear() allows handles!
return seg1._handleOut.isZero() && seg2._handleIn.isZero() return seg1._handleOut.isZero() && seg2._handleIn.isZero()
&& seg2._handleOut.isZero() && seg3._handleIn.isZero() && seg2._handleOut.isZero() && seg3._handleIn.isZero()
&& seg2._point.subtract(seg1._point).isOrthogonal( && seg2._point.subtract(seg1._point).isOrthogonal(

View file

@ -107,10 +107,10 @@ test('Curve list after removing a segment - 2', function() {
}, 1, 'After removing the last segment, we should be left with one curve'); }, 1, 'After removing the last segment, we should be left with one curve');
}); });
test('Splitting a straight path should produce straight segments', function() { test('Splitting a straight path should produce segments without handles', function() {
var path = new Path.Line([0, 0], [50, 50]); var path1 = new Path.Line([0, 0], [50, 50]);
var path2 = path.split(0, 0.5); var path2 = path1.split(0, 0.5);
equals(function() { equals(function() {
return path2.firstSegment.isStraight(); return !path1.lastSegment.hasHandles() && !path2.firstSegment.hasHandles();
}, true); }, true);
}); });