计算半径内的 100 英里

Posted

技术标签:

【中文标题】计算半径内的 100 英里【英文标题】:Calculating 100 Miles Within a Radius 【发布时间】:2013-04-16 18:43:04 【问题描述】:

假设我有一个包含机场列表及其相关经纬度坐标的表格,我将如何获取距离另一个坐标 100 英里范围内的机场列表?我的最终目标是让用户按城市搜索并找到该城市纬度和经度 100 英里范围内的机场。我有所有数据,只是不知道从哪里开始。

我的数据在 SQL Server 中。

【问题讨论】:

纬度和经度之间有多少英里?这就是你需要找出的 您使用的是什么版本的 SQL-Server?如果您有 SQL Server 2008,则可以使用 GeoCoordinates。 ***.com/questions/862856/… 也包含一些很好的信息。 我在***.com/questions/15628794/… 回答了一个非常相似的问题。需要 SQL 2008 或更高版本。 【参考方案1】:
create function dbo.F_GREAT_CIRCLE_DISTANCE
(
    @Latitude1  float,
    @Longitude1 float,
    @Latitude2  float,
    @Longitude2 float
)
returns float as
begin
    declare @radius float

    declare @lon1  float
    declare @lon2  float
    declare @lat1  float
    declare @lat2  float

    declare @a float
    declare @distance float

    -- Sets average radius of Earth in Miles
    set @radius = 3956

    -- Convert degrees to radians
    set @lon1 = radians( @Longitude1 )
    set @lon2 = radians( @Longitude2 )
    set @lat1 = radians( @Latitude1 )
    set @lat2 = radians( @Latitude2 )

    set @a = sqrt(square(sin((@lat2-@lat1)/2.0E)) + (cos(@lat1) * cos(@lat2) * square(sin((@lon2-@lon1)/2.0E))) )
    set @distance = @radius * ( 2.0E *asin(case when 1.0E < @a then 1.0E else @a end ))

    return @distance
end

【讨论】:

@Markus 是英里的结果? @LoneWOLFs 是的,如果你想要以公里为单位,请将半径更改为 6366.7。【参考方案2】:

你可以使用System.Device.Location.GeoCoordinate

GeoCoordinate city = ....;
double distance = .......;
List<GeoCoordinate> airports = .......; //load from db.

var found = airports.Where(c=>c.GetDistanceTo(city) < distance);

编辑

对于那些可能对实际工作代码感兴趣的人

var airports1 = Airports.Search(51, 0, 100).ToList(); //~London
var airports2 = Airports.Search(40.714623, -74.006605,100).ToList(); //~NY

public class Airports

    public class Airport
    
        public string Name;
        public GeoCoordinate Location;

        public override string ToString()
        
            return Name;
        
    

    static Lazy<List<Airport>> _Airports = new Lazy<List<Airport>>(() =>
        
            using (var wc = new WebClient())
            
                var json = wc.DownloadString("http://www.flightradar24.com/AirportDataService2.php");
                var jObj = new javascriptSerializer().Deserialize<Dictionary<string,string[]>>(json);

                return jObj.Values
                           .Select(j => new Airport
                            
                                Name = (string)j[2],
                                Location = new GeoCoordinate(double.Parse(j[3].ToString(), CultureInfo.InvariantCulture),double.Parse(j[4].ToString(), CultureInfo.InvariantCulture))
                            )
                            .ToList();
            
        , true);

    public static IEnumerable<Airport> Search(double lat,double lon, double distInMiles)
    
        var loc = new GeoCoordinate(lat, lon);
        return _Airports.Value.Where(c => c.Location.GetDistanceTo(loc) < distInMiles * 1609.344);
    

【讨论】:

我认为 OP 正在寻求 T-SQL 中的解决方案。 @Pheonixblade9 可能是这样,但它被标记为 C#。【参考方案3】:

你可以这样做:

 --SELECT Points closer than @radius
select * from #Points p
WHERE power(p.x - @locX, 2) + POWER(p.y - @locY, 2) < POWER(@radius,2)

(这已无耻地从http://www.sqlservercentral.com/Forums/Topic1228111-8-1.aspx#bm1229043 中删除,通过 Google Search for SQL + Pyhtagoras 找到)。

【讨论】:

不幸的是,两条经线之间的距离因纬度而异,因此该解决方案在实践中根本行不通。 另外,不要忘记地球表面的距离测量的是地球曲线的距离,而不是直接穿过地球的距离 两点之间。如果你直接去中国的话会快很多,但是挖那条隧道是一件很麻烦的事。【参考方案4】:

如果您的机场位于 0,0 点, 半径 30 英里内的所有机场都应在一个圆圈内。 要测试点是否在圆内,您需要测试每个平方方程: sqrt(X*X + Y*Y)

【讨论】:

【参考方案5】:

下面是 'as the crow fly 两点之间的距离的公式: 半正弦

formula:     a = sin²(Δφ/2) + cos(φ1).cos(φ2).sin²(Δλ/2)
c = 2.atan2(√a, √(1−a))
d = R.c

其中 φ 是纬度,λ 是经度,R 是地球半径(平均半径 = 6,371km) 请注意,角度需要以弧度为单位才能传递给三角函数!

你可以把这段代码翻译成 SQL

JavaScript: 
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();

var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c;

这里是数学函数的 T-SQL 页面的链接: http://msdn.microsoft.com/en-us/library/ms188919.aspx

【讨论】:

以上是关于计算半径内的 100 英里的主要内容,如果未能解决你的问题,请参考以下文章

sql MySQL计算距离(km),假设地球半径为6,371 km(3,959英里)

从另一个邮政编码获取n英里半径内的所有邮政编码[关闭]

如何返回邮政编码列表的## 英里半径内的所有实例

计算所有邮政编码都在 x 英里内的最小邮政编码集的函数

使用 Google 地图 API 在 100 英里半径内使用相同产品的人们的 GPS 位置

如何用最少 30 英里半径的圆圈覆盖美国地图?