我正在将WMS与Telerik地图集成。在Telerik论坛中,我找到了一些正常工作的示例代码,直到缩放很好并且执行计算不正确,因为MaxX和MinX返回相同的值,而Miny和Maxy返回相同的值。 我不太了解QuadKey,BBox,Tilex,Tiley的功能......以及不正确的代码。在这里,我将您的论坛telerik中提供的示例代码放入。 看看是否有人看到了这个错误。
public class WMSCustomSource : TiledMapSource
{
private const string TileUrlFormat = @"http://www1.sedecatastro.gob.es/Cartografia/WMS/ServidorWMS.aspx?SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&BBOX={0},{1},{2},{3}&WIDTH={4}&HEIGHT={4}&Layers=Catastro&TRANSPARENT=TRUE&STYLES=PositionStyle&FORMAT=image/png";
private const int TileSize = 256;
/// <summary>
/// Earth Circumference.
/// </summary>
private double earthCircumference;
private double halfEarthCircumference;
private double earthRadius;
/// <summary>
/// Initializes a new instance of the OSMCustomSource class.
/// </summary>
public WMSCustomSource(ISpatialReference spatialReference)
: base(1, 20, TileSize, TileSize)
{
this.earthRadius = spatialReference.SpheroidRadius;
this.earthCircumference = this.earthRadius * 2 * Math.PI;
this.halfEarthCircumference = this.earthCircumference / 2d;
}
/// <summary>
/// Initialize provider.
/// </summary>
public override void Initialize()
{
// Raise provider intialized event.
this.RaiseIntializeCompleted();
}
/// <summary>
/// Returns the bounding BBox for a grid square represented by the given quad key
/// </summary>
/// <param name="quadKey"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="zoomLevel"></param>
/// <returns></returns>
private BBOX ConvertQuadKeyToBBox(string quadKey, int x, int y, int zoomLevel)
{
char c = quadKey[0];
int tileSize = 2 << (18 - zoomLevel - 1);
if (c == '0')
{
y = y - tileSize;
}
else if (c == '1')
{
y = y - tileSize;
x = x + tileSize;
}
else if (c == '3')
{
x = x + tileSize;
}
if (quadKey.Length > 1)
{
return ConvertQuadKeyToBBox(quadKey.Substring(1), x, y, zoomLevel + 1);
}
return new BBOX(x, y, tileSize, tileSize);
}
private BBOX ConvertQuadKeyToBBox(string quadKey)
{
const int x = 0;
const int y = 262144;
return ConvertQuadKeyToBBox(quadKey, x, y, 1);
}
/// <summary>
/// Converts radians to degrees
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private double RadiansToDegrees(double radians)
{
return radians / Math.PI * 180d;
}
/// <summary>
/// Converts a grid row to Latitude
/// </summary>
/// <param name="y"></param>
/// <param name="zoom"></param>
/// <returns></returns>
private double ConvertYToLatitude(int y, int zoom)
{
double arc = this.earthCircumference / ((double)(1 << zoom) * (double)TileSize);
double metersY = this.halfEarthCircumference - ((double)y * (double)TileSize * arc);
double a = Math.Exp(metersY * 2d / this.earthRadius);
double result = RadiansToDegrees(Math.Asin((a - 1d) / (a + 1d)));
return result;
}
/// <summary>
/// Converts a grid column to Longitude
/// </summary>
/// <param name="x"></param>
/// <param name="zoom"></param>
/// <returns></returns>
private double ConvertXToLongitude(int x, int zoom)
{
double arc = this.earthCircumference / ((double)(1 << zoom) * (double)TileSize);
double metersX = ((double)x * (double)TileSize * arc) - this.halfEarthCircumference;
double result = RadiansToDegrees(metersX / this.earthRadius);
return result;
}
private static string GetQuadKey(int tileX, int tileY, int levelOfDetail)
{
var 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>
/// Gets the image URI.
/// </summary>
/// <param name="tileLevel">Tile level.</param>
/// <param name="tilePositionX">Tile X.</param>
/// <param name="tilePositionY">Tile Y.</param>
/// <returns>URI of image.</returns>
protected override Uri GetTile(int tileLevel, int tilePositionX, int tilePositionY)
{
int zoomLevel = ConvertTileToZoomLevel(tileLevel);
string quadKey = GetQuadKey(tilePositionX, tilePositionY, zoomLevel);
BBOX boundingBox = ConvertQuadKeyToBBox(quadKey);
**double longitude = ConvertXToLongitude(boundingBox.x, 18);
double latitude = ConvertYToLatitude(boundingBox.y, 18);
double longitude2 = ConvertXToLongitude(boundingBox.x + boundingBox.width, 18);
double latitude2 = ConvertYToLatitude(boundingBox.y - boundingBox.height, 18);**
string url = string.Format(CultureInfo.InvariantCulture, TileUrlFormat,
longitude, latitude, longitude2, latitude2, TileSize);
return new Uri(url);
}
/// <summary>
/// The box of the bounds of a tile
/// </summary>
private class BBOX
{
public int x;
public int y;
public int width;
public int height;
public BBOX(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
}
当缩放高时我返回相同值的函数是: ConvertYToLatitude和ConvertXToLongitude。虽然我提供给X1和X2的值是不同的。并且Y1和Y2的值也不同。
我不知道十进制和双精度是否有问题。
谢谢,对不起我的英文
答案 0 :(得分:2)
我找到了解决方案! 我使用http://alastaira.wordpress.com/2011/01/07/accessing-a-wms-tile-server-from-bing-maps-v7/中的另一个函数来转换BBox中的QuadKey 最后的课程将为:
public class WMSCustomSource : TiledMapSource
{
private const string TileUrlFormat = @"http://www1.sedecatastro.gob.es/Cartografia/WMS/ServidorWMS.aspx?SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&BBOX={0}&WIDTH={1}&HEIGHT={1}&Layers=Catastro&TRANSPARENT=TRUE&STYLES=PositionStyle&FORMAT=image/png";
private const int TileSize = 256;
/// <summary>
/// Earth Circumference.
/// </summary>
private double earthCircumference;
private double halfEarthCircumference;
private double earthRadius;
/// <summary>
/// Initializes a new instance of the OSMCustomSource class.
/// </summary>
public WMSCustomSource(ISpatialReference spatialReference)
: base(1, 20, TileSize, TileSize)
{
this.earthRadius = spatialReference.SpheroidRadius;
this.earthCircumference = this.earthRadius * 2 * Math.PI;
this.halfEarthCircumference = this.earthCircumference / 2d;
}
/// <summary>
/// Initialize provider.
/// </summary>
public override void Initialize()
{
// Raise provider intialized event.
this.RaiseIntializeCompleted();
}
public string QuadKeyToBBox(string quadKey)
{
int zoom = quadKey.Length;
int x = 0, y = 0;
// Work out the x and y position of this tile
for (int i = zoom; i > 0; i--)
{
int mask = 1 << (i - 1);
switch (quadKey[zoom - i])
{
case '0':
break;
case '1':
x |= mask;
break;
case '2':
y |= mask;
break;
case '3':
x |= mask;
y |= mask;
break;
default:
throw new ArgumentException("Invalid QuadKey digit sequence.");
}
}
// From the grid position and zoom, work out the min and max Latitude / Longitude values of this tile
double W = (float)(x * TileSize) * 360 / (float)(TileSize * Math.Pow(2, zoom)) - 180;
double N = (float)Math.Asin((Math.Exp((0.5 - (y * TileSize) / (TileSize) / Math.Pow(2, zoom)) * 4 * Math.PI) - 1) / (Math.Exp((0.5 - (y * TileSize) / 256 / Math.Pow(2, zoom)) * 4 * Math.PI) + 1)) * 180 / (float)Math.PI;
double E = (float)((x + 1) * TileSize) * 360 / (float)(TileSize * Math.Pow(2, zoom)) - 180;
double S = (float)Math.Asin((Math.Exp((0.5 - ((y + 1) * TileSize) / (TileSize) / Math.Pow(2, zoom)) * 4 * Math.PI) - 1) / (Math.Exp((0.5 - ((y + 1) * TileSize) / 256 / Math.Pow(2, zoom)) * 4 * Math.PI) + 1)) * 180 / (float)Math.PI;
double[] bounds = new double[] { W, S, E, N };
// Return a comma-separated string of the bounding coordinates
return string.Join(",", Array.ConvertAll(bounds, s => s.ToString().Replace(',','.')));
}
/// <summary>
/// Converts radians to degrees
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private double RadiansToDegrees(double radians)
{
return radians / Math.PI * 180d;
}
/// <summary>
/// Converts a grid row to Latitude
/// </summary>
/// <param name="y"></param>
/// <param name="zoom"></param>
/// <returns></returns>
private double ConvertYToLatitude(int y, int zoom)
{
double arc = this.earthCircumference / ((double)(1 << zoom) * (double)TileSize);
double metersY = this.halfEarthCircumference - ((double)y * (double)TileSize * arc);
double a = Math.Exp(metersY * 2d / this.earthRadius);
double result = RadiansToDegrees(Math.Asin((a - 1d) / (a + 1d)));
return result;
}
/// <summary>
/// Converts a grid column to Longitude
/// </summary>
/// <param name="x"></param>
/// <param name="zoom"></param>
/// <returns></returns>
private double ConvertXToLongitude(int x, int zoom)
{
double arc = this.earthCircumference / ((double)(1 << zoom) * (double)TileSize);
double metersX = ((double)x * (double)TileSize * arc) - this.halfEarthCircumference;
double result = RadiansToDegrees(metersX / this.earthRadius);
return result;
}
private static string GetQuadKey(int tileX, int tileY, int levelOfDetail)
{
var 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>
/// Gets the image URI.
/// </summary>
/// <param name="tileLevel">Tile level.</param>
/// <param name="tilePositionX">Tile X.</param>
/// <param name="tilePositionY">Tile Y.</param>
/// <returns>URI of image.</returns>
protected override Uri GetTile(int tileLevel, int tilePositionX, int tilePositionY)
{
int zoomLevel = ConvertTileToZoomLevel(tileLevel);
string quadKey = GetQuadKey(tilePositionX, tilePositionY, zoomLevel);
**string bbox = QuadKeyToBBox(quadKey);**
string url = string.Format(CultureInfo.InvariantCulture, TileUrlFormat, bbox, TileSize);
return new Uri(url);
}
}