telegps-v1.0: Provide one log and append to it
[fw/altos] / src / kernel / ao_distance.c
1 /*
2  * Copyright © 2014 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_distance.h>
20
21 static uint32_t
22 ao_dist(int32_t a, int32_t b)
23 {
24         int32_t d = a - b;
25         if (d < 0)
26                 d = -d;
27
28         return (uint32_t) ((int64_t) d * 111198 / 10000000);
29 }
30
31 static uint32_t
32 ao_lat_dist(int32_t lat_a, int32_t lat_b)
33 {
34         return ao_dist(lat_a, lat_b);
35 }
36
37 static const uint8_t cos_table[] = {
38    0, /*  0 */
39    0, /*  1 */
40    0, /*  2 */
41  255, /*  3 */
42  254, /*  4 */
43  253, /*  5 */
44  252, /*  6 */
45  251, /*  7 */
46  249, /*  8 */
47  247, /*  9 */
48  245, /* 10 */
49  243, /* 11 */
50  240, /* 12 */
51  238, /* 13 */
52  235, /* 14 */
53  232, /* 15 */
54  228, /* 16 */
55  225, /* 17 */
56  221, /* 18 */
57  217, /* 19 */
58  213, /* 20 */
59  209, /* 21 */
60  205, /* 22 */
61  200, /* 23 */
62  195, /* 24 */
63  190, /* 25 */
64  185, /* 26 */
65  180, /* 27 */
66  175, /* 28 */
67  169, /* 29 */
68  163, /* 30 */
69  158, /* 31 */
70  152, /* 32 */
71  145, /* 33 */
72  139, /* 34 */
73  133, /* 35 */
74  126, /* 36 */
75  120, /* 37 */
76  113, /* 38 */
77  106, /* 39 */
78  100, /* 40 */
79   93, /* 41 */
80   86, /* 42 */
81   79, /* 43 */
82   71, /* 44 */
83   64, /* 45 */
84   57, /* 46 */
85   49, /* 47 */
86   42, /* 48 */
87   35, /* 49 */
88   27, /* 50 */
89   20, /* 51 */
90   12, /* 52 */
91    5, /* 53 */
92    1, /* 54 */
93 };
94
95 static uint32_t
96 ao_lon_dist(int32_t lon_a, int32_t lon_b)
97 {
98         uint8_t         c = cos_table[lon_a >> 24];
99         uint32_t        lon_dist;
100
101         /* check if it's shorter to go the other way around */
102         if ((lon_a >> 1) < (lon_b >> 1) - (1800000000 >> 1))
103                 lon_a += 3600000000;
104         lon_dist = ao_dist(lon_a, lon_b);
105         if (c) {
106                 if (lon_dist & 0x7f800000)
107                         lon_dist = (lon_dist >> 8) * c;
108                 else
109                         lon_dist = (lon_dist * (int16_t) c) >> 8;
110         }
111         return lon_dist;
112 }
113
114 static uint32_t sqr(uint32_t x) { return x * x; }
115
116 uint32_t
117 ao_distance(int32_t lat_a, int32_t lon_a, int32_t lat_b, int32_t lon_b)
118 {
119         uint32_t        lat_dist = ao_lat_dist(lat_a, lat_b);
120         uint32_t        lon_dist = ao_lon_dist(lon_a, lon_b);
121
122         return ao_sqrt (sqr(lat_dist) + sqr(lon_dist));
123 }