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实现的主要内容,如果未能解决你的问题,请参考以下文章