QGIS API Documentation  3.21.0-Master (56b4176581)
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  QgsPointCloudIndex *lIndex = index();
48  return lIndex && lIndex->isValid();
49 }
50 
52 {
53  return QgsGeometry::fromRect( extent() );
54 }
55 
57 {
58  return QVariantMap();
59 }
60 
62 {
63  return nullptr;
64 }
65 
67 {
68  static QMap< int, QString > sCodes
69  {
70  {0, QStringLiteral( "Created, Never Classified" )},
71  {1, QStringLiteral( "Unclassified" )},
72  {2, QStringLiteral( "Ground" )},
73  {3, QStringLiteral( "Low Vegetation" )},
74  {4, QStringLiteral( "Medium Vegetation" )},
75  {5, QStringLiteral( "High Vegetation" )},
76  {6, QStringLiteral( "Building" )},
77  {7, QStringLiteral( "Low Point (Low Noise)" )},
78  {8, QStringLiteral( "Reserved" )},
79  {9, QStringLiteral( "Water" )},
80  {10, QStringLiteral( "Rail" )},
81  {11, QStringLiteral( "Road Surface" )},
82  {12, QStringLiteral( "Reserved" )},
83  {13, QStringLiteral( "Wire - Guard (Shield)" )},
84  {14, QStringLiteral( "Wire - Conductor (Phase)" )},
85  {15, QStringLiteral( "Transmission Tower" )},
86  {16, QStringLiteral( "Wire-Structure Connector (Insulator)" )},
87  {17, QStringLiteral( "Bridge Deck" )},
88  {18, QStringLiteral( "High Noise" )},
89  };
90 
91  static std::once_flag initialized;
92  std::call_once( initialized, [ = ]( )
93  {
94  for ( int i = 19; i <= 63; ++i )
95  sCodes.insert( i, QStringLiteral( "Reserved" ) );
96  for ( int i = 64; i <= 255; ++i )
97  sCodes.insert( i, QStringLiteral( "User Definable" ) );
98  } );
99 
100  return sCodes;
101 }
102 
104 {
105  static QMap< int, QString > sCodes
106  {
107  {0, QObject::tr( "Created, Never Classified" )},
108  {1, QObject::tr( "Unclassified" )},
109  {2, QObject::tr( "Ground" )},
110  {3, QObject::tr( "Low Vegetation" )},
111  {4, QObject::tr( "Medium Vegetation" )},
112  {5, QObject::tr( "High Vegetation" )},
113  {6, QObject::tr( "Building" )},
114  {7, QObject::tr( "Low Point (Noise)" )},
115  {8, QObject::tr( "Reserved" )},
116  {9, QObject::tr( "Water" )},
117  {10, QObject::tr( "Rail" )},
118  {11, QObject::tr( "Road Surface" )},
119  {12, QObject::tr( "Reserved" )},
120  {13, QObject::tr( "Wire - Guard (Shield)" )},
121  {14, QObject::tr( "Wire - Conductor (Phase)" )},
122  {15, QObject::tr( "Transmission Tower" )},
123  {16, QObject::tr( "Wire-Structure Connector (Insulator)" )},
124  {17, QObject::tr( "Bridge Deck" )},
125  {18, QObject::tr( "High Noise" )},
126  };
127 
128  static std::once_flag initialized;
129  std::call_once( initialized, [ = ]( )
130  {
131  for ( int i = 19; i <= 63; ++i )
132  sCodes.insert( i, QObject::tr( "Reserved" ) );
133  for ( int i = 64; i <= 255; ++i )
134  sCodes.insert( i, QObject::tr( "User Definable" ) );
135  } );
136 
137  return sCodes;
138 }
139 
141 {
142  static const QMap< int, QString > sCodes
143  {
144  {0, QStringLiteral( "No color or time stored" )},
145  {1, QStringLiteral( "Time is stored" )},
146  {2, QStringLiteral( "Color is stored" )},
147  {3, QStringLiteral( "Color and time are stored" )},
148  {6, QStringLiteral( "Time is stored" )},
149  {7, QStringLiteral( "Time and color are stored)" )},
150  {8, QStringLiteral( "Time, color and near infrared are stored" )},
151  };
152 
153  return sCodes;
154 }
155 
157 {
158  static const QMap< int, QString > sCodes
159  {
160  {0, QObject::tr( "No color or time stored" )},
161  {1, QObject::tr( "Time is stored" )},
162  {2, QObject::tr( "Color is stored" )},
163  {3, QObject::tr( "Color and time are stored" )},
164  {6, QObject::tr( "Time is stored" )},
165  {7, QObject::tr( "Time and color are stored)" )},
166  {8, QObject::tr( "Time, color and near infrared are stored" )},
167  };
168 
169  return sCodes;
170 }
171 
173 {
174  return QVariant();
175 }
176 
177 QVariantList QgsPointCloudDataProvider::metadataClasses( const QString & ) const
178 {
179  return QVariantList();
180 }
181 
183 {
184  return QVariant();
185 }
186 
188 {
189  typedef QVector<QMap<QString, QVariant>> result_type;
190 
191  MapIndexedPointCloudNode( QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset,
192  const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit )
193  : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit )
194  { }
195 
196  QVector<QVariantMap> operator()( IndexedPointCloudNode n )
197  {
198  QVector<QVariantMap> acceptedPoints;
199  std::unique_ptr<QgsPointCloudBlock> block( mIndex->nodeData( n, mRequest ) );
200 
201  if ( !block || pointsCount == mPointsLimit )
202  return acceptedPoints;
203 
204  const char *ptr = block->data();
205  const QgsPointCloudAttributeCollection blockAttributes = block->attributes();
206  const std::size_t recordSize = blockAttributes.pointRecordSize();
207  int xOffset = 0, yOffset = 0, zOffset = 0;
208  const QgsPointCloudAttribute::DataType xType = blockAttributes.find( QStringLiteral( "X" ), xOffset )->type();
209  const QgsPointCloudAttribute::DataType yType = blockAttributes.find( QStringLiteral( "Y" ), yOffset )->type();
210  const QgsPointCloudAttribute::DataType zType = blockAttributes.find( QStringLiteral( "Z" ), zOffset )->type();
211  std::unique_ptr< QgsGeometryEngine > extentEngine( QgsGeometry::createGeometryEngine( mExtentGeometry.constGet() ) );
212  extentEngine->prepareGeometry();
213  for ( int i = 0; i < block->pointCount() && pointsCount < mPointsLimit; ++i )
214  {
215  double x, y, z;
216  QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, block->scale(), block->offset(), x, y, z );
217  QgsPoint point( x, y );
218 
219  if ( mZRange.contains( z ) && extentEngine->contains( &point ) )
220  {
221  QVariantMap pointAttr = QgsPointCloudAttribute::getAttributeMap( ptr, i * recordSize, blockAttributes );
222  pointAttr[ QStringLiteral( "X" ) ] = x;
223  pointAttr[ QStringLiteral( "Y" ) ] = y;
224  pointAttr[ QStringLiteral( "Z" ) ] = z;
225  pointsCount++;
226  acceptedPoints.push_back( pointAttr );
227  }
228  }
229  return acceptedPoints;
230  }
231 
239  int pointsCount = 0;
240 };
241 
243  double maxError,
244  const QgsGeometry &extentGeometry,
245  const QgsDoubleRange &extentZRange, int pointsLimit )
246 {
247  QVector<QVariantMap> acceptedPoints;
248 
249  QgsPointCloudIndex *index = this->index();
250  const IndexedPointCloudNode root = index->root();
251 
252  const QgsRectangle rootNodeExtent = index->nodeMapExtent( root );
253  const double rootError = rootNodeExtent.width() / index->span();
254 
255  const QVector<IndexedPointCloudNode> nodes = traverseTree( index, root, maxError, rootError, extentGeometry, extentZRange );
256 
257  const QgsPointCloudAttributeCollection attributeCollection = index->attributes();
258  QgsPointCloudRequest request;
259  request.setAttributes( attributeCollection );
260 
261  acceptedPoints = QtConcurrent::blockingMappedReduced( nodes,
262  MapIndexedPointCloudNode( request, index->scale(), index->offset(), extentGeometry, extentZRange, index, pointsLimit ),
263  qOverload<const QVector<QMap<QString, QVariant>>&>( &QVector<QMap<QString, QVariant>>::append ),
264  QtConcurrent::UnorderedReduce );
265 
266  return acceptedPoints;
267 }
268 
269 QVector<IndexedPointCloudNode> QgsPointCloudDataProvider::traverseTree(
270  const QgsPointCloudIndex *pc,
272  double maxError,
273  double nodeError,
274  const QgsGeometry &extentGeometry,
275  const QgsDoubleRange &extentZRange )
276 {
277  QVector<IndexedPointCloudNode> nodes;
278 
279  const QgsDoubleRange nodeZRange = pc->nodeZRange( n );
280  if ( !extentZRange.overlaps( nodeZRange ) )
281  return nodes;
282 
283  if ( !extentGeometry.intersects( pc->nodeMapExtent( n ) ) )
284  return nodes;
285 
286  nodes.append( n );
287 
288  const double childrenError = nodeError / 2.0;
289  if ( childrenError < maxError )
290  return nodes;
291 
292  const QList<IndexedPointCloudNode> children = pc->nodeChildren( n );
293  for ( const IndexedPointCloudNode &nn : children )
294  {
295  if ( extentGeometry.intersects( pc->nodeMapExtent( nn ) ) )
296  nodes += traverseTree( pc, nn, maxError, childrenError, extentGeometry, extentZRange );
297  }
298 
299  return nodes;
300 }
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 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.
~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.
virtual 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: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.
Definition: qgsrectangle.h:42
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
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.