24#include <QJsonDocument>
40#include "qgspointcloudexpression.h"
46QgsRemoteEptPointCloudIndex::QgsRemoteEptPointCloudIndex() : QgsEptPointCloudIndex()
51QgsRemoteEptPointCloudIndex::~QgsRemoteEptPointCloudIndex() =
default;
53std::unique_ptr<QgsPointCloudIndex> QgsRemoteEptPointCloudIndex::clone()
const
55 QgsRemoteEptPointCloudIndex *clone =
new QgsRemoteEptPointCloudIndex;
56 QMutexLocker locker( &mHierarchyMutex );
57 copyCommonProperties( clone );
58 return std::unique_ptr<QgsPointCloudIndex>( clone );
61QList<IndexedPointCloudNode> QgsRemoteEptPointCloudIndex::nodeChildren(
const IndexedPointCloudNode &n )
const
63 QList<IndexedPointCloudNode> lst;
64 if ( !loadNodeHierarchy( n ) )
67 const int d = n.
d() + 1;
68 const int x = n.
x() * 2;
69 const int y = n.
y() * 2;
70 const int z = n.
z() * 2;
73 for (
int i = 0; i < 8; ++i )
75 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
77 if ( loadNodeHierarchy( n2 ) )
83void QgsRemoteEptPointCloudIndex::load(
const QString &uri )
87 QStringList splitUrl = uri.split(
'/' );
89 mUrlFileNamePart = splitUrl.back();
91 mUrlDirectoryPart = splitUrl.join(
'/' );
93 QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) );
106 mIsValid = loadSchema( reply.
content() );
113 return std::unique_ptr<QgsPointCloudBlock>( cached );
116 std::unique_ptr<QgsPointCloudBlockRequest> blockRequest( asyncNodeData( n, request ) );
124 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->takeBlock();
127 QgsDebugError( QStringLiteral(
"Error downloading node %1 data, error : %2 " ).arg( n.
toString(), blockRequest->errorStr() ) );
130 storeNodeDataToCache( block.get(), n, request );
139 scale(), offset(), mFilterExpression, request.
filterRect() );
142 if ( !loadNodeHierarchy( n ) )
146 if ( mDataType == QLatin1String(
"binary" ) )
148 fileUrl = QStringLiteral(
"%1/ept-data/%2.bin" ).arg( mUrlDirectoryPart, n.
toString() );
150 else if ( mDataType == QLatin1String(
"zstandard" ) )
152 fileUrl = QStringLiteral(
"%1/ept-data/%2.zst" ).arg( mUrlDirectoryPart, n.
toString() );
154 else if ( mDataType == QLatin1String(
"laszip" ) )
156 fileUrl = QStringLiteral(
"%1/ept-data/%2.laz" ).arg( mUrlDirectoryPart, n.
toString() );
166 QgsPointCloudExpression filterExpression = mFilterExpression;
168 requestAttributes.
extend( attributes(), filterExpression.referencedAttributes() );
174 return loadNodeHierarchy( n );
179 mHierarchyMutex.lock();
180 bool found = mHierarchy.contains( nodeId );
181 mHierarchyMutex.unlock();
185 QVector<IndexedPointCloudNode> nodePathToRoot;
190 nodePathToRoot.push_back( currentNode );
193 while ( currentNode.
d() >= 0 );
196 for (
int i = nodePathToRoot.size() - 1; i >= 0 && !mHierarchy.contains( nodeId ); --i )
200 mHierarchyMutex.lock();
201 const bool foundInHierarchy = mHierarchy.contains( node );
202 const bool foundInHierarchyNodes = mHierarchyNodes.contains( node );
203 mHierarchyMutex.unlock();
204 if ( foundInHierarchy )
207 if ( !foundInHierarchyNodes )
210 const QString fileUrl = QStringLiteral(
"%1/ept-hierarchy/%2.json" ).arg( mUrlDirectoryPart, node.
toString() );
211 QNetworkRequest nr( fileUrl );
213 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
214 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
222 if ( reply->
error() != QNetworkReply::NoError )
224 QgsDebugError( QStringLiteral(
"Request failed: " ) + mUri );
228 const QByteArray dataJsonH = reply->data();
229 QJsonParseError errH;
230 const QJsonDocument docH = QJsonDocument::fromJson( dataJsonH, &errH );
231 if ( errH.error != QJsonParseError::NoError )
233 QgsDebugMsgLevel( QStringLiteral(
"QJsonParseError when reading hierarchy from file %1" ).arg( fileUrl ), 2 );
237 const QJsonObject rootHObj = docH.object();
238 for (
auto it = rootHObj.constBegin(); it != rootHObj.constEnd(); ++it )
240 const QString nodeIdStr = it.key();
241 const int nodePointCount = it.value().toInt();
243 mHierarchyMutex.lock();
244 if ( nodePointCount >= 0 )
245 mHierarchy[nodeId] = nodePointCount;
246 else if ( nodePointCount == -1 )
247 mHierarchyNodes.insert( nodeId );
248 mHierarchyMutex.unlock();
252 mHierarchyMutex.lock();
253 found = mHierarchy.contains( nodeId );
254 mHierarchyMutex.unlock();
259bool QgsRemoteEptPointCloudIndex::isValid()
const
264void QgsRemoteEptPointCloudIndex::copyCommonProperties( QgsRemoteEptPointCloudIndex *destination )
const
266 QgsEptPointCloudIndex::copyCommonProperties( destination );
269 destination->mUrlDirectoryPart = mUrlDirectoryPart;
270 destination->mUrlFileNamePart = mUrlFileNamePart;
271 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...
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
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)