36 #include <QtConcurrent>
37 #include <Qt3DRender/QAttribute>
38 #include <Qt3DRender/QTechnique>
39 #include <Qt3DRender/QShaderProgram>
40 #include <Qt3DRender/QGraphicsApiFilter>
48 QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader(
const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
50 : QgsChunkLoader( node )
52 , mContext( factory->mMap, coordinateTransform, std::move( symbol ), zValueScale, zValueOffset )
58 const QgsChunkNodeId nodeId = node->tileId();
61 Q_ASSERT( pc->
hasNode( pcNode ) );
63 QgsDebugMsgLevel( QStringLiteral(
"loading entity %1" ).arg( node->tileId().text() ), 2 );
65 if ( mContext.symbol()->symbolType() == QLatin1String(
"single-color" ) )
66 mHandler.reset(
new QgsSingleColorPointCloud3DSymbolHandler() );
67 else if ( mContext.symbol()->symbolType() == QLatin1String(
"color-ramp" ) )
68 mHandler.reset(
new QgsColorRampPointCloud3DSymbolHandler() );
69 else if ( mContext.symbol()->symbolType() == QLatin1String(
"rgb" ) )
70 mHandler.reset(
new QgsRGBPointCloud3DSymbolHandler() );
71 else if ( mContext.symbol()->symbolType() == QLatin1String(
"classification" ) )
73 mHandler.reset(
new QgsClassificationPointCloud3DSymbolHandler() );
81 mFutureWatcher =
new QFutureWatcher<void>(
this );
82 connect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
84 const QgsAABB bbox = node->bbox();
85 const QFuture<void> future = QtConcurrent::run( [pc, pcNode, bbox,
this]
87 const QgsEventTracing::ScopedEvent e( QStringLiteral(
"3D" ), QStringLiteral(
"PC chunk load" ) );
89 if ( mContext.isCanceled() )
95 mHandler->processNode( pc, pcNode, mContext );
96 if ( mContext.symbol()->renderAsTriangles() )
97 mHandler->triangulate( pc, pcNode, mContext, bbox );
101 mFutureWatcher->setFuture( future );
104 QgsPointCloudLayerChunkLoader::~QgsPointCloudLayerChunkLoader()
106 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
108 disconnect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
109 mContext.cancelRendering();
110 mFutureWatcher->waitForFinished();
114 void QgsPointCloudLayerChunkLoader::cancel()
116 mContext.cancelRendering();
119 Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntity *parent )
122 const QgsChunkNodeId nodeId = mNode->tileId();
124 Q_ASSERT( pc->
hasNode( pcNode ) );
126 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity( parent );
127 mHandler->finalize( entity, mContext );
135 double zValueScale,
double zValueOffset,
int pointBudget )
137 , mCoordinateTransform( coordinateTransform )
138 , mPointCloudIndex( pc )
139 , mZValueScale( zValueScale )
140 , mZValueOffset( zValueOffset )
141 , mPointBudget( pointBudget )
146 QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node )
const
148 const QgsChunkNodeId
id = node->tileId();
152 return new QgsPointCloudLayerChunkLoader(
this, node, std::unique_ptr< QgsPointCloud3DSymbol >( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset );
155 int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node )
const
157 const QgsChunkNodeId
id = node->tileId();
159 Q_ASSERT( mPointCloudIndex->hasNode( n ) );
160 return mPointCloudIndex->nodePointCount( n );
165 QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode()
const
167 const QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds(
IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mCoordinateTransform, mZValueOffset );
169 return new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
172 QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( QgsChunkNode *node )
const
174 QVector<QgsChunkNode *> children;
175 const QgsChunkNodeId nodeId = node->tileId();
176 const QgsAABB bbox = node->bbox();
177 const float childError = node->error() / 2;
180 for (
int i = 0; i < 8; ++i )
182 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
183 const QgsChunkNodeId childId( nodeId.d + 1, nodeId.x * 2 + dx, nodeId.y * 2 + dy, nodeId.z * 2 + dz );
185 if ( !mPointCloudIndex->hasNode(
IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ) )
191 const float chXMin = dx ? xc : bbox.
xMin;
192 const float chXMax = dx ? bbox.
xMax : xc;
194 const float chZMin = !dy ? zc : bbox.
zMin;
195 const float chZMax = !dy ? bbox.
zMax : zc;
196 const float chYMin = dz ? yc : bbox.
yMin;
197 const float chYMax = dz ? bbox.
yMax : yc;
198 children <<
new QgsChunkNode( childId,
QgsAABB( chXMin, chYMin, chZMin, chXMax, chYMax, chZMax ), childError, node );
208 QgsVector3D extentMin3D( nodeBounds.
xMin() * scale.
x() + offset.
x(), nodeBounds.
yMin() * scale.
y() + offset.
y(), nodeBounds.
zMin() * scale.
z() + offset.
z() + zValueOffset );
209 QgsVector3D extentMax3D( nodeBounds.
xMax() * scale.
x() + offset.
x(), nodeBounds.
yMax() * scale.
y() + offset.
y(), nodeBounds.
zMax() * scale.
z() + offset.
z() + zValueOffset );
214 extentMin3D = extentTransform.
transform( extentMin3D );
215 extentMax3D = extentTransform.
transform( extentMax3D );
219 QgsDebugMsg( QStringLiteral(
"Error transforming node bounds coordinate" ) );
223 QgsAABB rootBbox( worldExtentMin3D.
x(), worldExtentMin3D.
y(), worldExtentMin3D.
z(),
224 worldExtentMax3D.
x(), worldExtentMax3D.
y(), worldExtentMax3D.
z() );
231 float maximumScreenSpaceError,
bool showBoundingBoxes,
232 double zValueScale,
double zValueOffset,
234 : QgsChunkedEntity( maximumScreenSpaceError,
235 new QgsPointCloudLayerChunkLoaderFactory( map, coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
241 QgsPointCloudLayerChunkedEntity::~QgsPointCloudLayerChunkedEntity()