Skip to content

Commit 53dd12a

Browse files
author
Jeff Brown
committed
Implement an integrating VelocityTracker strategy.
This algorithm better tolerates certain kinds of errors in the touch input than the least squares strategy but it may underestimate the velocity of accelerating movements. This algorithm is mainly of interest as a baseline for testing and comparison with the least squares algorithm, which remains the default. Bug: 6413587 Change-Id: I8ddb50084e44875e234717907e5b06d03f59788c
1 parent 9eb7d86 commit 53dd12a

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

include/androidfw/VelocityTracker.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,39 @@ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
172172
Movement mMovements[HISTORY_SIZE];
173173
};
174174

175+
176+
/*
177+
* Velocity tracker algorithm that uses an IIR filter.
178+
*/
179+
class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
180+
public:
181+
IntegratingVelocityTrackerStrategy();
182+
~IntegratingVelocityTrackerStrategy();
183+
184+
virtual void clear();
185+
virtual void clearPointers(BitSet32 idBits);
186+
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
187+
const VelocityTracker::Position* positions);
188+
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
189+
190+
private:
191+
// Current state estimate for a particular pointer.
192+
struct State {
193+
nsecs_t updateTime;
194+
bool first;
195+
196+
float xpos, xvel;
197+
float ypos, yvel;
198+
};
199+
200+
BitSet32 mPointerIdBits;
201+
State mPointerState[MAX_POINTER_ID + 1];
202+
203+
static void initState(State& state, nsecs_t eventTime, float xpos, float ypos);
204+
static void updateState(State& state, nsecs_t eventTime, float xpos, float ypos);
205+
static void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator);
206+
};
207+
175208
} // namespace android
176209

177210
#endif // _ANDROIDFW_VELOCITY_TRACKER_H

libs/androidfw/VelocityTracker.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,14 @@ VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
161161
// of the velocity when the finger is released.
162162
return new LeastSquaresVelocityTrackerStrategy(3);
163163
}
164+
if (!strcmp("int1", strategy)) {
165+
// 1st order integrating filter. Quality: GOOD.
166+
// Not as good as 'lsq2' because it cannot estimate acceleration but it is
167+
// more tolerant of errors. Like 'lsq1', this strategy tends to underestimate
168+
// the velocity of a fling but this strategy tends to respond to changes in
169+
// direction more quickly and accurately.
170+
return new IntegratingVelocityTrackerStrategy();
171+
}
164172
return NULL;
165173
}
166174

@@ -564,4 +572,100 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
564572
return true;
565573
}
566574

575+
576+
// --- IntegratingVelocityTrackerStrategy ---
577+
578+
IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy() {
579+
}
580+
581+
IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
582+
}
583+
584+
void IntegratingVelocityTrackerStrategy::clear() {
585+
mPointerIdBits.clear();
586+
}
587+
588+
void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
589+
mPointerIdBits.value &= ~idBits.value;
590+
}
591+
592+
void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
593+
const VelocityTracker::Position* positions) {
594+
uint32_t index = 0;
595+
for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
596+
uint32_t id = iterIdBits.clearFirstMarkedBit();
597+
State& state = mPointerState[id];
598+
const VelocityTracker::Position& position = positions[index++];
599+
if (mPointerIdBits.hasBit(id)) {
600+
updateState(state, eventTime, position.x, position.y);
601+
} else {
602+
initState(state, eventTime, position.x, position.y);
603+
}
604+
}
605+
606+
mPointerIdBits = idBits;
607+
}
608+
609+
bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id,
610+
VelocityTracker::Estimator* outEstimator) const {
611+
outEstimator->clear();
612+
613+
if (mPointerIdBits.hasBit(id)) {
614+
const State& state = mPointerState[id];
615+
populateEstimator(state, outEstimator);
616+
return true;
617+
}
618+
619+
return false;
620+
}
621+
622+
void IntegratingVelocityTrackerStrategy::initState(State& state,
623+
nsecs_t eventTime, float xpos, float ypos) {
624+
state.updateTime = eventTime;
625+
state.first = true;
626+
627+
state.xpos = xpos;
628+
state.xvel = 0;
629+
state.ypos = ypos;
630+
state.yvel = 0;
631+
}
632+
633+
void IntegratingVelocityTrackerStrategy::updateState(State& state,
634+
nsecs_t eventTime, float xpos, float ypos) {
635+
const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
636+
const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
637+
638+
if (eventTime <= state.updateTime + MIN_TIME_DELTA) {
639+
return;
640+
}
641+
642+
float dt = (eventTime - state.updateTime) * 0.000000001f;
643+
state.updateTime = eventTime;
644+
645+
float xvel = (xpos - state.xpos) / dt;
646+
float yvel = (ypos - state.ypos) / dt;
647+
if (state.first) {
648+
state.xvel = xvel;
649+
state.yvel = yvel;
650+
state.first = false;
651+
} else {
652+
float alpha = dt / (FILTER_TIME_CONSTANT + dt);
653+
state.xvel += (xvel - state.xvel) * alpha;
654+
state.yvel += (yvel - state.yvel) * alpha;
655+
}
656+
state.xpos = xpos;
657+
state.ypos = ypos;
658+
}
659+
660+
void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
661+
VelocityTracker::Estimator* outEstimator) {
662+
outEstimator->time = state.updateTime;
663+
outEstimator->degree = 1;
664+
outEstimator->confidence = 1.0f;
665+
outEstimator->xCoeff[0] = state.xpos;
666+
outEstimator->xCoeff[1] = state.xvel;
667+
outEstimator->yCoeff[0] = state.ypos;
668+
outEstimator->yCoeff[1] = state.yvel;
669+
}
670+
567671
} // namespace android

0 commit comments

Comments
 (0)