From 49e15ce4247a53a54b968800a4d32887f5084aad Mon Sep 17 00:00:00 2001 From: ClemensF Date: Sat, 28 Mar 2020 21:53:38 +0100 Subject: [PATCH] Version 5.0: Reworked MapBase and MapPath --- MapControl.sln | 57 ++--- MapControl/Shared/MapBase.cs | 109 +++++---- MapControl/Shared/MapImageLayer.cs | 34 +-- MapControl/Shared/MapItemsControl.cs | 8 +- MapControl/Shared/MapPanel.cs | 23 +- MapControl/Shared/MapPath.cs | 142 +++++++++++ MapControl/Shared/MapPolygon.cs | 7 +- MapControl/Shared/MapPolyline.cs | 7 +- MapControl/Shared/MapScale.cs | 7 +- MapControl/Shared/MapShape.cs | 125 ---------- MapControl/Shared/MapTileLayer.cs | 17 +- MapControl/Shared/ViewTransform.cs | 55 +++-- MapControl/Shared/ViewportChangedEventArgs.cs | 2 +- MapControl/Shared/WmtsTileMatrixLayer.cs | 6 +- MapControl/Shared/WorldMercatorProjection.cs | 4 +- MapControl/UWP/MapBase.UWP.cs | 8 + MapControl/UWP/MapControl.UWP.csproj | 8 +- MapControl/UWP/MapGraticule.UWP.cs | 44 ++-- MapControl/UWP/MapPanel.UWP.cs | 8 +- .../UWP/{MapShape.UWP.cs => MapPath.UWP.cs} | 10 +- MapControl/UWP/Vector.UWP.cs | 10 + MapControl/WPF/MapBase.WPF.cs | 10 + MapControl/WPF/MapGraticule.WPF.cs | 14 +- MapControl/WPF/MapMultiPolygon.WPF.cs | 7 +- MapControl/WPF/MapPanel.WPF.cs | 10 +- .../WPF/{MapShape.WPF.cs => MapPath.WPF.cs} | 18 +- MapControlExtended.sln | 25 +- SampleApps/ProjectionDemo/MainWindow.xaml.cs | 2 +- SampleApps/UniversalApp/MainPage.xaml | 9 + SampleApps/WpfApplication/MainWindow.xaml | 31 ++- SampleApps/WpfApplication/MainWindow.xaml.cs | 6 +- .../WpfApplication/Properties/AssemblyInfo.cs | 14 -- .../WpfApplication/WpfApplication.csproj | 149 ++++-------- .../WpfApplication.csproj.user} | 4 +- SampleApps/WpfCoreApp/App.xaml | 7 - SampleApps/WpfCoreApp/App.xaml.cs | 8 - .../LocationToVisibilityConverter.cs | 36 --- SampleApps/WpfCoreApp/MainWindow.xaml | 221 ------------------ SampleApps/WpfCoreApp/MainWindow.xaml.cs | 91 -------- SampleApps/WpfCoreApp/OutlinedText.cs | 145 ------------ SampleApps/WpfCoreApp/WpfCoreApp.csproj | 36 --- 41 files changed, 466 insertions(+), 1068 deletions(-) create mode 100644 MapControl/Shared/MapPath.cs delete mode 100644 MapControl/Shared/MapShape.cs rename MapControl/UWP/{MapShape.UWP.cs => MapPath.UWP.cs} (89%) rename MapControl/WPF/{MapShape.WPF.cs => MapPath.WPF.cs} (83%) delete mode 100644 SampleApps/WpfApplication/Properties/AssemblyInfo.cs rename SampleApps/{WpfCoreApp/WpfCoreApp.csproj.user => WpfApplication/WpfApplication.csproj.user} (79%) delete mode 100644 SampleApps/WpfCoreApp/App.xaml delete mode 100644 SampleApps/WpfCoreApp/App.xaml.cs delete mode 100644 SampleApps/WpfCoreApp/LocationToVisibilityConverter.cs delete mode 100644 SampleApps/WpfCoreApp/MainWindow.xaml delete mode 100644 SampleApps/WpfCoreApp/MainWindow.xaml.cs delete mode 100644 SampleApps/WpfCoreApp/OutlinedText.cs delete mode 100644 SampleApps/WpfCoreApp/WpfCoreApp.csproj diff --git a/MapControl.sln b/MapControl.sln index e22a014f..0837cfbe 100644 --- a/MapControl.sln +++ b/MapControl.sln @@ -7,16 +7,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapControl", "MapControl", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{8F2103C2-78AF-4810-8FB9-67572F50C8FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.UWP", "MapControl\UWP\MapControl.UWP.csproj", "{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfCoreApp", "SampleApps\WpfCoreApp\WpfCoreApp.csproj", "{E9D15B9A-75F5-40A9-A582-9BFBB074C127}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapControl.WPF", "MapControl\WPF\MapControl.WPF.csproj", "{62F1726B-3144-49F4-8BCC-94160A3B2186}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,22 +27,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.Build.0 = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.ActiveCfg = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.Build.0 = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.ActiveCfg = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.Build.0 = Debug|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.Build.0 = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.ActiveCfg = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.Build.0 = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.ActiveCfg = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.Build.0 = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.ActiveCfg = Release|Any CPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.Build.0 = Release|Any CPU {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|x64 {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Build.0 = Debug|x64 {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Deploy.0 = Debug|x64 @@ -85,22 +67,6 @@ Global {9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x64.Build.0 = Release|Any CPU {9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.ActiveCfg = Release|Any CPU {9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.Build.0 = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|ARM.ActiveCfg = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|ARM.Build.0 = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x64.ActiveCfg = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x64.Build.0 = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x86.ActiveCfg = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x86.Build.0 = Debug|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|Any CPU.Build.0 = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|ARM.ActiveCfg = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|ARM.Build.0 = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x64.ActiveCfg = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x64.Build.0 = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x86.ActiveCfg = Release|Any CPU - {E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x86.Build.0 = Release|Any CPU {62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.Build.0 = Debug|Any CPU {62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -117,16 +83,31 @@ Global {62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x64.Build.0 = Release|Any CPU {62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.ActiveCfg = Release|Any CPU {62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.Build.0 = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|ARM.Build.0 = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x64.Build.0 = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x86.Build.0 = Debug|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|Any CPU.Build.0 = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|ARM.ActiveCfg = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|ARM.Build.0 = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x64.ActiveCfg = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x64.Build.0 = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x86.ActiveCfg = Release|Any CPU + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {9545F73C-9C35-4CF6-BAAE-19A0BAEBD344} = {52AECE49-F314-4F76-98F2-FA800F07824B} - {E9D15B9A-75F5-40A9-A582-9BFBB074C127} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {62F1726B-3144-49F4-8BCC-94160A3B2186} = {52AECE49-F314-4F76-98F2-FA800F07824B} + {CA60DFDB-0BE1-40F6-B575-CDC797A40E2E} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB} diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs index ce4d785f..6a9b7ee1 100644 --- a/MapControl/Shared/MapBase.cs +++ b/MapControl/Shared/MapBase.cs @@ -69,12 +69,12 @@ namespace MapControl private DoubleAnimation zoomLevelAnimation; private DoubleAnimation headingAnimation; private Location transformCenter; - private Point viewportCenter; + private Point viewCenter; private double centerLongitude; private bool internalPropertyChange; /// - /// Raised when the current viewport has changed. + /// Raised when the current map viewport has changed. /// public event EventHandler ViewportChanged; @@ -224,59 +224,56 @@ namespace MapControl } /// - /// Gets the transformation from cartesian map coordinates to viewport coordinates. + /// Gets the scaling factor from cartesian map coordinates to view coordinates, + /// i.e. pixels per meter, as a read-only dependency property. + /// + public double ViewScale + { + get { return (double)GetValue(ViewScaleProperty); } + private set { SetViewScale(value); } + } + + /// + /// Gets the ViewTransform instance that is used to transform between cartesian map coordinates + /// and view coordinates. /// public ViewTransform ViewTransform { get; } = new ViewTransform(); /// - /// Gets the transformation from cartesian map coordinates to viewport coordinates as MatrixTransform. + /// Gets a MatrixTransform that can be used to transform from cartesian map coordinates + /// to view coordinates. /// - public MatrixTransform ViewportTransform { get; } = new MatrixTransform(); + public MatrixTransform MapToViewTransform { get; } = new MatrixTransform(); /// - /// Gets the scaling transformation from meters to viewport coordinates at the Center location. + /// Gets the horizontal and vertical scaling factors from cartesian map coordinates to view + /// coordinates at the specified location, i.e. pixels per meter. /// - public ScaleTransform ScaleTransform { get; } = new ScaleTransform(); - - /// - /// Gets the transformation that rotates by the value of the Heading property. - /// - public RotateTransform RotateTransform { get; } = new RotateTransform(); - - /// - /// Gets the combination of ScaleTransform and RotateTransform - /// - public TransformGroup ScaleRotateTransform + public Vector GetScale(Location location) { - get - { - var transform = new TransformGroup(); - transform.Children.Add(ScaleTransform); - transform.Children.Add(RotateTransform); - return transform; - } + return ViewTransform.Scale * MapProjection.GetRelativeScale(location); } /// - /// Transforms a Location in geographic coordinates to a Point in viewport coordinates. + /// Transforms a Location in geographic coordinates to a Point in view coordinates. /// - public Point LocationToViewportPoint(Location location) + public Point LocationToView(Location location) { return ViewTransform.MapToView(MapProjection.LocationToMap(location)); } /// - /// Transforms a Point in viewport coordinates to a Location in geographic coordinates. + /// Transforms a Point in view coordinates to a Location in geographic coordinates. /// - public Location ViewportPointToLocation(Point point) + public Location ViewToLocation(Point point) { return MapProjection.MapToLocation(ViewTransform.ViewToMap(point)); } /// - /// Transforms a Rect in viewport coordinates to a BoundingBox in geographic coordinates. + /// Transforms a Rect in view coordinates to a BoundingBox in geographic coordinates. /// - public BoundingBox ViewportRectToBoundingBox(Rect rect) + public BoundingBox ViewRectToBoundingBox(Rect rect) { var p1 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y)); var p2 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y + rect.Height)); @@ -292,13 +289,13 @@ namespace MapControl } /// - /// Sets a temporary center point in viewport coordinates for scaling and rotation transformations. + /// Sets a temporary center point in view coordinates for scaling and rotation transformations. /// This center point is automatically reset when the Center property is set by application code. /// public void SetTransformCenter(Point center) { - transformCenter = ViewportPointToLocation(center); - viewportCenter = center; + transformCenter = ViewToLocation(center); + viewCenter = center; } /// @@ -307,11 +304,11 @@ namespace MapControl public void ResetTransformCenter() { transformCenter = null; - viewportCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d); + viewCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d); } /// - /// Changes the Center property according to the specified translation in viewport coordinates. + /// Changes the Center property according to the specified translation in view coordinates. /// public void TranslateMap(Vector translation) { @@ -323,21 +320,21 @@ namespace MapControl if (translation.X != 0d || translation.Y != 0d) { - Center = ViewportPointToLocation(viewportCenter - translation); + Center = ViewToLocation(viewCenter - translation); } } /// /// Changes the Center, Heading and ZoomLevel properties according to the specified - /// viewport coordinate translation, rotation and scale delta values. Rotation and scaling - /// is performed relative to the specified center point in viewport coordinates. + /// view coordinate translation, rotation and scale delta values. Rotation and scaling + /// is performed relative to the specified center point in view coordinates. /// public void TransformMap(Point center, Vector translation, double rotation, double scale) { if (rotation != 0d || scale != 1d) { - transformCenter = ViewportPointToLocation(center); - viewportCenter = center + translation; + transformCenter = ViewToLocation(center); + viewCenter = center + translation; if (rotation != 0d) { @@ -363,7 +360,7 @@ namespace MapControl /// /// Sets the value of the TargetZoomLevel property while retaining the specified center point - /// in viewport coordinates. + /// in view coordinates. /// public void ZoomMap(Point center, double zoomLevel) { @@ -378,16 +375,15 @@ namespace MapControl /// /// Sets the TargetZoomLevel and TargetCenter properties so that the specified bounding box - /// fits into the current viewport. The TargetHeading property is set to zero. + /// fits into the current view. The TargetHeading property is set to zero. /// public void ZoomToBounds(BoundingBox boundingBox) { var rect = MapProjection.BoundingBoxToRect(boundingBox); var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d); - var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height) - * MapProjection.Wgs84MetersPerDegree * 360d / 256d; + var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height); - TargetZoomLevel = Math.Log(scale, 2d); + TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale); TargetCenter = MapProjection.MapToLocation(center); TargetHeading = 0d; } @@ -703,16 +699,19 @@ namespace MapControl private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false) { var projection = MapProjection; - var viewportScale = 256d * Math.Pow(2d, ZoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree); - var center = transformCenter ?? Center; projection.Center = ProjectionCenter ?? Center; - ViewTransform.SetTransform(projection.LocationToMap(center), viewportCenter, viewportScale, Heading); + var center = transformCenter ?? Center; + var mapCenter = projection.LocationToMap(center); + + var viewScale = ViewTransform.ZoomLevelToScale(ZoomLevel); + + ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading); if (transformCenter != null) { - center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d)); + center = ViewToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d)); center.Longitude = Location.NormalizeLongitude(center.Longitude); if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude) @@ -733,18 +732,14 @@ namespace MapControl ResetTransformCenter(); projection.Center = ProjectionCenter ?? center; + mapCenter = projection.LocationToMap(center); - ViewTransform.SetTransform(projection.LocationToMap(center), viewportCenter, viewportScale, Heading); + ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading); } } - ViewportTransform.Matrix = ViewTransform.MapToViewMatrix; - - var scale = projection.GetRelativeScale(center); - ScaleTransform.ScaleX = scale.X * ViewTransform.Scale; - ScaleTransform.ScaleY = scale.Y * ViewTransform.Scale; - - RotateTransform.Angle = ViewTransform.Rotation; + ViewScale = ViewTransform.Scale; + MapToViewTransform.Matrix = ViewTransform.MapToViewMatrix; OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude)); diff --git a/MapControl/Shared/MapImageLayer.cs b/MapControl/Shared/MapImageLayer.cs index a8f92ba7..722f2a28 100644 --- a/MapControl/Shared/MapImageLayer.cs +++ b/MapControl/Shared/MapImageLayer.cs @@ -23,11 +23,14 @@ using System.Windows.Threading; namespace MapControl { /// - /// Map image layer. Fills the entire viewport with a map image, e.g. provided by a Web Map Service. + /// Map image layer. Fills the viewport with a single map image, e.g. provided by a Web Map Service. /// The image must be provided by the abstract GetImageAsync method. /// public abstract class MapImageLayer : MapPanel, IMapLayer { + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( + nameof(Description), typeof(string), typeof(MapImageLayer), new PropertyMetadata(null)); + public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register( nameof(MinLatitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN)); @@ -53,9 +56,6 @@ namespace MapControl public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register( nameof(UpdateWhileViewportChanging), typeof(bool), typeof(MapImageLayer), new PropertyMetadata(false)); - public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( - nameof(Description), typeof(string), typeof(MapImageLayer), new PropertyMetadata(null)); - public static readonly DependencyProperty MapBackgroundProperty = DependencyProperty.Register( nameof(MapBackground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null)); @@ -74,6 +74,16 @@ namespace MapControl updateTimer.Tick += async (s, e) => await UpdateImageAsync(); } + /// + /// Description of the MapImageLayer. + /// Used to display copyright information on top of the map. + /// + public string Description + { + get { return (string)GetValue(DescriptionProperty); } + set { SetValue(DescriptionProperty, value); } + } + /// /// Optional minimum latitude value. Default is NaN. /// @@ -120,9 +130,9 @@ namespace MapControl } /// - /// Relative size of the map image in relation to the current viewport size. + /// Relative size of the map image in relation to the current view size. /// Setting a value greater than one will let MapImageLayer request images that - /// are larger than the viewport, in order to support smooth panning. + /// are larger than the view, in order to support smooth panning. /// public double RelativeImageSize { @@ -148,16 +158,6 @@ namespace MapControl set { SetValue(UpdateWhileViewportChangingProperty, value); } } - /// - /// Description of the MapImageLayer. - /// Used to display copyright information on top of the map. - /// - public string Description - { - get { return (string)GetValue(DescriptionProperty); } - set { SetValue(DescriptionProperty, value); } - } - /// /// Optional foreground brush. /// Sets MapBase.Foreground if not null and the MapImageLayer is the base map layer. @@ -258,7 +258,7 @@ namespace MapControl var y = (ParentMap.RenderSize.Height - height) / 2d; var rect = new Rect(x, y, width, height); - BoundingBox = ParentMap.ViewportRectToBoundingBox(rect); + BoundingBox = ParentMap.ViewRectToBoundingBox(rect); if (BoundingBox != null) { diff --git a/MapControl/Shared/MapItemsControl.cs b/MapControl/Shared/MapItemsControl.cs index c67461d5..8a5f1f41 100644 --- a/MapControl/Shared/MapItemsControl.cs +++ b/MapControl/Shared/MapItemsControl.cs @@ -74,7 +74,7 @@ namespace MapControl { SelectItems(item => { - var pos = MapPanel.GetViewportPosition(ContainerFromItem(item)); + var pos = MapPanel.GetViewPosition(ContainerFromItem(item)); return pos.HasValue && predicate(pos.Value); }); } @@ -116,10 +116,10 @@ namespace MapControl } else if (shiftKey && SelectedItem != null) { - // Extended with Shift -> select items in viewport rectangle + // Extended with Shift -> select items in view rectangle - var p1 = MapPanel.GetViewportPosition(ContainerFromItem(SelectedItem)); - var p2 = MapPanel.GetViewportPosition(mapItem); + var p1 = MapPanel.GetViewPosition(ContainerFromItem(SelectedItem)); + var p2 = MapPanel.GetViewPosition(mapItem); if (p1.HasValue && p2.HasValue) { diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index 8b400c4c..ca335af4 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -58,9 +58,9 @@ namespace MapControl element.SetValue(BoundingBoxProperty, value); } - public static Point? GetViewportPosition(FrameworkElement element) + public static Point? GetViewPosition(FrameworkElement element) { - return (Point?)element.GetValue(ViewportPositionProperty); + return (Point?)element.GetValue(ViewPositionProperty); } public MapBase ParentMap @@ -118,9 +118,9 @@ namespace MapControl if (location != null) { - var viewportPosition = ArrangeElement(element, location); + var viewPosition = ArrangeElement(element, location); - SetViewportPosition(element, viewportPosition); + SetViewPosition(element, viewPosition); } else { @@ -135,7 +135,7 @@ namespace MapControl ArrangeElement(element, finalSize); } - SetViewportPosition(element, null); + SetViewPosition(element, null); } } } @@ -145,13 +145,13 @@ namespace MapControl private Point ArrangeElement(FrameworkElement element, Location location) { - var pos = parentMap.LocationToViewportPoint(location); + var pos = parentMap.LocationToView(location); if (parentMap.MapProjection.IsNormalCylindrical && (pos.X < 0d || pos.X > parentMap.RenderSize.Width || pos.Y < 0d || pos.Y > parentMap.RenderSize.Height)) { - pos = parentMap.LocationToViewportPoint(new Location( + pos = parentMap.LocationToView(new Location( location.Latitude, Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude))); } @@ -210,7 +210,7 @@ namespace MapControl var location = projection.MapToLocation(center); location.Longitude = Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude); - pos = parentMap.LocationToViewportPoint(location); + pos = parentMap.LocationToView(location); } rect.Width *= parentMap.ViewTransform.Scale; @@ -229,14 +229,15 @@ namespace MapControl element.Arrange(rect); var rotateTransform = element.RenderTransform as RotateTransform; + var rotation = parentMap.ViewTransform.Rotation; if (rotateTransform != null) { - rotateTransform.Angle = parentMap.Heading; + rotateTransform.Angle = rotation; } - else if (parentMap.Heading != 0d) + else if (rotation != 0d) { - rotateTransform = new RotateTransform { Angle = parentMap.Heading }; + rotateTransform = new RotateTransform { Angle = rotation }; element.RenderTransform = rotateTransform; element.RenderTransformOrigin = new Point(0.5, 0.5); } diff --git a/MapControl/Shared/MapPath.cs b/MapControl/Shared/MapPath.cs new file mode 100644 index 00000000..638b8cfe --- /dev/null +++ b/MapControl/Shared/MapPath.cs @@ -0,0 +1,142 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2020 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +#if WINDOWS_UWP +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#else +using System.Windows; +using System.Windows.Media; +#endif + +namespace MapControl +{ + /// + /// A path element with a Data property that holds a Geometry in cartesian map coordinates + /// or view coordinates. Cartesian coordinates can optionally be relative to an origin Location. + /// + public partial class MapPath : IMapElement + { + public static readonly DependencyProperty LocationProperty = DependencyProperty.Register( + nameof(Location), typeof(Location), typeof(MapPath), + new PropertyMetadata(null, (o, e) => ((MapPath)o).LocationOrViewportChanged())); + + private MapBase parentMap; + private MatrixTransform dataTransform; + private double longitudeOffset; + + public MapPath() + { + MapPanel.InitMapElement(this); + } + + /// + /// Gets or sets a Location that is used as + /// - either the origin point of a geometry specified in cartesian map units (meters) + /// - or as an optional value to constrain the view position of MapPaths with multiple + /// Locations (like MapPolyline or MapPolygon) to the visible map viewport, as done + /// for elements where the MapPanel.Location property is set. + /// + public Location Location + { + get { return (Location)GetValue(LocationProperty); } + set { SetValue(LocationProperty, value); } + } + + public MapBase ParentMap + { + get { return parentMap; } + set + { + if (parentMap != null) + { + parentMap.ViewportChanged -= OnViewportChanged; + } + + parentMap = value; + + if (parentMap != null) + { + parentMap.ViewportChanged += OnViewportChanged; + } + + LocationOrViewportChanged(); + } + } + + private void OnViewportChanged(object sender, ViewportChangedEventArgs e) + { + LocationOrViewportChanged(); + } + + private void LocationOrViewportChanged() + { + longitudeOffset = 0d; + + if (parentMap != null && parentMap.MapProjection.IsNormalCylindrical && Location != null) + { + var viewPos = LocationToView(Location); + + if (viewPos.X < 0d || viewPos.X > parentMap.RenderSize.Width || + viewPos.Y < 0d || viewPos.Y > parentMap.RenderSize.Height) + { + longitudeOffset = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude) - Location.Longitude; + } + } + + UpdateData(); + } + + protected virtual void UpdateData() + { + if (parentMap != null && Data != null) + { + if (dataTransform == null) + { + Data.Transform = dataTransform = new MatrixTransform(); + } + + if (Location != null) + { + var viewPos = LocationToView(Location); + var scale = parentMap.GetScale(Location); + var matrix = new Matrix(scale.X, 0, 0, scale.Y, 0, 0); + matrix.Rotate(parentMap.Heading); + matrix.Translate(viewPos.X, viewPos.Y); + dataTransform.Matrix = matrix; + } + else + { + dataTransform.Matrix = parentMap.ViewTransform.MapToViewMatrix; + } + } + } + + protected Point LocationToMap(Location location) + { + if (longitudeOffset != 0d) + { + location = new Location(location.Latitude, location.Longitude + longitudeOffset); + } + + var point = parentMap.MapProjection.LocationToMap(location); + + if (point.Y == double.PositiveInfinity) + { + point.Y = 1e9; + } + else if (point.X == double.NegativeInfinity) + { + point.Y = -1e9; + } + + return point; + } + + protected Point LocationToView(Location location) + { + return parentMap.ViewTransform.MapToView(LocationToMap(location)); + } + } +} diff --git a/MapControl/Shared/MapPolygon.cs b/MapControl/Shared/MapPolygon.cs index c6a27933..06a18eef 100644 --- a/MapControl/Shared/MapPolygon.cs +++ b/MapControl/Shared/MapPolygon.cs @@ -17,7 +17,7 @@ namespace MapControl /// /// A polygon defined by a collection of Locations. /// - public class MapPolygon : MapShape + public class MapPolygon : MapPath { public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register( nameof(Locations), typeof(IEnumerable), typeof(MapPolygon), @@ -35,6 +35,11 @@ namespace MapControl set { SetValue(LocationsProperty, value); } } + public MapPolygon() + { + Data = new PathGeometry(); + } + protected override void UpdateData() { var figures = ((PathGeometry)Data).Figures; diff --git a/MapControl/Shared/MapPolyline.cs b/MapControl/Shared/MapPolyline.cs index 9605791e..a2df81db 100644 --- a/MapControl/Shared/MapPolyline.cs +++ b/MapControl/Shared/MapPolyline.cs @@ -17,7 +17,7 @@ namespace MapControl /// /// A polyline defined by a collection of Locations. /// - public class MapPolyline : MapShape + public class MapPolyline : MapPath { public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register( nameof(Locations), typeof(IEnumerable), typeof(MapPolyline), @@ -35,6 +35,11 @@ namespace MapControl set { SetValue(LocationsProperty, value); } } + public MapPolyline() + { + Data = new PathGeometry(); + } + protected override void UpdateData() { var figures = ((PathGeometry)Data).Figures; diff --git a/MapControl/Shared/MapScale.cs b/MapControl/Shared/MapScale.cs index 3a80e4b8..a2c8d36c 100644 --- a/MapControl/Shared/MapScale.cs +++ b/MapControl/Shared/MapScale.cs @@ -59,9 +59,10 @@ namespace MapControl { var size = new Size(); - if (ParentMap != null && ParentMap.ScaleTransform.ScaleX > 0d) + if (ParentMap != null) { - var length = MinWidth / ParentMap.ScaleTransform.ScaleX; + var scale = ParentMap.GetScale(ParentMap.Center).X; + var length = MinWidth / scale; var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length))); if (length / magnitude < 2d) @@ -77,7 +78,7 @@ namespace MapControl length = 10d * magnitude; } - size.Width = length * ParentMap.ScaleTransform.ScaleX + StrokeThickness + Padding.Left + Padding.Right; + size.Width = length * scale + StrokeThickness + Padding.Left + Padding.Right; size.Height = 1.25 * FontSize + StrokeThickness + Padding.Top + Padding.Bottom; var x1 = Padding.Left + StrokeThickness / 2d; diff --git a/MapControl/Shared/MapShape.cs b/MapControl/Shared/MapShape.cs deleted file mode 100644 index 3ef8fc01..00000000 --- a/MapControl/Shared/MapShape.cs +++ /dev/null @@ -1,125 +0,0 @@ -// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control -// © 2020 Clemens Fischer -// Licensed under the Microsoft Public License (Ms-PL) - -#if WINDOWS_UWP -using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; -#else -using System.Windows; -using System.Windows.Media; -#endif - -namespace MapControl -{ - /// - /// Base class for MapPolyline and MapPolygon. - /// - public abstract partial class MapShape : IMapElement - { - public static readonly DependencyProperty LocationProperty = DependencyProperty.Register( - nameof(Location), typeof(Location), typeof(MapShape), - new PropertyMetadata(null, (o, e) => ((MapShape)o).LocationPropertyChanged())); - - /// - /// Gets or sets an optional Location to constrain the viewport position to the visible - /// map viewport, as done for elements where the MapPanel.Location property is set. - /// - public Location Location - { - get { return (Location)GetValue(LocationProperty); } - set { SetValue(LocationProperty, value); } - } - - private void LocationPropertyChanged() - { - if (parentMap != null) - { - UpdateData(); - } - } - - private MapBase parentMap; - - public MapBase ParentMap - { - get { return parentMap; } - set - { - if (parentMap != null) - { - parentMap.ViewportChanged -= OnViewportChanged; - } - - parentMap = value; - - if (parentMap != null) - { - parentMap.ViewportChanged += OnViewportChanged; - } - - UpdateData(); - } - } - - private void OnViewportChanged(object sender, ViewportChangedEventArgs e) - { - UpdateData(); - } - - protected abstract void UpdateData(); - - protected MapShape() - : this(new PathGeometry()) - { - } - - protected MapShape(Geometry data) - { - Data = data; - - MapPanel.InitMapElement(this); - } - - protected Point LocationToMap(Location location) - { - var point = parentMap.MapProjection.LocationToMap(location); - - if (point.Y == double.PositiveInfinity) - { - point.Y = 1e9; - } - else if (point.X == double.NegativeInfinity) - { - point.Y = -1e9; - } - - return point; - } - - protected Point LocationToViewportPoint(Location location) - { - return parentMap.ViewTransform.MapToView(LocationToMap(location)); - } - - protected double GetLongitudeOffset() - { - var longitudeOffset = 0d; - - if (parentMap.MapProjection.IsNormalCylindrical && Location != null) - { - var viewportPosition = LocationToViewportPoint(Location); - - if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width || - viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height) - { - var nearestLongitude = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude); - - longitudeOffset = nearestLongitude - Location.Longitude; - } - } - - return longitudeOffset; - } - } -} diff --git a/MapControl/Shared/MapTileLayer.cs b/MapControl/Shared/MapTileLayer.cs index 6aa6a7d4..86d35ab1 100644 --- a/MapControl/Shared/MapTileLayer.cs +++ b/MapControl/Shared/MapTileLayer.cs @@ -17,7 +17,7 @@ using System.Windows.Media; namespace MapControl { /// - /// Fills the map viewport with map tiles from a TileSource. + /// Fills the viewport with map tiles from a TileSource. /// public class MapTileLayer : MapTileLayerBase { @@ -26,11 +26,6 @@ namespace MapControl public static readonly Point TileMatrixTopLeft = new Point( -180d * MapProjection.Wgs84MetersPerDegree, 180d * MapProjection.Wgs84MetersPerDegree); - public static double TileMatrixScale(int zoomLevel) - { - return (TileSize << zoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree); - } - /// /// A default MapTileLayer using OpenStreetMap data. /// @@ -117,18 +112,22 @@ namespace MapControl // var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin); + var tileMatrixScale = ViewTransform.ZoomLevelToScale(TileMatrix.ZoomLevel); + ((MatrixTransform)RenderTransform).Matrix = ParentMap.ViewTransform.GetTileLayerTransform( - TileMatrixScale(TileMatrix.ZoomLevel), TileMatrixTopLeft, tileMatrixOrigin); + tileMatrixScale, TileMatrixTopLeft, tileMatrixOrigin); } private bool SetTileMatrix() { var tileMatrixZoomLevel = (int)Math.Floor(ParentMap.ZoomLevel + 0.001); // avoid rounding issues - // bounds in tile pixels from viewport size + var tileMatrixScale = ViewTransform.ZoomLevelToScale(tileMatrixZoomLevel); + + // bounds in tile pixels from view size // var tileBounds = ParentMap.ViewTransform.GetTileMatrixBounds( - TileMatrixScale(tileMatrixZoomLevel), TileMatrixTopLeft, ParentMap.RenderSize); + tileMatrixScale, TileMatrixTopLeft, ParentMap.RenderSize); // tile column and row index bounds // diff --git a/MapControl/Shared/ViewTransform.cs b/MapControl/Shared/ViewTransform.cs index dd7ff6cd..f7dc0663 100644 --- a/MapControl/Shared/ViewTransform.cs +++ b/MapControl/Shared/ViewTransform.cs @@ -2,6 +2,7 @@ // © 2020 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) +using System; #if WINDOWS_UWP using Windows.Foundation; using Windows.UI.Xaml.Media; @@ -13,22 +14,14 @@ using System.Windows.Media; namespace MapControl { /// - /// Defines the transformation between cartesian map coordinates and viewport coordinates. + /// Defines the transformation between cartesian map coordinates in meters + /// and view coordinates in pixels. /// public class ViewTransform { /// - /// Gets the transform matrix from cartesian map coordinates to viewport coordinates. - /// - public Matrix MapToViewMatrix { get; private set; } - - /// - /// Gets the transform matrix from viewport coordinates to cartesian map coordinates. - /// - public Matrix ViewToMapMatrix { get; private set; } - - /// - /// Gets the scaling factor from cartesian map coordinates to viewport coordinates. + /// Gets the scaling factor from cartesian map coordinates to view coordinates, + /// i.e. pixels per meter. /// public double Scale { get; private set; } @@ -38,7 +31,17 @@ namespace MapControl public double Rotation { get; private set; } /// - /// Transforms a Point from cartesian map coordinates to viewport coordinates. + /// Gets the transform matrix from cartesian map coordinates to view coordinates. + /// + public Matrix MapToViewMatrix { get; private set; } + + /// + /// Gets the transform matrix from view coordinates to cartesian map coordinates. + /// + public Matrix ViewToMapMatrix { get; private set; } + + /// + /// Transforms a Point from cartesian map coordinates to view coordinates. /// public Point MapToView(Point point) { @@ -46,14 +49,14 @@ namespace MapControl } /// - /// Transforms a Point from viewport coordinates to cartesian map coordinates. + /// Transforms a Point from view coordinates to cartesian map coordinates. /// public Point ViewToMap(Point point) { return ViewToMapMatrix.Transform(point); } - public void SetTransform(Point mapCenter, Point viewportCenter, double scale, double rotation) + public void SetTransform(Point mapCenter, Point viewCenter, double scale, double rotation) { Scale = scale; Rotation = rotation; @@ -61,7 +64,7 @@ namespace MapControl var transform = new Matrix(Scale, 0d, 0d, -Scale, -Scale * mapCenter.X, Scale * mapCenter.Y); transform.Rotate(Rotation); - transform.Translate(viewportCenter.X, viewportCenter.Y); + transform.Translate(viewCenter.X, viewCenter.Y); MapToViewMatrix = transform; @@ -83,7 +86,7 @@ namespace MapControl tileMatrixTopLeft.X + tileMatrixOrigin.X / tileMatrixScale, tileMatrixTopLeft.Y - tileMatrixOrigin.Y / tileMatrixScale); - // tile matrix origin in viewport coordinates + // tile matrix origin in view coordinates // var viewOrigin = MapToView(mapOrigin); @@ -92,14 +95,14 @@ namespace MapControl return transform; } - public Rect GetTileMatrixBounds(double tileMatrixScale, Point tileMatrixTopLeft, Size viewportSize) + public Rect GetTileMatrixBounds(double tileMatrixScale, Point tileMatrixTopLeft, Size viewSize) { var transformScale = tileMatrixScale / Scale; var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d); transform.Rotate(-Rotation); - // viewport origin in map coordinates + // view origin in map coordinates // var origin = ViewToMap(new Point()); @@ -109,10 +112,20 @@ namespace MapControl tileMatrixScale * (origin.X - tileMatrixTopLeft.X), tileMatrixScale * (tileMatrixTopLeft.Y - origin.Y)); - // transform viewport bounds to tile pixel bounds + // transform view bounds to tile pixel bounds // return new MatrixTransform { Matrix = transform } - .TransformBounds(new Rect(0d, 0d, viewportSize.Width, viewportSize.Height)); + .TransformBounds(new Rect(0d, 0d, viewSize.Width, viewSize.Height)); + } + + public static double ZoomLevelToScale(double zoomLevel) + { + return 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree); + } + + public static double ScaleToZoomLevel(double scale) + { + return Math.Log(scale * 360d * MapProjection.Wgs84MetersPerDegree / 256d, 2d); } } } diff --git a/MapControl/Shared/ViewportChangedEventArgs.cs b/MapControl/Shared/ViewportChangedEventArgs.cs index e80a0572..46527a8a 100644 --- a/MapControl/Shared/ViewportChangedEventArgs.cs +++ b/MapControl/Shared/ViewportChangedEventArgs.cs @@ -16,7 +16,7 @@ namespace MapControl /// /// Indicates if the map projection has changed, i.e. if a MapTileLayer or MapImageLayer should - /// be updated immediately, or MapShape Data in cartesian map coordinates should be recalculated. + /// be updated immediately, or MapPath Data in cartesian map coordinates should be recalculated. /// public bool ProjectionChanged { get; } diff --git a/MapControl/Shared/WmtsTileMatrixLayer.cs b/MapControl/Shared/WmtsTileMatrixLayer.cs index bf2c881b..86a6dc46 100644 --- a/MapControl/Shared/WmtsTileMatrixLayer.cs +++ b/MapControl/Shared/WmtsTileMatrixLayer.cs @@ -47,11 +47,11 @@ namespace MapControl viewTransform.GetTileLayerTransform(TileMatrix.Scale, TileMatrix.TopLeft, tileMatrixOrigin); } - public bool SetBounds(ViewTransform viewTransform, Size viewportSize) + public bool SetBounds(ViewTransform viewTransform, Size viewSize) { - // bounds in tile pixels from viewport size + // bounds in tile pixels from view size // - var bounds = viewTransform.GetTileMatrixBounds(TileMatrix.Scale, TileMatrix.TopLeft, viewportSize); + var bounds = viewTransform.GetTileMatrixBounds(TileMatrix.Scale, TileMatrix.TopLeft, viewSize); // tile column and row index bounds // diff --git a/MapControl/Shared/WorldMercatorProjection.cs b/MapControl/Shared/WorldMercatorProjection.cs index 590cd835..4d3ddcdb 100644 --- a/MapControl/Shared/WorldMercatorProjection.cs +++ b/MapControl/Shared/WorldMercatorProjection.cs @@ -15,11 +15,11 @@ namespace MapControl /// public class WorldMercatorProjection : MapProjection { - private static readonly double maxLatitude = YToLatitude(180d); - public static double ConvergenceTolerance = 1e-6; public static int MaxIterations = 10; + private static readonly double maxLatitude = YToLatitude(180d); + public WorldMercatorProjection() { CrsId = "EPSG:3395"; diff --git a/MapControl/UWP/MapBase.UWP.cs b/MapControl/UWP/MapBase.UWP.cs index b4b10375..02ed8374 100644 --- a/MapControl/UWP/MapBase.UWP.cs +++ b/MapControl/UWP/MapBase.UWP.cs @@ -39,6 +39,9 @@ namespace MapControl nameof(TargetHeading), typeof(double), typeof(MapBase), new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue))); + public static readonly DependencyProperty ViewScaleProperty = DependencyProperty.Register( + nameof(ViewScale), typeof(double), typeof(MapBase), new PropertyMetadata(0d)); + internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register( "CenterPoint", typeof(Windows.Foundation.Point), typeof(MapBase), new PropertyMetadata(new Windows.Foundation.Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Windows.Foundation.Point)e.NewValue))); @@ -62,6 +65,11 @@ namespace MapControl }; } + private void SetViewScale(double scale) + { + SetValue(ViewScaleProperty, scale); + } + private void CenterPointPropertyChanged(Windows.Foundation.Point center) { CenterPointPropertyChanged(new Location(center.Y, center.X)); diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index 8760dd14..8858827e 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -107,6 +107,9 @@ MapPanel.cs + + MapPath.cs + MapPolygon.cs @@ -119,9 +122,6 @@ MapScale.cs - - MapShape.cs - MapTileLayer.cs @@ -188,7 +188,7 @@ - + diff --git a/MapControl/UWP/MapGraticule.UWP.cs b/MapControl/UWP/MapGraticule.UWP.cs index 0725ea7e..f5d61348 100644 --- a/MapControl/UWP/MapGraticule.UWP.cs +++ b/MapControl/UWP/MapGraticule.UWP.cs @@ -4,11 +4,9 @@ using System; using Windows.Foundation; -using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Shapes; -using Windows.UI.Xaml.Data; namespace MapControl { @@ -40,7 +38,7 @@ namespace MapControl Children.Add(path); } - var bounds = map.ViewportRectToBoundingBox(new Rect(0d, 0d, map.RenderSize.Width, map.RenderSize.Height)); + var bounds = map.ViewRectToBoundingBox(new Rect(0d, 0d, map.RenderSize.Width, map.RenderSize.Height)); var lineDistance = GetLineDistance(); var labelStart = new Location( @@ -66,14 +64,14 @@ namespace MapControl { var figure = new PathFigure { - StartPoint = map.LocationToViewportPoint(new Location(lat, lineStart.Longitude)), + StartPoint = map.LocationToView(new Location(lat, lineStart.Longitude)), IsClosed = false, IsFilled = false }; figure.Segments.Add(new LineSegment { - Point = map.LocationToViewportPoint(new Location(lat, lineEnd.Longitude)) + Point = map.LocationToView(new Location(lat, lineEnd.Longitude)) }); geometry.Figures.Add(figure); @@ -83,14 +81,14 @@ namespace MapControl { var figure = new PathFigure { - StartPoint = map.LocationToViewportPoint(new Location(lineStart.Latitude, lon)), + StartPoint = map.LocationToView(new Location(lineStart.Latitude, lon)), IsClosed = false, IsFilled = false }; figure.Segments.Add(new LineSegment { - Point = map.LocationToViewportPoint(new Location(lineEnd.Latitude, lon)) + Point = map.LocationToView(new Location(lineEnd.Latitude, lon)) }); geometry.Figures.Add(figure); @@ -111,22 +109,18 @@ namespace MapControl } else { - var renderTransform = new TransformGroup(); - renderTransform.Children.Add(new TranslateTransform()); - renderTransform.Children.Add(map.RotateTransform); - renderTransform.Children.Add(new TranslateTransform()); - - label = new TextBlock { RenderTransform = renderTransform }; - if (FontFamily != null) - { - label.SetBinding(TextBlock.FontFamilyProperty, GetBinding(FontFamilyProperty, nameof(FontFamily))); - } + label = new TextBlock { RenderTransform = new MatrixTransform() }; label.SetBinding(TextBlock.FontSizeProperty, GetBinding(FontSizeProperty, nameof(FontSize))); label.SetBinding(TextBlock.FontStyleProperty, GetBinding(FontStyleProperty, nameof(FontStyle))); label.SetBinding(TextBlock.FontStretchProperty, GetBinding(FontStretchProperty, nameof(FontStretch))); label.SetBinding(TextBlock.FontWeightProperty, GetBinding(FontWeightProperty, nameof(FontWeight))); label.SetBinding(TextBlock.ForegroundProperty, GetBinding(ForegroundProperty, nameof(Foreground))); + if (FontFamily != null) + { + label.SetBinding(TextBlock.FontFamilyProperty, GetBinding(FontFamilyProperty, nameof(FontFamily))); + } + Children.Add(label); } @@ -135,10 +129,6 @@ namespace MapControl 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) @@ -153,10 +143,14 @@ namespace MapControl { var label = (TextBlock)Children[i]; var location = (Location)label.Tag; - var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2]; - var viewportPosition = map.LocationToViewportPoint(location); - viewportTransform.X = viewportPosition.X; - viewportTransform.Y = viewportPosition.Y; + var viewPosition = map.LocationToView(location); + var matrix = new Matrix(1, 0, 0, 1, 0, 0); + + matrix.Translate(StrokeThickness / 2d + 2d, -label.DesiredSize.Height / 2d); + matrix.Rotate(map.ViewTransform.Rotation); + matrix.Translate(viewPosition.X, viewPosition.Y); + + ((MatrixTransform)label.RenderTransform).Matrix = matrix; } } else if (path != null) diff --git a/MapControl/UWP/MapPanel.UWP.cs b/MapControl/UWP/MapPanel.UWP.cs index be19e7f3..6a840151 100644 --- a/MapControl/UWP/MapPanel.UWP.cs +++ b/MapControl/UWP/MapPanel.UWP.cs @@ -20,8 +20,8 @@ namespace MapControl public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached( "ParentMap", typeof(MapBase), typeof(MapPanel), new PropertyMetadata(null, ParentMapPropertyChanged)); - private static readonly DependencyProperty ViewportPositionProperty = DependencyProperty.RegisterAttached( - "ViewportPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata(null)); + private static readonly DependencyProperty ViewPositionProperty = DependencyProperty.RegisterAttached( + "ViewPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata(null)); public static void InitMapElement(FrameworkElement element) { @@ -61,9 +61,9 @@ namespace MapControl ?? FindParentMap(parent)); } - private static void SetViewportPosition(FrameworkElement element, Point? viewportPosition) + private static void SetViewPosition(FrameworkElement element, Point? viewPosition) { - element.SetValue(ViewportPositionProperty, viewportPosition); + element.SetValue(ViewPositionProperty, viewPosition); } } } diff --git a/MapControl/UWP/MapShape.UWP.cs b/MapControl/UWP/MapPath.UWP.cs similarity index 89% rename from MapControl/UWP/MapShape.UWP.cs rename to MapControl/UWP/MapPath.UWP.cs index 9003ccbe..294da581 100644 --- a/MapControl/UWP/MapShape.UWP.cs +++ b/MapControl/UWP/MapPath.UWP.cs @@ -12,7 +12,7 @@ using Windows.UI.Xaml.Shapes; namespace MapControl { - public abstract partial class MapShape : Path + public partial class MapPath : Path { protected void DataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { @@ -40,13 +40,7 @@ namespace MapControl { if (locations != null && locations.Count() >= 2) { - var offset = GetLongitudeOffset(); - if (offset != 0d) - { - locations = locations.Select(loc => new Location(loc.Latitude, loc.Longitude + offset)); - } - - var points = locations.Select(loc => LocationToViewportPoint(loc)).ToList(); + var points = locations.Select(loc => LocationToView(loc)).ToList(); if (closed) { points.Add(points[0]); diff --git a/MapControl/UWP/Vector.UWP.cs b/MapControl/UWP/Vector.UWP.cs index 988163a0..13dd882c 100644 --- a/MapControl/UWP/Vector.UWP.cs +++ b/MapControl/UWP/Vector.UWP.cs @@ -50,6 +50,16 @@ namespace MapControl return new Vector(v1.X - v2.X, v1.Y - v2.Y); } + public static Vector operator *(double f, Vector v) + { + return new Vector(f * v.X, f * v.Y); + } + + public static Vector operator *(Vector v, double f) + { + return new Vector(f * v.X, f * v.Y); + } + public static bool operator ==(Vector v1, Vector v2) { return v1.X == v2.X && v1.Y == v2.Y; diff --git a/MapControl/WPF/MapBase.WPF.cs b/MapControl/WPF/MapBase.WPF.cs index 66754f4c..4eec0360 100644 --- a/MapControl/WPF/MapBase.WPF.cs +++ b/MapControl/WPF/MapBase.WPF.cs @@ -43,6 +43,11 @@ namespace MapControl 0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue))); + private static readonly DependencyPropertyKey ViewScalePropertyKey = DependencyProperty.RegisterReadOnly( + nameof(ViewScale), typeof(double), typeof(MapBase), new PropertyMetadata(0d)); + + public static readonly DependencyProperty ViewScaleProperty = ViewScalePropertyKey.DependencyProperty; + private static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register( "CenterPoint", typeof(Point), typeof(MapBase), new PropertyMetadata(new Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue))); @@ -61,6 +66,11 @@ namespace MapControl UpdateTransform(); } + private void SetViewScale(double scale) + { + SetValue(ViewScalePropertyKey, scale); + } + private void CenterPointPropertyChanged(Point center) { CenterPointPropertyChanged(new Location(center.Y, center.X)); diff --git a/MapControl/WPF/MapGraticule.WPF.cs b/MapControl/WPF/MapGraticule.WPF.cs index 5200671c..ad9ebfe0 100644 --- a/MapControl/WPF/MapGraticule.WPF.cs +++ b/MapControl/WPF/MapGraticule.WPF.cs @@ -56,7 +56,7 @@ namespace MapControl private void DrawCylindricalGraticule(DrawingContext drawingContext, double lineDistance, string labelFormat) { - var boundingBox = ParentMap.ViewportRectToBoundingBox(new Rect(ParentMap.RenderSize)); + var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(ParentMap.RenderSize)); var latLabelStart = Math.Ceiling(boundingBox.South / lineDistance) * lineDistance; var lonLabelStart = Math.Ceiling(boundingBox.West / lineDistance) * lineDistance; var latLabels = new List - public class MapMultiPolygon : MapShape + public class MapMultiPolygon : MapPath { public static readonly DependencyProperty PolygonsProperty = DependencyProperty.Register( nameof(Polygons), typeof(IEnumerable>), typeof(MapMultiPolygon), @@ -31,6 +31,11 @@ namespace MapControl set { SetValue(PolygonsProperty, value); } } + public MapMultiPolygon() + { + Data = new PathGeometry(); + } + protected override void UpdateData() { var figures = ((PathGeometry)Data).Figures; diff --git a/MapControl/WPF/MapPanel.WPF.cs b/MapControl/WPF/MapPanel.WPF.cs index 3ba9c49c..e91cedc1 100644 --- a/MapControl/WPF/MapPanel.WPF.cs +++ b/MapControl/WPF/MapPanel.WPF.cs @@ -20,11 +20,11 @@ namespace MapControl "ParentMap", typeof(MapBase), typeof(MapPanel), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged)); - private static readonly DependencyPropertyKey ViewportPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "ViewportPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata()); + private static readonly DependencyPropertyKey ViewPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly( + "ViewPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata()); public static readonly DependencyProperty ParentMapProperty = ParentMapPropertyKey.DependencyProperty; - public static readonly DependencyProperty ViewportPositionProperty = ViewportPositionPropertyKey.DependencyProperty; + public static readonly DependencyProperty ViewPositionProperty = ViewPositionPropertyKey.DependencyProperty; public static MapBase GetParentMap(FrameworkElement element) { @@ -39,9 +39,9 @@ namespace MapControl } } - private static void SetViewportPosition(FrameworkElement element, Point? viewportPosition) + private static void SetViewPosition(FrameworkElement element, Point? viewPosition) { - element.SetValue(ViewportPositionPropertyKey, viewportPosition); + element.SetValue(ViewPositionPropertyKey, viewPosition); } } } diff --git a/MapControl/WPF/MapShape.WPF.cs b/MapControl/WPF/MapPath.WPF.cs similarity index 83% rename from MapControl/WPF/MapShape.WPF.cs rename to MapControl/WPF/MapPath.WPF.cs index 0e13e898..3feeff47 100644 --- a/MapControl/WPF/MapShape.WPF.cs +++ b/MapControl/WPF/MapPath.WPF.cs @@ -12,9 +12,15 @@ using System.Windows.Shapes; namespace MapControl { - public abstract partial class MapShape : Shape, IWeakEventListener + public partial class MapPath : Shape, IWeakEventListener { - public Geometry Data { get; } + public static readonly DependencyProperty DataProperty = Path.DataProperty.AddOwner(typeof(MapPath)); + + public Geometry Data + { + get { return (Geometry)GetValue(DataProperty); } + set { SetValue(DataProperty, value); } + } protected override Geometry DefiningGeometry { @@ -48,13 +54,7 @@ namespace MapControl { if (locations != null && locations.Count() >= 2) { - var offset = GetLongitudeOffset(); - if (offset != 0d) - { - locations = locations.Select(loc => new Location(loc.Latitude, loc.Longitude + offset)); - } - - var points = locations.Select(loc => LocationToViewportPoint(loc)); + var points = locations.Select(loc => LocationToView(loc)); var figure = new PathFigure { StartPoint = points.First(), diff --git a/MapControlExtended.sln b/MapControlExtended.sln index a0447fea..628515a8 100644 --- a/MapControlExtended.sln +++ b/MapControlExtended.sln @@ -29,7 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapProjections", "MapProjec EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.WPF", "MapProjections\WPF\MapProjections.WPF.csproj", "{426C21C0-5F14-491F-BCD1-6D2993510420}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}" EndProject @@ -45,8 +45,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.UWP", "SQLiteCa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.WPF", "SQLiteCache\WPF\SQLiteCache.WPF.csproj", "{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfCoreApp", "SampleApps\WpfCoreApp\WpfCoreApp.csproj", "{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -347,26 +345,6 @@ Global {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x64.Build.0 = Release|Any CPU {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.ActiveCfg = Release|Any CPU {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.Build.0 = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM.ActiveCfg = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM.Build.0 = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM64.Build.0 = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x64.ActiveCfg = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x64.Build.0 = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x86.ActiveCfg = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x86.Build.0 = Debug|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|Any CPU.Build.0 = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM.ActiveCfg = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM.Build.0 = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM64.ActiveCfg = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM64.Build.0 = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x64.ActiveCfg = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x64.Build.0 = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x86.ActiveCfg = Release|Any CPU - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -386,7 +364,6 @@ Global {BE08B7BC-8C89-4837-BCE7-EDDDABEAB372} = {2FDC8B91-FB95-4C57-8183-63587FBFE180} {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A} {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A} - {43380AAB-EE6E-40BF-90EB-FFD86F885CAF} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB} diff --git a/SampleApps/ProjectionDemo/MainWindow.xaml.cs b/SampleApps/ProjectionDemo/MainWindow.xaml.cs index 0c7e63ff..917c1d5a 100644 --- a/SampleApps/ProjectionDemo/MainWindow.xaml.cs +++ b/SampleApps/ProjectionDemo/MainWindow.xaml.cs @@ -66,7 +66,7 @@ namespace ProjectionDemo var map = (MapBase)sender; var pos = e.GetPosition(map); - viewModel.PushpinLocation = map.ViewportPointToLocation(pos); + viewModel.PushpinLocation = map.ViewToLocation(pos); } } diff --git a/SampleApps/UniversalApp/MainPage.xaml b/SampleApps/UniversalApp/MainPage.xaml index 3c72eb44..d8b1f027 100644 --- a/SampleApps/UniversalApp/MainPage.xaml +++ b/SampleApps/UniversalApp/MainPage.xaml @@ -130,6 +130,15 @@ + + + + + + + + + diff --git a/SampleApps/WpfApplication/MainWindow.xaml b/SampleApps/WpfApplication/MainWindow.xaml index f68b5e4e..67910c83 100644 --- a/SampleApps/WpfApplication/MainWindow.xaml +++ b/SampleApps/WpfApplication/MainWindow.xaml @@ -1,12 +1,11 @@ - + @@ -88,7 +87,7 @@ - + @@ -159,17 +158,17 @@ - - - - - + + + + + - + diff --git a/SampleApps/WpfApplication/MainWindow.xaml.cs b/SampleApps/WpfApplication/MainWindow.xaml.cs index 6dc464d0..f73ca188 100644 --- a/SampleApps/WpfApplication/MainWindow.xaml.cs +++ b/SampleApps/WpfApplication/MainWindow.xaml.cs @@ -12,7 +12,7 @@ namespace WpfApplication public MainWindow() { ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application"); - //TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder); + TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder); //TileImageLoader.Cache = new MapControl.Caching.FileDbCache(TileImageLoader.DefaultCacheFolder); //TileImageLoader.Cache = new MapControl.Caching.SQLiteCache(TileImageLoader.DefaultCacheFolder); //TileImageLoader.Cache = null; @@ -26,7 +26,7 @@ namespace WpfApplication { //map.ZoomMap(e.GetPosition(map), Math.Floor(map.ZoomLevel + 1.5)); //map.ZoomToBounds(new BoundingBox(53, 7, 54, 9)); - map.TargetCenter = map.ViewportPointToLocation(e.GetPosition(map)); + map.TargetCenter = map.ViewToLocation(e.GetPosition(map)); } } @@ -40,7 +40,7 @@ namespace WpfApplication private void MapMouseMove(object sender, MouseEventArgs e) { - var location = map.ViewportPointToLocation(e.GetPosition(map)); + var location = map.ViewToLocation(e.GetPosition(map)); var latitude = (int)Math.Round(location.Latitude * 60000d); var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d); var latHemisphere = 'N'; diff --git a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs b/SampleApps/WpfApplication/Properties/AssemblyInfo.cs deleted file mode 100644 index 82c6a4bf..00000000 --- a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("WPF Sample Application")] -[assembly: AssemblyDescription("XAML Map Control WPF Sample Application")] -[assembly: AssemblyProduct("XAML Map Control")] -[assembly: AssemblyCompany("Clemens Fischer")] -[assembly: AssemblyCopyright("Copyright © 2020 Clemens Fischer")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("5.0.0")] -[assembly: AssemblyFileVersion("5.0.0")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] diff --git a/SampleApps/WpfApplication/WpfApplication.csproj b/SampleApps/WpfApplication/WpfApplication.csproj index 70fba3cd..46dd1894 100644 --- a/SampleApps/WpfApplication/WpfApplication.csproj +++ b/SampleApps/WpfApplication/WpfApplication.csproj @@ -1,110 +1,41 @@ - - - - - Debug - AnyCPU - {F92DA93D-75DB-4308-A5F9-6B4C3908A675} - WinExe - Properties - WpfApplication - WpfApplication - v4.6.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - - - prompt - 4 - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MapLayers.cs - - - MapViewModel.cs - - - App.xaml - Code - - - - MainWindow.xaml - Code - - - - - - Code - - - - - - - - - 10_535_330.jpg - - - - - {62f1726b-3144-49f4-8bcc-94160a3b2186} - MapControl.WPF - - - {0109c2f0-ba2c-420f-b2ca-db5b29b1a349} - SQLiteCache.WPF - - - - + + + + WinExe + netcoreapp3.1;net48 + true + WpfApplication + XAML Map Control + 5.0.0 + XAML Map Control WPF Sample Application + Clemens Fischer + Copyright © 2020 Clemens Fischer + + + + DEBUG + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SampleApps/WpfCoreApp/WpfCoreApp.csproj.user b/SampleApps/WpfApplication/WpfApplication.csproj.user similarity index 79% rename from SampleApps/WpfCoreApp/WpfCoreApp.csproj.user rename to SampleApps/WpfApplication/WpfApplication.csproj.user index 644b0a6f..a10cc1cc 100644 --- a/SampleApps/WpfCoreApp/WpfCoreApp.csproj.user +++ b/SampleApps/WpfApplication/WpfApplication.csproj.user @@ -1,6 +1,8 @@  - + + netcoreapp3.1 + Designer diff --git a/SampleApps/WpfCoreApp/App.xaml b/SampleApps/WpfCoreApp/App.xaml deleted file mode 100644 index dcc41a2c..00000000 --- a/SampleApps/WpfCoreApp/App.xaml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/SampleApps/WpfCoreApp/App.xaml.cs b/SampleApps/WpfCoreApp/App.xaml.cs deleted file mode 100644 index 6105bf88..00000000 --- a/SampleApps/WpfCoreApp/App.xaml.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Windows; - -namespace WpfApplication -{ - public partial class App : Application - { - } -} diff --git a/SampleApps/WpfCoreApp/LocationToVisibilityConverter.cs b/SampleApps/WpfCoreApp/LocationToVisibilityConverter.cs deleted file mode 100644 index 0ba383c8..00000000 --- a/SampleApps/WpfCoreApp/LocationToVisibilityConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Globalization; -using System.Windows; -using System.Windows.Data; -using MapControl; - -namespace WpfCoreApp -{ - public class LocationToVisibilityConverter : IMultiValueConverter - { - public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) - { - var visibility = Visibility.Hidden; - - if (values.Length == 2 && values[0] is MapBase && values[1] is Point?) - { - var parentMap = (MapBase)values[0]; - var position = (Point?)values[1]; - - if (position.HasValue && - position.Value.X >= 0d && position.Value.X <= parentMap.ActualWidth && - position.Value.Y >= 0d && position.Value.Y <= parentMap.ActualHeight) - { - visibility = Visibility.Visible; - } - } - - return visibility; - } - - public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - } -} diff --git a/SampleApps/WpfCoreApp/MainWindow.xaml b/SampleApps/WpfCoreApp/MainWindow.xaml deleted file mode 100644 index fab923dd..00000000 --- a/SampleApps/WpfCoreApp/MainWindow.xaml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SampleApps/WpfCoreApp/MainWindow.xaml.cs b/SampleApps/WpfCoreApp/MainWindow.xaml.cs deleted file mode 100644 index 4007acad..00000000 --- a/SampleApps/WpfCoreApp/MainWindow.xaml.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Globalization; -using System.Windows; -using System.Windows.Input; -using MapControl; -using ViewModel; - -namespace WpfCoreApp -{ - public partial class MainWindow : Window - { - public MainWindow() - { - ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application"); - //TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder); - - InitializeComponent(); - } - - private void MapMouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - if (e.ClickCount == 2) - { - //map.ZoomMap(e.GetPosition(map), Math.Floor(map.ZoomLevel + 1.5)); - //map.ZoomToBounds(new BoundingBox(53, 7, 54, 9)); - map.TargetCenter = map.ViewportPointToLocation(e.GetPosition(map)); - } - } - - private void MapMouseRightButtonDown(object sender, MouseButtonEventArgs e) - { - if (e.ClickCount == 2) - { - //map.ZoomMap(e.GetPosition(map), Math.Ceiling(map.ZoomLevel - 1.5)); - } - } - - private void MapMouseMove(object sender, MouseEventArgs e) - { - var location = map.ViewportPointToLocation(e.GetPosition(map)); - var latitude = (int)Math.Round(location.Latitude * 60000d); - var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d); - var latHemisphere = 'N'; - var lonHemisphere = 'E'; - - if (latitude < 0) - { - latitude = -latitude; - latHemisphere = 'S'; - } - - if (longitude < 0) - { - longitude = -longitude; - lonHemisphere = 'W'; - } - - mouseLocation.Text = string.Format(CultureInfo.InvariantCulture, - "{0} {1:00} {2:00.000}\n{3} {4:000} {5:00.000}", - latHemisphere, latitude / 60000, (latitude % 60000) / 1000d, - lonHemisphere, longitude / 60000, (longitude % 60000) / 1000d); - } - - private void MapMouseLeave(object sender, MouseEventArgs e) - { - mouseLocation.Text = string.Empty; - } - - private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) - { - e.TranslationBehavior.DesiredDeceleration = 0.001; - } - - private void MapItemTouchDown(object sender, TouchEventArgs e) - { - var mapItem = (MapItem)sender; - mapItem.IsSelected = !mapItem.IsSelected; - e.Handled = true; - } - - private void SeamarksChecked(object sender, RoutedEventArgs e) - { - map.Children.Insert(map.Children.IndexOf(mapGraticule), ((MapViewModel)DataContext).MapLayers.SeamarksLayer); - } - - private void SeamarksUnchecked(object sender, RoutedEventArgs e) - { - map.Children.Remove(((MapViewModel)DataContext).MapLayers.SeamarksLayer); - } - } -} diff --git a/SampleApps/WpfCoreApp/OutlinedText.cs b/SampleApps/WpfCoreApp/OutlinedText.cs deleted file mode 100644 index f36477c3..00000000 --- a/SampleApps/WpfCoreApp/OutlinedText.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace WpfCoreApp -{ - public class OutlinedText : FrameworkElement - { - private GlyphRun glyphRun; - private Geometry outline; - - public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty FontStyleProperty = TextBlock.FontStyleProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty FontWeightProperty = TextBlock.FontWeightProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty FontStretchProperty = TextBlock.FontStretchProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty BackgroundProperty = TextBlock.BackgroundProperty.AddOwner( - typeof(OutlinedText), new FrameworkPropertyMetadata(Brushes.White, (o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true }); - - public static readonly DependencyProperty OutlineThicknessProperty = DependencyProperty.Register( - "OutlineThickness", typeof(double), typeof(OutlinedText), - new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((OutlinedText)o).glyphRun = null)); - - public string Text - { - get { return (string)GetValue(TextProperty); } - set { SetValue(TextProperty, value); } - } - - public double FontSize - { - get { return (double)GetValue(FontSizeProperty); } - set { SetValue(FontSizeProperty, value); } - } - - public FontFamily FontFamily - { - get { return (FontFamily)GetValue(FontFamilyProperty); } - set { SetValue(FontFamilyProperty, value); } - } - - public FontStyle FontStyle - { - get { return (FontStyle)GetValue(FontStyleProperty); } - set { SetValue(FontStyleProperty, value); } - } - - public FontWeight FontWeight - { - get { return (FontWeight)GetValue(FontWeightProperty); } - set { SetValue(FontWeightProperty, value); } - } - - public FontStretch FontStretch - { - get { return (FontStretch)GetValue(FontStretchProperty); } - set { SetValue(FontStretchProperty, value); } - } - - public Brush Foreground - { - get { return (Brush)GetValue(ForegroundProperty); } - set { SetValue(ForegroundProperty, value); } - } - - public Brush Background - { - get { return (Brush)GetValue(BackgroundProperty); } - set { SetValue(BackgroundProperty, value); } - } - - public double OutlineThickness - { - get { return (double)GetValue(OutlineThicknessProperty); } - set { SetValue(OutlineThicknessProperty, value); } - } - - protected override Size MeasureOverride(Size availableSize) - { - return CheckGlyphRun() ? outline.Bounds.Size : new Size(); - } - - protected override void OnRender(DrawingContext drawingContext) - { - if (CheckGlyphRun()) - { - var location = outline.Bounds.Location; - drawingContext.PushTransform(new TranslateTransform(-location.X, -location.Y)); - drawingContext.DrawGeometry(Background, null, outline); - drawingContext.DrawGlyphRun(Foreground, glyphRun); - } - } - - private bool CheckGlyphRun() - { - if (glyphRun == null) - { - if (string.IsNullOrEmpty(Text)) - { - return false; - } - - var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch); - GlyphTypeface glyphTypeface; - - if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) - { - return false; - } - - var glyphIndices = new ushort[Text.Length]; - var advanceWidths = new double[Text.Length]; - - for (int i = 0; i < Text.Length; i++) - { - var glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[i]]; - glyphIndices[i] = glyphIndex; - advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * FontSize; - } - - glyphRun = new GlyphRun(glyphTypeface, 0, false, FontSize, 1f, glyphIndices, new Point(), advanceWidths, null, null, null, null, null, null); - - outline = glyphRun.BuildGeometry().GetWidenedPathGeometry(new Pen(null, OutlineThickness * 2d)); - } - - return true; - } - } -} diff --git a/SampleApps/WpfCoreApp/WpfCoreApp.csproj b/SampleApps/WpfCoreApp/WpfCoreApp.csproj deleted file mode 100644 index fc396bd4..00000000 --- a/SampleApps/WpfCoreApp/WpfCoreApp.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - WinExe - netcoreapp3.1 - true - WpfCoreApp - XAML Map Control - 5.0.0 - XAML Map Control WPF Sample Application - Clemens Fischer - Copyright © 2020 Clemens Fischer - - - - DEBUG - - - - - - - - - - - - - - - - - - - - \ No newline at end of file