Expose control over buffer join, cap, miter limit to expression "buffer" function

This commit is contained in:
Nyall Dawson 2021-10-13 15:36:50 +10:00
parent ea699105cc
commit 54f77cee5a
3 changed files with 35 additions and 10 deletions

View File

@ -5,7 +5,10 @@
"description": "Returns a geometry that represents all points whose distance from this geometry is less than or equal to distance. Calculations are in the Spatial Reference System of this geometry.",
"arguments": [ {"arg":"geometry","description":"a geometry"},
{"arg":"distance","description":"buffer distance in layer units"},
{"arg":"segments","optional":true,"default":"8","description":"number of segments to use to represent a quarter circle when a round join style is used. A larger number results in a smoother buffer with more nodes."}],
{"arg":"segments","optional":true,"default":"8","description":"number of segments to use to represent a quarter circle when a round join style is used. A larger number results in a smoother buffer with more nodes."},
{"arg":"cap","optional":true,"default":"8","description":"end cap style for buffer. Valid values are 'round', 'flat' or 'square'"},
{"arg":"join","optional":true,"default":"'round'","description":"join style for buffer. Valid values are 'round', 'bevel' or 'miter'."},
{"arg":"miter_limit","optional":true,"default":"2","description":"miter distance limit, for use when the join style is set to 'miter'"}],
"examples": [ { "expression":"buffer($geometry, 10.5)", "returns":"polygon of the current feature's geometry buffered by 10.5 units"}]
}

View File

@ -3823,18 +3823,29 @@ static QVariant fcnWithin( const QVariantList &values, const QgsExpressionContex
QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
return fGeom.within( sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
if ( values.length() < 2 || values.length() > 3 )
return QVariant();
const QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
const double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
const int seg = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
const QString endCapString = QgsExpressionUtils::getStringValue( values.at( 3 ), parent ).trimmed();
const QString joinString = QgsExpressionUtils::getStringValue( values.at( 4 ), parent ).trimmed();
const double miterLimit = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
int seg = 8;
if ( values.length() == 3 )
seg = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
Qgis::EndCapStyle capStyle = Qgis::EndCapStyle::Round;
if ( endCapString.compare( QLatin1String( "flat" ), Qt::CaseInsensitive ) == 0 )
capStyle = Qgis::EndCapStyle::Flat;
else if ( endCapString.compare( QLatin1String( "square" ), Qt::CaseInsensitive ) == 0 )
capStyle = Qgis::EndCapStyle::Square;
QgsGeometry geom = fGeom.buffer( dist, seg );
Qgis::JoinStyle joinStyle = Qgis::JoinStyle::Round;
if ( joinString.compare( QLatin1String( "miter" ), Qt::CaseInsensitive ) == 0 )
joinStyle = Qgis::JoinStyle::Miter;
else if ( joinString.compare( QLatin1String( "bevel" ), Qt::CaseInsensitive ) == 0 )
joinStyle = Qgis::JoinStyle::Bevel;
QgsGeometry geom = fGeom.buffer( dist, seg, capStyle, joinStyle, miterLimit );
QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
return result;
}
@ -7025,7 +7036,10 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
fcnAffineTransform, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8 ),
<< QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8 )
<< QgsExpressionFunction::Parameter( QStringLiteral( "cap" ), true, QStringLiteral( "round" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QStringLiteral( "round" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2 ),
fcnBuffer, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnForceRHR, QStringLiteral( "GeometryGroup" ) )

View File

@ -3377,6 +3377,14 @@ class TestQgsExpression: public QObject
QTest::newRow( "buffer" ) << "buffer( $geometry, 1.0, 3)" << geom << false << true << geom.buffer( 1.0, 3 );
geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "buffer" ) << "buffer( $geometry, 2.0)" << geom << false << true << geom.buffer( 2.0, 8 );
geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "buffer flat cap" ) << "buffer( $geometry, 2.0, cap:='flat' )" << geom << false << true << geom.buffer( 2.0, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 );
geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "buffer square cap" ) << "buffer( $geometry, 2.0, cap:='SQUARE' )" << geom << false << true << geom.buffer( 2.0, 8, Qgis::EndCapStyle::Square, Qgis::JoinStyle::Round, 2 );
geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "buffer bevel join" ) << "buffer( $geometry, 2.0, join:='bevel' )" << geom << false << true << geom.buffer( 2.0, 8, Qgis::EndCapStyle::Round, Qgis::JoinStyle::Bevel, 2 );
geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "buffer miter join" ) << "buffer( $geometry, 2.0, join:='MITER', miter_limit:=5 )" << geom << false << true << geom.buffer( 2.0, 8, Qgis::EndCapStyle::Round, Qgis::JoinStyle::Miter, 5 );
QgsPointXY point1( 10, 20 );
QgsPointXY point2( 30, 20 );