From 3c159957f863cf8d367a9261e7016e52cd0348c1 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 23 Mar 2016 22:26:08 +0100 Subject: [PATCH] TouchPoint: add horizontalDiameter, verticalDiameter; deprecate rects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contact patch of a finger on a touchscreen tends to be roughly elliptical. If we model it as a QRectF, it's not clear whether the ellipse should be considered to be inscribed in the rectangle and then rotated, or whether the rectangle represents the outer bounds of the rotated ellipse. In practice, since most touchscreens can't measure rotation, it is effectively the latter. But modeling it that way means information is lost if the touchscreen can measure rotation: you can determine the bounds of a rotated ellipse, but you cannot derive the rotated ellipse from its bounds. So it's better to model the axes of the ellipse explicitly. This has the added benefit of saving a little storage space: we replace 3 QRectF instances, whose width and height will normally be the same, with 3 positions (bringing the total to 12 QPointF's) and one set of axes. Further, most applications only care about the center of each contact patch, so it's better to store that explicitly instead of calculating QRectF::center() repeatedly. In the past there may have been an assumption that the width of the rect is the same as the horizontalDiameter of the ellipse, so the rect could be considered to be rotated, and the ellipse to be inscribed. But in d0b1c646b4a351f7eea2137c68993ae63b2b6bab and 40e4949674eaf7ceb09f6d18479ead1a36b384fd the point was made that the rect is actually the bounding box of the rotated ellipse. [ChangeLog][QtGui][QTouchEvent] TouchPoint::rect(), sceneRect() and screenRect() are deprecated; a touchpoint is now modeled as an ellipse, so please use pos(), scenePos(), screenPos(), horizontalDiameter() and verticalDiameter() instead. Change-Id: Ic06f6165e2d90fc9d4cc19cf4938d4faf5766bb4 Reviewed-by: Jan Arve Sæther --- doc/src/images/touchpoint-metrics.png | Bin 0 -> 46111 bytes src/gui/kernel/qevent.cpp | 106 ++++++++++++++++++++---- src/gui/kernel/qevent.h | 11 ++- src/gui/kernel/qevent_p.h | 9 +- src/gui/kernel/qguiapplication.cpp | 9 +- src/gui/kernel/qwindowsysteminterface.h | 6 +- src/widgets/kernel/qapplication.cpp | 8 +- 7 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 doc/src/images/touchpoint-metrics.png diff --git a/doc/src/images/touchpoint-metrics.png b/doc/src/images/touchpoint-metrics.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e6cd4f0fbf88d83b99ab2efe5dd1139c7de653 GIT binary patch literal 46111 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�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 literal 0 HcmV?d00001 diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index fcb9c14406..8fd03cdb76 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4417,6 +4417,8 @@ QTouchEvent::~QTouchEvent() \brief The TouchPoint class provides information about a touch point in a QTouchEvent. \since 4.6 \inmodule QtGui + + \image touchpoint-metrics.png */ /*! \enum TouchPoint::InfoFlag @@ -4502,7 +4504,7 @@ Qt::TouchPointState QTouchEvent::TouchPoint::state() const */ QPointF QTouchEvent::TouchPoint::pos() const { - return d->rect.center(); + return d->pos; } /*! @@ -4517,7 +4519,7 @@ QPointF QTouchEvent::TouchPoint::pos() const */ QPointF QTouchEvent::TouchPoint::scenePos() const { - return d->sceneRect.center(); + return d->scenePos; } /*! @@ -4527,7 +4529,7 @@ QPointF QTouchEvent::TouchPoint::scenePos() const */ QPointF QTouchEvent::TouchPoint::screenPos() const { - return d->screenRect.center(); + return d->screenPos; } /*! @@ -4650,10 +4652,19 @@ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const around the point returned by pos(). \note This function returns an empty rect if the device does not report touch point sizes. + + \obsolete This function is deprecated in 5.9 because it returns the outer bounds + of the touchpoint regardless of rotation, whereas a touchpoint is more correctly + modeled as an ellipse at position pos() with horizontalDiameter() and + verticalDiameter() which are independent of rotation(). + + \sa scenePos(), horizontalDiameter(), verticalDiameter() */ QRectF QTouchEvent::TouchPoint::rect() const { - return d->rect; + QRectF ret(0, 0, d->horizontalDiameter, d->verticalDiameter); + ret.moveCenter(d->pos); + return ret; } /*! @@ -4661,11 +4672,18 @@ QRectF QTouchEvent::TouchPoint::rect() const \note This function returns an empty rect if the device does not report touch point sizes. - \sa scenePos(), rect() + \obsolete This function is deprecated in 5.9 because it returns the outer bounds + of the touchpoint regardless of rotation, whereas a touchpoint is more correctly + modeled as an ellipse at position scenePos() with horizontalDiameter() and + verticalDiameter() which are independent of rotation(). + + \sa scenePos(), horizontalDiameter(), verticalDiameter() */ QRectF QTouchEvent::TouchPoint::sceneRect() const { - return d->sceneRect; + QRectF ret(0, 0, d->horizontalDiameter, d->verticalDiameter); + ret.moveCenter(d->scenePos); + return ret; } /*! @@ -4673,11 +4691,18 @@ QRectF QTouchEvent::TouchPoint::sceneRect() const \note This function returns an empty rect if the device does not report touch point sizes. - \sa screenPos(), rect() + \obsolete This function is deprecated because it returns the outer bounds of the + touchpoint regardless of rotation, whereas a touchpoint is more correctly + modeled as an ellipse at position screenPos() with horizontalDiameter() and + verticalDiameter() which are independent of rotation(). + + \sa screenPos(), horizontalDiameter(), verticalDiameter() */ QRectF QTouchEvent::TouchPoint::screenRect() const { - return d->screenRect; + QRectF ret(0, 0, d->horizontalDiameter, d->verticalDiameter); + ret.moveCenter(d->screenPos); + return ret; } /*! @@ -4702,6 +4727,30 @@ qreal QTouchEvent::TouchPoint::rotation() const return d->rotation; } +/*! + \since 5.9 + Returns the width of the bounding ellipse of this touch point. + The return value is in logical pixels, along the horizontal axis + when rotation() is zero. Most touchscreens do not detect the shape of the + contact point, so zero is the most common value. +*/ +qreal QTouchEvent::TouchPoint::horizontalDiameter() const +{ + return d->horizontalDiameter; +} + +/*! + \since 5.9 + Returns the height of the bounding ellipse of this touch point. + The return value is in logical pixels, along the vertical axis + when rotation() is zero. Most touchscreens do not detect the shape + of the contact point, so zero is the most common value. +*/ +qreal QTouchEvent::TouchPoint::verticalDiameter() const +{ + return d->verticalDiameter; +} + /*! Returns a velocity vector for this touch point. The vector is in the screen's coordinate system, using pixels per seconds for the magnitude. @@ -4773,7 +4822,7 @@ void QTouchEvent::TouchPoint::setPos(const QPointF &pos) { if (d->ref.load() != 1) d = d->detach(); - d->rect.moveCenter(pos); + d->pos = pos; } /*! \internal */ @@ -4781,7 +4830,7 @@ void QTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos) { if (d->ref.load() != 1) d = d->detach(); - d->sceneRect.moveCenter(scenePos); + d->scenePos = scenePos; } /*! \internal */ @@ -4789,7 +4838,7 @@ void QTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos) { if (d->ref.load() != 1) d = d->detach(); - d->screenRect.moveCenter(screenPos); + d->screenPos = screenPos; } /*! \internal */ @@ -4864,28 +4913,35 @@ void QTouchEvent::TouchPoint::setLastNormalizedPos(const QPointF &lastNormalized d->lastNormalizedPos = lastNormalizedPos; } -/*! \internal */ +// ### remove the following 3 setRect functions and their usages soon +/*! \internal \obsolete */ void QTouchEvent::TouchPoint::setRect(const QRectF &rect) { if (d->ref.load() != 1) d = d->detach(); - d->rect = rect; + d->pos = rect.center(); + d->verticalDiameter = rect.height(); + d->horizontalDiameter = rect.width(); } -/*! \internal */ +/*! \internal \obsolete */ void QTouchEvent::TouchPoint::setSceneRect(const QRectF &sceneRect) { if (d->ref.load() != 1) d = d->detach(); - d->sceneRect = sceneRect; + d->scenePos = sceneRect.center(); + d->verticalDiameter = sceneRect.height(); + d->horizontalDiameter = sceneRect.width(); } -/*! \internal */ +/*! \internal \obsolete */ void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect) { if (d->ref.load() != 1) d = d->detach(); - d->screenRect = screenRect; + d->screenPos = screenRect.center(); + d->verticalDiameter = screenRect.height(); + d->horizontalDiameter = screenRect.width(); } /*! \internal */ @@ -4904,6 +4960,22 @@ void QTouchEvent::TouchPoint::setRotation(qreal angle) d->rotation = angle; } +/*! \internal */ +void QTouchEvent::TouchPoint::setVerticalDiameter(qreal dia) +{ + if (d->ref.load() != 1) + d = d->detach(); + d->verticalDiameter = dia; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setHorizontalDiameter(qreal dia) +{ + if (d->ref.load() != 1) + d = d->detach(); + d->horizontalDiameter = dia; +} + /*! \internal */ void QTouchEvent::TouchPoint::setVelocity(const QVector2D &v) { diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index a062331bd8..982072c7d4 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -870,6 +870,9 @@ public: qreal pressure() const; qreal rotation() const; + qreal horizontalDiameter() const; + qreal verticalDiameter() const; + QVector2D velocity() const; InfoFlags flags() const; QVector rawScreenPositions() const; @@ -890,11 +893,13 @@ public: void setLastScenePos(const QPointF &lastScenePos); void setLastScreenPos(const QPointF &lastScreenPos); void setLastNormalizedPos(const QPointF &lastNormalizedPos); - void setRect(const QRectF &rect); - void setSceneRect(const QRectF &sceneRect); - void setScreenRect(const QRectF &screenRect); + void setRect(const QRectF &rect); // deprecated + void setSceneRect(const QRectF &sceneRect); // deprecated + void setScreenRect(const QRectF &screenRect); // deprecated void setPressure(qreal pressure); void setRotation(qreal angle); + void setVerticalDiameter(qreal dia); + void setHorizontalDiameter(qreal dia); void setVelocity(const QVector2D &v); void setFlags(InfoFlags flags); void setRawScreenPositions(const QVector &positions); diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index 7e82b9c654..a8b4d520d4 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -66,7 +66,9 @@ public: id(id), state(Qt::TouchPointReleased), pressure(qreal(-1.)), - rotation(qreal(0.)) + rotation(qreal(0.)), + verticalDiameter(0), + horizontalDiameter(0) { } inline QTouchEventTouchPointPrivate *detach() @@ -82,12 +84,13 @@ public: int id; QPointerUniqueId uniqueId; Qt::TouchPointStates state; - QRectF rect, sceneRect, screenRect; - QPointF normalizedPos, + QPointF pos, scenePos, screenPos, normalizedPos, startPos, startScenePos, startScreenPos, startNormalizedPos, lastPos, lastScenePos, lastScreenPos, lastNormalizedPos; qreal pressure; qreal rotation; + qreal verticalDiameter; + qreal horizontalDiameter; QVector2D velocity; QTouchEvent::TouchPoint::InfoFlags flags; QVector rawScreenPositions; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index dda88da20c..1277e85d0a 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2564,7 +2564,9 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To Q_ASSERT(w.data() != 0); // make the *scene* functions return the same as the *screen* functions - touchPoint.d->sceneRect = touchPoint.screenRect(); + touchPoint.d->scenePos = touchPoint.screenPos(); + touchPoint.d->verticalDiameter = touchPoint.screenRect().height(); + touchPoint.d->horizontalDiameter = touchPoint.screenRect().width(); touchPoint.d->startScenePos = touchPoint.startScreenPos(); touchPoint.d->lastScenePos = touchPoint.lastScreenPos(); @@ -2634,8 +2636,9 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To const QPointF screenPos = rect.center(); const QPointF delta = screenPos - screenPos.toPoint(); - rect.moveCenter(w->mapFromGlobal(screenPos.toPoint()) + delta); - touchPoint.d->rect = rect; + touchPoint.d->pos = w->mapFromGlobal(screenPos.toPoint()) + delta; + touchPoint.d->verticalDiameter = rect.height(); + touchPoint.d->horizontalDiameter = rect.width(); if (touchPoint.state() == Qt::TouchPointPressed) { touchPoint.d->startPos = w->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta; touchPoint.d->lastPos = w->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta; diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 5368c75964..b6b57e01f5 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -131,9 +131,11 @@ public: qint64 uniqueId; // for TUIO: object/token ID; otherwise empty // TODO for TUIO 2.0: add registerPointerUniqueID(QPointerUniqueId) QPointF normalPosition; // touch device coordinates, (0 to 1, 0 to 1) - QRectF area; // the touched area, centered at position in screen coordinates + QRectF area; // dimensions of the elliptical contact patch, unrotated, and centered at position in screen coordinates + // width is the horizontal diameter, height is the vertical diameter qreal pressure; // 0 to 1 - qreal rotation; // 0 means pointing straight up; 0 if unknown (like QTabletEvent::rotation) + qreal rotation; // rotation applied to the elliptical contact patch + // 0 means pointing straight up; 0 if unknown (like QTabletEvent::rotation) Qt::TouchPointState state; //Qt::TouchPoint{Pressed|Moved|Stationary|Released} QVector2D velocity; // in screen coordinate system, pixels / seconds QTouchEvent::TouchPoint::InfoFlags flags; diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index b0e7293b88..9588b631a0 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3552,7 +3552,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QTouchEvent::TouchPoint &pt = touchEvent->_touchPoints[i]; QRectF rect = pt.rect(); rect.translate(offset); - pt.d->rect = rect; + pt.d->pos = rect.center(); + pt.d->verticalDiameter = rect.height(); + pt.d->horizontalDiameter = rect.width(); pt.d->startPos = pt.startPos() + offset; pt.d->lastPos = pt.lastPos() + offset; } @@ -4254,7 +4256,9 @@ bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven const QPointF delta = screenPos - screenPos.toPoint(); rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta); - touchPoint.d->rect = rect; + touchPoint.d->pos = rect.center(); + touchPoint.d->verticalDiameter = rect.height(); + touchPoint.d->horizontalDiameter = rect.width(); touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta; touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;