使用 linq 或亚音速计算距离

发布于 2024-08-24 01:13:16 字数 605 浏览 4 评论 0原文

我从搜索页面得到了这个 MySQL 语句,用户输入邮政编码,它会在输入的邮政编码 15 英里内找到最近的 stiocklist。

 SELECT *  , (
(
ACOS( SIN( "+SENTLNG +" * PI( ) /180 ) * SIN( s_lat * PI( ) /180 ) + COS( " + SENTLNG +" * PI( ) /180 ) * COS( s_lat * PI( ) /180 ) *  COS( (
" + SENTLANG + " - s_lng
) * PI( ) /180 ) ) *180 / PI( )
) *60 * 1.1515
) AS distance_miles
FROM new_stockists
WHERE s_lat IS NOT NULL
HAVING distance_miles <15
ORDER BY distance_miles ASC
LIMIT 0 , 15  

但现在我正在使用 linq 和 subsonic,但不知道如何在 linq 或 subsonic 中做到这一点 我们将非常感谢您的帮助,也请注意,我必须发送动态的发件人地址,即页面顶部提到的邮政编码,我会致电谷歌,从他们那里获取给定邮政编码的 lng 和 lat 。

i have this MySQL statement from a search page, the user enters there postcode and it finds the nearest stiocklist within 15 MIles of the entered postcode.

 SELECT *  , (
(
ACOS( SIN( "+SENTLNG +" * PI( ) /180 ) * SIN( s_lat * PI( ) /180 ) + COS( " + SENTLNG +" * PI( ) /180 ) * COS( s_lat * PI( ) /180 ) *  COS( (
" + SENTLANG + " - s_lng
) * PI( ) /180 ) ) *180 / PI( )
) *60 * 1.1515
) AS distance_miles
FROM new_stockists
WHERE s_lat IS NOT NULL
HAVING distance_miles <15
ORDER BY distance_miles ASC
LIMIT 0 , 15  

but now i am using linq and subsonic and not got a clue how do do this in linq or subsonic
your help would be much appreciated, please also not that i have to sent in a dynamic from address, thats the postcode mentioned at the top of the page, i do a call to google to get then lng and lat from them for the postcode given.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

弄潮 2024-08-31 01:13:17

我建议(如果可能)获取邮政编码的中心点,然后应用半正弦公式来查找特定半径内的所有商店。

这里的公式以公里为单位。
您必须更改相关数字,它将适用于英里。
例如:将 6371.392896 转换为英里。

DECLARE @radiusInKm AS FLOAT
将 @lat2Compare 声明为 FLOAT
将@long2Compare声明为FLOAT
设置@radiusInKm = 5.000
SET @lat2Compare = insert_your_lat_to_compare_here
SET @long2Compare = insert_you_long_to_compare_here

SELECT * FROM insert_your_table_here WITH(NOLOCK)
WHERE (6371.392896*2*ATN2(SQRT((sin((弧度(GeoLatitude - @lat2Compare)) / 2) * sin((弧度(GeoLatitude - @lat2Compare)) / 2)) + (cos(弧度(GeoLatitude)) * cos(弧度(@lat2Compare)) * sin(弧度(GeoLongitude - @long2Compare)/2) * sin(弧度(GeoLongitude - @long2Compare)/2)))
, SQRT(1-((sin((弧度(GeoLatitude - @lat2Compare)) / 2) * sin((弧度(GeoLatitude - @lat2Compare)) / 2)) + (cos(弧度(GeoLatitude)) * cos(弧度(@lat2Compare)) * sin(弧度(GeoLongitude - @long2Compare)/2) * sin(弧度(GeoLongitude - @long2Compare)/2)))
))) <= @radiusInKm

如果您想在 C# 中执行半正矢公式,则

double resultDistance = 0.0;
双avgRadiusOfEarth = 6371.392896; //地球半径不同,我取平均值。

//半正矢公式
//距离= R * 2 * aTan2(A的平方根,1 - A的平方根)
// 其中 A = 正弦平方(纬度差 / 2)+(纬度 1 的余弦 * 纬度 2 的余弦 * 正弦平方(经度差 / 2))
// 且 R = 地球周长

double DifferenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare);
双差InLong = DegreeToRadian(currentLongitude - longtitudeToCompare);
double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude)) * Math.Cos(DegreeToRadian(latitudeToCompare)) * Math.Sin(differenceInLong / 2) * Math.Sin(differenceInLong / 2);
double aFormula = (Math.Sin((differenceInLat) / 2) * Math.Sin((differenceInLat) / 2)) + (aInnerFormula);
resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula), Math.Sqrt(1 - aFormula));

DegreesToRadian 是我自定义创建的函数。
这是一个简单的 1 行“Math.PI * 角度 / 180.0”

对于 LINQ,您可以使用 C# 数学函数以及所有 C# 检查。例如:!= 等于不等于等
请参阅以下示例。
它并不完整,因此请根据您的喜好进行调整。

var linqQuery = 来自 linqCollection 中
在此处插入您的收藏
其中 s_lat != 什么都没有
选择 Math.ACos(Math.Sin(DegreesToRadian(sentlng))
* Math.Pi / 180))

请查找下面的 MSDN 链接以获取所有简单的 LINQ 示例。尝试一下,希望这有帮助

我的博客条目 - SQL Haversine

MSDN - 101 LINQ 示例

I would suggest (if possible) getting the centre point of the postcode and then applying the Haversine formula to find all stores within a certain radius.

The formula here is in kilometres.
You will have to change the relevant numbers and it will work for miles.
Eg: Convert 6371.392896 to miles.

DECLARE @radiusInKm AS FLOAT
DECLARE @lat2Compare AS FLOAT
DECLARE @long2Compare AS FLOAT
SET @radiusInKm = 5.000
SET @lat2Compare = insert_your_lat_to_compare_here
SET @long2Compare = insert_you_long_to_compare_here

SELECT * FROM insert_your_table_here WITH(NOLOCK)
WHERE (6371.392896*2*ATN2(SQRT((sin((radians(GeoLatitude - @lat2Compare)) / 2) * sin((radians(GeoLatitude - @lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2)))
, SQRT(1-((sin((radians(GeoLatitude - @lat2Compare)) / 2) * sin((radians(GeoLatitude - @lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2)))
))) <= @radiusInKm

if you would like to perform the Haversine formula in C#,

double resultDistance = 0.0;
double avgRadiusOfEarth = 6371.392896; //Radius of the earth differ, I'm taking the average.

//Haversine formula
//distance = R * 2 * aTan2 ( square root of A, square root of 1 - A )
// where A = sinus squared (difference in latitude / 2) + (cosine of latitude 1 * cosine of latitude 2 * sinus squared (difference in longitude / 2))
// and R = the circumference of the earth

double differenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare);
double differenceInLong = DegreeToRadian(currentLongitude - longtitudeToCompare);
double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude)) * Math.Cos(DegreeToRadian(latitudeToCompare)) * Math.Sin(differenceInLong / 2) * Math.Sin(differenceInLong / 2);
double aFormula = (Math.Sin((differenceInLat) / 2) * Math.Sin((differenceInLat) / 2)) + (aInnerFormula);
resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula), Math.Sqrt(1 - aFormula));

DegreesToRadian is a function I custom created.
It is a simple 1 liner of "Math.PI * angle / 180.0"

For LINQ, you can use the C# math functions as well as all C# checks. Eg: != equals not equal, etc.
See the following as an example.
It is not complete, so kindly tweak it to your liking.

var linqQuery = from linqCollection in
insert_your_collection_here
where s_lat != nothing
select Math.ACos(Math.Sin(DegreesToRadian(sentlng)
* Math.Pi / 180))

Look up the MSDN link below for all simple LINQ example. Have a play around with it, hope this helps

My blog entry - SQL Haversine

MSDN - 101 LINQ Samples

莳間冲淡了誓言ζ 2024-08-31 01:13:17

使用 SQL 的这一部分在 SQL Server 中创建一个新视图:

SELECT * , (your equation here) as distance
FROM new_stocklists
WHERE s_lat is not NULL

然后您可以为您的视图创建一个 Linq 对象(SQLMetal 将执行此操作或 Visual Studio 中的 Linq to SQL)。然后您可以使用 Linq 来查询该视图。假设您的对象是 StockDistance:

var list = db.StockDistance.Where(x=>x.distance<15)
    .OrderBy(x=>x.distance)
    .Take(15);

Create a new view in SQL Server using this part of the SQL:

SELECT * , (your equation here) as distance
FROM new_stocklists
WHERE s_lat is not NULL

Then you can create a Linq object for your view (SQLMetal will do this or Linq to SQL in Visual Studio). Then you can use Linq to query this view. Let's say your object is StockDistance:

var list = db.StockDistance.Where(x=>x.distance<15)
    .OrderBy(x=>x.distance)
    .Take(15);
明媚如初 2024-08-31 01:13:16

您可以在 MS SQL 中创建一个存储过程来执行您的查询的操作,然后从您的应用程序调用该查询。 Linq 确实支持存储过程 - 有点像这样

partial class StockistsDataContext
{
    [Function(Name = "dbo.NewStockistsByDistance")]
    public ISingleResult<NewStockist> NewStockistsByDistance(
        [Parameter(DbType = "Int", Name = "s_lat")] int lat,
        [Parameter(DbType = "Int", Name = "s_lng")] int lng)
    {
        var result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lat, lng);
        return ((ISingleResult<NewStockist>)(result.ReturnValue));
    }
}

回退到存储过程有点令人恼火,但我不认为 Linq 解析 Queryables 表达式树的部分可以检测相关数学函数并将它们映射到 SQL。

You can create a stored procedure in MS SQL that does what your query does, and then call that query from your app. Linq does support stored procedures - kindof like this

partial class StockistsDataContext
{
    [Function(Name = "dbo.NewStockistsByDistance")]
    public ISingleResult<NewStockist> NewStockistsByDistance(
        [Parameter(DbType = "Int", Name = "s_lat")] int lat,
        [Parameter(DbType = "Int", Name = "s_lng")] int lng)
    {
        var result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lat, lng);
        return ((ISingleResult<NewStockist>)(result.ReturnValue));
    }
}

It's a little irritating to fall back to stored procs, but I don't think the part of Linq that parses the Queryables expressiontrees can detect the revant math functions and map them to SQL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文