geohash解码的matlab实现

Posted 这是小魔仙的账户

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了geohash解码的matlab实现相关的知识,希望对你有一定的参考价值。

引子:因为做到李雷老师给的2017数模模拟题“共享单车问题”时,用了“2017摩拜杯大赛”的数据(说起来很幸运正好遇到这么个比赛,才可以比较轻松找到数据,一共300w条,我们取了其中2w条),里面单车出发点和目的地用的是一坨字母和数字组成的编码,作为一个菜鸡我自然是不晓得这是啥玩意的,后来百度之后看了一些博客才明白,后面找到了解码的c语言代码,但是想用matlab,于是把c的解码部分转换成了matlab代码。

虽然只是一个简单的转换,但是这个过程里也是感觉到代码世界的神奇(哈哈我可能是个菜鸡中的菜鸡),就和中文英文一样,是可以互相翻译的,还蛮好玩的。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<algorithm>
  6 
  7 using namespace std;
  8 
  9 #define clegh 7//geohash编码长度
 10 
 11 char Base32[32]= {0,1,2,3,4,5,6,7,8,9,b,
 12                   c,d,e,f,g,h,j,k,m,n,p,
 13                   q,r,s,t,u,v,w,x,y,z
 14                  };//Base32编码
 15 
 16 char geohash[15]= {\0};
 17 
 18 
 19 
 20 void encode(double lat,double lot,int prec)//<span style="font-family:Arial;">译码</span>
 21 {
 22     memset(geohash,\0,sizeof(geohash));
 23     double latitude[2] = {-90, 90};
 24     double logitude[2] = {-180, 180};
 25 
 26     int length = prec * 5; // 需要的二进制编码长度
 27     int bits = 0 ;// 记录二进制码
 28     int k=0;
 29 
 30     for(int i=0; i<length; i++)
 31     {
 32         if(i%2==0)//从0开始偶数位为经度
 33         {
 34             double mid = (logitude[0] + logitude[1]) / 2;
 35             if(lot > mid)
 36             {
 37                 bits=bits*2+1;
 38                 logitude[0] = mid;
 39             }
 40             else
 41             {
 42                 bits=bits*2;
 43                 logitude[1] = mid;
 44             }
 45         }
 46         else
 47         {
 48             double mid = (latitude[0] + latitude[1]) / 2;
 49             if(lat > mid)
 50             {
 51                 bits=bits*2+1;
 52                 latitude[0] = mid;
 53             }
 54             else
 55             {
 56                 bits=bits*2;
 57                 latitude[1] = mid;
 58             }
 59         }
 60         if(!((i+1)%5))
 61         {
 62             geohash[k++] = Base32[bits];
 63             //printf("%d\n",bits);
 64             bits = 0;// 重置二进制码
 65         }
 66     }
 67 }
 68 
 69 
 70 
 71 double lat=0, lot=0;
 72 
 73 void docode(char *geoh)//解码
 74 {
 75     bool odd = true ;// 当前计算位的奇偶性
 76     double latitude[2] = {-90, 90};
 77     double longitude[2] = {-180, 180};
 78     for(int i=0; i<strlen(geoh); i++)
 79     {
 80         int bits;
 81         for(int j=0; j<32; j++)
 82             if(Base32[j]==geoh[i])
 83             {
 84                 bits=j;// 找到第i个字符对应的数
 85                 //printf("%d\n",j);
 86                 break;
 87             }
 88 
 89         for(j=4; j>=0; j--)
 90         {
 91             int bit = (bits >> j) & 1 ;// 通过位运算取出对应的位
 92             if(odd)
 93             {
 94                 double mid = (longitude[0] + longitude[1]) / 2;
 95                 longitude[1 - bit] = mid;
 96             }
 97             else
 98             {
 99                 double mid = (latitude[0] + latitude[1]) / 2;
100                 latitude[1 - bit] = mid;
101             }
102             odd = !odd;
103         }
104     }
105     lat = (latitude[0] + latitude[1]) / 2;
106     lot = (longitude[0] + longitude[1]) / 2;
107 }
108 
109 
110 
111 int main()
112 {
113     //freopen("in.in","r",stdin);
114     int  m;
115     scanf("%d",&m);
116     char c=getchar();
117     memset(geohash,\0,sizeof(geohash));
118     for(int i=1; i<=m; i++)
119     {
120         scanf("%s",geohash);
121         c=getchar();
122         //printf("%s\n",geohash);
123         docode(geohash);
124         printf("%lf %lf\n",lat,lot);
125     }
126     return 0;
127 }

当然这段代码包括了编码和解码,我只需要用解码部分,就只转换了这部分,转换成matlab之后如下:

function [lat,lot]=docode(geoh)      %解码
% 编码长度    
Len=7;
% Base32编码    
Base32= ‘0123456789bcdefghjkmnpqrstuvwxyz‘;
% geoh为待解析的编码,是字符串

%当前计算位的奇偶性
odd = true ;
latitude=[-90,90];%纬度
longitude=[-180, 180];%经度
for i=1:Len
   for j=1:32
            if(Base32(j)==geoh(i))
                bits=j-1;    % 找到第i个字符对应的数
                break;
            end
    end

    for jj=1:5
            j=6-jj;
        switch j    
            case 5
                ad=16;
            case 4
                ad=8;
            case 3
                ad=4;
            case 2
                ad=2;
            case 1
                ad=1;
        end
            
          if  bitand(bits,ad)
              bit=1;
          else
              bit=0;
          end      % 取出对应的位
            if odd
                mid = (longitude(1) + longitude(2)) / 2;
                if bit==0
                    longitude(2)= mid;
                else
                    longitude(1)= mid;
                end
                    
                
            else
            
                mid = (latitude(1) + latitude(2)) / 2;
                if bit==0
                    latitude(2)= mid;
                else
                    latitude(1)= mid;
                end
            end
            
            
            odd = ~odd;
    end
    
end

    lat = (latitude(1) + latitude(2)) / 2;
    lot = (longitude(1) + longitude(2)) / 2;
end

还有一个问题,是数据文件是excel表格,而且编码是文本,不是数值。

 

对于一个菜鸡来说,这就触及到我的知识盲区了,不过机智如我,先把它保存为txt文件,然后逐行读取字符串,逐行解码。如下:

clc
clear all

i=1;
fidin=fopen(‘end.txt‘,‘r‘);          %打开文件                                       
while ~feof(fidin)                   %判断是不是文件末尾                                      
   data1{i,1}=fgetl(fidin);          %读取一行,读文一行后,光标就会自动到下一行 
   i=i+1;
end
fclose(fidin);


for k=1:size(data1,1)
    
    [DATA(k,1) DATA(k,2)]=docode(data1{k,1});
end

 

最后DATA就是解码出来的纬度和经度的数据了。

技术分享

以上是关于geohash解码的matlab实现的主要内容,如果未能解决你的问题,请参考以下文章

基于geohash6编码实现相邻4916网格合并

matlab实现通信原理(附上完整仿真源码)

ABAP实现Geohash

php通过geohash算法实现查找附近的商铺

Hbase geohash实现地理轨迹的空间搜索实现思路设计

Hbase geohash实现地理轨迹的空间搜索实现思路设计