QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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"
22 #include "qgspointcloudrequest.h"
23 #include "qgsgeometryengine.h"
24 #include <mutex>
25 #include <QDebug>
26 #include <QtMath>
27 
28 #include <QtConcurrent/QtConcurrentMap>
29 
31  const QString &uri,
32  const QgsDataProvider::ProviderOptions &options,
33  QgsDataProvider::ReadFlags flags )
34  : QgsDataProvider( uri, options, flags )
35 {
36 }
37 
39 
40 QgsPointCloudDataProvider::Capabilities QgsPointCloudDataProvider::capabilities() const
41 {
43 }
44 
46 {
47  return index() && index()->isValid();
48 }
49 
51 {
52  return QgsGeometry::fromRect( extent() );
53 }
54 
56 {
57  return QVariantMap();
58 }
59 
61 {
62  return nullptr;
63 }
64 
66 {
67  static QMap< int, QString > sCodes
68  {
69  {0, QStringLiteral( "Created, Never Classified" )},
70  {1, QStringLiteral( "Unclassified" )},
71  {2, QStringLiteral( "Ground" )},
72  {3, QStringLiteral( "Low Vegetation" )},
73  {4, QStringLiteral( "Medium Vegetation" )},
74  {5, QStringLiteral( "High Vegetation" )},
75  {6, QStringLiteral( "Building" )},
76  {7, QStringLiteral( "Low Point (Low Noise)" )},
77  {8, QStringLiteral( "Reserved" )},
78  {9, QStringLiteral( "Water" )},
79  {10, QStringLiteral( "Rail" )},
80  {11, QStringLiteral( "Road Surface" )},
81  {12, QStringLiteral( "Reserved" )},
82  {13, QStringLiteral( "Wire - Guard (Shield)" )},
83  {14, QStringLiteral( "Wire - Conductor (Phase)" )},
84  {15, QStringLiteral( "Transmission Tower" )},
85  {16, QStringLiteral( "Wire-Structure Connector (Insulator)" )},
86  {17, QStringLiteral( "Bridge Deck" )},
87  {18, QStringLiteral( "High Noise" )},
88  };
89 
90  static std::once_flag initialized;
91  std::call_once( initialized, [ = ]( )
92  {
93  for ( int i = 19; i <= 63; ++i )
94  sCodes.insert( i, QStringLiteral( "Reserved" ) );
95  for ( int i = 64; i <= 255; ++i )
96  sCodes.insert( i, QStringLiteral( "User Definable" ) );
97  } );
98 
99  return sCodes;
100 }
101 
103 {
104  static QMap< int, QString > sCodes
105  {
106  {0, QObject::tr( "Created, Never Classified" )},
107  {1, QObject::tr( "Unclassified" )},
108  {2, QObject::tr( "Ground" )},
109  {3, QObject::tr( "Low Vegetation" )},
110  {4, QObject::tr( "Medium Vegetation" )},
111  {5, QObject::tr( "High Vegetation" )},
112  {6, QObject::tr( "Building" )},
113  {7, QObject::tr( "Low Point (Noise)" )},
114  {8, QObject::tr( "Reserved" )},
115  {9, QObject::tr( "Water" )},
116  {10, QObject::tr( "Rail" )},
117  {11, QObject::tr( "Road Surface" )},
118  {12, QObject::tr( "Reserved" )},
119  {13, QObject::tr( "Wire - Guard (Shield)" )},
120  {14, QObject::tr( "Wire - Conductor (Phase)" )},
121  {15, QObject::tr( "Transmission Tower" )},
122  {16, QObject::tr( "Wire-Structure Connector (Insulator)" )},
123  {17, QObject::tr( "Bridge Deck" )},
124  {18, QObject::tr( "High Noise" )},
125  };
126 
127  static std::once_flag initialized;
128  std::call_once( initialized, [ = ]( )
129  {
130  for ( int i = 19; i <= 63; ++i )
131  sCodes.insert( i, QObject::tr( "Reserved" ) );
132  for ( int i = 64; i <= 255; ++i )
133  sCodes.insert( i, QObject::tr( "User Definable" ) );
134  } );
135 
136  return sCodes;
137 }
138 
140 {
141  static QMap< int, QString > sCodes
142  {
143  {0, QStringLiteral( "No color or time stored" )},
144  {1, QStringLiteral( "Time is stored" )},
145  {2, QStringLiteral( "Color is stored" )},
146  {3, QStringLiteral( "Color and time are stored" )},
147  {6, QStringLiteral( "Time is stored" )},
148  {7, QStringLiteral( "Time and color are stored)" )},
149  {8, QStringLiteral( "Time, color and near infrared are stored" )},
150  };
151 
152  return sCodes;
153 }
154 
156 {
157  static QMap< int, QString > sCodes
158  {
159  {0, QObject::tr( "No color or time stored" )},
160  {1, QObject::tr( "Time is stored" )},
161  {2, QObject::tr( "Color is stored" )},
162  {3, QObject::tr( "Color and time are stored" )},
163  {6, QObject::tr( "Time is stored" )},
164  {7, QObject::tr( "Time and color are stored)" )},
165  {8, QObject::tr( "Time, color and near infrared are stored" )},
166  };
167 
168  return sCodes;
169 }
170 
172 {
173  return QVariant();
174 }
175 
176 QVariantList QgsPointCloudDataProvider::metadataClasses( const QString & ) const
177 {
178  return QVariantList();
179 }
180 
182 {
183  return QVariant();
184 }
185 
187 {
188  typedef QVector<QMap<QString, QVariant>> result_type;
189 
190  MapIndexedPointCloudNode( QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset,
191  const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit )
192  : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit )
193  { }
194 
195  QVector<QVariantMap> operator()( IndexedPointCloudNode n )
196  {
197  QVector<QVariantMap> acceptedPoints;
198  std::unique_ptr<QgsPointCloudBlock> block( mIndex->nodeData( n, mRequest ) );
199 
200  if ( !block || pointsCount == mPointsLimit )
201  return acceptedPoints;
202 
203  const char *ptr = block->data();
204  QgsPointCloudAttributeCollection blockAttributes = block->attributes();
205  const std::size_t recordSize = blockAttributes.pointRecordSize();
206  int xOffset = 0, yOffset = 0, zOffset = 0;
207  const QgsPointCloudAttribute::DataType xType = blockAttributes.find( QStringLiteral( "X" ), xOffset )->type();
208  const QgsPointCloudAttribute::DataType yType = blockAttributes.find( QStringLiteral( "Y" ), yOffset )->type();
209  const QgsPointCloudAttribute::DataType zType = blockAttributes.find( QStringLiteral( "Z" ), zOffset )->type();
210  std::unique_ptr< QgsGeometryEngine > extentEngine( QgsGeometry::createGeometryEngine( mExtentGeometry.constGet() ) );
211  extentEngine->prepareGeometry();
212  for ( int i = 0; i < block->pointCount() && pointsCount < mPointsLimit; ++i )
213  {
214  double x, y, z;
215  QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, mIndexScale, mIndexOffset, x, y, z );
216  QgsPoint point( x, y );
217 
218  if ( mZRange.contains( z ) && extentEngine->contains( &point ) )
219  {
220  QVariantMap pointAttr = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, blockAttributes );
221  pointAttr[ QStringLiteral( "X" ) ] = x;
222  pointAttr[ QStringLiteral( "Y" ) ] = y;
223  pointAttr[ QStringLiteral( "Z" ) ] = z;
224  pointsCount++;
225  acceptedPoints.push_back( pointAttr );
226  }
227  }
228  return acceptedPoints;
229  }
230 
238  int pointsCount = 0;
239 };
240 
242  double maxError,
243  const QgsGeometry &extentGeometry,
244  const QgsDoubleRange &extentZRange, int pointsLimit )
245 {
246  QVector<QVariantMap> acceptedPoints;
247 
248  QgsPointCloudIndex *index = this->index();
249  const IndexedPointCloudNode root = index->root();
250 
251  QgsRectangle rootNodeExtent = index->nodeMapExtent( root );
252  const double rootError = rootNodeExtent.width() / index->span();
253 
254  QVector<IndexedPointCloudNode> nodes = traverseTree( index, root, maxError, rootError, extentGeometry, extentZRange );
255 
256  QgsPointCloudAttributeCollection attributeCollection = index->attributes();
257  QgsPointCloudRequest request;
258  request.setAttributes( attributeCollection );
259 
260  acceptedPoints = QtConcurrent::blockingMappedReduced( nodes,
261  MapIndexedPointCloudNode( request, index->scale(), index->offset(), extentGeometry, extentZRange, index, pointsLimit ),
262  qgis::overload<const QVector<QMap<QString, QVariant>>&>::of( &QVector<QMap<QString, QVariant>>::append ),
263  QtConcurrent::UnorderedReduce );
264 
265  return acceptedPoints;
266 }
267 
268 QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(
269  const QgsPointCloudIndex *pc,
271  double maxError,
272  double nodeError,
273  const QgsGeometry &extentGeometry,
274  const QgsDoubleRange &extentZRange )
275 {
276  QVector<IndexedPointCloudNode> nodes;
277 
278  const QgsDoubleRange nodeZRange = pc->nodeZRange( n );
279  if ( !extentZRange.overlaps( nodeZRange ) )
280  return nodes;
281 
282  if ( !extentGeometry.intersects( pc->nodeMapExtent( n ) ) )
283  return nodes;
284 
285  nodes.append( n );
286 
287  double childrenError = nodeError / 2.0;
288  if ( childrenError < maxError )
289  return nodes;
290 
291  const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
292  for ( const IndexedPointCloudNode &nn : children )
293  {
294  if ( extentGeometry.intersects( pc->nodeMapExtent( nn ) ) )
295  nodes += traverseTree( pc, nn, maxError, childrenError, extentGeometry, extentZRange );
296  }
297 
298  return nodes;
299 }
Represents a indexed point cloud node in octree.
Abstract base class for spatial data provider implementations.
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.
Definition: qgsgeometry.h:124
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
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.
~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.
virtual QgsPointCloudIndex * index() const
Returns the point cloud index associated with the provider.
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...
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 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.
QList< IndexedPointCloudNode > nodeChildren(const IndexedPointCloudNode &n) const
Returns all children of node.
QgsVector3D offset() const
Returns offset.
QgsVector3D scale() const
Returns scale.
virtual QgsPointCloudBlock * nodeData(const IndexedPointCloudNode &n, const QgsPointCloudRequest &request)=0
Returns node data block.
virtual bool isValid() const =0
Returns whether index is loaded and valid.
IndexedPointCloudNode root()
Returns root node of the index.
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.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
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.
Definition: qgsrectangle.h:42
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
Statistic
Enumeration of flags that specify statistics to be calculated.
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)
QVector< QVariantMap > operator()(IndexedPointCloudNode n)
Setting options for creating vector data providers.