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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl", "MapControl\MapControl.csproj", "{06481252-2310-414A-B9FC-D5739FDF6BD3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "TestApplication\TestApplication.csproj", "{A3F251EE-A1A0-4752-8C3D-C6BACBFB2AF2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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.Build.0 = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
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.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains helper methods for creating GlyphRun objects.
|
||||
/// </summary>
|
||||
public static class GlyphRunText
|
||||
{
|
||||
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.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
|
@ -7,6 +11,12 @@ using System.Windows.Media.Animation;
|
|||
|
||||
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 const double MeterPerDegree = 1852d * 60d;
|
||||
|
|
@ -34,24 +44,24 @@ namespace MapControl
|
|||
"TileLayers", typeof(TileLayerCollection), typeof(Map), new FrameworkPropertyMetadata(
|
||||
(o, e) => ((Map)o).SetTileLayers((TileLayerCollection)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty BaseTileLayerProperty = DependencyProperty.Register(
|
||||
"BaseTileLayer", typeof(TileLayer), typeof(Map), new FrameworkPropertyMetadata(
|
||||
(o, e) => ((Map)o).SetBaseTileLayer((TileLayer)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceBaseTileLayer((TileLayer)v)));
|
||||
public static readonly DependencyProperty MainTileLayerProperty = DependencyProperty.Register(
|
||||
"MainTileLayer", typeof(TileLayer), typeof(Map), new FrameworkPropertyMetadata(
|
||||
(o, e) => ((Map)o).SetMainTileLayer((TileLayer)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceMainTileLayer((TileLayer)v)));
|
||||
|
||||
public static readonly DependencyProperty TileOpacityProperty = DependencyProperty.Register(
|
||||
"TileOpacity", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d,
|
||||
(o, e) => ((Map)o).tileContainer.Opacity = (double)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
||||
"Center", typeof(Point), typeof(Map), new FrameworkPropertyMetadata(new Point(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((Map)o).SetCenter((Point)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceCenter((Point)v)));
|
||||
"Center", typeof(Location), typeof(Map), new FrameworkPropertyMetadata(new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((Map)o).SetCenter((Location)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceCenter((Location)v)));
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
||||
"TargetCenter", typeof(Point), typeof(Map), new FrameworkPropertyMetadata(new Point(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((Map)o).SetTargetCenter((Point)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceCenter((Point)v)));
|
||||
"TargetCenter", typeof(Location), typeof(Map), new FrameworkPropertyMetadata(new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((Map)o).SetTargetCenter((Location)e.NewValue),
|
||||
(o, v) => ((Map)o).CoerceCenter((Location)v)));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
||||
"ZoomLevel", typeof(double), typeof(Map), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
|
|
@ -79,13 +89,13 @@ namespace MapControl
|
|||
public static readonly DependencyProperty CenterScaleProperty = CenterScalePropertyKey.DependencyProperty;
|
||||
|
||||
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 RotateTransform rotateTransform = new RotateTransform();
|
||||
private readonly MatrixTransform scaleRotateTransform = new MatrixTransform();
|
||||
private Point? transformOrigin;
|
||||
private Point viewOrigin;
|
||||
private PointAnimation centerAnimation;
|
||||
private Location transformOrigin;
|
||||
private Point viewportOrigin;
|
||||
private LocationAnimation centerAnimation;
|
||||
private DoubleAnimation zoomLevelAnimation;
|
||||
private DoubleAnimation headingAnimation;
|
||||
private bool updateTransform = true;
|
||||
|
|
@ -96,9 +106,8 @@ namespace MapControl
|
|||
MaxZoomLevel = 20;
|
||||
|
||||
AddVisualChild(tileContainer);
|
||||
mapViewTransform.ViewTransform = tileContainer.ViewTransform;
|
||||
|
||||
BaseTileLayer = new TileLayer
|
||||
MainTileLayer = new TileLayer
|
||||
{
|
||||
Description = "© {y} OpenStreetMap Contributors, CC-BY-SA",
|
||||
TileSource = new OpenStreetMapTileSource { UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png" }
|
||||
|
|
@ -190,12 +199,12 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <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>
|
||||
public TileLayer BaseTileLayer
|
||||
public TileLayer MainTileLayer
|
||||
{
|
||||
get { return (TileLayer)GetValue(BaseTileLayerProperty); }
|
||||
set { SetValue(BaseTileLayerProperty, value); }
|
||||
get { return (TileLayer)GetValue(MainTileLayerProperty); }
|
||||
set { SetValue(MainTileLayerProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -208,20 +217,20 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <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>
|
||||
public Point Center
|
||||
public Location Center
|
||||
{
|
||||
get { return (Point)GetValue(CenterProperty); }
|
||||
get { return (Location)GetValue(CenterProperty); }
|
||||
set { SetValue(CenterProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target value of a Center animation.
|
||||
/// </summary>
|
||||
public Point TargetCenter
|
||||
public Location TargetCenter
|
||||
{
|
||||
get { return (Point)GetValue(TargetCenterProperty); }
|
||||
get { return (Location)GetValue(TargetCenterProperty); }
|
||||
set { SetValue(TargetCenterProperty, value); }
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +271,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <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>
|
||||
public double CenterScale
|
||||
{
|
||||
|
|
@ -271,34 +280,24 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the transformation from world coordinates (latitude and longitude)
|
||||
/// to cartesian map coordinates.
|
||||
/// Gets the transformation from geographic coordinates to cartesian map coordinates.
|
||||
/// </summary>
|
||||
public MapTransform MapTransform
|
||||
{
|
||||
get { return mapViewTransform.MapTransform; }
|
||||
get { return mapTransform; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the transformation from cartesian map coordinates to view coordinates.
|
||||
/// Gets the transformation from cartesian map coordinates to viewport coordinates.
|
||||
/// </summary>
|
||||
public Transform ViewTransform
|
||||
public Transform ViewportTransform
|
||||
{
|
||||
get { return mapViewTransform.ViewTransform; }
|
||||
get { return tileContainer.ViewportTransform; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the combination of MapTransform and ViewTransform, i.e. the transformation
|
||||
/// from longitude and latitude values to view coordinates.
|
||||
/// </summary>
|
||||
public GeneralTransform MapViewTransform
|
||||
{
|
||||
get { return mapViewTransform; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaling transformation from meters to view coordinate units (pixels)
|
||||
/// at the view center point.
|
||||
/// Gets the scaling transformation from meters to viewport coordinate units (pixels)
|
||||
/// at the viewport center point.
|
||||
/// </summary>
|
||||
public Transform ScaleTransform
|
||||
{
|
||||
|
|
@ -322,57 +321,73 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <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.
|
||||
/// </summary>
|
||||
public void SetTransformOrigin(Point origin)
|
||||
{
|
||||
transformOrigin = origin;
|
||||
viewOrigin = MapViewTransform.Transform(origin);
|
||||
viewportOrigin.X = Math.Min(Math.Max(origin.X, 0d), RenderSize.Width);
|
||||
viewportOrigin.Y = Math.Min(Math.Max(origin.Y, 0d), RenderSize.Height);
|
||||
transformOrigin = CoerceCenter(ViewportPointToLocation(viewportOrigin));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an intermittent origin point in view coordinates for scaling and rotation transformations.
|
||||
/// 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.
|
||||
/// Removes the temporary transform origin point set by SetTransformOrigin.
|
||||
/// </summary>
|
||||
public void ResetTransformOrigin()
|
||||
{
|
||||
transformOrigin = null;
|
||||
viewOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||
viewportOrigin = new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public void TranslateMap(Vector translation)
|
||||
{
|
||||
if (translation.X != 0d || translation.Y != 0d)
|
||||
{
|
||||
ResetTransformOrigin();
|
||||
Center = MapViewTransform.Inverse.Transform(viewOrigin - translation);
|
||||
Center = ViewportPointToLocation(viewportOrigin - translation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
||||
/// view coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||
/// is performed relative to the specified origin point in view coordinates.
|
||||
/// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||
/// is performed relative to the specified origin point in viewport coordinates.
|
||||
/// </summary>
|
||||
public void TransformMap(Point origin, Vector translation, double rotation, double scale)
|
||||
{
|
||||
if (rotation != 0d || scale != 1d)
|
||||
{
|
||||
SetTransformViewOrigin(origin);
|
||||
SetTransformOrigin(origin);
|
||||
updateTransform = false;
|
||||
Heading += rotation;
|
||||
ZoomLevel += Math.Log(scale, 2d);
|
||||
|
|
@ -385,21 +400,20 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Sets the value of the ZoomLevel property while retaining the specified origin point
|
||||
/// in view coordinates.
|
||||
/// in viewport coordinates.
|
||||
/// </summary>
|
||||
public void ZoomMap(Point origin, double zoomLevel)
|
||||
{
|
||||
SetTransformViewOrigin(origin);
|
||||
SetTransformOrigin(origin);
|
||||
TargetZoomLevel = zoomLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the map scale at the specified world coordinate point
|
||||
/// as view coordinate units (pixels) per meter.
|
||||
/// Gets the map scale at the specified location as viewport coordinate units (pixels) per meter.
|
||||
/// </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
|
||||
|
|
@ -477,40 +491,40 @@ namespace MapControl
|
|||
|
||||
private void SetTileLayers(TileLayerCollection tileLayers)
|
||||
{
|
||||
BaseTileLayer = tileLayers.Count > 0 ? tileLayers[0] : null;
|
||||
MainTileLayer = tileLayers.Count > 0 ? tileLayers[0] : null;
|
||||
tileContainer.TileLayers = tileLayers;
|
||||
}
|
||||
|
||||
private void SetBaseTileLayer(TileLayer baseTileLayer)
|
||||
private void SetMainTileLayer(TileLayer mainTileLayer)
|
||||
{
|
||||
if (baseTileLayer != null)
|
||||
if (mainTileLayer != null)
|
||||
{
|
||||
if (TileLayers == null)
|
||||
{
|
||||
TileLayers = new TileLayerCollection(baseTileLayer);
|
||||
TileLayers = new TileLayerCollection(mainTileLayer);
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
|
@ -524,7 +538,7 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
private void SetTargetCenter(Point targetCenter)
|
||||
private void SetTargetCenter(Location targetCenter)
|
||||
{
|
||||
if (targetCenter != Center)
|
||||
{
|
||||
|
|
@ -533,7 +547,7 @@ namespace MapControl
|
|||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
}
|
||||
|
||||
centerAnimation = new PointAnimation
|
||||
centerAnimation = new LocationAnimation
|
||||
{
|
||||
From = Center,
|
||||
To = targetCenter,
|
||||
|
|
@ -557,11 +571,11 @@ namespace MapControl
|
|||
centerAnimation = null;
|
||||
}
|
||||
|
||||
private Point CoerceCenter(Point point)
|
||||
private Location CoerceCenter(Location location)
|
||||
{
|
||||
point.X = ((point.X + 180d) % 360d + 360d) % 360d - 180d;
|
||||
point.Y = Math.Min(Math.Max(point.Y, -MapTransform.MaxLatitude), MapTransform.MaxLatitude);
|
||||
return point;
|
||||
location.Latitude = Math.Min(Math.Max(location.Latitude, -MapTransform.MaxLatitude), MapTransform.MaxLatitude);
|
||||
location.Longitude = ((location.Longitude + 180d) % 360d + 360d) % 360d - 180d;
|
||||
return location;
|
||||
}
|
||||
|
||||
private void SetZoomLevel(double zoomLevel)
|
||||
|
|
@ -682,16 +696,16 @@ namespace MapControl
|
|||
{
|
||||
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;
|
||||
Center = MapViewTransform.Inverse.Transform(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
Center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
updateTransform = true;
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
|
@ -42,21 +43,20 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GlyphRunText.cs" />
|
||||
<Compile Include="Location.cs" />
|
||||
<Compile Include="LocationAnimation.cs" />
|
||||
<Compile Include="LocationCollection.cs" />
|
||||
<Compile Include="MapElement.cs" />
|
||||
<Compile Include="MapGraticule.cs" />
|
||||
<Compile Include="MapItem.cs" />
|
||||
<Compile Include="MapItemsControl.cs" />
|
||||
<Compile Include="MapPanel.cs" />
|
||||
<Compile Include="MapPath.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MapPathGeometry.cs" />
|
||||
<Compile Include="MapStreamGeometry.cs" />
|
||||
<Compile Include="MapPolygon.cs" />
|
||||
<Compile Include="MapPolyline.cs" />
|
||||
<Compile Include="TileImageLoader.cs" />
|
||||
<Compile Include="MapTransform.cs" />
|
||||
<Compile Include="Map.cs" />
|
||||
<Compile Include="MapInput.cs" />
|
||||
<Compile Include="MapViewTransform.cs" />
|
||||
<Compile Include="MercatorTransform.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.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;
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -8,6 +12,9 @@ namespace MapControl
|
|||
void ParentMapChanged(Map oldParentMap, Map newParentMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for child elements of a MapPanel.
|
||||
/// </summary>
|
||||
public abstract class MapElement : FrameworkElement, INotifyParentMapChanged
|
||||
{
|
||||
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.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
|
@ -7,6 +11,10 @@ using System.Windows.Shapes;
|
|||
|
||||
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 static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
|
||||
|
|
@ -36,7 +44,7 @@ namespace MapControl
|
|||
public static readonly DependencyProperty MinSpacingPixelsProperty = DependencyProperty.Register(
|
||||
"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 };
|
||||
|
||||
private readonly DrawingVisual visual = new DrawingVisual();
|
||||
|
|
@ -116,17 +124,19 @@ namespace MapControl
|
|||
|
||||
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 spacing = GridSpacings[GridSpacings.Length - 1];
|
||||
double spacing = Spacings[Spacings.Length - 1];
|
||||
|
||||
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(bounds.Top / spacing) * spacing;
|
||||
double latitudeStart = Math.Ceiling(loc1.Latitude / spacing) * spacing;
|
||||
double longitudeStart = Math.Ceiling(loc1.Longitude / spacing) * spacing;
|
||||
|
||||
if (pen.Brush == null)
|
||||
{
|
||||
|
|
@ -135,18 +145,18 @@ namespace MapControl
|
|||
|
||||
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,
|
||||
parentMap.MapViewTransform.Transform(new Point(lon, bounds.Bottom)),
|
||||
parentMap.MapViewTransform.Transform(new Point(lon, bounds.Top)));
|
||||
parentMap.LocationToViewportPoint(new Location(lat, loc1.Longitude)),
|
||||
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,
|
||||
parentMap.MapViewTransform.Transform(new Point(bounds.Left, lat)),
|
||||
parentMap.MapViewTransform.Transform(new Point(bounds.Right, lat)));
|
||||
parentMap.LocationToViewportPoint(new Location(loc1.Latitude, lon)),
|
||||
parentMap.LocationToViewportPoint(new Location(loc2.Latitude, lon)));
|
||||
}
|
||||
|
||||
if (Foreground != null && Foreground != Brushes.Transparent)
|
||||
|
|
@ -158,12 +168,12 @@ namespace MapControl
|
|||
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;
|
||||
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 lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
|
||||
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.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.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
|
@ -7,22 +11,21 @@ using System.Windows.Media;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = "Normal")]
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = "Disabled")]
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = "MouseOver")]
|
||||
[TemplateVisualState(GroupName = "SelectionStates", Name = "Unselected")]
|
||||
[TemplateVisualState(GroupName = "SelectionStates", Name = "Selected")]
|
||||
[TemplateVisualState(GroupName = "CurrentStates", Name = "NonCurrent")]
|
||||
[TemplateVisualState(GroupName = "CurrentStates", Name = "Current")]
|
||||
/// <summary>
|
||||
/// Container class for an item in a MapItemsControl.
|
||||
/// </summary>
|
||||
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
|
||||
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
|
||||
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
|
||||
[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 static readonly RoutedEvent SelectedEvent = ListBoxItem.SelectedEvent.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(
|
||||
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;
|
||||
|
||||
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()
|
||||
{
|
||||
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem),
|
||||
|
|
@ -45,9 +41,6 @@ namespace MapControl
|
|||
|
||||
UIElement.IsEnabledProperty.OverrideMetadata(typeof(MapItem),
|
||||
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
|
||||
|
|
@ -67,27 +60,6 @@ namespace MapControl
|
|||
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
|
||||
{
|
||||
get { return (bool)GetValue(IsSelectedProperty); }
|
||||
|
|
@ -104,28 +76,12 @@ namespace MapControl
|
|||
SetValue(IsCurrentPropertyKey, value);
|
||||
int zIndex = Panel.GetZIndex(this);
|
||||
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
|
||||
{
|
||||
get { return (bool)GetValue(IsInsideMapBoundsProperty); }
|
||||
}
|
||||
|
||||
public object Item
|
||||
{
|
||||
get { return item; }
|
||||
internal set
|
||||
{
|
||||
item = value;
|
||||
if (HasViewPosition)
|
||||
{
|
||||
ViewPositionChanged(ViewPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
public object Item { get; internal set; }
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
|
|
@ -159,24 +115,6 @@ namespace MapControl
|
|||
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()
|
||||
{
|
||||
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.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
|
@ -8,6 +12,10 @@ namespace MapControl
|
|||
{
|
||||
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 static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register(
|
||||
|
|
@ -114,7 +122,7 @@ namespace MapControl
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
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 static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
||||
|
|
@ -12,17 +23,17 @@ namespace MapControl
|
|||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
|
||||
"Location", typeof(Point?), typeof(MapPanel),
|
||||
"Location", typeof(Location), typeof(MapPanel),
|
||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, LocationPropertyChanged));
|
||||
|
||||
internal static readonly DependencyPropertyKey ViewPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"ViewPosition", typeof(Point), typeof(MapPanel), null);
|
||||
private static readonly DependencyPropertyKey ViewportPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"ViewportPosition", typeof(Point), typeof(MapPanel), null);
|
||||
|
||||
private static readonly DependencyPropertyKey ViewPositionTransformPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"ViewPositionTransform", typeof(Transform), typeof(MapPanel), null);
|
||||
private static readonly DependencyPropertyKey IsInsideMapBoundsPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"IsInsideMapBounds", typeof(bool), typeof(MapPanel), null);
|
||||
|
||||
public static readonly DependencyProperty ViewPositionProperty = ViewPositionPropertyKey.DependencyProperty;
|
||||
public static readonly DependencyProperty ViewPositionTransformProperty = ViewPositionTransformPropertyKey.DependencyProperty;
|
||||
public static readonly DependencyProperty ViewportPositionProperty = ViewportPositionPropertyKey.DependencyProperty;
|
||||
public static readonly DependencyProperty IsInsideMapBoundsProperty = IsInsideMapBoundsPropertyKey.DependencyProperty;
|
||||
|
||||
public MapPanel()
|
||||
{
|
||||
|
|
@ -39,24 +50,29 @@ namespace MapControl
|
|||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -75,10 +91,10 @@ namespace MapControl
|
|||
{
|
||||
foreach (UIElement element in InternalChildren)
|
||||
{
|
||||
object viewPosition = element.ReadLocalValue(ViewPositionProperty);
|
||||
object viewportPosition = element.ReadLocalValue(ViewportPositionProperty);
|
||||
|
||||
if (viewPosition == DependencyProperty.UnsetValue ||
|
||||
!ArrangeElement(element, (Point)viewPosition))
|
||||
if (viewportPosition == DependencyProperty.UnsetValue ||
|
||||
!ArrangeElement(element, (Point)viewportPosition))
|
||||
{
|
||||
ArrangeElement(element, finalSize);
|
||||
}
|
||||
|
|
@ -91,11 +107,11 @@ namespace MapControl
|
|||
{
|
||||
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)
|
||||
{
|
||||
UIElement element = (UIElement)obj;
|
||||
Point? location = (Point?)eventArgs.NewValue;
|
||||
Location location = (Location)eventArgs.NewValue;
|
||||
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
|
||||
{
|
||||
element.ClearValue(ViewPositionPropertyKey);
|
||||
element.ClearValue(ViewPositionTransformPropertyKey);
|
||||
element.ClearValue(ViewportPositionPropertyKey);
|
||||
element.ClearValue(IsInsideMapBoundsPropertyKey);
|
||||
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);
|
||||
MatrixTransform viewTransform = element.GetValue(ViewPositionTransformProperty) as MatrixTransform;
|
||||
|
||||
if (viewTransform != null)
|
||||
{
|
||||
viewTransform.Matrix = matrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.SetValue(ViewPositionTransformPropertyKey, new MatrixTransform(matrix));
|
||||
}
|
||||
|
||||
ArrangeElement(element, viewPosition);
|
||||
ArrangeElement(element, viewportPosition);
|
||||
}
|
||||
|
||||
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.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
"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();
|
||||
private readonly GeometryDrawing drawing = new GeometryDrawing();
|
||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||
"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);
|
||||
|
||||
using (DrawingContext drawingContext = visual.RenderOpen())
|
||||
|
|
@ -59,18 +63,6 @@ namespace MapControl
|
|||
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
|
||||
{
|
||||
get { return (Brush)GetValue(StrokeProperty); }
|
||||
|
|
@ -131,6 +123,12 @@ namespace MapControl
|
|||
set { SetValue(TransformStrokeProperty, value); }
|
||||
}
|
||||
|
||||
public LocationCollection Locations
|
||||
{
|
||||
get { return (LocationCollection)GetValue(LocationsProperty); }
|
||||
set { SetValue(LocationsProperty, value); }
|
||||
}
|
||||
|
||||
public double TransformedStrokeThickness
|
||||
{
|
||||
get { return drawing.Pen.Thickness; }
|
||||
|
|
@ -162,23 +160,26 @@ namespace MapControl
|
|||
{
|
||||
double scale = 1d;
|
||||
|
||||
if (TransformStroke && Data != null)
|
||||
if (TransformStroke)
|
||||
{
|
||||
Point center = Data.Bounds.Location + (Vector)Data.Bounds.Size / 2d;
|
||||
scale = parentMap.GetMapScale(center) * Map.MeterPerDegree;
|
||||
scale = parentMap.CenterScale * Map.MeterPerDegree;
|
||||
}
|
||||
|
||||
drawing.Pen.Thickness = scale * StrokeThickness;
|
||||
}
|
||||
|
||||
private void UpdateGeometry()
|
||||
protected virtual void UpdateGeometry()
|
||||
{
|
||||
UpdateGeometry(false);
|
||||
}
|
||||
|
||||
protected void UpdateGeometry(bool closed)
|
||||
{
|
||||
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.Transform = parentMap.ViewTransform;
|
||||
drawing.Geometry = CreateGeometry(parentMap, Locations, closed);
|
||||
OnViewTransformChanged(parentMap);
|
||||
}
|
||||
else
|
||||
|
|
@ -196,5 +197,25 @@ namespace MapControl
|
|||
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.Media;
|
||||
|
||||
|
|
@ -9,7 +15,7 @@ namespace MapControl
|
|||
/// 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].
|
||||
/// </summary>
|
||||
public abstract class MapTransform : GeneralTransform
|
||||
public abstract class MapTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the point scale factor of the map projection at the specified point
|
||||
/// relative to the point (0, 0).
|
||||
/// Gets the scale factor of the map projection at the specified geographic location
|
||||
/// relative to the scale at latitude zero.
|
||||
/// </summary>
|
||||
public abstract double RelativeScale(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.Media;
|
||||
|
||||
|
|
@ -10,101 +14,50 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public class MercatorTransform : MapTransform
|
||||
{
|
||||
private GeneralTransform inverse = new InverseMercatorTransform();
|
||||
|
||||
public MercatorTransform()
|
||||
{
|
||||
Freeze();
|
||||
}
|
||||
|
||||
public override GeneralTransform Inverse
|
||||
{
|
||||
get { return inverse; }
|
||||
}
|
||||
|
||||
public override double MaxLatitude
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (point.Y >= 90d)
|
||||
if (location.Latitude >= 90d)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else if (point.Y >= 90d)
|
||||
else if (location.Latitude >= 90d)
|
||||
{
|
||||
result.Y = double.PositiveInfinity;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
return new Location(Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d, point.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ using System.Windows;
|
|||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Map Control")]
|
||||
[assembly: AssemblyDescription("MapControl")]
|
||||
[assembly: AssemblyDescription("WPF Map Control")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyProduct("MapControl")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012")]
|
||||
[assembly: AssemblyProduct("WPF Map Control")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[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.Media;
|
||||
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.Specialized;
|
||||
using System.Windows;
|
||||
|
|
@ -22,7 +26,7 @@ namespace MapControl
|
|||
private Int32Rect tileGrid;
|
||||
private TileLayerCollection tileLayers;
|
||||
private readonly DispatcherTimer updateTimer;
|
||||
private readonly MatrixTransform viewTransform = new MatrixTransform();
|
||||
private readonly MatrixTransform viewportTransform = new MatrixTransform();
|
||||
|
||||
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;
|
||||
rotation = mapRotation;
|
||||
size = viewSize;
|
||||
origin = viewOrigin;
|
||||
size = viewportSize;
|
||||
origin = viewportOrigin;
|
||||
|
||||
double scale = Math.Pow(2d, zoomLevel) * 256d / 360d;
|
||||
offset.X = origin.X - (180d + mapOrigin.X) * scale;
|
||||
|
|
@ -72,7 +76,7 @@ namespace MapControl
|
|||
transform.Scale(scale, scale);
|
||||
transform.Translate(offset.X, offset.Y);
|
||||
transform.RotateAt(rotation, origin.X, origin.Y);
|
||||
viewTransform.Matrix = transform;
|
||||
viewportTransform.Matrix = transform;
|
||||
|
||||
transform = GetVisualTransform();
|
||||
|
||||
|
|
@ -110,7 +114,7 @@ namespace MapControl
|
|||
int zoom = (int)Math.Floor(zoomLevel + 1d - zoomLevelSwitchOffset);
|
||||
int numTiles = 1 << zoom;
|
||||
double mapToTileScale = (double)numTiles / 360d;
|
||||
Matrix transform = viewTransform.Matrix;
|
||||
Matrix transform = viewportTransform.Matrix;
|
||||
transform.Invert(); // view to map coordinates
|
||||
transform.Translate(180d, -180d);
|
||||
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.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -10,9 +14,13 @@ using System.Windows.Threading;
|
|||
|
||||
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 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);
|
||||
|
||||
private readonly Queue<Tile> pendingTiles = new Queue<Tile>();
|
||||
|
|
@ -45,7 +53,7 @@ namespace MapControl
|
|||
|
||||
lock (pendingTiles)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(TileCacheDirectory) &&
|
||||
if (!string.IsNullOrEmpty(TileCacheFolder) &&
|
||||
!string.IsNullOrEmpty(TileLayerName))
|
||||
{
|
||||
List<Tile> expiredTiles = new List<Tile>(newTiles.Count);
|
||||
|
|
@ -174,7 +182,7 @@ namespace MapControl
|
|||
|
||||
string tilePath;
|
||||
|
||||
if (!string.IsNullOrEmpty(TileCacheDirectory) &&
|
||||
if (!string.IsNullOrEmpty(TileCacheFolder) &&
|
||||
!string.IsNullOrEmpty(TileLayerName) &&
|
||||
(tilePath = TilePath(tile, decoder)) != null)
|
||||
{
|
||||
|
|
@ -213,7 +221,7 @@ namespace MapControl
|
|||
|
||||
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)
|
||||
|
|
@ -255,7 +263,7 @@ namespace MapControl
|
|||
|
||||
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));
|
||||
#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.Linq;
|
||||
using System.Windows;
|
||||
|
|
@ -7,11 +11,17 @@ using System.Windows.Media;
|
|||
|
||||
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")]
|
||||
public class TileLayer : DrawingVisual
|
||||
{
|
||||
private readonly TileImageLoader tileImageLoader = new TileImageLoader();
|
||||
private readonly List<Tile> tiles = new List<Tile>();
|
||||
private bool isCached = false;
|
||||
private string name = string.Empty;
|
||||
private string description = string.Empty;
|
||||
private Int32Rect grid;
|
||||
private int zoomLevel;
|
||||
|
|
@ -36,10 +46,24 @@ namespace MapControl
|
|||
set { tileImageLoader.MaxDownloads = value; }
|
||||
}
|
||||
|
||||
public bool IsCached
|
||||
{
|
||||
get { return isCached; }
|
||||
set
|
||||
{
|
||||
isCached = value;
|
||||
tileImageLoader.TileLayerName = isCached ? name : null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return tileImageLoader.TileLayerName; }
|
||||
set { tileImageLoader.TileLayerName = value; }
|
||||
get { return name; }
|
||||
set
|
||||
{
|
||||
name = value;
|
||||
tileImageLoader.TileLayerName = isCached ? name : null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
|
|
@ -136,7 +160,7 @@ namespace MapControl
|
|||
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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.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.Globalization;
|
||||
using System.Text;
|
||||
|
|
@ -6,6 +10,9 @@ using System.Windows;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the URI of a map tile.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(TileSourceTypeConverter))]
|
||||
public class TileSource
|
||||
{
|
||||
|
|
@ -90,20 +97,20 @@ namespace MapControl
|
|||
{
|
||||
public override Uri GetUri(int x, int y, int zoomLevel)
|
||||
{
|
||||
InverseMercatorTransform t = new InverseMercatorTransform();
|
||||
MercatorTransform t = new MercatorTransform();
|
||||
double n = 1 << zoomLevel;
|
||||
double x1 = (double)x * 360d / n - 180d;
|
||||
double x2 = (double)(x + 1) * 360d / n - 180d;
|
||||
double y1 = 180d - (double)(y + 1) * 360d / n;
|
||||
double y2 = 180d - (double)y * 360d / n;
|
||||
Point p1 = t.Transform(new Point(x1, y1));
|
||||
Point p2 = t.Transform(new Point(x2, y2));
|
||||
Location p1 = t.TransformBack(new Point(x1, y1));
|
||||
Location p2 = t.TransformBack(new Point(x2, y2));
|
||||
|
||||
return new Uri(UriFormat.
|
||||
Replace("{w}", p1.X.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{s}", p1.Y.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{e}", p2.X.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{n}", p2.Y.ToString(CultureInfo.InvariantCulture)));
|
||||
Replace("{w}", p1.Longitude.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{s}", p1.Latitude.ToString(CultureInfo.InvariantCulture)).
|
||||
Replace("{e}", p2.Longitude.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