| // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "touch_noise_filter/single_position_filter.h" |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdio> |
| |
| #include <base/basictypes.h> |
| |
| namespace touch_noise_filter { |
| |
| namespace { |
| |
| // Max squared distance between fingers to be considered in the same position. |
| __s32 kMaxDistance2 = 2 * 2; |
| |
| // Max squared movement of a finger before it's no longer considered noise. |
| __s32 kMaxMovement2 = 2 * 2; |
| |
| // Min duration (s) after which a common position is considered noise. |
| double kMinDurationSecs = 2; |
| |
| // Max duration (s) to check for common positions with previous touches. |
| double kMaxDurationSecs = 4; |
| |
| // Returns the squared distance between (x1, y1) and (x2, y2). |
| __s32 Distance2(__s32 x1, __s32 y1, __s32 x2, __s32 y2) { |
| return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); |
| } |
| |
| } // namespace {} |
| |
| SinglePositionFilter::SinglePositionFilter() |
| : touches_start_(0), touches_end_(0) { |
| for (size_t i = 0; i < TOUCH_NOISE_MAX_SLOTS; i++) |
| tracked_slots_[i] = SINGLE_POSITION_MAX_TOUCHES; |
| } |
| |
| void SinglePositionFilter::FilterFrame(Frame* previous, Frame* current, |
| size_t num_slots) { |
| // Forget old touches which will no longer be considered for overlap. |
| double touch_cutoff = current->timestamp_ - kMaxDurationSecs; |
| for (size_t i = touches_start_; i != touches_end_; |
| i = (i + 1) % SINGLE_POSITION_MAX_TOUCHES) { |
| if (tracked_touches_[i].tracking_id_ == -1) |
| continue; |
| if (tracked_touches_[i].end_ < touch_cutoff) |
| StopTrackingTouch(i); |
| } |
| |
| for (size_t slot = 0; slot < num_slots; slot++) { |
| Finger* cur = ¤t->fingers_[slot]; |
| Finger* prev = &previous->fingers_[slot]; |
| |
| bool arrived = prev->tracking_id_ == -1 && cur->tracking_id_ >= 0; |
| bool departed = prev->tracking_id_ >= 0 && cur->tracking_id_ == -1; |
| if (departed) |
| tracked_slots_[slot] = SINGLE_POSITION_MAX_TOUCHES; |
| if (cur->tracking_id_ == -1) |
| continue; |
| |
| // Track all new touches until they move too far. |
| if (arrived) |
| TrackTouch(slot, current); |
| |
| size_t t_ind = tracked_slots_[slot]; |
| if (t_ind != SINGLE_POSITION_MAX_TOUCHES) { |
| tracked_touches_[t_ind].end_ = current->timestamp_; |
| // Stop tracking if touch moves more than sqrt(kMaxMovement2). |
| if (Distance2(cur->x_pos_, cur->y_pos_, |
| tracked_touches_[t_ind].x_pos_, |
| tracked_touches_[t_ind].y_pos_) > |
| kMaxMovement2) { |
| StopTrackingTouch(t_ind); |
| } else { |
| // Determine duration over which touches have been occuring in this |
| // position. |
| double duration = 0; |
| for (size_t i = touches_start_; i != touches_end_; |
| i = (i + 1) % SINGLE_POSITION_MAX_TOUCHES) { |
| if (tracked_touches_[i].tracking_id_ == -1) |
| continue; |
| if (Distance2(cur->x_pos_, cur->y_pos_, |
| tracked_touches_[i].x_pos_, |
| tracked_touches_[i].y_pos_) <= |
| kMaxDistance2) |
| duration = std::max( |
| duration, current->timestamp_ - tracked_touches_[i].begin_); |
| } |
| |
| if (duration > kMinDurationSecs) { |
| Log("Cancel tracking id %d, in position occurring for %fs", |
| cur->tracking_id_, duration); |
| cur->canceled_ = true; |
| } |
| } |
| } |
| } |
| } |
| |
| void SinglePositionFilter::StopTrackingTouch(size_t index) { |
| size_t slot = tracked_touches_[index].slot_; |
| if (tracked_slots_[slot] == index) |
| tracked_slots_[slot] = SINGLE_POSITION_MAX_TOUCHES; |
| tracked_touches_[index].tracking_id_ = -1; |
| |
| // If first touch is canceled, remove all dead touches. |
| if (index == touches_start_) { |
| while (tracked_touches_[touches_start_].tracking_id_ == -1 && |
| touches_start_ != touches_end_) |
| touches_start_ = (touches_start_ + 1) % SINGLE_POSITION_MAX_TOUCHES; |
| } |
| } |
| |
| bool SinglePositionFilter::TrackTouch(size_t slot, Frame* frame) { |
| size_t index = touches_end_; |
| touches_end_ = (touches_end_ + 1) % SINGLE_POSITION_MAX_TOUCHES; |
| // If we would reach the start touch index, we cannot track any more touches. |
| if (touches_end_ == touches_start_) { |
| touches_end_ = index; |
| return false; |
| } |
| |
| tracked_touches_[index].x_pos_ = frame->fingers_[slot].x_pos_; |
| tracked_touches_[index].y_pos_ = frame->fingers_[slot].y_pos_; |
| tracked_touches_[index].begin_ = frame->timestamp_; |
| tracked_touches_[index].end_ = frame->timestamp_; |
| tracked_touches_[index].slot_ = slot; |
| tracked_touches_[index].tracking_id_ = frame->fingers_[slot].tracking_id_; |
| tracked_slots_[slot] = index; |
| return true; |
| } |
| |
| } // namespace touch_noise_filter |