2013-12-13 44 views
20

我還沒有在我的搜索中找到答案,這裏有幾個答案,但它們不適用於我。在LatLngBounds構建器上設置最大縮放級別

我在地圖上有2個標記,我使用的是LatLngBounds構建器,以便讓相機縮放到正確的縮放級別以包含它們。一切都如預期般運作,除了一件事情,當兩個標記彼此非常接近時,地圖非常非常放大而且很好,這種縮放級別沒有任何意義。

LatLngBounds.Builder builder = new LatLngBounds.Builder(); 
builder.include(firstMarker.getPosition()); 
builder.include(secondMarker.getPosition()); 
LatLngBounds bounds = builder.build(); 

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, markerPadding); 

有沒有辦法強制某個級別的縮放,之後相機不會縮放?這將避免讓地圖過於放大/縮小。基本上我使用15.0f作爲縮放級別。如果點太遠,我想要縮放以適應它們。如果積分越來越近,我不希望縮放級別超過15.0f。

+0

最後我去了f rom http://stackoverflow.com/questions/15700808/setting-max-zoom-level-in-google-maps-android-api-v2它的工作原理合理 – Alin

+0

Alin,我的建議與您所提到的答案類似有一個主要區別:相同的經度差異轉換爲非常不同的距離(以公里爲單位),具體取決於測量的緯度。用我的方法,你沒有這種變化。最小的縮放比例總是由相同的以千米爲單位的地圖對角線來定義,而不管您是在赤道上還是在極點上顯示標記(我知道,您無法在Google地圖中顯示極點)。 – user2808624

+0

你可以在你的答案中添加代碼示例,以便我可以接受它嗎? – Alin

回答

40

我有一個類似的情況,我想至少有一個2公里的地圖對角線。 因此,我只是在建造者中增加兩個點:原始邊界中心西北部的第一個1公里和中心東南部第二個1公里處。如果這些在邊界內,它們不會改變任何東西。如果它們超出了原始邊界,它們會將邊界增加到一個有意義的大小。

這是一個完整的代碼示例:

public LatLngBounds createBoundsWithMinDiagonal(MarkerOptions firstMarker, MarkerOptions secondMarker) { 
    LatLngBounds.Builder builder = new LatLngBounds.Builder(); 
    builder.include(firstMarker.getPosition()); 
    builder.include(secondMarker.getPosition()); 

    LatLngBounds tmpBounds = builder.build(); 
    /** Add 2 points 1000m northEast and southWest of the center. 
    * They increase the bounds only, if they are not already larger 
    * than this. 
    * 1000m on the diagonal translates into about 709m to each direction. */ 
    LatLng center = tmpBounds.getCenter(); 
    LatLng northEast = move(center, 709, 709); 
    LatLng southWest = move(center, -709, -709); 
    builder.include(southWest); 
    builder.include(northEast); 
    return builder.build();  
} 

private static final double EARTHRADIUS = 6366198; 
/** 
* Create a new LatLng which lies toNorth meters north and toEast meters 
* east of startLL 
*/ 
private static LatLng move(LatLng startLL, double toNorth, double toEast) { 
    double lonDiff = meterToLongitude(toEast, startLL.latitude); 
    double latDiff = meterToLatitude(toNorth); 
    return new LatLng(startLL.latitude + latDiff, startLL.longitude 
      + lonDiff); 
} 

private static double meterToLongitude(double meterToEast, double latitude) { 
    double latArc = Math.toRadians(latitude); 
    double radius = Math.cos(latArc) * EARTHRADIUS; 
    double rad = meterToEast/radius; 
    return Math.toDegrees(rad); 
} 


private static double meterToLatitude(double meterToNorth) { 
    double rad = meterToNorth/EARTHRADIUS; 
    return Math.toDegrees(rad); 
} 
+0

請同時添加meterToLatitude函數,以便測試代碼。它需要'雙latDiff = meterToLatitude(toNorth);'謝謝 – Alin

+0

對不起,只是錯過了。我會補充一下。 – user2808624

+0

非常感謝。它確實比以前的解決方案效果更好。我唯一注意到的是基於熨平板dpi的距離可能太大,所以最後我爲不同的密度設置了不同的距離值以適應我的需要。 – Alin

0

從4.0.30開始,無法限制縮放級別,但您可以跟蹤this issue

最簡單的方法可能是強制縮放級別像這個視頻:http://www.youtube.com/watch?v=-nCZ37HdheY
基本上他們都呼籲animateCamera達到一定的縮放級別時。

這看起來有點奇怪,因爲你有2個不是由用戶啓動的動畫。

困難的方法會自己做數學。嘗試使用CameraUpdateFactory.newLatLngZoomLatLng作爲這些點之間的中心,當您檢測到的點彼此靠近時,您可以使用最大縮放。

1

你有沒有考慮做是隱藏的地圖碎片,並用它來確定您的變焦/界限?這顯然不是最好的計算方法,但它可能是最簡單/最準確的解決方案。例如,製作一個數學解決方案可以在極點附近和零度經度(如果你關心的話)上工作很複雜。如果您使用地圖,則全部內置。您也可以在現有的地圖上使用此解決方案,但用戶會看到反彈。

這裏是你會怎麼做:

  1. 轉到界限,你在前面已經
  2. 定義獲取使用map.getCameraPosition()變焦變焦。
  3. 如果變焦> 15縮小以15使用CameraUpdateFactory.zoomTo(15)
7

我根據user2808624答案實現這一解決方案,但使用SphericalUtilAndroid Maps Utility Library做計算。

final double HEADING_NORTH_EAST = 45; 
final double HEADING_SOUTH_WEST = 215; 
LatLng center = tmpBounds.getCenter(); 
LatLng norhtEast = SphericalUtil.computeOffset(center, 709,HEADING_NORTH_EAST); 
LatLng southWest = SphericalUtil.computeOffset(center, 709,HEADING_SOUTH_WEST); 
2

來晚了,但也許有人有相同的問題,我曾:我收到界從一個地方,而不是從LatLngBounds.Builder:

我用Location.distanceBetween(...),找出如果此範圍太小,然後用最小縮放級別與邊界的中心:

if (areBoundsTooSmall(bounds, 300)) { 
    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(bounds.getCenter(), 17)); 
} else { 
    mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 20)); 
} 

的檢查方法是:

private boolean areBoundsTooSmall(LatLngBounds bounds, int minDistanceInMeter) { 
    float[] result = new float[1]; 
    Location.distanceBetween(bounds.southwest.latitude, bounds.southwest.longitude, bounds.northeast.latitude, bounds.northeast.longitude, result); 
    return result[0] < minDistanceInMeter; 
} 

我使用了最小縮放級別17和填充20來設置太小的邊界,在這裏用米300中的最小距離定義的邊界太小。您可以根據需要調整數字。

2

谷歌已經添加了api限制最大/最小縮放級別。

GoogleMap.setMaxZoomPreference() 
GoogleMap.setMinZoomPreference() 
+1

注意:這也會限制用戶在這些限制之外進行縮放。 – DoruChidean

0

快速的解決方法是:

gMap.setOnMapLoadedCallback(this); 
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding); 
gMap.setMaxZoomPreference(10); 
gMap.animateCamera(cu); 


@Override 
public void onMapLoaded() { 
    gMap.resetMinMaxZoomPreference(); 
} 

要注意的是它可以阻止變焦,直到地圖完全重新加載。但作爲一個快速修復它的作品。

2

下面是基於user2808624answer的短得多的版本。

 LatLngBounds bounds = builder.build(); 
     LatLng center = bounds.getCenter(); 
     builder.include(new LatLng(center.latitude-0.001f,center.longitude-0.001f)); 
     builder.include(new LatLng(center.latitude+0.001f,center.longitude+0.001f)); 
     bounds = builder.build(); 

它有點草率,但您可以使用0.001放大不小於城市街區,0.01不低於城市景觀。唯一的優點是它只有4行額外的代碼。

0

這僅僅是簡單的:

LatLngBounds.Builder latlngBuilder = new LatLngBounds.Builder(); 

LatLng sydney1 = new LatLng(57.149651, -2.099075); 

LatLng sydney2 = new LatLng(51.621441, -3.943646); 

latlngBuilder.include(sydney1); 
latlngBuilder.include(sydney2); 

googlemap.animateCamera(CameraUpdateFactory.newLatLngBounds(latlngBuilder.build(), 100)); 
0

由user2808624和dvdrlee的答案之後,我寫了科特林擴展:

fun LatLngBounds.Builder.createBoundsWithZoomMaintained(bounds: LatLngBounds) : LatLngBounds { 
    val HEADING_NORTH_EAST = 45.0 //NorthEast angle 
    val HEADING_SOUTH_WEST = 215.0 //SouthWest angle 
    val center = bounds.center 
    val northEast = SphericalUtil.computeOffset(center, 709.0, HEADING_NORTH_EAST) //1000 metres on the diagonal translates to 709 metres on either side. 
    val southWest = SphericalUtil.computeOffset(center, 709.0, HEADING_SOUTH_WEST) 
    this.include(northEast).include(southWest) 
    return this.build() 
} 

這通常是在你的utils的或擴展文件,然後你可以在任何地方使用它,就像這樣:

var bounds = builder.build() //To include all your existing points. 
bounds = builder.createBoundsWithZoomMaintained(bounds) //Updated bounds. 
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 10)) 
相關問題