| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
2
|
|
|
|
|
|
|
#include "perl.h" |
|
3
|
|
|
|
|
|
|
#include "XSUB.h" |
|
4
|
|
|
|
|
|
|
#include "INLINE.h" |
|
5
|
|
|
|
|
|
|
/* Start of C code */ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
// This code requires at least a C99 compiler (for uint_* types and // comments) |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#define MAJOR_VERSION 0 |
|
10
|
|
|
|
|
|
|
#define MINOR_VERSION 0 |
|
11
|
|
|
|
|
|
|
#define SUB_VERSION 7 |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
/* Do not put void in the parameters below, it'll break XS */ |
|
14
|
2
|
|
|
|
|
|
unsigned int GetCCodeVersion( ) { |
|
15
|
2
|
|
|
|
|
|
return ( MAJOR_VERSION << 20 ) | ( MINOR_VERSION << 10 ) | SUB_VERSION; |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
/* |
|
19
|
|
|
|
|
|
|
All functions below come in two versions, one using single-precision (float) |
|
20
|
|
|
|
|
|
|
math and variables and the other using double-precision (double) math and |
|
21
|
|
|
|
|
|
|
variables. Functionally, the two versions of each function are identical. |
|
22
|
|
|
|
|
|
|
*/ |
|
23
|
|
|
|
|
|
|
|
|
24
|
100
|
|
|
|
|
|
unsigned int fast_log2_double(double n) { |
|
25
|
100
|
|
|
|
|
|
return ceil( log2(n) ); |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
|
|
28
|
29
|
|
|
|
|
|
unsigned int fast_log2_float(float n) { |
|
29
|
29
|
|
|
|
|
|
return ceilf( log2f(n) ); |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
#define PI 3.14159265358979 |
|
34
|
|
|
|
|
|
|
#define DEG2RAD (PI / 180.0) * |
|
35
|
|
|
|
|
|
|
#define RAD2DEG (180.0 / PI) * |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
/* |
|
38
|
|
|
|
|
|
|
This code accelerates the set-up code in the Search(...) method. Functionally it is identical to the Perl version. |
|
39
|
|
|
|
|
|
|
Called as ( $grid_level, $grid_size, $max_grid_idx, $lat_0_idx, $lat_1_idx, $lon_0_idx, $lon_1_idx ) = ComputeAreaExtrema( $tile_adjust, $max_size, $max_level, $p_lat, $p_lat_rad, $p_lon, $self->{polar_circumference}, $search_radius ); |
|
40
|
|
|
|
|
|
|
*/ |
|
41
|
|
|
|
|
|
|
|
|
42
|
29
|
|
|
|
|
|
void ComputeAreaExtrema_float( int tile_adjust, unsigned long max_size, unsigned int max_level, float p_lat, float p_lat_rad, float p_lon, float polar_circumference, float search_radius ) { |
|
43
|
29
|
|
|
|
|
|
Inline_Stack_Vars; /* For return values */ |
|
44
|
|
|
|
|
|
|
|
|
45
|
29
|
|
|
|
|
|
uint_fast8_t grid_level = 0; |
|
46
|
29
|
|
|
|
|
|
uint_fast32_t grid_size = 0; |
|
47
|
29
|
|
|
|
|
|
uint_fast32_t max_grid_idx = 0; |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
// Determine grid level to search at |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
// Size of most detailed grid tile at this point (in meters) |
|
52
|
29
|
|
|
|
|
|
float ns_indexed_meters = ( polar_circumference / 2.0 ) / max_size; // Dividing by two to get pole-to-pole distance |
|
53
|
|
|
|
|
|
|
|
|
54
|
29
|
|
|
|
|
|
uint_fast8_t shift = fast_log2_float( search_radius / ns_indexed_meters ); |
|
55
|
|
|
|
|
|
|
|
|
56
|
29
|
|
|
|
|
|
shift += tile_adjust; |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
// Make sure the shift we computed lies within the index levels |
|
59
|
|
|
|
|
|
|
if (shift < 0) { |
|
60
|
|
|
|
|
|
|
shift = 0; |
|
61
|
29
|
100
|
|
|
|
|
} else if (shift >= max_level) { |
|
62
|
7
|
|
|
|
|
|
shift = max_level - 1; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
// Shift is relative to the highest-resolution zoom level |
|
66
|
|
|
|
|
|
|
// Determine grid level to use |
|
67
|
29
|
|
|
|
|
|
grid_level = max_level - shift; |
|
68
|
|
|
|
|
|
|
|
|
69
|
29
|
|
|
|
|
|
grid_size = 1 << (grid_level+1); |
|
70
|
29
|
|
|
|
|
|
max_grid_idx = grid_size - 1; |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
// Determine which grid tiles need to be checked |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
// Get search point's grid indices |
|
75
|
|
|
|
|
|
|
|
|
76
|
29
|
|
|
|
|
|
float lat_meter_in_degrees = 360.0 / polar_circumference; |
|
77
|
|
|
|
|
|
|
|
|
78
|
29
|
|
|
|
|
|
float lat_radius = search_radius * lat_meter_in_degrees; |
|
79
|
29
|
|
|
|
|
|
float lat_radius_rad = DEG2RAD( lat_radius ); |
|
80
|
29
|
|
|
|
|
|
float lon_radius = RAD2DEG( atan2f( sinf(lat_radius_rad), cosf(lat_radius_rad) * cosf(p_lat_rad) ) ); |
|
81
|
|
|
|
|
|
|
|
|
82
|
29
|
|
|
|
|
|
float lat_0 = p_lat - lat_radius; |
|
83
|
29
|
|
|
|
|
|
float lat_1 = p_lat + lat_radius; |
|
84
|
|
|
|
|
|
|
|
|
85
|
29
|
|
|
|
|
|
float lon_0 = p_lon - lon_radius; |
|
86
|
29
|
|
|
|
|
|
float lon_1 = p_lon + lon_radius; |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
29
|
100
|
|
|
|
|
if (lat_0 <= -90) { |
|
90
|
7
|
|
|
|
|
|
lat_0 = -90; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
29
|
100
|
|
|
|
|
if (lat_1 >= 90) { |
|
94
|
5
|
|
|
|
|
|
lat_1 = 90; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
29
|
100
|
|
|
|
|
if ( lon_0 < -180.0 ) { lon_0 += 360.0; } |
|
98
|
27
|
50
|
|
|
|
|
else if ( lon_0 > 180.0 ) { lon_0 -= 360.0; } |
|
99
|
|
|
|
|
|
|
|
|
100
|
29
|
50
|
|
|
|
|
if ( lon_1 < -180.0 ) { lon_1 += 360.0; } |
|
101
|
29
|
100
|
|
|
|
|
else if ( lon_1 > 180.0 ) { lon_1 -= 360.0; } |
|
102
|
|
|
|
|
|
|
|
|
103
|
29
|
50
|
|
|
|
|
if ( lat_0 < -90.0 ) { lat_0 = -90.0; } |
|
104
|
29
|
50
|
|
|
|
|
else if ( lat_0 > 90.0 ) { lat_0 = 90.0; } |
|
105
|
|
|
|
|
|
|
|
|
106
|
29
|
50
|
|
|
|
|
if ( lat_1 < -90.0 ) { lat_1 = -90.0; } |
|
107
|
29
|
50
|
|
|
|
|
else if ( lat_1 > 90.0 ) { lat_1 = 90.0; } |
|
108
|
|
|
|
|
|
|
|
|
109
|
29
|
|
|
|
|
|
uint_fast32_t lat_0_idx = (uint_fast32_t)( ( lat_0 + 90.0 ) * max_size / 180.0 ); |
|
110
|
29
|
100
|
|
|
|
|
if (lat_0_idx >= max_size) lat_0_idx = max_size - 1; |
|
111
|
29
|
|
|
|
|
|
lat_0_idx >>= shift; |
|
112
|
|
|
|
|
|
|
|
|
113
|
29
|
|
|
|
|
|
uint_fast32_t lat_1_idx = (uint_fast32_t)( ( lat_1 + 90.0 ) * max_size / 180.0 ); |
|
114
|
29
|
100
|
|
|
|
|
if (lat_1_idx >= max_size) lat_1_idx = max_size - 1; |
|
115
|
29
|
|
|
|
|
|
lat_1_idx >>= shift; |
|
116
|
|
|
|
|
|
|
|
|
117
|
29
|
|
|
|
|
|
uint_fast32_t lon_0_idx = ( (uint_fast32_t)( ( lon_0 + 180.0 ) * max_size / 360.0 ) % max_size ) >> shift; |
|
118
|
|
|
|
|
|
|
|
|
119
|
29
|
|
|
|
|
|
uint_fast32_t lon_1_idx = ( (uint_fast32_t)( ( lon_1 + 180.0 ) * max_size / 360.0 ) % max_size ) >> shift; |
|
120
|
|
|
|
|
|
|
|
|
121
|
29
|
50
|
|
|
|
|
if (lat_0_idx > lat_1_idx) { |
|
122
|
0
|
|
|
|
|
|
uint_fast32_t tmp = lat_1_idx; |
|
123
|
0
|
|
|
|
|
|
lat_1_idx = lat_0_idx; |
|
124
|
0
|
|
|
|
|
|
lat_0_idx = tmp; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
/* Populate return values (all unsigned integers) */ |
|
128
|
|
|
|
|
|
|
|
|
129
|
29
|
|
|
|
|
|
Inline_Stack_Reset; |
|
130
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( grid_level ))); |
|
131
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( grid_size ))); |
|
132
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( max_grid_idx ))); |
|
133
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lat_0_idx ))); |
|
134
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lat_1_idx ))); |
|
135
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lon_0_idx ))); |
|
136
|
29
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lon_1_idx ))); |
|
137
|
29
|
|
|
|
|
|
Inline_Stack_Done; |
|
138
|
29
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
|
141
|
62
|
|
|
|
|
|
void ComputeAreaExtrema_double( int tile_adjust, unsigned long max_size, unsigned int max_level, double p_lat, double p_lat_rad, double p_lon, double polar_circumference, double search_radius ) { |
|
142
|
62
|
|
|
|
|
|
Inline_Stack_Vars; /* For return values */ |
|
143
|
|
|
|
|
|
|
|
|
144
|
62
|
|
|
|
|
|
uint_fast8_t grid_level = 0; |
|
145
|
62
|
|
|
|
|
|
uint_fast32_t grid_size = 0; |
|
146
|
62
|
|
|
|
|
|
uint_fast32_t max_grid_idx = 0; |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
// Determine grid level to search at |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
// Size of most detailed grid tile at this point (in meters) |
|
151
|
62
|
|
|
|
|
|
double ns_indexed_meters = ( polar_circumference / 2.0 ) / max_size; // Dividing by two to get pole-to-pole distance |
|
152
|
|
|
|
|
|
|
|
|
153
|
62
|
|
|
|
|
|
uint_fast8_t shift = fast_log2_double( search_radius / ns_indexed_meters ); |
|
154
|
|
|
|
|
|
|
|
|
155
|
62
|
|
|
|
|
|
shift += tile_adjust; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
// Make sure the shift we computed lies within the index levels |
|
158
|
|
|
|
|
|
|
if (shift < 0) { |
|
159
|
|
|
|
|
|
|
shift = 0; |
|
160
|
62
|
100
|
|
|
|
|
} else if (shift >= max_level) { |
|
161
|
14
|
|
|
|
|
|
shift = max_level - 1; |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
// Shift is relative to the highest-resolution zoom level |
|
165
|
|
|
|
|
|
|
// Determine grid level to use |
|
166
|
62
|
|
|
|
|
|
grid_level = max_level - shift; |
|
167
|
|
|
|
|
|
|
|
|
168
|
62
|
|
|
|
|
|
grid_size = 1 << (grid_level+1); |
|
169
|
62
|
|
|
|
|
|
max_grid_idx = grid_size - 1; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
// Determine which grid tiles need to be checked |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
// Get search point's grid indices |
|
174
|
|
|
|
|
|
|
|
|
175
|
62
|
|
|
|
|
|
double lat_meter_in_degrees = 360.0 / polar_circumference; |
|
176
|
|
|
|
|
|
|
|
|
177
|
62
|
|
|
|
|
|
double lat_radius = search_radius * lat_meter_in_degrees; |
|
178
|
62
|
|
|
|
|
|
double lat_radius_rad = DEG2RAD( lat_radius ); |
|
179
|
62
|
|
|
|
|
|
double lon_radius = RAD2DEG( atan2( sin(lat_radius_rad), cos(lat_radius_rad) * cos(p_lat_rad) ) ); |
|
180
|
|
|
|
|
|
|
|
|
181
|
62
|
|
|
|
|
|
double lat_0 = p_lat - lat_radius; |
|
182
|
62
|
|
|
|
|
|
double lat_1 = p_lat + lat_radius; |
|
183
|
|
|
|
|
|
|
|
|
184
|
62
|
|
|
|
|
|
double lon_0 = p_lon - lon_radius; |
|
185
|
62
|
|
|
|
|
|
double lon_1 = p_lon + lon_radius; |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
|
188
|
62
|
100
|
|
|
|
|
if (lat_0 <= -90) { |
|
189
|
15
|
|
|
|
|
|
lat_0 = -90; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
62
|
100
|
|
|
|
|
if (lat_1 >= 90) { |
|
193
|
10
|
|
|
|
|
|
lat_1 = 90; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
62
|
100
|
|
|
|
|
if ( lon_0 < -180.0 ) { lon_0 += 360.0; } |
|
197
|
58
|
50
|
|
|
|
|
else if ( lon_0 > 180.0 ) { lon_0 -= 360.0; } |
|
198
|
|
|
|
|
|
|
|
|
199
|
62
|
50
|
|
|
|
|
if ( lon_1 < -180.0 ) { lon_1 += 360.0; } |
|
200
|
62
|
100
|
|
|
|
|
else if ( lon_1 > 180.0 ) { lon_1 -= 360.0; } |
|
201
|
|
|
|
|
|
|
|
|
202
|
62
|
50
|
|
|
|
|
if ( lat_0 < -90.0 ) { lat_0 = -90.0; } |
|
203
|
62
|
50
|
|
|
|
|
else if ( lat_0 > 90.0 ) { lat_0 = 90.0; } |
|
204
|
|
|
|
|
|
|
|
|
205
|
62
|
50
|
|
|
|
|
if ( lat_1 < -90.0 ) { lat_1 = -90.0; } |
|
206
|
62
|
50
|
|
|
|
|
else if ( lat_1 > 90.0 ) { lat_1 = 90.0; } |
|
207
|
|
|
|
|
|
|
|
|
208
|
62
|
|
|
|
|
|
uint_fast32_t lat_0_idx = (uint_fast32_t)( ( lat_0 + 90.0 ) * max_size / 180.0 ); |
|
209
|
62
|
100
|
|
|
|
|
if (lat_0_idx >= max_size) lat_0_idx = max_size - 1; |
|
210
|
62
|
|
|
|
|
|
lat_0_idx >>= shift; |
|
211
|
|
|
|
|
|
|
|
|
212
|
62
|
|
|
|
|
|
uint_fast32_t lat_1_idx = (uint_fast32_t)( ( lat_1 + 90.0 ) * max_size / 180.0 ); |
|
213
|
62
|
100
|
|
|
|
|
if (lat_1_idx >= max_size) lat_1_idx = max_size - 1; |
|
214
|
62
|
|
|
|
|
|
lat_1_idx >>= shift; |
|
215
|
|
|
|
|
|
|
|
|
216
|
62
|
|
|
|
|
|
uint_fast32_t lon_0_idx = ( (uint_fast32_t)( ( lon_0 + 180.0 ) * max_size / 360.0 ) % max_size ) >> shift; |
|
217
|
|
|
|
|
|
|
|
|
218
|
62
|
|
|
|
|
|
uint_fast32_t lon_1_idx = ( (uint_fast32_t)( ( lon_1 + 180.0 ) * max_size / 360.0 ) % max_size ) >> shift; |
|
219
|
|
|
|
|
|
|
|
|
220
|
62
|
50
|
|
|
|
|
if (lat_0_idx > lat_1_idx) { |
|
221
|
0
|
|
|
|
|
|
uint_fast32_t tmp = lat_1_idx; |
|
222
|
0
|
|
|
|
|
|
lat_1_idx = lat_0_idx; |
|
223
|
0
|
|
|
|
|
|
lat_0_idx = tmp; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
/* Populate return values (all unsigned integers) */ |
|
227
|
|
|
|
|
|
|
|
|
228
|
62
|
|
|
|
|
|
Inline_Stack_Reset; |
|
229
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( grid_level ))); |
|
230
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( grid_size ))); |
|
231
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( max_grid_idx ))); |
|
232
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lat_0_idx ))); |
|
233
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lat_1_idx ))); |
|
234
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lon_0_idx ))); |
|
235
|
62
|
50
|
|
|
|
|
Inline_Stack_Push(sv_2mortal(newSVuv( lon_1_idx ))); |
|
236
|
62
|
|
|
|
|
|
Inline_Stack_Done; |
|
237
|
62
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
/* |
|
243
|
|
|
|
|
|
|
Compute distance between two points on a sphere |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
diameter is in meters |
|
246
|
|
|
|
|
|
|
lat_0, lon_0, lat_1, and lon_1 are in radians |
|
247
|
|
|
|
|
|
|
Distance returned is in meters |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
To compute a distance first call SetUpDistance(...) with the first point |
|
250
|
|
|
|
|
|
|
then call HaversineDistance(...) to get the distance to a second point. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
The C version can use either floats or doubles whereas Perl uses doubles. |
|
253
|
|
|
|
|
|
|
When using floats instead of doubles the loss of precision is typically less |
|
254
|
|
|
|
|
|
|
than a meter (about 2 meters in the worst case). On modern hardware there |
|
255
|
|
|
|
|
|
|
should be little noticable difference between using floats and doubles. On |
|
256
|
|
|
|
|
|
|
older hardware or in embedded systems floats may give better performance. |
|
257
|
|
|
|
|
|
|
*/ |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
/* Functions using floats */ |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
float f_diameter, f_lat_1, f_lon_1; |
|
263
|
|
|
|
|
|
|
float f_cos_lat_1; |
|
264
|
|
|
|
|
|
|
|
|
265
|
51
|
|
|
|
|
|
void SetUpDistance_float(float new_diameter, float new_lat_1, float new_lon_1) { |
|
266
|
51
|
|
|
|
|
|
f_diameter = new_diameter; |
|
267
|
51
|
|
|
|
|
|
f_lat_1 = new_lat_1; |
|
268
|
51
|
|
|
|
|
|
f_lon_1 = new_lon_1; |
|
269
|
51
|
|
|
|
|
|
f_cos_lat_1 = cosf( new_lat_1 ); |
|
270
|
51
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
170
|
|
|
|
|
|
float HaversineDistance_float(float lat_0, float lon_0) { |
|
273
|
170
|
|
|
|
|
|
float sin_lat_diff_over_2 = sinf( ( lat_0 - f_lat_1 ) / 2.0 ); |
|
274
|
170
|
|
|
|
|
|
float sin_lon_diff_over_2 = sinf( ( lon_0 - f_lon_1 ) / 2.0 ); |
|
275
|
|
|
|
|
|
|
|
|
276
|
340
|
|
|
|
|
|
float n = ( sin_lat_diff_over_2 * sin_lat_diff_over_2 ) |
|
277
|
|
|
|
|
|
|
+ ( |
|
278
|
170
|
|
|
|
|
|
( sin_lon_diff_over_2 * sin_lon_diff_over_2 ) |
|
279
|
170
|
|
|
|
|
|
* f_cos_lat_1 |
|
280
|
170
|
|
|
|
|
|
* cosf( lat_0 ) |
|
281
|
|
|
|
|
|
|
); |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
/* The haversine formula may get messy around antipodal points so clip to the largest sane value. */ |
|
284
|
170
|
50
|
|
|
|
|
if ( n < 0.0 ) { n = 0.0; } |
|
285
|
|
|
|
|
|
|
|
|
286
|
170
|
|
|
|
|
|
return f_diameter * asinf( sqrtf(n) ); |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
/* Functions using doubles */ |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
double d_diameter, d_lat_1, d_lon_1; |
|
294
|
|
|
|
|
|
|
double d_cos_lat_1; |
|
295
|
|
|
|
|
|
|
|
|
296
|
140
|
|
|
|
|
|
void SetUpDistance_double(double new_diameter, double new_lat_1, double new_lon_1) { |
|
297
|
140
|
|
|
|
|
|
d_diameter = new_diameter; |
|
298
|
140
|
|
|
|
|
|
d_lat_1 = new_lat_1; |
|
299
|
140
|
|
|
|
|
|
d_lon_1 = new_lon_1; |
|
300
|
140
|
|
|
|
|
|
d_cos_lat_1 = cos( new_lat_1 ); |
|
301
|
140
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
|
|
303
|
1218
|
|
|
|
|
|
double HaversineDistance_double(double lat_0, double lon_0) { |
|
304
|
1218
|
|
|
|
|
|
double sin_lat_diff_over_2 = sin( ( lat_0 - d_lat_1 ) / 2.0 ); |
|
305
|
1218
|
|
|
|
|
|
double sin_lon_diff_over_2 = sin( ( lon_0 - d_lon_1 ) / 2.0 ); |
|
306
|
|
|
|
|
|
|
|
|
307
|
2436
|
|
|
|
|
|
double n = ( sin_lat_diff_over_2 * sin_lat_diff_over_2 ) |
|
308
|
|
|
|
|
|
|
+ ( |
|
309
|
1218
|
|
|
|
|
|
( sin_lon_diff_over_2 * sin_lon_diff_over_2 ) |
|
310
|
1218
|
|
|
|
|
|
* d_cos_lat_1 |
|
311
|
1218
|
|
|
|
|
|
* cos( lat_0 ) |
|
312
|
|
|
|
|
|
|
); |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
/* The haversine formula may get messy around antipodal points so clip to the largest sane value. */ |
|
315
|
1218
|
50
|
|
|
|
|
if ( n < 0.0 ) { n = 0.0; } |
|
316
|
|
|
|
|
|
|
|
|
317
|
1218
|
|
|
|
|
|
return d_diameter * asin( sqrt(n) ); |
|
318
|
|
|
|
|
|
|
} |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
/* End of C code */ |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
MODULE = Geo::Index PACKAGE = Geo::Index |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
unsigned int |
|
328
|
|
|
|
|
|
|
GetCCodeVersion () |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
unsigned int |
|
331
|
|
|
|
|
|
|
fast_log2_double (n) |
|
332
|
|
|
|
|
|
|
double n |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
unsigned int |
|
335
|
|
|
|
|
|
|
fast_log2_float (n) |
|
336
|
|
|
|
|
|
|
float n |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
void |
|
339
|
|
|
|
|
|
|
ComputeAreaExtrema_float (tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius) |
|
340
|
|
|
|
|
|
|
int tile_adjust |
|
341
|
|
|
|
|
|
|
unsigned long max_size |
|
342
|
|
|
|
|
|
|
unsigned int max_level |
|
343
|
|
|
|
|
|
|
float p_lat |
|
344
|
|
|
|
|
|
|
float p_lat_rad |
|
345
|
|
|
|
|
|
|
float p_lon |
|
346
|
|
|
|
|
|
|
float polar_circumference |
|
347
|
|
|
|
|
|
|
float search_radius |
|
348
|
|
|
|
|
|
|
PREINIT: |
|
349
|
|
|
|
|
|
|
I32* temp; |
|
350
|
|
|
|
|
|
|
PPCODE: |
|
351
|
29
|
|
|
|
|
|
temp = PL_markstack_ptr++; |
|
352
|
29
|
|
|
|
|
|
ComputeAreaExtrema_float(tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius); |
|
353
|
29
|
50
|
|
|
|
|
if (PL_markstack_ptr != temp) { |
|
354
|
|
|
|
|
|
|
/* truly void, because dXSARGS not invoked */ |
|
355
|
0
|
|
|
|
|
|
PL_markstack_ptr = temp; |
|
356
|
0
|
|
|
|
|
|
XSRETURN_EMPTY; /* return empty stack */ |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
/* must have used dXSARGS; list context implied */ |
|
359
|
29
|
|
|
|
|
|
return; /* assume stack size is correct */ |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
void |
|
362
|
|
|
|
|
|
|
ComputeAreaExtrema_double (tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius) |
|
363
|
|
|
|
|
|
|
int tile_adjust |
|
364
|
|
|
|
|
|
|
unsigned long max_size |
|
365
|
|
|
|
|
|
|
unsigned int max_level |
|
366
|
|
|
|
|
|
|
double p_lat |
|
367
|
|
|
|
|
|
|
double p_lat_rad |
|
368
|
|
|
|
|
|
|
double p_lon |
|
369
|
|
|
|
|
|
|
double polar_circumference |
|
370
|
|
|
|
|
|
|
double search_radius |
|
371
|
|
|
|
|
|
|
PREINIT: |
|
372
|
|
|
|
|
|
|
I32* temp; |
|
373
|
|
|
|
|
|
|
PPCODE: |
|
374
|
62
|
|
|
|
|
|
temp = PL_markstack_ptr++; |
|
375
|
62
|
|
|
|
|
|
ComputeAreaExtrema_double(tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius); |
|
376
|
62
|
50
|
|
|
|
|
if (PL_markstack_ptr != temp) { |
|
377
|
|
|
|
|
|
|
/* truly void, because dXSARGS not invoked */ |
|
378
|
0
|
|
|
|
|
|
PL_markstack_ptr = temp; |
|
379
|
0
|
|
|
|
|
|
XSRETURN_EMPTY; /* return empty stack */ |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
/* must have used dXSARGS; list context implied */ |
|
382
|
62
|
|
|
|
|
|
return; /* assume stack size is correct */ |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
void |
|
385
|
|
|
|
|
|
|
SetUpDistance_float (new_diameter, new_lat_1, new_lon_1) |
|
386
|
|
|
|
|
|
|
float new_diameter |
|
387
|
|
|
|
|
|
|
float new_lat_1 |
|
388
|
|
|
|
|
|
|
float new_lon_1 |
|
389
|
|
|
|
|
|
|
PREINIT: |
|
390
|
|
|
|
|
|
|
I32* temp; |
|
391
|
|
|
|
|
|
|
PPCODE: |
|
392
|
51
|
|
|
|
|
|
temp = PL_markstack_ptr++; |
|
393
|
51
|
|
|
|
|
|
SetUpDistance_float(new_diameter, new_lat_1, new_lon_1); |
|
394
|
51
|
50
|
|
|
|
|
if (PL_markstack_ptr != temp) { |
|
395
|
|
|
|
|
|
|
/* truly void, because dXSARGS not invoked */ |
|
396
|
51
|
|
|
|
|
|
PL_markstack_ptr = temp; |
|
397
|
51
|
|
|
|
|
|
XSRETURN_EMPTY; /* return empty stack */ |
|
398
|
|
|
|
|
|
|
} |
|
399
|
|
|
|
|
|
|
/* must have used dXSARGS; list context implied */ |
|
400
|
0
|
|
|
|
|
|
return; /* assume stack size is correct */ |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
float |
|
403
|
|
|
|
|
|
|
HaversineDistance_float (lat_0, lon_0) |
|
404
|
|
|
|
|
|
|
float lat_0 |
|
405
|
|
|
|
|
|
|
float lon_0 |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
void |
|
408
|
|
|
|
|
|
|
SetUpDistance_double (new_diameter, new_lat_1, new_lon_1) |
|
409
|
|
|
|
|
|
|
double new_diameter |
|
410
|
|
|
|
|
|
|
double new_lat_1 |
|
411
|
|
|
|
|
|
|
double new_lon_1 |
|
412
|
|
|
|
|
|
|
PREINIT: |
|
413
|
|
|
|
|
|
|
I32* temp; |
|
414
|
|
|
|
|
|
|
PPCODE: |
|
415
|
140
|
|
|
|
|
|
temp = PL_markstack_ptr++; |
|
416
|
140
|
|
|
|
|
|
SetUpDistance_double(new_diameter, new_lat_1, new_lon_1); |
|
417
|
140
|
50
|
|
|
|
|
if (PL_markstack_ptr != temp) { |
|
418
|
|
|
|
|
|
|
/* truly void, because dXSARGS not invoked */ |
|
419
|
140
|
|
|
|
|
|
PL_markstack_ptr = temp; |
|
420
|
140
|
|
|
|
|
|
XSRETURN_EMPTY; /* return empty stack */ |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
/* must have used dXSARGS; list context implied */ |
|
423
|
0
|
|
|
|
|
|
return; /* assume stack size is correct */ |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
double |
|
426
|
|
|
|
|
|
|
HaversineDistance_double (lat_0, lon_0) |
|
427
|
|
|
|
|
|
|
double lat_0 |
|
428
|
|
|
|
|
|
|
double lon_0 |
|
429
|
|
|
|
|
|
|
|