XAML-Map-Control/MapControl/TileLayer.cs

158 lines
4.9 KiB
C#
Raw Normal View History

// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © Clemens Fischer 2012-2013
2012-05-04 12:52:20 +02:00
// Licensed under the Microsoft Public License (Ms-PL)
using System;
2012-04-25 22:02:53 +02:00
using System.Collections.Generic;
using System.Linq;
#if NETFX_CORE
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
#else
2012-04-25 22:02:53 +02:00
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
#endif
2012-04-25 22:02:53 +02:00
namespace MapControl
{
2012-05-04 12:52:20 +02:00
/// <summary>
/// Fills a rectangular area with map tiles from a TileSource.
2012-05-04 12:52:20 +02:00
/// </summary>
#if NETFX_CORE
[ContentProperty(Name = "TileSource")]
#else
2012-04-25 22:02:53 +02:00
[ContentProperty("TileSource")]
#endif
public partial class TileLayer
2012-04-25 22:02:53 +02:00
{
public static TileLayer Default
{
get
{
return new TileLayer
{
SourceName = "OpenStreetMap",
Description = "© {y} OpenStreetMap Contributors, CC-BY-SA",
TileSource = new TileSource("http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png")
};
}
}
private readonly MatrixTransform transform = new MatrixTransform();
2012-06-24 23:42:11 +02:00
private readonly TileImageLoader tileImageLoader;
private List<Tile> tiles = new List<Tile>();
2012-04-25 22:02:53 +02:00
private string description = string.Empty;
private Int32Rect grid;
private int zoomLevel;
public TileLayer()
{
2012-06-24 23:42:11 +02:00
tileImageLoader = new TileImageLoader(this);
2012-04-25 22:02:53 +02:00
MinZoomLevel = 1;
MaxZoomLevel = 18;
MaxParallelDownloads = 8;
LoadLowerZoomLevels = true;
Initialize();
2012-04-25 22:02:53 +02:00
}
partial void Initialize();
public string SourceName { get; set; }
2012-06-24 23:42:11 +02:00
public TileSource TileSource { get; set; }
2012-04-25 22:02:53 +02:00
public int MinZoomLevel { get; set; }
public int MaxZoomLevel { get; set; }
public int MaxParallelDownloads { get; set; }
public bool LoadLowerZoomLevels { get; set; }
public Brush Foreground { get; set; }
2012-04-25 22:02:53 +02:00
public string Description
{
get { return description; }
set { description = value.Replace("{y}", DateTime.Now.Year.ToString()); }
}
public string TileSourceUriFormat
{
get { return TileSource != null ? TileSource.UriFormat : string.Empty; }
set { TileSource = new TileSource(value); }
}
internal void SetTransformMatrix(Matrix transformMatrix)
2012-04-25 22:02:53 +02:00
{
transform.Matrix = transformMatrix;
2012-04-25 22:02:53 +02:00
}
protected internal virtual void UpdateTiles(int zoomLevel, Int32Rect grid)
2012-04-25 22:02:53 +02:00
{
this.grid = grid;
this.zoomLevel = zoomLevel;
tileImageLoader.CancelGetTiles();
2012-04-25 22:02:53 +02:00
2012-08-08 20:42:06 +02:00
if (TileSource != null)
2012-04-25 22:02:53 +02:00
{
SelectTiles();
RenderTiles();
tileImageLoader.BeginGetTiles(tiles);
2012-04-25 22:02:53 +02:00
}
}
protected internal virtual void ClearTiles()
2012-04-25 22:02:53 +02:00
{
tileImageLoader.CancelGetTiles();
tiles.Clear();
RenderTiles();
2012-04-25 22:02:53 +02:00
}
protected void SelectTiles()
2012-04-25 22:02:53 +02:00
{
var maxZoomLevel = Math.Min(zoomLevel, MaxZoomLevel);
var minZoomLevel = maxZoomLevel;
var container = TileContainer;
2012-04-25 22:02:53 +02:00
if (LoadLowerZoomLevels && container != null && container.Children.IndexOf(this) == 0)
2012-04-25 22:02:53 +02:00
{
2012-06-18 20:12:35 +02:00
minZoomLevel = MinZoomLevel;
2012-04-25 22:02:53 +02:00
}
var newTiles = new List<Tile>();
2012-04-25 22:02:53 +02:00
for (var z = minZoomLevel; z <= maxZoomLevel; z++)
2012-04-25 22:02:53 +02:00
{
var tileSize = 1 << (zoomLevel - z);
var x1 = (int)Math.Floor((double)grid.X / tileSize); // may be negative
var x2 = (grid.X + grid.Width - 1) / tileSize;
var y1 = Math.Max(grid.Y / tileSize, 0);
var y2 = Math.Min((grid.Y + grid.Height - 1) / tileSize, (1 << z) - 1);
2012-04-25 22:02:53 +02:00
for (var y = y1; y <= y2; y++)
2012-04-25 22:02:53 +02:00
{
for (var x = x1; x <= x2; x++)
2012-04-25 22:02:53 +02:00
{
var tile = tiles.FirstOrDefault(t => t.ZoomLevel == z && t.X == x && t.Y == y);
if (tile == null)
2012-04-25 22:02:53 +02:00
{
tile = new Tile(z, x, y);
2012-04-25 22:02:53 +02:00
var equivalentTile = tiles.FirstOrDefault(
t => t.ImageSource != null && t.ZoomLevel == z && t.XIndex == tile.XIndex && t.Y == y);
if (equivalentTile != null)
2012-04-25 22:02:53 +02:00
{
// do not animate to avoid flicker when crossing date line
tile.SetImageSource(equivalentTile.ImageSource, false);
2012-04-25 22:02:53 +02:00
}
}
newTiles.Add(tile);
2012-04-25 22:02:53 +02:00
}
}
}
tiles = newTiles;
2012-04-25 22:02:53 +02:00
}
}
2012-06-24 23:42:11 +02:00
}