Skip to content

Instantly share code, notes, and snippets.

@stkrp
Last active January 10, 2018 17:36
Show Gist options
  • Save stkrp/468610f7be70be2d01adccb79ecccd6e to your computer and use it in GitHub Desktop.
Save stkrp/468610f7be70be2d01adccb79ecccd6e to your computer and use it in GitHub Desktop.
Portable version of `django.contrib.gis.geos.geometry.GEOSGeometryBase.buffer_with_style()`
'''
https://code.djangoproject.com/ticket/28960
For Python 2.x you need to delete the annotations and related imports.
'''
from ctypes import c_double, c_int
from django.contrib.gis.geos.libgeos import GEOM_PTR
from django.contrib.gis.geos.prototypes.topology import Topology
from django.contrib.gis.geos.geometry import GEOSGeometry
# https://github.com/OSGeo/geos/blob/master/capi/geos_c.h.in#L1442
# > extern GEOSGeometry GEOS_DLL *GEOSBufferWithStyle(const GEOSGeometry* g,
# > double width, int quadsegs, int endCapStyle, int joinStyle,
# > double mitreLimit);
geos_bufferwithstyle = Topology(
'GEOSBufferWithStyle',
argtypes=[GEOM_PTR, c_double, c_int, c_int, c_int, c_double],
)
# https://github.com/OSGeo/geos/blob/master/include/geos/operation/buffer/BufferParameters.h#L57
BUFFER_CAP_ROUND = 1
BUFFER_CAP_FLAT = 2
BUFFER_CAP_SQUARE = 3
BUFFER_JOIN_ROUND = 1
BUFFER_JOIN_MITRE = 2
BUFFER_JOIN_BEVEL = 3
def buffer_with_style(
geometry: GEOSGeometry,
width: float,
quadsegs: int = 8,
end_cap_style: int = BUFFER_CAP_ROUND,
join_style: int = BUFFER_JOIN_ROUND,
mitre_limit: float = 5.0,
) -> GEOSGeometry:
"""
Advanced version of the `geometry.buffer()`. Does the same, but allows to
customize the styles of the final value.
End cap style can be round (1), flat (2) or square (3). Default is round.
Join style can be round (1), mitre (2) or bevel (3). Default is round.
Mitre ratio limit only affects mitered join style. Default is 5.0.
More about styles: http://www.postgis.net/docs/ST_Buffer.html
"""
return geometry._topology(geos_bufferwithstyle(
geometry.ptr, width, quadsegs, end_cap_style, join_style, mitre_limit,
))
# ========================================================================== #
# ==== DEMO ================================================================ #
# ========================================================================== #
# Delete it before use in production
if __name__ == '__main__':
from django.contrib.gis.geos import LineString
from geos_buffer_with_style import buffer_with_style, BUFFER_CAP_FLAT, BUFFER_JOIN_MITRE
line = LineString((5, 5), (8, 16))
rectangle = buffer_with_style(line, 1.5, end_cap_flat=BUFFER_CAP_FLAT, join_style=BUFFER_JOIN_MITRE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment