Skip to content

Commit

Permalink
add QgsRay3D
Browse files Browse the repository at this point in the history
  • Loading branch information
NEDJIMAbelgacem authored and wonder-sk committed Jan 13, 2021
1 parent a97ade0 commit 4e2133f
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 57 deletions.
10 changes: 6 additions & 4 deletions src/3d/qgs3dmapscene.cpp
Expand Up @@ -1101,10 +1101,10 @@ void Qgs3DMapScene::exportScene( const Qgs3DMapExportSettings &exportSettings )
}
}

void Qgs3DMapScene::identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QVector3D &rayOrigin, const QVector3D &rayDirection )
void Qgs3DMapScene::identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QgsRay3D &ray )
{
QgsVector3D originMapCoords = mMap.worldToMapCoordinates( rayOrigin );
QgsVector3D pointMapCoords = mMap.worldToMapCoordinates( rayOrigin + rayOrigin.length() * rayDirection.normalized() );
QgsVector3D originMapCoords = mMap.worldToMapCoordinates( ray.origin() );
QgsVector3D pointMapCoords = mMap.worldToMapCoordinates( ray.origin() + ray.origin().length() * ray.direction().normalized() );
QgsVector3D directionMapCoords = pointMapCoords - originMapCoords;
directionMapCoords.normalize();

Expand Down Expand Up @@ -1132,7 +1132,9 @@ void Qgs3DMapScene::identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVecto
QVector3D adjutedRayDirection = QVector3D( rayDirectionMapCoords.x(), rayDirectionMapCoords.y(), rayDirectionMapCoords.z() / elevationProps->zScale() );
adjutedRayDirection.normalize();

QVector<QVariantMap> points = pc->dataProvider()->getPointsOnRay( adjutedRayOrigin, adjutedRayDirection, maxScreenError, fov, screenSizePx, angle );
QgsRay3D ray( adjutedRayOrigin, adjutedRayDirection );

QVector<QVariantMap> points = pc->dataProvider()->getPointsOnRay( ray, maxScreenError, fov, screenSizePx, angle );
selectedPoints.append( qMakePair( layer, points ) );
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/3d/qgs3dmapscene.h
Expand Up @@ -22,6 +22,7 @@

#include "qgsfeatureid.h"
#include "qgsshadowrenderingframegraph.h"
#include "qgsray3d.h"

namespace Qt3DRender
{
Expand Down Expand Up @@ -128,7 +129,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
*
* \since QGIS 3.18
*/
void identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QVector3D &rayOrigin, const QVector3D &rayDirection );
void identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QgsRay3D &ray );

signals:
//! Emitted when the current terrain entity is replaced by a new one
Expand Down
3 changes: 2 additions & 1 deletion src/app/3d/qgs3dmapcanvas.cpp
Expand Up @@ -33,6 +33,7 @@
#include "qgstemporalcontroller.h"
#include "qgsflatterraingenerator.h"
#include "qgsonlineterraingenerator.h"
#include "qgsray3d.h"

Qgs3DMapCanvas::Qgs3DMapCanvas( QWidget *parent )
: QWidget( parent )
Expand Down Expand Up @@ -278,5 +279,5 @@ void Qgs3DMapCanvas::identifyPointCloudOnMouseEvent( QVector<QPair<QgsMapLayer *
QVector3D rayDirWorld( rayDirWorld4D.x(), rayDirWorld4D.y(), rayDirWorld4D.z() );
rayDirWorld = rayDirWorld.normalized();

mScene->identifyPointCloudOnRay( result, QVector3D( rayOriginWorld ), rayDirWorld );
mScene->identifyPointCloudOnRay( result, QgsRay3D( QVector3D( rayOriginWorld ), rayDirWorld ) );
}
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -687,6 +687,7 @@ set(QGIS_CORE_SRCS
geometry/qgstriangle.cpp
geometry/qgswkbptr.cpp
geometry/qgswkbtypes.cpp
geometry/qgsray3d.cpp

3d/qgs3drendererregistry.cpp
3d/qgs3dsymbolregistry.cpp
Expand Down Expand Up @@ -1194,6 +1195,7 @@ set(QGIS_CORE_HDRS
geometry/qgstriangle.h
geometry/qgswkbptr.h
geometry/qgswkbtypes.h
geometry/qgsray3d.h

gps/qgsgpsconnection.h
gps/qgsgpsdconnection.h
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgsbox3d.cpp
Expand Up @@ -125,7 +125,7 @@ bool QgsBox3d::operator==( const QgsBox3d &other ) const
qgsDoubleNear( mZmax, other.mZmax );
}

float QgsBox3d::distanceFromPoint( double x, double y, double z )
float QgsBox3d::distanceFromPoint( double x, double y, double z ) const
{
float dx = std::max( mBounds2d.xMinimum() - x, std::max( 0., x - mBounds2d.xMaximum() ) );
float dy = std::max( mBounds2d.yMinimum() - y, std::max( 0., y - mBounds2d.yMaximum() ) );
Expand Down
88 changes: 88 additions & 0 deletions src/core/geometry/qgsray3d.cpp
@@ -0,0 +1,88 @@
#include "qgsray3d.h"

#include "qgsrange.h"

#include <QtMath>

QgsRay3D::QgsRay3D( const QVector3D &origin, const QVector3D &direction )
: mOrigin( origin )
, mDirection( direction )
{

}

void QgsRay3D::setOrigin( const QVector3D &origin )
{
mOrigin = origin;
}

void QgsRay3D::setDirection( const QVector3D direction )
{
mDirection = direction;
}

bool QgsRay3D::intersectsWith( const QgsBox3d &box ) const
{
double tminX = box.xMinimum() - mOrigin.x(), tmaxX = box.xMaximum() - mOrigin.x();
double tminY = box.yMinimum() - mOrigin.y(), tmaxY = box.yMaximum() - mOrigin.y();
double tminZ = box.zMinimum() - mOrigin.z(), tmaxZ = box.zMaximum() - mOrigin.z();
if ( mDirection.x() < 0 ) std::swap( tminX, tmaxX );
if ( mDirection.y() < 0 ) std::swap( tminY, tmaxY );
if ( mDirection.z() < 0 ) std::swap( tminZ, tmaxZ );
if ( mDirection.x() != 0 )
{
tminX /= mDirection.x();
tmaxX /= mDirection.x();
}
else
{
tminX = std::numeric_limits<double>::lowest();
tmaxX = std::numeric_limits<double>::max();
}
if ( mDirection.y() != 0 )
{
tminY /= mDirection.y();
tmaxY /= mDirection.y();
}
else
{
tminY = std::numeric_limits<double>::lowest();
tmaxY = std::numeric_limits<double>::max();
}
if ( mDirection.z() != 0 )
{
tminZ /= mDirection.z();
tmaxZ /= mDirection.z();
}
else
{
tminZ = std::numeric_limits<double>::lowest();
tmaxZ = std::numeric_limits<double>::max();
}
QgsDoubleRange tRange( std::max( std::max( tminX, tminY ), tminZ ), std::min( std::min( tmaxX, tmaxY ), tmaxZ ) );
return !tRange.isEmpty();
}

bool QgsRay3D::isInFront( const QVector3D &point ) const
{
return QVector3D::dotProduct( point - mOrigin, mDirection ) > 0.0;
}

double QgsRay3D::angleToPoint( const QVector3D &point ) const
{
// project point to the ray
QVector3D projectedPoint = mOrigin + QVector3D::dotProduct( point - mOrigin, mDirection ) * mDirection;

// calculate the angle between the point and the projected point
QVector3D v1 = ( projectedPoint - mOrigin ).normalized();
QVector3D v2 = ( point - mOrigin ).normalized();
return qRadiansToDegrees( std::acos( std::abs( QVector3D::dotProduct( v1, v2 ) ) ) );
}

double QgsRay3D::distanceTo( const QgsBox3d &box ) const
{
float dx = std::max( box.xMinimum() - mOrigin.x(), std::max( 0., mOrigin.x() - box.xMaximum() ) );
float dy = std::max( box.yMinimum() - mOrigin.y(), std::max( 0., mOrigin.y() - box.yMaximum() ) );
float dz = std::max( box.zMinimum() - mOrigin.z(), std::max( 0., mOrigin.z() - box.zMaximum() ) );
return sqrt( dx * dx + dy * dy + dz * dz );
}
29 changes: 29 additions & 0 deletions src/core/geometry/qgsray3d.h
@@ -0,0 +1,29 @@
#ifndef QGSRAY3D_H
#define QGSRAY3D_H

#include "qgsbox3d.h"

#include <QVector3D>

class CORE_EXPORT QgsRay3D
{
public:
QgsRay3D( const QVector3D &origin, const QVector3D &direction );

QVector3D origin() const { return mOrigin; }
QVector3D direction() const { return mDirection; }

void setOrigin( const QVector3D &origin );
void setDirection( const QVector3D direction );

bool intersectsWith( const QgsBox3d &box ) const;
bool isInFront( const QVector3D &point ) const;
double angleToPoint( const QVector3D &point ) const;
double distanceTo( const QgsBox3d &box ) const;

private:
QVector3D mOrigin;
QVector3D mDirection;
};

#endif // QGSRAY3D_H
56 changes: 8 additions & 48 deletions src/core/pointcloud/qgspointclouddataprovider.cpp
Expand Up @@ -409,15 +409,17 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(
return nodes;
}

QVector<QVariantMap> QgsPointCloudDataProvider::getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle, int pointsLimit )
QVector<QVariantMap> QgsPointCloudDataProvider::getPointsOnRay( const QgsRay3D &ray, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle, int pointsLimit )
{
QVector3D rayOrigin = ray.origin();
QVector3D rayDirection = ray.direction();
QVector<QVariantMap> points;
QgsPointCloudIndex *index = this->index();
IndexedPointCloudNode root = index->root();
QgsRectangle rootNodeExtentMapCoords = index->nodeMapExtent( root );
const float rootErrorInMapCoordinates = rootNodeExtentMapCoords.width() / index->span();

QVector<IndexedPointCloudNode> nodes = getNodesIntersectingWithRay( index, root, maxScreenError, rootErrorInMapCoordinates, cameraFov, screenSizePx, rayOrigin, rayDirection );
QVector<IndexedPointCloudNode> nodes = getNodesIntersectingWithRay( index, root, maxScreenError, rootErrorInMapCoordinates, cameraFov, screenSizePx, ray );

QgsPointCloudAttributeCollection attributeCollection = index->attributes();
QgsPointCloudRequest request;
Expand Down Expand Up @@ -472,52 +474,10 @@ QVector<QVariantMap> QgsPointCloudDataProvider::getPointsOnRay( const QVector3D
return points;
}

bool __boxIntesects( const QgsBox3d &box, const QVector3D &rayOrigin, const QVector3D &rayDirection )
{
double tminX = box.xMinimum() - rayOrigin.x(), tmaxX = box.xMaximum() - rayOrigin.x();
double tminY = box.yMinimum() - rayOrigin.y(), tmaxY = box.yMaximum() - rayOrigin.y();
double tminZ = box.zMinimum() - rayOrigin.z(), tmaxZ = box.zMaximum() - rayOrigin.z();
if ( rayDirection.x() < 0 ) std::swap( tminX, tmaxX );
if ( rayDirection.y() < 0 ) std::swap( tminY, tmaxY );
if ( rayDirection.z() < 0 ) std::swap( tminZ, tmaxZ );
if ( rayDirection.x() != 0 )
{
tminX /= rayDirection.x();
tmaxX /= rayDirection.x();
}
else
{
tminX = std::numeric_limits<double>::lowest();
tmaxX = std::numeric_limits<double>::max();
}
if ( rayDirection.y() != 0 )
{
tminY /= rayDirection.y();
tmaxY /= rayDirection.y();
}
else
{
tminY = std::numeric_limits<double>::lowest();
tmaxY = std::numeric_limits<double>::max();
}
if ( rayDirection.z() != 0 )
{
tminZ /= rayDirection.z();
tmaxZ /= rayDirection.z();
}
else
{
tminZ = std::numeric_limits<double>::lowest();
tmaxZ = std::numeric_limits<double>::max();
}
QgsDoubleRange tRange( std::max( std::max( tminX, tminY ), tminZ ), std::min( std::min( tmaxX, tmaxY ), tmaxZ ) );
return !tRange.isEmpty();
}

QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::getNodesIntersectingWithRay(
const QgsPointCloudIndex *pc, IndexedPointCloudNode n,
double maxError, double nodeError, double cameraFov, int screenSizePx,
const QVector3D &rayOrigin, const QVector3D &rayDirection )
const QgsRay3D &ray )
{
QVector<IndexedPointCloudNode> nodes;

Expand All @@ -526,10 +486,10 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::getNodesIntersectingWi
QgsBox3d box( n2DExtent.xMinimum(), n2DExtent.yMinimum(), zRange.lower(), n2DExtent.xMaximum(), n2DExtent.yMaximum(), zRange.upper() );

// calculate screen space error:
float distance = box.distanceFromPoint( rayOrigin.x(), rayOrigin.y(), rayOrigin.z() );
float distance = ray.distanceTo( box );
float phi = nodeError * screenSizePx / ( 2 * distance * tan( cameraFov * M_PI / ( 2 * 180 ) ) );

if ( !__boxIntesects( box, rayOrigin, rayDirection ) )
if ( !ray.intersectsWith( box ) )
{
return nodes;
}
Expand All @@ -543,7 +503,7 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::getNodesIntersectingWi
const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
for ( const IndexedPointCloudNode &nn : children )
{
nodes += getNodesIntersectingWithRay( pc, nn, maxError, childrenError, cameraFov, screenSizePx, rayOrigin, rayDirection );
nodes += getNodesIntersectingWithRay( pc, nn, maxError, childrenError, cameraFov, screenSizePx, ray );
}

return nodes;
Expand Down
5 changes: 3 additions & 2 deletions src/core/pointcloud/qgspointclouddataprovider.h
Expand Up @@ -24,6 +24,7 @@
#include "qgsstatisticalsummary.h"
#include "qgspointcloudindex.h"
#include "qgspoint.h"
#include "qgsray3d.h"
#include <memory>

class IndexedPointCloudNode;
Expand Down Expand Up @@ -139,7 +140,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider
*
* \since QGIS 3.18
*/
QVector<QVariantMap> getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle, int pointsLimit = 1000 );
QVector<QVariantMap> getPointsOnRay( const QgsRay3D &ray, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle, int pointsLimit = 1000 );
#else

/**
Expand Down Expand Up @@ -399,7 +400,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider

private:
QVector<IndexedPointCloudNode> traverseTree( const QgsPointCloudIndex *pc, IndexedPointCloudNode n, double maxError, double nodeError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange );
QVector<IndexedPointCloudNode> getNodesIntersectingWithRay( const QgsPointCloudIndex *pc, IndexedPointCloudNode n, double maxError, double nodeError, double cameraFov, int screenSizePx, const QVector3D &rayOrigin, const QVector3D &rayDirection );
QVector<IndexedPointCloudNode> getNodesIntersectingWithRay( const QgsPointCloudIndex *pc, IndexedPointCloudNode n, double maxError, double nodeError, double cameraFov, int screenSizePx, const QgsRay3D &ray );
};

#endif // QGSMESHDATAPROVIDER_H

0 comments on commit 4e2133f

Please sign in to comment.