xref: /aosp_15_r20/external/libchrome-gestures/src/split_correcting_filter_interpreter.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
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