aboutsummaryrefslogtreecommitdiffstats
path: root/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2020-01-23 17:00:00 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2020-01-24 08:42:31 +0000
commitfd40bdd606c646fb027fb65197071a3cf8b99d3f (patch)
treeadac7d920b0b3d75c96f65668a2c69ff4dafb306 /share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
parent4d269f930a8be037ac8735280aaae52954dd5176 (diff)
QmlDesigner: Use double precision to calculate ray-plane intersections
Float precision becomes issue when calculating ray-plane intersections for gizmo hit detection when camera is very zoomed (in or out). Do the critical calculations in double precision to mitigate the issue. Change-Id: I8c33e17bf19d092e24ab19f8f8f2a54cd83304cc Fixes: QDS-1526 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Diffstat (limited to 'share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp')
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp70
1 files changed, 60 insertions, 10 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
index 03a1c20c80..2c6d0d32ce 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
@@ -37,6 +37,50 @@
namespace QmlDesigner {
namespace Internal {
+// Double precision vec3 for cases where float calculations can suffer from rounding errors
+class DoubleVec {
+public:
+ DoubleVec(const QVector3D &v)
+ : x(double(v.x())),
+ y(double(v.y())),
+ z(double(v.z()))
+ {}
+ DoubleVec(double xx, double yy, double zz)
+ : x(xx),
+ y(yy),
+ z(zz)
+ {}
+
+ static double dotProduct(const DoubleVec &v1, const DoubleVec &v2)
+ {
+ return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
+ }
+
+ QVector3D toVec3()
+ {
+ return QVector3D(float(x), float(y), float(z));
+ }
+
+ double x;
+ double y;
+ double z;
+};
+
+DoubleVec operator*(double factor, const DoubleVec &v)
+{
+ return DoubleVec(v.x * factor, v.y * factor, v.z * factor);
+}
+
+DoubleVec operator+(const DoubleVec &v1, const DoubleVec &v2)
+{
+ return DoubleVec(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
+}
+
+DoubleVec operator-(const DoubleVec &v1, const DoubleVec &v2)
+{
+ return DoubleVec(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
+}
+
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
@@ -256,17 +300,21 @@ QVector3D MouseArea3D::rayIntersectsPlane(const QVector3D &rayPos0,
const QVector3D &planePos,
const QVector3D &planeNormal) const
{
- QVector3D rayDirection = rayPos1 - rayPos0;
- QVector3D rayPos0RelativeToPlane = rayPos0 - planePos;
+ const DoubleVec rayPos0D(rayPos0);
+ const DoubleVec rayPos1D(rayPos1);
+ const DoubleVec planePosD(planePos);
+ const DoubleVec planeNormalD(planeNormal);
+ const DoubleVec rayDirectionD = rayPos1D - rayPos0D;
+ const DoubleVec rayPos0RelativeToPlaneD = rayPos0D - planePosD;
- float dotPlaneRayDirection = QVector3D::dotProduct(planeNormal, rayDirection);
- float dotPlaneRayPos0 = -QVector3D::dotProduct(planeNormal, rayPos0RelativeToPlane);
+ const double dotPlaneRayDirection = DoubleVec::dotProduct(planeNormalD, rayDirectionD);
+ const double dotPlaneRayPos0 = -DoubleVec::dotProduct(planeNormalD, rayPos0RelativeToPlaneD);
if (qFuzzyIsNull(dotPlaneRayDirection)) {
// The ray is is parallel to the plane. Note that if dotLinePos0 == 0, it
// additionally means that the line lies in plane as well. In any case, we
// signal that we cannot find a single intersection point.
- return QVector3D(0, 0, -1);
+ return QVector3D(0.f, 0.f, -1.f);
}
// Since we work with a ray (that has a start), distanceFromLinePos0ToPlane
@@ -275,10 +323,10 @@ QVector3D MouseArea3D::rayIntersectsPlane(const QVector3D &rayPos0,
// it has neither a start, nor an end). Then we wouldn't need to check the distance at all.
// But that would also mean that the line could intersect the plane behind the camera, if
// the line were directed away from the plane when looking forward.
- float distanceFromRayPos0ToPlane = dotPlaneRayPos0 / dotPlaneRayDirection;
- if (distanceFromRayPos0ToPlane <= 0)
- return QVector3D(0, 0, -1);
- return rayPos0 + distanceFromRayPos0ToPlane * rayDirection;
+ const double distanceFromRayPos0ToPlane = dotPlaneRayPos0 / dotPlaneRayDirection;
+ if (distanceFromRayPos0ToPlane <= 0.)
+ return QVector3D(0.f, 0.f, -1.f);
+ return (rayPos0D + distanceFromRayPos0ToPlane * rayDirectionD).toVec3();
}
// Get a new scale based on a relative scene distance along a drag axes.
@@ -423,9 +471,11 @@ QVector3D MouseArea3D::getMousePosInPlane(const MouseArea3D *helper,
{
if (!helper)
helper = this;
+
const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0);
- const QVector3D mousePos2(float(mousePosInView.x()), float(mousePosInView.y()), 1);
const QVector3D rayPos0 = m_view3D->mapTo3DScene(mousePos1);
+ const QVector3D mousePos2(float(mousePosInView.x()), float(mousePosInView.y()),
+ rayPos0.length());
const QVector3D rayPos1 = m_view3D->mapTo3DScene(mousePos2);
const QVector3D globalPlanePosition = helper->mapPositionToScene(QVector3D(0, 0, 0));
const QVector3D intersectGlobalPos = rayIntersectsPlane(rayPos0, rayPos1,