summaryrefslogtreecommitdiff
path: root/src/finger_metrics.cc
blob: a79ea10aba6204bb7ec3dbb1db4ef91084e21803 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "include/finger_metrics.h"

namespace gestures {

Vector2 Add(const Vector2& left, const Vector2& right) {
  return Vector2(left).Add(right);
}

Vector2 Sub(const Vector2& left, const Vector2& right) {
  return Vector2(left).Sub(right);
}

float Dot(const Vector2& left, const Vector2& right) {
  return left.x * right.x +  left.y * right.y;
}

MetricsProperties::MetricsProperties(PropRegistry* prop_reg)
    : two_finger_close_horizontal_distance_thresh(
          prop_reg,
          "Two Finger Horizontal Close Distance Thresh",
          50.0),
      two_finger_close_vertical_distance_thresh(
          prop_reg,
          "Two Finger Vertical Close Distance Thresh",
          45.0) {}

FingerMetrics::FingerMetrics()
    : tracking_id_(-1) {}

FingerMetrics::FingerMetrics(short tracking_id)
    : tracking_id_(tracking_id) {}

FingerMetrics::FingerMetrics(short tracking_id, stime_t timestamp)
    : tracking_id_(tracking_id),
      origin_time_(timestamp) {}

FingerMetrics::FingerMetrics(const FingerState& state,
                             stime_t timestamp)
    : tracking_id_(state.tracking_id),
      position_(state.position_x, state.position_y),
      origin_position_(state.position_x, state.position_y),
      origin_time_(timestamp) {}

void FingerMetrics::Update(const FingerState& state, stime_t timestamp,
                           bool gesture_start) {
  Vector2 new_position = Vector2(state.position_x, state.position_y);
  delta_ = Sub(new_position, position_);
  position_ = new_position;

  if (gesture_start) {
    start_position_ = position_;
    start_time_ = timestamp;
  }
}

bool Metrics::CloseEnoughToGesture(const Vector2& pos_a,
                                   const Vector2& pos_b) const {
  float horiz_axis_sq =
      properties_->two_finger_close_horizontal_distance_thresh.val_ *
      properties_->two_finger_close_horizontal_distance_thresh.val_;
  float vert_axis_sq =
      properties_->two_finger_close_vertical_distance_thresh.val_ *
      properties_->two_finger_close_vertical_distance_thresh.val_;
  Vector2 delta = Sub(pos_a, pos_b);
  // Equation of ellipse:
  //    ,.--+--..
  //  ,'   V|    `.   x^2   y^2
  // |      +------|  --- + --- < 1
  //  \        H  /   H^2   V^2
  //   `-..__,,.-'
  return vert_axis_sq * delta.x * delta.x + horiz_axis_sq * delta.y * delta.y
         < vert_axis_sq * horiz_axis_sq;
}

Metrics::Metrics(MetricsProperties* properties) : properties_(properties) {}

const FingerMetrics* Metrics::GetFinger(short tracking_id) const {
  auto iter = fingers_.find(FingerMetrics(tracking_id));
  if (iter != fingers_.end())
    return iter;
  else
    return nullptr;
}

const FingerMetrics* Metrics::GetFinger(const FingerState& state) const {
  return GetFinger(state.tracking_id);
}

void Metrics::Update(const HardwareState& hwstate) {
  int previous_count = fingers_.size();
  int existing_count = 0;
  int new_count = 0;

  // create metrics for new fingers
  for (int i=0; i<hwstate.finger_cnt; ++i) {
    const FingerState& state = hwstate.fingers[i];
    auto iter = fingers_.find(FingerMetrics(state.tracking_id));
    if (iter == fingers_.end()) {
      fingers_.push_back(FingerMetrics(state,
                                       hwstate.timestamp));
      ++new_count;
    } else {
      ++existing_count;
    }
  }

  // remove metrics for lifted fingers
  if (existing_count != previous_count) {
    auto iter = fingers_.begin();
    while (iter != fingers_.end()) {
      if (!hwstate.GetFingerState(iter->tracking_id()))
        iter = fingers_.erase(iter);
      else
        ++iter;
    }
  }

  // when a new finger has been added or a finger has been removed
  // we consider this to be a new gesture starting
  bool gesture_start = (existing_count != previous_count) || new_count > 0;
  for (FingerMetrics& finger: fingers_) {
    const FingerState* fs = hwstate.GetFingerState(finger.tracking_id());
    if (!fs) {
      Err("Unexpected missing finger state!");
      continue;
    }
    finger.Update(*fs, hwstate.timestamp, gesture_start);
  }
}

void Metrics::Clear() {
  fingers_.clear();
}

void Metrics::SetFingerOriginTimestampForTesting(short tracking_id,
                                                 stime_t time) {
  if (auto iter = fingers_.find(FingerMetrics(tracking_id));
      iter != fingers_.end()) {
    fingers_.erase(iter);
  }
  fingers_.push_back(FingerMetrics(tracking_id, time));
}

}  // namespace gestures