24#include <QJsonDocument>
45#include "qgspointcloudexpression.h"
49QgsRemoteEptPointCloudIndex::QgsRemoteEptPointCloudIndex() : QgsEptPointCloudIndex()
54QgsRemoteEptPointCloudIndex::~QgsRemoteEptPointCloudIndex() =
default;
56std::unique_ptr<QgsPointCloudIndex> QgsRemoteEptPointCloudIndex::clone()
const
58 QgsRemoteEptPointCloudIndex *clone =
new QgsRemoteEptPointCloudIndex;
59 QMutexLocker locker( &mHierarchyMutex );
60 copyCommonProperties( clone );
61 return std::unique_ptr<QgsPointCloudIndex>( clone );
64QList<IndexedPointCloudNode> QgsRemoteEptPointCloudIndex::nodeChildren(
const IndexedPointCloudNode &n )
const
66 QList<IndexedPointCloudNode> lst;
67 if ( !loadNodeHierarchy( n ) )
70 const int d = n.
d() + 1;
71 const int x = n.
x() * 2;
72 const int y = n.
y() * 2;
73 const int z = n.
z() * 2;
76 for (
int i = 0; i < 8; ++i )
78 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
80 if ( loadNodeHierarchy( n2 ) )
86void QgsRemoteEptPointCloudIndex::load(
const QString &url )
90 QStringList splitUrl = url.split(
'/' );
92 mUrlFileNamePart = splitUrl.back();
94 mUrlDirectoryPart = splitUrl.join(
'/' );
96 QNetworkRequest nr( url );
102 QgsDebugMsg( QStringLiteral(
"Request failed: " ) + url );
108 mIsValid = loadSchema( reply.
content() );
113 std::unique_ptr<QgsPointCloudBlockRequest> blockRequest( asyncNodeData( n, request ) );
121 if ( !blockRequest->block() )
123 QgsDebugMsg( QStringLiteral(
"Error downloading node %1 data, error : %2 " ).arg( n.
toString(), blockRequest->errorStr() ) );
126 return blockRequest->block();
131 if ( !loadNodeHierarchy( n ) )
135 if ( mDataType == QLatin1String(
"binary" ) )
137 fileUrl = QStringLiteral(
"%1/ept-data/%2.bin" ).arg( mUrlDirectoryPart, n.
toString() );
139 else if ( mDataType == QLatin1String(
"zstandard" ) )
141 fileUrl = QStringLiteral(
"%1/ept-data/%2.zst" ).arg( mUrlDirectoryPart, n.
toString() );
143 else if ( mDataType == QLatin1String(
"laszip" ) )
145 fileUrl = QStringLiteral(
"%1/ept-data/%2.laz" ).arg( mUrlDirectoryPart, n.
toString() );
155 QgsPointCloudExpression filterExpression = mFilterExpression;
157 requestAttributes.
extend( attributes(), filterExpression.referencedAttributes() );
163 return loadNodeHierarchy( n );
168 mHierarchyMutex.lock();
169 bool found = mHierarchy.contains( nodeId );
170 mHierarchyMutex.unlock();
174 QVector<IndexedPointCloudNode> nodePathToRoot;
179 nodePathToRoot.push_back( currentNode );
182 while ( currentNode.
d() >= 0 );
185 for (
int i = nodePathToRoot.size() - 1; i >= 0 && !mHierarchy.contains( nodeId ); --i )
189 mHierarchyMutex.lock();
190 const bool foundInHierarchy = mHierarchy.contains( node );
191 const bool foundInHierarchyNodes = mHierarchyNodes.contains( node );
192 mHierarchyMutex.unlock();
193 if ( foundInHierarchy )
196 if ( !foundInHierarchyNodes )
199 const QString fileUrl = QStringLiteral(
"%1/ept-hierarchy/%2.json" ).arg( mUrlDirectoryPart, node.
toString() );
200 QNetworkRequest nr( fileUrl );
202 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
203 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
209 QgsDebugMsgLevel( QStringLiteral(
"unable to read hierarchy from file %1" ).arg( fileUrl ), 2 );
215 const QByteArray dataJsonH = reply.
content();
216 QJsonParseError errH;
217 const QJsonDocument docH = QJsonDocument::fromJson( dataJsonH, &errH );
218 if ( errH.error != QJsonParseError::NoError )
220 QgsDebugMsgLevel( QStringLiteral(
"QJsonParseError when reading hierarchy from file %1" ).arg( fileUrl ), 2 );
224 const QJsonObject rootHObj = docH.object();
225 for (
auto it = rootHObj.constBegin(); it != rootHObj.constEnd(); ++it )
227 const QString nodeIdStr = it.key();
228 const int nodePointCount = it.value().toInt();
230 mHierarchyMutex.lock();
231 if ( nodePointCount >= 0 )
232 mHierarchy[nodeId] = nodePointCount;
233 else if ( nodePointCount == -1 )
234 mHierarchyNodes.insert( nodeId );
235 mHierarchyMutex.unlock();
239 mHierarchyMutex.lock();
240 found = mHierarchy.contains( nodeId );
241 mHierarchyMutex.unlock();
246bool QgsRemoteEptPointCloudIndex::isValid()
const
251void QgsRemoteEptPointCloudIndex::copyCommonProperties( QgsRemoteEptPointCloudIndex *destination )
const
253 QgsEptPointCloudIndex::copyCommonProperties( destination );
256 destination->mUrlDirectoryPart = mUrlDirectoryPart;
257 destination->mUrlFileNamePart = mUrlFileNamePart;
258 destination->mUrl = mUrl;
259 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.
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...
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.
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.
#define QgsDebugMsgLevel(str, level)