Android Maps v2-设置相机动画以包含大多数标记
我有一组来自Web服务的点需要显示在地图上 我有一个当前的解决方案在大多数情况下都能很好地工作,它使用了著名的Android Maps v2-设置相机动画以包含大多数标记,android,google-maps-android-api-2,Android,Google Maps Android Api 2,我有一组来自Web服务的点需要显示在地图上 我有一个当前的解决方案在大多数情况下都能很好地工作,它使用了著名的LatLngBounds.Builder,CameraUpdateFactory.newLatLngBounds和map.animateCamera 但我有一些例子会产生问题:当点太远时,地图会以这些点的重心上的最大缩放级别为中心。例如:我在法国得了10分,在夏威夷得了2分。地图或多或少以最小缩放级别在caribeans上居中。因此,在屏幕上我没有显示任何内容,用户必须滚动才能真正看到其
LatLngBounds.Builder
,CameraUpdateFactory.newLatLngBounds
和map.animateCamera
但我有一些例子会产生问题:当点太远时,地图会以这些点的重心上的最大缩放级别为中心。例如:我在法国得了10分,在夏威夷得了2分。地图或多或少以最小缩放级别在caribeans上居中。因此,在屏幕上我没有显示任何内容,用户必须滚动才能真正看到其中的内容
所以我的问题是:
有没有一种方法可以让地图缩小到足够远的距离,这样我就可以看到所有的点(最好是这样)
或者:哪种方法是过滤掉那些只有几个点与多数点相差甚远的情况的最佳方法,并选择一组点进行放大(在我的示例中,我会选择放大法国的10个点,而忘记夏威夷的那些点)。在我以前的代码中发现一个错误,决定坐下来重写它 我以前也做过类似的事情,我有大约4500个标记,我想选择在特定位置一定距离内的标记。将该代码推广到任何类型的标记 我将在下面发布的代码包含两种可供使用的方法: 选择LowDistanceMarkers 测量每个标记之间的距离,并仅选择与任何其他标记之间距离不长的标记。这需要一个O(n+n^2)运行时,因为每个标记之间的比较和之后的检查 getSurroundingMarkers 如果您已经知道要放大的位置,则此方法执行与上面相同的操作。此方法的CPU占用量要小得多,因为它只需对所有标记进行O(n)运行,并将它们与给定位置进行比较
private List<Marker> selectLowDistanceMarkers(List<Marker> markers,
int maxDistanceMeters) {
List<Marker> acceptedMarkers = new ArrayList<Marker>();
if (markers == null) return acceptedMarkers;
Map<Marker, Float> longestDist = new HashMap<Marker, Float>();
for (Marker marker1 : markers) {
// in this for loop we remember the max distance for each marker
// think of a map with a flight company's routes from an airport
// these lines is drawn for each airport
// marker1 being the airport and marker2 destinations
for (Marker marker2 : markers) {
if (!marker1.equals(marker2)) {
float distance = distBetween(marker1.getPosition(),
marker2.getPosition());
if (longestDist.containsKey(marker1)) {
// possible we have a longer distance
if (distance > longestDist.get(marker1))
longestDist.put(marker1, distance);
} else {
// first distance
longestDist.put(marker1, distance);
}
}
}
}
// examine the distances collected
for (Marker marker: longestDist.keySet()) {
if (longestDist.get(marker) <= maxDistanceMeters) acceptedMarkers.add(marker);
}
return acceptedMarkers;
}
private List<Marker> getSurroundingMarkers(List<Marker> markers,
LatLng origin, int maxDistanceMeters) {
List<Marker> surroundingMarkers = surroundingMarkers = new ArrayList<Marker>();
if (markers == null) return surroundingMarkers ;
for (Marker marker : markers) {
double dist = distBetween(origin, marker.getPosition());
if (dist < getHydrantsLoadradius()) {
surroundingMarkers.add(marker);
}
}
return surroundingMarkers;
}
private float distBetween(LatLng pos1, LatLng pos2) {
return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
pos2.longitude);
}
/** distance in meters **/
private float distBetween(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;
int meterConversion = 1609;
return (float) (dist * meterConversion);
}
private List选择LowDistanceMarkers(列表标记,
int(最大距离计){
List acceptedMarkers=new ArrayList();
if(markers==null)返回acceptedMarkers;
Map longestDist=newhashmap();
用于(标记标记1:标记){
//在这个for循环中,我们记住每个标记的最大距离
//想象一张地图,上面有一家航空公司从机场出发的路线
//这些线是为每个机场绘制的
//marker1为机场和marker2目的地
用于(标记2:标记){
如果(!marker1.等于(marker2)){
浮动距离=距离(marker1.getPosition(),
marker2.getPosition());
if(集装箱最长距离(标记1)){
//可能我们有更长的距离
如果(距离>最长距离获取(标记1))
最长距离放置(标记1,距离);
}否则{
//第一距离
最长距离放置(标记1,距离);
}
}
}
}
//检查收集的距离
对于(标记:longestDist.keySet()){
如果(longestDist.get(marker)将所有标记的LatLng放在列表中,并将它们传递给此方法,在newLatLngBounds(bounds,50)的最后一行中,
50表示地图边缘和每边最外层标记之间的填充
public void centerIncidentRouteOnMap(List<LatLng> copiedPoints) {
double minLat = Integer.MAX_VALUE;
double maxLat = Integer.MIN_VALUE;
double minLon = Integer.MAX_VALUE;
double maxLon = Integer.MIN_VALUE;
for (LatLng point : copiedPoints) {
maxLat = Math.max(point.latitude, maxLat);
minLat = Math.min(point.latitude, minLat);
maxLon = Math.max(point.longitude, maxLon);
minLon = Math.min(point.longitude, minLon);
}
final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
mapFragment.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
}
public void centerIncidentRouteOnMap(列出复制点){
double minLat=整数.MAX_值;
double maxLat=整数.MIN_值;
double minLon=整数最大值;
double maxLon=整数.MIN_值;
用于(LatLng点:复制点){
maxLat=数学最大值(点纬度,maxLat);
minLat=Math.min(点纬度,minLat);
maxLon=Math.max(点经度,maxLon);
minLon=Math.min(点经度,minLon);
}
最终LatLngBounds边界=新LatLngBounds.Builder().include(新LatLng(maxLat,maxLon)).include(新LatLng(minLat,minLon)).build();
mapFragment.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,50));
}
基于cYrixmorten的一些想法,我简化了这个问题,因为我知道地图可以容纳至少4000公里的表面。因此,下面是构建被忽略的网络摄像头列表的函数(然后我简单地忽略该网络摄像头进行摄像头边界计算,但仍然添加标记,以便在用户移动时将其显示在地图上)
私有列表buildIgnoredWebcamsList(列出网络摄像头){
if(webcams==null | | webcams.size()<2)返回Lists.newArrayList();
int webcamCount=webcams.size();
//索引处摄像机的冲突数(距离>4000 km)#
float Average ConflictCount=0;
int[]conflictCount=新int[webcamCount];
数组.fill(conflictCount,0);
//查找摄影机对之间的冲突数
浮动[]距离=新浮动[1];
对于(int i=0;i<网络摄像头计数-1;++i){
网络摄像头a=网络摄像头。获取(i);
//我们不必从0开始,只需比较a和b一次
对于(int j=i+1;j4000*1000){
冲突计数[i]+=1;
冲突计数[j]+=1;
averageConflictCount+=2;
}
}
}
averageConflictCount/=网络摄像机计数;
//排除冲突数量大于平均值的所有网络摄像头
List ignoredCamerasForBounds=Lists.newArrayList();
private List<Webcam> buildIgnoredWebcamsList(List<Webcam> webcams) {
if (webcams == null || webcams.size() < 2) return Lists.newArrayList();
int webcamCount = webcams.size();
// Number of conflicts (distance > 4000 km) for the camera at index #
float averageConflictCount = 0;
int[] conflictCount = new int[webcamCount];
Arrays.fill(conflictCount, 0);
// Find number of conflicts between camera pairs
float[] distance = new float[1];
for (int i = 0; i < webcamCount - 1; ++i) {
Webcam a = webcams.get(i);
// We don't have to start from 0, compare a and b only once
for (int j = i + 1; j < webcamCount; ++j) {
Webcam b = webcams.get(j);
Location.distanceBetween(a.getLatitude(), a.getLongitude(), b.getLatitude(), b.getLongitude(), distance);
// We have a conflict between a and b if they are more than 4000km away
if (distance[0] > 4000 * 1000) {
conflictCount[i] += 1;
conflictCount[j] += 1;
averageConflictCount += 2;
}
}
}
averageConflictCount /= webcamCount;
// Exclude all webcams with a number of conflicts greater than the average
List<Webcam> ignoredCamerasForBounds = Lists.newArrayList();
for (int i = 0; i < webcamCount; ++i) {
if (conflictCount[i] > averageConflictCount) {
ignoredCamerasForBounds.add(webcams.get(i));
}
}
return ignoredCamerasForBounds;
}
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int ancho = size.x;
int alto =size.y;
List<LatLng> copiedPoints = new ArrayList<LatLng>();
copiedPoints.add(origin);
copiedPoints.add(dest);
centerIncidentRouteOnMap(copiedPoints, ancho, alto);
public void centerIncidentRouteOnMap(List<LatLng> copiedPoints, int ancho, int alto) {
double minLat = Integer.MAX_VALUE;
double maxLat = Integer.MIN_VALUE;
double minLon = Integer.MAX_VALUE;
double maxLon = Integer.MIN_VALUE;
for (LatLng point : copiedPoints) {
maxLat = Math.max(point.latitude, maxLat);
minLat = Math.min(point.latitude, minLat);
maxLon = Math.max(point.longitude, maxLon);
minLon = Math.min(point.longitude, minLon);
}
final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,ancho, alto, 50));
}