mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-08-28 22:08:54 -04:00
Various changes on #isLinear(), #hasHandles() & co
Relates to #652 - Implement #hasHandles() on Path, Segment and Curve - Remove Path#isPolygon() - Define #isLinear() consistently across Path, Segment and Curve. - Introduce new Segment#isStraight()
This commit is contained in:
parent
97ca1f6ff8
commit
f8314f927e
6 changed files with 99 additions and 40 deletions
|
@ -291,14 +291,27 @@ var Curve = Base.extend(/** @lends Curve# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Checks if this curve is linear, meaning it does not define any curve
|
||||
* handle.
|
||||
* Checks if this curve defines any curve handle.
|
||||
*
|
||||
* @return {Boolean} {@true if the curve has handles defined}
|
||||
* @see Segment#hasHandles()
|
||||
* @see Path#hasHandles()
|
||||
*/
|
||||
hasHandles: function() {
|
||||
return !this._segment1._handleOut.isZero()
|
||||
|| !this._segment2._handleIn.isZero();
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if this curve appears as a line. This can mean that it has no
|
||||
* handles defined, or that the handles run collinear with the line.
|
||||
*
|
||||
* @return {Boolean} {@true if the curve is linear}
|
||||
* @see Segment#isLinear()
|
||||
* @see Path#isLinear()
|
||||
*/
|
||||
isLinear: function() {
|
||||
return this._segment1._handleOut.isZero()
|
||||
&& this._segment2._handleIn.isZero();
|
||||
return this._segment1.isLinear();
|
||||
},
|
||||
|
||||
// DOCS: Curve#getIntersections()
|
||||
|
@ -643,10 +656,19 @@ statics: {
|
|||
return v;
|
||||
},
|
||||
|
||||
isLinear: function(v) {
|
||||
hasHandles: function(v) {
|
||||
var isZero = Numerical.isZero;
|
||||
return isZero(v[0] - v[2]) && isZero(v[1] - v[3])
|
||||
&& isZero(v[4] - v[6]) && isZero(v[5] - v[7]);
|
||||
return !(isZero(v[0] - v[2]) && isZero(v[1] - v[3])
|
||||
&& isZero(v[4] - v[6]) && isZero(v[5] - v[7]));
|
||||
},
|
||||
|
||||
isLinear: function(v) {
|
||||
// See Segment#isLinear():
|
||||
var p1x = v[0], p1y = v[1],
|
||||
p2x = v[6], p2y = v[7],
|
||||
l = new Point(p2x - p1x, p2y - p1y);
|
||||
return l.isCollinear(new Point(v[2] - p1x, v[3] - p1y))
|
||||
&& l.isCollinear(new Point(v[4] - p2x, v[5] - p2y));
|
||||
},
|
||||
|
||||
isFlatEnough: function(v, tolerance) {
|
||||
|
|
|
@ -368,14 +368,40 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
return this._segments.length === 0;
|
||||
},
|
||||
|
||||
isPolygon: function() {
|
||||
for (var i = 0, l = this._segments.length; i < l; i++) {
|
||||
if (!this._segments[i].isLinear())
|
||||
/**
|
||||
* Checks if this path consists of only linear curves. This can mean that
|
||||
* the curves have no handles defined, or that the handles run collinear
|
||||
* with the line.
|
||||
*
|
||||
* @return {Boolean} {@true if the path is entirely linear}
|
||||
* @see Segment#isLinear()
|
||||
* @see Curve#isLinear()
|
||||
*/
|
||||
isLinear: function() {
|
||||
var segments = this._segments;
|
||||
for (var i = 0, l = segments.length; i < l; i++) {
|
||||
if (!segments[i].isLinear())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if none of the curves in the path define any curve handles.
|
||||
*
|
||||
* @return {Boolean} {@true if the path contains no curve handles}
|
||||
* @see Segment#hasHandles()
|
||||
* @see Curve#hasHandles()
|
||||
*/
|
||||
hasHandles: function() {
|
||||
var segments = this._segments;
|
||||
for (var i = 0, l = segments.length; i < l; i++) {
|
||||
if (segments[i].hasHandles())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_transformContent: function(matrix) {
|
||||
var coords = new Array(6);
|
||||
for (var i = 0, l = this._segments.length; i < l; i++)
|
||||
|
@ -1402,7 +1428,7 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
// See if actually have any curves in the path. Differentiate
|
||||
// between straight objects (line, polyline, rect, and polygon) and
|
||||
// objects with curves(circle, ellipse, roundedRectangle).
|
||||
if (this.isPolygon() && segments.length === 4
|
||||
if (!this.hasHandles() && segments.length === 4
|
||||
&& isCollinear(0, 2) && isCollinear(1, 3) && isOrthogonal(1)) {
|
||||
type = Shape.Rectangle;
|
||||
size = new Size(getDistance(0, 3), getDistance(0, 1));
|
||||
|
|
|
@ -465,12 +465,11 @@ PathItem.inject(new function() {
|
|||
// Add the path to the result, while avoiding stray segments and
|
||||
// incomplete paths. The amount of segments for valid paths depend
|
||||
// on their geometry:
|
||||
// - Closed paths with only straight lines (polygons) need more than
|
||||
// two segments.
|
||||
// - Closed paths with curves can consist of only one segment.
|
||||
// - Open paths need at least two segments.
|
||||
// - Closed paths with only straight lines need more than 2 segments
|
||||
// - Closed paths with curves can consist of only one segment
|
||||
// - Open paths need at least two segments
|
||||
if (path._segments.length >
|
||||
(path._closed ? path.isPolygon() ? 2 : 0 : 1))
|
||||
(path._closed ? path.isLinear() ? 2 : 0 : 1))
|
||||
paths.push(path);
|
||||
}
|
||||
return paths;
|
||||
|
|
|
@ -145,8 +145,8 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
},
|
||||
|
||||
_serialize: function(options) {
|
||||
// If the Segment is linear, only serialize point, otherwise handles too
|
||||
return Base.serialize(this.isLinear() ? this._point
|
||||
// If it is straight, only serialize point, otherwise handles too.
|
||||
return Base.serialize(this.isStraight() ? this._point
|
||||
: [this._point, this._handleIn, this._handleOut],
|
||||
options, true);
|
||||
},
|
||||
|
@ -209,8 +209,6 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
var point = Point.read(arguments);
|
||||
// See #setPoint:
|
||||
this._handleIn.set(point.x, point.y);
|
||||
// Update corner accordingly
|
||||
// this.corner = !this._handleIn.isCollinear(this._handleOut);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -228,33 +226,47 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
var point = Point.read(arguments);
|
||||
// See #setPoint:
|
||||
this._handleOut.set(point.x, point.y);
|
||||
// Update corner accordingly
|
||||
// this.corner = !this._handleIn.isCollinear(this._handleOut);
|
||||
},
|
||||
|
||||
// TODO: Rename this to #corner?
|
||||
/**
|
||||
* Specifies whether the segment has no handles defined, meaning it connects
|
||||
* two straight lines.
|
||||
* Checks whether the segment has curve handles defined, meaning it is not
|
||||
* a straight segment.
|
||||
*
|
||||
* @type Boolean
|
||||
* @bean
|
||||
* @return {Boolean} {@true if the segment has handles defined}
|
||||
* @see Curve#hasHandles()
|
||||
* @see Path#hasHandles()
|
||||
*/
|
||||
isLinear: function() {
|
||||
hasHandles: function() {
|
||||
return !this.isStraight();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return {Boolean} {@true if the segment is straight}
|
||||
*/
|
||||
isStraight: function() {
|
||||
return this._handleIn.isZero() && this._handleOut.isZero();
|
||||
},
|
||||
|
||||
setLinear: function(linear) {
|
||||
if (linear) {
|
||||
this._handleIn.set(0, 0);
|
||||
this._handleOut.set(0, 0);
|
||||
} else {
|
||||
// TODO: smooth() ?
|
||||
}
|
||||
/**
|
||||
* Checks if the curve that starts in this segment appears as a line. This
|
||||
* can mean that it has no handles defined, or that the handles run
|
||||
* collinear with the line.
|
||||
*
|
||||
* @return {Boolean} {@true if the curve is linear}
|
||||
* @see Curve#isLinear()
|
||||
* @see Path#isLinear()
|
||||
*/
|
||||
isLinear: function() {
|
||||
var next = this.getNext(),
|
||||
l = next._point.subtract(this._point);
|
||||
return l.isCollinear(this._handleOut) && l.isCollinear(next._handleIn);
|
||||
},
|
||||
|
||||
// DOCS: #isCollinear(segment), #isOrthogonal(), #isArc()
|
||||
|
||||
/**
|
||||
* Returns true if the the two segments are the beginning of two lines and
|
||||
* if these two lines are running parallel.
|
||||
|
|
|
@ -125,7 +125,7 @@ new function() {
|
|||
attrs = getTransform(item._matrix);
|
||||
if (segments.length === 0)
|
||||
return null;
|
||||
if (matchShapes && item.isPolygon()) {
|
||||
if (matchShapes && !item.hasHandles()) {
|
||||
if (segments.length >= 3) {
|
||||
type = item._closed ? 'polygon' : 'polyline';
|
||||
var parts = [];
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
|
||||
test('Splitting a straight path should produce linear segments', function() {
|
||||
test('Splitting a straight path should produce straight segments', function() {
|
||||
var path = new Path.Line([0, 0], [50, 50]);
|
||||
var path2 = path.split(0, 0.5);
|
||||
equals(function() {
|
||||
return path2.firstSegment.linear;
|
||||
return path2.firstSegment.isStraight();
|
||||
}, true);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue