1 /*
2  * Copyright (c) 2021 Marti Riba Pons
3  * Copyright (c) 2021 Kevin Townsend
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <stdio.h>
9 #include <math.h>
10 #include <errno.h>
11 #include <zsl/orientation/compass.h>
12 
zsl_comp_dms_to_dd(zsl_real_t d,zsl_real_t m,zsl_real_t s,zsl_real_t * dd)13 int zsl_comp_dms_to_dd(zsl_real_t d, zsl_real_t m, zsl_real_t s, zsl_real_t *dd)
14 {
15 	int rc = 0;
16 
17 	*dd = 0.0;
18 
19 #if CONFIG_ZSL_BOUNDS_CHECKS
20 	/* Minutes should always be positive and less than 60. */
21 	if ((m < 0.0) || (m > 60.0)) {
22 		rc = -EINVAL;
23 		goto err;
24 	}
25 
26 	/* Seconds should always be positive and less than 60. */
27 	if ((s < 0.0) || (s > 60.0)) {
28 		rc = -EINVAL;
29 		goto err;
30 	}
31 
32 	/* Degrees longitude must be between -180.0 and 180.0, and latitude must be
33 	 * between -90.0 and 90.0. Since we don't know which is being converted,
34 	 * the best we can do is limit this to the worst-case scenario.
35 	 */
36 	if ((d < -180.0) || (d > 180.0)) {
37 		rc = -EINVAL;
38 		goto err;
39 	}
40 #endif
41 
42 	/* Adjust for negative values with south and west. */
43 	if (d < 0.0) {
44 		/* South and west. */
45 		*dd = d - (m / 60.0) - (s / 3600.0);
46 	} else {
47 		/* North and east. */
48 		*dd = d + (m / 60.0) + (s / 3600.0);
49 	}
50 
51 err:
52 	return rc;
53 }
54 
zsl_comp_magn_north(struct zsl_vec * m,zsl_real_t * d)55 int zsl_comp_magn_north(struct zsl_vec *m, zsl_real_t *d)
56 {
57 	int rc = 0;
58 
59 #if CONFIG_ZSL_BOUNDS_CHECKS
60 	/* Make sure that the input vector have dimension 3. */
61 	if (m->sz != 3) {
62 		rc = -EINVAL;
63 		goto err;
64 	}
65 #endif
66 
67 	if (ZSL_ABS(m->data[1]) < 1E-6) {
68 		if (m->data[0] > 0.0) {
69 			*d = 0.0;
70 		} else {
71 			*d = 180.0;
72 		}
73 	} else if (m->data[1] > 0.0) {
74 		*d = 90.0 - ZSL_ATAN2(m->data[0], m->data[1]) * 180.0 / ZSL_PI;
75 	} else if (m->data[1] < 0.0) {
76 		*d = 270.0 - ZSL_ATAN2(m->data[0], m->data[1]) * 180.0 / ZSL_PI;
77 	}
78 
79 err:
80 	return rc;
81 }
82 
zsl_comp_geo_north(struct zsl_vec * m,zsl_real_t dec,zsl_real_t * d)83 int zsl_comp_geo_north(struct zsl_vec *m, zsl_real_t dec, zsl_real_t *d)
84 {
85 	int rc = 0;
86 
87 #if CONFIG_ZSL_BOUNDS_CHECKS
88 	/* Make sure that the input vector have dimension 3. */
89 	if (m->sz != 3) {
90 		rc = -EINVAL;
91 		goto err;
92 	}
93 #endif
94 
95 	zsl_comp_magn_north(m, d);
96 	*d += dec;
97 
98 err:
99 	return rc;
100 }
101