Version 2.6.0: -replaced static fields by static properties and dependency properties

- improved class TileLayer
- MapGraticule with arc seconds
This commit is contained in:
ClemensF 2015-11-11 19:48:50 +01:00
parent 43e87f26ba
commit bc30e1d9ca
40 changed files with 337 additions and 266 deletions

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,43 +0,0 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// © 2015 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
namespace MapControl
{
public struct Int32Rect
{
public Int32Rect(int x, int y, int width, int height)
: this()
{
X = x;
Y = y;
Width = width;
Height = height;
}
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public override int GetHashCode()
{
return X ^ Y ^ Width ^ Height;
}
public override bool Equals(object obj)
{
return obj is Int32Rect && (Int32Rect)obj == this;
}
public static bool operator ==(Int32Rect rect1, Int32Rect rect2)
{
return rect1.X == rect2.X && rect1.Y == rect2.Y && rect1.Width == rect2.Width && rect1.Height == rect2.Height;
}
public static bool operator !=(Int32Rect rect1, Int32Rect rect2)
{
return !(rect1 == rect2);
}
}
}

View file

@ -20,31 +20,32 @@ namespace MapControl
public partial class MapBase
{
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
"Foreground", typeof(Brush), typeof(MapBase), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
"Foreground", typeof(Brush), typeof(MapBase),
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
"Center", typeof(Location), typeof(MapBase), new PropertyMetadata(new Location(),
(o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
"Center", typeof(Location), typeof(MapBase),
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
"TargetCenter", typeof(Location), typeof(MapBase), new PropertyMetadata(new Location(),
(o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
"TargetCenter", typeof(Location), typeof(MapBase),
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
"ZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(1d,
(o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
"ZoomLevel", typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
"TargetZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(1d,
(o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
"TargetZoomLevel", typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
"Heading", typeof(double), typeof(MapBase), new PropertyMetadata(0d,
(o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
"Heading", typeof(double), typeof(MapBase),
new PropertyMetadata(0d, (o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
"TargetHeading", typeof(double), typeof(MapBase), new PropertyMetadata(0d,
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
"TargetHeading", typeof(double), typeof(MapBase),
new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
partial void Initialize()
{
@ -67,7 +68,7 @@ namespace MapControl
private void SetViewportTransform(Location origin)
{
MapOrigin = mapTransform.Transform(origin);
ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
ViewportScale = Math.Pow(2d, ZoomLevel) * (double)TileSource.TileSize / 360d;
viewportTransform.Matrix =
new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y)

View file

@ -46,10 +46,10 @@ namespace MapControl
static MapBase()
{
UIElement.ClipToBoundsProperty.OverrideMetadata(
ClipToBoundsProperty.OverrideMetadata(
typeof(MapBase), new FrameworkPropertyMetadata(true));
Panel.BackgroundProperty.OverrideMetadata(
BackgroundProperty.OverrideMetadata(
typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
}
@ -69,7 +69,7 @@ namespace MapControl
private void SetViewportTransform(Location origin)
{
MapOrigin = mapTransform.Transform(origin);
ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
ViewportScale = Math.Pow(2d, ZoomLevel) * (double)TileSource.TileSize / 360d;
var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y);
transform.Scale(ViewportScale, -ViewportScale);

View file

@ -30,28 +30,37 @@ namespace MapControl
{
private const double MaximumZoomLevel = 22d;
public static TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.3);
public static EasingFunctionBase AnimationEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut };
public static readonly DependencyProperty TileLayerProperty = DependencyProperty.Register(
"TileLayer", typeof(TileLayer), typeof(MapBase), new PropertyMetadata(null,
(o, e) => ((MapBase)o).TileLayerPropertyChanged((TileLayer)e.NewValue)));
"TileLayer", typeof(TileLayer), typeof(MapBase),
new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayerPropertyChanged((TileLayer)e.NewValue)));
public static readonly DependencyProperty TileLayersProperty = DependencyProperty.Register(
"TileLayers", typeof(IList<TileLayer>), typeof(MapBase), new PropertyMetadata(null,
(o, e) => ((MapBase)o).TileLayersPropertyChanged((IList<TileLayer>)e.OldValue, (IList<TileLayer>)e.NewValue)));
"TileLayers", typeof(IList<TileLayer>), typeof(MapBase),
new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayersPropertyChanged((IList<TileLayer>)e.OldValue, (IList<TileLayer>)e.NewValue)));
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
"MinZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(1d,
(o, e) => ((MapBase)o).MinZoomLevelPropertyChanged((double)e.NewValue)));
"MinZoomLevel", typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).MinZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
"MaxZoomLevel", typeof(double), typeof(MapBase), new PropertyMetadata(19d,
(o, e) => ((MapBase)o).MaxZoomLevelPropertyChanged((double)e.NewValue)));
"MaxZoomLevel", typeof(double), typeof(MapBase),
new PropertyMetadata(19d, (o, e) => ((MapBase)o).MaxZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register(
"AnimationDuration", typeof(TimeSpan), typeof(MapBase),
new PropertyMetadata(TimeSpan.FromSeconds(0.3)));
public static readonly DependencyProperty AnimationEasingFunctionProperty = DependencyProperty.Register(
"AnimationEasingFunction", typeof(EasingFunctionBase), typeof(MapBase),
new PropertyMetadata(new QuadraticEase { EasingMode = EasingMode.EaseOut }));
public static readonly DependencyProperty TileFadeDurationProperty = DependencyProperty.Register(
"TileFadeDuration", typeof(TimeSpan), typeof(MapBase),
new PropertyMetadata(Tile.FadeDuration, (o, e) => Tile.FadeDuration = (TimeSpan)e.NewValue));
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
"CenterPoint", typeof(Point), typeof(MapBase), new PropertyMetadata(new Point(),
(o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue)));
"CenterPoint", typeof(Point), typeof(MapBase),
new PropertyMetadata(new Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue)));
private readonly PanelBase tileLayerPanel = new PanelBase();
private readonly MapTransform mapTransform = new MercatorTransform();
@ -138,6 +147,7 @@ namespace MapControl
/// <summary>
/// Gets or sets the minimum value of the ZoomLevel and TargetZommLevel properties.
/// Must be greater than or equal to zero and less than or equal to MaxZoomLevel.
/// The default value is 1.
/// </summary>
public double MinZoomLevel
{
@ -148,6 +158,7 @@ namespace MapControl
/// <summary>
/// Gets or sets the maximum value of the ZoomLevel and TargetZommLevel properties.
/// Must be greater than or equal to MinZoomLevel and less than or equal to 20.
/// The default value is 19.
/// </summary>
public double MaxZoomLevel
{
@ -191,6 +202,36 @@ namespace MapControl
set { SetValue(TargetHeadingProperty, value); }
}
/// <summary>
/// Gets or sets the Duration of the Center, ZoomLevel and Heading animations.
/// The default value is 0.3 seconds.
/// </summary>
public TimeSpan AnimationDuration
{
get { return (TimeSpan)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
/// <summary>
/// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations.
/// The default value is a QuadraticEase with EasingMode.EaseOut.
/// </summary>
public EasingFunctionBase AnimationEasingFunction
{
get { return (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty); }
set { SetValue(AnimationEasingFunctionProperty, value); }
}
/// <summary>
/// Gets or sets the Duration of the Tile Opacity animation.
/// The default value is 0.2 seconds.
/// </summary>
public TimeSpan TileFadeDuration
{
get { return (TimeSpan)GetValue(TileFadeDurationProperty); }
set { SetValue(TileFadeDurationProperty, value); }
}
/// <summary>
/// Gets the transformation from geographic coordinates to cartesian map coordinates.
/// </summary>
@ -247,7 +288,7 @@ namespace MapControl
public double GetMapScale(Location location)
{
return mapTransform.RelativeScale(location) *
Math.Pow(2d, ZoomLevel) * TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
Math.Pow(2d, ZoomLevel) * (double)TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
}
/// <summary>
@ -364,8 +405,8 @@ namespace MapControl
{
var p1 = mapTransform.Transform(southWest);
var p2 = mapTransform.Transform(northEast);
var lonScale = RenderSize.Width / (p2.X - p1.X) * 360d / TileSource.TileSize;
var latScale = RenderSize.Height / (p2.Y - p1.Y) * 360d / TileSource.TileSize;
var lonScale = RenderSize.Width / (p2.X - p1.X) * 360d / (double)TileSource.TileSize;
var latScale = RenderSize.Height / (p2.Y - p1.Y) * 360d / (double)TileSource.TileSize;
var lonZoom = Math.Log(lonScale, 2d);
var latZoom = Math.Log(latScale, 2d);
@ -764,17 +805,12 @@ namespace MapControl
private void UpdateTransform(bool resetTransformOrigin = false)
{
Location center;
var center = transformOrigin ?? Center;
if (transformOrigin == null)
{
center = Center;
SetViewportTransform(center);
}
else
{
SetViewportTransform(transformOrigin);
SetViewportTransform(center);
if (transformOrigin != null)
{
center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
center.Longitude = Location.NormalizeLongitude(center.Longitude);
@ -799,7 +835,7 @@ namespace MapControl
}
}
CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree; // pixels per meter at center latitude
CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree;
scaleTransform.ScaleX = CenterScale;
scaleTransform.ScaleY = CenterScale;
rotateTransform.Angle = Heading;

View file

@ -74,7 +74,6 @@
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.Silverlight.WinRT.cs" />
<Compile Include="IMapElement.cs" />
<Compile Include="Int32Rect.cs" />
<Compile Include="ITileImageLoader.cs" />
<Compile Include="Location.cs" />
<Compile Include="LocationCollection.cs" />
@ -107,6 +106,7 @@
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.Silverlight.WinRT.cs" />
<Compile Include="TileGrid.cs" />
<Compile Include="TileImageLoader.Silverlight.cs" />
<Compile Include="TileLayer.cs" />
<Compile Include="TileLayer.Silverlight.WinRT.cs" />

View file

@ -90,6 +90,7 @@
<Compile Include="Pushpin.WPF.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.WPF.cs" />
<Compile Include="TileGrid.cs" />
<Compile Include="TileImageLoader.WPF.cs" />
<Compile Include="TileLayer.cs" />
<Compile Include="TileLayer.WPF.cs" />

View file

@ -57,29 +57,23 @@ namespace MapControl
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(new Point(), ParentMap.RenderSize));
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * 256d);
var spacing = LineSpacings[LineSpacings.Length - 1];
if (spacing >= minSpacing)
{
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
}
var lineDistance = GetLineDistance();
var labelStart = new Location(
Math.Ceiling(start.Latitude / spacing) * spacing,
Math.Ceiling(start.Longitude / spacing) * spacing);
Math.Ceiling(start.Latitude / lineDistance) * lineDistance,
Math.Ceiling(start.Longitude / lineDistance) * lineDistance);
var labelEnd = new Location(
Math.Floor(end.Latitude / spacing) * spacing,
Math.Floor(end.Longitude / spacing) * spacing);
Math.Floor(end.Latitude / lineDistance) * lineDistance,
Math.Floor(end.Longitude / lineDistance) * lineDistance);
var lineStart = new Location(
Math.Min(Math.Max(labelStart.Latitude - spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelStart.Longitude - spacing);
Math.Min(Math.Max(labelStart.Latitude - lineDistance, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelStart.Longitude - lineDistance);
var lineEnd = new Location(
Math.Min(Math.Max(labelEnd.Latitude + spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelEnd.Longitude + spacing);
Math.Min(Math.Max(labelEnd.Latitude + lineDistance, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelEnd.Longitude + lineDistance);
if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
{
@ -90,7 +84,7 @@ namespace MapControl
geometry.Figures.Clear();
geometry.Transform = ParentMap.ViewportTransform;
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += lineDistance)
{
var figure = new PathFigure
{
@ -107,7 +101,7 @@ namespace MapControl
geometry.Figures.Add(figure);
}
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += lineDistance)
{
var figure = new PathFigure
{
@ -124,12 +118,12 @@ namespace MapControl
geometry.Figures.Add(figure);
}
var labelFormat = GetLabelFormat(lineDistance);
var childIndex = 1; // 0 for Path
var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += lineDistance)
{
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += lineDistance)
{
TextBlock label;
@ -169,7 +163,7 @@ namespace MapControl
label.FontStyle = FontStyle;
label.FontStretch = FontStretch;
label.FontWeight = FontWeight;
label.Text = string.Format("{0}\n{1}", CoordinateString(lat, format, "NS"), CoordinateString(Location.NormalizeLongitude(lon), format, "EW"));
label.Text = GetLabelText(lat, labelFormat, "NS") + "\n" + GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW");
label.Tag = new Location(lat, lon);
label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

View file

@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Media;
@ -27,10 +26,10 @@ namespace MapControl
static MapGraticule()
{
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
IsHitTestVisibleProperty.OverrideMetadata(
typeof(MapGraticule), new FrameworkPropertyMetadata(false));
MapOverlay.StrokeThicknessProperty.OverrideMetadata(
StrokeThicknessProperty.OverrideMetadata(
typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
}
@ -46,24 +45,17 @@ namespace MapControl
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(ParentMap.RenderSize));
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * TileSource.TileSize);
var spacing = LineSpacings[LineSpacings.Length - 1];
var lineDistance = GetLineDistance();
var labelFormat = GetLabelFormat(lineDistance);
var latLabelStart = Math.Ceiling(start.Latitude / lineDistance) * lineDistance;
var lonLabelStart = Math.Ceiling(start.Longitude / lineDistance) * lineDistance;
var latLabels = new List<Label>((int)((end.Latitude - latLabelStart) / lineDistance) + 1);
var lonLabels = new List<Label>((int)((end.Longitude - lonLabelStart) / lineDistance) + 1);
if (spacing >= minSpacing)
{
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
}
var latLabelStart = Math.Ceiling(start.Latitude / spacing) * spacing;
var lonLabelStart = Math.Ceiling(start.Longitude / spacing) * spacing;
var latLabels = new List<Label>((int)((end.Latitude - latLabelStart) / spacing) + 1);
var lonLabels = new List<Label>((int)((end.Longitude - lonLabelStart) / spacing) + 1);
var labelFormat = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
for (var lat = latLabelStart; lat <= end.Latitude; lat += spacing)
for (var lat = latLabelStart; lat <= end.Latitude; lat += lineDistance)
{
latLabels.Add(new Label(lat, new FormattedText(
CoordinateString(lat, labelFormat, "NS"),
GetLabelText(lat, labelFormat, "NS"),
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
drawingContext.DrawLine(Pen,
@ -71,10 +63,10 @@ namespace MapControl
ParentMap.LocationToViewportPoint(new Location(lat, end.Longitude)));
}
for (var lon = lonLabelStart; lon <= end.Longitude; lon += spacing)
for (var lon = lonLabelStart; lon <= end.Longitude; lon += lineDistance)
{
lonLabels.Add(new Label(lon, new FormattedText(
CoordinateString(Location.NormalizeLongitude(lon), labelFormat, "EW"),
GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW"),
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
drawingContext.DrawLine(Pen,

View file

@ -16,25 +16,56 @@ namespace MapControl
/// </summary>
public partial class MapGraticule : MapOverlay
{
/// <summary>
/// Graticule line spacings in degrees.
/// </summary>
public static double[] LineSpacings =
new double[] { 1d / 60d, 1d / 30d, 1d / 12d, 1d / 6d, 1d / 4d, 1d / 3d, 1d / 2d, 1d, 2d, 5d, 10d, 15d, 20d, 30d, 45d };
public static readonly DependencyProperty MinLineSpacingProperty = DependencyProperty.Register(
"MinLineSpacing", typeof(double), typeof(MapGraticule), new PropertyMetadata(150d));
public static readonly DependencyProperty MinLineDistanceProperty = DependencyProperty.Register(
"MinLineDistance", typeof(double), typeof(MapGraticule), new PropertyMetadata(150d));
/// <summary>
/// Minimum spacing in pixels between adjacent graticule lines.
/// Minimum graticule line distance in pixels. The default value is 150.
/// </summary>
public double MinLineSpacing
public double MinLineDistance
{
get { return (double)GetValue(MinLineSpacingProperty); }
set { SetValue(MinLineSpacingProperty, value); }
get { return (double)GetValue(MinLineDistanceProperty); }
set { SetValue(MinLineDistanceProperty, value); }
}
private static string CoordinateString(double value, string format, string hemispheres)
private double GetLineDistance()
{
var minDistance = MinLineDistance * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * (double)TileSource.TileSize);
var scale = 1d;
if (minDistance < 1d)
{
scale = minDistance < 1d / 60d ? 3600d : 60d;
minDistance *= scale;
}
var lineDistances = new double[] { 1d, 2d, 5d, 10d, 15d, 30d, 60d };
var i = 0;
while (i < lineDistances.Length - 1 && lineDistances[i] < minDistance)
{
i++;
}
return lineDistances[i] / scale;
}
private static string GetLabelFormat(double lineDistance)
{
if (lineDistance < 1d / 60d)
{
return "{0} {1}°{2:00}'{3:00}\"";
}
if (lineDistance < 1d)
{
return "{0} {1}°{2:00}'";
}
return "{0} {1}°";
}
private static string GetLabelText(double value, string format, string hemispheres)
{
var hemisphere = hemispheres[0];
@ -44,9 +75,9 @@ namespace MapControl
hemisphere = hemispheres[1];
}
var minutes = (int)Math.Round(value * 60d);
var seconds = (int)Math.Round(value * 3600d);
return string.Format(format, hemisphere, minutes / 60, (double)(minutes % 60));
return string.Format(format, hemisphere, seconds / 3600, (seconds / 60) % 60, seconds % 60);
}
}
}

View file

@ -194,7 +194,7 @@ namespace MapControl
{
From = 0d,
To = 1d,
Duration = Tile.OpacityAnimationDuration,
Duration = Tile.FadeDuration,
FillBehavior = FillBehavior.Stop
};

View file

@ -31,8 +31,8 @@ namespace MapControl
/// <summary>
/// Helper method to work around missing property value inheritance in Silverlight and Windows Runtime.
/// Adds Loaded and Unloaded handlers to the specified FrameworkElement, which set and clear the value
/// of the MapPanel.ParentMap attached property.
/// Adds Loaded and Unloaded event handlers to the specified FrameworkElement, which set and clear the
/// value of the MapPanel.ParentMap attached property.
/// </summary>
public static void AddParentMapHandlers(FrameworkElement element)
{

View file

@ -16,8 +16,8 @@ namespace MapControl
public partial class MapPolyline
{
public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
"FillRule", typeof(FillRule), typeof(MapPolyline), new PropertyMetadata(FillRule.EvenOdd,
(o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
"FillRule", typeof(FillRule), typeof(MapPolyline),
new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
public MapPolyline()
{

View file

@ -11,8 +11,8 @@ namespace MapControl
public partial class MapPolyline
{
public static readonly DependencyProperty FillRuleProperty = StreamGeometry.FillRuleProperty.AddOwner(
typeof(MapPolyline), new FrameworkPropertyMetadata(
(o, e) => ((StreamGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
typeof(MapPolyline),
new FrameworkPropertyMetadata((o, e) => ((StreamGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
public MapPolyline()
{

View file

@ -23,22 +23,22 @@ namespace MapControl
static MapScale()
{
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
IsHitTestVisibleProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(false));
FrameworkElement.MinWidthProperty.OverrideMetadata(
MinWidthProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(100d));
FrameworkElement.HorizontalAlignmentProperty.OverrideMetadata(
HorizontalAlignmentProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(HorizontalAlignment.Right));
FrameworkElement.VerticalAlignmentProperty.OverrideMetadata(
VerticalAlignmentProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(VerticalAlignment.Bottom));
MapOverlay.StrokeStartLineCapProperty.OverrideMetadata(
StrokeStartLineCapProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
MapOverlay.StrokeEndLineCapProperty.OverrideMetadata(
StrokeEndLineCapProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
}

View file

@ -14,8 +14,8 @@ using System.Windows;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -21,13 +21,13 @@ namespace MapControl
{
public partial class Tile
{
public void SetImage(ImageSource image, bool animateOpacity = true, bool isDownloading = true)
public void SetImage(ImageSource image, bool fadeIn = true, bool isDownloading = true)
{
Pending = false;
if (image != null)
{
if (animateOpacity && OpacityAnimationDuration > TimeSpan.Zero)
if (fadeIn && FadeDuration > TimeSpan.Zero)
{
BitmapImage bitmap;
@ -39,7 +39,7 @@ namespace MapControl
else
{
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation { From = 0d, To = 1d, Duration = OpacityAnimationDuration });
new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration });
}
}
else
@ -59,7 +59,7 @@ namespace MapControl
bitmap.ImageFailed -= BitmapImageFailed;
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation { From = 0d, To = 1d, Duration = OpacityAnimationDuration });
new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration });
}
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)

View file

@ -12,13 +12,13 @@ namespace MapControl
{
public partial class Tile
{
public void SetImage(ImageSource image, bool animateOpacity = true)
public void SetImage(ImageSource image, bool fadeIn = true)
{
Pending = false;
if (image != null)
{
if (animateOpacity && OpacityAnimationDuration > TimeSpan.Zero)
if (fadeIn && FadeDuration > TimeSpan.Zero)
{
var bitmap = image as BitmapSource;
@ -30,7 +30,7 @@ namespace MapControl
else
{
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation(0d, 1d, OpacityAnimationDuration));
new DoubleAnimation(0d, 1d, FadeDuration));
}
}
else
@ -50,7 +50,7 @@ namespace MapControl
bitmap.DownloadFailed -= BitmapDownloadFailed;
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation(0d, 1d, OpacityAnimationDuration));
new DoubleAnimation(0d, 1d, FadeDuration));
}
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)

View file

@ -13,7 +13,12 @@ namespace MapControl
{
public partial class Tile
{
public static TimeSpan OpacityAnimationDuration = TimeSpan.FromSeconds(0.1);
public static TimeSpan FadeDuration { get; set; }
static Tile()
{
FadeDuration = TimeSpan.FromSeconds(0.2);
}
public readonly int ZoomLevel;
public readonly int X;

46
MapControl/TileGrid.cs Normal file
View file

@ -0,0 +1,46 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// © 2015 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
namespace MapControl
{
public class TileGrid : IEquatable<TileGrid>
{
public readonly int ZoomLevel;
public readonly int XMin;
public readonly int YMin;
public readonly int XMax;
public readonly int YMax;
public TileGrid(int zoomLevel, int xMin, int yMin, int xMax, int yMax)
{
ZoomLevel = zoomLevel;
XMin = xMin;
YMin = yMin;
XMax = xMax;
YMax = yMax;
}
public bool Equals(TileGrid tileGrid)
{
return tileGrid != null
&& tileGrid.ZoomLevel == ZoomLevel
&& tileGrid.XMin == XMin
&& tileGrid.YMin == YMin
&& tileGrid.XMax == XMax
&& tileGrid.YMax == YMax;
}
public override bool Equals(object obj)
{
return Equals(obj as TileGrid);
}
public override int GetHashCode()
{
return ZoomLevel ^ XMin ^ YMin ^ XMax ^ YMax;
}
}
}

View file

@ -40,17 +40,23 @@ namespace MapControl
/// was transmitted on download. The default and recommended minimum value is seven days.
/// See OpenStreetMap tile usage policy: http://wiki.openstreetmap.org/wiki/Tile_usage_policy
/// </summary>
public static TimeSpan DefaultCacheExpiration = TimeSpan.FromDays(7);
public static TimeSpan DefaultCacheExpiration { get; set; }
/// <summary>
/// The ObjectCache used to cache tile images. The default is MemoryCache.Default.
/// </summary>
public static ObjectCache Cache = MemoryCache.Default;
public static ObjectCache Cache { get; set; }
/// <summary>
/// Optional value to be used for the HttpWebRequest.UserAgent property. The default is null.
/// </summary>
public static string HttpUserAgent;
public static string HttpUserAgent { get; set; }
static TileImageLoader()
{
DefaultCacheExpiration = TimeSpan.FromDays(7);
Cache = MemoryCache.Default;
}
private class PendingTile
{

View file

@ -38,13 +38,18 @@ namespace MapControl
/// was transmitted on download. The default and recommended minimum value is seven days.
/// See OpenStreetMap tile usage policy: http://wiki.openstreetmap.org/wiki/Tile_usage_policy
/// </summary>
public static TimeSpan DefaultCacheExpiration = TimeSpan.FromDays(7);
public static TimeSpan DefaultCacheExpiration { get; set; }
/// <summary>
/// The IImageCache implementation used to cache tile images. The default is null.
/// </summary>
public static Caching.IImageCache Cache;
static TileImageLoader()
{
DefaultCacheExpiration = TimeSpan.FromDays(7);
}
private class PendingTile
{
public readonly Tile Tile;

View file

@ -4,8 +4,10 @@
using System;
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
@ -20,24 +22,28 @@ namespace MapControl
MapPanel.AddParentMapHandlers(this);
}
private Matrix GetTileIndexMatrix(int zoomLevel)
private Rect GetTileIndexBounds(int zoomLevel)
{
var scale = (double)(1 << zoomLevel) / 360d;
var transform = new MatrixTransform
{
Matrix = parentMap.ViewportTransform.Matrix
.Invert() // view to map coordinates
.Translate(180d, -180d)
.Scale(scale, -scale) // map coordinates to tile indices
};
return parentMap.ViewportTransform.Matrix
.Invert() // view to map coordinates
.Translate(180d, -180d)
.Scale(scale, -scale); // map coordinates to tile indices
return transform.TransformBounds(new Rect(new Point(), parentMap.RenderSize));
}
private void SetRenderTransform()
{
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileZoomLevel);
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileGrid.ZoomLevel);
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)
new Matrix(1d, 0d, 0d, 1d, TileSource.TileSize * TileGrid.XMin, TileSource.TileSize * TileGrid.YMin)
.Scale(scale, scale)
.Translate(offsetX, offsetY)
.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y); ;

View file

@ -12,11 +12,11 @@ namespace MapControl
{
static TileLayer()
{
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
IsHitTestVisibleProperty.OverrideMetadata(
typeof(TileLayer), new FrameworkPropertyMetadata(false));
}
private Matrix GetTileIndexMatrix(int zoomLevel)
private Rect GetTileIndexBounds(int zoomLevel)
{
var scale = (double)(1 << zoomLevel) / 360d;
var transform = parentMap.ViewportTransform.Matrix;
@ -25,16 +25,16 @@ namespace MapControl
transform.Translate(180d, -180d);
transform.Scale(scale, -scale); // map coordinates to tile indices
return transform;
return new MatrixTransform(transform).TransformBounds(new Rect(parentMap.RenderSize));
}
private void SetRenderTransform()
{
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileZoomLevel);
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileGrid.ZoomLevel);
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);
var transform = new Matrix(1d, 0d, 0d, 1d, TileSource.TileSize * TileGrid.XMin, TileSource.TileSize * TileGrid.YMin);
transform.Scale(scale, scale);
transform.Translate(offsetX, offsetY);
transform.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y);

View file

@ -15,7 +15,6 @@ using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Threading;
using System.Diagnostics;
#endif
namespace MapControl
@ -58,7 +57,7 @@ namespace MapControl
public static readonly DependencyProperty ZoomLevelOffsetProperty = DependencyProperty.Register(
"ZoomLevelOffset", typeof(double), typeof(TileLayer),
new PropertyMetadata(0d, (o, e) => ((TileLayer)o).UpdateTileRect()));
new PropertyMetadata(0d, (o, e) => ((TileLayer)o).UpdateTileGrid()));
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
"MinZoomLevel", typeof(int), typeof(TileLayer), new PropertyMetadata(0));
@ -98,18 +97,16 @@ namespace MapControl
RenderTransform = new MatrixTransform();
TileImageLoader = tileImageLoader;
Tiles = new List<Tile>();
TileZoomLevel = -1;
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
updateTimer.Tick += (s, e) => UpdateTileRect();
updateTimer.Tick += (s, e) => UpdateTileGrid();
}
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; }
public TileGrid TileGrid { get; private set; }
/// <summary>
/// Provides map tile URIs or images.
@ -228,8 +225,6 @@ namespace MapControl
if (parentMap != null)
{
parentMap.ViewportChanged -= ViewportChanged;
TileZoomLevel = -1;
UpdateTiles(true);
}
parentMap = value;
@ -237,64 +232,62 @@ namespace MapControl
if (parentMap != null)
{
parentMap.ViewportChanged += ViewportChanged;
ViewportChanged(this, EventArgs.Empty);
mapOriginX = parentMap.MapOrigin.X;
}
UpdateTileGrid();
}
}
private void ViewportChanged(object sender, EventArgs e)
{
if (TileZoomLevel < 0 || Math.Abs(parentMap.MapOrigin.X - mapOriginX) > 180d)
if (TileGrid == null || Math.Abs(parentMap.MapOrigin.X - mapOriginX) > 180d)
{
// immediately handle map origin leap when map center moves across 180° longitude
UpdateTileRect();
UpdateTileGrid();
}
else
{
SetRenderTransform();
if (!UpdateWhileViewportChanging)
if (updateTimer.IsEnabled && !UpdateWhileViewportChanging)
{
updateTimer.Stop();
updateTimer.Stop(); // restart
}
updateTimer.Start();
if (!updateTimer.IsEnabled)
{
updateTimer.Start();
}
}
mapOriginX = parentMap.MapOrigin.X;
}
protected void UpdateTileRect()
protected void UpdateTileGrid()
{
updateTimer.Stop();
if (parentMap != null)
{
var zoomLevel = (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset);
var transform = GetTileIndexMatrix(zoomLevel);
var zoomLevel = Math.Max(0, (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset));
var bounds = GetTileIndexBounds(zoomLevel);
var tileGrid = new TileGrid(zoomLevel,
(int)Math.Floor(bounds.X), (int)Math.Floor(bounds.Y),
(int)Math.Floor(bounds.X + bounds.Width), (int)Math.Floor(bounds.Y + bounds.Height));
// 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)
if (!tileGrid.Equals(TileGrid))
{
TileZoomLevel = zoomLevel;
TileRect = rect;
TileGrid = tileGrid;
SetRenderTransform();
UpdateTiles(false);
}
}
else
{
TileGrid = null;
UpdateTiles(true);
}
}
protected virtual void UpdateTiles(bool clearTiles)
@ -328,9 +321,9 @@ namespace MapControl
{
var newTiles = new List<Tile>();
if (TileZoomLevel >= 0 && parentMap != null && TileSource != null)
if (TileGrid != null && parentMap != null && TileSource != null)
{
var maxZoomLevel = Math.Min(TileZoomLevel, MaxZoomLevel);
var maxZoomLevel = Math.Min(TileGrid.ZoomLevel, MaxZoomLevel);
var minZoomLevel = MinZoomLevel;
if (minZoomLevel < maxZoomLevel && this != parentMap.TileLayers.FirstOrDefault())
@ -341,11 +334,11 @@ namespace MapControl
for (var z = minZoomLevel; z <= maxZoomLevel; z++)
{
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);
var tileSize = 1 << (TileGrid.ZoomLevel - z);
var x1 = (int)Math.Floor((double)TileGrid.XMin / tileSize); // may be negative
var x2 = TileGrid.XMax / tileSize;
var y1 = Math.Max(TileGrid.YMin / tileSize, 0);
var y2 = Math.Min(TileGrid.YMax / tileSize, (1 << z) - 1);
for (var y = y1; y <= y2; y++)
{
@ -378,13 +371,13 @@ namespace MapControl
protected override Size ArrangeOverride(Size finalSize)
{
if (TileZoomLevel >= 0)
if (TileGrid != null)
{
foreach (var tile in Tiles)
{
var tileSize = (double)(256 << (TileZoomLevel - tile.ZoomLevel));
var x = tileSize * tile.X - 256 * TileRect.X;
var y = tileSize * tile.Y - 256 * TileRect.Y;
var tileSize = TileSource.TileSize << (TileGrid.ZoomLevel - tile.ZoomLevel);
var x = tileSize * tile.X - TileSource.TileSize * TileGrid.XMin;
var y = tileSize * tile.Y - TileSource.TileSize * TileGrid.YMin;
tile.Image.Width = tileSize;
tile.Image.Height = tileSize;

View file

@ -12,7 +12,7 @@ namespace MapControl
/// </summary>
public partial class TileSource
{
public const double TileSize = 256;
public const int TileSize = 256;
public const double MetersPerDegree = 6378137d * Math.PI / 180d; // WGS 84 semi major axis
private Func<int, int, int, Uri> getUri;
@ -165,15 +165,14 @@ 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))
.Replace("{X}", imageSize)
.Replace("{Y}", imageSize));
.Replace("{X}", TileSize.ToString())
.Replace("{Y}", TileSize.ToString()));
}
private Uri GetLatLonBoundingBoxUri(int x, int y, int zoomLevel)
@ -183,15 +182,14 @@ 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))
.Replace("{X}", imageSize)
.Replace("{Y}", imageSize));
.Replace("{X}", TileSize.ToString())
.Replace("{Y}", TileSize.ToString()));
}
}
}

View file

@ -57,9 +57,6 @@
<Compile Include="..\IMapElement.cs">
<Link>IMapElement.cs</Link>
</Compile>
<Compile Include="..\Int32Rect.cs">
<Link>Int32Rect.cs</Link>
</Compile>
<Compile Include="..\ITileImageLoader.cs">
<Link>ITileImageLoader.cs</Link>
</Compile>
@ -147,6 +144,9 @@
<Compile Include="..\Tile.Silverlight.WinRT.cs">
<Link>Tile.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\TileGrid.cs">
<Link>TileGrid.cs</Link>
</Compile>
<Compile Include="..\TileImageLoader.WinRT.cs">
<Link>TileImageLoader.WinRT.cs</Link>
</Compile>

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -35,7 +35,7 @@
Foreground="White" Background="Black"/>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg"
MaxZoomLevel="19"/>
<map:TileLayer SourceName="Seamarks"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"
@ -140,7 +140,7 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<map:Map x:Name="map" TileLayer="{Binding [OpenStreetMap], Source={StaticResource TileLayers}}"
Center="{Binding MapCenter}" MinZoomLevel="2" MaxZoomLevel="18" ZoomLevel="11"
Center="{Binding MapCenter}" MinZoomLevel="2" ZoomLevel="11"
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave">
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: ComVisible(false)]

View file

@ -39,7 +39,7 @@
</map:TileLayer>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
<map:TileSource UriFormat="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg"/>
</map:TileLayer>
<map:TileLayer SourceName="Seamarks" Description="© OpenSeaMap Contributors"
MinZoomLevel="10" MaxZoomLevel="18">
@ -167,7 +167,7 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<map:Map x:Name="map" TileLayer="{Binding [OpenStreetMap], Source={StaticResource TileLayers}}"
Center="{Binding MapCenter}" MinZoomLevel="2" MaxZoomLevel="18" ZoomLevel="11" ManipulationMode="All">
Center="{Binding MapCenter}" MinZoomLevel="2" ZoomLevel="11" ManipulationMode="All">
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity="0.5"/>
<map:MapGraticule Opacity="0.6"/>
@ -194,7 +194,7 @@
</Path.Data>
</Path>
<map:MapPath Fill="Aqua" Opacity="0.5">
<map:MapPath Stroke="Blue" Fill="Aqua" Opacity="0.5">
<map:MapPath.Data>
<GeometryGroup FillRule="EvenOdd">
<EllipseGeometry Center="8.2,63.5" RadiusX="0.025" RadiusY="0.025"/>

View file

@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: ComVisible(false)]

View file

@ -33,7 +33,7 @@
Foreground="White" Background="Black"/>
<map:TileLayer x:Key="MapQuest" SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg"
MaxZoomLevel="19"/>
<map:TileLayer x:Key="Seamarks" SourceName="Seamarks"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.5.1")]
[assembly: AssemblyFileVersion("2.5.1")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]