diff --git a/python/core/auto_generated/geometry/qgsbox3d.sip.in b/python/core/auto_generated/geometry/qgsbox3d.sip.in index 32fc12e2119..777a9a168af 100644 --- a/python/core/auto_generated/geometry/qgsbox3d.sip.in +++ b/python/core/auto_generated/geometry/qgsbox3d.sip.in @@ -229,6 +229,8 @@ Converts the box to a 2D rectangle. %Docstring Returns the smallest distance between the box and the point ``point`` (returns 0 if the point is inside the box) + +.. versionadded:: 3.18 %End bool operator==( const QgsBox3d &other ) const; diff --git a/python/core/auto_generated/geometry/qgsray3d.sip.in b/python/core/auto_generated/geometry/qgsray3d.sip.in index edbed25523a..63fe965e6dc 100644 --- a/python/core/auto_generated/geometry/qgsray3d.sip.in +++ b/python/core/auto_generated/geometry/qgsray3d.sip.in @@ -45,6 +45,8 @@ Sets the origin of the ray Sets the direction of the ray %End + bool operator==( const QgsRay3D &r ); + QVector3D projectedPoint( const QVector3D &point ) const; %Docstring Returns the projection of the point on the ray diff --git a/python/core/auto_generated/pointcloud/qgspointclouddataprovider.sip.in b/python/core/auto_generated/pointcloud/qgspointclouddataprovider.sip.in index 2bcc5a8b702..aa5256577db 100644 --- a/python/core/auto_generated/pointcloud/qgspointclouddataprovider.sip.in +++ b/python/core/auto_generated/pointcloud/qgspointclouddataprovider.sip.in @@ -108,7 +108,7 @@ Returns the points that are on a ray %End %MethodCode { - QVector> res = sipCpp->getPointsOnRay( *a0, a2, a3, a4, a5, a6 ); + QVector> res = sipCpp->getPointsOnRay( *a0, a1, a2, a3, a4, a5 ); sipRes = PyList_New( res.size() ); for ( int i = 0; i < res.size(); ++i ) { diff --git a/src/3d/qgs3dutils.cpp b/src/3d/qgs3dutils.cpp index 3f8be9adc07..f00818212db 100644 --- a/src/3d/qgs3dutils.cpp +++ b/src/3d/qgs3dutils.cpp @@ -575,18 +575,18 @@ QgsRay3D Qgs3DUtils::rayFromScreenPoint( const QPoint &point, const QSize &windo // clip coordinates QVector4D rayClip( normDeviceCoords.x(), normDeviceCoords.y(), -1.0, 0.0 ); - QMatrix4x4 projMatrix = camera->projectionMatrix(); - QMatrix4x4 viewMatrix = camera->viewMatrix(); + QMatrix4x4 invertedProjMatrix = camera->projectionMatrix().inverted(); + QMatrix4x4 invertedViewMatrix = camera->viewMatrix().inverted(); // ray direction in view coordinates - QVector4D rayDirView = projMatrix.inverted() * rayClip; + QVector4D rayDirView = invertedProjMatrix * rayClip; // ray origin in world coordinates - QVector4D rayOriginWorld = viewMatrix.inverted() * QVector4D( 0.0f, 0.0f, 0.0f, 1.0f ); + QVector4D rayOriginWorld = invertedViewMatrix * QVector4D( 0.0f, 0.0f, 0.0f, 1.0f ); // ray direction in world coordinates rayDirView.setZ( -1.0f ); rayDirView.setW( 0.0f ); - QVector4D rayDirWorld4D = viewMatrix.inverted() * rayDirView; + QVector4D rayDirWorld4D = invertedViewMatrix * rayDirView; QVector3D rayDirWorld( rayDirWorld4D.x(), rayDirWorld4D.y(), rayDirWorld4D.z() ); rayDirWorld = rayDirWorld.normalized(); diff --git a/src/core/geometry/qgsbox3d.h b/src/core/geometry/qgsbox3d.h index 49849254acf..cb4b9f069c6 100644 --- a/src/core/geometry/qgsbox3d.h +++ b/src/core/geometry/qgsbox3d.h @@ -208,6 +208,8 @@ class CORE_EXPORT QgsBox3d /** * Returns the smallest distance between the box and the point \a point * (returns 0 if the point is inside the box) + * + * \since QGIS 3.18 */ double distanceTo( const QVector3D &point ) const; diff --git a/src/core/geometry/qgsray3d.cpp b/src/core/geometry/qgsray3d.cpp index 7ad1ec22ff3..235fe121b7b 100644 --- a/src/core/geometry/qgsray3d.cpp +++ b/src/core/geometry/qgsray3d.cpp @@ -35,6 +35,11 @@ void QgsRay3D::setDirection( const QVector3D direction ) mDirection = direction; } +bool QgsRay3D::operator==( const QgsRay3D &r ) +{ + return this->mOrigin == r.origin() && this->direction() == r.direction(); +} + QVector3D QgsRay3D::projectedPoint( const QVector3D &point ) const { return mOrigin + QVector3D::dotProduct( point - mOrigin, mDirection ) * mDirection; diff --git a/src/core/geometry/qgsray3d.h b/src/core/geometry/qgsray3d.h index 0802b8a4643..0af40b26d25 100644 --- a/src/core/geometry/qgsray3d.h +++ b/src/core/geometry/qgsray3d.h @@ -43,6 +43,9 @@ class CORE_EXPORT QgsRay3D //! Sets the direction of the ray void setDirection( const QVector3D direction ); + //! Comparison operator + bool operator==( const QgsRay3D &r ); + /** * Returns the projection of the point on the ray * (which is the closest point of the ray to \a point) diff --git a/src/core/pointcloud/qgspointclouddataprovider.h b/src/core/pointcloud/qgspointclouddataprovider.h index 864134306f0..0c981cfaab5 100644 --- a/src/core/pointcloud/qgspointclouddataprovider.h +++ b/src/core/pointcloud/qgspointclouddataprovider.h @@ -159,7 +159,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider SIP_PYLIST getPointsOnRay( const QgsRay3D &ray, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle, int pointsLimit = 1000 ); % MethodCode { - QVector> res = sipCpp->getPointsOnRay( *a0, a2, a3, a4, a5, a6 ); + QVector> res = sipCpp->getPointsOnRay( *a0, a1, a2, a3, a4, a5 ); sipRes = PyList_New( res.size() ); for ( int i = 0; i < res.size(); ++i ) { diff --git a/tests/src/3d/testqgs3dutils.cpp b/tests/src/3d/testqgs3dutils.cpp index 18a580d9fb8..f0155618200 100644 --- a/tests/src/3d/testqgs3dutils.cpp +++ b/tests/src/3d/testqgs3dutils.cpp @@ -34,6 +34,7 @@ class TestQgs3DUtils : public QObject void cleanupTestCase();// will be called after the last testfunction was executed. void testTransforms(); + void testRayFromScreenPoint(); private: }; @@ -82,5 +83,63 @@ void TestQgs3DUtils::testTransforms() QCOMPARE( mapPoint1, mapPoint2 ); } +void TestQgs3DUtils::testRayFromScreenPoint() +{ + + Qt3DRender::QCamera camera; + { + camera.setFieldOfView( 45.0f ); + camera.setNearPlane( 10.0f ); + camera.setFarPlane( 100.0f ); + camera.setAspectRatio( 2 ); + camera.setPosition( QVector3D( 9.0f, 15.0f, 30.0f ) ); + camera.setUpVector( QVector3D( 0.0f, 1.0f, 0.0f ) ); + camera.setViewCenter( QVector3D( 0.0f, 0.0f, 0.0f ) ); + + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 50, 50 ), QSize( 100, 100 ), &camera ); + QgsRay3D ray2( QVector3D( 8.99999904632568, 14.9999980926514, 29.9999980926514 ), QVector3D( -0.25916051864624, -0.431934207677841, -0.863868415355682 ) ); + QVERIFY( ray1 == ray2 ); + } + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 0, 0 ), QSize( 100, 100 ), &camera ); + QgsRay3D ray2( QVector3D( 8.99999904632568, 14.9999980926514, 29.9999980926514 ), QVector3D( -0.810001313686371, -0.0428109727799892, -0.584863305091858 ) ); + QVERIFY( ray1 == ray2 ); + } + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 100, 100 ), QSize( 100, 100 ), &camera ); + QgsRay3D ray2( QVector3D( 8.99999904632568, 14.9999980926514, 29.9999980926514 ), QVector3D( 0.429731547832489, -0.590972006320953, -0.682702660560608 ) ); + QVERIFY( ray1 == ray2 ); + } + } + + { + camera.setFieldOfView( 60.0f ); + camera.setNearPlane( 1.0f ); + camera.setFarPlane( 1000.0f ); + camera.setAspectRatio( 2 ); + camera.setPosition( QVector3D( 0.0f, 0.0f, 0.0f ) ); + camera.setUpVector( QVector3D( 0.0f, 1.0f, 0.0f ) ); + camera.setViewCenter( QVector3D( 0.0f, 100.0f, -100.0f ) ); + + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 500, 500 ), QSize( 1000, 1000 ), &camera ); + QgsRay3D ray2( QVector3D( 0, 0, 0 ), QVector3D( 0, 0.70710676908493, -0.70710676908493 ) ); + QVERIFY( ray1 == ray2 ); + } + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 0, 0 ), QSize( 1000, 1000 ), &camera ); + QgsRay3D ray2( QVector3D( 0, 0, 0 ), QVector3D( -0.70710676908493, 0.683012664318085, -0.183012709021568 ) ); + QVERIFY( ray1 == ray2 ); + } + { + QgsRay3D ray1 = Qgs3DUtils::rayFromScreenPoint( QPoint( 500, 1000 ), QSize( 1000, 1000 ), &camera ); + QgsRay3D ray2( QVector3D( 0, 0, 0 ), QVector3D( 0, 0.258819073438644, -0.965925812721252 ) ); + QVERIFY( ray1 == ray2 ); + } + } + +} + QGSTEST_MAIN( TestQgs3DUtils ) #include "testqgs3dutils.moc"