Skip to content

Commit

Permalink
[feature][expressions] Add new densify_by_count and densify_by_distance
Browse files Browse the repository at this point in the history
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 3d8fc9d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 0 deletions.
13 changes: 13 additions & 0 deletions resources/function_help/json/densify_by_count
@@ -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)"}
]
}
13 changes: 13 additions & 0 deletions resources/function_help/json/densify_by_distance
@@ -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)"}
]
}
40 changes: 40 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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" ) )
Expand Down
10 changes: 10 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -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 );
Expand Down

0 comments on commit 3d8fc9d

Please sign in to comment.