XAML-Map-Control/MapControl/TileContainer.cs

167 lines
5.7 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-08-08 20:42:06 +02:00
using System.Collections.Generic;
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#else
2012-04-25 22:02:53 +02:00
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
#endif
2012-04-25 22:02:53 +02:00
namespace MapControl
{
internal partial class TileContainer
2012-04-25 22:02:53 +02:00
{
private const double maxScaledTileSize = 400d; // scaled tile size 200..400 units
2013-05-15 15:58:07 +02:00
private static double zoomLevelSwitchDelta = Math.Log(maxScaledTileSize / TileSource.TileSize, 2d);
2012-04-25 22:02:53 +02:00
internal static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5);
private readonly DispatcherTimer updateTimer;
private Size viewportSize;
private Point viewportOrigin;
private Point tileLayerOffset;
2012-04-25 22:02:53 +02:00
private double rotation;
private double zoomLevel;
private int tileZoomLevel;
private Int32Rect tileGrid;
2012-08-08 20:42:06 +02:00
public readonly MatrixTransform ViewportTransform = new MatrixTransform();
2012-04-25 22:02:53 +02:00
public TileContainer()
{
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
updateTimer.Tick += UpdateTiles;
2012-04-25 22:02:53 +02:00
}
2012-08-08 20:42:06 +02:00
public void AddTileLayers(int index, IEnumerable<TileLayer> tileLayers)
2012-04-25 22:02:53 +02:00
{
var tileLayerTransform = GetTileLayerTransformMatrix();
2012-08-08 20:42:06 +02:00
foreach (var tileLayer in tileLayers)
2012-04-25 22:02:53 +02:00
{
if (index < Children.Count)
2012-04-25 22:02:53 +02:00
{
Children.Insert(index, tileLayer);
}
else
{
Children.Add(tileLayer);
2012-04-25 22:02:53 +02:00
}
index++;
tileLayer.SetTransformMatrix(tileLayerTransform);
2012-08-08 20:42:06 +02:00
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}
}
2012-04-25 22:02:53 +02:00
public void RemoveTileLayers(int index, int count)
2012-08-08 20:42:06 +02:00
{
while (count-- > 0)
2012-08-08 20:42:06 +02:00
{
((TileLayer)Children[index]).ClearTiles();
Children.RemoveAt(index);
2012-04-25 22:02:53 +02:00
}
}
2012-08-08 20:42:06 +02:00
public void ClearTileLayers()
2012-04-25 22:02:53 +02:00
{
2012-08-08 20:42:06 +02:00
foreach (TileLayer tileLayer in Children)
{
tileLayer.ClearTiles();
}
Children.Clear();
2012-04-25 22:02:53 +02:00
}
public double SetViewportTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point vpOrigin, Size vpSize)
2012-04-25 22:02:53 +02:00
{
var scale = Math.Pow(2d, zoomLevel) * TileSource.TileSize / 360d;
var oldMapOriginX = (viewportOrigin.X - tileLayerOffset.X) / scale - 180d;
if (zoomLevel != mapZoomLevel)
{
zoomLevel = mapZoomLevel;
scale = Math.Pow(2d, zoomLevel) * TileSource.TileSize / 360d;
}
2012-04-25 22:02:53 +02:00
rotation = mapRotation;
viewportSize = vpSize;
viewportOrigin = vpOrigin;
2012-04-25 22:02:53 +02:00
var transformOffsetX = viewportOrigin.X - mapOrigin.X * scale;
var transformOffsetY = viewportOrigin.Y + mapOrigin.Y * scale;
2012-04-25 22:02:53 +02:00
tileLayerOffset.X = transformOffsetX - 180d * scale;
tileLayerOffset.Y = transformOffsetY - 180d * scale;
2012-04-25 22:02:53 +02:00
SetViewportTransform(new Matrix(scale, 0d, 0d, -scale, transformOffsetX, transformOffsetY));
if (Math.Sign(mapOrigin.X) != Math.Sign(oldMapOriginX) && Math.Abs(mapOrigin.X) > 90d)
{
// immediately handle map origin leap when map center moves across the date line
UpdateTiles(this, EventArgs.Empty);
}
else
{
var tileLayerTransform = GetTileLayerTransformMatrix();
foreach (TileLayer tileLayer in Children)
{
tileLayer.SetTransformMatrix(tileLayerTransform);
}
updateTimer.Start();
}
2012-04-25 22:02:53 +02:00
return scale;
}
private void UpdateTiles(object sender, object e)
2012-04-25 22:02:53 +02:00
{
updateTimer.Stop();
2012-04-25 22:02:53 +02:00
2013-05-15 15:58:07 +02:00
var zoom = (int)Math.Floor(zoomLevel + 1d - zoomLevelSwitchDelta);
var numTiles = 1 << zoom;
var transform = GetTileIndexMatrix(numTiles);
2012-04-25 22:02:53 +02:00
// tile indices of visible rectangle
var p1 = transform.Transform(new Point(0d, 0d));
var p2 = transform.Transform(new Point(viewportSize.Width, 0d));
var p3 = transform.Transform(new Point(0d, viewportSize.Height));
var p4 = transform.Transform(new Point(viewportSize.Width, viewportSize.Height));
2012-04-25 22:02:53 +02:00
var left = Math.Min(p1.X, Math.Min(p2.X, Math.Min(p3.X, p4.X)));
var right = Math.Max(p1.X, Math.Max(p2.X, Math.Max(p3.X, p4.X)));
var top = Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y)));
var bottom = Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y)));
2012-04-25 22:02:53 +02:00
// index ranges of visible tiles
var x1 = (int)Math.Floor(left);
var x2 = (int)Math.Floor(right);
var y1 = Math.Max((int)Math.Floor(top), 0);
var y2 = Math.Min((int)Math.Floor(bottom), numTiles - 1);
var grid = new Int32Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2012-04-25 22:02:53 +02:00
if (tileZoomLevel != zoom || tileGrid != grid)
{
tileZoomLevel = zoom;
tileGrid = grid;
var tileLayerTransform = GetTileLayerTransformMatrix();
2012-04-25 22:02:53 +02:00
2012-08-08 20:42:06 +02:00
foreach (TileLayer tileLayer in Children)
2012-04-25 22:02:53 +02:00
{
tileLayer.SetTransformMatrix(tileLayerTransform);
2012-08-08 20:42:06 +02:00
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
2012-04-25 22:02:53 +02:00
}
}
}
}
}