1. 程式人生 > >與地圖經緯度計算有關的一些函式

與地圖經緯度計算有關的一些函式

網上有關這些的東西很多,但是試過之後有的計算偏差大一點,有的小一點。下面這幾個相關計算我自己試過之後相對來說計算的誤差小一點。

1、已知兩點經緯度計算方位角

 /**
     * 以真北為0度起點,由東向南向西順時針旋轉360度,主要是用於控制象限。
     * 根據2點經緯度,計算方位角
     * 給定2點,獲得經緯度
     * 起點經緯度,都是以度為單位
     * 終點經緯度,都是以度為單位
     */
    public static double computeAzimuth(LatLng la1, LatLng la2) {
        double
lat1 = la1.getLatitude(), lon1 = la1.getLongitude(), lat2 = la2.getLatitude(), lon2 = la2.getLongitude(); double result = 0.0; int ilat1 = (int) (0.50 + lat1 * 360000.0); int ilat2 = (int) (0.50 + lat2 * 360000.0); int ilon1 = (int) (0.50 + lon1 * 360000.0);
int ilon2 = (int) (0.50 + lon2 * 360000.0); lat1 = Math.toRadians(lat1); lon1 = Math.toRadians(lon1); lat2 = Math.toRadians(lat2); lon2 = Math.toRadians(lon2); if ((ilat1 == ilat2) && (ilon1 == ilon2)) { return result; } else if
(ilon1 == ilon2) { if (ilat1 > ilat2) result = 180.0; } else { double c = Math .acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos((lon2 - lon1))); double A = Math.asin(Math.cos(lat2) * Math.sin((lon2 - lon1)) / Math.sin(c)); result = Math.toDegrees(A); if ((ilat2 > ilat1) && (ilon2 > ilon1)) { } else if ((ilat2 < ilat1) && (ilon2 < ilon1)) { result = 180.0 - result; } else if ((ilat2 < ilat1) && (ilon2 > ilon1)) { result = 180.0 - result; } else if ((ilat2 > ilat1) && (ilon2 < ilon1)) { result += 360.0; } } return result; }

2、已知一點經緯度、方位角和距離,求另一點經緯度

/*
     * 大地座標系資料WGS-84 長半徑a=6378137 短半徑b=6356752.3142 扁率f=1/298.2572236
     */
    /**
     * 長半徑a=6378137
     */
    private static double a = 6378137;
    /**
     * 短半徑b=6356752.3142
     */
    private static double b = 6356752.3142;
    /**
     * 扁率f=1/298.2572236
     */
    private static double f = 1 / 298.2572236;

    /**
     * 計算另一點經緯度
     *
     * @param, lon
     * 經度
     * @param, lat
     * 維度
     * @param, lonlat
     * 已知點經緯度
     * @param, brng
     * 方位角 度
     * @param, dist
     * 距離(米)
     * 已知一點經緯度,方位角,距離,求另一點經緯度
     */
    public static LatLng getLatlngByFixedPointAziDistance(double brng, double dist, LatLng fixedPoint) {
        double lon = fixedPoint.getLongitude();
        double lat = fixedPoint.getLatitude();

        double alpha1 = rad(brng);
        double sinAlpha1 = Math.sin(alpha1);
        double cosAlpha1 = Math.cos(alpha1);

        double tanU1 = (1 - f) * Math.tan(rad(lat));
        double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
        double sinU1 = tanU1 * cosU1;
        double sigma1 = Math.atan2(tanU1, cosAlpha1);
        double sinAlpha = cosU1 * sinAlpha1;
        double cosSqAlpha = 1 - sinAlpha * sinAlpha;
        double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
        double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
        double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));

        double cos2SigmaM = 0;
        double sinSigma = 0;
        double cosSigma = 0;
        double sigma = dist / (b * A), sigmaP = 2 * Math.PI;
        while (Math.abs(sigma - sigmaP) > 1e-12) {
            cos2SigmaM = Math.cos(2 * sigma1 + sigma);
            sinSigma = Math.sin(sigma);
            cosSigma = Math.cos(sigma);
            double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)
                    - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
            sigmaP = sigma;
            sigma = dist / (b * A) + deltaSigma;
        }

        double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
        double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
                (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
        double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
        double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
        double L = lambda - (1 - C) * f * sinAlpha
                * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));

        double revAz = Math.atan2(sinAlpha, -tmp); // final bearing

        //System.out.println(revAz);
        //Log.e("方位角",String.valueOf(revAz));
        //Log.e("經緯度",String.valueOf(deg(lat2))+"經度"+String.valueOf(lon+deg(L)));
        //System.out.println(+","+);

        return new LatLng(deg(lat2), lon + deg(L));
    }

3、已知兩個座標和其對應的方位角,求另一點座標

 public static LatLng getLatlngByTwoFixedPointAziIntersect(double aziOne, double aziTwo, LatLng fixedPointOne, LatLng fixedPointTwo) {
        double azi;
        LatLng latLng;
        if (fixedPointOne.getLongitude() > fixedPointTwo.getLongitude()) {
            azi = aziOne;
            latLng = fixedPointOne;
            aziOne = aziTwo;
            fixedPointOne = fixedPointTwo;
            aziTwo = azi;
            fixedPointTwo = latLng;
        }
        Double aziAB = computeAzimuth(fixedPointOne, fixedPointTwo);
        Double aziBA = 180 + aziAB;

        if (0 <= aziOne && aziOne < 180) {
            if (aziOne <= aziAB) {
                if (aziOne <= aziTwo && aziTwo < aziBA) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
            if (aziOne > aziAB) {
                if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo <= 360)) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
        }

        if (180 <= aziOne && aziOne < 270) {
            if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo < 360)) {
                Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                return new LatLng();
            }
        }
        if (270 <= aziOne && aziOne < 360) {
            if ((0 <= aziTwo && aziTwo < aziBA) || (aziOne < aziTwo && aziTwo < 360)) {
                Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                return new LatLng();
            }
        }
        double k1 = Math.tan(rad(90 - aziOne));
        double k2 = Math.tan(rad(90 - aziTwo));
        double y1 = fixedPointOne.getLatitude();
        double x1 = fixedPointOne.getLongitude();
        double y2 = fixedPointTwo.getLatitude();
        double x2 = fixedPointTwo.getLongitude();
        double lon = (y2 - y1 + k1 * x1 - k2 * x2) / (k1 - k2);
        double lat = (k1 * y2 - k2 * y1 + k1 * k2 * x1 - k1 * k2 * x2) / (k1 - k2);
/*        if (0 <= aziOne && aziOne < 180) {
            if (aziOne < aziAB) {
                if (lat < y1) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
            if (aziOne > aziAB) {
                if (lat > y2) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
        }*/
        if (lat > 90 || lat < -90) {
            Toast.makeText(MyApplication.getContextObject(), "不能相交,請重新輸入方位角", Toast.LENGTH_SHORT).show();
            return new LatLng();
        }
        return new LatLng(lat, lon);
    }

4、度與弧度的轉換關係

 /**
     * 度換成弧度
     *
     * @param d 度
     * @return 弧度
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 弧度換成度
     *
     * @param x 弧度
     * @return*/
    private static double deg(double x) {
        return x * 180 / Math.PI;
    }