Skip to content
Permalink
Browse files

Expressions for geometry Z and M minimum and maximum (#35928)

* add expressions for min and max M and Z - including tests

* add my info to contributors.json

* Apply suggestions from code review

suggestions to help for expressions from Nyall

Co-Authored-By: Nyall Dawson <nyall.dawson@gmail.com>

* Apply suggestions from code review

add suggestions to qgsexpressionfunction.cpp from Nyall

Co-Authored-By: Nyall Dawson <nyall.dawson@gmail.com>

* [feature][expressions] - fix expressions Z/M min and max

* [feature][expressions] - fix styling Z/M min and max expressions

Co-authored-by: Nyall Dawson <nyall.dawson@gmail.com>
  • Loading branch information
JanCaha and nyalldawson committed Apr 27, 2020
1 parent 4065ae4 commit 3656b101ee26de3123beb6b92a87394700ea63bb
@@ -924,6 +924,23 @@
45.93943
]
}
},
{
"type": "Feature",
"properties": {
"Name": "Jan Caha",
"Committer": "Yes",
"First Commit Message": "ascii expression",
"First Commit Date": "18-04-2020",
"GIT Nickname": "jancaha"
},
"geometry": {
"type": "Point",
"coordinates": [
16.98311,
49.281418
]
}
}
]
}
@@ -0,0 +1,9 @@
{
"name": "m_max",
"type": "function",
"description": "Returns the maximum m (measure) value of a geometry.",
"arguments": [ {"arg":"geometry","description":"a geometry containing m values"}],
"examples": [ { "expression":"m_max( make_point_m( 0,0,1 ) )", "returns":"1"},
{ "expression":"m_max(make_line( make_point_m( 0,0,1 ), make_point_m( -1,-1,2 ), make_point_m( -2,-2,0 ) ) )", "returns":"2"}
]
}
@@ -0,0 +1,9 @@
{
"name": "m_min",
"type": "function",
"description": "Returns the minimum m (measure) value of a geometry.",
"arguments": [ {"arg":"geometry","description":"a geometry containing m values"}],
"examples": [ { "expression":"m_min( make_point_m( 0,0,1 ) )", "returns":"1"},
{ "expression":"m_min(make_line( make_point_m( 0,0,1 ), make_point_m( -1,-1,2 ), make_point_m( -2,-2,0 ) ) )", "returns":"0"}
]
}
@@ -0,0 +1,9 @@
{
"name": "z_max",
"type": "function",
"description": "Returns the maximum z coordinate of a geometry.",
"arguments": [ {"arg":"geometry","description":"a geometry with z coordinate"}],
"examples": [ { "expression":"z_max( geom_from_wkt( 'POINT ( 0 0 1 )' ) )", "returns":"1"},
{ "expression":"z_max( make_line( make_point( 0,0,0 ), make_point( -1,-1,-2 ) ) )", "returns":"0"}
]
}
@@ -0,0 +1,9 @@
{
"name": "z_min",
"type": "function",
"description": "Returns the minimum z coordinate of a geometry.",
"arguments": [ {"arg":"geometry","description":"a geometry with z coordinate"}],
"examples": [ { "expression":"z_min( geom_from_wkt( 'POINT ( 0 0 1 )' ) )", "returns":"1"},
{ "expression":"z_min( make_line( make_point( 0,0,0 ), make_point( -1,-1,-2 ) ) )", "returns":"-2"}
]
}
@@ -3253,6 +3253,110 @@ static QVariant fcnYMax( const QVariantList &values, const QgsExpressionContext
return QVariant::fromValue( geom.boundingBox().yMaximum() );
}

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

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

if ( !geom.constGet()->is3D() )
return QVariant();

double max = std::numeric_limits< double >::lowest();

for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
{
double z = ( *it ).z();

if ( max < z )
max = z;
}

if ( max == std::numeric_limits< double >::lowest() )
return QVariant( QVariant::Double );

return QVariant( max );
}

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

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

if ( !geom.constGet()->is3D() )
return QVariant();

double min = std::numeric_limits< double >::max();

for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
{
double z = ( *it ).z();

if ( z < min )
min = z;
}

if ( min == std::numeric_limits< double >::max() )
return QVariant( QVariant::Double );

return QVariant( min );
}

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

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

if ( !geom.constGet()->isMeasure() )
return QVariant();

double min = std::numeric_limits< double >::max();

for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
{
double m = ( *it ).m();

if ( m < min )
min = m;
}

if ( min == std::numeric_limits< double >::max() )
return QVariant( QVariant::Double );

return QVariant( min );
}

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

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

if ( !geom.constGet()->isMeasure() )
return QVariant();

double max = std::numeric_limits< double >::lowest();

for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
{
double m = ( *it ).m();

if ( max < m )
max = m;
}

if ( max == std::numeric_limits< double >::lowest() )
return QVariant( QVariant::Double );

return QVariant( max );
}

static QVariant fcnFlipCoordinates( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
@@ -5938,7 +6042,15 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< QgsExpressionFunction::Parameter( QStringLiteral( "y" ) ),
fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
<< new QgsStaticExpressionFunction( QStringLiteral( "is_multipart" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnGeomIsMultipart, QStringLiteral( "GeometryGroup" ) );
fcnGeomIsMultipart, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "z_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnZMax, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "z_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnZMin, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "m_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnMMax, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "m_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnMMin, QStringLiteral( "GeometryGroup" ) );


QgsStaticExpressionFunction *orderPartsFunc = new QgsStaticExpressionFunction( QStringLiteral( "order_parts" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
@@ -1184,6 +1184,30 @@ class TestQgsExpression: public QObject
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 );
QTest::newRow( "is_multipart null" ) << "is_multipart(NULL)" << false << QVariant();
QTest::newRow( "z_max no 3D" ) << "z_max(geom_from_wkt('POINT (0 0)'))" << false << QVariant();
QTest::newRow( "z_max NULL" ) << "z_max(geom_from_wkt(NULL))" << false << QVariant();
QTest::newRow( "z_max point Z NaN" ) << "z_max(geom_from_wkt('PointZ (1 1 nan)'))" << false << QVariant( QVariant::Double );
QTest::newRow( "z_max line Z NaN" ) << "z_max(make_line(geom_from_wkt('PointZ (0 0 nan)'),make_point(-1,-1,-2)))" << false << QVariant( -2.0 );
QTest::newRow( "z_max point" ) << "z_max(geom_from_wkt('POINT (0 0 1)'))" << false << QVariant( 1.0 );
QTest::newRow( "z_max line" ) << "z_max(make_line(make_point(0,0,0),make_point(-1,-1,-2)))" << false << QVariant( 0.0 );
QTest::newRow( "z_min no 3D" ) << "z_min(geom_from_wkt('POINT (0 0)'))" << false << QVariant();
QTest::newRow( "z_min NULL" ) << "z_min(geom_from_wkt(NULL))" << false << QVariant();
QTest::newRow( "z_min point Z NaN" ) << "z_min(geom_from_wkt('PointZ (1 1 nan)'))" << false << QVariant( QVariant::Double );
QTest::newRow( "z_min line Z NaN" ) << "z_min(make_line(geom_from_wkt('PointZ (0 0 nan)'),make_point(-1,-1,-2)))" << false << QVariant( -2.0 );
QTest::newRow( "z_min point" ) << "z_min(geom_from_wkt('POINT (0 0 1)'))" << false << QVariant( 1.0 );
QTest::newRow( "z_min line" ) << "z_min(make_line(make_point(0,0,0),make_point(-1,-1,-2)))" << false << QVariant( -2.0 );
QTest::newRow( "m_max no measure" ) << "m_max(geom_from_wkt('POINT (0 0)'))" << false << QVariant();
QTest::newRow( "m_max NULL" ) << "m_max(geom_from_wkt(NULL))" << false << QVariant();
QTest::newRow( "m_max point M NaN" ) << "m_max(geom_from_wkt('PointZM (0 0 0 nan)'))" << false << QVariant( QVariant::Double );
QTest::newRow( "m_max line M NaN" ) << "m_max(make_line(geom_from_wkt('PointZM (0 0 0 nan)'),geom_from_wkt('PointZM (1 1 1 2)')))" << false << QVariant( 2.0 );
QTest::newRow( "m_max point" ) << "m_max(make_point_m(0,0,1))" << false << QVariant( 1.0 );
QTest::newRow( "m_max line" ) << "m_max(make_line(make_point_m(0,0,1),make_point_m(-1,-1,2),make_point_m(-2,-2,0)))" << false << QVariant( 2.0 );
QTest::newRow( "m_min no measure" ) << "m_min(geom_from_wkt('POINT (0 0)'))" << false << QVariant();
QTest::newRow( "m_min NULL" ) << "m_min(geom_from_wkt(NULL))" << false << QVariant();
QTest::newRow( "m_min point M NaN" ) << "m_min(geom_from_wkt('PointZM (0 0 0 nan)'))" << false << QVariant( QVariant::Double );
QTest::newRow( "m_min line M NaN" ) << "m_min(make_line(geom_from_wkt('PointZM (0 0 0 nan)'),geom_from_wkt('PointZM (1 1 1 2)')))" << false << QVariant( 2.0 );
QTest::newRow( "m_min point" ) << "m_min(make_point_m(0,0,1))" << false << QVariant( 1.0 );
QTest::newRow( "m_min line" ) << "m_min(make_line(make_point_m(0,0,1),make_point_m(-1,-1,2),make_point_m(-2,-2,0)))" << false << QVariant( 0.0 );

// string functions
QTest::newRow( "format_number" ) << "format_number(1999.567,2)" << false << QVariant( "1,999.57" );

0 comments on commit 3656b10

Please sign in to comment.
You can’t perform that action at this time.