Android: MapController.zoomToSpan: сделать интервал с учетом расстояния и центральной точки - PullRequest
4 голосов
/ 24 февраля 2012

Я исследовал это на Google и ТАК, но я застрял, я думаю, что упускаю что-то фундаментальное. Большинство примеров , которые я видел, не имеют дело с произвольной mapWidth и одной точкой, а только с диапазоном наложения.

У меня есть база данных точек карты, MapView и Geocoder. Я могу найти почтовый индекс в моем приложении, и Address вернул мой Geocoder.

Используя эту Address, я могу построить GeoPoint, выполнить поиск в моей БД и получить список ближайших точек. Проблема возникает из-за попытки zoomToSpan с использованием диапазона, построенного из возвращенной точки 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 на основе ближайшего значения и пытаюсь вычислить диапазон из этого.

У меня такой вопрос, как я могу построить промежуток из заданного расстояния и центральной точки ?

1 Ответ

5 голосов
/ 24 февраля 2012

Через очень, очень долгое время я в конце концов понял, что не рассматривал какую-то важную информацию, главным из которых был тот факт, что расстояния на Android рассчитываются с использованием эллипсоида WGS84.

Я закончил тем, что использовал вспомогательные методы внутри Отличный и простой класс GeoLocation Яна Матушека , который содержит очень подробное объяснение задействованных концепций.

Мой метод сводился к следующему. Вероятно, его можно оптимизировать, вплоть до простого 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;
}
...