• 【算法】经纬度常用计算


    最近工作中遇到经纬度搜索的需求,初步想法是计算所有目标城市距该点的距离,然后进行筛选,但头疼的是,没有所有产品的缓存,计算距离的操作只能放到DB端,这样是不可接受的;所以打算先将所有产品放到缓存中,再进行计算。可这么做的话,一方面改造工时比较长,另一方面目前的缓存系统不是很稳定,几番思考征得产品经理同意后得出一个不精确的方形搜索方案。

    即以目标点为中心,画一个正方型,在应用端根据目标点经纬度、范围距离、角度算出正方型左下点和右上点的经纬度,然后以此去DB里between。恩,在要求不精确且没有缓存的情况下这是一个较好的折中方案。

    于是接下来就开始考虑算法,参考了博客园的帖子(http://www.cnblogs.com/hellofox2000/archive/2010/07/13/1776159.html#2042746),试验后发现计算两点间距离的方法偏差有点大,于是对其做了一些修改,作为工具类收藏起来,代码如下:

    实体类:

    GeographicPoint
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Xinwei.Test.Geography
    {
        public class GeographicPoint
        {
            /// <summary>
            /// 赤道半径
            /// </summary>
            public const double EARTH_RADIUS = 6378137;
    
            /// <summary>
            /// 极半径
            /// </summary>
            public const double POLAR_RADIUS = 6356725;
    
            /// <summary>
            /// 
            /// </summary>
            public GeographicPoint()
            { }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="lat">维度</param>
            /// <param name="lon">经度</param>
            public GeographicPoint(double lat, double lon)
            {
                this.Latitude = lat;
                this.Longitude = lon;
            }
    
            /// <summary>
            /// 纬度
            /// </summary>
            public double Latitude
            { get; set; }
    
            /// <summary>
            /// 经度
            /// </summary>
            public double Longitude
            { get; set; }
            
            /// <summary>
            /// 纬度的弧度
            /// </summary>
            public double RadianOfLatitude
            {
                get
                {
                    return Latitude * Math.PI / 180;
                }
            }
            
            /// <summary>
            /// 经度的弧度
            /// </summary>
            public double RadianOfLongitude
            {
                get
                {
                    return Longitude * Math.PI / 180;
                }
            }
    
            /// <summary>
            /// 暂时不知意义,请大神们帮助
            /// </summary>
            public double Ec
            {
                get
                {
                    return POLAR_RADIUS + (EARTH_RADIUS - POLAR_RADIUS) * (90 - Latitude) / 90;
                }
            }
    
            /// <summary>
            /// 暂时不知意义,请大神们帮助
            /// </summary>
            public double Ed
            {
                get
                {
                    return Ec * Math.Cos(RadianOfLatitude);
                }
            }
        }
    }

    Helper类:

    GeographyHelper
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Xinwei.Test.Geography
    {
        public static class GeographyHelper
        {
            /// <summary>
            /// 根据两点的经纬度计算两点距离
            /// </summary>
            /// <param name="sourcePoint">A点维度</param>        
            /// <param name="destinationPoint">B点经度</param>
            /// <returns></returns>
            public static double GetDistance(GeographicPoint sourcePoint, GeographicPoint destinationPoint)
            {
                if (Math.Abs(sourcePoint.Latitude) > 90 || Math.Abs(destinationPoint.Latitude) > 90 || Math.Abs(sourcePoint.Longitude) > 180 || Math.Abs(destinationPoint.Longitude) > 180)
                    throw new ArgumentException("经纬度信息不正确!");
    
                double distance = GeographicPoint.EARTH_RADIUS / 1000 * Math.Acos(Math.Cos(sourcePoint.RadianOfLatitude)
                    * Math.Cos(destinationPoint.RadianOfLatitude) * Math.Cos(destinationPoint.RadianOfLongitude - sourcePoint.RadianOfLongitude)
                    + Math.Sin(sourcePoint.RadianOfLatitude) * Math.Sin(destinationPoint.RadianOfLatitude));
    
                return distance;
            }
    
            /// <summary>
            /// 已知点A经纬度,根据B点据A点的距离,和方位,求B点的经纬度
            /// </summary>
            /// <param name="sourcePoint">已知点A</param>
            /// <param name="distance">B点到A点的距离 </param>
            /// <param name="angle">B点相对于A点的方位,12点钟方向为零度,角度顺时针增加</param>
            /// <returns>B点的经纬度坐标</returns>
            public static GeographicPoint GetGeographicPoint(GeographicPoint sourcePoint, double distance, double angle)
            {
                double dx = distance * 1000 * Math.Sin(angle * Math.PI / 180);
                double dy = distance * 1000 * Math.Cos(angle * Math.PI / 180);
    
                double longitude = (dx / sourcePoint.Ed + sourcePoint.RadianOfLongitude) * 180 / Math.PI;
                double latitude = (dy / sourcePoint.Ec + sourcePoint.RadianOfLatitude) * 180 / Math.PI;
    
                GeographicPoint destinationPoint = new GeographicPoint(latitude, longitude);
                return destinationPoint;
            }
        }
    }
  • 相关阅读:
    认识弹性盒子
    管理Linux服务器的用户和组(续篇)
    管理Linux服务器的用户和组
    centos7 mysql数据库安装和配置
    熟练使用Linux进程管理类命令
    熟练使用Linux系统信息类命令
    Linux操作系统-基本命令(二)
    Linux操作系统-基本命令(一)
    api接口统一封装
    10分钟,让你彻底明白Promise原理
  • 原文地址:https://www.cnblogs.com/bbgasj/p/2993745.html
Copyright © 2020-2023  润新知