2010-04-15 62 views
4

鑑於下面的代碼,我如何比較對象的值列表與測試值?找到最接近的匹配陣列的雙打

我正在構建一個地理定位應用程序。我會傳遞經緯度,並希望服務回覆與最接近這些值的位置。

我開始轉換爲字符串的路徑,並將這些值的格式設置爲小數點後兩位,但這看起來有點過分貧民窟,我正在尋找更優雅的解決方案。

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

你的意思是在dblInLat值進行比較的myList中值和找到最近的比賽? – Sunny 2010-04-15 19:58:09

+0

我的意思是循環訪問位置列表並查看每個「lat」並將其與我的dblInLat進行比較。我正在尋找最接近的價值。換句話說,我會將傳入變量與列表中的每個緯度進行比較,並查找其值之間的最小差異。 – Scott 2010-04-15 20:14:58

回答

0

我發現this其創建人計算跨使用幾種不同的方法之一,全球兩個距離之間的距離。我不得不將.NET項目轉換爲更新的VS2008,但似乎工作正常。然後,我將這個項目添加到我的解決方案中,並對其進行了參考。

我的代碼,然後變成了:

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

我覺得最簡單的是做以下事情。但不是最高性能:)

遍歷列表並計算每個位置與參考位置之間的距離。在每一步中,檢查這是否是迄今爲止所見到的最短距離並存儲該距離。一旦你得到列表的結尾,你將在你的存儲變量中有最接近的位置。

如果你正在談論大量的位置,並且你打算做很多這種性質的空間查詢,你可以考慮在數據上設置一個四叉樹索引。

這是我在做一個快速'必應'後發現的鏈接,我希望它應該有助於距離計算。請參考以下鏈接:

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

3

你會想用正確的距離公式來進行,如果你不想用怪異的結果落得:

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; 
} 

我希望是這樣的正確的公式,我的數學可能在這裏有點生疏。所有的參數需要在拉德,所以如果你在服用度投入,編寫一個工具方法,以及:

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

不管怎樣,在這之後,你可以計算出的最短距離爲:

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(); 
} 

這不是技術上最高效的解決方案,因爲它必須做一個排序,但有沒有好看的LINQ的擴展方法做分下,用投影。如果你想要的,你必須寫自己的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

這聽起來像我應該做的。但我實際上做的是使用我在這裏找到的.NET解決方案:http://www.gavaghan.org/blog/free-source-code/geodesy-library-vincentys-formula/ – Scott 2010-04-16 13:27:50