diff --git a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs index a76f61b5..df431a18 100644 --- a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs +++ b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs @@ -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)] diff --git a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs index 3f56882d..aa679200 100644 --- a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs +++ b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs @@ -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)] diff --git a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs index f90aaa72..c585e4bb 100644 --- a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs +++ b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs @@ -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)] diff --git a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs index 200cd12f..ab237da0 100644 --- a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs +++ b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs @@ -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)] diff --git a/MapControl/Int32Rect.cs b/MapControl/Int32Rect.cs deleted file mode 100644 index 8649a489..00000000 --- a/MapControl/Int32Rect.cs +++ /dev/null @@ -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); - } - } -} diff --git a/MapControl/MapBase.Silverlight.WinRT.cs b/MapControl/MapBase.Silverlight.WinRT.cs index c33cbc17..80562528 100644 --- a/MapControl/MapBase.Silverlight.WinRT.cs +++ b/MapControl/MapBase.Silverlight.WinRT.cs @@ -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) diff --git a/MapControl/MapBase.WPF.cs b/MapControl/MapBase.WPF.cs index fcdfb40c..f6f72d9a 100644 --- a/MapControl/MapBase.WPF.cs +++ b/MapControl/MapBase.WPF.cs @@ -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); diff --git a/MapControl/MapBase.cs b/MapControl/MapBase.cs index b45cbc51..aae93df7 100644 --- a/MapControl/MapBase.cs +++ b/MapControl/MapBase.cs @@ -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), typeof(MapBase), new PropertyMetadata(null, - (o, e) => ((MapBase)o).TileLayersPropertyChanged((IList)e.OldValue, (IList)e.NewValue))); + "TileLayers", typeof(IList), typeof(MapBase), + new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayersPropertyChanged((IList)e.OldValue, (IList)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 /// /// 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. /// public double MinZoomLevel { @@ -148,6 +158,7 @@ namespace MapControl /// /// 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. /// public double MaxZoomLevel { @@ -191,6 +202,36 @@ namespace MapControl set { SetValue(TargetHeadingProperty, value); } } + /// + /// Gets or sets the Duration of the Center, ZoomLevel and Heading animations. + /// The default value is 0.3 seconds. + /// + public TimeSpan AnimationDuration + { + get { return (TimeSpan)GetValue(AnimationDurationProperty); } + set { SetValue(AnimationDurationProperty, value); } + } + + /// + /// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations. + /// The default value is a QuadraticEase with EasingMode.EaseOut. + /// + public EasingFunctionBase AnimationEasingFunction + { + get { return (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty); } + set { SetValue(AnimationEasingFunctionProperty, value); } + } + + /// + /// Gets or sets the Duration of the Tile Opacity animation. + /// The default value is 0.2 seconds. + /// + public TimeSpan TileFadeDuration + { + get { return (TimeSpan)GetValue(TileFadeDurationProperty); } + set { SetValue(TileFadeDurationProperty, value); } + } + /// /// Gets the transformation from geographic coordinates to cartesian map coordinates. /// @@ -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); } /// @@ -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; diff --git a/MapControl/MapControl.Silverlight.csproj b/MapControl/MapControl.Silverlight.csproj index dccb6836..d5376343 100644 --- a/MapControl/MapControl.Silverlight.csproj +++ b/MapControl/MapControl.Silverlight.csproj @@ -74,7 +74,6 @@ - @@ -107,6 +106,7 @@ + diff --git a/MapControl/MapControl.WPF.csproj b/MapControl/MapControl.WPF.csproj index a4e0eeec..5b4e26a0 100644 --- a/MapControl/MapControl.WPF.csproj +++ b/MapControl/MapControl.WPF.csproj @@ -90,6 +90,7 @@ + diff --git a/MapControl/MapGraticule.Silverlight.WinRT.cs b/MapControl/MapGraticule.Silverlight.WinRT.cs index 0a251acc..5abe923e 100644 --- a/MapControl/MapGraticule.Silverlight.WinRT.cs +++ b/MapControl/MapGraticule.Silverlight.WinRT.cs @@ -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)); diff --git a/MapControl/MapGraticule.WPF.cs b/MapControl/MapGraticule.WPF.cs index 70408edf..be1e6afd 100644 --- a/MapControl/MapGraticule.WPF.cs +++ b/MapControl/MapGraticule.WPF.cs @@ -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 public partial class MapGraticule : MapOverlay { - /// - /// Graticule line spacings in degrees. - /// - 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)); /// - /// Minimum spacing in pixels between adjacent graticule lines. + /// Minimum graticule line distance in pixels. The default value is 150. /// - 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); } } } diff --git a/MapControl/MapImageLayer.cs b/MapControl/MapImageLayer.cs index ed12a319..560ef667 100644 --- a/MapControl/MapImageLayer.cs +++ b/MapControl/MapImageLayer.cs @@ -194,7 +194,7 @@ namespace MapControl { From = 0d, To = 1d, - Duration = Tile.OpacityAnimationDuration, + Duration = Tile.FadeDuration, FillBehavior = FillBehavior.Stop }; diff --git a/MapControl/MapPanel.Silverlight.WinRT.cs b/MapControl/MapPanel.Silverlight.WinRT.cs index d6e6a1ea..9d723f98 100644 --- a/MapControl/MapPanel.Silverlight.WinRT.cs +++ b/MapControl/MapPanel.Silverlight.WinRT.cs @@ -31,8 +31,8 @@ namespace MapControl /// /// 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. /// public static void AddParentMapHandlers(FrameworkElement element) { diff --git a/MapControl/MapPolyline.Silverlight.WinRT.cs b/MapControl/MapPolyline.Silverlight.WinRT.cs index 6bbc49d1..1be26ada 100644 --- a/MapControl/MapPolyline.Silverlight.WinRT.cs +++ b/MapControl/MapPolyline.Silverlight.WinRT.cs @@ -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() { diff --git a/MapControl/MapPolyline.WPF.cs b/MapControl/MapPolyline.WPF.cs index 016b0860..020d93e3 100644 --- a/MapControl/MapPolyline.WPF.cs +++ b/MapControl/MapPolyline.WPF.cs @@ -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() { diff --git a/MapControl/MapScale.cs b/MapControl/MapScale.cs index c0e28635..d61ee5d5 100644 --- a/MapControl/MapScale.cs +++ b/MapControl/MapScale.cs @@ -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)); } diff --git a/MapControl/Properties/AssemblyInfo.cs b/MapControl/Properties/AssemblyInfo.cs index 33d6c979..97ed6cc2 100644 --- a/MapControl/Properties/AssemblyInfo.cs +++ b/MapControl/Properties/AssemblyInfo.cs @@ -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)] diff --git a/MapControl/Tile.Silverlight.WinRT.cs b/MapControl/Tile.Silverlight.WinRT.cs index de0673a2..294c6ba0 100644 --- a/MapControl/Tile.Silverlight.WinRT.cs +++ b/MapControl/Tile.Silverlight.WinRT.cs @@ -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) diff --git a/MapControl/Tile.WPF.cs b/MapControl/Tile.WPF.cs index 0246eb15..f0266015 100644 --- a/MapControl/Tile.WPF.cs +++ b/MapControl/Tile.WPF.cs @@ -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) diff --git a/MapControl/Tile.cs b/MapControl/Tile.cs index 1bb94586..a3a8cd70 100644 --- a/MapControl/Tile.cs +++ b/MapControl/Tile.cs @@ -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; diff --git a/MapControl/TileGrid.cs b/MapControl/TileGrid.cs new file mode 100644 index 00000000..9368bd1a --- /dev/null +++ b/MapControl/TileGrid.cs @@ -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 + { + 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; + } + } +} diff --git a/MapControl/TileImageLoader.WPF.cs b/MapControl/TileImageLoader.WPF.cs index 8aca3448..e5898770 100644 --- a/MapControl/TileImageLoader.WPF.cs +++ b/MapControl/TileImageLoader.WPF.cs @@ -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 /// - public static TimeSpan DefaultCacheExpiration = TimeSpan.FromDays(7); + public static TimeSpan DefaultCacheExpiration { get; set; } /// /// The ObjectCache used to cache tile images. The default is MemoryCache.Default. /// - public static ObjectCache Cache = MemoryCache.Default; + public static ObjectCache Cache { get; set; } /// /// Optional value to be used for the HttpWebRequest.UserAgent property. The default is null. /// - public static string HttpUserAgent; + public static string HttpUserAgent { get; set; } + + static TileImageLoader() + { + DefaultCacheExpiration = TimeSpan.FromDays(7); + Cache = MemoryCache.Default; + } private class PendingTile { diff --git a/MapControl/TileImageLoader.WinRT.cs b/MapControl/TileImageLoader.WinRT.cs index c189b16a..13d45d16 100644 --- a/MapControl/TileImageLoader.WinRT.cs +++ b/MapControl/TileImageLoader.WinRT.cs @@ -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 /// - public static TimeSpan DefaultCacheExpiration = TimeSpan.FromDays(7); + public static TimeSpan DefaultCacheExpiration { get; set; } /// /// The IImageCache implementation used to cache tile images. The default is null. /// public static Caching.IImageCache Cache; + static TileImageLoader() + { + DefaultCacheExpiration = TimeSpan.FromDays(7); + } + private class PendingTile { public readonly Tile Tile; diff --git a/MapControl/TileLayer.Silverlight.WinRT.cs b/MapControl/TileLayer.Silverlight.WinRT.cs index abfc6f55..98ebfb39 100644 --- a/MapControl/TileLayer.Silverlight.WinRT.cs +++ b/MapControl/TileLayer.Silverlight.WinRT.cs @@ -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); ; diff --git a/MapControl/TileLayer.WPF.cs b/MapControl/TileLayer.WPF.cs index 5fa90af8..a761ecde 100644 --- a/MapControl/TileLayer.WPF.cs +++ b/MapControl/TileLayer.WPF.cs @@ -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); diff --git a/MapControl/TileLayer.cs b/MapControl/TileLayer.cs index 56d8f340..dc684381 100644 --- a/MapControl/TileLayer.cs +++ b/MapControl/TileLayer.cs @@ -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(); - 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 Tiles { get; private set; } - public Int32Rect TileRect { get; private set; } - public int TileZoomLevel { get; private set; } + public TileGrid TileGrid { get; private set; } /// /// 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(); - 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; diff --git a/MapControl/TileSource.cs b/MapControl/TileSource.cs index b3e9a47a..53ecb058 100644 --- a/MapControl/TileSource.cs +++ b/MapControl/TileSource.cs @@ -12,7 +12,7 @@ namespace MapControl /// 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 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())); } } } diff --git a/MapControl/WinRT/MapControl.WinRT.csproj b/MapControl/WinRT/MapControl.WinRT.csproj index eade977d..23f2cb29 100644 --- a/MapControl/WinRT/MapControl.WinRT.csproj +++ b/MapControl/WinRT/MapControl.WinRT.csproj @@ -57,9 +57,6 @@ IMapElement.cs - - Int32Rect.cs - ITileImageLoader.cs @@ -147,6 +144,9 @@ Tile.Silverlight.WinRT.cs + + TileGrid.cs + TileImageLoader.WinRT.cs diff --git a/MapControl/WinRT/Properties/AssemblyInfo.cs b/MapControl/WinRT/Properties/AssemblyInfo.cs index ea73bb9a..154be8d8 100644 --- a/MapControl/WinRT/Properties/AssemblyInfo.cs +++ b/MapControl/WinRT/Properties/AssemblyInfo.cs @@ -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)] diff --git a/SampleApps/PhoneApplication/Properties/AssemblyInfo.cs b/SampleApps/PhoneApplication/Properties/AssemblyInfo.cs index de411602..3283e985 100644 --- a/SampleApps/PhoneApplication/Properties/AssemblyInfo.cs +++ b/SampleApps/PhoneApplication/Properties/AssemblyInfo.cs @@ -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)] diff --git a/SampleApps/SilverlightApplication.Web/Properties/AssemblyInfo.cs b/SampleApps/SilverlightApplication.Web/Properties/AssemblyInfo.cs index da895f11..6dfb8ef5 100644 --- a/SampleApps/SilverlightApplication.Web/Properties/AssemblyInfo.cs +++ b/SampleApps/SilverlightApplication.Web/Properties/AssemblyInfo.cs @@ -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)] diff --git a/SampleApps/SilverlightApplication/MainPage.xaml b/SampleApps/SilverlightApplication/MainPage.xaml index 6fc33f83..18d66452 100644 --- a/SampleApps/SilverlightApplication/MainPage.xaml +++ b/SampleApps/SilverlightApplication/MainPage.xaml @@ -35,7 +35,7 @@ Foreground="White" Background="Black"/> - + @@ -167,7 +167,7 @@ + Center="{Binding MapCenter}" MinZoomLevel="2" ZoomLevel="11" ManipulationMode="All"> @@ -194,7 +194,7 @@ - + diff --git a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs index e1f5ed20..596f4506 100644 --- a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs +++ b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs @@ -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)] diff --git a/SampleApps/WpfApplication/MainWindow.xaml b/SampleApps/WpfApplication/MainWindow.xaml index a9228745..81ca600a 100644 --- a/SampleApps/WpfApplication/MainWindow.xaml +++ b/SampleApps/WpfApplication/MainWindow.xaml @@ -33,7 +33,7 @@ Foreground="White" Background="Black"/>