Fixed #28960 -- Added GEOSGeometry.buffer_with_style().

This commit is contained in:
Stanislav Karpov 2018-01-09 19:15:04 +03:00 committed by Tim Graham
parent 2162f0983d
commit 6d794fb762
8 changed files with 91 additions and 10 deletions

View File

@ -752,6 +752,7 @@ answer newbie questions, and generally made Django that much better:
Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
Stanislas Guerra <stan@slashdev.me>
Stanislaus Madueke
Stanislav Karpov <work@stkrp.ru>
starrynight <cmorgh@gmail.com>
Stefane Fermgier <sf@fermigier.com>
Stefano Rivera <stefano@rivera.za.net>

View File

@ -499,6 +499,18 @@ class GEOSGeometryBase(GEOSBase):
"""
return self._topology(capi.geos_buffer(self.ptr, width, quadsegs))
def buffer_with_style(self, width, quadsegs=8, end_cap_style=1, join_style=1, mitre_limit=5.0):
"""
Same as buffer() but allows customizing the style of the buffer.
End cap style can be round (1), flat (2), or square (3).
Join style can be round (1), mitre (2), or bevel (3).
Mitre ratio limit only affects mitered join style.
"""
return self._topology(
capi.geos_bufferwithstyle(self.ptr, width, quadsegs, end_cap_style, join_style, mitre_limit),
)
@property
def centroid(self):
"""

View File

@ -21,6 +21,7 @@ class Topology(GEOSFuncFactory):
# Topology Routines
geos_boundary = Topology('GEOSBoundary')
geos_buffer = Topology('GEOSBuffer', argtypes=[GEOM_PTR, c_double, c_int])
geos_bufferwithstyle = Topology('GEOSBufferWithStyle', argtypes=[GEOM_PTR, c_double, c_int, c_int, c_int, c_double])
geos_centroid = Topology('GEOSGetCentroid')
geos_convexhull = Topology('GEOSConvexHull')
geos_difference = Topology('GEOSDifference', argtypes=[GEOM_PTR, GEOM_PTR])

View File

@ -496,6 +496,16 @@ Topological Methods
optional ``quadsegs`` keyword sets the number of segments used to
approximate a quarter circle (defaults is 8).
.. method:: GEOSGeometry.buffer_with_style(width, quadsegs=8, end_cap_style=1, join_style=1, mitre_limit=5.0)
.. versionadded:: 2.1
Same as :meth:`buffer`, but allows customizing the style of the buffer.
* ``end_cap_style`` can be round (``1``), flat (``2``), or square (``3``).
* ``join_style`` can be round (``1``), mitre (``2``), or bevel (``3``).
* Mitre ratio limit (``mitre_limit``) only affects mitered join style.
.. method:: GEOSGeometry.difference(other)
Returns a :class:`GEOSGeometry` representing the points making up this

View File

@ -70,7 +70,9 @@ Minor features
:mod:`django.contrib.gis`
~~~~~~~~~~~~~~~~~~~~~~~~~
* ...
* The new :meth:`.GEOSGeometry.buffer_with_style` method is a version of
:meth:`~.GEOSGeometry.buffer` that allows customizing the style of the
buffer.
:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -407,6 +407,7 @@ minified
minify
mis
misconfiguration
mitre
mixin
mixins
modelforms

View File

@ -78,6 +78,24 @@
"width": 2.0, "quadsegs": 8
}
],
"buffer_with_style_geoms": [
{"wkt": "POINT (0 0)",
"buffer_wkt": "POLYGON EMPTY",
"width": 5.0, "end_cap_style": 2, "join_style": 2
},
{"wkt": "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
"buffer_wkt": "POLYGON ((-2 -2, -2 12, 12 12, 12 -2, -2 -2))",
"width": 2.0, "end_cap_style": 2, "join_style": 2
},
{"wkt": "LINESTRING (0 0, 10 0)",
"buffer_wkt": "POLYGON ((10 2, 10 -2, 0 -2, 0 2, 10 2))",
"width": 2.0, "end_cap_style": 2, "join_style": 2
},
{"wkt": "LINESTRING (0 0, 10 0, 10 10, 0 10)",
"buffer_wkt": "POLYGON ((8 2, 8 8, 0 8, 0 12, 12 12, 12 -2, 0 -2, 0 2, 8 2))",
"width": 2.0, "end_cap_style": 2, "join_style": 2
}
],
"relate_geoms": [
{"wkt_a": "MULTIPOINT(80 70, 20 20, 200 170, 140 120)",
"wkt_b": "MULTIPOINT(80 170, 140 120, 200 80, 80 70)",

View File

@ -1,4 +1,5 @@
import ctypes
import itertools
import json
import pickle
import random
@ -650,21 +651,56 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertEqual(d1, a)
def test_buffer(self):
"Testing buffer()."
for bg in self.geometries.buffer_geoms:
bg = self.geometries.buffer_geoms[0]
g = fromstr(bg.wkt)
# Can't use a floating-point for the number of quadsegs.
with self.assertRaises(ctypes.ArgumentError):
g.buffer(bg.width, quadsegs=1.1)
self._test_buffer(self.geometries.buffer_geoms, 'buffer')
def test_buffer_with_style(self):
bg = self.geometries.buffer_with_style_geoms[0]
g = fromstr(bg.wkt)
# Can't use a floating-point for the number of quadsegs.
with self.assertRaises(ctypes.ArgumentError):
g.buffer_with_style(bg.width, quadsegs=1.1)
# Can't use a floating-point for the end cap style.
with self.assertRaises(ctypes.ArgumentError):
g.buffer_with_style(bg.width, end_cap_style=1.2)
# Can't use a end cap style that is not in the enum.
with self.assertRaises(GEOSException):
g.buffer_with_style(bg.width, end_cap_style=55)
# Can't use a floating-point for the join style.
with self.assertRaises(ctypes.ArgumentError):
g.buffer_with_style(bg.width, join_style=1.3)
# Can't use a join style that is not in the enum.
with self.assertRaises(GEOSException):
g.buffer_with_style(bg.width, join_style=66)
self._test_buffer(
itertools.chain(self.geometries.buffer_geoms, self.geometries.buffer_with_style_geoms),
'buffer_with_style',
)
def _test_buffer(self, geometries, buffer_method_name):
for bg in geometries:
g = fromstr(bg.wkt)
# The buffer we expect
exp_buf = fromstr(bg.buffer_wkt)
quadsegs = bg.quadsegs
width = bg.width
# Can't use a floating-point for the number of quadsegs.
with self.assertRaises(ctypes.ArgumentError):
g.buffer(width, float(quadsegs))
# Constructing our buffer
buf = g.buffer(width, quadsegs)
buf_kwargs = {
kwarg_name: getattr(bg, kwarg_name)
for kwarg_name in ('width', 'quadsegs', 'end_cap_style', 'join_style', 'mitre_limit')
if hasattr(bg, kwarg_name)
}
buf = getattr(g, buffer_method_name)(**buf_kwargs)
self.assertEqual(exp_buf.num_coords, buf.num_coords)
self.assertEqual(len(exp_buf), len(buf))