diff --git a/resources/function_help/json/minimal_circle b/resources/function_help/json/minimal_circle new file mode 100644 index 00000000000..6a062c52f0a --- /dev/null +++ b/resources/function_help/json/minimal_circle @@ -0,0 +1,10 @@ +{ + "name": "minimal_circle", + "type": "function", + "description": "Returns the minimal enclosing circle of a geometry. It represents the minimum circle that encloses all geometries within the set.", + "arguments": [ {"arg":"geometry","description":"a geometry"}, + {"arg":"segment", "description": "optional argument for polygon segmentation. By default this value is 36"}], + "examples": [ { "expression":"geom_to_wkt( minimal_circle( geom_from_wkt( 'LINESTRING(0 5, 0 -5, 2 1)' ), 4 ) )", "returns":"Polygon ((0 5, 5 -0, -0 -5, -5 0, 0 5))"}, + { "expression":"geom_to_wkt( minimal_circle( geom_from_wkt( 'MULTIPOINT(1 2, 3 4, 3 2)' ), 4 ) )", "returns":"Polygon ((3 4, 3 2, 1 2, 1 4, 3 4))"} + ] +} diff --git a/resources/function_help/json/oriented_bbox b/resources/function_help/json/oriented_bbox new file mode 100644 index 00000000000..f7ab837b14a --- /dev/null +++ b/resources/function_help/json/oriented_bbox @@ -0,0 +1,8 @@ +{ + "name": "oriented_bbox", + "type": "function", + "description":"Returns a geometry which represents the minimal oriented bounding box of an input geometry.", + "arguments": [ {"arg":"geom","description":"a geometry"} ], + "examples": [ { "expression":"geom_to_wkt( oriented_bbox( geom_from_wkt( 'MULTIPOINT(1 2, 3 4, 3 2)' ) ) )", "returns":"Polygon ((1 4, 1 2, 3 2, 3 4, 1 4))"}] +} + diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index ef059390d43..a054156f4ee 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -2535,6 +2535,29 @@ static QVariant fcnConvexHull( const QVariantList &values, const QgsExpressionCo QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant(); return result; } + +static QVariant fcnMinimalCircle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent ) +{ + QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent ); + QgsPointXY center; + double radius; + unsigned int segments = 36; + if ( values.length() == 2 ) + segments = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent ); + QgsGeometry geom = fGeom.minimalEnclosingCircle( center, radius, segments ); + QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant(); + return result; +} + +static QVariant fcnOrientedBBox( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent ) +{ + QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent ); + double area, angle, width, height; + QgsGeometry geom = fGeom.orientedMinimumBoundingBox( area, angle, width, height ); + QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant(); + return result; +} + static QVariant fcnDifference( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent ) { QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent ); @@ -4139,6 +4162,13 @@ const QList &QgsExpression::Functions() << new QgsStaticExpressionFunction( QStringLiteral( "bounds_height" ), 1, fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "is_closed" ), 1, fcnIsClosed, QStringLiteral( "GeometryGroup" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "convex_hull" ), 1, fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet(), false, QStringList() << QStringLiteral( "convexHull" ) ) + << new QgsStaticExpressionFunction( QStringLiteral( "oriented_bbox" ), QgsExpressionFunction::ParameterList() + << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), + fcnOrientedBBox, QStringLiteral( "GeometryGroup" ) ) + << new QgsStaticExpressionFunction( QStringLiteral( "minimal_circle" ), QgsExpressionFunction::ParameterList() + << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) + << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ), + fcnMinimalCircle, QStringLiteral( "GeometryGroup" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "difference" ), 2, fcnDifference, QStringLiteral( "GeometryGroup" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "distance" ), 2, fcnDistance, QStringLiteral( "GeometryGroup" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "hausdorff_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ) diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index b2d9db39654..32165d8fcec 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -2302,6 +2302,14 @@ class TestQgsExpression: public QObject geom = QgsGeometry::fromPolygon( polygon ); QTest::newRow( "bounds" ) << "bounds( $geometry )" << geom << false << true << QgsGeometry::fromRect( geom.boundingBox() ); + geom = QgsGeometry::fromPolygon( polygon ); + double bbox_area, bbox_angle, bbox_width, bbox_height; + QTest::newRow( "oriented_bbox" ) << "oriented_bbox( $geometry )" << geom << false << true << geom.orientedMinimumBoundingBox( bbox_area, bbox_angle, bbox_width, bbox_height ); + geom = QgsGeometry::fromPolygon( polygon ); + QgsPointXY circ_center; + double circ_radius; + QTest::newRow( "minimal_circle" ) << "minimal_circle( $geometry )" << geom << false << true << geom.minimalEnclosingCircle( circ_center, circ_radius ); + geom = QgsGeometry::fromPolygon( polygon ); QTest::newRow( "translate" ) << "translate( $geometry, 1, 2)" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "POLYGON ((1 2,11 12,11 2,1 2))" ) ); geom = QgsGeometry::fromPolyline( line );