與地圖經緯度計算有關的一些函式
阿新 • • 發佈:2018-11-12
網上有關這些的東西很多,但是試過之後有的計算偏差大一點,有的小一點。下面這幾個相關計算我自己試過之後相對來說計算的誤差小一點。
1、已知兩點經緯度計算方位角
/** * 以真北為0度起點,由東向南向西順時針旋轉360度,主要是用於控制象限。 * 根據2點經緯度,計算方位角 * 給定2點,獲得經緯度 * 起點經緯度,都是以度為單位 * 終點經緯度,都是以度為單位 */ public static double computeAzimuth(LatLng la1, LatLng la2) { doublelat1 = 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; }