Turfjs / turf

A modular geospatial engine written in JavaScript and TypeScript
https://turfjs.org/
MIT License
9.22k stars 935 forks source link

Testing turf.buffer accuracy #1246

Open SteveCline opened 6 years ago

SteveCline commented 6 years ago

I am getting a rather large difference comparing turf.buffer to the result of a buffer generated in GIS software. The GIS buffer was projected in MD state plane, then queried to a geoJson feature using SR 4326 via esri's REST api. Using a leaflet measure tool to ground truth, the GIS buffer was accurate. Does anyone have a good explanation?

var point = turf.point([-76.675801, 38.935749]);
var buffered = turf.buffer(point, 10, {units: 'miles'});

turf

rowanwins commented 6 years ago

Hi @SteveCline

I've just run the operation and opened the result in QGIS, the width measured in QGIS comes in at 20 miles as expected however the height comes in around 15miles.

Under the hood turf/buffer projects input geometries to a transverse mercator projection, I suspect this is the cause of the discrepancy between the results you're getting. It's not documented that it's happening and I wonder if we'd be better off providing an option allowing people to pass in a chosen projection?

Projections are one of those complicated things and Turf generally tries to avoid providing options around them to users, we generally go for a 'just works as expected' philosophy, although buffering is one are in particular where I think we could perhaps provide some more options for educated users.

Hope that helps explain things Cheers Rowan

SteveCline commented 6 years ago

Thanks @rowanwins

I think passing a spatial reference code as an option would be very helpful for the buffer and probably some other methods too. I would argue, if turf's philosophy is to 'just work as expected', using proper spatial reference is vitally important to that expectation of working.

Mid latitude buffers will be off by 25% and running turf.circle will give a more accurate result in these parts of the globe.

If turf has the goal of being the geoprocessing engine of the future, which I hope it does, it can't have inaccuracies this large and be used in serious GIS applications. Thanks again for your help and good work with Turf!

rowanwins commented 6 years ago

No worries @SteveCline - we'll have a think about the best way we can expose that functionality.

Re your comment: I'm not sure Turf necessarily aims to be the "geoprocessing engine of the future" (although it's a great slogan - someone should adopt that!). One of the challenges is with Turf is that we don't really have the benefits that you can get with more complete geoprocessing engines like JTS which gets to leverage things like geometry classes. We deal with geojson in and geojson out which puts in place a bunch of limitations. For example we try and leverage spatial indexing where it makes sense for particular operations but we can't easily bake it into featurecollections because we don't know if people will tamper with those feature collections etc.

That said I do wonder if we could develop a geojson-like powered library that had things like geometry classes and observers in place, eg if a geometry is changed then the bounding box is nulled. You could keep a geojson-like structure but make it smarter.... but that's just me dreaming and won't happen unless someone invested some $$$ in Turf unfortunately :(

Anyway dreaming aside we still want Turf to be a super-awesome piece of kit that people can pick up and use. It'll probably never compete with things like PostGIS for some operations but hopefully it has that sweet-spot of performant enough operations in the browser without the need for DB's and network calls etc,

craiggoldstone commented 6 years ago

I've also encountered this problem where buffers are created too small by about 15%. I guess we will just use JSTS directly until there's a solution with Turf. I think it should at least be documented that this occurs because of reprojection!

image

ruben-grossmann commented 6 years ago

I'm having the same Problem. I created a 30 meters buffer in PostGIS (yellow) and the same buffer in turf (blue).

image

jo-me commented 6 years ago

Hi, I'm also in the same boat. As far as I understand from this thread turf buffers in general are very inaccurate and therefore basically unusable.

A couple of questions:

Thanks

ZacLiveEarth commented 6 years ago

Taking a look at the buffer code, it appears there is also a bug where Mercator instead of TransverseMercator is incorrectly chosen when the polygon is near the south pole.

See line 100 of turf-buffer/index.js - var needsTransverseMercator = bbox[1] > 50 && bbox[3] > 50;

I think this should read var needsTransverseMercator = (bbox[1] > 50 && bbox[3] > 50) || (bbox[1] < -50 && bbox[3] < -50); (I don't write Javascript and don't use TurfJS - so please double-check that code)

I'm posting this here instead of as a separate issue because it may be exaggerating some of the inaccuracies being seen here, and also because hopefully the actual code that this replaces may fix this bug along the way.

rowanwins commented 6 years ago

Thanks for the comment @ZacLiveEarth , I think you've correctly identified a bug there although I suspect that's only having an impact on a few occassions and we're in need a broader overhaul.

Doing a bit of googling as to how other libraries are tackling this

PostGIS from here

It first determines the best SRID that fits the bounding box of the geography object (favoring UTM, Lambert Azimuthal Equal Area (LAEA) north/south pole, and falling back on mercator in worst case scenario) and then buffers in that planar spatial ref and retransforms back to WGS84 geography.

ArcMap Some useful info here

Will try and do some more hunting

beaero commented 2 years ago

One thing which i tried and helped is calculate buffer, find the inaccuracy and rebuffer with a factor of that inaccuracy. e.g if i try line.offset(line, distance). i calculate the distance between the original line and the new line and then increase the distance by a factor of that inaccuracy and redraw the line. Comes way more accurate. At least a work around even if not preferable. I could provide a working example of this if someone needs it. I was able to reach accuracies of almost 99.9 percent easily.

chrispahm commented 2 years ago

@SteveCline @JamesLMilner Trying to help clean up some older issues here: Similar to issues #1470, #1484, #1547 this issue has been fixed with Turf >v6.2.0.

Here's a small notebook showcasing Turf's buffer operation on the point and 10 mile buffer radius presented in @SteveCline's original question for both Turf v6.5.0 and v5.1.6. The buffer is compared to a buffer calculated using GeoPandas (link to Jupyter notebook used for the calculation.

https://observablehq.com/@chrispahm/turf-issue-1246

image

Since the difference is arguably small, I guess this issue can be closed as well!