@@ -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