TileProvider método getTile – necesita traducir xyy a lat / long
Estoy portando una aplicación iOS a Android, y usando Google Maps Android API v2.
La aplicación necesita dibujar una superposición de mapa de calor en el mapa.
Hasta ahora, parece que la mejor opción es usar un TileOverlay
e implementar un TileProvider
personalizado. En el método getTile
, mi método se da x, y, y el zoom, y necesita devolver un mapa de bits en forma de un Tile
. Hasta aquí todo bien.
- Técnica para ejecutar varias MapActivities en el mismo proceso
- Varias ventanas de información en Android Maps API 2
- Buscar lugares dentro de una ciudad en Google Places Apis
- google maps api clave no funciona v2
- ¿Qué es el nivel de zoom 15 equivalente a?
Tengo una serie de elementos de mapa de calor que voy a utilizar para dibujar gradientes radiales en el mapa de bits, cada uno con un lat / largo. Tengo problemas con las siguientes dos tareas:
- ¿Cómo puedo determinar si el mosaico representado por x, y y zoom contiene el lat / long del elemento heatmap?
- ¿Cómo puedo traducir el lat / long del elemento heatmap a coordenadas x / y del mapa de bits.
¡Gracias por tu ayuda!
ACTUALIZAR
Gracias a la respuesta de MaciejGórski a continuación, y la implementación de marcin, pude obtener la primera mitad de mi pregunta, pero todavía necesito ayuda con la segunda parte. Para aclarar, necesito una función para devolver las coordenadas x / y del mosaico para un lat / long especificado. He intentado invertir los cálculos de MaciejGórski y la respuesta de Marcin sin suerte.
public static Point fromLatLng(LatLng latlng, int zoom){ int noTiles = (1 << zoom); double longitudeSpan = 360.0 / noTiles; double mercator = fromLatitude(latlng.latitude); int y = ((int)(mercator / 360 * noTiles)) + 180; int x = (int)(latlng.longitude / longitudeSpan) + 180; return new Point(x, y); }
Cualquier ayuda es apreciada!
- Aplicación de Android Studio 0.2 que utiliza Google Maps - Gradle modify
- NoClassDefFoundError en la biblioteca Google Play Services V2
- Calcular el nivel de zoom para Google Map para dos valores de LatLong
- Pantalla en blanco de la API de Google Map API V2
- No se puede lanzar el proyecto de la biblioteca de Android?
- ¿Qué significa el parámetro en la URL de Google Maps
- Aplicación de setRotation a Maps API v2
- Obtener latitud y longitud utilizando código postal
Esto funcionó para mí:
double n = Math.pow(2, zoom); double longitudeMin = x/n * 360 -180; double lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * y/n))); double latitudeMin = lat_rad * 180/Math.PI; double longitudeMax = (x + 1)/n * 360 -180; lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * (y + 1)/n))); double latitudeMax = lat_rad * 180/Math.PI;
Referencias: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
En el nivel de zoom 0, sólo hay un mosaico (x = 0, y = 0). En el siguiente nivel de zoom, el número de mosaicos se cuadruplica (se duplica en x e y).
Esto significa que en el nivel de zoom W
, x puede ser un valor en el rango <0, 1 << W).
De la documentación:
Las coordenadas de los azulejos se miden desde la esquina superior izquierda (noroeste) del mapa. En el nivel de zoom N, los valores de x de las coordenadas del mosaico varían de 0 a 2N – 1 y aumentan de oeste a este y los valores de y van de 0 a 2N – 1 y aumentan de norte a sur.
Usted puede lograr esto usando cálculos simples.
Para la longitud esto es sencillo:
double longitudeMin = (((double) x) / (1 << zoom)) * 360 - 180; double longitudeMax = (((double) x + 1) / (1 << zoom)) * 360 - 180; longitudeMax = Double.longBitsToDouble(Double.doubleToLongBits(longitudeMax) - 1); // adjust
Aquí x es primero escalado en <0,1), luego en <-180,180).
El valor máximo se ajusta, por lo que no se superpone con la siguiente área. Puede omitir esto.
Para la latitud esto será un poco más difícil, porque Google Maps utiliza la proyección de Mercator.
Primero escalas y igual que en el rango <-180,180). Tenga en cuenta que los valores deben ser invertidos.
double mercatorMax = 180 - (((double) y) / (1 << zoom)) * 360; double mercatorMin = 180 - (((double) y + 1) / (1 << zoom)) * 360;
Ahora usas una función mágica que hace la proyección de Mercator (de SphericalMercator.java ):
public static double toLatitude(double mercator) { double radians = Math.atan(Math.exp(Math.toRadians(mercator))); return Math.toDegrees(2 * radians) - 90; } latitudeMax = SphericalMercator.toLatitude(mercatorMax); latitudeMin = SphericalMercator.toLatitude(mercatorMin); latitudeMin = Double.longBitsToDouble(Double.doubleToLongBits(latitudeMin) + 1);
Esto se escribió de memoria y no se probó de ninguna manera, así que si hay un error allí, por favor, ponga un comentario y lo arreglaré.
MaciejGórski si no te importa (si lo haces, quitaré este post) compilé tu código en un método listo para usar:
private LatLngBounds boundsOfTile(int x, int y, int zoom) { int noTiles = (1 << zoom); double longitudeSpan = 360.0 / noTiles; double longitudeMin = -180.0 + x * longitudeSpan; double mercatorMax = 180 - (((double) y) / noTiles) * 360; double mercatorMin = 180 - (((double) y + 1) / noTiles) * 360; double latitudeMax = toLatitude(mercatorMax); double latitudeMin = toLatitude(mercatorMin); LatLngBounds bounds = new LatLngBounds(new LatLng(latitudeMin, longitudeMin), new LatLng(latitudeMax, longitudeMin + longitudeSpan)); return bounds; }
- Android Parse Presione el registro de dispositivo de notificación sólo una vez en un dispositivo
- ScrollView dentro de ViewPager, se desplaza automáticamente hacia el centro