Note: This article is submitted by Alexey Zakharov for Silverlight: Write and Win contest.Thanks a lot, Alexey! Hello All, Please drop a comment if you like it.
“It is time to vote now! Please, choose your favorite articles and enter your vote by going to contest page. Thank you!„
Introduction
In this article I'd like to tell you how you can easily create your own Virtual Earth viewer based on Silverlight Deep Zoom technology.
Concept
As you may be already know Silverlight MultiScaleImage control have a property called Source, which type is MultiScaleTileSource. And if you have created simple deep zoom composer project your MultiScaleImage source would be somethig like this:
new DeepZoomImageTileSource(new Uri("GeneratedImages/dzc_output.xml", UriKind.Relative));
In silverlight project generated by deep zoom composer project we already have all functionality to move and zoom our MultiScaleImage.
So all we need to do is to create our own implementation of base MultiScaleTileSource class, which will provide virtual earth image tiles.
Step 1: Virtual earth tile system
All virtual earth image tiles can be get via http using special url format : http://h{0}.ortho.tiles.virtualearth.net/tiles/h{1}.jpeg?g=203 (for arial map) and http://r{0}.ortho.tiles.virtualearth.net/tiles/r{1}.png?g=203 (for road map)
First paramter is number of virtual earth (there are 4 tile servers) tile server and the second is tile quad key.
To transform X Y coordinate into quad key you can ues this function (more information about virtual earth tile system you can find here http://msdn.microsoft.com/en-us/library/bb259689.aspx):
1: /// <summary>
2: /// Converts tile XY coordinates into a QuadKey at a specified level of detail.
3: /// </summary>
4: /// <param name="tileX">Tile X coordinate.</param>
5: /// <param name="tileY">Tile Y coordinate.</param>
6: /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
7: /// to 23 (highest detail).</param>
8: /// <returns>A string containing the QuadKey.</returns>
9: private static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
10: {
11: var quadKey = new StringBuilder();
12: for (int i = levelOfDetail; i > 0; i--)
13: {
14: char digit = '0';
15: int mask = 1 << (i - 1);
16: if ((tileX & mask) != 0)
17: {
18: digit++;
19: }
20: if ((tileY & mask) != 0)
21: {
22: digit++;
23: digit++;
24: }
25: quadKey.Append(digit);
26: }
27: return quadKey.ToString();
28: }
Step 2: Creating of custom MultiScaleTileSource for Virtual earth.
Let's create base tile source for arial and road virtual earth tiles.
To implement your own MultiScaleTileSource you should override GetTileLayers method and use base constructor.
In constructor we will set max image size and size of image tiles. In hex numerical notation max virtual earth image width and height are 0x8000000 and tile width and height are 0x100.
1: /// <summary>
2: /// Setting of tile size and max image size.
3: /// </summary>
4: protected BaseVETileSource()
5: : base(0x8000000, 0x8000000, 0x100, 0x100, 0)
6: {
7: }
Next step is to override GetTileLayers method. It adds image uris for specified zoom level, x and y tile positions. Zoom level of MultiScaleImage is not equal to virtual earth zoom level so we should subtract 8 from the value which was received as an input parameter.
1: /// <summary>
2: /// Get tiles for <see cref="MultiScaleImage" />.
3: /// </summary>
4: /// <param name="tileLevel">Tile Level</param>
5: /// <param name="tilePositionX">Tile X position</param>
6: /// <param name="tilePositionY">Tile Y position</param>
7: /// <param name="tileImageLayerSources">Tile images repository</param>
8: protected override void GetTileLayers(int tileLevel, int tilePositionX, int tilePositionY,
9: IList<object> tileImageLayerSources)
10: {
11: int zoom = tileLevel - 8;
12: if (zoom > 0)
13: {
14: string QuadKey = TileXYToQuadKey(tilePositionX, tilePositionY, zoom);
15: string veLink = string.Format(UriFormat,
16: new object[] {QuadKey[QuadKey.Length - 1], QuadKey});
17: var veUri = new Uri(veLink);
18: tileImageLayerSources.Add(veUri);
19: }
20: }
Now we should add abstract string property for UrlFormat. We will implement it differently for road and arial tile sources.
1: /// <summary>
2: /// Format for map tile uri.
3: /// </summary>
4: public abstract string UriFormat { get; }
The last thing we should do is to create two clases for road tile images (VERoadTileSource) and arial tile images (VEArialTileSource). They are inherited from the base tile source class created above and implement uri format property.
VERoadTileSource:
1: public class VERoadTileSource : BaseVETileSource
2: {
3: public override string UriFormat
4: {
5: get { return "http://r{0}.ortho.tiles.virtualearth.net/tiles/r{1}.png?g=203"; }
6: }
7: }
VEArialTileSource:
1: public class VEArialTileSource : BaseVETileSource
2: {
3: public override string UriFormat
4: {
5: get { return "http://h{0}.ortho.tiles.virtualearth.net/tiles/h{1}.jpeg?g=203"; }
6: }
7: }
Step 3: Add virtual earth tile source to you deep zoom application.
Replace MultiScaleImage source property initialization in deep zoom composer genereated project and start browse Virtual Earth with deep zoom!
1: msi.Source = new VERoadTileSource();
2: // or try arial tile source:
3: // new VEArialTileSource();
Summary
Concept of using deep zoom technology for viewing virtual earth map which was showed in article can be used for Google Maps too. Also you should remember that direct usage of virtual earth tile system is not legal. And if you want to create your silverlight Api for Virtual earth you should first discuss it with microsoft.
Source code : http://weblogs.asp.net/blogs/alexeyzakharov/VESilverlightApplication.zip