unas - obtener latitud y longitud de una direccion c#
¿Cómo obtener coordenadas cuando se conoce la dirección? (3)
Microsoft Mappoint también contiene una API que puede utilizar. Es capaz de devolver geocoordinates.
Obtuve / adapté el siguiente código del libro de Adam Freeman "Metro revelado: creación de aplicaciones para Windows 8 con XAML y C #" para obtener la dirección cuando se conocen las coordenadas:
public static async Task<string> GetAddressForCoordinates(double latitude, double longitude)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("reverse?format=json&lat={0}&lon={1}", latitude, longitude));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
return jsonObject.GetNamedObject("address").GetNamedString("road");
}
¿Cómo puedo obtener lo opuesto (las coordenadas si se conoce la dirección)?
ACTUALIZAR
Estoy agregando una recompensa a esto; Lo que ya tengo (se muestra arriba) es la geocodificación inversa (obteniendo la dirección para las coordenadas); lo que necesito es geocodificación (obtener las coordenadas de la dirección).
Basado en mi código de geocodificación inversa anterior, supongo que podría ser algo como esto:
public static async Task<string> GetCoordinatesForAddress(string address)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("format=json&address={0}", address));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
return jsonObject.GetNamedObject("address").GetNamedString("lat"); // <-- what about "lon"?
}
... pero no sé cómo combinar los dos valores de coordenadas (longitud y latitud) (suponiendo que esto sea correcto o esté cerca de ser correcto). ¿Alguien puede verificar esto, limpiarlo o dar un mejor ejemplo (ya sea usando nominatim o de otro modo)?
ACTUALIZACIÓN 2
Para responder la pregunta / comentario de Peter Ritchie a continuación:
En el original (código de geocodificación inversa), tengo:
return jsonObject.GetNamedObject("address").GetNamedString("road");
Simplemente devuelve el camino; algo así como "157 Riverside Avenue", supongo.
Pero para geocodificar (que necesitan dos valores, una longitud y una latitud), tengo este pseudocódigo:
return jsonObject.GetNamedObject("address").GetNamedString("lat"); // <-- what about "lon"?
Así que no sé si necesito cambiar el valor de retorno de la Tarea <string
> a la Tarea <List
y llamar (pseudocódigo detallado) [Nota: me está costando escapar de los corchetes angulares para Tarea con una Lista de cadenas ]
var latitude jsonObject.GetNamedObject("address").GetNamedString("lat");
var longitude jsonObject.GetNamedObject("address").GetNamedString("lat");
List<string> listCoordinates = new List<string>();
listCoordinates.Add(latitude);
listCoordinates.Add(longitude);
return listCoordinates;
... o algo así:
string latitude jsonObject.GetNamedObject("address").GetNamedString("lat");
string longtude jsonObject.GetNamedObject("address").GetNamedString("long");
return string.Format("{0};{1}", latitude, longitude);
... o ???
ACTUALIZACIÓN 3
En respuesta al código Json propuesto para geocodificación:
En función del código de geocodificación inverso original, ¿no debería la llamada ser más así?
HttpClient httpClient = new HttpClient { BaseAddress = new Uri("http://nominatim.openstreetmap.org/") };
var httpResult = await httpClient.GetAsync(
String.Format("search?format=json&addressdetails={0}", address);
... pero en cualquier caso: el tipo JArray no se reconoce, aunque JsonArray sí lo está. El tipo JValue no se reconoce, aunque JsonValue sí lo está. El tipo JsonConverter no es reconocido; tal vez parte de Json.Net?
Lo más cerca que puedo llegar para obtener el código proferido para compilar es:
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JsonArray)JsonConverter.DeserializeObject(result);//<-- JsonConvert[er] not recognized; part of Json.NET?
var latString = ((JsonValue)r[0]["lat"]).ValueType as string;
var longString = ((JsonValue)r[0]["lon"]).ValueType as string;
... pero incluso con esto (cercano pero sin Bob Seger), JsonConvert y JsonConverter no son reconocidos.
ACTUALIZACIÓN 4
Después de trabajar de manera más concertada a través de la documentación en http://wiki.openstreetmap.org/wiki/Nominatim#Search , creo que mi método original (geocodificación inversa) podría ser mejor como:
public static async Task`<string`> GetAddressForCoordinates(double latitude, double longitude)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org/")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("reverse?format=json&lat={0}&lon={1}", latitude, longitude));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
string house = jsonObject.GetNamedObject("addressparts").GetNamedString("house");
string road = jsonObject.GetNamedObject("addressparts").GetNamedString("road");
string city = jsonObject.GetNamedObject("addressparts").GetNamedString("city");
string state = jsonObject.GetNamedObject("addressparts").GetNamedString("state");
string postcode = jsonObject.GetNamedObject("addressparts").GetNamedString("postcode");
string country = jsonObject.GetNamedObject("addressparts").GetNamedString("country");
return string.Format("{0} {1}, {2}, {3} {4} ({5})", house, road, city, state, postcode, country);
}
Esto volvería, para los correspondientes argumentos de coordenadas pasados, algo así como: " 157 Riverside Avenue, Champaign, IL 55555 (EE. UU.) "
Lo que me parece extraño acerca de la documentación es que no hay ningún elemento de "estado" entre las partes de la dirección; si eso es realmente cierto, y no solo un descuido de la documentación, mi código anterior fallaría en la llamada a GetNamedString ("estado").
Todavía no estoy seguro de cuál es la sintaxis correcta, etc., para el método opuesto (código geográfico), recuperar las coordenadas después de pasar una dirección.
ACTUALIZACIÓN 5
De acuerdo, descargué Json.NET y lo compilé. Todavía no lo he probado, pero he marcado la respuesta de Peter Ritchie como THE (50 puntos).
Este es el código que estoy usando:
public static async Task<string> GetCoordinatesForAddress(string address)
{
HttpClient httpClient = new HttpClient { BaseAddress = new Uri("http://nominatim.openstreetmap.org/") };
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("search?q={0}&format=json&addressdetails=1", Pluggify(address))); // In my Pluggify() method, I replace spaces with + and then lowercase it all
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JArray)JsonConvert.DeserializeObject(result);
var latString = ((JValue)r[0]["lat"]).Value as string;
var longString = ((JValue)r[0]["lon"]).Value as string;
return string.Format("{0};{1}", latString, longString);
}
También: Algo gracioso sucedió en el camino de regreso a este foro: al instalar Json.NET a través de NuGet, también vi "Servidorizador JSON más rápido de .NET por ServiceStack", que dice ser 3 veces más rápido que Json.NET. FIWW, se ha actualizado más recientemente que Json.NET. Pensamientos / reacción?
ACTUALIZACIÓN 6
Tengo este código para implementar esto (la identificación de la aplicación y el código han sido cambiados para proteger a los semi-inocentes (yo)):
// If address has not been explicitly entered, try to suss it out:
address = textBoxAddress1.Text.Trim();
lat = textBoxLatitude1.Text.Trim();
lng = textBoxLongitude1.Text.Trim();
if (string.IsNullOrWhiteSpace(address))
{
address = await SOs_Classes.SOs_Utils.GetAddressForCoordinates(lat, lng);
}
. . .
public async static Task<string> GetAddressForCoordinates(string latitude, string longitude)
{
string currentgeoLoc = string.Format("{0},{1}", latitude, longitude);
string queryString = string.Empty;
string nokiaAppID = "j;dsfj;fasdkdf";
object nokiaAppCode = "-14-14-1-7-47-178-78-4";
var hereNetUrl = string.Format(
"http://demo.places.nlp.nokia.com/places/v1/discover/search?at={0}&q={1}&app_id={2}
&app_code={3}&accept=application/json",
currentgeoLoc, queryString, nokiaAppID, nokiaAppCode);
// get data from HERE.net REST API
var httpClient = new HttpClient();
var hereNetResponse = await httpClient.GetStringAsync(hereNetUrl);
// deseralize JSON from Here.net
using (var tr = new StringReader(hereNetResponse))
using (var jr = new JsonTextReader(tr))
{
var rootObjectResponse = new JsonSerializer
().Deserialize<JsonDOTNetHelperClasses.RootObject>(jr);
var firstplace = rootObjectResponse.results.items.First();
return HtmlUtilities.ConvertToText(firstplace.vicinity);
// NOTE: There is also a title (such as "Donut Shop", "Fire stations", etc.?) and type (such as "residence" or "business", etc.?)
}
}
... pero en esta línea en GetAddressForCoordinates ():
var firstplace = rootObjectResponse.results.items.First();
... Recibo este error msg: "* System.InvalidOperationException no fue manejado por el código de usuario HResult = -2146233079 Message = La secuencia no contiene elementos Source = System.Core StackTrace: en System.Linq.Enumerable.First [TSource] (IEnumerable` 1 fuente) en SpaceOverlays.SOs_Classes.SOs_Utils.d__12.MoveNext () en c: ... * "
El valor de hereNetResponse es:
{"results":{"items":[]},"search":{"context":{"location":{"position":[38.804967,-90.113183],"address":
{"postalCode":"62048","city":"Hartford","stateCode":"IL","county":"Madison","countryCode":"USA","country":"
USA","text":"Hartford IL 62048
USA"}},"type":"urn:nlp-types:place","href":"http://demo.places.nlp.nokia.com/places/v1/places/loc-
dmVyc2lvbj0xO3RpdGxlPUhhcnRmb3JkO2xhdD0zOC44MDQ5Njc7bG9uPS05MC4xMTMxODM7Y2l0eT1IY
XJ0Zm9yZDtwb3N0YWxDb2RlPTYyMDQ4O2NvdW50cnk9VVNBO3N0YXRlQ29kZT1JTDtjb3VudHk9TWFka
XNvbjtjYXRlZ29yeUlkPWNpdHktdG93bi12aWxsYWdl;context=Zmxvdy1pZD02YmUzZDM4Yi0wNGVhLTUyM
jgtOWZmNy1kNWNkZGM0ODI5OThfMTM1NzQyMDI1NTg1M18wXzE2MA?
app_id=F6zpNc3TjnkiCLwl_Xmh&app_code=QoAM_5BaVDZvkE2jRvc0mw"}}}
... por lo que parece que hay información válida allí, como debería devolver "Hartford, IL"
Y en cualquier caso, un valor de retorno en blanco no debería arrojar una excepción, creo que ...
Si buscas geocodificación de google maps, puedes encontrarla aquí:
https://developers.google.com/maps/documentation/geocoding/
y un ejemplo de uso es:
http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false
Convierte a Json y toma el objeto Geometry.
en cuanto a cómo, básicamente, devolver dos valores de una función, en C # tiene 4 opciones:
- convierta ambos objetos en un solo objeto del mismo tipo (en el caso de las cadenas, simplemente sepárelos por un delimitador, como lo hizo) y luego analice los dos después.
- devolver una lista, en este caso, una Tarea (o matriz).
- crea una nueva clase / objeto que contenga ambos (en este caso puedes llamarlo Geometría, por ejemplo).
- devuelve uno o ambos objetos al requerir que se pasen como referencia a la función. En una función asíncrona, esto seguramente será muy complicado, pero dependiendo de quién llame a la función y quién procese el resultado, podría ser posible.
Lo que estás preguntando es simplemente "geocodificación". Si desea utilizar Nominatim específicamente, lo llaman "Buscar". Esto es, hasta cierto punto, la validación de direcciones; pero parte de la "validación" incluye coordenadas (cuadro delimitador, latitud / longitud, etc., dependiendo de qué se busca y qué tipo de resultado). Hay muchos detalles sobre los resultados, demasiado para simplemente publicar aquí; pero este detalle se puede encontrar aquí: http://wiki.openstreetmap.org/wiki/Nominatim#Search (incluidos los exámenes).
Tendrá que analizar los resultados (XML, JSON o HTML) para obtener los campos que le interesan.
Actualización 1:
En cuanto a qué hacer con los valores reales: depende. Si desea ver las coordenadas en un formulario, simplemente puede poner las cadenas largas y lat en controles individuales. Si quiere ponerlo en un solo control, podría usar string.Format("{0}, {1}", latString, longString)
. Si desea utilizar los coords con varios métodos / tipos para una aplicación de la Tienda Windows, es posible que deba utilizar la clase Microsoft.Maps.MapControl.Location
. Por ejemplo:
Double latNumber;
Double longNumber;
if(false == Double.TryParse(latString, out latNumber)) throw new InvalidOperationException();
if(false == Double.TryParse(longString, out longNumber)) throw new InvalidOperationException();
var location = new Location(latNumber, longNumber);
Lo anterior supone que has extraído el lat y long de la respuesta y los latString
puesto en latString
, longString
respectivamente.
Algunas interfaces pueden requerir lat / long como valores dobles separados, en cuyo caso solo use latNumber
y longNumber
arriba.
Además de eso, realmente depende específicamente de las interfaces que quiere usar. Pero, lo anterior debería darle suficiente para usar la mayoría de las interfaces.
Actualización 2:
Si la pregunta no es "cómo obtener coordenadas", sino "cómo analizar objetos json", recomendaría usar JSon.Net para obtener las cadenas lat / long en el resultado json. Por ejemplo:
var httpClient = new HttpClient();
var httpResult = await httpClient.GetAsync(
"http://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=json&polygon=1&addressdetails=1");
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JArray) JsonConvert.DeserializeObject(result);
var latString = ((JValue) r[0]["lat"]).Value as string;
var longString = ((JValue)r[0]["lon"]).Value as string;
... ver arriba wrt qué hacer con latString
y longString