diff --git a/Caching/FileDbCache.WPF/FileDbCache.cs b/Caching/FileDbCache.WPF/FileDbCache.cs
index 40d532d9..b9a97d28 100644
--- a/Caching/FileDbCache.WPF/FileDbCache.cs
+++ b/Caching/FileDbCache.WPF/FileDbCache.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
index 68a0ee2f..0a9fe1cc 100644
--- a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
+++ b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("ObjectCache implementation based on EzTools FileDb")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
+[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("2.14.0")]
-[assembly: AssemblyFileVersion("2.14.0")]
+[assembly: AssemblyVersion("3.1.0")]
+[assembly: AssemblyFileVersion("3.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/Caching/FileDbCache.WinRT/FileDbCache.cs b/Caching/FileDbCache.WinRT/FileDbCache.cs
index c3dcf9cb..46b381e8 100644
--- a/Caching/FileDbCache.WinRT/FileDbCache.cs
+++ b/Caching/FileDbCache.WinRT/FileDbCache.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs
index 30cc8632..b4a6df75 100644
--- a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs
+++ b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
+[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("2.14.0")]
-[assembly: AssemblyFileVersion("2.14.0")]
+[assembly: AssemblyVersion("3.1.0")]
+[assembly: AssemblyFileVersion("3.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/Caching/ImageFileCache.WPF/ImageFileCache.cs b/Caching/ImageFileCache.WPF/ImageFileCache.cs
index c5e10675..d2dcf71a 100644
--- a/Caching/ImageFileCache.WPF/ImageFileCache.cs
+++ b/Caching/ImageFileCache.WPF/ImageFileCache.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs
index 5706ccb7..0b1058e1 100644
--- a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs
+++ b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("ObjectCache implementation based on local image files")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
+[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("2.14.0")]
-[assembly: AssemblyFileVersion("2.14.0")]
+[assembly: AssemblyVersion("3.1.0")]
+[assembly: AssemblyFileVersion("3.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/Caching/ImageFileCache.WinRT/ImageFileCache.cs b/Caching/ImageFileCache.WinRT/ImageFileCache.cs
index 0e5b99c6..51040ec7 100644
--- a/Caching/ImageFileCache.WinRT/ImageFileCache.cs
+++ b/Caching/ImageFileCache.WinRT/ImageFileCache.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs
index 87206b9c..cf64836d 100644
--- a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs
+++ b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IImageCache implementation based on local image files")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
+[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("2.14.0")]
-[assembly: AssemblyFileVersion("2.14.0")]
+[assembly: AssemblyVersion("3.1.0")]
+[assembly: AssemblyFileVersion("3.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/MapControl VS2015.sln b/MapControl VS2015.sln
deleted file mode 100644
index 152f2071..00000000
--- a/MapControl VS2015.sln
+++ /dev/null
@@ -1,238 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WinRT", "Caching\FileDbCache.WinRT\FileDbCache.WinRT.csproj", "{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WPF", "Caching\FileDbCache.WPF\FileDbCache.WPF.csproj", "{EF44F661-B98A-4676-927F-85D138F82300}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageFileCache.WinRT", "Caching\ImageFileCache.WinRT\ImageFileCache.WinRT.csproj", "{F789647E-96F7-43E3-A895-FA3FE8D01260}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageFileCache.WPF", "Caching\ImageFileCache.WPF\ImageFileCache.WPF.csproj", "{86470440-FEE2-4120-AF5A-3762FB9C536F}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.Silverlight", "MapControl\MapControl.Silverlight.csproj", "{EB133B78-DEFF-416A-8F0C-89E54D766576}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WinRT", "MapControl\WinRT\MapControl.WinRT.csproj", "{63CEFDF7-5170-43B6-86F8-5C4A383A1615}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\MapControl.WPF.csproj", "{226F3575-B683-446D-A2F0-181291DC8787}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication", "SampleApps\SilverlightApplication\SilverlightApplication.csproj", "{CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication.Web", "SampleApps\SilverlightApplication.Web\SilverlightApplication.Web.csproj", "{177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{9949326E-9261-4F95-89B1-151F60498951}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{100879CC-8910-459E-856E-253D629E45DE}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{AE8A7E02-0F7D-41B0-AB23-15394150ED17}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|ARM = Debug|ARM
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|ARM = Release|ARM
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.Build.0 = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.Build.0 = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.Build.0 = Debug|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.Build.0 = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.ActiveCfg = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.Build.0 = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.ActiveCfg = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.Build.0 = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.ActiveCfg = Release|Any CPU
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.Build.0 = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.Build.0 = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.Build.0 = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.Build.0 = Debug|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.Build.0 = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.ActiveCfg = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.Build.0 = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.ActiveCfg = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.Build.0 = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.ActiveCfg = Release|Any CPU
- {EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.Build.0 = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.Build.0 = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.Build.0 = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.Build.0 = Debug|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.Build.0 = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.ActiveCfg = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.Build.0 = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.ActiveCfg = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.Build.0 = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.ActiveCfg = Release|Any CPU
- {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.Build.0 = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.Build.0 = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.ActiveCfg = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.Build.0 = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.Build.0 = Debug|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.Build.0 = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.ActiveCfg = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.Build.0 = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.ActiveCfg = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.Build.0 = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.ActiveCfg = Release|Any CPU
- {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.Build.0 = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.Build.0 = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.Build.0 = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.Build.0 = Debug|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.ActiveCfg = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.Build.0 = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.ActiveCfg = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.Build.0 = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.ActiveCfg = Release|Any CPU
- {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.Build.0 = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.Build.0 = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.ActiveCfg = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.Build.0 = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.ActiveCfg = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.Build.0 = Debug|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.Build.0 = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.ActiveCfg = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.Build.0 = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.ActiveCfg = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.Build.0 = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.ActiveCfg = Release|Any CPU
- {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.Build.0 = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.Build.0 = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.ActiveCfg = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.Build.0 = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.ActiveCfg = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.Build.0 = Debug|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.Build.0 = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.ActiveCfg = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.Build.0 = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.ActiveCfg = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.Build.0 = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.ActiveCfg = Release|Any CPU
- {226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.Build.0 = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|ARM.Build.0 = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|x64.ActiveCfg = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|x64.Build.0 = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|x86.ActiveCfg = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|x86.Build.0 = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|Any CPU.Build.0 = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|ARM.ActiveCfg = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|ARM.Build.0 = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|x64.ActiveCfg = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|x64.Build.0 = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|x86.ActiveCfg = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|x86.Build.0 = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|ARM.Build.0 = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|x64.Build.0 = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|x86.Build.0 = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|Any CPU.Build.0 = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|ARM.ActiveCfg = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|ARM.Build.0 = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|x64.ActiveCfg = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|x64.Build.0 = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|x86.ActiveCfg = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|x86.Build.0 = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.Build.0 = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.Build.0 = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.Build.0 = Debug|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.Build.0 = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.ActiveCfg = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.Build.0 = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|x64.ActiveCfg = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|x64.Build.0 = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|x86.ActiveCfg = Release|Any CPU
- {9949326E-9261-4F95-89B1-151F60498951}.Release|x86.Build.0 = Release|Any CPU
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.ActiveCfg = Debug|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Build.0 = Debug|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Deploy.0 = Debug|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.ActiveCfg = Debug|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.Build.0 = Debug|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.Deploy.0 = Debug|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.ActiveCfg = Debug|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.Build.0 = Debug|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.Deploy.0 = Debug|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|Any CPU.ActiveCfg = Release|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.ActiveCfg = Release|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.Build.0 = Release|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.Deploy.0 = Release|ARM
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.ActiveCfg = Release|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.Build.0 = Release|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.Deploy.0 = Release|x64
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.ActiveCfg = Release|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Build.0 = Release|x86
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Deploy.0 = Release|x86
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {C7BF2B18-CC74-430B-BCB2-600304EFA3D8} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
- {EF44F661-B98A-4676-927F-85D138F82300} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
- {F789647E-96F7-43E3-A895-FA3FE8D01260} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
- {86470440-FEE2-4120-AF5A-3762FB9C536F} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21} = {100879CC-8910-459E-856E-253D629E45DE}
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1} = {100879CC-8910-459E-856E-253D629E45DE}
- {9949326E-9261-4F95-89B1-151F60498951} = {100879CC-8910-459E-856E-253D629E45DE}
- {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {100879CC-8910-459E-856E-253D629E45DE}
- EndGlobalSection
-EndGlobal
diff --git a/MapControl.sln b/MapControl.sln
index 542e3931..49a24d8c 100644
--- a/MapControl.sln
+++ b/MapControl.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WinRT", "Caching\FileDbCache.WinRT\FileDbCache.WinRT.csproj", "{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}"
EndProject
@@ -17,78 +17,210 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WinRT", "MapCont
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\MapControl.WPF.csproj", "{226F3575-B683-446D-A2F0-181291DC8787}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneApplication", "SampleApps\PhoneApplication\PhoneApplication.csproj", "{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication", "SampleApps\SilverlightApplication\SilverlightApplication.csproj", "{CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication.Web", "SampleApps\SilverlightApplication.Web\SilverlightApplication.Web.csproj", "{177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StoreApplication", "SampleApps\StoreApplication\StoreApplication.csproj", "{747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{9949326E-9261-4F95-89B1-151F60498951}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{100879CC-8910-459E-856E-253D629E45DE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{AE8A7E02-0F7D-41B0-AB23-15394150ED17}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication", "SampleApps\SilverlightApplication\SilverlightApplication.csproj", "{85AACDB7-959D-406D-A8DF-2F1E013F8F40}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication.Web", "SampleApps\SilverlightApplication.Web\SilverlightApplication.Web.csproj", "{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.Build.0 = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.Build.0 = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.Build.0 = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.ActiveCfg = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.Build.0 = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.ActiveCfg = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.Build.0 = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.ActiveCfg = Release|Any CPU
+ {C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.Build.0 = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.Build.0 = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.Build.0 = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.Build.0 = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.ActiveCfg = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.Build.0 = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.ActiveCfg = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.Build.0 = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.ActiveCfg = Release|Any CPU
+ {EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.Build.0 = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.Build.0 = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.Build.0 = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.Build.0 = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.ActiveCfg = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.Build.0 = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.ActiveCfg = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.Build.0 = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.ActiveCfg = Release|Any CPU
+ {F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.Build.0 = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.Build.0 = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.Build.0 = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.Build.0 = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.ActiveCfg = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.Build.0 = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.ActiveCfg = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.Build.0 = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.ActiveCfg = Release|Any CPU
+ {86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.Build.0 = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.Build.0 = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.Build.0 = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.Build.0 = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.ActiveCfg = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.Build.0 = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.ActiveCfg = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.Build.0 = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.ActiveCfg = Release|Any CPU
+ {EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.Build.0 = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.Build.0 = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.Build.0 = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.Build.0 = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.Build.0 = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.ActiveCfg = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.Build.0 = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.ActiveCfg = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.Build.0 = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.ActiveCfg = Release|Any CPU
+ {63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.Build.0 = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.Build.0 = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.Build.0 = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.Build.0 = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.ActiveCfg = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Deploy.0 = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21}.Release|Any CPU.Build.0 = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1}.Release|Any CPU.Build.0 = Release|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Release|Any CPU.Build.0 = Release|Any CPU
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.ActiveCfg = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.Build.0 = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.ActiveCfg = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.Build.0 = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.ActiveCfg = Release|Any CPU
+ {226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.Build.0 = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.Build.0 = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.Build.0 = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.Build.0 = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.ActiveCfg = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.Build.0 = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|x64.ActiveCfg = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|x64.Build.0 = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|x86.ActiveCfg = Release|Any CPU
+ {9949326E-9261-4F95-89B1-151F60498951}.Release|x86.Build.0 = Release|Any CPU
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.ActiveCfg = Debug|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Build.0 = Debug|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Deploy.0 = Debug|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.ActiveCfg = Debug|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.Build.0 = Debug|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x64.Deploy.0 = Debug|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.ActiveCfg = Debug|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.Build.0 = Debug|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|x86.Deploy.0 = Debug|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|Any CPU.ActiveCfg = Release|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.ActiveCfg = Release|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.Build.0 = Release|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|ARM.Deploy.0 = Release|ARM
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.ActiveCfg = Release|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.Build.0 = Release|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x64.Deploy.0 = Release|x64
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.ActiveCfg = Release|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Build.0 = Release|x86
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Deploy.0 = Release|x86
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|ARM.Build.0 = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x64.Build.0 = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x86.Build.0 = Debug|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|ARM.ActiveCfg = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|ARM.Build.0 = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x64.ActiveCfg = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x64.Build.0 = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x86.ActiveCfg = Release|Any CPU
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x86.Build.0 = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|ARM.Build.0 = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x64.Build.0 = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x86.Build.0 = Debug|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|ARM.ActiveCfg = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|ARM.Build.0 = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x64.ActiveCfg = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x64.Build.0 = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x86.ActiveCfg = Release|Any CPU
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -98,10 +230,9 @@ Global
{EF44F661-B98A-4676-927F-85D138F82300} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
{F789647E-96F7-43E3-A895-FA3FE8D01260} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
{86470440-FEE2-4120-AF5A-3762FB9C536F} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
- {8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9} = {100879CC-8910-459E-856E-253D629E45DE}
- {CBA8C535-CCA3-4F60-8D3E-0E25791CBD21} = {100879CC-8910-459E-856E-253D629E45DE}
- {177C4EF8-0B0A-426E-BDCC-168DC10AC1C1} = {100879CC-8910-459E-856E-253D629E45DE}
- {747A3F84-E11F-4EC8-9463-98BBB1E0D0A4} = {100879CC-8910-459E-856E-253D629E45DE}
{9949326E-9261-4F95-89B1-151F60498951} = {100879CC-8910-459E-856E-253D629E45DE}
+ {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {100879CC-8910-459E-856E-253D629E45DE}
+ {85AACDB7-959D-406D-A8DF-2F1E013F8F40} = {100879CC-8910-459E-856E-253D629E45DE}
+ {7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4} = {100879CC-8910-459E-856E-253D629E45DE}
EndGlobalSection
EndGlobal
diff --git a/MapControl/AzimuthalEquidistantProjection.cs b/MapControl/AzimuthalEquidistantProjection.cs
new file mode 100644
index 00000000..96df920f
--- /dev/null
+++ b/MapControl/AzimuthalEquidistantProjection.cs
@@ -0,0 +1,58 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+#if NETFX_CORE
+using Windows.Foundation;
+#else
+using System.Windows;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Transforms map coordinates according to the Azimuthal Equidistant Projection.
+ ///
+ public class AzimuthalEquidistantProjection : AzimuthalProjection
+ {
+ public AzimuthalEquidistantProjection()
+ {
+ // No known standard or de-facto standard CRS ID
+ }
+
+ public AzimuthalEquidistantProjection(string crsId)
+ {
+ CrsId = crsId;
+ }
+
+ public override Point LocationToPoint(Location location)
+ {
+ if (location.Equals(projectionCenter))
+ {
+ return new Point();
+ }
+
+ double azimuth, distance;
+
+ GetAzimuthDistance(projectionCenter, location, out azimuth, out distance);
+
+ distance *= Wgs84EquatorialRadius;
+
+ return new Point(distance * Math.Sin(azimuth), distance * Math.Cos(azimuth));
+ }
+
+ public override Location PointToLocation(Point point)
+ {
+ if (point.X == 0d && point.Y == 0d)
+ {
+ return projectionCenter;
+ }
+
+ var azimuth = Math.Atan2(point.X, point.Y);
+ var distance = Math.Sqrt(point.X * point.X + point.Y * point.Y) / Wgs84EquatorialRadius;
+
+ return GetLocation(projectionCenter, azimuth, distance);
+ }
+ }
+}
diff --git a/MapControl/AzimuthalProjection.cs b/MapControl/AzimuthalProjection.cs
new file mode 100644
index 00000000..573bef23
--- /dev/null
+++ b/MapControl/AzimuthalProjection.cs
@@ -0,0 +1,137 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+using System.Globalization;
+#if NETFX_CORE
+using Windows.Foundation;
+#else
+using System.Windows;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Base class for azimuthal map projections.
+ ///
+ public abstract class AzimuthalProjection : MapProjection
+ {
+ protected Location projectionCenter = new Location();
+
+ public AzimuthalProjection()
+ {
+ IsAzimuthal = true;
+ LongitudeScale = double.NaN;
+ }
+
+ public override double GetViewportScale(double zoomLevel)
+ {
+ return base.GetViewportScale(zoomLevel) / MetersPerDegree;
+ }
+
+ public override Point GetMapScale(Location location)
+ {
+ return new Point(ViewportScale, ViewportScale);
+ }
+
+ public override Location TranslateLocation(Location location, Point translation)
+ {
+ var scaleY = ViewportScale * MetersPerDegree;
+ var scaleX = scaleY * Math.Cos(location.Latitude * Math.PI / 180d);
+
+ return new Location(
+ location.Latitude - translation.Y / scaleY,
+ location.Longitude + translation.X / scaleX);
+ }
+
+ public override Rect BoundingBoxToRect(BoundingBox boundingBox)
+ {
+ var cbbox = boundingBox as CenteredBoundingBox;
+
+ if (cbbox != null)
+ {
+ var center = LocationToPoint(cbbox.Center);
+
+ return new Rect(
+ center.X - cbbox.Width / 2d, center.Y - cbbox.Height / 2d,
+ cbbox.Width, cbbox.Height);
+ }
+
+ return base.BoundingBoxToRect(boundingBox);
+ }
+
+ public override BoundingBox RectToBoundingBox(Rect rect)
+ {
+ var center = PointToLocation(new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d));
+
+ return new CenteredBoundingBox(center, rect.Width, rect.Height); // width and height in meters
+ }
+
+ public override void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading)
+ {
+ this.projectionCenter = projectionCenter;
+
+ base.SetViewportTransform(projectionCenter, mapCenter, viewportCenter, zoomLevel, heading);
+ }
+
+ public override string WmsQueryParameters(BoundingBox boundingBox, string version)
+ {
+ if (string.IsNullOrEmpty(CrsId))
+ {
+ return null;
+ }
+
+ var rect = BoundingBoxToRect(boundingBox);
+ var width = (int)Math.Round(ViewportScale * rect.Width);
+ var height = (int)Math.Round(ViewportScale * rect.Height);
+ var crs = version.StartsWith("1.1.") ? "SRS" : "CRS";
+
+ return string.Format(CultureInfo.InvariantCulture,
+ "{0}={1},1,{2},{3}&BBOX={4},{5},{6},{7}&WIDTH={8}&HEIGHT={9}",
+ crs, CrsId, projectionCenter.Longitude, projectionCenter.Latitude,
+ rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height);
+ }
+
+ ///
+ /// Calculates azimuth and distance in radians from location1 to location2.
+ /// The returned distance has to be multiplied with an appropriate earth radius.
+ ///
+ public static void GetAzimuthDistance(Location location1, Location location2, out double azimuth, out double distance)
+ {
+ var lat1 = location1.Latitude * Math.PI / 180d;
+ var lon1 = location1.Longitude * Math.PI / 180d;
+ var lat2 = location2.Latitude * Math.PI / 180d;
+ var lon2 = location2.Longitude * Math.PI / 180d;
+ var cosLat1 = Math.Cos(lat1);
+ var sinLat1 = Math.Sin(lat1);
+ var cosLat2 = Math.Cos(lat2);
+ var sinLat2 = Math.Sin(lat2);
+ var cosLon12 = Math.Cos(lon2 - lon1);
+ var sinLon12 = Math.Sin(lon2 - lon1);
+ var cosDistance = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosLon12;
+
+ azimuth = Math.Atan2(sinLon12, cosLat1 * sinLat2 / cosLat2 - sinLat1 * cosLon12);
+ distance = Math.Acos(Math.Max(Math.Min(cosDistance, 1d), -1d));
+ }
+
+ ///
+ /// Calculates the Location of the point given by azimuth and distance in radians from location.
+ ///
+ public static Location GetLocation(Location location, double azimuth, double distance)
+ {
+ var lat1 = location.Latitude * Math.PI / 180d;
+ var sinDistance = Math.Sin(distance);
+ var cosDistance = Math.Cos(distance);
+ var cosAzimuth = Math.Cos(azimuth);
+ var sinAzimuth = Math.Sin(azimuth);
+ var cosLat1 = Math.Cos(lat1);
+ var sinLat1 = Math.Sin(lat1);
+ var sinLat2 = sinLat1 * cosDistance + cosLat1 * sinDistance * cosAzimuth;
+ var lat2 = Math.Asin(Math.Max(Math.Min(sinLat2, 1d), -1d));
+ var dLon = Math.Atan2(sinDistance * sinAzimuth, cosLat1 * cosDistance - sinLat1 * sinDistance * cosAzimuth);
+
+ return new Location(180d / Math.PI * lat2, location.Longitude + 180d / Math.PI * dLon);
+ }
+ }
+}
diff --git a/MapControl/BingMapsTileLayer.cs b/MapControl/BingMapsTileLayer.cs
index c1bc6f27..9ebaa46d 100644
--- a/MapControl/BingMapsTileLayer.cs
+++ b/MapControl/BingMapsTileLayer.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -10,9 +10,11 @@ using System.Net;
using System.Xml;
#if NETFX_CORE
using Windows.UI.Xaml;
+using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows;
+using System.Windows.Media;
using System.Windows.Media.Imaging;
#endif
@@ -20,8 +22,10 @@ namespace MapControl
{
///
/// Displays Bing Maps tiles. The static ApiKey property must be set to a Bing Maps API Key.
+ /// Tile image URLs and min/max zoom levels are retrieved from the Imagery Metadata Service
+ /// (see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
///
- public class BingMapsTileLayer : TileLayer
+ public class BingMapsTileLayer : MapTileLayer
{
public enum MapMode
{
@@ -45,6 +49,7 @@ namespace MapControl
public MapMode Mode { get; set; }
public string Culture { get; set; }
+ public ImageSource LogoImage { get; set; }
private void OnLoaded(object sender, RoutedEventArgs e)
{
@@ -52,13 +57,15 @@ namespace MapControl
if (string.IsNullOrEmpty(ApiKey))
{
- throw new InvalidOperationException("BingMapsTileLayer requires a Bing Maps API Key.");
+ Debug.WriteLine("BingMapsTileLayer requires a Bing Maps API Key");
}
+ else
+ {
+ var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);
+ var request = WebRequest.CreateHttp(uri);
- var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);
- var request = WebRequest.CreateHttp(uri);
-
- request.BeginGetResponse(HandleImageryMetadataResponse, request);
+ request.BeginGetResponse(HandleImageryMetadataResponse, request);
+ }
}
private void HandleImageryMetadataResponse(IAsyncResult asyncResult)
@@ -122,7 +129,7 @@ namespace MapControl
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
{
- var _ = Dispatcher.BeginInvoke(new Action(() =>
+ var op = Dispatcher.BeginInvoke(new Action(() =>
{
if (string.IsNullOrEmpty(Culture))
{
diff --git a/MapControl/BingMapsTileSource.cs b/MapControl/BingMapsTileSource.cs
index 44df45ee..69be1948 100644
--- a/MapControl/BingMapsTileSource.cs
+++ b/MapControl/BingMapsTileSource.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/ImageLoader.cs b/MapControl/BitmapSourceHelper.cs
similarity index 76%
rename from MapControl/ImageLoader.cs
rename to MapControl/BitmapSourceHelper.cs
index 1cb1e889..e43a4b5d 100644
--- a/MapControl/ImageLoader.cs
+++ b/MapControl/BitmapSourceHelper.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -13,7 +13,7 @@ namespace MapControl
///
/// Creates frozen BitmapSources from Stream or Uri.
///
- internal static class ImageLoader
+ public static class BitmapSourceHelper
{
public static BitmapSource FromStream(Stream stream)
{
@@ -30,19 +30,16 @@ namespace MapControl
public static BitmapSource FromUri(Uri uri)
{
- BitmapSource bitmap = null;
-
try
{
- var request = WebRequest.Create(uri);
-
- using (var response = request.GetResponse())
+ using (var response = WebRequest.Create(uri).GetResponse())
using (var responseStream = response.GetResponseStream())
using (var memoryStream = new MemoryStream())
{
responseStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
- bitmap = FromStream(memoryStream);
+
+ return FromStream(memoryStream);
}
}
catch (Exception ex)
@@ -50,7 +47,7 @@ namespace MapControl
Debug.WriteLine(ex.Message);
}
- return bitmap;
+ return null;
}
}
}
diff --git a/MapControl/BoundingBox.cs b/MapControl/BoundingBox.cs
new file mode 100644
index 00000000..906a2e0d
--- /dev/null
+++ b/MapControl/BoundingBox.cs
@@ -0,0 +1,92 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+using System.Globalization;
+
+namespace MapControl
+{
+ ///
+ /// A geographic bounding box with south and north latitude and west and east longitude values in degrees.
+ ///
+ public partial class BoundingBox
+ {
+ private double south;
+ private double west;
+ private double north;
+ private double east;
+
+ public BoundingBox()
+ {
+ }
+
+ public BoundingBox(double south, double west, double north, double east)
+ {
+ South = south;
+ West = west;
+ North = north;
+ East = east;
+ }
+
+ public double South
+ {
+ get { return south; }
+ set { south = Math.Min(Math.Max(value, -90d), 90d); }
+ }
+
+ public double West
+ {
+ get { return west; }
+ set { west = value; }
+ }
+
+ public double North
+ {
+ get { return north; }
+ set { north = Math.Min(Math.Max(value, -90d), 90d); }
+ }
+
+ public double East
+ {
+ get { return east; }
+ set { east = value; }
+ }
+
+ public virtual double Width
+ {
+ get { return east - west; }
+ }
+
+ public virtual double Height
+ {
+ get { return north - south; }
+ }
+
+ public bool HasValidBounds
+ {
+ get { return south < north && west < east; }
+ }
+
+ public virtual BoundingBox Clone()
+ {
+ return new BoundingBox(south, west, north, east);
+ }
+
+ public static BoundingBox Parse(string s)
+ {
+ var values = s.Split(new char[] { ',' });
+
+ if (values.Length != 4)
+ {
+ throw new FormatException("BoundingBox string must be a comma-separated list of four double values");
+ }
+
+ return new BoundingBox(
+ double.Parse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture),
+ double.Parse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture),
+ double.Parse(values[2], NumberStyles.Float, CultureInfo.InvariantCulture),
+ double.Parse(values[3], NumberStyles.Float, CultureInfo.InvariantCulture));
+ }
+ }
+}
diff --git a/MapControl/BoundingBoxConverter.cs b/MapControl/BoundingBoxConverter.cs
new file mode 100644
index 00000000..6c76f1b7
--- /dev/null
+++ b/MapControl/BoundingBoxConverter.cs
@@ -0,0 +1,31 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace MapControl
+{
+ public class BoundingBoxConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ return BoundingBox.Parse((string)value);
+ }
+ }
+
+ [TypeConverter(typeof(BoundingBoxConverter))]
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public partial class BoundingBox
+ {
+ }
+}
diff --git a/MapControl/CenteredBoundingBox.cs b/MapControl/CenteredBoundingBox.cs
new file mode 100644
index 00000000..07cab657
--- /dev/null
+++ b/MapControl/CenteredBoundingBox.cs
@@ -0,0 +1,40 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+namespace MapControl
+{
+ public class CenteredBoundingBox : BoundingBox
+ {
+ private readonly Location center;
+ private readonly double width;
+ private readonly double height;
+
+ public CenteredBoundingBox(Location center, double width, double height)
+ {
+ this.center = center;
+ this.width = width;
+ this.height = height;
+ }
+
+ public Location Center
+ {
+ get { return center; }
+ }
+
+ public override double Width
+ {
+ get { return width; }
+ }
+
+ public override double Height
+ {
+ get { return height; }
+ }
+
+ public override BoundingBox Clone()
+ {
+ return new CenteredBoundingBox(center, width, height);
+ }
+ }
+}
diff --git a/MapControl/EquirectangularProjection.cs b/MapControl/EquirectangularProjection.cs
new file mode 100644
index 00000000..ac100a71
--- /dev/null
+++ b/MapControl/EquirectangularProjection.cs
@@ -0,0 +1,54 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+#if NETFX_CORE
+using Windows.Foundation;
+#else
+using System.Windows;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Transforms map coordinates according to the Equirectangular Projection.
+ /// Longitude and Latitude values are transformed identically to X and Y.
+ ///
+ public class EquirectangularProjection : MapProjection
+ {
+ public EquirectangularProjection()
+ : this("EPSG:4326")
+ {
+ }
+
+ public EquirectangularProjection(string crsId)
+ {
+ CrsId = crsId;
+ }
+
+ public override Point GetMapScale(Location location)
+ {
+ return new Point(
+ ViewportScale / (MetersPerDegree * Math.Cos(location.Latitude * Math.PI / 180d)),
+ ViewportScale / MetersPerDegree);
+ }
+
+ public override Point LocationToPoint(Location location)
+ {
+ return new Point(location.Longitude, location.Latitude);
+ }
+
+ public override Location PointToLocation(Point point)
+ {
+ return new Location(point.Y, point.X);
+ }
+
+ public override Location TranslateLocation(Location location, Point translation)
+ {
+ return new Location(
+ location.Latitude - translation.Y / ViewportScale,
+ location.Longitude + translation.X / ViewportScale);
+ }
+ }
+}
diff --git a/MapControl/Extensions.Silverlight.cs b/MapControl/Extensions.Silverlight.cs
index f633eeee..eb6352eb 100644
--- a/MapControl/Extensions.Silverlight.cs
+++ b/MapControl/Extensions.Silverlight.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Windows;
diff --git a/MapControl/Extensions.WinRT.cs b/MapControl/Extensions.WinRT.cs
index 72bc95c7..b12db969 100644
--- a/MapControl/Extensions.WinRT.cs
+++ b/MapControl/Extensions.WinRT.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/GnomonicProjection.cs b/MapControl/GnomonicProjection.cs
new file mode 100644
index 00000000..3492f77a
--- /dev/null
+++ b/MapControl/GnomonicProjection.cs
@@ -0,0 +1,61 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+#if NETFX_CORE
+using Windows.Foundation;
+#else
+using System.Windows;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Transforms map coordinates according to the Gnomonic Projection.
+ ///
+ public class GnomonicProjection : AzimuthalProjection
+ {
+ public GnomonicProjection()
+ : this("AUTO2:97001") // GeoServer non-standard CRS ID
+ {
+ }
+
+ public GnomonicProjection(string crsId)
+ {
+ CrsId = crsId;
+ }
+
+ public override Point LocationToPoint(Location location)
+ {
+ if (location.Equals(projectionCenter))
+ {
+ return new Point();
+ }
+
+ double azimuth, distance;
+
+ GetAzimuthDistance(projectionCenter, location, out azimuth, out distance);
+
+ var mapDistance = distance < Math.PI / 2d
+ ? Wgs84EquatorialRadius * Math.Tan(distance)
+ : double.PositiveInfinity;
+
+ return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
+ }
+
+ public override Location PointToLocation(Point point)
+ {
+ if (point.X == 0d && point.Y == 0d)
+ {
+ return projectionCenter;
+ }
+
+ var azimuth = Math.Atan2(point.X, point.Y);
+ var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
+ var distance = Math.Atan(mapDistance / Wgs84EquatorialRadius);
+
+ return GetLocation(projectionCenter, azimuth, distance);
+ }
+ }
+}
diff --git a/MapControl/HyperlinkText.cs b/MapControl/HyperlinkText.cs
index dac1d07e..442d56ac 100644
--- a/MapControl/HyperlinkText.cs
+++ b/MapControl/HyperlinkText.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/IMapElement.cs b/MapControl/IMapElement.cs
deleted file mode 100644
index 4ac2d67e..00000000
--- a/MapControl/IMapElement.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-namespace MapControl
-{
- public interface IMapElement
- {
- MapBase ParentMap { get; set; }
- }
-}
diff --git a/MapControl/ITileImageLoader.cs b/MapControl/ITileImageLoader.cs
deleted file mode 100644
index 3b3404f0..00000000
--- a/MapControl/ITileImageLoader.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System.Collections.Generic;
-
-namespace MapControl
-{
- public interface ITileImageLoader
- {
- void BeginLoadTiles(TileLayer tileLayer, IEnumerable tiles);
- void CancelLoadTiles(TileLayer tileLayer);
- }
-}
diff --git a/MapControl/ImageCache.WinRT.cs b/MapControl/ImageCache.WinRT.cs
index 56a77b42..ac2c780e 100644
--- a/MapControl/ImageCache.WinRT.cs
+++ b/MapControl/ImageCache.WinRT.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/ImageTileSource.Silverlight.WinRT.cs b/MapControl/ImageTileSource.Silverlight.WinRT.cs
index b979f3ee..6c14b103 100644
--- a/MapControl/ImageTileSource.Silverlight.WinRT.cs
+++ b/MapControl/ImageTileSource.Silverlight.WinRT.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
diff --git a/MapControl/ImageTileSource.WPF.cs b/MapControl/ImageTileSource.WPF.cs
index b49e0ced..2030b548 100644
--- a/MapControl/ImageTileSource.WPF.cs
+++ b/MapControl/ImageTileSource.WPF.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Windows.Media;
@@ -28,7 +28,7 @@ namespace MapControl
{
if (IsAsync)
{
- image = ImageLoader.FromUri(uri);
+ image = BitmapSourceHelper.FromUri(uri);
}
else
{
diff --git a/MapControl/Location.cs b/MapControl/Location.cs
index 2c12a28b..73d8b32a 100644
--- a/MapControl/Location.cs
+++ b/MapControl/Location.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -62,16 +62,16 @@ namespace MapControl
public static Location Parse(string s)
{
- var pair = s.Split(new char[] { ',' });
+ var values = s.Split(new char[] { ',' });
- if (pair.Length != 2)
+ if (values.Length != 2)
{
throw new FormatException("Location string must be a comma-separated pair of double values");
}
return new Location(
- double.Parse(pair[0], NumberStyles.Float, CultureInfo.InvariantCulture),
- double.Parse(pair[1], NumberStyles.Float, CultureInfo.InvariantCulture));
+ double.Parse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture),
+ double.Parse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture));
}
///
diff --git a/MapControl/LocationCollection.cs b/MapControl/LocationCollection.cs
index 6fd0cfd0..b4f58941 100644
--- a/MapControl/LocationCollection.cs
+++ b/MapControl/LocationCollection.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -10,7 +10,7 @@ using System.Linq;
namespace MapControl
{
///
- /// A collection of geographic locations.
+ /// An ObservableCollection of Location with support for parsing.
///
public partial class LocationCollection : ObservableCollection
{
diff --git a/MapControl/LocationCollectionConverter.cs b/MapControl/LocationCollectionConverter.cs
index 54682618..8c9874f0 100644
--- a/MapControl/LocationCollectionConverter.cs
+++ b/MapControl/LocationCollectionConverter.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/LocationConverter.cs b/MapControl/LocationConverter.cs
index 35cd1545..8318df1b 100644
--- a/MapControl/LocationConverter.cs
+++ b/MapControl/LocationConverter.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
diff --git a/MapControl/Map.Silverlight.cs b/MapControl/Map.Silverlight.cs
index 413f310c..fc6c3839 100644
--- a/MapControl/Map.Silverlight.cs
+++ b/MapControl/Map.Silverlight.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Windows;
@@ -13,7 +13,7 @@ namespace MapControl
public class Map : MapBase
{
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
- "MouseWheelZoomDelta", typeof(double), typeof(Map), new PropertyMetadata(1d));
+ nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
private Point? mousePosition;
diff --git a/MapControl/Map.WPF.cs b/MapControl/Map.WPF.cs
index 02dd65a4..2368ade6 100644
--- a/MapControl/Map.WPF.cs
+++ b/MapControl/Map.WPF.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Windows;
@@ -13,10 +13,10 @@ namespace MapControl
public class Map : MapBase
{
public static readonly DependencyProperty ManipulationModeProperty = DependencyProperty.Register(
- "ManipulationMode", typeof(ManipulationModes), typeof(Map), new PropertyMetadata(ManipulationModes.All));
+ nameof(ManipulationMode), typeof(ManipulationModes), typeof(Map), new PropertyMetadata(ManipulationModes.All));
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
- "MouseWheelZoomDelta", typeof(double), typeof(Map), new PropertyMetadata(1d));
+ nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
private Point? mousePosition;
diff --git a/MapControl/Map.WinRT.cs b/MapControl/Map.WinRT.cs
index 86a747bb..19d517c1 100644
--- a/MapControl/Map.WinRT.cs
+++ b/MapControl/Map.WinRT.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -15,7 +15,7 @@ namespace MapControl
public class Map : MapBase
{
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
- "MouseWheelZoomDelta", typeof(double), typeof(Map), new PropertyMetadata(1d));
+ nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
private bool transformPending;
private Point transformTranslation;
diff --git a/MapControl/MapBase.Silverlight.WinRT.cs b/MapControl/MapBase.Silverlight.WinRT.cs
index c0f64af5..3ee6a594 100644
--- a/MapControl/MapBase.Silverlight.WinRT.cs
+++ b/MapControl/MapBase.Silverlight.WinRT.cs
@@ -1,9 +1,7 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
-using System;
-using System.Linq;
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI;
@@ -19,36 +17,36 @@ namespace MapControl
public partial class MapBase
{
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
- "Foreground", typeof(Brush), typeof(MapBase),
+ nameof(Foreground), typeof(Brush), typeof(MapBase),
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
- "Center", typeof(Location), typeof(MapBase),
+ nameof(Center), typeof(Location), typeof(MapBase),
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
- "TargetCenter", typeof(Location), typeof(MapBase),
+ nameof(TargetCenter), typeof(Location), typeof(MapBase),
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
- "ZoomLevel", typeof(double), typeof(MapBase),
+ nameof(ZoomLevel), typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
- "TargetZoomLevel", typeof(double), typeof(MapBase),
+ nameof(TargetZoomLevel), typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
- "Heading", typeof(double), typeof(MapBase),
+ nameof(Heading), typeof(double), typeof(MapBase),
new PropertyMetadata(0d, (o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
- "TargetHeading", typeof(double), typeof(MapBase),
+ nameof(TargetHeading), typeof(double), typeof(MapBase),
new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
partial void Initialize()
{
- // set Background by Style to enable resetting by ClearValue in RemoveTileLayers
+ // set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged
var style = new Style(typeof(MapBase));
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
Style = style;
@@ -62,28 +60,10 @@ namespace MapControl
{
clip.Rect = new Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height);
- ResetTransformOrigin();
+ ResetTransformCenter();
UpdateTransform();
}
};
}
-
- private void SetViewportTransform(Location origin)
- {
- MapOrigin = mapTransform.Transform(origin);
- ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
-
- var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y)
- .Rotate(-Heading)
- .Scale(ViewportScale, -ViewportScale)
- .Translate(ViewportOrigin.X, ViewportOrigin.Y);
-
- viewportTransform.Matrix = transform;
- }
-
- private void SetTileLayer(TileLayer tileLayer)
- {
- TileLayer = tileLayer;
- }
}
}
diff --git a/MapControl/MapBase.WPF.cs b/MapControl/MapBase.WPF.cs
index 64b48c4d..b21702a0 100644
--- a/MapControl/MapBase.WPF.cs
+++ b/MapControl/MapBase.WPF.cs
@@ -1,8 +1,7 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
-using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
@@ -15,42 +14,39 @@ namespace MapControl
Control.ForegroundProperty.AddOwner(typeof(MapBase));
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
- "Center", typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(Center), typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
- "TargetCenter", typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(TargetCenter), typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
- "ZoomLevel", typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(ZoomLevel), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
- "TargetZoomLevel", typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(TargetZoomLevel), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
- "Heading", typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(Heading), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
- "TargetHeading", typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
+ nameof(TargetHeading), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
static MapBase()
{
- ClipToBoundsProperty.OverrideMetadata(
- typeof(MapBase), new FrameworkPropertyMetadata(true));
-
- BackgroundProperty.OverrideMetadata(
- typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
+ ClipToBoundsProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(true));
+ BackgroundProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
}
partial void RemoveAnimation(DependencyProperty property)
@@ -69,37 +65,19 @@ namespace MapControl
///
/// 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 origin point in viewport coordinates.
+ /// is performed relative to the specified center point in viewport coordinates.
///
- public void TransformMap(Point origin, Vector translation, double rotation, double scale)
+ public void TransformMap(Point center, Vector translation, double rotation, double scale)
{
- TransformMap(origin, (Point)translation, rotation, scale);
+ TransformMap(center, (Point)translation, rotation, scale);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
- ResetTransformOrigin();
+ ResetTransformCenter();
UpdateTransform();
}
-
- private void SetViewportTransform(Location origin)
- {
- MapOrigin = mapTransform.Transform(origin);
- ViewportScale = Math.Pow(2d, ZoomLevel) * TileSource.TileSize / 360d;
-
- var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y);
- transform.Rotate(-Heading);
- transform.Scale(ViewportScale, -ViewportScale);
- transform.Translate(ViewportOrigin.X, ViewportOrigin.Y);
-
- viewportTransform.Matrix = transform;
- }
-
- private void SetTileLayer(TileLayer tileLayer)
- {
- SetCurrentValue(TileLayerProperty, tileLayer);
- }
}
}
diff --git a/MapControl/MapBase.cs b/MapControl/MapBase.cs
index d9ec0d5c..b0bfe14c 100644
--- a/MapControl/MapBase.cs
+++ b/MapControl/MapBase.cs
@@ -1,12 +1,8 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.Linq;
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml;
@@ -20,8 +16,14 @@ using System.Windows.Media.Animation;
namespace MapControl
{
+ public interface IMapLayer : IMapElement
+ {
+ Brush MapBackground { get; }
+ Brush MapForeground { get; }
+ }
+
///
- /// The map control. Displays map content provided by the TileLayer or TileLayers property.
+ /// The map control. Displays map content provided by one or more MapTileLayers or MapImageLayers.
/// The visible map area is defined by the Center and ZoomLevel properties.
/// The map can be rotated by an angle that is given by the Heading property.
/// MapBase can contain map overlay child elements like other MapPanels or MapItemsControls.
@@ -30,60 +32,57 @@ namespace MapControl
{
private const double MaximumZoomLevel = 22d;
- public static readonly DependencyProperty TileLayerProperty = DependencyProperty.Register(
- "TileLayer", typeof(TileLayer), typeof(MapBase),
- new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayerPropertyChanged((TileLayer)e.NewValue)));
+ public static readonly DependencyProperty MapLayerProperty = DependencyProperty.Register(
+ nameof(MapLayer), typeof(UIElement), typeof(MapBase),
+ new PropertyMetadata(null, (o, e) => ((MapBase)o).MapLayerPropertyChanged((UIElement)e.OldValue, (UIElement)e.NewValue)));
- public static readonly DependencyProperty TileLayersProperty = DependencyProperty.Register(
- "TileLayers", typeof(IList), typeof(MapBase),
- new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayersPropertyChanged((IList)e.OldValue, (IList)e.NewValue)));
+ public static readonly DependencyProperty MapProjectionProperty = DependencyProperty.Register(
+ nameof(MapProjection), typeof(MapProjection), typeof(MapBase),
+ new PropertyMetadata(null, (o, e) => ((MapBase)o).MapProjectionPropertyChanged()));
+
+ public static readonly DependencyProperty ProjectionCenterProperty = DependencyProperty.Register(
+ nameof(ProjectionCenter), typeof(Location), typeof(MapBase),
+ new PropertyMetadata(null, (o, e) => ((MapBase)o).ProjectionCenterPropertyChanged()));
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
- "MinZoomLevel", typeof(double), typeof(MapBase),
+ nameof(MinZoomLevel), typeof(double), typeof(MapBase),
new PropertyMetadata(1d, (o, e) => ((MapBase)o).MinZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
- "MaxZoomLevel", typeof(double), typeof(MapBase),
+ nameof(MaxZoomLevel), typeof(double), typeof(MapBase),
new PropertyMetadata(19d, (o, e) => ((MapBase)o).MaxZoomLevelPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register(
- "AnimationDuration", typeof(TimeSpan), typeof(MapBase),
+ nameof(AnimationDuration), typeof(TimeSpan), typeof(MapBase),
new PropertyMetadata(TimeSpan.FromSeconds(0.3)));
public static readonly DependencyProperty AnimationEasingFunctionProperty = DependencyProperty.Register(
- "AnimationEasingFunction", typeof(EasingFunctionBase), typeof(MapBase),
+ nameof(AnimationEasingFunction), typeof(EasingFunctionBase), typeof(MapBase),
new PropertyMetadata(new QuadraticEase { EasingMode = EasingMode.EaseOut }));
public static readonly DependencyProperty TileFadeDurationProperty = DependencyProperty.Register(
- "TileFadeDuration", typeof(TimeSpan), typeof(MapBase),
+ nameof(TileFadeDuration), typeof(TimeSpan), typeof(MapBase),
new PropertyMetadata(Tile.FadeDuration, (o, e) => Tile.FadeDuration = (TimeSpan)e.NewValue));
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
"CenterPoint", typeof(Point), typeof(MapBase),
new PropertyMetadata(new Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue)));
- private readonly PanelBase tileLayerPanel = new PanelBase();
- private readonly MapTransform mapTransform = new MercatorTransform();
- private readonly MatrixTransform viewportTransform = new MatrixTransform();
- private readonly ScaleTransform scaleTransform = new ScaleTransform();
- private readonly RotateTransform rotateTransform = new RotateTransform();
- private readonly TransformGroup scaleRotateTransform = new TransformGroup();
-
- private Location transformOrigin;
private PointAnimation centerAnimation;
private DoubleAnimation zoomLevelAnimation;
private DoubleAnimation headingAnimation;
+ private Location transformCenter;
+ private Point viewportCenter;
+ private double centerLongitude;
private bool internalPropertyChange;
public MapBase()
{
Initialize();
- scaleRotateTransform.Children.Add(scaleTransform);
- scaleRotateTransform.Children.Add(rotateTransform);
-
- Children.Add(tileLayerPanel);
- TileLayers = new ObservableCollection();
+ MapProjection = new WebMercatorProjection();
+ ScaleRotateTransform.Children.Add(ScaleTransform);
+ ScaleRotateTransform.Children.Add(RotateTransform);
}
partial void Initialize(); // Windows Runtime and Silverlight only
@@ -104,27 +103,37 @@ namespace MapControl
}
///
- /// Gets or sets the base TileLayer used by the Map control.
+ /// Gets or sets the base map layer, which is added as first element to the Children collection.
+ /// If the layer implements IMapLayer (like MapTileLayer or MapImageLayer), its (non-null) MapBackground
+ /// and MapForeground property values are used for the MapBase Background and Foreground properties.
///
- public TileLayer TileLayer
+ public UIElement MapLayer
{
- get { return (TileLayer)GetValue(TileLayerProperty); }
- set { SetValue(TileLayerProperty, value); }
+ get { return (UIElement)GetValue(MapLayerProperty); }
+ set { SetValue(MapLayerProperty, value); }
}
///
- /// Gets or sets optional multiple TileLayers that are used simultaneously.
- /// The first element in the collection is equal to the value of the TileLayer
- /// property. The additional TileLayers usually have transparent backgrounds.
+ /// Gets or sets the MapProjection used by the map control.
///
- public IList TileLayers
+ public MapProjection MapProjection
{
- get { return (IList)GetValue(TileLayersProperty); }
- set { SetValue(TileLayersProperty, value); }
+ get { return (MapProjection)GetValue(MapProjectionProperty); }
+ set { SetValue(MapProjectionProperty, value); }
}
///
- /// Gets or sets the location of the center point of the Map.
+ /// Gets or sets an optional center (reference point) for azimuthal projections.
+ /// If ProjectionCenter is null, the Center property value will be used instead.
+ ///
+ public Location ProjectionCenter
+ {
+ get { return (Location)GetValue(ProjectionCenterProperty); }
+ set { SetValue(ProjectionCenterProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the location of the center point of the map.
///
public Location Center
{
@@ -229,111 +238,54 @@ namespace MapControl
set { SetValue(TileFadeDurationProperty, value); }
}
- ///
- /// Gets the transformation from geographic coordinates to cartesian map coordinates.
- ///
- public MapTransform MapTransform
- {
- get { return mapTransform; }
- }
-
- ///
- /// Gets the transformation from cartesian map coordinates to viewport coordinates (i.e. pixels).
- ///
- public MatrixTransform ViewportTransform
- {
- get { return viewportTransform; }
- }
-
///
/// Gets the scaling transformation from meters to viewport coordinate units at the Center location.
///
- public ScaleTransform ScaleTransform
- {
- get { return scaleTransform; }
- }
+ public ScaleTransform ScaleTransform { get; } = new ScaleTransform();
///
/// Gets the transformation that rotates by the value of the Heading property.
///
- public RotateTransform RotateTransform
- {
- get { return rotateTransform; }
- }
+ public RotateTransform RotateTransform { get; } = new RotateTransform();
///
/// Gets the combination of ScaleTransform and RotateTransform
///
- public TransformGroup ScaleRotateTransform
- {
- get { return scaleRotateTransform; }
- }
-
- internal Point MapOrigin { get; private set; }
- internal Point ViewportOrigin { get; private set; }
+ public TransformGroup ScaleRotateTransform { get; } = new TransformGroup();
///
- /// Gets the scaling factor from cartesian map coordinates to viewport coordinates.
- ///
- public double ViewportScale { get; private set; }
-
- ///
- /// Gets the scaling factor from meters to viewport coordinate units at the Center location (px/m).
- ///
- public double CenterScale { get; private set; }
-
- ///
- /// Gets the map scale at the specified location as viewport coordinate units per meter (px/m).
- ///
- public double GetMapScale(Location location)
- {
- return mapTransform.RelativeScale(location) *
- Math.Pow(2d, ZoomLevel) * TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
- }
-
- ///
- /// Transforms a geographic location to a viewport coordinates point.
+ /// Transforms a Location in geographic coordinates to a Point in viewport coordinates.
///
public Point LocationToViewportPoint(Location location)
{
- return viewportTransform.Transform(mapTransform.Transform(location));
+ return MapProjection.LocationToViewportPoint(location);
}
///
- /// Transforms a viewport coordinates point to a geographic location.
+ /// Transforms a Point in viewport coordinates to a Location in geographic coordinates.
///
public Location ViewportPointToLocation(Point point)
{
- return mapTransform.Transform(viewportTransform.Inverse.Transform(point));
+ return MapProjection.ViewportPointToLocation(point);
}
///
- /// Sets a temporary origin location in geographic coordinates for scaling and rotation transformations.
- /// This origin location is automatically reset when the Center property is set by application code.
+ /// Sets a temporary center point in viewport coordinates for scaling and rotation transformations.
+ /// This center point is automatically reset when the Center property is set by application code.
///
- public void SetTransformOrigin(Location origin)
+ public void SetTransformCenter(Point center)
{
- transformOrigin = origin;
- ViewportOrigin = LocationToViewportPoint(origin);
+ transformCenter = MapProjection.ViewportPointToLocation(center);
+ viewportCenter = center;
}
///
- /// Sets a temporary origin point in viewport coordinates for scaling and rotation transformations.
- /// This origin point is automatically reset when the Center property is set by application code.
+ /// Resets the temporary transform center point set by SetTransformCenter.
///
- public void SetTransformOrigin(Point origin)
+ public void ResetTransformCenter()
{
- transformOrigin = ViewportPointToLocation(origin);
- ViewportOrigin = origin;
- }
-
- ///
- /// Resets the temporary transform origin point set by SetTransformOrigin.
- ///
- public void ResetTransformOrigin()
- {
- transformOrigin = null;
- ViewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
+ transformCenter = null;
+ viewportCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
}
///
@@ -341,9 +293,9 @@ namespace MapControl
///
public void TranslateMap(Point translation)
{
- if (transformOrigin != null)
+ if (transformCenter != null)
{
- ResetTransformOrigin();
+ ResetTransformCenter();
UpdateTransform();
}
@@ -359,24 +311,24 @@ namespace MapControl
translation.Y * cos - translation.X * sin);
}
- translation.X /= -ViewportScale;
- translation.Y /= ViewportScale;
+ translation.X = -translation.X;
+ translation.Y = -translation.Y;
- Center = mapTransform.Transform(Center, MapOrigin, translation);
+ Center = MapProjection.TranslateLocation(Center, 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 origin point in viewport coordinates.
+ /// is performed relative to the specified center point in viewport coordinates.
///
- public void TransformMap(Point origin, Point translation, double rotation, double scale)
+ public void TransformMap(Point center, Point translation, double rotation, double scale)
{
if (rotation != 0d || scale != 1d)
{
- transformOrigin = ViewportPointToLocation(origin);
- ViewportOrigin = new Point(origin.X + translation.X, origin.Y + translation.Y);
+ transformCenter = MapProjection.ViewportPointToLocation(center);
+ viewportCenter = new Point(center.X + translation.X, center.Y + translation.Y);
if (rotation != 0d)
{
@@ -401,175 +353,104 @@ namespace MapControl
}
///
- /// Sets the value of the TargetZoomLevel property while retaining the specified origin point
+ /// Sets the value of the TargetZoomLevel property while retaining the specified center point
/// in viewport coordinates.
///
- public void ZoomMap(Point origin, double zoomLevel)
+ public void ZoomMap(Point center, double zoomLevel)
{
zoomLevel = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
if (TargetZoomLevel != zoomLevel)
{
- SetTransformOrigin(origin);
- TargetZoomLevel = zoomLevel;
+ SetTransformCenter(center);
+
+ if (double.IsNaN(MapProjection.LongitudeScale))
+ {
+ ZoomLevel = zoomLevel;
+ }
+ else
+ {
+ TargetZoomLevel = zoomLevel;
+ }
}
}
///
- /// Sets the TargetZoomLevel and TargetCenter properties such that the specified bounding box
+ /// Sets the TargetZoomLevel and TargetCenter properties so that the specified bounding box
/// fits into the current viewport. The TargetHeading property is set to zero.
///
- public void ZoomToBounds(Location southWest, Location northEast)
+ public void ZoomToBounds(BoundingBox boundingBox)
{
- if (southWest.Latitude < northEast.Latitude && southWest.Longitude < northEast.Longitude)
+ if (boundingBox != null && boundingBox.HasValidBounds)
{
- var p1 = mapTransform.Transform(southWest);
- var p2 = mapTransform.Transform(northEast);
- var lonScale = RenderSize.Width / (p2.X - p1.X) * 360d / TileSource.TileSize;
- var latScale = RenderSize.Height / (p2.Y - p1.Y) * 360d / TileSource.TileSize;
+ var rect = MapProjection.BoundingBoxToRect(boundingBox);
+ var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
+ var scale0 = 1d / MapProjection.GetViewportScale(0d);
+ var lonScale = scale0 * RenderSize.Width / rect.Width;
+ var latScale = scale0 * RenderSize.Height / rect.Height;
var lonZoom = Math.Log(lonScale, 2d);
var latZoom = Math.Log(latScale, 2d);
TargetZoomLevel = Math.Min(lonZoom, latZoom);
- TargetCenter = mapTransform.Transform(new Point((p1.X + p2.X) / 2d, (p1.Y + p2.Y) / 2d));
+ TargetCenter = MapProjection.PointToLocation(center);
TargetHeading = 0d;
}
}
- private void TileLayerPropertyChanged(TileLayer tileLayer)
+ private void MapLayerPropertyChanged(UIElement oldLayer, UIElement newLayer)
{
- if (tileLayer != null)
+ if (oldLayer != null)
{
- if (TileLayers == null)
+ Children.Remove(oldLayer);
+
+ var mapLayer = oldLayer as IMapLayer;
+ if (mapLayer != null)
{
- TileLayers = new ObservableCollection(new TileLayer[] { tileLayer });
- }
- else if (TileLayers.Count == 0)
- {
- TileLayers.Add(tileLayer);
- }
- else if (TileLayers[0] != tileLayer)
- {
- TileLayers[0] = tileLayer;
- }
- }
- }
-
- private void TileLayersPropertyChanged(IList oldTileLayers, IList newTileLayers)
- {
- if (oldTileLayers != null)
- {
- var oldCollection = oldTileLayers as INotifyCollectionChanged;
- if (oldCollection != null)
- {
- oldCollection.CollectionChanged -= TileLayerCollectionChanged;
- }
-
- SetTileLayer(null);
- ClearTileLayers();
- }
-
- if (newTileLayers != null)
- {
- SetTileLayer(newTileLayers.FirstOrDefault());
- AddTileLayers(0, newTileLayers);
-
- var newCollection = newTileLayers as INotifyCollectionChanged;
- if (newCollection != null)
- {
- newCollection.CollectionChanged += TileLayerCollectionChanged;
- }
- }
- }
-
- private void TileLayerCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
- {
- switch (e.Action)
- {
- case NotifyCollectionChangedAction.Add:
- AddTileLayers(e.NewStartingIndex, e.NewItems.Cast());
- break;
-
- case NotifyCollectionChangedAction.Remove:
- RemoveTileLayers(e.OldStartingIndex, e.OldItems.Count);
- break;
-#if !SILVERLIGHT
- case NotifyCollectionChangedAction.Move:
-#endif
- case NotifyCollectionChangedAction.Replace:
- RemoveTileLayers(e.NewStartingIndex, e.OldItems.Count);
- AddTileLayers(e.NewStartingIndex, e.NewItems.Cast());
- break;
-
- case NotifyCollectionChangedAction.Reset:
- ClearTileLayers();
- if (e.NewItems != null)
+ if (mapLayer.MapBackground != null)
{
- AddTileLayers(0, e.NewItems.Cast());
+ ClearValue(BackgroundProperty);
}
- break;
-
- default:
- break;
- }
-
- var tileLayer = TileLayers.FirstOrDefault();
-
- if (TileLayer != tileLayer)
- {
- SetTileLayer(tileLayer);
- }
- }
-
- private void AddTileLayers(int index, IEnumerable tileLayers)
- {
- foreach (var tileLayer in tileLayers)
- {
- if (index == 0)
- {
- if (tileLayer.Background != null)
+ if (mapLayer.MapForeground != null)
{
- Background = tileLayer.Background;
- }
-
- if (tileLayer.Foreground != null)
- {
- Foreground = tileLayer.Foreground;
+ ClearValue(ForegroundProperty);
}
}
-
- tileLayerPanel.Children.Insert(index++, tileLayer);
}
- }
- private void RemoveTileLayers(int index, int count)
- {
- while (count-- > 0)
+ if (newLayer != null)
{
- tileLayerPanel.Children.RemoveAt(index + count);
- }
+ Children.Insert(0, newLayer);
- if (index == 0)
+ var mapLayer = newLayer as IMapLayer;
+ if (mapLayer != null)
+ {
+ if (mapLayer.MapBackground != null)
+ {
+ Background = mapLayer.MapBackground;
+ }
+ if (mapLayer.MapForeground != null)
+ {
+ Foreground = mapLayer.MapForeground;
+ }
+ }
+ }
+ }
+
+ private void MapProjectionPropertyChanged()
+ {
+ ResetTransformCenter();
+ UpdateTransform(false, true);
+ }
+
+ private void ProjectionCenterPropertyChanged()
+ {
+ if (MapProjection.IsAzimuthal)
{
- ClearValue(BackgroundProperty);
- ClearValue(ForegroundProperty);
+ ResetTransformCenter();
+ UpdateTransform();
}
}
- private void ClearTileLayers()
- {
- tileLayerPanel.Children.Clear();
- ClearValue(BackgroundProperty);
- ClearValue(ForegroundProperty);
- }
-
- private void InternalSetValue(DependencyProperty property, object value)
- {
- internalPropertyChange = true;
- SetValue(property, value);
- internalPropertyChange = false;
- }
-
private void AdjustCenterProperty(DependencyProperty property, ref Location center)
{
if (center == null)
@@ -578,10 +459,10 @@ namespace MapControl
InternalSetValue(property, center);
}
else if (center.Longitude < -180d || center.Longitude > 180d ||
- center.Latitude < -mapTransform.MaxLatitude || center.Latitude > mapTransform.MaxLatitude)
+ center.Latitude < -MapProjection.MaxLatitude || center.Latitude > MapProjection.MaxLatitude)
{
center = new Location(
- Math.Min(Math.Max(center.Latitude, -mapTransform.MaxLatitude), mapTransform.MaxLatitude),
+ Math.Min(Math.Max(center.Latitude, -MapProjection.MaxLatitude), MapProjection.MaxLatitude),
Location.NormalizeLongitude(center.Longitude));
InternalSetValue(property, center);
}
@@ -597,7 +478,7 @@ namespace MapControl
if (centerAnimation == null)
{
InternalSetValue(TargetCenterProperty, center);
- InternalSetValue(CenterPointProperty, mapTransform.Transform(center));
+ InternalSetValue(CenterPointProperty, MapProjection.LocationToPoint(center));
}
}
}
@@ -618,8 +499,8 @@ namespace MapControl
// animate private CenterPoint property by PointAnimation
centerAnimation = new PointAnimation
{
- From = mapTransform.Transform(Center),
- To = mapTransform.Transform(new Location(
+ From = MapProjection.LocationToPoint(Center),
+ To = MapProjection.LocationToPoint(new Location(
targetCenter.Latitude,
Location.NearestLongitude(targetCenter.Longitude, Center.Longitude))),
Duration = AnimationDuration,
@@ -640,7 +521,7 @@ namespace MapControl
centerAnimation = null;
InternalSetValue(CenterProperty, TargetCenter);
- InternalSetValue(CenterPointProperty, mapTransform.Transform(TargetCenter));
+ InternalSetValue(CenterPointProperty, MapProjection.LocationToPoint(TargetCenter));
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
UpdateTransform();
}
@@ -650,8 +531,10 @@ namespace MapControl
{
if (!internalPropertyChange)
{
- centerPoint.X = Location.NormalizeLongitude(centerPoint.X);
- InternalSetValue(CenterProperty, mapTransform.Transform(centerPoint));
+ var center = MapProjection.PointToLocation(centerPoint);
+ center.Longitude = Location.NormalizeLongitude(center.Longitude);
+
+ InternalSetValue(CenterProperty, center);
UpdateTransform();
}
}
@@ -742,6 +625,7 @@ namespace MapControl
InternalSetValue(ZoomLevelProperty, TargetZoomLevel);
RemoveAnimation(ZoomLevelProperty); // remove holding animation in WPF
+
UpdateTransform(true);
}
}
@@ -819,22 +703,29 @@ namespace MapControl
}
}
- private void UpdateTransform(bool resetOrigin = false)
+ private void InternalSetValue(DependencyProperty property, object value)
{
- var mapOriginX = MapOrigin.X;
- var center = transformOrigin ?? Center;
+ internalPropertyChange = true;
+ SetValue(property, value);
+ internalPropertyChange = false;
+ }
- SetViewportTransform(center);
+ private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false)
+ {
+ var projection = MapProjection;
+ var center = transformCenter ?? Center;
- if (transformOrigin != null)
+ projection.SetViewportTransform(ProjectionCenter ?? Center, center, viewportCenter, ZoomLevel, Heading);
+
+ if (transformCenter != null)
{
- center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
+ center = projection.ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
center.Longitude = Location.NormalizeLongitude(center.Longitude);
- if (center.Latitude < -mapTransform.MaxLatitude || center.Latitude > mapTransform.MaxLatitude)
+ if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude)
{
- center.Latitude = Math.Min(Math.Max(center.Latitude, -mapTransform.MaxLatitude), mapTransform.MaxLatitude);
- resetOrigin = true;
+ center.Latitude = Math.Min(Math.Max(center.Latitude, -projection.MaxLatitude), projection.MaxLatitude);
+ resetTransformCenter = true;
}
InternalSetValue(CenterProperty, center);
@@ -842,22 +733,24 @@ namespace MapControl
if (centerAnimation == null)
{
InternalSetValue(TargetCenterProperty, center);
- InternalSetValue(CenterPointProperty, mapTransform.Transform(center));
+ InternalSetValue(CenterPointProperty, projection.LocationToPoint(center));
}
- if (resetOrigin)
+ if (resetTransformCenter)
{
- ResetTransformOrigin();
- SetViewportTransform(center);
+ ResetTransformCenter();
+ projection.SetViewportTransform(ProjectionCenter ?? center, center, viewportCenter, ZoomLevel, Heading);
}
}
- CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree;
- scaleTransform.ScaleX = CenterScale;
- scaleTransform.ScaleY = CenterScale;
- rotateTransform.Angle = Heading;
+ var scale = projection.GetMapScale(center);
+ ScaleTransform.ScaleX = scale.X;
+ ScaleTransform.ScaleY = scale.Y;
+ RotateTransform.Angle = Heading;
- OnViewportChanged(new ViewportChangedEventArgs(MapOrigin.X - mapOriginX));
+ OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
+
+ centerLongitude = Center.Longitude;
}
protected override void OnViewportChanged(ViewportChangedEventArgs e)
diff --git a/MapControl/MapControl.Silverlight.csproj b/MapControl/MapControl.Silverlight.csproj
index baf3f127..b928a02f 100644
--- a/MapControl/MapControl.Silverlight.csproj
+++ b/MapControl/MapControl.Silverlight.csproj
@@ -68,13 +68,18 @@
+
+
+
+
+
+
+
-
-
@@ -82,11 +87,10 @@
-
-
-
+
+
@@ -97,23 +101,23 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
diff --git a/MapControl/MapControl.WPF.csproj b/MapControl/MapControl.WPF.csproj
index 1e89bd4d..8686ca08 100644
--- a/MapControl/MapControl.WPF.csproj
+++ b/MapControl/MapControl.WPF.csproj
@@ -52,13 +52,18 @@
+
+
-
+
+
+
+
+
+
-
-
@@ -66,41 +71,39 @@
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
-
+
diff --git a/MapControl/MapGraticule.Silverlight.WinRT.cs b/MapControl/MapGraticule.Silverlight.WinRT.cs
index 702ae56c..5afc34a0 100644
--- a/MapControl/MapGraticule.Silverlight.WinRT.cs
+++ b/MapControl/MapGraticule.Silverlight.WinRT.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -34,169 +34,180 @@ namespace MapControl
protected override void OnViewportChanged(ViewportChangedEventArgs e)
{
- if (path == null)
+ var projection = ParentMap.MapProjection;
+
+ if (!double.IsNaN(projection.LongitudeScale))
{
- path = new Path
+ if (path == null)
{
- Data = new PathGeometry()
- };
-
- path.SetBinding(Shape.StrokeProperty,
- GetBindingExpression(StrokeProperty)?.ParentBinding ??
- new Binding
+ path = new Path
{
- Source = this,
- Path = new PropertyPath("Stroke")
- });
-
- path.SetBinding(Shape.StrokeThicknessProperty,
- GetBindingExpression(StrokeThicknessProperty)?.ParentBinding ??
- new Binding
- {
- Source = this,
- Path = new PropertyPath("StrokeThickness")
- });
-
- Children.Add(path);
- }
-
- var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(new Point(), ParentMap.RenderSize));
- var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
- var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
- var lineDistance = GetLineDistance();
-
- var labelStart = new Location(
- Math.Ceiling(start.Latitude / lineDistance) * lineDistance,
- Math.Ceiling(start.Longitude / lineDistance) * lineDistance);
-
- var labelEnd = new Location(
- Math.Floor(end.Latitude / lineDistance) * lineDistance,
- Math.Floor(end.Longitude / lineDistance) * lineDistance);
-
- var lineStart = new Location(
- Math.Min(Math.Max(labelStart.Latitude - lineDistance, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
- labelStart.Longitude - lineDistance);
-
- var lineEnd = new Location(
- Math.Min(Math.Max(labelEnd.Latitude + lineDistance, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
- labelEnd.Longitude + lineDistance);
-
- if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
- {
- graticuleStart = lineStart;
- graticuleEnd = lineEnd;
-
- var geometry = (PathGeometry)path.Data;
- geometry.Figures.Clear();
- geometry.Transform = ParentMap.ViewportTransform;
-
- for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += lineDistance)
- {
- var figure = new PathFigure
- {
- StartPoint = ParentMap.MapTransform.Transform(new Location(lat, lineStart.Longitude)),
- IsClosed = false,
- IsFilled = false
+ Data = new PathGeometry()
};
- figure.Segments.Add(new LineSegment
- {
- Point = ParentMap.MapTransform.Transform(new Location(lat, lineEnd.Longitude)),
- });
+ path.SetBinding(Shape.StrokeProperty,
+ GetBindingExpression(StrokeProperty)?.ParentBinding ??
+ new Binding
+ {
+ Source = this,
+ Path = new PropertyPath("Stroke")
+ });
- geometry.Figures.Add(figure);
+ path.SetBinding(Shape.StrokeThicknessProperty,
+ GetBindingExpression(StrokeThicknessProperty)?.ParentBinding ??
+ new Binding
+ {
+ Source = this,
+ Path = new PropertyPath("StrokeThickness")
+ });
+
+ Children.Add(path);
}
- for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += lineDistance)
+ var bounds = projection.ViewportRectToBoundingBox(new Rect(0d, 0d, ParentMap.RenderSize.Width, ParentMap.RenderSize.Height));
+ var lineDistance = GetLineDistance();
+
+ var labelStart = new Location(
+ Math.Ceiling(bounds.South / lineDistance) * lineDistance,
+ Math.Ceiling(bounds.West / lineDistance) * lineDistance);
+
+ var labelEnd = new Location(
+ Math.Floor(bounds.North / lineDistance) * lineDistance,
+ Math.Floor(bounds.East / lineDistance) * lineDistance);
+
+ var lineStart = new Location(
+ Math.Min(Math.Max(labelStart.Latitude - lineDistance, -projection.MaxLatitude), projection.MaxLatitude),
+ labelStart.Longitude - lineDistance);
+
+ var lineEnd = new Location(
+ Math.Min(Math.Max(labelEnd.Latitude + lineDistance, -projection.MaxLatitude), projection.MaxLatitude),
+ labelEnd.Longitude + lineDistance);
+
+ if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
{
- var figure = new PathFigure
+ 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)
{
- StartPoint = ParentMap.MapTransform.Transform(new Location(lineStart.Latitude, lon)),
- IsClosed = false,
- IsFilled = false
- };
-
- figure.Segments.Add(new LineSegment
- {
- Point = ParentMap.MapTransform.Transform(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 <= end.Latitude; lat += lineDistance)
- {
- for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += lineDistance)
- {
- TextBlock label;
-
- if (childIndex < Children.Count)
+ var figure = new PathFigure
{
- label = (TextBlock)Children[childIndex];
- }
- else
- {
- var renderTransform = new TransformGroup();
- renderTransform.Children.Add(new TranslateTransform());
- renderTransform.Children.Add(ParentMap.RotateTransform);
- renderTransform.Children.Add(new TranslateTransform());
+ StartPoint = projection.LocationToPoint(new Location(lat, lineStart.Longitude)),
+ IsClosed = false,
+ IsFilled = false
+ };
- label = new TextBlock
+ figure.Segments.Add(new LineSegment
+ {
+ Point = projection.LocationToPoint(new Location(lat, lineEnd.Longitude)),
+ });
+
+ geometry.Figures.Add(figure);
+ }
+
+ for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance)
+ {
+ var figure = new PathFigure
+ {
+ 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)
{
- RenderTransform = renderTransform
- };
+ 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.SetBinding(TextBlock.ForegroundProperty,
- GetBindingExpression(ForegroundProperty)?.ParentBinding ??
- new Binding
+ label = new TextBlock
{
- Source = this,
- Path = new PropertyPath("Foreground")
- });
+ RenderTransform = renderTransform
+ };
- Children.Add(label);
+ 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;
}
+ }
- 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)
+ {
+ Children.RemoveAt(Children.Count - 1);
}
}
- while (Children.Count > childIndex)
+ // don't use MapPanel.Location because labels may be at more than 180° distance from map center
+
+ for (int i = 1; i < Children.Count; i++)
{
- Children.RemoveAt(Children.Count - 1);
+ var label = (TextBlock)Children[i];
+ var location = (Location)label.Tag;
+ var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
+ var viewportPosition = projection.LocationToViewportPoint(location);
+ viewportTransform.X = viewportPosition.X;
+ viewportTransform.Y = viewportPosition.Y;
}
}
-
- // don't use MapPanel.Location because labels may be at more than 180° distance from map center
-
- for (int i = 1; i < Children.Count; i++)
+ else if (path != null)
{
- var label = (TextBlock)Children[i];
- var location = (Location)label.Tag;
- var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
- var viewportPosition = ParentMap.LocationToViewportPoint(location);
- viewportTransform.X = viewportPosition.X;
- viewportTransform.Y = viewportPosition.Y;
+ path = null;
+ graticuleStart = null;
+ graticuleEnd = null;
+
+ Children.Clear();
}
base.OnViewportChanged(e);
diff --git a/MapControl/MapGraticule.WPF.cs b/MapControl/MapGraticule.WPF.cs
index 3035b2fa..df215e59 100644
--- a/MapControl/MapGraticule.WPF.cs
+++ b/MapControl/MapGraticule.WPF.cs
@@ -1,5 +1,5 @@
-// XAML Map Control - http://xamlmapcontrol.codeplex.com/
-// © 2016 Clemens Fischer
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
@@ -26,11 +26,8 @@ namespace MapControl
static MapGraticule()
{
- IsHitTestVisibleProperty.OverrideMetadata(
- typeof(MapGraticule), new FrameworkPropertyMetadata(false));
-
- StrokeThicknessProperty.OverrideMetadata(
- typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
+ IsHitTestVisibleProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(false));
+ StrokeThicknessProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
}
protected override void OnViewportChanged(ViewportChangedEventArgs e)
@@ -40,45 +37,45 @@ namespace MapControl
protected override void OnRender(DrawingContext drawingContext)
{
- if (ParentMap != null)
+ var projection = ParentMap?.MapProjection;
+
+ if (projection != null && !double.IsNaN(projection.LongitudeScale))
{
- var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(ParentMap.RenderSize));
- var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
- var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
+ var bounds = projection.ViewportRectToBoundingBox(new Rect(ParentMap.RenderSize));
var lineDistance = GetLineDistance();
var labelFormat = GetLabelFormat(lineDistance);
- var latLabelStart = Math.Ceiling(start.Latitude / lineDistance) * lineDistance;
- var lonLabelStart = Math.Ceiling(start.Longitude / lineDistance) * lineDistance;
- var latLabels = new List