2

TL;DR: Spatial computation with turfjs does not work well in a EPSG:3857 map.

In a OpenLayers map, I use turf for transforming a line into a polygon by computing the offset line (aka side-buffer for instance in PostGIS).

Here's the process:

  1. Draw a line using OpenLayers
  2. Compute an offset line by a given distance offsetDistance using turf.lineOffset()
  3. Gather all points and convert to a polygon.

And here's the code

const offsetLine = turf.lineOffset(line, offsetDistance / 1000);
const line2polygon = turf.lineString([
    ...turf.getCoords(line),
    ...turf.getCoords(offsetLine).reverse()
]);
const polygon = turf.lineToPolygon(line2polygon);

The process works well except that there is a projection issue. In the image below I drew a line along the soccer pitch and I enter an offset distance of 53m, which is the width of the pitch. The problem is that the offset line is computed in the WGS84 coordinate system so the distance is actually too small (it is 53 m * cos(latitude)) and it does not result in a square polygon. The OpenLayers map is in EPSG:3857 and I would not like to change that.

enter image description here

I manage to do something OK by converting first the line to Mercator and by multiplying the offset distance by a scale factor (1.783 * 100000) that I got by trial-error:

const offsetLine = turf.lineOffset(turf.toMercator(line), offsetDistance / 1000 * 100000 * 1.783);
const line2polygon = turf.lineString([
    ...turf.getCoords(line),
    ...turf.getCoords(turf.toWgs84(offsetLine)).reverse()
]);

const polygon = turf.lineToPolygon(line2polygon);

And I got this:

enter image description here

So the result is OK but is there a better way to do it? And how can I compute my scale factor properly (I guess it is dependent on the latitude but I could not find the formula)? Surprisingly, my scale factor is not equal to cos(latitude).

2
  • Does this help: gis.stackexchange.com/questions/347548/…
    – TomazicM
    Apr 25, 2020 at 9:46
  • Yes, this is completely related. But my scale factor is not exactly equal to cos(latitude) and I don't figure out why. And I wonder if there is a proper way to do computation without resorting to multiplying by a scale factor.
    – juminet
    Apr 25, 2020 at 10:33

1 Answer 1

2

I don't think Turf can deal with Mercator projection in it's functions. Instead of trying to find out the algorithm for the right factor, it's possible to get the correct offset line with Turf's turf.bearing and turf.destination methods.

If the line goes down, the code below will calculate polygon with offset 65m to the right of the line:

var linePoints = turf.getCoords(line);
var bearing = turf.bearing(turf.point(linePoints[0]), turf.point(linePoints[1]));
var destPoint4 = turf.destination(turf.point(linePoints[0]), 0.065, bearing - 90);
var destPoint3 = turf.destination(turf.point(linePoints[1]), 0.065, bearing - 90);
var point4 = turf.getCoords(destPoint4);
var point3 = turf.getCoords(destPoint3);
var polygon = turf.polygon([[linePoints[0], linePoints[1], point3, point4, linePoints[0]]]);

I was able to find very similar plot in our country, here is the result when the initial line goes top down on the left side of the field:

enter image description here

4
  • Thank you. This is a correct answer for a line with 2 points but I need a solution for any lines with >= 2 points. This could be the basis however for an algorithm for any lines >= 2 points.
    – juminet
    Apr 27, 2020 at 11:27
  • I think I got the algo for n-lines:
    – juminet
    Apr 27, 2020 at 12:12
  • See here hebdo.framapad.org/p/9gd0-lineoffsetalgo?lang=fr. You can add it to your answer to make it complete.
    – juminet
    Apr 27, 2020 at 12:15
  • Question was about a line, not a line string (as was also illustrated with the image), so answer is correct and complete.
    – TomazicM
    Apr 27, 2020 at 14:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.