首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Telerik Map + WMS

Telerik Map + WMS
EN

Stack Overflow用户
提问于 2012-03-19 19:47:32
回答 1查看 1.1K关注 0票数 1

我正在集成一个WMS与Telerik地图。在Telerik论坛中,我发现了一些示例代码,它们可以正常工作,直到缩放效果很好,但执行计算是错误的,因为MaxX和MinX返回相同的值,Miny和Maxy返回相同的值。我不太理解QuadKey,BBox,Tilex,Tiley的功能...这样就不会纠正代码。这里我把你的论坛telerik中提供的示例代码放在这里。看看是否有人看到了这个错误的位置。

代码语言:javascript
复制
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的值也是不同的。

我不知道这是否会成为小数和双精度的问题。

感谢并为我的英语道歉

EN

回答 1

Stack Overflow用户

发布于 2012-03-21 01:28:25

我找到解决方案了!我使用http://alastaira.wordpress.com/2011/01/07/accessing-a-wms-tile-server-from-bing-maps-v7/中的另一个函数将QuadKey转换为BBox,最终的类将为:

代码语言:javascript
复制
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);
    }


}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9769581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档