1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "AxisPhysicsModel.h"
13 * The simulation is advanced forward in time with a fixed time step to ensure
14 * that it remains deterministic given variable framerates. To determine the
15 * position at any variable time, two samples are interpolated.
17 * kFixedtimestep is set to 120hz in order to ensure that every frame in a
18 * common 60hz refresh rate display will have at least one physics simulation
19 * sample. More accuracy can be obtained by reducing kFixedTimestep to smaller
20 * intervals, such as 240hz or 1000hz, at the cost of more CPU cycles. If
21 * kFixedTimestep is increased to much longer intervals, interpolation will
22 * become less effective at reducing temporal jitter and the simulation will
25 const double AxisPhysicsModel::kFixedTimestep
= 1.0 / 120.0; // 120hz
28 * Constructs an AxisPhysicsModel with initial values for state.
30 * @param aInitialPosition sets the initial position of the simulation,
32 * @param aInitialVelocity sets the initial velocity of the simulation,
33 * in AppUnits / second.
35 AxisPhysicsModel::AxisPhysicsModel(double aInitialPosition
,
36 double aInitialVelocity
)
38 mPrevState(aInitialPosition
, aInitialVelocity
),
39 mNextState(aInitialPosition
, aInitialVelocity
) {}
41 AxisPhysicsModel::~AxisPhysicsModel() = default;
43 double AxisPhysicsModel::GetVelocity() const {
44 return LinearInterpolate(mPrevState
.v
, mNextState
.v
, mProgress
);
47 double AxisPhysicsModel::GetPosition() const {
48 return LinearInterpolate(mPrevState
.p
, mNextState
.p
, mProgress
);
51 void AxisPhysicsModel::SetVelocity(double aVelocity
) {
52 mNextState
.v
= aVelocity
;
53 mNextState
.p
= GetPosition();
57 void AxisPhysicsModel::SetPosition(double aPosition
) {
58 mNextState
.v
= GetVelocity();
59 mNextState
.p
= aPosition
;
63 void AxisPhysicsModel::Simulate(const TimeDuration
& aDeltaTime
) {
64 for (mProgress
+= aDeltaTime
.ToSeconds() / kFixedTimestep
; mProgress
> 1.0;
66 Integrate(kFixedTimestep
);
70 void AxisPhysicsModel::Integrate(double aDeltaTime
) {
71 mPrevState
= mNextState
;
73 // RK4 (Runge-Kutta method) Integration
74 // http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
75 Derivative a
= Evaluate(mNextState
, 0.0, Derivative());
76 Derivative b
= Evaluate(mNextState
, aDeltaTime
* 0.5, a
);
77 Derivative c
= Evaluate(mNextState
, aDeltaTime
* 0.5, b
);
78 Derivative d
= Evaluate(mNextState
, aDeltaTime
, c
);
80 double dpdt
= 1.0 / 6.0 * (a
.dp
+ 2.0 * (b
.dp
+ c
.dp
) + d
.dp
);
81 double dvdt
= 1.0 / 6.0 * (a
.dv
+ 2.0 * (b
.dv
+ c
.dv
) + d
.dv
);
83 mNextState
.p
+= dpdt
* aDeltaTime
;
84 mNextState
.v
+= dvdt
* aDeltaTime
;
87 AxisPhysicsModel::Derivative
AxisPhysicsModel::Evaluate(
88 const State
& aInitState
, double aDeltaTime
, const Derivative
& aDerivative
) {
89 State
state(aInitState
.p
+ aDerivative
.dp
* aDeltaTime
,
90 aInitState
.v
+ aDerivative
.dv
* aDeltaTime
);
92 return Derivative(state
.v
, Acceleration(state
));
95 double AxisPhysicsModel::LinearInterpolate(double aV1
, double aV2
,
97 return aV1
* (1.0 - aBlend
) + aV2
* aBlend
;
100 } // namespace layers
101 } // namespace mozilla