Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geodesic buffering in python

Given land polygons as a Shapely MultiPolygon, I want to find the (Multi-)Polygon that represents the e.g. 12 nautical mile buffer around the coastlines.

Using the Shapely buffer method does not work since it uses euclidean calculations.

Can somebody tell me how to calculate geodesic buffers in python?

like image 809
ARF Avatar asked Apr 04 '16 09:04

ARF


People also ask

What is a geodesic buffer?

Geodesic buffers account for the earth's actual shape in the calculation of the buffers. The earth is an ellipsoid (or, more properly, a geoid), and when the Buffer tool generates geodesic buffers, distances are measured between two points on a globe.

What is the difference between a geodesic buffer and a Cartesian or Euclidean buffer?

Geodesic buffers were generated by buffering a point feature class with a geographic coordinate system, and Euclidean buffers were generated by buffering a point feature class with a projected coordinate system (in both the projected and unprojected datasets the points represent the same cities).

What is a buffer used for in GIS?

You can use the Buffer tool to identify or define an area within a specified distance around a feature. For example, you may create a buffer to define an area around a river to identify land that can't be developed, or you may want to create a buffer to select features within a specified distance of a feature.


1 Answers

This is not a shapely problem, since shapely explicitly tells in its documentation that the library is for planar computation only. Nevertheless, in order to answer your question, you should specify the coordinate systems you are using for your multipolygons. Assuming you are using WGS84 projection (lat,lon), this is a recipe I found in another SO question (fix-up-shapely-polygon-object-when-discontinuous-after-map-projection). You will need pyproj library.

import pyproj
from shapely.geometry import MultiPolygon, Polygon
from shapely.ops import transform as sh_transform
from functools import partial

wgs84_globe = pyproj.Proj(proj='latlong', ellps='WGS84')

def pol_buff_on_globe(pol, radius):
    _lon, _lat = pol.centroid.coords[0]
    aeqd = pyproj.Proj(proj='aeqd', ellps='WGS84', datum='WGS84',
                       lat_0=_lat, lon_0=_lon)
    project_pol = sh_transform(partial(pyproj.transform, wgs84_globe, aeqd), pol)
    return sh_transform( partial(pyproj.transform, aeqd, wgs84_globe),
                          project_pol.buffer(radius))

def multipol_buff_on_globe(multipol, radius):
    return MultiPolygon([pol_buff_on_globe(g, radius) for g in multipol])

pol_buff_on_globe function does the following. First, build an azimuthal equidistant projection centered in the polygon centroid. Then, change the coordinate system of the polygon to that projection. After that, builds the buffer there, and then change the coordinate system of the buffered polygon to WGS84 coordinate system.

Some special care is needed:

  • You will need to find out how to translate the distance you want to the distance used in aeqd projection.
  • Be careful of not buffering including the poles (see the mentioned SO question).
  • The fact that we are using the centroid of the polygon to center the projection should guaranty the answer is good enough, but if you have specif precision requirements you should NOT USE this solution, or at least make a characterization of the error for the typical polygon you are using.
like image 198
eguaio Avatar answered Sep 18 '22 16:09

eguaio