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