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