Unity 8
AxisVelocityCalculator.cpp
1 /*
2  * Copyright (C) 2013 - Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License, as
6  * published by the Free Software Foundation; either version 2.1 or 3.0
7  * of the License.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranties of
11  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12  * PURPOSE. See the applicable version of the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of both the GNU Lesser General Public
16  * License along with this program. If not, see <http://www.gnu.org/licenses/>
17  *
18  * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19  */
20 
21 #include "AxisVelocityCalculator.h"
22 #include <QtCore/QElapsedTimer>
23 
24 using namespace UbuntuGestures;
25 
26 AxisVelocityCalculator::AxisVelocityCalculator(QObject *parent)
27  : AxisVelocityCalculator(SharedTimeSource(new RealTimeSource), parent)
28 {
29 }
30 
31 AxisVelocityCalculator::AxisVelocityCalculator(const SharedTimeSource &timeSource,
32  QObject *parent)
33  : QObject(parent)
34  , m_timeSource(timeSource)
35  , m_trackedPosition(0.0)
36 {
37  reset();
38 }
39 
40 AxisVelocityCalculator::~AxisVelocityCalculator()
41 {
42 }
43 
44 qreal AxisVelocityCalculator::trackedPosition() const
45 {
46  return m_trackedPosition;
47 }
48 
49 void AxisVelocityCalculator::setTrackedPosition(qreal newPosition)
50 {
51  processMovement(newPosition - m_trackedPosition);
52 
53  if (newPosition != m_trackedPosition) {
54  m_trackedPosition = newPosition;
55  Q_EMIT trackedPositionChanged(newPosition);
56  }
57 }
58 
59 void AxisVelocityCalculator::updateIdleTime()
60 {
61  processMovement(0);
62 }
63 
64 void AxisVelocityCalculator::processMovement(qreal movement)
65 {
66  if (m_samplesRead == -1) {
67  m_samplesRead = m_samplesWrite;
68  } else if (m_samplesRead == m_samplesWrite) {
69  /* the oldest value is going to be overwritten.
70  so now the oldest will be the next one. */
71  m_samplesRead = (m_samplesRead + 1) % MAX_SAMPLES;
72  }
73 
74  m_samples[m_samplesWrite].mov = movement;
75  m_samples[m_samplesWrite].time = m_timeSource->msecsSinceReference();
76  m_samplesWrite = (m_samplesWrite + 1) % MAX_SAMPLES;
77 }
78 
79 qreal AxisVelocityCalculator::calculate()
80 {
81  if (numSamples() < MIN_SAMPLES_NEEDED) {
82  return 0.0;
83  }
84  updateIdleTime(); // consider the time elapsed since the last update and now
85 
86  int lastIndex;
87  if (m_samplesWrite == 0) {
88  lastIndex = MAX_SAMPLES - 1;
89  } else {
90  lastIndex = m_samplesWrite - 1;
91  }
92 
93  qint64 currTime = m_samples[lastIndex].time;
94 
95  qreal totalTime = 0;
96  qreal totalDistance = 0;
97 
98  int sampleIndex = (m_samplesRead + 1) % MAX_SAMPLES;
99  qint64 previousTime = m_samples[m_samplesRead].time;
100  while (sampleIndex != m_samplesWrite) {
101  // Skip this sample if it's too old
102  if (currTime - m_samples[sampleIndex].time <= AGE_OLDEST_SAMPLE) {
103  int deltaTime = m_samples[sampleIndex].time - previousTime;
104  totalDistance += m_samples[sampleIndex].mov;
105  totalTime += deltaTime;
106  }
107 
108  previousTime = m_samples[sampleIndex].time;
109  sampleIndex = (sampleIndex + 1) % MAX_SAMPLES;
110  }
111 
112  return totalDistance / totalTime;
113 }
114 
115 void AxisVelocityCalculator::reset()
116 {
117  m_samplesRead = -1;
118  m_samplesWrite = 0;
119 }
120 
121 int AxisVelocityCalculator::numSamples() const
122 {
123  if (m_samplesRead == -1) {
124  return 0;
125  } else {
126  if (m_samplesWrite == 0) {
127  /* consider only what's to the right of m_samplesRead (including himself) */
128  return MAX_SAMPLES - m_samplesRead;
129  } else if (m_samplesWrite == m_samplesRead) {
130  return MAX_SAMPLES; /* buffer is full */
131  } else if (m_samplesWrite < m_samplesRead) {
132  return (MAX_SAMPLES - m_samplesRead) + m_samplesWrite;
133  } else {
134  return m_samplesWrite - m_samplesRead;
135  }
136  }
137 }
138 
139 void AxisVelocityCalculator::setTimeSource(const SharedTimeSource &timeSource)
140 {
141  m_timeSource = timeSource;
142 
143  if (numSamples() > 0) {
144  qWarning("AxisVelocityCalculator: changing time source while there are samples present.");
145  // Any existent samples are based on the old time source and are, therefore, incompatible
146  // with this new one.
147  reset();
148  }
149 }