summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Karpov <stkrp@yandex.ru>2018-01-09 19:15:04 +0300
committerTim Graham <timograham@gmail.com>2018-02-10 19:45:58 -0500
commit6d794fb76212bb8a62fe2cd97cff173054e1c626 (patch)
treea947f691b5c831f64b2759a46100c7e046df88dd
parent2162f0983de0dfe2178531638ce7ea56f54dd4e7 (diff)
Fixed #28960 -- Added GEOSGeometry.buffer_with_style().
-rw-r--r--AUTHORS1
-rw-r--r--django/contrib/gis/geos/geometry.py12
-rw-r--r--django/contrib/gis/geos/prototypes/topology.py1
-rw-r--r--docs/ref/contrib/gis/geos.txt10
-rw-r--r--docs/releases/2.1.txt4
-rw-r--r--docs/spelling_wordlist1
-rw-r--r--tests/gis_tests/data/geometries.json18
-rw-r--r--tests/gis_tests/geos_tests/test_geos.py54
8 files changed, 91 insertions, 10 deletions
diff --git a/AUTHORS b/AUTHORS
index 58df5eacbf..fb32b97887 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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>
diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py
index 1ebecc864b..80770dfa6b 100644
--- a/django/contrib/gis/geos/geometry.py
+++ b/django/contrib/gis/geos/geometry.py
@@ -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):
"""
diff --git a/django/contrib/gis/geos/prototypes/topology.py b/django/contrib/gis/geos/prototypes/topology.py
index f8c36bc6f5..9ca0dce695 100644
--- a/django/contrib/gis/geos/prototypes/topology.py
+++ b/django/contrib/gis/geos/prototypes/topology.py
@@ -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])
diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt
index 6334f76598..e79e621239 100644
--- a/docs/ref/contrib/gis/geos.txt
+++ b/docs/ref/contrib/gis/geos.txt
@@ -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
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index 31252432bb..33d6982443 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 4d5c9a508f..57b999bacb 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -407,6 +407,7 @@ minified
minify
mis
misconfiguration
+mitre
mixin
mixins
modelforms
diff --git a/tests/gis_tests/data/geometries.json b/tests/gis_tests/data/geometries.json
index b8b1c3eab3..7786f26e9b 100644
--- a/tests/gis_tests/data/geometries.json
+++ b/tests/gis_tests/data/geometries.json
@@ -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)",
diff --git a/tests/gis_tests/geos_tests/test_geos.py b/tests/gis_tests/geos_tests/test_geos.py
index 7488acbb3e..5f8d1c84b1 100644
--- a/tests/gis_tests/geos_tests/test_geos.py
+++ b/tests/gis_tests/geos_tests/test_geos.py
@@ -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))