2015-09-27 167 views
2

有誰知道一個公式,我可以用它來將谷歌地圖Android API中的縮放:https://developers.google.com/maps/documentation/android-api/streetview轉換爲谷歌街景圖片API中使用的視角:https://developers.google.com/maps/documentation/streetview/intro谷歌街景:FOV和縮放之間的轉換

我發現一對夫婦舊公式的位置:

  1. https://groups.google.com/forum/#!topic/google-maps-js-api-v3/uqKfg0ZBhWc
  2. https://groups.google.com/forum/#!msg/google-maps-image-apis/O_Odb0A7_0c/Q74cHCoRuscJ

然後我把他們一個測試,由此FOV將被計算,當我變焦相機我android手機:

FOV1:3.9018*Math.pow(streetViewPanoramaCamera.zoom,2) - 42.432*streetViewPanoramaCamera.zoom + 123

FOV2:Math.abs(streetViewPanoramaCamera.zoom/5*108-120

FOV3:180/Math.pow(2,streetViewPanoramaCamera.zoom)

@Override 
public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera streetViewPanoramaCamera) { 

    Log.e("Pano", "Bearing: " + streetViewPanoramaCamera.bearing + " Tilt: " + streetViewPanoramaCamera.tilt + 
      " Zoom: " + streetViewPanoramaCamera.zoom + 
    " FOV1: "+ String.valueOf(3.9018*Math.pow(streetViewPanoramaCamera.zoom,2) - 42.432*streetViewPanoramaCamera.zoom + 123) +" FOV2: "+ 
      Math.abs(streetViewPanoramaCamera.zoom/5*108-120) +" FOV3: "+ 180/Math.pow(2,streetViewPanoramaCamera.zoom)) ; 

} 

在Android上0.0的放大,我們有以下FOV值返回:

09-27 15:53:52.322è/Pano:方位:228.28955傾斜度:14.516191變焦: 0.0 FOV1:123.0 FOV2:120.0 FOV3:180.0

由於FOV具有120°的最大值,FOV2公式起初看起來有前途的,但是當我在2倍放大,它給了我一個值的76.8,其是與實際相差不遠:

09-27 16: 01:48.235 E /帕諾:軸承:223.11241傾斜:1.852709變焦:2.0 FOV1:53.7432 FOV2:76.8 FOV3:45.0

這是以後的2倍變焦我的手機上的圖像:

Google Map Android Streetview

這是在FOV 76.8(https://maps.googleapis.com/maps/api/streetview?size=600x300&location=-33.87365,151.20689&heading=223.11241&pitch=1.852709&fov=76.8&key=APIKEY)從谷歌街景圖像API下載的圖像:

GoogleStreetView Image API 76.8

這是在FOV 45(https://maps.googleapis.com/maps/api/streetview?size=600x300&location=-33.87365,151.20689&heading=223.11241&pitch=1.852709&fov=45&key=APIKEY)從谷歌街景圖像API下載的圖像:

GoogleStreetView Image API 45

我得到的最接近的是如果我製作FOV 26但是這是我猜測並且不使用公式 - 下圖是FOV 26:

GoogleStreetView Image API 26

回答

1

我終於不得不倒退線來得到指數公式了。

我用這個網站,並一起運作良好,雙方FOV的數據點和變焦值的組合手動鍵入:http://www.had2know.com/academics/regression-calculator-statistics-best-fit.html

我的數據點:

FOV(ZOOM在旁邊的括號中FOV)

120(0)

50(1)

45(1.2)

37(1.5)

26(2)

69(0.5)

78(0.3)

31(1.9)

爲了得到一個更接近式,則可以不斷增加更多的「合適」數據點,但我沒有時間 - 任何想要完善公式的人都可以嘗試。

我得到了下面的公式,其中Y是FOV,X是縮放。

Y = 103.7587(0.5051^X)

相關= -0.9882

0

可以使用下面的公式(在JavaScript代碼):

  • 轉換FOVzoom

    zoom = Math.log(180/fov)/(Math.log(2))

  • 轉換變焦FOV

    fov = 180/Math.pow(2,zoom)

+0

此公式不適用於Android。在Android中,特定縮放的FOV與網絡非常不同。 – OldSchool4664

0

谷歌搜索這個答案,我只能找到網站的公式。網站是不同的,因爲首先,在文檔中有一個縮放與FOV圖表: https://developers.google.com/maps/documentation/javascript/streetview#TilingPanoramas

因此,可以拿出一個公式。 Android文檔沒有這樣的表格,而人們用於Web的公式並不適用於Android(甚至沒有關閉)。

然而有一些好消息,而正是這種功能可以在Android API中: StreetViewPanorama.orientationToPoint(StreetViewPanoramaOrientation orientation)

此功能使我們能夠提供一個方向,它會在屏幕上返回一個點,該方向的謊言。該功能的文檔說,如果該方向不在屏幕上,它將返回null,但實際上,我發現它會在屏幕的可視區域之外給出一個點;但是,如果我們知道屏幕尺寸,我們可以檢查點是否有效。通過循環180度,我們可以發現該範圍有多少可見,因此也是視野。

警告:此功能效率低下。只有在縮放變化後才能撥打電話!

注意:下面的示例代碼計算HORIZONTAL視野。要計算垂直視野,您需要進行一些更改。例如,改變point.x到point.y,改變screenSize.x的所有實例screenSize.y,改變streetViewPanoramaCamera.bearing的所有實例streetViewPanoramaCamera.tilt,並更改的所有實例:

orientation = new StreetViewPanoramaOrientation(streetViewPanoramaCamera.tilt, angleCheck); 

到:

orientation = new StreetViewPanoramaOrientation(angleCheck, streetViewPanoramaCamera.bearing); 

下面是簡單的方法,在這裏我們只是從-90到+90度循環,看看有多少是180度的是在可視區域(注意:這隻能傾斜是否是0度,即用戶沒有擡頭或俯視):

private StreetViewPanorama mStreetViewPanorama; 

private float mZoom = -1f; 
private int mFieldOfViewDegrees; 

private void onOrientationUpdate(StreetViewPanoramaCamera streetViewPanoramaCamera) { 

    if (streetViewPanoramaCamera.zoom != mZoom) { 
     mFieldOfViewDegrees = getFieldOfView(streetViewPanoramaCamera); 
     mZoom = streetViewPanoramaCamera.zoom; 
    } 
} 

private int getFieldOfView(StreetViewPanoramaCamera streetViewPanoramaCamera) { 

    WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 
    Display display = windowManager.getDefaultDisplay(); 
    Point screenSize = new Point(); 
    display.getSize(screenSize); 

    StreetViewPanoramaOrientation orientation; 
    Integer lowerFovDegrees = null; 
    Integer upperFovDegrees = null; 

    for (int angleCheck = (int) streetViewPanoramaCamera.bearing - 90; 
     angleCheck <= (int) streetViewPanoramaCamera.bearing + 90; 
     angleCheck++) { 
     orientation = new StreetViewPanoramaOrientation(streetViewPanoramaCamera.tilt, angleCheck); 
     Point point = mStreetViewPanorama.orientationToPoint(orientation); 

     if (lowerFovDegrees == null) { 
      if ((point != null) && (point.x >= 0)) { 
       lowerFovDegrees = angleCheck; 
      } 
     } else if (upperFovDegrees == null) { 
      if ((point == null) || (point.x > screenSize.x)) { 
       upperFovDegrees = angleCheck - 1; 
       break; 
      } 
     } 
    } 

    int fieldOfViewDegrees = upperFovDegrees - lowerFovDegrees; 

    return fieldOfViewDegrees; 
} 

但是,orientationToPoint()的代價很高,最多可以調用180次。我們可以使用二進制搜索來使這種效率更高(雖然更復雜),並將其降低到更像〜13個調用。在這種情況下,我使用遞歸函數來執行二進制搜索。此外還有一個侷限性,即水平赤道必須在視野內或FOV不能準確計算;在這種情況下,它返回null。只要用戶不會一直向下或向上傾斜,這並不是一個真正的問題,但是如果他們這樣做,FOV將返回null,並且您需要隱藏依賴於FOV的任何UI元素都是準確的(或者他們將不在正確的位置)。

private StreetViewPanorama mStreetViewPanorama; 

private float mZoom = -1f; 
private float mFieldOfViewDegrees; 

private void onOrientationUpdate(StreetViewPanoramaCamera streetViewPanoramaCamera) { 

    if (streetViewPanoramaCamera.zoom != mZoom) { 
     Float fieldOfViewDegrees = getFieldOfView(streetViewPanoramaCamera); 
     if (fieldOfViewDegrees == null) { // If FOV cannot be determined, hide any overlay UI overlay elements so they don't display misaligned 
      mZoom = -1f; 
      // Hide UI overlay elements 
     } else { 
      mFieldOfViewDegrees = fieldOfViewDegrees; 
      mZoom = streetViewPanoramaCamera.zoom; 
      // Show UI overlay elements 
     } 
    } 
} 


/* 
* Determine field of view. Must use roundabout way since the info is not provided directly. 
* StreetViewPanorama.orientationToPoint() will tell us if a particular orientation is visible on the 
* screen, so we can loop from looking left (-90) to right (+90) and see how much of the 180 degrees is in 
* the field of view. 
* 
* This is is CPU intensive, so instead of a simple loop we use a recursive binary search, and make sure 
* to only call this function when the zoom has changed. 
* 
* WARNING: This method of getting the FOV only works if the equator is still in view. If the user tilts 
* too far down or up, it will return null. 
*/ 
private Float getFieldOfView(StreetViewPanoramaCamera streetViewPanoramaCamera) { 

    WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 
    Display display = windowManager.getDefaultDisplay(); 
    Point screenSize = new Point(); 
    display.getSize(screenSize); 

    // If the equator is no longer in view, FOV cannot be accurately calculated 
    StreetViewPanoramaOrientation orientation = 
      new StreetViewPanoramaOrientation(0, streetViewPanoramaCamera.bearing); 
    Point point = mStreetViewPanorama.orientationToPoint(orientation); 
    if (point.y < 0 || point.y > screenSize.y) { 
     return null; 
    } 

    Float lowerFovDegrees = getLowerFieldOfViewDegrees(
      streetViewPanoramaCamera, 
      screenSize, 
      streetViewPanoramaCamera.bearing - 90f, 
      streetViewPanoramaCamera.bearing + 90f); 
    Float upperFovDegrees = getUpperFieldOfViewDegrees(
      streetViewPanoramaCamera, 
      screenSize, 
      streetViewPanoramaCamera.bearing - 90f, 
      streetViewPanoramaCamera.bearing + 90f); 

    if ((lowerFovDegrees == null) || (upperFovDegrees == null)) return null; 

    float fieldOfViewDegrees = upperFovDegrees - lowerFovDegrees; 

    return fieldOfViewDegrees; 
} 

// Recursive binary search function 
private Float getLowerFieldOfViewDegrees(StreetViewPanoramaCamera streetViewPanoramaCamera, 
             Point screenSize, 
             float startDegrees, 
             float endDegrees) { 
    StreetViewPanoramaOrientation orientation; 
    float midpointDegrees = (int) (startDegrees + ((endDegrees - startDegrees)/2f)); 

    orientation = new StreetViewPanoramaOrientation(0, midpointDegrees); 
    Point point = mStreetViewPanorama.orientationToPoint(orientation); 

    if ((point == null) || (point.x < 0)) { 
     if (endDegrees - midpointDegrees <= 1f) { 
      return endDegrees; 
     } 

     return getLowerFieldOfViewDegrees(
       streetViewPanoramaCamera, 
       screenSize, 
       midpointDegrees, 
       endDegrees); 
    } else { 
     if (midpointDegrees - startDegrees <= 1f) { 
      return midpointDegrees; 
     } 

     return getLowerFieldOfViewDegrees(
       streetViewPanoramaCamera, 
       screenSize, 
       startDegrees, 
       midpointDegrees); 
    } 
} 

// Recursive binary search function 
private Float getUpperFieldOfViewDegrees(StreetViewPanoramaCamera streetViewPanoramaCamera, 
             Point screenSize, 
             float startDegrees, 
             float endDegrees) { 
    StreetViewPanoramaOrientation orientation; 
    float midpointDegrees = (int) (startDegrees + ((endDegrees - startDegrees)/2f)); 

    orientation = new StreetViewPanoramaOrientation(0, midpointDegrees); 
    Point point = mStreetViewPanorama.orientationToPoint(orientation); 

    if ((point == null) || (point.x > screenSize.x)) { 
     if (midpointDegrees - startDegrees <= 1f) { 
      return startDegrees; 
     } 

     return getUpperFieldOfViewDegrees(
       streetViewPanoramaCamera, 
       screenSize, 
       startDegrees, 
       midpointDegrees); 
    } else { 
     if (endDegrees - midpointDegrees <= 1f) { 
      return midpointDegrees; 
     } 

     return getUpperFieldOfViewDegrees(
       streetViewPanoramaCamera, 
       screenSize, 
       midpointDegrees, 
       endDegrees); 
    } 
} 

上面的函數的粒度是到最近的程度。您可以修改它以縮小粒度,但運行時間會更長。由於它可能已經導致圖形的口吃,我沒有這樣做。

我希望這可以幫助別人,因爲這似乎是一個常見問題,我沒有看到它解決了Android。