2010-08-02 12 views
8

Kiedy opracowuję aplikację mapową na Androida, chcę narysować okrąg na mapie, której promień wynosi 1 metr. Jak wiadomo, nie mogę bezpośrednio rysować 1 metra, powinienem przekonwertować 1 metr na odległość dwóch pikseli w zależności od poziomu zoomu. Jak mogę go przekonwertować, czy jest coś, co mogę wykorzystać.Jak zmienić odległość od 1 metra do piksela?

Canvas.draw (x, y, radius), jaką wartość powinienem umieścić w tej metodzie?

+1

jeśli chcesz przekonwertować 1 metr na dwa piksele, a chcesz mieć promień 1 metra, to chcesz przekazać '2' do parametru' promień'. Teraz mówisz, że * zależy od poziomu powiększenia *, więc myślę, że będziesz musiał podać coś w rodzaju '2 * (zoomLevel * zoomLevelCoefficient)' –

+0

To było interesujące pytanie, czy znalazłeś rozwiązanie, które zadziałało dla ciebie? – Idistic

Odpowiedz

3

Trzy pytania masz zapytać 1- Jak duża jest twoja mapa 2- Jaki jest Twój poziom zoom 3- Jak duży jest ekran

Zróbmy założenie, że mapa ma takie same proporcje jako twój ekran (jeśli nie, to musisz się martwić, w którą stronę przyciąć (wertykalnie lub poziomo) lub w jaki sposób rozciągnąć, a następnie zmienić naszą odpowiedź na 1)

Po uzyskaniu odpowiedzi 1 i 3 możesz pracować stosunek między licznikami i pikselami w przypadku powiększenia 100%, więc będziesz miał piksele na metr

Następnie trzeba utrzymywać współczynnik powiększenia (np: zoom w podwójnej wielkości wynosi 200%)

rozmowa narysować okrąg będzie wyglądać następująco

Canvas.draw(x,y, radius_in_meters * pixels_per_meter * zoom_factor/100); 
+0

Znalezienie pikseli na metr to sedno tego pytania. Jak duża jest Twoja mapa może być łatwo odpowiedzieć w sposób lat x lon, a nie piksów kwadratowych. Jak przejść od lateksu do kwadratowych pikseli? – jamesh

9

Zakładając, że mapa jest Google Maps, używają projekcji Mercator, więc musisz użyć jej do konwersji. W projekcji Mercator odległość, którą piksel reprezentuje w metrach, zmienia się wraz z szerokością geograficzną, więc gdy licznik jest bardzo małą odległością w stosunku do promienia Ziemi, szerokość geograficzna jest ważna.

Wszystkie poniższe przykłady to javascript, więc może być konieczne przetłumaczenie ich.

Oto ogólnego wyjaśnienia układu współrzędnych:

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

Przykład zawiera obiekt odwzorowanie walcowe równokątne, który obejmuje metody fromLatLngToPoint() i fromPointToLatLng():

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

Po konwersji (x, y) na (lat, lon), tak narysujesz okrąg:

// 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) 
} 

Te dwa mashups narysować okrąg o danym promieniu na powierzchni Ziemi:

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

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

Jeśli zdecydujesz się zignorować projekcję wtedy byłoby użyć współrzędnych kartezjańskich i po prostu narysuj okrąg za pomocą Twierdzenia Pitagorasa:

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

8

Spójrz na obiekt Projection w interfejsie API. Ma na nim metodę o nazwie metaToEquatorPixels(). Biorąc pod uwagę opis w api, może on być dokładny tylko wzdłuż równika, ale pomyślałem, że warto wspomnieć, jeśli dokładność nie była dla ciebie problemem.

Oto sposób na wykorzystanie tego wewnątrz metody wyciągania nakładki, biorąc pod uwagę promień w metrach, a szerokość i długość geograficzna, gdzie chcesz, aby narysować okrąg:

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()); 
+0

Możesz być zainteresowany tym tematem, który daje prostą formułę, aby zrekompensować zniekształcenie Mercatora: http://stackoverflow.com/questions/2077054/how-to-compute-a-radius-around-a-point-in -an-android-widok mapy – Gromix

2
public static int metersToRadius(float meters, MapView map, double latitude) { 
    return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));   
} 
1

Można obliczyć poziom powiększenia dla pożądanego promienia:

Najpierw musimy obliczyć szerokość ekranu telefonu. Na poziomie zbliżenia 1 równik Ziemi ma 256 pikseli długości, a każdy kolejny poziom powiększenia podwaja liczbę pikseli potrzebnych do przedstawienia rów gruntowy. Poniższa funkcja zwraca poziom powiększenia, w którym ekran pokaże obszar o szerokości 1 km.

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; 
} 
Powiązane problemy