summaryrefslogtreecommitdiff
path: root/include/finger_metrics.h
blob: d5186412dacf8a22cece57004d484c82a5599400 (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
149
150
151
152
153
154
155
156
157
158
159
160
// 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.

#ifndef GESTURES_FINGER_METRICS_H_
#define GESTURES_FINGER_METRICS_H_

#include <cmath>

#include "include/gestures.h"
#include "include/prop_registry.h"
#include "include/vector.h"

namespace gestures {

static const size_t kMaxFingers = 10;
static const size_t kMaxGesturingFingers = 4;
static const size_t kMaxTapFingers = 10;

// A datastructure describing a 2D vector in the mathematical sense.
struct Vector2 {
  Vector2() : x(0), y(0) {}
  Vector2(float x, float y) : x(x), y(y) {}
  Vector2(const Vector2& other) : x(other.x), y(other.y) {}
  explicit Vector2(const FingerState& state) : x(state.position_x),
                                               y(state.position_y) {}

  Vector2 Sub(const Vector2& other) {
    return Vector2(x - other.x, y - other.y);
  }

  Vector2 Add(const Vector2& other) {
    return Vector2(x + other.x, y + other.y);
  }

  float MagSq() const {
    return x * x + y * y;
  }
  float Mag() const {
    return sqrtf(MagSq());
  }
  bool operator==(const Vector2& that) const {
    return x == that.x && y == that.y;
  }
  bool operator!=(const Vector2& that) const {
    return !(*this == that);
  }

  float x;
  float y;
};

extern Vector2 Add(const Vector2& left, const Vector2& right);
extern Vector2 Sub(const Vector2& left, const Vector2& right);
extern float Dot(const Vector2& left, const Vector2& right);

class MetricsProperties {
 public:
  explicit MetricsProperties(PropRegistry* prop_reg);

  // Maximum distance [mm] two fingers may be separated and still be eligible
  // for a two-finger gesture (e.g., scroll / tap / click). These define an
  // ellipse with horizontal and vertical axes lengths (think: radii).
  DoubleProperty two_finger_close_horizontal_distance_thresh;
  DoubleProperty two_finger_close_vertical_distance_thresh;
};

// This class describes a finger and derives additional metrics that
// are useful for gesture recognition.
// In contrast to a FingerState an instance of this class has the
// lifetime of the duration the finger touches the touchpad. This allows
// metrics to be derived from the history of a finger.
class FingerMetrics {
 public:
  FingerMetrics();
  explicit FingerMetrics(short tracking_id);
  FingerMetrics(const FingerState& state, stime_t timestamp);

  // Update the finger metrics from a FingerState.
  // gesture_start: true if fingers have been added or removed during this
  //                sync.
  void Update(const FingerState& state, stime_t timestamp,
              bool gesture_start);

  short tracking_id() const { return tracking_id_; }

  // current position
  Vector2 position() const { return position_; }

  // position delta between current and last frame
  Vector2 delta() const { return delta_; }

  // origin is the time and position where the finger first touched
  Vector2 origin_position() const { return origin_position_; }
  stime_t origin_time() const { return origin_time_; }
  Vector2 origin_delta() const { return Sub(position_, origin_position_); }

  // start is the time and postion where the fingers were located
  // when the last of all current fingers touched (i.e. the gesture started)
  Vector2 start_position() const { return start_position_; }
  stime_t start_time() const { return start_time_; }
  Vector2 start_delta() const { return Sub(position_, start_position_); }

  // instances with the same tracking id are considered equal.
  bool operator==(const FingerMetrics& other) const {
    return other.tracking_id() == tracking_id_;
  }

 private:
  short tracking_id_;
  Vector2 position_;
  Vector2 delta_;
  Vector2 origin_position_;
  Vector2 start_position_;
  stime_t origin_time_;
  stime_t start_time_;
};

// The Metrics class is a container for FingerMetrics and additional
// metrics that are based on the interaction of multiple fingers.
// It is responsible for keeping the FingerMetrics instances updated
// with the latest FingerStates.
class Metrics {
 public:
  Metrics(MetricsProperties* properties);

  bool CloseEnoughToGesture(const Vector2& pos_a,
                            const Vector2& pos_b) const;

  // A collection of FingerMetrics describing the current hardware state.
  // The collection is sorted to yield the oldest finger first.
  vector<FingerMetrics, kMaxFingers>& fingers() { return fingers_; }

  // Find a FingerMetrics instance by it's tracking id.
  // Returns nullptr if not found.
  FingerMetrics* GetFinger(short tracking_id) {
      return const_cast<FingerMetrics*>(
          const_cast<const Metrics*>(this)->GetFinger(tracking_id));
  }
  const FingerMetrics* GetFinger(short tracking_id) const;

  FingerMetrics* GetFinger(const FingerState& state);
  const FingerMetrics* GetFinger(const FingerState& state) const;

  // Update the collection of FingerMetrics using information from 'hwstate'.
  void Update(const HardwareState& hwstate);

  // Clear all finger information
  void Clear();

 private:
  vector<FingerMetrics, kMaxFingers> fingers_;

  MetricsProperties* properties_;
  std::unique_ptr<MetricsProperties> own_properties_;
};

}  // namespace gestures

#endif  // GESTURES_FINGER_METRICS_H_