Skip to content

Commit

Permalink
[processing] add support for point clouds to map layer and multiple
Browse files Browse the repository at this point in the history
layer parameters
  • Loading branch information
alexbruy committed Aug 5, 2021
1 parent 05da0c7 commit 63952c1
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 14 deletions.
3 changes: 2 additions & 1 deletion python/core/auto_generated/processing/qgsprocessing.sip.in
Expand Up @@ -37,7 +37,8 @@ and parameters.
TypeFile,
TypeVector,
TypeMesh,
TypePlugin
TypePlugin,
TypePointCloud
};

enum PythonOutputType
Expand Down
29 changes: 29 additions & 0 deletions python/core/auto_generated/processing/qgsprocessingutils.sip.in
Expand Up @@ -39,6 +39,8 @@ value.

.. seealso:: :py:func:`compatiblePluginLayers`

.. seealso:: :py:func:`compatiblePointCloudLayers`

.. seealso:: :py:func:`compatibleLayers`
%End

Expand All @@ -63,6 +65,8 @@ value.

.. seealso:: :py:func:`compatiblePluginLayers`

.. seealso:: :py:func:`compatiblePointCloudLayers`

.. seealso:: :py:func:`compatibleLayers`
%End

Expand All @@ -80,6 +84,8 @@ value.

.. seealso:: :py:func:`compatiblePluginLayers`

.. seealso:: :py:func:`compatiblePointCloudLayers`

.. seealso:: :py:func:`compatibleLayers`

.. versionadded:: 3.6
Expand All @@ -99,6 +105,29 @@ value.

.. seealso:: :py:func:`compatibleMeshLayers`

.. seealso:: :py:func:`compatiblePointCloudLayers`

.. seealso:: :py:func:`compatibleLayers`

.. versionadded:: 3.22
%End

static QList<QgsPointCloudLayer *> compatiblePointCloudLayers( QgsProject *project, bool sort = true );
%Docstring
Returns a list of point cloud layers from a ``project`` which are compatible with the processing
framework.

If the ``sort`` argument is ``True`` then the layers will be sorted by their :py:func:`QgsMapLayer.name()`
value.

.. seealso:: :py:func:`compatibleRasterLayers`

.. seealso:: :py:func:`compatibleVectorLayers`

.. seealso:: :py:func:`compatibleMeshLayers`

.. seealso:: :py:func:`compatiblePluginLayers`

.. seealso:: :py:func:`compatibleLayers`

.. versionadded:: 3.22
Expand Down
5 changes: 4 additions & 1 deletion src/core/processing/qgsprocessing.h
Expand Up @@ -53,7 +53,8 @@ class CORE_EXPORT QgsProcessing
TypeFile = 4, //!< Files (i.e. non map layer sources, such as text files)
TypeVector = 5, //!< Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink has no geometry.
TypeMesh = 6, //!< Mesh layers \since QGIS 3.6
TypePlugin = 7 //!< Plugin layers \since QGIS 3.22
TypePlugin = 7, //!< Plugin layers \since QGIS 3.22
TypePointCloud = 8 //!< Point cloud layers \since QGIS 3.22
};

//! Available Python output types
Expand Down Expand Up @@ -91,6 +92,8 @@ class CORE_EXPORT QgsProcessing
return QStringLiteral( "TypeMesh" );
case QgsProcessing::TypePlugin:
return QStringLiteral( "TypePlugin" );
case QgsProcessing::TypePointCloud:
return QStringLiteral( "TypePointCloud" );
}
return QString();
}
Expand Down
21 changes: 21 additions & 0 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -2691,6 +2691,12 @@ QString createAllMapLayerFileFilter()
if ( !vectors.contains( mesh ) )
vectors << mesh;
}
QStringList pointCloudFilters = QgsProviderRegistry::instance()->filePointCloudFilters().split( QStringLiteral( ";;" ) );
for ( const QString &pointCloud : pointCloudFilters )
{
if ( !vectors.contains( pointCloud ) )
vectors << pointCloud;
}
vectors.removeAll( QObject::tr( "All files (*.*)" ) );
std::sort( vectors.begin(), vectors.end() );

Expand Down Expand Up @@ -2740,6 +2746,10 @@ QString QgsProcessingParameterMapLayer::asScriptCode() const
case QgsProcessing::TypePlugin:
code += QLatin1String( "plugin " );
break;

case QgsProcessing::TypePointCloud:
code += QLatin1String( "pointcloud " );
break;
}
}

Expand Down Expand Up @@ -2795,6 +2805,12 @@ QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode(
def = def.mid( 7 );
continue;
}
else if ( def.startsWith( QLatin1String( "pointcloud" ), Qt::CaseInsensitive ) )
{
types << QgsProcessing::TypePointCloud;
def = def.mid( 11 );
continue;
}
break;
}

Expand Down Expand Up @@ -3872,6 +3888,9 @@ QString QgsProcessingParameterMultipleLayers::createFileFilter() const
case QgsProcessing::TypeMesh:
return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );

case QgsProcessing::TypePointCloud:
return QgsProviderRegistry::instance()->filePointCloudFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );

case QgsProcessing::TypeMapLayer:
case QgsProcessing::TypePlugin:
return createAllMapLayerFileFilter();
Expand Down Expand Up @@ -5865,6 +5884,7 @@ bool QgsProcessingParameterFeatureSink::hasGeometry() const
case QgsProcessing::TypeVector:
case QgsProcessing::TypeMesh:
case QgsProcessing::TypePlugin:
case QgsProcessing::TypePointCloud:
return false;
}
return true;
Expand Down Expand Up @@ -6561,6 +6581,7 @@ bool QgsProcessingParameterVectorDestination::hasGeometry() const
case QgsProcessing::TypeVector:
case QgsProcessing::TypeMesh:
case QgsProcessing::TypePlugin:
case QgsProcessing::TypePointCloud:
return false;
}
return true;
Expand Down
16 changes: 11 additions & 5 deletions src/core/processing/qgsprocessingutils.cpp
Expand Up @@ -77,6 +77,11 @@ QList<QgsPluginLayer *> QgsProcessingUtils::compatiblePluginLayers( QgsProject *
return compatibleMapLayers< QgsPluginLayer >( project, sort );
}

QList<QgsPointCloudLayer *> QgsProcessingUtils::compatiblePointCloudLayers( QgsProject *project, bool sort )
{
return compatibleMapLayers< QgsPointCloudLayer >( project, sort );
}

template<typename T> QList<T *> QgsProcessingUtils::compatibleMapLayers( QgsProject *project, bool sort )
{
if ( !project )
Expand Down Expand Up @@ -107,7 +112,6 @@ QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project,

QList<QgsMapLayer *> layers;

//~ const auto rasterLayers = compatibleRasterLayers( project, false );
const auto rasterLayers = compatibleMapLayers< QgsRasterLayer >( project, false );
for ( QgsRasterLayer *rl : rasterLayers )
layers << rl;
Expand All @@ -116,12 +120,14 @@ QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project,
for ( QgsVectorLayer *vl : vectorLayers )
layers << vl;

//~ const auto meshLayers = compatibleMeshLayers( project, false );
const auto meshLayers = compatibleMapLayers< QgsMeshLayer >( project, false );
for ( QgsMeshLayer *vl : meshLayers )
layers << vl;
for ( QgsMeshLayer *ml : meshLayers )
layers << ml;

const auto pointCloudLayers = compatibleMapLayers< QgsPointCloudLayer >( project, false );
for ( QgsPointCloudLayer *pcl : pointCloudLayers )
layers << pcl;

//~ const auto pluginLayers = compatiblePluginLayers( project, false );
const auto pluginLayers = compatibleMapLayers< QgsPluginLayer >( project, false );
for ( QgsPluginLayer *pl : pluginLayers )
layers << pl;
Expand Down
21 changes: 21 additions & 0 deletions src/core/processing/qgsprocessingutils.h
Expand Up @@ -62,6 +62,7 @@ class CORE_EXPORT QgsProcessingUtils
* \see compatibleVectorLayers()
* \see compatibleMeshLayers()
* \see compatiblePluginLayers()
* \see compatiblePointCloudLayers()
* \see compatibleLayers()
*/
static QList< QgsRasterLayer * > compatibleRasterLayers( QgsProject *project, bool sort = true );
Expand All @@ -80,6 +81,7 @@ class CORE_EXPORT QgsProcessingUtils
* \see compatibleRasterLayers()
* \see compatibleMeshLayers()
* \see compatiblePluginLayers()
* \see compatiblePointCloudLayers()
* \see compatibleLayers()
*/
static QList< QgsVectorLayer * > compatibleVectorLayers( QgsProject *project,
Expand All @@ -96,6 +98,7 @@ class CORE_EXPORT QgsProcessingUtils
* \see compatibleRasterLayers()
* \see compatibleVectorLayers()
* \see compatiblePluginLayers()
* \see compatiblePointCloudLayers()
* \see compatibleLayers()
*
* \since QGIS 3.6
Expand All @@ -112,12 +115,30 @@ class CORE_EXPORT QgsProcessingUtils
* \see compatibleRasterLayers()
* \see compatibleVectorLayers()
* \see compatibleMeshLayers()
* \see compatiblePointCloudLayers()
* \see compatibleLayers()
*
* \since QGIS 3.22
*/
static QList<QgsPluginLayer *> compatiblePluginLayers( QgsProject *project, bool sort = true );

/**
* Returns a list of point cloud layers from a \a project which are compatible with the processing
* framework.
*
* If the \a sort argument is TRUE then the layers will be sorted by their QgsMapLayer::name()
* value.
*
* \see compatibleRasterLayers()
* \see compatibleVectorLayers()
* \see compatibleMeshLayers()
* \see compatiblePluginLayers()
* \see compatibleLayers()
*
* \since QGIS 3.22
*/
static QList<QgsPointCloudLayer *> compatiblePointCloudLayers( QgsProject *project, bool sort = true );

/**
* Returns a list of map layers from a \a project which are compatible with the processing
* framework.
Expand Down
17 changes: 17 additions & 0 deletions src/gui/processing/qgsprocessingmultipleselectiondialog.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsmeshlayer.h"
#include "qgsrasterlayer.h"
#include "qgspluginlayer.h"
#include "qgspointcloudlayer.h"
#include "qgsproject.h"
#include "processing/models/qgsprocessingmodelchildparametersource.h"
#include <QStandardItemModel>
Expand Down Expand Up @@ -416,6 +417,17 @@ void QgsProcessingMultipleInputPanelWidget::populateFromProject( QgsProject *pro
break;
}

case QgsProcessing::TypePointCloud:
{
const QList<QgsPointCloudLayer *> options = QgsProcessingUtils::compatiblePointCloudLayers( project, false );
for ( const QgsPointCloudLayer *layer : options )
{
addLayer( layer );
}

break;
}

case QgsProcessing::TypeVector:
case QgsProcessing::TypeVectorAnyGeometry:
{
Expand Down Expand Up @@ -450,6 +462,11 @@ void QgsProcessingMultipleInputPanelWidget::populateFromProject( QgsProject *pro
{
addLayer( layer );
}
const QList<QgsPointCloudLayer *> pointClouds = QgsProcessingUtils::compatiblePointCloudLayers( project );
for ( const QgsPointCloudLayer *layer : pointClouds )
{
addLayer( layer );
}

break;
}
Expand Down
13 changes: 13 additions & 0 deletions src/gui/processing/qgsprocessingwidgetwrapperimpl.cpp
Expand Up @@ -5802,6 +5802,7 @@ QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDe
mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );

if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
{
Expand Down Expand Up @@ -6792,6 +6793,17 @@ void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorith
break;
}

case QgsProcessing::TypePointCloud:
{
mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterPointCloudLayer::typeName()
<< QgsProcessingParameterMultipleLayers::typeName()
<< QgsProcessingParameterFile::typeName(),
QStringList() << QgsProcessingOutputFile::typeName()
<< QgsProcessingOutputMapLayer::typeName()
<< QgsProcessingOutputMultipleLayers::typeName() );
break;
}

case QgsProcessing::TypeVector:
{
mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
Expand Down Expand Up @@ -6934,6 +6946,7 @@ QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerP
mLayerTypeComboBox->addItem( tr( "File" ), QgsProcessing::TypeFile );
mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( layersParam->layerType() ) );

Expand Down
32 changes: 29 additions & 3 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -860,10 +860,16 @@ void TestQgsProcessing::compatibleLayers()
QgsMeshLayer *m2 = new QgsMeshLayer( fm.filePath(), "mA", "mdal" );
QVERIFY( m2->isValid() );

QFileInfo fpc( testDataDir + "/point_clouds/las/cloud.las" );
QgsPointCloudLayer *pc1 = new QgsPointCloudLayer( fpc.filePath(), "PCX", "pdal" );
QVERIFY( m1->isValid() );
QgsPointCloudLayer *pc2 = new QgsPointCloudLayer( fpc.filePath(), "pcA", "pdal" );
QVERIFY( m2->isValid() );

DummyPluginLayer *pl1 = new DummyPluginLayer( "dummylayer", "PX" );
DummyPluginLayer *pl2 = new DummyPluginLayer( "dummylayer", "pA" );

p.addMapLayers( QList<QgsMapLayer *>() << r1 << r2 << r3 << v1 << v2 << v3 << v4 << m1 << m2 << pl1 << pl2 );
p.addMapLayers( QList<QgsMapLayer *>() << r1 << r2 << r3 << v1 << v2 << v3 << v4 << m1 << m2 << pl1 << pl2 << pc1 << pc2 );

// compatibleRasterLayers
QVERIFY( QgsProcessingUtils::compatibleRasterLayers( nullptr ).isEmpty() );
Expand Down Expand Up @@ -926,6 +932,21 @@ void TestQgsProcessing::compatibleLayers()
lIds << pl->name();
QCOMPARE( lIds, QStringList() << "PX" << "pA" );

// compatiblePointCloudLayers
QVERIFY( QgsProcessingUtils::compatiblePointCloudLayers( nullptr ).isEmpty() );

// sorted
lIds.clear();
for ( QgsPointCloudLayer *pcl : QgsProcessingUtils::compatiblePointCloudLayers( &p ) )
lIds << pcl->name();
QCOMPARE( lIds, QStringList() << "pcA" << "PCX" );

// unsorted
lIds.clear();
for ( QgsPointCloudLayer *pcl : QgsProcessingUtils::compatiblePointCloudLayers( &p, false ) )
lIds << pcl->name();
QCOMPARE( lIds, QStringList() << "PCX" << "pcA" );

// point only
lIds.clear();
for ( QgsVectorLayer *vl : QgsProcessingUtils::compatibleVectorLayers( &p, QList<int>() << QgsProcessing::TypeVectorPoint ) )
Expand Down Expand Up @@ -969,13 +990,13 @@ void TestQgsProcessing::compatibleLayers()
lIds.clear();
for ( QgsMapLayer *l : QgsProcessingUtils::compatibleLayers( &p ) )
lIds << l->name();
QCOMPARE( lIds, QStringList() << "ar2" << "mA" << "MX" << "pA" << "PX" << "R1" << "v1" << "v3" << "V4" << "vvvv4" << "zz" );
QCOMPARE( lIds, QStringList() << "ar2" << "mA" << "MX" << "pA" << "pcA" << "PCX" << "PX" << "R1" << "v1" << "v3" << "V4" << "vvvv4" << "zz" );

// unsorted
lIds.clear();
for ( QgsMapLayer *l : QgsProcessingUtils::compatibleLayers( &p, false ) )
lIds << l->name();
QCOMPARE( lIds, QStringList() << "R1" << "ar2" << "zz" << "V4" << "v1" << "v3" << "vvvv4" << "MX" << "mA" << "PX" << "pA" );
QCOMPARE( lIds, QStringList() << "R1" << "ar2" << "zz" << "V4" << "v1" << "v3" << "vvvv4" << "MX" << "mA" << "PCX" << "pcA" << "PX" << "pA" );
}

void TestQgsProcessing::encodeDecodeUriProvider()
Expand Down Expand Up @@ -2971,6 +2992,11 @@ void TestQgsProcessing::parameterMapLayer()
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMapLayer('non_optional', '', defaultValue='', types=[QgsProcessing.TypePlugin])" ) );
code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##non_optional=layer plugin" ) );
def->setDataTypes( QList< int >() << QgsProcessing::TypePointCloud );
pythonCode = def->asPythonString();
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMapLayer('non_optional', '', defaultValue='', types=[QgsProcessing.TypePointCloud])" ) );
code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##non_optional=layer pointcloud" ) );

// optional
def.reset( new QgsProcessingParameterMapLayer( "optional", QString(), v1->id(), true ) );
Expand Down

0 comments on commit 63952c1

Please sign in to comment.