Как изменить расстояние от метра до пикселя? - PullRequest
10 голосов
/ 02 августа 2010

Когда я разрабатываю приложение для карты Android, я хочу нарисовать на карте круг с радиусом 1 метр. Как вы знаете, я не могу нарисовать 1 метр напрямую, я должен конвертировать 1 метр на расстояние двух пикселей в зависимости от уровня масштабирования. Как мне конвертировать, есть ли что-нибудь, что я могу использовать API.

Canvas.draw (x, y, radius), какое значение я должен указать этому методу?

Ответы [ 5 ]

10 голосов
/ 02 августа 2010

Предполагая, что ваша карта Google Maps, они используют проекцию Меркатора, поэтому вам нужно будет использовать ее для преобразования.В проекции Меркатора расстояние, которое пиксель представляет в метрах, зависит от широты, поэтому, несмотря на то, что метр является очень небольшим расстоянием по сравнению с радиусом Земли, широта важна.

Все приведенные ниже примеры являются JavaScript, поэтомувам может понадобиться перевести их.

Вот общее объяснение системы координат:

http://code.google.com/apis/maps/documentation/javascript/maptypes.html#WorldCoordinates

В этом примере содержится объект MercatorProjection, который включает методы fromLatLngToPoint() и fromPointToLatLng ():

http://code.google.com/apis/maps/documentation/javascript/examples/map-coordinates.html

Как только вы преобразовали (x, y) в (lat, lon), вот как вы рисуете круг:

// Pseudo code
var d = radius/6378800; // 6378800 is Earth radius in meters
var lat1 = (PI/180)* centerLat;
var lng1 = (PI/180)* centerLng;

// Go around a circle from 0 to 360 degrees, every 10 degrees
for (var a = 0 ; a < 361 ; a+=10 ) {
    var tc = (PI/180)*a;
    var y = asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc));
    var dlng = atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(y));
    var x = ((lng1-dlng+PI) % (2*PI)) - PI ;
    var lat = y*(180/PI);
    var lon = x*(180/PI);

    // Convert the lat and lon to pixel (x,y) 
}

Эти два гибридных приложения рисуют на поверхности Земли круг заданного радиуса:

http://maps.forum.nu/gm_sensitive_circle2.html

http://maps.forum.nu/gm_drag_polygon.html

Если вы выберетечтобы игнорировать проекцию, вы должны использовать декартовы координаты и просто нарисовать круг, используя теорему Пифагора:

http://en.wikipedia.org/wiki/Circle#Cartesian_coordinates

8 голосов
/ 24 ноября 2010

Посмотрите на Проекция объект в API. У него есть метод с именем meterToEquatorPixels (). Учитывая описание в API, оно может быть точным только вдоль экватора, но я подумал, что стоит упомянуть, если точность не является проблемой для вас.

Вот способ использовать это в методе рисования вашего оверлея, учитывая радиус в метрах, а также широту и долготу, где вы хотите нарисовать круг:

Projection projection = mapView.getProjection();
Point center = projection.toPixels(new GeoPoint(yourLat * E6, yourLong * E6), null);
float radius = projection.metersToEquatorPixels(radiusInMeters);
canvas.draw(center.x, center.y, radius, new Paint());
3 голосов
/ 15 апреля 2011
public static int metersToRadius(float meters, MapView map, double latitude) {
    return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));         
}
3 голосов
/ 02 августа 2010

Три вопроса, которые вы должны задать 1- Насколько велика ваша карта 2- Каков ваш уровень масштабирования? 3- Насколько велик ваш экран

Давайте сделаем предположение, что карта имеет такое же соотношение сторон, что и ваш экран (если нет, то вам нужно беспокоиться о том, какой способ обрезки (по вертикали или горизонтали) или в каком направлении растянуть, а затем измените наш ответ на 1)

Когда у вас есть ответы 1 и 3, вы можете определить соотношение между метрами и пикселями в случае увеличения 100%, так что у вас будет количество пикселей на метр

Далее необходимо сохранить коэффициент масштабирования (например, увеличение в два раза составляет 200%)

Ваш призыв нарисовать круг будет выглядеть так

 Canvas.draw(x,y, radius_in_meters * pixels_per_meter * zoom_factor/100);
1 голос
/ 29 февраля 2012

Вы можете рассчитать уровень масштабирования для желаемого радиуса:

Сначала нам нужно вычислить ширину экрана телефона. На уровне масштабирования 1 экватор Земли имеет длину 256 пикселей, а каждый последующий уровень масштабирования удваивает количество пикселей, необходимое для представления экватора Земли. Следующая функция возвращает уровень масштабирования, при котором на экране отображается область шириной 1 км.

private int calculateZoomLevel() {

    int ht, screenWidth;
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    ht = displaymetrics.heightPixels;
    screenWidth = displaymetrics.widthPixels;

    double equatorLength = 40075004; // in meters
    double widthInPixels = screenWidth;
    double metersPerPixel = equatorLength / 256;
    int zoomLevel = 1;
    while ((metersPerPixel * widthInPixels) > 1000) {
        metersPerPixel /= 2;
        ++zoomLevel;
    }

    Log.i(tag, "zoom level = " + zoomLevel);
    return zoomLevel;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...