Skip to content

Commit

Permalink
[feature] close_line expression function
Browse files Browse the repository at this point in the history
Closes an open (multi)linestring geometry
  • Loading branch information
JanCaha committed May 1, 2020
1 parent fddc6b4 commit 89fe634
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
8 changes: 8 additions & 0 deletions resources/function_help/json/close_line
@@ -0,0 +1,8 @@
{
"name": "close_line",
"type": "function",
"description": "Returns a closed line string of the input line string by appending the first point to the end of the line, if it is not already closed. If the geometry is not a line string or multi line string then the result will be null.",
"arguments": [ {"arg":"geometry","description":"a line string geometry"}],
"examples": [ { "expression":"geom_to_wkt(close_line(geom_from_wkt('LINESTRING(0 0, 1 0, 1 1)')))", "returns":"LineString (0 0, 1 0, 1 1, 0 0)"},
{ "expression":"geom_to_wkt(close_line(geom_from_wkt('LINESTRING(0 0, 1 0, 1 1, 0 0)')))", "returns":"LineString (0 0, 1 0, 1 1, 0 0)"}]
}
43 changes: 43 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -3392,6 +3392,48 @@ static QVariant fcnIsClosed( const QVariantList &values, const QgsExpressionCont
return QVariant::fromValue( curve->isClosed() );
}

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

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

QVariant result;
if ( !geom.isMultipart() )
{
const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( geom.constGet() );

if ( !line )
return QVariant();

std::unique_ptr< QgsLineString > closedLine( line->clone() );
closedLine->close();

result = QVariant::fromValue( QgsGeometry( std::move( closedLine ) ) );
}
else
{
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( geom.constGet() );

std::unique_ptr< QgsGeometryCollection > closed( collection->createEmptyWithSameType() );

for ( int i = 0; i < collection->numGeometries(); ++i )
{
if ( const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( collection->geometryN( i ) ) )
{
std::unique_ptr< QgsLineString > closedLine( line->clone() );
closedLine->close();

closed->addGeometry( closedLine.release() );
}
}
result = QVariant::fromValue( QgsGeometry( std::move( closed ) ) );
}

return result;
}

static QVariant fcnIsEmpty( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -5999,6 +6041,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "bounds_width" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "bounds_height" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "is_closed" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "close_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCloseLine, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "is_empty" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsEmpty, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "is_empty_or_null" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsEmptyOrNull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList(), true )
<< new QgsStaticExpressionFunction( QStringLiteral( "convex_hull" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
Expand Down
7 changes: 7 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -1004,6 +1004,13 @@ class TestQgsExpression: public QObject
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString ((6501338.13976828 4850981.51459331, 6501343.09036573 4850984.01453377, 6501338.13976828 4850988.96491092, 6501335.63971657 4850984.01453377, 6501338.13976828 4850981.51459331))'))" << false << QVariant( true );
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString ((6501338.13976828 4850981.51459331, 6501343.09036573 4850984.01453377, 6501338.13976828 4850988.96491092, 6501335.63971657 4850984.01453377, 6501438.13976828 4850981.51459331))'))" << false << QVariant( false );
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString EMPTY'))" << false << QVariant();
QTest::newRow( "close_line not geom" ) << "close_line('g')" << true << QVariant();
QTest::newRow( "close_line null" ) << "close_line(NULL)" << false << QVariant();
QTest::newRow( "close_line point" ) << "close_line(geom_from_wkt('POINT(0 0)'))" << false << QVariant();
QTest::newRow( "close_line polygon" ) << "close_line(geom_from_wkt('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'))" << false << QVariant();
QTest::newRow( "close_line not closed" ) << "geom_to_wkt(close_line(geom_from_wkt('LINESTRING(0 0, 1 0, 1 1)')))" << false << QVariant( "LineString (0 0, 1 0, 1 1, 0 0)" );
QTest::newRow( "close_line closed" ) << "geom_to_wkt(close_line(geom_from_wkt('LINESTRING(0 0, 1 0, 1 1, 0 0)')))" << false << QVariant( "LineString (0 0, 1 0, 1 1, 0 0)" );
QTest::newRow( "close_line multiline" ) << "geom_to_wkt(close_line(geom_from_wkt('MULTILINESTRING ((0 0, 1 1, 1 0),(2 2, 3 3, 3 2))')))" << false << QVariant( "MultiLineString ((0 0, 1 1, 1 0, 0 0),(2 2, 3 3, 3 2, 2 2))" );
QTest::newRow( "is_empty not geom" ) << "is_empty('g')" << true << QVariant();
QTest::newRow( "is_empty null" ) << "is_empty(NULL)" << false << QVariant();
QTest::newRow( "is_empty point" ) << "is_empty(geom_from_wkt('POINT(1 2)'))" << false << QVariant( false );
Expand Down

0 comments on commit 89fe634

Please sign in to comment.