解决Halversine中的lat或lon?

时间:2012-03-05 10:13:56

标签: gis

我需要一个函数,在给定纬度/经度坐标,以英里为单位的距离和相交的纬度时返回经度值。要做到这一点,我需要使用Halversine,如下所述: https://stackoverflow.com/a/7179026/78202。我意识到将有两个经度与给定纬度相交一个给定距离与另一个有序对,我只想得到一个点,我有一个函数正确返回其中一个,我将决定如何打破然后领带。

我随便为lon1解决了Holversine,这就是我所拥有的。这部分是一个数学问题,部分是编程问题 - 这有什么问题?没有语法错误,我只是没有达到我的预期(见下文)。

function toRad(Value) {
    /** Converts numeric degrees to radians */
    return Value * Math.PI / 180;
}

/** returns the longitude a certain number of miles from another point given a latitude. **/
function getLon(miles, lat1, lat2, lon2) {
  // see http://www.movable-type.co.uk/scripts/latlong.html
  //Radius of the earth in:  1.609344 miles,  6371 km  | var R = (6371 / 1.609344);
    var R = 3958.7558657440545; // Radius of earth in Miles 
    miles = (typeof miles === "undefined") ? 1.46628357399041 : miles;
    lat1 = (typeof lat1 === "undefined") ? 42.34769 : lat1;
    lat2 = (typeof lat2 === "undefined") ? 42.367137 : lat2;
    lon2 = (typeof lon2 === "undefined") ? -71.124383 : lon2;
    var dLat =   toRad( lat2-lat1 );
    var sinInsideN1 = Math.sin(dLat);
    var sinInsideN2 = Math.sin(miles/2*R);
    var n1 = Math.pow(sinInsideN1,2);
    var n2 = Math.pow(sinInsideN2,2);
    var d1 = Math.cos(lat1)*Math.cos(lat2);
    var inArcsin = Math.sqrt((n2-n1)/d1);
    var translation = inArcsin-Math.floor(inArcsin);
    var ret = -(lat1+2*Math.asin(translation))
    return ret; // should be 42.34769
}

我得到42.242513701215,与42.34769形成一个坐标,距离(42.367137,-71.124383)为8.63065661614176,而不是预期的1.46628357399041 mi。

2 个答案:

答案 0 :(得分:1)

我在这里找到了一个Haversine的C实现http://code.google.com/p/siklon/source/browse/trunk/source/Haversine.c?r=11,然后我重写了lon1:

#include <math.h>

/*Earth Radius in Kilometers.*/
/* static const double R = 6372.797560856; */
/*Earth Radius in Miles.*/
static const double R = 3958.7558657440545;
/*Degree vs. Radian conservation variables*/
static const double DEG_TO_RAD = M_PI/180.0;
static const double RAD_TO_DEG = 180.0/M_PI;

double Haversine_Distance(double lat1,double lon1, double lat2, double lon2)
    {
    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));
    return R * c;
    }

double inverseHaversine_Distance_lon1(double lat1, double dist, double lat2, double lon2)
    {
    /* Rewrite Haversine_Distance wrt lon1: */
    /* dist = R * c = R * 2.0 * atan2(sqrt(a), sqrt(1-a)) */
    /* dist / R / 2.0 = atan2(sqrt(a), sqrt(1-a)) */
    /* sqrt(a) = sin(dist / R / 2.0); sqrt(1-a) = cos(dist / R / 2.0) */
    /* a = (sin(dist / R / 2.0))^2; 1 - a = (cos(dist / R / 2.0))^2 */
    /* pow(sin(dlat * 0.5),2) + cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2) = (sin(dist / R / 2.0))^2 */
    /* cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2) = (sin(dist / R / 2.0))^2 - pow(sin(dlat * 0.5),2) */
    /* pow(sin(dlon * 0.5),2) = (pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD))  */
    /* sin(dlon * 0.5) = sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD))) */
    /* dlon = (lon2 - lon1) * DEG_TO_RAD = asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 */
    /* lon2 - lon1 = asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 / DEG_TO_RAD*/
    /* lon1 = lon2 - asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 / DEG_TO_RAD*/
    double dlat = (lat2 - lat1) * DEG_TO_RAD;
    return lon2 - asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 * RAD_TO_DEG;
    }

int main()
    {
    double lat1 = 42.34769;
    double dist = 1.46628357399041;
    double lat2 = 42.367137;
    double lon2 = -71.124383;
    double lon1 = inverseHaversine_Distance_lon1(lat1, dist, lat2, lon2);

    printf("lon1 %f\n", lon1);
    printf("dist %f\n", Haversine_Distance(lat1, lon1, lat2, lon2));
    }

结果:
gcc inverse_haversine.c -lm
./a.out
lon1 -71.135880
dist 1.466284

有可能减少表达......

答案 1 :(得分:0)

在调用三角函数之前,至少必须将lat1,lat2和lon2转换为弧度!但也许还有更多问题...... :)

示例:使用简单版本我得到了这个代码i C:

#include <math.h>

#define METERS_PER_DEGREE_EQUATOR 111319.5
#define MILES_PER_DEGREE_EQUATOR (METERS_PER_DEGREE_EQUATOR / 1000.0 / 1.609344)

/* Select preferred unit: */
#define UNITS_PER_DEGREE_EQUATOR MILES_PER_DEGREE_EQUATOR

double horDist(double lat1, double lon1, double lat2, double lon2)
    {
    /* From "Note on conversion from decimal degrees to meters"
     * (http://southport.jpl.nasa.gov/GRFM/cdrom/2a/DOCS/HTML/GEOLOC/METERS.HTM)
     * NOTE: BELOW IS ONLY PRECISE IF THE TWO LATITUDES ARE NOT TOO DISTANT! */
    double latDelta = UNITS_PER_DEGREE_EQUATOR * (lat1 - lat2);
    double lonDelta = UNITS_PER_DEGREE_EQUATOR * (lon1 - lon2) * cos(lat1 * M_PI / 180);
    return sqrt(latDelta * latDelta + lonDelta * lonDelta);
    }

double invHorDist_lon1(double lat1, double dist, double lat2, double lon2)
    {
    /* Rewrite horDist wrt lon1: */
    /* (dist * dist) = (latDelta * latDelta) + (lonDelta * lonDelta); */
    /* (dist * dist) - (latDelta * latDelta) = (lonDelta * lonDelta); */
    /* sqrt((dist * dist) - (latDelta * latDelta)) = lonDelta = UNITS_PER_DEGREE_EQUATOR * (lon1 - lon2) * cos(lat1 * M_PI / 180); */
    /* sqrt((dist * dist) - (latDelta * latDelta)) / UNITS_PER_DEGREE_EQUATOR / cos(lat1 * M_PI / 180) = (lon1 - lon2); */
    double latDelta = UNITS_PER_DEGREE_EQUATOR * (lat1 - lat2);
    return sqrt((dist * dist) - (latDelta * latDelta)) / UNITS_PER_DEGREE_EQUATOR / cos(lat1 * M_PI / 180) + lon2;
    }

int main()
    {
    double lon1 = invHorDist_lon1(42.34769, 1.46628357399041, 42.367137, -71.124383);
    printf("lon1 %f\n", lon1);
    printf("dist %f\n", horDist(42.34769, lon1, 42.367137, -71.124383));
    }

结果是:
gcc hasrsine.c -lm
./a.out
lon1 -71.112968
dist 1.466284

但如果两个纬度太远,这个简单的版本也不合适。但是尝试再次重写Haversine并在使用三角函数时转换为弧度。