gistools/geometry/tools/points/
destination.rs

1use crate::space::EARTH_RADIUS;
2use libm::{asin, atan2, cos, sin};
3use s2json::{GetXY, NewXY};
4
5/// Get the destination given a start point, bearing, and distance
6///
7/// Assumes the starting point is in degrees
8///
9/// Assumes the bearing is in degrees
10///
11/// Assumes the distance is in meters
12///
13/// If no radius is provided, defaults to the Earth's radius
14pub fn destination<P: GetXY, Q: NewXY>(
15    start: &P,
16    bearing: f64,
17    distance: f64,
18    radius: Option<f64>,
19) -> Q {
20    let s_lon = start.x().to_radians();
21    let s_lat = start.y().to_radians();
22    let bearing = bearing.to_radians();
23    let radius = radius.unwrap_or(EARTH_RADIUS);
24    let radians = distance / radius;
25
26    let e_lat = asin(sin(s_lat) * cos(radians) + cos(s_lat) * sin(radians) * cos(bearing));
27    let e_lon = s_lon
28        + atan2(sin(bearing) * sin(radians) * cos(s_lat), cos(radians) - sin(s_lat) * sin(e_lat));
29
30    Q::new_xy(e_lon.to_degrees(), e_lat.to_degrees())
31}