In alsmaar meer maatsoftware die we opleveren komt ergens wel de vraag “we willen een lijst van klanten/leveranciers in de buurt van …” Tot voor een tijdje werkten we daarom met een query op postcode (select * from tabel where postcode like ‘85%’). Het gaf een vrij goed idee maar effectief gaan filteren op adressen die in een straal van X km rond een bepaald punt liggen is natuurlijk veel exacter. Sinds kort hebben we dit in een aantal pakketten geïntegreerd; het berekenen van de afstand tussen twee punten is in principe vrij simpel.
1: public Double GetDistance(Double[] from, Double[] to)
2: {
3: Double dLat1LnRad = from[0] * (Math.PI / 180.0);
4: Double dLong1LnRad = from[1] * (Math.PI / 180.0);
5: Double dLat2LnRad = to[0] * (Math.PI / 180.0);
6: Double dLong2LnRad = to[1] * (Math.PI / 180.0);
7:
8: Double dLongitude = dLong2LnRad - dLong1LnRad;
9: Double dLatitude = dLat2LnRad - dLat1LnRad;
10:
11: Double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) + Math.Cos(dLat1LnRad) * Math.Cos(dLat2LnRad) * Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
12: Double c = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a));
13:
14: const Double kEarthRadiusKms = 6376.5;
15: return kEarthRadiusKms * c;
16: }
De moeilijkheid was om op een vlotte manier aan de juiste gps coordinaten te komen en dat is nu vrij simpel geworden dankzij Google Earth API.
1: private const string _googleUri = "http://maps.google.com/maps/geo?q=";
2: private const string _googleKey = "Get Your Own Free Google Key";
3: private const string _outputType = "csv";
4:
5: public Double[] GetCoordinates(string address)
6: {
7: address = HttpUtility.UrlEncode(address);
8: WebClient client = new WebClient();
9:
10: string[] geocodeInfo = client.DownloadString(new Uri(String.Format("{0}{1}&output={2}&key={3}", _googleUri, address, _outputType, _googleKey))).ToString().Split(',');
11: Double lat = Convert.ToDouble(geocodeInfo[2].Replace(".", ","));
12: Double lon = Convert.ToDouble(geocodeInfo[3].Replace(".",","));
13: Double[] returnvalue = new Double[2];
14: returnvalue[0] = lat;
15: returnvalue[1] = lon;
16:
17: return returnvalue;
18: }
Als je nu wil weten welke adressen in een straal van 30 km rond je bedrijf liggen kan je dat eenvoudig berekenen door je eigen gps coordinaten op te vragen en dan alle adressen in je databank overlopen om te zien of ze verder of minder ver dan 30 km van je bedrijf verwijdert liggen. Voor kleine databanken is dat haalbaar voor grotere is het behalve CPU intensief ook IO intensief en het kan dus intelligenter.
Bepalen welke GPS coordinaten in een straal van x KM rond je bedrijf liggen is mogelijk maar onpraktisch, je zou in detail elk puntje op de cirkellijn moeten bijhouden en elk gps coordinaat van je contacten moeten afwegen bij de cirkellijn. We zouden het moeten testen maar hoewel het intelligenter lijkt zou het waarschijnlijk meer belastend zijn voor de server dan de eerste oplossing.
We kozen ervoor een vierkant te tekenen waar onze cirkel net in kan. Op basis van de coordinaat links boven en die rechtsonder kunnen we een SQL commando schrijven die de adressen selecteert die in het vierkant zitten. We moeten dan enkel manueel nog de adressen in de paarse zone eruit filteren.