import * as validate from '@mmit/validate';
import { EQUATOR_RADIUS, radianToDeg, degToRadian } from '../convert.js';
import { LatLng } from '../LatLng.js';

/**
 * Calculates distance with Haversine algorithm.
 *
 * Accuracy can be out by 0.3%
 * More on [Wikipedia](https://en.wikipedia.org/wiki/Haversine_formula)
 */
class Haversine {
    /**
     * Calculates distance with Haversine algorithm.
     */
    distance(p1, p2) {
        const sinDLat = Math.sin((p2.latitudeInRad - p1.latitudeInRad) / 2);
        const sinDLng = Math.sin((p2.longitudeInRad - p1.longitudeInRad) / 2);
        // Sides
        const a = sinDLat * sinDLat +
            sinDLng * sinDLng * Math.cos(p1.latitudeInRad) * Math.cos(p2.latitudeInRad);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return EQUATOR_RADIUS * c;
    }
    offset(from, distanceInMeter, bearing) {
        validate.inclusiveBetween(bearing, -180, 180, () => `Angle must be between -180 and 180 degrees but was ${bearing}`);
        const h = degToRadian(bearing);
        const a = distanceInMeter / EQUATOR_RADIUS;
        const lat2 = Math.asin(Math.sin(from.latitudeInRad) * Math.cos(a) +
            Math.cos(from.latitudeInRad) * Math.sin(a) * Math.cos(h));
        const lng2 = from.longitudeInRad +
            Math.atan2(Math.sin(h) * Math.sin(a) * Math.cos(from.latitudeInRad), Math.cos(a) - Math.sin(from.latitudeInRad) * Math.sin(lat2));
        return new LatLng(radianToDeg(lat2), radianToDeg(lng2));
    }
}

export { Haversine };
//# sourceMappingURL=Haversine.js.map
