QGIS API Documentation 3.41.0-Master (d2aaa9c6e02)
Loading...
Searching...
No Matches
qgspointcloudeditingindex.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudeditingindex.cpp
3 ---------------------
4 begin : December 2024
5 copyright : (C) 2024 by Stefanos Natsis
6 email : uclaros at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "qgspointcloudlayer.h"
21#include "qgscopcupdate.h"
22#include "qgslazdecoder.h"
23
24#include <QDir>
25#include <QFileInfo>
26
27
29{
30 if ( !layer ||
31 !layer->dataProvider() ||
32 !layer->dataProvider()->hasValidIndex() ||
34 return;
35
36 mUri = layer->source();
37 mIndex = layer->dataProvider()->index();
38
39 mAttributes = mIndex.attributes();
40 mScale = mIndex.scale();
41 mOffset = mIndex.offset();
42 mExtent = mIndex.extent();
43 mZMin = mIndex.zMin();
44 mZMax = mIndex.zMax();
45 mRootBounds = mIndex.rootNodeBounds();
46 mSpan = mIndex.span();
47 mIsValid = true;
48}
49
50std::unique_ptr<QgsAbstractPointCloudIndex> QgsPointCloudEditingIndex::clone() const
51{
52 return nullptr;
53}
54
55void QgsPointCloudEditingIndex::load( const QString & )
56{
57 return;
58}
59
61{
62 return mIsValid && mIndex.isValid();
63}
64
69
74
76{
77 return mIndex.pointCount();
78}
79
81{
82 return mIndex.originalMetadata();
83}
84
86{
87 return mIndex.hasNode( n );
88}
89
91{
92 return mIndex.getNode( id );
93}
94
95std::unique_ptr< QgsPointCloudBlock > QgsPointCloudEditingIndex::nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request )
96{
97 if ( mEditedNodeData.contains( n ) )
98 {
99 // we need to create a copy of the expression to pass to the decoder
100 // as the same QgsPointCloudExpression object mighgt be concurrently
101 // used on another thread, for example in a 3d view
102 QgsPointCloudExpression filterExpression = mFilterExpression;
103 QgsPointCloudAttributeCollection requestAttributes = request.attributes();
104 requestAttributes.extend( attributes(), filterExpression.referencedAttributes() );
105
106 QgsRectangle filterRect = request.filterRect();
107
108 QByteArray rawBlockData = mEditedNodeData[n];
109
110 QgsCopcPointCloudIndex *copcIndex = static_cast<QgsCopcPointCloudIndex *>( mIndex.get() );
111
112 int pointCount = copcIndex->mHierarchy.value( n );
113
114 return QgsLazDecoder::decompressCopc( rawBlockData, *copcIndex->mLazInfo.get(), pointCount, requestAttributes, filterExpression, filterRect );
115 }
116 else
117 {
118 return mIndex.nodeData( n, request );
119 }
120}
121
123{
124 Q_ASSERT( false );
125 return nullptr;
126}
127
128bool QgsPointCloudEditingIndex::commitChanges( QString *errorMessage )
129{
130 if ( !isModified() )
131 return true;
132
133 QHash<QgsPointCloudNodeId, QgsCopcUpdate::UpdatedChunk> updatedChunks;
134 for ( auto it = mEditedNodeData.constBegin(); it != mEditedNodeData.constEnd(); ++it )
135 {
136 QgsPointCloudNodeId n = it.key();
137 // right now we're assuming there's no change of point count
138 qint32 nodePointCount = static_cast<qint32>( getNode( n ).pointCount() );
139 updatedChunks[n] = QgsCopcUpdate::UpdatedChunk{ nodePointCount, it.value() };
140 }
141
142 QFileInfo fileInfo( mUri );
143 const QString outputFilename = fileInfo.dir().filePath( fileInfo.baseName() + QStringLiteral( "-update.copc.laz" ) );
144
145 if ( !QgsCopcUpdate::writeUpdatedFile( mUri, outputFilename, updatedChunks, errorMessage ) )
146 {
147 return false;
148 }
149
150 // reset the underlying index - we will reload it at the end
151 QgsCopcPointCloudIndex *copcIndex = static_cast<QgsCopcPointCloudIndex *>( mIndex.get() );
152 copcIndex->reset();
153
154 const QString originalFilename = fileInfo.dir().filePath( fileInfo.baseName() + QStringLiteral( "-original.copc.laz" ) );
155 if ( !QFile::rename( mUri, originalFilename ) )
156 {
157 if ( errorMessage )
158 *errorMessage = QStringLiteral( "Rename of the old COPC failed!" );
159 QFile::remove( outputFilename );
160 return false;
161 }
162
163 if ( !QFile::rename( outputFilename, mUri ) )
164 {
165 if ( errorMessage )
166 *errorMessage = QStringLiteral( "Rename of the new COPC failed!" );
167 QFile::rename( originalFilename, mUri );
168 QFile::remove( outputFilename );
169 return false;
170 }
171
172 if ( !QFile::remove( originalFilename ) )
173 {
174 if ( errorMessage )
175 *errorMessage = QStringLiteral( "Removal of the old COPC failed!" );
176 // TODO: cleanup here as well?
177 return false;
178 }
179
180 mEditedNodeData.clear();
181
182 // now let's reload
183 copcIndex->load( mUri );
184
185 return true;
186}
187
189{
190 return !mEditedNodeData.isEmpty();
191}
192
193bool QgsPointCloudEditingIndex::updateNodeData( const QHash<QgsPointCloudNodeId, QByteArray> &data )
194{
195 for ( auto it = data.constBegin(); it != data.constEnd(); ++it )
196 {
197 mEditedNodeData[it.key()] = it.value();
198 }
199
200 // get rid of cached keys that got modified
201 {
202 QMutexLocker locker( &sBlockCacheMutex );
203 const QList<QgsPointCloudCacheKey> cacheKeys = sBlockCache.keys();
204 for ( const QgsPointCloudCacheKey &cacheKey : cacheKeys )
205 {
206 if ( cacheKey.uri() == mUri && data.contains( cacheKey.node() ) )
207 sBlockCache.remove( cacheKey );
208 }
209 }
210
211 return true;
212}
PointCloudAccessType
The access type of the data, local is for local files and remote for remote files (over HTTP).
Definition qgis.h:5731
QgsPointCloudAttributeCollection mAttributes
QgsBox3D mRootBounds
Bounds of the root node's cube (in int32 coordinates)
QgsVector3D mOffset
Offset of our int32 coordinates compared to CRS coords.
QgsPointCloudExpression mFilterExpression
The filter expression to be evaluated when fetching node data.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
static QCache< QgsPointCloudCacheKey, QgsPointCloudBlock > sBlockCache
int mSpan
All native attributes stored in the file.
double mZMax
Vertical extent of data.
QgsRectangle mExtent
2D extent of data
QgsVector3D mScale
Scale of our int32 coordinates compared to CRS coords.
This class represents a coordinate reference system (CRS).
static bool writeUpdatedFile(const QString &inputFilename, const QString &outputFilename, const QHash< QgsPointCloudNodeId, UpdatedChunk > &updatedChunks, QString *errorMessage=nullptr)
Convenience function to do the whole process in one go: load a COPC file, then write a new COPC file ...
QString source() const
Returns the source for the layer.
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.
Container class for QgsPointCloudBlock cache keys.
@ ChangeAttributeValues
Provider can modify the values of point attributes.
virtual QgsPointCloudIndex index() const
Returns the point cloud index associated with the provider.
virtual QgsPointCloudDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities for the data provider.
bool hasValidIndex() const
Returns whether provider has index which is valid.
std::unique_ptr< QgsAbstractPointCloudIndex > clone() const override
Returns a clone of the current point cloud index object.
bool hasNode(const QgsPointCloudNodeId &n) const override
Returns whether the octree contain given node.
bool isModified() const
Returns true if there are uncommitted changes, false otherwise.
QVariantMap originalMetadata() const override
Returns the original metadata map.
qint64 pointCount() const override
Returns the number of points in the point cloud.
bool commitChanges(QString *errorMessage=nullptr)
Tries to store pending changes to the data provider.
void load(const QString &fileName) override
Loads the index from the file.
QgsPointCloudBlockRequest * asyncNodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request) override
Returns a handle responsible for loading a node data block.
QgsPointCloudEditingIndex(QgsPointCloudLayer *layer)
Ctor.
bool isValid() const override
Returns whether index is loaded and valid.
std::unique_ptr< QgsPointCloudBlock > nodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request) override
Returns node data block.
QgsPointCloudNode getNode(const QgsPointCloudNodeId &id) const override
Returns object for a given node.
Qgis::PointCloudAccessType accessType() const override
Returns the access type of the data If the access type is Remote, data will be fetched from an HTTP s...
bool updateNodeData(const QHash< QgsPointCloudNodeId, QByteArray > &data) override
Tries to update the data for the specified nodes.
QgsCoordinateReferenceSystem crs() const override
Returns the coordinate reference system of the point cloud index.
int span() const
Returns the number of points in one direction in a single node.
double zMax() const
Returns z max.
QgsBox3D rootNodeBounds() const
Returns bounding box of root node in CRS coords.
double zMin() const
Returns z min.
QgsVector3D offset() const
Returns offset of data from CRS.
QgsVector3D scale() const
Returns scale of data relative to CRS.
bool isValid() const
Returns whether index is loaded and valid.
QgsRectangle extent() const
Returns extent of the data.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system of the point cloud index.
qint64 pointCount() const
Returns the number of points in the point cloud.
std::unique_ptr< QgsPointCloudBlock > nodeData(const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request)
Returns node data block.
QgsPointCloudNode getNode(const QgsPointCloudNodeId &id) const
Returns object for a given node.
bool hasNode(const QgsPointCloudNodeId &id) const
Returns whether the octree contain given node.
QgsAbstractPointCloudIndex * get()
Returns pointer to the implementation class.
QVariantMap originalMetadata() const
Returns the original metadata map.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
Qgis::PointCloudAccessType accessType() const
Returns the access type of the data If the access type is Remote, data will be fetched from an HTTP s...
Represents a map layer supporting display of point clouds.
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Represents a indexed point cloud node's position in octree.
Keeps metadata for indexed point cloud node.
qint64 pointCount() const
Returns number of points contained in node data.
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.
A rectangle specified with double values.
Keeps information how points of a single chunk has been modified.