24#include <QJsonDocument>
40#include "qgspointcloudexpression.h"
45QgsRemoteEptPointCloudIndex::QgsRemoteEptPointCloudIndex() : QgsEptPointCloudIndex()
50QgsRemoteEptPointCloudIndex::~QgsRemoteEptPointCloudIndex() =
default;
52std::unique_ptr<QgsPointCloudIndex> QgsRemoteEptPointCloudIndex::clone()
const
54 QgsRemoteEptPointCloudIndex *clone =
new QgsRemoteEptPointCloudIndex;
55 QMutexLocker locker( &mHierarchyMutex );
56 copyCommonProperties( clone );
57 return std::unique_ptr<QgsPointCloudIndex>( clone );
60QList<IndexedPointCloudNode> QgsRemoteEptPointCloudIndex::nodeChildren(
const IndexedPointCloudNode &n )
const
62 QList<IndexedPointCloudNode> lst;
63 if ( !loadNodeHierarchy( n ) )
66 const int d = n.
d() + 1;
67 const int x = n.
x() * 2;
68 const int y = n.
y() * 2;
69 const int z = n.
z() * 2;
72 for (
int i = 0; i < 8; ++i )
74 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
76 if ( loadNodeHierarchy( n2 ) )
82void QgsRemoteEptPointCloudIndex::load(
const QString &uri )
86 QStringList splitUrl = uri.split(
'/' );
88 mUrlFileNamePart = splitUrl.back();
90 mUrlDirectoryPart = splitUrl.join(
'/' );
92 QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) );
104 mIsValid = loadSchema( reply.
content() );
111 return std::unique_ptr<QgsPointCloudBlock>( cached );
114 std::unique_ptr<QgsPointCloudBlockRequest> blockRequest( asyncNodeData( n, request ) );
122 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->takeBlock();
125 QgsDebugError( QStringLiteral(
"Error downloading node %1 data, error : %2 " ).arg( n.
toString(), blockRequest->errorStr() ) );
128 storeNodeDataToCache( block.get(), n, request );
137 scale(), offset(), mFilterExpression, request.
filterRect() );
140 if ( !loadNodeHierarchy( n ) )
144 if ( mDataType == QLatin1String(
"binary" ) )
146 fileUrl = QStringLiteral(
"%1/ept-data/%2.bin" ).arg( mUrlDirectoryPart, n.
toString() );
148 else if ( mDataType == QLatin1String(
"zstandard" ) )
150 fileUrl = QStringLiteral(
"%1/ept-data/%2.zst" ).arg( mUrlDirectoryPart, n.
toString() );
152 else if ( mDataType == QLatin1String(
"laszip" ) )
154 fileUrl = QStringLiteral(
"%1/ept-data/%2.laz" ).arg( mUrlDirectoryPart, n.
toString() );
164 QgsPointCloudExpression filterExpression = mFilterExpression;
166 requestAttributes.
extend( attributes(), filterExpression.referencedAttributes() );
172 return loadNodeHierarchy( n );
177 mHierarchyMutex.lock();
178 bool found = mHierarchy.contains( nodeId );
179 mHierarchyMutex.unlock();
183 QVector<IndexedPointCloudNode> nodePathToRoot;
188 nodePathToRoot.push_back( currentNode );
191 while ( currentNode.
d() >= 0 );
194 for (
int i = nodePathToRoot.size() - 1; i >= 0 && !mHierarchy.contains( nodeId ); --i )
198 mHierarchyMutex.lock();
199 const bool foundInHierarchy = mHierarchy.contains( node );
200 const bool foundInHierarchyNodes = mHierarchyNodes.contains( node );
201 mHierarchyMutex.unlock();
202 if ( foundInHierarchy )
205 if ( !foundInHierarchyNodes )
208 const QString fileUrl = QStringLiteral(
"%1/ept-hierarchy/%2.json" ).arg( mUrlDirectoryPart, node.
toString() );
209 QNetworkRequest nr( fileUrl );
211 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
212 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
220 if ( reply->
error() != QNetworkReply::NoError )
222 QgsDebugError( QStringLiteral(
"Request failed: " ) + mUri );
226 const QByteArray dataJsonH = reply->data();
227 QJsonParseError errH;
228 const QJsonDocument docH = QJsonDocument::fromJson( dataJsonH, &errH );
229 if ( errH.error != QJsonParseError::NoError )
231 QgsDebugMsgLevel( QStringLiteral(
"QJsonParseError when reading hierarchy from file %1" ).arg( fileUrl ), 2 );
235 const QJsonObject rootHObj = docH.object();
236 for (
auto it = rootHObj.constBegin(); it != rootHObj.constEnd(); ++it )
238 const QString nodeIdStr = it.key();
239 const int nodePointCount = it.value().toInt();
241 mHierarchyMutex.lock();
242 if ( nodePointCount >= 0 )
243 mHierarchy[nodeId] = nodePointCount;
244 else if ( nodePointCount == -1 )
245 mHierarchyNodes.insert( nodeId );
246 mHierarchyMutex.unlock();
250 mHierarchyMutex.lock();
251 found = mHierarchy.contains( nodeId );
252 mHierarchyMutex.unlock();
257bool QgsRemoteEptPointCloudIndex::isValid()
const
262void QgsRemoteEptPointCloudIndex::copyCommonProperties( QgsRemoteEptPointCloudIndex *destination )
const
264 QgsEptPointCloudIndex::copyCommonProperties( destination );
267 destination->mUrlDirectoryPart = mUrlDirectoryPart;
268 destination->mUrlFileNamePart = mUrlFileNamePart;
269 destination->mHierarchyNodes = mHierarchyNodes;
Represents a indexed point cloud node in octree.
static IndexedPointCloudNode fromString(const QString &str)
Creates node from string.
QString toString() const
Encode node to string.
IndexedPointCloudNode parentNode() const
Returns the parent of the node.
static QgsTileDownloadManager * tileDownloadManager()
Returns the application's tile download manager, used for download of map tiles when rendering.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
@ NoError
No error was encountered.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
Class for handling a QgsPointCloudBlockRequest using existing cached QgsPointCloudBlock.
Base class for handling loading QgsPointCloudBlock asynchronously from a remote EPT dataset.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
QNetworkReply::NetworkError error() const
Returns the reply's error message, or QNetworkReply::NoError if no error was encountered.
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 QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)