【算法】经纬度常用计算

最近工作中遇到经纬度搜索的需求,初步想法是计算所有目标城市距该点的距离,然后进行筛选,但头疼的是,没有所有产品的缓存,计算距离的操作只能放到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;

        }

    }

}

 

你可能感兴趣的:(算法)