import adder from "./adder.js"; import {atan2, cos, quarterPi, radians, sin, tau} from "./math.js"; import noop from "./noop.js"; import stream from "./stream.js"; export var areaRingSum = adder(); var areaSum = adder(), lambda00, phi00, lambda0, cosPhi0, sinPhi0; export var areaStream = { point: noop, lineStart: noop, lineEnd: noop, polygonStart: function() { areaRingSum.reset(); areaStream.lineStart = areaRingStart; areaStream.lineEnd = areaRingEnd; }, polygonEnd: function() { var areaRing = +areaRingSum; areaSum.add(areaRing < 0 ? tau + areaRing : areaRing); this.lineStart = this.lineEnd = this.point = noop; }, sphere: function() { areaSum.add(tau); } }; function areaRingStart() { areaStream.point = areaPointFirst; } function areaRingEnd() { areaPoint(lambda00, phi00); } function areaPointFirst(lambda, phi) { areaStream.point = areaPoint; lambda00 = lambda, phi00 = phi; lambda *= radians, phi *= radians; lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi); } function areaPoint(lambda, phi) { lambda *= radians, phi *= radians; phi = phi / 2 + quarterPi; // half the angular distance from south pole // Spherical excess E for a spherical triangle with vertices: south pole, // previous point, current point. Uses a formula derived from Cagnoli’s // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2). var dLambda = lambda - lambda0, sdLambda = dLambda >= 0 ? 1 : -1, adLambda = sdLambda * dLambda, cosPhi = cos(phi), sinPhi = sin(phi), k = sinPhi0 * sinPhi, u = cosPhi0 * cosPhi + k * cos(adLambda), v = k * sdLambda * sin(adLambda); areaRingSum.add(atan2(v, u)); // Advance the previous points. lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi; } export default function(object) { areaSum.reset(); stream(object, areaStream); return areaSum * 2; }