大地正题算法正算-用于计算从指定的 LatLng 出发,按某个方向行进指定距离所得到的 LatLng(Java实现版)

大地主题算法正算-用于计算从指定的 LatLng 出发,按某个方向行进指定距离所得到的 LatLng(Java实现版)

主要算法修改自网络上一个VB 脚本实现版。已经通过Google 地图 API提供的方法进行了验证。具体计算的经纬度存在一定的误差,可以容忍。

/**

* ** a, b, c, alpha, e, e2, W, V As Double
'a      长轴半径
'b      短轴
'c      极曲率半径
'alpha  扁率
'e      第一偏心率
'e2     第二偏心率
'W      第一基本纬度函数
'V      第二基本纬度函数
** B1, L1, B2, L2 As Double
'B1   点1的纬度
'L1  点1的经度
'B2   点1的纬度
'L2  点2的经度
** S As Double  '''''大地线长度
** A1, A2 As Double
'A1     点1到点2的方位角
'A2     点2到点1的方位角
*/
private final static double pi=Math.PI;
private final static double M_RAD = 1.74532925199433E-02;
private double a,b,c,alpha,e,e2,w,V;
private double B1, L1, B2, L2;
private double s;

private double A1,A2;

         private final double R = 6371229;              //地球的半径

private void getellipseparameter(){
/**
* 椭球体 长半轴 a(米)短半轴b(米)
Krassovsky (北京54采用)6378245 6356863.0188
IAG 75(西安80采用)     6378140 6356755.2882
WGS 84 63781376356752.3142
*/
a = 6378140;//6378245;//6378137
b = 6356755.2882;
c = Math.pow(a,2)/b;
alpha = (a-b)/a;
e = Math.sqrt(Math.pow(a,2)-Math.pow(b,2))/a;
e2 = Math.sqrt(Math.pow(a,2)-Math.pow(b,2))/b;
}
private void computerw(){
   w = Math.sqrt(1 - Math.pow(e,2)*(Math.pow(Math.sin(B1),2)));
   V = w*(a/b);
}
/**
* 获取数值的正负号
* @param v
* @return
*/
private int Sgn(double v){
if(v>0){
return 1;
}else if(v<0){
return -1;
}else{
return 0;
}
}
/**
*  1弧度约为57°17'44.806'',1°为π/180,近似值为0.01745弧度,周角为2π弧度,平角(即180°角)为π弧度,直角为π/2弧度。
* 已知角度求弧度
* @param angle_d
* @return
*/
public double rad(double angle_d){
double rad = angle_d * Math.PI / 180;
return rad;

}

/**
* 用于计算从指定的 LatLng 出发,按某个方向行进指定距离所得到的 LatLng。
* @param STARTLAT 起点维度
* @param STARTLONG 起点经度
* @param ANGLE1  起点到终点的方位角
* @param DISTANCE 距离长度
* @return  经纬度
*/
public double[] computeOffset(double STARTLAT, double STARTLONG, double ANGLE1, double DISTANCE ){//正算
double sinu1, cosu1, sinA0, cotq1, sin2q1, cos2q1, cos2A0;
   double k2, q0, sin2q1q0, cos2q1q0 ;
   double q ;
   double theta;
   double aa, BB, cc, EE22, AAlpha, BBeta;
   double sinu2, lamuda;
   double e1;
   double W1;
   B1 = STARTLAT;
   L1 = STARTLONG;
   A1 = ANGLE1;
   s = DISTANCE;
   //
   getellipseparameter();
   
   if(B1 == 0){
    if(A1 == 90){
    A2 = 270;
            B2 = 0;
            L2 = L1 + s / a * 180 / Math.PI;
    }
    if(A1 == 270){
    A2 = 90;
           B2 = 0;
           L2 = L1 - s / a * 180 / Math.PI;
    }
    return null;
   }
   B1 = rad(B1); //弧度函数
   L1 = rad(L1);
   A1 = rad(A1);
   computerw();
   e1 = e;
   W1 = w;  
   sinu1 = Math.sin(B1) * Math.sqrt(1 - e1 * e1)/W1;
   cosu1 = Math.cos(B1) / W1;
   sinA0 = cosu1 * Math.sin(A1);
   cotq1 = cosu1 * Math.cos(A1);
   sin2q1 = 2 * cotq1 / (Math.pow(cotq1, 2) + 1);
   cos2q1 = (Math.pow(cotq1,2) - 1) / (Math.pow(cotq1, 2) + 1);
   cos2A0 = 1 - Math.pow(sinA0 , 2);
   e2 = Math.sqrt(Math.pow(a ,2) - Math.pow(b, 2)) / b;
   k2 = e2 * e2 * cos2A0;
   aa = b * (1 + k2 / 4 - 3 * k2 * k2 / 64 + 5 * k2 * k2 * k2 / 256);
   BB = b * (k2 / 8 - k2 * k2 / 32 + 15 * k2 * k2 * k2 / 1024);
   cc = b * (k2 * k2 / 128 - 3 * k2 * k2 * k2 / 512);
   e2 = e1 * e1;
   //计算扁率
   AAlpha = (e2 / 2 + e2 * e2 / 8 + e2 * e2 * e2 / 16) - (e2 * e2 / 16 + e2 * e2 * e2 / 16) * cos2A0 + (3 * e2 * e2 * e2 / 128) * cos2A0 * cos2A0;
   BBeta = (e2 * e2 / 32 + e2 * e2 * e2 / 32) * cos2A0 - (e2 * e2 * e2 / 64) * cos2A0 * cos2A0;
   q0 = (s - (BB + cc * cos2q1) * sin2q1) / aa;
   sin2q1q0 = sin2q1 * Math.cos(2 * q0) + cos2q1 * Math.sin(2 * q0);
   cos2q1q0 = cos2q1 * Math.cos(2 * q0) - sin2q1 * Math.sin(2 * q0);
   q = q0 + (BB + 5 * cc * cos2q1q0) * sin2q1q0 / aa;
   //theta = (AAlpha * q + BBeta * (sin2q1q0 - sin2q1)) * sinA0;
   theta = (AAlpha * q + BBeta * (sin2q1q0 - sin2q1)) * sinA0;
   sinu2 = sinu1 * Math.cos(q) + cosu1 * Math.cos(A1) * Math.sin(q);
   B2 = Math.atan(sinu2 / (Math.sqrt(1 - e1 * e1) * Math.sqrt(1 - sinu2 * sinu2))) * 180 / Math.PI;
   lamuda = Math.atan(Math.sin(A1) * Math.sin(q) / (cosu1 * Math.cos(q) - sinu1 * Math.sin(q) * Math.cos(A1))) * 180 / Math.PI;
   if(Math.sin(A1)>0){
    if (Math.sin(A1) * Math.sin(q) / (cosu1 * Math.cos(q) - sinu1 * Math.sin(q) * Math.cos(A1)) > 0) {
    lamuda = Math.abs(lamuda);
    }else{
    lamuda = 180 - Math.abs(lamuda);
    }
   }else{
    if (Math.sin(A1) * Math.sin(q) / (cosu1 * Math.cos(q) - sinu1 * Math.sin(q) * Math.cos(A1)) > 0) {
    lamuda =  Math.abs(lamuda) - 180;
    }else{
    lamuda = - Math.abs(lamuda);
    }
   }
   L2 = L1 * 180 / Math.PI + lamuda - theta * 180 / Math.PI;
   A2 = Math.atan(cosu1 * Math.sin(A1) / (cosu1 * Math.cos(q) * Math.cos(A1) - sinu1 * Math.sin(q))) * 180 / Math.PI;
   if(Math.sin(A1)>0){
    if (cosu1 * Math.sin(A1) / (cosu1 * Math.cos(q) * Math.cos(A1) - sinu1 * Math.sin(q)) > 0) {
    A2 = 180 +  Math.abs(A2);
    }else{
    A2 = 360 -  Math.abs(A2);
    }
   }else{
    if (cosu1 * Math.sin(A1) / (cosu1 * Math.cos(q) * Math.cos(A1) - sinu1 * Math.sin(q)) > 0) {
    A2 = Math.abs(A2);
    }else{
    A2 = 180 - Math.abs(A2);
    }
   }
   System.out.println(B2+","+L2);
   return new double[]{B2,L2};
}