Skip to content

Commit aaede28

Browse files
lbartolettinyalldawson
authored andcommittedJan 16, 2019
[feature] Add expression for square by diagonal and rectangle from 3 points
With the new class QgsQuadrilateral, we can add expressions to create a square by a diagonal and rectangles by 3 points
1 parent 200d4f6 commit aaede28

File tree

4 files changed

+112
-2
lines changed

4 files changed

+112
-2
lines changed
 
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "make_rectangle_3points",
3+
"type": "function",
4+
"description": "Creates a rectangle from 3 points.",
5+
"variableLenArguments": true,
6+
"arguments": [
7+
{"arg":"point1", "description": "First point."},
8+
{"arg":"point2", "description": "Second point."},
9+
{"arg":"point3", "description": "Third point."},
10+
{"arg":"option", "optional": true, "default": "0", "description":
11+
"An optional argument to construct the rectangle. By default this value is 0. Value can be 0 (distance) or 1 (projected). Option distance: Second distance is equal to the distance between 2nd and 3rd point. Option projected: Second distance is equal to the distance of the perpendicular projection of the 3rd point on the segment or its extension."}
12+
],
13+
"examples": [
14+
{ "expression":"geom_to_wkt(make_rectangle(make_point(0, 0), make_point(0,5), make_point(5, 5), 0)))", "returns":"'Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))'"},
15+
{ "expression":"geom_to_wkt(make_rectangle(make_point(0, 0), make_point(0,5), make_point(5, 3), 1)))", "returns":"'Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))'"}
16+
]
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "make_square",
3+
"type": "function",
4+
"description": "Creates a square from a diagonal.",
5+
"variableLenArguments": true,
6+
"arguments": [
7+
{"arg":"point1", "description": "First point of the regular polygon"},
8+
{"arg":"point2", "description": "Second point"}
9+
],
10+
"examples": [
11+
{ "expression":"geom_to_wkt(make_square( make_point(0,0), make_point(5,5)))", "returns":"'Polygon ((0 0, -0 5, 5 5, 5 0, 0 0))'"},
12+
{ "expression":"geom_to_wkt(make_square( make_point(5,0), make_point(5,5)))", "returns":"'Polygon ((5 0, 2.5 2.5, 5 5, 7.5 2.5, 5 0))'"}
13+
]
14+
}

‎src/core/expression/qgsexpressionfunction.cpp

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "qgstriangle.h"
3131
#include "qgscurve.h"
3232
#include "qgsregularpolygon.h"
33+
#include "qgsquadrilateral.h"
3334
#include "qgsmultipolygon.h"
3435
#include "qgsogcutils.h"
3536
#include "qgsdistancearea.h"
@@ -2487,6 +2488,60 @@ static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpr
24872488

24882489
}
24892490

2491+
static QVariant fcnMakeSquare( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2492+
{
2493+
QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2494+
if ( pt1.isNull() )
2495+
return QVariant();
2496+
if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
2497+
return QVariant();
2498+
2499+
QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
2500+
if ( pt2.isNull() )
2501+
return QVariant();
2502+
if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
2503+
return QVariant();
2504+
2505+
const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
2506+
const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
2507+
QgsQuadrilateral square = QgsQuadrilateral::squareFromDiagonal( *point1, *point2 );
2508+
2509+
return QVariant::fromValue( QgsGeometry( square.toPolygon() ) );
2510+
}
2511+
2512+
static QVariant fcnMakeRectangleFrom3Points( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2513+
{
2514+
QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2515+
if ( pt1.isNull() )
2516+
return QVariant();
2517+
if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
2518+
return QVariant();
2519+
2520+
QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
2521+
if ( pt2.isNull() )
2522+
return QVariant();
2523+
if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
2524+
return QVariant();
2525+
2526+
QgsGeometry pt3 = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
2527+
if ( pt3.isNull() )
2528+
return QVariant();
2529+
if ( pt3.type() != QgsWkbTypes::PointGeometry || pt3.isMultipart() )
2530+
return QVariant();
2531+
2532+
QgsQuadrilateral::ConstructionOption option = static_cast< QgsQuadrilateral::ConstructionOption >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
2533+
if ( ( option < QgsQuadrilateral::Distance ) || ( option > QgsQuadrilateral::Projected ) )
2534+
{
2535+
parent->setEvalErrorString( QObject::tr( "Option can be 0 (distance) or 1 (projected)" ) );
2536+
return QVariant();
2537+
}
2538+
const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
2539+
const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
2540+
const QgsPoint *point3 = qgsgeometry_cast< const QgsPoint *>( pt3.constGet() );
2541+
QgsQuadrilateral rect = QgsQuadrilateral::rectangleFrom3Points( *point1, *point2, *point3, option );
2542+
return QVariant::fromValue( QgsGeometry( rect.toPolygon() ) );
2543+
}
2544+
24902545
static QVariant pointAt( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent ) // helper function
24912546
{
24922547
FEAT_FROM_CONTEXT( context, f );
@@ -4888,8 +4943,17 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
48884943
<< QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
48894944
<< QgsExpressionFunction::Parameter( QStringLiteral( "number_sides" ) )
48904945
<< QgsExpressionFunction::Parameter( QStringLiteral( "circle" ), true, 0 ),
4891-
fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) );
4892-
4946+
fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) )
4947+
<< new QgsStaticExpressionFunction( QStringLiteral( "make_square" ), QgsExpressionFunction::ParameterList()
4948+
<< QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
4949+
<< QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) ),
4950+
fcnMakeSquare, QStringLiteral( "GeometryGroup" ) )
4951+
<< new QgsStaticExpressionFunction( QStringLiteral( "make_rectangle_3points" ), QgsExpressionFunction::ParameterList()
4952+
<< QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
4953+
<< QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
4954+
<< QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) )
4955+
<< QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, 0 ),
4956+
fcnMakeRectangleFrom3Points, QStringLiteral( "GeometryGroup" ) );
48934957
QgsStaticExpressionFunction *xAtFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x_at" ), 1, fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) );
48944958
xAtFunc->setIsStatic( false );
48954959
sFunctions << xAtFunc;

‎tests/src/core/testqgsexpression.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,21 @@ class TestQgsExpression: public QObject
944944
QTest::newRow( "make_regular_polygon bad (numEdges < 3)" ) << "make_regular_polygon(make_point(0,0), make_point(0,5), 2)" << true << QVariant();
945945
QTest::newRow( "make_regular_polygon" ) << "geom_to_wkt(make_regular_polygon(make_point(0,0), make_point(0,5), 5), 2)" << false << QVariant( "Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))" );
946946
QTest::newRow( "make_regular_polygon" ) << "geom_to_wkt(make_regular_polygon(make_point(0,0), project(make_point(0,0), 4.0451, radians(36)), 5, 1), 2)" << false << QVariant( "Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))" );
947+
QTest::newRow( "make_square not geom (point 1)" ) << "make_square(make_line(make_point(1,2), make_point(3,4)), make_point(5,5))" << false << QVariant();
948+
QTest::newRow( "make_square not geom (point 2)" ) << "make_square(make_point(0,0), make_line(make_point(1,2), make_point(3,4)))" << false << QVariant();
949+
QTest::newRow( "make_square bad (point 1)" ) << "make_square('a', make_point(5,5))" << true << QVariant();
950+
QTest::newRow( "make_square bad (point 2)" ) << "make_square(make_point(0,0), 'a')" << true << QVariant();
951+
QTest::newRow( "make_square" ) << "geom_to_wkt(make_square(make_point(5, 5), make_point(1, 1)))" << false << QVariant( "Polygon ((5 5, 5 1, 1 1, 1 5, 5 5))" );
952+
QTest::newRow( "make_rectangle_3points not geom (point 1)" ) << "make_rectangle_3points( make_line(make_point(1,2), make_point(3,4)), make_point(0,5), make_point(5,5))" << false << QVariant();
953+
QTest::newRow( "make_rectangle_3points not geom (point 2)" ) << "make_rectangle_3points(make_point(0,0), make_line(make_point(1,2), make_point(3,4)), make_point(5,5))" << false << QVariant();
954+
QTest::newRow( "make_rectangle_3points not geom (point 3)" ) << "make_rectangle_3points(make_point(0,0), make_point(0,5), make_line(make_point(1,2), make_point(3,4)))" << false << QVariant();
955+
QTest::newRow( "make_rectangle_3points bad (point 1)" ) << "make_rectangle_3points('a', make_point(0,5), make_point(5,5))" << true << QVariant();
956+
QTest::newRow( "make_rectangle_3points bad (point 2)" ) << "make_rectangle_3points(make_point(0,0), 'a', make_point(5,5))" << true << QVariant();
957+
QTest::newRow( "make_rectangle_3points bad (point 3)" ) << "make_rectangle_3points(make_point(0,0), make_point(0,5), 'a')" << true << QVariant();
958+
QTest::newRow( "make_rectangle_3points bad (invalid option)" ) << "make_rectangle_3points(make_point(0,0), make_point(0,5), make_point(5,5), 2)" << true << QVariant();
959+
QTest::newRow( "make_rectangle_3points (distance default)" ) << "geom_to_wkt(make_rectangle_3points(make_point(0, 0), make_point(0,5), make_point(5, 5)))" << false << QVariant( "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))" );
960+
QTest::newRow( "make_rectangle_3points (distance)" ) << "geom_to_wkt(make_rectangle_3points(make_point(0, 0), make_point(0,5), make_point(5, 5), 0))" << false << QVariant( "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))" );
961+
QTest::newRow( "make_rectangle_3points (projected)" ) << "geom_to_wkt(make_rectangle_3points(make_point(0, 0), make_point(0,5), make_point(5, 3), 1))" << false << QVariant( "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))" );
947962
QTest::newRow( "x point" ) << "x(make_point(2.2,4.4))" << false << QVariant( 2.2 );
948963
QTest::newRow( "y point" ) << "y(make_point(2.2,4.4))" << false << QVariant( 4.4 );
949964
QTest::newRow( "z point" ) << "z(make_point(2.2,4.4,6.6))" << false << QVariant( 6.6 );

0 commit comments

Comments
 (0)
Please sign in to comment.