Skip to content

Commit 7f86e7c

Browse files
authored
Prefer using copc index file for processing if it exist (#61771)
* prefer using copc index file for processing if it exist * ensure that copc layer is valid * read using copc data provider * add test case to verify that copc file is used in alg * fix error in doc * review suggestions * add more complex test * simplify test * wait for index to be created and verify that it exists * reflow for copc input check * avoid marking lyr as unused
1 parent 5e2826e commit 7f86e7c

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

src/analysis/processing/pdal/qgspdalalgorithmbase.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgspointcloudlayer.h"
2323
#include "qgspointcloudexpression.h"
2424
#include "qgsrasterlayerelevationproperties.h"
25+
#include "qgscopcprovider.h"
2526

2627
#include <QRegularExpression>
2728

@@ -281,4 +282,46 @@ QVariantMap QgsPdalAlgorithmBase::processAlgorithm( const QVariantMap &parameter
281282
return outputs;
282283
}
283284

285+
QgsPointCloudLayer *QgsPdalAlgorithmBase::parameterAsPointCloudLayer( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, QgsProcessing::LayerOptionsFlags flags ) const
286+
{
287+
QgsPointCloudLayer *layer = QgsProcessingParameters::parameterAsPointCloudLayer( parameterDefinition( name ), parameters, context, flags );
288+
289+
// if layer or its data provider are empty return nullptr
290+
if ( !layer || !layer->dataProvider() )
291+
return nullptr;
292+
293+
// if COPC provider, return as it is
294+
if ( layer->dataProvider()->name() == QStringLiteral( "copc" ) )
295+
{
296+
return layer;
297+
}
298+
299+
// if source is remote file, use it as it is
300+
const QUrl url = QUrl( layer->source() );
301+
if ( url.isValid() && ( url.scheme() == "http" || url.scheme() == "https" ) )
302+
{
303+
return layer;
304+
}
305+
306+
// for local files try to find COPC index file
307+
const QString copcFileName = QgsPdalAlgorithmBase::copcIndexFile( layer->source() );
308+
309+
if ( QFileInfo::exists( copcFileName ) )
310+
{
311+
QgsPointCloudLayer *copcLayer = new QgsPointCloudLayer( copcFileName, layer->name(), "copc" );
312+
if ( copcLayer && copcLayer->isValid() )
313+
return copcLayer;
314+
}
315+
316+
return layer;
317+
}
318+
319+
QString QgsPdalAlgorithmBase::copcIndexFile( const QString &filename )
320+
{
321+
const QFileInfo fi( filename );
322+
const QDir directory = fi.absoluteDir();
323+
const QString outputFile = QStringLiteral( "%1/%2.copc.laz" ).arg( directory.absolutePath() ).arg( fi.completeBaseName() );
324+
return outputFile;
325+
}
326+
284327
///@endcond

src/analysis/processing/pdal/qgspdalalgorithmbase.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,22 @@ class QgsPdalAlgorithmBase : public QgsProcessingAlgorithm
8686

8787
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
8888

89+
/**
90+
* Returns name of index copc file for given \a filename of point cloud.
91+
*
92+
* \param filename name of the original dataset
93+
*
94+
* \since 3.44
95+
*/
96+
static QString copcIndexFile( const QString &filename );
97+
98+
/**
99+
* Override that prefers copc.laz index file as datasource for faster processing (if the index file exists) otherwise uses original layer.
100+
*
101+
* \since 3.44
102+
*/
103+
QgsPointCloudLayer *parameterAsPointCloudLayer( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, QgsProcessing::LayerOptionsFlags flags ) const;
104+
89105
private:
90106
QMap<QString, QVariant> mOutputValues;
91107
bool mEnableElevationProperties = false;

tests/src/analysis/testqgsprocessingpdalalgs.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
#include "qgsprocessingcontext.h"
2323
#include "qgspdalalgorithms.h"
2424
#include "qgspdalalgorithmbase.h"
25+
#include "qgspointcloudlayer.h"
2526

27+
#include <QThread>
2628

2729
class TestQgsProcessingPdalAlgs : public QgsTest
2830
{
@@ -56,6 +58,8 @@ class TestQgsProcessingPdalAlgs : public QgsTest
5658
void thinByRadius();
5759
void tile();
5860

61+
void useIndexCopcFile();
62+
5963
private:
6064
void updateFileListArg( QStringList &args, const QString &fileName );
6165

@@ -854,5 +858,41 @@ void TestQgsProcessingPdalAlgs::filter()
854858
QCOMPARE( args, QStringList() << QStringLiteral( "translate" ) << QStringLiteral( "--input=%1" ).arg( mPointCloudLayerPath ) << QStringLiteral( "--output=%1" ).arg( outputPointCloud ) << QStringLiteral( "--filter=Classification == 7 || Classification == 8" ) << QStringLiteral( "--bounds=([1, 3], [2, 4])" ) << QStringLiteral( "--threads=2" ) );
855859
}
856860

861+
void TestQgsProcessingPdalAlgs::useIndexCopcFile()
862+
{
863+
const QString pointCloudFileName = QString( TEST_DATA_DIR ) + "/point_clouds/las/cloud.las";
864+
const QFileInfo pointCloudFileInfo( pointCloudFileName );
865+
const QString pointCloudLayerPath = pointCloudFileInfo.filePath();
866+
const QString copcIndexFileName = pointCloudFileInfo.absolutePath() + "/" + pointCloudFileInfo.completeBaseName() + ".copc.laz";
867+
868+
QgsPdalAlgorithmBase *alg = const_cast<QgsPdalAlgorithmBase *>( static_cast<const QgsPdalAlgorithmBase *>( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "pdal:exportvector" ) ) ) );
869+
870+
auto context = std::make_unique<QgsProcessingContext>();
871+
context->setMaximumThreads( 0 );
872+
873+
QgsProcessingFeedback feedback;
874+
875+
// generate index for use in algorithm
876+
QgsPointCloudLayer *lyr = new QgsPointCloudLayer( pointCloudLayerPath, "layer", "pdal" );
877+
Q_UNUSED( lyr );
878+
879+
//wait for index to be generated
880+
while ( !QFileInfo::exists( copcIndexFileName ) )
881+
{
882+
QThread::sleep( 1 );
883+
}
884+
QVERIFY( QFileInfo::exists( copcIndexFileName ) );
885+
886+
const QString outputFile = QDir::tempPath() + "/points.gpkg";
887+
888+
QVariantMap parameters;
889+
parameters.insert( QStringLiteral( "INPUT" ), pointCloudLayerPath );
890+
parameters.insert( QStringLiteral( "OUTPUT" ), outputFile );
891+
892+
QStringList args = alg->createArgumentLists( parameters, *context, &feedback );
893+
QCOMPARE( args, QStringList() << QStringLiteral( "to_vector" ) << QStringLiteral( "--input=%1" ).arg( copcIndexFileName ) << QStringLiteral( "--output=%1" ).arg( outputFile ) );
894+
QVERIFY( args.at( 1 ).endsWith( "copc.laz" ) );
895+
}
896+
857897
QGSTEST_MAIN( TestQgsProcessingPdalAlgs )
858898
#include "testqgsprocessingpdalalgs.moc"

0 commit comments

Comments
 (0)