0

我正在計算地圖位置點之間的貝塞爾曲線的必要oint,以在Google Maps V2上繪製線條。我的問題是,如果線路必須在'太平洋上'繪製,它不能正常工作,例如,起點在東京,終點在溫哥華。點的計算方向錯誤(向地球周圍的東部),而不是向西。整個大西洋或亞洲的位置點計算並繪製正確。計算地圖的貝塞爾曲線的點

我的代碼或我的思想錯誤在哪裏?

下面是用於計算的代碼:

public static ArrayList<LatLng> bezier(LatLng p1, LatLng p2, double arcHeight, double skew, boolean up){ 
    ArrayList<LatLng> list = new ArrayList<LatLng>(); 
    try { 
     if(p1.longitude > p2.longitude){ 
      LatLng tmp = p1; 
      p1 = p2; 
      p2 = tmp; 
     } 

     LatLng c = midPoint(p1, p2, 0); 
     Log.v(TAG, "P1: " + p1.toString()); 
     Log.v(TAG, "P2: " + p2.toString()); 
     Log.v(TAG, "C: " + c.toString()); 

     double cLat = c.latitude; 
     double cLon = c.longitude; 


     //add skew and arcHeight to move the midPoint 
     if(Math.abs(p1.longitude - p2.longitude) < 0.0001){ 
      if(up){ 
       cLon -= arcHeight; 
      }else{ 
       cLon += arcHeight; 
       cLat += skew; 
      } 
     }else{ 
      if(up){ 
       cLat += arcHeight; 
      }else{ 
       cLat -= arcHeight; 
       cLon += skew; 
      } 
     } 

     list.add(p1); 
     //calculating points for bezier 
     double tDelta = 1.0/10; 
     for (double t = 0; t <= 1.0; t+=tDelta) { 
      double oneMinusT = (1.0-t); 
      double t2 = Math.pow(t, 2); 
      double lon = oneMinusT * oneMinusT * p1.longitude 
         + 2 * oneMinusT * t * cLon 
         + t2 * p2.longitude; 
      double lat = oneMinusT * oneMinusT * p1.latitude 
         + 2 * oneMinusT * t * cLat 
         + t2 * p2.latitude; 
      Log.v(TAG, "t: " + t + "[" + lat +"|" + lon + "]"); 
      list.add(new LatLng(lat, lon)); 
     } 

     list.add(p2); 
    } catch (Exception e) { 
     Log.e(TAG, "bezier", e); 
    } 
    return list; 
} 

這裏是從logcat的輸出與計算出的點;

P1: lat/lng: (35.76472,140.38639) 
P2: lat/lng: (49.19489,-123.17923) 
C: lat/lng: (53.760800330485814,-178.27615766444313) 
t: 0.0[35.76472|140.38639] 
t: 0.1[39.17431615948745|80.39147522040025] 
t: 0.2[42.12467250575547|27.871749947378213] 
t: 0.3[44.61578903880404|-17.172785819066128] 
t: 0.4[46.647665758633195|-54.7421320789327] 
t: 0.5[48.22030266524291|-84.83628883222157] 
t: 0.6[49.333699758633195|-107.4552560789327] 
t: 0.7[49.98785703880404|-122.59903381906611] 
t: 0.7[50.18277450575546|-130.2676220526218] 
t: 0.8[49.918452159487444|-130.46102077959978] 
t: 0.9[49.19489|-123.17923000000002] 

這裏是地圖的截圖:

enter image description here

回答

2

我已經決定了地理位置的一個cartesian coordinate system轉換,然後做計算。這工作。

下面是變化:

//inside bezier(...) 

CartesianCoordinates cart1 = new CartesianCoordinates(p1); 
CartesianCoordinates cart2 = new CartesianCoordinates(p2); 
CartesianCoordinates cart3 = new CartesianCoordinates(cLat, cLon); 

for (double t = 0; t <= 1.0; t += tDelta) { 
    double oneMinusT = (1.0 - t); 
    double t2 = Math.pow(t, 2); 

    double y = oneMinusT * oneMinusT * cart1.y + 2 * t * oneMinusT * cart3.y + t2 * cart2.y; 
    double x = oneMinusT * oneMinusT * cart1.x + 2 * t * oneMinusT * cart3.x + t2 * cart2.x; 
    double z = oneMinusT * oneMinusT * cart1.z + 2 * t * oneMinusT * cart3.z + t2 * cart2.z; 
    LatLng control = CartesianCoordinates.toLatLng(x, y, z); 
    if (Config.DEBUG) 
     Log.v(TAG, "t: " + t + control.toString()); 
    list.add(control); 
} 

與CartesianCoordinates:

private static class CartesianCoordinates { 
private static final int R = 6371; // approximate radius of earth 
double x; 
double y; 
double z; 

public CartesianCoordinates(LatLng p) { 
    this(p.latitude, p.longitude); 
} 

public CartesianCoordinates(double lat, double lon) { 
    double _lat = Math.toRadians(lat); 
    double _lon = Math.toRadians(lon); 

    x = R * Math.cos(_lat) * Math.cos(_lon); 
    y = R * Math.cos(_lat) * Math.sin(_lon); 
    z = R * Math.sin(_lat); 
} 

public static LatLng toLatLng(double x, double y, double z){ 
     return new LatLng(Math.toDegrees(Math.asin(z/R)), Math.toDegrees(Math.atan2(y, x))); 
    } 
} 

方法來計算兩個座標(完美的也許不是100%在數學上是正確的)的中點:

private static LatLng midPoint(LatLng p1, LatLng p2) throws IllegalArgumentException{ 

    if(p1 == null || p2 == null) 
     throw new IllegalArgumentException("two points are needed for calculation"); 

    double lat1; 
    double lon1; 
    double lat2; 
    double lon2; 

    //convert to radians 
    lat1 = Math.toRadians(p1.latitude); 
    lon1 = Math.toRadians(p1.longitude); 
    lat2 = Math.toRadians(p2.latitude); 
    lon2 = Math.toRadians(p2.longitude); 

    double x1 = Math.cos(lat1) * Math.cos(lon1); 
    double y1 = Math.cos(lat1) * Math.sin(lon1); 
    double z1 = Math.sin(lat1); 

    double x2 = Math.cos(lat2) * Math.cos(lon2); 
    double y2 = Math.cos(lat2) * Math.sin(lon2); 
    double z2 = Math.sin(lat2); 

    double x = (x1 + x2)/2; 
    double y = (y1 + y2)/2; 
    double z = (z1 + z2)/2; 

    double lon = Math.atan2(y, x); 
    double hyp = Math.sqrt(x*x + y*y); 

    // HACK: 0.9 and 1.1 was found by trial and error; this is probably *not* the right place to apply mid point shifting 
    double lat = Math.atan2(.9*z, hyp); 
    if(lat>0) lat = Math.atan2(1.1*z, hyp); 

    if(Config.DEBUG) 
     Log.v(TAG, Math.toDegrees(lat) + " " + Math.toDegrees(lon)); 

    return new LatLng(Math.toDegrees(lat), Math.toDegrees(lon)); 
} 
+1

您可能希望將此設置爲正確答案,以便其他人不會嘗試回答。 –

+0

你介意給你的midPoint方法嗎?我試圖達到真正接近這個的東西:) – gbero