Add methods to directly buffer/offset GEOS geometry in QgsGeos

These methods directly work with GEOS geometries and avoid the
forced conversions to/from QgsAbstractGeometry objects, and are
intended for use in chained operations where the intermediate conversions
are not required.
This commit is contained in:
Nyall Dawson 2025-02-12 13:26:59 +10:00
parent 8f4893d8b2
commit a48ec1012f
4 changed files with 45 additions and 8 deletions

View File

@ -106,6 +106,8 @@ Curved geometries are not supported.
virtual QgsAbstractGeometry *buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = 0 ) const;
virtual QgsAbstractGeometry *simplify( double tolerance, QString *errorMsg = 0 ) const;
virtual QgsAbstractGeometry *interpolate( double distance, QString *errorMsg = 0 ) const;
@ -287,6 +289,7 @@ This method requires a QGIS build based on GEOS 3.7 or later.
QgsPointSequence &topologyTestPoints,
QString *errorMsg = 0, bool skipIntersectionCheck = false ) const;
virtual QgsAbstractGeometry *offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = 0 ) const;

View File

@ -106,6 +106,8 @@ Curved geometries are not supported.
virtual QgsAbstractGeometry *buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = 0 ) const;
virtual QgsAbstractGeometry *simplify( double tolerance, QString *errorMsg = 0 ) const;
virtual QgsAbstractGeometry *interpolate( double distance, QString *errorMsg = 0 ) const;
@ -287,6 +289,7 @@ This method requires a QGIS build based on GEOS 3.7 or later.
QgsPointSequence &topologyTestPoints,
QString *errorMsg = 0, bool skipIntersectionCheck = false ) const;
virtual QgsAbstractGeometry *offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = 0 ) const;

View File

@ -2094,7 +2094,13 @@ QgsAbstractGeometry *QgsGeos::buffer( double distance, int segments, QString *er
QgsAbstractGeometry *QgsGeos::buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg ) const
{
if ( !mGeos )
geos::unique_ptr geos = buffer( mGeos.get(), distance, segments, endCapStyle, joinStyle, miterLimit, errorMsg );
return fromGeos( geos.get() ).release();
}
geos::unique_ptr QgsGeos::buffer( const GEOSGeometry *geometry, double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg )
{
if ( !geometry )
{
return nullptr;
}
@ -2102,10 +2108,10 @@ QgsAbstractGeometry *QgsGeos::buffer( double distance, int segments, Qgis::EndCa
geos::unique_ptr geos;
try
{
geos.reset( GEOSBufferWithStyle_r( QgsGeosContext::get(), mGeos.get(), distance, segments, static_cast< int >( endCapStyle ), static_cast< int >( joinStyle ), miterLimit ) );
geos.reset( GEOSBufferWithStyle_r( QgsGeosContext::get(), geometry, distance, segments, static_cast< int >( endCapStyle ), static_cast< int >( joinStyle ), miterLimit ) );
}
CATCH_GEOS_WITH_ERRMSG( nullptr )
return fromGeos( geos.get() ).release();
return geos;
}
QgsAbstractGeometry *QgsGeos::simplify( double tolerance, QString *errorMsg ) const
@ -2743,9 +2749,9 @@ geos::unique_ptr QgsGeos::createGeosPolygon( const QgsAbstractGeometry *poly, do
return geosPolygon;
}
QgsAbstractGeometry *QgsGeos::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg ) const
geos::unique_ptr QgsGeos::offsetCurve( const GEOSGeometry *geometry, double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg )
{
if ( !mGeos )
if ( !geometry )
return nullptr;
geos::unique_ptr offset;
@ -2755,11 +2761,19 @@ QgsAbstractGeometry *QgsGeos::offsetCurve( double distance, int segments, Qgis::
// https://github.com/qgis/QGIS/issues/53165#issuecomment-1563470832
if ( segments < 8 )
segments = 8;
offset.reset( GEOSOffsetCurve_r( QgsGeosContext::get(), mGeos.get(), distance, segments, static_cast< int >( joinStyle ), miterLimit ) );
offset.reset( GEOSOffsetCurve_r( QgsGeosContext::get(), geometry, distance, segments, static_cast< int >( joinStyle ), miterLimit ) );
}
CATCH_GEOS_WITH_ERRMSG( nullptr )
std::unique_ptr< QgsAbstractGeometry > offsetGeom = fromGeos( offset.get() );
return offsetGeom.release();
return offset;
}
QgsAbstractGeometry *QgsGeos::offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg ) const
{
geos::unique_ptr res = offsetCurve( mGeos.get(), distance, segments, joinStyle, miterLimit, errorMsg );
if ( !res )
return nullptr;
return fromGeos( res.get() ).release();
}
std::unique_ptr<QgsAbstractGeometry> QgsGeos::singleSidedBuffer( double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg ) const

View File

@ -226,6 +226,15 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
QgsAbstractGeometry *symDifference( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr, const QgsGeometryParameters &parameters = QgsGeometryParameters() ) const override;
QgsAbstractGeometry *buffer( double distance, int segments, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *buffer( double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = nullptr ) const override;
/**
* Directly calculates the buffer for a GEOS geometry object and returns a GEOS geometry result.
*
* \note Not available in Python bindings
* \since QGIS 3.42
*/
SIP_SKIP static geos::unique_ptr buffer( const GEOSGeometry *geometry, double distance, int segments, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = nullptr );
QgsAbstractGeometry *simplify( double tolerance, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *interpolate( double distance, QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *envelope( QString *errorMsg = nullptr ) const override;
@ -380,6 +389,14 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
QgsPointSequence &topologyTestPoints,
QString *errorMsg = nullptr, bool skipIntersectionCheck = false ) const override;
/**
* Directly calculates the offset curve for a GEOS geometry object and returns a GEOS geometry result.
*
* \note Not available in Python bindings
* \since QGIS 3.42
*/
SIP_SKIP static geos::unique_ptr offsetCurve( const GEOSGeometry *geometry, double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = nullptr );
QgsAbstractGeometry *offsetCurve( double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg = nullptr ) const override;
/**