Google、Soso、Baidu卫星图url研究
2013-04-25 14:01
489 查看
前一段时间因为公司有个项目需要我研究一下Google的卫星图的地址规律,开始我以为会很艰难认为Google那么大公司url应该会加密什么的,结果发现Google和Soso、Baidu、Sogou这几个比较起来Google的url演算是最简单且明了的,废话不说了。
打开Google Map我们可以看到一张地图,将它放大或者缩小就可以看到不同的地图(很多张的图片)。url像这样:http://khm1.google.com/kh/v=125&src=app&x=0&y=0&z=0 (红色部分均为可变的参数)
Google的作法是世界的第0层(z=0)就是一张图构成:
z=1的效果就是将它切分为4份见下图:
依次类推,我们可以得到一个公式:NUM=2^(N+1)
NUM:x或者y方向上的图片数
N:第几层z轴
然后引入Mercator库(我自己写的麦卡拓转换)code:
主要是Y轴方向转换麻烦需要用到这些函数,因为Mercator当初设计的缺陷就是越往两极地区越不准确。
下面两个函数Google_XYZ_to_LatLng、Google_LatLngZ_to_XY提供了将XYZ转换成为 经纬度,和经纬度转换成Google的XYZ轴,有了这些基础我们就可以用html和JQuery写出一个简易的GoogleMap 网页键盘版本:
soso map和baidu map的地图url规律就蛋疼许多,因为他们的Y轴非要与google的方向相反。。没法,为了适应他们单独写了函数
这还不算什么,soso还单独弄出来一个参数dx、dy,后来我还是自己看sosomap中的已经被搅乱的js代码才分析出来只是由x和y通过Math.floor(x/16)运算得到的,腾讯这样搞这有木有意义@@ ,为了后台省资源?
百度也是跟着腾讯一样把地图的Y轴弄反,不过没有dx、dy,不过他们我实测都有经过偏移模组的偏移。也就是说你给定一个经纬度通过标准的麦卡拓算出来的xyz总有一点点几百米的偏移。这些倒是怪不到他。更变态的是sogoumap完全没有办法猜清楚是什么规律,我直接选择放弃了,都不想看它的js代码了,还是洗洗睡吧。
打开Google Map我们可以看到一张地图,将它放大或者缩小就可以看到不同的地图(很多张的图片)。url像这样:http://khm1.google.com/kh/v=125&src=app&x=0&y=0&z=0 (红色部分均为可变的参数)
Google的作法是世界的第0层(z=0)就是一张图构成:
z=1的效果就是将它切分为4份见下图:
NUM:x或者y方向上的图片数
N:第几层z轴
然后引入Mercator库(我自己写的麦卡拓转换)code:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; namespace MapsDownloader { class Mercator { private double NormalToMercator(double y) { y -= 0.5; y *= 2.0 * Math.PI; y = Math.Exp(y * 2.0); y = (y - 1) / (y + 1.0); y = Math.Asin(y); y = y * -180.0 / Math.PI; return y; } private double MercatorToNormal(double y) { y = -y * Math.PI / 180.0; y = Math.Sin(y); y = (1.0 + y) / (1.0 - y); y = 0.5 * Math.Log(y); y *= 1.0 / (2.0 * Math.PI); y += 0.5; return y; } private double getNormailByY(double y,int picnum) { return y/picnum; } private double getYByNormail(double y, int picnum) { return picnum * y; } /////////////////////////////////////////////// ///传入:-26.851029008675013 返回:-26° 51' 3" public string GetSexagesimalNotation(double x) { //to string format: 23° 27′ 30" var ret = ""; if (x < 0) { ret += '-'; x = -x; } ret += Math.Floor(x); ret += "° "; x = (x - Math.Floor(x)) * 60; ret += Math.Floor(x); ret += "' "; x = (x - Math.Floor(x)) * 60; ret += Math.Floor(x); ret += "\" "; return ret; } public Point Google_XYZ_to_LatLng(int x, int y, int z) //lat [0] , lng [1] { Point LatLng = new Point(); int picnum = 2 << (z - 1); //z层在x、y轴上存在多少张 double onex = 360.0 / picnum; //平均每一张占用多少经纬度 double xlat = onex * x; if (xlat > 360.0) //如果超过360就剪掉它 xlat = xlat % 360.0; if (xlat > 180.0) LatLng.X = onex * x - 180.0; else LatLng.X = -(180.0 - onex * x); LatLng.Y = NormalToMercator(getNormailByY(y, picnum)); return LatLng; } public Point Google_LatLngZ_to_XY(double Lat, double Lng, int z) //return x,y array { Point xy = new Point(); int picnum = 2 << (z - 1); //z层在x、y轴上存在多少张 double onex = 360.0 / picnum; ////平均每一张占用多少经纬度 Lat += 180.0; xy.X = Convert.ToInt32(Lat / onex); //x xy.Y = Convert.ToInt32(getYByNormail(MercatorToNormal(Lng), picnum)); //y return xy; } } }
主要是Y轴方向转换麻烦需要用到这些函数,因为Mercator当初设计的缺陷就是越往两极地区越不准确。
下面两个函数Google_XYZ_to_LatLng、Google_LatLngZ_to_XY提供了将XYZ转换成为 经纬度,和经纬度转换成Google的XYZ轴,有了这些基础我们就可以用html和JQuery写出一个简易的GoogleMap 网页键盘版本:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Keyboard Google Map——By MaxHo</title> <script type="text/javascript" src="jquery-1.8.0.min.js"></script> <script type="text/javascript"> $(document).ready(function() { readImage(); }); function readImage() { var url=""; //http://khmdbs0.google.com/pm?v=9&src=app&x=0&y=4&z=4&s=Gali //http://khm1.google.com/kh/v=125&src=app&x= // if($("#mapTypeSelect").val() == 1) { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); var picnum = 2<<(zz-1); var onex = 360 / picnum; /*var oney = 180 / picnum; if(oney * yy > 90) var lng = -(oney * yy - 90); else var lng = 90 - oney * yy;*/ var lng = NormalToMercator (getNormailByY(yy,picnum)); if(onex * xx > 180) var lat = onex * xx - 180; else var lat = -(180 - onex * xx); $("#latlng").text(lng + " , " + lat); $("table td").each(function(i){ var ix = i%5 + parseInt($("#x").val()); var iy = parseInt(i/5) + parseInt($("#y").val()); url = "http://khm1.google.com/kh/v=125&src=app&x="+ix +"&y="+iy+"&z="+$("#z").val(); $(this).html("<img style='width:100%;height:100%;' src='"+url+"'/>"); }); } else if($("#mapTypeSelect").val() == 2) //soso { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); $("table td").each(function(i){ var ix = i%5 + parseInt($("#x").val()); var iy = 2 - parseInt(i/5) + parseInt($("#y").val()); var dx = Math.floor(ix/16); var dy = Math.floor(iy/16); url = "http://p1.map.soso.com/sateTiles/"+$("#z").val() +"/"+dx+"/"+dy+"/"+ix+"_"+iy+".jpg"; $(this).html("<img style='width:100%;height:100%;' src='"+url+"'/>"); }); } else if($("#mapTypeSelect").val() == 3) //baidu { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); $("table td").each(function(i){ var ix = i%5 + parseInt($("#x").val()); var iy = 2 - parseInt(i/5) + parseInt($("#y").val()); url = "http://q1.baidu.com/it/u=x="+ix+";y="+iy+";z="+$("#z").val() +";v=009;type=sate&fm=46"; $(this).html("<img style='width:100%;height:100%;' src='"+url+"'/>"); }); } else if($("#mapTypeSelect").val() == 4) //cangbao { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); var picnum = 2<<(zz-1); var onex = 360 / picnum; /*var oney = 180 / picnum; if(oney * yy > 90) var lng = -(oney * yy - 90); else var lng = 90 - oney * yy;*/ var lng = NormalToMercator (getNormailByY(yy,picnum)); if(onex * xx > 180) var lat = onex * xx - 180; else var lat = -(180 - onex * xx); $("#latlng").text(lng + " , " + lat); $("table td").each(function(i){ var ix = i%5 + parseInt($("#x").val()); var iy = parseInt(i/5) + parseInt($("#y").val()); url = "http://khmdbs0.google.com/pm?v=9&src=app&x="+ix +"&y="+iy+"&z="+$("#z").val(); $(this).html("<img style='width:100%;height:100%;' src='"+url+"'/>"); }); } } function left() { var xx = parseInt($("#x").val()); $("#x").val(--xx); } function up() { var yy = parseInt($("#y").val()); if($("#mapTypeSelect").val() == 2 || $("#mapTypeSelect").val() == 3 ) $("#y").val(++yy); else $("#y").val(--yy); } function right() { var xx = parseInt($("#x").val()); $("#x").val(++xx); } function down() { var yy = parseInt($("#y").val()); if($("#mapTypeSelect").val() == 2 || $("#mapTypeSelect").val() == 3 ) $("#y").val(--yy); else $("#y").val(++yy); } function enter() { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); if($("#mapTypeSelect").val() == 1) { var centerX = (xx+2)*2 - 2; var centerY = (yy+1)*2 - 1; var centerZ = zz+1; } else if($("#mapTypeSelect").val() == 2 || $("#mapTypeSelect").val() == 3 ) { var centerX = (xx+2)*2 - 2; var centerY = (yy-1)*2 + 3; var centerZ = zz+1; } $("#x").val(centerX); $("#y").val(centerY); $("#z").val(centerZ); } function exit() { var xx = parseInt($("#x").val()); var yy = parseInt($("#y").val()); var zz = parseInt($("#z").val()); if($("#mapTypeSelect").val() == 1) { var centerX = parseInt((xx+2)/2) - 2; var centerY = parseInt((yy+1)/2) - 1; var centerZ = zz-1; } else if($("#mapTypeSelect").val() == 2 || $("#mapTypeSelect").val() == 3 ) { var centerX = parseInt((xx+2)/2) - 2; var centerY = parseInt((yy-1)/2); var centerZ = zz-1; } $("#x").val(centerX); $("#y").val(centerY); $("#z").val(centerZ); } $(this).bind('focus',function(event){ $(this).select(); }); $(document).bind('keydown',function(e){ e = (e) ? e : ((window.event) ? window.event : ""); var key = e.keyCode?e.keyCode:e.which; switch(key) { case 37: //left left(); readImage(); break; case 38: //up up(); readImage(); break; case 39: //right right(); readImage(); break; case 40: //down down(); readImage(); break; /*case 13: //enter enter(); readImage(); break;*/ case 69: //E enter(); readImage(); break; /*case 27: //exit exit(); readImage(); break;*/ case 81: //Q exit(); readImage(); break; default: //alert(key); break; } }); function MercatorToNormal(y) { y = -y * Math.PI / 180; // convert to radians y = Math.sin(y); y = (1+y)/(1-y); y = 0.5 * Math.log(y); y *= 1.0 / (2 * Math.PI); // scale factor from radians to normalized y += 0.5; // and make y range from 0 - 1 return y; } function NormalToMercator(y) { y -= 0.5; y *= 2 * Math.PI; y = Math.exp(y * 2); y = (y-1)/(y+1); y = Math.asin(y); y = y * -180/Math.PI; return y; } function getNormailByY(y,picnum) { /*var scale = 1.0; var ry = 0.0; for (var i = 0; i< y ; i++) { scale *= 0.5; ry += scale; } return ry;*/ return y/picnum; } function changeMapTypeSelect() { if($("#mapTypeSelect").val() == 2) { $("#x").val(10); $("#y").val(8); $("#z").val(4); } else if($("#mapTypeSelect").val() == 1) { $("#x").val(10); $("#y").val(5); $("#z").val(4); } else if ($("#mapTypeSelect").val() == 3 ) { $("#x").val(3); $("#y").val(0); $("#z").val(5); } readImage(); } </script> </head> <body> <form action="#"> x:<input id="x" type="text" value="10" style="width:60px;"/> y:<input id="y" type="text" value="5" style="width:60px;"/> z:<input id="z" type="text" value="4" style="width:60px;"/> <input type="submit" value="重新載入" onclick="readImage()"/> <span style="font-size:12px; color:#808080"> <select id="mapTypeSelect" onchange="changeMapTypeSelect()"> <option value="1" selected="selected">GoogleMap</option> <option value="2">SosoMap</option> <option value="3">BaiduMap</option> <option value="4">藏宝图</option> </select> 使用鍵盤熱鍵上下左右鍵調節方向,E、Q控制地圖縮放</span> <input type="button" value="←" onclick="left(),readImage()"/> <input type="button" value="↑" onclick="up(),readImage()"/> <input type="button" value="↓" onclick="down(),readImage()"/> <input type="button" value="→" onclick="right(),readImage()"/> <input type="button" value="㈩" onclick="enter(),readImage()"/> <input type="button" value="㈠" onclick="exit(),readImage()"/> </form> 左上角經緯度: <span id="latlng"></span> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> </table> </body> </html>
soso map和baidu map的地图url规律就蛋疼许多,因为他们的Y轴非要与google的方向相反。。没法,为了适应他们单独写了函数
这还不算什么,soso还单独弄出来一个参数dx、dy,后来我还是自己看sosomap中的已经被搅乱的js代码才分析出来只是由x和y通过Math.floor(x/16)运算得到的,腾讯这样搞这有木有意义@@ ,为了后台省资源?
百度也是跟着腾讯一样把地图的Y轴弄反,不过没有dx、dy,不过他们我实测都有经过偏移模组的偏移。也就是说你给定一个经纬度通过标准的麦卡拓算出来的xyz总有一点点几百米的偏移。这些倒是怪不到他。更变态的是sogoumap完全没有办法猜清楚是什么规律,我直接选择放弃了,都不想看它的js代码了,还是洗洗睡吧。
相关文章推荐
- 实现google baidu yahoo soso ... 站内搜索代码
- Google卫星地图的URL计算
- baidu,google和阿里巴巴的赢利模式研究
- Baidu、Google、Soso等搜索引擎网站登录入口
- Google排名技术研究-Google的奇怪规则:URL不能以.0结尾
- Google和Baidu的URL参数说明
- Google卫星地图的URL计算
- 识别真假搜索引擎(搜索蜘蛛)方法(baidu,google,Msn,sogou,soso等)
- 关于baidu,google,收录本网站的url地址,当地址是.html后缀的时候
- 搜索pl/sql破解版的时候baidu,google,soso使用的不同结果
- 关于baidu,google,收录本网站的url地址,当地址是.html后缀的时候
- 也说Google卫星地图的URL地址的qrts编码算法
- Baidu与Google的差距
- ]XXX.class.getResource()与XXX.class.getClassLoader().getResource(url)研究
- Failed to fetch URL http://dl-ssl.google.com/android/repository/repository.xml, reason:
- 更新SDK失败解决办法(Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-1.xml)
- 使用baidu的最后一个理由即将消失:原创Google词典脚本