Qualche giorno fa ho postato sui miei account Twitter e Facebook una piccola richiesta di aiuto, subito accolta da tutti i miei amici, che mi hanno suggerito la soluzione. La espongo qua, perchè può essere utile a qualcun’altro. E siccome sono blogorroico, vi descriverò lo scenario all’interno del quale l’ha utilizzata.
Anche in questo caso c’entra Flight Simulator.
Vediamo come e perchè.
Supponiamo il diagramma seguente. Scusatemi, ma non ho avuto il tempo di farlo in scala (cit.), e quello che vedete qui sotto non rappresenta in alcun modo una cartina vera. E’ solo un esempio, ma basta ed avanza.
Il pallino verde è un aeroplano che sta volando da qualche parte nel mondo.
La freccia blu è la direzione che sta seguendo.
I confini rossi sono appena gli ipotetici confini di tre nazioni: nazione A, B e C.
Il diagramma sopra mostra quindi l’aereo che sta volando nello spazio aereo della nazione C. Ma sta volando nella direzione indicata, quindi prima o poi oltrepasserà i confini della nazione C ed entrerà in B.
Esiste un servizio Web che mi permette, date latitudine e longitudine, di sapere in quale nazione mi trovo?
La risposta è ovviamente sì. Mi è stato ovviamente suggerito Google Map, e così ho fatto, ottenendo il risultato che volevo. Per la documentazione del caso, rivolgetevi a questo url.
La versione breve è questa. Richiamando (anche da un semplice browser) il seguente URL:
http://maps.google.com/maps/geo?q=45,9&output=kml&sensor=false&key=your_api_key
ottenete uno Stream di risposta in codice KML.
Il parametro q nella querystring sono latitudine/longitudine, separate da “,†(virgola). Latitudine 45, Longitudine 9 è un qualche punto della Lombardia, precisamente Voghera (PV). Il parametro output indica il formato di output che vogliamo in risposta: kml va più che bene. Il parametro sensor è messo a false. Il parametro key deve riportare l’api key che avete richiesto direttamente a Google.
KML non è nient’altro che XML che, opportunamente parserizzato, vi restituisce tutta una serie di informazioni, tra cui anche il country name.
Prima vediamo il codice della mia classe GoogleMapLookupCountry:
1: public class GoogleMapLookupContry : ILookupCountry
2: {
3: KmlParser parser = new KmlParser();
4:
5: public string GetCountry(double latitude, double longitude)
6: {
7: string apiKey = "your_api_key";
8:
9: string countryName = string.Empty;
10:
11: string outputFormat = "kml";
12: string stringLatitude = latitude.ToString().Replace(',', '.');
13: string stringLongitude = longitude.ToString().Replace(',', '.');
14: string url = string.Format("http://maps.google.com/maps/geo?q={0},{1}&output={2}&sensor=false&key={3}",
15: stringLatitude, stringLongitude, outputFormat, apiKey);
16: HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
17:
18: string kml = ServiceHelper.GetStringResponse(request.GetResponse());
19:
20: return parser.GetCountryName(kml);
21: }
22: }
La prima cosa da fare è registrarvi su Google e richiedere un’API key, da incollare alla riga 7 del codice qui sopra.
Il metodo GetCountry ottiene in ingresso latitudine e longitudine (in formato double). Alla riga 14 costruisco l’url da richiamare via HttpWebRequest. Notare che l’output che vogliamo ottenere da Google Map deve essere in formato KML: il parametro {2} all’interno dell’url indica proprio il formato di output, che nel codice è cablato a “kml†(riga 11).
Alla riga 18 nascondo un po’ di complessità : passo la WebResponse (ottenuta da request.GetResponse()) al metodo statico GetStringResponse che prende il byte[] e mi ritorna la stringa in caratteri ASCII. Tutto ciò finisce nella variabile string kml (riga 18).
Alla riga 20 passo il codice KML al metodo GetCountryName che restituisce appunto il nome in chiaro della nazione in cui mi trovo. Ecco il codice della classe KmlParser:
1: public class KmlParser
2: {
3: XmlNamespaceManager nsmgr;
4:
5: public KmlParser()
6: {
7: nsmgr = new XmlNamespaceManager(new NameTable());
8: nsmgr.AddNamespace("google", "http://earth.google.com/kml/2.0");
9: nsmgr.AddNamespace("address", "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0");
10: }
11:
12: public string GetCountryName(string kmlCode)
13: {
14: string countryName = string.Empty;
15:
16: XmlDocument document = new XmlDocument();
17: document.LoadXml(kmlCode);
18:
19: XmlNode node = document.SelectSingleNode("//address:CountryName", nsmgr);
20:
21: if (node != null) countryName = node.InnerText;
22:
23: return countryName;
24: }
25: }
Non sto qui a descrivervi il codice riga per riga. Voglio solo fare questa annotazione: il codice KML restituito da Google dichiara il namespace specificato alla riga 8 del codice qui sopra (“http://earth.google.com/kml/2.0â€). Prima di poter fare il SelectSingleNode (riga 19), dovete quindi istanziare un XmlNamespaceManager ed aggiungere i vari namespace che ci servono (nel nostro caso due). La ricerca tramite XPath, quindi, deve utilizzare “//†per selezionare il primo nodo che si chiama CountryName, indipendentemente da dove questo si trovi all’interno dell’KML, ma deve anche specificare il prefix per il namespace (“addressâ€) e l’istanza di XmlNamespaceManager creata nel costruttore della classe.
Conclusione
Supponiamo di interrogare FSX ogni 60 secondi per chiedere la posizione dell’aereo. Otterremo la sua latitudine e la sua longitudine ogni 60 secondi. E’ sufficiente una piccola chiamata al servizio di Google Map ed otterremo la nazione in cui ci troviamo. Esempio pratico: decollate da Trieste ed otterremo ovviamente “Italiaâ€. Dopo aver preso quota, virate verso est (direzione 90°) e quando entrerete in Slovenja, ecco che magicamente il servizio Google Map ci dirà – guarda caso – proprio “Slovenjaâ€.
Detta così è una cosa banale e stupida, ma vi posso assicurare che si possono tirar fuori un certo numero di cose interessanti.