19#include "moc_qgsremoteeptpointcloudindex.cpp"
25#include <QJsonDocument>
41#include "qgspointcloudexpression.h"
47QgsRemoteEptPointCloudIndex::QgsRemoteEptPointCloudIndex() : QgsEptPointCloudIndex()
52QgsRemoteEptPointCloudIndex::~QgsRemoteEptPointCloudIndex() =
default;
54std::unique_ptr<QgsPointCloudIndex> QgsRemoteEptPointCloudIndex::clone()
const
56 QgsRemoteEptPointCloudIndex *clone =
new QgsRemoteEptPointCloudIndex;
57 QMutexLocker locker( &mHierarchyMutex );
58 copyCommonProperties( clone );
59 return std::unique_ptr<QgsPointCloudIndex>( clone );
62QList<IndexedPointCloudNode> QgsRemoteEptPointCloudIndex::nodeChildren(
const IndexedPointCloudNode &n )
const
64 QList<IndexedPointCloudNode> lst;
65 if ( !loadNodeHierarchy( n ) )
68 const int d = n.
d() + 1;
69 const int x = n.
x() * 2;
70 const int y = n.
y() * 2;
71 const int z = n.
z() * 2;
74 for (
int i = 0; i < 8; ++i )
76 int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 );
78 if ( loadNodeHierarchy( n2 ) )
84void QgsRemoteEptPointCloudIndex::load(
const QString &uri )
88 QStringList splitUrl = uri.split(
'/' );
90 mUrlFileNamePart = splitUrl.back();
92 mUrlDirectoryPart = splitUrl.join(
'/' );
94 QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) );
107 mIsValid = loadSchema( reply.
content() );
114 return std::unique_ptr<QgsPointCloudBlock>( cached );
117 std::unique_ptr<QgsPointCloudBlockRequest> blockRequest( asyncNodeData( n, request ) );
125 std::unique_ptr<QgsPointCloudBlock> block = blockRequest->takeBlock();
128 QgsDebugError( QStringLiteral(
"Error downloading node %1 data, error : %2 " ).arg( n.
toString(), blockRequest->errorStr() ) );
131 storeNodeDataToCache( block.get(), n, request );
140 scale(), offset(), mFilterExpression, request.
filterRect() );
143 if ( !loadNodeHierarchy( n ) )
147 if ( mDataType == QLatin1String(
"binary" ) )
149 fileUrl = QStringLiteral(
"%1/ept-data/%2.bin" ).arg( mUrlDirectoryPart, n.
toString() );
151 else if ( mDataType == QLatin1String(
"zstandard" ) )
153 fileUrl = QStringLiteral(
"%1/ept-data/%2.zst" ).arg( mUrlDirectoryPart, n.
toString() );
155 else if ( mDataType == QLatin1String(
"laszip" ) )
157 fileUrl = QStringLiteral(
"%1/ept-data/%2.laz" ).arg( mUrlDirectoryPart, n.
toString() );
167 QgsPointCloudExpression filterExpression = mFilterExpression;
169 requestAttributes.
extend( attributes(), filterExpression.referencedAttributes() );
175 return loadNodeHierarchy( n );
180 mHierarchyMutex.lock();
181 bool found = mHierarchy.contains( nodeId );
182 mHierarchyMutex.unlock();
186 QVector<IndexedPointCloudNode> nodePathToRoot;
191 nodePathToRoot.push_back( currentNode );
194 while ( currentNode.
d() >= 0 );
197 for (
int i = nodePathToRoot.size() - 1; i >= 0 && !mHierarchy.contains( nodeId ); --i )
201 mHierarchyMutex.lock();
202 const bool foundInHierarchy = mHierarchy.contains( node );
203 const bool foundInHierarchyNodes = mHierarchyNodes.contains( node );
204 mHierarchyMutex.unlock();
205 if ( foundInHierarchy )
208 if ( !foundInHierarchyNodes )
211 const QString fileUrl = QStringLiteral(
"%1/ept-hierarchy/%2.json" ).arg( mUrlDirectoryPart, node.
toString() );
212 QNetworkRequest nr( fileUrl );
214 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
215 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
223 if ( reply->
error() != QNetworkReply::NoError )
225 QgsDebugError( QStringLiteral(
"Request failed: " ) + mUri );
229 const QByteArray dataJsonH = reply->data();
230 QJsonParseError errH;
231 const QJsonDocument docH = QJsonDocument::fromJson( dataJsonH, &errH );
232 if ( errH.error != QJsonParseError::NoError )
234 QgsDebugMsgLevel( QStringLiteral(
"QJsonParseError when reading hierarchy from file %1" ).arg( fileUrl ), 2 );
238 const QJsonObject rootHObj = docH.object();
239 for (
auto it = rootHObj.constBegin(); it != rootHObj.constEnd(); ++it )
241 const QString nodeIdStr = it.key();
242 const int nodePointCount = it.value().toInt();
244 mHierarchyMutex.lock();
245 if ( nodePointCount >= 0 )
246 mHierarchy[nodeId] = nodePointCount;
247 else if ( nodePointCount == -1 )
248 mHierarchyNodes.insert( nodeId );
249 mHierarchyMutex.unlock();
253 mHierarchyMutex.lock();
254 found = mHierarchy.contains( nodeId );
255 mHierarchyMutex.unlock();
260bool QgsRemoteEptPointCloudIndex::isValid()
const
265void QgsRemoteEptPointCloudIndex::copyCommonProperties( QgsRemoteEptPointCloudIndex *destination )
const
267 QgsEptPointCloudIndex::copyCommonProperties( destination );
270 destination->mUrlDirectoryPart = mUrlDirectoryPart;
271 destination->mUrlFileNamePart = mUrlFileNamePart;
272 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)