2012-10-02 13 views
9

Estoy cargando mosaicos de mapas de Google Maps usando Static Maps, usando .NET.API estática de Google Maps: obtenga SW y NE por coordenadas del centro

El problema que tengo es que no sé qué son las coordenadas SW y NE de la imagen devuelta.

He encontrado muchos ejemplos de códigos diferentes, fórmulas, pero todas parecen estar defectuosas. Este es el que se acercó más a la respuesta correcta. Cuando ingresé las coordenadas en Google Maps, mostró que estaba un poco apagado.

var result = GoogleMapsAPI.GetBounds(new Coordinate(4.79635, 51.15479), 20, 512, 512); 

public static class GoogleMapsAPI 
{ 
    public static MapCoordinates GetBounds(Coordinate center, int zoom, int mapWidth, int mapHeight) 
    { 
     var scale = Math.Pow(2, zoom); 

     var SWPoint = new Coordinate(center.X - (mapWidth/2)/scale, center.Y - (mapHeight/2)/scale); 
     var NEPoint = new Coordinate(center.X + (mapWidth/2)/scale, center.Y + (mapHeight/2)/scale); 

     return new MapCoordinates() { SouthWest = SWPoint, NorthEast = NEPoint }; 
    } 
} 

public class MapCoordinates 
{ 
    public Coordinate SouthWest { get; set; } 
    public Coordinate NorthEast { get; set; } 
} 

public class Coordinate 
{ 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 

    public double X { get { return Latitude; } set { Latitude = value; } } 
    public double Y { get { return Longitude; } set { Longitude = value; } } 

    public Coordinate(double lat, double lng) 
    { 
     Latitude = lat; 
     Longitude = lng; 
    } 

    public override string ToString() 
    { 
     return X.ToString() + ", " + Y.ToString(); 
    } 
} 

Fuentes:
How to get bounds of a google static map?
http://www.easywms.com/easywms/?q=zh-hans/node/3612

imagen cargada por el centro de coordenadas:
http://maps.googleapis.com/maps/api/staticmap?center=51.15479,4.79635&zoom=20&size=512x512&sensor=false

SW defectuoso:
https://maps.google.be/maps?q=51.154545859375,+4.796105859375&hl=en&ll=51.154763,4.796695&spn=0.000568,0.001635&sll=51.154687,4.796838&sspn=0.001136,0.00327&t=m&z=20

NE defectuoso:
https://maps.google.be/maps?q=+51.155034140625,+4.796594140625&hl=en&ll=51.154764,4.796684&spn=0.000568,0.001635&sll=51.154599,4.796723&sspn=0.001136,0.00327&t=m&z=20

Respuesta

4

EDIT: Wow, me di cuenta de que esta pregunta tiene casi dos años. Lo siento por eso.

OK, así que creo que hay algunas cosas que están sucediendo aquí. Lo más importante es que no está haciendo la proyección de Mercator mencionada en los enlaces que proporcionó. Puedes verlo en acción con un code sample en los documentos de la API de google maps. Creo que la razón por la que te estás acercando es que el factor de escala es tan grande en el nivel de zoom 20 que ahoga los detalles del problema.

Para obtener los límites, debe tomar el centro lat/lon, convertirlo a coordenadas de píxel, sumar/restar para obtener las coordenadas de píxel de las esquinas que desee y luego convertir nuevamente a lat/lon. El código en el primer enlace puede hacer la proyección y la proyección inversa. A continuación lo he traducido en C#.

En su solución anterior, está tomando coordenadas lat/lon y sumando/restando coordenadas mundiales (coordenadas/escala de píxeles), por lo que está combinando dos sistemas de coordenadas diferentes.

Un problema que encontré al tratar de resolver esto es que su clase Coordinate es un poco confusa. Espero que no tenga esto al revés, pero parece que estás retrocediendo en la latitud y la longitud. Esto es importante porque la proyección de Mercator es diferente en cada dirección, entre otras razones. Su mapeo X/Y también parece estar al revés, porque Latitude es su posición Norte/Sur, que debería ser la coordenada Y cuando se proyecta, y Longitude es su posición Este/Oeste, que debería ser la coordenada X cuando se proyecta.

Para encontrar los límites, se necesitan three coordinate systems: Longitud/Latitud, Coordenadas mundiales y Coordenadas de píxeles. El proceso es Centro Lat/Lon - (Proyección Mercator) -> Coordenadas mundiales centrales -> Coordenadas de píxeles centrales -> Coordenadas NE/SW de píxeles -> Coordenadas mundiales NE/SW - (Proyección de Mercator inversa) -> NE/SW Lat/Lon .

Encuentra las coordenadas de los píxeles sumando/restando las dimensiones de la imagen/2. Sin embargo, el sistema de coordenadas de píxel comienza desde la esquina superior izquierda, por lo que para obtener la esquina NE necesita agregar ancho/2 de x y restar altura/2 de y. Para la esquina SW, debe restar ancho/2 de xy agregar altura/2 a y.

Aquí está el código de proyección (como parte de su clase GoogleMapsAPI) en C#, la traducción desde el primer enlace anterior javascript:

static GoogleMapsAPI() 
{ 
    OriginX = TileSize/2; 
    OriginY = TileSize/2; 
    PixelsPerLonDegree = TileSize/360.0; 
    PixelsPerLonRadian = TileSize/(2 * Math.PI); 
} 

public static int TileSize = 256; 
public static double OriginX, OriginY; 
public static double PixelsPerLonDegree; 
public static double PixelsPerLonRadian; 

public static double DegreesToRadians(double deg) 
{ 
    return deg * Math.PI/180.0; 
} 

public static double RadiansToDegrees(double rads) 
{ 
    return rads * 180.0/Math.PI; 
} 

public static double Bound(double value, double min, double max) 
{ 
    value = Math.Min(value, max); 
    return Math.Max(value, min);  
} 

//From Lat, Lon to World Coordinate X, Y. I'm being explicit in assigning to 
//X and Y properties. 
public static Coordinate Mercator(double latitude, double longitude) 
{ 
    double siny = Bound(Math.Sin(DegreesToRadians(latitude)), -.9999, .9999); 

    Coordinate c = new Coordinate(0,0); 
    c.X = OriginX + longitude*PixelsPerLonDegree; 
    c.Y = OriginY + .5 * Math.Log((1 + siny)/(1 - siny)) * -PixelsPerLonRadian; 

    return c; 
} 

//From World Coordinate X, Y to Lat, Lon. I'm being explicit in assigning to 
//Latitude and Longitude properties. 
public static Coordinate InverseMercator(double x, double y) 
{  
    Coordinate c = new Coordinate(0, 0); 

    c.Longitude = (x - OriginX)/PixelsPerLonDegree; 
    double latRadians = (y - OriginY)/-PixelsPerLonRadian; 
    c.Latitude = RadiansToDegrees(Math.Atan(Math.Sinh(latRadians))); 

    return c; 
} 

Puede comprobar el código Javascript original para comentarios más detallados.

Lo probé al aproximar manualmente los límites y luego compararlos con la respuesta que dio el código. Mis aproximaciones manuales para la esquina NE fueron (51.15501, 4.796695) y el código escupió (51.155005..., 4.797038...), que parece bastante cercano. La esquina SW fue aproximada (51.154572, 4.796007), escupió el código (51.154574..., 4.796006...).

Esto fue divertido, ¡espero que esto ayude!

EDIT: di cuenta que no incluyo el nuevo GetBounds función:

public static MapCoordinates GetBounds(Coordinate center, int zoom, int mapWidth, int mapHeight) 
{ 
    var scale = Math.Pow(2, zoom); 

    var centerWorld = Mercator(center.Latitude, center.Longitude); 
    var centerPixel = new Coordinate(0, 0); 
    centerPixel.X = centerWorld.X * scale; 
    centerPixel.Y = centerWorld.Y * scale; 

    var NEPixel = new Coordinate(0, 0); 
    NEPixel.X = centerPixel.X + mapWidth/2.0; 
    NEPixel.Y = centerPixel.Y - mapHeight/2.0; 

    var SWPixel = new Coordinate(0, 0); 
    SWPixel.X = centerPixel.X - mapWidth/2.0; 
    SWPixel.Y = centerPixel.Y + mapHeight/2.0; 

    var NEWorld = new Coordinate(0, 0); 
    NEWorld.X = NEPixel.X/scale; 
    NEWorld.Y = NEPixel.Y/scale; 

    var SWWorld = new Coordinate(0, 0); 
    SWWorld.X = SWPixel.X/scale; 
    SWWorld.Y = SWPixel.Y/scale; 

    var NELatLon = InverseMercator(NEWorld.X, NEWorld.Y); 
    var SWLatLon = InverseMercator(SWWorld.X, SWWorld.Y); 

    return new MapCoordinates() { NorthEast = NELatLon, SouthWest = SWLatLon }; 
} 

Sólo recuerde asegurarse de que tienes la latitud y la longitud de allí a la derecha:

var result = GoogleMapsAPI.GetBounds(new Coordinate(51.15479, 4.79635), 20, 512, 512); 

que sé el código no es el mejor, pero espero que esté claro.

+0

Muchas gracias por la respuesta bien escrita, por desgracia, es 2 años demasiado tarde :) – FrieK

+0

Gracias por el voto :) – peterjb

+0

Estoy un montón a menos que multiplique 'Math.Pow (2, zoom)' con 2. También comparé con otras fuentes y probé todas las pequeñas variaciones. ¿Alguna idea de por qué es eso? – clankill3r

Cuestiones relacionadas