Fastest Way to Find Distance Between Two Lat/Long Points

后端 未结 15 980
时光说笑
时光说笑 2020-11-21 10:12

I currently have just under a million locations in a mysql database all with longitude and latitude information.

I am trying to find the distance between one point a

15条回答
  •  囚心锁ツ
    2020-11-21 10:44

    The full code with details about how to install as MySQL plugin are here: https://github.com/lucasepe/lib_mysqludf_haversine

    I posted this last year as comment. Since kindly @TylerCollier suggested me to post as answer, here it is.

    Another way is to write a custom UDF function that returns the haversine distance from two points. This function can take in input:

    lat1 (real), lng1 (real), lat2 (real), lng2 (real), type (string - optinal - 'km', 'ft', 'mi')
    

    So we can write something like this:

    SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2) < 40;
    

    to fetch all records with a distance less then 40 kilometers. Or:

    SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2, 'ft') < 25;
    

    to fetch all records with a distance less then 25 feet.

    The core function is:

    double
    haversine_distance( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ) {
        double result = *(double*) initid->ptr;
        /*Earth Radius in Kilometers.*/ 
        double R = 6372.797560856;
        double DEG_TO_RAD = M_PI/180.0;
        double RAD_TO_DEG = 180.0/M_PI;
        double lat1 = *(double*) args->args[0];
        double lon1 = *(double*) args->args[1];
        double lat2 = *(double*) args->args[2];
        double lon2 = *(double*) args->args[3];
        double dlon = (lon2 - lon1) * DEG_TO_RAD;
        double dlat = (lat2 - lat1) * DEG_TO_RAD;
        double a = pow(sin(dlat * 0.5),2) + 
            cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
        double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
        result = ( R * c );
        /*
         * If we have a 5th distance type argument...
         */
        if (args->arg_count == 5) {
            str_to_lowercase(args->args[4]);
            if (strcmp(args->args[4], "ft") == 0) result *= 3280.8399;
            if (strcmp(args->args[4], "mi") == 0) result *= 0.621371192;
        }
    
        return result;
    }
    

提交回复
热议问题