From a3542bf1060e02fc89d1fbc28cc61c7b1fa31f69 Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Tue, 6 Mar 2018 22:22:58 +0100 Subject: [PATCH] Version 4.6.0: Own Point and Matrix to work around rounding errors in UWP --- FileDbCache/UWP/Properties/AssemblyInfo.cs | 4 +- FileDbCache/WPF/Properties/AssemblyInfo.cs | 4 +- MBTiles/UWP/Properties/AssemblyInfo.cs | 4 +- MBTiles/WPF/Properties/AssemblyInfo.cs | 4 +- .../Shared/AzimuthalEquidistantProjection.cs | 4 +- .../Shared/EquirectangularProjection.cs | 4 +- MapControl/Shared/GnomonicProjection.cs | 4 +- MapControl/Shared/MapBase.cs | 1 - MapControl/Shared/MapPanel.cs | 2 +- MapControl/Shared/MapProjection.cs | 36 +++- MapControl/Shared/MapShape.cs | 3 +- MapControl/Shared/MapTileLayer.cs | 4 +- MapControl/Shared/OrthographicProjection.cs | 4 +- MapControl/Shared/StereographicProjection.cs | 4 +- MapControl/Shared/WebMercatorProjection.cs | 4 +- MapControl/Shared/WorldMercatorProjection.cs | 4 +- MapControl/UWP/Extensions.UWP.cs | 7 - MapControl/UWP/Map.UWP.cs | 1 - MapControl/UWP/MapControl.UWP.csproj | 3 +- MapControl/UWP/MapGraticule.UWP.cs | 176 ++++++++---------- MapControl/UWP/Matrix.UWP.cs | 101 ++++++++++ MapControl/UWP/MatrixEx.UWP.cs | 87 --------- MapControl/UWP/Point.UWP.cs | 48 +++++ MapControl/UWP/Properties/AssemblyInfo.cs | 4 +- MapControl/WPF/MapControl.WPF.csproj | 1 - MapControl/WPF/MatrixEx.WPF.cs | 26 --- MapControl/WPF/Properties/AssemblyInfo.cs | 4 +- .../UniversalApp/Properties/AssemblyInfo.cs | 4 +- SampleApps/UniversalApp/UniversalApp.csproj | 8 +- .../WpfApplication/Properties/AssemblyInfo.cs | 4 +- 30 files changed, 295 insertions(+), 269 deletions(-) create mode 100644 MapControl/UWP/Matrix.UWP.cs delete mode 100644 MapControl/UWP/MatrixEx.UWP.cs create mode 100644 MapControl/UWP/Point.UWP.cs delete mode 100644 MapControl/WPF/MatrixEx.WPF.cs diff --git a/FileDbCache/UWP/Properties/AssemblyInfo.cs b/FileDbCache/UWP/Properties/AssemblyInfo.cs index 1585e4a7..e36cb138 100644 --- a/FileDbCache/UWP/Properties/AssemblyInfo.cs +++ b/FileDbCache/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/FileDbCache/WPF/Properties/AssemblyInfo.cs b/FileDbCache/WPF/Properties/AssemblyInfo.cs index 2b6e054a..0e3c8a61 100644 --- a/FileDbCache/WPF/Properties/AssemblyInfo.cs +++ b/FileDbCache/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MBTiles/UWP/Properties/AssemblyInfo.cs b/MBTiles/UWP/Properties/AssemblyInfo.cs index 2a504bcc..d474d2eb 100644 --- a/MBTiles/UWP/Properties/AssemblyInfo.cs +++ b/MBTiles/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MBTiles/WPF/Properties/AssemblyInfo.cs b/MBTiles/WPF/Properties/AssemblyInfo.cs index 87307be1..c14b2b3a 100644 --- a/MBTiles/WPF/Properties/AssemblyInfo.cs +++ b/MBTiles/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/Shared/AzimuthalEquidistantProjection.cs b/MapControl/Shared/AzimuthalEquidistantProjection.cs index 7565961c..52016c77 100644 --- a/MapControl/Shared/AzimuthalEquidistantProjection.cs +++ b/MapControl/Shared/AzimuthalEquidistantProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/EquirectangularProjection.cs b/MapControl/Shared/EquirectangularProjection.cs index 42f10cc3..719cb488 100644 --- a/MapControl/Shared/EquirectangularProjection.cs +++ b/MapControl/Shared/EquirectangularProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/GnomonicProjection.cs b/MapControl/Shared/GnomonicProjection.cs index 468f5033..dfdf9b75 100644 --- a/MapControl/Shared/GnomonicProjection.cs +++ b/MapControl/Shared/GnomonicProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs index 567766c5..428482fd 100644 --- a/MapControl/Shared/MapBase.cs +++ b/MapControl/Shared/MapBase.cs @@ -4,7 +4,6 @@ using System; #if WINDOWS_UWP -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index a7b1878b..dc3b36df 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -261,7 +261,7 @@ namespace MapControl var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d); rotation = parentMap.Heading; - viewportPosition = projection.ViewportTransform.Transform(center); + viewportPosition = projection.ViewportTransformMatrix.Transform(center); if (parentMap.MapProjection.IsContinuous && (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width || diff --git a/MapControl/Shared/MapProjection.cs b/MapControl/Shared/MapProjection.cs index fbdd92f0..84660786 100644 --- a/MapControl/Shared/MapProjection.cs +++ b/MapControl/Shared/MapProjection.cs @@ -25,6 +25,8 @@ namespace MapControl public const double Wgs84EquatorialRadius = 6378137d; public const double MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d; + private Matrix inverseViewportTransformMatrix; + /// /// Gets or sets the WMS 1.3.0 CRS Identifier. /// @@ -56,6 +58,11 @@ namespace MapControl /// public double MaxLatitude { get; protected set; } = 90d; + /// + /// Gets the transformation matrix from cartesian map coordinates to viewport coordinates (pixels). + /// + public Matrix ViewportTransformMatrix { get; private set; } + /// /// Gets the transformation from cartesian map coordinates to viewport coordinates (pixels). /// @@ -112,7 +119,7 @@ namespace MapControl /// public Point LocationToViewportPoint(Location location) { - return ViewportTransform.Transform(LocationToPoint(location)); + return ViewportTransformMatrix.Transform(LocationToPoint(location)); } /// @@ -120,7 +127,7 @@ namespace MapControl /// public Location ViewportPointToLocation(Point point) { - return PointToLocation(ViewportTransform.Inverse.Transform(point)); + return PointToLocation(inverseViewportTransformMatrix.Transform(point)); } /// @@ -128,7 +135,9 @@ namespace MapControl /// public BoundingBox ViewportRectToBoundingBox(Rect rect) { - return RectToBoundingBox(ViewportTransform.Inverse.TransformBounds(rect)); + var transform = new MatrixTransform { Matrix = inverseViewportTransformMatrix }; + + return RectToBoundingBox(transform.TransformBounds(rect)); } /// @@ -139,9 +148,14 @@ namespace MapControl ViewportScale = Math.Pow(2d, zoomLevel) * PixelPerDegree / TrueScale; var center = LocationToPoint(mapCenter); - - ViewportTransform.Matrix = MatrixEx.TranslateScaleRotateTranslate( + var transformMatrix = CreateTransformMatrix( -center.X, -center.Y, ViewportScale, -ViewportScale, heading, viewportCenter.X, viewportCenter.Y); + + ViewportTransformMatrix = transformMatrix; + ViewportTransform.Matrix = transformMatrix; + + transformMatrix.Invert(); + inverseViewportTransformMatrix = transformMatrix; } /// @@ -173,5 +187,17 @@ namespace MapControl return string.Format(CultureInfo.InvariantCulture, format, CrsId, rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height); } + + public static Matrix CreateTransformMatrix( + double translation1X, double translation1Y, + double scaleX, double scaleY, double rotationAngle, + double translation2X, double translation2Y) + { + var matrix = new Matrix(1d, 0d, 0d, 1d, translation1X, translation1Y); + matrix.Scale(scaleX, scaleY); + matrix.Rotate(rotationAngle); + matrix.Translate(translation2X, translation2Y); + return matrix; + } } } diff --git a/MapControl/Shared/MapShape.cs b/MapControl/Shared/MapShape.cs index 4b9d5147..467ac2ac 100644 --- a/MapControl/Shared/MapShape.cs +++ b/MapControl/Shared/MapShape.cs @@ -3,7 +3,6 @@ // Licensed under the Microsoft Public License (Ms-PL) #if WINDOWS_UWP -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; #else @@ -98,7 +97,7 @@ namespace MapControl protected Point LocationToViewportPoint(Location location) { - return parentMap.MapProjection.ViewportTransform.Transform(LocationToPoint(location)); + return parentMap.MapProjection.ViewportTransformMatrix.Transform(LocationToPoint(location)); } protected double GetLongitudeOffset() diff --git a/MapControl/Shared/MapTileLayer.cs b/MapControl/Shared/MapTileLayer.cs index 3238ad1d..2e585075 100644 --- a/MapControl/Shared/MapTileLayer.cs +++ b/MapControl/Shared/MapTileLayer.cs @@ -312,7 +312,7 @@ namespace MapControl var transform = new MatrixTransform { - Matrix = MatrixEx.TranslateScaleRotateTranslate(-viewCenterX, -viewCenterY, scale, scale, -parentMap.Heading, tileCenterX, tileCenterY) + Matrix = MapProjection.CreateTransformMatrix(-viewCenterX, -viewCenterY, scale, scale, -parentMap.Heading, tileCenterX, tileCenterY) }; var bounds = transform.TransformBounds(new Rect(0d, 0d, parentMap.RenderSize.Width, parentMap.RenderSize.Height)); @@ -333,7 +333,7 @@ namespace MapControl var viewCenterX = parentMap.RenderSize.Width / 2d; var viewCenterY = parentMap.RenderSize.Height / 2d; - ((MatrixTransform)RenderTransform).Matrix = MatrixEx.TranslateScaleRotateTranslate( + ((MatrixTransform)RenderTransform).Matrix = MapProjection.CreateTransformMatrix( -tileOriginX, -tileOriginY, scale, scale, parentMap.Heading, viewCenterX, viewCenterY); } diff --git a/MapControl/Shared/OrthographicProjection.cs b/MapControl/Shared/OrthographicProjection.cs index d650d6b1..04c52aa8 100644 --- a/MapControl/Shared/OrthographicProjection.cs +++ b/MapControl/Shared/OrthographicProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/StereographicProjection.cs b/MapControl/Shared/StereographicProjection.cs index 9abb283b..e77ed078 100644 --- a/MapControl/Shared/StereographicProjection.cs +++ b/MapControl/Shared/StereographicProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/WebMercatorProjection.cs b/MapControl/Shared/WebMercatorProjection.cs index 094ff2de..ea950b05 100644 --- a/MapControl/Shared/WebMercatorProjection.cs +++ b/MapControl/Shared/WebMercatorProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/Shared/WorldMercatorProjection.cs b/MapControl/Shared/WorldMercatorProjection.cs index 72dae059..7d1085e3 100644 --- a/MapControl/Shared/WorldMercatorProjection.cs +++ b/MapControl/Shared/WorldMercatorProjection.cs @@ -3,9 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.Foundation; -#else +#if !WINDOWS_UWP using System.Windows; #endif diff --git a/MapControl/UWP/Extensions.UWP.cs b/MapControl/UWP/Extensions.UWP.cs index 1783309a..c60240f5 100644 --- a/MapControl/UWP/Extensions.UWP.cs +++ b/MapControl/UWP/Extensions.UWP.cs @@ -2,20 +2,13 @@ // © 2018 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) -using Windows.Foundation; using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; namespace MapControl { internal static class Extensions { - public static Point Transform(this GeneralTransform transform, Point point) - { - return transform.TransformPoint(point); - } - public static void BeginAnimation(this DependencyObject obj, DependencyProperty property, Timeline animation) { if (animation != null) diff --git a/MapControl/UWP/Map.UWP.cs b/MapControl/UWP/Map.UWP.cs index 6e725894..e9a11915 100644 --- a/MapControl/UWP/Map.UWP.cs +++ b/MapControl/UWP/Map.UWP.cs @@ -3,7 +3,6 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Input; diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index 1c20e261..56e189c2 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -153,7 +153,8 @@ - + + diff --git a/MapControl/UWP/MapGraticule.UWP.cs b/MapControl/UWP/MapGraticule.UWP.cs index d4621b4e..d1ed0f42 100644 --- a/MapControl/UWP/MapGraticule.UWP.cs +++ b/MapControl/UWP/MapGraticule.UWP.cs @@ -15,8 +15,6 @@ namespace MapControl public partial class MapGraticule { private Path path; - private Location graticuleStart; - private Location graticuleEnd; public MapGraticule() { @@ -75,104 +73,97 @@ namespace MapControl Math.Min(Math.Max(labelEnd.Latitude + lineDistance, -projection.MaxLatitude), projection.MaxLatitude), labelEnd.Longitude + lineDistance); - if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd)) + var geometry = (PathGeometry)path.Data; + geometry.Figures.Clear(); + + for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance) { - graticuleStart = lineStart; - graticuleEnd = lineEnd; - - var geometry = (PathGeometry)path.Data; - geometry.Figures.Clear(); - geometry.Transform = projection.ViewportTransform; - - for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance) + var figure = new PathFigure { - var figure = new PathFigure - { - StartPoint = projection.LocationToPoint(new Location(lat, lineStart.Longitude)), - IsClosed = false, - IsFilled = false - }; + StartPoint = projection.LocationToViewportPoint(new Location(lat, lineStart.Longitude)), + IsClosed = false, + IsFilled = false + }; - figure.Segments.Add(new LineSegment - { - Point = projection.LocationToPoint(new Location(lat, lineEnd.Longitude)), - }); + figure.Segments.Add(new LineSegment + { + Point = projection.LocationToViewportPoint(new Location(lat, lineEnd.Longitude)) + }); - geometry.Figures.Add(figure); - } + geometry.Figures.Add(figure); + } + for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance) + { + var figure = new PathFigure + { + StartPoint = projection.LocationToViewportPoint(new Location(lineStart.Latitude, lon)), + IsClosed = false, + IsFilled = false + }; + + figure.Segments.Add(new LineSegment + { + Point = projection.LocationToViewportPoint(new Location(lineEnd.Latitude, lon)) + }); + + geometry.Figures.Add(figure); + } + + var labelFormat = GetLabelFormat(lineDistance); + var childIndex = 1; // 0 for Path + + for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance) + { for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance) { - var figure = new PathFigure + TextBlock label; + + if (childIndex < Children.Count) { - StartPoint = projection.LocationToPoint(new Location(lineStart.Latitude, lon)), - IsClosed = false, - IsFilled = false - }; - - figure.Segments.Add(new LineSegment - { - Point = projection.LocationToPoint(new Location(lineEnd.Latitude, lon)), - }); - - geometry.Figures.Add(figure); - } - - var labelFormat = GetLabelFormat(lineDistance); - var childIndex = 1; // 0 for Path - - for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance) - { - for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance) - { - TextBlock label; - - if (childIndex < Children.Count) - { - label = (TextBlock)Children[childIndex]; - } - else - { - var renderTransform = new TransformGroup(); - renderTransform.Children.Add(new TranslateTransform()); - renderTransform.Children.Add(ParentMap.RotateTransform); - renderTransform.Children.Add(new TranslateTransform()); - - label = new TextBlock - { - RenderTransform = renderTransform - }; - - label.SetBinding(TextBlock.ForegroundProperty, - GetBindingExpression(ForegroundProperty)?.ParentBinding ?? - new Binding - { - Source = this, - Path = new PropertyPath("Foreground") - }); - - Children.Add(label); - } - - childIndex++; - - if (FontFamily != null) - { - label.FontFamily = FontFamily; - } - - label.FontSize = FontSize; - label.FontStyle = FontStyle; - label.FontStretch = FontStretch; - label.FontWeight = FontWeight; - 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)); - - var translateTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[0]; - translateTransform.X = StrokeThickness / 2d + 2d; - translateTransform.Y = -label.DesiredSize.Height / 2d; + label = (TextBlock)Children[childIndex]; } + else + { + var renderTransform = new TransformGroup(); + renderTransform.Children.Add(new TranslateTransform()); + renderTransform.Children.Add(ParentMap.RotateTransform); + renderTransform.Children.Add(new TranslateTransform()); + + label = new TextBlock + { + RenderTransform = renderTransform + }; + + label.SetBinding(TextBlock.ForegroundProperty, + GetBindingExpression(ForegroundProperty)?.ParentBinding ?? + new Binding + { + Source = this, + Path = new PropertyPath("Foreground") + }); + + Children.Add(label); + } + + childIndex++; + + if (FontFamily != null) + { + label.FontFamily = FontFamily; + } + + label.FontSize = FontSize; + label.FontStyle = FontStyle; + label.FontStretch = FontStretch; + label.FontWeight = FontWeight; + 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)); + + var translateTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[0]; + translateTransform.X = StrokeThickness / 2d + 2d; + translateTransform.Y = -label.DesiredSize.Height / 2d; } while (Children.Count > childIndex) @@ -196,9 +187,6 @@ namespace MapControl else if (path != null) { path = null; - graticuleStart = null; - graticuleEnd = null; - Children.Clear(); } diff --git a/MapControl/UWP/Matrix.UWP.cs b/MapControl/UWP/Matrix.UWP.cs new file mode 100644 index 00000000..27484b15 --- /dev/null +++ b/MapControl/UWP/Matrix.UWP.cs @@ -0,0 +1,101 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2018 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; + +namespace MapControl +{ + public struct Matrix + { + public double M11 { get; set; } + public double M12 { get; set; } + public double M21 { get; set; } + public double M22 { get; set; } + public double OffsetX { get; set; } + public double OffsetY { get; set; } + + public static implicit operator Windows.UI.Xaml.Media.Matrix(Matrix m) + { + return new Windows.UI.Xaml.Media.Matrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY); + } + + public Matrix(double m11, double m12, double m21, double m22, double offsetX, double offsetY) + { + M11 = m11; + M12 = m12; + M21 = m21; + M22 = m22; + OffsetX = offsetX; + OffsetY = offsetY; + } + + public Point Transform(Point p) + { + return new Point(M11 * p.X + M12 * p.Y + OffsetX, M21 * p.X + M22 * p.Y + OffsetY); + } + + public void Translate(double x, double y) + { + OffsetX += x; + OffsetY += y; + } + + public void Scale(double scaleX, double scaleY) + { + if (M12 != 0d || M21 != 0d) + { + throw new NotSupportedException("Scale not supported for rotated Matrix"); + } + + SetMatrix(scaleX * M11, 0d, 0d, scaleY * M22, scaleX * OffsetX, scaleY * OffsetY); + } + + public void Rotate(double angle) + { + angle = (angle % 360d) / 180d * Math.PI; + + if (angle != 0d) + { + var cos = Math.Cos(angle); + var sin = Math.Sin(angle); + + SetMatrix( + cos * M11 - sin * M12, + sin * M11 + cos * M12, + cos * M21 - sin * M22, + sin * M21 + cos * M22, + cos * OffsetX - sin * OffsetY, + sin * OffsetX + cos * OffsetY); + } + } + + public void Invert() + { + var invDet = 1d / (M11 * M22 - M12 * M21); + + if (double.IsInfinity(invDet)) + { + throw new InvalidOperationException("Matrix is not invertible"); + } + + SetMatrix( + invDet * M22, + invDet * -M12, + invDet * -M21, + invDet * M11, + invDet * (M21 * OffsetY - M22 * OffsetX), + invDet * (M12 * OffsetX - M11 * OffsetY)); + } + + private void SetMatrix(double m11, double m12, double m21, double m22, double offsetX, double offsetY) + { + M11 = m11; + M12 = m12; + M21 = m21; + M22 = m22; + OffsetX = offsetX; + OffsetY = offsetY; + } + } +} diff --git a/MapControl/UWP/MatrixEx.UWP.cs b/MapControl/UWP/MatrixEx.UWP.cs deleted file mode 100644 index 4f0a2ca0..00000000 --- a/MapControl/UWP/MatrixEx.UWP.cs +++ /dev/null @@ -1,87 +0,0 @@ -// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control -// © 2018 Clemens Fischer -// Licensed under the Microsoft Public License (Ms-PL) - -using System; -using Windows.UI.Xaml.Media; - -namespace MapControl -{ - internal static class MatrixEx - { - /// - /// Used in MapProjection and MapTileLayer. - /// - public static Matrix TranslateScaleRotateTranslate( - double translation1X, double translation1Y, - double scaleX, double scaleY, double rotationAngle, - double translation2X, double translation2Y) - { - var matrix = new Matrix( - scaleX, 0d, 0d, scaleY, - scaleX * translation1X, - scaleY * translation1Y); - - if (rotationAngle != 0d) - { - rotationAngle = (rotationAngle % 360d) / 180d * Math.PI; - - var cos = Math.Cos(rotationAngle); - var sin = Math.Sin(rotationAngle); - - matrix = new Matrix( - matrix.M11 * cos - matrix.M12 * sin, - matrix.M11 * sin + matrix.M12 * cos, - matrix.M21 * cos - matrix.M22 * sin, - matrix.M21 * sin + matrix.M22 * cos, - cos * matrix.OffsetX - sin * matrix.OffsetY, - sin * matrix.OffsetX + cos * matrix.OffsetY); - } - - matrix.OffsetX += translation2X; - matrix.OffsetY += translation2Y; - - return matrix; - } - - public static Matrix TranslateScaleRotateTranslate_( - double translation1X, double translation1Y, - double scaleX, double scaleY, double rotationAngle, - double translation2X, double translation2Y) - { - var m11 = scaleX; - var m12 = 0d; - var m21 = 0d; - var m22 = scaleY; - var offsetX = scaleX * translation1X; - var offsetY = scaleY * translation1Y; - - if (rotationAngle != 0d) - { - rotationAngle = (rotationAngle % 360d) / 180d * Math.PI; - - var cos = Math.Cos(rotationAngle); - var sin = Math.Sin(rotationAngle); - - var _m11 = m11; - var _m12 = m12; - var _m21 = m21; - var _m22 = m22; - var _offsetX = offsetX; - var _offsetY = offsetY; - - m11 = _m11 * cos - _m12 * sin; - m12 = _m11 * sin + _m12 * cos; - m21 = _m21 * cos - _m22 * sin; - m22 = _m21 * sin + _m22 * cos; - offsetX = cos * _offsetX - sin * _offsetY; - offsetY = sin * _offsetX + cos * _offsetY; - } - - offsetX += translation2X; - offsetY += translation2Y; - - return new Matrix(m11, m12, m21, m22, offsetX, offsetY); - } - } -} diff --git a/MapControl/UWP/Point.UWP.cs b/MapControl/UWP/Point.UWP.cs new file mode 100644 index 00000000..833c592f --- /dev/null +++ b/MapControl/UWP/Point.UWP.cs @@ -0,0 +1,48 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2018 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +namespace MapControl +{ + public struct Point + { + public double X { get; set; } + public double Y { get; set; } + + public Point(double x, double y) + { + X = x; + Y = y; + } + + public static implicit operator Point(Windows.Foundation.Point p) + { + return new Point(p.X, p.Y); + } + + public static implicit operator Windows.Foundation.Point(Point p) + { + return new Windows.Foundation.Point(p.X, p.Y); + } + + public static bool operator ==(Point p1, Point p2) + { + return p1.X == p2.X && p1.Y == p2.Y; + } + + public static bool operator !=(Point p1, Point p2) + { + return !(p1 == p2); + } + + public override bool Equals(object o) + { + return o is Point && this == (Point)o; + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + } +} diff --git a/MapControl/UWP/Properties/AssemblyInfo.cs b/MapControl/UWP/Properties/AssemblyInfo.cs index 5979b0e5..e04f14c4 100644 --- a/MapControl/UWP/Properties/AssemblyInfo.cs +++ b/MapControl/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/WPF/MapControl.WPF.csproj b/MapControl/WPF/MapControl.WPF.csproj index d1eb863f..1b838a51 100644 --- a/MapControl/WPF/MapControl.WPF.csproj +++ b/MapControl/WPF/MapControl.WPF.csproj @@ -177,7 +177,6 @@ - Code diff --git a/MapControl/WPF/MatrixEx.WPF.cs b/MapControl/WPF/MatrixEx.WPF.cs deleted file mode 100644 index 3998b222..00000000 --- a/MapControl/WPF/MatrixEx.WPF.cs +++ /dev/null @@ -1,26 +0,0 @@ -// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control -// © 2018 Clemens Fischer -// Licensed under the Microsoft Public License (Ms-PL) - -using System.Windows.Media; - -namespace MapControl -{ - internal static class MatrixEx - { - /// - /// Used in MapProjection and MapTileLayer. - /// - public static Matrix TranslateScaleRotateTranslate( - double translation1X, double translation1Y, - double scaleX, double scaleY, double rotationAngle, - double translation2X, double translation2Y) - { - var matrix = new Matrix(1d, 0d, 0d, 1d, translation1X, translation1Y); - matrix.Scale(scaleX, scaleY); - matrix.Rotate(rotationAngle); - matrix.Translate(translation2X, translation2Y); - return matrix; - } - } -} diff --git a/MapControl/WPF/Properties/AssemblyInfo.cs b/MapControl/WPF/Properties/AssemblyInfo.cs index 4991c358..3b9f196d 100644 --- a/MapControl/WPF/Properties/AssemblyInfo.cs +++ b/MapControl/WPF/Properties/AssemblyInfo.cs @@ -8,8 +8,8 @@ using System.Windows; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.5.0")] -[assembly: AssemblyFileVersion("4.5.0")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs index 520ebe65..9fb632a8 100644 --- a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs +++ b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("4.4.1")] -[assembly: AssemblyFileVersion("4.4.1")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: ComVisible(false)] diff --git a/SampleApps/UniversalApp/UniversalApp.csproj b/SampleApps/UniversalApp/UniversalApp.csproj index 078a78d5..c4069022 100644 --- a/SampleApps/UniversalApp/UniversalApp.csproj +++ b/SampleApps/UniversalApp/UniversalApp.csproj @@ -11,8 +11,8 @@ UniversalApp en-US UAP - 10.0.10240.0 - 10.0.10240.0 + 10.0.10586.0 + 10.0.10586.0 14 true 512 @@ -70,7 +70,7 @@ false prompt true - true + false false @@ -156,7 +156,7 @@ - 6.0.1 + 6.0.7 diff --git a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs b/SampleApps/WpfApplication/Properties/AssemblyInfo.cs index c7f92947..787e542a 100644 --- a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs +++ b/SampleApps/WpfApplication/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2018 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.4.1")] -[assembly: AssemblyFileVersion("4.4.1")] +[assembly: AssemblyVersion("4.6.0")] +[assembly: AssemblyFileVersion("4.6.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)]