QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
qgspointcloudindex.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudindex.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 "qgspointcloudindex.h"
19#include "moc_qgspointcloudindex.cpp"
20#include <QFile>
21#include <QFileInfo>
22#include <QDir>
23#include <QJsonArray>
24#include <QJsonDocument>
25#include <QJsonObject>
26#include <QTime>
27#include <QtDebug>
28
31#include "qgslogger.h"
32
34 mD( -1 ),
35 mX( 0 ),
36 mY( 0 ),
37 mZ( 0 )
38{}
39
40IndexedPointCloudNode::IndexedPointCloudNode( int _d, int _x, int _y, int _z ):
41 mD( _d ),
42 mX( _x ),
43 mY( _y ),
44 mZ( _z )
45{}
46
48{
49 return IndexedPointCloudNode( mD - 1, mX / 2, mY / 2, mZ / 2 );
50}
51
53{
54 QStringList lst = str.split( '-' );
55 if ( lst.count() != 4 )
56 return IndexedPointCloudNode();
57 return IndexedPointCloudNode( lst[0].toInt(), lst[1].toInt(), lst[2].toInt(), lst[3].toInt() );
58}
59
61{
62 return QStringLiteral( "%1-%2-%3-%4" ).arg( mD ).arg( mX ).arg( mY ).arg( mZ );
63}
64
66{
67 return mD;
68}
69
71{
72 return mX;
73}
74
76{
77 return mY;
78}
79
81{
82 return mZ;
83}
84
86{
87 return id.d() + id.x() + id.y() + id.z();
88}
89
91
92//
93// QgsPointCloudCacheKey
94//
95
96QgsPointCloudCacheKey::QgsPointCloudCacheKey( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri )
97 : mNode( n )
98 , mUri( uri )
99 , mRequest( request )
100 , mFilterExpression( expression )
101{
102}
103
105{
106 return mNode == other.mNode &&
107 mUri == other.mUri &&
108 mRequest == other.mRequest &&
109 mFilterExpression == other.mFilterExpression;
110}
111
112uint qHash( const QgsPointCloudCacheKey &key )
113{
114 return qHash( key.node() ) ^ qHash( key.request() ) ^ qHash( key.uri() ) ^ qHash( key.filterExpression() );
115}
116
117//
118// QgsPointCloudDataBounds
119//
120
122
123QgsPointCloudDataBounds::QgsPointCloudDataBounds( qint64 xmin, qint64 ymin, qint64 zmin, qint64 xmax, qint64 ymax, qint64 zmax )
124 : mXMin( xmin )
125 , mYMin( ymin )
126 , mZMin( zmin )
127 , mXMax( xmax )
128 , mYMax( ymax )
129 , mZMax( zmax )
130{
131
132}
133
135{
136 return mXMin;
137}
138
140{
141 return mYMin;
142}
143
145{
146 return mXMax;
147}
148
150{
151 return mYMax;
152}
153
155{
156 return mZMin;
157}
158
160{
161 return mZMax;
162}
163
165{
166 return QgsRectangle(
167 mXMin * scale.x() + offset.x(), mYMin * scale.y() + offset.y(),
168 mXMax * scale.x() + offset.x(), mYMax * scale.y() + offset.y()
169 );
170}
171
173{
174 return QgsDoubleRange( mZMin * scale.z() + offset.z(), mZMax * scale.z() + offset.z() );
175}
176
178
179//
180// QgsPointCloudIndex
181//
182
184QCache<QgsPointCloudCacheKey, QgsPointCloudBlock> QgsPointCloudIndex::sBlockCache( 200'000'000 ); // 200MB of cached points
185
187
189
191{
192 QMutexLocker locker( &mHierarchyMutex );
193 return mHierarchy.contains( n );
194}
195
197{
198 QMutexLocker locker( &mHierarchyMutex );
199 return mHierarchy.value( n, -1 );
200}
201
202QList<IndexedPointCloudNode> QgsPointCloudIndex::nodeChildren( const IndexedPointCloudNode &n ) const
203{
204 QMutexLocker locker( &mHierarchyMutex );
205 Q_ASSERT( mHierarchy.contains( n ) );
206 QList<IndexedPointCloudNode> lst;
207 const int d = n.d() + 1;
208 const int x = n.x() * 2;
209 const int y = n.y() * 2;
210 const int z = n.z() * 2;
211
212 for ( int i = 0; i < 8; ++i )
213 {
214 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
215 const IndexedPointCloudNode n2( d, x + dx, y + dy, z + dz );
216 if ( mHierarchy.contains( n2 ) )
217 lst.append( n2 );
218 }
219 return lst;
220}
221
226
228{
229 qint64 xMin, yMin, zMin, xMax, yMax, zMax;
230
231 const qint64 d = mRootBounds.xMax() - mRootBounds.xMin();
232 const double dLevel = ( double )d / pow( 2, n.d() );
233
234 xMin = round( mRootBounds.xMin() + dLevel * n.x() );
235 xMax = round( mRootBounds.xMin() + dLevel * ( n.x() + 1 ) );
236 yMin = round( mRootBounds.yMin() + dLevel * n.y() );
237 yMax = round( mRootBounds.yMin() + dLevel * ( n.y() + 1 ) );
238 zMin = round( mRootBounds.zMin() + dLevel * n.z() );
239 zMax = round( mRootBounds.zMin() + dLevel * ( n.z() + 1 ) );
240
241 QgsPointCloudDataBounds db( xMin, yMin, zMin, xMax, yMax, zMax );
242 return db;
243}
244
249
254
256{
257 const double w = nodeMapExtent( n ).width();
258 return w / mSpan;
259}
260
262{
263 return mScale;
264}
265
267{
268 return mOffset;
269}
270
275
277{
278 return mSpan;
279}
280
282{
283 mHierarchyMutex.lock();
284 const int count = mHierarchy.value( n, -1 );
285 mHierarchyMutex.unlock();
286 return count;
287}
288
289bool QgsPointCloudIndex::setSubsetString( const QString &subset )
290{
291 const QString lastExpression = mFilterExpression;
292 mFilterExpression.setExpression( subset );
293 if ( mFilterExpression.hasParserError() && !subset.isEmpty() )
294 {
295 mFilterExpression.setExpression( lastExpression );
296 return false;
297 }
298
299 // fail if expression references unknown attributes
300 int offset;
301 const QSet<QString> attributes = mFilterExpression.referencedAttributes();
302 for ( const QString &attribute : attributes )
303 {
304 if ( !mAttributes.find( attribute, offset ) )
305 {
306 mFilterExpression.setExpression( lastExpression );
307 return false;
308 }
309 }
310 return true;
311}
312
314{
315 return mFilterExpression;
316}
317
318QVariant QgsPointCloudIndex::metadataStatistic( const QString &attribute, Qgis::Statistic statistic ) const
319{
320 if ( attribute == QLatin1String( "X" ) && statistic == Qgis::Statistic::Min )
321 return mExtent.xMinimum();
322 if ( attribute == QLatin1String( "X" ) && statistic == Qgis::Statistic::Max )
323 return mExtent.xMaximum();
324
325 if ( attribute == QLatin1String( "Y" ) && statistic == Qgis::Statistic::Min )
326 return mExtent.yMinimum();
327 if ( attribute == QLatin1String( "Y" ) && statistic == Qgis::Statistic::Max )
328 return mExtent.yMaximum();
329
330 if ( attribute == QLatin1String( "Z" ) && statistic == Qgis::Statistic::Min )
331 return mZMin;
332 if ( attribute == QLatin1String( "Z" ) && statistic == Qgis::Statistic::Max )
333 return mZMax;
334
335 return QVariant();
336}
337
338QVariantList QgsPointCloudIndex::metadataClasses( const QString &attribute ) const
339{
340 Q_UNUSED( attribute );
341 return QVariantList();
342}
343
344QVariant QgsPointCloudIndex::metadataClassStatistic( const QString &attribute, const QVariant &value, Qgis::Statistic statistic ) const
345{
346 Q_UNUSED( attribute );
347 Q_UNUSED( value );
348 Q_UNUSED( statistic );
349 return QVariant();
350}
351
353{
354 QMap<QString, QgsPointCloudAttributeStatistics> statsMap;
355 for ( QgsPointCloudAttribute attribute : attributes().attributes() )
356 {
357 QString name = attribute.name();
359 QVariant min = metadataStatistic( name, Qgis::Statistic::Min );
360 QVariant max = metadataStatistic( name, Qgis::Statistic::Max );
361 QVariant mean = metadataStatistic( name, Qgis::Statistic::Mean );
362 QVariant stDev = metadataStatistic( name, Qgis::Statistic::StDev );
363 if ( !min.isValid() )
364 continue;
365
366 s.minimum = min.toDouble();
367 s.maximum = max.toDouble();
368 s.mean = mean.toDouble();
369 s.stDev = stDev.toDouble();
371 QVariantList classes = metadataClasses( name );
372 for ( QVariant c : classes )
373 {
374 s.classCount[ c.toInt() ] = metadataClassStatistic( name, c, Qgis::Statistic::Count ).toInt();
375 }
376 statsMap[ name ] = s;
377 }
378 return QgsPointCloudStatistics( pointCount(), statsMap );
379}
380
382{
383 // Base QgsPointCloudIndex fields
384 destination->mUri = mUri;
385 destination->mExtent = mExtent;
386 destination->mZMin = mZMin;
387 destination->mZMax = mZMax;
388 destination->mHierarchy = mHierarchy;
389 destination->mScale = mScale;
390 destination->mOffset = mOffset;
391 destination->mRootBounds = mRootBounds;
392 destination->mAttributes = mAttributes;
393 destination->mSpan = mSpan;
395}
396
398{
399 QgsPointCloudCacheKey key( node, request, mFilterExpression, mUri );
400
401 QMutexLocker l( &sBlockCacheMutex );
402 QgsPointCloudBlock *cached = sBlockCache.object( key );
403 return cached ? cached->clone() : nullptr;
404}
405
410
411void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri )
412{
413 if ( !data )
414 return;
415
416 QgsPointCloudCacheKey key( node, request, expression, uri );
417
418 const int cost = data->pointCount() * data->pointRecordSize();
419
420 QMutexLocker l( &sBlockCacheMutex );
421 QgsDebugMsgLevel( QStringLiteral( "(%1/%2): Caching node %3 of %4" ).arg( sBlockCache.totalCost() ).arg( sBlockCache.maxCost() ).arg( key.node().toString() ).arg( key.uri() ), 4 );
422 sBlockCache.insert( key, data->clone(), cost );
423}
Represents a indexed point cloud node in octree.
int y() const
Returns y.
static IndexedPointCloudNode fromString(const QString &str)
Creates node from string.
int x() const
Returns x.
QString toString() const
Encode node to string.
int d() const
Returns d.
IndexedPointCloudNode parentNode() const
Returns the parent of the node.
int z() const
Returns z.
IndexedPointCloudNode()
Constructs invalid node.
Statistic
Available generic statistics.
Definition qgis.h:5432
@ StDev
Standard deviation of values.
@ Mean
Mean of values.
@ Max
Max of values.
@ Min
Min of values.
QgsRange which stores a range of double values.
Definition qgsrange.h:231
Collection of point cloud attributes.
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
Attribute for point cloud data pair of name and size in bytes.
Base class for storing raw data from point cloud nodes.
int pointCount() const
Returns number of points that are stored in the block.
int pointRecordSize() const
Returns the total size of each individual point record.
QgsPointCloudBlock * clone() const
Clones the QgsPointCloudBlock returning a new copy.
Container class for QgsPointCloudBlock cache keys.
IndexedPointCloudNode node() const
Returns the key's IndexedPointCloudNode.
QgsPointCloudExpression filterExpression() const
Returns the key's QgsPointCloudExpression.
QgsPointCloudRequest request() const
Returns the key's QgsPointCloudRequest.
QgsPointCloudCacheKey(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri)
Ctor.
bool operator==(const QgsPointCloudCacheKey &other) const
QString uri() const
Returns the key's uri.
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.
QgsDoubleRange zRange(const QgsVector3D &offset, const QgsVector3D &scale) const
Returns the z range, applying the specified offset and scale.
QgsPointCloudDataBounds()
Constructs invalid bounds.
QgsRectangle mapExtent(const QgsVector3D &offset, const QgsVector3D &scale) const
Returns 2D rectangle in map coordinates.
qint64 zMax() const
Returns z max.
qint64 yMin() const
Returns y min.
Represents a indexed point clouds data in octree.
int span() const
Returns the number of points in one direction in a single node.
double zMax() const
Returns z max.
QgsPointCloudBlock * getNodeDataFromCache(const IndexedPointCloudNode &node, const QgsPointCloudRequest &request)
Fetches the requested node data from the cache for the specified node and request.
static void storeNodeDataToCacheStatic(QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri)
Stores existing data to the cache for the specified node, request, expression and uri.
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 QList< IndexedPointCloudNode > nodeChildren(const IndexedPointCloudNode &n) const
Returns all children of node.
QgsPointCloudIndex()
Constructs index.
QString subsetString() const
Returns the string used to define a subset of the point cloud.
double zMin() const
Returns z min.
void storeNodeDataToCache(QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request)
Stores existing data to the cache for the specified node and request.
QgsVector3D offset() const
Returns offset.
QgsVector3D scale() const
Returns scale.
virtual qint64 pointCount() const =0
Returns the number of points in the point cloud.
virtual QVariantList metadataClasses(const QString &attribute) const
Returns the classes of attribute.
void copyCommonProperties(QgsPointCloudIndex *destination) const
Copies common properties to the destination index.
bool setSubsetString(const QString &subset)
Sets the string used to define a subset of the point cloud.
QHash< IndexedPointCloudNode, int > mHierarchy
Data hierarchy.
double mZMax
Vertical extent of data.
QgsPointCloudDataBounds mRootBounds
Bounds of the root node's cube (in int32 coordinates)
virtual QgsPointCloudStatistics metadataStatistics() const
Returns the object containing the statistics metadata extracted from the dataset.
QgsRectangle mExtent
2D extent of data
QgsPointCloudAttributeCollection mAttributes
QgsPointCloudDataBounds nodeBounds(const IndexedPointCloudNode &node) const
Returns bounds of particular node.
virtual bool hasNode(const IndexedPointCloudNode &n) const
Returns whether the octree contain given node.
QgsVector3D mOffset
Offset of our int32 coordinates compared to CRS coords.
static QMutex sBlockCacheMutex
QgsDoubleRange nodeZRange(const IndexedPointCloudNode &node) const
Returns the z range of a node.
static QCache< QgsPointCloudCacheKey, QgsPointCloudBlock > sBlockCache
virtual QVariant metadataStatistic(const QString &attribute, Qgis::Statistic statistic) const
Returns the statistic statistic of attribute.
float nodeError(const IndexedPointCloudNode &n) const
Returns node's error in map units (used to determine in whether the node has enough detail for the cu...
int mSpan
All native attributes stored in the file.
QgsVector3D mScale
Scale of our int32 coordinates compared to CRS coords.
virtual QVariant metadataClassStatistic(const QString &attribute, const QVariant &value, Qgis::Statistic statistic) const
Returns the statistic statistic of the class value of the attribute attribute.
QgsPointCloudExpression mFilterExpression
The filter expression to be evaluated when fetching node data.
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.
Class used to store statistics of a point cloud dataset.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition qgsvector3d.h:31
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:50
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:52
double x() const
Returns X coordinate.
Definition qgsvector3d.h:48
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
#define str(x)
Definition qgis.cpp:39
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
uint qHash(IndexedPointCloudNode id)
Hash function for indexed nodes.
Class used to store statistics of one attribute of a point cloud dataset.