mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Added Location
This commit is contained in:
parent
caab7208a3
commit
a98f59e1a9
|
|
@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
# Visual Studio 2010
|
# Visual Studio 2010
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl", "MapControl\MapControl.csproj", "{06481252-2310-414A-B9FC-D5739FDF6BD3}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl", "MapControl\MapControl.csproj", "{06481252-2310-414A-B9FC-D5739FDF6BD3}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "TestApplication\TestApplication.csproj", "{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -23,6 +25,16 @@ Global
|
||||||
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|x86.ActiveCfg = Release|Any CPU
|
{06481252-2310-414A-B9FC-D5739FDF6BD3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}.Release|x86.Build.0 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains helper methods for creating GlyphRun objects.
|
||||||
|
/// </summary>
|
||||||
public static class GlyphRunText
|
public static class GlyphRunText
|
||||||
{
|
{
|
||||||
public static GlyphRun Create(string text, Typeface typeface, double emSize, Point baselineOrigin)
|
public static GlyphRun Create(string text, Typeface typeface, double emSize, Point baselineOrigin)
|
||||||
|
|
|
||||||
51
MapControl/Location.cs
Normal file
51
MapControl/Location.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A geographic location given as latitude and longitude.
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(LocationConverter))]
|
||||||
|
public class Location
|
||||||
|
{
|
||||||
|
public Location()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location(double latitude, double longitude)
|
||||||
|
{
|
||||||
|
Latitude = latitude;
|
||||||
|
Longitude = longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Latitude { get; set; }
|
||||||
|
public double Longitude { get; set; }
|
||||||
|
|
||||||
|
public static Location Parse(string source)
|
||||||
|
{
|
||||||
|
Point p = Point.Parse(source);
|
||||||
|
return new Location(p.X, p.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.00000},{1:0.00000}", Latitude, Longitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocationConverter : TypeConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||||
|
{
|
||||||
|
return sourceType == typeof(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
|
{
|
||||||
|
return Location.Parse((string)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
MapControl/LocationAnimation.cs
Normal file
50
MapControl/LocationAnimation.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Animates the value of a Location property between two values.
|
||||||
|
/// </summary>
|
||||||
|
public class LocationAnimation : AnimationTimeline
|
||||||
|
{
|
||||||
|
public Location From { get; set; }
|
||||||
|
public Location To { get; set; }
|
||||||
|
public IEasingFunction EasingFunction { get; set; }
|
||||||
|
|
||||||
|
public override Type TargetPropertyType
|
||||||
|
{
|
||||||
|
get { return typeof(Location); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Freezable CreateInstanceCore()
|
||||||
|
{
|
||||||
|
return new LocationAnimation
|
||||||
|
{
|
||||||
|
From = From,
|
||||||
|
To = To,
|
||||||
|
EasingFunction = EasingFunction
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
|
||||||
|
{
|
||||||
|
if (!animationClock.CurrentProgress.HasValue)
|
||||||
|
{
|
||||||
|
return defaultOriginValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double progress = animationClock.CurrentProgress.Value;
|
||||||
|
|
||||||
|
if (EasingFunction != null)
|
||||||
|
{
|
||||||
|
progress = EasingFunction.Ease(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Location(
|
||||||
|
(1d - progress) * From.Latitude + progress * To.Latitude,
|
||||||
|
(1d - progress) * From.Longitude + progress * To.Longitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
MapControl/LocationCollection.cs
Normal file
52
MapControl/LocationCollection.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of geographic locations.
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(LocationCollectionConverter))]
|
||||||
|
public class LocationCollection : ObservableCollection<Location>
|
||||||
|
{
|
||||||
|
public LocationCollection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocationCollection(IEnumerable<Location> locations)
|
||||||
|
{
|
||||||
|
foreach (Location location in locations)
|
||||||
|
{
|
||||||
|
Add(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocationCollection Parse(string source)
|
||||||
|
{
|
||||||
|
LocationCollection locations = new LocationCollection();
|
||||||
|
|
||||||
|
foreach (string locString in source.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
locations.Add(Location.Parse(locString));
|
||||||
|
}
|
||||||
|
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocationCollectionConverter : TypeConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||||
|
{
|
||||||
|
return sourceType == typeof(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
|
{
|
||||||
|
return LocationCollection.Parse((string)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
@ -7,6 +11,12 @@ using System.Windows.Media.Animation;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main map control. Draws map content provided by the TileLayers or the MainTileLayer property.
|
||||||
|
/// The visible map area is defined by the Center and ZoomLevel properties. The map can be rotated
|
||||||
|
/// by an angle that is given by the Heading property.
|
||||||
|
/// Map is a MapPanel and hence can contain map overlays like other MapPanels or MapItemsControls.
|
||||||
|
/// </summary>
|
||||||
public partial class Map : MapPanel
|
public partial class Map : MapPanel
|
||||||
{
|
{
|
||||||
public const double MeterPerDegree = 1852d * 60d;
|
public const double MeterPerDegree = 1852d * 60d;
|
||||||
|
|
@ -34,24 +44,24 @@ namespace MapControl
|
||||||
"TileLayers", typeof(TileLayerCollection), typeof(Map), new FrameworkPropertyMetadata(
|
"TileLayers", typeof(TileLayerCollection), typeof(Map), new FrameworkPropertyMetadata(
|
||||||
(o, e) => ((Map)o).SetTileLayers((TileLayerCollection)e.NewValue)));
|
(o, e) => ((Map)o).SetTileLayers((TileLayerCollection)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty BaseTileLayerProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MainTileLayerProperty = DependencyProperty.Register(
|
||||||
"BaseTileLayer", typeof(TileLayer), typeof(Map), new FrameworkPropertyMetadata(
|
"MainTileLayer", typeof(TileLayer), typeof(Map), new FrameworkPropertyMetadata(
|
||||||
(o, e) => ((Map)o).SetBaseTileLayer((TileLayer)e.NewValue),
|
(o, e) => ((Map)o).SetMainTileLayer((TileLayer)e.NewValue),
|
||||||
(o, v) => ((Map)o).CoerceBaseTileLayer((TileLayer)v)));
|
(o, v) => ((Map)o).CoerceMainTileLayer((TileLayer)v)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TileOpacityProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TileOpacityProperty = DependencyProperty.Register(
|
||||||
"TileOpacity", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d,
|
"TileOpacity", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d,
|
||||||
(o, e) => ((Map)o).tileContainer.Opacity = (double)e.NewValue));
|
(o, e) => ((Map)o).tileContainer.Opacity = (double)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
||||||
"Center", typeof(Point), typeof(Map), new FrameworkPropertyMetadata(new Point(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
"Center", typeof(Location), typeof(Map), new FrameworkPropertyMetadata(new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((Map)o).SetCenter((Point)e.NewValue),
|
(o, e) => ((Map)o).SetCenter((Location)e.NewValue),
|
||||||
(o, v) => ((Map)o).CoerceCenter((Point)v)));
|
(o, v) => ((Map)o).CoerceCenter((Location)v)));
|
||||||
|
|
||||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
||||||
"TargetCenter", typeof(Point), typeof(Map), new FrameworkPropertyMetadata(new Point(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
"TargetCenter", typeof(Location), typeof(Map), new FrameworkPropertyMetadata(new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
(o, e) => ((Map)o).SetTargetCenter((Point)e.NewValue),
|
(o, e) => ((Map)o).SetTargetCenter((Location)e.NewValue),
|
||||||
(o, v) => ((Map)o).CoerceCenter((Point)v)));
|
(o, v) => ((Map)o).CoerceCenter((Location)v)));
|
||||||
|
|
||||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
||||||
"ZoomLevel", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
"ZoomLevel", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||||
|
|
@ -79,13 +89,13 @@ namespace MapControl
|
||||||
public static readonly DependencyProperty CenterScaleProperty = CenterScalePropertyKey.DependencyProperty;
|
public static readonly DependencyProperty CenterScaleProperty = CenterScalePropertyKey.DependencyProperty;
|
||||||
|
|
||||||
private readonly TileContainer tileContainer = new TileContainer();
|
private readonly TileContainer tileContainer = new TileContainer();
|
||||||
private readonly MapViewTransform mapViewTransform = new MapViewTransform();
|
private readonly MapTransform mapTransform = new MercatorTransform();
|
||||||
private readonly ScaleTransform scaleTransform = new ScaleTransform();
|
private readonly ScaleTransform scaleTransform = new ScaleTransform();
|
||||||
private readonly RotateTransform rotateTransform = new RotateTransform();
|
private readonly RotateTransform rotateTransform = new RotateTransform();
|
||||||
private readonly MatrixTransform scaleRotateTransform = new MatrixTransform();
|
private readonly MatrixTransform scaleRotateTransform = new MatrixTransform();
|
||||||
private Point? transformOrigin;
|
private Location transformOrigin;
|
||||||
private Point viewOrigin;
|
private Point viewportOrigin;
|
||||||
private PointAnimation centerAnimation;
|
private LocationAnimation centerAnimation;
|
||||||
private DoubleAnimation zoomLevelAnimation;
|
private DoubleAnimation zoomLevelAnimation;
|
||||||
private DoubleAnimation headingAnimation;
|
private DoubleAnimation headingAnimation;
|
||||||
private bool updateTransform = true;
|
private bool updateTransform = true;
|
||||||
|
|
@ -96,9 +106,8 @@ namespace MapControl
|
||||||
MaxZoomLevel = 20;
|
MaxZoomLevel = 20;
|
||||||
|
|
||||||
AddVisualChild(tileContainer);
|
AddVisualChild(tileContainer);
|
||||||
mapViewTransform.ViewTransform = tileContainer.ViewTransform;
|
|
||||||
|
|
||||||
BaseTileLayer = new TileLayer
|
MainTileLayer = new TileLayer
|
||||||
{
|
{
|
||||||
Description = "© {y} OpenStreetMap Contributors, CC-BY-SA",
|
Description = "© {y} OpenStreetMap Contributors, CC-BY-SA",
|
||||||
TileSource = new OpenStreetMapTileSource { UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png" }
|
TileSource = new OpenStreetMapTileSource { UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png" }
|
||||||
|
|
@ -190,12 +199,12 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the base TileLayer used by this Map, i.e. TileLayers[0].
|
/// Gets or sets the main TileLayer used by this Map, i.e. TileLayers[0].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TileLayer BaseTileLayer
|
public TileLayer MainTileLayer
|
||||||
{
|
{
|
||||||
get { return (TileLayer)GetValue(BaseTileLayerProperty); }
|
get { return (TileLayer)GetValue(MainTileLayerProperty); }
|
||||||
set { SetValue(BaseTileLayerProperty, value); }
|
set { SetValue(MainTileLayerProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -208,20 +217,20 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the world coordinates (latitude and longitude) of the center point.
|
/// Gets or sets the location of the center point of the Map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point Center
|
public Location Center
|
||||||
{
|
{
|
||||||
get { return (Point)GetValue(CenterProperty); }
|
get { return (Location)GetValue(CenterProperty); }
|
||||||
set { SetValue(CenterProperty, value); }
|
set { SetValue(CenterProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the target value of a Center animation.
|
/// Gets or sets the target value of a Center animation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point TargetCenter
|
public Location TargetCenter
|
||||||
{
|
{
|
||||||
get { return (Point)GetValue(TargetCenterProperty); }
|
get { return (Location)GetValue(TargetCenterProperty); }
|
||||||
set { SetValue(TargetCenterProperty, value); }
|
set { SetValue(TargetCenterProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,7 +271,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the map scale at the Center point as view coordinate units (pixels) per meter.
|
/// Gets the map scale at the Center location as viewport coordinate units (pixels) per meter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CenterScale
|
public double CenterScale
|
||||||
{
|
{
|
||||||
|
|
@ -271,34 +280,24 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transformation from world coordinates (latitude and longitude)
|
/// Gets the transformation from geographic coordinates to cartesian map coordinates.
|
||||||
/// to cartesian map coordinates.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MapTransform MapTransform
|
public MapTransform MapTransform
|
||||||
{
|
{
|
||||||
get { return mapViewTransform.MapTransform; }
|
get { return mapTransform; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the transformation from cartesian map coordinates to view coordinates.
|
/// Gets the transformation from cartesian map coordinates to viewport coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Transform ViewTransform
|
public Transform ViewportTransform
|
||||||
{
|
{
|
||||||
get { return mapViewTransform.ViewTransform; }
|
get { return tileContainer.ViewportTransform; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the combination of MapTransform and ViewTransform, i.e. the transformation
|
/// Gets the scaling transformation from meters to viewport coordinate units (pixels)
|
||||||
/// from longitude and latitude values to view coordinates.
|
/// at the viewport center point.
|
||||||
/// </summary>
|
|
||||||
public GeneralTransform MapViewTransform
|
|
||||||
{
|
|
||||||
get { return mapViewTransform; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the scaling transformation from meters to view coordinate units (pixels)
|
|
||||||
/// at the view center point.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Transform ScaleTransform
|
public Transform ScaleTransform
|
||||||
{
|
{
|
||||||
|
|
@ -322,57 +321,73 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets an intermittent origin point in world coordinates for scaling and rotation transformations.
|
/// Transforms a geographic location to a viewport coordinates point.
|
||||||
|
/// </summary>
|
||||||
|
public Point LocationToViewportPoint(Location location)
|
||||||
|
{
|
||||||
|
return ViewportTransform.Transform(MapTransform.Transform(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a viewport coordinates point to a geographic location.
|
||||||
|
/// </summary>
|
||||||
|
public Location ViewportPointToLocation(Point point)
|
||||||
|
{
|
||||||
|
return MapTransform.TransformBack(ViewportTransform.Inverse.Transform(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a temporary origin location in geographic coordinates for scaling and rotation transformations.
|
||||||
|
/// This origin location is automatically removed when the Center property is set by application code.
|
||||||
|
/// </summary>
|
||||||
|
public void SetTransformOrigin(Location origin)
|
||||||
|
{
|
||||||
|
transformOrigin = origin;
|
||||||
|
viewportOrigin = LocationToViewportPoint(origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a temporary origin point in viewport coordinates for scaling and rotation transformations.
|
||||||
/// This origin point is automatically removed when the Center property is set by application code.
|
/// This origin point is automatically removed when the Center property is set by application code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetTransformOrigin(Point origin)
|
public void SetTransformOrigin(Point origin)
|
||||||
{
|
{
|
||||||
transformOrigin = origin;
|
viewportOrigin.X = Math.Min(Math.Max(origin.X, 0d), RenderSize.Width);
|
||||||
viewOrigin = MapViewTransform.Transform(origin);
|
viewportOrigin.Y = Math.Min(Math.Max(origin.Y, 0d), RenderSize.Height);
|
||||||
|
transformOrigin = CoerceCenter(ViewportPointToLocation(viewportOrigin));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets an intermittent origin point in view coordinates for scaling and rotation transformations.
|
/// Removes the temporary transform origin point set by SetTransformOrigin.
|
||||||
/// This origin point is automatically removed when the Center property is set by application code.
|
|
||||||
/// </summary>
|
|
||||||
public void SetTransformViewOrigin(Point origin)
|
|
||||||
{
|
|
||||||
viewOrigin.X = Math.Min(Math.Max(origin.X, 0d), RenderSize.Width);
|
|
||||||
viewOrigin.Y = Math.Min(Math.Max(origin.Y, 0d), RenderSize.Height);
|
|
||||||
transformOrigin = CoerceCenter(MapViewTransform.Inverse.Transform(viewOrigin));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the intermittent transform origin point set by SetTransformOrigin.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ResetTransformOrigin()
|
public void ResetTransformOrigin()
|
||||||
{
|
{
|
||||||
transformOrigin = null;
|
transformOrigin = null;
|
||||||
viewOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
viewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the Center property according to the specified translation in view coordinates.
|
/// Changes the Center property according to the specified translation in viewport coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TranslateMap(Vector translation)
|
public void TranslateMap(Vector translation)
|
||||||
{
|
{
|
||||||
if (translation.X != 0d || translation.Y != 0d)
|
if (translation.X != 0d || translation.Y != 0d)
|
||||||
{
|
{
|
||||||
ResetTransformOrigin();
|
ResetTransformOrigin();
|
||||||
Center = MapViewTransform.Inverse.Transform(viewOrigin - translation);
|
Center = ViewportPointToLocation(viewportOrigin - 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
|
||||||
/// view coordinate translation, rotation and scale delta values. Rotation and scaling
|
/// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||||
/// is performed relative to the specified origin point in view coordinates.
|
/// is performed relative to the specified origin point in viewport coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TransformMap(Point origin, Vector translation, double rotation, double scale)
|
public void TransformMap(Point origin, Vector translation, double rotation, double scale)
|
||||||
{
|
{
|
||||||
if (rotation != 0d || scale != 1d)
|
if (rotation != 0d || scale != 1d)
|
||||||
{
|
{
|
||||||
SetTransformViewOrigin(origin);
|
SetTransformOrigin(origin);
|
||||||
updateTransform = false;
|
updateTransform = false;
|
||||||
Heading += rotation;
|
Heading += rotation;
|
||||||
ZoomLevel += Math.Log(scale, 2d);
|
ZoomLevel += Math.Log(scale, 2d);
|
||||||
|
|
@ -385,21 +400,20 @@ namespace MapControl
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the value of the ZoomLevel property while retaining the specified origin point
|
/// Sets the value of the ZoomLevel property while retaining the specified origin point
|
||||||
/// in view coordinates.
|
/// in viewport coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomMap(Point origin, double zoomLevel)
|
public void ZoomMap(Point origin, double zoomLevel)
|
||||||
{
|
{
|
||||||
SetTransformViewOrigin(origin);
|
SetTransformOrigin(origin);
|
||||||
TargetZoomLevel = zoomLevel;
|
TargetZoomLevel = zoomLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the map scale at the specified world coordinate point
|
/// Gets the map scale at the specified location as viewport coordinate units (pixels) per meter.
|
||||||
/// as view coordinate units (pixels) per meter.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double GetMapScale(Point point)
|
public double GetMapScale(Location location)
|
||||||
{
|
{
|
||||||
return MapTransform.RelativeScale(point) * Math.Pow(2d, ZoomLevel) * 256d / (MeterPerDegree * 360d);
|
return mapTransform.RelativeScale(location) * Math.Pow(2d, ZoomLevel) * 256d / (MeterPerDegree * 360d);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override int VisualChildrenCount
|
protected override int VisualChildrenCount
|
||||||
|
|
@ -477,40 +491,40 @@ namespace MapControl
|
||||||
|
|
||||||
private void SetTileLayers(TileLayerCollection tileLayers)
|
private void SetTileLayers(TileLayerCollection tileLayers)
|
||||||
{
|
{
|
||||||
BaseTileLayer = tileLayers.Count > 0 ? tileLayers[0] : null;
|
MainTileLayer = tileLayers.Count > 0 ? tileLayers[0] : null;
|
||||||
tileContainer.TileLayers = tileLayers;
|
tileContainer.TileLayers = tileLayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetBaseTileLayer(TileLayer baseTileLayer)
|
private void SetMainTileLayer(TileLayer mainTileLayer)
|
||||||
{
|
{
|
||||||
if (baseTileLayer != null)
|
if (mainTileLayer != null)
|
||||||
{
|
{
|
||||||
if (TileLayers == null)
|
if (TileLayers == null)
|
||||||
{
|
{
|
||||||
TileLayers = new TileLayerCollection(baseTileLayer);
|
TileLayers = new TileLayerCollection(mainTileLayer);
|
||||||
}
|
}
|
||||||
else if (TileLayers.Count == 0)
|
else if (TileLayers.Count == 0)
|
||||||
{
|
{
|
||||||
TileLayers.Add(baseTileLayer);
|
TileLayers.Add(mainTileLayer);
|
||||||
}
|
}
|
||||||
else if (TileLayers[0] != baseTileLayer)
|
else if (TileLayers[0] != mainTileLayer)
|
||||||
{
|
{
|
||||||
TileLayers[0] = baseTileLayer;
|
TileLayers[0] = mainTileLayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TileLayer CoerceBaseTileLayer(TileLayer baseTileLayer)
|
private TileLayer CoerceMainTileLayer(TileLayer mainTileLayer)
|
||||||
{
|
{
|
||||||
if (baseTileLayer == null && TileLayers.Count > 0)
|
if (mainTileLayer == null && TileLayers.Count > 0)
|
||||||
{
|
{
|
||||||
baseTileLayer = TileLayers[0];
|
mainTileLayer = TileLayers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseTileLayer;
|
return mainTileLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCenter(Point center)
|
private void SetCenter(Location center)
|
||||||
{
|
{
|
||||||
if (updateTransform)
|
if (updateTransform)
|
||||||
{
|
{
|
||||||
|
|
@ -524,7 +538,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetTargetCenter(Point targetCenter)
|
private void SetTargetCenter(Location targetCenter)
|
||||||
{
|
{
|
||||||
if (targetCenter != Center)
|
if (targetCenter != Center)
|
||||||
{
|
{
|
||||||
|
|
@ -533,7 +547,7 @@ namespace MapControl
|
||||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
centerAnimation = new PointAnimation
|
centerAnimation = new LocationAnimation
|
||||||
{
|
{
|
||||||
From = Center,
|
From = Center,
|
||||||
To = targetCenter,
|
To = targetCenter,
|
||||||
|
|
@ -557,11 +571,11 @@ namespace MapControl
|
||||||
centerAnimation = null;
|
centerAnimation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Point CoerceCenter(Point point)
|
private Location CoerceCenter(Location location)
|
||||||
{
|
{
|
||||||
point.X = ((point.X + 180d) % 360d + 360d) % 360d - 180d;
|
location.Latitude = Math.Min(Math.Max(location.Latitude, -MapTransform.MaxLatitude), MapTransform.MaxLatitude);
|
||||||
point.Y = Math.Min(Math.Max(point.Y, -MapTransform.MaxLatitude), MapTransform.MaxLatitude);
|
location.Longitude = ((location.Longitude + 180d) % 360d + 360d) % 360d - 180d;
|
||||||
return point;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetZoomLevel(double zoomLevel)
|
private void SetZoomLevel(double zoomLevel)
|
||||||
|
|
@ -682,16 +696,16 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
double scale;
|
double scale;
|
||||||
|
|
||||||
if (transformOrigin.HasValue)
|
if (transformOrigin != null)
|
||||||
{
|
{
|
||||||
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(transformOrigin.Value), viewOrigin, RenderSize);
|
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(transformOrigin), viewportOrigin, RenderSize);
|
||||||
updateTransform = false;
|
updateTransform = false;
|
||||||
Center = MapViewTransform.Inverse.Transform(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
Center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||||
updateTransform = true;
|
updateTransform = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(Center), viewOrigin, RenderSize);
|
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(Center), viewportOrigin, RenderSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
scale *= MapTransform.RelativeScale(Center) / MeterPerDegree; // Pixels per meter at center latitude
|
scale *= MapTransform.RelativeScale(Center) / MeterPerDegree; // Pixels per meter at center latitude
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,11 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>none</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>
|
||||||
|
</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
@ -42,21 +43,20 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="GlyphRunText.cs" />
|
<Compile Include="GlyphRunText.cs" />
|
||||||
|
<Compile Include="Location.cs" />
|
||||||
|
<Compile Include="LocationAnimation.cs" />
|
||||||
|
<Compile Include="LocationCollection.cs" />
|
||||||
<Compile Include="MapElement.cs" />
|
<Compile Include="MapElement.cs" />
|
||||||
<Compile Include="MapGraticule.cs" />
|
<Compile Include="MapGraticule.cs" />
|
||||||
<Compile Include="MapItem.cs" />
|
<Compile Include="MapItem.cs" />
|
||||||
<Compile Include="MapItemsControl.cs" />
|
<Compile Include="MapItemsControl.cs" />
|
||||||
<Compile Include="MapPanel.cs" />
|
<Compile Include="MapPanel.cs" />
|
||||||
<Compile Include="MapPath.cs">
|
<Compile Include="MapPolygon.cs" />
|
||||||
<SubType>Code</SubType>
|
<Compile Include="MapPolyline.cs" />
|
||||||
</Compile>
|
|
||||||
<Compile Include="MapPathGeometry.cs" />
|
|
||||||
<Compile Include="MapStreamGeometry.cs" />
|
|
||||||
<Compile Include="TileImageLoader.cs" />
|
<Compile Include="TileImageLoader.cs" />
|
||||||
<Compile Include="MapTransform.cs" />
|
<Compile Include="MapTransform.cs" />
|
||||||
<Compile Include="Map.cs" />
|
<Compile Include="Map.cs" />
|
||||||
<Compile Include="MapInput.cs" />
|
<Compile Include="MapInput.cs" />
|
||||||
<Compile Include="MapViewTransform.cs" />
|
|
||||||
<Compile Include="MercatorTransform.cs" />
|
<Compile Include="MercatorTransform.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Tile.cs" />
|
<Compile Include="Tile.cs" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
|
|
@ -8,6 +12,9 @@ namespace MapControl
|
||||||
void ParentMapChanged(Map oldParentMap, Map newParentMap);
|
void ParentMapChanged(Map oldParentMap, Map newParentMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for child elements of a MapPanel.
|
||||||
|
/// </summary>
|
||||||
public abstract class MapElement : FrameworkElement, INotifyParentMapChanged
|
public abstract class MapElement : FrameworkElement, INotifyParentMapChanged
|
||||||
{
|
{
|
||||||
protected MapElement()
|
protected MapElement()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
@ -7,6 +11,10 @@ using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a graticule overlay. The minimum spacing in pixels between adjacent graticule lines
|
||||||
|
/// is specified by the MinSpacingPixels property.
|
||||||
|
/// </summary>
|
||||||
public class MapGraticule : MapElement
|
public class MapGraticule : MapElement
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
|
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
|
||||||
|
|
@ -36,7 +44,7 @@ namespace MapControl
|
||||||
public static readonly DependencyProperty MinSpacingPixelsProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MinSpacingPixelsProperty = DependencyProperty.Register(
|
||||||
"MinSpacingPixels", typeof(double), typeof(MapGraticule), new FrameworkPropertyMetadata(100d));
|
"MinSpacingPixels", typeof(double), typeof(MapGraticule), new FrameworkPropertyMetadata(100d));
|
||||||
|
|
||||||
public static double[] GridSpacings =
|
public static double[] Spacings =
|
||||||
new double[] { 1d / 60d, 1d / 30d, 1d / 12d, 1d / 6d, 1d / 4d, 1d / 3d, 1d / 2d, 1d, 2d, 5d, 10d, 15d, 20d, 30d, 45d };
|
new double[] { 1d / 60d, 1d / 30d, 1d / 12d, 1d / 6d, 1d / 4d, 1d / 3d, 1d / 2d, 1d, 2d, 5d, 10d, 15d, 20d, 30d, 45d };
|
||||||
|
|
||||||
private readonly DrawingVisual visual = new DrawingVisual();
|
private readonly DrawingVisual visual = new DrawingVisual();
|
||||||
|
|
@ -116,17 +124,19 @@ namespace MapControl
|
||||||
|
|
||||||
protected override void OnViewTransformChanged(Map parentMap)
|
protected override void OnViewTransformChanged(Map parentMap)
|
||||||
{
|
{
|
||||||
Rect bounds = parentMap.MapViewTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize));
|
Rect bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize));
|
||||||
|
Location loc1 = parentMap.MapTransform.TransformBack(bounds.TopLeft);
|
||||||
|
Location loc2 = parentMap.MapTransform.TransformBack(bounds.BottomRight);
|
||||||
double minSpacing = MinSpacingPixels * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d);
|
double minSpacing = MinSpacingPixels * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d);
|
||||||
double spacing = GridSpacings[GridSpacings.Length - 1];
|
double spacing = Spacings[Spacings.Length - 1];
|
||||||
|
|
||||||
if (spacing >= minSpacing)
|
if (spacing >= minSpacing)
|
||||||
{
|
{
|
||||||
spacing = GridSpacings.FirstOrDefault(s => s >= minSpacing);
|
spacing = Spacings.FirstOrDefault(s => s >= minSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
double longitudeStart = Math.Ceiling(bounds.Left / spacing) * spacing;
|
double latitudeStart = Math.Ceiling(loc1.Latitude / spacing) * spacing;
|
||||||
double latitudeStart = Math.Ceiling(bounds.Top / spacing) * spacing;
|
double longitudeStart = Math.Ceiling(loc1.Longitude / spacing) * spacing;
|
||||||
|
|
||||||
if (pen.Brush == null)
|
if (pen.Brush == null)
|
||||||
{
|
{
|
||||||
|
|
@ -135,18 +145,18 @@ namespace MapControl
|
||||||
|
|
||||||
using (DrawingContext drawingContext = visual.RenderOpen())
|
using (DrawingContext drawingContext = visual.RenderOpen())
|
||||||
{
|
{
|
||||||
for (double lon = longitudeStart; lon <= bounds.Right; lon += spacing)
|
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
|
||||||
{
|
{
|
||||||
drawingContext.DrawLine(pen,
|
drawingContext.DrawLine(pen,
|
||||||
parentMap.MapViewTransform.Transform(new Point(lon, bounds.Bottom)),
|
parentMap.LocationToViewportPoint(new Location(lat, loc1.Longitude)),
|
||||||
parentMap.MapViewTransform.Transform(new Point(lon, bounds.Top)));
|
parentMap.LocationToViewportPoint(new Location(lat, loc2.Longitude)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (double lat = latitudeStart; lat <= bounds.Bottom; lat += spacing)
|
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||||
{
|
{
|
||||||
drawingContext.DrawLine(pen,
|
drawingContext.DrawLine(pen,
|
||||||
parentMap.MapViewTransform.Transform(new Point(bounds.Left, lat)),
|
parentMap.LocationToViewportPoint(new Location(loc1.Latitude, lon)),
|
||||||
parentMap.MapViewTransform.Transform(new Point(bounds.Right, lat)));
|
parentMap.LocationToViewportPoint(new Location(loc2.Latitude, lon)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Foreground != null && Foreground != Brushes.Transparent)
|
if (Foreground != null && Foreground != Brushes.Transparent)
|
||||||
|
|
@ -158,12 +168,12 @@ namespace MapControl
|
||||||
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (double lon = longitudeStart; lon <= bounds.Right; lon += spacing)
|
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
|
||||||
{
|
{
|
||||||
for (double lat = latitudeStart; lat <= bounds.Bottom; lat += spacing)
|
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||||
{
|
{
|
||||||
double t = StrokeThickness / 2d;
|
double t = StrokeThickness / 2d;
|
||||||
Point p = parentMap.MapViewTransform.Transform(new Point(lon, lat));
|
Point p = parentMap.LocationToViewportPoint(new Location(lat, lon));
|
||||||
Point latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
|
Point latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
|
||||||
Point lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
|
Point lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
|
||||||
string latString = CoordinateString(lat, format, "NS");
|
string latString = CoordinateString(lat, format, "NS");
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
|
|
@ -7,22 +11,21 @@ using System.Windows.Media;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
[TemplateVisualState(GroupName = "CommonStates", Name = "Normal")]
|
/// <summary>
|
||||||
[TemplateVisualState(GroupName = "CommonStates", Name = "Disabled")]
|
/// Container class for an item in a MapItemsControl.
|
||||||
[TemplateVisualState(GroupName = "CommonStates", Name = "MouseOver")]
|
/// </summary>
|
||||||
[TemplateVisualState(GroupName = "SelectionStates", Name = "Unselected")]
|
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
|
||||||
[TemplateVisualState(GroupName = "SelectionStates", Name = "Selected")]
|
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
|
||||||
[TemplateVisualState(GroupName = "CurrentStates", Name = "NonCurrent")]
|
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
|
||||||
[TemplateVisualState(GroupName = "CurrentStates", Name = "Current")]
|
[TemplateVisualState(Name = "Unselected", GroupName = "SelectionStates")]
|
||||||
|
[TemplateVisualState(Name = "Selected", GroupName = "SelectionStates")]
|
||||||
|
[TemplateVisualState(Name = "NotCurrent", GroupName = "CurrentStates")]
|
||||||
|
[TemplateVisualState(Name = "Current", GroupName = "CurrentStates")]
|
||||||
public class MapItem : ContentControl
|
public class MapItem : ContentControl
|
||||||
{
|
{
|
||||||
public static readonly RoutedEvent SelectedEvent = ListBoxItem.SelectedEvent.AddOwner(typeof(MapItem));
|
public static readonly RoutedEvent SelectedEvent = ListBoxItem.SelectedEvent.AddOwner(typeof(MapItem));
|
||||||
public static readonly RoutedEvent UnselectedEvent = ListBoxItem.UnselectedEvent.AddOwner(typeof(MapItem));
|
public static readonly RoutedEvent UnselectedEvent = ListBoxItem.UnselectedEvent.AddOwner(typeof(MapItem));
|
||||||
|
|
||||||
public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem));
|
|
||||||
public static readonly DependencyProperty ViewPositionProperty = MapPanel.ViewPositionProperty.AddOwner(typeof(MapItem));
|
|
||||||
public static readonly DependencyProperty ViewPositionTransformProperty = MapPanel.ViewPositionTransformProperty.AddOwner(typeof(MapItem));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(
|
public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(
|
||||||
typeof(MapItem), new FrameworkPropertyMetadata((o, e) => ((MapItem)o).IsSelectedChanged((bool)e.NewValue)));
|
typeof(MapItem), new FrameworkPropertyMetadata((o, e) => ((MapItem)o).IsSelectedChanged((bool)e.NewValue)));
|
||||||
|
|
||||||
|
|
@ -31,13 +34,6 @@ namespace MapControl
|
||||||
|
|
||||||
public static readonly DependencyProperty IsCurrentProperty = IsCurrentPropertyKey.DependencyProperty;
|
public static readonly DependencyProperty IsCurrentProperty = IsCurrentPropertyKey.DependencyProperty;
|
||||||
|
|
||||||
private static readonly DependencyPropertyKey IsInsideMapBoundsPropertyKey = DependencyProperty.RegisterReadOnly(
|
|
||||||
"IsInsideMapBounds", typeof(bool), typeof(MapItem), null);
|
|
||||||
|
|
||||||
public static readonly DependencyProperty IsInsideMapBoundsProperty = IsInsideMapBoundsPropertyKey.DependencyProperty;
|
|
||||||
|
|
||||||
private object item;
|
|
||||||
|
|
||||||
static MapItem()
|
static MapItem()
|
||||||
{
|
{
|
||||||
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem),
|
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem),
|
||||||
|
|
@ -45,9 +41,6 @@ namespace MapControl
|
||||||
|
|
||||||
UIElement.IsEnabledProperty.OverrideMetadata(typeof(MapItem),
|
UIElement.IsEnabledProperty.OverrideMetadata(typeof(MapItem),
|
||||||
new FrameworkPropertyMetadata((o, e) => ((MapItem)o).CommonStateChanged()));
|
new FrameworkPropertyMetadata((o, e) => ((MapItem)o).CommonStateChanged()));
|
||||||
|
|
||||||
MapPanel.ViewPositionPropertyKey.OverrideMetadata(typeof(MapItem),
|
|
||||||
new FrameworkPropertyMetadata((o, e) => ((MapItem)o).ViewPositionChanged((Point)e.NewValue)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public event RoutedEventHandler Selected
|
public event RoutedEventHandler Selected
|
||||||
|
|
@ -67,27 +60,6 @@ namespace MapControl
|
||||||
get { return MapPanel.GetParentMap(this); }
|
get { return MapPanel.GetParentMap(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point? Location
|
|
||||||
{
|
|
||||||
get { return (Point?)GetValue(LocationProperty); }
|
|
||||||
set { SetValue(LocationProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasViewPosition
|
|
||||||
{
|
|
||||||
get { return ReadLocalValue(ViewPositionProperty) != DependencyProperty.UnsetValue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point ViewPosition
|
|
||||||
{
|
|
||||||
get { return (Point)GetValue(ViewPositionProperty); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transform ViewPositionTransform
|
|
||||||
{
|
|
||||||
get { return (Transform)GetValue(ViewPositionTransformProperty); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSelected
|
public bool IsSelected
|
||||||
{
|
{
|
||||||
get { return (bool)GetValue(IsSelectedProperty); }
|
get { return (bool)GetValue(IsSelectedProperty); }
|
||||||
|
|
@ -104,28 +76,12 @@ namespace MapControl
|
||||||
SetValue(IsCurrentPropertyKey, value);
|
SetValue(IsCurrentPropertyKey, value);
|
||||||
int zIndex = Panel.GetZIndex(this);
|
int zIndex = Panel.GetZIndex(this);
|
||||||
Panel.SetZIndex(this, value ? (zIndex | 0x40000000) : (zIndex & ~0x40000000));
|
Panel.SetZIndex(this, value ? (zIndex | 0x40000000) : (zIndex & ~0x40000000));
|
||||||
VisualStateManager.GoToState(this, value ? "Current" : "NonCurrent", true);
|
VisualStateManager.GoToState(this, value ? "Current" : "NotCurrent", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInsideMapBounds
|
public object Item { get; internal set; }
|
||||||
{
|
|
||||||
get { return (bool)GetValue(IsInsideMapBoundsProperty); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Item
|
|
||||||
{
|
|
||||||
get { return item; }
|
|
||||||
internal set
|
|
||||||
{
|
|
||||||
item = value;
|
|
||||||
if (HasViewPosition)
|
|
||||||
{
|
|
||||||
ViewPositionChanged(ViewPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseEnter(MouseEventArgs e)
|
protected override void OnMouseEnter(MouseEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -159,24 +115,6 @@ namespace MapControl
|
||||||
IsSelected = !IsSelected;
|
IsSelected = !IsSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnViewPositionChanged(Point viewPosition)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ViewPositionChanged(Point viewPosition)
|
|
||||||
{
|
|
||||||
Map map = ParentMap;
|
|
||||||
|
|
||||||
if (map != null)
|
|
||||||
{
|
|
||||||
SetValue(IsInsideMapBoundsPropertyKey,
|
|
||||||
viewPosition.X >= 0d && viewPosition.X <= map.ActualWidth &&
|
|
||||||
viewPosition.Y >= 0d && viewPosition.Y <= map.ActualHeight);
|
|
||||||
|
|
||||||
OnViewPositionChanged(viewPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CommonStateChanged()
|
private void CommonStateChanged()
|
||||||
{
|
{
|
||||||
if (!IsEnabled)
|
if (!IsEnabled)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
|
|
@ -8,6 +12,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public enum MapItemSelectionMode { Single, Extended }
|
public enum MapItemSelectionMode { Single, Extended }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages a collection of selectable items on a Map. Uses MapItem as container for items
|
||||||
|
/// and updates the MapItem.IsCurrent property when Items.CurrentItem changes.
|
||||||
|
/// </summary>
|
||||||
public class MapItemsControl : MultiSelector
|
public class MapItemsControl : MultiSelector
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register(
|
||||||
|
|
@ -114,7 +122,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
MapItem mapItem = GetMapItem(item);
|
MapItem mapItem = GetMapItem(item);
|
||||||
|
|
||||||
if (mapItem != null && mapItem.HasViewPosition && geometry.FillContains(mapItem.ViewPosition))
|
if (mapItem != null && MapPanel.HasViewportPosition(mapItem) && geometry.FillContains(MapPanel.GetViewportPosition(mapItem)))
|
||||||
{
|
{
|
||||||
SelectedItems.Add(item);
|
SelectedItems.Add(item);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Positions child elements on a Map. A child element's position is specified by the
|
||||||
|
/// attached property Location, given as geographic location with latitude and longitude.
|
||||||
|
/// The attached property ViewportPosition gets a child element's position in viewport
|
||||||
|
/// coordinates. IsInsideMapBounds indicates if the viewport coordinates are located
|
||||||
|
/// inside the visible part of the map.
|
||||||
|
/// </summary>
|
||||||
public class MapPanel : Panel, INotifyParentMapChanged
|
public class MapPanel : Panel, INotifyParentMapChanged
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
||||||
|
|
@ -12,17 +23,17 @@ namespace MapControl
|
||||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
||||||
|
|
||||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
|
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
|
||||||
"Location", typeof(Point?), typeof(MapPanel),
|
"Location", typeof(Location), typeof(MapPanel),
|
||||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, LocationPropertyChanged));
|
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, LocationPropertyChanged));
|
||||||
|
|
||||||
internal static readonly DependencyPropertyKey ViewPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
private static readonly DependencyPropertyKey ViewportPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||||
"ViewPosition", typeof(Point), typeof(MapPanel), null);
|
"ViewportPosition", typeof(Point), typeof(MapPanel), null);
|
||||||
|
|
||||||
private static readonly DependencyPropertyKey ViewPositionTransformPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
private static readonly DependencyPropertyKey IsInsideMapBoundsPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||||
"ViewPositionTransform", typeof(Transform), typeof(MapPanel), null);
|
"IsInsideMapBounds", typeof(bool), typeof(MapPanel), null);
|
||||||
|
|
||||||
public static readonly DependencyProperty ViewPositionProperty = ViewPositionPropertyKey.DependencyProperty;
|
public static readonly DependencyProperty ViewportPositionProperty = ViewportPositionPropertyKey.DependencyProperty;
|
||||||
public static readonly DependencyProperty ViewPositionTransformProperty = ViewPositionTransformPropertyKey.DependencyProperty;
|
public static readonly DependencyProperty IsInsideMapBoundsProperty = IsInsideMapBoundsPropertyKey.DependencyProperty;
|
||||||
|
|
||||||
public MapPanel()
|
public MapPanel()
|
||||||
{
|
{
|
||||||
|
|
@ -39,24 +50,29 @@ namespace MapControl
|
||||||
return (Map)element.GetValue(ParentMapProperty);
|
return (Map)element.GetValue(ParentMapProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Point? GetLocation(UIElement element)
|
public static Location GetLocation(UIElement element)
|
||||||
{
|
{
|
||||||
return (Point?)element.GetValue(LocationProperty);
|
return (Location)element.GetValue(LocationProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetLocation(UIElement element, Point? value)
|
public static void SetLocation(UIElement element, Location value)
|
||||||
{
|
{
|
||||||
element.SetValue(LocationProperty, value);
|
element.SetValue(LocationProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Point GetViewPosition(UIElement element)
|
public static bool HasViewportPosition(UIElement element)
|
||||||
{
|
{
|
||||||
return (Point)element.GetValue(ViewPositionProperty);
|
return element.ReadLocalValue(ViewportPositionProperty) != DependencyProperty.UnsetValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Transform GetViewPositionTransform(UIElement element)
|
public static Point GetViewportPosition(UIElement element)
|
||||||
{
|
{
|
||||||
return (Transform)element.GetValue(ViewPositionTransformProperty);
|
return (Point)element.GetValue(ViewportPositionProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetIsInsideMapBounds(UIElement element)
|
||||||
|
{
|
||||||
|
return (bool)element.GetValue(IsInsideMapBoundsProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
|
@ -75,10 +91,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
foreach (UIElement element in InternalChildren)
|
foreach (UIElement element in InternalChildren)
|
||||||
{
|
{
|
||||||
object viewPosition = element.ReadLocalValue(ViewPositionProperty);
|
object viewportPosition = element.ReadLocalValue(ViewportPositionProperty);
|
||||||
|
|
||||||
if (viewPosition == DependencyProperty.UnsetValue ||
|
if (viewportPosition == DependencyProperty.UnsetValue ||
|
||||||
!ArrangeElement(element, (Point)viewPosition))
|
!ArrangeElement(element, (Point)viewportPosition))
|
||||||
{
|
{
|
||||||
ArrangeElement(element, finalSize);
|
ArrangeElement(element, finalSize);
|
||||||
}
|
}
|
||||||
|
|
@ -91,11 +107,11 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
foreach (UIElement element in InternalChildren)
|
foreach (UIElement element in InternalChildren)
|
||||||
{
|
{
|
||||||
Point? location = GetLocation(element);
|
Location location = GetLocation(element);
|
||||||
|
|
||||||
if (location.HasValue)
|
if (location != null)
|
||||||
{
|
{
|
||||||
SetViewPosition(element, parentMap, location);
|
SetViewportPosition(element, parentMap, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,40 +147,31 @@ namespace MapControl
|
||||||
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
|
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
UIElement element = (UIElement)obj;
|
UIElement element = (UIElement)obj;
|
||||||
Point? location = (Point?)eventArgs.NewValue;
|
Location location = (Location)eventArgs.NewValue;
|
||||||
Map parentMap;
|
Map parentMap;
|
||||||
|
|
||||||
if (location.HasValue && (parentMap = Map.GetParentMap(element)) != null)
|
if (location != null && (parentMap = GetParentMap(element)) != null)
|
||||||
{
|
{
|
||||||
SetViewPosition(element, parentMap, location);
|
SetViewportPosition(element, parentMap, location);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
element.ClearValue(ViewPositionPropertyKey);
|
element.ClearValue(ViewportPositionPropertyKey);
|
||||||
element.ClearValue(ViewPositionTransformPropertyKey);
|
element.ClearValue(IsInsideMapBoundsPropertyKey);
|
||||||
element.Arrange(new Rect());
|
element.Arrange(new Rect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetViewPosition(UIElement element, Map parentMap, Point? location)
|
private static void SetViewportPosition(UIElement element, Map parentMap, Location location)
|
||||||
{
|
{
|
||||||
Point viewPosition = parentMap.MapViewTransform.Transform(location.Value);
|
Point viewportPosition = parentMap.LocationToViewportPoint(location);
|
||||||
|
|
||||||
element.SetValue(ViewPositionPropertyKey, viewPosition);
|
element.SetValue(ViewportPositionPropertyKey, viewportPosition);
|
||||||
|
element.SetValue(IsInsideMapBoundsPropertyKey,
|
||||||
|
viewportPosition.X >= 0d && viewportPosition.X <= parentMap.ActualWidth &&
|
||||||
|
viewportPosition.Y >= 0d && viewportPosition.Y <= parentMap.ActualHeight);
|
||||||
|
|
||||||
Matrix matrix = new Matrix(1d, 0d, 0d, 1d, viewPosition.X, viewPosition.Y);
|
ArrangeElement(element, viewportPosition);
|
||||||
MatrixTransform viewTransform = element.GetValue(ViewPositionTransformProperty) as MatrixTransform;
|
|
||||||
|
|
||||||
if (viewTransform != null)
|
|
||||||
{
|
|
||||||
viewTransform.Matrix = matrix;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
element.SetValue(ViewPositionTransformPropertyKey, new MatrixTransform(matrix));
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrangeElement(element, viewPosition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ArrangeElement(UIElement element, Point position)
|
private static bool ArrangeElement(UIElement element, Point position)
|
||||||
|
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public static class MapPathGeometry
|
|
||||||
{
|
|
||||||
public static PathGeometry Transform(this GeneralTransform transform, Geometry geometry)
|
|
||||||
{
|
|
||||||
PathGeometry pathGeometry = geometry as PathGeometry;
|
|
||||||
|
|
||||||
if (pathGeometry == null)
|
|
||||||
{
|
|
||||||
pathGeometry = PathGeometry.CreateFromGeometry(geometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geometry.Transform != null && geometry.Transform != System.Windows.Media.Transform.Identity)
|
|
||||||
{
|
|
||||||
GeneralTransformGroup transformGroup = new GeneralTransformGroup();
|
|
||||||
transformGroup.Children.Add(geometry.Transform);
|
|
||||||
transformGroup.Children.Add(transform);
|
|
||||||
transform = transformGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PathGeometry(Transform(transform, pathGeometry.Figures),
|
|
||||||
pathGeometry.FillRule, System.Windows.Media.Transform.Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PathFigureCollection Transform(this GeneralTransform transform, PathFigureCollection figures)
|
|
||||||
{
|
|
||||||
PathFigureCollection transformedFigures = new PathFigureCollection();
|
|
||||||
|
|
||||||
foreach (PathFigure figure in figures)
|
|
||||||
{
|
|
||||||
transformedFigures.Add(Transform(transform, figure));
|
|
||||||
}
|
|
||||||
|
|
||||||
transformedFigures.Freeze();
|
|
||||||
|
|
||||||
return transformedFigures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PathFigure Transform(this GeneralTransform transform, PathFigure figure)
|
|
||||||
{
|
|
||||||
PathSegmentCollection transformedSegments = new PathSegmentCollection(figure.Segments.Count);
|
|
||||||
|
|
||||||
foreach (PathSegment segment in figure.Segments)
|
|
||||||
{
|
|
||||||
PathSegment transformedSegment = null;
|
|
||||||
|
|
||||||
if (segment is LineSegment)
|
|
||||||
{
|
|
||||||
LineSegment lineSegment = (LineSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new LineSegment(
|
|
||||||
transform.Transform(lineSegment.Point),
|
|
||||||
lineSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is PolyLineSegment)
|
|
||||||
{
|
|
||||||
PolyLineSegment polyLineSegment = (PolyLineSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new PolyLineSegment(
|
|
||||||
polyLineSegment.Points.Select(transform.Transform),
|
|
||||||
polyLineSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is ArcSegment)
|
|
||||||
{
|
|
||||||
ArcSegment arcSegment = (ArcSegment)segment;
|
|
||||||
Size size = arcSegment.Size;
|
|
||||||
MapTransform mapTransform = transform as MapTransform;
|
|
||||||
|
|
||||||
if (mapTransform != null)
|
|
||||||
{
|
|
||||||
double yScale = mapTransform.RelativeScale(arcSegment.Point);
|
|
||||||
|
|
||||||
if (arcSegment.RotationAngle == 0d)
|
|
||||||
{
|
|
||||||
size.Height *= yScale;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double sinR = Math.Sin(arcSegment.RotationAngle * Math.PI / 180d);
|
|
||||||
double cosR = Math.Cos(arcSegment.RotationAngle * Math.PI / 180d);
|
|
||||||
|
|
||||||
size.Width *= Math.Sqrt(yScale * yScale * sinR * sinR + cosR * cosR);
|
|
||||||
size.Height *= Math.Sqrt(yScale * yScale * cosR * cosR + sinR * sinR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transformedSegment = new ArcSegment(
|
|
||||||
transform.Transform(arcSegment.Point),
|
|
||||||
size,
|
|
||||||
arcSegment.RotationAngle,
|
|
||||||
arcSegment.IsLargeArc,
|
|
||||||
arcSegment.SweepDirection,
|
|
||||||
arcSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is BezierSegment)
|
|
||||||
{
|
|
||||||
BezierSegment bezierSegment = (BezierSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new BezierSegment(
|
|
||||||
transform.Transform(bezierSegment.Point1),
|
|
||||||
transform.Transform(bezierSegment.Point2),
|
|
||||||
transform.Transform(bezierSegment.Point3),
|
|
||||||
bezierSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is PolyBezierSegment)
|
|
||||||
{
|
|
||||||
PolyBezierSegment polyBezierSegment = (PolyBezierSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new PolyBezierSegment(
|
|
||||||
polyBezierSegment.Points.Select(transform.Transform),
|
|
||||||
polyBezierSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is QuadraticBezierSegment)
|
|
||||||
{
|
|
||||||
QuadraticBezierSegment quadraticBezierSegment = (QuadraticBezierSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new QuadraticBezierSegment(
|
|
||||||
transform.Transform(quadraticBezierSegment.Point1),
|
|
||||||
transform.Transform(quadraticBezierSegment.Point2),
|
|
||||||
quadraticBezierSegment.IsStroked);
|
|
||||||
}
|
|
||||||
else if (segment is PolyQuadraticBezierSegment)
|
|
||||||
{
|
|
||||||
PolyQuadraticBezierSegment polyQuadraticBezierSegment = (PolyQuadraticBezierSegment)segment;
|
|
||||||
|
|
||||||
transformedSegment = new PolyQuadraticBezierSegment(
|
|
||||||
polyQuadraticBezierSegment.Points.Select(transform.Transform),
|
|
||||||
polyQuadraticBezierSegment.IsStroked);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transformedSegment != null)
|
|
||||||
{
|
|
||||||
transformedSegment.IsSmoothJoin = segment.IsSmoothJoin;
|
|
||||||
transformedSegments.Add(transformedSegment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PathFigure transformedFigure = new PathFigure(
|
|
||||||
transform.Transform(figure.StartPoint),
|
|
||||||
transformedSegments,
|
|
||||||
figure.IsClosed);
|
|
||||||
|
|
||||||
transformedFigure.IsFilled = figure.IsFilled;
|
|
||||||
transformedFigure.Freeze();
|
|
||||||
|
|
||||||
return transformedFigure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
35
MapControl/MapPolygon.cs
Normal file
35
MapControl/MapPolygon.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A closed map polygon, defined by a collection of geographic locations in the Locations property.
|
||||||
|
/// </summary>
|
||||||
|
public class MapPolygon : MapPolyline
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty FillProperty = Shape.FillProperty.AddOwner(
|
||||||
|
typeof(MapPolygon), new FrameworkPropertyMetadata((o, e) => ((MapPolygon)o).drawing.Brush = (Brush)e.NewValue));
|
||||||
|
|
||||||
|
public MapPolygon()
|
||||||
|
{
|
||||||
|
drawing.Brush = Fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Brush Fill
|
||||||
|
{
|
||||||
|
get { return (Brush)GetValue(FillProperty); }
|
||||||
|
set { SetValue(FillProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateGeometry()
|
||||||
|
{
|
||||||
|
UpdateGeometry(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,54 +1,58 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public class MapPath : MapElement
|
/// <summary>
|
||||||
|
/// An open map polygon, defined by a collection of geographic locations in the Locations property.
|
||||||
|
/// </summary>
|
||||||
|
public class MapPolyline : MapElement
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty DataProperty = Path.DataProperty.AddOwner(
|
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).UpdateGeometry()));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty FillProperty = Shape.FillProperty.AddOwner(
|
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Brush = (Brush)e.NewValue));
|
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata(Brushes.Black, (o, e) => ((MapPath)o).drawing.Pen.Brush = (Brush)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata(Brushes.Black, (o, e) => ((MapPolyline)o).drawing.Pen.Brush = (Brush)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapPath)o).StrokeDashOffset)));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapPolyline)o).StrokeDashOffset)));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.DashStyle = new DashStyle(((MapPath)o).StrokeDashArray, (double)e.NewValue)));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashStyle = new DashStyle(((MapPolyline)o).StrokeDashArray, (double)e.NewValue)));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.DashCap = (PenLineCap)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashCap = (PenLineCap)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.StartLineCap = (PenLineCap)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.StartLineCap = (PenLineCap)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.EndLineCap = (PenLineCap)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.EndLineCap = (PenLineCap)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.LineJoin = (PenLineJoin)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.LineJoin = (PenLineJoin)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).drawing.Pen.MiterLimit = (double)e.NewValue));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.MiterLimit = (double)e.NewValue));
|
||||||
|
|
||||||
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
||||||
typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).UpdatePenThickness()));
|
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdatePenThickness()));
|
||||||
|
|
||||||
public static readonly DependencyProperty TransformStrokeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TransformStrokeProperty = DependencyProperty.Register(
|
||||||
"TransformStroke", typeof(bool), typeof(MapPath), new FrameworkPropertyMetadata((o, e) => ((MapPath)o).UpdatePenThickness()));
|
"TransformStroke", typeof(bool), typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdatePenThickness()));
|
||||||
|
|
||||||
private readonly DrawingVisual visual = new DrawingVisual();
|
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||||
private readonly GeometryDrawing drawing = new GeometryDrawing();
|
"Locations", typeof(LocationCollection), typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdateGeometry()));
|
||||||
|
|
||||||
public MapPath()
|
protected readonly DrawingVisual visual = new DrawingVisual();
|
||||||
|
protected readonly GeometryDrawing drawing = new GeometryDrawing();
|
||||||
|
|
||||||
|
public MapPolyline()
|
||||||
{
|
{
|
||||||
drawing.Brush = Fill;
|
|
||||||
drawing.Pen = new Pen(Stroke, StrokeThickness);
|
drawing.Pen = new Pen(Stroke, StrokeThickness);
|
||||||
|
|
||||||
using (DrawingContext drawingContext = visual.RenderOpen())
|
using (DrawingContext drawingContext = visual.RenderOpen())
|
||||||
|
|
@ -59,18 +63,6 @@ namespace MapControl
|
||||||
Loaded += (o, e) => UpdateGeometry();
|
Loaded += (o, e) => UpdateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Geometry Data
|
|
||||||
{
|
|
||||||
get { return (Geometry)GetValue(DataProperty); }
|
|
||||||
set { SetValue(DataProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Brush Fill
|
|
||||||
{
|
|
||||||
get { return (Brush)GetValue(FillProperty); }
|
|
||||||
set { SetValue(FillProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Brush Stroke
|
public Brush Stroke
|
||||||
{
|
{
|
||||||
get { return (Brush)GetValue(StrokeProperty); }
|
get { return (Brush)GetValue(StrokeProperty); }
|
||||||
|
|
@ -131,6 +123,12 @@ namespace MapControl
|
||||||
set { SetValue(TransformStrokeProperty, value); }
|
set { SetValue(TransformStrokeProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocationCollection Locations
|
||||||
|
{
|
||||||
|
get { return (LocationCollection)GetValue(LocationsProperty); }
|
||||||
|
set { SetValue(LocationsProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
public double TransformedStrokeThickness
|
public double TransformedStrokeThickness
|
||||||
{
|
{
|
||||||
get { return drawing.Pen.Thickness; }
|
get { return drawing.Pen.Thickness; }
|
||||||
|
|
@ -162,23 +160,26 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
double scale = 1d;
|
double scale = 1d;
|
||||||
|
|
||||||
if (TransformStroke && Data != null)
|
if (TransformStroke)
|
||||||
{
|
{
|
||||||
Point center = Data.Bounds.Location + (Vector)Data.Bounds.Size / 2d;
|
scale = parentMap.CenterScale * Map.MeterPerDegree;
|
||||||
scale = parentMap.GetMapScale(center) * Map.MeterPerDegree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawing.Pen.Thickness = scale * StrokeThickness;
|
drawing.Pen.Thickness = scale * StrokeThickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGeometry()
|
protected virtual void UpdateGeometry()
|
||||||
|
{
|
||||||
|
UpdateGeometry(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateGeometry(bool closed)
|
||||||
{
|
{
|
||||||
Map parentMap = MapPanel.GetParentMap(this);
|
Map parentMap = MapPanel.GetParentMap(this);
|
||||||
|
|
||||||
if (parentMap != null && Data != null)
|
if (parentMap != null && Locations != null && Locations.Count > 0)
|
||||||
{
|
{
|
||||||
drawing.Geometry = parentMap.MapTransform.Transform(Data);
|
drawing.Geometry = CreateGeometry(parentMap, Locations, closed);
|
||||||
drawing.Geometry.Transform = parentMap.ViewTransform;
|
|
||||||
OnViewTransformChanged(parentMap);
|
OnViewTransformChanged(parentMap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -196,5 +197,25 @@ namespace MapControl
|
||||||
OnViewTransformChanged(parentMap);
|
OnViewTransformChanged(parentMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Geometry CreateGeometry(Map parentMap, LocationCollection locations, bool closed)
|
||||||
|
{
|
||||||
|
StreamGeometry geometry = new StreamGeometry
|
||||||
|
{
|
||||||
|
Transform = parentMap.ViewportTransform
|
||||||
|
};
|
||||||
|
|
||||||
|
using (StreamGeometryContext sgc = geometry.Open())
|
||||||
|
{
|
||||||
|
sgc.BeginFigure(parentMap.MapTransform.Transform(locations.First()), closed, closed);
|
||||||
|
|
||||||
|
if (Locations.Count > 1)
|
||||||
|
{
|
||||||
|
sgc.PolyLineTo(parentMap.MapTransform.Transform(locations.Skip(1)), true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public static class MapStreamGeometry
|
|
||||||
{
|
|
||||||
public static MapStreamGeometryContext Open(this StreamGeometry mapGeometry, MapTransform transform)
|
|
||||||
{
|
|
||||||
return new MapStreamGeometryContext(mapGeometry.Open(), transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MapStreamGeometryContext : IDisposable
|
|
||||||
{
|
|
||||||
StreamGeometryContext context;
|
|
||||||
MapTransform transform;
|
|
||||||
|
|
||||||
public MapStreamGeometryContext(StreamGeometryContext context, MapTransform transform)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
this.transform = transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDisposable.Dispose()
|
|
||||||
{
|
|
||||||
context.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
context.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BeginFigure(Point startPoint, bool isFilled, bool isClosed)
|
|
||||||
{
|
|
||||||
context.BeginFigure(transform.Transform(startPoint), isFilled, isClosed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
double yScale = transform.RelativeScale(point);
|
|
||||||
|
|
||||||
if (rotationAngle == 0d)
|
|
||||||
{
|
|
||||||
size.Height *= yScale;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double sinR = Math.Sin(rotationAngle * Math.PI / 180d);
|
|
||||||
double cosR = Math.Cos(rotationAngle * Math.PI / 180d);
|
|
||||||
|
|
||||||
size.Width *= Math.Sqrt(yScale * yScale * sinR * sinR + cosR * cosR);
|
|
||||||
size.Height *= Math.Sqrt(yScale * yScale * cosR * cosR + sinR * sinR);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.ArcTo(transform.Transform(point), size, rotationAngle, isLargeArc, sweepDirection, isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LineTo(Point point, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.LineTo(transform.Transform(point), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QuadraticBezierTo(Point point1, Point point2, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.QuadraticBezierTo(transform.Transform(point1), transform.Transform(point2), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BezierTo(Point point1, Point point2, Point point3, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.BezierTo(transform.Transform(point1), transform.Transform(point2), transform.Transform(point3), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PolyLineTo(IList<Point> points, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.PolyLineTo(TransformPoints(points), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PolyQuadraticBezierTo(IList<Point> points, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.PolyQuadraticBezierTo(TransformPoints(points), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PolyBezierTo(IList<Point> points, bool isStroked, bool isSmoothJoin)
|
|
||||||
{
|
|
||||||
context.PolyBezierTo(TransformPoints(points), isStroked, isSmoothJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IList<Point> TransformPoints(IList<Point> points)
|
|
||||||
{
|
|
||||||
Point[] transformedPoints = new Point[points.Count];
|
|
||||||
|
|
||||||
for (int i = 0; i < transformedPoints.Length; i++)
|
|
||||||
{
|
|
||||||
transformedPoints[i] = transform.Transform(points[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return transformedPoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
|
@ -9,7 +15,7 @@ namespace MapControl
|
||||||
/// are transformed to cartesian coordinates with origin at latitude = 0 and longitude = 0.
|
/// are transformed to cartesian coordinates with origin at latitude = 0 and longitude = 0.
|
||||||
/// Longitude values are transformed identically to x values in the interval [-180 .. 180].
|
/// Longitude values are transformed identically to x values in the interval [-180 .. 180].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MapTransform : GeneralTransform
|
public abstract class MapTransform
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the absolute value of the minimum and maximum latitude that can be transformed.
|
/// Gets the absolute value of the minimum and maximum latitude that can be transformed.
|
||||||
|
|
@ -17,9 +23,35 @@ namespace MapControl
|
||||||
public abstract double MaxLatitude { get; }
|
public abstract double MaxLatitude { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the point scale factor of the map projection at the specified point
|
/// Gets the scale factor of the map projection at the specified geographic location
|
||||||
/// relative to the point (0, 0).
|
/// relative to the scale at latitude zero.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract double RelativeScale(Point point);
|
public abstract double RelativeScale(Location location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a geographic location to a cartesian coordinate point.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Point Transform(Location location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a cartesian coordinate point to a geographic location.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Location TransformBack(Point point);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a collection of geographic locations to a collection of cartesian coordinate points.
|
||||||
|
/// </summary>
|
||||||
|
public PointCollection Transform(IEnumerable<Location> locations)
|
||||||
|
{
|
||||||
|
return new PointCollection(locations.Select(l => Transform(l)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms a collection of cartesian coordinate points to a collections of geographic location.
|
||||||
|
/// </summary>
|
||||||
|
public LocationCollection TransformBack(IEnumerable<Point> points)
|
||||||
|
{
|
||||||
|
return new LocationCollection(points.Select(p => TransformBack(p)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public class MapViewTransform : GeneralTransform
|
|
||||||
{
|
|
||||||
private readonly GeneralTransform inverse;
|
|
||||||
|
|
||||||
public MapViewTransform()
|
|
||||||
{
|
|
||||||
MapTransform = new MercatorTransform();
|
|
||||||
inverse = new InverseMapViewTransform(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapTransform MapTransform { get; set; }
|
|
||||||
public Transform ViewTransform { get; set; }
|
|
||||||
|
|
||||||
public override GeneralTransform Inverse
|
|
||||||
{
|
|
||||||
get { return inverse; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryTransform(Point point, out Point result)
|
|
||||||
{
|
|
||||||
result = ViewTransform.Transform(MapTransform.Transform(point));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rect TransformBounds(Rect rect)
|
|
||||||
{
|
|
||||||
return ViewTransform.TransformBounds(MapTransform.TransformBounds(rect));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Freezable CreateInstanceCore()
|
|
||||||
{
|
|
||||||
return new MapViewTransform();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class InverseMapViewTransform : GeneralTransform
|
|
||||||
{
|
|
||||||
private readonly MapViewTransform inverse;
|
|
||||||
|
|
||||||
public InverseMapViewTransform(MapViewTransform inverse)
|
|
||||||
{
|
|
||||||
this.inverse = inverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override GeneralTransform Inverse
|
|
||||||
{
|
|
||||||
get { return inverse; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryTransform(Point point, out Point result)
|
|
||||||
{
|
|
||||||
result = inverse.MapTransform.Inverse.Transform(inverse.ViewTransform.Inverse.Transform(point));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rect TransformBounds(Rect rect)
|
|
||||||
{
|
|
||||||
return inverse.MapTransform.Inverse.TransformBounds(inverse.ViewTransform.Inverse.TransformBounds(rect));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Freezable CreateInstanceCore()
|
|
||||||
{
|
|
||||||
return new InverseMapViewTransform(inverse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
|
@ -10,101 +14,50 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MercatorTransform : MapTransform
|
public class MercatorTransform : MapTransform
|
||||||
{
|
{
|
||||||
private GeneralTransform inverse = new InverseMercatorTransform();
|
|
||||||
|
|
||||||
public MercatorTransform()
|
|
||||||
{
|
|
||||||
Freeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override GeneralTransform Inverse
|
|
||||||
{
|
|
||||||
get { return inverse; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override double MaxLatitude
|
public override double MaxLatitude
|
||||||
{
|
{
|
||||||
get { return 85.0511; }
|
get { return 85.0511; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double RelativeScale(Point point)
|
public override double RelativeScale(Location location)
|
||||||
{
|
{
|
||||||
if (point.Y <= -90d)
|
if (location.Latitude <= -90d)
|
||||||
{
|
{
|
||||||
return double.NegativeInfinity;
|
return double.NegativeInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (point.Y >= 90d)
|
if (location.Latitude >= 90d)
|
||||||
{
|
{
|
||||||
return double.PositiveInfinity;
|
return double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1d / Math.Cos(point.Y * Math.PI / 180d);
|
return 1d / Math.Cos(location.Latitude * Math.PI / 180d);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TryTransform(Point point, out Point result)
|
public override Point Transform(Location location)
|
||||||
{
|
{
|
||||||
result = point;
|
Point result = new Point(location.Longitude, 0d);
|
||||||
|
|
||||||
if (point.Y <= -90d)
|
if (location.Latitude <= -90d)
|
||||||
{
|
{
|
||||||
result.Y = double.NegativeInfinity;
|
result.Y = double.NegativeInfinity;
|
||||||
}
|
}
|
||||||
else if (point.Y >= 90d)
|
else if (location.Latitude >= 90d)
|
||||||
{
|
{
|
||||||
result.Y = double.PositiveInfinity;
|
result.Y = double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double lat = point.Y * Math.PI / 180d;
|
double lat = location.Latitude * Math.PI / 180d;
|
||||||
result.Y = (Math.Log(Math.Tan(lat) + 1d / Math.Cos(lat))) / Math.PI * 180d;
|
result.Y = (Math.Log(Math.Tan(lat) + 1d / Math.Cos(lat))) / Math.PI * 180d;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Rect TransformBounds(Rect rect)
|
public override Location TransformBack(Point point)
|
||||||
{
|
{
|
||||||
return new Rect(Transform(rect.TopLeft), Transform(rect.BottomRight));
|
return new Location(Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d, point.X);
|
||||||
}
|
|
||||||
|
|
||||||
protected override Freezable CreateInstanceCore()
|
|
||||||
{
|
|
||||||
return new MercatorTransform();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms cartesian coordinates to latitude and longitude values in degrees
|
|
||||||
/// according to the inverse Mercator transform.
|
|
||||||
/// </summary>
|
|
||||||
public class InverseMercatorTransform : GeneralTransform
|
|
||||||
{
|
|
||||||
public InverseMercatorTransform()
|
|
||||||
{
|
|
||||||
Freeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override GeneralTransform Inverse
|
|
||||||
{
|
|
||||||
get { return new MercatorTransform(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryTransform(Point point, out Point result)
|
|
||||||
{
|
|
||||||
result = point;
|
|
||||||
result.Y = Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Rect TransformBounds(Rect rect)
|
|
||||||
{
|
|
||||||
return new Rect(Transform(rect.TopLeft), Transform(rect.BottomRight));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Freezable CreateInstanceCore()
|
|
||||||
{
|
|
||||||
return new InverseMercatorTransform();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ using System.Windows;
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("Map Control")]
|
[assembly: AssemblyTitle("Map Control")]
|
||||||
[assembly: AssemblyDescription("MapControl")]
|
[assembly: AssemblyDescription("WPF Map Control")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyProduct("MapControl")]
|
[assembly: AssemblyProduct("WPF Map Control")]
|
||||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012")]
|
[assembly: AssemblyCopyright("Copyright © 2012 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -22,7 +26,7 @@ namespace MapControl
|
||||||
private Int32Rect tileGrid;
|
private Int32Rect tileGrid;
|
||||||
private TileLayerCollection tileLayers;
|
private TileLayerCollection tileLayers;
|
||||||
private readonly DispatcherTimer updateTimer;
|
private readonly DispatcherTimer updateTimer;
|
||||||
private readonly MatrixTransform viewTransform = new MatrixTransform();
|
private readonly MatrixTransform viewportTransform = new MatrixTransform();
|
||||||
|
|
||||||
public TileContainer()
|
public TileContainer()
|
||||||
{
|
{
|
||||||
|
|
@ -52,17 +56,17 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transform ViewTransform
|
public Transform ViewportTransform
|
||||||
{
|
{
|
||||||
get { return viewTransform; }
|
get { return viewportTransform; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public double SetTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point viewOrigin, Size viewSize)
|
public double SetTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point viewportOrigin, Size viewportSize)
|
||||||
{
|
{
|
||||||
zoomLevel = mapZoomLevel;
|
zoomLevel = mapZoomLevel;
|
||||||
rotation = mapRotation;
|
rotation = mapRotation;
|
||||||
size = viewSize;
|
size = viewportSize;
|
||||||
origin = viewOrigin;
|
origin = viewportOrigin;
|
||||||
|
|
||||||
double scale = Math.Pow(2d, zoomLevel) * 256d / 360d;
|
double scale = Math.Pow(2d, zoomLevel) * 256d / 360d;
|
||||||
offset.X = origin.X - (180d + mapOrigin.X) * scale;
|
offset.X = origin.X - (180d + mapOrigin.X) * scale;
|
||||||
|
|
@ -72,7 +76,7 @@ namespace MapControl
|
||||||
transform.Scale(scale, scale);
|
transform.Scale(scale, scale);
|
||||||
transform.Translate(offset.X, offset.Y);
|
transform.Translate(offset.X, offset.Y);
|
||||||
transform.RotateAt(rotation, origin.X, origin.Y);
|
transform.RotateAt(rotation, origin.X, origin.Y);
|
||||||
viewTransform.Matrix = transform;
|
viewportTransform.Matrix = transform;
|
||||||
|
|
||||||
transform = GetVisualTransform();
|
transform = GetVisualTransform();
|
||||||
|
|
||||||
|
|
@ -110,7 +114,7 @@ namespace MapControl
|
||||||
int zoom = (int)Math.Floor(zoomLevel + 1d - zoomLevelSwitchOffset);
|
int zoom = (int)Math.Floor(zoomLevel + 1d - zoomLevelSwitchOffset);
|
||||||
int numTiles = 1 << zoom;
|
int numTiles = 1 << zoom;
|
||||||
double mapToTileScale = (double)numTiles / 360d;
|
double mapToTileScale = (double)numTiles / 360d;
|
||||||
Matrix transform = viewTransform.Matrix;
|
Matrix transform = viewportTransform.Matrix;
|
||||||
transform.Invert(); // view to map coordinates
|
transform.Invert(); // view to map coordinates
|
||||||
transform.Translate(180d, -180d);
|
transform.Translate(180d, -180d);
|
||||||
transform.Scale(mapToTileScale, -mapToTileScale); // map coordinates to tile indices
|
transform.Scale(mapToTileScale, -mapToTileScale); // map coordinates to tile indices
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -10,9 +14,13 @@ using System.Windows.Threading;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Loads map tiles by their URIs and optionally caches their image files in a folder
|
||||||
|
/// defined by the static TileCacheFolder property.
|
||||||
|
/// </summary>
|
||||||
public class TileImageLoader : DispatcherObject
|
public class TileImageLoader : DispatcherObject
|
||||||
{
|
{
|
||||||
public static string TileCacheDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapCache");
|
public static string TileCacheFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl Cache");
|
||||||
public static TimeSpan TileCacheExpiryAge = TimeSpan.FromDays(1);
|
public static TimeSpan TileCacheExpiryAge = TimeSpan.FromDays(1);
|
||||||
|
|
||||||
private readonly Queue<Tile> pendingTiles = new Queue<Tile>();
|
private readonly Queue<Tile> pendingTiles = new Queue<Tile>();
|
||||||
|
|
@ -45,7 +53,7 @@ namespace MapControl
|
||||||
|
|
||||||
lock (pendingTiles)
|
lock (pendingTiles)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(TileCacheDirectory) &&
|
if (!string.IsNullOrEmpty(TileCacheFolder) &&
|
||||||
!string.IsNullOrEmpty(TileLayerName))
|
!string.IsNullOrEmpty(TileLayerName))
|
||||||
{
|
{
|
||||||
List<Tile> expiredTiles = new List<Tile>(newTiles.Count);
|
List<Tile> expiredTiles = new List<Tile>(newTiles.Count);
|
||||||
|
|
@ -174,7 +182,7 @@ namespace MapControl
|
||||||
|
|
||||||
string tilePath;
|
string tilePath;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(TileCacheDirectory) &&
|
if (!string.IsNullOrEmpty(TileCacheFolder) &&
|
||||||
!string.IsNullOrEmpty(TileLayerName) &&
|
!string.IsNullOrEmpty(TileLayerName) &&
|
||||||
(tilePath = TilePath(tile, decoder)) != null)
|
(tilePath = TilePath(tile, decoder)) != null)
|
||||||
{
|
{
|
||||||
|
|
@ -213,7 +221,7 @@ namespace MapControl
|
||||||
|
|
||||||
private string TileDirectory(Tile tile)
|
private string TileDirectory(Tile tile)
|
||||||
{
|
{
|
||||||
return Path.Combine(TileCacheDirectory, TileLayerName, tile.ZoomLevel.ToString(), tile.XIndex.ToString());
|
return Path.Combine(TileCacheFolder, TileLayerName, tile.ZoomLevel.ToString(), tile.XIndex.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private string TilePath(Tile tile, BitmapDecoder decoder)
|
private string TilePath(Tile tile, BitmapDecoder decoder)
|
||||||
|
|
@ -255,7 +263,7 @@ namespace MapControl
|
||||||
|
|
||||||
private static void TraceInformation(string format, params object[] args)
|
private static void TraceInformation(string format, params object[] args)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if TRACE
|
||||||
System.Diagnostics.Trace.TraceInformation("[{0:00}] {1}", Thread.CurrentThread.ManagedThreadId, string.Format(format, args));
|
System.Diagnostics.Trace.TraceInformation("[{0:00}] {1}", Thread.CurrentThread.ManagedThreadId, string.Format(format, args));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -7,11 +11,17 @@ using System.Windows.Media;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fills a rectangular area with map tiles from a TileSource. If the IsCached property is true,
|
||||||
|
/// map tiles are cached in a folder defined by the TileImageLoader.TileCacheFolder property.
|
||||||
|
/// </summary>
|
||||||
[ContentProperty("TileSource")]
|
[ContentProperty("TileSource")]
|
||||||
public class TileLayer : DrawingVisual
|
public class TileLayer : DrawingVisual
|
||||||
{
|
{
|
||||||
private readonly TileImageLoader tileImageLoader = new TileImageLoader();
|
private readonly TileImageLoader tileImageLoader = new TileImageLoader();
|
||||||
private readonly List<Tile> tiles = new List<Tile>();
|
private readonly List<Tile> tiles = new List<Tile>();
|
||||||
|
private bool isCached = false;
|
||||||
|
private string name = string.Empty;
|
||||||
private string description = string.Empty;
|
private string description = string.Empty;
|
||||||
private Int32Rect grid;
|
private Int32Rect grid;
|
||||||
private int zoomLevel;
|
private int zoomLevel;
|
||||||
|
|
@ -36,10 +46,24 @@ namespace MapControl
|
||||||
set { tileImageLoader.MaxDownloads = value; }
|
set { tileImageLoader.MaxDownloads = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCached
|
||||||
|
{
|
||||||
|
get { return isCached; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
isCached = value;
|
||||||
|
tileImageLoader.TileLayerName = isCached ? name : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return tileImageLoader.TileLayerName; }
|
get { return name; }
|
||||||
set { tileImageLoader.TileLayerName = value; }
|
set
|
||||||
|
{
|
||||||
|
name = value;
|
||||||
|
tileImageLoader.TileLayerName = isCached ? name : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Description
|
public string Description
|
||||||
|
|
@ -136,7 +160,7 @@ namespace MapControl
|
||||||
|
|
||||||
tiles.Sort((t1, t2) => t1.ZoomLevel - t2.ZoomLevel);
|
tiles.Sort((t1, t2) => t1.ZoomLevel - t2.ZoomLevel);
|
||||||
|
|
||||||
System.Diagnostics.Trace.TraceInformation("{0} Tiles: {1}", tiles.Count, string.Join(", ", tiles.Select(t => t.ZoomLevel.ToString())));
|
//System.Diagnostics.Trace.TraceInformation("{0} Tiles: {1}", tiles.Count, string.Join(", ", tiles.Select(t => t.ZoomLevel.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderTiles()
|
private void RenderTiles()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using System;
|
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||||
|
// Copyright © 2012 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -6,6 +10,9 @@ using System.Windows;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the URI of a map tile.
|
||||||
|
/// </summary>
|
||||||
[TypeConverter(typeof(TileSourceTypeConverter))]
|
[TypeConverter(typeof(TileSourceTypeConverter))]
|
||||||
public class TileSource
|
public class TileSource
|
||||||
{
|
{
|
||||||
|
|
@ -90,20 +97,20 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public override Uri GetUri(int x, int y, int zoomLevel)
|
public override Uri GetUri(int x, int y, int zoomLevel)
|
||||||
{
|
{
|
||||||
InverseMercatorTransform t = new InverseMercatorTransform();
|
MercatorTransform t = new MercatorTransform();
|
||||||
double n = 1 << zoomLevel;
|
double n = 1 << zoomLevel;
|
||||||
double x1 = (double)x * 360d / n - 180d;
|
double x1 = (double)x * 360d / n - 180d;
|
||||||
double x2 = (double)(x + 1) * 360d / n - 180d;
|
double x2 = (double)(x + 1) * 360d / n - 180d;
|
||||||
double y1 = 180d - (double)(y + 1) * 360d / n;
|
double y1 = 180d - (double)(y + 1) * 360d / n;
|
||||||
double y2 = 180d - (double)y * 360d / n;
|
double y2 = 180d - (double)y * 360d / n;
|
||||||
Point p1 = t.Transform(new Point(x1, y1));
|
Location p1 = t.TransformBack(new Point(x1, y1));
|
||||||
Point p2 = t.Transform(new Point(x2, y2));
|
Location p2 = t.TransformBack(new Point(x2, y2));
|
||||||
|
|
||||||
return new Uri(UriFormat.
|
return new Uri(UriFormat.
|
||||||
Replace("{w}", p1.X.ToString(CultureInfo.InvariantCulture)).
|
Replace("{w}", p1.Longitude.ToString(CultureInfo.InvariantCulture)).
|
||||||
Replace("{s}", p1.Y.ToString(CultureInfo.InvariantCulture)).
|
Replace("{s}", p1.Latitude.ToString(CultureInfo.InvariantCulture)).
|
||||||
Replace("{e}", p2.X.ToString(CultureInfo.InvariantCulture)).
|
Replace("{e}", p2.Longitude.ToString(CultureInfo.InvariantCulture)).
|
||||||
Replace("{n}", p2.Y.ToString(CultureInfo.InvariantCulture)));
|
Replace("{n}", p2.Latitude.ToString(CultureInfo.InvariantCulture)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
7
TestApplication/App.xaml
Normal file
7
TestApplication/App.xaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<Application x:Class="MapControlTestApp.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>
|
||||||
8
TestApplication/App.xaml.cs
Normal file
8
TestApplication/App.xaml.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace MapControlTestApp
|
||||||
|
{
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
210
TestApplication/MainWindow.xaml
Normal file
210
TestApplication/MainWindow.xaml
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
<Window x:Class="MapControlTestApp.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"
|
||||||
|
xmlns:local="clr-namespace:MapControlTestApp"
|
||||||
|
Title="MainWindow" Height="600" Width="800">
|
||||||
|
<Window.Resources>
|
||||||
|
<map:TileLayer x:Key="SeamarksTileLayer"
|
||||||
|
Name="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA"
|
||||||
|
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True" MinZoomLevel="10" MaxZoomLevel="18"/>
|
||||||
|
<local:SampleItemCollection x:Key="SampleItems"/>
|
||||||
|
<local:SampleItemStyleSelector x:Key="SampleItemStyleSelector"/>
|
||||||
|
<Style x:Key="SamplePushpinItemStyle" TargetType="map:MapItem">
|
||||||
|
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
|
||||||
|
<Setter Property="Content" Value="{Binding Name}"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsSelected" Value="True">
|
||||||
|
<Setter Property="Foreground" Value="OrangeRed"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="SamplePointItemStyle" TargetType="map:MapItem">
|
||||||
|
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
|
||||||
|
<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="1" Duration="0:0:0.1"/>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="SelectionStates">
|
||||||
|
<VisualState x:Name="Unselected"/>
|
||||||
|
<VisualState x:Name="Selected"/>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="CurrentStates">
|
||||||
|
<VisualState x:Name="NotCurrent"/>
|
||||||
|
<VisualState x:Name="Current">
|
||||||
|
<Storyboard>
|
||||||
|
<ColorAnimation Storyboard.TargetName="path" Storyboard.TargetProperty="Stroke.Color" To="Magenta" Duration="0:0:0.1"/>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
<Path Name="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="10" Canvas.Bottom="3">
|
||||||
|
<Rectangle Name="labelBackground" Fill="White" Opacity="0.5"/>
|
||||||
|
<TextBlock Margin="2,0,2,1" Text="{Binding Name}"/>
|
||||||
|
</Grid>
|
||||||
|
</Canvas>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="SampleShapeItemStyle" TargetType="map:MapItem">
|
||||||
|
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
|
||||||
|
<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="1" Duration="0:0:0.1"/>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="SelectionStates">
|
||||||
|
<VisualState x:Name="Unselected"/>
|
||||||
|
<VisualState x:Name="Selected"/>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="CurrentStates">
|
||||||
|
<VisualState x:Name="NotCurrent"/>
|
||||||
|
<VisualState x:Name="Current">
|
||||||
|
<Storyboard>
|
||||||
|
<ColorAnimation Storyboard.TargetName="path" Storyboard.TargetProperty="Stroke.Color" To="Magenta" Duration="0:0:0.1"/>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
<Path Name="path" StrokeThickness="2" Fill="#50FFA500">
|
||||||
|
<Path.RenderTransform>
|
||||||
|
<RotateTransform Angle="{Binding Rotation}"/>
|
||||||
|
</Path.RenderTransform>
|
||||||
|
<Path.Stroke>
|
||||||
|
<SolidColorBrush Color="Gray"/>
|
||||||
|
</Path.Stroke>
|
||||||
|
<Path.Data>
|
||||||
|
<EllipseGeometry RadiusX="{Binding RadiusX}" RadiusY="{Binding RadiusY}"
|
||||||
|
Transform="{Binding ScaleRotateTransform, ElementName=map}"/>
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
<Line Stroke="Gray" StrokeThickness="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
|
||||||
|
<Grid Canvas.Left="3" Canvas.Bottom="3">
|
||||||
|
<Rectangle Name="labelBackground" Fill="White" Opacity="0.5"/>
|
||||||
|
<TextBlock Margin="2,0,2,1" Text="{Binding Name}"/>
|
||||||
|
</Grid>
|
||||||
|
</Canvas>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="SamplePolylineItemStyle" TargetType="map:MapItem">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="map:MapItem">
|
||||||
|
<map:MapPolyline Stroke="Blue" StrokeThickness="2" Locations="{Binding Locations}"/>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="SamplePolygonItemStyle" TargetType="map:MapItem">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="map:MapItem">
|
||||||
|
<map:MapPolygon Stroke="Green" StrokeThickness="2" Locations="{Binding Locations}"/>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<map:Map Name="map" IsManipulationEnabled="True" Margin="2" FontSize="10"
|
||||||
|
LightForeground="Black" LightBackground="White" DarkForeground="White" DarkBackground="#FF3F3F3F"
|
||||||
|
Center="53.5,8.2" ZoomLevel="11"
|
||||||
|
MainTileLayer="{Binding ElementName=tileSourceComboBox, Path=SelectedItem}"
|
||||||
|
ManipulationInertiaStarting="MapManipulationInertiaStarting"
|
||||||
|
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave">
|
||||||
|
<map:MapGraticule Opacity="0.6"/>
|
||||||
|
<map:MapItemsControl ItemsSource="{StaticResource SampleItems}"
|
||||||
|
ItemContainerStyleSelector="{StaticResource SampleItemStyleSelector}"
|
||||||
|
IsSynchronizedWithCurrentItem="True"/>
|
||||||
|
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="2,0,0,0" FontSize="10"
|
||||||
|
Text="{Binding ElementName=map, Path=MainTileLayer.Description}"/>
|
||||||
|
</map:Map>
|
||||||
|
<Grid Grid.Row="1" Margin="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Name="mouseLocation" Margin="4" VerticalAlignment="Center"/>
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Slider Name="zoomSlider" ToolTip="Zoom Level" Margin="4,0,4,0" Width="100" Minimum="1" Maximum="20" SmallChange="0.01"
|
||||||
|
Value="{Binding ElementName=map, Path=TargetZoomLevel}" />
|
||||||
|
<Slider Name="headingSlider" ToolTip="Heading" Margin="4,0,4,0" Width="100" Minimum="0" Maximum="360" SmallChange="10" LargeChange="45"
|
||||||
|
Value="{Binding ElementName=map, Path=TargetHeading}"/>
|
||||||
|
<CheckBox ToolTip="Map Overlay" Margin="4,0,4,0" VerticalAlignment="Center" Content="Seamarks" Click="SeamarksClick"/>
|
||||||
|
<ComboBox Name="tileSourceComboBox" ToolTip="Main Tile Layer" Margin="4,0,4,0" DisplayMemberPath="Name" SelectedIndex="0">
|
||||||
|
<ComboBox.Items>
|
||||||
|
<map:TileLayer Name="OpenStreetMap" Description="© {y} OpenStreetMap Contributors, CC-BY-SA"
|
||||||
|
TileSource="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True"/>
|
||||||
|
<map:TileLayer Name="OpenCycleMap" Description="OpenCycleMap - © {y} Andy Allen & OpenStreetMap Contributors, CC-BY-SA"
|
||||||
|
TileSource="http://{c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True"/>
|
||||||
|
<map:TileLayer Name="OCM Transport" Description="OpenCycleMap Transport - © {y} Andy Allen & OpenStreetMap Contributors, CC-BY-SA"
|
||||||
|
TileSource="http://{c}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True"/>
|
||||||
|
<map:TileLayer Name="OCM Landscape" Description="OpenCycleMap Landscape - © {y} Andy Allen & OpenStreetMap Contributors, CC-BY-SA"
|
||||||
|
TileSource="http://{c}.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True"/>
|
||||||
|
<map:TileLayer Name="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest & OpenStreetMap Contributors"
|
||||||
|
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"
|
||||||
|
IsCached="True" MaxZoomLevel="20"/>
|
||||||
|
<!--<map:TileLayer Name="Google Maps" Description="Google Maps - © {y} Google"
|
||||||
|
TileSource="http://mt{i}.google.com/vt/x={x}&y={y}&z={z}"
|
||||||
|
IsCached="True" MaxZoomLevel="20"/>
|
||||||
|
<map:TileLayer Name="Google Images" Description="Google Maps - © {y} Google"
|
||||||
|
TileSource="http://khm{i}.google.com/kh/v=108&x={x}&y={y}&z={z}"
|
||||||
|
IsCached="True" MaxZoomLevel="20" HasDarkBackground="True"/>
|
||||||
|
<map:TileLayer Name="Bing Maps" Description="Bing Maps - © {y} Microsoft Corporation"
|
||||||
|
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/r{q}.png?g=0&stl=h"
|
||||||
|
IsCached="True" MaxZoomLevel="20"/>
|
||||||
|
<map:TileLayer Name="Bing Images" Description="Bing Maps - © {y} Microsoft Corporation"
|
||||||
|
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/a{q}.jpeg?g=0"
|
||||||
|
IsCached="True" MaxZoomLevel="20" HasDarkBackground="True"/>
|
||||||
|
<map:TileLayer Name="Bing Hybrid" Description="Bing Maps - © {y} Microsoft Corporation"
|
||||||
|
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/h{q}.jpeg?g=0&stl=h"
|
||||||
|
IsCached="True" MaxZoomLevel="20" HasDarkBackground="True"/>-->
|
||||||
|
</ComboBox.Items>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
131
TestApplication/MainWindow.xaml.cs
Normal file
131
TestApplication/MainWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using MapControl;
|
||||||
|
|
||||||
|
namespace MapControlTestApp
|
||||||
|
{
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
SampleItemCollection items = (SampleItemCollection)Resources["SampleItems"];
|
||||||
|
items.Add(
|
||||||
|
new SamplePolyline
|
||||||
|
{
|
||||||
|
Name = "WHV - Eckwarderhörne",
|
||||||
|
Locations = LocationCollection.Parse("53.5140,8.1451 53.5123,8.1506 53.5156,8.1623 53.5276,8.1757 53.5491,8.1852 53.5495,8.1877 53.5426,8.1993 53.5184,8.2219 53.5182,8.2386 53.5195,8.2387")
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePolygon
|
||||||
|
{
|
||||||
|
Name = "JadeWeserPort",
|
||||||
|
Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317")
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePushpin
|
||||||
|
{
|
||||||
|
Name = "WHV - Eckwarderhörne",
|
||||||
|
Location = new Location(53.5495, 8.1877)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePushpin
|
||||||
|
{
|
||||||
|
Name = "JadeWeserPort",
|
||||||
|
Location = new Location(53.5914, 8.14)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePushpin
|
||||||
|
{
|
||||||
|
Name = "Kurhaus Dangast",
|
||||||
|
Location = new Location(53.447, 8.1114)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePushpin
|
||||||
|
{
|
||||||
|
Name = "Eckwarderhörne",
|
||||||
|
Location = new Location(53.5207, 8.2323)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Steinbake Leitdamm",
|
||||||
|
Location = new Location(53.51217, 8.16603)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Buhne 2",
|
||||||
|
Location = new Location(53.50926, 8.15815)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Buhne 4",
|
||||||
|
Location = new Location(53.50468, 8.15343)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Buhne 6",
|
||||||
|
Location = new Location(53.50092, 8.15267)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Buhne 8",
|
||||||
|
Location = new Location(53.49871, 8.15321)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SamplePoint
|
||||||
|
{
|
||||||
|
Name = "Buhne 10",
|
||||||
|
Location = new Location(53.49350, 8.15563)
|
||||||
|
});
|
||||||
|
items.Add(
|
||||||
|
new SampleShape
|
||||||
|
{
|
||||||
|
Name = "N 53°30' E 8°12'",
|
||||||
|
Location = new Location(53.5, 8.2),
|
||||||
|
RadiusX = 200d, // meters
|
||||||
|
RadiusY = 300d, // meters
|
||||||
|
Rotation = 30d
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
|
||||||
|
{
|
||||||
|
e.TranslationBehavior.DesiredDeceleration = 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapMouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
mouseLocation.Text = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapMouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
mouseLocation.Text = map.ViewportPointToLocation(e.GetPosition(map)).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SeamarksClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
TileLayer seamarks = (TileLayer)Resources["SeamarksTileLayer"];
|
||||||
|
CheckBox checkBox = (CheckBox)sender;
|
||||||
|
|
||||||
|
if ((bool)checkBox.IsChecked)
|
||||||
|
{
|
||||||
|
map.TileLayers.Add(seamarks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map.TileLayers.Remove(seamarks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
TestApplication/MapBackgroundConverter.cs
Normal file
28
TestApplication/MapBackgroundConverter.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using MapControl;
|
||||||
|
|
||||||
|
namespace MapControlTestApp
|
||||||
|
{
|
||||||
|
class MapBackgroundConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
MapBackground mapBackground = (MapBackground)value;
|
||||||
|
|
||||||
|
if (parameter as string == "Foreground")
|
||||||
|
{
|
||||||
|
return mapBackground == MapBackground.Light ? Brushes.Black : Brushes.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapBackground == MapBackground.Light ? Brushes.White : Brushes.Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
TestApplication/Properties/AssemblyInfo.cs
Normal file
55
TestApplication/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("TestApplication")]
|
||||||
|
[assembly: AssemblyDescription("WPF Map Control Test Application")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
|
[assembly: AssemblyProduct("WPF Map Control")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2012 Clemens Fischer")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
//In order to begin building localizable applications, set
|
||||||
|
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||||
|
//inside a <PropertyGroup>. For example, if you are using US english
|
||||||
|
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||||
|
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||||
|
//the line below to match the UICulture setting in the project file.
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
71
TestApplication/SampleItems.cs
Normal file
71
TestApplication/SampleItems.cs
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using MapControl;
|
||||||
|
|
||||||
|
namespace MapControlTestApp
|
||||||
|
{
|
||||||
|
class SampleItem
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SamplePoint : SampleItem
|
||||||
|
{
|
||||||
|
public Location Location { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SamplePushpin : SamplePoint
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleShape : SamplePoint
|
||||||
|
{
|
||||||
|
public double RadiusX { get; set; }
|
||||||
|
public double RadiusY { get; set; }
|
||||||
|
public double Rotation { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SamplePolyline : SampleItem
|
||||||
|
{
|
||||||
|
public LocationCollection Locations { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SamplePolygon : SampleItem
|
||||||
|
{
|
||||||
|
public LocationCollection Locations { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleItemCollection : ObservableCollection<SampleItem>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleItemStyleSelector : StyleSelector
|
||||||
|
{
|
||||||
|
public override Style SelectStyle(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
if (item is SamplePolyline)
|
||||||
|
{
|
||||||
|
return Application.Current.Windows[0].Resources["SamplePolylineItemStyle"] as Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is SamplePolygon)
|
||||||
|
{
|
||||||
|
return Application.Current.Windows[0].Resources["SamplePolygonItemStyle"] as Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is SampleShape)
|
||||||
|
{
|
||||||
|
return Application.Current.Windows[0].Resources["SampleShapeItemStyle"] as Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is SamplePushpin)
|
||||||
|
{
|
||||||
|
return Application.Current.Windows[0].Resources["SamplePushpinItemStyle"] as Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Application.Current.Windows[0].Resources["SamplePointItemStyle"] as Style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
TestApplication/TestApplication.csproj
Normal file
87
TestApplication/TestApplication.csproj
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{CCBCDAE5-E68F-43A8-930A-0749E476D29D}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>MapControlTestApp</RootNamespace>
|
||||||
|
<AssemblyName>MapControlTestApp</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xaml">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="SampleItems.cs" />
|
||||||
|
<Page Include="MainWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<AppDesigner Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MapControl\MapControl.csproj">
|
||||||
|
<Project>{06481252-2310-414A-B9FC-D5739FDF6BD3}</Project>
|
||||||
|
<Name>MapControl</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>
|
||||||
Loading…
Reference in a new issue