1*aed3e508SAndroid Build Coastguard Worker // Copyright 2012 The ChromiumOS Authors
2*aed3e508SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*aed3e508SAndroid Build Coastguard Worker // found in the LICENSE file.
4*aed3e508SAndroid Build Coastguard Worker
5*aed3e508SAndroid Build Coastguard Worker #include "include/finger_metrics.h"
6*aed3e508SAndroid Build Coastguard Worker
7*aed3e508SAndroid Build Coastguard Worker namespace gestures {
8*aed3e508SAndroid Build Coastguard Worker
Add(const Vector2 & left,const Vector2 & right)9*aed3e508SAndroid Build Coastguard Worker Vector2 Add(const Vector2& left, const Vector2& right) {
10*aed3e508SAndroid Build Coastguard Worker return Vector2(left).Add(right);
11*aed3e508SAndroid Build Coastguard Worker }
12*aed3e508SAndroid Build Coastguard Worker
Sub(const Vector2 & left,const Vector2 & right)13*aed3e508SAndroid Build Coastguard Worker Vector2 Sub(const Vector2& left, const Vector2& right) {
14*aed3e508SAndroid Build Coastguard Worker return Vector2(left).Sub(right);
15*aed3e508SAndroid Build Coastguard Worker }
16*aed3e508SAndroid Build Coastguard Worker
Dot(const Vector2 & left,const Vector2 & right)17*aed3e508SAndroid Build Coastguard Worker float Dot(const Vector2& left, const Vector2& right) {
18*aed3e508SAndroid Build Coastguard Worker return left.x * right.x + left.y * right.y;
19*aed3e508SAndroid Build Coastguard Worker }
20*aed3e508SAndroid Build Coastguard Worker
MetricsProperties(PropRegistry * prop_reg)21*aed3e508SAndroid Build Coastguard Worker MetricsProperties::MetricsProperties(PropRegistry* prop_reg)
22*aed3e508SAndroid Build Coastguard Worker : two_finger_close_horizontal_distance_thresh(
23*aed3e508SAndroid Build Coastguard Worker prop_reg,
24*aed3e508SAndroid Build Coastguard Worker "Two Finger Horizontal Close Distance Thresh",
25*aed3e508SAndroid Build Coastguard Worker 50.0),
26*aed3e508SAndroid Build Coastguard Worker two_finger_close_vertical_distance_thresh(
27*aed3e508SAndroid Build Coastguard Worker prop_reg,
28*aed3e508SAndroid Build Coastguard Worker "Two Finger Vertical Close Distance Thresh",
29*aed3e508SAndroid Build Coastguard Worker 45.0) {}
30*aed3e508SAndroid Build Coastguard Worker
FingerMetrics()31*aed3e508SAndroid Build Coastguard Worker FingerMetrics::FingerMetrics()
32*aed3e508SAndroid Build Coastguard Worker : tracking_id_(-1) {}
33*aed3e508SAndroid Build Coastguard Worker
FingerMetrics(short tracking_id)34*aed3e508SAndroid Build Coastguard Worker FingerMetrics::FingerMetrics(short tracking_id)
35*aed3e508SAndroid Build Coastguard Worker : tracking_id_(tracking_id) {}
36*aed3e508SAndroid Build Coastguard Worker
FingerMetrics(short tracking_id,stime_t timestamp)37*aed3e508SAndroid Build Coastguard Worker FingerMetrics::FingerMetrics(short tracking_id, stime_t timestamp)
38*aed3e508SAndroid Build Coastguard Worker : tracking_id_(tracking_id),
39*aed3e508SAndroid Build Coastguard Worker origin_time_(timestamp) {}
40*aed3e508SAndroid Build Coastguard Worker
FingerMetrics(const FingerState & state,stime_t timestamp)41*aed3e508SAndroid Build Coastguard Worker FingerMetrics::FingerMetrics(const FingerState& state,
42*aed3e508SAndroid Build Coastguard Worker stime_t timestamp)
43*aed3e508SAndroid Build Coastguard Worker : tracking_id_(state.tracking_id),
44*aed3e508SAndroid Build Coastguard Worker position_(state.position_x, state.position_y),
45*aed3e508SAndroid Build Coastguard Worker origin_position_(state.position_x, state.position_y),
46*aed3e508SAndroid Build Coastguard Worker origin_time_(timestamp) {}
47*aed3e508SAndroid Build Coastguard Worker
Update(const FingerState & state,stime_t timestamp,bool gesture_start)48*aed3e508SAndroid Build Coastguard Worker void FingerMetrics::Update(const FingerState& state, stime_t timestamp,
49*aed3e508SAndroid Build Coastguard Worker bool gesture_start) {
50*aed3e508SAndroid Build Coastguard Worker Vector2 new_position = Vector2(state.position_x, state.position_y);
51*aed3e508SAndroid Build Coastguard Worker delta_ = Sub(new_position, position_);
52*aed3e508SAndroid Build Coastguard Worker position_ = new_position;
53*aed3e508SAndroid Build Coastguard Worker
54*aed3e508SAndroid Build Coastguard Worker if (gesture_start) {
55*aed3e508SAndroid Build Coastguard Worker start_position_ = position_;
56*aed3e508SAndroid Build Coastguard Worker start_time_ = timestamp;
57*aed3e508SAndroid Build Coastguard Worker }
58*aed3e508SAndroid Build Coastguard Worker }
59*aed3e508SAndroid Build Coastguard Worker
CloseEnoughToGesture(const Vector2 & pos_a,const Vector2 & pos_b) const60*aed3e508SAndroid Build Coastguard Worker bool Metrics::CloseEnoughToGesture(const Vector2& pos_a,
61*aed3e508SAndroid Build Coastguard Worker const Vector2& pos_b) const {
62*aed3e508SAndroid Build Coastguard Worker float horiz_axis_sq =
63*aed3e508SAndroid Build Coastguard Worker properties_->two_finger_close_horizontal_distance_thresh.val_ *
64*aed3e508SAndroid Build Coastguard Worker properties_->two_finger_close_horizontal_distance_thresh.val_;
65*aed3e508SAndroid Build Coastguard Worker float vert_axis_sq =
66*aed3e508SAndroid Build Coastguard Worker properties_->two_finger_close_vertical_distance_thresh.val_ *
67*aed3e508SAndroid Build Coastguard Worker properties_->two_finger_close_vertical_distance_thresh.val_;
68*aed3e508SAndroid Build Coastguard Worker Vector2 delta = Sub(pos_a, pos_b);
69*aed3e508SAndroid Build Coastguard Worker // Equation of ellipse:
70*aed3e508SAndroid Build Coastguard Worker // ,.--+--..
71*aed3e508SAndroid Build Coastguard Worker // ,' V| `. x^2 y^2
72*aed3e508SAndroid Build Coastguard Worker // | +------| --- + --- < 1
73*aed3e508SAndroid Build Coastguard Worker // \ H / H^2 V^2
74*aed3e508SAndroid Build Coastguard Worker // `-..__,,.-'
75*aed3e508SAndroid Build Coastguard Worker return vert_axis_sq * delta.x * delta.x + horiz_axis_sq * delta.y * delta.y
76*aed3e508SAndroid Build Coastguard Worker < vert_axis_sq * horiz_axis_sq;
77*aed3e508SAndroid Build Coastguard Worker }
78*aed3e508SAndroid Build Coastguard Worker
Metrics(MetricsProperties * properties)79*aed3e508SAndroid Build Coastguard Worker Metrics::Metrics(MetricsProperties* properties) : properties_(properties) {
80*aed3e508SAndroid Build Coastguard Worker fingers_.reserve(kMaxFingers);
81*aed3e508SAndroid Build Coastguard Worker }
82*aed3e508SAndroid Build Coastguard Worker
GetFinger(short tracking_id) const83*aed3e508SAndroid Build Coastguard Worker const FingerMetrics* Metrics::GetFinger(short tracking_id) const {
84*aed3e508SAndroid Build Coastguard Worker for (auto iter = fingers_.cbegin(); iter != fingers_.cend(); ++iter) {
85*aed3e508SAndroid Build Coastguard Worker if(iter->tracking_id() == tracking_id) {
86*aed3e508SAndroid Build Coastguard Worker return &(*iter);
87*aed3e508SAndroid Build Coastguard Worker }
88*aed3e508SAndroid Build Coastguard Worker }
89*aed3e508SAndroid Build Coastguard Worker return nullptr;
90*aed3e508SAndroid Build Coastguard Worker }
91*aed3e508SAndroid Build Coastguard Worker
GetFinger(const FingerState & state) const92*aed3e508SAndroid Build Coastguard Worker const FingerMetrics* Metrics::GetFinger(const FingerState& state) const {
93*aed3e508SAndroid Build Coastguard Worker return GetFinger(state.tracking_id);
94*aed3e508SAndroid Build Coastguard Worker }
95*aed3e508SAndroid Build Coastguard Worker
Update(const HardwareState & hwstate)96*aed3e508SAndroid Build Coastguard Worker void Metrics::Update(const HardwareState& hwstate) {
97*aed3e508SAndroid Build Coastguard Worker int previous_count = fingers_.size();
98*aed3e508SAndroid Build Coastguard Worker int existing_count = 0;
99*aed3e508SAndroid Build Coastguard Worker int new_count = 0;
100*aed3e508SAndroid Build Coastguard Worker
101*aed3e508SAndroid Build Coastguard Worker // create metrics for new fingers
102*aed3e508SAndroid Build Coastguard Worker for (int i=0; i<hwstate.finger_cnt; ++i) {
103*aed3e508SAndroid Build Coastguard Worker const FingerState& state = hwstate.fingers[i];
104*aed3e508SAndroid Build Coastguard Worker if (GetFinger(state.tracking_id) == nullptr) {
105*aed3e508SAndroid Build Coastguard Worker fingers_.push_back(FingerMetrics(state,
106*aed3e508SAndroid Build Coastguard Worker hwstate.timestamp));
107*aed3e508SAndroid Build Coastguard Worker ++new_count;
108*aed3e508SAndroid Build Coastguard Worker } else {
109*aed3e508SAndroid Build Coastguard Worker ++existing_count;
110*aed3e508SAndroid Build Coastguard Worker }
111*aed3e508SAndroid Build Coastguard Worker }
112*aed3e508SAndroid Build Coastguard Worker
113*aed3e508SAndroid Build Coastguard Worker // remove metrics for lifted fingers
114*aed3e508SAndroid Build Coastguard Worker if (existing_count != previous_count) {
115*aed3e508SAndroid Build Coastguard Worker auto iter = fingers_.begin();
116*aed3e508SAndroid Build Coastguard Worker while (iter != fingers_.end()) {
117*aed3e508SAndroid Build Coastguard Worker if (!hwstate.GetFingerState(iter->tracking_id()))
118*aed3e508SAndroid Build Coastguard Worker iter = fingers_.erase(iter);
119*aed3e508SAndroid Build Coastguard Worker else
120*aed3e508SAndroid Build Coastguard Worker ++iter;
121*aed3e508SAndroid Build Coastguard Worker }
122*aed3e508SAndroid Build Coastguard Worker }
123*aed3e508SAndroid Build Coastguard Worker
124*aed3e508SAndroid Build Coastguard Worker // when a new finger has been added or a finger has been removed
125*aed3e508SAndroid Build Coastguard Worker // we consider this to be a new gesture starting
126*aed3e508SAndroid Build Coastguard Worker bool gesture_start = (existing_count != previous_count) || new_count > 0;
127*aed3e508SAndroid Build Coastguard Worker for (FingerMetrics& finger: fingers_) {
128*aed3e508SAndroid Build Coastguard Worker const FingerState* fs = hwstate.GetFingerState(finger.tracking_id());
129*aed3e508SAndroid Build Coastguard Worker if (!fs) {
130*aed3e508SAndroid Build Coastguard Worker Err("Unexpected missing finger state!");
131*aed3e508SAndroid Build Coastguard Worker continue;
132*aed3e508SAndroid Build Coastguard Worker }
133*aed3e508SAndroid Build Coastguard Worker finger.Update(*fs, hwstate.timestamp, gesture_start);
134*aed3e508SAndroid Build Coastguard Worker }
135*aed3e508SAndroid Build Coastguard Worker }
136*aed3e508SAndroid Build Coastguard Worker
Clear()137*aed3e508SAndroid Build Coastguard Worker void Metrics::Clear() {
138*aed3e508SAndroid Build Coastguard Worker fingers_.clear();
139*aed3e508SAndroid Build Coastguard Worker }
140*aed3e508SAndroid Build Coastguard Worker
SetFingerOriginTimestampForTesting(short tracking_id,stime_t time)141*aed3e508SAndroid Build Coastguard Worker void Metrics::SetFingerOriginTimestampForTesting(short tracking_id,
142*aed3e508SAndroid Build Coastguard Worker stime_t time) {
143*aed3e508SAndroid Build Coastguard Worker for (auto iter = fingers_.begin(); iter != fingers_.end(); ++iter) {
144*aed3e508SAndroid Build Coastguard Worker if(iter->tracking_id() == tracking_id) {
145*aed3e508SAndroid Build Coastguard Worker fingers_.erase(iter);
146*aed3e508SAndroid Build Coastguard Worker break;
147*aed3e508SAndroid Build Coastguard Worker }
148*aed3e508SAndroid Build Coastguard Worker }
149*aed3e508SAndroid Build Coastguard Worker fingers_.push_back(FingerMetrics(tracking_id, time));
150*aed3e508SAndroid Build Coastguard Worker }
151*aed3e508SAndroid Build Coastguard Worker
152*aed3e508SAndroid Build Coastguard Worker } // namespace gestures
153