32#include <QtConcurrent> 
   33#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 
   34#include <Qt3DRender/QAttribute> 
   36#include <Qt3DCore/QAttribute> 
   38#include <Qt3DRender/QTechnique> 
   39#include <Qt3DRender/QShaderProgram> 
   40#include <Qt3DRender/QGraphicsApiFilter> 
   48QgsPointCloudLayerChunkLoader::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 );
 
  104QgsPointCloudLayerChunkLoader::~QgsPointCloudLayerChunkLoader()
 
  106  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
 
  108    disconnect( mFutureWatcher, &QFutureWatcher<void>::finished, 
this, &QgsChunkQueueJob::finished );
 
  109    mContext.cancelRendering();
 
  110    mFutureWatcher->waitForFinished();
 
  114void QgsPointCloudLayerChunkLoader::cancel()
 
  116  mContext.cancelRendering();
 
  119Qt3DCore::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 )
 
  143  mSymbol.reset( symbol );
 
  152    QgsDebugError( QStringLiteral( 
"Transformation of extent failed." ) );
 
  156QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node )
 const 
  158  const QgsChunkNodeId 
id = node->tileId();
 
  162  return new QgsPointCloudLayerChunkLoader( 
this, node, std::unique_ptr< QgsPointCloud3DSymbol >( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset );
 
  165int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node )
 const 
  167  const QgsChunkNodeId 
id = node->tileId();
 
  169  Q_ASSERT( mPointCloudIndex->hasNode( n ) );
 
  170  return mPointCloudIndex->nodePointCount( n );
 
  175QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode()
 const 
  177  const QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds( 
IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mCoordinateTransform, mZValueOffset );
 
  179  QgsChunkNode *node = 
new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
 
  184QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( QgsChunkNode *node )
 const 
  186  QVector<QgsChunkNode *> children;
 
  187  const QgsChunkNodeId nodeId = node->tileId();
 
  188  const QgsAABB bbox = node->bbox();
 
  189  const float childError = node->error() / 2;
 
  192  for ( 
int i = 0; i < 8; ++i )
 
  194    int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
 
  195    const QgsChunkNodeId childId( nodeId.d + 1, nodeId.x * 2 + dx, nodeId.y * 2 + dy, nodeId.z * 2 + dz );
 
  197    if ( !mPointCloudIndex->hasNode( 
IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ) )
 
  199    if ( !mExtent.isEmpty() &&
 
  200         !mPointCloudIndex->nodeMapExtent( 
IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ).intersects( mExtent ) )
 
  206    const float chXMin = dx ? xc : bbox.
xMin;
 
  207    const float chXMax = dx ? bbox.
xMax : xc;
 
  209    const float chZMin = !dy ? zc : bbox.
zMin;
 
  210    const float chZMax = !dy ? bbox.
zMax : zc;
 
  211    const float chYMin = dz ? yc : bbox.
yMin;
 
  212    const float chYMax = dz ? bbox.
yMax : yc;
 
  213    QgsChunkNode *child = 
new QgsChunkNode( childId, 
QgsAABB( chXMin, chYMin, chZMin, chXMax, chYMax, chZMax ), childError, node );
 
  225  QgsVector3D extentMin3D( nodeBounds.
xMin() * scale.
x() + offset.
x(), nodeBounds.
yMin() * scale.
y() + offset.
y(), nodeBounds.
zMin() * scale.
z() + offset.
z() + zValueOffset );
 
  226  QgsVector3D extentMax3D( nodeBounds.
xMax() * scale.
x() + offset.
x(), nodeBounds.
yMax() * scale.
y() + offset.
y(), nodeBounds.
zMax() * scale.
z() + offset.
z() + zValueOffset );
 
  231    extentMin3D = extentTransform.
transform( extentMin3D );
 
  232    extentMax3D = extentTransform.
transform( extentMax3D );
 
  236    QgsDebugError( QStringLiteral( 
"Error transforming node bounds coordinate" ) );
 
  240  QgsAABB rootBbox( worldExtentMin3D.
x(), worldExtentMin3D.
y(), worldExtentMin3D.
z(),
 
  241                    worldExtentMax3D.
x(), worldExtentMax3D.
y(), worldExtentMax3D.
z() );
 
  248    float maximumScreenSpaceError, 
bool showBoundingBoxes,
 
  249    double zValueScale, 
double zValueOffset,
 
  251  : QgsChunkedEntity( maximumScreenSpaceError,
 
  252                      new QgsPointCloudLayerChunkLoaderFactory( map, coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
 
  254  setShowBoundingBoxes( showBoundingBoxes );
 
  257QgsPointCloudLayerChunkedEntity::~QgsPointCloudLayerChunkedEntity()
 
  263QVector<QgsRayCastingUtils::RayHit> QgsPointCloudLayerChunkedEntity::rayIntersection( 
const QgsRayCastingUtils::Ray3D &ray, 
const QgsRayCastingUtils::RayCastContext &context )
 const 
  265  QVector<QgsRayCastingUtils::RayHit> result;
 
  266  QgsPointCloudLayerChunkLoaderFactory *factory = 
static_cast<QgsPointCloudLayerChunkLoaderFactory *
>( mChunkLoaderFactory );
 
  269  const QgsVector3D rayOriginMapCoords = factory->mMap.worldToMapCoordinates( ray.origin() );
 
  270  const QgsVector3D pointMapCoords = factory->mMap.worldToMapCoordinates( ray.origin() + ray.origin().length() * ray.direction().normalized() );
 
  271  QgsVector3D rayDirectionMapCoords = pointMapCoords - rayOriginMapCoords;
 
  280  const double pointSize = symbol->
pointSize();
 
  285  const double limitAngle = 2. * pointSize / screenSizePx * factory->mMap.fieldOfView();
 
  288  const QgsVector3D adjustedRayOrigin = 
QgsVector3D( rayOriginMapCoords.x(), rayOriginMapCoords.y(), ( rayOriginMapCoords.z() -  factory->mZValueOffset ) / factory->mZValueScale );
 
  289  QgsVector3D adjustedRayDirection = 
QgsVector3D( rayDirectionMapCoords.
x(), rayDirectionMapCoords.
y(), rayDirectionMapCoords.
z() / factory->mZValueScale );
 
  298  double minDist = -1.;
 
  299  const QList<QgsChunkNode *> activeNodes = this->activeNodes();
 
  300  for ( QgsChunkNode *node : activeNodes )
 
  302    const QgsChunkNodeId 
id = node->tileId();
 
  308    if ( !QgsRayCastingUtils::rayBoxIntersection( ray, node->bbox() ) )
 
  311    std::unique_ptr<QgsPointCloudBlock> block( index->
nodeData( n, request ) );
 
  318    const char *ptr = block->data();
 
  321    int xOffset = 0, yOffset = 0, zOffset = 0;
 
  325    for ( 
int i = 0; i < block->pointCount(); ++i )
 
  328      QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, blockScale, blockOffset, x, y, z );
 
  333      QgsVector3D vectorToPoint = point - adjustedRayOrigin;
 
  341      const QgsVector3D v1 = projPoint - adjustedRayOrigin ;
 
  344      if ( angle > limitAngle )
 
  347      const double dist = rayOriginMapCoords.distance( point );
 
  349      if ( minDist < 0 || dist < minDist )
 
  360      pointAttr[ QStringLiteral( 
"X" ) ] = x;
 
  361      pointAttr[ QStringLiteral( 
"Y" ) ] = y;
 
  362      pointAttr[ QStringLiteral( 
"Z" ) ] = z;
 
  364      const QgsVector3D worldPoint = factory->mMap.mapToWorldCoordinates( point );
 
  368      result.append( hit );
 
Represents a indexed point cloud node in octree.
 
The Qgis class provides global constants for use throughout the application.
 
@ Replacement
When tile is refined then its children should be used in place of itself.
 
@ Reverse
Reverse/inverse transform (from destination to source)
 
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.
 
float pointSize() const
Returns the point size of the point cloud.
 
Collection of point cloud attributes.
 
int pointRecordSize() const
Returns total size of record.
 
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
 
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
 
DataType
Systems of unit measurement.
 
static void getPointXYZ(const char *ptr, int i, std::size_t pointRecordSize, int xOffset, QgsPointCloudAttribute::DataType xType, int yOffset, QgsPointCloudAttribute::DataType yType, int zOffset, QgsPointCloudAttribute::DataType zType, const QgsVector3D &indexScale, const QgsVector3D &indexOffset, double &x, double &y, double &z)
Retrieves the x, y, z values for the point at index i.
 
static QVariantMap getAttributeMap(const char *data, std::size_t recordOffset, const QgsPointCloudAttributeCollection &attributeCollection)
Retrieves all the attributes of a point.
 
DataType type() const
Returns the data type.
 
Represents packaged data bounds.
 
qint64 xMin() const
Returns x min.
 
qint64 zMin() const
Returns z min.
 
qint64 yMax() const
Returns y max.
 
qint64 xMax() const
Returns x max.
 
qint64 zMax() const
Returns z max.
 
qint64 yMin() const
Returns y min.
 
Represents a indexed point clouds data in octree.
 
virtual bool hasNode(const IndexedPointCloudNode &n) const
Returns whether the octree contain given node.
 
virtual std::unique_ptr< QgsPointCloudBlock > nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
 
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Sets native attributes of the data.
 
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
 
Point cloud data request.
 
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
 
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.
 
static double dotProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the dot product of two vectors.
 
double x() const
Returns X coordinate.
 
void normalize()
Normalizes the current vector in place.
 
double length() const
Returns the length of the vector.
 
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
Helper struct to store ray casting parameters.
 
QSize screenSize
QSize of the 3d engine window.
 
bool singleResult
If set to true, only the closest point cloud hit will be returned (other entities always return only ...
 
Helper struct to store ray casting results.