mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-20 22:39:50 -05:00
Merge branch 'master' into bool-new
* master: Share code that handles bounds in roots between solveQuadratic() and solveCubic() Inline EPSILON and TOLERANCE for better performance in Numerical. Clean up code a bit. Filter out insert property in Item#set() Typo Paelette -> Palette Rename Item#anchor -> Item#pivot Minor documentation fixes.
This commit is contained in:
commit
f23303e371
6 changed files with 85 additions and 79 deletions
|
@ -2,7 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Paelette</title>
|
||||
<title>Palette</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<script type="text/javascript" src="../../dist/paper.js"></script>
|
||||
<script type="text/paperscript" canvas="canvas">
|
||||
|
@ -70,4 +70,4 @@
|
|||
<body>
|
||||
<canvas id="canvas" width="640" height="100"></canvas>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
strokeWidth: 30,
|
||||
strokeJoin: 'round',
|
||||
strokeCap: 'butt',
|
||||
anchor: leftPath.position,
|
||||
pivot: leftPath.position,
|
||||
position: view.center
|
||||
});
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
|||
}
|
||||
leftPath.smooth();
|
||||
rightPath.smooth();
|
||||
group.anchor = [leftPath.position.x, 0];
|
||||
group.pivot = [leftPath.position.x, 0];
|
||||
group.position = view.center;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
_serializeFields: {
|
||||
name: null,
|
||||
matrix: new Matrix(),
|
||||
anchor: null,
|
||||
pivot: null,
|
||||
locked: false,
|
||||
visible: true,
|
||||
blendMode: 'normal',
|
||||
|
@ -279,7 +279,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
*/
|
||||
set: function(props) {
|
||||
if (props)
|
||||
this._set(props);
|
||||
this._set(props, { insert: true });
|
||||
return this;
|
||||
},
|
||||
|
||||
|
@ -772,11 +772,11 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
// modified, it would hold new values already and only then cause the
|
||||
// calling of #setPosition.
|
||||
if (!position) {
|
||||
// If an anchor point is provided, use it to determine position
|
||||
// If an pivot point is provided, use it to determine position
|
||||
// based on the matrix. Otherwise use the center of the bounds.
|
||||
var anchor = this._anchor;
|
||||
position = this._position = anchor
|
||||
? this._matrix._transformPoint(anchor)
|
||||
var pivot = this._pivot;
|
||||
position = this._position = pivot
|
||||
? this._matrix._transformPoint(pivot)
|
||||
: this.getBounds().getCenter(true);
|
||||
}
|
||||
return new ctor(position.x, position.y, this, 'setPosition');
|
||||
|
@ -790,11 +790,11 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* The item's anchor point specified in the item coordinate system, defining
|
||||
* the reference point for {@link #position}, as well as the pivot point for
|
||||
* all transformations. By default, it is set to {@code null}, meaning the
|
||||
* {@link Rectangle#center} of the item's {@link #bounds} rectangle is used
|
||||
* as the anchor.
|
||||
* The item's pivot point specified in the item coordinate system, defining
|
||||
* the point around which all transformations are hinging. This is also the
|
||||
* reference point for {@link #position}. By default, it is set to
|
||||
* {@code null}, meaning the {@link Rectangle#center} of the item's
|
||||
* {@link #bounds} rectangle is used as pivot.
|
||||
*
|
||||
* @type Point
|
||||
* @bean
|
||||
|
@ -802,22 +802,22 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
*
|
||||
* @example {@paperscript}
|
||||
*/
|
||||
getAnchor: function(/* dontLink */) {
|
||||
var anchor = this._anchor;
|
||||
if (anchor) {
|
||||
getPivot: function(/* dontLink */) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot) {
|
||||
var ctor = arguments[0] ? Point : LinkedPoint;
|
||||
anchor = new ctor(anchor.x, anchor.y, this, 'setAnchor');
|
||||
pivot = new ctor(pivot.x, pivot.y, this, 'setAnchor');
|
||||
}
|
||||
return anchor;
|
||||
return pivot;
|
||||
},
|
||||
|
||||
setAnchor: function(/* point */) {
|
||||
this._anchor = Point.read(arguments);
|
||||
setPivot: function(/* point */) {
|
||||
this._pivot = Point.read(arguments);
|
||||
// No need for _changed() since the only thing this affects is _position
|
||||
delete this._position;
|
||||
},
|
||||
|
||||
_anchor: null,
|
||||
_pivot: null,
|
||||
|
||||
// TODO: Keep these around for a bit since it was introduced on the mailing
|
||||
// list, then remove in a while.
|
||||
|
@ -2781,15 +2781,15 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
var matrix = this._matrix;
|
||||
if (this._applyMatrix(matrix, true)) {
|
||||
// When the matrix could be applied, we also need to transform
|
||||
// color styles (only gradients so far) and anchor point:
|
||||
var anchor = this._anchor,
|
||||
// color styles (only gradients so far) and pivot point:
|
||||
var pivot = this._pivot,
|
||||
style = this._style,
|
||||
// pass true for dontMerge so we don't recursively transform
|
||||
// styles on groups' children.
|
||||
fillColor = style.getFillColor(true),
|
||||
strokeColor = style.getStrokeColor(true);
|
||||
if (anchor)
|
||||
anchor.transform(matrix);
|
||||
if (pivot)
|
||||
pivot.transform(matrix);
|
||||
if (fillColor)
|
||||
fillColor.transform(matrix);
|
||||
if (strokeColor)
|
||||
|
|
|
@ -69,11 +69,12 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
curves2 = path.getCurves(),
|
||||
matrix1 = this._matrix.orNullIfIdentity(),
|
||||
matrix2 = path._matrix.orNullIfIdentity(),
|
||||
length1 = curves1.length,
|
||||
length2 = curves2.length,
|
||||
values2 = [];
|
||||
for (var i = 0; i < length2; i++)
|
||||
values2[i] = curves2[i].getValues(matrix2);
|
||||
for (var i = 0, l = curves1.length; i < l; i++) {
|
||||
for (var i = 0; i < length1; i++) {
|
||||
var curve1 = curves1[i],
|
||||
values1 = curve1.getValues(matrix1);
|
||||
for (var j = 0; j < length2; j++)
|
||||
|
|
|
@ -365,8 +365,8 @@ var Color = Base.extend(new function() {
|
|||
* {@code destination: Point} — the destination point of the gradient
|
||||
* {@code stops: Array of GradientStop} — the gradient stops describing
|
||||
* the gradient, as an alternative to providing a gradient object<br>
|
||||
* {@code radial: Boolean} — controls whether the gradient is radial, as
|
||||
* an alternative to providing a gradient object<br>
|
||||
* {@code radial: Boolean} — controls whether the gradient is radial,
|
||||
* as an alternative to providing a gradient object<br>
|
||||
*
|
||||
* @name Color#initialize
|
||||
* @param {Object} object an object describing the components and
|
||||
|
@ -454,13 +454,18 @@ var Color = Base.extend(new function() {
|
|||
* // Create a circle shaped path at the center of the view
|
||||
* // with a radius of 80:
|
||||
* var path = new Path.Circle({
|
||||
* center: view.center,
|
||||
* radius: 80
|
||||
* center: view.center,
|
||||
* radius: 80
|
||||
* });
|
||||
*
|
||||
* // The stops array: yellow mixes with red between 0 and 15%,
|
||||
* // 15% to 30% is pure red, red mixes with black between 30% to 100%:
|
||||
* var stops = [['yellow', 0], ['red', 0.15], ['red', 0.3], ['black', 0.9]];
|
||||
* var stops = [
|
||||
* ['yellow', 0],
|
||||
* ['red', 0.15],
|
||||
* ['red', 0.3],
|
||||
* ['black', 0.9]
|
||||
* ];
|
||||
*
|
||||
* // Create a radial gradient using the color stops array:
|
||||
* var gradient = new Gradient(stops, true);
|
||||
|
@ -971,14 +976,16 @@ var Color = Base.extend(new function() {
|
|||
* }
|
||||
*/
|
||||
/**
|
||||
* The saturation of the color as a value between {@code 0} and {@code 1}.
|
||||
* The saturation of the color as a value between {@code 0} and
|
||||
* {@code 1}.
|
||||
*
|
||||
* @name Color#saturation
|
||||
* @property
|
||||
* @type Number
|
||||
*/
|
||||
/**
|
||||
* The brightness of the color as a value between {@code 0} and {@code 1}.
|
||||
* The brightness of the color as a value between {@code 0} and
|
||||
* {@code 1}.
|
||||
*
|
||||
* @name Color#brightness
|
||||
* @property
|
||||
|
@ -988,8 +995,9 @@ var Color = Base.extend(new function() {
|
|||
/**
|
||||
* {@grouptitle HSL Components}
|
||||
*
|
||||
* The lightness of the color as a value between {@code 0} and {@code 1}.
|
||||
* All other components are shared with HSB.
|
||||
* The lightness of the color as a value between {@code 0} and
|
||||
* {@code 1}.
|
||||
* Note that all other components are shared with HSB.
|
||||
*
|
||||
* @name Color#lightness
|
||||
* @property
|
||||
|
@ -1043,8 +1051,8 @@ var Color = Base.extend(new function() {
|
|||
* @type Point
|
||||
*
|
||||
* @example {@paperscript height=300}
|
||||
* // Move the destination point of the gradient, by moving your mouse over
|
||||
* // the view below:
|
||||
* // Move the destination point of the gradient, by moving your mouse
|
||||
* // over the view below:
|
||||
*
|
||||
* // Create a circle shaped path at the center of the view,
|
||||
* // using 40% of the height of the view as its radius
|
||||
|
@ -1167,7 +1175,8 @@ var Color = Base.extend(new function() {
|
|||
* @function
|
||||
* @operator
|
||||
* @param {Number} number the number to add
|
||||
* @return {Color} the addition of the color and the value as a new color
|
||||
* @return {Color} the addition of the color and the value as a new
|
||||
* color
|
||||
*
|
||||
* @example
|
||||
* var color = new Color(0.5, 1, 1);
|
||||
|
|
|
@ -56,12 +56,29 @@ var Numerical = new function() {
|
|||
sqrt = Math.sqrt,
|
||||
pow = Math.pow,
|
||||
cos = Math.cos,
|
||||
PI = Math.PI;
|
||||
PI = Math.PI,
|
||||
TOLERANCE = 10e-6,
|
||||
EPSILON = 10e-12;
|
||||
|
||||
// Sets up min and max values for roots and returns a add() function that
|
||||
// handles bounds checks and itself retuns the amount of added roots.
|
||||
function setupRoots(roots, min, max) {
|
||||
var unbound = min === undefined,
|
||||
minE = min - EPSILON,
|
||||
maxE = max + EPSILON,
|
||||
count = 0;
|
||||
// Returns a function that adds roots with checks
|
||||
return function(root) {
|
||||
if (unbound || root > minE && root < maxE)
|
||||
roots[count++] = root < min ? min : root > max ? max : root;
|
||||
return count;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
TOLERANCE: 10e-6,
|
||||
TOLERANCE: TOLERANCE,
|
||||
// Precision when comparing against 0
|
||||
EPSILON: 10e-12,
|
||||
EPSILON: EPSILON,
|
||||
// Kappa, see: http://www.whizkidtech.redprince.net/bezier/circle/kappa/
|
||||
KAPPA: 4 * (sqrt(2) - 1) / 3,
|
||||
|
||||
|
@ -70,7 +87,7 @@ var Numerical = new function() {
|
|||
* Numerical.EPSILON.
|
||||
*/
|
||||
isZero: function(val) {
|
||||
return abs(val) <= Numerical.EPSILON;
|
||||
return abs(val) <= EPSILON;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -127,36 +144,26 @@ var Numerical = new function() {
|
|||
* a*x^2 + b*x + c = 0
|
||||
*/
|
||||
solveQuadratic: function(a, b, c, roots, min, max) {
|
||||
var epsilon = Numerical.EPSILON,
|
||||
unbound = min === undefined,
|
||||
minE = min - epsilon,
|
||||
maxE = max + epsilon,
|
||||
count = 0;
|
||||
|
||||
function add(root) {
|
||||
if (unbound || root > minE && root < maxE)
|
||||
roots[count++] = root < min ? min : root > max ? max : root;
|
||||
return count;
|
||||
}
|
||||
var add = setupRoots(roots, min, max);
|
||||
|
||||
// Code ported over and adapted from Uintah library (MIT license).
|
||||
// If a is 0, equation is actually linear, return 0 or 1 easy roots.
|
||||
if (abs(a) < epsilon) {
|
||||
if (abs(b) >= epsilon)
|
||||
if (abs(a) < EPSILON) {
|
||||
if (abs(b) >= EPSILON)
|
||||
return add(-c / b);
|
||||
// If all the coefficients are 0, we have infinite solutions!
|
||||
return abs(c) < epsilon ? -1 : 0; // Infinite or 0 solutions
|
||||
return abs(c) < EPSILON ? -1 : 0; // Infinite or 0 solutions
|
||||
}
|
||||
// Convert to normal form: x^2 + px + q = 0
|
||||
var p = b / (2 * a);
|
||||
var q = c / a;
|
||||
var p2 = p * p;
|
||||
if (p2 < q - epsilon)
|
||||
if (p2 < q - EPSILON)
|
||||
return 0;
|
||||
var s = p2 > q ? sqrt(p2 - q) : 0;
|
||||
add (s - p);
|
||||
var s = p2 > q ? sqrt(p2 - q) : 0,
|
||||
count = add(s - p);
|
||||
if (s > 0)
|
||||
add(-s - p);
|
||||
count = add(-s - p);
|
||||
return count;
|
||||
},
|
||||
|
||||
|
@ -167,29 +174,18 @@ var Numerical = new function() {
|
|||
* a*x^3 + b*x^2 + c*x + d = 0
|
||||
*/
|
||||
solveCubic: function(a, b, c, d, roots, min, max) {
|
||||
var epsilon = Numerical.EPSILON;
|
||||
// If a is 0, equation is actually quadratic.
|
||||
if (abs(a) < epsilon)
|
||||
if (abs(a) < EPSILON)
|
||||
return Numerical.solveQuadratic(b, c, d, roots, min, max);
|
||||
|
||||
var unbound = min === undefined,
|
||||
minE = min - epsilon,
|
||||
maxE = max + epsilon,
|
||||
count = 0;
|
||||
|
||||
function add(root) {
|
||||
if (unbound || root > minE && root < maxE)
|
||||
roots[count++] = root < min ? min : root > max ? max : root;
|
||||
return count;
|
||||
}
|
||||
|
||||
// Code ported over and adapted from Uintah library (MIT license).
|
||||
// Normalize to form: x^3 + b x^2 + c x + d = 0:
|
||||
b /= a;
|
||||
c /= a;
|
||||
d /= a;
|
||||
// Compute discriminants
|
||||
var bb = b * b,
|
||||
var add = setupRoots(roots, min, max),
|
||||
// Compute discriminants
|
||||
bb = b * b,
|
||||
p = (bb - 3 * c) / 9,
|
||||
q = (2 * bb * b - 9 * b * c + 27 * d) / 54,
|
||||
// Use Cardano's formula
|
||||
|
@ -197,8 +193,8 @@ var Numerical = new function() {
|
|||
D = q * q - ppp;
|
||||
// Substitute x = y - b/3 to eliminate quadric term: x^3 +px + q = 0
|
||||
b /= 3;
|
||||
if (abs(D) < epsilon) {
|
||||
if (abs(q) < epsilon) // One triple solution.
|
||||
if (abs(D) < EPSILON) {
|
||||
if (abs(q) < EPSILON) // One triple solution.
|
||||
return add(-b);
|
||||
// One single and one double solution.
|
||||
var sqp = sqrt(p),
|
||||
|
|
Loading…
Reference in a new issue