MythTV  master
mythgesture.cpp
Go to the documentation of this file.
1 /* -*- myth -*- */
29 #include "mythgesture.h"
30 
31 #include <array>
32 #include <cmath>
33 #include <algorithm>
34 #include <complex>
35 
36 #include <QMutex>
37 #include <QMap>
38 
39 QEvent::Type MythGestureEvent::kEventType =
40  (QEvent::Type) QEvent::registerEventType();
41 
42 // Force this class to have a vtable so that dynamic_cast works.
43 // NOLINTNEXTLINE(modernize-use-equals-default)
45 {
46 }
47 
53 
54 public:
55  QMutex m_m;
56  QMap <QString, MythGestureEvent::Gesture> m_sequences;
57 };
58 
59 
60 
61 /* comments in header */
62 MythGesture::MythGesture(size_t max_points, size_t min_points,
63  size_t max_sequence, size_t scale_ratio,
64  float bin_percent) :
65  m_maxPoints(max_points), m_minPoints(min_points), m_maxSequence(max_sequence),
66  m_scaleRatio(scale_ratio), m_binPercent(bin_percent)
67 {
68  /* default to an invalid event */
70 
71  /* create new private information */
72  p = new MythGesturePrivate();
73 
74  /* Click */
76 
77  /* Lines */
78  p->m_sequences.insert("456", MythGestureEvent::Right);
79  p->m_sequences.insert("654", MythGestureEvent::Left);
80  p->m_sequences.insert("258", MythGestureEvent::Down);
81  p->m_sequences.insert("852", MythGestureEvent::Up);
82 
83  /* Diagonals */
84  p->m_sequences.insert("951", MythGestureEvent::UpLeft);
85  p->m_sequences.insert("753", MythGestureEvent::UpRight);
88 
89  /* Double Lines*/
100  p->m_sequences.insert("85258",MythGestureEvent::UpThenDown);
101  p->m_sequences.insert("25852",MythGestureEvent::DownThenUp);
102 }
103 
105 {
106  delete p;
107 }
108 
109 /* comments in header */
110 void MythGesture::adjustExtremes(int x, int y)
111 {
112  m_minX = std::min(m_minX, x);
113  m_maxX = std::max(m_maxX, x);
114  m_minY = std::min(m_minY, y);
115  m_maxY = std::max(m_maxY, y);
116 }
117 
118 bool MythGesture::recording(void) const
119 {
120  p->m_m.lock();
121  bool temp = m_recording;
122  p->m_m.unlock();
123  return temp;
124 }
125 
126 /* comments in header */
128 {
129  p->m_m.lock();
130  m_recording = true;
131  p->m_m.unlock();
132 }
133 
134 /* comments in header */
136 {
137  p->m_m.lock();
138 
139  if (m_recording)
140  {
141  m_recording = false;
142 
143  /* translate before resetting maximums */
145 
146  m_minX = m_minY = 10000;
147  m_maxX = m_maxY = -1;
148  }
149 
150  p->m_m.unlock();
151 }
152 
154 {
155  return new MythGestureEvent(m_lastGesture);
156 }
157 
158 /* comments in header */
159 static int determineBin (const QPoint & p, int x1, int x2, int y1, int y2)
160 {
161  int bin_num = 1;
162  if (p.x() > x1)
163  bin_num += 1;
164  if (p.x() > x2)
165  bin_num += 1;
166  if (p.y() > y1)
167  bin_num += 3;
168  if (p.y() > y2)
169  bin_num += 3;
170 
171  return bin_num;
172 }
173 
174 /* comments in header */
176 {
177  size_t total_points = m_points.count();
178 
179  if (total_points > m_maxPoints)
180  {
181  m_points.clear();
182  return "0";
183  }
184 
185  /* treat any stroke with less than the minimum number of points as
186  * a click (not a drag), which is the center bin */
187  if (total_points < m_minPoints)
188  {
189  m_points.clear();
190  return "5";
191  }
192 
193  QString sequence;
194 
195  /* number of bins recorded in the stroke */
196  size_t sequence_count = 0;
197 
198  /* points-->sequence translation scratch variables */
199  int prev_bin = 0;
200  int current_bin = 0;
201  int bin_count = 0;
202 
203  /*flag indicating the start of a stroke - always count it in the sequence*/
204  bool first_bin = true;
205 
206  /* determine size of grid */
207  int delta_x = m_maxX - m_minX;
208  int delta_y = m_maxY - m_minY;
209 
210  /* calculate bin boundary positions */
211  int bound_x_1 = m_minX + (delta_x / 3);
212  int bound_x_2 = m_minX + 2 * (delta_x / 3);
213 
214  int bound_y_1 = m_minY + (delta_y / 3);
215  int bound_y_2 = m_minY + 2 * (delta_y / 3);
216 
217  if (delta_x > m_scaleRatio * delta_y)
218  {
219  bound_y_1 = (m_maxY + m_minY - delta_x) / 2 + (delta_x / 3);
220  bound_y_2 = (m_maxY + m_minY - delta_x) / 2 + 2 * (delta_x / 3);
221  }
222  else if (delta_y > m_scaleRatio * delta_x)
223  {
224  bound_x_1 = (m_maxX + m_minX - delta_y) / 2 + (delta_y / 3);
225  bound_x_2 = (m_maxX + m_minX - delta_y) / 2 + 2 * (delta_y / 3);
226  }
227 
228  /* build string by placing points in bins, collapsing bins and
229  discarding those with too few points... */
230 
231  while (!m_points.empty())
232  {
233  QPoint pt = m_points.front();
234  m_points.pop_front();
235 
236  /* figure out which bin the point falls in */
237  current_bin = determineBin(pt, bound_x_1, bound_x_2, bound_y_1,
238  bound_y_2);
239 
240  /* if this is the first point, consider it the previous bin, too. */
241  prev_bin = (prev_bin == 0) ? current_bin : prev_bin;
242 
243  if (prev_bin == current_bin)
244  bin_count++;
245  else
246  {
247 
248  /* we are moving to a new bin -- consider adding to the
249  sequence */
250  if ((bin_count > (total_points * m_binPercent)) || first_bin)
251  {
252  first_bin = false;
253  sequence += '0' + prev_bin;
254  sequence_count ++;
255  }
256 
257  /* restart counting points in the new bin */
258  bin_count = 0;
259  prev_bin = current_bin;
260  }
261  }
262 
263  /* add the last run of points to the sequence */
264  sequence += '0' + current_bin;
265  sequence_count++;
266 
267  /* bail out on error cases */
268  if (sequence_count > m_maxSequence)
269  sequence = '0';
270 
271  return sequence;
272 }
273 
274 /* comments in header */
275 bool MythGesture::record(const QPoint & pt)
276 {
277  /* only record if we haven't exceeded the maximum points */
278  if (((uint)m_points.size() >= m_maxPoints) || !recording())
279  return false;
280 
281  if (m_points.empty())
282  {
283  m_points.push_back(pt);
284  return true;
285  }
286 
287  /* interpolate between last and current point */
288  int delx = pt.x() - m_points.back().x();
289  int dely = pt.y() - m_points.back().y();
290 
291  /* step by the greatest delta direction */
292  if (abs(delx) > abs(dely))
293  {
294  float fy = m_points.back().y();
295 
296  /* go from the last point to the current, whatever direction
297  * it may be */
298  for (int ix = m_points.back().x();
299  (delx > 0) ? (ix < pt.x()) : (ix > pt.x());
300  ix += (delx > 0) ? 1 : -1)
301  {
302  /* step the other axis by the correct increment */
303  fy += std::fabs(static_cast<float>(dely) / static_cast<float>(delx))
304  * ((dely < 0) ? -1.0F : 1.0F);
305  int iy = static_cast<int>(fy);
306 
307  /* add the interpolated point */
308  m_points.push_back(QPoint(ix, iy));
309  adjustExtremes(ix, iy);
310  }
311  }
312  else /* same thing, but for dely larger than delx case... */
313  {
314  float fx = m_points.back().x();
315 
316  /* go from the last point to the current, whatever direction
317  it may be */
318  for (int iy = m_points.back().y();
319  (dely > 0) ? (iy < pt.y()) : (iy > pt.y());
320  iy += (dely > 0) ? 1 : -1)
321  {
322  /* step the other axis by the correct increment */
323  fx += std::fabs(static_cast<float>(delx) / static_cast<float>(dely))
324  * ((delx < 0) ? -1.0F : 1.0F);
325  int ix = static_cast<int>(fx);
326 
327  /* add the interpolated point */
328  m_points.push_back(QPoint((int)ix, iy));
329  adjustExtremes((int)ix, iy);
330  }
331  }
332 
333  m_points.push_back(pt);
334 
335  return true;
336 }
337 
338 
339 static const std::array<const std::string,23> gesturename {
340  "Unknown",
341  "Up",
342  "Down",
343  "Left",
344  "Right",
345  "UpLeft",
346  "UpRight",
347  "DownLeft",
348  "DownRight",
349  "UpThenLeft",
350  "UpThenRight",
351  "DownThenLeft",
352  "DownThenRight",
353  "LeftThenUp",
354  "LeftThenDown",
355  "RightThenUp",
356  "RightThenDown",
357  "RightThenLeft",
358  "LeftThenRight",
359  "UpThenDown",
360  "DownThenUp",
361  "Click",
362  "MaxGesture"
363 };
364 
365 /* comments in header */
366 MythGestureEvent::operator QString() const
367 {
368  return QString::fromStdString(gesturename[m_gesture]);
369 }
MythGestureEvent::Down
@ Down
Definition: mythgesture.h:50
MythGestureEvent::LeftThenUp
@ LeftThenUp
Definition: mythgesture.h:65
MythGestureEvent::DownThenLeft
@ DownThenLeft
Definition: mythgesture.h:63
MythGesture::m_scaleRatio
int m_scaleRatio
Definition: mythgesture.h:229
MythGestureEvent::~MythGestureEvent
~MythGestureEvent() override
Definition: mythgesture.cpp:44
MythGestureEvent::UpRight
@ UpRight
Definition: mythgesture.h:56
MythGestureEvent::Up
@ Up
Definition: mythgesture.h:49
MythGesture::m_points
QList< QPoint > m_points
Definition: mythgesture.h:232
MythGesture::p
MythGesturePrivate * p
Definition: mythgesture.h:234
x2
static int x2
Definition: mythsocket.cpp:61
MythGestureEvent::RightThenDown
@ RightThenDown
Definition: mythgesture.h:68
MythGesture::m_maxPoints
size_t m_maxPoints
Definition: mythgesture.h:226
MythGestureEvent::MaxGesture
@ MaxGesture
Definition: mythgesture.h:78
MythGesture::m_minPoints
size_t m_minPoints
Definition: mythgesture.h:227
MythGestureEvent::UpThenLeft
@ UpThenLeft
Definition: mythgesture.h:61
MythGestureEvent::DownThenUp
@ DownThenUp
Definition: mythgesture.h:72
gesturename
static const std::array< const std::string, 23 > gesturename
Definition: mythgesture.cpp:339
determineBin
static int determineBin(const QPoint &p, int x1, int x2, int y1, int y2)
Definition: mythgesture.cpp:159
MythGesture::MythGesture
MythGesture(size_t max_points=10000, size_t min_points=50, size_t max_sequence=20, size_t scale_ratio=4, float bin_percent=0.07)
Create a new stroke, specifying tuning values.
Definition: mythgesture.cpp:62
MythGesture::m_recording
bool m_recording
Definition: mythgesture.h:221
hardwareprofile.config.p
p
Definition: config.py:33
MythGesture::m_maxX
int m_maxX
Definition: mythgesture.h:223
MythGesture::m_lastGesture
MythGestureEvent::Gesture m_lastGesture
Definition: mythgesture.h:231
MythGesture::start
void start(void)
Start recording.
Definition: mythgesture.cpp:127
MythGesturePrivate::m_sequences
QMap< QString, MythGestureEvent::Gesture > m_sequences
Definition: mythgesture.cpp:56
x1
static int x1
Definition: mythsocket.cpp:60
MythGesture::recording
bool recording(void) const
Determine if the stroke is being recorded.
Definition: mythgesture.cpp:118
MythGesture::m_binPercent
float m_binPercent
Definition: mythgesture.h:230
MythGesture::m_minX
int m_minX
Definition: mythgesture.h:222
MythGestureEvent::Right
@ Right
Definition: mythgesture.h:52
MythGesture::gesture
MythGestureEvent * gesture(void) const
Complete the gesture event of the last completed stroke.
Definition: mythgesture.cpp:153
MythGestureEvent::UpLeft
@ UpLeft
Definition: mythgesture.h:55
MythGesture::stop
void stop(void)
Stop recording.
Definition: mythgesture.cpp:135
MythGestureEvent::DownThenRight
@ DownThenRight
Definition: mythgesture.h:64
MythGesture::m_minY
int m_minY
Definition: mythgesture.h:224
MythGestureEvent::Click
@ Click
Definition: mythgesture.h:75
uint
unsigned int uint
Definition: compat.h:140
MythGestureEvent::Left
@ Left
Definition: mythgesture.h:51
mythgesture.h
A C++ ripoff of the stroke library for MythTV.
MythGestureEvent::UpThenDown
@ UpThenDown
Definition: mythgesture.h:71
MythGesture::adjustExtremes
void adjustExtremes(int x, int y)
Adjust horizontal and vertical extremes.
Definition: mythgesture.cpp:110
MythGesture::~MythGesture
~MythGesture()
Definition: mythgesture.cpp:104
MythGestureEvent::LeftThenDown
@ LeftThenDown
Definition: mythgesture.h:66
MythGestureEvent::kEventType
static Type kEventType
Definition: mythgesture.h:123
MythGesture::m_maxY
int m_maxY
Definition: mythgesture.h:225
MythGestureEvent::DownLeft
@ DownLeft
Definition: mythgesture.h:57
MythGesture::translate
QString translate(void)
Translate the stroke into a sequence.
Definition: mythgesture.cpp:175
MythGestureEvent::UpThenRight
@ UpThenRight
Definition: mythgesture.h:62
MythGestureEvent
A custom event that represents a mouse gesture.
Definition: mythgesture.h:40
MythGesture::record
bool record(const QPoint &p)
Record a point.
Definition: mythgesture.cpp:275
MythGestureEvent::RightThenLeft
@ RightThenLeft
Definition: mythgesture.h:69
MythGesturePrivate
Private information used only by a stroke class.
Definition: mythgesture.cpp:52
MythGesture::m_maxSequence
size_t m_maxSequence
Definition: mythgesture.h:228
MythGestureEvent::RightThenUp
@ RightThenUp
Definition: mythgesture.h:67
MythGestureEvent::DownRight
@ DownRight
Definition: mythgesture.h:58
MythGestureEvent::LeftThenRight
@ LeftThenRight
Definition: mythgesture.h:70
MythGesturePrivate::m_m
QMutex m_m
Definition: mythgesture.cpp:55