turf icon indicating copy to clipboard operation
turf copied to clipboard

Self-intersection linestring's buffer is not exactly?

Open wtusmchen opened this issue 4 years ago • 1 comments

Please provide the following when reporting an issue:

turf 6.3.0 let buffered = turf.buffer(fea, 100, {units:'kilometers'});

0001

  • [ ] The version of Turf you are using, and any other relevant versions.
  • [ ] GeoJSON data as a gist file or geojson.io (filename extension must be .geojson).
  • [ ] Snippet of source code or for complex examples use jsfiddle.

wtusmchen avatar Apr 26 '21 02:04 wtusmchen

Hey @wtusmchen,

TLDR; use one of the solutions outlined in this notebook https://observablehq.com/@chrispahm/turf-issue-2075

I'm just guessing here, but since Turf >v.6.2.0, GeoJSON input objects are projected into Azimuthal Equidistant projection instead of Transverse Mercator which has been used in previous versions < 5.1.6 (see #1956). While this fixes a number of issues related to the buffer operation (e.g. #1246, #1470, #1484, #1547), it may be responsible for the somewhat unexpected result you're seeing.

It looks as if the intersection of the west-east facing line and the south-north facing line in your example are internally corrected for their actual geodesic position (see the mapbox-gl-draw-plugin-geodesic to draw geodesic lines) image Wich explains why the buffer intersection is further north than where it would be expected given the straight line.

This theory is (somewhat) confirmed by the fact that if you move your shape towards the equator, it's following the straight line accordingly image

Anyways, there are (at least) four possible solutions for your problem:

  1. You can add a point to your lineString at the intersection of the east-west/south-north line prior to applying the buffer operation
  2. You can apply the buffer operation for each segment of the lineString, and concatenate the lineStrings to a single one using turf.union
const arrayOfLineStrings = turf.segmentReduce(data[ls], (buffers, currentSegment, i) => {
    const segmentBuffer = turf.buffer(currentSegment, 100);
    buffers.push(segmentBuffer);
    return buffers;
  }, [])

const linestringBuffer = arrayOfLineStrings.reduce((u, c) => turf.union(u, c), arrayOfLineStrings[0])
  1. You may want to display your lineString using a software/service that supports geodesic lines (e.g. mapbox-gl-draw-plugin-geodesic)
  2. You can downgrade to Turf <v.5.1.6, which does not incorporate the fixes mentioned above. Note that in this case the size of your buffer will not be truly equal to 100km (or whichever size you need).

Hope this helps!

chrispahm avatar Oct 21 '21 13:10 chrispahm