GEOSEARCH BYBOX: Simplified haversine distance formula when longitude diff is 0 (#11579)
This is take 2 of `GEOSEARCH BYBOX` optimizations based on haversine distance formula when longitude diff is 0. The first one was in #11535 . - Given longitude diff is 0 the asin(sqrt(a)) on the haversine is asin(sin(abs(u))). - arcsin(sin(x)) equal to x when x ∈[−𝜋/2,𝜋/2]. - Given latitude is between [−𝜋/2,𝜋/2] we can simplifiy arcsin(sin(x)) to x. On the sample dataset with 60M datapoints, we've measured 55% increase in the achievable ops/sec.
This commit is contained in:
parent
2d80cd7840
commit
e48ac075c0
@ -216,20 +216,28 @@ GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) {
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* Calculate distance using simplified haversine great circle distance formula.
|
||||
* Given longitude diff is 0 the asin(sqrt(a)) on the haversine is asin(sin(abs(u))).
|
||||
* arcsin(sin(x)) equal to x when x ∈[−𝜋/2,𝜋/2]. Given latitude is between [−𝜋/2,𝜋/2]
|
||||
* we can simplify arcsin(sin(x)) to x.
|
||||
*/
|
||||
double geohashGetLatDistance(double lat1d, double lat2d) {
|
||||
return EARTH_RADIUS_IN_METERS * fabs(deg_rad(lat2d) - deg_rad(lat1d));
|
||||
}
|
||||
|
||||
/* Calculate distance using haversine great circle distance formula. */
|
||||
double geohashGetDistance(double lon1d, double lat1d, double lon2d, double lat2d) {
|
||||
double lat1r, lon1r, lat2r, lon2r, u, v;
|
||||
lat1r = deg_rad(lat1d);
|
||||
double lat1r, lon1r, lat2r, lon2r, u, v, a;
|
||||
lon1r = deg_rad(lon1d);
|
||||
lat2r = deg_rad(lat2d);
|
||||
lon2r = deg_rad(lon2d);
|
||||
u = sin((lat2r - lat1r) / 2);
|
||||
v = sin((lon2r - lon1r) / 2);
|
||||
double a = u * u;
|
||||
/* if v == 0 we can avoid doing expensive math */
|
||||
if (v != 0.0){
|
||||
a += cos(lat1r) * cos(lat2r) * v * v;
|
||||
}
|
||||
/* if v == 0 we can avoid doing expensive math when lons are practically the same */
|
||||
if (v == 0.0)
|
||||
return geohashGetLatDistance(lat1d, lat2d);
|
||||
lat1r = deg_rad(lat1d);
|
||||
lat2r = deg_rad(lat2d);
|
||||
u = sin((lat2r - lat1r) / 2);
|
||||
a = u * u + cos(lat1r) * cos(lat2r) * v * v;
|
||||
return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(a));
|
||||
}
|
||||
|
||||
@ -259,7 +267,7 @@ int geohashGetDistanceIfInRectangle(double width_m, double height_m, double x1,
|
||||
double x2, double y2, double *distance) {
|
||||
/* latitude distance is less expensive to compute than longitude distance
|
||||
* so we check first for the latitude condition */
|
||||
double lat_distance = geohashGetDistance(x2, y2, x2, y1);
|
||||
double lat_distance = geohashGetLatDistance(y2, y1);
|
||||
if (lat_distance > height_m/2) {
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user