QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgspointcloudlayerrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspointcloudlayerrenderer.cpp
3  --------------------
4  begin : October 2020
5  copyright : (C) 2020 by Peter Petrik
6  email : zilolv at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <QElapsedTimer>
19 #include <QPointer>
20 
22 #include "qgspointcloudlayer.h"
23 #include "qgsrendercontext.h"
24 #include "qgspointcloudindex.h"
25 #include "qgsstyle.h"
26 #include "qgscolorramp.h"
27 #include "qgspointcloudrequest.h"
28 #include "qgspointcloudattribute.h"
29 #include "qgspointcloudrenderer.h"
31 #include "qgslogger.h"
33 #include "qgsmessagelog.h"
34 #include "qgscircle.h"
35 #include "qgsmapclippingutils.h"
37 
39  : QgsMapLayerRenderer( layer->id(), &context )
40  , mLayer( layer )
41  , mLayerAttributes( layer->attributes() )
42  , mFeedback( new QgsFeedback )
43 {
44  // TODO: we must not keep pointer to mLayer (it's dangerous) - we must copy anything we need for rendering
45  // or use some locking to prevent read/write from multiple threads
46  if ( !mLayer || !mLayer->dataProvider() || !mLayer->renderer() )
47  return;
48 
49  mRenderer.reset( mLayer->renderer()->clone() );
50 
51  if ( mLayer->dataProvider()->index() )
52  {
53  mScale = mLayer->dataProvider()->index()->scale();
54  mOffset = mLayer->dataProvider()->index()->offset();
55  }
56 
57  if ( const QgsPointCloudLayerElevationProperties *elevationProps = qobject_cast< const QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() ) )
58  {
59  mZOffset = elevationProps->zOffset();
60  mZScale = elevationProps->zScale();
61  }
62 
63  mCloudExtent = mLayer->dataProvider()->polygonBounds();
64 
66 
67  mReadyToCompose = false;
68 }
69 
71 {
72  QgsPointCloudRenderContext context( *renderContext(), mScale, mOffset, mZScale, mZOffset, mFeedback.get() );
73 
74  // Set up the render configuration options
75  QPainter *painter = context.renderContext().painter();
76 
77  QgsScopedQPainterState painterState( painter );
78  context.renderContext().setPainterFlagsUsingContext( painter );
79 
80  if ( !mClippingRegions.empty() )
81  {
82  bool needsPainterClipPath = false;
83  const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), QgsMapLayerType::VectorTileLayer, needsPainterClipPath );
84  if ( needsPainterClipPath )
85  renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
86  }
87 
88  if ( mRenderer->type() == QLatin1String( "extent" ) )
89  {
90  // special case for extent only renderer!
91  mRenderer->startRender( context );
92  static_cast< QgsPointCloudExtentRenderer * >( mRenderer.get() )->renderExtent( mCloudExtent, context );
93  mRenderer->stopRender( context );
94  mReadyToCompose = true;
95  return true;
96  }
97 
98  // TODO cache!?
99  QgsPointCloudIndex *pc = mLayer->dataProvider()->index();
100  if ( !pc || !pc->isValid() )
101  {
102  mReadyToCompose = true;
103  return false;
104  }
105 
106  // if the previous layer render was relatively quick (e.g. less than 3 seconds), the we show any previously
107  // cached version of the layer during rendering instead of the usual progressive updates
108  if ( mRenderTimeHint > 0 && mRenderTimeHint <= MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
109  {
110  mBlockRenderUpdates = true;
111  mElapsedTimer.start();
112  }
113 
114  mRenderer->startRender( context );
115 
116  mAttributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
117  mAttributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
118 
119  if ( !context.renderContext().zRange().isInfinite() ||
120  mRenderer->drawOrder2d() == Qgis::PointCloudDrawOrder::BottomToTop ||
121  mRenderer->drawOrder2d() == Qgis::PointCloudDrawOrder::TopToBottom )
122  mAttributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
123 
124  // collect attributes required by renderer
125  QSet< QString > rendererAttributes = mRenderer->usedAttributes( context );
126 
127 
128  for ( const QString &attribute : std::as_const( rendererAttributes ) )
129  {
130  if ( mAttributes.indexOf( attribute ) >= 0 )
131  continue; // don't re-add attributes we are already going to fetch
132 
133  const int layerIndex = mLayerAttributes.indexOf( attribute );
134  if ( layerIndex < 0 )
135  {
136  QgsMessageLog::logMessage( QObject::tr( "Required attribute %1 not found in layer" ).arg( attribute ), QObject::tr( "Point Cloud" ) );
137  continue;
138  }
139 
140  mAttributes.push_back( mLayerAttributes.at( layerIndex ) );
141  }
142 
144 
145 #ifdef QGISDEBUG
146  QElapsedTimer t;
147  t.start();
148 #endif
149 
150  const IndexedPointCloudNode root = pc->root();
151 
152  const double maximumError = context.renderContext().convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );// in pixels
153 
154  const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root );
155  QgsRectangle rootNodeExtentMapCoords;
157  {
158  try
159  {
160  QgsCoordinateTransform extentTransform = context.renderContext().coordinateTransform();
161  extentTransform.setBallparkTransformsAreAppropriate( true );
162  rootNodeExtentMapCoords = extentTransform.transformBoundingBox( rootNodeExtentLayerCoords );
163  }
164  catch ( QgsCsException & )
165  {
166  QgsDebugMsg( QStringLiteral( "Could not transform node extent to map CRS" ) );
167  rootNodeExtentMapCoords = rootNodeExtentLayerCoords;
168  }
169  }
170  else
171  {
172  rootNodeExtentMapCoords = rootNodeExtentLayerCoords;
173  }
174 
175  const double rootErrorInMapCoordinates = rootNodeExtentMapCoords.width() / pc->span(); // in map coords
176 
177  double mapUnitsPerPixel = context.renderContext().mapToPixel().mapUnitsPerPixel();
178  if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumError < 0.0 ) )
179  {
180  QgsDebugMsg( QStringLiteral( "invalid screen error" ) );
181  mReadyToCompose = true;
182  return false;
183  }
184  double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels
185  const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, context.renderContext(), pc->root(), maximumError, rootErrorPixels );
186 
187  QgsPointCloudRequest request;
188  request.setAttributes( mAttributes );
189 
190  // drawing
191  int nodesDrawn = 0;
192  bool canceled = false;
193 
194  switch ( mRenderer->drawOrder2d() )
195  {
198  {
199  nodesDrawn += renderNodesSorted( nodes, pc, context, request, canceled, mRenderer->drawOrder2d() );
200  break;
201  }
203  {
204  switch ( pc->accessType() )
205  {
206  case QgsPointCloudIndex::AccessType::Local:
207  {
208  nodesDrawn += renderNodesSync( nodes, pc, context, request, canceled );
209  break;
210  }
211  case QgsPointCloudIndex::AccessType::Remote:
212  {
213  nodesDrawn += renderNodesAsync( nodes, pc, context, request, canceled );
214  break;
215  }
216  }
217  }
218  }
219 
220 #ifdef QGISDEBUG
221  QgsDebugMsgLevel( QStringLiteral( "totals: %1 nodes | %2 points | %3ms" ).arg( nodesDrawn )
222  .arg( context.pointsRendered() )
223  .arg( t.elapsed() ), 2 );
224 #else
225  ( void )nodesDrawn;
226 #endif
227 
228  mRenderer->stopRender( context );
229 
230  mReadyToCompose = true;
231  return !canceled;
232 }
233 
234 int QgsPointCloudLayerRenderer::renderNodesSync( const QVector<IndexedPointCloudNode> &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled )
235 {
236  int nodesDrawn = 0;
237  for ( const IndexedPointCloudNode &n : nodes )
238  {
239  if ( context.renderContext().renderingStopped() )
240  {
241  QgsDebugMsgLevel( QStringLiteral( "canceled" ), 2 );
242  canceled = true;
243  break;
244  }
245  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
246 
247  if ( !block )
248  continue;
249 
250  QgsVector3D contextScale = context.scale();
251  QgsVector3D contextOffset = context.offset();
252 
253  context.setScale( block->scale() );
254  context.setOffset( block->offset() );
255 
256  context.setAttributes( block->attributes() );
257 
258  mRenderer->renderBlock( block.get(), context );
259 
260  context.setScale( contextScale );
261  context.setOffset( contextOffset );
262 
263  ++nodesDrawn;
264 
265  // as soon as first block is rendered, we can start showing layer updates.
266  // but if we are blocking render updates (so that a previously cached image is being shown), we wait
267  // at most e.g. 3 seconds before we start forcing progressive updates.
268  if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
269  {
270  mReadyToCompose = true;
271  }
272  }
273  return nodesDrawn;
274 }
275 
276 int QgsPointCloudLayerRenderer::renderNodesAsync( const QVector<IndexedPointCloudNode> &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled )
277 {
278  int nodesDrawn = 0;
279 
280  if ( context.feedback() && context.feedback()->isCanceled() )
281  return 0;
282 
283  // Async loading of nodes
284  QVector<QgsPointCloudBlockRequest *> blockRequests;
285  QEventLoop loop;
286  if ( context.feedback() )
287  QObject::connect( context.feedback(), &QgsFeedback::canceled, &loop, &QEventLoop::quit );
288 
289  for ( int i = 0; i < nodes.size(); ++i )
290  {
291  const IndexedPointCloudNode &n = nodes[i];
292  const QString nStr = n.toString();
293  QgsPointCloudBlockRequest *blockRequest = pc->asyncNodeData( n, request );
294  blockRequests.append( blockRequest );
295  QObject::connect( blockRequest, &QgsPointCloudBlockRequest::finished, &loop,
296  [ this, &canceled, &nodesDrawn, &loop, &blockRequests, &context, nStr, blockRequest ]()
297  {
298  blockRequests.removeOne( blockRequest );
299 
300  // If all blocks are loaded, exit the event loop
301  if ( blockRequests.isEmpty() )
302  loop.exit();
303 
304  std::unique_ptr<QgsPointCloudBlock> block( blockRequest->block() );
305 
306  blockRequest->deleteLater();
307 
308  if ( context.feedback() && context.feedback()->isCanceled() )
309  {
310  canceled = true;
311  return;
312  }
313 
314  if ( !block )
315  {
316  QgsDebugMsg( QStringLiteral( "Unable to load node %1, error: %2" ).arg( nStr, blockRequest->errorStr() ) );
317  return;
318  }
319 
320  QgsVector3D contextScale = context.scale();
321  QgsVector3D contextOffset = context.offset();
322 
323  context.setScale( block->scale() );
324  context.setOffset( block->offset() );
325  context.setAttributes( block->attributes() );
326 
327  mRenderer->renderBlock( block.get(), context );
328 
329  context.setScale( contextScale );
330  context.setOffset( contextOffset );
331 
332  ++nodesDrawn;
333 
334  // as soon as first block is rendered, we can start showing layer updates.
335  // but if we are blocking render updates (so that a previously cached image is being shown), we wait
336  // at most e.g. 3 seconds before we start forcing progressive updates.
337  if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
338  {
339  mReadyToCompose = true;
340  }
341 
342  } );
343  }
344 
345  // Wait for all point cloud nodes to finish loading
346  loop.exec();
347 
348  // Rendering may have got canceled and the event loop exited before finished()
349  // was called for all blocks, so let's clean up anything that is left
350  for ( QgsPointCloudBlockRequest *blockRequest : std::as_const( blockRequests ) )
351  {
352  delete blockRequest->block();
353  blockRequest->deleteLater();
354  }
355 
356  return nodesDrawn;
357 }
358 
359 int QgsPointCloudLayerRenderer::renderNodesSorted( const QVector<IndexedPointCloudNode> &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled, Qgis::PointCloudDrawOrder order )
360 {
361  int blockCount = 0;
362  int pointCount = 0;
363 
364  QgsVector3D blockScale;
365  QgsVector3D blockOffset;
366  QgsPointCloudAttributeCollection blockAttributes;
367  int recordSize = 0;
368 
369  // We'll collect byte array data from all blocks
370  QByteArray allByteArrays;
371  // And pairs of byte array start positions paired with their Z values for sorting
372  QVector<QPair<int, double>> allPairs;
373 
374  for ( const IndexedPointCloudNode &n : nodes )
375  {
376  if ( context.renderContext().renderingStopped() )
377  {
378  QgsDebugMsgLevel( QStringLiteral( "canceled" ), 2 );
379  canceled = true;
380  break;
381  }
382  std::unique_ptr<QgsPointCloudBlock> block( pc->nodeData( n, request ) );
383 
384  if ( !block )
385  continue;
386 
387  // Individual nodes may have different offset values than the root node
388  // we'll calculate the differences and translate x,y,z values to use the root node's offset
389  QgsVector3D offsetDifference = QgsVector3D( 0, 0, 0 );
390  if ( blockCount == 0 )
391  {
392  blockScale = block->scale();
393  blockOffset = block->offset();
394  blockAttributes = block->attributes();
395  }
396  else
397  {
398  offsetDifference = blockOffset - block->offset();
399  }
400 
401  const char *ptr = block->data();
402 
403  context.setScale( block->scale() );
404  context.setOffset( block->offset() );
405  context.setAttributes( block->attributes() );
406 
407  recordSize = context.pointRecordSize();
408 
409  for ( int i = 0; i < block->pointCount(); ++i )
410  {
411  allByteArrays.append( ptr + i * recordSize, recordSize );
412 
413  // Calculate the translated values only for axes that have a different offset
414  if ( offsetDifference.x() != 0 )
415  {
416  qint32 ix = *reinterpret_cast< const qint32 * >( ptr + i * recordSize + context.xOffset() );
417  ix -= std::lround( offsetDifference.x() / context.scale().x() );
418  const char *xPtr = reinterpret_cast< const char * >( &ix );
419  allByteArrays.replace( pointCount * recordSize + context.xOffset(), 4, QByteArray( xPtr, 4 ) );
420  }
421  if ( offsetDifference.y() != 0 )
422  {
423  qint32 iy = *reinterpret_cast< const qint32 * >( ptr + i * recordSize + context.yOffset() );
424  iy -= std::lround( offsetDifference.y() / context.scale().y() );
425  const char *yPtr = reinterpret_cast< const char * >( &iy );
426  allByteArrays.replace( pointCount * recordSize + context.yOffset(), 4, QByteArray( yPtr, 4 ) );
427  }
428  // We need the Z value regardless of the node's offset
429  qint32 iz = *reinterpret_cast< const qint32 * >( ptr + i * recordSize + context.zOffset() );
430  if ( offsetDifference.z() != 0 )
431  {
432  iz -= std::lround( offsetDifference.z() / context.scale().z() );
433  const char *zPtr = reinterpret_cast< const char * >( &iz );
434  allByteArrays.replace( pointCount * recordSize + context.zOffset(), 4, QByteArray( zPtr, 4 ) );
435  }
436  allPairs.append( qMakePair( pointCount, double( iz ) + block->offset().z() ) );
437 
438  ++pointCount;
439  }
440  ++blockCount;
441  }
442 
443  if ( pointCount == 0 )
444  return 0;
445 
446  switch ( order )
447  {
449  std::sort( allPairs.begin(), allPairs.end(), []( QPair<int, double> a, QPair<int, double> b ) { return a.second < b.second; } );
450  break;
452  std::sort( allPairs.begin(), allPairs.end(), []( QPair<int, double> a, QPair<int, double> b ) { return a.second > b.second; } );
453  break;
455  break;
456  }
457 
458  // Now we can reconstruct a byte array sorted by Z value
459  QByteArray sortedByteArray;
460  sortedByteArray.reserve( allPairs.size() );
461  for ( QPair<int, double> pair : allPairs )
462  sortedByteArray.append( allByteArrays.mid( pair.first * recordSize, recordSize ) );
463 
464  std::unique_ptr<QgsPointCloudBlock> bigBlock { new QgsPointCloudBlock( pointCount,
465  blockAttributes,
466  sortedByteArray,
467  blockScale,
468  blockOffset ) };
469 
470  QgsVector3D contextScale = context.scale();
471  QgsVector3D contextOffset = context.offset();
472 
473  context.setScale( bigBlock->scale() );
474  context.setOffset( bigBlock->offset() );
475  context.setAttributes( bigBlock->attributes() );
476 
477  mRenderer->renderBlock( bigBlock.get(), context );
478 
479  context.setScale( contextScale );
480  context.setOffset( contextOffset );
481 
482  return blockCount;
483 }
484 
486 {
487  // unless we are using the extent only renderer, point cloud layers should always be rasterized -- we don't want to export points as vectors
488  // to formats like PDF!
489  return mRenderer ? mRenderer->type() != QLatin1String( "extent" ) : false;
490 }
491 
493 {
494  mRenderTimeHint = time;
495 }
496 
497 QVector<IndexedPointCloudNode> QgsPointCloudLayerRenderer::traverseTree( const QgsPointCloudIndex *pc,
498  const QgsRenderContext &context,
500  double maxErrorPixels,
501  double nodeErrorPixels )
502 {
503  QVector<IndexedPointCloudNode> nodes;
504 
505  if ( context.renderingStopped() )
506  {
507  QgsDebugMsgLevel( QStringLiteral( "canceled" ), 2 );
508  return nodes;
509  }
510 
511  if ( !context.extent().intersects( pc->nodeMapExtent( n ) ) )
512  return nodes;
513 
514  const QgsDoubleRange nodeZRange = pc->nodeZRange( n );
515  const QgsDoubleRange adjustedNodeZRange = QgsDoubleRange( nodeZRange.lower() + mZOffset, nodeZRange.upper() + mZOffset );
516  if ( !context.zRange().isInfinite() && !context.zRange().overlaps( adjustedNodeZRange ) )
517  return nodes;
518 
519  nodes.append( n );
520 
521  double childrenErrorPixels = nodeErrorPixels / 2.0;
522  if ( childrenErrorPixels < maxErrorPixels )
523  return nodes;
524 
525  const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
526  for ( const IndexedPointCloudNode &nn : children )
527  {
528  nodes += traverseTree( pc, context, nn, maxErrorPixels, childrenErrorPixels );
529  }
530 
531  return nodes;
532 }
533 
QgsRectangle::intersects
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:349
QgsMapClippingUtils::collectClippingRegionsForLayer
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.
Definition: qgsmapclippingutils.cpp:24
QgsPointCloudIndex::nodeMapExtent
QgsRectangle nodeMapExtent(const IndexedPointCloudNode &node) const
Returns the extent of a node in map coordinates.
Definition: qgspointcloudindex.cpp:216
QgsPointCloudLayerRenderer::render
bool render() override
Do the rendering (based on data stored in the class).
Definition: qgspointcloudlayerrenderer.cpp:70
QgsPointCloudIndex::offset
QgsVector3D offset() const
Returns offset.
Definition: qgspointcloudindex.cpp:237
QgsRenderContext::setPainterFlagsUsingContext
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
Definition: qgsrendercontext.cpp:169
QgsPointCloudBlockRequest::block
QgsPointCloudBlock * block()
Returns the requested block.
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:258
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns the current map units per pixel.
Definition: qgsmaptopixel.h:229
QgsPointCloudIndex::nodeData
virtual QgsPointCloudBlock * nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
QgsRange::overlaps
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
Definition: qgsrange.h:147
qgspointcloudblockrequest.h
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsVector3D::y
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:64
QgsPointCloudLayerElevationProperties
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
Definition: qgspointcloudlayerelevationproperties.h:33
QgsPointCloudLayer
Represents a map layer supporting display of point clouds.
Definition: qgspointcloudlayer.h:45
QgsVector3D
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition: qgsvector3d.h:31
QgsFeedback::canceled
void canceled()
Internal routines can connect to this signal if they use event loop.
QgsPointCloudIndex::nodeChildren
virtual QList< IndexedPointCloudNode > nodeChildren(const IndexedPointCloudNode &n) const
Returns all children of node.
Definition: qgspointcloudindex.cpp:172
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
QgsPointCloudAttributeCollection::at
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
Definition: qgspointcloudattribute.h:170
QgsPointCloudExtentRenderer
A renderer for 2d visualisation of point clouds which shows the dataset's extents using a fill symbol...
Definition: qgspointcloudextentrenderer.h:33
QgsPointCloudRenderContext::setScale
void setScale(const QgsVector3D &scale)
Sets the scale of the layer's int32 coordinates compared to CRS coords.
Definition: qgspointcloudrenderer.h:86
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsMapLayerRenderer::renderContext
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
Definition: qgsmaplayerrenderer.h:111
QgsPointCloudRenderer::clone
virtual QgsPointCloudRenderer * clone() const =0
Create a deep copy of this renderer.
qgspointcloudattribute.h
QgsMapLayerRenderer::mReadyToCompose
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
Definition: qgsmaplayerrenderer.h:171
QgsPointCloudBlock
Base class for storing raw data from point cloud nodes.
Definition: qgspointcloudblock.h:38
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsPointCloudLayer::renderer
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
Definition: qgspointcloudlayer.cpp:706
QgsRenderContext::extent
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
Definition: qgsrendercontext.h:239
QgsPointCloudIndex::isValid
virtual bool isValid() const =0
Returns whether index is loaded and valid.
Qgis::PointCloudDrawOrder::TopToBottom
@ TopToBottom
Draw points with larger Z values first.
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsPointCloudIndex::accessType
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...
QgsMapLayerRenderer
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Definition: qgsmaplayerrenderer.h:54
QgsPointCloudRequest
Point cloud data request.
Definition: qgspointcloudrequest.h:39
QgsPointCloudRenderContext::xOffset
int xOffset() const
Returns the offset for the x value in a point record.
Definition: qgspointcloudrenderer.h:137
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:285
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsPointCloudLayer::dataProvider
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Definition: qgspointcloudlayer.cpp:114
IndexedPointCloudNode
Represents a indexed point cloud node in octree.
Definition: qgspointcloudindex.h:57
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsRange::lower
T lower() const
Returns the lower bound of the range.
Definition: qgsrange.h:66
QgsCoordinateTransform::isShortCircuited
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
Definition: qgscoordinatetransform.cpp:905
QgsPointCloudDataProvider::polygonBounds
virtual QgsGeometry polygonBounds() const
Returns the polygon bounds of the layer.
Definition: qgspointclouddataprovider.cpp:53
qgspointcloudlayer.h
QgsPointCloudAttribute::Int32
@ Int32
Int32 4 bytes.
Definition: qgspointcloudattribute.h:50
QgsPointCloudAttributeCollection::attributes
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
Definition: qgspointcloudattribute.cpp:163
QgsPointCloudRenderContext
Encapsulates the render context for a 2D point cloud rendering operation.
Definition: qgspointcloudrenderer.h:41
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
QgsVector3D::z
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:66
Qgis::PointCloudDrawOrder::BottomToTop
@ BottomToTop
Draw points with larger Z values last.
QgsPointCloudRenderContext::setAttributes
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Sets the attributes associated with the rendered block.
Definition: qgspointcloudrenderer.cpp:51
qgscolorramp.h
QgsMapClippingUtils::calculatePainterClipRegion
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, QgsMapLayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
Definition: qgsmapclippingutils.cpp:127
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsRange::upper
T upper() const
Returns the upper bound of the range.
Definition: qgsrange.h:73
qgscircle.h
QgsPointCloudAttributeCollection
Collection of point cloud attributes.
Definition: qgspointcloudattribute.h:141
QgsPointCloudLayerRenderer::~QgsPointCloudLayerRenderer
~QgsPointCloudLayerRenderer()
QgsPointCloudLayerRenderer::QgsPointCloudLayerRenderer
QgsPointCloudLayerRenderer(QgsPointCloudLayer *layer, QgsRenderContext &context)
Ctor.
Definition: qgspointcloudlayerrenderer.cpp:38
QgsPointCloudRenderContext::yOffset
int yOffset() const
Returns the offset for the y value in a point record.
Definition: qgspointcloudrenderer.h:145
qgsrendercontext.h
QgsPointCloudRenderContext::offset
QgsVector3D offset() const
Returns the offset of the layer's int32 coordinates compared to CRS coords.
Definition: qgspointcloudrenderer.h:91
QgsPointCloudIndex::scale
QgsVector3D scale() const
Returns scale.
Definition: qgspointcloudindex.cpp:232
QgsPointCloudBlockRequest::errorStr
QString errorStr()
Returns the error message string of the request.
QgsPointCloudRenderContext::zOffset
int zOffset() const
Returns the offset for the y value in a point record.
Definition: qgspointcloudrenderer.h:153
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
Qgis::PointCloudDrawOrder
PointCloudDrawOrder
Pointcloud rendering order for 2d views.
Definition: qgis.h:1900
QgsPointCloudIndex::root
IndexedPointCloudNode root()
Returns root node of the index.
Definition: qgspointcloudindex.h:227
QgsPointCloudAttribute
Attribute for point cloud data pair of name and size in bytes.
Definition: qgspointcloudattribute.h:40
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
qgspointcloudextentrenderer.h
QgsPointCloudRenderContext::feedback
QgsFeedback * feedback() const
Returns the feedback object used to cancel rendering.
Definition: qgspointcloudrenderer.h:174
qgsstyle.h
QgsDoubleRange::isInfinite
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:247
QgsPointCloudAttributeCollection::indexOf
int indexOf(const QString &name) const
Returns the index of the attribute with the specified name.
Definition: qgspointcloudattribute.cpp:181
qgspointcloudindex.h
QgsPointCloudLayerRenderer::setLayerRenderingTimeHint
void setLayerRenderingTimeHint(int time) override
Sets approximate render time (in ms) for the layer to render.
Definition: qgspointcloudlayerrenderer.cpp:492
QgsRenderContext::zRange
QgsDoubleRange zRange() const
Returns the range of z-values which should be rendered.
Definition: qgsrendercontext.cpp:650
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:367
QgsPointCloudIndex::asyncNodeData
virtual QgsPointCloudBlockRequest * asyncNodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns a handle responsible for loading a node data block.
QgsDoubleRange
QgsRange which stores a range of double values.
Definition: qgsrange.h:202
Qgis::PointCloudDrawOrder::Default
@ Default
Draw points in the order they are stored.
QgsPointCloudBlockRequest
Base class for handling loading QgsPointCloudBlock asynchronously.
Definition: qgspointcloudblockrequest.h:36
QgsPointCloudLayer::elevationProperties
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
Definition: qgspointcloudlayer.cpp:691
QgsPointCloudRenderContext::scale
QgsVector3D scale() const
Returns the scale of the layer's int32 coordinates compared to CRS coords.
Definition: qgspointcloudrenderer.h:80
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsPointCloudRequest::setAttributes
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
Definition: qgspointcloudrequest.cpp:29
QgsPointCloudDataBounds
Represents packaged data bounds.
Definition: qgspointcloudindex.h:118
QgsPointCloudRenderContext::pointRecordSize
int pointRecordSize() const
Returns the size of a single point record.
Definition: qgspointcloudrenderer.h:129
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
qgsmapclippingutils.h
QgsPointCloudRenderContext::setOffset
void setOffset(const QgsVector3D &offset)
Sets the offset of the layer's int32 coordinates compared to CRS coords.
Definition: qgspointcloudrenderer.h:97
QgsPointCloudBlockRequest::finished
void finished()
Emitted when the request processing has finished.
QgsPointCloudIndex::span
int span() const
Returns the number of points in one direction in a single node.
Definition: qgspointcloudindex.cpp:247
QgsPointCloudRenderContext::pointsRendered
long pointsRendered() const
Returns the total number of points rendered.
Definition: qgspointcloudrenderer.cpp:41
qgspointcloudlayerelevationproperties.h
QgsPointCloudIndex
Represents a indexed point clouds data in octree.
Definition: qgspointcloudindex.h:163
qgslogger.h
IndexedPointCloudNode::toString
QString toString() const
Encode node to string.
Definition: qgspointcloudindex.cpp:58
QgsPointCloudLayerRenderer::forceRasterRender
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
Definition: qgspointcloudlayerrenderer.cpp:485
QgsMapLayerRenderer::MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE
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,...
Definition: qgsmaplayerrenderer.h:181
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsPointCloudAttributeCollection::push_back
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
Definition: qgspointcloudattribute.cpp:142
qgspointcloudlayerrenderer.h
qgspointcloudrequest.h
QgsPointCloudRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgspointcloudrenderer.h:69
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
qgspointcloudrenderer.h
QgsVector3D::x
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:62
QgsPointCloudIndex::nodeZRange
QgsDoubleRange nodeZRange(const IndexedPointCloudNode &node) const
Returns the z range of a node.
Definition: qgspointcloudindex.cpp:221
QgsPointCloudDataProvider::index
virtual QgsPointCloudIndex * index() const
Returns the point cloud index associated with the provider.
Definition: qgspointclouddataprovider.h:164
qgsmessagelog.h