QGIS API Documentation 3.41.0-Master (af5edcb665c)
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 <QFile>
20#include <QFileInfo>
21#include <QDir>
22#include <QJsonArray>
23#include <QJsonDocument>
24#include <QJsonObject>
25#include <QTime>
26#include <QtDebug>
27#include <qglobal.h>
28
29#include "qgsbox3d.h"
32#include "qgslogger.h"
33
35 mD( -1 ),
36 mX( 0 ),
37 mY( 0 ),
38 mZ( 0 )
39{}
40
41QgsPointCloudNodeId::QgsPointCloudNodeId( int _d, int _x, int _y, int _z ):
42 mD( _d ),
43 mX( _x ),
44 mY( _y ),
45 mZ( _z )
46{}
47
49{
50 return QgsPointCloudNodeId( mD - 1, mX / 2, mY / 2, mZ / 2 );
51}
52
54{
55 QStringList lst = str.split( '-' );
56 if ( lst.count() != 4 )
57 return QgsPointCloudNodeId();
58 return QgsPointCloudNodeId( lst[0].toInt(), lst[1].toInt(), lst[2].toInt(), lst[3].toInt() );
59}
60
62{
63 return QStringLiteral( "%1-%2-%3-%4" ).arg( mD ).arg( mX ).arg( mY ).arg( mZ );
64}
65
67{
68 return mD;
69}
70
72{
73 return mX;
74}
75
77{
78 return mY;
79}
80
82{
83 return mZ;
84}
85
87{
88 return id.d() + id.x() + id.y() + id.z();
89}
90
92
93//
94// QgsPointCloudCacheKey
95//
96
97QgsPointCloudCacheKey::QgsPointCloudCacheKey( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri )
98 : mNode( n )
99 , mUri( uri )
100 , mRequest( request )
101 , mFilterExpression( expression )
102{
103}
104
106{
107 return mNode == other.mNode &&
108 mUri == other.mUri &&
109 mRequest == other.mRequest &&
110 mFilterExpression == other.mFilterExpression;
111}
112
113uint qHash( const QgsPointCloudCacheKey &key )
114{
115 return qHash( key.node() ) ^ qHash( key.request() ) ^ qHash( key.uri() ) ^ qHash( key.filterExpression() );
116}
117
118//
119// QgsPointCloudNode
120//
121
123{
124 return mBounds;
125}
126
128{
129 const double d = rootBounds.xMaximum() - rootBounds.xMinimum();
130 const double dLevel = d / pow( 2, id.d() );
131
132 const double xMin = rootBounds.xMinimum() + dLevel * id.x();
133 const double xMax = rootBounds.xMinimum() + dLevel * ( id.x() + 1 );
134 const double yMin = rootBounds.yMinimum() + dLevel * id.y();
135 const double yMax = rootBounds.yMinimum() + dLevel * ( id.y() + 1 );
136 const double zMin = rootBounds.zMinimum() + dLevel * id.z();
137 const double zMax = rootBounds.zMinimum() + dLevel * ( id.z() + 1 );
138
139 return QgsBox3D( xMin, yMin, zMin, xMax, yMax, zMax );
140}
141
142float QgsPointCloudNode::error() const
143{
144 return mError;
145}
146
148
149//
150// QgsPointCloudIndex
151//
152
154QCache<QgsPointCloudCacheKey, QgsPointCloudBlock> QgsPointCloudIndex::sBlockCache( 200'000'000 ); // 200MB of cached points
155
157
159
161{
162 QMutexLocker locker( &mHierarchyMutex );
163 return mHierarchy.contains( n );
164}
165
167{
168 Q_ASSERT( hasNode( id ) );
169
170 qint64 pointCount;
171 {
172 QMutexLocker locker( &mHierarchyMutex );
173 pointCount = mHierarchy.value( id, -1 );
174 }
175
176 QList<QgsPointCloudNodeId> children;
177 {
178 const int d = id.d() + 1;
179 const int x = id.x() * 2;
180 const int y = id.y() * 2;
181 const int z = id.z() * 2;
182
183 for ( int i = 0; i < 8; ++i )
184 {
185 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
186 const QgsPointCloudNodeId n2( d, x + dx, y + dy, z + dz );
187 if ( hasNode( n2 ) )
188 children.append( n2 );
189 }
190 }
191
193 return QgsPointCloudNode( id, pointCount, children, bounds.width() / mSpan, bounds );
194}
195
200
202{
203 return mScale;
204}
205
207{
208 return mOffset;
209}
210
215
217{
218 return mSpan;
219}
220
221bool QgsPointCloudIndex::setSubsetString( const QString &subset )
222{
223 const QString lastExpression = mFilterExpression;
224 mFilterExpression.setExpression( subset );
225 if ( mFilterExpression.hasParserError() && !subset.isEmpty() )
226 {
227 mFilterExpression.setExpression( lastExpression );
228 return false;
229 }
230
231 // fail if expression references unknown attributes
232 int offset;
233 const QSet<QString> attributes = mFilterExpression.referencedAttributes();
234 for ( const QString &attribute : attributes )
235 {
236 if ( !mAttributes.find( attribute, offset ) )
237 {
238 mFilterExpression.setExpression( lastExpression );
239 return false;
240 }
241 }
242 return true;
243}
244
246{
247 return mFilterExpression;
248}
249
251{
252 QMap<QString, QgsPointCloudAttributeStatistics> statsMap;
253 statsMap[ "X" ].minimum = mExtent.xMinimum();
254 statsMap[ "X" ].maximum = mExtent.xMaximum();
255 statsMap[ "Y" ].minimum = mExtent.yMinimum();
256 statsMap[ "Y" ].maximum = mExtent.yMinimum();
257 statsMap[ "Z" ].minimum = mZMin;
258 statsMap[ "Z" ].maximum = mZMax;
259
260 return QgsPointCloudStatistics( pointCount(), statsMap );
261}
262
264{
265 // Base QgsPointCloudIndex fields
266 destination->mUri = mUri;
267 destination->mExtent = mExtent;
268 destination->mZMin = mZMin;
269 destination->mZMax = mZMax;
270 destination->mHierarchy = mHierarchy;
271 destination->mScale = mScale;
272 destination->mOffset = mOffset;
273 destination->mRootBounds = mRootBounds;
274 destination->mAttributes = mAttributes;
275 destination->mSpan = mSpan;
277}
278
280{
281 QgsPointCloudCacheKey key( node, request, mFilterExpression, mUri );
282
283 QMutexLocker l( &sBlockCacheMutex );
284 QgsPointCloudBlock *cached = sBlockCache.object( key );
285 return cached ? cached->clone() : nullptr;
286}
287
292
293void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri )
294{
295 if ( !data )
296 return;
297
298 QgsPointCloudCacheKey key( node, request, expression, uri );
299
300 const int cost = data->pointCount() * data->pointRecordSize();
301
302 QMutexLocker l( &sBlockCacheMutex );
303 QgsDebugMsgLevel( QStringLiteral( "(%1/%2): Caching node %3 of %4" ).arg( sBlockCache.totalCost() ).arg( sBlockCache.maxCost() ).arg( key.node().toString() ).arg( key.uri() ), 4 );
304 sBlockCache.insert( key, data->clone(), cost );
305}
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:211
double xMaximum() const
Returns the maximum x value.
Definition qgsbox3d.h:218
double width() const
Returns the width of the box.
Definition qgsbox3d.h:293
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:267
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:239
Collection of point cloud attributes.
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
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.
QgsPointCloudExpression filterExpression() const
Returns the key's QgsPointCloudExpression.
QgsPointCloudCacheKey(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri)
Ctor.
QgsPointCloudRequest request() const
Returns the key's QgsPointCloudRequest.
QgsPointCloudNodeId node() const
Returns the key's QgsPointCloudNodeId.
bool operator==(const QgsPointCloudCacheKey &other) const
QString uri() const
Returns the key's uri.
Represents a indexed point clouds data in octree.
int span() const
Returns the number of points in one direction in a single node.
virtual bool hasNode(const QgsPointCloudNodeId &n) const
Returns whether the octree contain given node.
QgsPointCloudIndex()
Constructs index.
QString subsetString() const
Returns the string used to define a subset of the point cloud.
QgsVector3D offset() const
Returns offset of data from CRS.
QgsVector3D scale() const
Returns scale of data relative to CRS.
virtual qint64 pointCount() const =0
Returns the number of points in the point cloud.
void storeNodeDataToCache(QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request) const
Stores existing data to the cache for the specified node and request.
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.
double mZMax
Vertical extent of data.
virtual QgsPointCloudStatistics metadataStatistics() const
Returns the object containing the statistics metadata extracted from the dataset.
QgsRectangle mExtent
2D extent of data
QgsPointCloudAttributeCollection mAttributes
QHash< QgsPointCloudNodeId, int > mHierarchy
Data hierarchy.
QgsBox3D mRootBounds
Bounds of the root node's cube (in int32 coordinates)
QgsVector3D mOffset
Offset of our int32 coordinates compared to CRS coords.
static QMutex sBlockCacheMutex
static void storeNodeDataToCacheStatic(QgsPointCloudBlock *data, const QgsPointCloudNodeId &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 QgsPointCloudNode getNode(const QgsPointCloudNodeId &id) const
Returns object for a given node.
static QCache< QgsPointCloudCacheKey, QgsPointCloudBlock > sBlockCache
int mSpan
All native attributes stored in the file.
QgsVector3D mScale
Scale of our int32 coordinates compared to CRS coords.
QgsPointCloudExpression mFilterExpression
The filter expression to be evaluated when fetching node data.
QgsPointCloudBlock * getNodeDataFromCache(const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request)
Fetches the requested node data from the cache for the specified node and request.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Sets native attributes of the data.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
virtual ~QgsPointCloudIndex()
Represents a indexed point cloud node's position in octree.
int d() const
Returns d.
int y() const
Returns y.
int x() const
Returns x.
QgsPointCloudNodeId()
Constructs invalid node.
static QgsPointCloudNodeId fromString(const QString &str)
Creates node from string.
int z() const
Returns z.
QString toString() const
Encode node to string.
QgsPointCloudNodeId parentNode() const
Returns the parent of the node.
Keeps metadata for 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.
Class used to store statistics of a point cloud dataset.
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...
double xMinimum
double yMinimum
double xMaximum
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition qgsvector3d.h:31
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
uint qHash(QgsPointCloudNodeId id)
Hash function for indexed nodes.