| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /**
- Copyright (c) 2014-present, Facebook, Inc.
- All rights reserved.
- This source code is licensed under the BSD-style license found in the
- LICENSE file in the root directory of this source tree. An additional grant
- of patent rights can be found in the PATENTS file in the same directory.
- */
- #import <cmath>
- #import "POPAnimationExtras.h"
- #import "POPPropertyAnimationInternal.h"
- struct _POPSpringAnimationState : _POPPropertyAnimationState
- {
- SpringSolver4d *solver;
- CGFloat springSpeed;
- CGFloat springBounciness; // normalized springiness
- CGFloat dynamicsTension; // tension
- CGFloat dynamicsFriction; // friction
- CGFloat dynamicsMass; // mass
- _POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
- solver(nullptr),
- springSpeed(12.),
- springBounciness(4.),
- dynamicsTension(0),
- dynamicsFriction(0),
- dynamicsMass(0)
- {
- type = kPOPAnimationSpring;
- }
- bool hasConverged()
- {
- NSUInteger count = valueCount;
- if (shouldRound()) {
- return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec);
- } else {
- if (!previousVec || !previous2Vec)
- return false;
- CGFloat t = dynamicsThreshold / 5;
- const CGFloat *toValues = toVec->data();
- const CGFloat *previousValues = previousVec->data();
- const CGFloat *previous2Values = previous2Vec->data();
- for (NSUInteger idx = 0; idx < count; idx++) {
- if ((std::abs(toValues[idx] - previousValues[idx]) >= t) || (std::abs(previous2Values[idx] - previousValues[idx]) >= t)) {
- return false;
- }
- }
- return true;
- }
- }
- bool isDone() {
- if (_POPPropertyAnimationState::isDone()) {
- return true;
- }
- return solver->started() && (hasConverged() || solver->hasConverged());
- }
- void updatedDynamics()
- {
- if (NULL != solver) {
- solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
- }
- }
- void updatedDynamicsThreshold()
- {
- _POPPropertyAnimationState::updatedDynamicsThreshold();
- if (NULL != solver) {
- solver->setThreshold(dynamicsThreshold);
- }
- }
- void updatedBouncinessAndSpeed() {
- [POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass];
- updatedDynamics();
- }
- bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
- // advance past not yet initialized animations
- if (NULL == currentVec) {
- return false;
- }
- CFTimeInterval localTime = time - startTime;
- Vector4d value = vector4d(currentVec);
- Vector4d toValue = vector4d(toVec);
- Vector4d velocity = vector4d(velocityVec);
- SSState4d state;
- state.p = toValue - value;
- // the solver assumes a spring of size zero
- // flip the velocity from user perspective to solver perspective
- state.v = velocity * -1;
- solver->advance(state, localTime, dt);
- value = toValue - state.p;
- // flip velocity back to user perspective
- velocity = state.v * -1;
- *currentVec = value;
- if (velocityVec) {
- *velocityVec = velocity;
- }
- clampCurrentValue();
- return true;
- }
- virtual void reset(bool all) {
- _POPPropertyAnimationState::reset(all);
- if (solver) {
- solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
- solver->reset();
- }
- }
- };
- typedef struct _POPSpringAnimationState POPSpringAnimationState;
|