Geo-Index
view release on metacpan or search on metacpan
lat_0_idx = tmp;
}
/* Populate return values (all unsigned integers) */
Inline_Stack_Reset;
Inline_Stack_Push(sv_2mortal(newSVuv( grid_level )));
Inline_Stack_Push(sv_2mortal(newSVuv( grid_size )));
Inline_Stack_Push(sv_2mortal(newSVuv( max_grid_idx )));
Inline_Stack_Push(sv_2mortal(newSVuv( lat_0_idx )));
Inline_Stack_Push(sv_2mortal(newSVuv( lat_1_idx )));
Inline_Stack_Push(sv_2mortal(newSVuv( lon_0_idx )));
Inline_Stack_Push(sv_2mortal(newSVuv( lon_1_idx )));
Inline_Stack_Done;
}
/*
Compute distance between two points on a sphere
diameter is in meters
lat_0, lon_0, lat_1, and lon_1 are in radians
Distance returned is in meters
To compute a distance first call SetUpDistance(...) with the first point
then call HaversineDistance(...) to get the distance to a second point.
The C version can use either floats or doubles whereas Perl uses doubles.
When using floats instead of doubles the loss of precision is typically less
than a meter (about 2 meters in the worst case). On modern hardware there
should be little noticable difference between using floats and doubles. On
older hardware or in embedded systems floats may give better performance.
*/
/* Functions using floats */
float f_diameter, f_lat_1, f_lon_1;
float f_cos_lat_1;
void SetUpDistance_float(float new_diameter, float new_lat_1, float new_lon_1) {
f_diameter = new_diameter;
f_lat_1 = new_lat_1;
f_lon_1 = new_lon_1;
f_cos_lat_1 = cosf( new_lat_1 );
}
float HaversineDistance_float(float lat_0, float lon_0) {
float sin_lat_diff_over_2 = sinf( ( lat_0 - f_lat_1 ) / 2.0 );
float sin_lon_diff_over_2 = sinf( ( lon_0 - f_lon_1 ) / 2.0 );
float n = ( sin_lat_diff_over_2 * sin_lat_diff_over_2 )
+ (
( sin_lon_diff_over_2 * sin_lon_diff_over_2 )
* f_cos_lat_1
* cosf( lat_0 )
);
/* The haversine formula may get messy around antipodal points so clip to the largest sane value. */
if ( n < 0.0 ) { n = 0.0; }
return f_diameter * asinf( sqrtf(n) );
}
/* Functions using doubles */
double d_diameter, d_lat_1, d_lon_1;
double d_cos_lat_1;
void SetUpDistance_double(double new_diameter, double new_lat_1, double new_lon_1) {
d_diameter = new_diameter;
d_lat_1 = new_lat_1;
d_lon_1 = new_lon_1;
d_cos_lat_1 = cos( new_lat_1 );
}
double HaversineDistance_double(double lat_0, double lon_0) {
double sin_lat_diff_over_2 = sin( ( lat_0 - d_lat_1 ) / 2.0 );
double sin_lon_diff_over_2 = sin( ( lon_0 - d_lon_1 ) / 2.0 );
double n = ( sin_lat_diff_over_2 * sin_lat_diff_over_2 )
+ (
( sin_lon_diff_over_2 * sin_lon_diff_over_2 )
* d_cos_lat_1
* cos( lat_0 )
);
/* The haversine formula may get messy around antipodal points so clip to the largest sane value. */
if ( n < 0.0 ) { n = 0.0; }
return d_diameter * asin( sqrt(n) );
}
/* End of C code */
MODULE = Geo::Index PACKAGE = Geo::Index
PROTOTYPES: DISABLE
unsigned int
GetCCodeVersion ()
unsigned int
fast_log2_double (n)
double n
unsigned int
fast_log2_float (n)
float n
void
ComputeAreaExtrema_float (tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius)
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
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
ComputeAreaExtrema_float(tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
ComputeAreaExtrema_double (tile_adjust, max_size, max_level, p_lat, p_lat_rad, p_lon, polar_circumference, search_radius)
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
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
( run in 0.641 second using v1.01-cache-2.11-cpan-f56aa216473 )