-module(geokit@bearing).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/geokit/bearing.gleam").
-export([initial/2, final/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Initial and final compass bearing between two `LatLng` points.\n"
"\n"
" Bearings are reported in degrees clockwise from true north, in\n"
" `[0, 360)`. The initial bearing is the direction of travel when\n"
" departing `a` along the great-circle route to `b`; the final\n"
" bearing is the direction of arrival at `b`. The two differ along\n"
" any route except along a meridian or the equator (where they are\n"
" equal).\n"
"\n"
" Formula: <https://www.movable-type.co.uk/scripts/latlong.html>.\n"
).
-file("src/geokit/bearing.gleam", 55).
-spec normalise_degrees(float()) -> float().
normalise_degrees(Value) ->
Scaled = Value / 360.0,
Result = Value - (360.0 * math:floor(Scaled)),
gleam@bool:guard(
Result < +0.0,
+0.0,
fun() ->
gleam@bool:guard(Result >= 360.0, +0.0, fun() -> Result end)
end
).
-file("src/geokit/bearing.gleam", 30).
?DOC(
" Initial bearing (forward azimuth) from `a` to `b`, in degrees in\n"
" `[0, 360)`.\n"
"\n"
" ```gleam\n"
" import geokit/bearing\n"
" import geokit/latlng\n"
"\n"
" let assert Ok(tokyo) = latlng.new(lat: 35.6812, lng: 139.7671)\n"
" let assert Ok(osaka) = latlng.new(lat: 34.6937, lng: 135.5023)\n"
" bearing.initial(from: tokyo, to: osaka)\n"
" // ~= 254.0\n"
" ```\n"
).
-spec initial(geokit@latlng:lat_lng(), geokit@latlng:lat_lng()) -> float().
initial(From, To) ->
Phi_1 = gleam_community@maths:degrees_to_radians(geokit@latlng:lat(From)),
Phi_2 = gleam_community@maths:degrees_to_radians(geokit@latlng:lat(To)),
Lambda_1 = gleam_community@maths:degrees_to_radians(geokit@latlng:lng(From)),
Lambda_2 = gleam_community@maths:degrees_to_radians(geokit@latlng:lng(To)),
Delta_lambda = Lambda_2 - Lambda_1,
Y = gleam_community@maths:sin(Delta_lambda) * gleam_community@maths:cos(
Phi_2
),
X = (gleam_community@maths:cos(Phi_1) * gleam_community@maths:sin(Phi_2)) - ((gleam_community@maths:sin(
Phi_1
)
* gleam_community@maths:cos(Phi_2))
* gleam_community@maths:cos(Delta_lambda)),
Theta = gleam_community@maths:atan2(Y, X),
normalise_degrees(gleam_community@maths:radians_to_degrees(Theta)).
-file("src/geokit/bearing.gleam", 50).
?DOC(
" Final bearing when arriving at `to` along the great-circle route\n"
" from `from`, in degrees in `[0, 360)`. Computed as the reverse of\n"
" `initial(from: to, to: from)` plus 180°.\n"
).
-spec final(geokit@latlng:lat_lng(), geokit@latlng:lat_lng()) -> float().
final(From, To) ->
Reverse = initial(To, From),
normalise_degrees(Reverse + 180.0).