1. 程式人生 > >geohash解碼的matlab實現

geohash解碼的matlab實現

scan pri long cnblogs 共享單車 好玩 代碼 font 出發

引子:因為做到李雷老師給的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實現