9 Answers, 1 is accepted
You can use a custom map provider to display a map using WMS-based map server.
I have attached the CustomEnvinsaMapProvider class. You should change the TileUrlFormat template at top of this class before you can use it.
Best wishes,
Andrey Murzov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
I have attached new version of WMS custom provider which inherits the TileMapSource and TiledProvider classes.
Greetings,
Andrey Murzov
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Hello,
I'm using the latest example code for connecting to a Spanish WMS.
Everything works fine except that when the zoom is great, the calculations performed for the BBOX (XMIN, YMIN, XMAX, YMAX) is flawed and that WMS does not give me the right images.
You might say it does not return the correct values ​​when the zoom is great?
If you want to test the WMS I use, TileUrlFormat is:
To view the map should be located in Spain.
Thanks and sorry for my English
I found the solution!
I use another function found in http://alastaira.wordpress.com/2011/01/07/accessing-a-wms-tile-server-from-bing-maps-v7/ to convert the QuadKey in BBox
The final class will read:
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);
}
}
The tiles which can be used in custom provider should be compatible with the DeepZoom concept. The tiles should have the same size for different zoom levels. Also one tile from the previous zoom level should be covered by FOUR tiles from next zoom level. i.e. it should be 1 tile for level 0, 4 tiles for level 1 and etc.
It looks like the tile images on this server for levels 1-4 have not been generated according to these rules.
You can restrict the zooming using the RadMap.MinZoomLevel property. For more information you can take a look at the following documentation topic:
http://www.telerik.com/help/silverlight/radmap-howto-limit-panning-zooming-region.html
All the best,
Andrey Murzov
the Telerik team
I am making use of the provider you supplied
WMSCustomProvider.zip,
However the tiles are marginally out of alignment see attached screenshot. It happens at all zoom levels.
I'm hoping there is a quick fix for this...
Thanks,
It is quite difficult to say what is wrong with your tile server without URL which we can use to test provider. At the first glance the images on your server do not corresponds to the Mercator projection.
If you provide us with URI to access your WMS server then we can try it and check what is wrong. Also, the code you are using is quite old. There is built in implementation of the WMS map provider in the RadMap which uses another approach to get tiles. Could you, please, try it with your server?
Regards,
Andrey Murzov
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
I will log a ticket through the help centre as the URI contains sensitive access details.