xref: /aosp_15_r20/external/libchrome-gestures/src/finger_metrics.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
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