Skip to content

Commit 1fbbc07

Browse files
Jeff BrownAndroid (Google) Code Review
authored andcommitted
Merge "Implement an integrating VelocityTracker strategy." into jb-dev
2 parents f47e76e + 53dd12a commit 1fbbc07

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)