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);
}