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