2010-04-15 5 views
4

Étant donné le code ci-dessous, comment puis-je comparer une liste de valeurs d'objets avec une valeur de test?trouver la correspondance la plus proche du tableau de doubles

Je construis une application de géolocalisation. Je vais passer en longitude et latitude et je voudrais que le service réponde à l'endroit le plus proche de ces valeurs. J'ai commencé le chemin de la conversion à une chaîne, et le formatage des valeurs à deux décimales, mais cela semblait un peu trop ghetto, et je suis à la recherche d'une solution plus élégante.

public class Location : IEnumerable 
{ 
    public string label { get; set; } 
    public double lat { get; set; } 
    public double lon { get; set; } 

    //Implement IEnumerable 
    public IEnumerator GetEnumerator() 
    { 
     return (IEnumerator)this; 
    } 

} 
[HandleError] 
public class HomeController : Controller 
{ 
    private List<Location> myList = new List<Location> 
{    
    new Location { 
     label="Atlanta Midtown", 
     lon=33.657674, 
     lat=-84.423130}, 
    new Location { 
     label="Atlanta Airport", 
     lon=33.794151, 
     lat=-84.387228}, 
    new Location { 
     label="Stamford, CT", 
     lon=41.053758, 
     lat=-73.530979}, ... 
} 

public static int Main(String[] args) 
{ 
    string inLat = "-80.987654"; 
    double dblInLat = double.Parse(inLat); 

    // here's where I would like to find the closest location to the inLat 
    // once I figure out this, I'll implement the Longitude, and I'll be set 
} 
+0

Voulez-vous dire pour comparer la valeur dblInLat aux valeurs myList et trouver le match le plus proche? – Sunny

+0

Je veux parcourir la liste des emplacements et regarder chaque "lat" et le comparer à mon dblInLat. Je cherche la valeur la plus proche - plus ou moins. En d'autres termes, je compare la variable entrante à chaque lat dans la liste et cherche la moindre différence entre leurs valeurs. – Scott

Répondre

0

J'ai trouvé this que quelqu'un a créé qui calcule les distances entre les deux distances à travers le monde en utilisant l'une de plusieurs méthodes différentes. J'ai dû convertir le projet .NET en VS2008 mis à jour, mais cela semblait fonctionner correctement. Ensuite, je viens d'ajouter ce projet à ma solution et fait référence à celui-ci.

Mon code devient alors:

string inLat = "-80.987654"; 
string inLon = "33.521478"; 
var miles = GetNearestLocation(inLat, inLon); 

public double GetNearestLocation(string lat, string lon) 
{ 
    double dblInLat = double.Parse(lat); 
    double dblInLon = double.Parse(lon); 

    // instantiate the calculator 
    GeodeticCalculator geoCalc = new GeodeticCalculator(); 

    // select a reference elllipsoid 
    Ellipsoid reference = Ellipsoid.WGS84; 

    // set user's current coordinates 
    GlobalCoordinates userLocation; 
    userLocation = new GlobalCoordinates(
     new Angle(dblInLon), new Angle(dblInLat) 
    ); 

    // set example coordinates- when fully fleshed out, 
    // this would be passed into this method 
    GlobalCoordinates testLocation; 
    testLocation= new GlobalCoordinates(
     new Angle(41.88253), new Angle(-87.624207) // lon, then lat 
    ); 

    // calculate the geodetic curve 
    GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, userLocation, testLocation); 
    double ellipseKilometers = geoCurve.EllipsoidalDistance/1000.0; 
    double ellipseMiles = ellipseKilometers * 0.621371192; 
    /* 
    Console.WriteLine("2-D path from input location to test location using WGS84"); 
    Console.WriteLine(" Ellipsoidal Distance: {0:0.00} kilometers ({1:0.00} miles)", ellipseKilometers, ellipseMiles); 
    Console.WriteLine(" Azimuth:    {0:0.00} degrees", geoCurve.Azimuth.Degrees); 
    Console.WriteLine(" Reverse Azimuth:  {0:0.00} degrees", geoCurve.ReverseAzimuth.Degrees); 
    */ 
    return ellipseMiles; 
} 
0

Je pense que le plus simple serait de faire ce qui suit. Mais pas le plus performant :)

Parcourez la liste et calculez la distance entre chaque emplacement et votre emplacement de référence. À chaque étape, vérifiez si c'est la distance la plus courte que vous avez vue jusqu'ici et stockez-la. Une fois que vous obtenez la fin de la liste, vous aurez l'emplacement le plus proche dans votre variable stockée.

Si vous parlez d'un très grand nombre d'emplacements et que vous prévoyez de faire beaucoup de requêtes spatiales de cette nature, vous pouvez envisager de configurer un index quadtree sur les données.

Voici un lien que j'ai trouvé après avoir fait un rapide 'Bing', ça devrait aider avec le calcul de distance, j'espère. S'il vous plaît consulter ce lien:

http://www.delphiforfun.org/Programs/Math_Topics/Lat-Long%20Distance.htm

3

Vous allez vouloir utiliser la formule de distance correcte pour cela si vous ne voulez pas finir avec des résultats étranges:

double CalculateDistance(double lat1, double lon1, double lat2, double lon2) 
{ 
    const double R = 6371; 
    return Math.Acos(
     Math.Sin(lat1) * Math.Sin(lat2) + 
     Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon2 - lon1)) * R; 
} 

J'espère que c'est la bonne formule, mes maths pourraient être un peu rouillées ici. Tous les paramètres doivent être en rads, donc si vous prenez des entrées en degrés, écrire une méthode utilitaire ainsi:

double DegToRad(double deg) 
{ 
    return deg * Math.PI/180.0; 
} 

Quoi qu'il en soit, après cela, vous pouvez trouver la distance la plus courte que:

Location GetClosestLocation(Location origin) 
{ 
    double olatr = DegToRad(origin.Lat); 
    double olonr = DegToRad(origin.Lon); 
    return 
     (from l in locations 
     let latr = DegToRad(l.Lat) 
     let lonr = DegToRad(l.Lon) 
     orderby CalculateDistance(latr, lonr, olatr, olonr)) 
     .FirstOrDefault(); 
} 

Ce n'est techniquement pas la solution la plus performante, car elle doit faire un tri, mais il n'y a pas de méthode d'extension agréable à faire avec une projection. Si vous voulez, vous devrez écrire votre propre boucle foreach:

Location GetClosestLocation(Location origin) 
{ 
    double olatr = DegToRad(origin.Lat); 
    double olonr = DegToRad(origin.Lon); 
    Location closest = null; 
    double minDistance = double.MaxValue; 
    foreach (Location l in locations) 
    { 
     double latr = DegToRad(l.Lat); 
     double lonr = DegToRad(l.Lon); 
     double dist = CalculateDistance(latr, lonr, olatr, olonr)); 
     if (dist < minDistance) 
     { 
      minDistance = dist; 
      closest = l; 
     } 
    } 
    return closest; 
} 
+0

Cela ressemble à ce que j'aurais dû faire. Mais ce que j'ai réellement fait était d'utiliser une solution. NET, j'ai trouvé ici: http://www.gavaghan.org/blog/free-source-code/geodesy-library-vincentys-formula/ – Scott

Questions connexes