【问题标题】:How to return a list of stores which are a specified distance from the entered Postcode如何返回距输入的邮政编码指定距离的商店列表
【发布时间】:2013-05-21 10:12:33
【问题描述】:

我正在使用 Google 地图创建商店定位器。

用户将输入他们的邮政编码并从下拉菜单中选择距该位置的距离 - 5、10 15 20 英里。

这将返回距其位置指定距离的商店并在地图上放置标记。

我有一个包含以下列的邮政编码表:

 PostCode Latitude Longitude Easting Northing Grid Ref Country District Ward

还有一个和这个表有外键关系的stores表

我正在使用 MVC3 和 linq-sql,但我不知道如何编写查询以仅拉回距离输入的邮政编码 5 英里的商店

编辑

我发现了以下内容:

select *,
    acos(cos(51.720663 * (PI()/180)) *
     cos(-0.299929 * (PI()/180)) *
     cos(latitude * (PI()/180)) *
     cos(longitude * (PI()/180))
     +
     cos(51.720663 * (PI()/180)) *
     sin(-0.299929 * (PI()/180)) *
     cos(latitude * (PI()/180)) *
     sin(longitude * (PI()/180))
     +
     sin(51.720663 * (PI()/180)) *
     sin(latitude * (PI()/180))
    ) * 3959 as Dist
from postcodes
having Dist < radius
order by Dist

但这部分不起作用:

having Dist < radius
    order by Dist

我错过了什么吗..?

如果可能的话,我真的想在 linq 中执行此操作....

任何帮助将不胜感激。

谢谢

【问题讨论】:

    标签: asp.net-mvc-3 linq sql-server-2008 google-maps


    【解决方案1】:

    我实际上最终使用了 GeoCodeCal 类来解决我需要的东西。

    请看下面的课程:

    using System;
    
    namespace WidgetData
    {
        /// <summary>
        /// Used when we need to calculate the distance between two geocodes (lat/long) points. 
        /// </summary>
        public static class GeoCodeCalc
        {
    
            ///<summary>
            ///</summary>
            public const double EarthRadiusInMiles = 3956.0;
    
            ///<summary>
            ///</summary>
            public const double EarthRadiusInKilometers = 6367.0;
    
            ///<summary>
            ///</summary>
            ///<param name="val"></param>
            ///<returns></returns>
            public static double ToRadian(double val)
            {
                return val * (Math.PI / 180);
            }
    
            ///<summary>
            ///</summary>
            ///<param name="val1"></param>
            ///<param name="val2"></param>
            ///<returns></returns>
            public static double DiffRadian(double val1, double val2)
            {
                return ToRadian(val2) - ToRadian(val1);
            }
    
            /// <summary> 
            /// Calculate the distance between two geocodes. Defaults to using Miles. 
            /// </summary> 
            public static double CalcDistance(double lat1, double lng1, double lat2, double lng2)
            {
                return CalcDistance(lat1, lng1, lat2, lng2, GeoCodeCalcMeasurement.Miles);
            }
    
            /// <summary> 
            /// Calculate the distance between two geocodes. 
            /// </summary> 
            public static double CalcDistance(double lat1, double lng1, double lat2, double lng2, GeoCodeCalcMeasurement m)
            {
                double radius = EarthRadiusInMiles;
                if (m == GeoCodeCalcMeasurement.Kilometers)
                {
                    radius = EarthRadiusInKilometers;
                }
                return radius * 2 * Math.Asin(Math.Min(1, Math.Sqrt((Math.Pow(Math.Sin((DiffRadian(lat1, lat2)) / 2.0), 2.0) + Math.Cos(ToRadian(lat1)) * Math.Cos(ToRadian(lat2)) * Math.Pow(Math.Sin((DiffRadian(lng1, lng2)) / 2.0), 2.0)))));
            }
    
            /// <summary>
            /// Convert the OS Grid reference numbers which are easting and norhing into a latitude/longitude
            /// </summary>
            /// <param name="easting"></param>
            /// <param name="northing"></param>
            /// <param name="latitude"></param>
            /// <param name="londgitude"></param>
            public static void ConvertOsGridToLatLong(int easting, int northing, out double latitude, out double londgitude)
            {
                var e = easting;
                var N = northing;
                const double a = 6377563.396;
                const double b = 6356256.910; // Airy 1830 major & minor semi-axes  
                const double f0 = 0.9996012717; // NatGrid scale factor on central meridian  
                const double lat0 = 49*Math.PI/180;
                const double lon0 = -2*Math.PI/180; // NatGrid true origin  
                const int n0 = -100000;
                const int e0 = 400000; // northing & easting of true origin, metres  
                const double e2 = 1 - (b*b)/(a*a); // eccentricity squared  
                const double n = (a - b)/(a + b);
                const double n2 = n*n;
                const double n3 = n*n*n;
                var lat = lat0;
                var m=0.0;                                         
                do 
                {    
                    lat = (N-n0-m)/(a*f0) + lat;    
                    var ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);    
                    var mb = (3*n + 3*n*n + (21/8)*n3) * Math.Sin(lat-lat0) * Math.Cos(lat+lat0);    
                    var mc = ((15/8)*n2 + (15/8)*n3) * Math.Sin(2*(lat-lat0)) * Math.Cos(2*(lat+lat0));    
                    var md = (35/24)*n3 * Math.Sin(3*(lat-lat0)) * Math.Cos(3*(lat+lat0));    
                    m = b * f0 * (ma - mb + mc - md);                // meridional arc  
                } while (N-n0-m >= 0.00001);  // ie until < 0.01mm  
                var cosLat = Math.Cos(lat);
                var sinLat = Math.Sin(lat);  
                var nu = a*f0/Math.Sqrt(1-e2*sinLat*sinLat);              // transverse radius of curvature  
                var rho = a*f0*(1-e2)/Math.Pow(1-e2*sinLat*sinLat, 1.5);  // meridional radius of curvature  
                var eta2 = nu/rho-1;  
                var tanLat = Math.Tan(lat);
                var tan2Lat = tanLat*tanLat;
                var tan4Lat = tan2Lat*tan2Lat;
                var tan6Lat = tan4Lat*tan2Lat;  
                var secLat = 1/cosLat;
                var nu3 = nu*nu*nu;
                var nu5 = nu3*nu*nu;
                var nu7 = nu5*nu*nu;  
                var vii = tanLat/(2*rho*nu);  
                var viii = tanLat/(24*rho*nu3)*(5+3*tan2Lat+eta2-9*tan2Lat*eta2);  
                var ix = tanLat/(720*rho*nu5)*(61+90*tan2Lat+45*tan4Lat);  
                var x = secLat/nu;  
                var xi = secLat/(6*nu3)*(nu/rho+2*tan2Lat);  
                var xii = secLat/(120*nu5)*(5+28*tan2Lat+24*tan4Lat);  
                var xiia = secLat/(5040*nu7)*(61+662*tan2Lat+1320*tan4Lat+720*tan6Lat);
                var dE = (e - e0);
                var dE2 = dE*dE;
                var dE3 = dE2*dE;
                var dE4 = dE2*dE2;
                var dE5 = dE3*dE2;
                var dE6 = dE4*dE2;
                var dE7 = dE5*dE2;  
                lat = lat - vii*dE2 + viii*dE4 - ix*dE6;  
                var lon = lon0 + x*dE - xi*dE3 + xii*dE5 - xiia*dE7;
                latitude = ToDegree(lat);
                londgitude = ToDegree(lon);
            }
    
            /// <summary>
            /// Convert radians to degreens
            /// </summary>
            /// <param name="angle"></param>
            /// <returns></returns>    
            public static double ToDegree(double angle)
            {
                return Math.PI * angle / 180.0;
            }
    
        }
    
    
        ///<summary>
        ///</summary>
        public enum GeoCodeCalcMeasurement
        {
            ///<summary>
            /// Miles
            ///</summary>
            Miles = 0,
            ///<summary>
            /// Kilometers
            ///</summary>
            Kilometers = 1
        }
    }
    

    并使用从我的控制器调用的 CalcDistance(post 是初始邮政编码,store 是另一个邮政编码)

    var calcDistance = GeoCodeCalc.CalcDistance(postLong, postLat, storeLong, storeLat);
    

    【讨论】:

      【解决方案2】:

      以下是我如何使用 LINQ over EF 按城市执行类似操作的小片段:

                  var cityloc = _db.Cities.Find(t.CityId).location;
                  var radius = Int32.Parse(t.CityRadius);
                  results = results.Where(x => x.City.location.Distance(cityloc) < radius * metersPerMile || x.city_id == t.CityId);
      

      t.CityId 是您所在的城市,它会找到距离您 t.CityRadius 英里范围内的结果。结果是具有 City 类的 city 属性的对象。 City 类有一个 DbGeography 类型的属性 location。

      LINQ over SQL 中不存在空间支持。但是,EF 5 支持它。您可能想查看这篇关于 LINQ over SQL 以及如何与空间类型相互转换的文章:Is it possible to use SqlGeography with Linq to Sql?

      好消息是,一旦您将邮政编码表放入一个类中,您就可以使用内置的 .NET 空间数据为您计算距离(或者您可以像以前一样手动计算) .

      如果您的开发并不太深入,您甚至可以考虑将 LINQ over SQL 切换到 LINQ over Entity Frameworks。它非常相似,并且完全支持空间数据类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多