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.

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:

  1. ¿Cómo puedo determinar si el mosaico representado por x, y y zoom contiene el lat / long del elemento heatmap?
  2. ¿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!

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; } 
  • Google Maps API V2 'Error al cargar mapa. No se pudo contactar con Google Servers, ni siquiera comprobar permiso y keystore
  • Error de Google maps: la posición del marcador no se actualiza después de arrastrar
  • Extracción de datos de Google Maps Place (específicamente los precios de la gasolina)
  • Error en Google Maps android "android Error al cargar el mapa. No se pudo contactar con los servidores de Google. "
  • Suprimir diálogo de selección al llamar al mapa de Google con la intención
  • Deshabilitar la agrupación en el nivel máximo de zoom utilizando android-maps-utils
  • ¿Cuál es la mejor manera de soportar apis de Google Maps (v1 y v2)?
  • Google Maps API Android
  • Google Maps Android API v2 en China - la carga del mapa tomó alrededor de una hora
  • El mapa de Google llamado dentro de un fragmento devuelve null
  • Determinar un nivel de zoom razonable para Google Maps dada la precisión de la ubicación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.