blob: 65900d8237fa04ff2e5fcfca9a66d9de7669d093 [file] [log] [blame]
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
part of touch;
/**
* Functions to model constant acceleration as a cubic Bezier
* curve (http://en.wikipedia.org/wiki/Bezier_curve). These functions are
* intended to generate the transition timing function for CSS transitions.
* Please see
* [http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag].
*
* The main operation of computing a cubic Bezier is split up into multiple
* functions so that, should it be required, more operations and cases can be
* supported in the future.
*/
class BezierPhysics {
static const _ONE_THIRD = 1 / 3;
static const _TWO_THIRDS = 2 / 3;
/**
* A list [:[x1, y1, x2, y2]:] of the intermediate control points of a cubic
* bezier when the final velocity is zero. This is a special case for which
* these control points are constants.
*/
static const List<num> _FINAL_VELOCITY_ZERO_BEZIER = const [
_ONE_THIRD,
_TWO_THIRDS,
_TWO_THIRDS,
1
];
/**
* Given consistent kinematics parameters for constant acceleration, returns
* the intermediate control points of the cubic Bezier curve that models the
* motion. All input values must have correct signs.
* Returns a list [:[x1, y1, x2, y2]:] representing the intermediate control
* points of the cubic Bezier.
*/
static List<num> calculateCubicBezierFromKinematics(num initialVelocity,
num finalVelocity, num totalTime, num totalDisplacement) {
// Total time must be greater than 0.
assert(!GoogleMath.nearlyEquals(totalTime, 0) && totalTime > 0);
// Total displacement must not be 0.
assert(!GoogleMath.nearlyEquals(totalDisplacement, 0));
// Parameters must form a consistent constant acceleration model in
// Newtonian kinematics.
assert(GoogleMath.nearlyEquals(totalDisplacement,
(initialVelocity + finalVelocity) * 0.5 * totalTime));
if (GoogleMath.nearlyEquals(finalVelocity, 0)) {
return _FINAL_VELOCITY_ZERO_BEZIER;
}
List<num> controlPoint = _tangentLinesToQuadraticBezier(
initialVelocity, finalVelocity, totalTime, totalDisplacement);
controlPoint = _normalizeQuadraticBezier(
controlPoint[0], controlPoint[1], totalTime, totalDisplacement);
return _quadraticToCubic(controlPoint[0], controlPoint[1]);
}
/**
* Given a quadratic curve crossing points (0, 0) and (x2, y2), calculates the
* intermediate control point (x1, y1) of the equivalent quadratic Bezier
* curve with starting point (0, 0) and ending point (x2, y2).
* [m0] The slope of the line tangent to the curve at (0, 0).
* [m2] The slope of the line tangent to the curve at a different
* point (x2, y2).
* [x2] The x-coordinate of the other point on the curve.
* [y2] The y-coordinate of the other point on the curve.
* Returns a list [:[x1, y1]:] representing the intermediate
* control point of the quadratic Bezier.
*/
static List<num> _tangentLinesToQuadraticBezier(
num m0, num m2, num x2, num y2) {
if (GoogleMath.nearlyEquals(m0, m2)) {
return [0, 0];
}
num x1 = (y2 - x2 * m2) / (m0 - m2);
num y1 = x1 * m0;
return [x1, y1];
}
/**
* Normalizes a quadratic Bezier curve to have end point at (1, 1).
* [x1] The x-coordinate of the intermediate control point.
* [y1] The y-coordinate of the intermediate control point.
* [x2] The x-coordinate of the end point.
* [y2] The y-coordinate of the end point.
* Returns a list [:[x1, y1]:] representing the intermediate control point.
*/
static List<num> _normalizeQuadraticBezier(num x1, num y1, num x2, num y2) {
// The end point must not lie on any axes.
assert(!GoogleMath.nearlyEquals(x2, 0) && !GoogleMath.nearlyEquals(y2, 0));
return [x1 / x2, y1 / y2];
}
/**
* Converts a quadratic Bezier curve defined by the control points
* (x0, y0) = (0, 0), (x1, y1) = (x, y), and (x2, y2) = (1, 1) into an
* equivalent cubic Bezier curve with four control points. Note that the start
* and end points will be unchanged.
* [x] The x-coordinate of the intermediate control point.
* [y] The y-coordinate of the intermediate control point.
* Returns a list [:[x1, y1, x2, y2]:] containing the two
* intermediate points of the equivalent cubic Bezier curve.
*/
static List<num> _quadraticToCubic(num x, num y) {
// The intermediate control point must have coordinates within the
// interval [0,1].
assert(x >= 0 && x <= 1 && y >= 0 && y <= 1);
num x1 = x * _TWO_THIRDS;
num y1 = y * _TWO_THIRDS;
num x2 = x1 + _ONE_THIRD;
num y2 = y1 + _ONE_THIRD;
return [x1, y1, x2, y2];
}
}