Skip to content

Commit e047738

Browse files
committed
Add QgsGeometry method to create wedge shaped buffers
Creates a wedge shaped buffer using circular strings, with parameters for azimuth, wedge width (in degrees), outer radius and inner radius.
1 parent 9a6d966 commit e047738

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

python/core/geometry/qgsgeometry.sip.in

+18
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,24 @@ Creates a new geometry from a :py:class:`QgsRectangle`
211211
Creates a new multipart geometry from a list of QgsGeometry objects
212212
%End
213213

214+
static QgsGeometry createWedgeBuffer( const QgsPoint &center, double azimuth, double angularWidth,
215+
double outerRadius, double innerRadius = 0 );
216+
%Docstring
217+
Creates a wedge shaped buffer from a ``center`` point.
218+
219+
The ``azimuth`` gives the angle (in degrees) for the middle of the wedge to point.
220+
The buffer width (in degrees) is specified by the ``angularWidth`` parameter. Note that the
221+
wedge will extend to half of the ``angularWidth`` either side of the ``azimuth`` direction.
222+
223+
The outer radius of the buffer is specified via ``outerRadius``, and optionally an
224+
``innerRadius`` can also be specified.
225+
226+
The returned geometry will be a CurvePolygon geometry containing circular strings. It may
227+
need to be segmentized to convert to a standard Polygon geometry.
228+
229+
.. versionadded:: 3.2
230+
%End
231+
214232

215233

216234
void fromWkb( const QByteArray &wkb );

src/core/geometry/qgsgeometry.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,39 @@ QgsGeometry QgsGeometry::collectGeometry( const QVector< QgsGeometry > &geometri
258258
return collected;
259259
}
260260

261+
QgsGeometry QgsGeometry::createWedgeBuffer( const QgsPoint &center, const double azimuth, const double angularWidth, const double outerRadius, const double innerRadius )
262+
{
263+
std::unique_ptr< QgsCompoundCurve > wedge = qgis::make_unique< QgsCompoundCurve >();
264+
265+
const double startAngle = azimuth - angularWidth * 0.5;
266+
const double endAngle = azimuth + angularWidth * 0.5;
267+
268+
const QgsPoint outerP1 = center.project( outerRadius, startAngle );
269+
const QgsPoint outerP2 = center.project( outerRadius, endAngle );
270+
271+
const bool useShortestArc = angularWidth <= 180.0;
272+
273+
wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( outerP1, outerP2, center, useShortestArc ) ) );
274+
275+
if ( !qgsDoubleNear( innerRadius, 0.0 ) && innerRadius > 0 )
276+
{
277+
const QgsPoint innerP1 = center.project( innerRadius, startAngle );
278+
const QgsPoint innerP2 = center.project( innerRadius, endAngle );
279+
wedge->addCurve( new QgsLineString( outerP2, innerP2 ) );
280+
wedge->addCurve( new QgsCircularString( QgsCircularString::fromTwoPointsAndCenter( innerP2, innerP1, center, useShortestArc ) ) );
281+
wedge->addCurve( new QgsLineString( innerP1, outerP1 ) );
282+
}
283+
else
284+
{
285+
wedge->addCurve( new QgsLineString( outerP2, center ) );
286+
wedge->addCurve( new QgsLineString( center, outerP1 ) );
287+
}
288+
289+
std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
290+
cp->setExteriorRing( wedge.release() );
291+
return QgsGeometry( std::move( cp ) );
292+
}
293+
261294
void QgsGeometry::fromWkb( unsigned char *wkb, int length )
262295
{
263296
QgsConstWkbPtr ptr( wkb, length );

src/core/geometry/qgsgeometry.h

+18
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,24 @@ class CORE_EXPORT QgsGeometry
256256
//! Creates a new multipart geometry from a list of QgsGeometry objects
257257
static QgsGeometry collectGeometry( const QVector<QgsGeometry> &geometries );
258258

259+
/**
260+
* Creates a wedge shaped buffer from a \a center point.
261+
*
262+
* The \a azimuth gives the angle (in degrees) for the middle of the wedge to point.
263+
* The buffer width (in degrees) is specified by the \a angularWidth parameter. Note that the
264+
* wedge will extend to half of the \a angularWidth either side of the \a azimuth direction.
265+
*
266+
* The outer radius of the buffer is specified via \a outerRadius, and optionally an
267+
* \a innerRadius can also be specified.
268+
*
269+
* The returned geometry will be a CurvePolygon geometry containing circular strings. It may
270+
* need to be segmentized to convert to a standard Polygon geometry.
271+
*
272+
* \since QGIS 3.2
273+
*/
274+
static QgsGeometry createWedgeBuffer( const QgsPoint &center, double azimuth, double angularWidth,
275+
double outerRadius, double innerRadius = 0 );
276+
259277
/**
260278
* Set the geometry, feeding in a geometry in GEOS format.
261279
* This class will take ownership of the buffer.

tests/src/python/test_qgsgeometry.py

+29
Original file line numberDiff line numberDiff line change
@@ -4356,6 +4356,35 @@ def testClipped(self):
43564356
self.assertTrue(compareWkt(result, exp, 0.00001),
43574357
"clipped: mismatch Expected:\n{}\nGot:\n{}\n".format(exp, result))
43584358

4359+
def testCreateWedgeBuffer(self):
4360+
tests = [[QgsPoint(1, 11), 0, 45, 2, 0, 'CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1 11),(1 11, 0.23463313526982044 12.84775906502257392)))'],
4361+
[QgsPoint(1, 11), 90, 45, 2, 0,
4362+
'CurvePolygon (CompoundCurve (CircularString (2.84775906502257348 11.76536686473017923, 3 11, 2.84775906502257348 10.23463313526982077),(2.84775906502257348 10.23463313526982077, 1 11),(1 11, 2.84775906502257348 11.76536686473017923)))'],
4363+
[QgsPoint(1, 11), 180, 90, 2, 0,
4364+
'CurvePolygon (CompoundCurve (CircularString (2.41421356237309492 9.58578643762690419, 1.00000000000000022 9, -0.41421356237309492 9.58578643762690419),(-0.41421356237309492 9.58578643762690419, 1 11),(1 11, 2.41421356237309492 9.58578643762690419)))'],
4365+
[QgsPoint(1, 11), 0, 200, 2, 0,
4366+
'CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1 11),(1 11, -0.96961550602441604 10.65270364466613984)))'],
4367+
[QgsPoint(1, 11), 0, 45, 2, 1,
4368+
'CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1.38268343236508984 11.92387953251128607),CircularString (1.38268343236508984 11.92387953251128607, 0.99999999999999978 12, 0.61731656763491016 11.92387953251128607),(0.61731656763491016 11.92387953251128607, 0.23463313526982044 12.84775906502257392)))'],
4369+
[QgsPoint(1, 11), 0, 200, 2, 1,
4370+
'CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1.98480775301220813 10.82635182233306992),CircularString (1.98480775301220813 10.82635182233306992, 0.99999999999999978 12, 0.01519224698779198 10.82635182233306992),(0.01519224698779198 10.82635182233306992, -0.96961550602441604 10.65270364466613984)))'],
4371+
[QgsPoint(1, 11, 3), 0, 45, 2, 0,
4372+
'CurvePolygonZ (CompoundCurveZ (CircularStringZ (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))'],
4373+
[QgsPoint(1, 11, m=3), 0, 45, 2, 0,
4374+
'CurvePolygonM (CompoundCurveM (CircularStringM (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))']
4375+
]
4376+
for t in tests:
4377+
input = t[0]
4378+
azimuth = t[1]
4379+
width = t[2]
4380+
outer = t[3]
4381+
inner = t[4]
4382+
o = QgsGeometry.createWedgeBuffer(input, azimuth, width, outer, inner)
4383+
exp = t[5]
4384+
result = o.asWkt()
4385+
self.assertTrue(compareWkt(result, exp, 0.01),
4386+
"wedge buffer: mismatch Expected:\n{}\nGot:\n{}\n".format(exp, result))
4387+
43594388
def testHausdorff(self):
43604389
tests = [["POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))", "POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))", 0.707106781186548],
43614390
["LINESTRING (0 0, 2 1)", "LINESTRING (0 0, 2 0)", 1],

0 commit comments

Comments
 (0)