[FEATURE] Add make_line expression function variant which accepts

an array of points

Allows creation of lines from variable numbers of points, and
from sequences from aggregates/dynamically generated sequences

Fixes #31268
This commit is contained in:
Nyall Dawson 2019-08-29 12:59:17 +10:00
parent 36173d7c40
commit 80d77b4788
3 changed files with 47 additions and 14 deletions

View File

@ -2,12 +2,22 @@
"name": "make_line",
"type": "function",
"description": "Creates a line geometry from a series of point geometries.",
"variableLenArguments": true,
"arguments": [
"variants": [
{ "variant": "List of arguments variant",
"variant_description": "Line vertices are specified as seperate arguments to the function.",
"variableLenArguments": true,
"arguments": [
{"arg":"point1", "syntaxOnly": true},
{"arg":"point2", "syntaxOnly": true},
{"arg":"point", "descOnly": true, "description":"a point geometry"}],
{"arg":"point", "descOnly": true, "description":"a point geometry (or array of points)"}],
"examples": [ { "expression":"geom_to_wkt(make_line(make_point(2,4),make_point(3,5)))", "returns":"'LineString (2 4, 3 5)'"},
{ "expression":"geom_to_wkt(make_line(make_point(2,4),make_point(3,5),make_point(9,7)))", "returns":"'LineString (2 4, 3 5, 9 7)'"}
]
]},
{
"variant": "Array variant",
"variant_description": "Line vertices are specified as an array of points.",
"arguments": [ {"arg":"array","description":"array of points"}],
"examples": [ { "expression":"geom_to_wkt(make_line(array(make_point(2,4),make_point(3,5),make_point(9,7))))", "returns":"'LineString (2 4, 3 5, 9 7)'"} ]
}]
}

View File

@ -2425,31 +2425,49 @@ static QVariant fcnMakePointM( const QVariantList &values, const QgsExpressionCo
static QVariant fcnMakeLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
if ( values.count() < 2 )
if ( values.empty() )
{
return QVariant();
}
QgsLineString *lineString = new QgsLineString();
lineString->clear();
QVector<QgsPoint> points;
points.reserve( values.count() );
for ( const QVariant &value : values )
auto addPoint = [&points]( const QgsGeometry & geom )
{
QgsGeometry geom = QgsExpressionUtils::getGeometry( value, parent );
if ( geom.isNull() )
continue;
return;
if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
continue;
return;
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
if ( !point )
continue;
return;
lineString->addVertex( *point );
points << *point;
};
for ( const QVariant &value : values )
{
if ( value.type() == QVariant::List )
{
const QVariantList list = value.toList();
for ( const QVariant &v : list )
{
addPoint( QgsExpressionUtils::getGeometry( v, parent ) );
}
}
else
{
addPoint( QgsExpressionUtils::getGeometry( value, parent ) );
}
}
return QVariant::fromValue( QgsGeometry( lineString ) );
if ( points.count() < 2 )
return QVariant();
return QgsGeometry( new QgsLineString( points ) );
}
static QVariant fcnMakePolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )

View File

@ -994,6 +994,11 @@ class TestQgsExpression: public QObject
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4),make_point(4,6)))" << false << QVariant( "LineString (2 4, 4 6)" );
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4),make_point(4,6),make_point(7,9)))" << false << QVariant( "LineString (2 4, 4 6, 7 9)" );
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4,1,3),make_point(4,6,9,8),make_point(7,9,3,4)))" << false << QVariant( "LineStringZM (2 4 1 3, 4 6 9 8, 7 9 3 4)" );
QTest::newRow( "make_line array" ) << "geom_to_wkt(make_line(array(make_point(2,4),make_point(4,6))))" << false << QVariant( "LineString (2 4, 4 6)" );
QTest::newRow( "make_line one" ) << "geom_to_wkt(make_line(array(make_point(2,4))))" << false << QVariant();
QTest::newRow( "make_line array mixed" ) << "geom_to_wkt(make_line(array(make_point(2,4),make_point(4,6)),make_point(8,9)))" << false << QVariant( "LineString (2 4, 4 6, 8 9)" );
QTest::newRow( "make_line array bad" ) << "geom_to_wkt(make_line(array(make_point(2,4),66)))" << true << QVariant();
QTest::newRow( "make_line array empty" ) << "geom_to_wkt(make_line(array()))" << false << QVariant();
QTest::newRow( "make_polygon bad" ) << "make_polygon(make_point(2,4))" << false << QVariant();
QTest::newRow( "make_polygon" ) << "geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )')))" << false << QVariant( "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))" );
QTest::newRow( "make_polygon rings" ) << "geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )'),geom_from_wkt('LINESTRING( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1 )'),geom_from_wkt('LINESTRING( 0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8 )')))" << false