原文地址: http://bbs.msproject.cn/default.aspx?g=posts&t=205
[翻译]
Pascal Buirey著 How Google Map Works
[开发环境]
本例开发语言C#,不过可以应用到 任何一种语言
[简介]
本文分析了 Google地图是如何工作的,并指明 tile(翻译成阶砖,也就是相同的方格子)是如何编码的。Google Map采用了发送一个简单的URL能够获取的tile。本文将解释如何通过地理经度和纬度编制出获取对应tile的URL。
[Tile编码]
Google地图提供了两个不同的算法编码Tile的位置。
Google地图中,一个Tile的URL一般是这样的: http://mt1.google.com/mt?n=404&v=w2.12&x=130&y=93&zoom=9,x 和y是Tile的坐标(纬度经度),以及一个显示比例尺度。显示比例(zoom factor )从17(全部显示fully zoomed out)到0(最大精度)。当这个比例是17的时候,整个地球显示在一个Tile中,x=0且y=0;当是16,地球被分成2×2部分,0<=x& lt;=1,0<=y<=1。所以,我们假设zoom factor是z,那么水平和垂直的Tile总数是2^(17-z)。
[用纬度、经度和显示比例发现一个Tile的算法]
// instead of 90(north) to -90(south)
latitude=90-latitude;
//correct the longitude to go from 0 to 360
longitude=180+longitude;
//find tile size from zoom level
double latTileSize=180/(pow(2,(17-zoom)));
double longTileSize=360/(pow(2,(17-zoom)));
//find the tile coordinates
int tilex=(int)(longitude/longTileSize);
int tiley=(int)(latitude/latTileSize);
事实上,这个算法是理论上的,因为,覆盖的地区不和全球匹配。
[服务器]
Google采用4个服务器平衡负载。它们是mt0, mt1, mt2 和 mt3.
[Tile大小]
每个Tile是256×256的png图片
[卫星图像]
卫星图像的编码是不一样的,它的URL一般如此: http://kh0.google.com/kh?n=404&v=8&t=trtqtt,其中t参数编码了图像的位置,t长度表明zoom的级别。
要想看到全球,设置t为t;下一显示级别,Tile被分成4个象限,顺时针依次是:q,r,s和t;要想看哪个象限,就把这个字符附到t的后面就可以了。例如:t=tq,代表左上的象限。依次类推……
算法如下:
double xmin=-180;
double xmax=180;
double ymin=-90;
double ymax=90;
double xmid=0;
double ymid=0;
string location="t";
//google use a latitude divided by 2;
double halflat = latitude / 2;
for (int i = 0; i < zoom; i++)
{
xmoy = (xmax + xmin) / 2;
ymoy = (ymax + ymin) / 2;
if (halflat > ymoy) //upper part (q or r)
{
ymin = ymoy;
if (longitude < xmoy)
{ /*q*/
location+= "q";
xmax = xmoy;
}
else
{/*r*/
location+= "r";
xmin = xmoy;
}
}
else //lower part (t or s)
{
ymax = ymoy;
if (longitude < xmoy)
{ /*t*/
location+= "t";
xmax = xmoy;
}
else
{/*s*/
location+= "s";
xmin = xmoy;
}
}
}
//here, the location should contains the string corresponding to the tile...
同样,这个算法是理论上的。
[服务器]
Google采用4个服务器平衡负载。它们是kh0, kh1, kh2 和 kh3.
[Tile大小]
每个Tile是256×256的 jpg 图片
[墨卡托投影(Mercator projection)]
因为墨卡托投影,上面的算法必须要修正;在墨卡托投影中,两条并行线之间的距离不是衡定的,因此,一个Tile描绘的角度依赖于垂直位置。
下面的代码根据纬度计算垂直位置:
using Mercator projection formula</summary>*/
private int getMercatorLatitude(double lati)
{
double maxlat = Math.PI;
double lat = lati;
if (lat > 90) lat = lat - 180;
if (lat < -90) lat = lat + 180;
// conversion degre=>radians
double phi = Math.PI * lat / 180;
double res;
//double temp = Math.Tan(Math.PI / 4 - phi / 2);
//res = Math.Log(temp);
res = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
double maxTileY = Math.Pow(2, zoom);
int result = (int)(((1 - res / maxlat) / 2) * (maxTileY));
return (result);
}
[覆盖区]
理论上,纬度应该从-90到90,但是由于墨卡托投影存在,极点被投影到无穷点上,所以覆盖的区域小于-90到90。
[保护]
Google 地图使用了一个保护机制,以保证服务器的质量。如果一个IP的请求次数过多,它会被加到黑名单,并提示一个很友好的消息:(
We're sorry... ... but your query looks similar to automated requests from a computer virus or spyware application. To protect our users, we can't process your request right now. We'll restore your access as quickly as possible, so try again soon. In the meantime, if you suspect that your computer or network has been infected, you might want to run a virus checker or spyware remover to make sure that your systems are free of viruses and other spurious software. We apologize for the inconvenience, and hope we'll see you again on Google.
To avoid being blacklisted, developers should use a caching mechanism if possible...
[例子]
全球图片的URL,http://kh0.google.com/kh?n=404&v=8&t=t
4个对应的象限如下:(注意,4个服务器的名字进行负载平衡)
http://kh0.google.com/kh?n=404&v=8&t=tq
http://kh1.google.com/kh?n=404&v=8&t=tr
http://kh2.google.com/kh?n=404&v=8&t=ts
http://kh3.google.com/kh?n=404&v=8&t=tt
(处理了一下4幅图像合并到一个)
附件:/Files/dotnetdoor/GoogleMapCs.rar
第二篇:[源代码]如何在你的程序中使用Google地图资源(二) - 地区名称对应地理坐标
原文地址:http://bbs.msproject.cn/default.aspx?g=posts&t=223
[翻译]
Pascal Buirey著How Google Map Works (part2): The geocoder
如何使用Google Geocoder获取地区名称对应的地理坐标
[简介]
在发现如何通过地理坐标获得图片之后(任何在你的程序中使用Google地图资源 ××链接××),我想研究下一个Google地图的功能:geocoder。Geocoder是一个服务,允许你通过一个地区的名称获得其所在地理坐标(经度纬度)。本文将向你解释这些。
[URL请求]
为了向Google请求坐标,你需要构建Google能够认识的"问题"。这个"问题"URL可以表述成下面的样子:
http://maps.google.com/maps 将会把你的请求提交给Geocoder服务,其中的output=kml参数,告诉Google给一个简单的可理解的回答,q=my_street_name 参数表明你需要哪个地方的信息。
[Google的答案]
我发现了两个可能的答案:如果地区名称很精确,Google会发给你它的坐标。如果Google需要进一步精确位置,它会发给你一个地区名称的列表,然后你必须选择列表里的确定值,再次请求。最终的答案的XML文件如下:
<kml xmlns="http://earth.google.com/kml/2.0">
<Placemark>
<name>New York, NY</name>
<address>New York, NY</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
<Point>
<coordinates>-74.007130,40.714490,0</coordinates>
</Point>
<LookAt>
<longitude>-74.007130</longitude>
<latitude>40.714490</latitude>
<range>64586.917969</range>
</LookAt>
</Placemark>
</kml>
如果Google需要更精确的名称,得到的XML会是:
<kml xmlns="http://earth.google.com/kml/2.0">
<Folder>
<name>Did you mean:</name>
<open></open>
<Placemark>
<name>Paris, Lamar, Texas, United States</name>
<address>Paris, Lamar, Texas, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Henry, Tennessee, United States</name>
<address>Paris, Henry, Tennessee, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Edgar, Illinois, United States</name>
<address>Paris, Edgar, Illinois, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Bourbon, Kentucky, United States</name>
<address>Paris, Bourbon, Kentucky, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Logan, Arkansas, United States</name>
<address>Paris, Logan, Arkansas, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Monroe, Missouri, United States</name>
<address>Paris, Monroe, Missouri, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Mecosta, Michigan, United States</name>
<address>Paris, Mecosta, Michigan, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Bear Lake, Idaho, United States</name>
<address>Paris, Bear Lake, Idaho, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Stark, Ohio, United States</name>
<address>Paris, Stark, Ohio, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
<Placemark>
<name>Paris, Lafayette, Mississippi, United States</name>
<address>Paris, Lafayette, Mississippi, United States</address>
<styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
</Placemark>
</Folder>
</kml>
本文中的例子是采用C#写的允许于.NET Framework。
附件:
/Files/dotnetdoor/GoogleGeocoder.rar