原文链接:http://msdn.microsoft.com/en-us/library/bb259689.aspx
Bing Maps provides a world map thatusers can directly manipulate to pan and zoom. To make this interaction as fastand responsive as possible, we chose to pre-render the map at many differentlevels of detail, and to cut each map intotiles for quick retrieval anddisplay. This document describes the projection, coordinate systems, andaddressing scheme of the map tiles, which collectively are called the Bing MapsTile System.
Bing地图提供了用户可以直接交互的世界地图。为了使地图的交互响应速度进可能的快,
我们选择预渲染不同等级的地图(Lod),并且为了快速检索和显示将地图切割到不同的瓦片
这篇文档描述了投影,坐标系统和地图瓦片的定位方法,这个地图瓦片被称作BMTS,Bing地图瓦片体系。
To make the map seamless, and to ensure that aerialimages from different sources line up properly, we have to use a singleprojection for the entire world. We chose to use the Mercatorprojection, which looks like this:
为了实现地图的无缝,保证不同数据源的一系列影像正常的上线,我们不得不给整个世界选择一个统一的投影,这里选择墨卡托投影,形式如下:
Although the Mercator projection significantly distortsscale and area (particularly near the poles), it has two important propertiesthat outweigh the scale distortion:
尽管墨卡托有显著的尺度形变和面积形变(尤其是近极地地区),它有两个比长度形变更重要的属性
它是一个正形投影(等角投影),具有保持形状。这在显示航空影像时是尤其重要的。因为我们想避免建筑物形状的形变。方形的建筑物应该看着是方形的,不是长方形的。
它是圆柱投影,北极和南极总是指向上下。东西总是指向左右。
Since the Mercator projection goes to infinity at thepoles, it doesn’t actually show the entire world. Using a square aspect ratiofor the map, the maximum latitude shown is approximately 85.05 degrees.
To simplify the calculations, we use the spherical formof this projection, not the ellipsoidal form. Since the projection is used onlyfor map display, and not for displaying numeric coordinates, we don’t need theextra precision of an ellipsoidal projection. The spherical projection causesapproximately 0.33% scale distortion in the Y direction, which is not visuallynoticeable.
因为墨卡托投影在两极地区趋于无限,并不显示整个世界。为地图设定一个square比例,最大的显示纬度接近85.05度。为了简化计算,我们采用球进行投影,不是椭球。由于投影是为了地图的显示,不是为了展示坐标数值,我们没有必要采用高精度的椭球投影。球形投影产生大约0.33%的y方向的长度变形,这不会明显的可以察觉。
In addition to the projection, the ground resolution ormap scale must be specified in order to render a map. At the lowest level ofdetail (Level 1), the map is 512 x 512 pixels. At each successive level ofdetail, the map width and height grow by a factor of 2: Level 2 is 1024 x 1024pixels, Level 3 is 2048 x 2048 pixels, Level 4 is 4096 x 4096 pixels, and soon. In general, the width and height of the map (in pixels) can be calculated as:
mapwidth = map height = 256 * 2 level pixels
除了投影之外,为了展示地图,地面分辨率和地图比例尺必须被定义。在最低一级Level1,地图是512x512像素的。在每个Lod系列,地图的宽度和高度按照2倍比例增长:Level2是1024x1024像素,Level3是2048x2048像素,level4是4096x4096像素,依次…通常,宽度和高度的计算公式如下:
The ground resolution indicates thedistance on the ground that’s represented by a single pixel in the map. Forexample, at a ground resolution of 10 meters/pixel, each pixel represents aground distance of 10 meters. The ground resolution varies depending on thelevel of detail and the latitude at which it’s measured. Using an earth radiusof 6378137 meters, the ground resolution (in meters per pixel) can becalculated as:
groundresolution = cos(latitude * pi/180) * earth circumference / map width
= (cos(latitude* pi/180) * 2 * pi * 6378137 meters) / (256 * 2 level pixels)
地面分辨率指示地图上一个象素代表地面距离。例如,地面分辨率10m/pixel,每个像素代表地面距离10m。地面分辨率变量依赖被量测的Lod和纬度。采用地球半径6378137米,地面分辨率(m/pixel)按如下公式计算:
The map scale indicates the ratiobetween map distance and ground distance, when measured in the same units. Forinstance, at a map scale of 1 : 100,000, each inch on the map represents aground distance of 100,000 inches. Like the ground resolution, the map scalevaries with the level of detail and the latitude of measurement. It can becalculated from the ground resolution as follows, given the screen resolutionin dots per inch, typically 96 dpi:
mapscale = 1 : ground resolution * screen dpi / 0.0254 meters/inch
= 1: (cos(latitude * pi/180) * 2 * pi * 6378137 * screen dpi) / (256 * 2 level * 0.0254)
地图比例尺是指图上距离和实际距离的比值,以同样的测量单位。
例如,地图比例尺1 : 100,000,每英寸的地图距离代表地面100,000英寸的距离。和地面分辨率一样,地图比例尺随Lod和纬度变化。可以根据地面分辨率计算,方法如下:已知屏幕分辨率每英寸像素点数,一般为96dpi:
This table shows each of these values at each level ofdetail, as measured at the Equator. (Note that the groundresolution and map scale also vary with the latitude, as shown in the equationsabove, but not shown in the table below.)
下表显示了不同Lod在地球赤道测量的地面分辨率和比例尺的值。(提醒:地面分辨率和地图比例尺还随纬度变化,如上面的方程那样,但没有在下面的表格中显示。)
Level of Detail |
Map Width and Height (pixels) |
Ground Resolution (meters / pixel) |
Map Scale |
1 |
512 |
78,271.5170 |
1 : 295,829,355.45 |
2 |
1,024 |
39,135.7585 |
1 : 147,914,677.73 |
3 |
2,048 |
19,567.8792 |
1 : 73,957,338.86 |
4 |
4,096 |
9,783.9396 |
1 : 36,978,669.43 |
5 |
8,192 |
4,891.9698 |
1 : 18,489,334.72 |
6 |
16,384 |
2,445.9849 |
1 : 9,244,667.36 |
7 |
32,768 |
1,222.9925 |
1 : 4,622,333.68 |
8 |
65,536 |
611.4962 |
1 : 2,311,166.84 |
9 |
131,072 |
305.7481 |
1 : 1,155,583.42 |
10 |
262,144 |
152.8741 |
1 : 577,791.71 |
11 |
524,288 |
76.4370 |
1 : 288,895.85 |
12 |
1,048,576 |
38.2185 |
1 : 144,447.93 |
13 |
2,097,152 |
19.1093 |
1 : 72,223.96 |
14 |
4,194,304 |
9.5546 |
1 : 36,111.98 |
15 |
8,388,608 |
4.7773 |
1 : 18,055.99 |
16 |
16,777,216 |
2.3887 |
1 : 9,028.00 |
17 |
33,554,432 |
1.1943 |
1 : 4,514.00 |
18 |
67,108,864 |
0.5972 |
1 : 2,257.00 |
19 |
134,217,728 |
0.2986 |
1 : 1,128.50 |
20 |
268,435,456 |
0.1493 |
1 : 564.25 |
21 |
536,870,912 |
0.0746 |
1 : 282.12 |
22 |
1,073,741,824 |
0.0373 |
1 : 141.06 |
23 |
2,147,483,648 |
0.0187 |
1 : 70.53 |
Having chosen the projection and scale to use at eachlevel of detail, we can convert geographic coordinates into pixel coordinates.Since the map width and height is different at each level, so are the pixelcoordinates. The pixel at the upper-left corner of the map always has pixelcoordinates (0, 0). The pixel at the lower-right corner of the map haspixel coordinates (width-1, height-1), or referring to the equations in theprevious section, (256 * 2level–1, 256 * 2level–1). Forexample, at level 3, the pixel coordinates range from (0, 0) to(2047, 2047), like this:
选择了投影和不同Lod的比例尺,我们可以将地理坐标转换到像素坐标。由于每级地图的宽度和高度不同,同样的像素坐标也不相同。左上角的像素坐标总是(0,0)。右下角的地图象素坐标为(width-1,heght-1),或者参照上一节的方程,。例如,在Level3,象素坐标的范围是(0.0)到(2047,2047),如下:
Given latitude and longitude in degrees, and the level ofdetail, the pixel XY coordinates can be calculated as follows:
sinLatitude= sin(latitude * pi/180)
pixelX= ((longitude + 180) / 360) * 256 * 2 level
pixelY= (0.5 – log((1 + sinLatitude) / (1 – sinLatitude)) / (4 * pi)) * 256 * 2 level
给定经纬度和Lod等级,像素坐标可以按如下方式计算:
The latitude and longitude are assumed to be on the WGS84 datum. Even though Bing Maps uses a spherical projection, it’s important toconvert all geographic coordinates into a common datum, and WGS 84 was chosento be that datum. The longitude is assumed to range from -180 to +180 degrees,and the latitude must be clipped to range from -85.05112878 to 85.05112878.This avoids a singularity at the poles, and it causes the projected map to besquare.
经纬度假定在WGS84基准面。尽管Bing地图采用墨卡托投影,将地理坐标转换到通常的基准面是十分重要的,WGS84被作为基准面。经度范围-180到180,纬度范围必须被裁减在范围(-85.05112878 , 85.05112878)。这样可以避免极地的异常,它使投影的地图为方形的。
To optimize the performance of map retrieval and display,the rendered map is cut into tiles of 256 x 256 pixels each. As the number ofpixels differs at each level of detail, so does the number of tiles:
mapwidth = map height = 2 level tiles
为了优化地图的检索和显示,渲染地图被切割成256x256像素。不同Lod等级的象素数目不同,同样瓦片数目也不相同:
Each tile is given XY coordinates ranging from (0, 0) in theupper left to (2level–1, 2level–1) in the lower right.For example, at level 3 the tile coordinates range from (0, 0) to (7, 7) asfollows:
每个瓦片给定xy坐标范围左上角(0, 0),右下角(2level–1,2level–1)。例如Level3的瓦片坐标范围(0,0)到(7, 7)
Given a pair of pixel XY coordinates, you can easilydetermine the tile XY coordinates of the tile containing that pixel:
tileX= floor(pixelX / 256)
tileY= floor(pixelY / 256)
给定一组像素坐标XY,可以容易的计算包含该像素的瓦片的xy坐标。
To optimize the indexing and storage of tiles, thetwo-dimensional tile XY coordinates are combined into one-dimensional stringscalled quadtree keys, or “quadkeys” for short. Each quadkey uniquely identifiesa single tile at a particular level of detail, and it can be used as an key incommon database B-tree indexes. To convert tile coordinates into a quadkey, thebits of the Y and X coordinates are interleaved, and the result is interpretedas a base-4 number (with leading zeros maintained) and converted into a string.For instance, given tile XY coordinates of (3, 5) at level 3, the quadkey isdetermined as follows:
tileX= 3 = 011 2
tileY= 5 = 101 2
quadkey= 100111 2 = 213 4 = “213”
为了优化瓦片存储的索引,二维的瓦片坐标被包含在一维的字符串中,称为“四叉树键”,或者简称“四叉键”。每个四叉键唯一的定义了在特定Lod级别的一个瓦片,可以被用来作为通用数据库的b-tree索引。为了将瓦片坐标转换到四叉键,y和x坐标的位是隔行读取的,结果形成了4进制数,转换成字符串。例如,给定xy坐标(3, 5) 等级level 3,四叉键为下值:
Quadkeys have several interesting properties. First, thelength of a quadkey (the number of digits) equals the level of detail of thecorresponding tile. Second, the quadkey of any tile starts with the quadkey ofits parent tile (the containing tile at the previous level). As shown in theexample below, tile 2 is the parent of tiles 20 through 23, and tile 13 is theparent of tiles 130 through 133:
四叉键有一些有趣的属性。
首先,四叉键的长度等于Lod对应的瓦片等级。
第二,任何瓦片的四叉键开始于其父亲瓦片的四叉键。如下所示,瓦片2是瓦片20到23的父节点,瓦片13是瓦片130到133的父节点。
Finally, quadkeys provide a one-dimensional index keythat usually preserves the proximity of tiles in XY space. In other words, twotiles that have nearby XY coordinates usually have quadkeys that are relativelyclose together. This is important for optimizing database performance, becauseneighboring tiles are usually requested in groups, and it’s desirable to keepthose tiles on the same disk blocks, in order to minimize the number of diskreads.
最后,四叉键提供了一维的索引键,通常保存了邻近瓦片的XY空间。换言之,两个瓦片具有相邻的xy坐标通常具有相邻的四叉键。这对于优化数据库性能十分重要,因为相邻的瓦片通常会作为组进行请求,这样的描述可以保证这些瓦片在相同的硬盘块,减少磁盘的读取次数。
The following sample C# code illustrates how to implementthe functions described in this document. These functions can be easilytranslated into other programming languages as needed.
如下的C#代码阐述了如何实现本文的方法,这些方法可以很容易的转换到其他语言。
//------------------------------------------------------------------------------
//
// Copyright (c) 2006-2009 MicrosoftCorporation. All rights reserved.
//
//------------------------------------------------------------------------------
usingSystem;
usingSystem.Text;
namespaceMicrosoft.MapPoint
{
static class TileSystem
{
private const double EarthRadius =6378137;
private const double MinLatitude =-85.05112878;
private const double MaxLatitude =85.05112878;
private const double MinLongitude =-180;
private const double MaxLongitude =180;
///
/// Clips a number to the specifiedminimum and maximum values.
///
/// Thenumber to clip.
/// Minimum allowable value.
/// Maximum allowable value.
/// The clippedvalue.
private static double Clip(double n,double minValue, double maxValue)
{
return Math.Min(Math.Max(n,minValue), maxValue);
}
///
/// Determines the map width and height(in pixels) at a specified level
/// of detail.
///
/// Level of detail, from 1 (lowest detail)
/// to 23 (highestdetail).
/// The map width andheight in pixels.
public static uint MapSize(intlevelOfDetail)
{
return (uint) 256 <
/// Determines the ground resolution(in meters per pixel) at a specified
/// latitude and level of detail.
///
/// Latitude (in degrees) at which to measure the
/// ground resolution.
/// Level of detail, from 1 (lowest detail)
/// to 23 (highestdetail).
/// The groundresolution, in meters per pixel.
public static doubleGroundResolution(double latitude, int levelOfDetail)
{
latitude = Clip(latitude,MinLatitude, MaxLatitude);
return Math.Cos(latitude * Math.PI/ 180) * 2 * Math.PI * EarthRadius / MapSize(levelOfDetail);
}
///
/// Determines the map scale at aspecified latitude, level of detail,
/// and screen resolution.
///
/// Latitude (in degrees) at which to measure the
/// map scale.
/// Level of detail, from 1 (lowest detail)
/// to 23 (highestdetail).
/// Resolution of the screen, in dots perinch.
/// The map scale,expressed as the denominator N of the ratio 1 : N.
public static double MapScale(doublelatitude, int levelOfDetail, int screenDpi)
{
return GroundResolution(latitude,levelOfDetail) * screenDpi / 0.0254;
}
///
/// Converts a point from latitude/longitudeWGS-84 coordinates (in degrees)
/// into pixel XY coordinates at aspecified level of detail.
///
/// Latitude of the point, in degrees.
/// Longitude of the point, in degrees.
/// Level of detail, from 1 (lowest detail)
/// to 23 (highestdetail).
/// Output parameter receiving the X coordinate inpixels.
/// Output parameter receiving the Y coordinate inpixels.
public static voidLatLongToPixelXY(double latitude, double longitude, int levelOfDetail, out intpixelX, out int pixelY)
{
latitude = Clip(latitude,MinLatitude, MaxLatitude);
longitude = Clip(longitude,MinLongitude, MaxLongitude);
double x = (longitude + 180) / 360;
double sinLatitude =Math.Sin(latitude * Math.PI / 180);
double y = 0.5 - Math.Log((1 +sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
uint mapSize =MapSize(levelOfDetail);
pixelX = (int) Clip(x * mapSize +0.5, 0, mapSize - 1);
pixelY = (int) Clip(y * mapSize +0.5, 0, mapSize - 1);
}
///
/// Converts a pixel from pixel XYcoordinates at a specified level of detail
/// into latitude/longitude WGS-84coordinates (in degrees).
///
/// X coordinate of the point, in pixels.
/// Y coordinates of the point, in pixels.
/// Level of detail, from 1 (lowest detail)
/// to 23 (highest detail).
/// Output parameter receiving the latitude indegrees.
/// Output parameter receiving the longitude indegrees.
public static void PixelXYToLatLong(intpixelX, int pixelY, int levelOfDetail, out double latitude, out doublelongitude)
{
double mapSize =MapSize(levelOfDetail);
double x = (Clip(pixelX, 0, mapSize- 1) / mapSize) - 0.5;
double y = 0.5 - (Clip(pixelY, 0, mapSize- 1) / mapSize);
latitude = 90 - 360 *Math.Atan(Math.Exp(-y * 2 * Math.PI)) / Math.PI;
longitude = 360 * x;
}
///
/// Converts pixel XY coordinates intotile XY coordinates of the tile containing
/// the specified pixel.
///
/// Pixel X coordinate.
/// Pixel Y coordinate.
/// Output parameter receiving the tile Xcoordinate.
/// Output parameter receiving the tile Ycoordinate.
public static void PixelXYToTileXY(intpixelX, int pixelY, out int tileX, out int tileY)
{
tileX = pixelX / 256;
tileY = pixelY / 256;
}
///
/// Converts tile XY coordinates intopixel XY coordinates of the upper-left pixel
/// of the specified tile.
///
/// Tile X coordinate.
/// Tile Y coordinate.
/// Output parameter receiving the pixel Xcoordinate.
/// Output parameter receiving the pixel Ycoordinate.
public static void TileXYToPixelXY(inttileX, int tileY, out int pixelX, out int pixelY)
{
pixelX = tileX * 256;
pixelY = tileY * 256;
}
///
/// Converts tile XY coordinates into aQuadKey at a specified level of detail.
///
/// Tile X coordinate.
/// Tile Y coordinate.
/// Level of detail, from 1 (lowest detail)
/// to 23 (highestdetail).
/// A string containingthe QuadKey.
public static stringTileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
{
StringBuilder quadKey = newStringBuilder();
for (int i = levelOfDetail; i >0; i--)
{
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0)
{
digit++;
}
if ((tileY & mask) != 0)
{
digit++;
digit++;
}
quadKey.Append(digit);
}
return quadKey.ToString();
}
///
/// Converts a QuadKey into tile XYcoordinates.
///
/// QuadKey of the tile.
/// Output parameter receiving thetile X coordinate.
/// Output parameter receiving the tile Ycoordinate.
/// Output parameter receiving the level ofdetail.
public static voidQuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out intlevelOfDetail)
{
tileX = tileY = 0;
levelOfDetail = quadKey.Length;
for (int i = levelOfDetail; i > 0;i--)
{
int mask = 1 << (i - 1);
switch (quadKey[levelOfDetail -i])
{
case '0':
break;
case '1':
tileX |= mask;
break;
case '2':
tileY |= mask;
break;
case '3':
tileX |= mask;
tileY |= mask;
break;
default:
throw newArgumentException("Invalid QuadKey digit sequence.");
}
}
}
}
}