QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgspointclouddataprovider.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointclouddataprovider.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 "qgis.h"
20#include "qgspointcloudindex.h"
21#include "qgsgeometry.h"
23#include "qgsgeometryengine.h"
25#include "qgsthreadingutils.h"
26
27#include <mutex>
28#include <QDebug>
29#include <QtMath>
30
31#include <QtConcurrent/QtConcurrentMap>
32
34 const QString &uri,
37 : QgsDataProvider( uri, options, flags )
38{
39}
40
42
44{
46
48}
49
51{
53
54 QgsPointCloudIndex *lIndex = index();
55 return lIndex && lIndex->isValid();
56}
57
59{
61
62 return QgsGeometry::fromRect( extent() );
63}
64
66{
68
69 return QVariantMap();
70}
71
73{
75
76 return nullptr;
77}
78
80{
81 static QMap< int, QString > sCodes
82 {
83 {0, QStringLiteral( "Created, Never Classified" )},
84 {1, QStringLiteral( "Unclassified" )},
85 {2, QStringLiteral( "Ground" )},
86 {3, QStringLiteral( "Low Vegetation" )},
87 {4, QStringLiteral( "Medium Vegetation" )},
88 {5, QStringLiteral( "High Vegetation" )},
89 {6, QStringLiteral( "Building" )},
90 {7, QStringLiteral( "Low Point (Low Noise)" )},
91 {8, QStringLiteral( "Reserved" )},
92 {9, QStringLiteral( "Water" )},
93 {10, QStringLiteral( "Rail" )},
94 {11, QStringLiteral( "Road Surface" )},
95 {12, QStringLiteral( "Reserved" )},
96 {13, QStringLiteral( "Wire - Guard (Shield)" )},
97 {14, QStringLiteral( "Wire - Conductor (Phase)" )},
98 {15, QStringLiteral( "Transmission Tower" )},
99 {16, QStringLiteral( "Wire-Structure Connector (Insulator)" )},
100 {17, QStringLiteral( "Bridge Deck" )},
101 {18, QStringLiteral( "High Noise" )},
102 };
103
104 static std::once_flag initialized;
105 std::call_once( initialized, [ = ]( )
106 {
107 for ( int i = 19; i <= 63; ++i )
108 sCodes.insert( i, QStringLiteral( "Reserved" ) );
109 for ( int i = 64; i <= 255; ++i )
110 sCodes.insert( i, QStringLiteral( "User Definable" ) );
111 } );
112
113 return sCodes;
114}
115
117{
118 static QMap< int, QString > sCodes
119 {
120 {0, QObject::tr( "Created, Never Classified" )},
121 {1, QObject::tr( "Unclassified" )},
122 {2, QObject::tr( "Ground" )},
123 {3, QObject::tr( "Low Vegetation" )},
124 {4, QObject::tr( "Medium Vegetation" )},
125 {5, QObject::tr( "High Vegetation" )},
126 {6, QObject::tr( "Building" )},
127 {7, QObject::tr( "Low Point (Noise)" )},
128 {8, QObject::tr( "Reserved" )},
129 {9, QObject::tr( "Water" )},
130 {10, QObject::tr( "Rail" )},
131 {11, QObject::tr( "Road Surface" )},
132 {12, QObject::tr( "Reserved" )},
133 {13, QObject::tr( "Wire - Guard (Shield)" )},
134 {14, QObject::tr( "Wire - Conductor (Phase)" )},
135 {15, QObject::tr( "Transmission Tower" )},
136 {16, QObject::tr( "Wire-Structure Connector (Insulator)" )},
137 {17, QObject::tr( "Bridge Deck" )},
138 {18, QObject::tr( "High Noise" )},
139 };
140
141 static std::once_flag initialized;
142 std::call_once( initialized, [ = ]( )
143 {
144 for ( int i = 19; i <= 63; ++i )
145 sCodes.insert( i, QObject::tr( "Reserved" ) );
146 for ( int i = 64; i <= 255; ++i )
147 sCodes.insert( i, QObject::tr( "User Definable" ) );
148 } );
149
150 return sCodes;
151}
152
154{
155 static const QMap< int, QString > sCodes
156 {
157 {0, QStringLiteral( "No color or time stored" )},
158 {1, QStringLiteral( "Time is stored" )},
159 {2, QStringLiteral( "Color is stored" )},
160 {3, QStringLiteral( "Color and time are stored" )},
161 {6, QStringLiteral( "Time is stored" )},
162 {7, QStringLiteral( "Time and color are stored)" )},
163 {8, QStringLiteral( "Time, color and near infrared are stored" )},
164 };
165
166 return sCodes;
167}
168
170{
171 static const QMap< int, QString > sCodes
172 {
173 {0, QObject::tr( "No color or time stored" )},
174 {1, QObject::tr( "Time is stored" )},
175 {2, QObject::tr( "Color is stored" )},
176 {3, QObject::tr( "Color and time are stored" )},
177 {6, QObject::tr( "Time is stored" )},
178 {7, QObject::tr( "Time and color are stored)" )},
179 {8, QObject::tr( "Time, color and near infrared are stored" )},
180 };
181
182 return sCodes;
183}
184
186{
188
189 return index() && index()->hasStatisticsMetadata();
190}
191
192QVariant QgsPointCloudDataProvider::metadataStatistic( const QString &attribute, Qgis::Statistic statistic ) const
193{
195
196 QgsPointCloudIndex *pcIndex = index();
197 if ( pcIndex )
198 {
199 return pcIndex->metadataStatistic( attribute, statistic );
200 }
201 return QVariant();
202}
203
204QVariantList QgsPointCloudDataProvider::metadataClasses( const QString &attribute ) const
205{
207
208 QgsPointCloudIndex *pcIndex = index();
209 if ( pcIndex )
210 {
211 return pcIndex->metadataClasses( attribute );
212 }
213 return QVariantList();
214}
215
216QVariant QgsPointCloudDataProvider::metadataClassStatistic( const QString &attribute, const QVariant &value, Qgis::Statistic statistic ) const
217{
219
220 QgsPointCloudIndex *pcIndex = index();
221 if ( pcIndex )
222 {
223 return pcIndex->metadataClassStatistic( attribute, value, statistic );
224 }
225 return QVariant();
226}
227
229{
231
232 QgsPointCloudIndex *pcIndex = index();
233 if ( pcIndex )
234 {
235 return pcIndex->metadataStatistics();
236 }
238}
239
241{
242 typedef QVector<QMap<QString, QVariant>> result_type;
243
244 MapIndexedPointCloudNode( QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset,
245 const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit )
246 : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit )
247 { }
248
249 QVector<QVariantMap> operator()( IndexedPointCloudNode n )
250 {
251 QVector<QVariantMap> acceptedPoints;
252 std::unique_ptr<QgsPointCloudBlock> block( mIndex->nodeData( n, mRequest ) );
253
254 if ( !block || pointsCount == mPointsLimit )
255 return acceptedPoints;
256
257 const char *ptr = block->data();
258 const QgsPointCloudAttributeCollection blockAttributes = block->attributes();
259 const std::size_t recordSize = blockAttributes.pointRecordSize();
260 int xOffset = 0, yOffset = 0, zOffset = 0;
261 const QgsPointCloudAttribute::DataType xType = blockAttributes.find( QStringLiteral( "X" ), xOffset )->type();
262 const QgsPointCloudAttribute::DataType yType = blockAttributes.find( QStringLiteral( "Y" ), yOffset )->type();
263 const QgsPointCloudAttribute::DataType zType = blockAttributes.find( QStringLiteral( "Z" ), zOffset )->type();
264 std::unique_ptr< QgsGeometryEngine > extentEngine( QgsGeometry::createGeometryEngine( mExtentGeometry.constGet() ) );
265 extentEngine->prepareGeometry();
266 for ( int i = 0; i < block->pointCount() && pointsCount < mPointsLimit; ++i )
267 {
268 double x, y, z;
269 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, block->scale(), block->offset(), x, y, z );
270 QgsPoint point( x, y );
271
272 if ( mZRange.contains( z ) && extentEngine->contains( &point ) )
273 {
274 QVariantMap pointAttr = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, blockAttributes );
275 pointAttr[ QStringLiteral( "X" ) ] = x;
276 pointAttr[ QStringLiteral( "Y" ) ] = y;
277 pointAttr[ QStringLiteral( "Z" ) ] = z;
278 pointsCount++;
279 acceptedPoints.push_back( pointAttr );
280 }
281 }
282 return acceptedPoints;
283 }
284
292 int pointsCount = 0;
293};
294
296 double maxError,
297 const QgsGeometry &extentGeometry,
298 const QgsDoubleRange &extentZRange, int pointsLimit )
299{
301
302 QVector<QVariantMap> acceptedPoints;
303
304 QgsPointCloudIndex *index = this->index();
305
306 if ( !index || !index->isValid() )
307 return acceptedPoints;
308
309 const IndexedPointCloudNode root = index->root();
310
311 const QgsRectangle rootNodeExtent = index->nodeMapExtent( root );
312 const double rootError = rootNodeExtent.width() / index->span();
313
314 const QVector<IndexedPointCloudNode> nodes = traverseTree( index, root, maxError, rootError, extentGeometry, extentZRange );
315
316 const QgsPointCloudAttributeCollection attributeCollection = index->attributes();
317 QgsPointCloudRequest request;
318 request.setAttributes( attributeCollection );
319
320 acceptedPoints = QtConcurrent::blockingMappedReduced( nodes,
321 MapIndexedPointCloudNode( request, index->scale(), index->offset(), extentGeometry, extentZRange, index, pointsLimit ),
322 qOverload<const QVector<QMap<QString, QVariant>>&>( &QVector<QMap<QString, QVariant>>::append ),
323 QtConcurrent::UnorderedReduce );
324
325 return acceptedPoints;
326}
327
328QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(
329 const QgsPointCloudIndex *pc,
331 double maxError,
332 double nodeError,
333 const QgsGeometry &extentGeometry,
334 const QgsDoubleRange &extentZRange )
335{
337
338 QVector<IndexedPointCloudNode> nodes;
339
340 const QgsDoubleRange nodeZRange = pc->nodeZRange( n );
341 if ( !extentZRange.overlaps( nodeZRange ) )
342 return nodes;
343
344 if ( !extentGeometry.intersects( pc->nodeMapExtent( n ) ) )
345 return nodes;
346
347 nodes.append( n );
348
349 const double childrenError = nodeError / 2.0;
350 if ( childrenError < maxError )
351 return nodes;
352
353 const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
354 for ( const IndexedPointCloudNode &nn : children )
355 {
356 if ( extentGeometry.intersects( pc->nodeMapExtent( nn ) ) )
357 nodes += traverseTree( pc, nn, maxError, childrenError, extentGeometry, extentZRange );
358 }
359
360 return nodes;
361}
362
363bool QgsPointCloudDataProvider::setSubsetString( const QString &subset, bool updateFeatureCount )
364{
366
367 Q_UNUSED( updateFeatureCount )
368 const auto i = index();
369 if ( !i )
370 return false;
371
372 if ( !i->setSubsetString( subset ) )
373 return false;
374 mSubsetString = subset;
375 emit dataChanged();
376 return true;
377}
378
380{
382
383 return mSubsetString;
384}
385
Represents a indexed point cloud node in octree.
Statistic
Available generic statistics.
Definition: qgis.h:4747
Abstract base class for spatial data provider implementations.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
QFlags< ReadFlag > ReadFlags
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
QgsRange which stores a range of double values.
Definition: qgsrange.h:231
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
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.
@ NoCapabilities
Provider has no capabilities.
bool setSubsetString(const QString &subset, bool updateFeatureCount=false) override
Set the subset string used to create a subset of features in the layer.
~QgsPointCloudDataProvider() override
static QMap< int, QString > dataFormatIds()
Returns the map of LAS data format ID to untranslated string value.
QVector< QVariantMap > identify(double maxError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange=QgsDoubleRange(), int pointsLimit=1000)
Returns the list of points of the point cloud according to a zoom level defined by maxError (in layer...
QgsPointCloudDataProvider(const QString &uri, const QgsDataProvider::ProviderOptions &providerOptions, QgsDataProvider::ReadFlags flags=QgsDataProvider::ReadFlags())
Ctor.
QgsPointCloudStatistics metadataStatistics()
Returns the object containing the statistics metadata extracted from the dataset.
QString subsetString() const override
Returns the subset definition string (typically sql) currently in use by the layer and used by the pr...
static QMap< int, QString > translatedDataFormatIds()
Returns the map of LAS data format ID to translated string value.
virtual QgsPointCloudDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities for the data provider.
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
QString mSubsetString
String used to define a subset of the layer.
static QMap< int, QString > lasClassificationCodes()
Returns the map of LAS classification code to untranslated string value, corresponding to the ASPRS S...
virtual bool hasStatisticsMetadata() const
Returns whether the dataset contains statistics metadata.
virtual QgsPointCloudIndex * index() const
Returns the point cloud index associated with the provider.
virtual QVariant metadataStatistic(const QString &attribute, Qgis::Statistic statistic) const
Returns a statistic for the specified attribute, taken only from the metadata of the point cloud data...
virtual QgsPointCloudRenderer * createRenderer(const QVariantMap &configuration=QVariantMap()) const
Creates a new 2D point cloud renderer, using provider backend specific information.
bool hasValidIndex() const
Returns whether provider has index which is valid.
virtual QVariantMap originalMetadata() const
Returns a representation of the original metadata included in a point cloud dataset.
virtual QgsGeometry polygonBounds() const
Returns the polygon bounds of the layer.
virtual QVariantList metadataClasses(const QString &attribute) const
Returns a list of existing classes which are present for the specified attribute, taken only from the...
virtual QVariant metadataClassStatistic(const QString &attribute, const QVariant &value, Qgis::Statistic statistic) const
Returns a statistic for one class value from the specified attribute, taken only from the metadata of...
Represents a indexed point clouds data in octree.
int span() const
Returns the number of points in one direction in a single node.
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.
QgsVector3D offset() const
Returns offset.
QgsVector3D scale() const
Returns scale.
virtual bool isValid() const =0
Returns whether index is loaded and valid.
IndexedPointCloudNode root()
Returns root node of the index.
virtual bool hasStatisticsMetadata() const =0
Returns whether the dataset contains metadata of statistics.
QgsDoubleRange nodeZRange(const IndexedPointCloudNode &node) const
Returns the z range of a node.
virtual std::unique_ptr< QgsPointCloudBlock > nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
Abstract base class for 2d point cloud renderers.
Point cloud data request.
void setAttributes(const QgsPointCloudAttributeCollection &attributes)
Set attributes filter in the request.
Class used to store statistics of a point cloud dataset.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
Definition: qgsrange.h:176
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
Definition: qgsrange.h:137
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition: qgsvector3d.h:31
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
QVector< QVariantMap > operator()(IndexedPointCloudNode n)
QVector< QMap< QString, QVariant > > result_type
MapIndexedPointCloudNode(QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset, const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit)
Setting options for creating vector data providers.