GPS定位,经纬度附近地点查询–C#实现方法

本文介绍了一种使用C#类实现的高效商圈搜索算法,通过经纬度坐标计算,快速查找指定范围内附近的商家,大幅提高了搜索效率。文中详细阐述了算法原理及关键步骤,并提供了测试代码以验证其准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  目前的工作是需要手机查找附近N米以内的商户,功能如下图

数据库中记录了商家在百度标注的经纬度(如:116.412007, 39.947545),

最初想法  以圆心点为中心点,对半径做循环,半径每增加一个像素(暂定1米)再对周长做循环,到数据库中查询对应点的商家(真是一个长时间的循环工作)

上网百度类似的文章有了点眉目

大致想法是已知一个中心点,一个半径,求圆包含于圆抛物线里所有的点,这样的话就需要知道所要求的这个圆的对角线的顶点,问题来了 经纬度是一个点,半径是一个距离,不能直接加减

 终于找到想要的文章

http://digdeeply.org/archives/06152067.html

PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询–合理利用算法,效率提高2125倍

参考原文章 lz改成了C#类

废话不多少直接上代码:

  1 /// <summary>
  2     /// 经纬度坐标
  3     /// </summary>    
  4 
  5   public class Degree
  6     {
  7         public Degree(double x, double y)
  8         {
  9             X = x;
 10             Y = y;
 11         }
 12         private double x;
 13 
 14         public double X
 15         {
 16             get { return x; }
 17             set { x = value; }
 18         }
 19         private double y;
 20 
 21         public double Y
 22         {
 23             get { return y; }
 24             set { y = value; }
 25         }
 26     }
 27 
 28 
 29     public class CoordDispose
 30     {
 31         private const double EARTH_RADIUS = 6378137.0;//地球半径(米)
 32 
 33         /// <summary>
 34         /// 角度数转换为弧度公式
 35         /// </summary>
 36         /// <param name="d"></param>
 37         /// <returns></returns>
 38         private static double radians(double d)
 39         {
 40             return d * Math.PI / 180.0;
 41         }
 42 
 43         /// <summary>
 44         /// 弧度转换为角度数公式
 45         /// </summary>
 46         /// <param name="d"></param>
 47         /// <returns></returns>
 48         private static double degrees(double d)
 49         {
 50             return d * (180 / Math.PI);
 51         }
 52 
 53         /// <summary>
 54         /// 计算两个经纬度之间的直接距离
 55         /// </summary>
 56 
 57         public static double GetDistance(Degree Degree1, Degree Degree2)
 58         {
 59             double radLat1 = radians(Degree1.X);
 60             double radLat2 = radians(Degree2.X);
 61             double a = radLat1 - radLat2;
 62             double b = radians(Degree1.Y) - radians(Degree2.Y);
 63 
 64             double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
 65              Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
 66             s = s * EARTH_RADIUS;
 67             s = Math.Round(s * 10000) / 10000;
 68             return s;
 69         }
 70 
 71         /// <summary>
 72         /// 计算两个经纬度之间的直接距离(google 算法)
 73         /// </summary>
 74         public static double GetDistanceGoogle(Degree Degree1, Degree Degree2)
 75         {
 76             double radLat1 = radians(Degree1.X);
 77             double radLng1 = radians(Degree1.Y);
 78             double radLat2 = radians(Degree2.X);
 79             double radLng2 = radians(Degree2.Y);
 80 
 81             double s = Math.Acos(Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Cos(radLng1 - radLng2) + Math.Sin(radLat1) * Math.Sin(radLat2));
 82             s = s * EARTH_RADIUS;
 83             s = Math.Round(s * 10000) / 10000;
 84             return s;
 85         }
 86 
 87         /// <summary>
 88         /// 以一个经纬度为中心计算出四个顶点
 89         /// </summary>
 90         /// <param name="distance">半径(米)</param>
 91         /// <returns></returns>
 92         public static Degree[] GetDegreeCoordinates(Degree Degree1, double distance)
 93         {
 94             double dlng = 2 * Math.Asin(Math.Sin(distance / (2 * EARTH_RADIUS)) / Math.Cos(Degree1.X));
 95             dlng = degrees(dlng);//一定转换成角度数  原PHP文章这个地方说的不清楚根本不正确 后来lz又查了很多资料终于搞定了
 96 
 97             double dlat = distance / EARTH_RADIUS;
 98             dlat = degrees(dlat);//一定转换成角度数
 99 
100             return new Degree[] { new Degree(Math.Round(Degree1.X + dlat,6), Math.Round(Degree1.Y - dlng,6)),//left-top
101                                   new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y - dlng,6)),//left-bottom
102                                   new Degree(Math.Round(Degree1.X + dlat,6), Math.Round(Degree1.Y + dlng,6)),//right-top
103                                   new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y + dlng,6)) //right-bottom
104             };
105 
106         }
107     }

 

  测试方法:

 1  static void Main(string[] args)
 2         {
 3             double a = CoordDispose.GetDistance(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));//116.416984,39.944959
 4             double b = CoordDispose.GetDistanceGoogle(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));
 5             Degree[] dd = CoordDispose.GetDegreeCoordinates(new Degree(116.412007, 39.947545), 102);
 6             Console.WriteLine(a+" "+b);
 7             Console.WriteLine(dd[0].X + "," + dd[0].Y );
 8             Console.WriteLine(dd[3].X + "," + dd[3].Y);
 9             Console.ReadLine();
10         }

 

       lz试了很多次 误差在1米左右

拿到圆的顶点就好办了

数据库要是sql 2008的可以直接进行空间索引经纬度字段,这样应该性能更好(没有试过)

lz公司数据库还老 2005的 这也没关系,关键是经纬度拆分计算,这个就不用说了 网上多的是 最后上个实现的sql语句

SELECT id,zuobiao FROM dbo.zuobiao WHERE zuobiao<>'' AND 
dbo.Get_StrArrayStrOfIndex(zuobiao,',',1)>116.41021 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',1)<116.413804 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',2)<39.949369 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',2)>39.945721

 

 

转载于:https://www.cnblogs.com/cake/p/3240325.html

全套源代码,请咨询 ny_mrzhang@hotmail.com QQ:97302751 以前的协议是这样的。。。车载设备发往网络中心位置数据-80[功能] 车载设备向网络中心发送当前位置信息[去向] 网络中心[数据入库] 网络中心收到数据后将数据保存到动态位置数据表中 (DynData)[格式] 29 29 80 len1 len2 d3d2d1d0 yymmddhhmmss jjjj wwww ssff st lichen1 lichen2 lichen3 st1st2st3 st4 v1v2v3v4v5v6v7v8 len1 len2: 包长d3d2d1d0: 伪IP,终端ID号yymmddhhmmss:年月日时分秒日期表示范围:年份,后两位 ;月份,1-12;日期,1-31时间表示范围:小时,00——23;分钟,00——59;秒,00——59时、分、秒均采用压缩BCD编码。[例如]: 10点23分15秒表示为: 10H,23H,15Hjjjj:经度经度表示范围:000度00.000分——179度59.999分;采用压缩BCD编码,但最高位是符号位。“正”表示“东经”,“负”表示“西经”;“分”的单位是:千分之一分。[例如]: 西经130度45.608分表示为:(注意:1度=60分) 13H,04H,56H,08Hwwww:纬度纬度表示范围:00度00.000分——89度59.999分;采用压缩BCD编码,但最高位是符号位。“正”表示“北纬”,“负”表示“南纬”;“分”的单位是:千分之一分。[例如]: 南纬30度37.901分表示为: 3H,03H,79H,01Hssff:速度方向速度表示方法:表示范围:0——9999公里/小时采用压缩BCD编码。[例如]: 120公里/小时表示为: 01H,20H方位表示方法:表示范围:000——359度采用压缩BCD编码,正北为0度,顺时针方向计数。单位为:度。[例如]: 154度表示为: 01H,54Hst:定位,天线,电源状态定位状态由单字节组成,各位含义如下: D7 D6 D5 D4 D3 D2 D1 D0D7 定位标志0 GPS定位1 GPS定位D6 D5 1 1 GPS正常1 0 GPS天线短路0 1 GPS天线开路0 0 GPS天线故障D4 D3 电源状态1 1 正常1 0 主电源掉电0 1 主电源过高或过低 D2 D1 D0 保留 lichen1 lichen2 lichen3:里程数 HEX 格式:0——0XFFFFFF (0——16777215)米st1st2st3 st4:车辆状态现在协议格式:*HQ,000,S12,130305,60# 上传短信*HQ,000,S4,121212,0F,FF# 速度显示*HQ,000,S4,121212,9F,FF# 断油断电
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值