.NetCore给定坐标排序搜索附近的经纬度计算距离、WGS84 GCJ02 BD09坐标转换

先过滤出大概的经纬度范围再进行计算。我们求取的虽然是个圆,但我们可以先求出该圆的外接正方形(比方说正方形的四个点),先算出该点周围的矩形的四个点的经纬度,然后使用正方形的经纬度去直接匹配数据库中的记录,然后在用方法一进行筛选(相对于只使用方法一效率高了非常多 –合理利用算法)。

话不多说,直接上代码:

public static class DistanceHelper
    {
        /// <summary>
        /// 根据一个给定经纬度的点和距离,进行附近地点查询
        /// </summary>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="distance">距离(单位:公里或千米)</param>
        /// <returns>返回一个范围的4个点,最小纬度和纬度,最大经度和纬度</returns>
        public static PositionModel FindNeighPosition(double longitude, double latitude, double distance)
        {
            //先计算查询点的经纬度范围  
            double r = 6378.137;//地球半径千米  
            double dis = distance;//千米距离    
            double dlng = 2 * Math.Asin(Math.Sin(dis / (2 * r)) / Math.Cos(latitude * Math.PI / 180));
            dlng = dlng * 180 / Math.PI;//角度转为弧度  
            double dlat = dis / r;
            dlat = dlat * 180 / Math.PI;
            double minlat = latitude - dlat;
            double maxlat = latitude + dlat;
            double minlng = longitude - dlng;
            double maxlng = longitude + dlng;
            return new PositionModel
            {
                MinLat = minlat,
                MaxLat = maxlat,
                MinLng = minlng,
                MaxLng = maxlng
            };
        }

        /// <summary>
        /// 计算两点位置的距离,返回两点的距离,单位:公里或千米
        /// 该公式为GOOGLE提供,误差小于0.2米
        /// </summary>
        /// <param name="lat1">第一点纬度</param>
        /// <param name="lng1">第一点经度</param>
        /// <param name="lat2">第二点纬度</param>
        /// <param name="lng2">第二点经度</param>
        /// <returns>返回两点的距离,单位:公里或千米</returns>
        public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
        {
            //地球半径,单位米
            double EARTH_RADIUS = 6378137;
            double radLat1 = Rad(lat1);
            double radLng1 = Rad(lng1);
            double radLat2 = Rad(lat2);
            double radLng2 = Rad(lng2);
            double a = radLat1 - radLat2;
            double b = radLng1 - radLng2;
            double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS;
            return result / 1000;
        }

        /// <summary>
        /// 经纬度转化成弧度
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double Rad(double d)
        {
            return (double)d * Math.PI / 180d;
        }
    }

 

外卖根据中心坐标计算附近距离排序

query.OrderByDescending(d => Math.Sqrt((121.517759 - Convert.ToDouble(longitude)) * (121.517759 - Convert.ToDouble(d.longitude)) + (31.178469 - Convert.ToDouble(latitude)) * (31.178469 - Convert.ToDouble(d.latitude))));

 

距离计算

                  var dis = DistanceHelper.GetDistance(Convert.ToDouble(latitude), Convert.ToDouble(longitude), Convert.ToDouble(item.latitude), Convert.ToDouble(item.longitude));
                    if (dis>1)
                    {
                        item.distance = Math.Round(dis, 2).ToString() + "km";
                    }
                    else
                    {
                        item.distance = Convert.ToInt32(dis* 1000.0) + "m";
                    }

WGS84 GCJ02 BD09坐标转换

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace General.Core.Common.Map
{
    public class TempGps
    {

        public double Tlng;
        public double Tlat;
    }

    public class GPS
    {
        public string oLng;//经度 度分秒坐标
        public string oLat;//纬度 度分秒坐标

        public double lng;//经度 WGS-84
        public double lat;//纬度 WGS-84

        public double gLng;//经度 GCJ-02 中国坐标偏移标准 Google Map、高德、腾讯使用
        public double gLat;//纬度 GCJ-02 中国坐标偏移标准 Google Map、高德、腾讯使用

        public double bLng;//经度 BD-09 百度坐标偏移标准,Baidu Map使用
        public double bLat;//纬度 BD-09 百度坐标偏移标准,Baidu Map使用


        public double PI = Math.PI;
        double xPI = Math.PI * 3000.0 / 180.0;

        public TempGps delta(TempGps t)
        {
            var a = 6378245.0; //  a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
            var ee = 0.00669342162296594323; //  ee: 椭球的偏心率。
            var dLat = this.transformLat(t.Tlng - 105.0, t.Tlat - 35.0);
            var dLng = this.transformLng(t.Tlng - 105.0, t.Tlat - 35.0);
            var radLat = t.Tlat / 180.0 * PI;
            var magic = Math.Sin(radLat);
            magic = 1 - ee * magic * magic;
            var sqrtMagic = Math.Sqrt(magic);
            return new TempGps() { Tlat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI), Tlng = (dLng * 180.0) / (a / sqrtMagic * Math.Cos(radLat) * PI) };
        }
        //WGS-84 to GCJ-02
        public void gcj_encrypt()
        {
            if (this.outOfChina(lng, lat))
            {
                gLng = lng;
                gLat = lat;
            }
            var t = this.delta(new TempGps() { Tlng = lng, Tlat = lat });
            gLng = t.Tlng + lng;
            gLat = t.Tlat + lat;
        }

        //GCJ-02 to WGS-84
        public void gcj_decrypt()
        {


            if (this.outOfChina(gLng, gLat))
            {
                lng = gLng;
                lat = gLat;

            }
            var t = this.delta(new TempGps() { Tlng = gLng, Tlat = gLat });
            lng = gLng - t.Tlng;
            lat = gLat - t.Tlat;
        }

        //GCJ-02 to BD-09
        public void bd_encrypt()
        {
            double x = gLng;
            double y = gLat;
            double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * xPI);
            double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * xPI);
            bLng = z * Math.Cos(theta) + 0.0065;
            bLat = z * Math.Sin(theta) + 0.006;
        }
        //BD-09 to GCJ-02
        public void bd_decrypt()
        {
            double x = bLng - 0.0065;
            double y = bLat - 0.006;
            double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * xPI);
            double theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * xPI);
            gLng = z * Math.Cos(theta);
            gLat = z * Math.Sin(theta);
        }

        //WGS-84 to 度分秒坐标  
        public void wgs_decrypt()
        {
            oLng = TranDegreeToDMs(lng);
            oLat = TranDegreeToDMs(lat);
        }


        //度分秒坐标 to WGS-84
        public void wgs_encrypt()
        {
            lng = TranDMsToDegree(oLng);
            lat = TranDMsToDegree(oLat);
        }


        public double TranDMsToDegree(string _dms)
        {
            string[] dms = _dms.Split('.');
            if (dms.Length > 2)
                return double.Parse(dms[0]) + double.Parse(dms[1]) / 60 + double.Parse(dms[2] + "." + dms[3] ?? "0") / 3600;
            else
                return 0d;

        }


        private static string TranDegreeToDMs(double d)
        {
            int Degree = Convert.ToInt16(Math.Truncate(d));//度
            d = d - Degree;
            int M = Convert.ToInt16(Math.Truncate((d) * 60));//分
            int S = Convert.ToInt16(Math.Round((d * 60 - M) * 60));
            if (S == 60)
            {
                M = M + 1;
                S = 0;
            }
            if (M == 60)
            {
                M = 0;
                Degree = Degree + 1;
            }
            string rstr = Degree.ToString() + ".";
            if (M < 10)
                rstr = rstr + "0" + M.ToString();
            else
                rstr = rstr + M.ToString();
            if (S < 10)
                rstr = rstr + "0" + S.ToString();
            else
                rstr = rstr + S.ToString();
            return rstr;
        }

        private bool outOfChina(double _lng, double _lat)
        {
            if (lng < 72.004 || lng > 137.8347)
                return true;
            if (lat < 0.8293 || lat > 55.8271)
                return true;
            return false;
        }

        private double transformLat(double x, double y)
        {
            double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x));
            ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.Sin(y * PI) + 40.0 * Math.Sin(y / 3.0 * PI)) * 2.0 / 3.0;
            ret += (160.0 * Math.Sin(y / 12.0 * PI) + 320 * Math.Sin(y * PI / 30.0)) * 2.0 / 3.0;
            return ret;
        }

        private double transformLng(double x, double y)
        {
            double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));
            ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.Sin(x * PI) + 40.0 * Math.Sin(x / 3.0 * PI)) * 2.0 / 3.0;
            ret += (150.0 * Math.Sin(x / 12.0 * PI) + 300.0 * Math.Sin(x / 30.0 * PI)) * 2.0 / 3.0;
            return ret;
        }
    }
}

 

public class PositionModel
    {
        public double MinLat { get; internal set; }
        public double MaxLat { get; internal set; }
        public double MinLng { get; internal set; }
        public double MaxLng { get; internal set; }
    }