Skip to content

Commit

Permalink
[FEATURE] line_substring function
Browse files Browse the repository at this point in the history
Returns the portion of a line (or curve) geometry which falls
between the specified start and end distances (measured from the
beginning of the line). Z and M values are linearly interpolated
from existing values.

Fixes #15611
  • Loading branch information
nyalldawson committed Aug 15, 2018
1 parent 513bcb6 commit a4386d6
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
9 changes: 9 additions & 0 deletions resources/function_help/json/line_substring
@@ -0,0 +1,9 @@
{
"name": "line_substring",
"type": "function",
"description": "Returns the portion of a line (or curve) geometry which falls between the specified start and end distances (measured from the beginning of the line). Z and M values are linearly interpolated from existing values.",
"arguments": [ {"arg":"geometry","description":"a linestring or curve geometry"},
{"arg":"start_distance","description":"distance to start of substring"},
{"arg":"end_distance","description":"distance to end of substring"}],
"examples": [ { "expression":"geom_to_wkt(line_substring(geometry:=geom_from_wkt('LineString(0 0, 10 0)'),start_distance:=2,end_distance=6))", "returns":"'LineString (2 0,6 0)'"}]
}
37 changes: 36 additions & 1 deletion src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -3047,6 +3047,39 @@ static QVariant fcnLineInterpolatePoint( const QVariantList &values, const QgsEx
return result;
}

static QVariant fcnLineSubset( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
if ( lineGeom.type() != QgsWkbTypes::LineGeometry )
{
parent->setEvalErrorString( QObject::tr( "line_substring requires a curve geometry input" ) );
return QVariant();
}

const QgsCurve *curve = nullptr;
if ( !lineGeom.isMultipart() )
curve = qgsgeometry_cast< const QgsCurve * >( lineGeom.constGet() );
else
{
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( lineGeom.constGet() ) )
{
if ( collection->numGeometries() > 0 )
{
curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
}
}
}
if ( !curve )
return QVariant();

double startDistance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
double endDistance = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );

std::unique_ptr< QgsCurve > substring( curve->curveSubstring( startDistance, endDistance ) );
QgsGeometry result( std::move( substring ) );
return !result.isNull() ? QVariant::fromValue( result ) : QVariant();
}

static QVariant fcnLineInterpolateAngle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -4527,7 +4560,9 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "angle_at_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "distance_to_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) );
<< QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "line_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ), fcnLineSubset, QStringLiteral( "GeometryGroup" ) );


// **Record** functions
Expand Down
4 changes: 4 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -988,6 +988,10 @@ class TestQgsExpression: public QObject
QTest::newRow( "distance_to_vertex null" ) << "distance_to_vertex(NULL, 0)" << false << QVariant();
QTest::newRow( "distance_to_vertex point" ) << "distance_to_vertex(geom_from_wkt('POINT(1 2)'),0)" << false << QVariant( 0.0 );
QTest::newRow( "distance_to_vertex line" ) << "distance_to_vertex(geometry:=geom_from_wkt('LineString(0 0, 10 0, 10 10)'),vertex:=1)" << false << QVariant( 10.0 );
QTest::newRow( "line_substring not geom" ) << "line_substring('g', 5, 6)" << true << QVariant();
QTest::newRow( "line_substring null" ) << "line_substring(NULL, 5, 6)" << false << QVariant();
QTest::newRow( "line_substring point" ) << "line_substring(geom_from_wkt('POINT(1 2)'),5,6)" << true << QVariant();
QTest::newRow( "line_substring line" ) << "geom_to_wkt(line_substring(geometry:=geom_from_wkt('LineString(0 0, 10 0)'),start_distance:=5,end_distance:=6))" << false << QVariant( "LineString (5 0, 6 0)" );
QTest::newRow( "simplify not geom" ) << "simplify('g',5)" << true << QVariant();
QTest::newRow( "simplify null" ) << "simplify(NULL,5)" << false << QVariant();
QTest::newRow( "simplify point" ) << "geom_to_wkt(simplify(geom_from_wkt('POINT(1 2)'),10))" << false << QVariant( "Point (1 2)" );
Expand Down

0 comments on commit a4386d6

Please sign in to comment.