Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et 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/. */
6 :
7 : #include "AxisPhysicsModel.h"
8 :
9 : namespace mozilla {
10 : namespace layers {
11 :
12 : /**
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.
16 : *
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
23 : * lose accuracy.
24 : */
25 : const double AxisPhysicsModel::kFixedTimestep = 1.0 / 120.0; // 120hz
26 :
27 : /**
28 : * Constructs an AxisPhysicsModel with initial values for state.
29 : *
30 : * @param aInitialPosition sets the initial position of the simulation,
31 : * in AppUnits.
32 : * @param aInitialVelocity sets the initial velocity of the simulation,
33 : * in AppUnits / second.
34 : */
35 4 : AxisPhysicsModel::AxisPhysicsModel(double aInitialPosition,
36 4 : double aInitialVelocity)
37 : : mProgress(1.0)
38 : , mPrevState(aInitialPosition, aInitialVelocity)
39 4 : , mNextState(aInitialPosition, aInitialVelocity)
40 : {
41 :
42 4 : }
43 :
44 0 : AxisPhysicsModel::~AxisPhysicsModel()
45 : {
46 :
47 0 : }
48 :
49 : double
50 0 : AxisPhysicsModel::GetVelocity()
51 : {
52 0 : return LinearInterpolate(mPrevState.v, mNextState.v, mProgress);
53 : }
54 :
55 : double
56 0 : AxisPhysicsModel::GetPosition()
57 : {
58 0 : return LinearInterpolate(mPrevState.p, mNextState.p, mProgress);
59 : }
60 :
61 : void
62 0 : AxisPhysicsModel::SetVelocity(double aVelocity)
63 : {
64 0 : mNextState.v = aVelocity;
65 0 : mNextState.p = GetPosition();
66 0 : mProgress = 1.0;
67 0 : }
68 :
69 : void
70 0 : AxisPhysicsModel::SetPosition(double aPosition)
71 : {
72 0 : mNextState.v = GetVelocity();
73 0 : mNextState.p = aPosition;
74 0 : mProgress = 1.0;
75 0 : }
76 :
77 : void
78 0 : AxisPhysicsModel::Simulate(const TimeDuration& aDeltaTime)
79 : {
80 0 : for(mProgress += aDeltaTime.ToSeconds() / kFixedTimestep;
81 0 : mProgress > 1.0; mProgress -= 1.0) {
82 0 : Integrate(kFixedTimestep);
83 : }
84 0 : }
85 :
86 : void
87 0 : AxisPhysicsModel::Integrate(double aDeltaTime)
88 : {
89 0 : mPrevState = mNextState;
90 :
91 : // RK4 (Runge-Kutta method) Integration
92 : // http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
93 0 : Derivative a = Evaluate( mNextState, 0.0, Derivative() );
94 0 : Derivative b = Evaluate( mNextState, aDeltaTime * 0.5, a );
95 0 : Derivative c = Evaluate( mNextState, aDeltaTime * 0.5, b );
96 0 : Derivative d = Evaluate( mNextState, aDeltaTime, c );
97 :
98 0 : double dpdt = 1.0 / 6.0 * (a.dp + 2.0 * (b.dp + c.dp) + d.dp);
99 0 : double dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv);
100 :
101 0 : mNextState.p += dpdt * aDeltaTime;
102 0 : mNextState.v += dvdt * aDeltaTime;
103 0 : }
104 :
105 : AxisPhysicsModel::Derivative
106 0 : AxisPhysicsModel::Evaluate(const State &aInitState, double aDeltaTime,
107 : const Derivative &aDerivative)
108 : {
109 0 : State state( aInitState.p + aDerivative.dp*aDeltaTime, aInitState.v + aDerivative.dv*aDeltaTime );
110 :
111 0 : return Derivative( state.v, Acceleration(state) );
112 : }
113 :
114 : double
115 0 : AxisPhysicsModel::LinearInterpolate(double aV1, double aV2, double aBlend)
116 : {
117 0 : return aV1 * (1.0 - aBlend) + aV2 * aBlend;
118 : }
119 :
120 : } // namespace layers
121 : } // namespace mozilla
|