geohash解碼的matlab實現
阿新 • • 發佈:2017-09-04
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實現