首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linq to sql Haversine公式

Linq to sql Haversine公式
EN

Stack Overflow用户
提问于 2012-06-07 01:09:29
回答 2查看 2.1K关注 0票数 3

我有一个用c#实现的哈维正弦公式,还有一个用TSQL实现的例子。我不确定如何最好地在服务器端实现该公式,以便能够在Linq查询中使用它。

理想情况下,我只需要将本地公式链接到服务器上的函数。这样就避免了“不能翻译成sql”的错误,让一切都变得完美和无缝。

显然,对这个问题的任何观点都是有帮助的。

我知道SQL2008中的地理类型。然而,我正在使用的代码库已经对Linq to SQL有了如此大的依赖,我认为它的工作量超过了它的价值!

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-06-07 01:32:45

为什么不使用100%SQL,因为这是进行计算的最好方法,并简单地获得一个已经填满距离的表?

existing answer

代码语言:javascript
复制
CREATE FUNCTION dbo.udf_Haversine(@lat1 float, @long1 float, @lat2 float, @long2 float) RETURNS float 
  BEGIN
    DECLARE @dlon float, @dlat float, @rlat1 float, @rlat2 float, @rlong1 float, @rlong2 float, @a float, @c float, @R float, @d float, @DtoR float

    SELECT @DtoR = 0.017453293
    SELECT @R = 3937 --3976

    SELECT 
        @rlat1 = @lat1 * @DtoR,
        @rlong1 = @long1 * @DtoR,
        @rlat2 = @lat2 * @DtoR,
        @rlong2 = @long2 * @DtoR

    SELECT 
        @dlon = @rlong1 - @rlong2,
        @dlat = @rlat1 - @rlat2

    SELECT @a = power(sin(@dlat/2), 2) + cos(@rlat1) * cos(@rlat2) * power(sin(@dlon/2), 2)
    SELECT @c = 2 * atn2(sqrt(@a), sqrt(1-@a))
    SELECT @d = @R * @c

    RETURN @d 
  END

它的用法如下:

代码语言:javascript
复制
var table = from r in db.VenuePostCodes 
            select new {
                lat = r.Latitude,
                lng = r.Longitude,
                name = r.Name,
                distance = db.udf_Haversine(
                                  r.Latitude,r.Longitude,
                                  r.Latitude,r.Longitude2)
            };

但是最好的办法是让所有东西都放在SQL上,这样你的托管服务器就可以少做些事情,只需向你的SQL添加一个视图,然后调用这个视图,让我们想象一下:

代码语言:javascript
复制
SELECT 
   latitude, longitude, name, latitude1, longitude2, postcode, 
   udf_Haversine(latitude, longitude, latitude2, longitude2) AS distance 
FROM 
   venuepostcodes
ORDER BY 
   distance

并使用LINQ直接调用该视图。

票数 5
EN

Stack Overflow用户

发布于 2013-09-19 01:16:55

@balexandre的答案很好,但我对提供的SQL函数不满意(它缺少注释,有趣的注释掉了常量吗,是里程吗?千米?等等...)

代码语言:javascript
复制
CREATE FUNCTION [dbo].[udf_Haversine](@lat1 float, @long1 float, @lat2 float, @long2 float) RETURNS float 
BEGIN
    DECLARE @dlon float, @dlat float,
            @rlat1 float, @rlat2 float, @rlong1 float, @rlong2 float,
            @a float, @c float, @R float, @d float, @DtoR float

    SELECT
        @DtoR = PI() / 180, -- Degrees to radians const
        @R = 6371 -- Radius of Earth in KM

    SELECT 
        @rlat1 = @lat1 * @DtoR,
        @rlong1 = @long1 * @DtoR,
        @rlat2 = @lat2 * @DtoR,
        @rlong2 = @long2 * @DtoR

    SELECT 
        @dlat = @rlat1 - @rlat2,
        @dlon = @rlong1 - @rlong2

    SELECT @a = SIN(@dlat / 2) * SIN(@dlat / 2) +
                SIN(@dlon / 2) * SIN(@dlon / 2) * COS(@rlat2) * COS(@rlat1)

    SELECT @c = 2 * atn2(sqrt(@a), sqrt(1 - @a))
    SELECT @d = @R * @c -- Final distance in KM

    SELECT @d = @d * 0.621371192 -- Final distance in miles

RETURN @d 
END

它是从我们从这里抓取的JavaScript实现转换而来的,最后添加了转换为英里数:

代码语言:javascript
复制
// Converted from JavaScript implementation:
// http://www.movable-type.co.uk/scripts/latlong.html

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;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10918874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档