[GIS] Turf.js buffer distance not accurate

bufferopenlayersturf

I'm facing a strange behavior using buffers in Turf.js.

When trying to do a 50m buffer around a point, the result is actually closer to 35m.

On the screenshot below, the smaller circle is a turf.buffer() and the bigger one is a turf.circle() using the same radius/distance. This second one is correct.

enter image description here

Here's my code :

var map = new ol.Map({
   target: 'map',
   layers: [
     new ol.layer.Tile({
       source: new ol.source.OSM()
     })
   ],
   view: new ol.View({
     center: ol.proj.transform([5, 45], 'EPSG:4326', 'EPSG:3857'),
     zoom: 17
   })
});

var distance = 50

var center = turf.point([5, 45])

var bufferedWgs84 = turf.buffer(center, distance/1000, {units: 'kilometers'});

var circleWgs84 = turf.circle(center, distance/1000, {units: 'kilometers'});

var buffer = turf.toMercator(bufferedWgs84)

var circle = turf.toMercator(circleWgs84)

var layer = new ol.layer.Vector({ 
                source: new ol.source.Vector(),
        style: new ol.style.Style({
                fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 0)'
                }),
                stroke: new ol.style.Stroke({
                color: '#737373',
                width: 2
                })
            })
            });
map.addLayer(layer);
layer.getSource().addFeature(new ol.format.GeoJSON().readFeature(buffer))
layer.getSource().addFeature(new ol.format.GeoJSON().readFeature(circle))

Fiddle : https://jsfiddle.net/fhkgzd2o/1/

Best Answer

Simple experiment show it's really question of projection. If you take coordinate [0, 0] as center of the circle and buffer, they match. If you calculate factor for diameter difference betwee buffer and circle at 45° of latitude, you get approximately 1.41, whch is exactly the value of Mercator projection length factor 1/Math.cos(latitude*Math.PI/180).

This tells that turf.circle has real diameter and turf.buffer method somehow behaves as having diameter at latitude 0° in projected CRS. To get the same result as with turf.circle method, diameter has to be multiplied with Mercator projection length factor.

EDIT (July 2022):
This problem was present with turf.js version 5.1.6. It is corrected now with version 6.5.0.