mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Add #interpolate() method to Segment, Path and CompoundPath
Closes #624
This commit is contained in:
parent
53269ab169
commit
922a502ee2
3 changed files with 99 additions and 1 deletions
|
@ -315,7 +315,7 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
&& this._getWinding(point);
|
||||
return !!(this.getFillRule() === 'evenodd' ? winding & 1 : winding);
|
||||
/*#*/ } // !__options.nativeContains && __options.booleanOperations
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: Write about negative indices, and add an example for ranges.
|
||||
/**
|
||||
|
@ -467,6 +467,47 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
* paths[4].smooth({ type: 'continuous', from: -1, to: 1 });
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interpolates between the two specified path items and uses the result
|
||||
* as the geometry for this path item. The number of children and
|
||||
* segments in the two paths involved in the operation should be the same.
|
||||
*
|
||||
* @param {PathItem} from the path item defining the geometry when `factor`
|
||||
* is `0`
|
||||
* @param {PathItem} to the path item defining the geometry when `factor`
|
||||
* is `1`
|
||||
* @param {Number} factor the interpolation coefficient, typically between
|
||||
* `0` and `1`, but extrapolation is possible too
|
||||
*/
|
||||
interpolate: function(from, to, factor) {
|
||||
var isPath = !this._children,
|
||||
name = isPath ? '_segments' : '_children',
|
||||
itemsFrom = from[name],
|
||||
itemsTo = to[name],
|
||||
items = this[name];
|
||||
if (!itemsFrom || !itemsTo || itemsFrom.length !== itemsTo.length) {
|
||||
throw new Error('Invalid operands in interpolate() call: ' +
|
||||
from + ', ' + to);
|
||||
}
|
||||
var current = items.length,
|
||||
length = itemsTo.length;
|
||||
if (current < length) {
|
||||
var ctor = isPath ? Segment : Path;
|
||||
for (var i = current; i < length; i++) {
|
||||
this.add(new ctor());
|
||||
}
|
||||
} else if (current > length) {
|
||||
this[isPath ? 'removeSegments' : 'removeChildren'](length, current);
|
||||
}
|
||||
for (var i = 0; i < length; i++) {
|
||||
items[i].interpolate(itemsFrom[i], itemsTo[i], factor);
|
||||
}
|
||||
if (isPath) {
|
||||
this.setClosed(from._closed);
|
||||
this._changed(/*#=*/Change.GEOMETRY);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* {@grouptitle Postscript Style Drawing Commands}
|
||||
*
|
||||
|
|
|
@ -580,6 +580,38 @@ var Segment = Base.extend(/** @lends Segment# */{
|
|||
this._changed();
|
||||
},
|
||||
|
||||
/**
|
||||
* Interpolates between the two specified segments and sets the point and
|
||||
* handles of this segment accordingly.
|
||||
*
|
||||
* @param {Segment} from the segment defining the geometry when `factor` is
|
||||
* `0`
|
||||
* @param {Segment} to the segment defining the geometry when `factor` is
|
||||
* `1`
|
||||
* @param {Number} factor the interpolation coefficient, typically between
|
||||
* `0` and `1`, but extrapolation is possible too
|
||||
*/
|
||||
interpolate: function(from, to, factor) {
|
||||
var u = 1 - factor,
|
||||
v = factor,
|
||||
point1 = from._point,
|
||||
point2 = to._point,
|
||||
handleIn1 = from._handleIn,
|
||||
handleIn2 = to._handleIn,
|
||||
handleOut2 = to._handleOut,
|
||||
handleOut1 = from._handleOut;
|
||||
this._point.set(
|
||||
u * point1._x + v * point2._x,
|
||||
u * point1._y + v * point2._y, true);
|
||||
this._handleIn.set(
|
||||
u * handleIn1._x + v * handleIn2._x,
|
||||
u * handleIn1._y + v * handleIn2._y, true);
|
||||
this._handleOut.set(
|
||||
u * handleOut1._x + v * handleOut2._x,
|
||||
u * handleOut1._y + v * handleOut2._y, true);
|
||||
this._changed();
|
||||
},
|
||||
|
||||
_transformCoordinates: function(matrix, coords, change) {
|
||||
// Use matrix.transform version() that takes arrays of multiple
|
||||
// points for largely improved performance, as no calls to
|
||||
|
|
|
@ -292,6 +292,31 @@ test('Simplifying a path with three segments of the same position should not thr
|
|||
}, 1);
|
||||
});
|
||||
|
||||
test('Path#interpolate', function() {
|
||||
var path = new Path(),
|
||||
path0 = new Path.Circle({
|
||||
center: [0, 0],
|
||||
radius: 10
|
||||
}),
|
||||
path1 = new Path.Ellipse({
|
||||
center: [10, 20],
|
||||
radius: [20, 10]
|
||||
}),
|
||||
halfway = new Path.Ellipse({
|
||||
center: [5, 10],
|
||||
radius: [15, 10]
|
||||
});
|
||||
|
||||
path.interpolate(path0, path1, 0);
|
||||
equals(path, path0);
|
||||
|
||||
path.interpolate(path0, path1, 1);
|
||||
equals(path, path1);
|
||||
|
||||
path.interpolate(path0, path1, 0.5);
|
||||
equals(path, halfway);
|
||||
});
|
||||
|
||||
QUnit.module('Path Curves');
|
||||
|
||||
test('path.curves synchronisation', function() {
|
||||
|
|
Loading…
Reference in a new issue