QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
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
26#include <mutex>
27#include <QDebug>
28#include <QtMath>
29
30#include <QtConcurrent/QtConcurrentMap>
31
33 const QString &uri,
35 QgsDataProvider::ReadFlags flags )
36 : QgsDataProvider( uri, options, flags )
37{
38}
39
41
42QgsPointCloudDataProvider::Capabilities QgsPointCloudDataProvider::capabilities() const
43{
45}
46
48{
49 QgsPointCloudIndex *lIndex = index();
50 return lIndex && lIndex->isValid();
51}
52
57
59{
60 return QVariantMap();
61}
62
64{
65 return nullptr;
66}
67
69{
70 static QMap< int, QString > sCodes
71 {
72 {0, QStringLiteral( "Created, Never Classified" )},
73 {1, QStringLiteral( "Unclassified" )},
74 {2, QStringLiteral( "Ground" )},
75 {3, QStringLiteral( "Low Vegetation" )},
76 {4, QStringLiteral( "Medium Vegetation" )},
77 {5, QStringLiteral( "High Vegetation" )},
78 {6, QStringLiteral( "Building" )},
79 {7, QStringLiteral( "Low Point (Low Noise)" )},
80 {8, QStringLiteral( "Reserved" )},
81 {9, QStringLiteral( "Water" )},
82 {10, QStringLiteral( "Rail" )},
83 {11, QStringLiteral( "Road Surface" )},
84 {12, QStringLiteral( "Reserved" )},
85 {13, QStringLiteral( "Wire - Guard (Shield)" )},
86 {14, QStringLiteral( "Wire - Conductor (Phase)" )},
87 {15, QStringLiteral( "Transmission Tower" )},
88 {16, QStringLiteral( "Wire-Structure Connector (Insulator)" )},
89 {17, QStringLiteral( "Bridge Deck" )},
90 {18, QStringLiteral( "High Noise" )},
91 };
92
93 static std::once_flag initialized;
94 std::call_once( initialized, [ = ]( )
95 {
96 for ( int i = 19; i <= 63; ++i )
97 sCodes.insert( i, QStringLiteral( "Reserved" ) );
98 for ( int i = 64; i <= 255; ++i )
99 sCodes.insert( i, QStringLiteral( "User Definable" ) );
100 } );
101
102 return sCodes;
103}
104
106{
107 static QMap< int, QString > sCodes
108 {
109 {0, QObject::tr( "Created, Never Classified" )},
110 {1, QObject::tr( "Unclassified" )},
111 {2, QObject::tr( "Ground" )},
112 {3, QObject::tr( "Low Vegetation" )},
113 {4, QObject::tr( "Medium Vegetation" )},
114 {5, QObject::tr( "High Vegetation" )},
115 {6, QObject::tr( "Building" )},
116 {7, QObject::tr( "Low Point (Noise)" )},
117 {8, QObject::tr( "Reserved" )},
118 {9, QObject::tr( "Water" )},
119 {10, QObject::tr( "Rail" )},
120 {11, QObject::tr( "Road Surface" )},
121 {12, QObject::tr( "Reserved" )},
122 {13, QObject::tr( "Wire - Guard (Shield)" )},
123 {14, QObject::tr( "Wire - Conductor (Phase)" )},
124 {15, QObject::tr( "Transmission Tower" )},
125 {16, QObject::tr( "Wire-Structure Connector (Insulator)" )},
126 {17, QObject::tr( "Bridge Deck" )},
127 {18, QObject::tr( "High Noise" )},
128 };
129
130 static std::once_flag initialized;
131 std::call_once( initialized, [ = ]( )
132 {
133 for ( int i = 19; i <= 63; ++i )
134 sCodes.insert( i, QObject::tr( "Reserved" ) );
135 for ( int i = 64; i <= 255; ++i )
136 sCodes.insert( i, QObject::tr( "User Definable" ) );
137 } );
138
139 return sCodes;
140}
141
143{
144 static const QMap< int, QString > sCodes
145 {
146 {0, QStringLiteral( "No color or time stored" )},
147 {1, QStringLiteral( "Time is stored" )},
148 {2, QStringLiteral( "Color is stored" )},
149 {3, QStringLiteral( "Color and time are stored" )},
150 {6, QStringLiteral( "Time is stored" )},
151 {7, QStringLiteral( "Time and color are stored)" )},
152 {8, QStringLiteral( "Time, color and near infrared are stored" )},
153 };
154
155 return sCodes;
156}
157
159{
160 static const QMap< int, QString > sCodes
161 {
162 {0, QObject::tr( "No color or time stored" )},
163 {1, QObject::tr( "Time is stored" )},
164 {2, QObject::tr( "Color is stored" )},
165 {3, QObject::tr( "Color and time are stored" )},
166 {6, QObject::tr( "Time is stored" )},
167 {7, QObject::tr( "Time and color are stored)" )},
168 {8, QObject::tr( "Time, color and near infrared are stored" )},
169 };
170
171 return sCodes;
172}
173
178
179QVariant QgsPointCloudDataProvider::metadataStatistic( const QString &attribute, QgsStatisticalSummary::Statistic statistic ) const
180{
181 QgsPointCloudIndex *pcIndex = index();
182 if ( pcIndex )
183 {
184 return pcIndex->metadataStatistic( attribute, statistic );
185 }
186 return QVariant();
187}
188
189QVariantList QgsPointCloudDataProvider::metadataClasses( const QString &attribute ) const
190{
191 QgsPointCloudIndex *pcIndex = index();
192 if ( pcIndex )
193 {
194 return pcIndex->metadataClasses( attribute );
195 }
196 return QVariantList();
197}
198
199QVariant QgsPointCloudDataProvider::metadataClassStatistic( const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic ) const
200{
201 QgsPointCloudIndex *pcIndex = index();
202 if ( pcIndex )
203 {
204 return pcIndex->metadataClassStatistic( attribute, value, statistic );
205 }
206 return QVariant();
207}
208
209
211{
212 QgsPointCloudIndex *pcIndex = index();
213 if ( pcIndex )
214 {
215 return pcIndex->metadataStatistics();
216 }
218}
219
221{
222 typedef QVector<QMap<QString, QVariant>> result_type;
223
224 MapIndexedPointCloudNode( QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset,
225 const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit )
226 : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit )
227 { }
228
229 QVector<QVariantMap> operator()( IndexedPointCloudNode n )
230 {
231 QVector<QVariantMap> acceptedPoints;
232 std::unique_ptr<QgsPointCloudBlock> block( mIndex->nodeData( n, mRequest ) );
233
234 if ( !block || pointsCount == mPointsLimit )
235 return acceptedPoints;
236
237 const char *ptr = block->data();
238 const QgsPointCloudAttributeCollection blockAttributes = block->attributes();
239 const std::size_t recordSize = blockAttributes.pointRecordSize();
240 int xOffset = 0, yOffset = 0, zOffset = 0;
241 const QgsPointCloudAttribute::DataType xType = blockAttributes.find( QStringLiteral( "X" ), xOffset )->type();
242 const QgsPointCloudAttribute::DataType yType = blockAttributes.find( QStringLiteral( "Y" ), yOffset )->type();
243 const QgsPointCloudAttribute::DataType zType = blockAttributes.find( QStringLiteral( "Z" ), zOffset )->type();
244 std::unique_ptr< QgsGeometryEngine > extentEngine( QgsGeometry::createGeometryEngine( mExtentGeometry.constGet() ) );
245 extentEngine->prepareGeometry();
246 for ( int i = 0; i < block->pointCount() && pointsCount < mPointsLimit; ++i )
247 {
248 double x, y, z;
249 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, block->scale(), block->offset(), x, y, z );
250 QgsPoint point( x, y );
251
252 if ( mZRange.contains( z ) && extentEngine->contains( &point ) )
253 {
254 QVariantMap pointAttr = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, blockAttributes );
255 pointAttr[ QStringLiteral( "X" ) ] = x;
256 pointAttr[ QStringLiteral( "Y" ) ] = y;
257 pointAttr[ QStringLiteral( "Z" ) ] = z;
258 pointsCount++;
259 acceptedPoints.push_back( pointAttr );
260 }
261 }
262 return acceptedPoints;
263 }
264
272 int pointsCount = 0;
273};
274
276 double maxError,
277 const QgsGeometry &extentGeometry,
278 const QgsDoubleRange &extentZRange, int pointsLimit )
279{
280 QVector<QVariantMap> acceptedPoints;
281
282 QgsPointCloudIndex *index = this->index();
283
284 if ( !index || !index->isValid() )
285 return acceptedPoints;
286
287 const IndexedPointCloudNode root = index->root();
288
289 const QgsRectangle rootNodeExtent = index->nodeMapExtent( root );
290 const double rootError = rootNodeExtent.width() / index->span();
291
292 const QVector<IndexedPointCloudNode> nodes = traverseTree( index, root, maxError, rootError, extentGeometry, extentZRange );
293
294 const QgsPointCloudAttributeCollection attributeCollection = index->attributes();
295 QgsPointCloudRequest request;
296 request.setAttributes( attributeCollection );
297
298 acceptedPoints = QtConcurrent::blockingMappedReduced( nodes,
299 MapIndexedPointCloudNode( request, index->scale(), index->offset(), extentGeometry, extentZRange, index, pointsLimit ),
300 qOverload<const QVector<QMap<QString, QVariant>>&>( &QVector<QMap<QString, QVariant>>::append ),
301 QtConcurrent::UnorderedReduce );
302
303 return acceptedPoints;
304}
305
306QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(
307 const QgsPointCloudIndex *pc,
309 double maxError,
310 double nodeError,
311 const QgsGeometry &extentGeometry,
312 const QgsDoubleRange &extentZRange )
313{
314 QVector<IndexedPointCloudNode> nodes;
315
316 const QgsDoubleRange nodeZRange = pc->nodeZRange( n );
317 if ( !extentZRange.overlaps( nodeZRange ) )
318 return nodes;
319
320 if ( !extentGeometry.intersects( pc->nodeMapExtent( n ) ) )
321 return nodes;
322
323 nodes.append( n );
324
325 const double childrenError = nodeError / 2.0;
326 if ( childrenError < maxError )
327 return nodes;
328
329 const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
330 for ( const IndexedPointCloudNode &nn : children )
331 {
332 if ( extentGeometry.intersects( pc->nodeMapExtent( nn ) ) )
333 nodes += traverseTree( pc, nn, maxError, childrenError, extentGeometry, extentZRange );
334 }
335
336 return nodes;
337}
338
339bool QgsPointCloudDataProvider::setSubsetString( const QString &subset, bool updateFeatureCount )
340{
341 Q_UNUSED( updateFeatureCount )
342 const auto i = index();
343 if ( !i )
344 return false;
345
346 if ( !i->setSubsetString( subset ) )
347 return false;
348 mSubsetString = subset;
349 emit dataChanged();
350 return true;
351}
352
354{
355 return mSubsetString;
356}
357
Represents a indexed point cloud node in octree.
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'...
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
QgsRange which stores a range of double values.
Definition qgsrange.h:203
A geometry is the spatial representation of a feature.
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)
Creates and returns a new geometry engine representing the specified geometry.
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.
virtual QVariant metadataClassStatistic(const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic) const
Returns a statistic for one class value from the specified attribute, taken only from the metadata of...
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 containings the statistics metadata extracted from the dataset.
virtual QVariant metadataStatistic(const QString &attribute, QgsStatisticalSummary::Statistic statistic) const
Returns a statistic for the specified attribute, taken only from the metadata of the point cloud data...
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...
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 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...
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 QVariant metadataClassStatistic(const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic) const
Returns the statistic statistic of the class value of the attribute attribute.
virtual QList< IndexedPointCloudNode > nodeChildren(const IndexedPointCloudNode &n) const
Returns all children of node.
QgsVector3D offset() const
Returns offset.
QgsVector3D scale() const
Returns scale.
virtual QVariantList metadataClasses(const QString &attribute) const
Returns the classes of attribute.
virtual QVariant metadataStatistic(const QString &attribute, QgsStatisticalSummary::Statistic statistic) const
Returns the statistic statistic of attribute.
virtual bool isValid() const =0
Returns whether index is loaded and valid.
virtual QgsPointCloudStatistics metadataStatistics() const
Returns the object containings the statistics metadata extracted from the dataset.
virtual QgsPointCloudBlock * nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
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.
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:147
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
Definition qgsrange.h:108
A rectangle specified with double values.
double width() const
Returns the width of the rectangle.
Statistic
Enumeration of flags that specify statistics to be calculated.
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.