Skip to content

GEOS Buffer

What is GEOS buffer?

The GEOS buffer function creates a new geometry that represents all points within a specified distance of the input geometry. This is useful for creating zones of influence, safety margins, or areas of interest around geometric features.

For example, creating a buffer around a point:

julia
import GeometryOps as GO
import GeoInterface as GI
using Makie
using CairoMakie

# Create a point and buffer it
point = GI.Point(0, 0)
buffered = GO.buffer(GO.GEOS(), point, 1.0)  # 1 unit buffer
GeoInterface.Wrappers.Polygon{false, false}(POLYGON ((1 0, 0.9807852804032304 -0.1950903220161282, 0.9238795325112867 -0.3826834323650898, 0.8314696123025452 -0.5555702330196022, 0.7071067811865476 -0.7071067811865475, 0.5555702330196023 -0.8314696123025452, 0.3826834323650898 -0.9238795325112867, 0.1950903220161283 -0.9807852804032304, 0 -1, -0.1950903220161282 -0.9807852804032304, -0.3826834323650897 -0.9238795325112867, -0.555570233019602 -0.8314696123025455, -0.7071067811865475 -0.7071067811865476, -0.8314696123025453 -0.5555702330196022, -0.9238795325112867 -0.3826834323650899, -0.9807852804032304 -0.1950903220161286, -1 0, -0.9807852804032304 0.1950903220161284, -0.9238795325112868 0.3826834323650897, -0.8314696123025455 0.555570233019602, -0.7071067811865477 0.7071067811865475, -0.5555702330196022 0.8314696123025452, -0.3826834323650903 0.9238795325112865, -0.1950903220161287 0.9807852804032303, 0 1, 0.1950903220161283 0.9807852804032304, 0.38268343236509 0.9238795325112866, 0.5555702330196018 0.8314696123025455, 0.7071067811865474 0.7071067811865477, 0.8314696123025452 0.5555702330196022, 0.9238795325112865 0.3826834323650904, 0.9807852804032303 0.1950903220161287, 1 0)))

Implementation

The implementation uses GEOS's bufferWithStyle function through LibGEOS.jl. It supports various buffer styles:

  • Cap styles: round, flat, square

  • Join styles: round, mitre, bevel

  • Mitre limit for sharp corners

Key features:

  • Configurable number of segments for curved parts (quadsegs)

  • Support for different end cap styles

  • Customizable join styles for corners

  • Adjustable mitre limit for sharp angles

  • Preserves CRS information

  • Works with any GeoInterface-compatible geometry

The function handles the conversion between GeometryOps and GEOS geometries automatically, and wraps the result back in a GeoInterface-compatible format.

julia
const _GEOS_CAPSTYLE_LOOKUP = Dict{Symbol, LG.GEOSBufCapStyles}(
    :round => LG.GEOSBUF_CAP_ROUND,
    :flat => LG.GEOSBUF_CAP_FLAT,
    :square => LG.GEOSBUF_CAP_SQUARE,
)

const _GEOS_JOINSTYLE_LOOKUP = Dict{Symbol, LG.GEOSBufJoinStyles}(
    :round => LG.GEOSBUF_JOIN_ROUND,
    :mitre => LG.GEOSBUF_JOIN_MITRE,
    :bevel => LG.GEOSBUF_JOIN_BEVEL,
)

to_cap_style(style::Symbol) = _GEOS_CAPSTYLE_LOOKUP[style]
to_cap_style(style::LG.GEOSBufCapStyles) = style
to_cap_style(num::Integer) = num

to_join_style(style::Symbol) = _GEOS_JOINSTYLE_LOOKUP[style]
to_join_style(style::LG.GEOSBufJoinStyles) = style
to_join_style(num::Integer) = num

function GO.buffer(alg::GEOS, geometry, distance; calc_extent = true, kwargs...)

The reason we use apply here is so that this also works with featurecollections, tables, vectors of geometries, etc!

julia
    return apply(TraitTarget{GI.AbstractGeometryTrait}(), geometry; kwargs...) do geom
        newgeom = LG.bufferWithStyle(
            GI.convert(LG, geom), distance;
            quadsegs = get(alg, :quadsegs, 8),
            endCapStyle = to_cap_style(get(alg, :endCapStyle, :round)),
            joinStyle = to_join_style(get(alg, :joinStyle, :round)),
            mitreLimit = get(alg, :mitreLimit, 5.0),
        )
        return _wrap(newgeom; crs = GI.crs(geom), calc_extent)
    end
end

This page was generated using Literate.jl.