2012-02-24 152 views
4

我一直在谷歌和SO上研究这个,但我被卡住了,我想我错过了一些基本的东西。大多数examples我见过没有处理任意的mapWidth和单点,只是覆盖的跨度。Android:MapController.zoomToSpan:给定距离和中心点的距离

我有一个地图点数据库,一个MapView和一个Geocoder。我可以在我的应用程序中搜索邮政编码,并通过我的Geocoder返回Address

使用此Address,我可以构建一个GeoPoint并搜索我的数据库并获取附近点的列表。问题来自于使用从返回的Address点构建的跨度和到数据库中最近点的距离来尝试缩放到跨度。

我只希望跨度包含最近的两个点(如果可用)。下面是相关的代码:

Collections.sort(listingDisplay, mComparator); 
    listingDisplayAdapter.notifyDataSetChanged(); 

    float spanWidth =0; 

    if (listingDisplay.size() > 1) { 

     spanWidth = (float) (2 * distanceFromPoint(listingDisplay.get(1), 
       current)); 

    } else if (listingDisplay.size() == 1) { 

     spanWidth = (float) (2 * distanceFromPoint(listingDisplay.get(0), 
       current)); 

    } 

    Log.v(TAG, "SpanWidth: " + spanWidth); 

    // Create span 
    int minLat = (int) (current.getLatitudeE6() - (spanWidth * 1E6)/2); 
    int maxLat = (int) (current.getLatitudeE6() + (spanWidth * 1E6)/2); 
    int minLong = (int) (current.getLongitudeE6() - (spanWidth * 1E6)/2); 
    int maxLong = (int) (current.getLongitudeE6() + (spanWidth * 1E6)/2); 

     // Zoom against span. This appears to create a very small region that doesn't encompass the points 
mapController.setCenter(current); 
mapController.zoomToSpan(Math.abs(minLat - maxLat), Math.abs(minLong - maxLong)); 

ListingDisplay包含最近点的列表,比较,mComparator对该列表进行排序与​​到最接近的位置我返回Address(在GeoPoint称为:current)在列表的顶部。

然后,我根据最接近的值设置spanWidth的值,并尝试从中找出跨度。

我的问题是,我该如何构建一个给定的距离和中心点的跨度

回答

5

经过很长很长的一段时间后,我终于意识到我没有考虑一些重要的信息,主要是Android上的距离是使用WGS84椭球计算出来的。

我结束了使用Jan Matuschek's excellent and simple GeoLocation class里面的帮助器方法,它附带了一个非常彻底解释了所涉及的概念。

我的方法基本上归结为以下几点。它可以被优化为一个很好的交易,直到一个简单的SQL查询,但在这里它是为我的目的,其中listingDisplay是数据库检索的自定义LocationNode对象的数组,并且GeoPoint电流直接从返回的Address标准的Android地理编码器。

public void setRegionForGeoPoint(GeoPoint current) { 

    // Earth radius in KM 
    final double EARTH_RADIUS = 6371.01; 

    // Dummy span distance in KM for initial search; distance buffer is in M 
    final double DISTANCE_BUFFER = 50; 
    final double dummyDistance = 100.0; 
//Create a list to store distances 
    List<Double> distancesList = new ArrayList<Double>(); 


    // Loop through and modify LocationNodes with distance from user 
    for (LocationNode location : listingDisplay) { 
     location.setDistance((float) distanceFromUser(location)); 

     // Dynamically calculate distance from our current point (epicentre) 
     distancesList.add(distanceFromPoint(location, current)); 
    } 

    // Sort distances 
    Collections.sort(distancesList); 

    // Calculate regional span 
    float spanWidth = (float) dummyDistance; 
    double distance = 0; 

    if (distancesList.size() > 0) { 
     if (distancesList.size() > 1) { 

      distance = distancesList.get(1); 
      spanWidth = (float) (distance + DISTANCE_BUFFER); 

     } else if (distancesList.size() == 1) { 

      distance = distancesList.get(0); 
      spanWidth = (float) (distance + DISTANCE_BUFFER); 

     } 

     //Obtain the spanwidth in metres. 
     double spanWidthInKM = (double) spanWidth/1000; 

     // Create span 
     GeoLocation[] boundingBoxSpan = currentGeoLocation 
       .boundingCoordinates(spanWidthInKM, EARTH_RADIUS); 

     //Create min/max values for final span calculation 
     int minLatSpan = (int) (boundingBoxSpan[0].getLatitudeInDegrees() * 1E6); 
     int maxLatSpan = (int) (boundingBoxSpan[1].getLatitudeInDegrees() * 1E6); 
     int minLongSpan = (int) (boundingBoxSpan[0].getLongitudeInDegrees() * 1E6); 
     int maxLongSpan = (int) (boundingBoxSpan[1].getLongitudeInDegrees() * 1E6); 

     //Finally calculate span 
     int latSpanE6 = Math.abs(minLatSpan - maxLatSpan); 
     int lonSpanE6 = Math.abs(minLongSpan - maxLongSpan); 

     // Set center 
     mapController.setCenter(current); 

     // Zoom to span 
     mapController.zoomToSpan(latSpanE6, lonSpanE6); 

    } else { 

     //TODO: Handle the case when we have no distance values to use 
    } 
} 


public double distanceFromPoint(LocationNode location, GeoPoint point) { 

    // Calculate distance from user via result 
    Location locationA = new Location("point A"); 
    locationA.setLatitude(location.getLatitude()); 
    locationA.setLongitude(location.getLongitude()); 

    Location locationB = new Location("point B"); 
    locationB.setLatitude((double) (point.getLatitudeE6()/1E6)); 
    locationB.setLongitude((double) (point.getLongitudeE6()/1E6)); 
    double distance = locationA.distanceTo(locationB); 
    Log.v(TAG, "Calculated Distance: " + distance); 
    return distance; 
}