2

The approach I've been working on is implementing a sinusoidal projection to get x,y coordinates and then use a function to calculate the area of an irregular polygon in a plane. Below is the code I've been working on (the points variable is an array of Cesium Cartesian points that is defined elsewhere in the program).

https://stackoverflow.com/a/4682656/7924630 This was a very useful answer that helped me work on this

function polygonArea(X, Y, numPoints) {
  let area = 0;         // Accumulates area in the loop
  let j = numPoints-1;  // The last vertex is the 'previous' one to the first

  for (i=0; i<numPoints; i++) {
    area = area +  (X[j]+X[i]) * (Y[j]-Y[i]);
    j = i;  //j is previous vertex to i
  }
  return area/2;
}


let xpoints = [];
let ypoints = [];
let lat_dist = (6371009 * Math.PI) / 180;
var i;
for (i = 0; i < points.length; i++) {
    let cartoPoint = Cesium.Cartographic.fromCartesian(points[i]);
    let lng = cartoPoint.longitude;
    let lat = cartoPoint.latitude;
    xpoints[i] = lng * lat_dist * Math.cos(lat);
    ypoints[i] = lat * lat_dist;
};
surfaceArea = polygonArea(xpoints, ypoints, xpoints.length);

For some reason this is returning really small values for the area and I can't understand why. For example, I tested this on a rectangle area. The area should be approximately 45m², but it's returning 0.0137m². I've tried following other implementations of this, but haven't been able to find anything useful for native Javascript.

thornton
  • 21
  • 3
  • Formula and code looks right. Check real values of coordinates lat and lon. Also consider possibility of precision loss in float arithmetics (small difference of two large values `(Y[j]-Y[i])` – MBo Dec 04 '18 at 03:01
  • Small addition (don't influence on area magnitude, only corrects sign if needed): `return Math.abs(area/2);` – MBo Dec 04 '18 at 03:54
  • I thought that might be the case @MBo, but even on larger scales the formula still returns tiny values. – thornton Dec 04 '18 at 04:02
  • log `lng and lat` into console/file. For area 45m^2 I expect values like `40.0001-40.0000` for 10 m difference by latitude (111111m=1 degree, 0.0001 degree = 10 m) – MBo Dec 04 '18 at 04:06
  • I solved it using a different implementation. In case anyone wants help with this, here is the article that gave me the idea for my implementation: http://mathforum.org/library/drmath/view/73894.html – thornton Dec 04 '18 at 04:57
  • @MBo The difference between lng/lat points that I was testing on was approximately 0.000001 for lng and lat. I guess there was probably an issue somewhere there. They were just the points provided by Cesium when clicking on a position on the globe. – thornton Dec 04 '18 at 05:02
  • Link describes [shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula) that you have used (note - for Earth it gives approximation nad might fail at equator and 0th meridian) . So I was right about coordinates discrepance. 10^-6 degree is 0.1m, perhaps Cesium gives not degrees. – MBo Dec 04 '18 at 05:13
  • Just Cesium coordinates are radians. See my answer. – MBo Dec 04 '18 at 05:26

2 Answers2

1

You are using shoelace formula for polygon area, here it gives approximation for spherical polygon. Add Math/abs in the end to get result independently on traversal direction and beware of coordinate sign change at equator and 0th meridian.

But calculations are incorrect due to this issue:

Cesium.Cartographic.fromCartesian function returns result coordinates in radians

while you treat them as degrees (quick check: 45/(57*57)=0.0138).

So it is enough to make correction:

 let lat_dist = 6371009;
MBo
  • 77,366
  • 5
  • 53
  • 86
1

You can use Spherical Geometry Library This library ports a small but useful subset of classes from the Google Maps Javascript API

How to use

Install library

npm install spherical-geometry-js

include library in your code

import { computeArea ,LatLng} from 'spherical-geometry-js/src/index';

import computeArea ,LatLng

import { computeArea ,LatLng} from 'spherical-geometry-js/src/index';

Compute the area by passing coordinate array

  getArea(){
     var coords = [
        { lat: 12.963340185241163, lng: 77.59504217857734 },
        { lat: 12.963959666837907, lng: 77.5952513908759 },
        { lat: 12.96387994460954, lng: 77.59548340195072 },
        { lat: 12.963263076659977, lng: 77.59528357738415 }
     ];

     //convert coords to latlng
     var latLngs = coords.map(function(coord) { 
        return new LatLng(coord.lat, coord.lng);
     });


    return computeArea(latLngs)  //return the area 

   }
Jobincs
  • 4,003
  • 2
  • 14
  • 11