• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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