瓦片地图坐标相关计算
在给定level下,把行号tileY和列号tileX转换为2进制,然后行列交叉存储,再转换为4进制,即得到了相应的quadkey。譬如Level 3的第6行第4列的Tile计算:tileY = 5 = 101 ,tileX = 3 = 011;quadkey = 100111 = 213(4进制) = “213”。
那么,下面我们给出C#的代码实现
/// <summary>
/// Converts tile XY coordinates into a QuadKey at a specified level of detail.
/// </summary>
/// <param name="tileX">Tile X coordinate.</param>
/// <param name="tileY">Tile Y coordinate.</param>
/// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
/// to 23 (highest detail).</param>
/// <returns>A string containing the QuadKey.</returns>
public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
{
StringBuilder quadKey = new StringBuilder();
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();
}
接下来是反算代码
/// <summary>
/// Converts a QuadKey into tile XY coordinates.
/// </summary>
/// <param name="quadKey">QuadKey of the tile.</param>
/// <param name="tileX">Output parameter receiving the tile X coordinate.</param>
/// <param name="tileY">Output parameter receiving the tile Y coordinate.</param>
/// <param name="levelOfDetail">Output parameter receiving the level of detail.</param>
public static void QuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out int levelOfDetail)
{
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 new ArgumentException("Invalid QuadKey digit sequence.");
}
}
}
上面所讲到的是针对bingmap的情况,googleearth采用QRTS编码,即Q、R、T、S分别代表0、1、2、3,运算方法类似,代码如下
/// <summary> /// 由tileX、tileY和level求解quadkey /// </summary> /// <param name="tileX"></param> /// <param name="tileY"></param> /// <param name="levelOfDetail"></param> /// <returns></returns> private static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail) { var quadKey = new StringBuilder(); for (int i = levelOfDetail; i > 0; i--) { char digit = '0'; //掩码,最高位设为1,其他位设为0 int mask = 1 << (i - 1); //与运算取得tileX的最高位,若为1,则加1 if ((tileX & mask) != 0) { digit++; } //与运算取得tileY的最高位,若为1,则加2 if ((tileY & mask) != 0) { digit++; digit++; } //也即2*y+x quadKey.Append(digit); } return quadKey.ToString(); } protected static string QuadKeyNumberToAlpha(string base4) { return base4.Replace('0', 'q').Replace('1', 'r').Replace('2', 't').Replace('3', 's'); } private static string QuadKeyNumberToAlphaUrl(string url, int tilePositionX, int tilePositionY, int zoom) { string quadKey = TileXYToQuadKey(tilePositionX, tilePositionY, zoom); //获取最后一位,选择4个服务器中的一台 string str3 = quadKey.Substring(quadKey.Length - 1, 1); string str4 = QuadKeyNumberToAlpha(quadKey); url = string.Format(url, str4, str3); return url; }
Google卫星地图是由256x256大小的jpg图片拼接而成,每块图片的URL格式为“http://kh.google.com/kh?v=3&t=trstrq”样。参数v选择4台服务器中的一台,起到均衡负载的作用,参数t是“qrst”4个字符排列而成的字符串。为获取某经纬度的URL,就需要把经纬度转化为“qrst”字符串。 Google卫星地图在zoom=1时,全球就为一个256x256的图片,它的中心经纬度为(0,0),URL为“http://kh.google.com/kh?v=3&t=t”。zoom=2时裂化为4块,每块的编号为:左上”t=tq”,右上”t=tr”,右下“t=ts”,左下”t=tt”。依此类推,每放大一倍,每一小块都裂分为四,从左上到右下顺时针按qrst编号,裂分后的编码为裂分前的编号上小块的编号。
代码如下:
function GetQuadtreeAddress(long, lat) { var PI = 3.1415926535897; var digits = 18; // how many digits precision // now convert to normalized square coordinates // use standard equations to map into mercator projection var x = (180.0 + parseFloat(long)) / 360.0; var y = -parseFloat(lat) * PI / 180; // convert to radians y = 0.5 * Math.log((1+Math.sin(y)) / (1 - Math.sin(y))); y *= 1.0/(2 * PI); // scale factor from radians to normalized y += 0.5; // and make y range from 0 - 1 var quad = "t"; // google addresses start with t var lookup = "qrts"; // tl tr bl br while (digits–) { // make sure we only look at fractional part x -= Math.floor(x); y -= Math.floor(y); quad = quad + lookup.substr((x >= 0.5 ? 1 : 0) + (y >= 0.5 ? 2 : 0), 1); // now descend into that square x *= 2; y *= 2; } return quad; }