Skip to content
Permalink
Browse files
[feature][expressions] Add new densify_by_count and densify_by_distance
expression functions

These functions expose the existing Processing densify functionality
for use in expression functions

Fixes #24853
  • Loading branch information
nyalldawson committed Nov 5, 2021
1 parent a27a4ea commit 3d8fc9d52196813686ec6f092587ec4bc2b0a0e7
@@ -0,0 +1,13 @@
{
"name": "densify_by_count",
"type": "function",
"groups": ["GeometryGroup"],
"description": "Takes a polygon or line layer geometry and generates a new one in which the geometries have a larger number of vertices than the original one.",
"arguments": [
{"arg":"geometry","description":"a geometry (accepts (multi)linestrings or (multi)polygons)."},
{"arg":"vertices","description":"number of vertices to add (per segment)"}
],
"examples": [
{ "expression":"geom_to_wkt(densify_by_count(geom_from_wkt('LINESTRING(1 1, 10 1)'), 3))", "returns":"LineString (1 1, 3.25 1, 5.5 1, 7.75 1, 10 1)"}
]
}
@@ -0,0 +1,13 @@
{
"name": "densify_by_distance",
"type": "function",
"groups": ["GeometryGroup"],
"description": "Takes a polygon or line layer geometry and generates a new one in which the geometries are densified by adding additional vertices on edges that have a maximum distance of the specified interval distance.",
"arguments": [
{"arg":"geometry","description":"a geometry (accepts (multi)linestrings or (multi)polygons)."},
{"arg":"distance","description":"maximum interval distance between vertices in output geometry"}
],
"examples": [
{ "expression":"geom_to_wkt(densify_by_distance(geom_from_wkt('LINESTRING(1 1, 10 1)'), 4))", "returns":"LineString (1 1, 4 1, 7 1, 10 1)"}
]
}
@@ -3041,6 +3041,36 @@ static QVariant fcnApplyDashPattern( const QVariantList &values, const QgsExpres
return result;
}

static QVariant fcnDensifyByCount( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
const QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );

if ( geom.isNull() )
return QVariant();

const long long count = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
const QgsGeometry densified = geom.densifyByCount( static_cast< int >( count ) );
if ( densified.isNull() )
return QVariant();

return densified;
}

static QVariant fcnDensifyByDistance( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
const QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );

if ( geom.isNull() )
return QVariant();

const double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
const QgsGeometry densified = geom.densifyByDistance( distance );
if ( densified.isNull() )
return QVariant();

return densified;
}

static QVariant fcnCollectGeometries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QVariantList list;
@@ -7441,6 +7471,16 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
QgsExpressionFunction::Parameter( QStringLiteral( "adjustment" ), true, QStringLiteral( "both" ) ),
QgsExpressionFunction::Parameter( QStringLiteral( "pattern_offset" ), true, 0 ),
}, fcnApplyDashPattern, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "densify_by_count" ),
{
QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
QgsExpressionFunction::Parameter( QStringLiteral( "vertices" ) )
}, fcnDensifyByCount, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "densify_by_distance" ),
{
QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
}, fcnDensifyByDistance, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "num_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "num_interior_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "num_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
@@ -1404,6 +1404,16 @@ class TestQgsExpression: public QObject
QTest::newRow( "apply_dash_pattern geometry adjust 2" ) << "geom_to_wkt(apply_dash_pattern(geom_from_wkt('LINESTRING(1 1, 10 1)'), array(3, 1), end_rule:='full_dash', adjustment:='dash'))" << false << QVariant( "MultiLineString ((1 1, 3.33333333 1),(4.33333333 1, 6.66666667 1),(7.66666667 1, 10 1))" );
QTest::newRow( "apply_dash_pattern geometry adjust 3" ) << "geom_to_wkt(apply_dash_pattern(geom_from_wkt('LINESTRING(1 1, 10 1)'), array(3, 1), end_rule:='full_dash', adjustment:='gap'))" << false << QVariant( "MultiLineString ((1 1, 4 1),(4 1, 7 1),(7 1, 10 1),(10 1, 10 1, 10 1))" );
QTest::newRow( "apply_dash_pattern geometry pattern offset" ) << "geom_to_wkt(apply_dash_pattern(geom_from_wkt('LINESTRING(1 1, 10 1)'), array(3, 1), pattern_offset:=3))" << false << QVariant( "MultiLineString ((2 1, 5 1),(6 1, 9 1),(10 1, 10 1, 10 1))" );
QTest::newRow( "densify_by_count not geom" ) << "densify_by_count('g', 3)" << true << QVariant();
QTest::newRow( "densify_by_count null" ) << "densify_by_count(NULL, 3)" << false << QVariant();
QTest::newRow( "densify_by_count point" ) << "geom_to_wkt(densify_by_count(make_point(1,2),3))" << false << QVariant( "Point (1 2)" );
QTest::newRow( "densify_by_count geometry" ) << "geom_to_wkt(densify_by_count(geom_from_wkt('LINESTRING(1 1, 10 1)'), 3))" << false << QVariant( "LineString (1 1, 3.25 1, 5.5 1, 7.75 1, 10 1)" );
QTest::newRow( "densify_by_count polygon" ) << "geom_to_wkt(densify_by_count(geom_from_wkt('POLYGON((1 1, 10 1, 10 10, 1 10, 1 1))'), 2))" << false << QVariant( "Polygon ((1 1, 4 1, 7 1, 10 1, 10 4, 10 7, 10 10, 7 10, 4 10, 1 10, 1 7, 1 4, 1 1))" );
QTest::newRow( "densify_by_distance not geom" ) << "densify_by_distance('g', 3)" << true << QVariant();
QTest::newRow( "densify_by_distance null" ) << "densify_by_distance(NULL, 3)" << false << QVariant();
QTest::newRow( "densify_by_distance point" ) << "geom_to_wkt(densify_by_distance(make_point(1,2),3))" << false << QVariant( "Point (1 2)" );
QTest::newRow( "densify_by_distance geometry" ) << "geom_to_wkt(densify_by_distance(geom_from_wkt('LINESTRING(1 1, 10 1)'), 4))" << false << QVariant( "LineString (1 1, 4 1, 7 1, 10 1)" );
QTest::newRow( "densify_by_distance polygon" ) << "geom_to_wkt(densify_by_distance(geom_from_wkt('POLYGON((1 1, 10 1, 10 10, 1 10, 1 1))'), 2))" << false << QVariant( "Polygon ((1 1, 2.8 1, 4.6 1, 6.4 1, 8.2 1, 10 1, 10 2.8, 10 4.6, 10 6.4, 10 8.2, 10 10, 8.2 10, 6.4 10, 4.6 10, 2.8 10, 1 10, 1 8.2, 1 6.4, 1 4.6, 1 2.8, 1 1))" );
QTest::newRow( "is_multipart true" ) << "is_multipart(geom_from_wkt('MULTIPOINT ((0 0),(1 1),(2 2))'))" << false << QVariant( true );
QTest::newRow( "is_multipart false" ) << "is_multipart(geom_from_wkt('POINT (0 0)'))" << false << QVariant( false );
QTest::newRow( "is_multipart false empty geometry" ) << "is_multipart(geom_from_wkt('POINT EMPTY'))" << false << QVariant( false );

0 comments on commit 3d8fc9d

Please sign in to comment.