MythTV  master
mythgesture.cpp
Go to the documentation of this file.
1 /* -*- myth -*- */
29 // Qt
30 #include <QMetaEnum>
31 
32 // MythTV
33 #include "mythgesture.h"
34 
35 // Std
36 #include <array>
37 #include <cmath>
38 #include <algorithm>
39 #include <complex>
40 
41 const QEvent::Type MythGestureEvent::kEventType = static_cast<QEvent::Type>(QEvent::registerEventType());
42 
51 MythGestureEvent::MythGestureEvent(Gesture gesture, Qt::MouseButton Button)
52  : QEvent(kEventType),
53  m_gesture(gesture),
54  m_button(Button)
55 {
56 }
57 
58 const std::map<QString, MythGestureEvent::Gesture>MythGesture::kSequences =
59 {
61  { "5", MythGestureEvent::Click },
62  { "456", MythGestureEvent::Right },
63  { "654", MythGestureEvent::Left },
64  { "258", MythGestureEvent::Down },
65  { "852", MythGestureEvent::Up },
66  { "951", MythGestureEvent::UpLeft },
67  { "753", MythGestureEvent::UpRight },
68  { "159", MythGestureEvent::DownRight },
69  { "357", MythGestureEvent::DownLeft },
70  { "96321", MythGestureEvent::UpThenLeft },
71  { "74123", MythGestureEvent::UpThenRight },
72  { "36987", MythGestureEvent::DownThenLeft },
74  { "32147", MythGestureEvent::LeftThenDown },
75  { "98741", MythGestureEvent::LeftThenUp },
77  { "78963", MythGestureEvent::RightThenUp },
80  { "85258", MythGestureEvent::UpThenDown },
81  { "25852", MythGestureEvent::DownThenUp }
82 };
83 
88 {
89  return QMetaEnum::fromType<Gesture>().valueToKey(m_gesture);
90 }
91 
93 {
94  return QMetaEnum::fromType<Qt::MouseButtons>().valueToKey(static_cast<int>(m_button));
95 }
96 
116 MythGesture::MythGesture(size_t MaxPoints, size_t MinPoints,
117  size_t MaxSequence, int ScaleRatio,
118  float BinPercent)
119  : m_maxPoints(MaxPoints),
120  m_minPoints(MinPoints),
121  m_maxSequence(MaxSequence),
122  m_scaleRatio(ScaleRatio),
123  m_binPercent(BinPercent)
124 {
125 }
126 
131 void MythGesture::AdjustExtremes(int X, int Y)
132 {
133  m_minX = std::min(m_minX, X);
134  m_maxX = std::max(m_maxX, X);
135  m_minY = std::min(m_minY, Y);
136  m_maxY = std::max(m_maxY, Y);
137 }
138 
143 {
144  m_lock.lock();
145  bool temp = m_recording;
146  m_lock.unlock();
147  return temp;
148 }
149 
152 {
153  m_lock.lock();
154  m_recording = true;
155  m_lock.unlock();
156 }
157 
158 
163 void MythGesture::Stop(bool Timeout)
164 {
165  m_lock.lock();
166 
167  if (m_recording)
168  {
169  m_recording = false;
170 
171  // translate before resetting maximums
172  const QString gesture = Translate(Timeout);
173  auto found = kSequences.find(gesture);
174  if (found != kSequences.cend())
175  m_lastGesture = found->second;
176  else
178 
179  m_minX = m_minY = 10000;
180  m_maxX = m_maxY = -1;
181  }
182 
183  m_lock.unlock();
184 }
185 
186 
191 {
193 }
194 
195 /* comments in header */
196 static int determineBin (QPoint p, int x1, int x2, int y1, int y2)
197 {
198  int bin_num = 1;
199  if (p.x() > x1)
200  bin_num += 1;
201  if (p.x() > x2)
202  bin_num += 1;
203  if (p.y() > y1)
204  bin_num += 3;
205  if (p.y() > y2)
206  bin_num += 3;
207 
208  return bin_num;
209 }
210 
211 
217 QString MythGesture::Translate(bool Timeout)
218 {
219  auto total_points = static_cast<size_t>(m_points.count());
220 
221  if (total_points > m_maxPoints)
222  {
223  m_points.clear();
224  return "0";
225  }
226 
227  /* treat any stroke with less than the minimum number of points as
228  * a click (not a drag), which is the center bin */
229  if (total_points < m_minPoints)
230  {
231  m_points.clear();
232  if (Timeout)
233  return "1";
234  return "5";
235  }
236 
237  QString sequence;
238 
239  /* number of bins recorded in the stroke */
240  size_t sequence_count = 0;
241 
242  /* points-->sequence translation scratch variables */
243  int prev_bin = 0;
244  int current_bin = 0;
245  int bin_count = 0;
246 
247  /*flag indicating the start of a stroke - always count it in the sequence*/
248  bool first_bin = true;
249 
250  /* determine size of grid */
251  int delta_x = m_maxX - m_minX;
252  int delta_y = m_maxY - m_minY;
253 
254  /* calculate bin boundary positions */
255  int bound_x_1 = m_minX + (delta_x / 3);
256  int bound_x_2 = m_minX + (2 * (delta_x / 3));
257 
258  int bound_y_1 = m_minY + (delta_y / 3);
259  int bound_y_2 = m_minY + (2 * (delta_y / 3));
260 
261  if (delta_x > m_scaleRatio * delta_y)
262  {
263  bound_y_1 = (m_maxY + m_minY - delta_x) / 2 + (delta_x / 3);
264  bound_y_2 = (m_maxY + m_minY - delta_x) / 2 + 2 * (delta_x / 3);
265  }
266  else if (delta_y > m_scaleRatio * delta_x)
267  {
268  bound_x_1 = (m_maxX + m_minX - delta_y) / 2 + (delta_y / 3);
269  bound_x_2 = (m_maxX + m_minX - delta_y) / 2 + 2 * (delta_y / 3);
270  }
271 
272  /* build string by placing points in bins, collapsing bins and
273  discarding those with too few points... */
274 
275  while (!m_points.empty())
276  {
277  QPoint pt = m_points.front();
278  m_points.pop_front();
279 
280  /* figure out which bin the point falls in */
281  current_bin = determineBin(pt, bound_x_1, bound_x_2, bound_y_1,
282  bound_y_2);
283 
284  /* if this is the first point, consider it the previous bin, too. */
285  prev_bin = (prev_bin == 0) ? current_bin : prev_bin;
286 
287  if (prev_bin == current_bin)
288  bin_count++;
289  else
290  {
291 
292  /* we are moving to a new bin -- consider adding to the
293  sequence */
294  if ((bin_count > (total_points * m_binPercent)) || first_bin)
295  {
296  first_bin = false;
297  sequence += '0' + QChar(prev_bin);
298  sequence_count ++;
299  }
300 
301  /* restart counting points in the new bin */
302  bin_count = 0;
303  prev_bin = current_bin;
304  }
305  }
306 
307  /* add the last run of points to the sequence */
308  sequence += '0' + QChar(current_bin);
309  sequence_count++;
310 
311  /* bail out on error cases */
312  if (sequence_count > m_maxSequence)
313  sequence = '0';
314 
315  return sequence;
316 }
317 
318 
323 {
324  return static_cast<size_t>(m_points.size()) >= m_minPoints;
325 }
326 
331 bool MythGesture::Record(QPoint Point, Qt::MouseButton Button)
332 {
333  /* only record if we haven't exceeded the maximum points */
334  if ((static_cast<size_t>(m_points.size()) >= m_maxPoints) || !Recording())
335  return false;
336 
337  m_lastButton = Button;
338 
339  if (m_points.empty())
340  {
341  m_points.push_back(Point);
342  return true;
343  }
344 
345  /* interpolate between last and current point */
346  int delx = Point.x() - m_points.back().x();
347  int dely = Point.y() - m_points.back().y();
348 
349  /* step by the greatest delta direction */
350  if (abs(delx) > abs(dely))
351  {
352  float fy = m_points.back().y();
353 
354  /* go from the last point to the current, whatever direction
355  * it may be */
356  for (int ix = m_points.back().x();
357  (delx > 0) ? (ix < Point.x()) : (ix > Point.x());
358  ix += (delx > 0) ? 1 : -1)
359  {
360  /* step the other axis by the correct increment */
361  fy += std::fabs(static_cast<float>(dely) / static_cast<float>(delx))
362  * ((dely < 0) ? -1.0F : 1.0F);
363  int iy = static_cast<int>(fy);
364 
365  /* add the interpolated point */
366  m_points.push_back(QPoint(ix, iy));
367  AdjustExtremes(ix, iy);
368  }
369  }
370  else /* same thing, but for dely larger than delx case... */
371  {
372  float fx = m_points.back().x();
373 
374  /* go from the last point to the current, whatever direction
375  it may be */
376  for (int iy = m_points.back().y();
377  (dely > 0) ? (iy < Point.y()) : (iy > Point.y());
378  iy += (dely > 0) ? 1 : -1)
379  {
380  /* step the other axis by the correct increment */
381  fx += std::fabs(static_cast<float>(delx) / static_cast<float>(dely))
382  * ((delx < 0) ? -1.0F : 1.0F);
383  int ix = static_cast<int>(fx);
384 
385  /* add the interpolated point */
386  m_points.push_back(QPoint(ix, iy));
387  AdjustExtremes(ix, iy);
388  }
389  }
390 
391  m_points.push_back(Point);
392 
393  return true;
394 }
MythGestureEvent::DownThenUp
@ DownThenUp
Definition: mythgesture.h:72
MythGestureEvent::Click
@ Click
Definition: mythgesture.h:77
MythGestureEvent::GetButtonName
QString GetButtonName() const
Definition: mythgesture.cpp:92
MythGestureEvent::MythGestureEvent
MythGestureEvent(Gesture gesture, Qt::MouseButton Button)
Create a MythGesture.
Definition: mythgesture.cpp:51
MythGesture::m_scaleRatio
int m_scaleRatio
Definition: mythgesture.h:127
MythGesture::AdjustExtremes
void AdjustExtremes(int X, int Y)
Adjust horizontal and vertical extremes.
Definition: mythgesture.cpp:131
MythGesture::m_points
QList< QPoint > m_points
Definition: mythgesture.h:130
MythGesture::Recording
bool Recording()
Determine if the stroke is being recorded.
Definition: mythgesture.cpp:142
MythGesture::Start
void Start()
Start recording.
Definition: mythgesture.cpp:151
MythGestureEvent::UpThenRight
@ UpThenRight
Definition: mythgesture.h:62
x2
static int x2
Definition: mythsocket.cpp:51
MythGestureEvent::LeftThenDown
@ LeftThenDown
Definition: mythgesture.h:66
MythGestureEvent::Down
@ Down
Definition: mythgesture.h:50
MythGesture::m_maxPoints
size_t m_maxPoints
Definition: mythgesture.h:124
MythGestureEvent::m_button
Qt::MouseButton m_button
Definition: mythgesture.h:96
MythGestureEvent::m_gesture
Gesture m_gesture
Definition: mythgesture.h:94
MythGestureEvent::Left
@ Left
Definition: mythgesture.h:51
MythGestureEvent::LeftThenRight
@ LeftThenRight
Definition: mythgesture.h:70
MythGestureEvent::UpThenDown
@ UpThenDown
Definition: mythgesture.h:71
MythGesture::m_minPoints
size_t m_minPoints
Definition: mythgesture.h:125
MythGestureEvent::kEventType
static const Type kEventType
Definition: mythgesture.h:91
MythGestureEvent::Gesture
Gesture
Definition: mythgesture.h:44
MythGesture::Stop
void Stop(bool Timeout=false)
Stop recording.
Definition: mythgesture.cpp:163
MythGestureEvent::RightThenDown
@ RightThenDown
Definition: mythgesture.h:68
MythGesture::m_recording
bool m_recording
Definition: mythgesture.h:119
MythGestureEvent::DownRight
@ DownRight
Definition: mythgesture.h:58
hardwareprofile.config.p
p
Definition: config.py:33
MythGesture::m_maxX
int m_maxX
Definition: mythgesture.h:121
MythGestureEvent::DownThenRight
@ DownThenRight
Definition: mythgesture.h:64
MythGesture::m_lastGesture
MythGestureEvent::Gesture m_lastGesture
Definition: mythgesture.h:129
MythGestureEvent::UpThenLeft
@ UpThenLeft
Definition: mythgesture.h:61
x1
static int x1
Definition: mythsocket.cpp:50
MythGesture::Translate
QString Translate(bool Timeout)
Translate the stroke into a sequence.
Definition: mythgesture.cpp:217
MythGesture::m_binPercent
float m_binPercent
Definition: mythgesture.h:128
MythGesture::m_minX
int m_minX
Definition: mythgesture.h:120
MythGesture::Record
bool Record(QPoint Point, Qt::MouseButton Button)
Record a point.
Definition: mythgesture.cpp:331
MythGesture::MythGesture
MythGesture(size_t MaxPoints=10000, size_t MinPoints=50, size_t MaxSequence=20, int ScaleRatio=4, float BinPercent=0.07F)
Create a new stroke, specifying tuning values.
Definition: mythgesture.cpp:116
MythGestureEvent::UpRight
@ UpRight
Definition: mythgesture.h:56
MythGesture::m_minY
int m_minY
Definition: mythgesture.h:122
MythGestureEvent::DownThenLeft
@ DownThenLeft
Definition: mythgesture.h:63
MythGestureEvent::Right
@ Right
Definition: mythgesture.h:52
MythGestureEvent::Up
@ Up
Definition: mythgesture.h:49
MythGesture::kSequences
static const std::map< QString, MythGestureEvent::Gesture > kSequences
Definition: mythgesture.h:132
mythgesture.h
A C++ ripoff of the stroke library for MythTV.
MythGestureEvent::UpLeft
@ UpLeft
Definition: mythgesture.h:55
MythGestureEvent::GetName
QString GetName() const
Get the symbolic name of the gesture.
Definition: mythgesture.cpp:87
MythGestureEvent::LeftThenUp
@ LeftThenUp
Definition: mythgesture.h:65
MythGestureEvent::DownLeft
@ DownLeft
Definition: mythgesture.h:57
MythGestureEvent::RightThenLeft
@ RightThenLeft
Definition: mythgesture.h:69
determineBin
static int determineBin(QPoint p, int x1, int x2, int y1, int y2)
Definition: mythgesture.cpp:196
MythGestureEvent::LongClick
@ LongClick
Definition: mythgesture.h:76
MythGesture::m_maxY
int m_maxY
Definition: mythgesture.h:123
MythGesture::GetGesture
MythGestureEvent * GetGesture() const
Complete the gesture event of the last completed stroke.
Definition: mythgesture.cpp:190
MythGestureEvent
A custom event that represents a mouse gesture.
Definition: mythgesture.h:39
MythGesture::HasMinimumPoints
bool HasMinimumPoints() const
Determine if the stroke has the minimum required points.
Definition: mythgesture.cpp:322
MythGestureEvent::Unknown
@ Unknown
Definition: mythgesture.h:46
MythGesture::m_maxSequence
size_t m_maxSequence
Definition: mythgesture.h:126
MythGestureEvent::RightThenUp
@ RightThenUp
Definition: mythgesture.h:67
MythGesture::m_lastButton
Qt::MouseButton m_lastButton
Definition: mythgesture.h:133
MythGesture::m_lock
QMutex m_lock
Definition: mythgesture.h:131