Merge "Implement an integrating VelocityTracker strategy." into jb-dev

This commit is contained in:
Jeff Brown
2012-06-03 21:16:38 -07:00
committed by Android (Google) Code Review
2 changed files with 137 additions and 0 deletions

View File

@@ -172,6 +172,39 @@ private:
Movement mMovements[HISTORY_SIZE];
};
/*
* Velocity tracker algorithm that uses an IIR filter.
*/
class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
public:
IntegratingVelocityTrackerStrategy();
~IntegratingVelocityTrackerStrategy();
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
const VelocityTracker::Position* positions);
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
// Current state estimate for a particular pointer.
struct State {
nsecs_t updateTime;
bool first;
float xpos, xvel;
float ypos, yvel;
};
BitSet32 mPointerIdBits;
State mPointerState[MAX_POINTER_ID + 1];
static void initState(State& state, nsecs_t eventTime, float xpos, float ypos);
static void updateState(State& state, nsecs_t eventTime, float xpos, float ypos);
static void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator);
};
} // namespace android
#endif // _ANDROIDFW_VELOCITY_TRACKER_H

View File

@@ -161,6 +161,14 @@ VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
// of the velocity when the finger is released.
return new LeastSquaresVelocityTrackerStrategy(3);
}
if (!strcmp("int1", strategy)) {
// 1st order integrating filter. Quality: GOOD.
// Not as good as 'lsq2' because it cannot estimate acceleration but it is
// more tolerant of errors. Like 'lsq1', this strategy tends to underestimate
// the velocity of a fling but this strategy tends to respond to changes in
// direction more quickly and accurately.
return new IntegratingVelocityTrackerStrategy();
}
return NULL;
}
@@ -564,4 +572,100 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
return true;
}
// --- IntegratingVelocityTrackerStrategy ---
IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy() {
}
IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
}
void IntegratingVelocityTrackerStrategy::clear() {
mPointerIdBits.clear();
}
void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
mPointerIdBits.value &= ~idBits.value;
}
void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
const VelocityTracker::Position* positions) {
uint32_t index = 0;
for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
uint32_t id = iterIdBits.clearFirstMarkedBit();
State& state = mPointerState[id];
const VelocityTracker::Position& position = positions[index++];
if (mPointerIdBits.hasBit(id)) {
updateState(state, eventTime, position.x, position.y);
} else {
initState(state, eventTime, position.x, position.y);
}
}
mPointerIdBits = idBits;
}
bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id,
VelocityTracker::Estimator* outEstimator) const {
outEstimator->clear();
if (mPointerIdBits.hasBit(id)) {
const State& state = mPointerState[id];
populateEstimator(state, outEstimator);
return true;
}
return false;
}
void IntegratingVelocityTrackerStrategy::initState(State& state,
nsecs_t eventTime, float xpos, float ypos) {
state.updateTime = eventTime;
state.first = true;
state.xpos = xpos;
state.xvel = 0;
state.ypos = ypos;
state.yvel = 0;
}
void IntegratingVelocityTrackerStrategy::updateState(State& state,
nsecs_t eventTime, float xpos, float ypos) {
const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
if (eventTime <= state.updateTime + MIN_TIME_DELTA) {
return;
}
float dt = (eventTime - state.updateTime) * 0.000000001f;
state.updateTime = eventTime;
float xvel = (xpos - state.xpos) / dt;
float yvel = (ypos - state.ypos) / dt;
if (state.first) {
state.xvel = xvel;
state.yvel = yvel;
state.first = false;
} else {
float alpha = dt / (FILTER_TIME_CONSTANT + dt);
state.xvel += (xvel - state.xvel) * alpha;
state.yvel += (yvel - state.yvel) * alpha;
}
state.xpos = xpos;
state.ypos = ypos;
}
void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
VelocityTracker::Estimator* outEstimator) {
outEstimator->time = state.updateTime;
outEstimator->degree = 1;
outEstimator->confidence = 1.0f;
outEstimator->xCoeff[0] = state.xpos;
outEstimator->xCoeff[1] = state.xvel;
outEstimator->yCoeff[0] = state.ypos;
outEstimator->yCoeff[1] = state.yvel;
}
} // namespace android