QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
qgspointcloudlayerchunkloader_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudlayerchunkloader_p.cpp
3 --------------------------------------
4 Date : October 2020
5 Copyright : (C) 2020 by Peter Petrik
6 Email : zilolv dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <memory>
19
20#include "qgs3dutils.h"
21#include "qgsbox3d.h"
22#include "qgschunknode.h"
23#include "qgseventtracing.h"
24#include "qgslogger.h"
28#include "qgspointcloudindex.h"
31#include "qgsray3d.h"
32#include "qgsraycastcontext.h"
33#include "qgsraycastingutils.h"
34
35#include <QPointSize>
36#include <QString>
37#include <Qt3DCore/QAttribute>
38#include <Qt3DRender/QGraphicsApiFilter>
39#include <Qt3DRender/QShaderProgram>
40#include <Qt3DRender/QTechnique>
41#include <QtConcurrentRun>
42
43#include "moc_qgspointcloudlayerchunkloader_p.cpp"
44
45using namespace Qt::StringLiterals;
46
48
49
51
52QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr<QgsPointCloud3DSymbol> symbol, const QgsCoordinateTransform &coordinateTransform, double zValueScale, double zValueOffset )
53 : QgsChunkLoader( node )
54 , mFactory( factory )
55 , mContext( factory->mRenderContext, coordinateTransform, std::move( symbol ), zValueScale, zValueOffset )
56{
57}
58
59void QgsPointCloudLayerChunkLoader::start()
60{
61 QgsChunkNode *node = chunk();
62 QgsPointCloudIndex pc = mFactory->mPointCloudIndex;
63 mContext.setAttributes( pc.attributes() );
64
65 const QgsChunkNodeId nodeId = node->tileId();
66 const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z );
67
68 Q_ASSERT( pc.hasNode( pcNode ) );
69
70 QgsDebugMsgLevel( u"loading entity %1"_s.arg( node->tileId().text() ), 2 );
71
72 if ( mContext.symbol()->symbolType() == "single-color"_L1 )
73 mHandler = std::make_unique<QgsSingleColorPointCloud3DSymbolHandler>();
74 else if ( mContext.symbol()->symbolType() == "color-ramp"_L1 )
75 mHandler = std::make_unique<QgsColorRampPointCloud3DSymbolHandler>();
76 else if ( mContext.symbol()->symbolType() == "rgb"_L1 )
77 mHandler = std::make_unique<QgsRGBPointCloud3DSymbolHandler>();
78 else if ( mContext.symbol()->symbolType() == "classification"_L1 )
79 {
80 mHandler = std::make_unique<QgsClassificationPointCloud3DSymbolHandler>();
81 const QgsClassificationPointCloud3DSymbol *classificationSymbol = dynamic_cast<const QgsClassificationPointCloud3DSymbol *>( mContext.symbol() );
82 mContext.setFilteredOutCategories( classificationSymbol->getFilteredOutCategories() );
83 }
84
85 //
86 // this will be run in a background thread
87 //
88 mFutureWatcher = new QFutureWatcher<void>( this );
89 connect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
90
91 const QgsBox3D box3D = node->box3D();
92 const QFuture<void> future = QtConcurrent::run( [pc = std::move( pc ), pcNode, box3D, this] {
93 const QgsEventTracing::ScopedEvent e( u"3D"_s, u"PC chunk load"_s );
94
95 if ( mContext.isCanceled() )
96 {
97 QgsDebugMsgLevel( u"canceled"_s, 2 );
98 return;
99 }
100
101 QgsPointCloudIndex pc2 = pc; // Copy to discard const
102 mHandler->processNode( pc2, pcNode, mContext );
103
104 if ( mContext.isCanceled() )
105 {
106 QgsDebugMsgLevel( u"canceled"_s, 2 );
107 return;
108 }
109
110 if ( mContext.symbol()->renderAsTriangles() )
111 mHandler->triangulate( pc2, pcNode, mContext, box3D );
112 } );
113
114 // emit finished() as soon as the handler is populated with features
115 mFutureWatcher->setFuture( future );
116}
117
118QgsPointCloudLayerChunkLoader::~QgsPointCloudLayerChunkLoader()
119{
120 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
121 {
122 disconnect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
123 mContext.cancelRendering();
124 mFutureWatcher->waitForFinished();
125 }
126}
127
128void QgsPointCloudLayerChunkLoader::cancel()
129{
130 mContext.cancelRendering();
131}
132
133Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntity *parent )
134{
135 QgsPointCloudIndex pc = mFactory->mPointCloudIndex;
136 const QgsChunkNodeId nodeId = mNode->tileId();
137 const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z );
138 Q_ASSERT( pc.hasNode( pcNode ) );
139
140 Qt3DCore::QEntity *entity = new Qt3DCore::QEntity( parent );
141 mHandler->finalize( entity, mContext );
142 return entity;
143}
144
146
147
148QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DRenderContext &context, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex pc, QgsPointCloud3DSymbol *symbol, double zValueScale, double zValueOffset, int pointBudget )
149 : mRenderContext( context )
150 , mCoordinateTransform( coordinateTransform )
151 , mPointCloudIndex( std::move( pc ) )
152 , mZValueScale( zValueScale )
153 , mZValueOffset( zValueOffset )
154 , mPointBudget( pointBudget )
155{
156 mSymbol.reset( symbol );
157
158 if ( context.crs().type() != Qgis::CrsType::Geocentric ) // extent is not used for globe
159 {
160 try
161 {
162 mExtent = mCoordinateTransform.transformBoundingBox( mRenderContext.extent(), Qgis::TransformDirection::Reverse );
163 }
164 catch ( const QgsCsException & )
165 {
166 // bad luck, can't reproject for some reason
167 QgsDebugError( u"Transformation of extent failed."_s );
168 }
169 }
170}
171
172QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node ) const
173{
174 const QgsChunkNodeId id = node->tileId();
175
176 Q_ASSERT( mPointCloudIndex.hasNode( QgsPointCloudNodeId( id.d, id.x, id.y, id.z ) ) );
177 QgsPointCloud3DSymbol *symbol = static_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() );
178 return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr<QgsPointCloud3DSymbol>( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset );
179}
180
181int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node ) const
182{
183 const QgsChunkNodeId id = node->tileId();
184 const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z );
185 Q_ASSERT( mPointCloudIndex.hasNode( n ) );
186 return mPointCloudIndex.getNode( n ).pointCount();
187}
188
189
190static QgsBox3D nodeBoundsToBox3D( QgsBox3D nodeBounds, const QgsCoordinateTransform &coordinateTransform, double zValueOffset, double zValueScale )
191{
192 QgsVector3D extentMin3D( nodeBounds.xMinimum(), nodeBounds.yMinimum(), nodeBounds.zMinimum() * zValueScale + zValueOffset );
193 QgsVector3D extentMax3D( nodeBounds.xMaximum(), nodeBounds.yMaximum(), nodeBounds.zMaximum() * zValueScale + zValueOffset );
194 QgsCoordinateTransform extentTransform = coordinateTransform;
195 extentTransform.setBallparkTransformsAreAppropriate( true );
196 try
197 {
198 extentMin3D = extentTransform.transform( extentMin3D );
199 extentMax3D = extentTransform.transform( extentMax3D );
200 }
201 catch ( QgsCsException & )
202 {
203 QgsDebugError( u"Error transforming node bounds coordinate"_s );
204 }
205 return QgsBox3D( extentMin3D.x(), extentMin3D.y(), extentMin3D.z(), extentMax3D.x(), extentMax3D.y(), extentMax3D.z() );
206}
207
208
209QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode() const
210{
211 const QgsPointCloudNode pcNode = mPointCloudIndex.getNode( mPointCloudIndex.root() );
212 const QgsBox3D rootNodeBounds = pcNode.bounds();
213 QgsBox3D rootNodeBox3D = nodeBoundsToBox3D( rootNodeBounds, mCoordinateTransform, mZValueOffset, mZValueScale );
214
215 const float error = pcNode.error();
216 QgsChunkNode *node = new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), rootNodeBox3D, error );
217 node->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive );
218 return node;
219}
220
221QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( QgsChunkNode *node ) const
222{
223 QVector<QgsChunkNode *> children;
224 const QgsChunkNodeId nodeId = node->tileId();
225 const float childError = node->error() / 2;
226
227 for ( int i = 0; i < 8; ++i )
228 {
229 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
230 const QgsChunkNodeId childId( nodeId.d + 1, nodeId.x * 2 + dx, nodeId.y * 2 + dy, nodeId.z * 2 + dz );
231 const QgsPointCloudNodeId childPcId( childId.d, childId.x, childId.y, childId.z );
232 if ( !mPointCloudIndex.hasNode( childPcId ) )
233 continue;
234 const QgsPointCloudNode childNode = mPointCloudIndex.getNode( childPcId );
235 const QgsBox3D childBounds = childNode.bounds();
236 if ( !mExtent.isEmpty() && !childBounds.toRectangle().intersects( mExtent ) )
237 continue;
238
239 QgsBox3D childBox3D = nodeBoundsToBox3D( childBounds, mCoordinateTransform, mZValueOffset, mZValueScale );
240
241 QgsChunkNode *child = new QgsChunkNode( childId, childBox3D, childError, node );
242 child->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive );
243 children << child;
244 }
245 return children;
246}
247
249
250
251static QgsChunkNode *findChunkNodeFromNodeId( QgsChunkNode *rootNode, QgsPointCloudNodeId nodeId )
252{
253 // find path from the node to the root
254 QVector<QgsPointCloudNodeId> parentIds;
255 while ( nodeId.d() > 0 )
256 {
257 parentIds << nodeId;
258 nodeId = nodeId.parentNode();
259 }
260
261 // now descend from the root to the node in the QgsChunkNode hierarchy
262 QgsChunkNode *chunk = rootNode;
263 while ( !parentIds.empty() )
264 {
265 QgsPointCloudNodeId p = parentIds.takeLast();
266 QgsChunkNodeId childNodeId( p.d(), p.x(), p.y(), p.z() );
267
268 if ( !chunk->hasChildrenPopulated() )
269 return nullptr;
270
271 QgsChunkNode *chunkChild = nullptr;
272 QgsChunkNode *const *children = chunk->children();
273 for ( int i = 0; i < chunk->childCount(); ++i )
274 {
275 if ( children[i]->tileId() == childNodeId )
276 {
277 chunkChild = children[i];
278 break;
279 }
280 }
281 Q_ASSERT( chunkChild );
282 chunk = chunkChild;
283 }
284 return chunk;
285}
286
287
288QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( Qgs3DMapSettings *map, QgsPointCloudLayer *pcl, const int indexPosition, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
289 : QgsChunkedEntity( map, maximumScreenSpaceError, new QgsPointCloudLayerChunkLoaderFactory( Qgs3DRenderContext::fromMapSettings( map ), coordinateTransform, resolveIndex( pcl, indexPosition ), symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
290 , mLayer( pcl )
291 , mIndexPosition( indexPosition )
292{
293 setShowBoundingBoxes( showBoundingBoxes );
294
295 if ( pcl->supportsEditing() )
296 {
297 mChunkUpdaterFactory = std::make_unique<QgsChunkUpdaterFactory>( mChunkLoaderFactory );
298 // when editing starts or stops, we need to update our index to use the editing index (or not)
299 if ( ( pcl->isVpc() && indexPosition >= 0 ) || ( !pcl->isVpc() ) )
300 {
301 connect( pcl, &QgsPointCloudLayer::editingStarted, this, &QgsPointCloudLayerChunkedEntity::updateIndex );
302 connect( pcl, &QgsPointCloudLayer::editingStopped, this, &QgsPointCloudLayerChunkedEntity::updateIndex );
303 connect( pcl, &QgsPointCloudLayer::chunkAttributeValuesChanged, this, [this]( const QgsPointCloudNodeId &n, const int &indexPosition ) {
304 if ( indexPosition != mIndexPosition )
305 return;
306
307 QgsChunkNode *node = findChunkNodeFromNodeId( mRootNode, n );
308 if ( node )
309 {
310 updateNodes( QList<QgsChunkNode *>() << node, mChunkUpdaterFactory.get() );
311 }
312 } );
313 }
314 }
315}
316
317QgsPointCloudLayerChunkedEntity::~QgsPointCloudLayerChunkedEntity()
318{
319 // cancel / wait for jobs
320 cancelActiveJobs();
321}
322
323QgsPointCloudIndex QgsPointCloudLayerChunkedEntity::resolveIndex( const QgsPointCloudLayer *pcl, int indexPosition )
324{
325 if ( indexPosition >= 0 && pcl->isVpc() )
326 return pcl->subIndexes().at( indexPosition ).index();
327 else if ( indexPosition == -1 && !pcl->isVpc() )
328 return pcl->index();
329 else if ( indexPosition == -2 && pcl->isVpc() )
330 return pcl->overview();
331 else
332 return QgsPointCloudIndex();
333}
334
335void QgsPointCloudLayerChunkedEntity::updateIndex()
336{
337 if ( mLayer->isVpc() )
338 {
339 if ( mIndexPosition >= 0 )
340 static_cast<QgsPointCloudLayerChunkLoaderFactory *>( mChunkLoaderFactory )->mPointCloudIndex = mLayer->subIndexes().at( mIndexPosition ).index();
341 }
342 else
343 static_cast<QgsPointCloudLayerChunkLoaderFactory *>( mChunkLoaderFactory )->mPointCloudIndex = mLayer->index();
344}
345
346QList<QgsRayCastHit> QgsPointCloudLayerChunkedEntity::rayIntersection( const QgsRay3D &ray, const QgsRayCastContext &context ) const
347{
348 QList<QgsRayCastHit> result;
349 QgsPointCloudLayerChunkLoaderFactory *factory = static_cast<QgsPointCloudLayerChunkLoaderFactory *>( mChunkLoaderFactory );
350
351 const QgsPointCloud3DSymbol *symbol = factory->mSymbol.get();
352 // Symbol can be null in case of no rendering enabled
353 if ( !symbol )
354 return result;
355
356 // transform ray
357 const QgsVector3D rayOriginMapCoords = factory->mRenderContext.worldToMapCoordinates( ray.origin() );
358 const QgsVector3D pointMapCoords = factory->mRenderContext.worldToMapCoordinates( ray.origin() + ray.origin().length() * ray.direction().normalized() );
359 QgsVector3D rayDirectionMapCoords = pointMapCoords - rayOriginMapCoords;
360 rayDirectionMapCoords.normalize();
361
362 // We're using the angle as a tolerance, effectively meaning we're fetching points intersecting a cone.
363 // This may be revisited to use a cylinder instead, if the balance between near/far points does not scale
364 // well with different point sizes, screen sizes and fov values.
365 const double limitAngle = context.angleThreshold() * M_PI / 180.;
366
367 // adjust ray to elevation properties
368 const QgsVector3D adjustedRayOrigin = QgsVector3D( rayOriginMapCoords.x(), rayOriginMapCoords.y(), ( rayOriginMapCoords.z() - factory->mZValueOffset ) / factory->mZValueScale );
369 QgsVector3D adjustedRayDirection = QgsVector3D( rayDirectionMapCoords.x(), rayDirectionMapCoords.y(), rayDirectionMapCoords.z() / factory->mZValueScale );
370 adjustedRayDirection.normalize();
371
372 QgsPointCloudIndex index = factory->mPointCloudIndex;
373
374 const QgsPointCloudAttributeCollection attributeCollection = index.attributes();
375 QgsPointCloudRequest request;
376 request.setAttributes( attributeCollection );
377
378 double minDist = -1.;
379 const QList<QgsChunkNode *> activeNodes = this->activeNodes();
380 for ( QgsChunkNode *node : activeNodes )
381 {
382 const QgsChunkNodeId id = node->tileId();
383 const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z );
384
385 if ( !index.hasNode( n ) )
386 continue;
387
388 const QgsAABB nodeBbox = Qgs3DUtils::mapToWorldExtent( node->box3D(), mMapSettings->origin() );
389 if ( !QgsRayCastingUtils::rayBoxIntersection( ray, nodeBbox ) )
390 continue;
391
392 std::unique_ptr<QgsPointCloudBlock> block( index.nodeData( n, request ) );
393 if ( !block )
394 continue;
395
396 const QgsVector3D blockScale = block->scale();
397 const QgsVector3D blockOffset = block->offset();
398
399 const char *ptr = block->data();
400 const QgsPointCloudAttributeCollection blockAttributes = block->attributes();
401 const std::size_t recordSize = blockAttributes.pointRecordSize();
402 int xOffset = 0, yOffset = 0, zOffset = 0;
403 const QgsPointCloudAttribute::DataType xType = blockAttributes.find( u"X"_s, xOffset )->type();
404 const QgsPointCloudAttribute::DataType yType = blockAttributes.find( u"Y"_s, yOffset )->type();
405 const QgsPointCloudAttribute::DataType zType = blockAttributes.find( u"Z"_s, zOffset )->type();
406 for ( int i = 0; i < block->pointCount(); ++i )
407 {
408 double x, y, z;
409 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, blockScale, blockOffset, x, y, z );
410 const QgsVector3D point( x, y, z );
411
412 // check whether point is in front of the ray
413 // similar to QgsRay3D::isInFront(), but using doubles
414 QgsVector3D vectorToPoint = point - adjustedRayOrigin;
415 vectorToPoint.normalize();
416 if ( QgsVector3D::dotProduct( vectorToPoint, adjustedRayDirection ) < 0.0 )
417 continue;
418
419 // calculate the angle between the point and the projected point
420 // similar to QgsRay3D::angleToPoint(), but using doubles
421 const QgsVector3D projPoint = adjustedRayOrigin + adjustedRayDirection * QgsVector3D::dotProduct( point - adjustedRayOrigin, adjustedRayDirection );
422
423 const double d1 = projPoint.distance( adjustedRayOrigin );
424 const double d2 = projPoint.distance( point );
425 const double angle = std::atan2( d2, d1 );
426
427 if ( angle > limitAngle )
428 continue;
429
430 const double dist = rayOriginMapCoords.distance( point );
431
432 if ( minDist < 0 || dist < minDist )
433 {
434 minDist = dist;
435 }
436 else if ( context.singleResult() )
437 {
438 continue;
439 }
440
441 // Note : applying elevation properties is done in fromPointCloudIdentificationToIdentifyResults
442 QVariantMap pointAttr = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, blockAttributes );
443 pointAttr[u"X"_s] = x;
444 pointAttr[u"Y"_s] = y;
445 pointAttr[u"Z"_s] = z;
446
447 QgsRayCastHit hit;
448 hit.setDistance( dist );
449 hit.setMapCoordinates( point );
450 hit.setProperties( pointAttr );
451 if ( context.singleResult() )
452 result.clear();
453 result.append( hit );
454 }
455 }
456 return result;
457}
@ Geocentric
Geocentric CRS.
Definition qgis.h:2388
@ Additive
When tile is refined its content should be used alongside its children simultaneously.
Definition qgis.h:5959
@ Replacement
When tile is refined then its children should be used in place of itself.
Definition qgis.h:5958
Definition of the world.
Rendering context for preparation of 3D entities.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system used in the 3D scene.
static QgsAABB mapToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsVector3D &mapOrigin)
Converts map extent to axis aligned bounding box in 3D world coordinates.
Axis-aligned bounding box - in world coords.
Definition qgsaabb.h:35
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:45
double yMaximum() const
Returns the maximum y value.
Definition qgsbox3d.h:233
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:198
double zMaximum() const
Returns the maximum z value.
Definition qgsbox3d.h:261
double xMaximum() const
Returns the maximum x value.
Definition qgsbox3d.h:205
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:381
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:254
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:226
3D symbol that draws point cloud geometries as 3D objects using classification of the dataset.
QgsPointCloudCategoryList getFilteredOutCategories() const
Gets the list of categories of the classification that should not be rendered.
Qgis::CrsType type() const
Returns the type of the CRS.
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void editingStarted()
Emitted when editing on this layer has started.
3D symbol that draws point cloud geometries as 3D objects.
A 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.
Smart pointer for QgsAbstractPointCloudIndex.
std::unique_ptr< QgsPointCloudBlock > nodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request)
Returns node data block.
bool hasNode(const QgsPointCloudNodeId &id) const
Returns whether the octree contain given node.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
Represents a map layer supporting display of point clouds.
QgsPointCloudIndex index() const
Returns the point cloud index associated with the layer.
bool isVpc() const
Returns whether the layer has a virtual point cloud data provider or not.
QgsPointCloudIndex overview() const
Returns the overview point cloud index associated with the layer (only if the layer has a virtual poi...
QVector< QgsPointCloudSubIndex > subIndexes() const
Returns point cloud indexes associated with the layer (only if the layer has a virtual point cloud da...
bool supportsEditing() const override
Returns whether the layer supports editing or not.
void chunkAttributeValuesChanged(const QgsPointCloudNodeId &n, const int position)
Emitted when a node gets some attribute values of some points changed.
Represents an indexed point cloud node's position in octree.
int d() const
Returns d.
int y() const
Returns y.
int x() const
Returns x.
int z() const
Returns z.
QgsPointCloudNodeId parentNode() const
Returns the parent of the node.
Keeps metadata for an indexed point cloud node.
float error() const
Returns node's error in map units (used to determine in whether the node has enough detail for the cu...
QgsBox3D bounds() const
Returns node's bounding cube in CRS coords.
Point cloud data request.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
A representation of a ray in 3D.
Definition qgsray3d.h:31
QVector3D origin() const
Returns the origin of the ray.
Definition qgsray3d.h:44
QVector3D direction() const
Returns the direction of the ray see setDirection().
Definition qgsray3d.h:50
Responsible for defining parameters of the ray casting operations in 3D map canvases.
float angleThreshold() const
Sets an angle threshold in degrees for ray intersections, effectively turning a ray into a cone.
bool singleResult() const
Returns whether to fetch only the closest hit for each layer or entity type.
Contains details about the ray intersecting entities when ray casting in a 3D map canvas.
void setProperties(const QVariantMap &attributes)
Sets the point cloud point attributes, empty map if hit was not on a point cloud point.
void setMapCoordinates(const QgsVector3D &point)
Sets the hit point position in 3d map coordinates.
void setDistance(double distance)
Sets the hit's distance from the ray's origin.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:52
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:54
double distance(const QgsVector3D &other) const
Returns the distance with the other QgsVector3D.
static double dotProduct(const QgsVector3D &v1, const QgsVector3D &v2)
Returns the dot product of two vectors.
double x() const
Returns X coordinate.
Definition qgsvector3d.h:50
void normalize()
Normalizes the current vector in place.
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).
bool rayBoxIntersection(const QgsRay3D &ray, const QgsAABB &nodeBbox)
Tests whether an axis aligned box is intersected by a ray.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59