mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Version 3.1.Added support for different map projections.
This commit is contained in:
parent
06c3ed56c1
commit
643abeca1e
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyDescription("ObjectCache implementation based on EzTools FileDb")]
|
[assembly: AssemblyDescription("ObjectCache implementation based on EzTools FileDb")]
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")]
|
[assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")]
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyDescription("ObjectCache implementation based on local image files")]
|
[assembly: AssemblyDescription("ObjectCache implementation based on local image files")]
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyDescription("IImageCache implementation based on local image files")]
|
[assembly: AssemblyDescription("IImageCache implementation based on local image files")]
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
199
MapControl.sln
199
MapControl.sln
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 12.0.31101.0
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WinRT", "Caching\FileDbCache.WinRT\FileDbCache.WinRT.csproj", "{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -17,78 +17,210 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WinRT", "MapCont
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\MapControl.WPF.csproj", "{226F3575-B683-446D-A2F0-181291DC8787}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\MapControl.WPF.csproj", "{226F3575-B683-446D-A2F0-181291DC8787}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{9949326E-9261-4F95-89B1-151F60498951}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{100879CC-8910-459E-856E-253D629E45DE}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{100879CC-8910-459E-856E-253D629E45DE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{AE8A7E02-0F7D-41B0-AB23-15394150ED17}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{AE8A7E02-0F7D-41B0-AB23-15394150ED17}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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|Any CPU = Release|Any CPU
|
||||||
|
Release|ARM = Release|ARM
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{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|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.ActiveCfg = Release|Any CPU
|
||||||
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.Build.0 = 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
|
{226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Build.0 = Release|Any CPU
|
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Deploy.0 = 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}.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
|
|
||||||
{9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.ActiveCfg = Debug|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|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.ActiveCfg = Release|Any CPU
|
||||||
{9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -98,10 +230,9 @@ Global
|
||||||
{EF44F661-B98A-4676-927F-85D138F82300} = {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}
|
{F789647E-96F7-43E3-A895-FA3FE8D01260} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17}
|
||||||
{86470440-FEE2-4120-AF5A-3762FB9C536F} = {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}
|
{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
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
58
MapControl/AzimuthalEquidistantProjection.cs
Normal file
58
MapControl/AzimuthalEquidistantProjection.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Azimuthal Equidistant Projection.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
MapControl/AzimuthalProjection.cs
Normal file
137
MapControl/AzimuthalProjection.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for azimuthal map projections.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates azimuth and distance in radians from location1 to location2.
|
||||||
|
/// The returned distance has to be multiplied with an appropriate earth radius.
|
||||||
|
/// </summary>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the Location of the point given by azimuth and distance in radians from location.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -10,9 +10,11 @@ using System.Net;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -20,8 +22,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays Bing Maps tiles. The static ApiKey property must be set to a Bing Maps API Key.
|
/// 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).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BingMapsTileLayer : TileLayer
|
public class BingMapsTileLayer : MapTileLayer
|
||||||
{
|
{
|
||||||
public enum MapMode
|
public enum MapMode
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +49,7 @@ namespace MapControl
|
||||||
|
|
||||||
public MapMode Mode { get; set; }
|
public MapMode Mode { get; set; }
|
||||||
public string Culture { get; set; }
|
public string Culture { get; set; }
|
||||||
|
public ImageSource LogoImage { get; set; }
|
||||||
|
|
||||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -52,13 +57,15 @@ namespace MapControl
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ApiKey))
|
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);
|
request.BeginGetResponse(HandleImageryMetadataResponse, request);
|
||||||
var request = WebRequest.CreateHttp(uri);
|
}
|
||||||
|
|
||||||
request.BeginGetResponse(HandleImageryMetadataResponse, request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleImageryMetadataResponse(IAsyncResult asyncResult)
|
private void HandleImageryMetadataResponse(IAsyncResult asyncResult)
|
||||||
|
|
@ -122,7 +129,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
|
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
|
||||||
{
|
{
|
||||||
var _ = Dispatcher.BeginInvoke(new Action(() =>
|
var op = Dispatcher.BeginInvoke(new Action(() =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Culture))
|
if (string.IsNullOrEmpty(Culture))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -13,7 +13,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates frozen BitmapSources from Stream or Uri.
|
/// Creates frozen BitmapSources from Stream or Uri.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ImageLoader
|
public static class BitmapSourceHelper
|
||||||
{
|
{
|
||||||
public static BitmapSource FromStream(Stream stream)
|
public static BitmapSource FromStream(Stream stream)
|
||||||
{
|
{
|
||||||
|
|
@ -30,19 +30,16 @@ namespace MapControl
|
||||||
|
|
||||||
public static BitmapSource FromUri(Uri uri)
|
public static BitmapSource FromUri(Uri uri)
|
||||||
{
|
{
|
||||||
BitmapSource bitmap = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = WebRequest.Create(uri);
|
using (var response = WebRequest.Create(uri).GetResponse())
|
||||||
|
|
||||||
using (var response = request.GetResponse())
|
|
||||||
using (var responseStream = response.GetResponseStream())
|
using (var responseStream = response.GetResponseStream())
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
responseStream.CopyTo(memoryStream);
|
responseStream.CopyTo(memoryStream);
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
bitmap = FromStream(memoryStream);
|
|
||||||
|
return FromStream(memoryStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -50,7 +47,7 @@ namespace MapControl
|
||||||
Debug.WriteLine(ex.Message);
|
Debug.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
92
MapControl/BoundingBox.cs
Normal file
92
MapControl/BoundingBox.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A geographic bounding box with south and north latitude and west and east longitude values in degrees.
|
||||||
|
/// </summary>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
MapControl/BoundingBoxConverter.cs
Normal file
31
MapControl/BoundingBoxConverter.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
40
MapControl/CenteredBoundingBox.cs
Normal file
40
MapControl/CenteredBoundingBox.cs
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
MapControl/EquirectangularProjection.cs
Normal file
54
MapControl/EquirectangularProjection.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Equirectangular Projection.
|
||||||
|
/// Longitude and Latitude values are transformed identically to X and Y.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
61
MapControl/GnomonicProjection.cs
Normal file
61
MapControl/GnomonicProjection.cs
Normal file
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Gnomonic Projection.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<Tile> tiles);
|
|
||||||
void CancelLoadTiles(TileLayer tileLayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -28,7 +28,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (IsAsync)
|
if (IsAsync)
|
||||||
{
|
{
|
||||||
image = ImageLoader.FromUri(uri);
|
image = BitmapSourceHelper.FromUri(uri);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -62,16 +62,16 @@ namespace MapControl
|
||||||
|
|
||||||
public static Location Parse(string s)
|
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");
|
throw new FormatException("Location string must be a comma-separated pair of double values");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Location(
|
return new Location(
|
||||||
double.Parse(pair[0], NumberStyles.Float, CultureInfo.InvariantCulture),
|
double.Parse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture),
|
||||||
double.Parse(pair[1], NumberStyles.Float, CultureInfo.InvariantCulture));
|
double.Parse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -10,7 +10,7 @@ using System.Linq;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of geographic locations.
|
/// An ObservableCollection of Location with support for parsing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class LocationCollection : ObservableCollection<Location>
|
public partial class LocationCollection : ObservableCollection<Location>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -13,7 +13,7 @@ namespace MapControl
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
|
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;
|
private Point? mousePosition;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -13,10 +13,10 @@ namespace MapControl
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty ManipulationModeProperty = DependencyProperty.Register(
|
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(
|
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;
|
private Point? mousePosition;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -15,7 +15,7 @@ namespace MapControl
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
|
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 bool transformPending;
|
||||||
private Point transformTranslation;
|
private Point transformTranslation;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
@ -19,36 +17,36 @@ namespace MapControl
|
||||||
public partial class MapBase
|
public partial class MapBase
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||||
"Foreground", typeof(Brush), typeof(MapBase),
|
nameof(Foreground), typeof(Brush), typeof(MapBase),
|
||||||
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
|
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
|
||||||
|
|
||||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(1d, (o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(1d, (o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(0d, (o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
partial void Initialize()
|
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));
|
var style = new Style(typeof(MapBase));
|
||||||
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
|
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
|
||||||
Style = style;
|
Style = style;
|
||||||
|
|
@ -62,28 +60,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
clip.Rect = new Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height);
|
clip.Rect = new Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height);
|
||||||
|
|
||||||
ResetTransformOrigin();
|
ResetTransformCenter();
|
||||||
UpdateTransform();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -15,42 +14,39 @@ namespace MapControl
|
||||||
Control.ForegroundProperty.AddOwner(typeof(MapBase));
|
Control.ForegroundProperty.AddOwner(typeof(MapBase));
|
||||||
|
|
||||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
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,
|
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
(o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
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,
|
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
(o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
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,
|
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
(o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
|
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,
|
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
(o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
|
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,
|
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
(o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
|
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,
|
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
static MapBase()
|
static MapBase()
|
||||||
{
|
{
|
||||||
ClipToBoundsProperty.OverrideMetadata(
|
ClipToBoundsProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(true));
|
||||||
typeof(MapBase), new FrameworkPropertyMetadata(true));
|
BackgroundProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
|
||||||
|
|
||||||
BackgroundProperty.OverrideMetadata(
|
|
||||||
typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void RemoveAnimation(DependencyProperty property)
|
partial void RemoveAnimation(DependencyProperty property)
|
||||||
|
|
@ -69,37 +65,19 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
||||||
/// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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)
|
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||||
{
|
{
|
||||||
base.OnRenderSizeChanged(sizeInfo);
|
base.OnRenderSizeChanged(sizeInfo);
|
||||||
|
|
||||||
ResetTransformOrigin();
|
ResetTransformCenter();
|
||||||
UpdateTransform();
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
|
@ -20,8 +16,14 @@ using System.Windows.Media.Animation;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
public interface IMapLayer : IMapElement
|
||||||
|
{
|
||||||
|
Brush MapBackground { get; }
|
||||||
|
Brush MapForeground { get; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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 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.
|
/// 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.
|
/// MapBase can contain map overlay child elements like other MapPanels or MapItemsControls.
|
||||||
|
|
@ -30,60 +32,57 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
private const double MaximumZoomLevel = 22d;
|
private const double MaximumZoomLevel = 22d;
|
||||||
|
|
||||||
public static readonly DependencyProperty TileLayerProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MapLayerProperty = DependencyProperty.Register(
|
||||||
"TileLayer", typeof(TileLayer), typeof(MapBase),
|
nameof(MapLayer), typeof(UIElement), typeof(MapBase),
|
||||||
new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayerPropertyChanged((TileLayer)e.NewValue)));
|
new PropertyMetadata(null, (o, e) => ((MapBase)o).MapLayerPropertyChanged((UIElement)e.OldValue, (UIElement)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TileLayersProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MapProjectionProperty = DependencyProperty.Register(
|
||||||
"TileLayers", typeof(IList<TileLayer>), typeof(MapBase),
|
nameof(MapProjection), typeof(MapProjection), typeof(MapBase),
|
||||||
new PropertyMetadata(null, (o, e) => ((MapBase)o).TileLayersPropertyChanged((IList<TileLayer>)e.OldValue, (IList<TileLayer>)e.NewValue)));
|
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(
|
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)));
|
new PropertyMetadata(1d, (o, e) => ((MapBase)o).MinZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
|
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)));
|
new PropertyMetadata(19d, (o, e) => ((MapBase)o).MaxZoomLevelPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register(
|
||||||
"AnimationDuration", typeof(TimeSpan), typeof(MapBase),
|
nameof(AnimationDuration), typeof(TimeSpan), typeof(MapBase),
|
||||||
new PropertyMetadata(TimeSpan.FromSeconds(0.3)));
|
new PropertyMetadata(TimeSpan.FromSeconds(0.3)));
|
||||||
|
|
||||||
public static readonly DependencyProperty AnimationEasingFunctionProperty = DependencyProperty.Register(
|
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 }));
|
new PropertyMetadata(new QuadraticEase { EasingMode = EasingMode.EaseOut }));
|
||||||
|
|
||||||
public static readonly DependencyProperty TileFadeDurationProperty = DependencyProperty.Register(
|
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));
|
new PropertyMetadata(Tile.FadeDuration, (o, e) => Tile.FadeDuration = (TimeSpan)e.NewValue));
|
||||||
|
|
||||||
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
||||||
"CenterPoint", typeof(Point), typeof(MapBase),
|
"CenterPoint", typeof(Point), typeof(MapBase),
|
||||||
new PropertyMetadata(new Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Point)e.NewValue)));
|
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 PointAnimation centerAnimation;
|
||||||
private DoubleAnimation zoomLevelAnimation;
|
private DoubleAnimation zoomLevelAnimation;
|
||||||
private DoubleAnimation headingAnimation;
|
private DoubleAnimation headingAnimation;
|
||||||
|
private Location transformCenter;
|
||||||
|
private Point viewportCenter;
|
||||||
|
private double centerLongitude;
|
||||||
private bool internalPropertyChange;
|
private bool internalPropertyChange;
|
||||||
|
|
||||||
public MapBase()
|
public MapBase()
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
scaleRotateTransform.Children.Add(scaleTransform);
|
MapProjection = new WebMercatorProjection();
|
||||||
scaleRotateTransform.Children.Add(rotateTransform);
|
ScaleRotateTransform.Children.Add(ScaleTransform);
|
||||||
|
ScaleRotateTransform.Children.Add(RotateTransform);
|
||||||
Children.Add(tileLayerPanel);
|
|
||||||
TileLayers = new ObservableCollection<TileLayer>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void Initialize(); // Windows Runtime and Silverlight only
|
partial void Initialize(); // Windows Runtime and Silverlight only
|
||||||
|
|
@ -104,27 +103,37 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TileLayer TileLayer
|
public UIElement MapLayer
|
||||||
{
|
{
|
||||||
get { return (TileLayer)GetValue(TileLayerProperty); }
|
get { return (UIElement)GetValue(MapLayerProperty); }
|
||||||
set { SetValue(TileLayerProperty, value); }
|
set { SetValue(MapLayerProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets optional multiple TileLayers that are used simultaneously.
|
/// Gets or sets the MapProjection used by the map control.
|
||||||
/// The first element in the collection is equal to the value of the TileLayer
|
|
||||||
/// property. The additional TileLayers usually have transparent backgrounds.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<TileLayer> TileLayers
|
public MapProjection MapProjection
|
||||||
{
|
{
|
||||||
get { return (IList<TileLayer>)GetValue(TileLayersProperty); }
|
get { return (MapProjection)GetValue(MapProjectionProperty); }
|
||||||
set { SetValue(TileLayersProperty, value); }
|
set { SetValue(MapProjectionProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public Location ProjectionCenter
|
||||||
|
{
|
||||||
|
get { return (Location)GetValue(ProjectionCenterProperty); }
|
||||||
|
set { SetValue(ProjectionCenterProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the location of the center point of the map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Location Center
|
public Location Center
|
||||||
{
|
{
|
||||||
|
|
@ -229,111 +238,54 @@ namespace MapControl
|
||||||
set { SetValue(TileFadeDurationProperty, value); }
|
set { SetValue(TileFadeDurationProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the transformation from geographic coordinates to cartesian map coordinates.
|
|
||||||
/// </summary>
|
|
||||||
public MapTransform MapTransform
|
|
||||||
{
|
|
||||||
get { return mapTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates (i.e. pixels).
|
|
||||||
/// </summary>
|
|
||||||
public MatrixTransform ViewportTransform
|
|
||||||
{
|
|
||||||
get { return viewportTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scaling transformation from meters to viewport coordinate units at the Center location.
|
/// Gets the scaling transformation from meters to viewport coordinate units at the Center location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ScaleTransform ScaleTransform
|
public ScaleTransform ScaleTransform { get; } = new ScaleTransform();
|
||||||
{
|
|
||||||
get { return scaleTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transformation that rotates by the value of the Heading property.
|
/// Gets the transformation that rotates by the value of the Heading property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RotateTransform RotateTransform
|
public RotateTransform RotateTransform { get; } = new RotateTransform();
|
||||||
{
|
|
||||||
get { return rotateTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the combination of ScaleTransform and RotateTransform
|
/// Gets the combination of ScaleTransform and RotateTransform
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TransformGroup ScaleRotateTransform
|
public TransformGroup ScaleRotateTransform { get; } = new TransformGroup();
|
||||||
{
|
|
||||||
get { return scaleRotateTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Point MapOrigin { get; private set; }
|
|
||||||
internal Point ViewportOrigin { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scaling factor from cartesian map coordinates to viewport coordinates.
|
/// Transforms a Location in geographic coordinates to a Point in viewport coordinates.
|
||||||
/// </summary>
|
|
||||||
public double ViewportScale { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the scaling factor from meters to viewport coordinate units at the Center location (px/m).
|
|
||||||
/// </summary>
|
|
||||||
public double CenterScale { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the map scale at the specified location as viewport coordinate units per meter (px/m).
|
|
||||||
/// </summary>
|
|
||||||
public double GetMapScale(Location location)
|
|
||||||
{
|
|
||||||
return mapTransform.RelativeScale(location) *
|
|
||||||
Math.Pow(2d, ZoomLevel) * TileSource.TileSize / (TileSource.MetersPerDegree * 360d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms a geographic location to a viewport coordinates point.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point LocationToViewportPoint(Location location)
|
public Point LocationToViewportPoint(Location location)
|
||||||
{
|
{
|
||||||
return viewportTransform.Transform(mapTransform.Transform(location));
|
return MapProjection.LocationToViewportPoint(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a viewport coordinates point to a geographic location.
|
/// Transforms a Point in viewport coordinates to a Location in geographic coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Location ViewportPointToLocation(Point point)
|
public Location ViewportPointToLocation(Point point)
|
||||||
{
|
{
|
||||||
return mapTransform.Transform(viewportTransform.Inverse.Transform(point));
|
return MapProjection.ViewportPointToLocation(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a temporary origin location in geographic coordinates for scaling and rotation transformations.
|
/// Sets a temporary center point in viewport coordinates for scaling and rotation transformations.
|
||||||
/// This origin location is automatically reset when the Center property is set by application code.
|
/// This center point is automatically reset when the Center property is set by application code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetTransformOrigin(Location origin)
|
public void SetTransformCenter(Point center)
|
||||||
{
|
{
|
||||||
transformOrigin = origin;
|
transformCenter = MapProjection.ViewportPointToLocation(center);
|
||||||
ViewportOrigin = LocationToViewportPoint(origin);
|
viewportCenter = center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a temporary origin point in viewport coordinates for scaling and rotation transformations.
|
/// Resets the temporary transform center point set by SetTransformCenter.
|
||||||
/// This origin point is automatically reset when the Center property is set by application code.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetTransformOrigin(Point origin)
|
public void ResetTransformCenter()
|
||||||
{
|
{
|
||||||
transformOrigin = ViewportPointToLocation(origin);
|
transformCenter = null;
|
||||||
ViewportOrigin = origin;
|
viewportCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the temporary transform origin point set by SetTransformOrigin.
|
|
||||||
/// </summary>
|
|
||||||
public void ResetTransformOrigin()
|
|
||||||
{
|
|
||||||
transformOrigin = null;
|
|
||||||
ViewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -341,9 +293,9 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TranslateMap(Point translation)
|
public void TranslateMap(Point translation)
|
||||||
{
|
{
|
||||||
if (transformOrigin != null)
|
if (transformCenter != null)
|
||||||
{
|
{
|
||||||
ResetTransformOrigin();
|
ResetTransformCenter();
|
||||||
UpdateTransform();
|
UpdateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,24 +311,24 @@ namespace MapControl
|
||||||
translation.Y * cos - translation.X * sin);
|
translation.Y * cos - translation.X * sin);
|
||||||
}
|
}
|
||||||
|
|
||||||
translation.X /= -ViewportScale;
|
translation.X = -translation.X;
|
||||||
translation.Y /= ViewportScale;
|
translation.Y = -translation.Y;
|
||||||
|
|
||||||
Center = mapTransform.Transform(Center, MapOrigin, translation);
|
Center = MapProjection.TranslateLocation(Center, translation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
||||||
/// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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)
|
if (rotation != 0d || scale != 1d)
|
||||||
{
|
{
|
||||||
transformOrigin = ViewportPointToLocation(origin);
|
transformCenter = MapProjection.ViewportPointToLocation(center);
|
||||||
ViewportOrigin = new Point(origin.X + translation.X, origin.Y + translation.Y);
|
viewportCenter = new Point(center.X + translation.X, center.Y + translation.Y);
|
||||||
|
|
||||||
if (rotation != 0d)
|
if (rotation != 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -401,175 +353,104 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
/// in viewport coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomMap(Point origin, double zoomLevel)
|
public void ZoomMap(Point center, double zoomLevel)
|
||||||
{
|
{
|
||||||
zoomLevel = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
|
zoomLevel = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
|
||||||
|
|
||||||
if (TargetZoomLevel != zoomLevel)
|
if (TargetZoomLevel != zoomLevel)
|
||||||
{
|
{
|
||||||
SetTransformOrigin(origin);
|
SetTransformCenter(center);
|
||||||
TargetZoomLevel = zoomLevel;
|
|
||||||
|
if (double.IsNaN(MapProjection.LongitudeScale))
|
||||||
|
{
|
||||||
|
ZoomLevel = zoomLevel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TargetZoomLevel = zoomLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
/// fits into the current viewport. The TargetHeading property is set to zero.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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 rect = MapProjection.BoundingBoxToRect(boundingBox);
|
||||||
var p2 = mapTransform.Transform(northEast);
|
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
var lonScale = RenderSize.Width / (p2.X - p1.X) * 360d / TileSource.TileSize;
|
var scale0 = 1d / MapProjection.GetViewportScale(0d);
|
||||||
var latScale = RenderSize.Height / (p2.Y - p1.Y) * 360d / TileSource.TileSize;
|
var lonScale = scale0 * RenderSize.Width / rect.Width;
|
||||||
|
var latScale = scale0 * RenderSize.Height / rect.Height;
|
||||||
var lonZoom = Math.Log(lonScale, 2d);
|
var lonZoom = Math.Log(lonScale, 2d);
|
||||||
var latZoom = Math.Log(latScale, 2d);
|
var latZoom = Math.Log(latScale, 2d);
|
||||||
|
|
||||||
TargetZoomLevel = Math.Min(lonZoom, latZoom);
|
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;
|
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<TileLayer>(new TileLayer[] { tileLayer });
|
if (mapLayer.MapBackground != null)
|
||||||
}
|
|
||||||
else if (TileLayers.Count == 0)
|
|
||||||
{
|
|
||||||
TileLayers.Add(tileLayer);
|
|
||||||
}
|
|
||||||
else if (TileLayers[0] != tileLayer)
|
|
||||||
{
|
|
||||||
TileLayers[0] = tileLayer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TileLayersPropertyChanged(IList<TileLayer> oldTileLayers, IList<TileLayer> 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<TileLayer>());
|
|
||||||
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<TileLayer>());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
ClearTileLayers();
|
|
||||||
if (e.NewItems != null)
|
|
||||||
{
|
{
|
||||||
AddTileLayers(0, e.NewItems.Cast<TileLayer>());
|
ClearValue(BackgroundProperty);
|
||||||
}
|
}
|
||||||
break;
|
if (mapLayer.MapForeground != null)
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tileLayer = TileLayers.FirstOrDefault();
|
|
||||||
|
|
||||||
if (TileLayer != tileLayer)
|
|
||||||
{
|
|
||||||
SetTileLayer(tileLayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddTileLayers(int index, IEnumerable<TileLayer> tileLayers)
|
|
||||||
{
|
|
||||||
foreach (var tileLayer in tileLayers)
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
if (tileLayer.Background != null)
|
|
||||||
{
|
{
|
||||||
Background = tileLayer.Background;
|
ClearValue(ForegroundProperty);
|
||||||
}
|
|
||||||
|
|
||||||
if (tileLayer.Foreground != null)
|
|
||||||
{
|
|
||||||
Foreground = tileLayer.Foreground;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tileLayerPanel.Children.Insert(index++, tileLayer);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveTileLayers(int index, int count)
|
if (newLayer != null)
|
||||||
{
|
|
||||||
while (count-- > 0)
|
|
||||||
{
|
{
|
||||||
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);
|
ResetTransformCenter();
|
||||||
ClearValue(ForegroundProperty);
|
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)
|
private void AdjustCenterProperty(DependencyProperty property, ref Location center)
|
||||||
{
|
{
|
||||||
if (center == null)
|
if (center == null)
|
||||||
|
|
@ -578,10 +459,10 @@ namespace MapControl
|
||||||
InternalSetValue(property, center);
|
InternalSetValue(property, center);
|
||||||
}
|
}
|
||||||
else if (center.Longitude < -180d || center.Longitude > 180d ||
|
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(
|
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));
|
Location.NormalizeLongitude(center.Longitude));
|
||||||
InternalSetValue(property, center);
|
InternalSetValue(property, center);
|
||||||
}
|
}
|
||||||
|
|
@ -597,7 +478,7 @@ namespace MapControl
|
||||||
if (centerAnimation == null)
|
if (centerAnimation == null)
|
||||||
{
|
{
|
||||||
InternalSetValue(TargetCenterProperty, center);
|
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
|
// animate private CenterPoint property by PointAnimation
|
||||||
centerAnimation = new PointAnimation
|
centerAnimation = new PointAnimation
|
||||||
{
|
{
|
||||||
From = mapTransform.Transform(Center),
|
From = MapProjection.LocationToPoint(Center),
|
||||||
To = mapTransform.Transform(new Location(
|
To = MapProjection.LocationToPoint(new Location(
|
||||||
targetCenter.Latitude,
|
targetCenter.Latitude,
|
||||||
Location.NearestLongitude(targetCenter.Longitude, Center.Longitude))),
|
Location.NearestLongitude(targetCenter.Longitude, Center.Longitude))),
|
||||||
Duration = AnimationDuration,
|
Duration = AnimationDuration,
|
||||||
|
|
@ -640,7 +521,7 @@ namespace MapControl
|
||||||
centerAnimation = null;
|
centerAnimation = null;
|
||||||
|
|
||||||
InternalSetValue(CenterProperty, TargetCenter);
|
InternalSetValue(CenterProperty, TargetCenter);
|
||||||
InternalSetValue(CenterPointProperty, mapTransform.Transform(TargetCenter));
|
InternalSetValue(CenterPointProperty, MapProjection.LocationToPoint(TargetCenter));
|
||||||
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
|
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
|
||||||
UpdateTransform();
|
UpdateTransform();
|
||||||
}
|
}
|
||||||
|
|
@ -650,8 +531,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (!internalPropertyChange)
|
if (!internalPropertyChange)
|
||||||
{
|
{
|
||||||
centerPoint.X = Location.NormalizeLongitude(centerPoint.X);
|
var center = MapProjection.PointToLocation(centerPoint);
|
||||||
InternalSetValue(CenterProperty, mapTransform.Transform(centerPoint));
|
center.Longitude = Location.NormalizeLongitude(center.Longitude);
|
||||||
|
|
||||||
|
InternalSetValue(CenterProperty, center);
|
||||||
UpdateTransform();
|
UpdateTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -742,6 +625,7 @@ namespace MapControl
|
||||||
|
|
||||||
InternalSetValue(ZoomLevelProperty, TargetZoomLevel);
|
InternalSetValue(ZoomLevelProperty, TargetZoomLevel);
|
||||||
RemoveAnimation(ZoomLevelProperty); // remove holding animation in WPF
|
RemoveAnimation(ZoomLevelProperty); // remove holding animation in WPF
|
||||||
|
|
||||||
UpdateTransform(true);
|
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;
|
internalPropertyChange = true;
|
||||||
var center = transformOrigin ?? Center;
|
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);
|
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);
|
center.Latitude = Math.Min(Math.Max(center.Latitude, -projection.MaxLatitude), projection.MaxLatitude);
|
||||||
resetOrigin = true;
|
resetTransformCenter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalSetValue(CenterProperty, center);
|
InternalSetValue(CenterProperty, center);
|
||||||
|
|
@ -842,22 +733,24 @@ namespace MapControl
|
||||||
if (centerAnimation == null)
|
if (centerAnimation == null)
|
||||||
{
|
{
|
||||||
InternalSetValue(TargetCenterProperty, center);
|
InternalSetValue(TargetCenterProperty, center);
|
||||||
InternalSetValue(CenterPointProperty, mapTransform.Transform(center));
|
InternalSetValue(CenterPointProperty, projection.LocationToPoint(center));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetOrigin)
|
if (resetTransformCenter)
|
||||||
{
|
{
|
||||||
ResetTransformOrigin();
|
ResetTransformCenter();
|
||||||
SetViewportTransform(center);
|
projection.SetViewportTransform(ProjectionCenter ?? center, center, viewportCenter, ZoomLevel, Heading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CenterScale = ViewportScale * mapTransform.RelativeScale(center) / TileSource.MetersPerDegree;
|
var scale = projection.GetMapScale(center);
|
||||||
scaleTransform.ScaleX = CenterScale;
|
ScaleTransform.ScaleX = scale.X;
|
||||||
scaleTransform.ScaleY = CenterScale;
|
ScaleTransform.ScaleY = scale.Y;
|
||||||
rotateTransform.Angle = Heading;
|
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)
|
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -68,13 +68,18 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="AzimuthalEquidistantProjection.cs" />
|
||||||
|
<Compile Include="AzimuthalProjection.cs" />
|
||||||
<Compile Include="BingMapsTileLayer.cs" />
|
<Compile Include="BingMapsTileLayer.cs" />
|
||||||
<Compile Include="BingMapsTileSource.cs" />
|
<Compile Include="BingMapsTileSource.cs" />
|
||||||
|
<Compile Include="BoundingBox.cs" />
|
||||||
|
<Compile Include="BoundingBoxConverter.cs" />
|
||||||
|
<Compile Include="CenteredBoundingBox.cs" />
|
||||||
|
<Compile Include="EquirectangularProjection.cs" />
|
||||||
<Compile Include="Extensions.Silverlight.cs" />
|
<Compile Include="Extensions.Silverlight.cs" />
|
||||||
|
<Compile Include="GnomonicProjection.cs" />
|
||||||
<Compile Include="HyperlinkText.cs" />
|
<Compile Include="HyperlinkText.cs" />
|
||||||
<Compile Include="ImageTileSource.Silverlight.WinRT.cs" />
|
<Compile Include="ImageTileSource.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="IMapElement.cs" />
|
|
||||||
<Compile Include="ITileImageLoader.cs" />
|
|
||||||
<Compile Include="Location.cs" />
|
<Compile Include="Location.cs" />
|
||||||
<Compile Include="LocationCollection.cs" />
|
<Compile Include="LocationCollection.cs" />
|
||||||
<Compile Include="LocationCollectionConverter.cs" />
|
<Compile Include="LocationCollectionConverter.cs" />
|
||||||
|
|
@ -82,11 +87,10 @@
|
||||||
<Compile Include="Map.Silverlight.cs" />
|
<Compile Include="Map.Silverlight.cs" />
|
||||||
<Compile Include="MapBase.cs" />
|
<Compile Include="MapBase.cs" />
|
||||||
<Compile Include="MapBase.Silverlight.WinRT.cs" />
|
<Compile Include="MapBase.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapGraticule.cs" />
|
|
||||||
<Compile Include="MapGraticule.Silverlight.WinRT.cs" />
|
|
||||||
<Compile Include="MapImage.cs" />
|
|
||||||
<Compile Include="MapImageLayer.cs" />
|
<Compile Include="MapImageLayer.cs" />
|
||||||
<Compile Include="MapImageLayer.Silverlight.WinRT.cs" />
|
<Compile Include="MapImageLayer.Silverlight.WinRT.cs" />
|
||||||
|
<Compile Include="MapGraticule.cs" />
|
||||||
|
<Compile Include="MapGraticule.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapItem.Silverlight.WinRT.cs" />
|
<Compile Include="MapItem.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapItemsControl.Silverlight.WinRT.cs" />
|
<Compile Include="MapItemsControl.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapOverlay.cs" />
|
<Compile Include="MapOverlay.cs" />
|
||||||
|
|
@ -97,23 +101,23 @@
|
||||||
<Compile Include="MapPath.Silverlight.WinRT.cs" />
|
<Compile Include="MapPath.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapPolyline.cs" />
|
<Compile Include="MapPolyline.cs" />
|
||||||
<Compile Include="MapPolyline.Silverlight.WinRT.cs" />
|
<Compile Include="MapPolyline.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MapRectangle.cs" />
|
<Compile Include="MapProjection.cs" />
|
||||||
<Compile Include="MapTransform.cs" />
|
<Compile Include="MapTileLayer.cs" />
|
||||||
<Compile Include="MatrixEx.cs" />
|
<Compile Include="MatrixEx.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="MercatorTransform.cs" />
|
<Compile Include="OrthographicProjection.cs" />
|
||||||
<Compile Include="PanelBase.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
|
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
|
||||||
|
<Compile Include="StereographicProjection.cs" />
|
||||||
<Compile Include="Tile.cs" />
|
<Compile Include="Tile.cs" />
|
||||||
<Compile Include="Tile.Silverlight.WinRT.cs" />
|
<Compile Include="Tile.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="TileGrid.cs" />
|
<Compile Include="TileGrid.cs" />
|
||||||
<Compile Include="TileImageLoader.Silverlight.cs" />
|
<Compile Include="TileImageLoader.Silverlight.cs" />
|
||||||
<Compile Include="TileLayer.cs" />
|
<Compile Include="MapTileLayer.Silverlight.WinRT.cs" />
|
||||||
<Compile Include="TileLayer.Silverlight.WinRT.cs" />
|
|
||||||
<Compile Include="TileLayerCollection.cs" />
|
|
||||||
<Compile Include="TileSource.cs" />
|
<Compile Include="TileSource.cs" />
|
||||||
<Compile Include="TileSourceConverter.cs" />
|
<Compile Include="TileSourceConverter.cs" />
|
||||||
<Compile Include="ViewportChangedEventArgs.cs" />
|
<Compile Include="ViewportChangedEventArgs.cs" />
|
||||||
|
<Compile Include="WebMercatorProjection.cs" />
|
||||||
|
<Compile Include="WmsImageLayer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="Themes\Generic.xaml">
|
<Page Include="Themes\Generic.xaml">
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,18 @@
|
||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="AzimuthalEquidistantProjection.cs" />
|
||||||
|
<Compile Include="AzimuthalProjection.cs" />
|
||||||
<Compile Include="BingMapsTileLayer.cs" />
|
<Compile Include="BingMapsTileLayer.cs" />
|
||||||
<Compile Include="BingMapsTileSource.cs" />
|
<Compile Include="BingMapsTileSource.cs" />
|
||||||
<Compile Include="ImageLoader.cs" />
|
<Compile Include="BoundingBox.cs" />
|
||||||
|
<Compile Include="BoundingBoxConverter.cs" />
|
||||||
|
<Compile Include="CenteredBoundingBox.cs" />
|
||||||
|
<Compile Include="EquirectangularProjection.cs" />
|
||||||
|
<Compile Include="GnomonicProjection.cs" />
|
||||||
|
<Compile Include="BitmapSourceHelper.cs" />
|
||||||
<Compile Include="HyperlinkText.cs" />
|
<Compile Include="HyperlinkText.cs" />
|
||||||
<Compile Include="ImageTileSource.WPF.cs" />
|
<Compile Include="ImageTileSource.WPF.cs" />
|
||||||
<Compile Include="IMapElement.cs" />
|
|
||||||
<Compile Include="ITileImageLoader.cs" />
|
|
||||||
<Compile Include="Location.cs" />
|
<Compile Include="Location.cs" />
|
||||||
<Compile Include="LocationCollection.cs" />
|
<Compile Include="LocationCollection.cs" />
|
||||||
<Compile Include="LocationCollectionConverter.cs" />
|
<Compile Include="LocationCollectionConverter.cs" />
|
||||||
|
|
@ -66,41 +71,39 @@
|
||||||
<Compile Include="Map.WPF.cs" />
|
<Compile Include="Map.WPF.cs" />
|
||||||
<Compile Include="MapBase.cs" />
|
<Compile Include="MapBase.cs" />
|
||||||
<Compile Include="MapBase.WPF.cs" />
|
<Compile Include="MapBase.WPF.cs" />
|
||||||
<Compile Include="MapGraticule.cs" />
|
|
||||||
<Compile Include="MapGraticule.WPF.cs" />
|
|
||||||
<Compile Include="MapImage.cs" />
|
|
||||||
<Compile Include="MapImageLayer.cs" />
|
<Compile Include="MapImageLayer.cs" />
|
||||||
<Compile Include="MapImageLayer.WPF.cs" />
|
<Compile Include="MapImageLayer.WPF.cs" />
|
||||||
|
<Compile Include="MapGraticule.cs" />
|
||||||
|
<Compile Include="MapGraticule.WPF.cs" />
|
||||||
<Compile Include="MapItem.WPF.cs" />
|
<Compile Include="MapItem.WPF.cs" />
|
||||||
<Compile Include="MapItemsControl.WPF.cs" />
|
<Compile Include="MapItemsControl.WPF.cs" />
|
||||||
<Compile Include="MapOverlay.cs" />
|
<Compile Include="MapOverlay.cs" />
|
||||||
<Compile Include="MapOverlay.WPF.cs" />
|
<Compile Include="MapOverlay.WPF.cs" />
|
||||||
<Compile Include="MapPanel.cs" />
|
<Compile Include="MapPanel.cs" />
|
||||||
<Compile Include="MapPanel.WPF.cs" />
|
<Compile Include="MapPanel.WPF.cs" />
|
||||||
<Compile Include="MapRectangle.WPF.cs" />
|
|
||||||
<Compile Include="MapPath.cs" />
|
<Compile Include="MapPath.cs" />
|
||||||
<Compile Include="MapPath.WPF.cs" />
|
<Compile Include="MapPath.WPF.cs" />
|
||||||
<Compile Include="MapPolyline.cs" />
|
<Compile Include="MapPolyline.cs" />
|
||||||
<Compile Include="MapPolyline.WPF.cs" />
|
<Compile Include="MapPolyline.WPF.cs" />
|
||||||
<Compile Include="MapRectangle.cs" />
|
|
||||||
<Compile Include="MapScale.cs" />
|
<Compile Include="MapScale.cs" />
|
||||||
<Compile Include="MapTransform.cs" />
|
<Compile Include="MapProjection.cs" />
|
||||||
<Compile Include="MercatorTransform.cs" />
|
<Compile Include="MatrixEx.WPF.cs" />
|
||||||
<Compile Include="PanelBase.cs" />
|
<Compile Include="OrthographicProjection.cs" />
|
||||||
|
<Compile Include="StereographicProjection.cs" />
|
||||||
|
<Compile Include="WebMercatorProjection.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Pushpin.WPF.cs" />
|
<Compile Include="Pushpin.WPF.cs" />
|
||||||
<Compile Include="Tile.cs" />
|
<Compile Include="Tile.cs" />
|
||||||
<Compile Include="Tile.WPF.cs" />
|
<Compile Include="Tile.WPF.cs" />
|
||||||
<Compile Include="TileGrid.cs" />
|
<Compile Include="TileGrid.cs" />
|
||||||
<Compile Include="TileImageLoader.WPF.cs" />
|
<Compile Include="TileImageLoader.WPF.cs" />
|
||||||
<Compile Include="TileLayer.cs" />
|
<Compile Include="MapTileLayer.cs" />
|
||||||
<Compile Include="TileLayer.WPF.cs" />
|
<Compile Include="MapTileLayer.WPF.cs" />
|
||||||
<Compile Include="TileLayerCollection.cs" />
|
|
||||||
<Compile Include="TileSource.cs" />
|
<Compile Include="TileSource.cs" />
|
||||||
<Compile Include="TileSourceConverter.cs" />
|
<Compile Include="TileSourceConverter.cs" />
|
||||||
<Compile Include="ViewportChangedEventArgs.cs" />
|
<Compile Include="ViewportChangedEventArgs.cs" />
|
||||||
<Compile Include="WmsImageLayer.cs" />
|
<Compile Include="WmsImageLayer.cs" />
|
||||||
<Compile Include="WmsImageLayer.WPF.cs" />
|
<Compile Include="WmsLayers.WPF.WinRT.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="Themes\Generic.xaml">
|
<Page Include="Themes\Generic.xaml">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -34,169 +34,180 @@ namespace MapControl
|
||||||
|
|
||||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
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 = new Path
|
||||||
};
|
|
||||||
|
|
||||||
path.SetBinding(Shape.StrokeProperty,
|
|
||||||
GetBindingExpression(StrokeProperty)?.ParentBinding ??
|
|
||||||
new Binding
|
|
||||||
{
|
{
|
||||||
Source = this,
|
Data = new PathGeometry()
|
||||||
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
figure.Segments.Add(new LineSegment
|
path.SetBinding(Shape.StrokeProperty,
|
||||||
{
|
GetBindingExpression(StrokeProperty)?.ParentBinding ??
|
||||||
Point = ParentMap.MapTransform.Transform(new Location(lat, lineEnd.Longitude)),
|
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)),
|
var figure = new PathFigure
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
label = (TextBlock)Children[childIndex];
|
StartPoint = projection.LocationToPoint(new Location(lat, lineStart.Longitude)),
|
||||||
}
|
IsClosed = false,
|
||||||
else
|
IsFilled = false
|
||||||
{
|
};
|
||||||
var renderTransform = new TransformGroup();
|
|
||||||
renderTransform.Children.Add(new TranslateTransform());
|
|
||||||
renderTransform.Children.Add(ParentMap.RotateTransform);
|
|
||||||
renderTransform.Children.Add(new TranslateTransform());
|
|
||||||
|
|
||||||
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,
|
label = new TextBlock
|
||||||
GetBindingExpression(ForegroundProperty)?.ParentBinding ??
|
|
||||||
new Binding
|
|
||||||
{
|
{
|
||||||
Source = this,
|
RenderTransform = renderTransform
|
||||||
Path = new PropertyPath("Foreground")
|
};
|
||||||
});
|
|
||||||
|
|
||||||
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++;
|
while (Children.Count > childIndex)
|
||||||
|
{
|
||||||
if (FontFamily != null)
|
Children.RemoveAt(Children.Count - 1);
|
||||||
{
|
|
||||||
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)
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (path != null)
|
||||||
// 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++)
|
|
||||||
{
|
{
|
||||||
var label = (TextBlock)Children[i];
|
path = null;
|
||||||
var location = (Location)label.Tag;
|
graticuleStart = null;
|
||||||
var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
|
graticuleEnd = null;
|
||||||
var viewportPosition = ParentMap.LocationToViewportPoint(location);
|
|
||||||
viewportTransform.X = viewportPosition.X;
|
Children.Clear();
|
||||||
viewportTransform.Y = viewportPosition.Y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnViewportChanged(e);
|
base.OnViewportChanged(e);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -26,11 +26,8 @@ namespace MapControl
|
||||||
|
|
||||||
static MapGraticule()
|
static MapGraticule()
|
||||||
{
|
{
|
||||||
IsHitTestVisibleProperty.OverrideMetadata(
|
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(false));
|
||||||
typeof(MapGraticule), new FrameworkPropertyMetadata(false));
|
StrokeThicknessProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
|
||||||
|
|
||||||
StrokeThicknessProperty.OverrideMetadata(
|
|
||||||
typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||||
|
|
@ -40,45 +37,45 @@ namespace MapControl
|
||||||
|
|
||||||
protected override void OnRender(DrawingContext drawingContext)
|
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 bounds = projection.ViewportRectToBoundingBox(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 lineDistance = GetLineDistance();
|
var lineDistance = GetLineDistance();
|
||||||
var labelFormat = GetLabelFormat(lineDistance);
|
var labelFormat = GetLabelFormat(lineDistance);
|
||||||
var latLabelStart = Math.Ceiling(start.Latitude / lineDistance) * lineDistance;
|
var latLabelStart = Math.Ceiling(bounds.South / lineDistance) * lineDistance;
|
||||||
var lonLabelStart = Math.Ceiling(start.Longitude / lineDistance) * lineDistance;
|
var lonLabelStart = Math.Ceiling(bounds.West / lineDistance) * lineDistance;
|
||||||
var latLabels = new List<Label>((int)((end.Latitude - latLabelStart) / lineDistance) + 1);
|
var latLabels = new List<Label>((int)((bounds.North - latLabelStart) / lineDistance) + 1);
|
||||||
var lonLabels = new List<Label>((int)((end.Longitude - lonLabelStart) / lineDistance) + 1);
|
var lonLabels = new List<Label>((int)((bounds.East - lonLabelStart) / lineDistance) + 1);
|
||||||
|
|
||||||
for (var lat = latLabelStart; lat <= end.Latitude; lat += lineDistance)
|
for (var lat = latLabelStart; lat <= bounds.North; lat += lineDistance)
|
||||||
{
|
{
|
||||||
latLabels.Add(new Label(lat, new FormattedText(
|
latLabels.Add(new Label(lat, new FormattedText(
|
||||||
GetLabelText(lat, labelFormat, "NS"),
|
GetLabelText(lat, labelFormat, "NS"),
|
||||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
||||||
|
|
||||||
drawingContext.DrawLine(Pen,
|
drawingContext.DrawLine(Pen,
|
||||||
ParentMap.LocationToViewportPoint(new Location(lat, start.Longitude)),
|
projection.LocationToViewportPoint(new Location(lat, bounds.West)),
|
||||||
ParentMap.LocationToViewportPoint(new Location(lat, end.Longitude)));
|
projection.LocationToViewportPoint(new Location(lat, bounds.East)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var lon = lonLabelStart; lon <= end.Longitude; lon += lineDistance)
|
for (var lon = lonLabelStart; lon <= bounds.East; lon += lineDistance)
|
||||||
{
|
{
|
||||||
lonLabels.Add(new Label(lon, new FormattedText(
|
lonLabels.Add(new Label(lon, new FormattedText(
|
||||||
GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW"),
|
GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW"),
|
||||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
||||||
|
|
||||||
drawingContext.DrawLine(Pen,
|
drawingContext.DrawLine(Pen,
|
||||||
ParentMap.LocationToViewportPoint(new Location(start.Latitude, lon)),
|
projection.LocationToViewportPoint(new Location(bounds.South, lon)),
|
||||||
ParentMap.LocationToViewportPoint(new Location(end.Latitude, lon)));
|
projection.LocationToViewportPoint(new Location(bounds.North, lon)));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var latLabel in latLabels)
|
foreach (var latLabel in latLabels)
|
||||||
{
|
{
|
||||||
foreach (var lonLabel in lonLabels)
|
foreach (var lonLabel in lonLabels)
|
||||||
{
|
{
|
||||||
var position = ParentMap.LocationToViewportPoint(new Location(latLabel.Position, lonLabel.Position));
|
var position = projection.LocationToViewportPoint(new Location(latLabel.Position, lonLabel.Position));
|
||||||
|
|
||||||
drawingContext.PushTransform(new RotateTransform(ParentMap.Heading, position.X, position.Y));
|
drawingContext.PushTransform(new RotateTransform(ParentMap.Heading, position.X, position.Y));
|
||||||
drawingContext.DrawText(latLabel.Text,
|
drawingContext.DrawText(latLabel.Text,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -17,7 +17,7 @@ namespace MapControl
|
||||||
public partial class MapGraticule : MapOverlay
|
public partial class MapGraticule : MapOverlay
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty MinLineDistanceProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MinLineDistanceProperty = DependencyProperty.Register(
|
||||||
"MinLineDistance", typeof(double), typeof(MapGraticule), new PropertyMetadata(150d));
|
nameof(MinLineDistance), typeof(double), typeof(MapGraticule), new PropertyMetadata(150d));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimum graticule line distance in pixels. The default value is 150.
|
/// Minimum graticule line distance in pixels. The default value is 150.
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
#if NETFX_CORE
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Fills a rectangular area with an ImageBrush from the Source property.
|
|
||||||
/// </summary>
|
|
||||||
public class MapImage : MapRectangle
|
|
||||||
{
|
|
||||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
|
||||||
"Source", typeof(ImageSource), typeof(MapImage),
|
|
||||||
new PropertyMetadata(null, (o, e) => ((ImageBrush)((MapImage)o).Fill).ImageSource = (ImageSource)e.NewValue));
|
|
||||||
|
|
||||||
public MapImage()
|
|
||||||
{
|
|
||||||
Fill = new ImageBrush
|
|
||||||
{
|
|
||||||
RelativeTransform = new MatrixTransform
|
|
||||||
{
|
|
||||||
Matrix = new Matrix(1d, 0d, 0d, -1d, 0d, 1d)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSource Source
|
|
||||||
{
|
|
||||||
get { return (ImageSource)GetValue(SourceProperty); }
|
|
||||||
set { SetValue(SourceProperty, value); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -15,7 +17,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class MapImageLayer
|
public partial class MapImageLayer
|
||||||
{
|
{
|
||||||
protected virtual void UpdateImage(Uri uri)
|
protected void UpdateImage(Uri uri)
|
||||||
{
|
{
|
||||||
UpdateImage(new BitmapImage(uri));
|
UpdateImage(new BitmapImage(uri));
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +54,7 @@ namespace MapControl
|
||||||
bitmap.ImageOpened -= BitmapImageOpened;
|
bitmap.ImageOpened -= BitmapImageOpened;
|
||||||
bitmap.ImageFailed -= BitmapImageFailed;
|
bitmap.ImageFailed -= BitmapImageFailed;
|
||||||
|
|
||||||
var mapImage = (MapImage)Children[currentImageIndex];
|
((Image)Children[topImageIndex]).Source = null;
|
||||||
mapImage.Source = null;
|
|
||||||
|
|
||||||
SwapImages();
|
SwapImages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
|
@ -11,11 +12,11 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class MapImageLayer
|
public partial class MapImageLayer
|
||||||
{
|
{
|
||||||
protected virtual void UpdateImage(Uri uri)
|
protected void UpdateImage(Uri uri)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var image = ImageLoader.FromUri(uri);
|
var image = BitmapSourceHelper.FromUri(uri);
|
||||||
Dispatcher.BeginInvoke(new Action(() => UpdateImage(image)));
|
Dispatcher.BeginInvoke(new Action(() => UpdateImage(image)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -50,9 +51,7 @@ namespace MapControl
|
||||||
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
|
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
|
||||||
bitmap.DownloadFailed -= BitmapDownloadFailed;
|
bitmap.DownloadFailed -= BitmapDownloadFailed;
|
||||||
|
|
||||||
var mapImage = (MapImage)Children[currentImageIndex];
|
((Image)Children[topImageIndex]).Source = null;
|
||||||
mapImage.Source = null;
|
|
||||||
|
|
||||||
SwapImages();
|
SwapImages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Animation;
|
using Windows.UI.Xaml.Media.Animation;
|
||||||
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
|
@ -22,96 +23,59 @@ using System.Windows.Threading;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map image overlay. Fills the entire viewport with a map image provided by a web service,
|
/// Map image layer. Fills the entire viewport with a map image, e.g. provided by a Web Map Service (WMS).
|
||||||
/// e.g. a Web Map Service (WMS). The image request Uri is specified by the UriFormat property.
|
/// The image must be provided by the abstract UpdateImage(BoundingBox) method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MapImageLayer : MapPanel
|
public abstract partial class MapImageLayer : MapPanel, IMapLayer
|
||||||
{
|
{
|
||||||
public struct BoundingBox
|
|
||||||
{
|
|
||||||
public readonly double West;
|
|
||||||
public readonly double East;
|
|
||||||
public readonly double South;
|
|
||||||
public readonly double North;
|
|
||||||
|
|
||||||
public BoundingBox(double west, double east, double south, double north)
|
|
||||||
{
|
|
||||||
West = west;
|
|
||||||
East = east;
|
|
||||||
South = south;
|
|
||||||
North = north;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DependencyProperty UriFormatProperty = DependencyProperty.Register(
|
|
||||||
"UriFormat", typeof(string), typeof(MapImageLayer),
|
|
||||||
new PropertyMetadata(null, (o, e) => ((MapImageLayer)o).UpdateImage()));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty MinLongitudeProperty = DependencyProperty.Register(
|
|
||||||
"MinLongitude", typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxLongitudeProperty = DependencyProperty.Register(
|
|
||||||
"MaxLongitude", typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register(
|
||||||
"MinLatitude", typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
nameof(MinLatitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxLatitudeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MaxLatitudeProperty = DependencyProperty.Register(
|
||||||
"MaxLatitude", typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
nameof(MaxLatitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty MinLongitudeProperty = DependencyProperty.Register(
|
||||||
|
nameof(MinLongitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty MaxLongitudeProperty = DependencyProperty.Register(
|
||||||
|
nameof(MaxLongitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxBoundingBoxWidthProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MaxBoundingBoxWidthProperty = DependencyProperty.Register(
|
||||||
"MaxBoundingBoxWidth", typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
nameof(MaxBoundingBoxWidth), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
public static readonly DependencyProperty RelativeImageSizeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty RelativeImageSizeProperty = DependencyProperty.Register(
|
||||||
"RelativeImageSize", typeof(double), typeof(MapImageLayer), new PropertyMetadata(1d));
|
nameof(RelativeImageSize), typeof(double), typeof(MapImageLayer), new PropertyMetadata(1d));
|
||||||
|
|
||||||
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
||||||
"UpdateInterval", typeof(TimeSpan), typeof(MapImageLayer),
|
nameof(UpdateInterval), typeof(TimeSpan), typeof(MapImageLayer),
|
||||||
new PropertyMetadata(TimeSpan.FromSeconds(0.5), (o, e) => ((MapImageLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
new PropertyMetadata(TimeSpan.FromSeconds(0.2), (o, e) => ((MapImageLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
||||||
|
nameof(UpdateWhileViewportChanging), typeof(bool), typeof(MapImageLayer), new PropertyMetadata(false));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||||
|
nameof(Description), typeof(string), typeof(MapImageLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty MapBackgroundProperty = DependencyProperty.Register(
|
||||||
|
nameof(MapBackground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty MapForegroundProperty = DependencyProperty.Register(
|
||||||
|
nameof(MapForeground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
private readonly DispatcherTimer updateTimer;
|
private readonly DispatcherTimer updateTimer;
|
||||||
private int currentImageIndex;
|
private BoundingBox boundingBox;
|
||||||
|
private int topImageIndex;
|
||||||
private bool updateInProgress;
|
private bool updateInProgress;
|
||||||
|
|
||||||
public MapImageLayer()
|
public MapImageLayer()
|
||||||
{
|
{
|
||||||
Children.Add(new MapImage { Opacity = 0d });
|
Children.Add(new Image { Opacity = 0d, Stretch = Stretch.Fill });
|
||||||
Children.Add(new MapImage { Opacity = 0d });
|
Children.Add(new Image { Opacity = 0d, Stretch = Stretch.Fill });
|
||||||
|
|
||||||
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
|
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
|
||||||
updateTimer.Tick += (s, e) => UpdateImage();
|
updateTimer.Tick += (s, e) => UpdateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The format string of the image request Uri. The format must contain
|
|
||||||
/// {X} and {Y} format specifiers for the map width and height in pixels and either
|
|
||||||
/// {w},{s},{e},{n} for a latitude/longitude bounding box (like EPSG:4326) or
|
|
||||||
/// {W},{S},{E},{N} for a projected bounding box (e.g. in meters like EPSG:3857).
|
|
||||||
/// </summary>
|
|
||||||
public string UriFormat
|
|
||||||
{
|
|
||||||
get { return (string)GetValue(UriFormatProperty); }
|
|
||||||
set { SetValue(UriFormatProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Optional minimum longitude value. Default is NaN.
|
|
||||||
/// </summary>
|
|
||||||
public double MinLongitude
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(MinLongitudeProperty); }
|
|
||||||
set { SetValue(MinLongitudeProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Optional maximum longitude value. Default is NaN.
|
|
||||||
/// </summary>
|
|
||||||
public double MaxLongitude
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(MaxLongitudeProperty); }
|
|
||||||
set { SetValue(MaxLongitudeProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional minimum latitude value. Default is NaN.
|
/// Optional minimum latitude value. Default is NaN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -130,6 +94,24 @@ namespace MapControl
|
||||||
set { SetValue(MaxLatitudeProperty, value); }
|
set { SetValue(MaxLatitudeProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional minimum longitude value. Default is NaN.
|
||||||
|
/// </summary>
|
||||||
|
public double MinLongitude
|
||||||
|
{
|
||||||
|
get { return (double)GetValue(MinLongitudeProperty); }
|
||||||
|
set { SetValue(MinLongitudeProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional maximum longitude value. Default is NaN.
|
||||||
|
/// </summary>
|
||||||
|
public double MaxLongitude
|
||||||
|
{
|
||||||
|
get { return (double)GetValue(MaxLongitudeProperty); }
|
||||||
|
set { SetValue(MaxLongitudeProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional maximum width of the map image's bounding box. Default is NaN.
|
/// Optional maximum width of the map image's bounding box. Default is NaN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -140,8 +122,8 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Relative size of the map image in relation to the current viewport size.
|
/// Relative size of the map image in relation to the current viewport size.
|
||||||
/// Setting a value greater than one will let MapImageLayer request images that
|
/// Setting a value greater than one will let ImageLayer request images that
|
||||||
/// are larger than the viewport, in order to support smooth panning.
|
/// are larger than the viewport, in order to support smooth panning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double RelativeImageSize
|
public double RelativeImageSize
|
||||||
|
|
@ -159,42 +141,87 @@ namespace MapControl
|
||||||
set { SetValue(UpdateIntervalProperty, value); }
|
set { SetValue(UpdateIntervalProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BoundingBox ImageBoundingBox { get; private set; }
|
/// <summary>
|
||||||
|
/// Controls if images are updated while the viewport is still changing.
|
||||||
protected virtual BoundingBox ProjectedBoundingBox
|
/// </summary>
|
||||||
|
public bool UpdateWhileViewportChanging
|
||||||
{
|
{
|
||||||
get
|
get { return (bool)GetValue(UpdateWhileViewportChangingProperty); }
|
||||||
{
|
set { SetValue(UpdateWhileViewportChangingProperty, value); }
|
||||||
var p1 = ParentMap.MapTransform.Transform(new Location(ImageBoundingBox.South, ImageBoundingBox.West));
|
}
|
||||||
var p2 = ParentMap.MapTransform.Transform(new Location(ImageBoundingBox.North, ImageBoundingBox.East));
|
|
||||||
|
|
||||||
return new BoundingBox(
|
/// <summary>
|
||||||
TileSource.MetersPerDegree * p1.X, TileSource.MetersPerDegree * p2.X,
|
/// Description of the ImageLayer.
|
||||||
TileSource.MetersPerDegree * p1.Y, TileSource.MetersPerDegree * p2.Y);
|
/// Used to display copyright information on top of the map.
|
||||||
}
|
/// </summary>
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(DescriptionProperty); }
|
||||||
|
set { SetValue(DescriptionProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional foreground brush.
|
||||||
|
/// Sets MapBase.Foreground if not null and the ImageLayer is the base map layer.
|
||||||
|
/// </summary>
|
||||||
|
public Brush MapForeground
|
||||||
|
{
|
||||||
|
get { return (Brush)GetValue(MapForegroundProperty); }
|
||||||
|
set { SetValue(MapForegroundProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional background brush.
|
||||||
|
/// Sets MapBase.Background if not null and the ImageLayer is the base map layer.
|
||||||
|
/// </summary>
|
||||||
|
public Brush MapBackground
|
||||||
|
{
|
||||||
|
get { return (Brush)GetValue(MapBackgroundProperty); }
|
||||||
|
set { SetValue(MapBackgroundProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnViewportChanged(e);
|
base.OnViewportChanged(e);
|
||||||
|
|
||||||
if (Math.Abs(e.OriginOffset) > 180d)
|
if (e.ProjectionChanged)
|
||||||
{
|
{
|
||||||
var offset = 360d * Math.Sign(e.OriginOffset);
|
UpdateImage((BitmapSource)null);
|
||||||
|
UpdateImage();
|
||||||
ImageBoundingBox = new BoundingBox(ImageBoundingBox.West + offset, ImageBoundingBox.East + offset, ImageBoundingBox.South, ImageBoundingBox.North);
|
}
|
||||||
|
else
|
||||||
foreach (var mapImage in Children.OfType<MapImage>().Where(i => i.BoundingBoxValid))
|
{
|
||||||
|
if (Math.Abs(e.LongitudeOffset) > 180d && boundingBox != null && boundingBox.HasValidBounds)
|
||||||
{
|
{
|
||||||
mapImage.SetBoundingBox(mapImage.West + offset, mapImage.East + offset, mapImage.South, mapImage.North);
|
var offset = 360d * Math.Sign(e.LongitudeOffset);
|
||||||
|
|
||||||
|
boundingBox.West += offset;
|
||||||
|
boundingBox.East += offset;
|
||||||
|
|
||||||
|
foreach (UIElement element in Children)
|
||||||
|
{
|
||||||
|
var bbox = GetBoundingBox(element);
|
||||||
|
|
||||||
|
if (bbox != null && bbox.HasValidBounds)
|
||||||
|
{
|
||||||
|
SetBoundingBox(element, new BoundingBox(bbox.South, bbox.West + offset, bbox.North, bbox.East + offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateTimer.IsEnabled && !UpdateWhileViewportChanging)
|
||||||
|
{
|
||||||
|
updateTimer.Stop(); // restart
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updateTimer.IsEnabled)
|
||||||
|
{
|
||||||
|
updateTimer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTimer.Stop();
|
|
||||||
updateTimer.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void UpdateImage()
|
protected virtual void UpdateImage()
|
||||||
{
|
{
|
||||||
updateTimer.Stop();
|
updateTimer.Stop();
|
||||||
|
|
||||||
|
|
@ -206,129 +233,99 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
updateInProgress = true;
|
updateInProgress = true;
|
||||||
|
|
||||||
var relativeSize = Math.Max(RelativeImageSize, 1d);
|
var width = ParentMap.RenderSize.Width * RelativeImageSize;
|
||||||
var width = ParentMap.RenderSize.Width * relativeSize;
|
var height = ParentMap.RenderSize.Height * RelativeImageSize;
|
||||||
var height = ParentMap.RenderSize.Height * relativeSize;
|
var x = (ParentMap.RenderSize.Width - width) / 2d;
|
||||||
var dx = (ParentMap.RenderSize.Width - width) / 2d;
|
var y = (ParentMap.RenderSize.Height - height) / 2d;
|
||||||
var dy = (ParentMap.RenderSize.Height - height) / 2d;
|
var rect = new Rect(x, y, width, height);
|
||||||
|
|
||||||
var loc1 = ParentMap.ViewportPointToLocation(new Point(dx, dy));
|
boundingBox = ParentMap.MapProjection.ViewportRectToBoundingBox(rect);
|
||||||
var loc2 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy));
|
|
||||||
var loc3 = ParentMap.ViewportPointToLocation(new Point(dx, dy + height));
|
|
||||||
var loc4 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy + height));
|
|
||||||
|
|
||||||
var west = Math.Min(loc1.Longitude, Math.Min(loc2.Longitude, Math.Min(loc3.Longitude, loc4.Longitude)));
|
if (boundingBox != null && boundingBox.HasValidBounds)
|
||||||
var east = Math.Max(loc1.Longitude, Math.Max(loc2.Longitude, Math.Max(loc3.Longitude, loc4.Longitude)));
|
|
||||||
var south = Math.Min(loc1.Latitude, Math.Min(loc2.Latitude, Math.Min(loc3.Latitude, loc4.Latitude)));
|
|
||||||
var north = Math.Max(loc1.Latitude, Math.Max(loc2.Latitude, Math.Max(loc3.Latitude, loc4.Latitude)));
|
|
||||||
|
|
||||||
if (!double.IsNaN(MinLongitude) && west < MinLongitude)
|
|
||||||
{
|
{
|
||||||
west = MinLongitude;
|
if (!double.IsNaN(MinLatitude) && boundingBox.South < MinLatitude)
|
||||||
|
{
|
||||||
|
boundingBox.South = MinLatitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.IsNaN(MinLongitude) && boundingBox.West < MinLongitude)
|
||||||
|
{
|
||||||
|
boundingBox.West = MinLongitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.IsNaN(MaxLatitude) && boundingBox.North > MaxLatitude)
|
||||||
|
{
|
||||||
|
boundingBox.North = MaxLatitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.IsNaN(MaxLongitude) && boundingBox.East > MaxLongitude)
|
||||||
|
{
|
||||||
|
boundingBox.East = MaxLongitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.IsNaN(MaxBoundingBoxWidth) && boundingBox.Width > MaxBoundingBoxWidth)
|
||||||
|
{
|
||||||
|
var d = (boundingBox.Width - MaxBoundingBoxWidth) / 2d;
|
||||||
|
boundingBox.West += d;
|
||||||
|
boundingBox.East -= d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!double.IsNaN(MaxLongitude) && east > MaxLongitude)
|
var imageUpdated = false;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
east = MaxLongitude;
|
imageUpdated = UpdateImage(boundingBox);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!double.IsNaN(MinLatitude) && south < MinLatitude)
|
if (!imageUpdated)
|
||||||
{
|
{
|
||||||
south = MinLatitude;
|
UpdateImage((BitmapSource)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!double.IsNaN(MaxLatitude) && north > MaxLatitude)
|
|
||||||
{
|
|
||||||
north = MaxLatitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!double.IsNaN(MaxBoundingBoxWidth) && east - west > MaxBoundingBoxWidth)
|
|
||||||
{
|
|
||||||
var d = (east - west - MaxBoundingBoxWidth) / 2d;
|
|
||||||
west += d;
|
|
||||||
east -= d;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageBoundingBox = new BoundingBox(west, east, south, north);
|
|
||||||
|
|
||||||
var p1 = ParentMap.MapTransform.Transform(new Location(south, west));
|
|
||||||
var p2 = ParentMap.MapTransform.Transform(new Location(north, east));
|
|
||||||
|
|
||||||
UpdateImage((int)Math.Round((p2.X - p1.X) * ParentMap.ViewportScale),
|
|
||||||
(int)Math.Round((p2.Y - p1.Y) * ParentMap.ViewportScale));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateImage(int width, int height)
|
/// <summary>
|
||||||
{
|
/// Creates an image request Uri or a BitmapSource for the specified image bounding box.
|
||||||
if (UriFormat != null && width > 0 && height > 0)
|
/// Must either call UpdateImage(Uri) or UpdateImage(BitmapSource) or return false on failure.
|
||||||
{
|
/// </summary>
|
||||||
var uri = UriFormat
|
protected abstract bool UpdateImage(BoundingBox boundingBox);
|
||||||
.Replace("{X}", width.ToString())
|
|
||||||
.Replace("{Y}", height.ToString());
|
|
||||||
|
|
||||||
if (uri.Contains("{W}") && uri.Contains("{E}") && uri.Contains("{S}") && uri.Contains("{N}"))
|
|
||||||
{
|
|
||||||
var projectedBoundingBox = ProjectedBoundingBox;
|
|
||||||
|
|
||||||
uri = uri
|
|
||||||
.Replace("{W}", projectedBoundingBox.West.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{S}", projectedBoundingBox.South.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{E}", projectedBoundingBox.East.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{N}", projectedBoundingBox.North.ToString(CultureInfo.InvariantCulture));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uri = uri
|
|
||||||
.Replace("{w}", ImageBoundingBox.West.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{s}", ImageBoundingBox.South.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{e}", ImageBoundingBox.East.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.Replace("{n}", ImageBoundingBox.North.ToString(CultureInfo.InvariantCulture));
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateImage(new Uri(uri));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateImage((BitmapSource)null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetTopImage(BitmapSource bitmap)
|
private void SetTopImage(BitmapSource bitmap)
|
||||||
{
|
{
|
||||||
currentImageIndex = (currentImageIndex + 1) % 2;
|
topImageIndex = (topImageIndex + 1) % 2;
|
||||||
var topImage = (MapImage)Children[currentImageIndex];
|
var topImage = (Image)Children[topImageIndex];
|
||||||
|
|
||||||
topImage.SetBoundingBox(ImageBoundingBox.West, ImageBoundingBox.East, ImageBoundingBox.South, ImageBoundingBox.North);
|
|
||||||
topImage.Source = bitmap;
|
topImage.Source = bitmap;
|
||||||
|
SetBoundingBox(topImage, boundingBox?.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SwapImages()
|
private void SwapImages()
|
||||||
{
|
{
|
||||||
var topImage = (MapImage)Children[currentImageIndex];
|
var topImage = (Image)Children[topImageIndex];
|
||||||
var bottomImage = (MapImage)Children[(currentImageIndex + 1) % 2];
|
var bottomImage = (Image)Children[(topImageIndex + 1) % 2];
|
||||||
|
|
||||||
Canvas.SetZIndex(topImage, 1);
|
Canvas.SetZIndex(topImage, 1);
|
||||||
Canvas.SetZIndex(bottomImage, 0);
|
Canvas.SetZIndex(bottomImage, 0);
|
||||||
|
|
||||||
if (topImage.Source != null)
|
if (topImage.Source != null)
|
||||||
{
|
{
|
||||||
var fadeAnimation = new DoubleAnimation
|
topImage.BeginAnimation(OpacityProperty, new DoubleAnimation
|
||||||
{
|
{
|
||||||
From = 0d,
|
|
||||||
To = 1d,
|
To = 1d,
|
||||||
Duration = Tile.FadeDuration,
|
Duration = Tile.FadeDuration
|
||||||
FillBehavior = FillBehavior.Stop
|
});
|
||||||
};
|
|
||||||
|
|
||||||
fadeAnimation.Completed += (s, e) =>
|
bottomImage.BeginAnimation(OpacityProperty, new DoubleAnimation
|
||||||
{
|
{
|
||||||
bottomImage.Opacity = 0d;
|
To = 0d,
|
||||||
bottomImage.Source = null;
|
BeginTime = Tile.FadeDuration,
|
||||||
};
|
Duration = TimeSpan.Zero
|
||||||
|
});
|
||||||
topImage.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
|
|
||||||
topImage.Opacity = 1d;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -14,12 +14,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
static MapItem()
|
static MapItem()
|
||||||
{
|
{
|
||||||
DefaultStyleKeyProperty.OverrideMetadata(
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
|
||||||
typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty LocationProperty =
|
public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem));
|
||||||
MapPanel.LocationProperty.AddOwner(typeof(MapItem));
|
|
||||||
|
|
||||||
public Location Location
|
public Location Location
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -14,8 +14,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
static MapItemsControl()
|
static MapItemsControl()
|
||||||
{
|
{
|
||||||
DefaultStyleKeyProperty.OverrideMetadata(
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItemsControl), new FrameworkPropertyMetadata(typeof(MapItemsControl)));
|
||||||
typeof(MapItemsControl), new FrameworkPropertyMetadata(typeof(MapItemsControl)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DependencyObject GetContainerForItemOverride()
|
protected override DependencyObject GetContainerForItemOverride()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
@ -23,49 +23,49 @@ namespace MapControl
|
||||||
public partial class MapOverlay
|
public partial class MapOverlay
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
|
||||||
"FontSize", typeof(double), typeof(MapOverlay), new PropertyMetadata(10d));
|
nameof(FontSize), typeof(double), typeof(MapOverlay), new PropertyMetadata(10d));
|
||||||
|
|
||||||
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
|
||||||
"FontFamily", typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
|
nameof(FontFamily), typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
|
||||||
"FontStyle", typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyles.Normal));
|
nameof(FontStyle), typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyles.Normal));
|
||||||
|
|
||||||
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
|
||||||
"FontStretch", typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretches.Normal));
|
nameof(FontStretch), typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretches.Normal));
|
||||||
|
|
||||||
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
|
||||||
"FontWeight", typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal));
|
nameof(FontWeight), typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal));
|
||||||
|
|
||||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||||
"Foreground", typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
nameof(Foreground), typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
|
||||||
"Stroke", typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
nameof(Stroke), typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||||
"StrokeThickness", typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
nameof(StrokeThickness), typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||||
"StrokeDashArray", typeof(DoubleCollection), typeof(MapOverlay), new PropertyMetadata(null));
|
nameof(StrokeDashArray), typeof(DoubleCollection), typeof(MapOverlay), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register(
|
||||||
"StrokeDashOffset", typeof(double), typeof(MapOverlay), new PropertyMetadata(0d));
|
nameof(StrokeDashOffset), typeof(double), typeof(MapOverlay), new PropertyMetadata(0d));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register(
|
||||||
"StrokeDashCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
nameof(StrokeDashCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register(
|
||||||
"StrokeStartLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
nameof(StrokeStartLineCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register(
|
||||||
"StrokeEndLineCap", typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
nameof(StrokeEndLineCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register(
|
||||||
"StrokeLineJoin", typeof(PenLineJoin), typeof(MapOverlay), new PropertyMetadata(PenLineJoin.Miter));
|
nameof(StrokeLineJoin), typeof(PenLineJoin), typeof(MapOverlay), new PropertyMetadata(PenLineJoin.Miter));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register(
|
||||||
"StrokeMiterLimit", typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
nameof(StrokeMiterLimit), typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
||||||
|
|
||||||
protected override void SetParentMapOverride(MapBase parentMap)
|
protected override void SetParentMapOverride(MapBase parentMap)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
@ -13,7 +13,7 @@ using System.Windows.Media;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for map overlays with font, background, foreground and stroke properties.
|
/// Base class for map overlays with background, foreground, stroke and font properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MapOverlay : MapPanel
|
public partial class MapOverlay : MapPanel
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,40 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
public interface IMapElement
|
||||||
|
{
|
||||||
|
MapBase ParentMap { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Arranges child elements on a Map at positions specified by the attached property Location.
|
/// Arranges child elements on a Map at positions specified by the attached property Location,
|
||||||
/// The Location value is transformed to a viewport position and assigned as TranslateTransform
|
/// or in rectangles specified by the attached property BoundingBox.
|
||||||
/// to the RenderTransform of the element, either directly or as last child of a TransformGroup.
|
/// An element's viewport position is assigned as TranslateTransform to its RenderTransform property,
|
||||||
|
/// either directly or as last child of a TransformGroup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MapPanel : PanelBase, IMapElement
|
public partial class MapPanel : Panel, IMapElement
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
|
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
|
||||||
"Location", typeof(Location), typeof(MapPanel), new PropertyMetadata(null, LocationPropertyChanged));
|
"Location", typeof(Location), typeof(MapPanel), new PropertyMetadata(null, LocationPropertyChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty BoundingBoxProperty = DependencyProperty.RegisterAttached(
|
||||||
|
"BoundingBox", typeof(BoundingBox), typeof(MapPanel), new PropertyMetadata(null, BoundingBoxPropertyChanged));
|
||||||
|
|
||||||
public static Location GetLocation(UIElement element)
|
public static Location GetLocation(UIElement element)
|
||||||
{
|
{
|
||||||
return (Location)element.GetValue(LocationProperty);
|
return (Location)element.GetValue(LocationProperty);
|
||||||
|
|
@ -34,6 +45,16 @@ namespace MapControl
|
||||||
element.SetValue(LocationProperty, value);
|
element.SetValue(LocationProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundingBox GetBoundingBox(UIElement element)
|
||||||
|
{
|
||||||
|
return (BoundingBox)element.GetValue(BoundingBoxProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetBoundingBox(UIElement element, BoundingBox value)
|
||||||
|
{
|
||||||
|
element.SetValue(BoundingBoxProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
private MapBase parentMap;
|
private MapBase parentMap;
|
||||||
|
|
||||||
public MapBase ParentMap
|
public MapBase ParentMap
|
||||||
|
|
@ -42,20 +63,38 @@ namespace MapControl
|
||||||
set { SetParentMapOverride(value); }
|
set { SetParentMapOverride(value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||||
|
|
||||||
|
foreach (UIElement element in Children)
|
||||||
|
{
|
||||||
|
element.Measure(availableSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Size();
|
||||||
|
}
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
{
|
{
|
||||||
foreach (UIElement element in Children)
|
foreach (UIElement element in Children)
|
||||||
{
|
{
|
||||||
var location = GetLocation(element);
|
BoundingBox boundingBox;
|
||||||
|
Location location;
|
||||||
|
|
||||||
if (location != null)
|
if ((boundingBox = GetBoundingBox(element)) != null)
|
||||||
|
{
|
||||||
|
ArrangeElementWithBoundingBox(element);
|
||||||
|
SetBoundingBoxRect(element, parentMap, boundingBox);
|
||||||
|
}
|
||||||
|
else if ((location = GetLocation(element)) != null)
|
||||||
{
|
{
|
||||||
ArrangeElementWithLocation(element);
|
ArrangeElementWithLocation(element);
|
||||||
SetViewportPosition(element, parentMap, location);
|
SetViewportPosition(element, parentMap, location);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ArrangeElementWithoutLocation(element, finalSize);
|
ArrangeElement(element, finalSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,7 +113,7 @@ namespace MapControl
|
||||||
if (parentMap != null && parentMap != this)
|
if (parentMap != null && parentMap != this)
|
||||||
{
|
{
|
||||||
parentMap.ViewportChanged += OnViewportChanged;
|
parentMap.ViewportChanged += OnViewportChanged;
|
||||||
OnViewportChanged(new ViewportChangedEventArgs(0d));
|
OnViewportChanged(new ViewportChangedEventArgs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,9 +121,14 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
foreach (UIElement element in Children)
|
foreach (UIElement element in Children)
|
||||||
{
|
{
|
||||||
var location = GetLocation(element);
|
BoundingBox boundingBox;
|
||||||
|
Location location;
|
||||||
|
|
||||||
if (location != null)
|
if ((boundingBox = GetBoundingBox(element)) != null)
|
||||||
|
{
|
||||||
|
SetBoundingBoxRect(element, parentMap, boundingBox);
|
||||||
|
}
|
||||||
|
else if ((location = GetLocation(element)) != null)
|
||||||
{
|
{
|
||||||
SetViewportPosition(element, parentMap, location);
|
SetViewportPosition(element, parentMap, location);
|
||||||
}
|
}
|
||||||
|
|
@ -109,17 +153,37 @@ namespace MapControl
|
||||||
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var element = (UIElement)obj;
|
var element = (UIElement)obj;
|
||||||
|
var map = GetParentMap(element);
|
||||||
|
var location = (Location)e.NewValue;
|
||||||
|
|
||||||
if (e.NewValue == null)
|
if (location == null)
|
||||||
{
|
{
|
||||||
ArrangeElementWithoutLocation(element, Size.Empty);
|
ArrangeElement(element, map?.RenderSize ?? new Size());
|
||||||
}
|
}
|
||||||
else if (e.OldValue == null)
|
else if (e.OldValue == null)
|
||||||
{
|
{
|
||||||
ArrangeElementWithLocation(element);
|
ArrangeElementWithLocation(element); // arrange once when Location was null before
|
||||||
}
|
}
|
||||||
|
|
||||||
SetViewportPosition(element, GetParentMap(element), (Location)e.NewValue);
|
SetViewportPosition(element, map, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BoundingBoxPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var element = (FrameworkElement)obj;
|
||||||
|
var map = GetParentMap(element);
|
||||||
|
var boundingBox = (BoundingBox)e.NewValue;
|
||||||
|
|
||||||
|
if (boundingBox == null)
|
||||||
|
{
|
||||||
|
ArrangeElement(element, map?.RenderSize ?? new Size());
|
||||||
|
}
|
||||||
|
else if (e.OldValue == null)
|
||||||
|
{
|
||||||
|
ArrangeElementWithBoundingBox(element); // arrange once when BoundingBox was null before
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBoundingBoxRect(element, map, boundingBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetViewportPosition(UIElement element, MapBase parentMap, Location location)
|
private static void SetViewportPosition(UIElement element, MapBase parentMap, Location location)
|
||||||
|
|
@ -128,12 +192,12 @@ namespace MapControl
|
||||||
|
|
||||||
if (parentMap != null && location != null)
|
if (parentMap != null && location != null)
|
||||||
{
|
{
|
||||||
viewportPosition = parentMap.LocationToViewportPoint(location);
|
viewportPosition = parentMap.MapProjection.LocationToViewportPoint(location);
|
||||||
|
|
||||||
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
||||||
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
||||||
{
|
{
|
||||||
viewportPosition = parentMap.LocationToViewportPoint(new Location(
|
viewportPosition = parentMap.MapProjection.LocationToViewportPoint(new Location(
|
||||||
location.Latitude,
|
location.Latitude,
|
||||||
Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude)));
|
Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude)));
|
||||||
}
|
}
|
||||||
|
|
@ -145,14 +209,6 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var translateTransform = GetTranslateTransform(element);
|
|
||||||
|
|
||||||
translateTransform.X = viewportPosition.X;
|
|
||||||
translateTransform.Y = viewportPosition.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TranslateTransform GetTranslateTransform(UIElement element)
|
|
||||||
{
|
|
||||||
var translateTransform = element.RenderTransform as TranslateTransform;
|
var translateTransform = element.RenderTransform as TranslateTransform;
|
||||||
|
|
||||||
if (translateTransform == null)
|
if (translateTransform == null)
|
||||||
|
|
@ -179,17 +235,85 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return translateTransform;
|
translateTransform.X = viewportPosition.X;
|
||||||
|
translateTransform.Y = viewportPosition.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetBoundingBoxRect(UIElement element, MapBase parentMap, BoundingBox boundingBox)
|
||||||
|
{
|
||||||
|
var rotation = 0d;
|
||||||
|
var viewportPosition = new Point();
|
||||||
|
|
||||||
|
if (parentMap != null && boundingBox != null)
|
||||||
|
{
|
||||||
|
var projection = parentMap.MapProjection;
|
||||||
|
var rect = projection.BoundingBoxToRect(boundingBox);
|
||||||
|
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
|
|
||||||
|
rotation = parentMap.Heading;
|
||||||
|
viewportPosition = projection.ViewportTransform.Transform(center);
|
||||||
|
|
||||||
|
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
||||||
|
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
||||||
|
{
|
||||||
|
var location = projection.PointToLocation(center);
|
||||||
|
location.Longitude = Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude);
|
||||||
|
|
||||||
|
viewportPosition = projection.LocationToViewportPoint(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
var width = rect.Width * projection.ViewportScale;
|
||||||
|
var height = rect.Height * projection.ViewportScale;
|
||||||
|
|
||||||
|
if (element is FrameworkElement)
|
||||||
|
{
|
||||||
|
((FrameworkElement)element).Width = width;
|
||||||
|
((FrameworkElement)element).Height = height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
element.Arrange(new Rect(-width / 2d, -height / 2d, width, height)); // ???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var transformGroup = element.RenderTransform as TransformGroup;
|
||||||
|
RotateTransform rotateTransform;
|
||||||
|
TranslateTransform translateTransform;
|
||||||
|
|
||||||
|
if (transformGroup == null ||
|
||||||
|
transformGroup.Children.Count != 2 ||
|
||||||
|
(rotateTransform = transformGroup.Children[0] as RotateTransform) == null ||
|
||||||
|
(translateTransform = transformGroup.Children[1] as TranslateTransform) == null)
|
||||||
|
{
|
||||||
|
transformGroup = new TransformGroup();
|
||||||
|
rotateTransform = new RotateTransform();
|
||||||
|
translateTransform = new TranslateTransform();
|
||||||
|
transformGroup.Children.Add(rotateTransform);
|
||||||
|
transformGroup.Children.Add(translateTransform);
|
||||||
|
|
||||||
|
element.RenderTransform = transformGroup;
|
||||||
|
element.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
rotateTransform.Angle = rotation;
|
||||||
|
translateTransform.X = viewportPosition.X;
|
||||||
|
translateTransform.Y = viewportPosition.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ArrangeElementWithBoundingBox(UIElement element)
|
||||||
|
{
|
||||||
|
var size = element.DesiredSize;
|
||||||
|
|
||||||
|
element.Arrange(new Rect(-size.Width / 2d, -size.Height / 2d, size.Width, size.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ArrangeElementWithLocation(UIElement element)
|
private static void ArrangeElementWithLocation(UIElement element)
|
||||||
{
|
{
|
||||||
var rect = new Rect(new Point(), element.DesiredSize);
|
var rect = new Rect(new Point(), element.DesiredSize);
|
||||||
var frameworkElement = element as FrameworkElement;
|
|
||||||
|
|
||||||
if (frameworkElement != null)
|
if (element is FrameworkElement)
|
||||||
{
|
{
|
||||||
switch (frameworkElement.HorizontalAlignment)
|
switch (((FrameworkElement)element).HorizontalAlignment)
|
||||||
{
|
{
|
||||||
case HorizontalAlignment.Center:
|
case HorizontalAlignment.Center:
|
||||||
rect.X = -rect.Width / 2d;
|
rect.X = -rect.Width / 2d;
|
||||||
|
|
@ -203,7 +327,7 @@ namespace MapControl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (frameworkElement.VerticalAlignment)
|
switch (((FrameworkElement)element).VerticalAlignment)
|
||||||
{
|
{
|
||||||
case VerticalAlignment.Center:
|
case VerticalAlignment.Center:
|
||||||
rect.Y = -rect.Height / 2d;
|
rect.Y = -rect.Height / 2d;
|
||||||
|
|
@ -221,20 +345,13 @@ namespace MapControl
|
||||||
element.Arrange(rect);
|
element.Arrange(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ArrangeElementWithoutLocation(UIElement element, Size parentSize)
|
private static void ArrangeElement(UIElement element, Size parentSize)
|
||||||
{
|
{
|
||||||
var rect = new Rect(new Point(), element.DesiredSize);
|
var rect = new Rect(new Point(), element.DesiredSize);
|
||||||
var frameworkElement = element as FrameworkElement;
|
|
||||||
|
|
||||||
if (frameworkElement != null)
|
if (element is FrameworkElement)
|
||||||
{
|
{
|
||||||
if (parentSize.IsEmpty)
|
switch (((FrameworkElement)element).HorizontalAlignment)
|
||||||
{
|
|
||||||
var parent = frameworkElement.Parent as UIElement;
|
|
||||||
parentSize = parent?.RenderSize ?? new Size();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (frameworkElement.HorizontalAlignment)
|
|
||||||
{
|
{
|
||||||
case HorizontalAlignment.Center:
|
case HorizontalAlignment.Center:
|
||||||
rect.X = (parentSize.Width - rect.Width) / 2d;
|
rect.X = (parentSize.Width - rect.Width) / 2d;
|
||||||
|
|
@ -252,7 +369,7 @@ namespace MapControl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (frameworkElement.VerticalAlignment)
|
switch (((FrameworkElement)element).VerticalAlignment)
|
||||||
{
|
{
|
||||||
case VerticalAlignment.Center:
|
case VerticalAlignment.Center:
|
||||||
rect.Y = (parentSize.Height - rect.Height) / 2d;
|
rect.Y = (parentSize.Height - rect.Height) / 2d;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
@ -33,8 +33,17 @@ namespace MapControl
|
||||||
// Workaround for missing PropertyChangedCallback for the Data property.
|
// Workaround for missing PropertyChangedCallback for the Data property.
|
||||||
if (data != Data)
|
if (data != Data)
|
||||||
{
|
{
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
data.ClearValue(Geometry.TransformProperty);
|
||||||
|
}
|
||||||
|
|
||||||
data = Data;
|
data = Data;
|
||||||
UpdateData();
|
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
data.Transform = viewportTransform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path.MeasureOverride in Windows Runtime sometimes returns an empty Size,
|
// Path.MeasureOverride in Windows Runtime sometimes returns an empty Size,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -11,7 +11,7 @@ namespace MapControl
|
||||||
public partial class MapPath : Shape
|
public partial class MapPath : Shape
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
|
||||||
"Data", typeof(Geometry), typeof(MapPath), new FrameworkPropertyMetadata(
|
nameof(Data), typeof(Geometry), typeof(MapPath), new FrameworkPropertyMetadata(
|
||||||
null, FrameworkPropertyMetadataOptions.AffectsRender, DataPropertyChanged, CoerceDataProperty));
|
null, FrameworkPropertyMetadataOptions.AffectsRender, DataPropertyChanged, CoerceDataProperty));
|
||||||
|
|
||||||
static MapPath()
|
static MapPath()
|
||||||
|
|
@ -41,13 +41,24 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (!ReferenceEquals(e.OldValue, e.NewValue))
|
if (!ReferenceEquals(e.OldValue, e.NewValue))
|
||||||
{
|
{
|
||||||
((MapPath)obj).UpdateData();
|
var mapPath = (MapPath)obj;
|
||||||
|
|
||||||
|
if (e.OldValue != null)
|
||||||
|
{
|
||||||
|
((Geometry)e.OldValue).ClearValue(Geometry.TransformProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.NewValue != null)
|
||||||
|
{
|
||||||
|
((Geometry)e.NewValue).Transform = mapPath.viewportTransform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object CoerceDataProperty(DependencyObject obj, object value)
|
private static object CoerceDataProperty(DependencyObject obj, object value)
|
||||||
{
|
{
|
||||||
var data = (Geometry)value;
|
var data = (Geometry)value;
|
||||||
|
|
||||||
return (data != null && data.IsFrozen) ? data.CloneCurrentValue() : data;
|
return (data != null && data.IsFrozen) ? data.CloneCurrentValue() : data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
@ -22,11 +21,8 @@ namespace MapControl
|
||||||
public partial class MapPath : IMapElement
|
public partial class MapPath : IMapElement
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
|
||||||
"Location", typeof(Location), typeof(MapPath),
|
nameof(Location), typeof(Location), typeof(MapPath),
|
||||||
new PropertyMetadata(null, (o, e) => ((MapPath)o).LocationChanged((Location)e.OldValue, (Location)e.NewValue)));
|
new PropertyMetadata(null, (o, e) => ((MapPath)o).LocationPropertyChanged()));
|
||||||
|
|
||||||
private readonly TransformGroup viewportTransform = new TransformGroup();
|
|
||||||
private MapBase parentMap;
|
|
||||||
|
|
||||||
public Location Location
|
public Location Location
|
||||||
{
|
{
|
||||||
|
|
@ -34,19 +30,17 @@ namespace MapControl
|
||||||
set { SetValue(LocationProperty, value); }
|
set { SetValue(LocationProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransformGroup ViewportTransform
|
private readonly TransformGroup viewportTransform = new TransformGroup();
|
||||||
{
|
private MapBase parentMap;
|
||||||
get { return viewportTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapBase ParentMap
|
public MapBase ParentMap
|
||||||
{
|
{
|
||||||
get { return parentMap; }
|
get { return parentMap; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (parentMap != null && Location != null)
|
if (parentMap != null)
|
||||||
{
|
{
|
||||||
DetachViewportChanged();
|
parentMap.ViewportChanged -= OnViewportChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportTransform.Children.Clear();
|
viewportTransform.Children.Clear();
|
||||||
|
|
@ -54,12 +48,9 @@ namespace MapControl
|
||||||
|
|
||||||
if (parentMap != null)
|
if (parentMap != null)
|
||||||
{
|
{
|
||||||
viewportTransform.Children.Add(parentMap.ViewportTransform);
|
viewportTransform.Children.Add(new TranslateTransform());
|
||||||
|
viewportTransform.Children.Add(parentMap.MapProjection.ViewportTransform);
|
||||||
if (Location != null)
|
parentMap.ViewportChanged += OnViewportChanged;
|
||||||
{
|
|
||||||
AttachViewportChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateData();
|
UpdateData();
|
||||||
|
|
@ -68,52 +59,54 @@ namespace MapControl
|
||||||
|
|
||||||
protected virtual void UpdateData()
|
protected virtual void UpdateData()
|
||||||
{
|
{
|
||||||
if (Data != null)
|
}
|
||||||
|
|
||||||
|
protected virtual void OnViewportChanged(ViewportChangedEventArgs e)
|
||||||
|
{
|
||||||
|
double longitudeScale = parentMap.MapProjection.LongitudeScale;
|
||||||
|
|
||||||
|
if (e.ProjectionChanged)
|
||||||
{
|
{
|
||||||
Data.Transform = viewportTransform;
|
viewportTransform.Children[1] = parentMap.MapProjection.ViewportTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.ProjectionChanged || double.IsNaN(longitudeScale))
|
||||||
|
{
|
||||||
|
UpdateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.IsNaN(longitudeScale)) // a normal cylindrical projection
|
||||||
|
{
|
||||||
|
var longitudeOffset = 0d;
|
||||||
|
|
||||||
|
if (Location != null)
|
||||||
|
{
|
||||||
|
var viewportPosition = parentMap.MapProjection.LocationToViewportPoint(Location);
|
||||||
|
|
||||||
|
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
||||||
|
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
||||||
|
{
|
||||||
|
var nearestLongitude = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude);
|
||||||
|
|
||||||
|
longitudeOffset = longitudeScale * (nearestLongitude - Location.Longitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((TranslateTransform)viewportTransform.Children[0]).X = longitudeOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LocationChanged(Location oldValue, Location newValue)
|
private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
|
||||||
|
{
|
||||||
|
OnViewportChanged(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LocationPropertyChanged()
|
||||||
{
|
{
|
||||||
if (parentMap != null)
|
if (parentMap != null)
|
||||||
{
|
{
|
||||||
if (oldValue == null)
|
OnViewportChanged(new ViewportChangedEventArgs());
|
||||||
{
|
|
||||||
AttachViewportChanged();
|
|
||||||
}
|
|
||||||
else if (newValue == null)
|
|
||||||
{
|
|
||||||
DetachViewportChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttachViewportChanged()
|
|
||||||
{
|
|
||||||
viewportTransform.Children.Insert(0, new TranslateTransform());
|
|
||||||
parentMap.ViewportChanged += OnViewportChanged;
|
|
||||||
OnViewportChanged(parentMap, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DetachViewportChanged()
|
|
||||||
{
|
|
||||||
parentMap.ViewportChanged -= OnViewportChanged;
|
|
||||||
viewportTransform.Children.RemoveAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnViewportChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var viewportPosition = parentMap.LocationToViewportPoint(Location);
|
|
||||||
var longitudeOffset = 0d;
|
|
||||||
|
|
||||||
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
|
||||||
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
|
||||||
{
|
|
||||||
longitudeOffset = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude) - Location.Longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
((TranslateTransform)viewportTransform.Children[0]).X = longitudeOffset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -16,12 +16,12 @@ namespace MapControl
|
||||||
public partial class MapPolyline
|
public partial class MapPolyline
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
|
||||||
"FillRule", typeof(FillRule), typeof(MapPolyline),
|
nameof(FillRule), typeof(FillRule), typeof(MapPolyline),
|
||||||
new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
|
new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
|
||||||
|
|
||||||
public MapPolyline()
|
public MapPolyline()
|
||||||
{
|
{
|
||||||
Data = new PathGeometry { Transform = ViewportTransform };
|
Data = new PathGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateData()
|
protected override void UpdateData()
|
||||||
|
|
@ -31,7 +31,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (ParentMap != null && Locations != null && Locations.Any())
|
if (ParentMap != null && Locations != null && Locations.Any())
|
||||||
{
|
{
|
||||||
var points = Locations.Select(l => ParentMap.MapTransform.Transform(l));
|
var points = Locations.Select(l => ParentMap.MapProjection.LocationToPoint(l));
|
||||||
|
|
||||||
var figure = new PathFigure
|
var figure = new PathFigure
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -16,7 +16,7 @@ namespace MapControl
|
||||||
|
|
||||||
public MapPolyline()
|
public MapPolyline()
|
||||||
{
|
{
|
||||||
Data = new StreamGeometry { Transform = ViewportTransform };
|
Data = new StreamGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateData()
|
protected override void UpdateData()
|
||||||
|
|
@ -27,7 +27,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
using (var context = geometry.Open())
|
using (var context = geometry.Open())
|
||||||
{
|
{
|
||||||
var points = Locations.Select(l => ParentMap.MapTransform.Transform(l));
|
var points = Locations.Select(l => ParentMap.MapProjection.LocationToPoint(l));
|
||||||
|
|
||||||
context.BeginFigure(points.First(), IsClosed, IsClosed);
|
context.BeginFigure(points.First(), IsClosed, IsClosed);
|
||||||
context.PolyLineTo(points.Skip(1).ToList(), true, false);
|
context.PolyLineTo(points.Skip(1).ToList(), true, false);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using System.Collections;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
|
|
@ -21,18 +20,12 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MapPolyline : MapPath
|
public partial class MapPolyline : MapPath
|
||||||
{
|
{
|
||||||
#if NETFX_CORE
|
|
||||||
// Binding fails on Windows Runtime when property type is IEnumerable<Location>
|
|
||||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||||
"Locations", typeof(IEnumerable), typeof(MapPolyline),
|
nameof(Locations), typeof(IEnumerable<Location>), typeof(MapPolyline),
|
||||||
new PropertyMetadata(null, (o, e) => ((MapPolyline)o).LocationsChanged(e.OldValue as INotifyCollectionChanged, e.NewValue as INotifyCollectionChanged)));
|
new PropertyMetadata(null, (o, e) => ((MapPolyline)o).LocationsPropertyChanged(e)));
|
||||||
#else
|
|
||||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
|
||||||
"Locations", typeof(IEnumerable<Location>), typeof(MapPolyline),
|
|
||||||
new PropertyMetadata(null, (o, e) => ((MapPolyline)o).LocationsChanged(e.OldValue as INotifyCollectionChanged, e.NewValue as INotifyCollectionChanged)));
|
|
||||||
#endif
|
|
||||||
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
||||||
"IsClosed", typeof(bool), typeof(MapPolyline),
|
nameof(IsClosed), typeof(bool), typeof(MapPolyline),
|
||||||
new PropertyMetadata(false, (o, e) => ((MapPolyline)o).UpdateData()));
|
new PropertyMetadata(false, (o, e) => ((MapPolyline)o).UpdateData()));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -65,8 +58,11 @@ namespace MapControl
|
||||||
set { SetValue(FillRuleProperty, value); }
|
set { SetValue(FillRuleProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LocationsChanged(INotifyCollectionChanged oldCollection, INotifyCollectionChanged newCollection)
|
private void LocationsPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
var oldCollection = e.OldValue as INotifyCollectionChanged;
|
||||||
|
var newCollection = e.NewValue as INotifyCollectionChanged;
|
||||||
|
|
||||||
if (oldCollection != null)
|
if (oldCollection != null)
|
||||||
{
|
{
|
||||||
oldCollection.CollectionChanged -= LocationCollectionChanged;
|
oldCollection.CollectionChanged -= LocationCollectionChanged;
|
||||||
|
|
|
||||||
176
MapControl/MapProjection.cs
Normal file
176
MapControl/MapProjection.cs
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
// 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;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
#else
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a map projection between geographic coordinates and cartesian map coordinates
|
||||||
|
/// and viewport coordinates, i.e. pixels.
|
||||||
|
/// </summary>
|
||||||
|
public abstract partial class MapProjection
|
||||||
|
{
|
||||||
|
public const double Wgs84EquatorialRadius = 6378137d;
|
||||||
|
public const double MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the WMS 1.3.0 CRS Identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string CrsId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if this is a web mercator projection, i.e. compatible with map tile layers.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsWebMercator { get; protected set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if this is an azimuthal projection.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAzimuthal { get; protected set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scale factor from longitude to x values of a normal cylindrical projection.
|
||||||
|
/// Returns NaN if this is not a normal cylindrical projection.
|
||||||
|
/// </summary>
|
||||||
|
public double LongitudeScale { get; protected set; } = 1d;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the absolute value of the minimum and maximum latitude that can be transformed.
|
||||||
|
/// </summary>
|
||||||
|
public double MaxLatitude { get; protected set; } = 90d;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scaling factor from cartesian map coordinates to viewport coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public double ViewportScale { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the transformation from cartesian map coordinates to viewport coordinates (pixels).
|
||||||
|
/// </summary>
|
||||||
|
public MatrixTransform ViewportTransform { get; } = new MatrixTransform();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scaling factor from cartesian map coordinates to viewport coordinates for the specified zoom level.
|
||||||
|
/// </summary>
|
||||||
|
public virtual double GetViewportScale(double zoomLevel)
|
||||||
|
{
|
||||||
|
return Math.Pow(2d, zoomLevel) * TileSource.TileSize / 360d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the map scale at the specified Location as viewport coordinate units per meter (px/m).
|
||||||
|
/// </summary>
|
||||||
|
public abstract Point GetMapScale(Location location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Location in geographic coordinates to a Point in cartesian map coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Point LocationToPoint(Location location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Point in cartesian map coordinates to a Location in geographic coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Location PointToLocation(Point point);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Translates a Location in geographic coordinates by the specified small amount in viewport coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Location TranslateLocation(Location location, Point translation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a BoundingBox in geographic coordinates to a Rect in cartesian map coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Rect BoundingBoxToRect(BoundingBox boundingBox)
|
||||||
|
{
|
||||||
|
return new Rect(
|
||||||
|
LocationToPoint(new Location(boundingBox.South, boundingBox.West)),
|
||||||
|
LocationToPoint(new Location(boundingBox.North, boundingBox.East)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Rect in cartesian map coordinates to a BoundingBox in geographic coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public virtual BoundingBox RectToBoundingBox(Rect rect)
|
||||||
|
{
|
||||||
|
var sw = PointToLocation(new Point(rect.X, rect.Y));
|
||||||
|
var ne = PointToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
||||||
|
|
||||||
|
return new BoundingBox(sw.Latitude, sw.Longitude, ne.Latitude, ne.Longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Location in geographic coordinates to a Point in viewport coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public Point LocationToViewportPoint(Location location)
|
||||||
|
{
|
||||||
|
return ViewportTransform.Transform(LocationToPoint(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Point in viewport coordinates to a Location in geographic coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public Location ViewportPointToLocation(Point point)
|
||||||
|
{
|
||||||
|
return PointToLocation(ViewportTransform.Inverse.Transform(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Rect in viewport coordinates to a BoundingBox in geographic coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public BoundingBox ViewportRectToBoundingBox(Rect rect)
|
||||||
|
{
|
||||||
|
return RectToBoundingBox(ViewportTransform.Inverse.TransformBounds(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets ViewportScale and ViewportTransform values.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading)
|
||||||
|
{
|
||||||
|
ViewportScale = GetViewportScale(zoomLevel);
|
||||||
|
|
||||||
|
ViewportTransform.Matrix = MatrixEx.TranslateScaleRotateTranslate(
|
||||||
|
LocationToPoint(mapCenter), ViewportScale, -ViewportScale, heading, viewportCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a WMS 1.3.0 query parameter string from the specified bounding box,
|
||||||
|
/// e.g. "CRS=...&BBOX=...&WIDTH=...&HEIGHT=..."
|
||||||
|
/// </summary>
|
||||||
|
public virtual string WmsQueryParameters(BoundingBox boundingBox, string version = "1.3.0")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(CrsId))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = "CRS={0}&BBOX={1},{2},{3},{4}&WIDTH={5}&HEIGHT={6}";
|
||||||
|
|
||||||
|
if (version.StartsWith("1.1."))
|
||||||
|
{
|
||||||
|
format = "SRS={0}&BBOX={1},{2},{3},{4}&WIDTH={5}&HEIGHT={6}";
|
||||||
|
}
|
||||||
|
else if (CrsId == "EPSG:4326")
|
||||||
|
{
|
||||||
|
format = "CRS={0}&BBOX={2},{1},{4},{3}&WIDTH={5}&HEIGHT={6}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = BoundingBoxToRect(boundingBox);
|
||||||
|
var width = (int)Math.Round(ViewportScale * rect.Width);
|
||||||
|
var height = (int)Math.Round(ViewportScale * rect.Height);
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, format, CrsId,
|
||||||
|
rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class MapRectangle
|
|
||||||
{
|
|
||||||
static partial void ScaleRect(ref Rect rect, ref Transform transform)
|
|
||||||
{
|
|
||||||
// Scales the RectangleGeometry to compensate inaccurate hit testing in WPF.
|
|
||||||
// See http://stackoverflow.com/a/19335624/1136211
|
|
||||||
|
|
||||||
rect.Scale(1e6, 1e6);
|
|
||||||
|
|
||||||
var scaleTransform = new ScaleTransform(1e-6, 1e-6); // reverts rect scaling
|
|
||||||
scaleTransform.Freeze();
|
|
||||||
|
|
||||||
var transformGroup = new TransformGroup();
|
|
||||||
transformGroup.Children.Add(scaleTransform);
|
|
||||||
transformGroup.Children.Add(transform);
|
|
||||||
|
|
||||||
transform = transformGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
#if NETFX_CORE
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Fills a rectangular area defined by South, North, West and East with a Brush.
|
|
||||||
/// </summary>
|
|
||||||
public partial class MapRectangle : MapPath
|
|
||||||
{
|
|
||||||
public static readonly DependencyProperty WestProperty = DependencyProperty.Register(
|
|
||||||
"West", typeof(double), typeof(MapRectangle),
|
|
||||||
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty EastProperty = DependencyProperty.Register(
|
|
||||||
"East", typeof(double), typeof(MapRectangle),
|
|
||||||
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty SouthProperty = DependencyProperty.Register(
|
|
||||||
"South", typeof(double), typeof(MapRectangle),
|
|
||||||
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty NorthProperty = DependencyProperty.Register(
|
|
||||||
"North", typeof(double), typeof(MapRectangle),
|
|
||||||
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
|
|
||||||
|
|
||||||
private bool boundingBoxValid;
|
|
||||||
|
|
||||||
public MapRectangle()
|
|
||||||
{
|
|
||||||
StrokeThickness = 0d;
|
|
||||||
Data = new RectangleGeometry();
|
|
||||||
boundingBoxValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double West
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(WestProperty); }
|
|
||||||
set { SetValue(WestProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public double East
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(EastProperty); }
|
|
||||||
set { SetValue(EastProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public double South
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(SouthProperty); }
|
|
||||||
set { SetValue(SouthProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public double North
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(NorthProperty); }
|
|
||||||
set { SetValue(NorthProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BoundingBoxValid
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !double.IsNaN(South) && !double.IsNaN(North)
|
|
||||||
&& !double.IsNaN(West) && !double.IsNaN(East)
|
|
||||||
&& South < North && West < East;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetBoundingBox(double west, double east, double south, double north)
|
|
||||||
{
|
|
||||||
if (West != west || East != east || South != south || North != north)
|
|
||||||
{
|
|
||||||
boundingBoxValid = false;
|
|
||||||
West = west;
|
|
||||||
East = east;
|
|
||||||
South = south;
|
|
||||||
North = north;
|
|
||||||
boundingBoxValid = true;
|
|
||||||
UpdateData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateData()
|
|
||||||
{
|
|
||||||
if (boundingBoxValid)
|
|
||||||
{
|
|
||||||
var geometry = (RectangleGeometry)Data;
|
|
||||||
|
|
||||||
if (ParentMap != null && BoundingBoxValid)
|
|
||||||
{
|
|
||||||
var rect = new Rect(ParentMap.MapTransform.Transform(new Location(South, West)),
|
|
||||||
ParentMap.MapTransform.Transform(new Location(North, East)));
|
|
||||||
Transform transform = ViewportTransform;
|
|
||||||
|
|
||||||
ScaleRect(ref rect, ref transform);
|
|
||||||
|
|
||||||
geometry.Rect = rect;
|
|
||||||
RenderTransform = transform;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
geometry.ClearValue(RectangleGeometry.RectProperty);
|
|
||||||
ClearValue(RenderTransformProperty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static partial void ScaleRect(ref Rect rect, ref Transform transform); // WPF only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -23,23 +23,12 @@ namespace MapControl
|
||||||
|
|
||||||
static MapScale()
|
static MapScale()
|
||||||
{
|
{
|
||||||
IsHitTestVisibleProperty.OverrideMetadata(
|
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(false));
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(false));
|
MinWidthProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(100d));
|
||||||
|
HorizontalAlignmentProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(HorizontalAlignment.Right));
|
||||||
MinWidthProperty.OverrideMetadata(
|
VerticalAlignmentProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(VerticalAlignment.Bottom));
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(100d));
|
StrokeStartLineCapProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||||
|
StrokeEndLineCapProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||||
HorizontalAlignmentProperty.OverrideMetadata(
|
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(HorizontalAlignment.Right));
|
|
||||||
|
|
||||||
VerticalAlignmentProperty.OverrideMetadata(
|
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(VerticalAlignment.Bottom));
|
|
||||||
|
|
||||||
StrokeStartLineCapProperty.OverrideMetadata(
|
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
|
||||||
|
|
||||||
StrokeEndLineCapProperty.OverrideMetadata(
|
|
||||||
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Thickness Padding
|
public Thickness Padding
|
||||||
|
|
@ -50,9 +39,9 @@ namespace MapControl
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
{
|
{
|
||||||
if (ParentMap != null && ParentMap.CenterScale > 0d)
|
if (ParentMap != null && ParentMap.ScaleTransform.ScaleX > 0d)
|
||||||
{
|
{
|
||||||
length = MinWidth / ParentMap.CenterScale;
|
length = MinWidth / ParentMap.ScaleTransform.ScaleX;
|
||||||
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
|
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
|
||||||
|
|
||||||
if (length / magnitude < 2d)
|
if (length / magnitude < 2d)
|
||||||
|
|
@ -68,7 +57,7 @@ namespace MapControl
|
||||||
length = 10d * magnitude;
|
length = 10d * magnitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
size.Width = length * ParentMap.CenterScale + StrokeThickness + Padding.Left + Padding.Right;
|
size.Width = length * ParentMap.ScaleTransform.ScaleX + StrokeThickness + Padding.Left + Padding.Right;
|
||||||
size.Height = FontSize * FontFamily.LineSpacing + StrokeThickness + Padding.Top + Padding.Bottom;
|
size.Height = FontSize * FontFamily.LineSpacing + StrokeThickness + Padding.Top + Padding.Bottom;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
16
MapControl/MapTileLayer.Silverlight.WinRT.cs
Normal file
16
MapControl/MapTileLayer.Silverlight.WinRT.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2017 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
public partial class MapTileLayer
|
||||||
|
{
|
||||||
|
partial void Initialize()
|
||||||
|
{
|
||||||
|
IsHitTestVisible = false;
|
||||||
|
|
||||||
|
MapPanel.AddParentMapHandlers(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
MapControl/MapTileLayer.WPF.cs
Normal file
16
MapControl/MapTileLayer.WPF.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2017 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
public partial class MapTileLayer
|
||||||
|
{
|
||||||
|
static MapTileLayer()
|
||||||
|
{
|
||||||
|
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapTileLayer), new FrameworkPropertyMetadata(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -8,10 +8,12 @@ using System.Linq;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Markup;
|
using Windows.UI.Xaml.Markup;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
|
@ -19,6 +21,12 @@ using System.Windows.Threading;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
public interface ITileImageLoader
|
||||||
|
{
|
||||||
|
void BeginLoadTiles(MapTileLayer tileLayer, IEnumerable<Tile> tiles);
|
||||||
|
void CancelLoadTiles(MapTileLayer tileLayer);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills the map viewport with map tiles from a TileSource.
|
/// Fills the map viewport with map tiles from a TileSource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -27,13 +35,16 @@ namespace MapControl
|
||||||
#else
|
#else
|
||||||
[ContentProperty("TileSource")]
|
[ContentProperty("TileSource")]
|
||||||
#endif
|
#endif
|
||||||
public partial class TileLayer : PanelBase, IMapElement
|
public partial class MapTileLayer : Panel, IMapLayer
|
||||||
{
|
{
|
||||||
public static TileLayer OpenStreetMapTileLayer
|
/// <summary>
|
||||||
|
/// A default TileLayer using OpenStreetMap data.
|
||||||
|
/// </summary>
|
||||||
|
public static MapTileLayer OpenStreetMapTileLayer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TileLayer
|
return new MapTileLayer
|
||||||
{
|
{
|
||||||
SourceName = "OpenStreetMap",
|
SourceName = "OpenStreetMap",
|
||||||
Description = "© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)",
|
Description = "© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)",
|
||||||
|
|
@ -44,56 +55,53 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register(
|
||||||
"TileSource", typeof(TileSource), typeof(TileLayer),
|
nameof(TileSource), typeof(TileSource), typeof(MapTileLayer),
|
||||||
new PropertyMetadata(null, (o, e) => ((TileLayer)o).UpdateTiles(true)));
|
new PropertyMetadata(null, (o, e) => ((MapTileLayer)o).UpdateTiles(true)));
|
||||||
|
|
||||||
public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register(
|
||||||
"SourceName", typeof(string), typeof(TileLayer), new PropertyMetadata(null));
|
nameof(SourceName), typeof(string), typeof(MapTileLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||||
"Description", typeof(string), typeof(TileLayer), new PropertyMetadata(null));
|
nameof(Description), typeof(string), typeof(MapTileLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty LogoImageProperty = DependencyProperty.Register(
|
|
||||||
"LogoImage", typeof(ImageSource), typeof(TileLayer), new PropertyMetadata(null));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty ZoomLevelOffsetProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ZoomLevelOffsetProperty = DependencyProperty.Register(
|
||||||
"ZoomLevelOffset", typeof(double), typeof(TileLayer),
|
nameof(ZoomLevelOffset), typeof(double), typeof(MapTileLayer),
|
||||||
new PropertyMetadata(0d, (o, e) => ((TileLayer)o).UpdateTileGrid()));
|
new PropertyMetadata(0d, (o, e) => ((MapTileLayer)o).UpdateTileGrid()));
|
||||||
|
|
||||||
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
|
||||||
"MinZoomLevel", typeof(int), typeof(TileLayer), new PropertyMetadata(0));
|
nameof(MinZoomLevel), typeof(int), typeof(MapTileLayer), new PropertyMetadata(0));
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
|
||||||
"MaxZoomLevel", typeof(int), typeof(TileLayer), new PropertyMetadata(18));
|
nameof(MaxZoomLevel), typeof(int), typeof(MapTileLayer), new PropertyMetadata(18));
|
||||||
|
|
||||||
public static readonly DependencyProperty MaxParallelDownloadsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MaxParallelDownloadsProperty = DependencyProperty.Register(
|
||||||
"MaxParallelDownloads", typeof(int), typeof(TileLayer), new PropertyMetadata(4));
|
nameof(MaxParallelDownloads), typeof(int), typeof(MapTileLayer), new PropertyMetadata(4));
|
||||||
|
|
||||||
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
|
||||||
"UpdateInterval", typeof(TimeSpan), typeof(TileLayer),
|
nameof(UpdateInterval), typeof(TimeSpan), typeof(MapTileLayer),
|
||||||
new PropertyMetadata(TimeSpan.FromSeconds(0.5), (o, e) => ((TileLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
new PropertyMetadata(TimeSpan.FromSeconds(0.2), (o, e) => ((MapTileLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
||||||
"UpdateWhileViewportChanging", typeof(bool), typeof(TileLayer), new PropertyMetadata(true));
|
nameof(UpdateWhileViewportChanging), typeof(bool), typeof(MapTileLayer), new PropertyMetadata(true));
|
||||||
|
|
||||||
public static readonly DependencyProperty LoadTilesDescendingProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LoadTilesDescendingProperty = DependencyProperty.Register(
|
||||||
"LoadTilesDescending", typeof(bool), typeof(TileLayer), new PropertyMetadata(false));
|
nameof(LoadTilesDescending), typeof(bool), typeof(MapTileLayer), new PropertyMetadata(false));
|
||||||
|
|
||||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MapBackgroundProperty = DependencyProperty.Register(
|
||||||
"Foreground", typeof(Brush), typeof(TileLayer), new PropertyMetadata(null));
|
nameof(MapBackground), typeof(Brush), typeof(MapTileLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly new DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MapForegroundProperty = DependencyProperty.Register(
|
||||||
"Background", typeof(Brush), typeof(TileLayer), new PropertyMetadata(null));
|
nameof(MapForeground), typeof(Brush), typeof(MapTileLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
private readonly DispatcherTimer updateTimer;
|
private readonly DispatcherTimer updateTimer;
|
||||||
private MapBase parentMap;
|
private MapBase parentMap;
|
||||||
|
|
||||||
public TileLayer()
|
public MapTileLayer()
|
||||||
: this(new TileImageLoader())
|
: this(new TileImageLoader())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileLayer(ITileImageLoader tileImageLoader)
|
public MapTileLayer(ITileImageLoader tileImageLoader)
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
|
|
@ -130,7 +138,8 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Description of the TileLayer. Used to display copyright information on top of the map.
|
/// Description of the TileLayer.
|
||||||
|
/// Used to display copyright information on top of the map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Description
|
public string Description
|
||||||
{
|
{
|
||||||
|
|
@ -138,15 +147,6 @@ namespace MapControl
|
||||||
set { SetValue(DescriptionProperty, value); }
|
set { SetValue(DescriptionProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Logo image. Used to display a provider brand logo on top of the map.
|
|
||||||
/// </summary>
|
|
||||||
public ImageSource LogoImage
|
|
||||||
{
|
|
||||||
get { return (ImageSource)GetValue(LogoImageProperty); }
|
|
||||||
set { SetValue(LogoImageProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an offset to the Map's ZoomLevel for a relative scale between the Map and the TileLayer.
|
/// Adds an offset to the Map's ZoomLevel for a relative scale between the Map and the TileLayer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -193,7 +193,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls if tiles are updates while the viewport is still changing.
|
/// Controls if tiles are updated while the viewport is still changing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UpdateWhileViewportChanging
|
public bool UpdateWhileViewportChanging
|
||||||
{
|
{
|
||||||
|
|
@ -212,22 +212,23 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional foreground brush. Sets MapBase.Foreground, if not null.
|
/// Optional background brush.
|
||||||
|
/// Sets MapBase.Background if not null and the TileLayer is the base map layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Brush Foreground
|
public Brush MapBackground
|
||||||
{
|
{
|
||||||
get { return (Brush)GetValue(ForegroundProperty); }
|
get { return (Brush)GetValue(MapBackgroundProperty); }
|
||||||
set { SetValue(ForegroundProperty, value); }
|
set { SetValue(MapBackgroundProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional background brush. Sets MapBase.Background, if not null.
|
/// Optional foreground brush.
|
||||||
/// New property prevents filling of RenderTransformed TileLayer with Panel.Background.
|
/// Sets MapBase.Foreground if not null and the TileLayer is the base map layer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public new Brush Background
|
public Brush MapForeground
|
||||||
{
|
{
|
||||||
get { return (Brush)GetValue(BackgroundProperty); }
|
get { return (Brush)GetValue(MapForegroundProperty); }
|
||||||
set { SetValue(BackgroundProperty, value); }
|
set { SetValue(MapForegroundProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapBase ParentMap
|
public MapBase ParentMap
|
||||||
|
|
@ -251,11 +252,64 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||||
|
|
||||||
|
foreach (UIElement element in Children)
|
||||||
|
{
|
||||||
|
element.Measure(availableSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
|
{
|
||||||
|
if (TileGrid != null)
|
||||||
|
{
|
||||||
|
foreach (var tile in Tiles)
|
||||||
|
{
|
||||||
|
var tileSize = TileSource.TileSize << (TileGrid.ZoomLevel - tile.ZoomLevel);
|
||||||
|
var x = tileSize * tile.X - TileSource.TileSize * TileGrid.XMin;
|
||||||
|
var y = tileSize * tile.Y - TileSource.TileSize * TileGrid.YMin;
|
||||||
|
|
||||||
|
tile.Image.Width = tileSize;
|
||||||
|
tile.Image.Height = tileSize;
|
||||||
|
tile.Image.Arrange(new Rect(x, y, tileSize, tileSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateTileGrid()
|
||||||
|
{
|
||||||
|
updateTimer.Stop();
|
||||||
|
|
||||||
|
if (parentMap != null && parentMap.MapProjection.IsWebMercator)
|
||||||
|
{
|
||||||
|
var tileGrid = GetTileGrid();
|
||||||
|
|
||||||
|
if (!tileGrid.Equals(TileGrid))
|
||||||
|
{
|
||||||
|
TileGrid = tileGrid;
|
||||||
|
SetRenderTransform();
|
||||||
|
UpdateTiles(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TileGrid = null;
|
||||||
|
UpdateTiles(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
|
private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (TileGrid == null || Math.Abs(e.OriginOffset) > 180d)
|
if (TileGrid == null || e.ProjectionChanged || Math.Abs(e.LongitudeOffset) > 180d)
|
||||||
{
|
{
|
||||||
// immediate update when map center moves across 180° longitude
|
// update immediately when map projection has changed or map center has moved across 180° longitude
|
||||||
UpdateTileGrid();
|
UpdateTileGrid();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -274,33 +328,47 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void UpdateTileGrid()
|
private Point GetTileCenter(double tileScale)
|
||||||
{
|
{
|
||||||
updateTimer.Stop();
|
// map center in tile index coordinates
|
||||||
|
return new Point(
|
||||||
if (parentMap != null)
|
tileScale * (0.5 + parentMap.Center.Longitude / 360d),
|
||||||
{
|
tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d));
|
||||||
var zoomLevel = Math.Max(0, (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset));
|
|
||||||
var bounds = GetTileIndexBounds(zoomLevel);
|
|
||||||
var tileGrid = new TileGrid(zoomLevel,
|
|
||||||
(int)Math.Floor(bounds.X), (int)Math.Floor(bounds.Y),
|
|
||||||
(int)Math.Floor(bounds.X + bounds.Width), (int)Math.Floor(bounds.Y + bounds.Height));
|
|
||||||
|
|
||||||
if (!tileGrid.Equals(TileGrid))
|
|
||||||
{
|
|
||||||
TileGrid = tileGrid;
|
|
||||||
SetRenderTransform();
|
|
||||||
UpdateTiles(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TileGrid = null;
|
|
||||||
UpdateTiles(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateTiles(bool clearTiles)
|
private TileGrid GetTileGrid()
|
||||||
|
{
|
||||||
|
var tileZoomLevel = Math.Max(0, (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset));
|
||||||
|
var tileScale = (1 << tileZoomLevel);
|
||||||
|
var scale = tileScale / (Math.Pow(2d, parentMap.ZoomLevel) * TileSource.TileSize);
|
||||||
|
var tileCenter = GetTileCenter(tileScale);
|
||||||
|
var viewCenter = new Point(parentMap.RenderSize.Width / 2d, parentMap.RenderSize.Height / 2d);
|
||||||
|
|
||||||
|
var transform = new MatrixTransform
|
||||||
|
{
|
||||||
|
Matrix = MatrixEx.TranslateScaleRotateTranslate(viewCenter, scale, -parentMap.Heading, tileCenter)
|
||||||
|
};
|
||||||
|
|
||||||
|
var bounds = transform.TransformBounds(new Rect(0d, 0d, parentMap.RenderSize.Width, parentMap.RenderSize.Height));
|
||||||
|
|
||||||
|
return new TileGrid(tileZoomLevel,
|
||||||
|
(int)Math.Floor(bounds.X), (int)Math.Floor(bounds.Y),
|
||||||
|
(int)Math.Floor(bounds.X + bounds.Width), (int)Math.Floor(bounds.Y + bounds.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetRenderTransform()
|
||||||
|
{
|
||||||
|
var tileScale = (1 << TileGrid.ZoomLevel);
|
||||||
|
var scale = Math.Pow(2d, parentMap.ZoomLevel) / tileScale;
|
||||||
|
var tileCenter = GetTileCenter(tileScale);
|
||||||
|
var tileOrigin = new Point(TileSource.TileSize * (tileCenter.X - TileGrid.XMin), TileSource.TileSize * (tileCenter.Y - TileGrid.YMin));
|
||||||
|
var viewCenter = new Point(parentMap.RenderSize.Width / 2d, parentMap.RenderSize.Height / 2d);
|
||||||
|
|
||||||
|
((MatrixTransform)RenderTransform).Matrix =
|
||||||
|
MatrixEx.TranslateScaleRotateTranslate(tileOrigin, scale, parentMap.Heading, viewCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTiles(bool clearTiles)
|
||||||
{
|
{
|
||||||
if (Tiles.Count > 0)
|
if (Tiles.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -334,16 +402,16 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SelectTiles()
|
private void SelectTiles()
|
||||||
{
|
{
|
||||||
var newTiles = new List<Tile>();
|
var newTiles = new List<Tile>();
|
||||||
|
|
||||||
if (TileGrid != null && parentMap != null && TileSource != null)
|
if (parentMap != null && TileGrid != null && TileSource != null)
|
||||||
{
|
{
|
||||||
var maxZoomLevel = Math.Min(TileGrid.ZoomLevel, MaxZoomLevel);
|
var maxZoomLevel = Math.Min(TileGrid.ZoomLevel, MaxZoomLevel);
|
||||||
var minZoomLevel = MinZoomLevel;
|
var minZoomLevel = MinZoomLevel;
|
||||||
|
|
||||||
if (minZoomLevel < maxZoomLevel && this != parentMap.TileLayers.FirstOrDefault())
|
if (minZoomLevel < maxZoomLevel && this != parentMap.Children.Cast<UIElement>().FirstOrDefault())
|
||||||
{
|
{
|
||||||
// do not load background tiles if this is not the base layer
|
// do not load background tiles if this is not the base layer
|
||||||
minZoomLevel = maxZoomLevel;
|
minZoomLevel = maxZoomLevel;
|
||||||
|
|
@ -385,24 +453,5 @@ namespace MapControl
|
||||||
|
|
||||||
Tiles = newTiles;
|
Tiles = newTiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
|
||||||
{
|
|
||||||
if (TileGrid != null)
|
|
||||||
{
|
|
||||||
foreach (var tile in Tiles)
|
|
||||||
{
|
|
||||||
var tileSize = TileSource.TileSize << (TileGrid.ZoomLevel - tile.ZoomLevel);
|
|
||||||
var x = tileSize * tile.X - TileSource.TileSize * TileGrid.XMin;
|
|
||||||
var y = tileSize * tile.Y - TileSource.TileSize * TileGrid.YMin;
|
|
||||||
|
|
||||||
tile.Image.Width = tileSize;
|
|
||||||
tile.Image.Height = tileSize;
|
|
||||||
tile.Image.Arrange(new Rect(x, y, tileSize, tileSize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
#if NETFX_CORE
|
|
||||||
using System;
|
|
||||||
using Windows.Foundation;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines a normal cylindrical projection. Latitude and longitude values in degrees are
|
|
||||||
/// transformed to cartesian coordinates with origin at latitude = 0 and longitude = 0.
|
|
||||||
/// Longitude values are transformed identically to x values in the interval [-180 .. 180].
|
|
||||||
/// Latitude values in the interval [-MaxLatitude .. MaxLatitude] are transformed to y values in
|
|
||||||
/// the interval [-180 .. 180] according to the actual projection, e.g. the Mercator projection.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class MapTransform
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the absolute value of the minimum and maximum latitude that can be transformed.
|
|
||||||
/// </summary>
|
|
||||||
public abstract double MaxLatitude { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the scale factor of the map projection at the specified
|
|
||||||
/// geographic location relative to the scale at latitude zero.
|
|
||||||
/// </summary>
|
|
||||||
public abstract double RelativeScale(Location location);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms a geographic location to a cartesian coordinate point.
|
|
||||||
/// </summary>
|
|
||||||
public abstract Point Transform(Location location);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms a cartesian coordinate point to a geographic location.
|
|
||||||
/// </summary>
|
|
||||||
public abstract Location Transform(Point point);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms a geographic location by the specified translation in viewport coordinates.
|
|
||||||
/// </summary>
|
|
||||||
public Location Transform(Location origin, Point mapOrigin, Point translation)
|
|
||||||
{
|
|
||||||
#if NETFX_CORE
|
|
||||||
var latitudeTranslation = translation.Y / RelativeScale(origin);
|
|
||||||
|
|
||||||
if (Math.Abs(latitudeTranslation) < 1e-3) // avoid rounding errors
|
|
||||||
{
|
|
||||||
return new Location(origin.Latitude + latitudeTranslation, origin.Longitude + translation.X);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return Transform(new Point(mapOrigin.X + translation.X, mapOrigin.Y + translation.Y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -13,25 +15,43 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
internal static class MatrixEx
|
internal static class MatrixEx
|
||||||
{
|
{
|
||||||
public static Matrix Translate(this Matrix matrix, double offsetX, double offsetY)
|
/// <summary>
|
||||||
|
/// Used in MapProjection.
|
||||||
|
/// </summary>
|
||||||
|
public static Matrix TranslateScaleRotateTranslate(
|
||||||
|
Point translation1, double scaleX, double scaleY, double rotationAngle, Point translation2)
|
||||||
|
{
|
||||||
|
return new Matrix(1d, 0d, 0d, 1d, -translation1.X, -translation1.Y)
|
||||||
|
.Scale(scaleX, scaleY)
|
||||||
|
.Rotate(rotationAngle)
|
||||||
|
.Translate(translation2.X, translation2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in TileLayer.
|
||||||
|
/// </summary>
|
||||||
|
public static Matrix TranslateScaleRotateTranslate(
|
||||||
|
Point translation1, double scale, double rotationAngle, Point translation2)
|
||||||
|
{
|
||||||
|
return new Matrix(1d, 0d, 0d, 1d, -translation1.X, -translation1.Y)
|
||||||
|
.Scale(scale, scale)
|
||||||
|
.Rotate(rotationAngle)
|
||||||
|
.Translate(translation2.X, translation2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matrix Translate(this Matrix matrix, double offsetX, double offsetY)
|
||||||
{
|
{
|
||||||
matrix.OffsetX += offsetX;
|
matrix.OffsetX += offsetX;
|
||||||
matrix.OffsetY += offsetY;
|
matrix.OffsetY += offsetY;
|
||||||
|
|
||||||
return matrix;
|
return matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matrix TranslatePrepend(this Matrix matrix, double offsetX, double offsetY)
|
private static Matrix Scale(this Matrix matrix, double scaleX, double scaleY)
|
||||||
{
|
|
||||||
return new Matrix(1d, 0d, 0d, 1d, offsetX, offsetY).Multiply(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Matrix Scale(this Matrix matrix, double scaleX, double scaleY)
|
|
||||||
{
|
{
|
||||||
return Multiply(matrix, new Matrix(scaleX, 0d, 0d, scaleY, 0d, 0d));
|
return Multiply(matrix, new Matrix(scaleX, 0d, 0d, scaleY, 0d, 0d));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matrix Rotate(this Matrix matrix, double angle)
|
private static Matrix Rotate(this Matrix matrix, double angle)
|
||||||
{
|
{
|
||||||
if (angle == 0d)
|
if (angle == 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -45,23 +65,7 @@ namespace MapControl
|
||||||
return Multiply(matrix, new Matrix(cos, sin, -sin, cos, 0d, 0d));
|
return Multiply(matrix, new Matrix(cos, sin, -sin, cos, 0d, 0d));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matrix RotateAt(this Matrix matrix, double angle, double centerX, double centerY)
|
private static Matrix Invert(this Matrix matrix)
|
||||||
{
|
|
||||||
if (angle == 0d)
|
|
||||||
{
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
angle = (angle % 360d) / 180d * Math.PI;
|
|
||||||
var cos = Math.Cos(angle);
|
|
||||||
var sin = Math.Sin(angle);
|
|
||||||
var offsetX = centerX * (1d - cos) + centerY * sin;
|
|
||||||
var offsetY = centerY * (1d - cos) - centerX * sin;
|
|
||||||
|
|
||||||
return Multiply(matrix, new Matrix(cos, sin, -sin, cos, offsetX, offsetY));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Matrix Invert(this Matrix matrix)
|
|
||||||
{
|
{
|
||||||
var determinant = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21;
|
var determinant = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21;
|
||||||
|
|
||||||
|
|
@ -74,7 +78,7 @@ namespace MapControl
|
||||||
(matrix.M12 * matrix.OffsetX - matrix.M11 * matrix.OffsetY) / determinant);
|
(matrix.M12 * matrix.OffsetX - matrix.M11 * matrix.OffsetY) / determinant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matrix Multiply(this Matrix matrix1, Matrix matrix2)
|
private static Matrix Multiply(this Matrix matrix1, Matrix matrix2)
|
||||||
{
|
{
|
||||||
return new Matrix(
|
return new Matrix(
|
||||||
matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21,
|
matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21,
|
||||||
38
MapControl/MatrixEx.WPF.cs
Normal file
38
MapControl/MatrixEx.WPF.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2017 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
internal static class MatrixEx
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used in MapProjection.
|
||||||
|
/// </summary>
|
||||||
|
public static Matrix TranslateScaleRotateTranslate(
|
||||||
|
Point translation1, double scaleX, double scaleY, double rotationAngle, Point translation2)
|
||||||
|
{
|
||||||
|
var matrix = new Matrix(1d, 0d, 0d, 1d, -translation1.X, -translation1.Y);
|
||||||
|
matrix.Scale(scaleX, scaleY);
|
||||||
|
matrix.Rotate(rotationAngle);
|
||||||
|
matrix.Translate(translation2.X, translation2.Y);
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in TileLayer.
|
||||||
|
/// </summary>
|
||||||
|
public static Matrix TranslateScaleRotateTranslate(
|
||||||
|
Point translation1, double scale, double rotationAngle, Point translation2)
|
||||||
|
{
|
||||||
|
var matrix = new Matrix(1d, 0d, 0d, 1d, -translation1.X, -translation1.Y);
|
||||||
|
matrix.Scale(scale, scale);
|
||||||
|
matrix.Rotate(rotationAngle);
|
||||||
|
matrix.Translate(translation2.X, translation2.Y);
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms latitude and longitude values in degrees to cartesian coordinates
|
|
||||||
/// according to the Mercator projection.
|
|
||||||
/// </summary>
|
|
||||||
public class MercatorTransform : MapTransform
|
|
||||||
{
|
|
||||||
public static readonly double MaxLatitudeValue = YToLatitude(180d);
|
|
||||||
|
|
||||||
public static double RelativeScale(double latitude)
|
|
||||||
{
|
|
||||||
if (latitude <= -90d)
|
|
||||||
{
|
|
||||||
return double.NegativeInfinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (latitude >= 90d)
|
|
||||||
{
|
|
||||||
return double.PositiveInfinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1d / Math.Cos(latitude * Math.PI / 180d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double LatitudeToY(double latitude)
|
|
||||||
{
|
|
||||||
if (latitude <= -90d)
|
|
||||||
{
|
|
||||||
return double.NegativeInfinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (latitude >= 90d)
|
|
||||||
{
|
|
||||||
return double.PositiveInfinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.Log(Math.Tan((latitude + 90d) * Math.PI / 360d)) / Math.PI * 180d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double YToLatitude(double y)
|
|
||||||
{
|
|
||||||
return Math.Atan(Math.Exp(y * Math.PI / 180d)) / Math.PI * 360d - 90d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override double MaxLatitude
|
|
||||||
{
|
|
||||||
get { return MaxLatitudeValue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override double RelativeScale(Location location)
|
|
||||||
{
|
|
||||||
return RelativeScale(location.Latitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Point Transform(Location location)
|
|
||||||
{
|
|
||||||
return new Point(location.Longitude, LatitudeToY(location.Latitude));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Location Transform(Point point)
|
|
||||||
{
|
|
||||||
return new Location(YToLatitude(point.Y), point.X);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
74
MapControl/OrthographicProjection.cs
Normal file
74
MapControl/OrthographicProjection.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Orthographic Projection.
|
||||||
|
/// </summary>
|
||||||
|
public class OrthographicProjection : AzimuthalProjection
|
||||||
|
{
|
||||||
|
public OrthographicProjection()
|
||||||
|
: this("AUTO2:42003")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrthographicProjection(string crsId)
|
||||||
|
{
|
||||||
|
CrsId = crsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Point LocationToPoint(Location location)
|
||||||
|
{
|
||||||
|
if (location.Equals(projectionCenter))
|
||||||
|
{
|
||||||
|
return new Point();
|
||||||
|
}
|
||||||
|
|
||||||
|
var lat0 = projectionCenter.Latitude * Math.PI / 180d;
|
||||||
|
var lat = location.Latitude * Math.PI / 180d;
|
||||||
|
var dLon = (location.Longitude - projectionCenter.Longitude) * Math.PI / 180d;
|
||||||
|
|
||||||
|
return new Point(
|
||||||
|
Wgs84EquatorialRadius * Math.Cos(lat) * Math.Sin(dLon),
|
||||||
|
Wgs84EquatorialRadius * (Math.Cos(lat0) * Math.Sin(lat) - Math.Sin(lat0) * Math.Cos(lat) * Math.Cos(dLon)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Location PointToLocation(Point point)
|
||||||
|
{
|
||||||
|
if (point.X == 0d && point.Y == 0d)
|
||||||
|
{
|
||||||
|
return projectionCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = point.X / Wgs84EquatorialRadius;
|
||||||
|
var y = point.Y / Wgs84EquatorialRadius;
|
||||||
|
var r2 = x * x + y * y;
|
||||||
|
|
||||||
|
if (r2 > 1d)
|
||||||
|
{
|
||||||
|
return new Location(double.NaN, double.NaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = Math.Sqrt(r2);
|
||||||
|
var sinC = r;
|
||||||
|
var cosC = Math.Sqrt(1 - r2);
|
||||||
|
|
||||||
|
var lat0 = projectionCenter.Latitude * Math.PI / 180d;
|
||||||
|
var cosLat0 = Math.Cos(lat0);
|
||||||
|
var sinLat0 = Math.Sin(lat0);
|
||||||
|
|
||||||
|
return new Location(
|
||||||
|
180d / Math.PI * Math.Asin(cosC * sinLat0 + y * sinC * cosLat0 / r),
|
||||||
|
180d / Math.PI * Math.Atan2(x * sinC, r * cosC * cosLat0 - y * sinC * sinLat0) + projectionCenter.Longitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
#if NETFX_CORE
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Common base class for MapPanel and TileLayer.
|
|
||||||
/// </summary>
|
|
||||||
public class PanelBase : Panel
|
|
||||||
{
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
|
||||||
{
|
|
||||||
availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
|
||||||
|
|
||||||
foreach (UIElement element in Children)
|
|
||||||
{
|
|
||||||
element.Measure(availableSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Size();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
|
||||||
{
|
|
||||||
foreach (UIElement element in Children)
|
|
||||||
{
|
|
||||||
element.Arrange(new Rect(new Point(), finalSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,10 +12,10 @@ using System.Windows;
|
||||||
#endif
|
#endif
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -14,8 +14,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
static Pushpin()
|
static Pushpin()
|
||||||
{
|
{
|
||||||
DefaultStyleKeyProperty.OverrideMetadata(
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(Pushpin), new FrameworkPropertyMetadata(typeof(Pushpin)));
|
||||||
typeof(Pushpin), new FrameworkPropertyMetadata(typeof(Pushpin)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty LocationProperty =
|
public static readonly DependencyProperty LocationProperty =
|
||||||
|
|
|
||||||
59
MapControl/StereographicProjection.cs
Normal file
59
MapControl/StereographicProjection.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Gnomonic Projection.
|
||||||
|
/// </summary>
|
||||||
|
public class StereographicProjection : AzimuthalProjection
|
||||||
|
{
|
||||||
|
public StereographicProjection()
|
||||||
|
: this("AUTO2:97002") // GeoServer non-standard CRS ID
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StereographicProjection(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 = 2d * Wgs84EquatorialRadius * Math.Tan(distance / 2d);
|
||||||
|
|
||||||
|
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 = 2d * Math.Atan(mapDistance / (2d * Wgs84EquatorialRadius));
|
||||||
|
|
||||||
|
return GetLocation(projectionCenter, azimuth, distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -13,12 +13,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
public static TimeSpan FadeDuration { get; set; }
|
public static TimeSpan FadeDuration { get; set; } = TimeSpan.FromSeconds(0.2);
|
||||||
|
|
||||||
static Tile()
|
|
||||||
{
|
|
||||||
FadeDuration = TimeSpan.FromSeconds(0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly int ZoomLevel;
|
public readonly int ZoomLevel;
|
||||||
public readonly int X;
|
public readonly int X;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -15,7 +15,7 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class TileImageLoader : ITileImageLoader
|
internal class TileImageLoader : ITileImageLoader
|
||||||
{
|
{
|
||||||
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
|
public void BeginLoadTiles(MapTileLayer tileLayer, IEnumerable<Tile> tiles)
|
||||||
{
|
{
|
||||||
var imageTileSource = tileLayer.TileSource as ImageTileSource;
|
var imageTileSource = tileLayer.TileSource as ImageTileSource;
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelLoadTiles(TileLayer tileLayer)
|
public void CancelLoadTiles(MapTileLayer tileLayer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -78,7 +78,7 @@ namespace MapControl
|
||||||
private readonly ConcurrentQueue<PendingTile> pendingTiles = new ConcurrentQueue<PendingTile>();
|
private readonly ConcurrentQueue<PendingTile> pendingTiles = new ConcurrentQueue<PendingTile>();
|
||||||
private int taskCount;
|
private int taskCount;
|
||||||
|
|
||||||
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
|
public void BeginLoadTiles(MapTileLayer tileLayer, IEnumerable<Tile> tiles)
|
||||||
{
|
{
|
||||||
if (tiles.Any())
|
if (tiles.Any())
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +105,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelLoadTiles(TileLayer tileLayer)
|
public void CancelLoadTiles(MapTileLayer tileLayer)
|
||||||
{
|
{
|
||||||
PendingTile pendingTile;
|
PendingTile pendingTile;
|
||||||
|
|
||||||
|
|
@ -211,7 +211,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
{
|
{
|
||||||
image = ImageLoader.FromStream(fileStream);
|
image = BitmapSourceHelper.FromStream(fileStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -245,7 +245,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
responseStream.CopyTo(memoryStream);
|
responseStream.CopyTo(memoryStream);
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
image = ImageLoader.FromStream(memoryStream);
|
image = BitmapSourceHelper.FromStream(memoryStream);
|
||||||
|
|
||||||
if (cacheKey != null)
|
if (cacheKey != null)
|
||||||
{
|
{
|
||||||
|
|
@ -284,7 +284,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
using (var memoryStream = new MemoryStream(buffer))
|
using (var memoryStream = new MemoryStream(buffer))
|
||||||
{
|
{
|
||||||
image = ImageLoader.FromStream(memoryStream);
|
image = BitmapSourceHelper.FromStream(memoryStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime expiration = DateTime.MinValue;
|
DateTime expiration = DateTime.MinValue;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -71,7 +71,7 @@ namespace MapControl
|
||||||
private readonly ConcurrentQueue<PendingTile> pendingTiles = new ConcurrentQueue<PendingTile>();
|
private readonly ConcurrentQueue<PendingTile> pendingTiles = new ConcurrentQueue<PendingTile>();
|
||||||
private int taskCount;
|
private int taskCount;
|
||||||
|
|
||||||
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
|
public void BeginLoadTiles(MapTileLayer tileLayer, IEnumerable<Tile> tiles)
|
||||||
{
|
{
|
||||||
var tileSource = tileLayer.TileSource;
|
var tileSource = tileLayer.TileSource;
|
||||||
var imageTileSource = tileSource as ImageTileSource;
|
var imageTileSource = tileSource as ImageTileSource;
|
||||||
|
|
@ -127,7 +127,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelLoadTiles(TileLayer tileLayer)
|
public void CancelLoadTiles(MapTileLayer tileLayer)
|
||||||
{
|
{
|
||||||
PendingTile pendingTile;
|
PendingTile pendingTile;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
#if NETFX_CORE
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileLayer
|
|
||||||
{
|
|
||||||
partial void Initialize()
|
|
||||||
{
|
|
||||||
IsHitTestVisible = false;
|
|
||||||
|
|
||||||
MapPanel.AddParentMapHandlers(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rect GetTileIndexBounds(int zoomLevel)
|
|
||||||
{
|
|
||||||
var scale = (1 << zoomLevel) / 360d;
|
|
||||||
var transform = new MatrixTransform
|
|
||||||
{
|
|
||||||
Matrix = parentMap.ViewportTransform.Matrix
|
|
||||||
.Invert() // view to map coordinates
|
|
||||||
.Translate(180d, -180d)
|
|
||||||
.Scale(scale, -scale) // map coordinates to tile indices
|
|
||||||
};
|
|
||||||
|
|
||||||
return transform.TransformBounds(new Rect(new Point(), parentMap.RenderSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetRenderTransform()
|
|
||||||
{
|
|
||||||
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileGrid.ZoomLevel);
|
|
||||||
var offsetX = parentMap.ViewportOrigin.X - (180d + parentMap.MapOrigin.X) * parentMap.ViewportScale;
|
|
||||||
var offsetY = parentMap.ViewportOrigin.Y - (180d - parentMap.MapOrigin.Y) * parentMap.ViewportScale;
|
|
||||||
|
|
||||||
((MatrixTransform)RenderTransform).Matrix =
|
|
||||||
new Matrix(1d, 0d, 0d, 1d, TileSource.TileSize * TileGrid.XMin, TileSource.TileSize * TileGrid.YMin)
|
|
||||||
.Scale(scale, scale)
|
|
||||||
.Translate(offsetX, offsetY)
|
|
||||||
.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileLayer
|
|
||||||
{
|
|
||||||
static TileLayer()
|
|
||||||
{
|
|
||||||
IsHitTestVisibleProperty.OverrideMetadata(
|
|
||||||
typeof(TileLayer), new FrameworkPropertyMetadata(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rect GetTileIndexBounds(int zoomLevel)
|
|
||||||
{
|
|
||||||
var scale = (1 << zoomLevel) / 360d;
|
|
||||||
var transform = parentMap.ViewportTransform.Matrix;
|
|
||||||
|
|
||||||
transform.Invert(); // view to map coordinates
|
|
||||||
transform.Translate(180d, -180d);
|
|
||||||
transform.Scale(scale, -scale); // map coordinates to tile indices
|
|
||||||
|
|
||||||
return new MatrixTransform(transform).TransformBounds(new Rect(parentMap.RenderSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetRenderTransform()
|
|
||||||
{
|
|
||||||
var scale = Math.Pow(2d, parentMap.ZoomLevel - TileGrid.ZoomLevel);
|
|
||||||
var offsetX = parentMap.ViewportOrigin.X - (180d + parentMap.MapOrigin.X) * parentMap.ViewportScale;
|
|
||||||
var offsetY = parentMap.ViewportOrigin.Y - (180d - parentMap.MapOrigin.Y) * parentMap.ViewportScale;
|
|
||||||
|
|
||||||
var transform = new Matrix(1d, 0d, 0d, 1d, TileSource.TileSize * TileGrid.XMin, TileSource.TileSize * TileGrid.YMin);
|
|
||||||
transform.Scale(scale, scale);
|
|
||||||
transform.Translate(offsetX, offsetY);
|
|
||||||
transform.RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y);
|
|
||||||
|
|
||||||
((MatrixTransform)RenderTransform).Matrix = transform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
|
||||||
// © 2016 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A collection of TileLayers with a string indexer that allows
|
|
||||||
/// to retrieve individual TileLayers by their SourceName property.
|
|
||||||
/// </summary>
|
|
||||||
public class TileLayerCollection : Collection<TileLayer>
|
|
||||||
{
|
|
||||||
public TileLayer this[string sourceName]
|
|
||||||
{
|
|
||||||
get { return this.FirstOrDefault(t => t.SourceName == sourceName); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -13,7 +13,6 @@ namespace MapControl
|
||||||
public partial class TileSource
|
public partial class TileSource
|
||||||
{
|
{
|
||||||
public const int TileSize = 256;
|
public const int TileSize = 256;
|
||||||
public const double MetersPerDegree = 6378137d * Math.PI / 180d; // WGS 84 semi major axis
|
|
||||||
|
|
||||||
private Func<int, int, int, Uri> getUri;
|
private Func<int, int, int, Uri> getUri;
|
||||||
private string uriFormat = string.Empty;
|
private string uriFormat = string.Empty;
|
||||||
|
|
@ -58,6 +57,10 @@ namespace MapControl
|
||||||
getUri = GetBasicUri;
|
getUri = GetBasicUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (uriFormat.Contains("{x}") && uriFormat.Contains("{v}") && uriFormat.Contains("{z}"))
|
||||||
|
{
|
||||||
|
getUri = GetTmsUri;
|
||||||
|
}
|
||||||
else if (uriFormat.Contains("{q}")) // {i} is optional
|
else if (uriFormat.Contains("{q}")) // {i} is optional
|
||||||
{
|
{
|
||||||
getUri = GetQuadKeyUri;
|
getUri = GetQuadKeyUri;
|
||||||
|
|
@ -70,10 +73,6 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
getUri = GetLatLonBoundingBoxUri;
|
getUri = GetLatLonBoundingBoxUri;
|
||||||
}
|
}
|
||||||
else if (uriFormat.Contains("{x}") && uriFormat.Contains("{v}") && uriFormat.Contains("{z}"))
|
|
||||||
{
|
|
||||||
getUri = GetTmsUri;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,10 +160,10 @@ namespace MapControl
|
||||||
private Uri GetBoundingBoxUri(int x, int y, int zoomLevel)
|
private Uri GetBoundingBoxUri(int x, int y, int zoomLevel)
|
||||||
{
|
{
|
||||||
var tileSize = 360d / (1 << zoomLevel); // tile width in degrees
|
var tileSize = 360d / (1 << zoomLevel); // tile width in degrees
|
||||||
var west = MetersPerDegree * (x * tileSize - 180d);
|
var west = MapProjection.MetersPerDegree * (x * tileSize - 180d);
|
||||||
var east = MetersPerDegree * ((x + 1) * tileSize - 180d);
|
var east = MapProjection.MetersPerDegree * ((x + 1) * tileSize - 180d);
|
||||||
var south = MetersPerDegree * (180d - (y + 1) * tileSize);
|
var south = MapProjection.MetersPerDegree * (180d - (y + 1) * tileSize);
|
||||||
var north = MetersPerDegree * (180d - y * tileSize);
|
var north = MapProjection.MetersPerDegree * (180d - y * tileSize);
|
||||||
|
|
||||||
return new Uri(uriFormat
|
return new Uri(uriFormat
|
||||||
.Replace("{W}", west.ToString(CultureInfo.InvariantCulture))
|
.Replace("{W}", west.ToString(CultureInfo.InvariantCulture))
|
||||||
|
|
@ -180,8 +179,8 @@ namespace MapControl
|
||||||
var tileSize = 360d / (1 << zoomLevel); // tile width in degrees
|
var tileSize = 360d / (1 << zoomLevel); // tile width in degrees
|
||||||
var west = x * tileSize - 180d;
|
var west = x * tileSize - 180d;
|
||||||
var east = (x + 1) * tileSize - 180d;
|
var east = (x + 1) * tileSize - 180d;
|
||||||
var south = MercatorTransform.YToLatitude(180d - (y + 1) * tileSize);
|
var south = WebMercatorProjection.YToLatitude(180d - (y + 1) * tileSize);
|
||||||
var north = MercatorTransform.YToLatitude(180d - y * tileSize);
|
var north = WebMercatorProjection.YToLatitude(180d - y * tileSize);
|
||||||
|
|
||||||
return new Uri(uriFormat
|
return new Uri(uriFormat
|
||||||
.Replace("{w}", west.ToString(CultureInfo.InvariantCulture))
|
.Replace("{w}", west.ToString(CultureInfo.InvariantCulture))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2017 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
|
@ -8,15 +8,22 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public class ViewportChangedEventArgs : EventArgs
|
public class ViewportChangedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public ViewportChangedEventArgs(double originOffset)
|
public ViewportChangedEventArgs(bool projectionChanged = false, double longitudeOffset = 0d)
|
||||||
{
|
{
|
||||||
OriginOffset = originOffset;
|
ProjectionChanged = projectionChanged;
|
||||||
|
LongitudeOffset = longitudeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Offset of the X value of the map coordinate origin from the previous viewport.
|
/// Indicates if the map projection has changed, i.e. if a TileLayer or ImageLayer should be
|
||||||
|
/// immediately updated, or MapPath Data in cartesian map coordinates should be recalculated.
|
||||||
|
/// </summary>
|
||||||
|
public bool ProjectionChanged { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset of the map center longitude value from the previous viewport.
|
||||||
/// Used to detect if the map center has moved across 180° longitude.
|
/// Used to detect if the map center has moved across 180° longitude.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double OriginOffset { get; }
|
public double LongitudeOffset { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
83
MapControl/WebMercatorProjection.cs
Normal file
83
MapControl/WebMercatorProjection.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms map coordinates according to the Web Mercator Projection.
|
||||||
|
/// Longitude values are transformed linearly to X values in meters, by multiplying with MetersPerDegree.
|
||||||
|
/// Latitude values in the interval [-MaxLatitude .. MaxLatitude] are transformed to Y values in meters
|
||||||
|
/// in the interval [-R*pi .. R*pi], R=Wgs84EquatorialRadius.
|
||||||
|
/// </summary>
|
||||||
|
public class WebMercatorProjection : MapProjection
|
||||||
|
{
|
||||||
|
public WebMercatorProjection()
|
||||||
|
: this("EPSG:3857")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebMercatorProjection(string crsId)
|
||||||
|
{
|
||||||
|
CrsId = crsId;
|
||||||
|
IsWebMercator = true;
|
||||||
|
LongitudeScale = MetersPerDegree;
|
||||||
|
MaxLatitude = YToLatitude(180d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetViewportScale(double zoomLevel)
|
||||||
|
{
|
||||||
|
return base.GetViewportScale(zoomLevel) / MetersPerDegree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Point GetMapScale(Location location)
|
||||||
|
{
|
||||||
|
var scale = ViewportScale / Math.Cos(location.Latitude * Math.PI / 180d);
|
||||||
|
|
||||||
|
return new Point(scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Point LocationToPoint(Location location)
|
||||||
|
{
|
||||||
|
return new Point(
|
||||||
|
MetersPerDegree * location.Longitude,
|
||||||
|
MetersPerDegree * LatitudeToY(location.Latitude));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Location PointToLocation(Point point)
|
||||||
|
{
|
||||||
|
return new Location(
|
||||||
|
YToLatitude(point.Y / MetersPerDegree),
|
||||||
|
point.X / MetersPerDegree);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Location TranslateLocation(Location location, Point translation)
|
||||||
|
{
|
||||||
|
var scaleX = MetersPerDegree * ViewportScale;
|
||||||
|
var scaleY = scaleX / Math.Cos(location.Latitude * Math.PI / 180d);
|
||||||
|
|
||||||
|
return new Location(
|
||||||
|
location.Latitude - translation.Y / scaleY,
|
||||||
|
location.Longitude + translation.X / scaleX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double LatitudeToY(double latitude)
|
||||||
|
{
|
||||||
|
return latitude <= -90d ? double.NegativeInfinity
|
||||||
|
: latitude >= 90d ? double.PositiveInfinity
|
||||||
|
: Math.Log(Math.Tan((latitude + 90d) * Math.PI / 360d)) / Math.PI * 180d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double YToLatitude(double y)
|
||||||
|
{
|
||||||
|
return Math.Atan(Math.Exp(y * Math.PI / 180d)) / Math.PI * 360d - 90d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -36,15 +36,33 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\AzimuthalEquidistantProjection.cs">
|
||||||
|
<Link>AzimuthalEquidistantProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\AzimuthalProjection.cs">
|
||||||
|
<Link>AzimuthalProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\BingMapsTileLayer.cs">
|
<Compile Include="..\BingMapsTileLayer.cs">
|
||||||
<Link>BingMapsTileLayer.cs</Link>
|
<Link>BingMapsTileLayer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\BingMapsTileSource.cs">
|
<Compile Include="..\BingMapsTileSource.cs">
|
||||||
<Link>BingMapsTileSource.cs</Link>
|
<Link>BingMapsTileSource.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\BoundingBox.cs">
|
||||||
|
<Link>BoundingBox.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\CenteredBoundingBox.cs">
|
||||||
|
<Link>CenteredBoundingBox.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\EquirectangularProjection.cs">
|
||||||
|
<Link>EquirectangularProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Extensions.WinRT.cs">
|
<Compile Include="..\Extensions.WinRT.cs">
|
||||||
<Link>Extensions.WinRT.cs</Link>
|
<Link>Extensions.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\GnomonicProjection.cs">
|
||||||
|
<Link>GnomonicProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\HyperlinkText.cs">
|
<Compile Include="..\HyperlinkText.cs">
|
||||||
<Link>HyperlinkText.cs</Link>
|
<Link>HyperlinkText.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -54,12 +72,6 @@
|
||||||
<Compile Include="..\ImageTileSource.Silverlight.WinRT.cs">
|
<Compile Include="..\ImageTileSource.Silverlight.WinRT.cs">
|
||||||
<Link>ImageTileSource.Silverlight.WinRT.cs</Link>
|
<Link>ImageTileSource.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\IMapElement.cs">
|
|
||||||
<Link>IMapElement.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\ITileImageLoader.cs">
|
|
||||||
<Link>ITileImageLoader.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Location.cs">
|
<Compile Include="..\Location.cs">
|
||||||
<Link>Location.cs</Link>
|
<Link>Location.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -81,9 +93,6 @@
|
||||||
<Compile Include="..\MapGraticule.Silverlight.WinRT.cs">
|
<Compile Include="..\MapGraticule.Silverlight.WinRT.cs">
|
||||||
<Link>MapGraticule.Silverlight.WinRT.cs</Link>
|
<Link>MapGraticule.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\MapImage.cs">
|
|
||||||
<Link>MapImage.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\MapImageLayer.cs">
|
<Compile Include="..\MapImageLayer.cs">
|
||||||
<Link>MapImageLayer.cs</Link>
|
<Link>MapImageLayer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -120,24 +129,27 @@
|
||||||
<Compile Include="..\MapPolyline.Silverlight.WinRT.cs">
|
<Compile Include="..\MapPolyline.Silverlight.WinRT.cs">
|
||||||
<Link>MapPolyline.Silverlight.WinRT.cs</Link>
|
<Link>MapPolyline.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\MapRectangle.cs">
|
<Compile Include="..\MapProjection.cs">
|
||||||
<Link>MapRectangle.cs</Link>
|
<Link>MapProjection.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\MapTransform.cs">
|
<Compile Include="..\MapTileLayer.cs">
|
||||||
<Link>MapTransform.cs</Link>
|
<Link>MapTileLayer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\MatrixEx.cs">
|
<Compile Include="..\MapTileLayer.Silverlight.WinRT.cs">
|
||||||
<Link>MatrixEx.cs</Link>
|
<Link>MapTileLayer.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\MercatorTransform.cs">
|
<Compile Include="..\MatrixEx.Silverlight.WinRT.cs">
|
||||||
<Link>MercatorTransform.cs</Link>
|
<Link>MatrixEx.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\PanelBase.cs">
|
<Compile Include="..\OrthographicProjection.cs">
|
||||||
<Link>PanelBase.cs</Link>
|
<Link>OrthographicProjection.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\Pushpin.Silverlight.WinRT.cs">
|
<Compile Include="..\Pushpin.Silverlight.WinRT.cs">
|
||||||
<Link>Pushpin.Silverlight.WinRT.cs</Link>
|
<Link>Pushpin.Silverlight.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\StereographicProjection.cs">
|
||||||
|
<Link>StereographicProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Tile.cs">
|
<Compile Include="..\Tile.cs">
|
||||||
<Link>Tile.cs</Link>
|
<Link>Tile.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -150,26 +162,20 @@
|
||||||
<Compile Include="..\TileImageLoader.WinRT.cs">
|
<Compile Include="..\TileImageLoader.WinRT.cs">
|
||||||
<Link>TileImageLoader.WinRT.cs</Link>
|
<Link>TileImageLoader.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\TileLayer.cs">
|
|
||||||
<Link>TileLayer.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\TileLayer.Silverlight.WinRT.cs">
|
|
||||||
<Link>TileLayer.Silverlight.WinRT.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\TileLayerCollection.cs">
|
|
||||||
<Link>TileLayerCollection.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\TileSource.cs">
|
<Compile Include="..\TileSource.cs">
|
||||||
<Link>TileSource.cs</Link>
|
<Link>TileSource.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\ViewportChangedEventArgs.cs">
|
<Compile Include="..\ViewportChangedEventArgs.cs">
|
||||||
<Link>ViewportChangedEventArgs.cs</Link>
|
<Link>ViewportChangedEventArgs.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\WebMercatorProjection.cs">
|
||||||
|
<Link>WebMercatorProjection.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\WmsImageLayer.cs">
|
<Compile Include="..\WmsImageLayer.cs">
|
||||||
<Link>WmsImageLayer.cs</Link>
|
<Link>WmsImageLayer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\WmsImageLayer.WinRT.cs">
|
<Compile Include="..\WmsLayers.WPF.WinRT.cs">
|
||||||
<Link>WmsImageLayer.WinRT.cs</Link>
|
<Link>WmsLayers.WPF.WinRT.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyDescription("XAML Map Control Library for Windows Runtime")]
|
[assembly: AssemblyDescription("XAML Map Control Library for Windows Runtime")]
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
[assembly: AssemblyProduct("XAML Map Control")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2016 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.14.0")]
|
[assembly: AssemblyVersion("3.1.0")]
|
||||||
[assembly: AssemblyFileVersion("2.14.0")]
|
[assembly: AssemblyFileVersion("3.1.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
|
|
@ -9,10 +10,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class WmsImageLayer
|
public partial class WmsImageLayer
|
||||||
{
|
{
|
||||||
private static async Task<XmlDocument> LoadDocument(string requestUri)
|
private static async Task<XmlDocument> LoadDocument(Uri requestUri)
|
||||||
{
|
{
|
||||||
var document = new XmlDocument();
|
var document = new XmlDocument();
|
||||||
await Task.Run(() => document.Load(requestUri));
|
await Task.Run(() => document.Load(requestUri.ToString()));
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -10,9 +10,9 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class WmsImageLayer
|
public partial class WmsImageLayer
|
||||||
{
|
{
|
||||||
private static async Task<XmlDocument> LoadDocument(string requestUri)
|
private static async Task<XmlDocument> LoadDocument(Uri requestUri)
|
||||||
{
|
{
|
||||||
return await XmlDocument.LoadFromUriAsync(new Uri(requestUri));
|
return await XmlDocument.LoadFromUriAsync(requestUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,58 @@
|
||||||
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
// © 2016 Clemens Fischer
|
// © 2017 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
using Windows.Data.Xml.Dom;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Xml;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class WmsImageLayer : MapImageLayer
|
public partial class WmsImageLayer : MapImageLayer
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty BaseUriProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ServerUriProperty = DependencyProperty.Register(
|
||||||
"ServerUri", typeof(string), typeof(WmsImageLayer),
|
nameof(ServerUri), typeof(Uri), typeof(WmsImageLayer),
|
||||||
new PropertyMetadata(null, async (o, e) => await ((WmsImageLayer)o).UpdateUriFormat(true)));
|
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty VersionProperty = DependencyProperty.Register(
|
||||||
|
nameof(Version), typeof(string), typeof(WmsImageLayer),
|
||||||
|
new PropertyMetadata("1.3.0", (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
public static readonly DependencyProperty LayersProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LayersProperty = DependencyProperty.Register(
|
||||||
"Layers", typeof(string), typeof(WmsImageLayer),
|
nameof(Layers), typeof(string), typeof(WmsImageLayer),
|
||||||
new PropertyMetadata(null, async (o, e) => await ((WmsImageLayer)o).UpdateUriFormat()));
|
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty StylesProperty = DependencyProperty.Register(
|
||||||
|
nameof(Styles), typeof(string), typeof(WmsImageLayer),
|
||||||
|
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
public static readonly DependencyProperty ParametersProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ParametersProperty = DependencyProperty.Register(
|
||||||
"Parameters", typeof(string), typeof(WmsImageLayer),
|
nameof(Parameters), typeof(string), typeof(WmsImageLayer),
|
||||||
new PropertyMetadata(null, async (o, e) => await ((WmsImageLayer)o).UpdateUriFormat()));
|
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register(
|
||||||
|
nameof(Format), typeof(string), typeof(WmsImageLayer),
|
||||||
|
new PropertyMetadata("image/png", (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
public static readonly DependencyProperty TransparentProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TransparentProperty = DependencyProperty.Register(
|
||||||
"Transparent", typeof(bool), typeof(WmsImageLayer),
|
nameof(Transparent), typeof(bool), typeof(WmsImageLayer),
|
||||||
new PropertyMetadata(false, async (o, e) => await ((WmsImageLayer)o).UpdateUriFormat()));
|
new PropertyMetadata(false, (o, e) => ((WmsImageLayer)o).UpdateImage()));
|
||||||
|
|
||||||
public string ServerUri
|
private string layers = string.Empty;
|
||||||
|
|
||||||
|
public Uri ServerUri
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(BaseUriProperty); }
|
get { return (Uri)GetValue(ServerUriProperty); }
|
||||||
set { SetValue(BaseUriProperty, value); }
|
set { SetValue(ServerUriProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(VersionProperty); }
|
||||||
|
set { SetValue(VersionProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Layers
|
public string Layers
|
||||||
|
|
@ -47,106 +61,63 @@ namespace MapControl
|
||||||
set { SetValue(LayersProperty, value); }
|
set { SetValue(LayersProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Styles
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(StylesProperty); }
|
||||||
|
set { SetValue(StylesProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
public string Parameters
|
public string Parameters
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(ParametersProperty); }
|
get { return (string)GetValue(ParametersProperty); }
|
||||||
set { SetValue(ParametersProperty, value); }
|
set { SetValue(ParametersProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Format
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(FormatProperty); }
|
||||||
|
set { SetValue(FormatProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
public bool Transparent
|
public bool Transparent
|
||||||
{
|
{
|
||||||
get { return (bool)GetValue(TransparentProperty); }
|
get { return (bool)GetValue(TransparentProperty); }
|
||||||
set { SetValue(TransparentProperty, value); }
|
set { SetValue(TransparentProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<string>> GetAllLayers()
|
protected override bool UpdateImage(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var layers = new List<string>();
|
if (ServerUri == null)
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ServerUri))
|
|
||||||
{
|
{
|
||||||
try
|
return false;
|
||||||
{
|
|
||||||
var document = await LoadDocument(ServerUri
|
|
||||||
+ "?SERVICE=WMS"
|
|
||||||
+ "&VERSION=1.3.0"
|
|
||||||
+ "&REQUEST=GetCapabilities");
|
|
||||||
|
|
||||||
var capability = FirstChild(document.DocumentElement, "Capability");
|
|
||||||
if (capability != null)
|
|
||||||
{
|
|
||||||
var rootLayer = FirstChild(capability, "Layer");
|
|
||||||
if (rootLayer != null)
|
|
||||||
{
|
|
||||||
foreach (var layer in ChildElements(rootLayer, "Layer"))
|
|
||||||
{
|
|
||||||
var name = FirstChild(layer, "Name");
|
|
||||||
if (name != null)
|
|
||||||
{
|
|
||||||
layers.Add(name.InnerText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Debug.WriteLine(e.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return layers;
|
var version = Version ?? "1.3.0";
|
||||||
}
|
var queryParameters = ParentMap.MapProjection.WmsQueryParameters(boundingBox, version);
|
||||||
|
|
||||||
private string allLayers;
|
if (string.IsNullOrEmpty(queryParameters))
|
||||||
|
|
||||||
private async Task UpdateUriFormat(bool baseUriChanged = false)
|
|
||||||
{
|
|
||||||
if (baseUriChanged)
|
|
||||||
{
|
{
|
||||||
allLayers = null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string uriFormat = null;
|
var query = "?SERVICE=WMS"
|
||||||
var layers = Layers;
|
+ "&VERSION=" + version
|
||||||
|
+ "&REQUEST=GetMap"
|
||||||
|
+ "&LAYERS=" + (Layers ?? string.Empty)
|
||||||
|
+ "&STYLES=" + (Styles ?? string.Empty)
|
||||||
|
+ "&" + queryParameters
|
||||||
|
+ "&FORMAT=" + (Format ?? "image/png")
|
||||||
|
+ "&TRANSPARENT=" + (Transparent ? "TRUE" : "FALSE");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ServerUri) && !string.IsNullOrEmpty(layers))
|
if (!string.IsNullOrEmpty(Parameters))
|
||||||
{
|
{
|
||||||
if (layers == "*")
|
query += "&" + Parameters;
|
||||||
{
|
|
||||||
layers = allLayers ?? (allLayers = string.Join(",", await GetAllLayers()));
|
|
||||||
}
|
|
||||||
|
|
||||||
uriFormat = ServerUri
|
|
||||||
+ "?SERVICE=WMS"
|
|
||||||
+ "&VERSION=1.3.0"
|
|
||||||
+ "&REQUEST=GetMap"
|
|
||||||
+ "&LAYERS=" + layers.Replace(" ", "%20")
|
|
||||||
+ "&STYLES="
|
|
||||||
+ "&CRS=EPSG:3857"
|
|
||||||
+ "&BBOX={W},{S},{E},{N}"
|
|
||||||
+ "&WIDTH={X}"
|
|
||||||
+ "&HEIGHT={Y}"
|
|
||||||
+ "&FORMAT=image/png"
|
|
||||||
+ "&TRANSPARENT=" + (Transparent ? "TRUE" : "FALSE");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Parameters))
|
|
||||||
{
|
|
||||||
uriFormat += "&" + Parameters;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UriFormat = uriFormat;
|
var uri = new Uri(ServerUri, query.Replace(" ", "%20"));
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<XmlElement> ChildElements(XmlElement element, string name)
|
UpdateImage(uri);
|
||||||
{
|
return true;
|
||||||
return element.ChildNodes.OfType<XmlElement>().Where(e => (string)e.LocalName == name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static XmlElement FirstChild(XmlElement element, string name)
|
|
||||||
{
|
|
||||||
return element.ChildNodes.OfType<XmlElement>().FirstOrDefault(e => (string)e.LocalName == name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
MapControl/WmsLayers.WPF.WinRT.cs
Normal file
77
MapControl/WmsLayers.WPF.WinRT.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
#if NETFX_CORE
|
||||||
|
using Windows.Data.Xml.Dom;
|
||||||
|
#else
|
||||||
|
using System.Xml;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
public static class WmsLayers
|
||||||
|
{
|
||||||
|
public static async Task<List<string>> GetAllLayers(Uri serverUri)
|
||||||
|
{
|
||||||
|
var allLayers = new List<string>();
|
||||||
|
|
||||||
|
if (serverUri != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var document = await LoadDocument(new Uri(serverUri, "?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities"));
|
||||||
|
|
||||||
|
var capability = FirstChild(document.DocumentElement, "Capability");
|
||||||
|
if (capability != null)
|
||||||
|
{
|
||||||
|
var rootLayer = FirstChild(capability, "Layer");
|
||||||
|
if (rootLayer != null)
|
||||||
|
{
|
||||||
|
foreach (var layer in ChildElements(rootLayer, "Layer"))
|
||||||
|
{
|
||||||
|
var name = FirstChild(layer, "Name");
|
||||||
|
if (name != null)
|
||||||
|
{
|
||||||
|
allLayers.Add(name.InnerText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<XmlElement> ChildElements(XmlElement element, string name)
|
||||||
|
{
|
||||||
|
return element.ChildNodes.OfType<XmlElement>().Where(e => (string)e.LocalName == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XmlElement FirstChild(XmlElement element, string name)
|
||||||
|
{
|
||||||
|
return element.ChildNodes.OfType<XmlElement>().FirstOrDefault(e => (string)e.LocalName == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<XmlDocument> LoadDocument(Uri requestUri)
|
||||||
|
{
|
||||||
|
#if NETFX_CORE
|
||||||
|
return await XmlDocument.LoadFromUriAsync(requestUri);
|
||||||
|
#else
|
||||||
|
var document = new XmlDocument();
|
||||||
|
await Task.Run(() => document.Load(requestUri.ToString()));
|
||||||
|
return document;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue