26#include <QtConcurrentRun>
31size_t qHash(
const QgsChunkNodeId &n )
45 return size.
x() > 1e5 || size.
y() > 1e5 || size.
z() > 1e5;
50QgsTiledSceneChunkLoader::QgsTiledSceneChunkLoader( QgsChunkNode *node,
const QgsTiledSceneIndex &index,
const QgsTiledSceneChunkLoaderFactory &factory,
double zValueScale,
double zValueOffset )
51 : QgsChunkLoader( node )
55 mFutureWatcher =
new QFutureWatcher<void>(
this );
56 connect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
58 const QgsChunkNodeId tileId = node->tileId();
59 const QFuture<void> future = QtConcurrent::run( [
this, tileId, zValueScale, zValueOffset]
66 if ( hasLargeBounds( tile ) )
69 QString uri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
77 uri = tile.
baseUrl().resolved( uri ).toString();
78 QByteArray content = mFactory.mIndex.retrieveContent( uri );
79 if ( content.isEmpty() )
87 if ( tileContent.
gltf.isEmpty() )
93 QgsGltf3DUtils::EntityTransform entityTransform;
95 entityTransform.tileTransform.translate( tileContent.
rtcCenter );
96 entityTransform.sceneOriginTargetCrs = mFactory.mMap.origin();
97 entityTransform.ecefToTargetCrs = &mFactory.mBoundsTransform;
98 entityTransform.zValueScale = zValueScale;
99 entityTransform.zValueOffset = zValueOffset;
100 entityTransform.gltfUpAxis =
static_cast< Qgis::Axis >( tile.
metadata().value( QStringLiteral(
"gltfUpAxis" ),
static_cast< int >(
Qgis::Axis::Y ) ).toInt() );
103 mEntity = QgsGltf3DUtils::gltfToEntity( tileContent.
gltf, entityTransform, uri, &errors );
109 if ( !errors.isEmpty() )
116 mFutureWatcher->setFuture( future );
119QgsTiledSceneChunkLoader::~QgsTiledSceneChunkLoader()
121 if ( !mFutureWatcher->isFinished() )
123 disconnect( mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsChunkQueueJob::finished );
124 mFutureWatcher->waitForFinished();
128Qt3DCore::QEntity *QgsTiledSceneChunkLoader::createEntity( Qt3DCore::QEntity *parent )
131 return new Qt3DCore::QEntity( parent );
133 mEntity->setParent( parent );
139QgsTiledSceneChunkLoaderFactory::QgsTiledSceneChunkLoaderFactory(
const Qgs3DMapSettings &map,
const QgsTiledSceneIndex &index,
double zValueScale,
double zValueOffset )
142 , mZValueScale( zValueScale )
143 , mZValueOffset( zValueOffset )
148QgsChunkLoader *QgsTiledSceneChunkLoaderFactory::createChunkLoader( QgsChunkNode *node )
const
150 return new QgsTiledSceneChunkLoader( node, mIndex, *
this, mZValueScale, mZValueOffset );
156 const QgsBox3D b = b0 - sceneOriginTargetCrs;
160QgsChunkNode *QgsTiledSceneChunkLoaderFactory::nodeForTile(
const QgsTiledSceneTile &t,
const QgsChunkNodeId &nodeId, QgsChunkNode *parent )
const
162 QgsChunkNode *node =
nullptr;
163 if ( hasLargeBounds( t ) )
166 QgsVector3D v0 = mMap.mapToWorldCoordinates(
QgsVector3D( mMap.extent().xMinimum(), mMap.extent().yMinimum(), -100 ) );
167 QgsVector3D v1 = mMap.mapToWorldCoordinates(
QgsVector3D( mMap.extent().xMaximum(), mMap.extent().yMaximum(), +100 ) );
168 QgsAABB aabb( v0.
x(), v0.
y(), v0.
z(), v1.
x(), v1.
y(), v1.
z() );
170 node =
new QgsChunkNode( nodeId, aabb, err, parent );
177 const QgsAABB aabb = aabbConvert( box, mMap.origin() );
178 node =
new QgsChunkNode( nodeId, aabb, t.
geometricError(), parent );
186QgsChunkNode *QgsTiledSceneChunkLoaderFactory::createRootNode()
const
189 return nodeForTile( t, QgsChunkNodeId( t.
id() ),
nullptr );
193QVector<QgsChunkNode *> QgsTiledSceneChunkLoaderFactory::createChildren( QgsChunkNode *node )
const
195 QVector<QgsChunkNode *> children;
196 const long long indexTileId = node->tileId().uniqueId;
201 const QVector< long long > childIds = mIndex.childTileIds( indexTileId );
202 for (
long long childId : childIds )
204 const QgsChunkNodeId chId( childId );
208 if ( hasLargeBounds( t ) )
219 const double *half = obb.
halfAxes();
223 half[0], half[3], half[6], 0,
224 half[1], half[4], half[7], 0,
225 half[2], half[5], half[8], 0,
227 QVector3D aaa = rot.inverted().map( ecef2.
toVector3D() );
229 if ( aaa.x() > 1 || aaa.y() > 1 || aaa.z() > 1 ||
230 aaa.x() < -1 || aaa.y() < -1 || aaa.z() < -1 )
239 QgsChunkNode *nChild = nodeForTile( t, chId, node );
240 children.append( nChild );
245bool QgsTiledSceneChunkLoaderFactory::canCreateChildren( QgsChunkNode *node )
247 long long nodeId = node->tileId().uniqueId;
248 if ( mFutureHierarchyFetches.contains( nodeId ) || mPendingHierarchyFetches.contains( nodeId ) )
253 mFutureHierarchyFetches.insert( nodeId );
261 const QVector< long long > childIds = mIndex.childTileIds( nodeId );
262 for (
long long childId : childIds )
264 if ( mFutureHierarchyFetches.contains( childId ) || mPendingHierarchyFetches.contains( childId ) )
269 mFutureHierarchyFetches.insert( childId );
276void QgsTiledSceneChunkLoaderFactory::fetchHierarchyForNode(
long long nodeId, QgsChunkNode *origNode )
278 Q_ASSERT( !mPendingHierarchyFetches.contains( nodeId ) );
279 mFutureHierarchyFetches.remove( nodeId );
280 mPendingHierarchyFetches.insert( nodeId );
282 QFutureWatcher<void> *futureWatcher =
new QFutureWatcher<void>(
this );
283 connect( futureWatcher, &QFutureWatcher<void>::finished,
this, [
this, origNode, nodeId, futureWatcher]
285 mPendingHierarchyFetches.remove( nodeId );
286 emit childrenPrepared( origNode );
287 futureWatcher->deleteLater();
289 futureWatcher->setFuture( QtConcurrent::run( [
this, nodeId]
291 mIndex.fetchHierarchy( nodeId );
295void QgsTiledSceneChunkLoaderFactory::prepareChildren( QgsChunkNode *node )
297 long long nodeId = node->tileId().uniqueId;
298 if ( mFutureHierarchyFetches.contains( nodeId ) )
300 fetchHierarchyForNode( nodeId, node );
308 const QVector< long long > childIds = mIndex.childTileIds( nodeId );
309 for (
long long childId : childIds )
311 if ( mFutureHierarchyFetches.contains( childId ) )
313 fetchHierarchyForNode( childId, node );
321QgsTiledSceneLayerChunkedEntity::QgsTiledSceneLayerChunkedEntity(
const Qgs3DMapSettings &map,
const QgsTiledSceneIndex &index,
double maximumScreenError,
bool showBoundingBoxes,
double zValueScale,
double zValueOffset )
322 : QgsChunkedEntity( maximumScreenError, new QgsTiledSceneChunkLoaderFactory( map, index, zValueScale, zValueOffset ), true )
325 setShowBoundingBoxes( showBoundingBoxes );
328QgsTiledSceneLayerChunkedEntity::~QgsTiledSceneLayerChunkedEntity()
334int QgsTiledSceneLayerChunkedEntity::pendingJobsCount()
const
336 return QgsChunkedEntity::pendingJobsCount() +
static_cast<QgsTiledSceneChunkLoaderFactory *
>( mChunkLoaderFactory )->mPendingHierarchyFetches.count();
339QVector<QgsRayCastingUtils::RayHit> QgsTiledSceneLayerChunkedEntity::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray,
const QgsRayCastingUtils::RayCastContext &context )
const
349 QVector<QgsRayCastingUtils::RayHit> result;
351 QVector3D intersectionPoint;
352 QgsChunkNode *minNode =
nullptr;
353 int minTriangleIndex = -1;
355 const QList<QgsChunkNode *> active = activeNodes();
356 for ( QgsChunkNode *node : active )
361 if ( node->entity() &&
362 ( minDist < 0 || node->bbox().distanceFromPoint( ray.origin() ) < minDist ) &&
363 QgsRayCastingUtils::rayBoxIntersection( ray, node->bbox() ) )
368 const QList<Qt3DRender::QGeometryRenderer *> rendLst = node->entity()->findChildren<Qt3DRender::QGeometryRenderer *>();
369 for (
const auto &rend : rendLst )
371 QVector3D nodeIntPoint;
372 int triangleIndex = -1;
373 bool success = QgsRayCastingUtils::rayMeshIntersection( rend, ray, QMatrix4x4(), nodeIntPoint, triangleIndex );
379 float dist = ( ray.origin() - nodeIntPoint ).length();
380 if ( minDist < 0 || dist < minDist )
384 minTriangleIndex = triangleIndex;
385 intersectionPoint = nodeIntPoint;
397 vm[
"node_id"] = tile.
id();
399 vm[
"node_content"] = tile.
resources().value( QStringLiteral(
"content" ) );
400 vm[
"triangle_index"] = minTriangleIndex;
402 result.append( hit );
405 QgsDebugMsgLevel( QStringLiteral(
"Active Nodes: %1, checked nodes: %2, hits found: %3" ).arg( nodesAll ).arg( nodeUsed ).arg( hits ), 2 );
@ NeedFetching
Tile has children, but they are not yet available and must be fetched.
@ Reverse
Reverse/inverse transform (from destination to source)
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
A 3-dimensional box composed of x, y, z coordinates.
double yMaximum() const
Returns the maximum y value.
void setZMinimum(double z)
Sets the minimum z value.
void setZMaximum(double z)
Sets the maximum z value.
double xMinimum() const
Returns the minimum x value.
double zMaximum() const
Returns the maximum z value.
double xMaximum() const
Returns the maximum x value.
double zMinimum() const
Returns the minimum z value.
double yMinimum() const
Returns the minimum y value.
static TileContents extractGltfFromTileContent(const QByteArray &tileContent)
Parses tile content.
This class represents a coordinate reference system (CRS).
A simple 4x4 matrix implementation useful for transformation in 3D space.
Represents a oriented (rotated) box in 3 dimensions.
const double * halfAxes() const
Returns the half axes matrix;.
bool isNull() const
Returns true if the box is a null box.
QgsVector3D center() const
Returns the vector to the center of the box.
QgsVector3D size() const
Returns size of sides of the box.
A class to represent a 2D point.
QgsOrientedBox3D box() const
Returns the volume's oriented box.
QgsBox3D bounds(const QgsCoordinateTransform &transform=QgsCoordinateTransform(), Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Returns the axis aligned bounding box of the volume.
An index for tiled scene data providers.
Represents an individual tile from a tiled scene data source.
Qgis::TileRefinementProcess refinementProcess() const
Returns the tile's refinement process.
QVariantMap resources() const
Returns the resources attached to the tile.
const QgsTiledSceneBoundingVolume & boundingVolume() const
Returns the bounding volume for the tile.
QVariantMap metadata() const
Returns additional metadata attached to the tile.
long long id() const
Returns the tile's unique ID.
const QgsMatrix4x4 * transform() const
Returns the tile's transform.
double geometricError() const
Returns the tile's geometric error, which is the error, in scene CRS units, of the tile's simplified ...
QUrl baseUrl() const
Returns the tile's base URL.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
QVector3D toVector3D() const
Converts the current object to QVector3D.
double x() const
Returns X coordinate.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
uint qHash(const QVariant &variant)
Hash for QVariant.
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
Encapsulates the contents of a 3D tile.
QgsVector3D rtcCenter
Optional RTC center.
QByteArray gltf
GLTF binary content.
Helper struct to store ray casting parameters.
Helper struct to store ray casting results.