211 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			211 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 
								 | 
							
								using System;
							 | 
						|||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						|||
| 
								 | 
							
								using System.Text;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace APT.Utility
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    public static class GeohashHelper
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        #region Direction enum
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public enum Direction
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            Top = 0,
							 | 
						|||
| 
								 | 
							
								            Right = 1,
							 | 
						|||
| 
								 | 
							
								            Bottom = 2,
							 | 
						|||
| 
								 | 
							
								            Left = 3
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        #endregion
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private const string Base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
							 | 
						|||
| 
								 | 
							
								        private static readonly int[] Bits = new[] { 16, 8, 4, 2, 1 };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private static readonly string[][] Neighbors = {
							 | 
						|||
| 
								 | 
							
								                                                           new[]
							 | 
						|||
| 
								 | 
							
								                                                               {
							 | 
						|||
| 
								 | 
							
								                                                                   "p0r21436x8zb9dcf5h7kjnmqesgutwvy", // Top
							 | 
						|||
| 
								 | 
							
								                                                                   "bc01fg45238967deuvhjyznpkmstqrwx", // Right
							 | 
						|||
| 
								 | 
							
								                                                                   "14365h7k9dcfesgujnmqp0r2twvyx8zb", // Bottom
							 | 
						|||
| 
								 | 
							
								                                                                   "238967debc01fg45kmstqrwxuvhjyznp", // Left
							 | 
						|||
| 
								 | 
							
								                                                               }, new[]
							 | 
						|||
| 
								 | 
							
								                                                                      {
							 | 
						|||
| 
								 | 
							
								                                                                          "bc01fg45238967deuvhjyznpkmstqrwx", // Top
							 | 
						|||
| 
								 | 
							
								                                                                          "p0r21436x8zb9dcf5h7kjnmqesgutwvy", // Right
							 | 
						|||
| 
								 | 
							
								                                                                          "238967debc01fg45kmstqrwxuvhjyznp", // Bottom
							 | 
						|||
| 
								 | 
							
								                                                                          "14365h7k9dcfesgujnmqp0r2twvyx8zb", // Left
							 | 
						|||
| 
								 | 
							
								                                                                      }
							 | 
						|||
| 
								 | 
							
								                                                       };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private static readonly string[][] Borders = {
							 | 
						|||
| 
								 | 
							
								                                                         new[] {"prxz", "bcfguvyz", "028b", "0145hjnp"},
							 | 
						|||
| 
								 | 
							
								                                                         new[] {"bcfguvyz", "prxz", "0145hjnp", "028b"}
							 | 
						|||
| 
								 | 
							
								                                                     };
							 | 
						|||
| 
								 | 
							
								        /// <summary>
							 | 
						|||
| 
								 | 
							
								        /// 计算相邻
							 | 
						|||
| 
								 | 
							
								        /// </summary>
							 | 
						|||
| 
								 | 
							
								        /// <param name="hash"></param>
							 | 
						|||
| 
								 | 
							
								        /// <param name="direction"></param>
							 | 
						|||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						|||
| 
								 | 
							
								        public static String CalculateAdjacent(String hash, Direction direction)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            hash = hash.ToLower();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            char lastChr = hash[hash.Length - 1];
							 | 
						|||
| 
								 | 
							
								            int type = hash.Length % 2;
							 | 
						|||
| 
								 | 
							
								            var dir = (int)direction;
							 | 
						|||
| 
								 | 
							
								            string nHash = hash.Substring(0, hash.Length - 1);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            if (Borders[type][dir].IndexOf(lastChr) != -1)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                nHash = CalculateAdjacent(nHash, (Direction)dir);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return nHash + Base32[Neighbors[type][dir].IndexOf(lastChr)];
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        /// <summary>
							 | 
						|||
| 
								 | 
							
								        /// 细化间隔
							 | 
						|||
| 
								 | 
							
								        /// </summary>
							 | 
						|||
| 
								 | 
							
								        /// <param name="interval"></param>
							 | 
						|||
| 
								 | 
							
								        /// <param name="cd"></param>
							 | 
						|||
| 
								 | 
							
								        /// <param name="mask"></param>
							 | 
						|||
| 
								 | 
							
								        public static void RefineInterval(ref double[] interval, int cd, int mask)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if ((cd & mask) != 0)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                interval[0] = (interval[0] + interval[1]) / 2;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            else
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                interval[1] = (interval[0] + interval[1]) / 2;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        /// <summary>
							 | 
						|||
| 
								 | 
							
								        /// 解码
							 | 
						|||
| 
								 | 
							
								        /// </summary>
							 | 
						|||
| 
								 | 
							
								        /// <param name="geohash"></param>
							 | 
						|||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						|||
| 
								 | 
							
								        public static double[] Decode(String geohash)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            bool even = true;
							 | 
						|||
| 
								 | 
							
								            double[] lat = { -90.0, 90.0 };
							 | 
						|||
| 
								 | 
							
								            double[] lon = { -180.0, 180.0 };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            foreach (char c in geohash)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                int cd = Base32.IndexOf(c);
							 | 
						|||
| 
								 | 
							
								                for (int j = 0; j < 5; j++)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    int mask = Bits[j];
							 | 
						|||
| 
								 | 
							
								                    if (even)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        RefineInterval(ref lon, cd, mask);
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    else
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        RefineInterval(ref lat, cd, mask);
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    even = !even;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return new[] { (lat[0] + lat[1]) / 2, (lon[0] + lon[1]) / 2 };
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        /// <summary>
							 | 
						|||
| 
								 | 
							
								        /// 编码
							 | 
						|||
| 
								 | 
							
								        /// </summary>
							 | 
						|||
| 
								 | 
							
								        /// <param name="latitude">纬度</param>
							 | 
						|||
| 
								 | 
							
								        /// <param name="longitude">经度</param>
							 | 
						|||
| 
								 | 
							
								        /// <param name="precision">精度</param>
							 | 
						|||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						|||
| 
								 | 
							
								        public static String Encode(double latitude, double longitude, int precision = 12)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            bool even = true;
							 | 
						|||
| 
								 | 
							
								            int bit = 0;
							 | 
						|||
| 
								 | 
							
								            int ch = 0;
							 | 
						|||
| 
								 | 
							
								            string geohash = "";
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            double[] lat = { -90.0, 90.0 };
							 | 
						|||
| 
								 | 
							
								            double[] lon = { -180.0, 180.0 };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            if (precision < 1 || precision > 20) precision = 12;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            while (geohash.Length < precision)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                double mid;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                if (even)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    mid = (lon[0] + lon[1]) / 2;
							 | 
						|||
| 
								 | 
							
								                    if (longitude > mid)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        ch |= Bits[bit];
							 | 
						|||
| 
								 | 
							
								                        lon[0] = mid;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    else
							 | 
						|||
| 
								 | 
							
								                        lon[1] = mid;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                else
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    mid = (lat[0] + lat[1]) / 2;
							 | 
						|||
| 
								 | 
							
								                    if (latitude > mid)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        ch |= Bits[bit];
							 | 
						|||
| 
								 | 
							
								                        lat[0] = mid;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    else
							 | 
						|||
| 
								 | 
							
								                        lat[1] = mid;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                even = !even;
							 | 
						|||
| 
								 | 
							
								                if (bit < 4)
							 | 
						|||
| 
								 | 
							
								                    bit++;
							 | 
						|||
| 
								 | 
							
								                else
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    geohash += Base32[ch];
							 | 
						|||
| 
								 | 
							
								                    bit = 0;
							 | 
						|||
| 
								 | 
							
								                    ch = 0;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return geohash;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        /// <summary>
							 | 
						|||
| 
								 | 
							
								        /// 获取九个格子 顺序 本身 上、下、左、右、 左上、 右上、 左下、右下
							 | 
						|||
| 
								 | 
							
								        /// </summary>
							 | 
						|||
| 
								 | 
							
								        /// <param name="geohash"></param>
							 | 
						|||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						|||
| 
								 | 
							
								        public static String[] getGeoHashExpand(String geohash)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            try
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                String geohashTop = CalculateAdjacent(geohash, Direction.Top);//上
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashBottom = CalculateAdjacent(geohash, Direction.Bottom);//下
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashLeft = CalculateAdjacent(geohash, Direction.Left);//左
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashRight = CalculateAdjacent(geohash, Direction.Right);//右
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashTopLeft = CalculateAdjacent(geohashLeft, Direction.Top);//左上
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashTopRight = CalculateAdjacent(geohashRight, Direction.Top);//右上
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashBottomLeft = CalculateAdjacent(geohashLeft, Direction.Bottom);//左下
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String geohashBottomRight = CalculateAdjacent(geohashRight, Direction.Bottom);//右下
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                String[] expand = { geohash, geohashTop, geohashBottom, geohashLeft, geohashRight, geohashTopLeft, geohashTopRight, geohashBottomLeft, geohashBottomRight };
							 | 
						|||
| 
								 | 
							
								                return expand;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            catch (Exception e)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                return null;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |