mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Version 5.0: Reworked MapBase and MapPath
This commit is contained in:
parent
06fd31c17b
commit
49e15ce424
|
|
@ -7,16 +7,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapControl", "MapControl",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{8F2103C2-78AF-4810-8FB9-67572F50C8FC}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{8F2103C2-78AF-4810-8FB9-67572F50C8FC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.UWP", "MapControl\UWP\MapControl.UWP.csproj", "{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.UWP", "MapControl\UWP\MapControl.UWP.csproj", "{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfCoreApp", "SampleApps\WpfCoreApp\WpfCoreApp.csproj", "{E9D15B9A-75F5-40A9-A582-9BFBB074C127}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapControl.WPF", "MapControl\WPF\MapControl.WPF.csproj", "{62F1726B-3144-49F4-8BCC-94160A3B2186}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapControl.WPF", "MapControl\WPF\MapControl.WPF.csproj", "{62F1726B-3144-49F4-8BCC-94160A3B2186}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -29,22 +27,6 @@ Global
|
||||||
Release|x86 = Release|x86
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|x64
|
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Build.0 = Debug|x64
|
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Build.0 = Debug|x64
|
||||||
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Deploy.0 = Debug|x64
|
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Deploy.0 = Debug|x64
|
||||||
|
|
@ -85,22 +67,6 @@ Global
|
||||||
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x64.Build.0 = Release|Any CPU
|
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.ActiveCfg = Release|Any CPU
|
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.Build.0 = Release|Any CPU
|
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
|
@ -117,16 +83,31 @@ Global
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x64.Build.0 = Release|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.ActiveCfg = Release|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.Build.0 = Release|Any CPU
|
{62F1726B-3144-49F4-8BCC-94160A3B2186}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
|
||||||
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
||||||
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344} = {52AECE49-F314-4F76-98F2-FA800F07824B}
|
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344} = {52AECE49-F314-4F76-98F2-FA800F07824B}
|
||||||
{E9D15B9A-75F5-40A9-A582-9BFBB074C127} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
|
||||||
{62F1726B-3144-49F4-8BCC-94160A3B2186} = {52AECE49-F314-4F76-98F2-FA800F07824B}
|
{62F1726B-3144-49F4-8BCC-94160A3B2186} = {52AECE49-F314-4F76-98F2-FA800F07824B}
|
||||||
|
{CA60DFDB-0BE1-40F6-B575-CDC797A40E2E} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
|
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,12 @@ namespace MapControl
|
||||||
private DoubleAnimation zoomLevelAnimation;
|
private DoubleAnimation zoomLevelAnimation;
|
||||||
private DoubleAnimation headingAnimation;
|
private DoubleAnimation headingAnimation;
|
||||||
private Location transformCenter;
|
private Location transformCenter;
|
||||||
private Point viewportCenter;
|
private Point viewCenter;
|
||||||
private double centerLongitude;
|
private double centerLongitude;
|
||||||
private bool internalPropertyChange;
|
private bool internalPropertyChange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when the current viewport has changed.
|
/// Raised when the current map viewport has changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<ViewportChangedEventArgs> ViewportChanged;
|
public event EventHandler<ViewportChangedEventArgs> ViewportChanged;
|
||||||
|
|
||||||
|
|
@ -224,59 +224,56 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates.
|
/// Gets the scaling factor from cartesian map coordinates to view coordinates,
|
||||||
|
/// i.e. pixels per meter, as a read-only dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public double ViewScale
|
||||||
|
{
|
||||||
|
get { return (double)GetValue(ViewScaleProperty); }
|
||||||
|
private set { SetViewScale(value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ViewTransform instance that is used to transform between cartesian map coordinates
|
||||||
|
/// and view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ViewTransform ViewTransform { get; } = new ViewTransform();
|
public ViewTransform ViewTransform { get; } = new ViewTransform();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates as MatrixTransform.
|
/// Gets a MatrixTransform that can be used to transform from cartesian map coordinates
|
||||||
|
/// to view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MatrixTransform ViewportTransform { get; } = new MatrixTransform();
|
public MatrixTransform MapToViewTransform { get; } = new MatrixTransform();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scaling transformation from meters to viewport coordinates at the Center location.
|
/// Gets the horizontal and vertical scaling factors from cartesian map coordinates to view
|
||||||
|
/// coordinates at the specified location, i.e. pixels per meter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ScaleTransform ScaleTransform { get; } = new ScaleTransform();
|
public Vector GetScale(Location location)
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the transformation that rotates by the value of the Heading property.
|
|
||||||
/// </summary>
|
|
||||||
public RotateTransform RotateTransform { get; } = new RotateTransform();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the combination of ScaleTransform and RotateTransform
|
|
||||||
/// </summary>
|
|
||||||
public TransformGroup ScaleRotateTransform
|
|
||||||
{
|
{
|
||||||
get
|
return ViewTransform.Scale * MapProjection.GetRelativeScale(location);
|
||||||
{
|
|
||||||
var transform = new TransformGroup();
|
|
||||||
transform.Children.Add(ScaleTransform);
|
|
||||||
transform.Children.Add(RotateTransform);
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Location in geographic coordinates to a Point in viewport coordinates.
|
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point LocationToViewportPoint(Location location)
|
public Point LocationToView(Location location)
|
||||||
{
|
{
|
||||||
return ViewTransform.MapToView(MapProjection.LocationToMap(location));
|
return ViewTransform.MapToView(MapProjection.LocationToMap(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Point in viewport coordinates to a Location in geographic coordinates.
|
/// Transforms a Point in view coordinates to a Location in geographic coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Location ViewportPointToLocation(Point point)
|
public Location ViewToLocation(Point point)
|
||||||
{
|
{
|
||||||
return MapProjection.MapToLocation(ViewTransform.ViewToMap(point));
|
return MapProjection.MapToLocation(ViewTransform.ViewToMap(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Rect in viewport coordinates to a BoundingBox in geographic coordinates.
|
/// Transforms a Rect in view coordinates to a BoundingBox in geographic coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BoundingBox ViewportRectToBoundingBox(Rect rect)
|
public BoundingBox ViewRectToBoundingBox(Rect rect)
|
||||||
{
|
{
|
||||||
var p1 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y));
|
var p1 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y));
|
||||||
var p2 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y + rect.Height));
|
var p2 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y + rect.Height));
|
||||||
|
|
@ -292,13 +289,13 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a temporary center point in viewport coordinates for scaling and rotation transformations.
|
/// Sets a temporary center point in view coordinates for scaling and rotation transformations.
|
||||||
/// This center point is automatically reset when the Center property is set by application code.
|
/// This center point is automatically reset when the Center property is set by application code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetTransformCenter(Point center)
|
public void SetTransformCenter(Point center)
|
||||||
{
|
{
|
||||||
transformCenter = ViewportPointToLocation(center);
|
transformCenter = ViewToLocation(center);
|
||||||
viewportCenter = center;
|
viewCenter = center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -307,11 +304,11 @@ namespace MapControl
|
||||||
public void ResetTransformCenter()
|
public void ResetTransformCenter()
|
||||||
{
|
{
|
||||||
transformCenter = null;
|
transformCenter = null;
|
||||||
viewportCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
viewCenter = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the Center property according to the specified translation in viewport coordinates.
|
/// Changes the Center property according to the specified translation in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TranslateMap(Vector translation)
|
public void TranslateMap(Vector translation)
|
||||||
{
|
{
|
||||||
|
|
@ -323,21 +320,21 @@ namespace MapControl
|
||||||
|
|
||||||
if (translation.X != 0d || translation.Y != 0d)
|
if (translation.X != 0d || translation.Y != 0d)
|
||||||
{
|
{
|
||||||
Center = ViewportPointToLocation(viewportCenter - translation);
|
Center = ViewToLocation(viewCenter - 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
|
/// view coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||||
/// is performed relative to the specified center point in viewport coordinates.
|
/// is performed relative to the specified center point in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TransformMap(Point center, Vector translation, double rotation, double scale)
|
public void TransformMap(Point center, Vector translation, double rotation, double scale)
|
||||||
{
|
{
|
||||||
if (rotation != 0d || scale != 1d)
|
if (rotation != 0d || scale != 1d)
|
||||||
{
|
{
|
||||||
transformCenter = ViewportPointToLocation(center);
|
transformCenter = ViewToLocation(center);
|
||||||
viewportCenter = center + translation;
|
viewCenter = center + translation;
|
||||||
|
|
||||||
if (rotation != 0d)
|
if (rotation != 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -363,7 +360,7 @@ namespace MapControl
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the value of the TargetZoomLevel property while retaining the specified center point
|
/// Sets the value of the TargetZoomLevel property while retaining the specified center point
|
||||||
/// in viewport coordinates.
|
/// in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomMap(Point center, double zoomLevel)
|
public void ZoomMap(Point center, double zoomLevel)
|
||||||
{
|
{
|
||||||
|
|
@ -378,16 +375,15 @@ namespace MapControl
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the TargetZoomLevel and TargetCenter properties so 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 view. The TargetHeading property is set to zero.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomToBounds(BoundingBox boundingBox)
|
public void ZoomToBounds(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var rect = MapProjection.BoundingBoxToRect(boundingBox);
|
var rect = MapProjection.BoundingBoxToRect(boundingBox);
|
||||||
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height)
|
var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height);
|
||||||
* MapProjection.Wgs84MetersPerDegree * 360d / 256d;
|
|
||||||
|
|
||||||
TargetZoomLevel = Math.Log(scale, 2d);
|
TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
|
||||||
TargetCenter = MapProjection.MapToLocation(center);
|
TargetCenter = MapProjection.MapToLocation(center);
|
||||||
TargetHeading = 0d;
|
TargetHeading = 0d;
|
||||||
}
|
}
|
||||||
|
|
@ -703,16 +699,19 @@ namespace MapControl
|
||||||
private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false)
|
private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false)
|
||||||
{
|
{
|
||||||
var projection = MapProjection;
|
var projection = MapProjection;
|
||||||
var viewportScale = 256d * Math.Pow(2d, ZoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree);
|
|
||||||
var center = transformCenter ?? Center;
|
|
||||||
|
|
||||||
projection.Center = ProjectionCenter ?? Center;
|
projection.Center = ProjectionCenter ?? Center;
|
||||||
|
|
||||||
ViewTransform.SetTransform(projection.LocationToMap(center), viewportCenter, viewportScale, Heading);
|
var center = transformCenter ?? Center;
|
||||||
|
var mapCenter = projection.LocationToMap(center);
|
||||||
|
|
||||||
|
var viewScale = ViewTransform.ZoomLevelToScale(ZoomLevel);
|
||||||
|
|
||||||
|
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading);
|
||||||
|
|
||||||
if (transformCenter != null)
|
if (transformCenter != null)
|
||||||
{
|
{
|
||||||
center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
center = ViewToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||||
center.Longitude = Location.NormalizeLongitude(center.Longitude);
|
center.Longitude = Location.NormalizeLongitude(center.Longitude);
|
||||||
|
|
||||||
if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude)
|
if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude)
|
||||||
|
|
@ -733,18 +732,14 @@ namespace MapControl
|
||||||
ResetTransformCenter();
|
ResetTransformCenter();
|
||||||
|
|
||||||
projection.Center = ProjectionCenter ?? center;
|
projection.Center = ProjectionCenter ?? center;
|
||||||
|
mapCenter = projection.LocationToMap(center);
|
||||||
|
|
||||||
ViewTransform.SetTransform(projection.LocationToMap(center), viewportCenter, viewportScale, Heading);
|
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewportTransform.Matrix = ViewTransform.MapToViewMatrix;
|
ViewScale = ViewTransform.Scale;
|
||||||
|
MapToViewTransform.Matrix = ViewTransform.MapToViewMatrix;
|
||||||
var scale = projection.GetRelativeScale(center);
|
|
||||||
ScaleTransform.ScaleX = scale.X * ViewTransform.Scale;
|
|
||||||
ScaleTransform.ScaleY = scale.Y * ViewTransform.Scale;
|
|
||||||
|
|
||||||
RotateTransform.Angle = ViewTransform.Rotation;
|
|
||||||
|
|
||||||
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
|
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,14 @@ using System.Windows.Threading;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map image layer. Fills the entire viewport with a map image, e.g. provided by a Web Map Service.
|
/// Map image layer. Fills the viewport with a single map image, e.g. provided by a Web Map Service.
|
||||||
/// The image must be provided by the abstract GetImageAsync method.
|
/// The image must be provided by the abstract GetImageAsync method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MapImageLayer : MapPanel, IMapLayer
|
public abstract class MapImageLayer : MapPanel, IMapLayer
|
||||||
{
|
{
|
||||||
|
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||||
|
nameof(Description), typeof(string), typeof(MapImageLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register(
|
||||||
nameof(MinLatitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
nameof(MinLatitude), typeof(double), typeof(MapImageLayer), new PropertyMetadata(double.NaN));
|
||||||
|
|
||||||
|
|
@ -53,9 +56,6 @@ namespace MapControl
|
||||||
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty UpdateWhileViewportChangingProperty = DependencyProperty.Register(
|
||||||
nameof(UpdateWhileViewportChanging), typeof(bool), typeof(MapImageLayer), new PropertyMetadata(false));
|
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(
|
public static readonly DependencyProperty MapBackgroundProperty = DependencyProperty.Register(
|
||||||
nameof(MapBackground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
|
nameof(MapBackground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
|
@ -74,6 +74,16 @@ namespace MapControl
|
||||||
updateTimer.Tick += async (s, e) => await UpdateImageAsync();
|
updateTimer.Tick += async (s, e) => await UpdateImageAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Description of the MapImageLayer.
|
||||||
|
/// Used to display copyright information on top of the map.
|
||||||
|
/// </summary>
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(DescriptionProperty); }
|
||||||
|
set { SetValue(DescriptionProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional minimum latitude value. Default is NaN.
|
/// Optional minimum latitude value. Default is NaN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -120,9 +130,9 @@ 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 view size.
|
||||||
/// Setting a value greater than one will let MapImageLayer request images that
|
/// Setting a value greater than one will let MapImageLayer request images that
|
||||||
/// are larger than the viewport, in order to support smooth panning.
|
/// are larger than the view, in order to support smooth panning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double RelativeImageSize
|
public double RelativeImageSize
|
||||||
{
|
{
|
||||||
|
|
@ -148,16 +158,6 @@ namespace MapControl
|
||||||
set { SetValue(UpdateWhileViewportChangingProperty, value); }
|
set { SetValue(UpdateWhileViewportChangingProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Description of the MapImageLayer.
|
|
||||||
/// Used to display copyright information on top of the map.
|
|
||||||
/// </summary>
|
|
||||||
public string Description
|
|
||||||
{
|
|
||||||
get { return (string)GetValue(DescriptionProperty); }
|
|
||||||
set { SetValue(DescriptionProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optional foreground brush.
|
/// Optional foreground brush.
|
||||||
/// Sets MapBase.Foreground if not null and the MapImageLayer is the base map layer.
|
/// Sets MapBase.Foreground if not null and the MapImageLayer is the base map layer.
|
||||||
|
|
@ -258,7 +258,7 @@ namespace MapControl
|
||||||
var y = (ParentMap.RenderSize.Height - height) / 2d;
|
var y = (ParentMap.RenderSize.Height - height) / 2d;
|
||||||
var rect = new Rect(x, y, width, height);
|
var rect = new Rect(x, y, width, height);
|
||||||
|
|
||||||
BoundingBox = ParentMap.ViewportRectToBoundingBox(rect);
|
BoundingBox = ParentMap.ViewRectToBoundingBox(rect);
|
||||||
|
|
||||||
if (BoundingBox != null)
|
if (BoundingBox != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
SelectItems(item =>
|
SelectItems(item =>
|
||||||
{
|
{
|
||||||
var pos = MapPanel.GetViewportPosition(ContainerFromItem(item));
|
var pos = MapPanel.GetViewPosition(ContainerFromItem(item));
|
||||||
return pos.HasValue && predicate(pos.Value);
|
return pos.HasValue && predicate(pos.Value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -116,10 +116,10 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
else if (shiftKey && SelectedItem != null)
|
else if (shiftKey && SelectedItem != null)
|
||||||
{
|
{
|
||||||
// Extended with Shift -> select items in viewport rectangle
|
// Extended with Shift -> select items in view rectangle
|
||||||
|
|
||||||
var p1 = MapPanel.GetViewportPosition(ContainerFromItem(SelectedItem));
|
var p1 = MapPanel.GetViewPosition(ContainerFromItem(SelectedItem));
|
||||||
var p2 = MapPanel.GetViewportPosition(mapItem);
|
var p2 = MapPanel.GetViewPosition(mapItem);
|
||||||
|
|
||||||
if (p1.HasValue && p2.HasValue)
|
if (p1.HasValue && p2.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ namespace MapControl
|
||||||
element.SetValue(BoundingBoxProperty, value);
|
element.SetValue(BoundingBoxProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Point? GetViewportPosition(FrameworkElement element)
|
public static Point? GetViewPosition(FrameworkElement element)
|
||||||
{
|
{
|
||||||
return (Point?)element.GetValue(ViewportPositionProperty);
|
return (Point?)element.GetValue(ViewPositionProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapBase ParentMap
|
public MapBase ParentMap
|
||||||
|
|
@ -118,9 +118,9 @@ namespace MapControl
|
||||||
|
|
||||||
if (location != null)
|
if (location != null)
|
||||||
{
|
{
|
||||||
var viewportPosition = ArrangeElement(element, location);
|
var viewPosition = ArrangeElement(element, location);
|
||||||
|
|
||||||
SetViewportPosition(element, viewportPosition);
|
SetViewPosition(element, viewPosition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -135,7 +135,7 @@ namespace MapControl
|
||||||
ArrangeElement(element, finalSize);
|
ArrangeElement(element, finalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetViewportPosition(element, null);
|
SetViewPosition(element, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,13 +145,13 @@ namespace MapControl
|
||||||
|
|
||||||
private Point ArrangeElement(FrameworkElement element, Location location)
|
private Point ArrangeElement(FrameworkElement element, Location location)
|
||||||
{
|
{
|
||||||
var pos = parentMap.LocationToViewportPoint(location);
|
var pos = parentMap.LocationToView(location);
|
||||||
|
|
||||||
if (parentMap.MapProjection.IsNormalCylindrical &&
|
if (parentMap.MapProjection.IsNormalCylindrical &&
|
||||||
(pos.X < 0d || pos.X > parentMap.RenderSize.Width ||
|
(pos.X < 0d || pos.X > parentMap.RenderSize.Width ||
|
||||||
pos.Y < 0d || pos.Y > parentMap.RenderSize.Height))
|
pos.Y < 0d || pos.Y > parentMap.RenderSize.Height))
|
||||||
{
|
{
|
||||||
pos = parentMap.LocationToViewportPoint(new Location(
|
pos = parentMap.LocationToView(new Location(
|
||||||
location.Latitude,
|
location.Latitude,
|
||||||
Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude)));
|
Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude)));
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +210,7 @@ namespace MapControl
|
||||||
var location = projection.MapToLocation(center);
|
var location = projection.MapToLocation(center);
|
||||||
location.Longitude = Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude);
|
location.Longitude = Location.NearestLongitude(location.Longitude, parentMap.Center.Longitude);
|
||||||
|
|
||||||
pos = parentMap.LocationToViewportPoint(location);
|
pos = parentMap.LocationToView(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
rect.Width *= parentMap.ViewTransform.Scale;
|
rect.Width *= parentMap.ViewTransform.Scale;
|
||||||
|
|
@ -229,14 +229,15 @@ namespace MapControl
|
||||||
element.Arrange(rect);
|
element.Arrange(rect);
|
||||||
|
|
||||||
var rotateTransform = element.RenderTransform as RotateTransform;
|
var rotateTransform = element.RenderTransform as RotateTransform;
|
||||||
|
var rotation = parentMap.ViewTransform.Rotation;
|
||||||
|
|
||||||
if (rotateTransform != null)
|
if (rotateTransform != null)
|
||||||
{
|
{
|
||||||
rotateTransform.Angle = parentMap.Heading;
|
rotateTransform.Angle = rotation;
|
||||||
}
|
}
|
||||||
else if (parentMap.Heading != 0d)
|
else if (rotation != 0d)
|
||||||
{
|
{
|
||||||
rotateTransform = new RotateTransform { Angle = parentMap.Heading };
|
rotateTransform = new RotateTransform { Angle = rotation };
|
||||||
element.RenderTransform = rotateTransform;
|
element.RenderTransform = rotateTransform;
|
||||||
element.RenderTransformOrigin = new Point(0.5, 0.5);
|
element.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
142
MapControl/Shared/MapPath.cs
Normal file
142
MapControl/Shared/MapPath.cs
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2020 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
#if WINDOWS_UWP
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
#else
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A path element with a Data property that holds a Geometry in cartesian map coordinates
|
||||||
|
/// or view coordinates. Cartesian coordinates can optionally be relative to an origin Location.
|
||||||
|
/// </summary>
|
||||||
|
public partial class MapPath : IMapElement
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
|
||||||
|
nameof(Location), typeof(Location), typeof(MapPath),
|
||||||
|
new PropertyMetadata(null, (o, e) => ((MapPath)o).LocationOrViewportChanged()));
|
||||||
|
|
||||||
|
private MapBase parentMap;
|
||||||
|
private MatrixTransform dataTransform;
|
||||||
|
private double longitudeOffset;
|
||||||
|
|
||||||
|
public MapPath()
|
||||||
|
{
|
||||||
|
MapPanel.InitMapElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a Location that is used as
|
||||||
|
/// - either the origin point of a geometry specified in cartesian map units (meters)
|
||||||
|
/// - or as an optional value to constrain the view position of MapPaths with multiple
|
||||||
|
/// Locations (like MapPolyline or MapPolygon) to the visible map viewport, as done
|
||||||
|
/// for elements where the MapPanel.Location property is set.
|
||||||
|
/// </summary>
|
||||||
|
public Location Location
|
||||||
|
{
|
||||||
|
get { return (Location)GetValue(LocationProperty); }
|
||||||
|
set { SetValue(LocationProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapBase ParentMap
|
||||||
|
{
|
||||||
|
get { return parentMap; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (parentMap != null)
|
||||||
|
{
|
||||||
|
parentMap.ViewportChanged -= OnViewportChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentMap = value;
|
||||||
|
|
||||||
|
if (parentMap != null)
|
||||||
|
{
|
||||||
|
parentMap.ViewportChanged += OnViewportChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationOrViewportChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
|
||||||
|
{
|
||||||
|
LocationOrViewportChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LocationOrViewportChanged()
|
||||||
|
{
|
||||||
|
longitudeOffset = 0d;
|
||||||
|
|
||||||
|
if (parentMap != null && parentMap.MapProjection.IsNormalCylindrical && Location != null)
|
||||||
|
{
|
||||||
|
var viewPos = LocationToView(Location);
|
||||||
|
|
||||||
|
if (viewPos.X < 0d || viewPos.X > parentMap.RenderSize.Width ||
|
||||||
|
viewPos.Y < 0d || viewPos.Y > parentMap.RenderSize.Height)
|
||||||
|
{
|
||||||
|
longitudeOffset = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude) - Location.Longitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateData()
|
||||||
|
{
|
||||||
|
if (parentMap != null && Data != null)
|
||||||
|
{
|
||||||
|
if (dataTransform == null)
|
||||||
|
{
|
||||||
|
Data.Transform = dataTransform = new MatrixTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Location != null)
|
||||||
|
{
|
||||||
|
var viewPos = LocationToView(Location);
|
||||||
|
var scale = parentMap.GetScale(Location);
|
||||||
|
var matrix = new Matrix(scale.X, 0, 0, scale.Y, 0, 0);
|
||||||
|
matrix.Rotate(parentMap.Heading);
|
||||||
|
matrix.Translate(viewPos.X, viewPos.Y);
|
||||||
|
dataTransform.Matrix = matrix;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataTransform.Matrix = parentMap.ViewTransform.MapToViewMatrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Point LocationToMap(Location location)
|
||||||
|
{
|
||||||
|
if (longitudeOffset != 0d)
|
||||||
|
{
|
||||||
|
location = new Location(location.Latitude, location.Longitude + longitudeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
var point = parentMap.MapProjection.LocationToMap(location);
|
||||||
|
|
||||||
|
if (point.Y == double.PositiveInfinity)
|
||||||
|
{
|
||||||
|
point.Y = 1e9;
|
||||||
|
}
|
||||||
|
else if (point.X == double.NegativeInfinity)
|
||||||
|
{
|
||||||
|
point.Y = -1e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Point LocationToView(Location location)
|
||||||
|
{
|
||||||
|
return parentMap.ViewTransform.MapToView(LocationToMap(location));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A polygon defined by a collection of Locations.
|
/// A polygon defined by a collection of Locations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MapPolygon : MapShape
|
public class MapPolygon : MapPath
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||||
nameof(Locations), typeof(IEnumerable<Location>), typeof(MapPolygon),
|
nameof(Locations), typeof(IEnumerable<Location>), typeof(MapPolygon),
|
||||||
|
|
@ -35,6 +35,11 @@ namespace MapControl
|
||||||
set { SetValue(LocationsProperty, value); }
|
set { SetValue(LocationsProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MapPolygon()
|
||||||
|
{
|
||||||
|
Data = new PathGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateData()
|
protected override void UpdateData()
|
||||||
{
|
{
|
||||||
var figures = ((PathGeometry)Data).Figures;
|
var figures = ((PathGeometry)Data).Figures;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A polyline defined by a collection of Locations.
|
/// A polyline defined by a collection of Locations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MapPolyline : MapShape
|
public class MapPolyline : MapPath
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||||
nameof(Locations), typeof(IEnumerable<Location>), typeof(MapPolyline),
|
nameof(Locations), typeof(IEnumerable<Location>), typeof(MapPolyline),
|
||||||
|
|
@ -35,6 +35,11 @@ namespace MapControl
|
||||||
set { SetValue(LocationsProperty, value); }
|
set { SetValue(LocationsProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MapPolyline()
|
||||||
|
{
|
||||||
|
Data = new PathGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateData()
|
protected override void UpdateData()
|
||||||
{
|
{
|
||||||
var figures = ((PathGeometry)Data).Figures;
|
var figures = ((PathGeometry)Data).Figures;
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var size = new Size();
|
var size = new Size();
|
||||||
|
|
||||||
if (ParentMap != null && ParentMap.ScaleTransform.ScaleX > 0d)
|
if (ParentMap != null)
|
||||||
{
|
{
|
||||||
var length = MinWidth / ParentMap.ScaleTransform.ScaleX;
|
var scale = ParentMap.GetScale(ParentMap.Center).X;
|
||||||
|
var length = MinWidth / scale;
|
||||||
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
|
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
|
||||||
|
|
||||||
if (length / magnitude < 2d)
|
if (length / magnitude < 2d)
|
||||||
|
|
@ -77,7 +78,7 @@ namespace MapControl
|
||||||
length = 10d * magnitude;
|
length = 10d * magnitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
size.Width = length * ParentMap.ScaleTransform.ScaleX + StrokeThickness + Padding.Left + Padding.Right;
|
size.Width = length * scale + StrokeThickness + Padding.Left + Padding.Right;
|
||||||
size.Height = 1.25 * FontSize + StrokeThickness + Padding.Top + Padding.Bottom;
|
size.Height = 1.25 * FontSize + StrokeThickness + Padding.Top + Padding.Bottom;
|
||||||
|
|
||||||
var x1 = Padding.Left + StrokeThickness / 2d;
|
var x1 = Padding.Left + StrokeThickness / 2d;
|
||||||
|
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2020 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
#if WINDOWS_UWP
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for MapPolyline and MapPolygon.
|
|
||||||
/// </summary>
|
|
||||||
public abstract partial class MapShape : IMapElement
|
|
||||||
{
|
|
||||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
|
|
||||||
nameof(Location), typeof(Location), typeof(MapShape),
|
|
||||||
new PropertyMetadata(null, (o, e) => ((MapShape)o).LocationPropertyChanged()));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets an optional Location to constrain the viewport position to the visible
|
|
||||||
/// map viewport, as done for elements where the MapPanel.Location property is set.
|
|
||||||
/// </summary>
|
|
||||||
public Location Location
|
|
||||||
{
|
|
||||||
get { return (Location)GetValue(LocationProperty); }
|
|
||||||
set { SetValue(LocationProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LocationPropertyChanged()
|
|
||||||
{
|
|
||||||
if (parentMap != null)
|
|
||||||
{
|
|
||||||
UpdateData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MapBase parentMap;
|
|
||||||
|
|
||||||
public MapBase ParentMap
|
|
||||||
{
|
|
||||||
get { return parentMap; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (parentMap != null)
|
|
||||||
{
|
|
||||||
parentMap.ViewportChanged -= OnViewportChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
parentMap = value;
|
|
||||||
|
|
||||||
if (parentMap != null)
|
|
||||||
{
|
|
||||||
parentMap.ViewportChanged += OnViewportChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
|
|
||||||
{
|
|
||||||
UpdateData();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void UpdateData();
|
|
||||||
|
|
||||||
protected MapShape()
|
|
||||||
: this(new PathGeometry())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MapShape(Geometry data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
|
|
||||||
MapPanel.InitMapElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Point LocationToMap(Location location)
|
|
||||||
{
|
|
||||||
var point = parentMap.MapProjection.LocationToMap(location);
|
|
||||||
|
|
||||||
if (point.Y == double.PositiveInfinity)
|
|
||||||
{
|
|
||||||
point.Y = 1e9;
|
|
||||||
}
|
|
||||||
else if (point.X == double.NegativeInfinity)
|
|
||||||
{
|
|
||||||
point.Y = -1e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Point LocationToViewportPoint(Location location)
|
|
||||||
{
|
|
||||||
return parentMap.ViewTransform.MapToView(LocationToMap(location));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double GetLongitudeOffset()
|
|
||||||
{
|
|
||||||
var longitudeOffset = 0d;
|
|
||||||
|
|
||||||
if (parentMap.MapProjection.IsNormalCylindrical && Location != null)
|
|
||||||
{
|
|
||||||
var viewportPosition = LocationToViewportPoint(Location);
|
|
||||||
|
|
||||||
if (viewportPosition.X < 0d || viewportPosition.X > parentMap.RenderSize.Width ||
|
|
||||||
viewportPosition.Y < 0d || viewportPosition.Y > parentMap.RenderSize.Height)
|
|
||||||
{
|
|
||||||
var nearestLongitude = Location.NearestLongitude(Location.Longitude, parentMap.Center.Longitude);
|
|
||||||
|
|
||||||
longitudeOffset = nearestLongitude - Location.Longitude;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return longitudeOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,7 +17,7 @@ using System.Windows.Media;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills the map viewport with map tiles from a TileSource.
|
/// Fills the viewport with map tiles from a TileSource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MapTileLayer : MapTileLayerBase
|
public class MapTileLayer : MapTileLayerBase
|
||||||
{
|
{
|
||||||
|
|
@ -26,11 +26,6 @@ namespace MapControl
|
||||||
public static readonly Point TileMatrixTopLeft = new Point(
|
public static readonly Point TileMatrixTopLeft = new Point(
|
||||||
-180d * MapProjection.Wgs84MetersPerDegree, 180d * MapProjection.Wgs84MetersPerDegree);
|
-180d * MapProjection.Wgs84MetersPerDegree, 180d * MapProjection.Wgs84MetersPerDegree);
|
||||||
|
|
||||||
public static double TileMatrixScale(int zoomLevel)
|
|
||||||
{
|
|
||||||
return (TileSize << zoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default MapTileLayer using OpenStreetMap data.
|
/// A default MapTileLayer using OpenStreetMap data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -117,18 +112,22 @@ namespace MapControl
|
||||||
//
|
//
|
||||||
var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin);
|
var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin);
|
||||||
|
|
||||||
|
var tileMatrixScale = ViewTransform.ZoomLevelToScale(TileMatrix.ZoomLevel);
|
||||||
|
|
||||||
((MatrixTransform)RenderTransform).Matrix = ParentMap.ViewTransform.GetTileLayerTransform(
|
((MatrixTransform)RenderTransform).Matrix = ParentMap.ViewTransform.GetTileLayerTransform(
|
||||||
TileMatrixScale(TileMatrix.ZoomLevel), TileMatrixTopLeft, tileMatrixOrigin);
|
tileMatrixScale, TileMatrixTopLeft, tileMatrixOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SetTileMatrix()
|
private bool SetTileMatrix()
|
||||||
{
|
{
|
||||||
var tileMatrixZoomLevel = (int)Math.Floor(ParentMap.ZoomLevel + 0.001); // avoid rounding issues
|
var tileMatrixZoomLevel = (int)Math.Floor(ParentMap.ZoomLevel + 0.001); // avoid rounding issues
|
||||||
|
|
||||||
// bounds in tile pixels from viewport size
|
var tileMatrixScale = ViewTransform.ZoomLevelToScale(tileMatrixZoomLevel);
|
||||||
|
|
||||||
|
// bounds in tile pixels from view size
|
||||||
//
|
//
|
||||||
var tileBounds = ParentMap.ViewTransform.GetTileMatrixBounds(
|
var tileBounds = ParentMap.ViewTransform.GetTileMatrixBounds(
|
||||||
TileMatrixScale(tileMatrixZoomLevel), TileMatrixTopLeft, ParentMap.RenderSize);
|
tileMatrixScale, TileMatrixTopLeft, ParentMap.RenderSize);
|
||||||
|
|
||||||
// tile column and row index bounds
|
// tile column and row index bounds
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// © 2020 Clemens Fischer
|
// © 2020 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
#if WINDOWS_UWP
|
#if WINDOWS_UWP
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
@ -13,22 +14,14 @@ using System.Windows.Media;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the transformation between cartesian map coordinates and viewport coordinates.
|
/// Defines the transformation between cartesian map coordinates in meters
|
||||||
|
/// and view coordinates in pixels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ViewTransform
|
public class ViewTransform
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transform matrix from cartesian map coordinates to viewport coordinates.
|
/// Gets the scaling factor from cartesian map coordinates to view coordinates,
|
||||||
/// </summary>
|
/// i.e. pixels per meter.
|
||||||
public Matrix MapToViewMatrix { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the transform matrix from viewport coordinates to cartesian map coordinates.
|
|
||||||
/// </summary>
|
|
||||||
public Matrix ViewToMapMatrix { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the scaling factor from cartesian map coordinates to viewport coordinates.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Scale { get; private set; }
|
public double Scale { get; private set; }
|
||||||
|
|
||||||
|
|
@ -38,7 +31,17 @@ namespace MapControl
|
||||||
public double Rotation { get; private set; }
|
public double Rotation { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Point from cartesian map coordinates to viewport coordinates.
|
/// Gets the transform matrix from cartesian map coordinates to view coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public Matrix MapToViewMatrix { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the transform matrix from view coordinates to cartesian map coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public Matrix ViewToMapMatrix { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a Point from cartesian map coordinates to view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point MapToView(Point point)
|
public Point MapToView(Point point)
|
||||||
{
|
{
|
||||||
|
|
@ -46,14 +49,14 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Point from viewport coordinates to cartesian map coordinates.
|
/// Transforms a Point from view coordinates to cartesian map coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point ViewToMap(Point point)
|
public Point ViewToMap(Point point)
|
||||||
{
|
{
|
||||||
return ViewToMapMatrix.Transform(point);
|
return ViewToMapMatrix.Transform(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransform(Point mapCenter, Point viewportCenter, double scale, double rotation)
|
public void SetTransform(Point mapCenter, Point viewCenter, double scale, double rotation)
|
||||||
{
|
{
|
||||||
Scale = scale;
|
Scale = scale;
|
||||||
Rotation = rotation;
|
Rotation = rotation;
|
||||||
|
|
@ -61,7 +64,7 @@ namespace MapControl
|
||||||
var transform = new Matrix(Scale, 0d, 0d, -Scale, -Scale * mapCenter.X, Scale * mapCenter.Y);
|
var transform = new Matrix(Scale, 0d, 0d, -Scale, -Scale * mapCenter.X, Scale * mapCenter.Y);
|
||||||
|
|
||||||
transform.Rotate(Rotation);
|
transform.Rotate(Rotation);
|
||||||
transform.Translate(viewportCenter.X, viewportCenter.Y);
|
transform.Translate(viewCenter.X, viewCenter.Y);
|
||||||
|
|
||||||
MapToViewMatrix = transform;
|
MapToViewMatrix = transform;
|
||||||
|
|
||||||
|
|
@ -83,7 +86,7 @@ namespace MapControl
|
||||||
tileMatrixTopLeft.X + tileMatrixOrigin.X / tileMatrixScale,
|
tileMatrixTopLeft.X + tileMatrixOrigin.X / tileMatrixScale,
|
||||||
tileMatrixTopLeft.Y - tileMatrixOrigin.Y / tileMatrixScale);
|
tileMatrixTopLeft.Y - tileMatrixOrigin.Y / tileMatrixScale);
|
||||||
|
|
||||||
// tile matrix origin in viewport coordinates
|
// tile matrix origin in view coordinates
|
||||||
//
|
//
|
||||||
var viewOrigin = MapToView(mapOrigin);
|
var viewOrigin = MapToView(mapOrigin);
|
||||||
|
|
||||||
|
|
@ -92,14 +95,14 @@ namespace MapControl
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect GetTileMatrixBounds(double tileMatrixScale, Point tileMatrixTopLeft, Size viewportSize)
|
public Rect GetTileMatrixBounds(double tileMatrixScale, Point tileMatrixTopLeft, Size viewSize)
|
||||||
{
|
{
|
||||||
var transformScale = tileMatrixScale / Scale;
|
var transformScale = tileMatrixScale / Scale;
|
||||||
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
|
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
|
||||||
|
|
||||||
transform.Rotate(-Rotation);
|
transform.Rotate(-Rotation);
|
||||||
|
|
||||||
// viewport origin in map coordinates
|
// view origin in map coordinates
|
||||||
//
|
//
|
||||||
var origin = ViewToMap(new Point());
|
var origin = ViewToMap(new Point());
|
||||||
|
|
||||||
|
|
@ -109,10 +112,20 @@ namespace MapControl
|
||||||
tileMatrixScale * (origin.X - tileMatrixTopLeft.X),
|
tileMatrixScale * (origin.X - tileMatrixTopLeft.X),
|
||||||
tileMatrixScale * (tileMatrixTopLeft.Y - origin.Y));
|
tileMatrixScale * (tileMatrixTopLeft.Y - origin.Y));
|
||||||
|
|
||||||
// transform viewport bounds to tile pixel bounds
|
// transform view bounds to tile pixel bounds
|
||||||
//
|
//
|
||||||
return new MatrixTransform { Matrix = transform }
|
return new MatrixTransform { Matrix = transform }
|
||||||
.TransformBounds(new Rect(0d, 0d, viewportSize.Width, viewportSize.Height));
|
.TransformBounds(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ZoomLevelToScale(double zoomLevel)
|
||||||
|
{
|
||||||
|
return 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MetersPerDegree);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ScaleToZoomLevel(double scale)
|
||||||
|
{
|
||||||
|
return Math.Log(scale * 360d * MapProjection.Wgs84MetersPerDegree / 256d, 2d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace MapControl
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the map projection has changed, i.e. if a MapTileLayer or MapImageLayer should
|
/// Indicates if the map projection has changed, i.e. if a MapTileLayer or MapImageLayer should
|
||||||
/// be updated immediately, or MapShape Data in cartesian map coordinates should be recalculated.
|
/// be updated immediately, or MapPath Data in cartesian map coordinates should be recalculated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ProjectionChanged { get; }
|
public bool ProjectionChanged { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,11 @@ namespace MapControl
|
||||||
viewTransform.GetTileLayerTransform(TileMatrix.Scale, TileMatrix.TopLeft, tileMatrixOrigin);
|
viewTransform.GetTileLayerTransform(TileMatrix.Scale, TileMatrix.TopLeft, tileMatrixOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetBounds(ViewTransform viewTransform, Size viewportSize)
|
public bool SetBounds(ViewTransform viewTransform, Size viewSize)
|
||||||
{
|
{
|
||||||
// bounds in tile pixels from viewport size
|
// bounds in tile pixels from view size
|
||||||
//
|
//
|
||||||
var bounds = viewTransform.GetTileMatrixBounds(TileMatrix.Scale, TileMatrix.TopLeft, viewportSize);
|
var bounds = viewTransform.GetTileMatrixBounds(TileMatrix.Scale, TileMatrix.TopLeft, viewSize);
|
||||||
|
|
||||||
// tile column and row index bounds
|
// tile column and row index bounds
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WorldMercatorProjection : MapProjection
|
public class WorldMercatorProjection : MapProjection
|
||||||
{
|
{
|
||||||
private static readonly double maxLatitude = YToLatitude(180d);
|
|
||||||
|
|
||||||
public static double ConvergenceTolerance = 1e-6;
|
public static double ConvergenceTolerance = 1e-6;
|
||||||
public static int MaxIterations = 10;
|
public static int MaxIterations = 10;
|
||||||
|
|
||||||
|
private static readonly double maxLatitude = YToLatitude(180d);
|
||||||
|
|
||||||
public WorldMercatorProjection()
|
public WorldMercatorProjection()
|
||||||
{
|
{
|
||||||
CrsId = "EPSG:3395";
|
CrsId = "EPSG:3395";
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ namespace MapControl
|
||||||
nameof(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)));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ViewScaleProperty = DependencyProperty.Register(
|
||||||
|
nameof(ViewScale), typeof(double), typeof(MapBase), new PropertyMetadata(0d));
|
||||||
|
|
||||||
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
||||||
"CenterPoint", typeof(Windows.Foundation.Point), typeof(MapBase),
|
"CenterPoint", typeof(Windows.Foundation.Point), typeof(MapBase),
|
||||||
new PropertyMetadata(new Windows.Foundation.Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Windows.Foundation.Point)e.NewValue)));
|
new PropertyMetadata(new Windows.Foundation.Point(), (o, e) => ((MapBase)o).CenterPointPropertyChanged((Windows.Foundation.Point)e.NewValue)));
|
||||||
|
|
@ -62,6 +65,11 @@ namespace MapControl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetViewScale(double scale)
|
||||||
|
{
|
||||||
|
SetValue(ViewScaleProperty, scale);
|
||||||
|
}
|
||||||
|
|
||||||
private void CenterPointPropertyChanged(Windows.Foundation.Point center)
|
private void CenterPointPropertyChanged(Windows.Foundation.Point center)
|
||||||
{
|
{
|
||||||
CenterPointPropertyChanged(new Location(center.Y, center.X));
|
CenterPointPropertyChanged(new Location(center.Y, center.X));
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,9 @@
|
||||||
<Compile Include="..\Shared\MapPanel.cs">
|
<Compile Include="..\Shared\MapPanel.cs">
|
||||||
<Link>MapPanel.cs</Link>
|
<Link>MapPanel.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Shared\MapPath.cs">
|
||||||
|
<Link>MapPath.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Shared\MapPolygon.cs">
|
<Compile Include="..\Shared\MapPolygon.cs">
|
||||||
<Link>MapPolygon.cs</Link>
|
<Link>MapPolygon.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -119,9 +122,6 @@
|
||||||
<Compile Include="..\Shared\MapScale.cs">
|
<Compile Include="..\Shared\MapScale.cs">
|
||||||
<Link>MapScale.cs</Link>
|
<Link>MapScale.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\Shared\MapShape.cs">
|
|
||||||
<Link>MapShape.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Shared\MapTileLayer.cs">
|
<Compile Include="..\Shared\MapTileLayer.cs">
|
||||||
<Link>MapTileLayer.cs</Link>
|
<Link>MapTileLayer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -188,7 +188,7 @@
|
||||||
<Compile Include="MapItemsControl.UWP.cs" />
|
<Compile Include="MapItemsControl.UWP.cs" />
|
||||||
<Compile Include="MapOverlay.UWP.cs" />
|
<Compile Include="MapOverlay.UWP.cs" />
|
||||||
<Compile Include="MapPanel.UWP.cs" />
|
<Compile Include="MapPanel.UWP.cs" />
|
||||||
<Compile Include="MapShape.UWP.cs" />
|
<Compile Include="MapPath.UWP.cs" />
|
||||||
<Compile Include="Matrix.UWP.cs" />
|
<Compile Include="Matrix.UWP.cs" />
|
||||||
<Compile Include="Point.UWP.cs" />
|
<Compile Include="Point.UWP.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Shapes;
|
using Windows.UI.Xaml.Shapes;
|
||||||
using Windows.UI.Xaml.Data;
|
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
|
@ -40,7 +38,7 @@ namespace MapControl
|
||||||
Children.Add(path);
|
Children.Add(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = map.ViewportRectToBoundingBox(new Rect(0d, 0d, map.RenderSize.Width, map.RenderSize.Height));
|
var bounds = map.ViewRectToBoundingBox(new Rect(0d, 0d, map.RenderSize.Width, map.RenderSize.Height));
|
||||||
var lineDistance = GetLineDistance();
|
var lineDistance = GetLineDistance();
|
||||||
|
|
||||||
var labelStart = new Location(
|
var labelStart = new Location(
|
||||||
|
|
@ -66,14 +64,14 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var figure = new PathFigure
|
var figure = new PathFigure
|
||||||
{
|
{
|
||||||
StartPoint = map.LocationToViewportPoint(new Location(lat, lineStart.Longitude)),
|
StartPoint = map.LocationToView(new Location(lat, lineStart.Longitude)),
|
||||||
IsClosed = false,
|
IsClosed = false,
|
||||||
IsFilled = false
|
IsFilled = false
|
||||||
};
|
};
|
||||||
|
|
||||||
figure.Segments.Add(new LineSegment
|
figure.Segments.Add(new LineSegment
|
||||||
{
|
{
|
||||||
Point = map.LocationToViewportPoint(new Location(lat, lineEnd.Longitude))
|
Point = map.LocationToView(new Location(lat, lineEnd.Longitude))
|
||||||
});
|
});
|
||||||
|
|
||||||
geometry.Figures.Add(figure);
|
geometry.Figures.Add(figure);
|
||||||
|
|
@ -83,14 +81,14 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var figure = new PathFigure
|
var figure = new PathFigure
|
||||||
{
|
{
|
||||||
StartPoint = map.LocationToViewportPoint(new Location(lineStart.Latitude, lon)),
|
StartPoint = map.LocationToView(new Location(lineStart.Latitude, lon)),
|
||||||
IsClosed = false,
|
IsClosed = false,
|
||||||
IsFilled = false
|
IsFilled = false
|
||||||
};
|
};
|
||||||
|
|
||||||
figure.Segments.Add(new LineSegment
|
figure.Segments.Add(new LineSegment
|
||||||
{
|
{
|
||||||
Point = map.LocationToViewportPoint(new Location(lineEnd.Latitude, lon))
|
Point = map.LocationToView(new Location(lineEnd.Latitude, lon))
|
||||||
});
|
});
|
||||||
|
|
||||||
geometry.Figures.Add(figure);
|
geometry.Figures.Add(figure);
|
||||||
|
|
@ -111,22 +109,18 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var renderTransform = new TransformGroup();
|
label = new TextBlock { RenderTransform = new MatrixTransform() };
|
||||||
renderTransform.Children.Add(new TranslateTransform());
|
|
||||||
renderTransform.Children.Add(map.RotateTransform);
|
|
||||||
renderTransform.Children.Add(new TranslateTransform());
|
|
||||||
|
|
||||||
label = new TextBlock { RenderTransform = renderTransform };
|
|
||||||
if (FontFamily != null)
|
|
||||||
{
|
|
||||||
label.SetBinding(TextBlock.FontFamilyProperty, GetBinding(FontFamilyProperty, nameof(FontFamily)));
|
|
||||||
}
|
|
||||||
label.SetBinding(TextBlock.FontSizeProperty, GetBinding(FontSizeProperty, nameof(FontSize)));
|
label.SetBinding(TextBlock.FontSizeProperty, GetBinding(FontSizeProperty, nameof(FontSize)));
|
||||||
label.SetBinding(TextBlock.FontStyleProperty, GetBinding(FontStyleProperty, nameof(FontStyle)));
|
label.SetBinding(TextBlock.FontStyleProperty, GetBinding(FontStyleProperty, nameof(FontStyle)));
|
||||||
label.SetBinding(TextBlock.FontStretchProperty, GetBinding(FontStretchProperty, nameof(FontStretch)));
|
label.SetBinding(TextBlock.FontStretchProperty, GetBinding(FontStretchProperty, nameof(FontStretch)));
|
||||||
label.SetBinding(TextBlock.FontWeightProperty, GetBinding(FontWeightProperty, nameof(FontWeight)));
|
label.SetBinding(TextBlock.FontWeightProperty, GetBinding(FontWeightProperty, nameof(FontWeight)));
|
||||||
label.SetBinding(TextBlock.ForegroundProperty, GetBinding(ForegroundProperty, nameof(Foreground)));
|
label.SetBinding(TextBlock.ForegroundProperty, GetBinding(ForegroundProperty, nameof(Foreground)));
|
||||||
|
|
||||||
|
if (FontFamily != null)
|
||||||
|
{
|
||||||
|
label.SetBinding(TextBlock.FontFamilyProperty, GetBinding(FontFamilyProperty, nameof(FontFamily)));
|
||||||
|
}
|
||||||
|
|
||||||
Children.Add(label);
|
Children.Add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,10 +129,6 @@ namespace MapControl
|
||||||
label.Text = GetLabelText(lat, labelFormat, "NS") + "\n" + GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW");
|
label.Text = GetLabelText(lat, labelFormat, "NS") + "\n" + GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW");
|
||||||
label.Tag = new Location(lat, lon);
|
label.Tag = new Location(lat, lon);
|
||||||
label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
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)
|
while (Children.Count > childIndex)
|
||||||
|
|
@ -153,10 +143,14 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var label = (TextBlock)Children[i];
|
var label = (TextBlock)Children[i];
|
||||||
var location = (Location)label.Tag;
|
var location = (Location)label.Tag;
|
||||||
var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
|
var viewPosition = map.LocationToView(location);
|
||||||
var viewportPosition = map.LocationToViewportPoint(location);
|
var matrix = new Matrix(1, 0, 0, 1, 0, 0);
|
||||||
viewportTransform.X = viewportPosition.X;
|
|
||||||
viewportTransform.Y = viewportPosition.Y;
|
matrix.Translate(StrokeThickness / 2d + 2d, -label.DesiredSize.Height / 2d);
|
||||||
|
matrix.Rotate(map.ViewTransform.Rotation);
|
||||||
|
matrix.Translate(viewPosition.X, viewPosition.Y);
|
||||||
|
|
||||||
|
((MatrixTransform)label.RenderTransform).Matrix = matrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (path != null)
|
else if (path != null)
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ namespace MapControl
|
||||||
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
||||||
"ParentMap", typeof(MapBase), typeof(MapPanel), new PropertyMetadata(null, ParentMapPropertyChanged));
|
"ParentMap", typeof(MapBase), typeof(MapPanel), new PropertyMetadata(null, ParentMapPropertyChanged));
|
||||||
|
|
||||||
private static readonly DependencyProperty ViewportPositionProperty = DependencyProperty.RegisterAttached(
|
private static readonly DependencyProperty ViewPositionProperty = DependencyProperty.RegisterAttached(
|
||||||
"ViewportPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata(null));
|
"ViewPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata(null));
|
||||||
|
|
||||||
public static void InitMapElement(FrameworkElement element)
|
public static void InitMapElement(FrameworkElement element)
|
||||||
{
|
{
|
||||||
|
|
@ -61,9 +61,9 @@ namespace MapControl
|
||||||
?? FindParentMap(parent));
|
?? FindParentMap(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetViewportPosition(FrameworkElement element, Point? viewportPosition)
|
private static void SetViewPosition(FrameworkElement element, Point? viewPosition)
|
||||||
{
|
{
|
||||||
element.SetValue(ViewportPositionProperty, viewportPosition);
|
element.SetValue(ViewPositionProperty, viewPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ using Windows.UI.Xaml.Shapes;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public abstract partial class MapShape : Path
|
public partial class MapPath : Path
|
||||||
{
|
{
|
||||||
protected void DataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
protected void DataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -40,13 +40,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (locations != null && locations.Count() >= 2)
|
if (locations != null && locations.Count() >= 2)
|
||||||
{
|
{
|
||||||
var offset = GetLongitudeOffset();
|
var points = locations.Select(loc => LocationToView(loc)).ToList();
|
||||||
if (offset != 0d)
|
|
||||||
{
|
|
||||||
locations = locations.Select(loc => new Location(loc.Latitude, loc.Longitude + offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
var points = locations.Select(loc => LocationToViewportPoint(loc)).ToList();
|
|
||||||
if (closed)
|
if (closed)
|
||||||
{
|
{
|
||||||
points.Add(points[0]);
|
points.Add(points[0]);
|
||||||
|
|
@ -50,6 +50,16 @@ namespace MapControl
|
||||||
return new Vector(v1.X - v2.X, v1.Y - v2.Y);
|
return new Vector(v1.X - v2.X, v1.Y - v2.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vector operator *(double f, Vector v)
|
||||||
|
{
|
||||||
|
return new Vector(f * v.X, f * v.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector operator *(Vector v, double f)
|
||||||
|
{
|
||||||
|
return new Vector(f * v.X, f * v.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool operator ==(Vector v1, Vector v2)
|
public static bool operator ==(Vector v1, Vector v2)
|
||||||
{
|
{
|
||||||
return v1.X == v2.X && v1.Y == v2.Y;
|
return v1.X == v2.X && v1.Y == v2.Y;
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ namespace MapControl
|
||||||
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||||
|
|
||||||
|
private static readonly DependencyPropertyKey ViewScalePropertyKey = DependencyProperty.RegisterReadOnly(
|
||||||
|
nameof(ViewScale), typeof(double), typeof(MapBase), new PropertyMetadata(0d));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ViewScaleProperty = ViewScalePropertyKey.DependencyProperty;
|
||||||
|
|
||||||
private static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
private 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)));
|
||||||
|
|
@ -61,6 +66,11 @@ namespace MapControl
|
||||||
UpdateTransform();
|
UpdateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetViewScale(double scale)
|
||||||
|
{
|
||||||
|
SetValue(ViewScalePropertyKey, scale);
|
||||||
|
}
|
||||||
|
|
||||||
private void CenterPointPropertyChanged(Point center)
|
private void CenterPointPropertyChanged(Point center)
|
||||||
{
|
{
|
||||||
CenterPointPropertyChanged(new Location(center.Y, center.X));
|
CenterPointPropertyChanged(new Location(center.Y, center.X));
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace MapControl
|
||||||
|
|
||||||
private void DrawCylindricalGraticule(DrawingContext drawingContext, double lineDistance, string labelFormat)
|
private void DrawCylindricalGraticule(DrawingContext drawingContext, double lineDistance, string labelFormat)
|
||||||
{
|
{
|
||||||
var boundingBox = ParentMap.ViewportRectToBoundingBox(new Rect(ParentMap.RenderSize));
|
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(ParentMap.RenderSize));
|
||||||
var latLabelStart = Math.Ceiling(boundingBox.South / lineDistance) * lineDistance;
|
var latLabelStart = Math.Ceiling(boundingBox.South / lineDistance) * lineDistance;
|
||||||
var lonLabelStart = Math.Ceiling(boundingBox.West / lineDistance) * lineDistance;
|
var lonLabelStart = Math.Ceiling(boundingBox.West / lineDistance) * lineDistance;
|
||||||
var latLabels = new List<Label>((int)((boundingBox.North - latLabelStart) / lineDistance) + 1);
|
var latLabels = new List<Label>((int)((boundingBox.North - latLabelStart) / lineDistance) + 1);
|
||||||
|
|
@ -72,8 +72,8 @@ namespace MapControl
|
||||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground, pixelsPerDip)));
|
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground, pixelsPerDip)));
|
||||||
|
|
||||||
drawingContext.DrawLine(pen,
|
drawingContext.DrawLine(pen,
|
||||||
ParentMap.LocationToViewportPoint(new Location(lat, boundingBox.West)),
|
ParentMap.LocationToView(new Location(lat, boundingBox.West)),
|
||||||
ParentMap.LocationToViewportPoint(new Location(lat, boundingBox.East)));
|
ParentMap.LocationToView(new Location(lat, boundingBox.East)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var lon = lonLabelStart; lon <= boundingBox.East; lon += lineDistance)
|
for (var lon = lonLabelStart; lon <= boundingBox.East; lon += lineDistance)
|
||||||
|
|
@ -83,17 +83,17 @@ namespace MapControl
|
||||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground, pixelsPerDip)));
|
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground, pixelsPerDip)));
|
||||||
|
|
||||||
drawingContext.DrawLine(pen,
|
drawingContext.DrawLine(pen,
|
||||||
ParentMap.LocationToViewportPoint(new Location(boundingBox.South, lon)),
|
ParentMap.LocationToView(new Location(boundingBox.South, lon)),
|
||||||
ParentMap.LocationToViewportPoint(new Location(boundingBox.North, lon)));
|
ParentMap.LocationToView(new Location(boundingBox.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 = ParentMap.LocationToView(new Location(latLabel.Position, lonLabel.Position));
|
||||||
|
|
||||||
drawingContext.PushTransform(new RotateTransform(ParentMap.Heading, position.X, position.Y));
|
drawingContext.PushTransform(new RotateTransform(ParentMap.ViewTransform.Rotation, position.X, position.Y));
|
||||||
drawingContext.DrawText(latLabel.Text,
|
drawingContext.DrawText(latLabel.Text,
|
||||||
new Point(position.X + StrokeThickness / 2d + 2d, position.Y - StrokeThickness / 2d - latLabel.Text.Height));
|
new Point(position.X + StrokeThickness / 2d + 2d, position.Y - StrokeThickness / 2d - latLabel.Text.Height));
|
||||||
drawingContext.DrawText(lonLabel.Text,
|
drawingContext.DrawText(lonLabel.Text,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace MapControl
|
||||||
/// for the Polygons property if collection changes of the property itself and its
|
/// for the Polygons property if collection changes of the property itself and its
|
||||||
/// elements are both supposed to trigger a UI update.
|
/// elements are both supposed to trigger a UI update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MapMultiPolygon : MapShape
|
public class MapMultiPolygon : MapPath
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty PolygonsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty PolygonsProperty = DependencyProperty.Register(
|
||||||
nameof(Polygons), typeof(IEnumerable<IEnumerable<Location>>), typeof(MapMultiPolygon),
|
nameof(Polygons), typeof(IEnumerable<IEnumerable<Location>>), typeof(MapMultiPolygon),
|
||||||
|
|
@ -31,6 +31,11 @@ namespace MapControl
|
||||||
set { SetValue(PolygonsProperty, value); }
|
set { SetValue(PolygonsProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MapMultiPolygon()
|
||||||
|
{
|
||||||
|
Data = new PathGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateData()
|
protected override void UpdateData()
|
||||||
{
|
{
|
||||||
var figures = ((PathGeometry)Data).Figures;
|
var figures = ((PathGeometry)Data).Figures;
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ namespace MapControl
|
||||||
"ParentMap", typeof(MapBase), typeof(MapPanel),
|
"ParentMap", typeof(MapBase), typeof(MapPanel),
|
||||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
||||||
|
|
||||||
private static readonly DependencyPropertyKey ViewportPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
private static readonly DependencyPropertyKey ViewPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||||
"ViewportPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata());
|
"ViewPosition", typeof(Point?), typeof(MapPanel), new PropertyMetadata());
|
||||||
|
|
||||||
public static readonly DependencyProperty ParentMapProperty = ParentMapPropertyKey.DependencyProperty;
|
public static readonly DependencyProperty ParentMapProperty = ParentMapPropertyKey.DependencyProperty;
|
||||||
public static readonly DependencyProperty ViewportPositionProperty = ViewportPositionPropertyKey.DependencyProperty;
|
public static readonly DependencyProperty ViewPositionProperty = ViewPositionPropertyKey.DependencyProperty;
|
||||||
|
|
||||||
public static MapBase GetParentMap(FrameworkElement element)
|
public static MapBase GetParentMap(FrameworkElement element)
|
||||||
{
|
{
|
||||||
|
|
@ -39,9 +39,9 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetViewportPosition(FrameworkElement element, Point? viewportPosition)
|
private static void SetViewPosition(FrameworkElement element, Point? viewPosition)
|
||||||
{
|
{
|
||||||
element.SetValue(ViewportPositionPropertyKey, viewportPosition);
|
element.SetValue(ViewPositionPropertyKey, viewPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,15 @@ using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public abstract partial class MapShape : Shape, IWeakEventListener
|
public partial class MapPath : Shape, IWeakEventListener
|
||||||
{
|
{
|
||||||
public Geometry Data { get; }
|
public static readonly DependencyProperty DataProperty = Path.DataProperty.AddOwner(typeof(MapPath));
|
||||||
|
|
||||||
|
public Geometry Data
|
||||||
|
{
|
||||||
|
get { return (Geometry)GetValue(DataProperty); }
|
||||||
|
set { SetValue(DataProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
protected override Geometry DefiningGeometry
|
protected override Geometry DefiningGeometry
|
||||||
{
|
{
|
||||||
|
|
@ -48,13 +54,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (locations != null && locations.Count() >= 2)
|
if (locations != null && locations.Count() >= 2)
|
||||||
{
|
{
|
||||||
var offset = GetLongitudeOffset();
|
var points = locations.Select(loc => LocationToView(loc));
|
||||||
if (offset != 0d)
|
|
||||||
{
|
|
||||||
locations = locations.Select(loc => new Location(loc.Latitude, loc.Longitude + offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
var points = locations.Select(loc => LocationToViewportPoint(loc));
|
|
||||||
var figure = new PathFigure
|
var figure = new PathFigure
|
||||||
{
|
{
|
||||||
StartPoint = points.First(),
|
StartPoint = points.First(),
|
||||||
|
|
@ -29,7 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapProjections", "MapProjec
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.WPF", "MapProjections\WPF\MapProjections.WPF.csproj", "{426C21C0-5F14-491F-BCD1-6D2993510420}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.WPF", "MapProjections\WPF\MapProjections.WPF.csproj", "{426C21C0-5F14-491F-BCD1-6D2993510420}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -45,8 +45,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.UWP", "SQLiteCa
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.WPF", "SQLiteCache\WPF\SQLiteCache.WPF.csproj", "{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.WPF", "SQLiteCache\WPF\SQLiteCache.WPF.csproj", "{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfCoreApp", "SampleApps\WpfCoreApp\WpfCoreApp.csproj", "{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -347,26 +345,6 @@ Global
|
||||||
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x64.Build.0 = Release|Any CPU
|
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.ActiveCfg = Release|Any CPU
|
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.Build.0 = Release|Any CPU
|
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|ARM64.Build.0 = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM64.ActiveCfg = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|ARM64.Build.0 = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -386,7 +364,6 @@ Global
|
||||||
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
|
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
|
||||||
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
|
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
|
||||||
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
|
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
|
||||||
{43380AAB-EE6E-40BF-90EB-FFD86F885CAF} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
|
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ namespace ProjectionDemo
|
||||||
var map = (MapBase)sender;
|
var map = (MapBase)sender;
|
||||||
var pos = e.GetPosition(map);
|
var pos = e.GetPosition(map);
|
||||||
|
|
||||||
viewModel.PushpinLocation = map.ViewportPointToLocation(pos);
|
viewModel.PushpinLocation = map.ViewToLocation(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,15 @@
|
||||||
<map:MapItemsControl ItemsSource="{Binding Pushpins}"
|
<map:MapItemsControl ItemsSource="{Binding Pushpins}"
|
||||||
ItemContainerStyle="{StaticResource PushpinItemStyle}"/>
|
ItemContainerStyle="{StaticResource PushpinItemStyle}"/>
|
||||||
|
|
||||||
|
<map:MapPath Stroke="Blue" StrokeThickness="3" Fill="#1F007F00">
|
||||||
|
<map:MapPath.Location>
|
||||||
|
<map:Location Latitude="53.5" Longitude="8.2"/>
|
||||||
|
</map:MapPath.Location>
|
||||||
|
<map:MapPath.Data>
|
||||||
|
<EllipseGeometry RadiusX="1852" RadiusY="1852"/>
|
||||||
|
</map:MapPath.Data>
|
||||||
|
</map:MapPath>
|
||||||
|
|
||||||
<map:Pushpin Background="Yellow" Foreground="Blue" Content="N 53° 30' E 8° 12'">
|
<map:Pushpin Background="Yellow" Foreground="Blue" Content="N 53° 30' E 8° 12'">
|
||||||
<map:MapPanel.Location>
|
<map:MapPanel.Location>
|
||||||
<map:Location Latitude="53.5" Longitude="8.2"/>
|
<map:Location Latitude="53.5" Longitude="8.2"/>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
<Window
|
<Window x:Class="WpfApplication.MainWindow"
|
||||||
x:Class="WpfApplication.MainWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:map="clr-namespace:MapControl;assembly=MapControl.WPF"
|
xmlns:map="clr-namespace:MapControl;assembly=MapControl.WPF"
|
||||||
xmlns:vm="clr-namespace:ViewModel"
|
xmlns:vm="clr-namespace:ViewModel"
|
||||||
xmlns:local="clr-namespace:WpfApplication"
|
xmlns:local="clr-namespace:WpfApplication"
|
||||||
Title="XAML MapControl - WPF Test Application" Height="600" Width="800"
|
Title="XAML MapControl - WPF Test Application" Height="600" Width="900"
|
||||||
Stylus.IsPressAndHoldEnabled="False">
|
Stylus.IsPressAndHoldEnabled="False">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<local:LocationToVisibilityConverter x:Key="LocationToVisibilityConverter"/>
|
<local:LocationToVisibilityConverter x:Key="LocationToVisibilityConverter"/>
|
||||||
|
|
@ -88,7 +87,7 @@
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
||||||
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
||||||
<Binding Path="(map:MapPanel.ViewportPosition)" RelativeSource="{RelativeSource Self}"/>
|
<Binding Path="(map:MapPanel.ViewPosition)" RelativeSource="{RelativeSource Self}"/>
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
|
@ -159,17 +158,17 @@
|
||||||
<map:Pushpin map:MapPanel.Location="35,33" Content="Cyprus"/>
|
<map:Pushpin map:MapPanel.Location="35,33" Content="Cyprus"/>
|
||||||
<map:Pushpin map:MapPanel.Location="28.25,-16.5" Content="Tenerife"/>
|
<map:Pushpin map:MapPanel.Location="28.25,-16.5" Content="Tenerife"/>
|
||||||
|
|
||||||
<Path map:MapPanel.Location="53.5,8.2" Stroke="Blue" StrokeThickness="3" Fill="#1F007F00">
|
<map:MapPath Location="53.5,8.2" Stroke="Blue" StrokeThickness="3" Fill="#1F007F00">
|
||||||
<Path.Data>
|
<map:MapPath.Data>
|
||||||
<EllipseGeometry RadiusX="1852" RadiusY="1852" Transform="{Binding ScaleRotateTransform, ElementName=map}"/>
|
<EllipseGeometry RadiusX="1852" RadiusY="1852"/>
|
||||||
</Path.Data>
|
</map:MapPath.Data>
|
||||||
</Path>
|
</map:MapPath>
|
||||||
|
|
||||||
<map:Pushpin map:MapPanel.Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53°30' E 8°12'">
|
<map:Pushpin map:MapPanel.Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53°30' E 8°12'">
|
||||||
<map:Pushpin.Visibility>
|
<map:Pushpin.Visibility>
|
||||||
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
||||||
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
||||||
<Binding Path="(map:MapPanel.ViewportPosition)" RelativeSource="{RelativeSource Self}"/>
|
<Binding Path="(map:MapPanel.ViewPosition)" RelativeSource="{RelativeSource Self}"/>
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</map:Pushpin.Visibility>
|
</map:Pushpin.Visibility>
|
||||||
</map:Pushpin>
|
</map:Pushpin>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace WpfApplication
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application");
|
ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application");
|
||||||
//TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder);
|
TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder);
|
||||||
//TileImageLoader.Cache = new MapControl.Caching.FileDbCache(TileImageLoader.DefaultCacheFolder);
|
//TileImageLoader.Cache = new MapControl.Caching.FileDbCache(TileImageLoader.DefaultCacheFolder);
|
||||||
//TileImageLoader.Cache = new MapControl.Caching.SQLiteCache(TileImageLoader.DefaultCacheFolder);
|
//TileImageLoader.Cache = new MapControl.Caching.SQLiteCache(TileImageLoader.DefaultCacheFolder);
|
||||||
//TileImageLoader.Cache = null;
|
//TileImageLoader.Cache = null;
|
||||||
|
|
@ -26,7 +26,7 @@ namespace WpfApplication
|
||||||
{
|
{
|
||||||
//map.ZoomMap(e.GetPosition(map), Math.Floor(map.ZoomLevel + 1.5));
|
//map.ZoomMap(e.GetPosition(map), Math.Floor(map.ZoomLevel + 1.5));
|
||||||
//map.ZoomToBounds(new BoundingBox(53, 7, 54, 9));
|
//map.ZoomToBounds(new BoundingBox(53, 7, 54, 9));
|
||||||
map.TargetCenter = map.ViewportPointToLocation(e.GetPosition(map));
|
map.TargetCenter = map.ViewToLocation(e.GetPosition(map));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace WpfApplication
|
||||||
|
|
||||||
private void MapMouseMove(object sender, MouseEventArgs e)
|
private void MapMouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
var location = map.ViewportPointToLocation(e.GetPosition(map));
|
var location = map.ViewToLocation(e.GetPosition(map));
|
||||||
var latitude = (int)Math.Round(location.Latitude * 60000d);
|
var latitude = (int)Math.Round(location.Latitude * 60000d);
|
||||||
var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d);
|
var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d);
|
||||||
var latHemisphere = 'N';
|
var latHemisphere = 'N';
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
[assembly: AssemblyTitle("WPF Sample Application")]
|
|
||||||
[assembly: AssemblyDescription("XAML Map Control WPF Sample Application")]
|
|
||||||
[assembly: AssemblyProduct("XAML Map Control")]
|
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2020 Clemens Fischer")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyVersion("5.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("5.0.0")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
@ -1,110 +1,41 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{F92DA93D-75DB-4308-A5F9-6B4C3908A675}</ProjectGuid>
|
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<TargetFrameworks>netcoreapp3.1;net48</TargetFrameworks>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
<RootNamespace>WpfApplication</RootNamespace>
|
<RootNamespace>WpfApplication</RootNamespace>
|
||||||
<AssemblyName>WpfApplication</AssemblyName>
|
<Product>XAML Map Control</Product>
|
||||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
<Version>5.0.0</Version>
|
||||||
<FileAlignment>512</FileAlignment>
|
<Description>XAML Map Control WPF Sample Application</Description>
|
||||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
<Authors>Clemens Fischer</Authors>
|
||||||
<WarningLevel>4</WarningLevel>
|
<Copyright>Copyright © 2020 Clemens Fischer</Copyright>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
<NuGetPackageImportStamp>
|
|
||||||
</NuGetPackageImportStamp>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<DefineConstants></DefineConstants>
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>
|
|
||||||
</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Compile Include="..\Shared\MapLayers.cs" Link="MapLayers.cs" />
|
||||||
|
<Compile Include="..\Shared\MapViewModel.cs" Link="MapViewModel.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\MapControl\WPF\MapControl.WPF.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="..\Shared\10_535_330.jpg" Link="10_535_330.jpg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Runtime.Caching" />
|
<Reference Include="System.Runtime.Caching" />
|
||||||
<Reference Include="System.Xaml">
|
|
||||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="WindowsBase" />
|
|
||||||
<Reference Include="PresentationCore" />
|
|
||||||
<Reference Include="PresentationFramework" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ApplicationDefinition Include="App.xaml">
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</ApplicationDefinition>
|
|
||||||
<Page Include="MainWindow.xaml">
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Compile Include="..\Shared\MapLayers.cs">
|
|
||||||
<Link>MapLayers.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Shared\MapViewModel.cs">
|
|
||||||
<Link>MapViewModel.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="App.xaml.cs">
|
|
||||||
<DependentUpon>App.xaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="LocationToVisibilityConverter.cs" />
|
|
||||||
<Compile Include="MainWindow.xaml.cs">
|
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="OutlinedText.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<AppDesigner Include="Properties\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="App.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="..\Shared\10_535_330.jpg">
|
|
||||||
<Link>10_535_330.jpg</Link>
|
|
||||||
</Resource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MapControl\WPF\MapControl.WPF.csproj">
|
|
||||||
<Project>{62f1726b-3144-49f4-8bcc-94160a3b2186}</Project>
|
|
||||||
<Name>MapControl.WPF</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\..\SQLiteCache\WPF\SQLiteCache.WPF.csproj">
|
|
||||||
<Project>{0109c2f0-ba2c-420f-b2ca-db5b29b1a349}</Project>
|
|
||||||
<Name>SQLiteCache.WPF</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup />
|
<PropertyGroup>
|
||||||
|
<ActiveDebugFramework>netcoreapp3.1</ActiveDebugFramework>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ApplicationDefinition Update="App.xaml">
|
<ApplicationDefinition Update="App.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<Application x:Class="WpfCoreApp.App"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
StartupUri="MainWindow.xaml">
|
|
||||||
<Application.Resources>
|
|
||||||
</Application.Resources>
|
|
||||||
</Application>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace WpfApplication
|
|
||||||
{
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using MapControl;
|
|
||||||
|
|
||||||
namespace WpfCoreApp
|
|
||||||
{
|
|
||||||
public class LocationToVisibilityConverter : IMultiValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
var visibility = Visibility.Hidden;
|
|
||||||
|
|
||||||
if (values.Length == 2 && values[0] is MapBase && values[1] is Point?)
|
|
||||||
{
|
|
||||||
var parentMap = (MapBase)values[0];
|
|
||||||
var position = (Point?)values[1];
|
|
||||||
|
|
||||||
if (position.HasValue &&
|
|
||||||
position.Value.X >= 0d && position.Value.X <= parentMap.ActualWidth &&
|
|
||||||
position.Value.Y >= 0d && position.Value.Y <= parentMap.ActualHeight)
|
|
||||||
{
|
|
||||||
visibility = Visibility.Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,221 +0,0 @@
|
||||||
<Window x:Class="WpfCoreApp.MainWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:map="clr-namespace:MapControl;assembly=MapControl.WPF"
|
|
||||||
xmlns:vm="clr-namespace:ViewModel"
|
|
||||||
xmlns:local="clr-namespace:WpfCoreApp"
|
|
||||||
Title="XAML MapControl - WPF .NET Core 3.0 Test Application" Height="600" Width="800">
|
|
||||||
<Window.Resources>
|
|
||||||
<local:LocationToVisibilityConverter x:Key="LocationToVisibilityConverter"/>
|
|
||||||
|
|
||||||
<DataTemplate x:Key="PolylineItemTemplate">
|
|
||||||
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<Style x:Key="PolylineItemStyle" TargetType="map:MapItem">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="map:MapItem">
|
|
||||||
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="PointItemStyle" TargetType="map:MapItem">
|
|
||||||
<!--<EventSetter Event="TouchDown" Handler="MapItemTouchDown"/>-->
|
|
||||||
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
|
|
||||||
<Setter Property="Foreground" Value="Black"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="map:MapItem">
|
|
||||||
<Canvas>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal"/>
|
|
||||||
<VisualState x:Name="Disabled"/>
|
|
||||||
<VisualState x:Name="MouseOver">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Storyboard.TargetName="labelBackground" Storyboard.TargetProperty="Opacity" To="0.7" Duration="0:0:0.1"/>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
<VisualStateGroup x:Name="SelectionStates">
|
|
||||||
<VisualState x:Name="Unselected"/>
|
|
||||||
<VisualState x:Name="Selected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Storyboard.TargetName="selectedPath" Storyboard.TargetProperty="Opacity" To="0.7" Duration="0:0:0.1"/>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
<Path x:Name="selectedPath" Fill="White" Opacity="0">
|
|
||||||
<Path.Data>
|
|
||||||
<EllipseGeometry RadiusX="15" RadiusY="15"/>
|
|
||||||
</Path.Data>
|
|
||||||
</Path>
|
|
||||||
<Path StrokeThickness="2" Fill="Transparent">
|
|
||||||
<Path.Stroke>
|
|
||||||
<SolidColorBrush Color="Gray"/>
|
|
||||||
</Path.Stroke>
|
|
||||||
<Path.Data>
|
|
||||||
<EllipseGeometry RadiusX="8" RadiusY="8"/>
|
|
||||||
</Path.Data>
|
|
||||||
</Path>
|
|
||||||
<Grid Canvas.Left="15" Canvas.Top="-8">
|
|
||||||
<Rectangle x:Name="labelBackground" Fill="White" Opacity="0"/>
|
|
||||||
<local:OutlinedText Margin="1" OutlineThickness="1.5" Text="{Binding Name}"/>
|
|
||||||
</Grid>
|
|
||||||
</Canvas>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Style.Triggers>
|
|
||||||
<Trigger Property="IsSelected" Value="True">
|
|
||||||
<Setter Property="Panel.ZIndex" Value="1"/>
|
|
||||||
</Trigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="PushpinItemStyle" TargetType="map:MapItem">
|
|
||||||
<EventSetter Event="TouchDown" Handler="MapItemTouchDown"/>
|
|
||||||
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
|
|
||||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
|
||||||
<Setter Property="Foreground" Value="Black"/>
|
|
||||||
<Setter Property="Visibility">
|
|
||||||
<Setter.Value>
|
|
||||||
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
|
||||||
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
|
||||||
<Binding Path="(map:MapPanel.ViewportPosition)" RelativeSource="{RelativeSource Self}"/>
|
|
||||||
</MultiBinding>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="map:MapItem">
|
|
||||||
<map:Pushpin Content="{Binding Name}" Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Style.Triggers>
|
|
||||||
<Trigger Property="IsSelected" Value="True">
|
|
||||||
<Setter Property="Panel.ZIndex" Value="1"/>
|
|
||||||
<Setter Property="Foreground" Value="OrangeRed"/>
|
|
||||||
</Trigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<map:WebMercatorProjection x:Key="WebMercatorProjection"/>
|
|
||||||
<map:WorldMercatorProjection x:Key="WorldMercatorProjection"/>
|
|
||||||
<map:EquirectangularProjection x:Key="EquirectangularProjection"/>
|
|
||||||
<map:OrthographicProjection x:Key="OrthographicProjection"/>
|
|
||||||
<map:GnomonicProjection x:Key="GnomonicProjection"/>
|
|
||||||
<map:StereographicProjection x:Key="StereographicProjection"/>
|
|
||||||
</Window.Resources>
|
|
||||||
|
|
||||||
<Window.DataContext>
|
|
||||||
<vm:MapViewModel/>
|
|
||||||
</Window.DataContext>
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<map:Map x:Name="map" ZoomLevel="11" MaxZoomLevel="21"
|
|
||||||
Center="{Binding MapCenter}"
|
|
||||||
MapLayer="{Binding MapLayers.CurrentMapLayer}"
|
|
||||||
MapProjection="{Binding SelectedValue, ElementName=projectionComboBox,
|
|
||||||
FallbackValue={StaticResource WebMercatorProjection},
|
|
||||||
TargetNullValue={StaticResource WebMercatorProjection}}"
|
|
||||||
MouseLeftButtonDown="MapMouseLeftButtonDown"
|
|
||||||
MouseRightButtonDown="MapMouseRightButtonDown"
|
|
||||||
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave"
|
|
||||||
ManipulationInertiaStarting="MapManipulationInertiaStarting">
|
|
||||||
|
|
||||||
<Image x:Name="mapImage" Source="10_535_330.jpg" Opacity="0.5" Stretch="Fill"
|
|
||||||
map:MapPanel.BoundingBox="53.54031,8.08594,53.74871,8.43750"/>
|
|
||||||
|
|
||||||
<map:MapGraticule x:Name="mapGraticule" Opacity="0.6"/>
|
|
||||||
<map:MapScale HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
|
|
||||||
|
|
||||||
<!-- use ItemTemplate or ItemContainerStyle alternatively -->
|
|
||||||
<map:MapItemsControl ItemsSource="{Binding Polylines}"
|
|
||||||
ItemTemplate="{StaticResource PolylineItemTemplate}"/>
|
|
||||||
<!--<map:MapItemsControl ItemsSource="{Binding Polylines}"
|
|
||||||
ItemContainerStyle="{StaticResource PolylineItemStyle}"/>-->
|
|
||||||
|
|
||||||
<map:MapItemsControl ItemsSource="{Binding Points}"
|
|
||||||
ItemContainerStyle="{StaticResource PointItemStyle}"
|
|
||||||
SelectionMode="Extended"/>
|
|
||||||
|
|
||||||
<map:MapItemsControl ItemsSource="{Binding Pushpins}"
|
|
||||||
ItemContainerStyle="{StaticResource PushpinItemStyle}"/>
|
|
||||||
|
|
||||||
<map:Pushpin map:MapPanel.Location="65,-18" Content="Iceland"/>
|
|
||||||
<map:Pushpin map:MapPanel.Location="71,25" Content="Norway"/>
|
|
||||||
<map:Pushpin map:MapPanel.Location="35,33" Content="Cyprus"/>
|
|
||||||
<map:Pushpin map:MapPanel.Location="28.25,-16.5" Content="Tenerife"/>
|
|
||||||
|
|
||||||
<Path map:MapPanel.Location="53.5,8.2" Stroke="Blue" StrokeThickness="3" Fill="#1F007F00">
|
|
||||||
<Path.Data>
|
|
||||||
<EllipseGeometry RadiusX="1852" RadiusY="1852" Transform="{Binding ScaleRotateTransform, ElementName=map}"/>
|
|
||||||
</Path.Data>
|
|
||||||
</Path>
|
|
||||||
|
|
||||||
<map:Pushpin map:MapPanel.Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53°30' E 8°12'">
|
|
||||||
<map:Pushpin.Visibility>
|
|
||||||
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
|
|
||||||
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
|
|
||||||
<Binding Path="(map:MapPanel.ViewportPosition)" RelativeSource="{RelativeSource Self}"/>
|
|
||||||
</MultiBinding>
|
|
||||||
</map:Pushpin.Visibility>
|
|
||||||
</map:Pushpin>
|
|
||||||
</map:Map>
|
|
||||||
|
|
||||||
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#7FFFFFFF">
|
|
||||||
<TextBlock Margin="2" FontSize="10" map:HyperlinkText.InlinesSource="{Binding MapLayer.Description, ElementName=map}"/>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Grid Grid.Row="1">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock x:Name="mouseLocation" Margin="5" VerticalAlignment="Bottom" FontFamily="Segoe UI Mono"/>
|
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
|
|
||||||
<StackPanel Margin="5">
|
|
||||||
<TextBlock Text="Zoom Level" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
|
|
||||||
<Slider ToolTip="Zoom Level" Width="100" VerticalAlignment="Center" SmallChange="0.01"
|
|
||||||
Minimum="{Binding MinZoomLevel, ElementName=map}"
|
|
||||||
Maximum="{Binding MaxZoomLevel, ElementName=map}"
|
|
||||||
Value="{Binding TargetZoomLevel, ElementName=map}"/>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="5">
|
|
||||||
<TextBlock Text="Heading" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
|
|
||||||
<Slider ToolTip="Heading" Width="100" VerticalAlignment="Center" SmallChange="5" LargeChange="45"
|
|
||||||
Minimum="0" Maximum="360" Value="{Binding TargetHeading, ElementName=map}"/>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="5">
|
|
||||||
<TextBlock Text="Image Opacity" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
|
|
||||||
<Slider ToolTip="Image Opacity" Width="100" VerticalAlignment="Center"
|
|
||||||
Minimum="0" Maximum="1" Value="{Binding Opacity, ElementName=mapImage}"/>
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox ToolTip="Seamarks Overlay" Margin="7" VerticalAlignment="Bottom" Content="Seamarks"
|
|
||||||
Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
|
|
||||||
<ComboBox ToolTip="Map Layer" Width="200" Margin="5" VerticalAlignment="Bottom"
|
|
||||||
ItemsSource="{Binding MapLayers.MapLayerNames}"
|
|
||||||
SelectedItem="{Binding MapLayers.CurrentMapLayerName}"/>
|
|
||||||
<ComboBox x:Name="projectionComboBox" ToolTip="Map Projection" Width="120" Margin="5" VerticalAlignment="Bottom"
|
|
||||||
SelectedValuePath="Tag" SelectedIndex="0">
|
|
||||||
<ComboBoxItem Content="Web Mercator" Tag="{StaticResource WebMercatorProjection}"/>
|
|
||||||
<ComboBoxItem Content="World Mercator" Tag="{StaticResource WorldMercatorProjection}"/>
|
|
||||||
<ComboBoxItem Content="Equirectangular" Tag="{StaticResource EquirectangularProjection}"/>
|
|
||||||
<ComboBoxItem Content="Orthographic" Tag="{StaticResource OrthographicProjection}"/>
|
|
||||||
<ComboBoxItem Content="Gnomonic" Tag="{StaticResource GnomonicProjection}"/>
|
|
||||||
<ComboBoxItem Content="Stereographic" Tag="{StaticResource StereographicProjection}"/>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using MapControl;
|
|
||||||
using ViewModel;
|
|
||||||
|
|
||||||
namespace WpfCoreApp
|
|
||||||
{
|
|
||||||
public partial class MainWindow : Window
|
|
||||||
{
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application");
|
|
||||||
//TileImageLoader.Cache = new MapControl.Caching.ImageFileCache(TileImageLoader.DefaultCacheFolder);
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.ClickCount == 2)
|
|
||||||
{
|
|
||||||
//map.ZoomMap(e.GetPosition(map), Math.Floor(map.ZoomLevel + 1.5));
|
|
||||||
//map.ZoomToBounds(new BoundingBox(53, 7, 54, 9));
|
|
||||||
map.TargetCenter = map.ViewportPointToLocation(e.GetPosition(map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.ClickCount == 2)
|
|
||||||
{
|
|
||||||
//map.ZoomMap(e.GetPosition(map), Math.Ceiling(map.ZoomLevel - 1.5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapMouseMove(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
var location = map.ViewportPointToLocation(e.GetPosition(map));
|
|
||||||
var latitude = (int)Math.Round(location.Latitude * 60000d);
|
|
||||||
var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d);
|
|
||||||
var latHemisphere = 'N';
|
|
||||||
var lonHemisphere = 'E';
|
|
||||||
|
|
||||||
if (latitude < 0)
|
|
||||||
{
|
|
||||||
latitude = -latitude;
|
|
||||||
latHemisphere = 'S';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (longitude < 0)
|
|
||||||
{
|
|
||||||
longitude = -longitude;
|
|
||||||
lonHemisphere = 'W';
|
|
||||||
}
|
|
||||||
|
|
||||||
mouseLocation.Text = string.Format(CultureInfo.InvariantCulture,
|
|
||||||
"{0} {1:00} {2:00.000}\n{3} {4:000} {5:00.000}",
|
|
||||||
latHemisphere, latitude / 60000, (latitude % 60000) / 1000d,
|
|
||||||
lonHemisphere, longitude / 60000, (longitude % 60000) / 1000d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapMouseLeave(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
mouseLocation.Text = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
|
|
||||||
{
|
|
||||||
e.TranslationBehavior.DesiredDeceleration = 0.001;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MapItemTouchDown(object sender, TouchEventArgs e)
|
|
||||||
{
|
|
||||||
var mapItem = (MapItem)sender;
|
|
||||||
mapItem.IsSelected = !mapItem.IsSelected;
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SeamarksChecked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
map.Children.Insert(map.Children.IndexOf(mapGraticule), ((MapViewModel)DataContext).MapLayers.SeamarksLayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SeamarksUnchecked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
map.Children.Remove(((MapViewModel)DataContext).MapLayers.SeamarksLayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace WpfCoreApp
|
|
||||||
{
|
|
||||||
public class OutlinedText : FrameworkElement
|
|
||||||
{
|
|
||||||
private GlyphRun glyphRun;
|
|
||||||
private Geometry outline;
|
|
||||||
|
|
||||||
public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FontStyleProperty = TextBlock.FontStyleProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FontWeightProperty = TextBlock.FontWeightProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FontStretchProperty = TextBlock.FontStretchProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty BackgroundProperty = TextBlock.BackgroundProperty.AddOwner(
|
|
||||||
typeof(OutlinedText), new FrameworkPropertyMetadata(Brushes.White, (o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
|
||||||
|
|
||||||
public static readonly DependencyProperty OutlineThicknessProperty = DependencyProperty.Register(
|
|
||||||
"OutlineThickness", typeof(double), typeof(OutlinedText),
|
|
||||||
new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((OutlinedText)o).glyphRun = null));
|
|
||||||
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get { return (string)GetValue(TextProperty); }
|
|
||||||
set { SetValue(TextProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public double FontSize
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(FontSizeProperty); }
|
|
||||||
set { SetValue(FontSizeProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public FontFamily FontFamily
|
|
||||||
{
|
|
||||||
get { return (FontFamily)GetValue(FontFamilyProperty); }
|
|
||||||
set { SetValue(FontFamilyProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public FontStyle FontStyle
|
|
||||||
{
|
|
||||||
get { return (FontStyle)GetValue(FontStyleProperty); }
|
|
||||||
set { SetValue(FontStyleProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public FontWeight FontWeight
|
|
||||||
{
|
|
||||||
get { return (FontWeight)GetValue(FontWeightProperty); }
|
|
||||||
set { SetValue(FontWeightProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public FontStretch FontStretch
|
|
||||||
{
|
|
||||||
get { return (FontStretch)GetValue(FontStretchProperty); }
|
|
||||||
set { SetValue(FontStretchProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Brush Foreground
|
|
||||||
{
|
|
||||||
get { return (Brush)GetValue(ForegroundProperty); }
|
|
||||||
set { SetValue(ForegroundProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Brush Background
|
|
||||||
{
|
|
||||||
get { return (Brush)GetValue(BackgroundProperty); }
|
|
||||||
set { SetValue(BackgroundProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public double OutlineThickness
|
|
||||||
{
|
|
||||||
get { return (double)GetValue(OutlineThicknessProperty); }
|
|
||||||
set { SetValue(OutlineThicknessProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
|
||||||
{
|
|
||||||
return CheckGlyphRun() ? outline.Bounds.Size : new Size();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnRender(DrawingContext drawingContext)
|
|
||||||
{
|
|
||||||
if (CheckGlyphRun())
|
|
||||||
{
|
|
||||||
var location = outline.Bounds.Location;
|
|
||||||
drawingContext.PushTransform(new TranslateTransform(-location.X, -location.Y));
|
|
||||||
drawingContext.DrawGeometry(Background, null, outline);
|
|
||||||
drawingContext.DrawGlyphRun(Foreground, glyphRun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckGlyphRun()
|
|
||||||
{
|
|
||||||
if (glyphRun == null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(Text))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
|
||||||
GlyphTypeface glyphTypeface;
|
|
||||||
|
|
||||||
if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var glyphIndices = new ushort[Text.Length];
|
|
||||||
var advanceWidths = new double[Text.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < Text.Length; i++)
|
|
||||||
{
|
|
||||||
var glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[i]];
|
|
||||||
glyphIndices[i] = glyphIndex;
|
|
||||||
advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * FontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
glyphRun = new GlyphRun(glyphTypeface, 0, false, FontSize, 1f, glyphIndices, new Point(), advanceWidths, null, null, null, null, null, null);
|
|
||||||
|
|
||||||
outline = glyphRun.BuildGeometry().GetWidenedPathGeometry(new Pen(null, OutlineThickness * 2d));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<RootNamespace>WpfCoreApp</RootNamespace>
|
|
||||||
<Product>XAML Map Control</Product>
|
|
||||||
<Version>5.0.0</Version>
|
|
||||||
<Description>XAML Map Control WPF Sample Application</Description>
|
|
||||||
<Authors>Clemens Fischer</Authors>
|
|
||||||
<Copyright>Copyright © 2020 Clemens Fischer</Copyright>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
|
||||||
<DefineConstants></DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="..\Shared\MapLayers.cs" Link="MapLayers.cs" />
|
|
||||||
<Compile Include="..\Shared\MapViewModel.cs" Link="MapViewModel.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MapControl\WPF\MapControl.WPF.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="..\Shared\10_535_330.jpg" Link="10_535_330.jpg" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
Loading…
Reference in a new issue