3

I use QGIS to process polygons with a source CRS of EPSG:3006. I then use these in Mapbox for which I need to use Turf to calculate the area. When using turf.area to calculate the area of a polygon, it gives an error in the range of 5-100+ square meters depending on how large the polygon is.

I don't think a change in projection should make this much of a difference, since reimporting the GeoJSON into QGIS shows the correct area.

here is an example:

{"type":"MultiPolygon","coordinates":[[[[21.047718889610486,64.82033191759042],[21.04857430455677,64.82017082543153],[21.04864012759847,64.82017286432547],[21.048737014669026,64.82017588551749],[21.049347477289576,64.8203029713408],[21.048183280888004,64.82076998555335],[21.048148298733107,64.82076634452957],[21.048075365856995,64.82076446969718],[21.04807536413318,64.82076464986945],[21.048028595070818,64.82076386759066],[21.047970957341136,64.82076495201797],[21.047896882353275,64.82076579825836],[21.04781935735383,64.82076502937629],[21.047759673303265,64.82076791727027],[21.047705710046138,64.82076663626815],[21.04765642496363,64.82076641589033],[21.047575181891947,64.82076622197127],[21.0475127283145,64.8207635676798],[21.04745212003237,64.82076413386216],[21.047387061333392,64.82075845214167],[21.047334451190352,64.82074730920641],[21.04727888460505,64.82073636803764],[21.04723497313114,64.82072104266398],[21.047191306701446,64.82070070044496],[21.047165535515326,64.82067486371645],[21.04715574080304,64.82064731193529],[21.047163525126983,64.82061840289613],[21.04717953236544,64.82058207104411],[21.0471679380754,64.82055112579918],[21.047176219024998,64.82054856336232],[21.047718889610486,64.82033191759042]]]]}

Turf gives this multipolygon an area of 4012.8884841975305 square meters.

Importing this exact GeoJSON back into QGIS and calculating the area from there gives around 4030 square meters, which is exactly what the original projection of the polygon gave. For reference, the QGIS measurement I'm looking at is the ellipsoidal area calculated using GRS80.

I couldn't find anything about this issue when googling, but suspect it must have something to do with turf's area algorithm.

EDIT: I was able to get this working correctly using the answer from Francisco, with geographiclib-geodesic.

Here is the code I made for wrapping the functionality of that library for use with GeoJSON features and featurecollections (using turf's method and some questionable Typescript)

import { geomReduce } from "@turf/meta";
import { Coord, Feature, FeatureCollection, MultiPolygon, Polygon } from "@turf/turf";

const geodesic = require('geographiclib-geodesic');
const geod = geodesic.Geodesic.WGS84;

export default function area(geojson: FeatureCollection<MultiPolygon|Polygon> | Feature<MultiPolygon|Polygon>): number {
    return geomReduce(geojson, (value, geom) => value + calculateArea(geom), 0);
}

function calculateArea(geom: MultiPolygon|Polygon): number {
    switch (geom.type) {
        case 'Polygon':
            return  polygonArea(geom.coordinates);
        case 'MultiPolygon':
            return geom.coordinates.reduce((value, coords) => value + polygonArea(coords), 0);
        default:
            return 0;
    }
}

function polygonArea(coords: Coord[][]): number {
    return coords.reduce((value, coord) => value + computeRing(coord), 0);
}

function computeRing (coordinates: Coord[]): number {
    const poly = geod.Polygon(false);
    coordinates.forEach((coord) => {
        poly.AddPoint(coord[1], coord[0]); // NOTE - lat, lng order
    });

    let computed = poly.Compute(false, true); 
    return Math.abs(computed.area);
}

2 Answers 2

6

Probably you are affected by this bug. turf.area uses an earth radius value different that other software like PostGIS.

There is a fix in the repo but seems not to be available in the last published version of turf, v6.5.0. It seems that will be realeased with version 7.0.0.

My suggestion is build your own version of turf from GitHub repo, or make a small hack on your own copy.

Just search for const RADIUS = 6378137; and replace it with const RADIUS = 6371008.8. It is in packages/turf-area/index.ts.

But there are more tickets open in turf about troubles with how area is calculated. This one has a good explanations about the problem. The resume is that Turf's area algorithm is based on this paper, "that work directly on a sphere".

In the same ticket a reporter suggests the use of geographiclib-js that use ellipsoidal calculations and provides a sample of code (that I copy&paste here), and assumes that you have the library loaded.

// similar to turf, summing up rings (i.e. multipolygons)
// this may not be necessary if the geographic polygon can support multipolygons
function polygonArea(coords: number[][][][]) {
  let total = 0;
  if (coords && coords.length > 0) {
    for (let i = 0; i < coords.length; i++) {
      const area = geographicLibArea(coords[i][0]);
      total += area;
    }
  }
  return total;
}

const geographicLibArea = (coordinates: Array<Coord>) => {
  // the geodesic format of my lat, lng coordinates
  // you can specify your own if you have the appropriate constants
  const geod = GeographicLib.Geodesic.WGS84;


  // build polygon in geographic
  let poly = geod.Polygon(false);
  for (let i = 0; i < coordinates.length; ++i) {
    poly.AddPoint(coordinates[i][1], coordinates[i][0]);
  }

  poly = poly.Compute(false, true);

  return Math.abs(poly.area.toFixed(0));
};

So, Turf does not use ellipsoidal calculations for the area. If that is needed another library must be used.

3
  • Hmm so I tried this but it still seems to give an incorrect (or at least different) answer from that of QGIS. After changing the radius, I get 4003.92 for the example Multipolygon in my question.
    – Axekan
    Aug 28, 2022 at 9:19
  • @Axekan I updated the post after a quick research in turf issues. Aug 28, 2022 at 11:17
  • Thank you, I was able to get this to work.
    – Axekan
    Aug 28, 2022 at 13:32
0

Use

turf.area(plygon_trf)*0.993699583

I got exact value matching with QGIS Area

1
  • 1
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Dec 29, 2023 at 11:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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