diff --git a/MapControl/Map.WPF.cs b/MapControl/Map.WPF.cs
index 57c92d46..485698b5 100644
--- a/MapControl/Map.WPF.cs
+++ b/MapControl/Map.WPF.cs
@@ -79,7 +79,7 @@ namespace MapControl
if (mousePosition.HasValue)
{
var position = e.GetPosition(this);
- TranslateMap((Point)(position - mousePosition.Value));
+ TranslateMap(position - mousePosition.Value);
mousePosition = position;
}
}
@@ -96,7 +96,7 @@ namespace MapControl
base.OnManipulationDelta(e);
TransformMap(e.ManipulationOrigin,
- (Point)e.DeltaManipulation.Translation, e.DeltaManipulation.Rotation,
+ e.DeltaManipulation.Translation, e.DeltaManipulation.Rotation,
(e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2d);
}
}
diff --git a/MapControl/MapBase.Silverlight.WinRT.cs b/MapControl/MapBase.Silverlight.WinRT.cs
index 80562528..75f119f5 100644
--- a/MapControl/MapBase.Silverlight.WinRT.cs
+++ b/MapControl/MapBase.Silverlight.WinRT.cs
@@ -70,11 +70,12 @@ namespace MapControl
MapOrigin = mapTransform.Transform(origin);
ViewportScale = Math.Pow(2d, ZoomLevel) * (double)TileSource.TileSize / 360d;
- viewportTransform.Matrix =
- new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y)
+ var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y)
+ .Rotate(-Heading)
.Scale(ViewportScale, -ViewportScale)
- .Rotate(Heading)
.Translate(ViewportOrigin.X, ViewportOrigin.Y);
+
+ viewportTransform.Matrix = transform;
}
}
}
diff --git a/MapControl/MapBase.WPF.cs b/MapControl/MapBase.WPF.cs
index f6f72d9a..7c178000 100644
--- a/MapControl/MapBase.WPF.cs
+++ b/MapControl/MapBase.WPF.cs
@@ -53,6 +53,24 @@ namespace MapControl
typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
}
+ ///
+ /// Changes the Center property according to the specified translation in viewport coordinates.
+ ///
+ public void TranslateMap(Vector translation)
+ {
+ TranslateMap((Point)translation);
+ }
+
+ ///
+ /// Changes the Center, Heading and ZoomLevel properties according to the specified
+ /// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
+ /// is performed relative to the specified origin point in viewport coordinates.
+ ///
+ public void TransformMap(Point origin, Vector translation, double rotation, double scale)
+ {
+ TransformMap(origin, (Point)translation, rotation, scale);
+ }
+
partial void RemoveAnimation(DependencyProperty property)
{
BeginAnimation(property, null);
@@ -72,8 +90,8 @@ namespace MapControl
ViewportScale = Math.Pow(2d, ZoomLevel) * (double)TileSource.TileSize / 360d;
var transform = new Matrix(1d, 0d, 0d, 1d, -MapOrigin.X, -MapOrigin.Y);
+ transform.Rotate(-Heading);
transform.Scale(ViewportScale, -ViewportScale);
- transform.Rotate(Heading);
transform.Translate(ViewportOrigin.X, ViewportOrigin.Y);
viewportTransform.Matrix = transform;
diff --git a/MapControl/MapBase.cs b/MapControl/MapBase.cs
index e19144e8..e54b2956 100644
--- a/MapControl/MapBase.cs
+++ b/MapControl/MapBase.cs
@@ -75,9 +75,6 @@ namespace MapControl
private DoubleAnimation headingAnimation;
private bool internalPropertyChange;
- internal Point MapOrigin { get; private set; }
- internal Point ViewportOrigin { get; private set; }
-
public MapBase()
{
Initialize();
@@ -272,6 +269,9 @@ namespace MapControl
get { return scaleRotateTransform; }
}
+ internal Point MapOrigin { get; private set; }
+ internal Point ViewportOrigin { get; private set; }
+
///
/// Gets the scaling factor from cartesian map coordinates to viewport coordinates.
///
@@ -337,18 +337,32 @@ namespace MapControl
}
///
- /// Changes the Center property according to the specified translation in viewport coordinates.
+ /// Changes the Center property according to the specified map translation in viewport coordinates.
///
public void TranslateMap(Point translation)
{
if (transformOrigin != null)
{
ResetTransformOrigin();
+ UpdateTransform();
}
if (translation.X != 0d || translation.Y != 0d)
{
- Center = ViewportPointToLocation(new Point(ViewportOrigin.X - translation.X, ViewportOrigin.Y - translation.Y));
+ if (Heading != 0d)
+ {
+ var cos = Math.Cos(Heading / 180d * Math.PI);
+ var sin = Math.Sin(Heading / 180d * Math.PI);
+
+ translation = new Point(
+ translation.X * cos + translation.Y * sin,
+ translation.Y * cos - translation.X * sin);
+ }
+
+ translation.X /= -ViewportScale;
+ translation.Y /= ViewportScale;
+
+ Center = mapTransform.Transform(Center, MapOrigin, translation);
}
}
@@ -359,25 +373,31 @@ namespace MapControl
///
public void TransformMap(Point origin, Point translation, double rotation, double scale)
{
- SetTransformOrigin(origin);
-
- ViewportOrigin = new Point(ViewportOrigin.X + translation.X, ViewportOrigin.Y + translation.Y);
-
- if (rotation != 0d)
+ if (rotation != 0d || scale != 1d)
{
- var heading = (((Heading + rotation) % 360d) + 360d) % 360d;
- InternalSetValue(HeadingProperty, heading);
- InternalSetValue(TargetHeadingProperty, heading);
- }
+ transformOrigin = ViewportPointToLocation(origin);
+ ViewportOrigin = new Point(origin.X + translation.X, origin.Y + translation.Y);
- if (scale != 1d)
+ if (rotation != 0d)
+ {
+ var heading = (((Heading + rotation) % 360d) + 360d) % 360d;
+ InternalSetValue(HeadingProperty, heading);
+ InternalSetValue(TargetHeadingProperty, heading);
+ }
+
+ if (scale != 1d)
+ {
+ var zoomLevel = Math.Min(Math.Max(ZoomLevel + Math.Log(scale, 2d), MinZoomLevel), MaxZoomLevel);
+ InternalSetValue(ZoomLevelProperty, zoomLevel);
+ InternalSetValue(TargetZoomLevelProperty, zoomLevel);
+ }
+
+ UpdateTransform(true);
+ }
+ else
{
- var zoomLevel = Math.Min(Math.Max(ZoomLevel + Math.Log(scale, 2d), MinZoomLevel), MaxZoomLevel);
- InternalSetValue(ZoomLevelProperty, zoomLevel);
- InternalSetValue(TargetZoomLevelProperty, zoomLevel);
+ TranslateMap(translation); // more precise
}
-
- UpdateTransform(true);
}
///
@@ -567,7 +587,6 @@ namespace MapControl
if (!internalPropertyChange)
{
AdjustCenterProperty(CenterProperty, ref center);
- ResetTransformOrigin();
UpdateTransform();
if (centerAnimation == null)
@@ -616,8 +635,6 @@ namespace MapControl
InternalSetValue(CenterProperty, TargetCenter);
InternalSetValue(CenterPointProperty, mapTransform.Transform(TargetCenter));
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
-
- ResetTransformOrigin();
UpdateTransform();
}
}
@@ -628,7 +645,6 @@ namespace MapControl
{
centerPoint.X = Location.NormalizeLongitude(centerPoint.X);
InternalSetValue(CenterProperty, mapTransform.Transform(centerPoint));
- ResetTransformOrigin();
UpdateTransform();
}
}
@@ -720,7 +736,7 @@ namespace MapControl
InternalSetValue(ZoomLevelProperty, TargetZoomLevel);
RemoveAnimation(ZoomLevelProperty); // remove holding animation in WPF
- UpdateTransform(true);
+ Dispatcher.BeginInvoke(() => UpdateTransform(true));
}
}
@@ -793,12 +809,11 @@ namespace MapControl
InternalSetValue(HeadingProperty, TargetHeading);
RemoveAnimation(HeadingProperty); // remove holding animation in WPF
-
UpdateTransform();
}
}
- private void UpdateTransform(bool resetTransformOrigin = false)
+ private void UpdateTransform(bool resetOrigin = false)
{
var center = transformOrigin ?? Center;
@@ -812,7 +827,7 @@ namespace MapControl
if (center.Latitude < -mapTransform.MaxLatitude || center.Latitude > mapTransform.MaxLatitude)
{
center.Latitude = Math.Min(Math.Max(center.Latitude, -mapTransform.MaxLatitude), mapTransform.MaxLatitude);
- resetTransformOrigin = true;
+ resetOrigin = true;
}
InternalSetValue(CenterProperty, center);
@@ -823,7 +838,7 @@ namespace MapControl
InternalSetValue(CenterPointProperty, mapTransform.Transform(center));
}
- if (resetTransformOrigin)
+ if (resetOrigin)
{
ResetTransformOrigin();
SetViewportTransform(center);
diff --git a/MapControl/MapTransform.cs b/MapControl/MapTransform.cs
index fe5aa3f5..9be6c379 100644
--- a/MapControl/MapTransform.cs
+++ b/MapControl/MapTransform.cs
@@ -3,6 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
+using System;
using Windows.Foundation;
#else
using System.Windows;
@@ -25,21 +26,21 @@ namespace MapControl
public abstract double MaxLatitude { get; }
///
- /// Gets the scale factor of the map projection at the specified geographic location
- /// relative to the scale at latitude zero.
+ /// Gets the scale factor of the map projection at the specified
+ /// geographic location relative to the scale at latitude zero.
///
public abstract double RelativeScale(Location location);
- ///
- /// Transforms a cartesian coordinate point to a geographic location.
- ///
- public abstract Location Transform(Point point);
-
///
/// Transforms a geographic location to a cartesian coordinate point.
///
public abstract Point Transform(Location location);
+ ///
+ /// Transforms a cartesian coordinate point to a geographic location.
+ ///
+ public abstract Location Transform(Point point);
+
///
/// Transforms a geographic location to a cartesian coordinate point
/// with minumum distance to the specified reference longitude value.
@@ -61,5 +62,22 @@ namespace MapControl
return p;
}
+
+ ///
+ /// Transforms a geographic location by the specified translation in viewport coordinates.
+ ///
+ public Location Transform(Location origin, Point mapOrigin, Point translation)
+ {
+#if NETFX_CORE
+ var latitudeTranslation = translation.Y / RelativeScale(origin);
+
+ if (Math.Abs(latitudeTranslation) < 1e-3) // avoid rounding errors
+ {
+ return new Location(origin.Latitude + latitudeTranslation, origin.Longitude + translation.X);
+ }
+#endif
+ return Transform(new Point(mapOrigin.X + translation.X, mapOrigin.Y + translation.Y));
+ }
}
+
}
diff --git a/MapControl/MercatorTransform.cs b/MapControl/MercatorTransform.cs
index 002e776a..10f7ddeb 100644
--- a/MapControl/MercatorTransform.cs
+++ b/MapControl/MercatorTransform.cs
@@ -17,7 +17,7 @@ namespace MapControl
///
public class MercatorTransform : MapTransform
{
- public static readonly double MaxLatitudeValue = Math.Atan(Math.Sinh(Math.PI)) / Math.PI * 180d;
+ public static readonly double MaxLatitudeValue = YToLatitude(180d);
public static double RelativeScale(double latitude)
{
@@ -46,13 +46,12 @@ namespace MapControl
return double.PositiveInfinity;
}
- latitude *= Math.PI / 180d;
- return Math.Log(Math.Tan(latitude) + 1d / Math.Cos(latitude)) / Math.PI * 180d;
+ return Math.Log(Math.Tan((latitude + 90d) * Math.PI / 360d)) / Math.PI * 180d;
}
public static double YToLatitude(double y)
{
- return Math.Atan(Math.Sinh(y * Math.PI / 180d)) / Math.PI * 180d;
+ return Math.Atan(Math.Exp(y * Math.PI / 180d)) / Math.PI * 360d - 90d;
}
public override double MaxLatitude
diff --git a/MapControl/TileLayer.Silverlight.WinRT.cs b/MapControl/TileLayer.Silverlight.WinRT.cs
index 98ebfb39..9cef8906 100644
--- a/MapControl/TileLayer.Silverlight.WinRT.cs
+++ b/MapControl/TileLayer.Silverlight.WinRT.cs
@@ -46,7 +46,7 @@ namespace MapControl
new Matrix(1d, 0d, 0d, 1d, TileSource.TileSize * TileGrid.XMin, TileSource.TileSize * TileGrid.YMin)
.Scale(scale, scale)
.Translate(offsetX, offsetY)
- .RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y); ;
+ .RotateAt(parentMap.Heading, parentMap.ViewportOrigin.X, parentMap.ViewportOrigin.Y);
}
}
}