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
|
|
|
|
|
|
|
|