18#include <QElapsedTimer> 
   40  , mLayerAttributes( layer->attributes() )
 
   41  , mSubIndexes( layer && layer->dataProvider() ? layer->dataProvider()->subIndexes() : QVector<QgsPointCloudSubIndex>() )
 
   50  if ( !mSubIndexes.isEmpty() )
 
   61    mZOffset = elevationProps->zOffset();
 
   62    mZScale = elevationProps->zScale();
 
   82  if ( !mClippingRegions.empty() )
 
   84    bool needsPainterClipPath = 
false;
 
   86    if ( needsPainterClipPath )
 
   90  if ( mRenderer->type() == QLatin1String( 
"extent" ) )
 
   93    mRenderer->startRender( context );
 
   95    mRenderer->stopRender( context );
 
  102  if ( mSubIndexes.isEmpty() &&
 
  113    mBlockRenderUpdates = 
true;
 
  114    mElapsedTimer.start();
 
  117  mRenderer->startRender( context );
 
  129  QSet< QString > rendererAttributes = mRenderer->usedAttributes( context );
 
  132  for ( 
const QString &attribute : std::as_const( rendererAttributes ) )
 
  134    if ( mAttributes.
indexOf( attribute ) >= 0 )
 
  137    const int layerIndex = mLayerAttributes.
indexOf( attribute );
 
  138    if ( layerIndex < 0 )
 
  140      QgsMessageLog::logMessage( QObject::tr( 
"Required attribute %1 not found in layer" ).arg( attribute ), QObject::tr( 
"Point Cloud" ) );
 
  144    mAttributes.
push_back( mLayerAttributes.
at( layerIndex ) );
 
  154    QgsDebugError( QStringLiteral( 
"Transformation of extent failed!" ) );
 
  157  bool canceled = 
false;
 
  158  if ( mSubIndexes.isEmpty() )
 
  160    canceled = !renderIndex( pc );
 
  164    mSubIndexExtentRenderer->startRender( context );
 
  165    for ( 
const auto &si : mSubIndexes )
 
  172      if ( !renderExtent.
intersects( si.extent() ) )
 
  175      if ( !pc || !pc->
isValid() || renderExtent.
width() > si.extent().width() )
 
  179        mSubIndexExtentRenderer->renderExtent( si.polygonBounds(), context );
 
  183        canceled = !renderIndex( pc );
 
  186    mSubIndexExtentRenderer->stopRender( context );
 
  189  mRenderer->stopRender( context );
 
  211  const double maximumError = context.renderContext().convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );
 
  215  if ( !context.renderContext().coordinateTransform().isShortCircuited() )
 
  225      QgsDebugError( QStringLiteral( 
"Could not transform node extent to map CRS" ) );
 
  226      rootNodeExtentMapCoords = rootNodeExtentLayerCoords;
 
  231    rootNodeExtentMapCoords = rootNodeExtentLayerCoords;
 
  234  const double rootErrorInMapCoordinates = rootNodeExtentMapCoords.
width() / pc->
span(); 
 
  236  double mapUnitsPerPixel = context.renderContext().mapToPixel().mapUnitsPerPixel();
 
  237  if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumError < 0.0 ) )
 
  242  double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; 
 
  243  const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, context.renderContext(), pc->
root(), maximumError, rootErrorPixels );
 
  250  bool canceled = 
false;
 
  252  switch ( mRenderer->drawOrder2d() )
 
  257      nodesDrawn += renderNodesSorted( nodes, pc, context, request, canceled, mRenderer->drawOrder2d() );
 
  264        case QgsPointCloudIndex::AccessType::Local:
 
  266          nodesDrawn += renderNodesSync( nodes, pc, context, request, canceled );
 
  269        case QgsPointCloudIndex::AccessType::Remote:
 
  271          nodesDrawn += renderNodesAsync( nodes, pc, context, request, canceled );
 
  279  QgsDebugMsgLevel( QStringLiteral( 
"totals: %1 nodes | %2 points | %3ms" ).arg( nodesDrawn )
 
  280                    .arg( context.pointsRendered() )
 
  281                    .arg( t.elapsed() ), 2 );
 
  300    std::unique_ptr<QgsPointCloudBlock> block( pc->
nodeData( n, request ) );
 
  313    mRenderer->renderBlock( block.get(), context );
 
  339  QVector<QgsPointCloudBlockRequest *> blockRequests;
 
  344  for ( 
int i = 0; i < nodes.size(); ++i )
 
  349    blockRequests.append( blockRequest );
 
  351                      [ 
this, &canceled, &nodesDrawn, &loop, &blockRequests, &context, nStr, blockRequest ]()
 
  353      blockRequests.removeOne( blockRequest );
 
  356      if ( blockRequests.isEmpty() )
 
  359      std::unique_ptr<QgsPointCloudBlock> block( blockRequest->
block() );
 
  361      blockRequest->deleteLater();
 
  371        QgsDebugError( QStringLiteral( 
"Unable to load node %1, error: %2" ).arg( nStr, blockRequest->
errorStr() ) );
 
  382      mRenderer->renderBlock( block.get(), context );
 
  407    delete blockRequest->
block();
 
  408    blockRequest->deleteLater();
 
  425  QByteArray allByteArrays;
 
  427  QVector<QPair<int, double>> allPairs;
 
  437    std::unique_ptr<QgsPointCloudBlock> block( pc->
nodeData( n, request ) );
 
  445    if ( blockCount == 0 )
 
  447      blockScale = block->scale();
 
  448      blockOffset = block->offset();
 
  453      offsetDifference = blockOffset - block->offset();
 
  456    const char *ptr = block->data();
 
  464    for ( 
int i = 0; i < block->pointCount(); ++i )
 
  466      allByteArrays.append( ptr + i * recordSize, recordSize );
 
  469      if ( offsetDifference.
x() != 0 )
 
  471        qint32 ix = *
reinterpret_cast< const qint32 * 
>( ptr + i * recordSize + context.
xOffset() );
 
  472        ix -= std::lround( offsetDifference.
x() / context.
scale().
x() );
 
  473        const char *xPtr = 
reinterpret_cast< const char * 
>( &ix );
 
  474        allByteArrays.replace( pointCount * recordSize + context.
xOffset(), 4, QByteArray( xPtr, 4 ) );
 
  476      if ( offsetDifference.
y() != 0 )
 
  478        qint32 iy = *
reinterpret_cast< const qint32 * 
>( ptr + i * recordSize + context.
yOffset() );
 
  479        iy -= std::lround( offsetDifference.
y() / context.
scale().
y() );
 
  480        const char *yPtr = 
reinterpret_cast< const char * 
>( &iy );
 
  481        allByteArrays.replace( pointCount * recordSize + context.
yOffset(), 4, QByteArray( yPtr, 4 ) );
 
  484      qint32 iz = *
reinterpret_cast< const qint32 * 
>( ptr + i * recordSize + context.
zOffset() );
 
  485      if ( offsetDifference.
z() != 0 )
 
  487        iz -= std::lround( offsetDifference.
z() / context.
scale().
z() );
 
  488        const char *zPtr = 
reinterpret_cast< const char * 
>( &iz );
 
  489        allByteArrays.replace( pointCount * recordSize + context.
zOffset(), 4, QByteArray( zPtr, 4 ) );
 
  491      allPairs.append( qMakePair( pointCount, 
double( iz ) + block->offset().z() ) );
 
  498  if ( pointCount == 0 )
 
  504      std::sort( allPairs.begin(), allPairs.end(), []( QPair<int, double> a, QPair<int, double> b ) { return a.second < b.second; } );
 
  507      std::sort( allPairs.begin(), allPairs.end(), []( QPair<int, double> a, QPair<int, double> b ) { return a.second > b.second; } );
 
  514  QByteArray sortedByteArray;
 
  515  sortedByteArray.reserve( allPairs.size() );
 
  516  for ( QPair<int, double> pair : allPairs )
 
  517    sortedByteArray.append( allByteArrays.mid( pair.first * recordSize, recordSize ) );
 
  528  context.
setScale( bigBlock->scale() );
 
  532  mRenderer->renderBlock( bigBlock.get(), context );
 
  544  return mRenderer ? mRenderer->type() != QLatin1String( 
"extent" ) : 
false;
 
  549  mRenderTimeHint = time;
 
  552QVector<IndexedPointCloudNode> QgsPointCloudLayerRenderer::traverseTree( 
const QgsPointCloudIndex *pc,
 
  555    double maxErrorPixels,
 
  556    double nodeErrorPixels )
 
  558  QVector<IndexedPointCloudNode> nodes;
 
  577  double childrenErrorPixels = nodeErrorPixels / 2.0;
 
  578  if ( childrenErrorPixels < maxErrorPixels )
 
  581  const QList<IndexedPointCloudNode> children = pc->
nodeChildren( n );
 
  584    nodes += traverseTree( pc, context, nn, maxErrorPixels, childrenErrorPixels );
 
Represents a indexed point cloud node in octree.
 
QString toString() const
Encode node to string.
 
PointCloudDrawOrder
Pointcloud rendering order for 2d views.
 
@ BottomToTop
Draw points with larger Z values last.
 
@ Default
Draw points in the order they are stored.
 
@ TopToBottom
Draw points with larger Z values first.
 
Custom exception class for Coordinate Reference System related exceptions.
 
QgsRange which stores a range of double values.
 
bool isInfinite() const
Returns true if the range consists of all possible values.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
void canceled()
Internal routines can connect to this signal if they use event loop.
 
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
 
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
 
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
 
Base class for utility classes that encapsulate information necessary for rendering of map layers.
 
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
 
static constexpr int MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE
Maximum time (in ms) to allow display of a previously cached preview image while rendering layers,...
 
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
 
Collection of point cloud attributes.
 
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
 
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
 
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
 
int indexOf(const QString &name) const
Returns the index of the attribute with the specified name.
 
Attribute for point cloud data pair of name and size in bytes.
 
Base class for handling loading QgsPointCloudBlock asynchronously.
 
QString errorStr()
Returns the error message string of the request.
 
QgsPointCloudBlock * block()
Returns the requested block.
 
void finished()
Emitted when the request processing has finished.
 
Base class for storing raw data from point cloud nodes.
 
virtual QgsPointCloudIndex * index() const
Returns the point cloud index associated with the provider.
 
virtual QgsGeometry polygonBounds() const
Returns the polygon bounds of the layer.
 
A renderer for 2d visualisation of point clouds which shows the dataset's extents using a fill symbol...
 
Represents a indexed point clouds data in octree.
 
int span() const
Returns the number of points in one direction in a single node.
 
virtual qint64 nodePointCount(const IndexedPointCloudNode &n) const
Returns the number of points of a given node n.
 
QgsRectangle nodeMapExtent(const IndexedPointCloudNode &node) const
Returns the extent of a node in map coordinates.
 
virtual QgsPointCloudBlockRequest * asyncNodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns a handle responsible for loading a node data block.
 
virtual QList< IndexedPointCloudNode > nodeChildren(const IndexedPointCloudNode &n) const
Returns all children of node.
 
QgsVector3D offset() const
Returns offset.
 
QgsVector3D scale() const
Returns scale.
 
virtual AccessType accessType() const =0
Returns the access type of the data If the access type is Remote, data will be fetched from an HTTP s...
 
virtual bool isValid() const =0
Returns whether index is loaded and valid.
 
virtual QgsPointCloudBlock * nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
 
IndexedPointCloudNode root()
Returns root node of the index.
 
QgsDoubleRange nodeZRange(const IndexedPointCloudNode &node) const
Returns the z range of a node.
 
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
 
~QgsPointCloudLayerRenderer()
 
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
 
QgsPointCloudLayerRenderer(QgsPointCloudLayer *layer, QgsRenderContext &context)
Ctor.
 
void setLayerRenderingTimeHint(int time) override
Sets approximate render time (in ms) for the layer to render.
 
bool render() override
Do the rendering (based on data stored in the class).
 
Represents a map layer supporting display of point clouds.
 
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
 
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
 
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
 
Encapsulates the render context for a 2D point cloud rendering operation.
 
int yOffset() const
Returns the offset for the y value in a point record.
 
QgsVector3D offset() const
Returns the offset of the layer's int32 coordinates compared to CRS coords.
 
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
 
void setOffset(const QgsVector3D &offset)
Sets the offset of the layer's int32 coordinates compared to CRS coords.
 
void setScale(const QgsVector3D &scale)
Sets the scale of the layer's int32 coordinates compared to CRS coords.
 
int pointRecordSize() const
Returns the size of a single point record.
 
int xOffset() const
Returns the offset for the x value in a point record.
 
QgsVector3D scale() const
Returns the scale of the layer's int32 coordinates compared to CRS coords.
 
int zOffset() const
Returns the offset for the y value in a point record.
 
QgsFeedback * feedback() const
Returns the feedback object used to cancel rendering.
 
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Sets the attributes associated with the rendered block.
 
virtual QgsPointCloudRenderer * clone() const =0
Create a deep copy of this renderer.
 
Point cloud data request.
 
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
 
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
 
T lower() const
Returns the lower bound of the range.
 
T upper() const
Returns the upper bound of the range.
 
A rectangle specified with double values.
 
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
 
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
 
Contains information about the context of a rendering operation.
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
 
QgsElevationMap * elevationMap() const
Returns the destination elevation map for the render operation.
 
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
 
QgsDoubleRange zRange() const
Returns the range of z-values which should be rendered.
 
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
 
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
 
Scoped object for saving and restoring a QPainter object's state.
 
double y() const
Returns Y coordinate.
 
double z() const
Returns Z coordinate.
 
double x() const
Returns X coordinate.
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)