#include "stdafx.h" #include "geocompute.h" GeoCompute::GeoCompute(void) { } GeoCompute::~GeoCompute(void) { } /*@brief 根据起点坐标、方位角、距离,计算另一点坐标。 * 使用Vincenty's公式求解,使用WGS-84椭球 * startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180)) * bearing:方位角(度) * dist:两点之间距离(km) */ void GeoCompute::computeOffsetGeoPosition(double lon1, double lat1, double bearing, double dist,double& targetLon,double& targetLat) { //角度转化为弧度 // qreal lon1 = (fmod(startPoint.x()+540,360)-180.0)*PI/180; lon1 = lon1*PI/180.0; lat1 = lat1*PI/180.0; bearing = bearing*PI/180.0; dist = dist*1000; //WGS-84椭球参数 double flat = 298.257223563; double a = 6378137.0; double b = 6356752.314245; //开始求解坐标 double f = 1/flat; double sb = sin(bearing); double cb = cos(bearing); double tu1 = (1-f)*tan(lat1); double cu1 = 1/sqrt((1+tu1*tu1)); double su1 = tu1*cu1; double s2 = atan2(tu1, cb); double sa = cu1*sb; double csa = 1-sa*sa; double us = csa*(a*a - b*b)/(b*b); double A = 1+us/16384*(4096+us*(-768+us*(320-175*us))); double B = us/1024*(256+us*(-128+us*(74-47*us))); double s1 = dist/(b*A); double s1p = 2*PI; double cs1m = 0.0; double ss1 = 0.0; double cs1 = 0.0; double ds1 = 0.0; while (abs(s1-s1p) > 1e-12) { cs1m = cos(2*s2+s1); ss1 = sin(s1); cs1 = cos(s1); ds1 = B*ss1*(cs1m+B/4*(cs1*(-1+2*cs1m*cs1m)- B/6*cs1m*(-3+4*ss1*ss1)*(-3+4*cs1m*cs1m))); s1p = s1; s1 = dist/(b*A)+ds1; } double t = su1*ss1-cu1*cs1*cb; double lat2 = atan2(su1*cs1+cu1*ss1*cb, (1-f)*sqrt(sa*sa + t*t)); double l2 = atan2(ss1*sb, cu1*cs1-su1*ss1*cb); double c = f/16*csa*(4+f*(4-3*csa)); double l = l2-(1-c)*f*sa* (s1+c*ss1*(cs1m+c*cs1*(-1+2*cs1m*cs1m))); double lon2 = lon1+l; targetLon = lon2*180/PI; targetLat = lat2*180/PI; } // 使用Vincenty's公式计算地理距离 double GeoCompute::VincentyDistance(double lon1, double lat1, double lon2, double lat2) { // 常量定义 const double a = 6378137.0; // 地球长半轴 (米) const double f = 1 / 298.257223563; // 地球扁率 const double b = a * (1 - f); // 地球短半轴 (米) lat1 = lat1* M_PI / 180.0; lon1 = lon1* M_PI / 180.0; lat2 = lat2* M_PI / 180.0; lon2 = lon2* M_PI / 180.0; double L = lon2 - lon1; double U1 = atan((1 - f) * tan(lat1)); double U2 = atan((1 - f) * tan(lat2)); double sinU1 = sin(U1), cosU1 = cos(U1); double sinU2 = sin(U2), cosU2 = cos(U2); double lambda = L, lambdaP; int iterLimit = 100; double sinLambda, cosLambda; double sinSigma, cosSigma, sigma; double sinAlpha, cos2Alpha, cos2SigmaM; double C; do { sinLambda = sin(lambda); cosLambda = cos(lambda); sinSigma = sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); if (sinSigma == 0) return 0; // co-incident points cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = atan2(sinSigma, cosSigma); sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cos2Alpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cos2Alpha; if (cos2Alpha == 0) cos2SigmaM = 0; // equatorial line: cos2Alpha=0 C = f / 16 * cos2Alpha * (4 + f * (4 - 3 * cos2Alpha)); lambdaP = lambda; lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } while (fabs(lambda - lambdaP) > 1e-12 && --iterLimit > 0); if (iterLimit == 0) return -1; // formula failed to converge, return -1 or an appropriate error code double uSquared = cos2Alpha * (a * a - b * b) / (b * b); double A = 1 + uSquared / 16384 * (4096 + uSquared * (-768 + uSquared * (320 - 175 * uSquared))); double B = uSquared / 1024 * (256 + uSquared * (-128 + uSquared * (74 - 47 * uSquared))); double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); double s = b * A * (sigma - deltaSigma); return s; }