28#include "acfutils/perf.h"
31#define ROUND_ERROR 1e-10
41 .f = .00335281066474748071,
42 .ecc = 0.08181919084296430238,
43 .ecc2 = 0.00669437999019741354,
67matrix_mul(
const double *x,
const double *y,
double *z,
68 size_t xrows,
size_t ycols,
size_t sz)
70 memset(z, 0, sz * ycols *
sizeof (
double));
71 for (
size_t row = 0; row < xrows; row++) {
72 for (
size_t col = 0; col < ycols; col++) {
73 for (
size_t i = 0; i < sz; i++) {
74 z[row * ycols + col] += x[row * sz + i] *
93is_on_arc(
double angle_x,
double angle1,
double angle2, bool_t cw)
97 return (angle_x >= angle1 && angle_x <= angle2);
99 return (angle_x >= angle1 || angle_x <= angle2);
102 return (angle_x <= angle1 || angle_x >= angle2);
104 return (angle_x <= angle1 && angle_x >= angle2);
153 return (sqrt(
POW2(a.x) +
POW2(a.y)));
165 return (
VECT3(a.x * b.x, a.y * b.y, a.z * b.z));
174 return (
VECT3L(a.x * b.x, a.y * b.y, a.z * b.z));
183 return (
VECT2(a.x * b.x, a.y * b.y));
250 return (
VECT3(a.x / len, a.y / len, a.z / len));
257vect3l_unit(
vect3l_t a,
long double *l)
265 return (
VECT3L(a.x / len, a.y / len, a.z / len));
281 return (
VECT2(a.x / len, a.y / len));
294 return (
VECT3(a.x + b.x, a.y + b.y, a.z + b.z));
303 return (
VECT3L(a.x + b.x, a.y + b.y, a.z + b.z));
312 return (
VECT2(a.x + b.x, a.y + b.y));
325 return (
VECT3(a.x - b.x, a.y - b.y, a.z - b.z));
334 return (
VECT3L(a.x - b.x, a.y - b.y, a.z - b.z));
343 return (
VECT2(a.x - b.x, a.y - b.y));
357 return (
VECT3(a.x * b, a.y * b, a.z * b));
366 return (
VECT3L(a.x * b, a.y * b, a.z * b));
375 return (
VECT2(a.x * b, a.y * b));
388 return (a.x * b.x + a.y * b.y + a.z * b.z);
397 return (a.x * b.x + a.y * b.y + a.z * b.z);
406 return (a.x * b.x + a.y * b.y);
419 return (
VECT3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z,
420 a.x * b.y - a.y * b.x));
429 return (
VECT3L(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z,
430 a.x * b.y - a.y * b.x));
450 return (
VECT3((a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2));
459 return (
VECT3L((a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2));
468 return (
VECT2((a.x + b.x) / 2, (a.y + b.y) / 2));
485 return (
VECT3(v.x, v.y * cos_a - v.z * sin_a,
486 v.y * sin_a + v.z * cos_a));
490 return (
VECT3(v.x * cos_a - v.z * sin_a, v.y,
491 v.x * sin_a + v.z * cos_a));
495 return (
VECT3(v.x * cos_a - v.y * sin_a,
496 v.x * sin_a + v.y * cos_a, v.z));
499 VERIFY_MSG(0,
"Invalid axis value (%d) passed", axis);
513 return (
VECT3L(v.x, v.y * cos_a - v.z * sin_a,
514 v.y * sin_a + v.z * cos_a));
518 return (
VECT3L(v.x * cos_a - v.z * sin_a, v.y,
519 v.x * sin_a + v.z * cos_a));
523 return (
VECT3L(v.x * cos_a - v.y * sin_a,
524 v.x * sin_a + v.y * cos_a, v.z));
527 VERIFY_MSG(0,
"Invalid axis value (%d) passed", axis);
539 return (
VECT2(v.y, -v.x));
541 return (
VECT2(-v.y, v.x));
551 return (
VECT2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a));
562 return (
VECT2(v.x * cos_a + v.y * sin_a, v.y * cos_a - v.x * sin_a));
571 return (
VECT3(-v.x, -v.y, -v.z));
580 return (
VECT3L(-v.x, -v.y, -v.z));
589 return (
VECT2(-v.x, -v.y));
635 return (360 - a1 + a2);
640 return (-(360 - a2 + a1));
666 double lat_rad, lon_rad, R, R0;
677 R0 = R * cos(lat_rad);
679 result.x = R0 * cos(lon_rad);
680 result.y = R0 * sin(lon_rad);
681 result.z = R * sin(lat_rad);
753 return (
vect3_rot(pos, -delta_t * EARTH_ROT_RATE, 2));
765 return (
vect3_rot(pos, delta_t * EARTH_ROT_RATE, 2));
774 return (
VECT3(ecef.y, ecef.z, ecef.x));
783 return (
VECT3(opengl.z, opengl.x, opengl.y));
792 return (
VECT3L(ecef.y, ecef.z, ecef.x));
801 return (
VECT3L(opengl.z, opengl.x, opengl.y));
811ellip_init(
double semi_major,
double semi_minor,
double flattening)
815 ellip.
a = semi_major;
816 ellip.
b = semi_minor;
817 ellip.
ecc2 = flattening * (2 - flattening);
834 double sin_lat = sin(lat_r);
839 Rc = ellip->
a / sqrt(1 - ellip->
ecc2 *
POW2(sin_lat));
840 p = (Rc + pos.
elev) * cos(lat_r);
841 z = ((Rc * (1 - ellip->
ecc2)) + pos.
elev) * sin_lat;
867 double sin_lat = sin(lat_r), cos_lat = cos(lat_r);
868 double sin_lon = sin(lon_r), cos_lon = cos(lon_r);
870 Rc = ellip->
a / sqrt(1 - ellip->
ecc2 *
POW2(sin_lat));
872 res.x = (Rc + pos.
elev) * cos_lat * cos_lon;
873 res.y = (Rc + pos.
elev) * cos_lat * sin_lon;
874 res.z = (Rc * (1 - ellip->
ecc2) + pos.
elev) * sin_lat;
919 B = (pos.z >= 0 ? ellip->
b : -ellip->
b);
924 r = sqrt(
POW2(pos.x) +
POW2(pos.y));
925 e = (B * pos.z - (
POW2(ellip->
a) -
POW2(B))) / (ellip->
a * r);
926 f = (B * pos.z + (
POW2(ellip->
a) -
POW2(B))) / (ellip->
a * r);
932 p = (4.0 / 3.0) * (e * f + 1.0);
937 v = pow((sqrt(d) - q), (1.0 / 3.0)) - pow((sqrt(d) + q),
940 v = 2.0 * sqrt(-p) * cos(acos(q / (p * sqrt(-p))) / 3.0);
947 if (
POW2(v) < fabs(p))
948 v = -(
POW3(v) + 2.0 * q) / (3.0 * p);
949 g = (sqrt(
POW2(e) + v) + e) / 2.0;
950 t = sqrt(
POW2(g) + (f - v * g) / (2.0 * g - e)) - g;
952 res.
lat = atan((ellip->
a * (1.0 -
POW2(t))) / (2.0 * B * t));
957 res.
elev = (r - ellip->
a * t) * cos(res.
lat) +
958 (pos.z - B) * sin(res.
lat);
963 zlong = atan2(pos.y, pos.x);
965 zlong = zlong + (2 * M_PI);
974 if (res.
lon >= 180.0)
990 double lat_rad, lon_rad, R, R0;
992 R0 = sqrt(v.x * v.x + v.y * v.y);
998 lat_rad = atan(v.z / R0);
999 lon_rad = asin(v.y / R0);
1002 lon_rad = M_PI - lon_rad;
1004 lon_rad = -M_PI - lon_rad;
1039 double d, l_dot_o_min_c, sqrt_tmp, o_min_c_abs;
1059 sqrt_tmp =
POW2(l_dot_o_min_c) -
POW2(o_min_c_abs) +
POW2(r);
1063 unsigned intersects = 0;
1065 sqrt_tmp = sqrt(sqrt_tmp);
1067 i1_d = -l_dot_o_min_c - sqrt_tmp;
1068 if ((i1_d >= 0 && i1_d <= d) || !confined) {
1085 i2_d = -l_dot_o_min_c + sqrt_tmp;
1086 if ((i2_d >= 0 && i2_d <= d) || !confined) {
1097 return (intersects);
1098 }
else if (sqrt_tmp == 0) {
1105 i1_d = -l_dot_o_min_c;
1106 if ((i1_d >= 0 && i1_d <= d) || !confined) {
1148 i[0] =
VECT2(i3[0].x, i3[0].y);
1149 i[1] =
VECT2(i3[1].x, i3[1].y);
1184 det = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x);
1187 ca = p1.x * p2.y - p1.y * p2.x;
1188 cb = p3.x * p4.y - p3.y * p4.x;
1189 r.x = (ca * (p3.x - p4.x) - cb * (p1.x - p2.x)) / det;
1190 r.y = (ca * (p3.y - p4.y) - cb * (p1.y - p2.y)) / det;
1193 if (r.x < MIN(p1.x, p2.x) - ROUND_ERROR ||
1194 r.x > MAX(p1.x, p2.x) + ROUND_ERROR ||
1195 r.x < MIN(p3.x, p4.x) - ROUND_ERROR ||
1196 r.x > MAX(p3.x, p4.x) + ROUND_ERROR ||
1197 r.y < MIN(p1.y, p2.y) - ROUND_ERROR ||
1198 r.y > MAX(p1.y, p2.y) + ROUND_ERROR ||
1199 r.y < MIN(p3.y, p4.y) - ROUND_ERROR ||
1200 r.y > MAX(p3.y, p4.y) + ROUND_ERROR)
1230 if ((d == 0 && ra == rb) || d > ra + rb ||
1231 d + MIN(ra, rb) < MAX(ra, rb))
1256is_valid_poly(
const vect2_t *poly)
1264get_poly_num_pts(
const vect2_t *poly)
1266 for (
unsigned i = 0; ; i++) {
1292 vect2_t *isects,
unsigned cap)
1294 unsigned n_isects = 0;
1297 ASSERT(is_valid_poly(poly));
1298 npts = get_poly_num_pts(poly);
1300 for (
size_t i = 0; i < npts; i++) {
1302 vect2_t pt2 = poly[(i + 1) % npts];
1342 ASSERT(is_valid_poly(poly));
1351 return ((isects & 1) != 0);
1362 return (
VECT2(sin(truehdg), cos(truehdg)));
1375 if (dir.x >= 0 && dir.y >= 0)
1377 else if (dir.x < 0 && dir.y >= 0)
1379 else if (dir.x >= 0 && dir.y < 0)
1444 pos->
lat = atof(lat);
1445 pos->
lon = atof(lon);
1457 pos->
lat = atof(lat);
1458 pos->
lon = atof(lon);
1459 pos->
elev = atof(elev);
1468 return (1.0 / tan(x));
1475 return (1.0 / cos(x));
1509 double theta =
DEG2RAD(!inv ? rot : -rot);
1511#define M(m, r, c) ((m)[(r) * 3 + (c)])
1512 double R_a[3 * 3], R_b[3 * 3];
1513 double sin_alpha = sin(alpha), cos_alpha = cos(alpha);
1514 double sin_bravo = sin(bravo), cos_bravo = cos(bravo);
1515 double sin_theta = sin(theta), cos_theta = cos(theta);
1524 memset(R_a, 0,
sizeof (R_a));
1525 M(R_a, 0, 0) = cos_alpha;
1526 M(R_a, 0, 2) = sin_alpha;
1528 M(R_a, 2, 0) = -sin_alpha;
1529 M(R_a, 2, 2) = cos_alpha;
1538 memset(R_b, 0,
sizeof (R_b));
1539 M(R_b, 0, 0) = cos_bravo;
1540 M(R_b, 0, 1) = -sin_bravo;
1541 M(R_b, 1, 0) = sin_bravo;
1542 M(R_b, 1, 1) = cos_bravo;
1546 matrix_mul(R_a, R_b, xlate.sph_matrix, 3, 3, 3);
1548 matrix_mul(R_b, R_a, xlate.sph_matrix, 3, 3, 3);
1550 xlate.rot_matrix[0] = cos_theta;
1551 xlate.rot_matrix[1] = -sin_theta;
1552 xlate.rot_matrix[2] = sin_theta;
1553 xlate.rot_matrix[3] = cos_theta;
1572 r =
VECT2(p.y, p.z);
1573 matrix_mul(xlate->rot_matrix, (
double *)&r, (
double *)&s,
1579 matrix_mul(xlate->sph_matrix, (
double *)&p, (
double *)&q, 3, 1, 3);
1586 r =
VECT2(q.y, q.z);
1587 matrix_mul(xlate->rot_matrix, (
double *)&r, (
double *)&s,
1625 double alpha = asin(MIN(s2e_abs / 2 /
EARTH_MSL, 1.0));
1686 fpp.allow_inv = allow_inv;
1700 fpp.scale =
VECT2(1, 1);
1714 return (
fpp_init(center, rot, INFINITY, ellip, allow_inv));
1754 if (fpp->ellip != NULL)
1759 if (isfinite(fpp->dist)) {
1760 if (fpp->dist < 0.0 && pos_v.x <= fpp->dist +
EARTH_MSL)
1762 res_v.x = fpp->dist * (pos_v.y / (fpp->dist +
1764 res_v.y = fpp->dist * (pos_v.z / (fpp->dist +
1767 res_v =
VECT2(pos_v.y, pos_v.z);
1770 return (
VECT2(res_v.x * fpp->scale.x, res_v.y * fpp->scale.y));
1796 ASSERT(fpp->scale.x != 0);
1797 ASSERT(fpp->scale.y != 0);
1799 pos =
VECT2(pos.x / fpp->scale.x, pos.y / fpp->scale.y);
1800 if (isfinite(fpp->dist)) {
1801 v =
VECT3(-fpp->dist, pos.x, pos.y);
1809 v =
VECT3(-1e14, pos.x, pos.y);
1810 o =
VECT3(1e14, 0, 0);
1817 if (n == 2 && isfinite(fpp->dist)) {
1824 if (i[1].x > i[0].x)
1827 if (i[1].x < i[0].x)
1833 if (fpp->ellip != NULL)
1853 ASSERT(fpp->scale.x != 0);
1854 ASSERT(fpp->scale.y != 0);
1866 return (fpp->scale);
1892lcc_init(
double reflat,
double reflon,
double stdpar1,
double stdpar2)
1894 double phi0 =
DEG2RAD(reflat);
1895 double phi1 =
DEG2RAD(stdpar1);
1896 double phi2 =
DEG2RAD(stdpar2);
1902 if (stdpar1 == stdpar2)
1905 lcc.n = log(cos(phi1) * sec(phi2)) / log(tan(M_PI / 4.0 +
1906 phi2 / 2.0) * cot(M_PI / 4.0 + phi1 / 2.0));
1907 lcc.F = (cos(phi1) * pow(tan(M_PI / 4.0 * phi1 / 2.0), lcc.n)) /
1909 lcc.rho0 = lcc.F * pow(cot(M_PI / 4.0 + phi0 / 2.0), lcc.n);
1925 rho = lcc->F * pow(cot(M_PI / 4 + lat / 2), lcc->n);
1926 result.x = rho * sin(lon - lcc->reflon);
1927 result.y = lcc->rho0 - rho * cos(lcc->n * (lat - lcc->reflat));
1943 curve->n_pts = n_pts;
1977 ASSERT(func->n_pts >= 3 || func->n_pts % 3 == 2);
1979 if (x < func->pts[0].x)
1980 return (func->pts[0].y);
1981 else if (x > func->pts[func->n_pts - 1].x)
1982 return (func->pts[func->n_pts - 1].y);
1985 for (
size_t i = 0; i + 2 < func->n_pts; i += 2) {
1986 if (x <= func->pts[i + 2].x) {
1987 vect2_t p0 = func->pts[i], p1 = func->pts[i + 1];
1988 vect2_t p2 = func->pts[i + 2];
2040 2 * (p1.x - p0.x), p0.x - x, ts);
2042 if (ts[0] >= 0 && ts[0] <= 1) {
2044 }
else if (n == 2 && ts[1] >= 0 && ts[1] <= 1) {
2051 y =
POW2(1 - t) * p0.y + 2 * (1 - t) * t * p1.y +
2093 for (
size_t i = 0; i + 2 < func->n_pts; i += 2) {
2094 vect2_t p0 = func->pts[i], p1 = func->pts[i + 1];
2095 vect2_t p2 = func->pts[i + 2];
2099 if (p0.y == p1.y && p1.y == p2.y) {
2113 for (
unsigned i = 0; i < n; i++) {
2115 if (t < 0.0 || t > 1.0)
2118 xs = realloc(xs, num_xs *
sizeof (*xs));
2119 xs[num_xs - 1] =
POW2(1 - t) * p0.x +
2120 2 * (1 - t) * t * p1.x +
POW2(t) * p2.x;
2134 memset(mat, 0,
sizeof (*mat));
2135 MAT4(mat, 0, 0) = 1;
2136 MAT4(mat, 1, 1) = 1;
2137 MAT4(mat, 2, 2) = 1;
2138 MAT4(mat, 3, 3) = 1;
2147 memset(mat, 0,
sizeof (*mat));
2148 MAT3(mat, 0, 0) = 1;
2149 MAT3(mat, 1, 1) = 1;
2150 MAT3(mat, 2, 2) = 1;
#define ASSERT3U(x, op, y)
#define ASSERT3F(x, op, y)
#define VERIFY_MSG(x, fmt,...)
#define GEO2_TO_GEO3(v, a)
unsigned vect2sph_isect(vect3_t v, vect3_t o, vect3_t c, double r, bool_t confined, vect3_t i[2])
vect3_t vect3_neg(vect3_t v)
vect2_t fpp_get_scale(const fpp_t *fpp)
vect3l_t vect3l_xprod(vect3l_t a, vect3l_t b)
geo_pos3_t ecmi2geo(vect3_t pos, double delta_t, const ellip_t *ellip)
vect3_t vect3_scmul(vect3_t a, double b)
vect2_t vect2vect_isect(vect2_t da, vect2_t oa, vect2_t db, vect2_t ob, bool_t confined)
vect2_t vect2_add(vect2_t a, vect2_t b)
fpp_t gnomo_fpp_init(geo_pos2_t center, double rot, const ellip_t *ellip, bool_t allow_inv)
vect2_t vect2_rot(vect2_t v, double angle)
vect3_t gl2ecef(vect3_t opengl)
vect3_t ecef2gl(vect3_t ecmi)
vect2_t geo2fpp(geo_pos2_t pos, const fpp_t *fpp)
vect3_t vect3_xprod(vect3_t a, vect3_t b)
bool_t geo_pos3_from_str(const char *lat, const char *lon, const char *elev, geo_pos3_t *pos)
vect2_t vect2_sub(vect2_t a, vect2_t b)
vect3_t vect3_mul(vect3_t a, vect3_t b)
vect3_t ecmi2ecef(vect3_t ecmi, double delta_t)
vect3_t vect3_add(vect3_t a, vect3_t b)
long double vect3l_dist(vect3l_t a, vect3l_t b)
double vect2_abs(vect2_t a)
long double vect3l_dotprod(vect3l_t a, vect3l_t b)
vect3_t vect3_local2acf(vect3_t v, double roll, double pitch, double hdgt)
geo_pos2_t geo_displace_dir(const ellip_t *ellip, geo_pos2_t pos, vect2_t dir, double dist)
vect3l_t ecef2gl_l(vect3l_t ecmi)
void fpp_set_scale(fpp_t *fpp, vect2_t scale)
bool_t geo_pos2_from_str(const char *lat, const char *lon, geo_pos2_t *pos)
sph_xlate_t sph_xlate_init(geo_pos2_t displacement, double rotation, bool_t inv)
bool_t point_in_poly(vect2_t pt, const vect2_t *poly)
geo_pos2_t fpp2geo(vect2_t pos, const fpp_t *fpp)
vect3_t sph2ecef(geo_pos3_t pos)
fpp_t fpp_init(geo_pos2_t center, double rot, double dist, const ellip_t *ellip, bool_t allow_inv)
double gc_point_hdg(geo_pos2_t start, geo_pos2_t end)
vect3_t geo2ecef_mtr(geo_pos3_t pos, const ellip_t *ellip)
vect3_t ecef2ecmi(vect3_t ecef, double delta_t)
geo_pos2_t sph_xlate(geo_pos2_t pos, const sph_xlate_t *xlate)
vect3l_t gl2ecef_l(vect3l_t opengl)
unsigned vect2poly_isect(vect2_t a, vect2_t oa, const vect2_t *poly)
vect3l_t vect3l_mul(vect3l_t a, vect3l_t b)
ellip_t ellip_init(double semi_major, double semi_minor, double flattening)
vect2_t vect2_scmul(vect2_t a, double b)
vect3_t vect3_acf2local(vect3_t v, double roll, double pitch, double hdgt)
fpp_t stereo_fpp_init(geo_pos2_t center, double rot, const ellip_t *ellip, bool_t allow_inv)
double quad_bezier_func(double x, const bezier_t *func)
bezier_t * bezier_alloc(size_t num_pts)
geo_pos3_t ecmi2sph(vect3_t pos, double delta_t)
double fpp_get_gc_distance(vect2_t p1, vect2_t p2, const fpp_t *fpp)
#define GEO_POS3(lat, lon, elev)
vect3_t vect3_set_abs(vect3_t a, double abs)
vect3_t vect3_rot(vect3_t v, double angle, unsigned axis)
void bezier_free(bezier_t *curve)
vect2_t vect2_neg(vect2_t v)
double vect3_dotprod(vect3_t a, vect3_t b)
vect3l_t vect3l_scmul(vect3l_t a, long double b)
double gc_distance(geo_pos2_t start, geo_pos2_t end)
#define IS_NULL_GEO_POS(a)
void mat3_ident(mat3_t *mat)
double dir2hdg(vect2_t dir)
#define GEO_POS2(lat, lon)
vect2_t vect2_mul(vect2_t a, vect2_t b)
vect3_t vect3_sub(vect3_t a, vect3_t b)
vect3l_t vect3l_sub(vect3l_t a, vect3l_t b)
vect3_t geo2ecmi(geo_pos3_t pos, double delta_t, const ellip_t *ellip)
bool_t is_on_arc(double angle_x, double angle1, double angle2, bool_t cw)
vect2_t vect2_set_abs(vect2_t a, double abs)
double vect3_dist(vect3_t a, vect3_t b)
vect2_t vect2_mean(vect2_t a, vect2_t b)
vect3l_t vect3l_set_abs(vect3l_t a, long double abs)
double * quad_bezier_func_inv(double y, const bezier_t *func, size_t *n_xs)
geo_pos3_t geo2sph(geo_pos3_t pos, const ellip_t *ellip)
unsigned vect2poly_isect_get(vect2_t a, vect2_t oa, const vect2_t *poly, vect2_t *isects, unsigned cap)
double vect2_dist(vect2_t a, vect2_t b)
double rel_angle(double a1, double a2)
vect3_t sph2ecmi(geo_pos3_t pos, double delta_t)
vect3_t vect3_mean(vect3_t a, vect3_t b)
geo_pos3_t ecef2geo(vect3_t pos, const ellip_t *ellip)
vect2_t vect2_norm(vect2_t v, bool_t right)
vect3_t sph_xlate_vect(vect3_t pos, const sph_xlate_t *xlate)
double vect3_abs(vect3_t a)
unsigned circ2circ_isect(vect2_t ca, double ra, vect2_t cb, double rb, vect2_t i[2])
fpp_t ortho_fpp_init(geo_pos2_t center, double rot, const ellip_t *ellip, bool_t allow_inv)
unsigned vect2circ_isect(vect2_t v, vect2_t o, vect2_t c, double r, bool_t confined, vect2_t i[2])
vect3l_t vect3l_add(vect3l_t a, vect3l_t b)
double vect2_dotprod(vect2_t a, vect2_t b)
vect2_t vect2_rot_inv_y(vect2_t v, double angle)
geo_pos2_t geo_displace(const ellip_t *ellip, geo_pos2_t pos, double truehdg, double dist)
long double vect3l_abs(vect3l_t a)
lcc_t lcc_init(double reflat, double reflon, double stdpar1, double stdpar2)
vect3_t geo2ecef_ft(geo_pos3_t pos, const ellip_t *ellip)
vect3l_t vect3l_neg(vect3l_t v)
vect2_t geo2lcc(geo_pos2_t pos, const lcc_t *lcc)
vect3_t vect3_unit(vect3_t a, double *l)
vect2_t vect2_unit(vect2_t a, double *l)
vect3l_t vect3l_mean(vect3l_t a, vect3l_t b)
vect3l_t vect3l_rot(vect3l_t v, long double angle, unsigned axis)
geo_pos3_t ecef2sph(vect3_t v)
vect2_t hdg2dir(double truehdg)
void mat4_ident(mat4_t *mat)
static bool_t is_valid_elev(double elev)
static double normalize_hdg(double hdg)
static bool_t is_valid_lat(double lat)
static bool_t is_valid_lon(double lon)
unsigned quadratic_solve(double a, double b, double c, double x[2])
static void * safe_calloc(size_t nmemb, size_t size)
static void * safe_malloc(size_t size)