10#include <janus/math/Arithmetic.hpp>
11#include <janus/math/Logic.hpp>
12#include <janus/math/Trig.hpp>
35template <
typename Scalar>
38 const Scalar dlat = lla2.
lat - lla1.
lat;
39 const Scalar dlon = lla2.
lon - lla1.
lon;
41 const Scalar sin_dlat_2 = janus::sin(dlat / 2.0);
42 const Scalar sin_dlon_2 = janus::sin(dlon / 2.0);
44 const Scalar a = sin_dlat_2 * sin_dlat_2 + janus::cos(lla1.
lat) *
45 janus::cos(lla2.
lat) *
46 sin_dlon_2 * sin_dlon_2;
48 const Scalar c = 2.0 * janus::atan2(janus::sqrt(a), janus::sqrt(1.0 - a));
69template <
typename Scalar>
77 const Scalar U1 = janus::atan((1.0 - f) * janus::tan(lla1.
lat));
78 const Scalar U2 = janus::atan((1.0 - f) * janus::tan(lla2.
lat));
80 const Scalar sin_U1 = janus::sin(U1);
81 const Scalar cos_U1 = janus::cos(U1);
82 const Scalar sin_U2 = janus::sin(U2);
83 const Scalar cos_U2 = janus::cos(U2);
85 const Scalar L = lla2.
lon - lla1.
lon;
89 Scalar sin_sigma, cos_sigma, sigma;
90 Scalar sin_alpha, cos2_alpha, cos_2sigma_m;
93 constexpr int max_iterations = 20;
95 for (
int i = 0; i < max_iterations; ++i) {
96 const Scalar sin_lambda = janus::sin(lambda);
97 const Scalar cos_lambda = janus::cos(lambda);
99 const Scalar term1 = cos_U2 * sin_lambda;
100 const Scalar term2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;
101 sin_sigma = janus::sqrt(term1 * term1 + term2 * term2);
103 cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
104 sigma = janus::atan2(sin_sigma, cos_sigma);
108 sin_alpha = cos_U1 * cos_U2 * sin_lambda / (sin_sigma + 1e-15);
109 cos2_alpha = 1.0 - sin_alpha * sin_alpha;
113 cos_2sigma_m = cos_sigma - 2.0 * sin_U1 * sin_U2 / (cos2_alpha + 1e-15);
116 f / 16.0 * cos2_alpha * (4.0 + f * (4.0 - 3.0 * cos2_alpha));
118 const Scalar lambda_prev = lambda;
119 lambda = L + (1.0 - C) * f * sin_alpha *
124 (-1.0 + 2.0 * cos_2sigma_m * cos_2sigma_m)));
132 const Scalar u2 = cos2_alpha * (a * a - b * b) / (b * b);
135 u2 / 16384.0 * (4096.0 + u2 * (-768.0 + u2 * (320.0 - 175.0 * u2)));
137 u2 / 1024.0 * (256.0 + u2 * (-128.0 + u2 * (74.0 - 47.0 * u2)));
139 const Scalar cos2_2sigma_m = cos_2sigma_m * cos_2sigma_m;
140 const Scalar delta_sigma =
144 (cos_sigma * (-1.0 + 2.0 * cos2_2sigma_m) -
145 B / 6.0 * cos_2sigma_m * (-3.0 + 4.0 * sin_sigma * sin_sigma) *
146 (-3.0 + 4.0 * cos2_2sigma_m)));
148 return b * A * (sigma - delta_sigma);
165template <
typename Scalar>
172 const Scalar dlon = lla2.
lon - lla1.
lon;
174 const Scalar sin_dlon = janus::sin(dlon);
175 const Scalar cos_dlon = janus::cos(dlon);
176 const Scalar sin_lat1 = janus::sin(lla1.
lat);
177 const Scalar cos_lat1 = janus::cos(lla1.
lat);
178 const Scalar sin_lat2 = janus::sin(lla2.
lat);
179 const Scalar cos_lat2 = janus::cos(lla2.
lat);
181 const Scalar x = sin_dlon * cos_lat2;
182 const Scalar y = cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon;
184 Scalar bearing = janus::atan2(x, y);
190 bearing = bearing + Scalar(two_pi);
193 bearing = janus::where(bearing >= Scalar(two_pi), bearing - Scalar(two_pi),
196 janus::where(bearing < Scalar(0.0), bearing + Scalar(two_pi), bearing);
211template <
typename Scalar>
220 bearing = janus::where(bearing >= Scalar(two_pi), bearing - Scalar(two_pi),
241template <
typename Scalar>
243 const Scalar &distance,
245 const double a = m.a;
246 const double b = m.b;
247 const double f = m.f;
249 const Scalar sin_bearing = janus::sin(bearing);
250 const Scalar cos_bearing = janus::cos(bearing);
253 const Scalar U1 = janus::atan((1.0 - f) * janus::tan(lla.
lat));
254 const Scalar sin_U1 = janus::sin(U1);
255 const Scalar cos_U1 = janus::cos(U1);
258 const Scalar sigma1 = janus::atan2(janus::tan(U1), cos_bearing);
261 const Scalar sin_alpha = cos_U1 * sin_bearing;
262 const Scalar cos2_alpha = 1.0 - sin_alpha * sin_alpha;
264 const Scalar u2 = cos2_alpha * (a * a - b * b) / (b * b);
267 u2 / 16384.0 * (4096.0 + u2 * (-768.0 + u2 * (320.0 - 175.0 * u2)));
269 u2 / 1024.0 * (256.0 + u2 * (-128.0 + u2 * (74.0 - 47.0 * u2)));
272 Scalar sigma = distance / (b * A);
275 Scalar cos_2sigma_m, sin_sigma, cos_sigma;
277 constexpr int max_iterations = 20;
278 for (
int i = 0; i < max_iterations; ++i) {
279 cos_2sigma_m = janus::cos(2.0 * sigma1 + sigma);
280 sin_sigma = janus::sin(sigma);
281 cos_sigma = janus::cos(sigma);
283 const Scalar cos2_2sigma_m = cos_2sigma_m * cos_2sigma_m;
284 const Scalar delta_sigma =
286 (cos_2sigma_m + B / 4.0 *
287 (cos_sigma * (-1.0 + 2.0 * cos2_2sigma_m) -
288 B / 6.0 * cos_2sigma_m *
289 (-3.0 + 4.0 * sin_sigma * sin_sigma) *
290 (-3.0 + 4.0 * cos2_2sigma_m)));
292 const Scalar sigma_prev = sigma;
293 sigma = distance / (b * A) + delta_sigma;
298 sin_sigma = janus::sin(sigma);
299 cos_sigma = janus::cos(sigma);
300 cos_2sigma_m = janus::cos(2.0 * sigma1 + sigma);
303 const Scalar temp = sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_bearing;
304 const Scalar lat2 = janus::atan2(
305 sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_bearing,
306 (1.0 - f) * janus::sqrt(sin_alpha * sin_alpha + temp * temp));
309 const Scalar lambda =
310 janus::atan2(sin_sigma * sin_bearing,
311 cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_bearing);
314 f / 16.0 * cos2_alpha * (4.0 + f * (4.0 - 3.0 * cos2_alpha));
317 (1.0 - C) * f * sin_alpha *
321 C * cos_sigma * (-1.0 + 2.0 * cos_2sigma_m * cos_2sigma_m)));
323 const Scalar lon2 = lla.
lon + L;
344template <
typename Scalar>
348 const double R = (2.0 * m.a + m.b) / 3.0;
351 return janus::sqrt(altitude * (2.0 * R + altitude));
367template <
typename Scalar>
376 const Scalar ground_dist =
380 return (h1 + h2) - ground_dist;
409template <
typename Scalar>
412 const Vec3<Scalar> &direction,
415 const double a = m.a;
416 const double b = m.b;
417 const double a2 = a * a;
418 const double b2 = b * b;
421 const Scalar dir_norm =
422 janus::sqrt(direction(0) * direction(0) + direction(1) * direction(1) +
423 direction(2) * direction(2));
424 const Vec3<Scalar> d = direction / dir_norm;
427 const Scalar ox = origin(0);
428 const Scalar oy = origin(1);
429 const Scalar oz = origin(2);
432 const Scalar dx = d(0);
433 const Scalar dy = d(1);
434 const Scalar dz = d(2);
439 const Scalar A = dx * dx / a2 + dy * dy / a2 + dz * dz / b2;
440 const Scalar B = 2.0 * (ox * dx / a2 + oy * dy / a2 + oz * dz / b2);
441 const Scalar C = ox * ox / a2 + oy * oy / a2 + oz * oz / b2 - 1.0;
444 const Scalar discriminant = B * B - 4.0 * A * C;
447 const Scalar sqrt_disc = janus::sqrt(janus::abs(discriminant) + 1e-15);
448 const Scalar t_near = (-B - sqrt_disc) / (2.0 * A);
449 const Scalar t_far = (-B + sqrt_disc) / (2.0 * A);
452 Vec3<Scalar> point_near;
453 point_near(0) = origin(0) + t_near * d(0);
454 point_near(1) = origin(1) + t_near * d(1);
455 point_near(2) = origin(2) + t_near * d(2);
457 Vec3<Scalar> point_far;
458 point_far(0) = origin(0) + t_far * d(0);
459 point_far(1) = origin(1) + t_far * d(1);
460 point_far(2) = origin(2) + t_far * d(2);
463 result.
hit = discriminant;
465 result.
t_far = t_far;
constexpr double pi
Pi.
Definition Constants.hpp:153
constexpr double R_mean
Mean radius [m].
Definition Constants.hpp:22
Definition GeodesicUtils.hpp:14
Scalar final_bearing(const LLA< Scalar > &lla1, const LLA< Scalar > &lla2, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:212
RayIntersection< Scalar > ray_ellipsoid_intersection(const Vec3< Scalar > &origin, const Vec3< Scalar > &direction, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:411
Scalar horizon_distance(const Scalar &altitude, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:345
LLA< Scalar > destination_point(const LLA< Scalar > &lla, const Scalar &bearing, const Scalar &distance, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:242
Scalar initial_bearing(const LLA< Scalar > &lla1, const LLA< Scalar > &lla2, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:167
Scalar haversine_distance(const LLA< Scalar > &lla1, const LLA< Scalar > &lla2, double radius=constants::earth::R_mean)
Definition GeodesicUtils.hpp:36
Scalar great_circle_distance(const LLA< Scalar > &lla1, const LLA< Scalar > &lla2, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:70
Scalar is_visible(const LLA< Scalar > &lla_observer, const LLA< Scalar > &lla_target, const EarthModel &m=EarthModel::WGS84())
Definition GeodesicUtils.hpp:368
Definition EarthModel.hpp:27
static constexpr EarthModel WGS84()
WGS84 reference ellipsoid (most common for GPS/navigation).
Definition EarthModel.hpp:45
Definition Geodetic.hpp:27
Scalar lon
Longitude [rad], positive East, range [-π, π].
Definition Geodetic.hpp:28
Scalar alt
Altitude above ellipsoid [m].
Definition Geodetic.hpp:30
Scalar lat
Geodetic latitude [rad], range [-π/2, π/2].
Definition Geodetic.hpp:29
Result of ray-ellipsoid intersection.
Definition GeodesicUtils.hpp:388
Vec3< Scalar > point_far
Far intersection point (ECEF).
Definition GeodesicUtils.hpp:393
Scalar t_far
Parameter for far intersection point.
Definition GeodesicUtils.hpp:391
Scalar t_near
Parameter for near intersection point.
Definition GeodesicUtils.hpp:390
Scalar hit
Definition GeodesicUtils.hpp:389
Vec3< Scalar > point_near
Near intersection point (ECEF).
Definition GeodesicUtils.hpp:392