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