Skip to content
Permalink
Browse files

make identification work with point size

  • Loading branch information
NEDJIMAbelgacem authored and wonder-sk committed Jan 13, 2021
1 parent 4f3f95a commit 3a014ae0bf1d15c06e7d1b850a33a959f98175ed
@@ -56,6 +56,7 @@ Ctor

~QgsPointCloudDataProvider();


SIP_PYLIST identify( float maxErrorInMapCoords, QgsGeometry extentGeometry, const QgsDoubleRange extentZRange = QgsDoubleRange(), int pointsLimit = 1000 );
%Docstring
Returns the list of points of the point cloud according to a zoom level
@@ -132,7 +132,6 @@ Ownership of ``renderer`` is transferred to the layer.
.. seealso:: :py:func:`renderer`
%End

QVector<QMap<QString, QVariant>> getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx );
private:
QgsPointCloudLayer( const QgsPointCloudLayer &rhs );
};
@@ -54,16 +54,6 @@ static float screenSpaceError( float epsilon, float distance, float screenSize,
* camera
*/
float phi = epsilon * screenSize / ( 2 * distance * tan( fov * M_PI / ( 2 * 180 ) ) );
{
static int k = 0;
if ( k % 20 == 0 )
{
qDebug() << "screenSize: " << screenSize;
qDebug() << "fov: " << fov;
qDebug() << "epsilon: " << epsilon;
}
++k;
}
return phi;
}

@@ -77,6 +77,8 @@
#include "qgsskyboxsettings.h"

#include "qgswindow3dengine.h"
#include "qgspointcloudlayerelevationproperties.h"
#include "qgspointcloudlayer.h"

Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *engine )
: mMap( map )
@@ -1099,17 +1101,13 @@ void Qgs3DMapScene::exportScene( const Qgs3DMapExportSettings &exportSettings )
}
}

void Qgs3DMapScene::onRayCasted( const QVector3D &rayOrigin, const QVector3D &rayDirection )
void Qgs3DMapScene::identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QVector3D &rayOrigin, const QVector3D &rayDirection )
{
qDebug() << __PRETTY_FUNCTION__ << " " << rayOrigin << " " << rayDirection;
// QVector3D point2 = rayOrigin + rayOrigin.length() * rayDirection.normalized();
qDebug() << "Origin: " << mMap.origin().x() << " " << mMap.origin().y() << " " << mMap.origin().z();
QgsVector3D originMapCoords = mMap.worldToMapCoordinates( rayOrigin );
QgsVector3D pointMapCoords = mMap.worldToMapCoordinates( rayOrigin + rayOrigin.length() * rayDirection.normalized() );
QgsVector3D directionMapCoords = pointMapCoords - originMapCoords;
directionMapCoords.normalize();


QVector3D rayOriginMapCoords( originMapCoords.x(), originMapCoords.y(), originMapCoords.z() );
QVector3D rayDirectionMapCoords( directionMapCoords.x(), directionMapCoords.y(), directionMapCoords.z() );

@@ -1124,7 +1122,18 @@ void Qgs3DMapScene::onRayCasted( const QVector3D &rayOrigin, const QVector3D &ra
{
QgsPointCloudLayer3DRenderer *renderer = dynamic_cast<QgsPointCloudLayer3DRenderer *>( pc->renderer3D() );
double maxScreenError = renderer->maximumScreenError();
pc->getPointsOnRay( rayOriginMapCoords, rayDirectionMapCoords, maxScreenError, fov, screenSizePx );
const QgsPointCloud3DSymbol *symbol = renderer->symbol();
float pointSize = symbol->pointSize();
double angle = pointSize / screenSizePx * mCameraController->camera()->fieldOfView();

// adjust ray to elevation properties
QgsPointCloudLayerElevationProperties *elevationProps = dynamic_cast<QgsPointCloudLayerElevationProperties *>( pc->elevationProperties() );
QVector3D adjutedRayOrigin = QVector3D( rayOriginMapCoords.x(), rayOriginMapCoords.y(), ( rayOriginMapCoords.z() - elevationProps->zOffset() ) / elevationProps->zScale() );
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 );
selectedPoints.append( qMakePair( layer, points ) );
}
}
}
@@ -121,6 +121,9 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity

//! Exports the scene according to the scene export settings
void exportScene( const Qgs3DMapExportSettings &exportSettings );

void identifyPointCloudOnRay( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &selectedPoints, const QVector3D &rayOrigin, const QVector3D &rayDirection );

signals:
//! Emitted when the current terrain entity is replaced by a new one
void terrainEntityChanged();
@@ -143,7 +146,6 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
public slots:
//! Updates the temporale entities
void updateTemporal();
void onRayCasted( const QVector3D &rayOrigin, const QVector3D &rayDirection );

private slots:
void onCameraChanged();
@@ -254,26 +254,30 @@ void Qgs3DMapCanvas::updateTemporalRange( const QgsDateTimeRange &temporalrange
mScene->updateTemporal();
}


void Qgs3DMapCanvas::mouseReleased( QMouseEvent *event )
bool Qgs3DMapCanvas::identifyPointCloudOnMouseEvent( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &result, QMouseEvent *event )
{
// qDebug() << __PRETTY_FUNCTION__ << " " << event->x() << " " << event->y();
QVector3D deviceCoords( event->x(), event->y(), 0.0 );
QSize windowSize = mEngine->size();
// normalized device coordinates
QVector3D normDeviceCoords( 2.0 * deviceCoords.x() / windowSize.width() - 1.0f, 1.0f - 2.0 * deviceCoords.y() / windowSize.height(), mEngine->camera()->nearPlane() );
// qDebug() << "NDC " << normDeviceCoords.x() << " " << normDeviceCoords.y() << " " << normDeviceCoords.z();
QVector4D rayClip( normDeviceCoords.x(), normDeviceCoords.y(), -1.0f, 0.0f );
// clip coordinates
QVector4D rayClip( normDeviceCoords.x(), normDeviceCoords.y(), -1.0, 0.0 );

QMatrix4x4 projMatrix = mEngine->camera()->projectionMatrix();
QMatrix4x4 viewMatrix = mEngine->camera()->viewMatrix();

QVector4D rayEye = projMatrix.inverted() * rayClip;
rayEye.setZ( -1.0f );
rayEye.setW( 0.0f );
QVector4D rayWorld4D = viewMatrix.inverted() * rayEye;
QVector3D rayWorld( rayWorld4D.x(), rayWorld4D.y(), rayWorld4D.z() );
rayWorld = rayWorld.normalized();
// qDebug() << "rayEye: " << rayEye;
// qDebug() << "rayWorld: " << rayWorld;
QVector4D rayOrigin = viewMatrix.inverted() * QVector4D( 0.0f, 0.0f, 0.0f, 1.0f );
mScene->onRayCasted( QVector3D( rayOrigin ), rayWorld );
// ray direction in view coordinates
QVector4D rayDirView = projMatrix.inverted() * rayClip;
// ray origin in world coordinates
QVector4D rayOriginWorld = viewMatrix.inverted() * 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;
QVector3D rayDirWorld( rayDirWorld4D.x(), rayDirWorld4D.y(), rayDirWorld4D.z() );
rayDirWorld = rayDirWorld.normalized();

mScene->identifyPointCloudOnRay( result, QVector3D( rayOriginWorld ), rayDirWorld );
return true;
}
@@ -86,6 +86,9 @@ class Qgs3DMapCanvas : public QWidget
*/
void setTemporalController( QgsTemporalController *temporalController );

//
bool identifyPointCloudOnMouseEvent( QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &result, QMouseEvent *event );

signals:
//! Emitted when the 3D map canvas was successfully saved as image
void savedAsImage( QString fileName );
@@ -98,7 +101,6 @@ class Qgs3DMapCanvas : public QWidget
//! Emitted when the FPS counter is enabled or disabeld
void fpsCounterEnabledChanged( bool enabled );
public slots:
void mouseReleased( QMouseEvent *event );
private slots:
void updateTemporalRange( const QgsDateTimeRange &timeRange );

@@ -30,6 +30,7 @@
#include <Qt3DRender/QObjectPicker>
#include <Qt3DRender/QPickEvent>

#include "qgspointcloudlayer.h"

#include "qgs3dmapscenepickhandler.h"

@@ -66,7 +67,6 @@ Qgs3DMapToolIdentify::Qgs3DMapToolIdentify( Qgs3DMapCanvas *canvas )
{
mPickHandler.reset( new Qgs3DMapToolIdentifyPickHandler( this ) );
connect( canvas, &Qgs3DMapCanvas::mapSettingsChanged, this, &Qgs3DMapToolIdentify::onMapSettingsChanged );
connect( this, &Qgs3DMapToolIdentify::mouseReleased, canvas, &Qgs3DMapCanvas::mouseReleased );
}

Qgs3DMapToolIdentify::~Qgs3DMapToolIdentify() = default;
@@ -80,11 +80,35 @@ void Qgs3DMapToolIdentify::mousePressEvent( QMouseEvent *event )
identifyTool2D->clearResults();
}

void Qgs3DMapToolIdentify::mouseReleaseEvent( QMouseEvent *event )
{
if ( event->button() != Qt::MouseButton::LeftButton )
return;

QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> layerPoints;
canvas()->identifyPointCloudOnMouseEvent( layerPoints, event );

QgsMapToolIdentifyAction *identifyTool2D = QgisApp::instance()->identifyMapTool();
identifyTool2D->showPointCloudIdentifyResults( layerPoints );
}

void Qgs3DMapToolIdentify::activate()
{
if ( QgsTerrainEntity *terrainEntity = mCanvas->scene()->terrainEntity() )
{
connect( terrainEntity->terrainPicker(), &Qt3DRender::QObjectPicker::clicked, this, &Qgs3DMapToolIdentify::onTerrainPicked );
bool disableTerrainPicker = false;
const Qgs3DMapSettings &map = terrainEntity->map3D();
// if the terrain contains point cloud data disable the terrain picker signals
for ( QgsMapLayer *layer : map.layers() )
{
if ( layer->type() == QgsMapLayerType::PointCloudLayer )
{
disableTerrainPicker = true;
break;
}
}
if ( !disableTerrainPicker )
connect( terrainEntity->terrainPicker(), &Qt3DRender::QObjectPicker::clicked, this, &Qgs3DMapToolIdentify::onTerrainPicked );
}

mCanvas->scene()->registerPickHandler( mPickHandler.get() );
@@ -38,11 +38,7 @@ class Qgs3DMapToolIdentify : public Qgs3DMapTool
~Qgs3DMapToolIdentify() override;

void mousePressEvent( QMouseEvent *event ) override;
void mouseReleaseEvent( QMouseEvent *event ) override
{
Q_UNUSED( event )
emit mouseReleased( event );
}
void mouseReleaseEvent( QMouseEvent *event ) override;
void mouseMoveEvent( QMouseEvent *event ) override {Q_UNUSED( event )}

void activate() override;
@@ -41,6 +41,7 @@
#include "qgsactionscoperegistry.h"
#include "qgssettings.h"
#include "qgsmapmouseevent.h"
#include "qgspointcloudlayer.h"

#include <QCursor>
#include <QPixmap>
@@ -270,3 +271,23 @@ void QgsMapToolIdentifyAction::keyReleaseEvent( QKeyEvent *e )

QgsMapTool::keyReleaseEvent( e );
}

void QgsMapToolIdentifyAction::showPointCloudIdentifyResults( const QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &layersAndPoints )
{
for ( int i = 0; i < layersAndPoints.size(); ++i )
{
QgsMapLayer *layer = layersAndPoints[i].first;
int id = 0;
for ( const QVariantMap &pt : layersAndPoints[i].second )
{
QMap<QString, QString> strMap;
for ( QString key : pt.keys() )
strMap[ key ] = pt[ key ].toString();
resultsDialog()->addFeature( IdentifyResult( layer, QString( "%1_%2" ).arg( layer->name() ).arg( id ), strMap, strMap ) );
++id;
}
}
resultsDialog()->show();
// update possible view modes
resultsDialog()->updateViewModes();
}
@@ -69,6 +69,7 @@ class APP_EXPORT QgsMapToolIdentifyAction : public QgsMapToolIdentify
//! Looks up feature by its ID and outputs the result in GUI
void showResultsForFeature( QgsVectorLayer *vlayer, QgsFeatureId fid, const QgsPoint &pt );

void showPointCloudIdentifyResults( const QVector<QPair<QgsMapLayer *, QVector<QVariantMap>>> &layersAndPoints );
public slots:
void handleCopyToClipboard( QgsFeatureStore & );
void handleChangedRasterResults( QList<QgsMapToolIdentify::IdentifyResult> &results );
@@ -23,6 +23,7 @@
#include "qgsgeometryengine.h"
#include <mutex>
#include <QDebug>
#include <QtMath>

#include <QtConcurrent/QtConcurrentMap>

@@ -407,17 +408,64 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(

return nodes;
}
QVector<QMap<QString, QVariant>> QgsPointCloudDataProvider::getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx )

QVector<QMap<QString, QVariant>> QgsPointCloudDataProvider::getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle )
{
QVector<QMap<QString, QVariant>> points;
qDebug() << "Ray: " << rayOrigin << " " << rayDirection;
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 );
qDebug() << "Intersected nodes: " << nodes.size();

QgsPointCloudAttributeCollection attributeCollection = index->attributes();
QgsPointCloudRequest request;
request.setAttributes( attributeCollection );

for ( IndexedPointCloudNode n : nodes )
{
std::unique_ptr<QgsPointCloudBlock> block( index->nodeData( n, request ) );

if ( !block )
continue;
const char *ptr = block->data();
QgsPointCloudAttributeCollection blockAttributes = block->attributes();
const std::size_t recordSize = blockAttributes.pointRecordSize();
int xOffset, yOffset, zOffset;
blockAttributes.find( QStringLiteral( "X" ), xOffset );
blockAttributes.find( QStringLiteral( "Y" ), yOffset );
blockAttributes.find( QStringLiteral( "Z" ), zOffset );
for ( int i = 0; i < block->pointCount(); ++i )
{
double x, y, z;
_pointXY( ptr, i, recordSize, xOffset, yOffset, index->scale(), index->offset(), x, y );
z = _pointZ( ptr, i, recordSize, zOffset, index->scale(), index->offset() );
QVector3D point( x, y, z );
// project point on ray
QVector3D projectedPoint = rayOrigin + QgsVector3D::dotProduct( point - rayOrigin, rayDirection ) * rayDirection;
// check whether point is in front of the ray
bool isInFront = QgsVector3D::dotProduct( point - rayOrigin, rayDirection ) > 0.0;

if ( !isInFront )
continue;

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

if ( angle > pointAngle )
continue;

QVariantMap pointAttr = _attributeMap( ptr, i * recordSize, blockAttributes );
pointAttr[ QStringLiteral( "X" ) ] = x;
pointAttr[ QStringLiteral( "Y" ) ] = y;
pointAttr[ QStringLiteral( "Z" ) ] = z;
points.push_back( pointAttr );
}
}

return points;
}

@@ -476,7 +524,6 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::getNodesIntersectingWi

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

if ( !__boxIntesects( box, rayOrigin, rayDirection ) )
@@ -490,8 +537,6 @@ QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::getNodesIntersectingWi
if ( phi < maxError )
return nodes;

qDebug() << "Passed";

const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
for ( const IndexedPointCloudNode &nn : children )
{
@@ -121,7 +121,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider
}
% End
#endif
QVector<QMap<QString, QVariant>> getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx ) SIP_SKIP;
QVector<QMap<QString, QVariant>> getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx, double pointAngle ) SIP_SKIP;
QVector<IndexedPointCloudNode> getNodesIntersectingWithRay( const QgsPointCloudIndex *pc, IndexedPointCloudNode n, double maxError, double nodeError, double cameraFov, int screenSizePx, const QVector3D &rayOrigin, const QVector3D &rayDirection );

/**
@@ -621,15 +621,3 @@ void QgsPointCloudLayer::setRenderer( QgsPointCloudRenderer *renderer )
emit rendererChanged();
emit styleChanged();
}

QVector<QMap<QString, QVariant>> QgsPointCloudLayer::getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx )
{
qDebug() << __PRETTY_FUNCTION__ << rayOrigin << " " << rayDirection;
QVector<QMap<QString, QVariant>> points;
QVector3D adjutedRayOrigin = QVector3D( rayOrigin.x(), rayOrigin.y(), ( rayOrigin.z() - mElevationProperties->zOffset() ) / mElevationProperties->zScale() );
QVector3D adjutedRayDirection = QVector3D( rayDirection.x(), rayDirection.y(), rayDirection.z() / mElevationProperties->zScale() );
adjutedRayDirection.normalize();

points = mDataProvider->getPointsOnRay( adjutedRayOrigin, adjutedRayDirection, maxScreenError, cameraFov, screenSizePx );
return points;
}
@@ -167,7 +167,6 @@ class CORE_EXPORT QgsPointCloudLayer : public QgsMapLayer
*/
void setRenderer( QgsPointCloudRenderer *renderer SIP_TRANSFER );

QVector<QMap<QString, QVariant>> getPointsOnRay( const QVector3D &rayOrigin, const QVector3D &rayDirection, double maxScreenError, double cameraFov, int screenSizePx );
private slots:
void onPointCloudIndexGenerationStateChanged( QgsPointCloudDataProvider::PointCloudIndexGenerationState state );

0 comments on commit 3a014ae

Please sign in to comment.
You can’t perform that action at this time.