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/split_correcting_filter_interpreter.h"
6
7 #include <math.h>
8
9 #include "include/tracer.h"
10 #include "include/util.h"
11
12 namespace gestures {
13
14 // Takes ownership of |next|:
SplitCorrectingFilterInterpreter(PropRegistry * prop_reg,Interpreter * next,Tracer * tracer)15 SplitCorrectingFilterInterpreter::SplitCorrectingFilterInterpreter(
16 PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
17 : FilterInterpreter(nullptr, next, tracer, false),
18 enabled_(prop_reg, "Split Corrector Enabled", false),
19 merge_max_separation_(prop_reg, "Split Merge Max Separation", 17.0),
20 merge_max_movement_(prop_reg, "Split Merge Max Movement", 3.0),
21 merge_max_ratio_(prop_reg, "Merge Max Ratio", sinf(DegToRad(19.0))) {
22 InitName();
23 }
24
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)25 void SplitCorrectingFilterInterpreter::SyncInterpretImpl(
26 HardwareState& hwstate,
27 stime_t* timeout) {
28 const char name[] = "SplitCorrectingFilterInterpreter::SyncInterpretImpl";
29 LogHardwareStatePre(name, hwstate);
30
31 // Update internal state
32 if (enabled_.val_) {
33 RemoveMissingUnmergedContacts(hwstate);
34 MergeFingers(hwstate);
35 UnmergeFingers(hwstate);
36 UpdateUnmergedLocations(hwstate);
37 SetLastTrackingIds(hwstate);
38
39 // Use internal state to update hwstate
40 UpdateHwState(hwstate);
41 }
42 LogHardwareStatePost(name, hwstate);
43 next_->SyncInterpret(hwstate, timeout);
44 }
45
RemoveMissingUnmergedContacts(const HardwareState & hwstate)46 void SplitCorrectingFilterInterpreter::RemoveMissingUnmergedContacts(
47 const HardwareState& hwstate) {
48 for (UnmergedContact* it = unmerged_;
49 it < &unmerged_[arraysize(unmerged_)] &&
50 it->Valid();) {
51 if (!hwstate.GetFingerState(it->input_id)) {
52 // Erase this element
53 std::copy(it + 1, &unmerged_[arraysize(unmerged_)], it);
54 unmerged_[arraysize(unmerged_) - 1].Invalidate();
55 } else {
56 ++it;
57 }
58 }
59 }
60
MergeFingers(const HardwareState & hwstate)61 void SplitCorrectingFilterInterpreter::MergeFingers(
62 const HardwareState& hwstate) {
63 std::set<const FingerState*> unused;
64 for (size_t i = 0; i < hwstate.finger_cnt; i++) {
65 if (!SetContainsValue(last_tracking_ids_, hwstate.fingers[i].tracking_id))
66 unused.insert(&hwstate.fingers[i]);
67 }
68 if (unused.empty())
69 return;
70 for (UnmergedContact* it = unmerged_; it->Valid();) {
71 // Current state of the unmerged finger
72 const FingerState* existing_contact = hwstate.GetFingerState(it->input_id);
73 if (!existing_contact) {
74 Err("How is existing_contact null?");
75 return;
76 }
77 // try all fingers for possible merging
78 float min_error = INFINITY;
79 std::set<const FingerState*>::iterator min_error_it = unused.end();
80 for (std::set<const FingerState*>::iterator unused_it =
81 unused.begin(), e = unused.end(); unused_it != e; ++unused_it) {
82 const FingerState* new_contact = *unused_it;
83 if (new_contact == existing_contact)
84 continue;
85 float error = AreMergePair(*existing_contact, *new_contact, *it);
86 if (error < 0)
87 continue;
88 if (error < min_error) {
89 min_error = error;
90 min_error_it = unused_it;
91 }
92 }
93 if (min_error_it != unused.end()) {
94 // we have a merge!
95 AppendMergedContact(*existing_contact, *(*min_error_it), it->output_id);
96 unused.erase(min_error_it);
97 // Delete this UnmergedContact
98 std::copy(it + 1, &unmerged_[arraysize(unmerged_)], it);
99 unmerged_[arraysize(unmerged_) - 1].Invalidate();
100 continue;
101 }
102 it++;
103 }
104 if (unused.empty())
105 return;
106 // Put the unused new fingers into the unmerged fingers
107 // Find next slot
108 UnmergedContact* it = unmerged_;
109 for (; it->Valid() && it != &unmerged_[kMaxFingers]; ++it) {}
110 for (std::set<const FingerState*>::iterator unused_it =
111 unused.begin(), e = unused.end(); unused_it != e; ++unused_it) {
112 if (it == &unmerged_[kMaxFingers]) {
113 Err("How is there no space?");
114 return;
115 }
116 const FingerState& fs = *(*unused_it);
117 it->input_id = it->output_id = fs.tracking_id;
118 it->position_x = fs.position_x;
119 it->position_y = fs.position_y;
120 it++;
121 }
122 }
123
AppendMergedContact(const FingerState & input_a,const FingerState & input_b,short output_id)124 void SplitCorrectingFilterInterpreter::AppendMergedContact(
125 const FingerState& input_a,
126 const FingerState& input_b,
127 short output_id) {
128 for (size_t i = 0; i < arraysize(merged_); i++) {
129 if (merged_[i].Valid())
130 continue;
131 merged_[i].input_fingers[0] = input_a;
132 merged_[i].input_fingers[1] = input_b;
133 merged_[i].output_id = output_id;
134 return;
135 }
136 Err("No free merged contact?");
137 return;
138 }
139
AppendUnmergedContact(const FingerState & fs,short output_id)140 void SplitCorrectingFilterInterpreter::AppendUnmergedContact(
141 const FingerState& fs, short output_id) {
142 for (size_t i = 0; i < arraysize(unmerged_); i++) {
143 if (unmerged_[i].Valid())
144 continue;
145 unmerged_[i].input_id = fs.tracking_id;
146 unmerged_[i].output_id = output_id;
147 unmerged_[i].position_x = fs.position_x;
148 unmerged_[i].position_y = fs.position_y;
149 return;
150 }
151 Err("No free unmerged contact?");
152 }
153
AreMergePair(const FingerState & existing_contact,const FingerState & new_contact,const UnmergedContact & merge_recipient) const154 float SplitCorrectingFilterInterpreter::AreMergePair(
155 const FingerState& existing_contact,
156 const FingerState& new_contact,
157 const UnmergedContact& merge_recipient) const {
158 // Is it close enough to the old contact?
159 const float kMaxSepSq =
160 merge_max_separation_.val_ * merge_max_separation_.val_;
161 float sep_sq = DistSq(new_contact, existing_contact);
162 if (sep_sq > kMaxSepSq) {
163 return -1;
164 }
165 // Does this new contact help?
166 float existing_move_sq = DistSq(merge_recipient, existing_contact);
167 float mid_x = (new_contact.position_x + existing_contact.position_x) * 0.5;
168 float mid_y = (new_contact.position_y + existing_contact.position_y) * 0.5;
169 float old_to_mid_dist_sq = DistSqXY(merge_recipient, mid_x, mid_y);
170 if (old_to_mid_dist_sq < existing_move_sq)
171 return old_to_mid_dist_sq; // Return new distance; definite improvement
172
173 // Check if the merge recipient is too far from new_contact
174 float current_dist_sq = DistSq(existing_contact, new_contact);
175 float new_to_reicpient_sq = DistSq(merge_recipient, new_contact);
176 if (current_dist_sq < new_to_reicpient_sq)
177 return -1;
178
179 // Check if the new contact is, more or less, "along the line" from
180 // existing contact through merge_recipient, and beyond.
181
182 // Distance_sq from new_contact to the line that goes through merge_recipient
183 // and existing_contact.
184 const float orthogonal_dist_sq =
185 DistSqFromPointToLine(merge_recipient.position_x,
186 merge_recipient.position_y,
187 existing_contact.position_x,
188 existing_contact.position_y,
189 new_contact.position_x,
190 new_contact.position_y);
191
192 // Imagine a right-triangle like so:
193 // /|(new point)
194 // / | <== orthogonal_dist
195 // (existing_contact)/__m___|(right angle)
196 // ^^^^^ line between existing_contact and merge_recipient
197 // m = merge_recipient point.
198 // We compute the maximum ratio of orthogonal_dist / hypotenuse length
199
200 if (orthogonal_dist_sq <
201 merge_max_ratio_.val_ * merge_max_ratio_.val_ * current_dist_sq)
202 return old_to_mid_dist_sq; // merge!
203
204 return -1; // no merge
205 }
206
207 // static
DistSqFromPointToLine(float line_x_0,float line_y_0,float line_x_1,float line_y_1,float point_x,float point_y)208 float SplitCorrectingFilterInterpreter::DistSqFromPointToLine(float line_x_0,
209 float line_y_0,
210 float line_x_1,
211 float line_y_1,
212 float point_x,
213 float point_y) {
214 // Find general form (A*x + B*y + C = 0) of a line given two points.
215 float line_a = line_y_0 - line_y_1;
216 float line_b = line_x_1 - line_x_0;
217 float line_c = line_x_0 * line_y_1 - line_y_0 * line_x_1;
218 // Compute min distance from line to point_(x,y)
219 float num = line_a * point_x + line_b * point_y + line_c;
220 float den_sq = line_a * line_a + line_b * line_b;
221 if (den_sq == 0.0)
222 return 0.0; // don't crash
223 return num * num / den_sq;
224 }
225
UnmergeFingers(const HardwareState & hwstate)226 void SplitCorrectingFilterInterpreter::UnmergeFingers(
227 const HardwareState& hwstate) {
228 const float kMaxSepSq =
229 merge_max_separation_.val_ * merge_max_separation_.val_;
230 const float kMaxMoveSq =
231 merge_max_movement_.val_ * merge_max_movement_.val_;
232 for (size_t i = 0; i < arraysize(merged_);) {
233 MergedContact* mc = &merged_[i];
234 if (!mc->Valid())
235 break;
236 const FingerState* first =
237 hwstate.GetFingerState(mc->input_fingers[0].tracking_id);
238 const FingerState* second =
239 hwstate.GetFingerState(mc->input_fingers[1].tracking_id);
240 if (first && second && DistSq(*first, *second) <= kMaxSepSq &&
241 DistSq(*first, mc->input_fingers[0]) < kMaxMoveSq &&
242 DistSq(*second, mc->input_fingers[1]) < kMaxMoveSq) {
243 i++;
244 continue;
245 }
246 if (first)
247 AppendUnmergedContact(*first, mc->output_id);
248 if (second)
249 // For no good reason, if we have both first and second, we give
250 // first the output id, thus it takes over for the merged finger
251 AppendUnmergedContact(*second,
252 first ? second->tracking_id : mc->output_id);
253 // Delete this element
254 std::copy(&merged_[i + 1], &merged_[arraysize(merged_)], &merged_[i]);
255 merged_[arraysize(merged_) - 1].Invalidate();
256 }
257 }
258
UpdateHwState(HardwareState & hwstate) const259 void SplitCorrectingFilterInterpreter::UpdateHwState(
260 HardwareState& hwstate) const {
261 for (size_t i = 0; i < hwstate.finger_cnt; i++) {
262 FingerState* fs = &hwstate.fingers[i];
263 const UnmergedContact* unmerged = FindUnmerged(fs->tracking_id);
264 if (unmerged && unmerged->Valid()) {
265 // Easier case. Just update tracking id
266 fs->tracking_id = unmerged->output_id;
267 continue;
268 }
269 const MergedContact* merged = FindMerged(fs->tracking_id);
270 if (merged && merged->Valid()) {
271 short other_id = merged->input_fingers[0].tracking_id != fs->tracking_id ?
272 merged->input_fingers[0].tracking_id :
273 merged->input_fingers[1].tracking_id;
274 FingerState* other_fs = hwstate.GetFingerState(other_id);
275 if (!other_fs) {
276 Err("Missing other finger state?");
277 return;
278 }
279 JoinFingerState(fs, *other_fs);
280 fs->tracking_id = merged->output_id;
281 RemoveFingerStateFromHardwareState(hwstate, other_fs);
282 continue;
283 }
284 Err("Neither unmerged nor merged?");
285 return;
286 }
287 hwstate.touch_cnt = hwstate.finger_cnt;
288 }
289
FindUnmerged(short input_id) const290 const UnmergedContact* SplitCorrectingFilterInterpreter::FindUnmerged(
291 short input_id) const {
292 for (size_t i = 0; i < arraysize(unmerged_) && unmerged_[i].Valid(); i++)
293 if (unmerged_[i].input_id == input_id)
294 return &unmerged_[i];
295 return nullptr;
296 }
297
FindMerged(short input_id) const298 const MergedContact* SplitCorrectingFilterInterpreter::FindMerged(
299 short input_id) const {
300 for (size_t i = 0; i < arraysize(merged_) && merged_[i].Valid(); i++)
301 if (merged_[i].input_fingers[0].tracking_id == input_id ||
302 merged_[i].input_fingers[1].tracking_id == input_id)
303 return &merged_[i];
304 return nullptr;
305 }
306
307 // static
JoinFingerState(FingerState * in_out,const FingerState & newfinger)308 void SplitCorrectingFilterInterpreter::JoinFingerState(
309 FingerState* in_out, const FingerState& newfinger) {
310 float FingerState::*fields[] = { &FingerState::touch_major,
311 &FingerState::touch_minor,
312 &FingerState::width_major,
313 &FingerState::width_minor,
314 &FingerState::pressure,
315 &FingerState::orientation,
316 &FingerState::position_x,
317 &FingerState::position_y };
318 for (size_t f_idx = 0; f_idx < arraysize(fields); f_idx++) {
319 float FingerState::*field = fields[f_idx];
320 in_out->*field = (in_out->*field + newfinger.*field) * 0.5;
321 }
322 in_out->flags |= newfinger.flags |
323 GESTURES_FINGER_WARP_X |
324 GESTURES_FINGER_WARP_Y;
325 }
326
327 // static
RemoveFingerStateFromHardwareState(HardwareState & hwstate,FingerState * fs)328 void SplitCorrectingFilterInterpreter::RemoveFingerStateFromHardwareState(
329 HardwareState& hwstate,
330 FingerState* fs) {
331 std::copy(fs + 1, &hwstate.fingers[hwstate.finger_cnt], fs);
332 hwstate.finger_cnt--;
333 }
334
SetLastTrackingIds(const HardwareState & hwstate)335 void SplitCorrectingFilterInterpreter::SetLastTrackingIds(
336 const HardwareState& hwstate) {
337 last_tracking_ids_.clear();
338 for (size_t i = 0; i < hwstate.finger_cnt; i++)
339 last_tracking_ids_.insert(hwstate.fingers[i].tracking_id);
340 }
341
UpdateUnmergedLocations(const HardwareState & hwstate)342 void SplitCorrectingFilterInterpreter::UpdateUnmergedLocations(
343 const HardwareState& hwstate) {
344 for (size_t i = 0; i < arraysize(unmerged_) && unmerged_[i].Valid(); i++) {
345 const FingerState* fs = hwstate.GetFingerState(unmerged_[i].input_id);
346 if (!fs) {
347 Err("Missing finger state?");
348 continue;
349 }
350 unmerged_[i].position_x = fs->position_x;
351 unmerged_[i].position_y = fs->position_y;
352 }
353 }
354
Dump(const HardwareState & hwstate) const355 void SplitCorrectingFilterInterpreter::Dump(
356 const HardwareState& hwstate) const {
357 Log("Last Tracking IDs:");
358 for (std::set<short>::const_iterator it = last_tracking_ids_.begin(),
359 e = last_tracking_ids_.end(); it != e; ++it)
360 Log(" %d", *it);
361 Log("Unmerged:");
362 for (size_t i = 0; i < arraysize(unmerged_); i++)
363 Log(" %sin: %d out: %d x: %f y: %f",
364 unmerged_[i].Valid() ? "" : "INV ",
365 unmerged_[i].input_id,
366 unmerged_[i].output_id,
367 unmerged_[i].position_x,
368 unmerged_[i].position_y);
369 Log("Merged:");
370 for (size_t i = 0; i < arraysize(merged_); i++)
371 Log(" %sin: %d in: %d out: %d",
372 merged_[i].Valid() ? "" : "INV ",
373 merged_[i].input_fingers[0].tracking_id,
374 merged_[i].input_fingers[1].tracking_id,
375 merged_[i].output_id);
376 Log("HW state IDs:");
377 for (size_t i = 0; i < hwstate.finger_cnt; i++)
378 Log(" %d", hwstate.fingers[i].tracking_id);
379 }
380
381 }; // namespace gestures
382