zoukankan      html  css  js  c++  java
  • 【算法】经纬度常用计算

    最近工作中遇到经纬度搜索的需求,初步想法是计算所有目标城市距该点的距离,然后进行筛选,但头疼的是,没有所有产品的缓存,计算距离的操作只能放到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;
            }
        }
    }
  • 相关阅读:
    设置屏幕分辨率的函数 回复 "董勇" 的问题
    Delphi 的内存操作函数(5): 复制内存
    汉字与区位码(1) 转换函数
    汉字与多字节编码的转换 回复 "不知道" 的问题
    一个可以显示多边形的 TMyShape 类 回复 "董勇" 的问题
    Delphi 的内存操作函数(6): 跨进程的内存分配
    Delphi 中的 IfThen 函数 回复 "深挖洞、广积粮" 的问题
    Byte 数组转字符串 回复 "不知道" 问题
    汉字与区位码(2) 分析
    获取各种编码的识别符
  • 原文地址:https://www.cnblogs.com/bbgasj/p/2993745.html
Copyright © 2011-2022 走看看