Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add multipart option for processing geometry parameter
  • Loading branch information
dmarteau authored and nyalldawson committed Mar 30, 2021
1 parent e323787 commit 9eb172a
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 8 deletions.
Expand Up @@ -1694,12 +1694,13 @@ A geometry parameter for processing algorithms.
%End
public:

QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false, const QList< int > &geometryTypes = QList< int >() );
QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false, const QList< int > &geometryTypes = QList< int >(), bool allowMultipart = true );
%Docstring
Constructor for QgsProcessingParameterGeometry.

The ``geometryTypes`` argument allows for specifying a list of geometry types (see :py:class:`QgsWkbTypes`.GeometryType) acceptable for this
parameter. Passing a empty list will allow for any type of geometry.
The ``allowMultiPart`` argument allows specifying a multi part geometry
%End

static QString typeName();
Expand Down Expand Up @@ -1736,6 +1737,22 @@ Sets the allowed ``geometryTypes``, as a list of :py:class:`QgsWkbTypes`.Geomet
.. seealso:: :py:func:`geometryTypes`
%End

bool allowMultipart() const;
%Docstring
Returns the parameter allow multipart geometries.

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

void setAllowMultipart( bool allowMultipart );
%Docstring
Sets the allow multipart geometries

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



static QgsProcessingParameterGeometry *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) /Factory/;
%Docstring
Creates a new parameter using the definition from a script code.
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/core/parameters.py
Expand Up @@ -140,6 +140,8 @@ def getParameterFromString(s, context=''):
params[4] = [int(p) for p in params[4].split(';')]
except:
params[4] = [getattr(QgsWkbTypes, p.split(".")[1]) for p in params[4].split(';')]
if len(params) > 5:
params[5] = True if params[5].lower() == 'true' else False
elif clazz == QgsProcessingParameterCrs:
if len(params) > 3:
params[3] = True if params[3].lower() == 'true' else False
Expand Down
22 changes: 16 additions & 6 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -3046,9 +3046,10 @@ QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const
}

QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes )
const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes, bool allowMultipart )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
mGeomTypes( geometryTypes )
mGeomTypes( geometryTypes ),
mAllowMultipart( allowMultipart )
{

}
Expand All @@ -3072,12 +3073,14 @@ bool QgsProcessingParameterGeometry::checkValueIsAcceptable( const QVariant &inp

if ( input.canConvert< QgsGeometry >() )
{
return anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() );
return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() ) ) &&
( mAllowMultipart || !input.value<QgsGeometry>().isMultipart() );
}

if ( input.canConvert< QgsReferencedGeometry >() )
{
return anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() );
return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() ) ) &&
( mAllowMultipart || !input.value<QgsReferencedGeometry>().isMultipart() );
}

if ( input.canConvert< QgsPointXY >() )
Expand Down Expand Up @@ -3115,7 +3118,7 @@ bool QgsProcessingParameterGeometry::checkValueIsAcceptable( const QVariant &inp
QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
if ( ! g.isNull() )
{
return anyTypeAllowed || mGeomTypes.contains( g.type() );
return ( anyTypeAllowed || mGeomTypes.contains( g.type() ) ) && ( mAllowMultipart || !g.isMultipart() );
}
else
{
Expand Down Expand Up @@ -3210,7 +3213,7 @@ QString QgsProcessingParameterGeometry::asScriptCode() const
break;

default:
code += QLatin1String( "unknown" );
code += QLatin1String( "unknown " );
break;
}
}
Expand Down Expand Up @@ -3262,6 +3265,11 @@ QString QgsProcessingParameterGeometry::asPythonString( const QgsProcessing::Pyt
code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
}

if ( ! mAllowMultipart )
{
code += QStringLiteral( ", allowMultipart=False" );
}

QgsProcessingContext c;
code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
return code;
Expand All @@ -3279,6 +3287,7 @@ QVariantMap QgsProcessingParameterGeometry::toVariantMap() const
types << type;
}
map.insert( QStringLiteral( "geometrytypes" ), types );
map.insert( QStringLiteral( "multipart" ), mAllowMultipart );
return map;
}

Expand All @@ -3291,6 +3300,7 @@ bool QgsProcessingParameterGeometry::fromVariantMap( const QVariantMap &map )
{
mGeomTypes << val.toInt();
}
mAllowMultipart = map.value( QStringLiteral( "multipart" ) ).toBool();
return true;
}

Expand Down
18 changes: 17 additions & 1 deletion src/core/processing/qgsprocessingparameters.h
Expand Up @@ -1727,8 +1727,9 @@ class CORE_EXPORT QgsProcessingParameterGeometry : public QgsProcessingParameter
*
* The \a geometryTypes argument allows for specifying a list of geometry types (see QgsWkbTypes::GeometryType) acceptable for this
* parameter. Passing a empty list will allow for any type of geometry.
* The \a allowMultiPart argument allows specifying a multi part geometry
*/
QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false, const QList< int > &geometryTypes = QList< int >() );
QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false, const QList< int > &geometryTypes = QList< int >(), bool allowMultipart = true );

/**
* Returns the type name for the parameter class.
Expand All @@ -1755,6 +1756,20 @@ class CORE_EXPORT QgsProcessingParameterGeometry : public QgsProcessingParameter
*/
void setGeometryTypes( const QList<int> &geometryTypes ) { mGeomTypes = geometryTypes; }

/**
* Returns the parameter allow multipart geometries.
* \see setAllowMultipart()
*/
bool allowMultipart() const { return mAllowMultipart; }

/**
* Sets the allow multipart geometries
* \see allowMultipart()
*/
void setAllowMultipart( bool allowMultipart ) { mAllowMultipart = allowMultipart; }



/**
* Creates a new parameter using the definition from a script code.
*/
Expand All @@ -1763,6 +1778,7 @@ class CORE_EXPORT QgsProcessingParameterGeometry : public QgsProcessingParameter
private:

QList<int> mGeomTypes;
bool mAllowMultipart;

};

Expand Down
24 changes: 24 additions & 0 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -3445,6 +3445,7 @@ void TestQgsProcessing::parameterGeometry()
QVERIFY( def->checkValueIsAcceptable( QgsReferencedPointXY( QgsPointXY( 1, 2 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsRectangle( 10, 10, 20, 20 ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsReferencedRectangle( QgsRectangle( 10, 10, 20, 20 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QString( "MultiPoint((10 10), (20 20))" ) ) );

// string representing a geometry
QVariantMap params;
Expand Down Expand Up @@ -3612,9 +3613,32 @@ void TestQgsProcessing::parameterGeometry()
QCOMPARE( fromMap2.flags(), def->flags() );
QCOMPARE( fromMap2.defaultValue(), def->defaultValue() );
QCOMPARE( fromMap2.geometryTypes(), def->geometryTypes() );
QCOMPARE( fromMap2.allowMultipart(), def->allowMultipart() );
def.reset( dynamic_cast< QgsProcessingParameterGeometry *>( QgsProcessingParameters::parameterFromVariantMap( map2 ) ) );
QVERIFY( dynamic_cast< QgsProcessingParameterGeometry *>( def.get() ) );

// not multipart
def.reset( new QgsProcessingParameterGeometry( "not_multipart", QString(), QString( "Point(-1 3)" ), false, {}, false ) );
QVERIFY( !def->allowMultipart() );
QVERIFY( !def->checkValueIsAcceptable( QString( "MultiPoint((10 10), (20 20))" ) ) );
QVERIFY( !def->checkValueIsAcceptable( QgsGeometry::fromWkt( QStringLiteral( "MultiPoint((10 10), (20 20))" ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ) ) );

pythonCode = def->asPythonString();
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterGeometry('not_multipart', '', allowMultipart=False, defaultValue='Point(-1 3)')" ) );

QVariantMap map3 = def->toVariantMap();
QgsProcessingParameterGeometry fromMap3( "x" );
QVERIFY( fromMap3.fromVariantMap( map3 ) );
QCOMPARE( fromMap3.allowMultipart(), false );

std::unique_ptr< QgsProcessingParameterGeometry > cloned( dynamic_cast< QgsProcessingParameterGeometry *>( def->clone() ) );
QCOMPARE( cloned->name(), def->name() );
QCOMPARE( cloned->description(), def->description() );
QCOMPARE( cloned->flags(), def->flags() );
QCOMPARE( cloned->defaultValue(), def->defaultValue() );
QCOMPARE( cloned->geometryTypes(), def->geometryTypes() );
QCOMPARE( cloned->allowMultipart(), def->allowMultipart() );

}

Expand Down

0 comments on commit 9eb172a

Please sign in to comment.