@@ -114,6 +114,7 @@ DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
114 , m_wideningAngle(0)
114 , m_wideningAngle(0)
115 , m_wideningFactor(0)
115 , m_wideningFactor(0)
116 , m_distanceThreshold(0)
116 , m_distanceThreshold(0)
117+ , m_distanceThresholdSquared(0.)
117 , m_minSpeed(0)
118 , m_minSpeed(0)
118 , m_maxSilenceTime(200)
119 , m_maxSilenceTime(200)
119 , m_silenceTime(0)
120 , m_silenceTime(0)
@@ -162,7 +163,14 @@ void DirectionalDragArea::setWideningAngle(qreal angle)
164 m_wideningAngle = angle;
165 m_wideningAngle = angle;
167+ // wideningFactor = pow(cosine(angle), 2)
165− m_wideningFactor = qTan(angle * M_PI / 180.0);
169+ qreal angleRadians = angle * M_PI / 180.0;
170+ m_wideningFactor = qCos(angleRadians);
171+ m_wideningFactor = m_wideningFactor * m_wideningFactor;
166 Q_EMIT wideningAngleChanged(angle);
174 Q_EMIT wideningAngleChanged(angle);
@@ -170,6 +178,7 @@ void DirectionalDragArea::setDistanceThreshold(qreal value)
171 if (m_distanceThreshold != value) {
179 if (m_distanceThreshold != value) {
172 m_distanceThreshold = value;
180 m_distanceThreshold = value;
181+ m_distanceThresholdSquared = m_distanceThreshold * m_distanceThreshold;
173 Q_EMIT distanceThresholdChanged(value);
182 Q_EMIT distanceThresholdChanged(value);
@@ -335,12 +344,13 @@ void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
335 m_startScenePos = newTouchPoint->scenePos();
344 m_startScenePos = newTouchPoint->scenePos();
336 m_touchId = newTouchPoint->id();
345 m_touchId = newTouchPoint->id();
337 m_dampedScenePos.reset(m_startScenePos);
346 m_dampedScenePos.reset(m_startScenePos);
338− updateVelocityCalculator(m_startScenePos);
347+ m_velocityCalculator->setTrackedPosition(0.);
339 m_velocityCalculator->reset();
348 m_velocityCalculator->reset();
340 m_numSamplesOnLastSpeedCheck = 0;
349 m_numSamplesOnLastSpeedCheck = 0;
341 m_silenceTime = 0;
350 m_silenceTime = 0;
342 setPreviousPos(m_startPos);
351 setPreviousPos(m_startPos);
343 setPreviousScenePos(m_startScenePos);
352 setPreviousScenePos(m_startScenePos);
353+ updateSceneDirectionVector();
345 setStatus(Undecided);
355 setStatus(Undecided);
@@ -441,44 +451,53 @@ const QTouchEvent::TouchPoint *DirectionalDragArea::fetchTargetTouchPoint(QTouch
442bool DirectionalDragArea::pointInsideAllowedArea() const
452bool DirectionalDragArea::pointInsideAllowedArea() const
444− qreal dX = m_dampedScenePos.x() - m_startScenePos.x();
454+ // NB: Using squared values to avoid computing the square root to find
445− qreal dY = m_dampedScenePos.y() - m_startScenePos.y();
455+ // the length totalMovement
447− switch (m_direction) {
457+ QPointF totalMovement(m_dampedScenePos.x() - m_startScenePos.x(),
448− case Direction::Upwards:
458+ m_dampedScenePos.y() - m_startScenePos.y());
449− return dY <= 0 && qFabs(dX) <= qFabs(dY) * m_wideningFactor;
459+
450− case Direction::Downwards:
460+ qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() +
451− return dY >= 0 && qFabs(dX) <= dY * m_wideningFactor;
461+ totalMovement.y() * totalMovement.y();
452− case Direction::Leftwards:
462+
453− return dX <= 0 && qFabs(dY) <= qFabs(dX) * m_wideningFactor;
463+ if (squaredTotalMovSize == 0.) {
454− default: // Direction::Rightwards:
464+ // didn't move
455− return dX >= 0 && qFabs(dY) <= dX * m_wideningFactor;
465+ return true;
468+ qreal projectedMovement = projectOntoDirectionVector(totalMovement);
471+ qreal cosineAngleSquared = (projectedMovement * projectedMovement) / squaredTotalMovSize;
474+ // angle_between_movement_vector_and_gesture_direction_vector <= widening_angle
475+ return cosineAngleSquared >= m_wideningFactor;
459bool DirectionalDragArea::movingInRightDirection() const
478bool DirectionalDragArea::movingInRightDirection() const
461− switch (m_direction) {
462− case Direction::Upwards:
463− return m_dampedScenePos.y() <= m_previousDampedScenePos.y();
480+ QPointF movementVector(m_dampedScenePos.x() - m_previousDampedScenePos.x(),
464− case Direction::Downwards:
465− return m_dampedScenePos.y() >= m_previousDampedScenePos.y();
481+ m_dampedScenePos.y() - m_previousDampedScenePos.y());
466− case Direction::Leftwards:
482+
467− return m_dampedScenePos.x() <= m_previousDampedScenePos.x();
483+ qreal scalarProjection = projectOntoDirectionVector(movementVector);
468− default: // Direction::Rightwards:
484+
469− return m_dampedScenePos.x() >= m_previousDampedScenePos.x();
485+ return scalarProjection >= 0.;
473bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
488bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
475− if (m_distanceThreshold > 0) {
490+ if (m_distanceThreshold <= 0.) {
476− if (Direction::isHorizontal(m_direction))
491+ // distance threshold check is disabled
477− return qFabs(point.x() - m_startScenePos.x()) > m_distanceThreshold;
479− return qFabs(point.y() - m_startScenePos.y()) > m_distanceThreshold;
481 return true;
492 return true;
494+ QPointF totalMovement(point.x() - m_startScenePos.x(),
495+ point.y() - m_startScenePos.y());
497+ qreal squaredTotalMovSize = totalMovement.x() * totalMovement.x() +
498+ totalMovement.y() * totalMovement.y();
500+ return squaredTotalMovSize > m_distanceThresholdSquared;
@@ -583,13 +602,13 @@ void DirectionalDragArea::setPreviousScenePos(const QPointF &point)
586−void DirectionalDragArea::updateVelocityCalculator(const QPointF &point)
605+void DirectionalDragArea::updateVelocityCalculator(const QPointF &scenePos)
588− if (Direction::isHorizontal(m_direction)) {
607+ QPointF totalSceneMovement = scenePos - m_startScenePos;
589− m_velocityCalculator->setTrackedPosition(point.x());
608+
590− } else {
609+ qreal scalarProjection = projectOntoDirectionVector(totalSceneMovement);
591− m_velocityCalculator->setTrackedPosition(point.y());
611+ m_velocityCalculator->setTrackedPosition(scalarProjection);
595bool DirectionalDragArea::isWithinTouchCompositionWindow()
614bool DirectionalDragArea::isWithinTouchCompositionWindow()
@@ -693,5 +712,39 @@ qint64 DirectionalDragArea::ActiveTouchesInfo::mostRecentStartTime()
693 return highestStartTime;
712 return highestStartTime;
715+void DirectionalDragArea::updateSceneDirectionVector()
717+ QPointF localOrigin(0., 0.);
718+ QPointF localDirection;
719+ switch (m_direction) {
720+ case Direction::Upwards:
721+ localDirection.rx() = 0.;
722+ localDirection.ry() = -1.;
724+ case Direction::Downwards:
725+ localDirection.rx() = 0.;
726+ localDirection.ry() = 1;
728+ case Direction::Leftwards:
729+ localDirection.rx() = -1.;
730+ localDirection.ry() = 0.;
732+ default: // Direction::Rightwards:
733+ localDirection.rx() = 1.;
734+ localDirection.ry() = 0.;
737+ QPointF sceneOrigin = mapToScene(localOrigin);
738+ QPointF sceneDirection = mapToScene(localDirection);
739+ m_sceneDirectionVector = sceneDirection - sceneOrigin;
742+qreal DirectionalDragArea::projectOntoDirectionVector(const QPointF &sceneVector) const
744+ // same as dot product as m_sceneDirectionVector is a unit vector
745+ return sceneVector.x() * m_sceneDirectionVector.x() +
746+ sceneVector.y() * m_sceneDirectionVector.y();
696// Because we are defining a new QObject-based class (RecognitionTimer) here.
749// Because we are defining a new QObject-based class (RecognitionTimer) here.
697#include "DirectionalDragArea.moc"
750#include "DirectionalDragArea.moc"