Skip to content
Permalink
Browse files

Fix 3D point cloud position when layer CRS != project CRS (#41538)

* hopefully fixes CRS problem

* fix the 3D map position shift

* remove qDebug

* add catch throw around transformInPlace

* switch to using QgsCoordinateTransform::transform

* move QgsCoordinateTransform to transform context

* remove TODO and fix layout

* add docs

* rename variable

* hadle bounding box coordinate transformation
  • Loading branch information
NEDJIMAbelgacem committed Feb 18, 2021
1 parent a89241c commit d80c27d94b3adda4bea2305c10c0c7865dbda9b2
@@ -213,6 +213,20 @@ otherwise points are transformed from destination to source CRS.
:param direction: transform direction (defaults to ForwardTransform)

:return: transformed point
%End

QgsVector3D transform( const QgsVector3D &point, TransformDirection direction = ForwardTransform ) const;
%Docstring
Transform the point specified in 3D coordinates from the source CRS to the destination CRS.
If the direction is ForwardTransform then coordinates are transformed from source to destination,
otherwise points are transformed from destination to source CRS.

:param point: coordinates of point to transform
:param direction: transform direction (defaults to ForwardTransform)

:return: transformed point

.. versionadded:: 3.18
%End

QgsRectangle transformBoundingBox( const QgsRectangle &rectangle, TransformDirection direction = ForwardTransform, bool handle180Crossover = false ) const throw( QgsCsException );
@@ -29,11 +29,12 @@

#include "qgis.h"

QgsPointCloud3DRenderContext::QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, std::unique_ptr<QgsPointCloud3DSymbol> symbol, double zValueScale, double zValueFixedOffset )
QgsPointCloud3DRenderContext::QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, std::unique_ptr<QgsPointCloud3DSymbol> symbol, double zValueScale, double zValueFixedOffset )
: Qgs3DRenderContext( map )
, mSymbol( std::move( symbol ) )
, mZValueScale( zValueScale )
, mZValueFixedOffset( zValueFixedOffset )
, mCoordinateTransform( coordinateTransform )
{
auto callback = []()->bool
{
@@ -65,6 +66,11 @@ QSet<int> QgsPointCloud3DRenderContext::getFilteredOutValues() const
return filteredOut;
}

void QgsPointCloud3DRenderContext::setCoordinateTransform( const QgsCoordinateTransform &coordinateTransform )
{
mCoordinateTransform = coordinateTransform;
}

QgsPointCloudLayer3DRendererMetadata::QgsPointCloudLayer3DRendererMetadata()
: Qgs3DRendererAbstractMetadata( QStringLiteral( "pointcloud" ) )
{
@@ -121,7 +127,9 @@ Qt3DCore::QEntity *QgsPointCloudLayer3DRenderer::createEntity( const Qgs3DMapSet
if ( !mSymbol )
return nullptr;

return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), mMaximumScreenError, showBoundingBoxes(),
QgsCoordinateTransform coordinateTransform( pcl->crs(), map.crs(), map.transformContext() );

return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, coordinateTransform, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), maximumScreenError(), showBoundingBoxes(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zScale(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zOffset(), mPointBudget );
}
@@ -206,3 +214,5 @@ void QgsPointCloudLayer3DRenderer::setPointRenderingBudget( int budget )
{
mPointBudget = budget;
}


@@ -52,7 +52,7 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
* The \a zValueFixedOffset argument specifies any constant offset value which must be added to z values
* taken from the point cloud index.
*/
QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
double zValueScale, double zValueFixedOffset );

//! QgsPointCloudRenderContext cannot be copied.
@@ -160,6 +160,16 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
*/
bool isCanceled() const { return mIsCanceledCallback(); }

/**
* Sets the coordinate transform used to transform points from layer CRS to the map CRS
*/
void setCoordinateTransform( const QgsCoordinateTransform &coordinateTransform );

/**
* Returns the coordinate transform used to transform points from layer CRS to the map CRS
*/
QgsCoordinateTransform coordinateTransform() const { return mCoordinateTransform; }

private:
#ifdef SIP_RUN
QgsPointCloudRenderContext( const QgsPointCloudRenderContext &rh );
@@ -169,6 +179,7 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
QgsPointCloudCategoryList mFilteredOutCategories;
double mZValueScale = 1.0;
double mZValueFixedOffset = 0;
QgsCoordinateTransform mCoordinateTransform;

std::function< bool() > mIsCanceledCallback;

@@ -47,10 +47,10 @@
///////////////

QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
double zValueScale, double zValueOffset )
const QgsCoordinateTransform &coordinateTransform, double zValueScale, double zValueOffset )
: QgsChunkLoader( node )
, mFactory( factory )
, mContext( factory->mMap, std::move( symbol ), zValueScale, zValueOffset )
, mContext( factory->mMap, coordinateTransform, std::move( symbol ), zValueScale, zValueOffset )
{
mContext.setIsCanceledCallback( [this] { return mCanceled; } );

@@ -128,9 +128,10 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit
///////////////


QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
double zValueScale, double zValueOffset, int pointBudget )
: mMap( map )
, mCoordinateTransform( coordinateTransform )
, mPointCloudIndex( pc )
, mZValueScale( zValueScale )
, mZValueOffset( zValueOffset )
@@ -142,9 +143,10 @@ QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( cons
QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node ) const
{
QgsChunkNodeId id = node->tileId();
IndexedPointCloudNode n( id.d, id.x, id.y, id.z );
Q_ASSERT( mPointCloudIndex->hasNode( n ) );
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() ) ), mZValueScale, mZValueOffset );

Q_ASSERT( mPointCloudIndex->hasNode( IndexedPointCloudNode( id.d, id.x, id.y, id.z ) ) );
QgsPointCloud3DSymbol *symbol = static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() );
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset );
}

int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node ) const
@@ -155,11 +157,11 @@ int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node )
return mPointCloudIndex->nodePointCount( n );
}

QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, double zValueOffset );
QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, double zValueOffset );

QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode() const
{
QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds( IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mZValueOffset );
QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds( IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mCoordinateTransform, mZValueOffset );
float error = mPointCloudIndex->nodeError( IndexedPointCloudNode( 0, 0, 0, 0 ) );
return new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
}
@@ -198,11 +200,19 @@ QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( Qg
///////////////


QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, double zValueOffset )
QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, double zValueOffset )
{
// TODO: reprojection from layer to map coordinates if needed
QgsVector3D extentMin3D( nodeBounds.xMin() * scale.x() + offset.x(), nodeBounds.yMin() * scale.y() + offset.y(), nodeBounds.zMin() * scale.z() + offset.z() + zValueOffset );
QgsVector3D extentMax3D( nodeBounds.xMax() * scale.x() + offset.x(), nodeBounds.yMax() * scale.y() + offset.y(), nodeBounds.zMax() * scale.z() + offset.z() + zValueOffset );
try
{
extentMin3D = coordinateTransform.transform( extentMin3D );
extentMax3D = coordinateTransform.transform( extentMax3D );
}
catch ( QgsCsException &e )
{
QgsDebugMsg( QStringLiteral( "Error transforming node bounds coordinate" ) );
}
QgsVector3D worldExtentMin3D = Qgs3DUtils::mapToWorldCoordinates( extentMin3D, map.origin() );
QgsVector3D worldExtentMax3D = Qgs3DUtils::mapToWorldCoordinates( extentMax3D, map.origin() );
QgsAABB rootBbox( worldExtentMin3D.x(), worldExtentMin3D.y(), worldExtentMin3D.z(),
@@ -211,9 +221,9 @@ QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset
}


QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, double maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
: QgsChunkedEntity( maximumScreenSpaceError,
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
new QgsPointCloudLayerChunkLoaderFactory( map, coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
{
setUsingAdditiveStrategy( true );
setShowBoundingBoxes( showBoundingBoxes );
@@ -59,7 +59,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
* Constructs the factory
* The factory takes ownership over the passed \a symbol
*/
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
double zValueScale, double zValueOffset, int pointBudget );

//! Creates loader for the given chunk node. Ownership of the returned is passed to the caller.
@@ -68,6 +68,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
virtual QVector<QgsChunkNode *> createChildren( QgsChunkNode *node ) const override;
virtual int primitivesCount( QgsChunkNode *node ) const override;
const Qgs3DMapSettings &mMap;
QgsCoordinateTransform mCoordinateTransform;
QgsPointCloudIndex *mPointCloudIndex;
std::unique_ptr< QgsPointCloud3DSymbol > mSymbol;
double mZValueScale = 1.0;
@@ -92,7 +93,8 @@ class QgsPointCloudLayerChunkLoader : public QgsChunkLoader
* Constructs the loader
* QgsPointCloudLayerChunkLoader takes ownership over symbol
*/
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueScale, double zValueOffset );
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
const QgsCoordinateTransform &coordinateTransform, double zValueScale, double zValueOffset );
~QgsPointCloudLayerChunkLoader() override;

virtual void cancel() override;
@@ -121,7 +123,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity
{
Q_OBJECT
public:
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, double maximumScreenSpaceError, bool showBoundingBoxes,
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes,
double zValueScale, double zValueOffset, int pointBudget );

~QgsPointCloudLayerChunkedEntity();
@@ -261,6 +261,8 @@ void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *p
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();
QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
bool alreadyPrintedDebug = false;

for ( int i = 0; i < count; ++i )
{
@@ -274,8 +276,20 @@ void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *p
double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
try
{
coordinateTransform.transformInPlace( x, y, z );
}
catch ( QgsCsException &e )
{
if ( !alreadyPrintedDebug )
{
QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
alreadyPrintedDebug = true;
}
}
QgsVector3D point( x, y, z );
QgsVector3D p = context.map().mapToWorldCoordinates( point );
QgsVector3D p = context.map().mapToWorldCoordinates( QgsVector3D( x, y, z ) );
outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
}
}
@@ -320,6 +334,9 @@ void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc,
int attributeOffset = 0;
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();
QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
bool alreadyPrintedDebug = false;

QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
if ( symbol )
{
@@ -379,10 +396,21 @@ void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc,
double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
try
{
coordinateTransform.transformInPlace( x, y, z );
}
catch ( QgsCsException &e )
{
if ( !alreadyPrintedDebug )
{
QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
alreadyPrintedDebug = true;
}
}
QgsVector3D point( x, y, z );

QgsVector3D p = context.map().mapToWorldCoordinates( point );
outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
point = context.map().mapToWorldCoordinates( point );
outNormal.positions.push_back( QVector3D( point.x(), point.y(), point.z() ) );

if ( attrIsX )
outNormal.parameter.push_back( x );
@@ -462,6 +490,8 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();
QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
bool alreadyPrintedDebug = false;

QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
@@ -485,6 +515,18 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
try
{
coordinateTransform.transformInPlace( x, y, z );
}
catch ( QgsCsException &e )
{
if ( !alreadyPrintedDebug )
{
QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
alreadyPrintedDebug = true;
}
}
QgsVector3D point( x, y, z );
QgsVector3D p = context.map().mapToWorldCoordinates( point );

@@ -611,6 +653,8 @@ void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();
QgsCoordinateTransform coordinateTransform = context.coordinateTransform();
bool alreadyPrintedDebug = false;

QSet<int> filteredOutValues = context.getFilteredOutValues();
for ( int i = 0; i < count; ++i )
@@ -625,8 +669,19 @@ void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex
double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
try
{
coordinateTransform.transformInPlace( x, y, z );
}
catch ( QgsCsException &e )
{
if ( !alreadyPrintedDebug )
{
QgsDebugMsg( QStringLiteral( "Error transforming point coordinate" ) );
alreadyPrintedDebug = true;
}
}
QgsVector3D point( x, y, z );

QgsVector3D p = context.map().mapToWorldCoordinates( point );
float iParam = 0.0f;
if ( attrIsX )
@@ -24,6 +24,7 @@
#include "qgsexception.h"
#include "qgsproject.h"
#include "qgsreadwritelocker.h"
#include "qgsvector3d.h"

//qt includes
#include <QDomNode>
@@ -310,6 +311,24 @@ QgsRectangle QgsCoordinateTransform::transform( const QgsRectangle &rect, Transf
return QgsRectangle( x1, y1, x2, y2 );
}

QgsVector3D QgsCoordinateTransform::transform( const QgsVector3D &point, TransformDirection direction ) const
{
double x = point.x();
double y = point.y();
double z = point.z();
try
{
transformCoords( 1, &x, &y, &z, direction );
}
catch ( const QgsCsException & )
{
// rethrow the exception
QgsDebugMsgLevel( QStringLiteral( "rethrowing exception" ), 2 );
throw;
}
return QgsVector3D( x, y, z );
}

void QgsCoordinateTransform::transformInPlace( double &x, double &y, double &z,
TransformDirection direction ) const
{

0 comments on commit d80c27d

Please sign in to comment.