import { Haversine } from './calculator/Haversine.js';
import { Vincenty } from './calculator/Vincenty.js';
import { EARTH_RADIUS, radianToDeg } from './convert.js';
import { LengthUnit } from './LengthUnit.js';

/**
 * Calculates the distance between points.
 *
 * Default algorithm is [distanceWithVincenty], default radius is [EARTH_RADIUS]
 *
 *      final Distance distance = new Distance();
 *
 *      // km = 423
 *      final int km = distance.as(LengthUnit.Kilometer,
 *         new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
 *
 *      // meter = 422592
 *      final int meter = distance(new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
 */
class Distance {
    roundResult;
    /** Returns either [Haversine] oder [Vincenty] calculator */
    calculator;
    radius;
    // prettier-ignore
    constructor({ radius = EARTH_RADIUS, roundResult = true, calculator = new Vincenty() } = {}) {
        this.radius = radius;
        this.roundResult = roundResult;
        this.calculator = calculator;
    }
    /**
     * Shortcut for creating a Vincenty-Distance-Calculator
     *
     * const calculator = Distance.useVincenty()
     */
    static useVincenty({ radius = EARTH_RADIUS, roundResult = true, } = {}) {
        return new Distance({ radius, roundResult, calculator: new Vincenty() });
    }
    /**
     * Shortcut for creating a Haversine-Distance-Calculator
     *
     * const calculator = Distance.useHaversine()
     */
    static useHaversine({ radius = EARTH_RADIUS, roundResult = true, } = {}) {
        return new Distance({ radius, roundResult, calculator: new Haversine() });
    }
    /**
     * Converts the distance to the given [LengthUnit]
     *
     *     const km = distance.as(LengthUnit.Kilometer,
     *         new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
     */
    as(unit, p1, p2) {
        const dist = this.calculator.distance(p1, p2);
        return this.round(LengthUnit.Meter.to(unit, dist));
    }
    /**
     * Computes the distance between two points.
     *
     * The function uses the [DistanceAlgorithm] specified in the CTOR
     */
    distance(p1, p2) {
        return this.round(this.calculator.distance(p1, p2));
    }
    /**
     * Returns the great circle bearing (direction) in degrees to the next point ([p2])
     *
     * Find out about the difference between rhumb line and
     * great circle bearing on
     * [Wikipedia](http://en.wikipedia.org/wiki/Rhumb_line#General_and_mathematical_description).
     *
     *     final Distance distance = const Distance();
     *
     *     final LatLng p1 = new LatLng(0.0, 0.0);
     *     final LatLng p2 = new LatLng(-90.0, 0.0);
     *
     *     expect(distance.direction(p1, p2), equals(180));
     */
    bearing(p1, p2) {
        const diffLongitude = p2.longitudeInRad - p1.longitudeInRad;
        const y = Math.sin(diffLongitude);
        const x = Math.cos(p1.latitudeInRad) * Math.tan(p2.latitudeInRad) -
            Math.sin(p1.latitudeInRad) * Math.cos(diffLongitude);
        return radianToDeg(Math.atan2(y, x));
    }
    /**
     * Returns a destination point based on the given [distance] and [bearing]
     *
     * Given a [from] (start) point, initial [bearing], and [distance],
     * this will calculate the destination point and
     * final bearing travelling along a (shortest distance) great circle arc.
     *
     *     final Distance distance = const Distance();
     *
     *     final num distanceInMeter = (EARTH_RADIUS * math.PI / 4).round();
     *
     *     final p1 = new LatLng(0.0, 0.0);
     *     final p2 = distance.offset(p1, distanceInMeter, 180);
     *
     * Bearing: Left - 270°, right - 90°, up - 0°, down - 180°
     */
    offset(from, distanceInMeter, bearing) {
        return this.calculator.offset(from, distanceInMeter, bearing);
    }
    round(value) {
        return this.roundResult ? Math.round(value) : value;
    }
}

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