QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
qgsremotecopcpointcloudindex.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsremotecopcpointcloudindex.cpp
3 --------------------
4 begin : March 2022
5 copyright : (C) 2022 by Belgacem Nedjima
6 email : belgacem dot nedjima 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
19#include "moc_qgsremotecopcpointcloudindex.cpp"
20
21#include <QFile>
22#include <QFileInfo>
23#include <QDir>
24#include <QJsonArray>
25#include <QJsonDocument>
26#include <QJsonObject>
27#include <QTime>
28#include <QtDebug>
29#include <QQueue>
30#include <QTimer>
31
34#include "qgslogger.h"
36#include "qgsapplication.h"
39#include "qgspointcloudexpression.h"
42
44
45QgsRemoteCopcPointCloudIndex::QgsRemoteCopcPointCloudIndex() = default;
46
47QgsRemoteCopcPointCloudIndex::~QgsRemoteCopcPointCloudIndex() = default;
48
49std::unique_ptr<QgsPointCloudIndex> QgsRemoteCopcPointCloudIndex::clone() const
50{
51 QgsRemoteCopcPointCloudIndex *clone = new QgsRemoteCopcPointCloudIndex;
52 QMutexLocker locker( &mHierarchyMutex );
53 copyCommonProperties( clone );
54 return std::unique_ptr<QgsPointCloudIndex>( clone );
55}
56
57void QgsRemoteCopcPointCloudIndex::load( const QString &uri )
58{
59 mUri = uri;
60 QUrl url( uri );
61 mLazInfo.reset( new QgsLazInfo( QgsLazInfo::fromUrl( url ) ) );
62 mIsValid = mLazInfo->isValid();
63 if ( mIsValid )
64 {
65 mIsValid = loadSchema( *mLazInfo.get() );
66 if ( mIsValid )
67 {
68 loadHierarchy();
69 }
70 }
71 if ( !mIsValid )
72 {
73 mError = tr( "Unable to recognize %1 as a LAZ file: \"%2\"" ).arg( uri, mLazInfo->error() );
74 }
75}
76
77std::unique_ptr<QgsPointCloudBlock> QgsRemoteCopcPointCloudIndex::nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request )
78{
79 if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) )
80 {
81 return std::unique_ptr<QgsPointCloudBlock>( cached );
82 }
83
84 std::unique_ptr<QgsPointCloudBlockRequest> blockRequest( asyncNodeData( n, request ) );
85 if ( !blockRequest )
86 return nullptr;
87
88 QEventLoop loop;
89 connect( blockRequest.get(), &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit );
90 loop.exec();
91
92 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->takeBlock();
93
94 if ( !block )
95 {
96 QgsDebugError( QStringLiteral( "Error downloading node %1 data, error : %2 " ).arg( n.toString(), blockRequest->errorStr() ) );
97 }
98
99 storeNodeDataToCache( block.get(), n, request );
100 return block;
101}
102
103QgsPointCloudBlockRequest *QgsRemoteCopcPointCloudIndex::asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request )
104{
105 if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) )
106 {
107 return new QgsCachedPointCloudBlockRequest( cached, n, mUri, attributes(), request.attributes(),
108 scale(), offset(), mFilterExpression, request.filterRect() );
109 }
110
111 if ( !fetchNodeHierarchy( n ) )
112 return nullptr;
113 QMutexLocker locker( &mHierarchyMutex );
114
115 // we need to create a copy of the expression to pass to the decoder
116 // as the same QgsPointCloudExpression object might be concurrently
117 // used on another thread, for example in a 3d view
118 QgsPointCloudExpression filterExpression = mFilterExpression;
119 QgsPointCloudAttributeCollection requestAttributes = request.attributes();
120 requestAttributes.extend( attributes(), filterExpression.referencedAttributes() );
121 auto [ blockOffset, blockSize ] = mHierarchyNodePos.value( n );
122 int pointCount = mHierarchy.value( n );
123
124 return new QgsCopcPointCloudBlockRequest( n, mUri, attributes(), requestAttributes,
125 scale(), offset(), filterExpression, request.filterRect(),
126 blockOffset, blockSize, pointCount, *mLazInfo.get() );
127}
128
129bool QgsRemoteCopcPointCloudIndex::isValid() const
130{
131 return mIsValid;
132}
133
134void QgsRemoteCopcPointCloudIndex::fetchHierarchyPage( uint64_t offset, uint64_t byteSize ) const
135{
136 Q_ASSERT( byteSize > 0 );
137
138 QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) );
139 QgsSetRequestInitiatorClass( nr, QStringLiteral( "QgsRemoteCopcPointCloudIndex" ) );
140 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
141 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
142 QByteArray queryRange = QStringLiteral( "bytes=%1-%2" ).arg( offset ).arg( offset + byteSize - 1 ).toLocal8Bit();
143 nr.setRawHeader( "Range", queryRange );
144
145 std::unique_ptr<QgsTileDownloadManagerReply> reply( QgsApplication::tileDownloadManager()->get( nr ) );
146
147 QEventLoop loop;
148 connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit );
149 loop.exec();
150
151 if ( reply->error() != QNetworkReply::NoError )
152 {
153 QgsDebugError( QStringLiteral( "Request failed: " ) + mUri );
154 return;
155 }
156
157 QByteArray data = reply->data();
158
159 populateHierarchy( data.constData(), byteSize );
160}
161
162void QgsRemoteCopcPointCloudIndex::copyCommonProperties( QgsRemoteCopcPointCloudIndex *destination ) const
163{
164 QgsCopcPointCloudIndex::copyCommonProperties( destination );
165
166 // QgsRemoteCopcPointCloudIndex specific fields
167 destination->mHierarchyNodes = mHierarchyNodes;
168}
169
Represents a indexed point cloud node in octree.
QString toString() const
Encode node to string.
static QgsTileDownloadManager * tileDownloadManager()
Returns the application's tile download manager, used for download of map tiles when rendering.
Class for handling a QgsPointCloudBlockRequest using existing cached QgsPointCloudBlock.
Base class for handling loading QgsPointCloudBlock asynchronously from a remote COPC dataset.
Class for extracting information contained in LAZ file such as the public header block and variable l...
Definition qgslazinfo.h:39
static QgsLazInfo fromUrl(QUrl &url)
Static function to create a QgsLazInfo class from a file over network.
Collection of point cloud attributes.
void extend(const QgsPointCloudAttributeCollection &otherCollection, const QSet< QString > &matchingNames)
Adds specific missing attributes from another QgsPointCloudAttributeCollection.
Base class for handling loading QgsPointCloudBlock asynchronously.
void finished()
Emitted when the request processing has finished.
Base class for storing raw data from point cloud nodes.
Point cloud data request.
QgsPointCloudAttributeCollection attributes() const
Returns attributes.
QgsRectangle filterRect() const
Returns the rectangle from which points will be taken, in point cloud's crs.
void finished()
Emitted when the reply has finished (either with a success or with a failure)
#define QgsDebugError(str)
Definition qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)