2012-03-19 3 views
1

Я интегрирую WMS с картой Telerik. На форумах Telerik я нашел пример кода, который работает корректно до тех пор, пока масштаб не станет большим, и выполнение вычисления неверно, потому что MaxX и MinX возвращают одно и то же значение, а Miny и Maxy возвращают одинаковое значение. Я не совсем понимаю работу QuadKey, BBox, Tilex, Tiley ... и не исправляю код. Здесь я поставил код примера, представленный на вашем форуме telerik. Посмотрите, видит ли кто-нибудь эту ошибку.Telerik Map + WMS

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. Хотя значение I для X1 и X2 отличается. И значение Y1 и Y2 также различно.

Я не знаю, может ли быть проблема с десятичной и двойной.

Спасибо и извините за мой английский

+0

Хосе, опубликовать свое решение как ответ ..... – Simon

+0

OK Извините! решение опубликовано! – JoseMancebo

ответ

2

Я нашел решение! я использую другую функцию, найденную в http://alastaira.wordpress.com/2011/01/07/accessing-a-wms-tile-server-from-bing-maps-v7/ для преобразования QuadKey в BBox Окончательный класс будет читать:

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); 
    } 


} 
Смежные вопросы