mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-05 22:46:58 +00:00
Version 2.5.0:
- moved tile rect calculation from MapBase to TileLayer - added TileLayer.ZoomLevelOffset property - Windows Universal sample application in solution MapControl VS2015
This commit is contained in:
parent
36a8600faf
commit
98cdc95c5d
80 changed files with 16033 additions and 456 deletions
|
|
@ -8,7 +8,7 @@ using System.Diagnostics;
|
|||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ namespace MapControl
|
|||
quadkey[z] = (char)('0' + 2 * (y % 2) + (x % 2));
|
||||
}
|
||||
|
||||
return new Uri(UriFormat.
|
||||
Replace("{subdomain}", subdomain).
|
||||
Replace("{quadkey}", new string(quadkey)));
|
||||
return new Uri(UriFormat
|
||||
.Replace("{subdomain}", subdomain)
|
||||
.Replace("{quadkey}", new string(quadkey)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Documents;
|
||||
|
|
@ -45,7 +45,7 @@ namespace MapControl
|
|||
link.Inlines.Add(new Run { Text = match.Groups[1].Value });
|
||||
#if SILVERLIGHT
|
||||
link.TargetName = "_blank";
|
||||
#elif !WINDOWS_RUNTIME
|
||||
#elif !NETFX_CORE
|
||||
link.ToolTip = uri.ToString();
|
||||
link.RequestNavigate += (s, e) => System.Diagnostics.Process.Start(e.Uri.ToString());
|
||||
#endif
|
||||
|
|
@ -86,7 +86,7 @@ namespace MapControl
|
|||
{
|
||||
inlines = ((Paragraph)obj).Inlines;
|
||||
}
|
||||
#if WINDOWS_RUNTIME || SILVERLIGHT
|
||||
#if NETFX_CORE || SILVERLIGHT
|
||||
else if (obj is RichTextBlock)
|
||||
{
|
||||
var paragraph = new Paragraph();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -61,43 +61,21 @@ namespace MapControl
|
|||
private void OnRenderSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
((RectangleGeometry)Clip).Rect = new Rect(new Point(), e.NewSize);
|
||||
|
||||
ResetTransformOrigin();
|
||||
UpdateTransform();
|
||||
}
|
||||
|
||||
private void SetViewportTransform(Point mapOrigin)
|
||||
private void SetViewportTransform(Location origin)
|
||||
{
|
||||
viewportTransform.Matrix = Matrix.Identity
|
||||
.Translate(-mapOrigin.X, -mapOrigin.Y)
|
||||
MapOrigin = mapTransform.Transform(origin);
|
||||
ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
|
||||
|
||||
viewportTransform.Matrix =
|
||||
new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y)
|
||||
.Scale(ViewportScale, -ViewportScale)
|
||||
.Rotate(Heading)
|
||||
.Translate(viewportOrigin.X, viewportOrigin.Y);
|
||||
}
|
||||
|
||||
private void SetTileLayerTransform()
|
||||
{
|
||||
var scale = Math.Pow(2d, ZoomLevel - TileZoomLevel);
|
||||
|
||||
tileLayerTransform.Matrix = Matrix.Identity
|
||||
.Translate(TileGrid.X * TileSource.TileSize, TileGrid.Y * TileSource.TileSize)
|
||||
.Scale(scale, scale)
|
||||
.Translate(tileLayerOffset.X, tileLayerOffset.Y)
|
||||
.RotateAt(Heading, viewportOrigin.X, viewportOrigin.Y); ;
|
||||
}
|
||||
|
||||
private void SetTransformMatrixes()
|
||||
{
|
||||
scaleTransform.Matrix = Matrix.Identity.Scale(CenterScale, CenterScale);
|
||||
rotateTransform.Matrix = Matrix.Identity.Rotate(Heading);
|
||||
scaleRotateTransform.Matrix = scaleTransform.Matrix.Multiply(rotateTransform.Matrix);
|
||||
}
|
||||
|
||||
private Matrix GetTileIndexMatrix(double scale)
|
||||
{
|
||||
return viewportTransform.Matrix
|
||||
.Invert() // view to map coordinates
|
||||
.Translate(180d, -180d)
|
||||
.Scale(scale, -scale); // map coordinates to tile indices
|
||||
.Translate(ViewportOrigin.X, ViewportOrigin.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,54 +61,22 @@ namespace MapControl
|
|||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
|
||||
ResetTransformOrigin();
|
||||
UpdateTransform();
|
||||
}
|
||||
|
||||
private void SetViewportTransform(Point mapOrigin)
|
||||
private void SetViewportTransform(Location origin)
|
||||
{
|
||||
var transform = Matrix.Identity;
|
||||
transform.Translate(-mapOrigin.X, -mapOrigin.Y);
|
||||
MapOrigin = mapTransform.Transform(origin);
|
||||
ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
|
||||
|
||||
var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y);
|
||||
transform.Scale(ViewportScale, -ViewportScale);
|
||||
transform.Rotate(Heading);
|
||||
transform.Translate(viewportOrigin.X, viewportOrigin.Y);
|
||||
transform.Translate(ViewportOrigin.X, ViewportOrigin.Y);
|
||||
|
||||
viewportTransform.Matrix = transform;
|
||||
}
|
||||
|
||||
private void SetTileLayerTransform()
|
||||
{
|
||||
var scale = Math.Pow(2d, ZoomLevel - TileZoomLevel);
|
||||
var transform = Matrix.Identity;
|
||||
transform.Translate(TileGrid.X * TileSource.TileSize, TileGrid.Y * TileSource.TileSize);
|
||||
transform.Scale(scale, scale);
|
||||
transform.Translate(tileLayerOffset.X, tileLayerOffset.Y);
|
||||
transform.RotateAt(Heading, viewportOrigin.X, viewportOrigin.Y);
|
||||
|
||||
tileLayerTransform.Matrix = transform;
|
||||
}
|
||||
|
||||
private void SetTransformMatrixes()
|
||||
{
|
||||
var rotateMatrix = Matrix.Identity;
|
||||
rotateMatrix.Rotate(Heading);
|
||||
rotateTransform.Matrix = rotateMatrix;
|
||||
|
||||
var scaleMatrix = Matrix.Identity;
|
||||
scaleMatrix.Scale(CenterScale, CenterScale);
|
||||
scaleTransform.Matrix = scaleMatrix;
|
||||
|
||||
scaleRotateTransform.Matrix = scaleMatrix * rotateMatrix;
|
||||
}
|
||||
|
||||
private Matrix GetTileIndexMatrix(double scale)
|
||||
{
|
||||
var transform = viewportTransform.Matrix;
|
||||
transform.Invert(); // view to map coordinates
|
||||
transform.Translate(180d, -180d);
|
||||
transform.Scale(scale, -scale); // map coordinates to tile indices
|
||||
|
||||
return transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using System.Collections.Generic;
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
@ -16,24 +16,20 @@ using Windows.UI.Xaml.Media.Animation;
|
|||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The map control. Draws map content provided by the TileLayers or the TileLayer property.
|
||||
/// The visible map area is defined by the Center and ZoomLevel properties. The map can be rotated
|
||||
/// by an angle that is given by the Heading property.
|
||||
/// MapBase is a MapPanel and hence can contain map overlays like other MapPanels or MapItemsControls.
|
||||
/// The map control. Renders map content provided by the TileLayer or TileLayers property.
|
||||
/// The visible map area is defined by the Center and ZoomLevel properties.
|
||||
/// The map can be rotated by an angle that is given by the Heading property.
|
||||
/// MapBase can contain map overlay child elements like other MapPanels or MapItemsControls.
|
||||
/// </summary>
|
||||
public partial class MapBase : MapPanel
|
||||
{
|
||||
private const double MaximumZoomLevel = 22d;
|
||||
|
||||
public static double ZoomLevelSwitchDelta = 0d;
|
||||
public static bool UpdateTilesWhileViewportChanging = true;
|
||||
public static TimeSpan TileUpdateInterval = TimeSpan.FromSeconds(0.5);
|
||||
public static TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.3);
|
||||
public static EasingFunctionBase AnimationEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut };
|
||||
|
||||
|
|
@ -50,7 +46,7 @@ namespace MapControl
|
|||
(o, e) => ((MapBase)o).MinZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
|
||||
"MaxZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(18d,
|
||||
"MaxZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(19d,
|
||||
(o, e) => ((MapBase)o).MaxZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
||||
|
|
@ -58,46 +54,40 @@ namespace MapControl
|
|||
(o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue)));
|
||||
|
||||
private readonly PanelBase tileLayerPanel = new PanelBase();
|
||||
private readonly DispatcherTimer tileUpdateTimer = new DispatcherTimer { Interval = TileUpdateInterval };
|
||||
private readonly MapTransform mapTransform = new MercatorTransform();
|
||||
private readonly MatrixTransform viewportTransform = new MatrixTransform();
|
||||
private readonly MatrixTransform tileLayerTransform = new MatrixTransform();
|
||||
private readonly MatrixTransform scaleTransform = new MatrixTransform();
|
||||
private readonly MatrixTransform rotateTransform = new MatrixTransform();
|
||||
private readonly MatrixTransform scaleRotateTransform = new MatrixTransform();
|
||||
private readonly ScaleTransform scaleTransform = new ScaleTransform();
|
||||
private readonly RotateTransform rotateTransform = new RotateTransform();
|
||||
private readonly TransformGroup scaleRotateTransform = new TransformGroup();
|
||||
|
||||
private Location transformOrigin;
|
||||
private Point viewportOrigin;
|
||||
private Point tileLayerOffset;
|
||||
private PointAnimation centerAnimation;
|
||||
private DoubleAnimation zoomLevelAnimation;
|
||||
private DoubleAnimation headingAnimation;
|
||||
private bool internalPropertyChange;
|
||||
|
||||
internal Point MapOrigin { get; private set; }
|
||||
internal Point ViewportOrigin { get; private set; }
|
||||
|
||||
public MapBase()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
scaleRotateTransform.Children.Add(scaleTransform);
|
||||
scaleRotateTransform.Children.Add(rotateTransform);
|
||||
|
||||
Children.Add(tileLayerPanel);
|
||||
TileLayers = new ObservableCollection<TileLayer>();
|
||||
|
||||
tileUpdateTimer.Tick += UpdateTiles;
|
||||
Loaded += MapLoaded;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
partial void Initialize();
|
||||
partial void RemoveAnimation(DependencyProperty property);
|
||||
partial void Initialize(); // Windows Runtime and Silverlight only
|
||||
partial void RemoveAnimation(DependencyProperty property); // WPF only
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the current viewport has changed.
|
||||
/// </summary>
|
||||
public event EventHandler ViewportChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the TileZoomLevel or TileGrid properties have changed.
|
||||
/// </summary>
|
||||
public event EventHandler TileGridChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the map foreground Brush.
|
||||
/// </summary>
|
||||
|
|
@ -118,9 +108,8 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Gets or sets optional multiple TileLayers that are used simultaneously.
|
||||
/// The first element in the collection is equal to the value of the TileLayer property.
|
||||
/// The additional TileLayers usually have transparent backgrounds and their IsOverlay
|
||||
/// property is set to true.
|
||||
/// The first element in the collection is equal to the value of the TileLayer
|
||||
/// property. The additional TileLayers usually have transparent backgrounds.
|
||||
/// </summary>
|
||||
public IList<TileLayer> TileLayers
|
||||
{
|
||||
|
|
@ -185,7 +174,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the map heading, or clockwise rotation angle in degrees.
|
||||
/// Gets or sets the map heading, i.e. a clockwise rotation angle in degrees.
|
||||
/// </summary>
|
||||
public double Heading
|
||||
{
|
||||
|
|
@ -211,25 +200,17 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates.
|
||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates (i.e. pixels).
|
||||
/// </summary>
|
||||
public Transform ViewportTransform
|
||||
public MatrixTransform ViewportTransform
|
||||
{
|
||||
get { return viewportTransform; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RenderTransform to be used by TileLayers, with origin at TileGrid.X and TileGrid.Y.
|
||||
/// Gets the scaling transformation from meters to viewport coordinate units at the Center location.
|
||||
/// </summary>
|
||||
public Transform TileLayerTransform
|
||||
{
|
||||
get { return tileLayerTransform; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaling transformation from meters to viewport coordinate units (pixels) at the Center location.
|
||||
/// </summary>
|
||||
public Transform ScaleTransform
|
||||
public ScaleTransform ScaleTransform
|
||||
{
|
||||
get { return scaleTransform; }
|
||||
}
|
||||
|
|
@ -237,7 +218,7 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Gets the transformation that rotates by the value of the Heading property.
|
||||
/// </summary>
|
||||
public Transform RotateTransform
|
||||
public RotateTransform RotateTransform
|
||||
{
|
||||
get { return rotateTransform; }
|
||||
}
|
||||
|
|
@ -245,7 +226,7 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Gets the combination of ScaleTransform and RotateTransform
|
||||
/// </summary>
|
||||
public Transform ScaleRotateTransform
|
||||
public TransformGroup ScaleRotateTransform
|
||||
{
|
||||
get { return scaleRotateTransform; }
|
||||
}
|
||||
|
|
@ -256,26 +237,17 @@ namespace MapControl
|
|||
public double ViewportScale { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaling factor from meters to viewport coordinate units (pixels) at the Center location.
|
||||
/// Gets the scaling factor from meters to viewport coordinate units at the Center location.
|
||||
/// </summary>
|
||||
public double CenterScale { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zoom level to be used by TileLayers.
|
||||
/// </summary>
|
||||
public int TileZoomLevel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tile grid to be used by TileLayers.
|
||||
/// </summary>
|
||||
public Int32Rect TileGrid { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the map scale at the specified location as viewport coordinate units (pixels) per meter.
|
||||
/// Gets the map scale at the specified location as viewport coordinate units per meter.
|
||||
/// </summary>
|
||||
public double GetMapScale(Location location)
|
||||
{
|
||||
return mapTransform.RelativeScale(location) * Math.Pow(2d, ZoomLevel) * TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
|
||||
return mapTransform.RelativeScale(location) *
|
||||
Math.Pow(2d, ZoomLevel) * TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -296,32 +268,33 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Sets a temporary origin location in geographic coordinates for scaling and rotation transformations.
|
||||
/// This origin location is automatically removed when the Center property is set by application code.
|
||||
/// This origin location is automatically reset when the Center property is set by application code.
|
||||
/// </summary>
|
||||
public void SetTransformOrigin(Location origin)
|
||||
{
|
||||
transformOrigin = origin;
|
||||
viewportOrigin = LocationToViewportPoint(origin);
|
||||
ViewportOrigin = LocationToViewportPoint(origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a temporary origin point in viewport coordinates for scaling and rotation transformations.
|
||||
/// This origin point is automatically removed when the Center property is set by application code.
|
||||
/// This origin point is automatically reset when the Center property is set by application code.
|
||||
/// </summary>
|
||||
public void SetTransformOrigin(Point origin)
|
||||
{
|
||||
viewportOrigin.X = Math.Min(Math.Max(origin.X, 0d), RenderSize.Width);
|
||||
viewportOrigin.Y = Math.Min(Math.Max(origin.Y, 0d), RenderSize.Height);
|
||||
transformOrigin = ViewportPointToLocation(viewportOrigin);
|
||||
ViewportOrigin = new Point(
|
||||
Math.Min(Math.Max(origin.X, 0d), RenderSize.Width),
|
||||
Math.Min(Math.Max(origin.Y, 0d), RenderSize.Height));
|
||||
transformOrigin = ViewportPointToLocation(ViewportOrigin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the temporary transform origin point set by SetTransformOrigin.
|
||||
/// Resets the temporary transform origin point set by SetTransformOrigin.
|
||||
/// </summary>
|
||||
public void ResetTransformOrigin()
|
||||
{
|
||||
transformOrigin = null;
|
||||
viewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||
ViewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -336,7 +309,7 @@ namespace MapControl
|
|||
|
||||
if (translation.X != 0d || translation.Y != 0d)
|
||||
{
|
||||
Center = ViewportPointToLocation(new Point(viewportOrigin.X - translation.X, viewportOrigin.Y - translation.Y));
|
||||
Center = ViewportPointToLocation(new Point(ViewportOrigin.X - translation.X, ViewportOrigin.Y - translation.Y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,8 +322,7 @@ namespace MapControl
|
|||
{
|
||||
SetTransformOrigin(origin);
|
||||
|
||||
viewportOrigin.X += translation.X;
|
||||
viewportOrigin.Y += translation.Y;
|
||||
ViewportOrigin = new Point(ViewportOrigin.X + translation.X, ViewportOrigin.Y + translation.Y);
|
||||
|
||||
if (rotation != 0d)
|
||||
{
|
||||
|
|
@ -403,28 +375,6 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
base.OnViewportChanged();
|
||||
|
||||
var viewportChanged = ViewportChanged;
|
||||
|
||||
if (viewportChanged != null)
|
||||
{
|
||||
viewportChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void MapLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Loaded -= MapLoaded;
|
||||
|
||||
if (tileLayerPanel.Children.Count == 0 && !Children.OfType<TileLayer>().Any())
|
||||
{
|
||||
TileLayer = TileLayer.Default;
|
||||
}
|
||||
}
|
||||
|
||||
private void TileLayerPropertyChanged(TileLayer tileLayer)
|
||||
{
|
||||
if (tileLayer != null)
|
||||
|
|
@ -849,74 +799,23 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree; // Pixels per meter at center latitude
|
||||
CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree; // pixels per meter at center latitude
|
||||
scaleTransform.ScaleX = CenterScale;
|
||||
scaleTransform.ScaleY = CenterScale;
|
||||
rotateTransform.Angle = Heading;
|
||||
|
||||
SetTransformMatrixes();
|
||||
OnViewportChanged();
|
||||
}
|
||||
|
||||
private void SetViewportTransform(Location origin)
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
var oldMapOriginX = (viewportOrigin.X - tileLayerOffset.X) / ViewportScale - 180d;
|
||||
var mapOrigin = mapTransform.Transform(origin);
|
||||
base.OnViewportChanged();
|
||||
|
||||
ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
|
||||
SetViewportTransform(mapOrigin);
|
||||
var viewportChanged = ViewportChanged;
|
||||
|
||||
tileLayerOffset.X = viewportOrigin.X - (180d + mapOrigin.X) * ViewportScale;
|
||||
tileLayerOffset.Y = viewportOrigin.Y - (180d - mapOrigin.Y) * ViewportScale;
|
||||
|
||||
if (Math.Abs(mapOrigin.X - oldMapOriginX) > 180d)
|
||||
if (viewportChanged != null)
|
||||
{
|
||||
// immediately handle map origin leap when map center moves across 180° longitude
|
||||
UpdateTiles(this, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTileLayerTransform();
|
||||
|
||||
if (!UpdateTilesWhileViewportChanging)
|
||||
{
|
||||
tileUpdateTimer.Stop();
|
||||
}
|
||||
|
||||
tileUpdateTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTiles(object sender, object e)
|
||||
{
|
||||
tileUpdateTimer.Stop();
|
||||
|
||||
var zoomLevel = (int)Math.Round(ZoomLevel + ZoomLevelSwitchDelta);
|
||||
var transform = GetTileIndexMatrix((double)(1 << zoomLevel) / 360d);
|
||||
|
||||
// tile indices of visible rectangle
|
||||
var p1 = transform.Transform(new Point(0d, 0d));
|
||||
var p2 = transform.Transform(new Point(RenderSize.Width, 0d));
|
||||
var p3 = transform.Transform(new Point(0d, RenderSize.Height));
|
||||
var p4 = transform.Transform(new Point(RenderSize.Width, RenderSize.Height));
|
||||
|
||||
// index ranges of visible tiles
|
||||
var x1 = (int)Math.Floor(Math.Min(p1.X, Math.Min(p2.X, Math.Min(p3.X, p4.X))));
|
||||
var y1 = (int)Math.Floor(Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y))));
|
||||
var x2 = (int)Math.Floor(Math.Max(p1.X, Math.Max(p2.X, Math.Max(p3.X, p4.X))));
|
||||
var y2 = (int)Math.Floor(Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y))));
|
||||
var grid = new Int32Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
|
||||
if (TileZoomLevel != zoomLevel || TileGrid != grid)
|
||||
{
|
||||
TileZoomLevel = zoomLevel;
|
||||
TileGrid = grid;
|
||||
|
||||
SetTileLayerTransform();
|
||||
|
||||
var tileGridChanged = TileGridChanged;
|
||||
|
||||
if (tileGridChanged != null)
|
||||
{
|
||||
tileGridChanged(this, EventArgs.Empty);
|
||||
}
|
||||
viewportChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
#else
|
||||
using System.Windows;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
|
@ -33,6 +33,10 @@ namespace MapControl
|
|||
public static readonly DependencyProperty RelativeImageSizeProperty = DependencyProperty.Register(
|
||||
"RelativeImageSize", typeof(double), typeof(MapImageLayer), new PropertyMetadata(1d));
|
||||
|
||||
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
||||
"UpdateInterval", typeof(TimeSpan), typeof(MapImageLayer),
|
||||
new PropertyMetadata(TimeSpan.FromSeconds(0.5), (o, e) => ((MapImageLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
||||
|
||||
private readonly DispatcherTimer updateTimer;
|
||||
private int currentImageIndex;
|
||||
private bool updateInProgress;
|
||||
|
|
@ -42,7 +46,7 @@ namespace MapControl
|
|||
Children.Add(new MapImage { Opacity = 0d });
|
||||
Children.Add(new MapImage { Opacity = 0d });
|
||||
|
||||
updateTimer = new DispatcherTimer { Interval = MapBase.TileUpdateInterval };
|
||||
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
|
||||
updateTimer.Tick += (s, e) => UpdateImage();
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +73,15 @@ namespace MapControl
|
|||
set { SetValue(RelativeImageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum time interval between images updates.
|
||||
/// </summary>
|
||||
public TimeSpan UpdateInterval
|
||||
{
|
||||
get { return (TimeSpan)GetValue(UpdateIntervalProperty); }
|
||||
set { SetValue(UpdateIntervalProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
base.OnViewportChanged();
|
||||
|
|
@ -119,26 +132,28 @@ namespace MapControl
|
|||
{
|
||||
if (UriFormat != null && width > 0 && height > 0)
|
||||
{
|
||||
var uri = UriFormat.Replace("{X}", width.ToString()).Replace("{Y}", height.ToString());
|
||||
var uri = UriFormat
|
||||
.Replace("{X}", width.ToString())
|
||||
.Replace("{Y}", height.ToString());
|
||||
|
||||
if (uri.Contains("{W}") && uri.Contains("{S}") && uri.Contains("{E}") && uri.Contains("{N}"))
|
||||
{
|
||||
var p1 = ParentMap.MapTransform.Transform(new Location(south, west));
|
||||
var p2 = ParentMap.MapTransform.Transform(new Location(north, east));
|
||||
|
||||
uri = uri.
|
||||
Replace("{W}", (TileSource.MetersPerDegree * p1.X).ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{S}", (TileSource.MetersPerDegree * p1.Y).ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{E}", (TileSource.MetersPerDegree * p2.X).ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{N}", (TileSource.MetersPerDegree * p2.Y).ToString(CultureInfo.InvariantCulture));
|
||||
uri = uri
|
||||
.Replace("{W}", (TileSource.MetersPerDegree * p1.X).ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{S}", (TileSource.MetersPerDegree * p1.Y).ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{E}", (TileSource.MetersPerDegree * p2.X).ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{N}", (TileSource.MetersPerDegree * p2.Y).ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = uri.
|
||||
Replace("{w}", west.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{s}", south.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{e}", east.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{n}", north.ToString(CultureInfo.InvariantCulture));
|
||||
uri = uri
|
||||
.Replace("{w}", west.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{s}", south.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{e}", east.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{n}", north.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
UpdateImage(west, east, south, north, new Uri(uri));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#else
|
||||
using System.Windows.Controls;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -2,15 +2,21 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if !NETFX_CORE
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
#else
|
||||
using Windows.UI.Text;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
class FontStyles { public const FontStyle Normal = FontStyle.Normal; }
|
||||
class FontStretches { public const FontStretch Normal = FontStretch.Normal; }
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -21,16 +27,16 @@ namespace MapControl
|
|||
"FontSize", typeof(double), typeof(MapOverlay), new PropertyMetadata(10d));
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
|
||||
"FontFamily", typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(default(FontFamily)));
|
||||
"FontFamily", typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
|
||||
"FontStyle", typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(default(FontStyle)));
|
||||
"FontStyle", typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyles.Normal));
|
||||
|
||||
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
|
||||
"FontStretch", typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(default(FontStretch)));
|
||||
"FontStretch", typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretches.Normal));
|
||||
|
||||
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
|
||||
"FontWeight", typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(default(FontWeight)));
|
||||
"FontWeight", typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal));
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||
"Foreground", typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
|
@ -48,16 +54,16 @@ namespace MapControl
|
|||
"StrokeDashOffset", typeof(double), typeof(MapOverlay), new PropertyMetadata(0d));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register(
|
||||
"StrokeDashCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(default(PenLineCap)));
|
||||
"StrokeDashCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register(
|
||||
"StrokeStartLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(default(PenLineCap)));
|
||||
"StrokeStartLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register(
|
||||
"StrokeEndLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(default(PenLineCap)));
|
||||
"StrokeEndLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register(
|
||||
"StrokeLineJoin", typeof(PenLineJoin), typeof(MapOverlay), new PropertyMetadata(default(PenLineJoin)));
|
||||
"StrokeLineJoin", typeof(PenLineJoin), typeof(MapOverlay), new PropertyMetadata(PenLineJoin.Miter));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register(
|
||||
"StrokeMiterLimit", typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Text;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
@ -15,9 +15,9 @@ using System.Windows.Media;
|
|||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Arranges child elements on a Map at positions specified by the attached property Location,
|
||||
/// which is transformed to a viewport position by ParentMap.MapTransform and ParentMap.ViewportTransform
|
||||
/// and assigned to the child element's RenderTransform as a TranslateTransform.
|
||||
/// Arranges child elements on a Map at positions specified by the attached property Location.
|
||||
/// The Location value is transformed to a viewport position and assigned as TranslateTransform
|
||||
/// to the RenderTransform of the element, either directly or as last child of a TransformGroup.
|
||||
/// </summary>
|
||||
public partial class MapPanel : PanelBase, IMapElement
|
||||
{
|
||||
|
|
@ -42,22 +42,6 @@ namespace MapControl
|
|||
set { SetParentMapOverride(value); }
|
||||
}
|
||||
|
||||
protected virtual void SetParentMapOverride(MapBase map)
|
||||
{
|
||||
if (parentMap != null && parentMap != this)
|
||||
{
|
||||
parentMap.ViewportChanged -= OnViewportChanged;
|
||||
}
|
||||
|
||||
parentMap = map;
|
||||
|
||||
if (parentMap != null && parentMap != this)
|
||||
{
|
||||
parentMap.ViewportChanged += OnViewportChanged;
|
||||
OnViewportChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
foreach (UIElement element in Children)
|
||||
|
|
@ -78,6 +62,22 @@ namespace MapControl
|
|||
return finalSize;
|
||||
}
|
||||
|
||||
protected virtual void SetParentMapOverride(MapBase map)
|
||||
{
|
||||
if (parentMap != null && parentMap != this)
|
||||
{
|
||||
parentMap.ViewportChanged -= OnViewportChanged;
|
||||
}
|
||||
|
||||
parentMap = map;
|
||||
|
||||
if (parentMap != null && parentMap != this)
|
||||
{
|
||||
parentMap.ViewportChanged += OnViewportChanged;
|
||||
OnViewportChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnViewportChanged()
|
||||
{
|
||||
foreach (UIElement element in Children)
|
||||
|
|
@ -112,8 +112,6 @@ namespace MapControl
|
|||
|
||||
if (element != null)
|
||||
{
|
||||
var mapElement = element as IMapElement;
|
||||
var parentMap = mapElement != null ? mapElement.ParentMap : GetParentMap(element);
|
||||
var location = e.NewValue as Location;
|
||||
|
||||
if (location == null)
|
||||
|
|
@ -125,7 +123,7 @@ namespace MapControl
|
|||
ArrangeElementWithLocation(element); // arrange element when Location was null before
|
||||
}
|
||||
|
||||
SetViewportPosition(element, parentMap, location);
|
||||
SetViewportPosition(element, GetParentMap(element), location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,9 +137,7 @@ namespace MapControl
|
|||
|
||||
viewportPosition = parentMap.ViewportTransform.Transform(mapPosition);
|
||||
|
||||
var useLayoutRounding = element.GetValue(FrameworkElement.UseLayoutRoundingProperty);
|
||||
|
||||
if (useLayoutRounding != null && (bool)useLayoutRounding)
|
||||
if ((bool)element.GetValue(FrameworkElement.UseLayoutRoundingProperty))
|
||||
{
|
||||
viewportPosition.X = Math.Round(viewportPosition.X);
|
||||
viewportPosition.Y = Math.Round(viewportPosition.Y);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
|
|
@ -30,7 +30,7 @@ namespace MapControl
|
|||
Stretch = Stretch.None;
|
||||
}
|
||||
|
||||
// Work-around for missing PropertyChangedCallback for the Data property.
|
||||
// Workaround for missing PropertyChangedCallback for the Data property.
|
||||
if (data != Data)
|
||||
{
|
||||
data = Data;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
using System.Windows.Media;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Linq;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using System.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
@ -21,7 +21,7 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public partial class MapPolyline : MapPath
|
||||
{
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
// Binding fails on Windows Phone when property type is IEnumerable<Location>
|
||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||
"Locations", typeof(IEnumerable), typeof(MapPolyline),
|
||||
|
|
@ -38,7 +38,7 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Gets or sets the locations that define the polyline points.
|
||||
/// </summary>
|
||||
#if !WINDOWS_RUNTIME
|
||||
#if !NETFX_CORE
|
||||
[TypeConverter(typeof(LocationCollectionConverter))]
|
||||
#endif
|
||||
public IEnumerable<Location> Locations
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
@ -94,7 +94,7 @@ namespace MapControl
|
|||
{
|
||||
var rect = new Rect(ParentMap.MapTransform.Transform(new Location(South, West)),
|
||||
ParentMap.MapTransform.Transform(new Location(North, East)));
|
||||
var transform = ParentMap.ViewportTransform;
|
||||
Transform transform = ParentMap.ViewportTransform;
|
||||
|
||||
ScaleRect(ref rect, ref transform);
|
||||
|
||||
|
|
@ -109,6 +109,6 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
static partial void ScaleRect(ref Rect rect, ref Transform transform);
|
||||
static partial void ScaleRect(ref Rect rect, ref Transform transform); // WPF only
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
#else
|
||||
using System.Windows;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
using System.Windows.Media;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
#else
|
||||
using System.Windows;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ using System.Windows;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.12")]
|
||||
[assembly: AssemblyFileVersion("2.4.12")]
|
||||
[assembly: AssemblyVersion("2.5.0")]
|
||||
[assembly: AssemblyFileVersion("2.5.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#else
|
||||
using System.Windows.Controls;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#else
|
||||
using System.Windows.Controls;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if NETFX_CORE
|
||||
using Windows.UI.Xaml.Media;
|
||||
#else
|
||||
using System.Windows.Media;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class TileLayer
|
||||
|
|
@ -9,7 +16,31 @@ namespace MapControl
|
|||
partial void Initialize()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
|
||||
private Matrix GetTileIndexMatrix(int zoomLevel)
|
||||
{
|
||||
var scale = (double)(1 << zoomLevel) / 360d;
|
||||
|
||||
return parentMap.ViewportTransform.Matrix
|
||||
.Invert() // view to map coordinates
|
||||
.Translate(180d, -180d)
|
||||
.Scale(scale, -scale); // map coordinates to tile indices
|
||||
}
|
||||
|
||||
private void SetRenderTransform()
|
||||
{
|
||||
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileZoomLevel);
|
||||
var offsetX = parentMap.ViewportOrigin.X - (180d + parentMap.MapOrigin.X) * parentMap.ViewportScale;
|
||||
var offsetY = parentMap.ViewportOrigin.Y - (180d - parentMap.MapOrigin.Y) * parentMap.ViewportScale;
|
||||
|
||||
((MatrixTransform)RenderTransform).Matrix =
|
||||
new Matrix(1d, 0d, 0d, 1d, TileRect.X * TileSource.TileSize, TileRect.Y * TileSource.TileSize)
|
||||
.Scale(scale, scale)
|
||||
.Translate(offsetX, offsetY)
|
||||
.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// © 2015 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
|
|
@ -13,5 +15,31 @@ namespace MapControl
|
|||
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
|
||||
typeof(TileLayer), new FrameworkPropertyMetadata(false));
|
||||
}
|
||||
|
||||
private Matrix GetTileIndexMatrix(int zoomLevel)
|
||||
{
|
||||
var scale = (double)(1 << zoomLevel) / 360d;
|
||||
var transform = parentMap.ViewportTransform.Matrix;
|
||||
|
||||
transform.Invert(); // view to map coordinates
|
||||
transform.Translate(180d, -180d);
|
||||
transform.Scale(scale, -scale); // map coordinates to tile indices
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
private void SetRenderTransform()
|
||||
{
|
||||
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileZoomLevel);
|
||||
var offsetX = parentMap.ViewportOrigin.X - (180d + parentMap.MapOrigin.X) * parentMap.ViewportScale;
|
||||
var offsetY = parentMap.ViewportOrigin.Y - (180d - parentMap.MapOrigin.Y) * parentMap.ViewportScale;
|
||||
|
||||
var transform = new Matrix(1d, 0d, 0d, 1d, TileRect.X * TileSource.TileSize, TileRect.Y * TileSource.TileSize);
|
||||
transform.Scale(scale, scale);
|
||||
transform.Translate(offsetX, offsetY);
|
||||
transform.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y);
|
||||
|
||||
((MatrixTransform)RenderTransform).Matrix = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
|
|
@ -14,6 +14,8 @@ using Windows.UI.Xaml.Media;
|
|||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -21,14 +23,14 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Fills a rectangular area with map tiles from a TileSource.
|
||||
/// </summary>
|
||||
#if WINDOWS_RUNTIME
|
||||
#if NETFX_CORE
|
||||
[ContentProperty(Name = "TileSource")]
|
||||
#else
|
||||
[ContentProperty("TileSource")]
|
||||
#endif
|
||||
public partial class TileLayer : PanelBase, IMapElement
|
||||
{
|
||||
public static TileLayer Default
|
||||
public static TileLayer OpenStreetMapTileLayer
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -54,6 +56,10 @@ namespace MapControl
|
|||
public static readonly DependencyProperty LogoImageProperty = DependencyProperty.Register(
|
||||
"LogoImage", typeof(ImageSource), typeof(TileLayer), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelOffsetProperty = DependencyProperty.Register(
|
||||
"ZoomLevelOffset", typeof(double), typeof(TileLayer),
|
||||
new PropertyMetadata(0d, (o, e) => ((TileLayer)o).UpdateTileRect()));
|
||||
|
||||
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
|
||||
"MinZoomLevel", typeof(int), typeof(TileLayer), new PropertyMetadata(0));
|
||||
|
||||
|
|
@ -63,15 +69,22 @@ namespace MapControl
|
|||
public static readonly DependencyProperty MaxParallelDownloadsProperty = DependencyProperty.Register(
|
||||
"MaxParallelDownloads", typeof(int), typeof(TileLayer), new PropertyMetadata(4));
|
||||
|
||||
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
||||
"UpdateInterval", typeof(TimeSpan), typeof(TileLayer),
|
||||
new PropertyMetadata(TimeSpan.FromSeconds(0.5), (o, e) => ((TileLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
||||
"UpdateWhileViewportChanging", typeof(bool), typeof(TileLayer), new PropertyMetadata(true));
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||
"Foreground", typeof(Brush), typeof(TileLayer), new PropertyMetadata(null));
|
||||
|
||||
public static readonly new DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
||||
"Background", typeof(Brush), typeof(TileLayer), new PropertyMetadata(null));
|
||||
|
||||
private readonly ITileImageLoader tileImageLoader;
|
||||
private List<Tile> tiles = new List<Tile>();
|
||||
private readonly DispatcherTimer updateTimer;
|
||||
private MapBase parentMap;
|
||||
private double mapOriginX;
|
||||
|
||||
public TileLayer()
|
||||
: this(new TileImageLoader())
|
||||
|
|
@ -80,11 +93,23 @@ namespace MapControl
|
|||
|
||||
public TileLayer(ITileImageLoader tileImageLoader)
|
||||
{
|
||||
this.tileImageLoader = tileImageLoader;
|
||||
Initialize();
|
||||
|
||||
RenderTransform = new MatrixTransform();
|
||||
TileImageLoader = tileImageLoader;
|
||||
Tiles = new List<Tile>();
|
||||
TileZoomLevel = -1;
|
||||
|
||||
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
|
||||
updateTimer.Tick += (s, e) => UpdateTileRect();
|
||||
}
|
||||
|
||||
partial void Initialize();
|
||||
partial void Initialize(); // Windows Runtime and Silverlight only
|
||||
|
||||
public ITileImageLoader TileImageLoader { get; private set; }
|
||||
public ICollection<Tile> Tiles { get; private set; }
|
||||
public Int32Rect TileRect { get; private set; }
|
||||
public int TileZoomLevel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides map tile URIs or images.
|
||||
|
|
@ -122,6 +147,15 @@ namespace MapControl
|
|||
set { SetValue(LogoImageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an offset to the Map's ZoomLevel for a relative scale between the Map and the TileLayer.
|
||||
/// </summary>
|
||||
public double ZoomLevelOffset
|
||||
{
|
||||
get { return (double)GetValue(ZoomLevelOffsetProperty); }
|
||||
set { SetValue(ZoomLevelOffsetProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum zoom level supported by the TileLayer.
|
||||
/// </summary>
|
||||
|
|
@ -149,6 +183,24 @@ namespace MapControl
|
|||
set { SetValue(MaxParallelDownloadsProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum time interval between tile updates.
|
||||
/// </summary>
|
||||
public TimeSpan UpdateInterval
|
||||
{
|
||||
get { return (TimeSpan)GetValue(UpdateIntervalProperty); }
|
||||
set { SetValue(UpdateIntervalProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Controls if tiles are updates while the viewport is still changing.
|
||||
/// </summary>
|
||||
public bool UpdateWhileViewportChanging
|
||||
{
|
||||
get { return (bool)GetValue(UpdateWhileViewportChangingProperty); }
|
||||
set { SetValue(UpdateWhileViewportChangingProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optional foreground brush. Sets MapBase.Foreground, if not null.
|
||||
/// </summary>
|
||||
|
|
@ -175,63 +227,110 @@ namespace MapControl
|
|||
{
|
||||
if (parentMap != null)
|
||||
{
|
||||
parentMap.TileGridChanged -= UpdateTiles;
|
||||
ClearValue(RenderTransformProperty);
|
||||
parentMap.ViewportChanged -= ViewportChanged;
|
||||
TileZoomLevel = -1;
|
||||
UpdateTiles(true);
|
||||
}
|
||||
|
||||
parentMap = value;
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
parentMap.TileGridChanged += UpdateTiles;
|
||||
RenderTransform = parentMap.TileLayerTransform;
|
||||
parentMap.ViewportChanged += ViewportChanged;
|
||||
ViewportChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
UpdateTiles();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateTiles(bool clearTiles = false)
|
||||
private void ViewportChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (tiles.Count > 0)
|
||||
if (TileZoomLevel < 0 || Math.Abs(parentMap.MapOrigin.X - mapOriginX) > 180d)
|
||||
{
|
||||
tileImageLoader.CancelLoadTiles(this);
|
||||
// immediately handle map origin leap when map center moves across 180° longitude
|
||||
UpdateTileRect();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRenderTransform();
|
||||
|
||||
if (!UpdateWhileViewportChanging)
|
||||
{
|
||||
updateTimer.Stop();
|
||||
}
|
||||
|
||||
updateTimer.Start();
|
||||
}
|
||||
|
||||
mapOriginX = parentMap.MapOrigin.X;
|
||||
}
|
||||
|
||||
protected void UpdateTileRect()
|
||||
{
|
||||
updateTimer.Stop();
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
var zoomLevel = (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset);
|
||||
var transform = GetTileIndexMatrix(zoomLevel);
|
||||
|
||||
// tile indices of visible rectangle
|
||||
var p1 = transform.Transform(new Point(0d, 0d));
|
||||
var p2 = transform.Transform(new Point(parentMap.RenderSize.Width, 0d));
|
||||
var p3 = transform.Transform(new Point(0d, parentMap.RenderSize.Height));
|
||||
var p4 = transform.Transform(new Point(parentMap.RenderSize.Width, parentMap.RenderSize.Height));
|
||||
|
||||
// index ranges of visible tiles
|
||||
var x1 = (int)Math.Floor(Math.Min(p1.X, Math.Min(p2.X, Math.Min(p3.X, p4.X))));
|
||||
var y1 = (int)Math.Floor(Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y))));
|
||||
var x2 = (int)Math.Floor(Math.Max(p1.X, Math.Max(p2.X, Math.Max(p3.X, p4.X))));
|
||||
var y2 = (int)Math.Floor(Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y))));
|
||||
var rect = new Int32Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
|
||||
if (TileZoomLevel != zoomLevel || TileRect != rect)
|
||||
{
|
||||
TileZoomLevel = zoomLevel;
|
||||
TileRect = rect;
|
||||
|
||||
SetRenderTransform();
|
||||
UpdateTiles(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateTiles(bool clearTiles)
|
||||
{
|
||||
if (Tiles.Count > 0)
|
||||
{
|
||||
TileImageLoader.CancelLoadTiles(this);
|
||||
}
|
||||
|
||||
if (clearTiles)
|
||||
{
|
||||
tiles.Clear();
|
||||
Tiles.Clear();
|
||||
}
|
||||
|
||||
SelectTiles();
|
||||
|
||||
Children.Clear();
|
||||
|
||||
if (tiles.Count > 0)
|
||||
if (Tiles.Count > 0)
|
||||
{
|
||||
foreach (var tile in tiles)
|
||||
foreach (var tile in Tiles)
|
||||
{
|
||||
Children.Add(tile.Image);
|
||||
}
|
||||
|
||||
tileImageLoader.BeginLoadTiles(this, tiles.Where(t => t.Pending));
|
||||
TileImageLoader.BeginLoadTiles(this, Tiles.Where(t => t.Pending).OrderByDescending(t => t.ZoomLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTiles(object sender, EventArgs e)
|
||||
{
|
||||
UpdateTiles();
|
||||
}
|
||||
|
||||
private void SelectTiles()
|
||||
protected void SelectTiles()
|
||||
{
|
||||
var newTiles = new List<Tile>();
|
||||
|
||||
if (parentMap != null && TileSource != null)
|
||||
if (TileZoomLevel >= 0 && parentMap != null && TileSource != null)
|
||||
{
|
||||
var grid = parentMap.TileGrid;
|
||||
var zoomLevel = parentMap.TileZoomLevel;
|
||||
var maxZoomLevel = Math.Min(zoomLevel, MaxZoomLevel);
|
||||
var maxZoomLevel = Math.Min(TileZoomLevel, MaxZoomLevel);
|
||||
var minZoomLevel = MinZoomLevel;
|
||||
|
||||
if (minZoomLevel < maxZoomLevel && this != parentMap.TileLayers.FirstOrDefault())
|
||||
|
|
@ -242,23 +341,23 @@ namespace MapControl
|
|||
|
||||
for (var z = minZoomLevel; z <= maxZoomLevel; z++)
|
||||
{
|
||||
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);
|
||||
var tileSize = 1 << (TileZoomLevel - z);
|
||||
var x1 = (int)Math.Floor((double)TileRect.X / tileSize); // may be negative
|
||||
var x2 = (TileRect.X + TileRect.Width - 1) / tileSize;
|
||||
var y1 = Math.Max(TileRect.Y / tileSize, 0);
|
||||
var y2 = Math.Min((TileRect.Y + TileRect.Height - 1) / tileSize, (1 << z) - 1);
|
||||
|
||||
for (var y = y1; y <= y2; y++)
|
||||
{
|
||||
for (var x = x1; x <= x2; x++)
|
||||
{
|
||||
var tile = tiles.FirstOrDefault(t => t.ZoomLevel == z && t.X == x && t.Y == y);
|
||||
var tile = Tiles.FirstOrDefault(t => t.ZoomLevel == z && t.X == x && t.Y == y);
|
||||
|
||||
if (tile == null)
|
||||
{
|
||||
tile = new Tile(z, x, y);
|
||||
|
||||
var equivalentTile = tiles.FirstOrDefault(
|
||||
var equivalentTile = Tiles.FirstOrDefault(
|
||||
t => t.ZoomLevel == z && t.XIndex == tile.XIndex && t.Y == y && t.Image.Source != null);
|
||||
|
||||
if (equivalentTile != null)
|
||||
|
|
@ -274,18 +373,18 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
tiles = newTiles;
|
||||
Tiles = newTiles;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (parentMap != null)
|
||||
if (TileZoomLevel >= 0)
|
||||
{
|
||||
foreach (var tile in tiles)
|
||||
foreach (var tile in Tiles)
|
||||
{
|
||||
var tileSize = (double)(256 << (parentMap.TileZoomLevel - tile.ZoomLevel));
|
||||
var x = tileSize * tile.X - 256 * parentMap.TileGrid.X;
|
||||
var y = tileSize * tile.Y - 256 * parentMap.TileGrid.Y;
|
||||
var tileSize = (double)(256 << (TileZoomLevel - tile.ZoomLevel));
|
||||
var x = tileSize * tile.X - 256 * TileRect.X;
|
||||
var y = tileSize * tile.Y - 256 * TileRect.Y;
|
||||
|
||||
tile.Image.Width = tileSize;
|
||||
tile.Image.Height = tileSize;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public partial class TileSource
|
||||
{
|
||||
public const int TileSize = 256;
|
||||
public const double TileSize = 256;
|
||||
public const double MetersPerDegree = 6378137d * Math.PI / 180d; // WGS 84 semi major axis
|
||||
|
||||
private Func<int, int, int, Uri> getUri;
|
||||
|
|
@ -84,10 +84,10 @@ namespace MapControl
|
|||
|
||||
private Uri GetBasicUri(int x, int y, int zoomLevel)
|
||||
{
|
||||
return new Uri(uriFormat.
|
||||
Replace("{x}", x.ToString()).
|
||||
Replace("{y}", y.ToString()).
|
||||
Replace("{z}", zoomLevel.ToString()),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{x}", x.ToString())
|
||||
.Replace("{y}", y.ToString())
|
||||
.Replace("{z}", zoomLevel.ToString()),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -95,11 +95,11 @@ namespace MapControl
|
|||
{
|
||||
var hostIndex = (x + y) % 3;
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{c}", "abc".Substring(hostIndex, 1)).
|
||||
Replace("{x}", x.ToString()).
|
||||
Replace("{y}", y.ToString()).
|
||||
Replace("{z}", zoomLevel.ToString()),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{c}", "abc".Substring(hostIndex, 1))
|
||||
.Replace("{x}", x.ToString())
|
||||
.Replace("{y}", y.ToString())
|
||||
.Replace("{z}", zoomLevel.ToString()),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -107,11 +107,11 @@ namespace MapControl
|
|||
{
|
||||
var hostIndex = (x + y) % 4;
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{i}", hostIndex.ToString()).
|
||||
Replace("{x}", x.ToString()).
|
||||
Replace("{y}", y.ToString()).
|
||||
Replace("{z}", zoomLevel.ToString()),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{i}", hostIndex.ToString())
|
||||
.Replace("{x}", x.ToString())
|
||||
.Replace("{y}", y.ToString())
|
||||
.Replace("{z}", zoomLevel.ToString()),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -119,11 +119,11 @@ namespace MapControl
|
|||
{
|
||||
var hostIndex = (x + y) % 4 + 1;
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{n}", hostIndex.ToString()).
|
||||
Replace("{x}", x.ToString()).
|
||||
Replace("{y}", y.ToString()).
|
||||
Replace("{z}", zoomLevel.ToString()),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{n}", hostIndex.ToString())
|
||||
.Replace("{x}", x.ToString())
|
||||
.Replace("{y}", y.ToString())
|
||||
.Replace("{z}", zoomLevel.ToString()),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -131,10 +131,10 @@ namespace MapControl
|
|||
{
|
||||
y = (1 << zoomLevel) - 1 - y;
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{x}", x.ToString()).
|
||||
Replace("{v}", y.ToString()).
|
||||
Replace("{z}", zoomLevel.ToString()),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{x}", x.ToString())
|
||||
.Replace("{v}", y.ToString())
|
||||
.Replace("{z}", zoomLevel.ToString()),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -152,9 +152,9 @@ namespace MapControl
|
|||
quadkey[z] = (char)('0' + 2 * (y % 2) + (x % 2));
|
||||
}
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{i}", new string(quadkey[zoomLevel - 1], 1)).
|
||||
Replace("{q}", new string(quadkey)),
|
||||
return new Uri(uriFormat
|
||||
.Replace("{i}", new string(quadkey[zoomLevel - 1], 1))
|
||||
.Replace("{q}", new string(quadkey)),
|
||||
UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
|
|
@ -165,12 +165,15 @@ namespace MapControl
|
|||
var east = MetersPerDegree * ((double)(x + 1) * tileSize - 180d);
|
||||
var south = MetersPerDegree * (180d - (double)(y + 1) * tileSize);
|
||||
var north = MetersPerDegree * (180d - (double)y * tileSize);
|
||||
var imageSize = TileSize.ToString("F0");
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{W}", west.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{S}", south.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{E}", east.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{N}", north.ToString(CultureInfo.InvariantCulture)));
|
||||
return new Uri(uriFormat
|
||||
.Replace("{W}", west.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{S}", south.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{E}", east.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{N}", north.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{X}", imageSize)
|
||||
.Replace("{Y}", imageSize));
|
||||
}
|
||||
|
||||
private Uri GetLatLonBoundingBoxUri(int x, int y, int zoomLevel)
|
||||
|
|
@ -180,12 +183,15 @@ namespace MapControl
|
|||
var east = (double)(x + 1) * tileSize - 180d;
|
||||
var south = MercatorTransform.YToLatitude(180d - (double)(y + 1) * tileSize);
|
||||
var north = MercatorTransform.YToLatitude(180d - (double)y * tileSize);
|
||||
var imageSize = TileSize.ToString("F0");
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{w}", west.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{s}", south.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{e}", east.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{n}", north.ToString(CultureInfo.InvariantCulture)));
|
||||
return new Uri(uriFormat
|
||||
.Replace("{w}", west.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{s}", south.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{e}", east.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{n}", north.ToString(CultureInfo.InvariantCulture))
|
||||
.Replace("{X}", imageSize)
|
||||
.Replace("{Y}", imageSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;WINDOWS_RUNTIME</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;NETFX_CORE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;WINDOWS_RUNTIME</DefineConstants>
|
||||
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
|
@ -169,17 +169,16 @@
|
|||
<Link>MapControl.snk</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TargetPlatform Include="Windows, Version=8.1" />
|
||||
<TargetPlatform Include="WindowsPhoneApp, Version=8.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Page Include="Themes\Generic.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TargetPlatform Include="Windows, Version=8.1" />
|
||||
<TargetPlatform Include="WindowsPhoneApp, Version=8.1" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '12.0' ">
|
||||
<VisualStudioVersion>12.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
|
|
@ -198,8 +197,7 @@
|
|||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>copy "$(ProjectDir)MapControl.WinRT.xr.xml" "$(TargetDir)"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
|
|||
61
MapControl/WinRT/MapControl.WinRT.xr.xml
Normal file
61
MapControl/WinRT/MapControl.WinRT.xr.xml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Roots>
|
||||
<Roots.RootTypes>
|
||||
<RootType FullName="Windows.UI.Xaml.ResourceDictionary" />
|
||||
<RootType FullName="MapControl.MapItemsControl" />
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.Control">
|
||||
<RootProperty Name="Template" />
|
||||
<RootProperty Name="HorizontalContentAlignment" />
|
||||
<RootProperty Name="VerticalContentAlignment" />
|
||||
<RootProperty Name="Padding" />
|
||||
<RootProperty Name="Foreground" />
|
||||
<RootProperty Name="Background" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.ItemsControl">
|
||||
<RootProperty Name="ItemsPanel" />
|
||||
</RootType>
|
||||
<RootType FullName="MapControl.MapItem" />
|
||||
<RootType FullName="Windows.UI.Xaml.FrameworkElement">
|
||||
<RootProperty Name="HorizontalAlignment" />
|
||||
<RootProperty Name="VerticalAlignment" />
|
||||
</RootType>
|
||||
<RootType FullName="MapControl.Pushpin" />
|
||||
<RootType FullName="Windows.UI.Xaml.Setter">
|
||||
<RootProperty Name="Property" />
|
||||
<RootProperty Name="Value" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.ControlTemplate">
|
||||
<RootProperty Name="TargetType" />
|
||||
<RootProperty Name="Template" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.Grid">
|
||||
<RootProperty Name="RowDefinitions" />
|
||||
<RootProperty Name="Children" />
|
||||
<RootMethod Name="GetRow" />
|
||||
<RootMethod Name="SetRow" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.RowDefinition">
|
||||
<RootProperty Name="Height" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Shapes.Rectangle">
|
||||
<RootProperty Name="Fill" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Shapes.Path">
|
||||
<RootProperty Name="Fill" />
|
||||
<RootProperty Name="Data" />
|
||||
</RootType>
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.ContentPresenter">
|
||||
<RootProperty Name="Content" />
|
||||
<RootProperty Name="ContentTemplate" />
|
||||
<RootProperty Name="Margin" />
|
||||
<RootProperty Name="HorizontalAlignment" />
|
||||
<RootProperty Name="VerticalAlignment" />
|
||||
</RootType>
|
||||
<RootType FullName="Microsoft.Xaml.Tools.DirectUI.ProxyTypes.TemplateBindingExtension" />
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.ItemsPanelTemplate">
|
||||
<RootProperty Name="Template" />
|
||||
</RootType>
|
||||
<RootType FullName="MapControl.MapPanel" />
|
||||
<RootType FullName="Windows.UI.Xaml.Controls.ItemsPresenter" />
|
||||
</Roots.RootTypes>
|
||||
</Roots>
|
||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.12")]
|
||||
[assembly: AssemblyFileVersion("2.4.12")]
|
||||
[assembly: AssemblyVersion("2.5.0")]
|
||||
[assembly: AssemblyFileVersion("2.5.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
The Visual Studio Project for Windows Runtime resides in a separate folder
|
||||
MapControl/WinRT, because it needs to have its own Themes/Generic.xaml file.
|
||||
Output is generated to ../bin.
|
||||
Output is generated to ../bin.
|
||||
|
||||
This folder also contains the file MapControl.WinRT.xr.xml, which overwrites
|
||||
the generated file in the output folder. This is to remove the XML namespace
|
||||
declaration on the <Roots> element, which prevents a .NET Native build of a
|
||||
Universal Windows App that uses the MapControl.WinRT portable library.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue