30#include <QtConcurrent>
31#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
32#include <Qt3DRender/QAttribute>
34#include <Qt3DCore/QAttribute>
36#include <Qt3DRender/QTechnique>
37#include <Qt3DRender/QShaderProgram>
38#include <Qt3DRender/QGraphicsApiFilter>
46QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader(
const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
48 : QgsChunkLoader( node )
50 , mContext( factory->mMap, coordinateTransform, std::move( symbol ), zValueScale, zValueOffset )
56 const QgsChunkNodeId nodeId = node->tileId();
59 Q_ASSERT( pc->
hasNode( pcNode ) );
61 QgsDebugMsgLevel( QStringLiteral(
"loading entity %1" ).arg( node->tileId().text() ), 2 );
63 if ( mContext.symbol()->symbolType() == QLatin1String(
"single-color" ) )
64 mHandler.reset(
new QgsSingleColorPointCloud3DSymbolHandler() );
65 else if ( mContext.symbol()->symbolType() == QLatin1String(
"color-ramp" ) )
66 mHandler.reset(
new QgsColorRampPointCloud3DSymbolHandler() );
67 else if ( mContext.symbol()->symbolType() == QLatin1String(
"rgb" ) )
68 mHandler.reset(
new QgsRGBPointCloud3DSymbolHandler() );
69 else if ( mContext.symbol()->symbolType() == QLatin1String(
"classification" ) )
71 mHandler.reset(
new QgsClassificationPointCloud3DSymbolHandler() );
79 mFutureWatcher =
new QFutureWatcher<void>(
this );
80 connect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
82 const QgsAABB bbox = node->bbox();
83 const QFuture<void> future = QtConcurrent::run( [pc, pcNode, bbox,
this]
85 const QgsEventTracing::ScopedEvent e( QStringLiteral(
"3D" ), QStringLiteral(
"PC chunk load" ) );
87 if ( mContext.isCanceled() )
93 mHandler->processNode( pc, pcNode, mContext );
94 if ( mContext.symbol()->renderAsTriangles() )
95 mHandler->triangulate( pc, pcNode, mContext, bbox );
99 mFutureWatcher->setFuture( future );
102QgsPointCloudLayerChunkLoader::~QgsPointCloudLayerChunkLoader()
104 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
106 disconnect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
107 mContext.cancelRendering();
108 mFutureWatcher->waitForFinished();
112void QgsPointCloudLayerChunkLoader::cancel()
114 mContext.cancelRendering();
117Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntity *parent )
120 const QgsChunkNodeId nodeId = mNode->tileId();
122 Q_ASSERT( pc->
hasNode( pcNode ) );
124 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity( parent );
125 mHandler->finalize( entity, mContext );
133 double zValueScale,
double zValueOffset,
int pointBudget )
135 , mCoordinateTransform( coordinateTransform )
136 , mPointCloudIndex( pc )
137 , mZValueScale( zValueScale )
138 , mZValueOffset( zValueOffset )
139 , mPointBudget( pointBudget )
141 mSymbol.reset( symbol );
144QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node )
const
146 const QgsChunkNodeId
id = node->tileId();
150 return new QgsPointCloudLayerChunkLoader(
this, node, std::unique_ptr< QgsPointCloud3DSymbol >( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset );
153int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node )
const
155 const QgsChunkNodeId
id = node->tileId();
157 Q_ASSERT( mPointCloudIndex->hasNode( n ) );
158 return mPointCloudIndex->nodePointCount( n );
163QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode()
const
165 const QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds(
IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mCoordinateTransform, mZValueOffset );
167 return new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
170QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( QgsChunkNode *node )
const
172 QVector<QgsChunkNode *> children;
173 const QgsChunkNodeId nodeId = node->tileId();
174 const QgsAABB bbox = node->bbox();
175 const float childError = node->error() / 2;
178 for (
int i = 0; i < 8; ++i )
180 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
181 const QgsChunkNodeId childId( nodeId.d + 1, nodeId.x * 2 + dx, nodeId.y * 2 + dy, nodeId.z * 2 + dz );
183 if ( !mPointCloudIndex->hasNode(
IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ) )
189 const float chXMin = dx ? xc : bbox.
xMin;
190 const float chXMax = dx ? bbox.
xMax : xc;
192 const float chZMin = !dy ? zc : bbox.
zMin;
193 const float chZMax = !dy ? bbox.
zMax : zc;
194 const float chYMin = dz ? yc : bbox.
yMin;
195 const float chYMax = dz ? bbox.
yMax : yc;
196 children <<
new QgsChunkNode( childId,
QgsAABB( chXMin, chYMin, chZMin, chXMax, chYMax, chZMax ), childError, node );
206 QgsVector3D extentMin3D( nodeBounds.
xMin() * scale.
x() + offset.
x(), nodeBounds.
yMin() * scale.
y() + offset.
y(), nodeBounds.
zMin() * scale.
z() + offset.
z() + zValueOffset );
207 QgsVector3D extentMax3D( nodeBounds.
xMax() * scale.
x() + offset.
x(), nodeBounds.
yMax() * scale.
y() + offset.
y(), nodeBounds.
zMax() * scale.
z() + offset.
z() + zValueOffset );
212 extentMin3D = extentTransform.
transform( extentMin3D );
213 extentMax3D = extentTransform.
transform( extentMax3D );
217 QgsDebugMsg( QStringLiteral(
"Error transforming node bounds coordinate" ) );
221 QgsAABB rootBbox( worldExtentMin3D.
x(), worldExtentMin3D.
y(), worldExtentMin3D.
z(),
222 worldExtentMax3D.
x(), worldExtentMax3D.
y(), worldExtentMax3D.
z() );
229 float maximumScreenSpaceError,
bool showBoundingBoxes,
230 double zValueScale,
double zValueOffset,
232 : QgsChunkedEntity( maximumScreenSpaceError,
233 new QgsPointCloudLayerChunkLoaderFactory( map, coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
236 setShowBoundingBoxes( showBoundingBoxes );
239QgsPointCloudLayerChunkedEntity::~QgsPointCloudLayerChunkedEntity()
Represents a indexed point cloud node in octree.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
static QgsVector3D mapToWorldCoordinates(const QgsVector3D &mapCoords, const QgsVector3D &origin)
Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x,...
float xCenter() const
Returns center in X axis.
float yCenter() const
Returns center in Y axis.
float zCenter() const
Returns center in Z axis.
QgsPointCloudCategoryList getFilteredOutCategories() const
Gets the list of categories of the classification that should not be rendered.
Custom exception class for Coordinate Reference System related exceptions.
bool renderAsTriangles() const
Returns whether points are triangulated to render solid surface.
Represents packaged data bounds.
qint32 xMax() const
Returns x max.
qint32 xMin() const
Returns x min.
qint32 yMax() const
Returns y max.
qint32 zMax() const
Returns z max.
qint32 yMin() const
Returns y min.
qint32 zMin() const
Returns z min.
Represents a indexed point clouds data in octree.
virtual bool hasNode(const IndexedPointCloudNode &n) const
Returns whether the octree contain given node.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Sets native attributes of the data.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
#define QgsDebugMsgLevel(str, level)