mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Version 1.10.0: Removed Location.TransformedLatitude, cleanup in MapBase and TileImageLoader.
This commit is contained in:
parent
9241e5451f
commit
f11c71799f
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -15,15 +15,6 @@ namespace MapControl
|
|||
#endif
|
||||
public partial class Location
|
||||
{
|
||||
/// <summary>
|
||||
/// TransformedLatitude is set by the Transform methods in MercatorTransform.
|
||||
/// It holds the transformed latitude value to avoid redundant recalculation.
|
||||
/// </summary>
|
||||
#if !SILVERLIGHT && !NETFX_CORE
|
||||
[NonSerialized]
|
||||
#endif
|
||||
internal double TransformedLatitude = double.NaN;
|
||||
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
|
||||
|
|
@ -33,24 +24,14 @@ namespace MapControl
|
|||
|
||||
public Location(double latitude, double longitude)
|
||||
{
|
||||
this.latitude = Math.Min(Math.Max(latitude, -90d), 90d);
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
internal Location(double transformedLatitude, double latitude, double longitude)
|
||||
: this(latitude, longitude)
|
||||
{
|
||||
TransformedLatitude = transformedLatitude;
|
||||
Latitude = latitude;
|
||||
Longitude = longitude;
|
||||
}
|
||||
|
||||
public double Latitude
|
||||
{
|
||||
get { return latitude; }
|
||||
set
|
||||
{
|
||||
latitude = Math.Min(Math.Max(value, -90d), 90d);
|
||||
TransformedLatitude = double.NaN;
|
||||
}
|
||||
set { latitude = Math.Min(Math.Max(value, -90d), 90d); }
|
||||
}
|
||||
|
||||
public double Longitude
|
||||
|
|
@ -79,7 +60,16 @@ namespace MapControl
|
|||
|
||||
public static double NormalizeLongitude(double longitude)
|
||||
{
|
||||
return (longitude >= -180d && longitude <= 180d) ? longitude : ((longitude + 180d) % 360d + 360d) % 360d - 180d;
|
||||
if (longitude > 180)
|
||||
{
|
||||
longitude = ((longitude - 180d) % 360d) - 180d;
|
||||
}
|
||||
else if (longitude < -180d)
|
||||
{
|
||||
longitude = ((longitude + 180d) % 360d) + 180d;
|
||||
}
|
||||
|
||||
return longitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public partial class MapBase : MapPanel
|
||||
{
|
||||
private const double MaximumZoomLevel = 22d;
|
||||
|
||||
public static TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.5);
|
||||
public static EasingFunctionBase AnimationEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut };
|
||||
|
||||
|
|
@ -394,14 +396,10 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public void ZoomMap(Point origin, double zoomLevel)
|
||||
{
|
||||
SetTransformOrigin(origin);
|
||||
|
||||
var targetZoomLevel = TargetZoomLevel;
|
||||
TargetZoomLevel = zoomLevel;
|
||||
|
||||
if (TargetZoomLevel == targetZoomLevel) // TargetZoomLevel might be coerced
|
||||
if (zoomLevel >= MinZoomLevel && zoomLevel <= MaxZoomLevel)
|
||||
{
|
||||
ResetTransformOrigin();
|
||||
SetTransformOrigin(origin);
|
||||
TargetZoomLevel = zoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -572,48 +570,38 @@ namespace MapControl
|
|||
internalPropertyChange = false;
|
||||
}
|
||||
|
||||
private bool CoerceLocation(ref Location location, double latitudeEpsilon = 0d)
|
||||
private void AdjustCenterProperty(DependencyProperty property, ref Location center)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
location = new Location();
|
||||
return true;
|
||||
}
|
||||
|
||||
var maxLatitude = mapTransform.MaxLatitude + latitudeEpsilon;
|
||||
var latitude = Math.Min(Math.Max(location.Latitude, -maxLatitude), maxLatitude);
|
||||
var longitude = Location.NormalizeLongitude(location.Longitude);
|
||||
|
||||
if (location.Latitude != latitude || location.Longitude != longitude)
|
||||
{
|
||||
location.Latitude = latitude;
|
||||
location.Longitude = longitude;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CoerceCenterProperty(DependencyProperty property, ref Location center)
|
||||
{
|
||||
if (CoerceLocation(ref center))
|
||||
if (center == null)
|
||||
{
|
||||
center = new Location();
|
||||
InternalSetValue(property, center);
|
||||
}
|
||||
else
|
||||
{
|
||||
var latitude = Math.Min(Math.Max(center.Latitude, -mapTransform.MaxLatitude), mapTransform.MaxLatitude);
|
||||
var longitude = Location.NormalizeLongitude(center.Longitude);
|
||||
|
||||
if (center.Latitude != latitude || center.Longitude != longitude)
|
||||
{
|
||||
center = new Location(latitude, longitude);
|
||||
InternalSetValue(property, center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CenterPropertyChanged(Location center)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceCenterProperty(CenterProperty, ref center);
|
||||
AdjustCenterProperty(CenterProperty, ref center);
|
||||
ResetTransformOrigin();
|
||||
UpdateTransform();
|
||||
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
InternalSetValue(TargetCenterProperty, center);
|
||||
InternalSetValue(CenterPointProperty, new Point(center.Longitude, center.Latitude));
|
||||
InternalSetValue(CenterPointProperty, MapTransform.Transform(center));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -622,7 +610,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceCenterProperty(TargetCenterProperty, ref targetCenter);
|
||||
AdjustCenterProperty(TargetCenterProperty, ref targetCenter);
|
||||
|
||||
if (targetCenter.Latitude != Center.Latitude || targetCenter.Longitude != Center.Longitude)
|
||||
{
|
||||
|
|
@ -634,8 +622,8 @@ namespace MapControl
|
|||
// animate private CenterPoint property by PointAnimation
|
||||
centerAnimation = new PointAnimation
|
||||
{
|
||||
From = new Point(Center.Longitude, Center.Latitude),
|
||||
To = new Point(targetCenter.Longitude, targetCenter.Latitude),
|
||||
From = MapTransform.Transform(Center),
|
||||
To = MapTransform.Transform(targetCenter, Center.Longitude),
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
FillBehavior = FillBehavior.HoldEnd
|
||||
|
|
@ -655,7 +643,7 @@ namespace MapControl
|
|||
centerAnimation = null;
|
||||
|
||||
InternalSetValue(CenterProperty, TargetCenter);
|
||||
InternalSetValue(CenterPointProperty, new Point(TargetCenter.Longitude, TargetCenter.Latitude));
|
||||
InternalSetValue(CenterPointProperty, MapTransform.Transform(TargetCenter));
|
||||
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
|
||||
|
||||
ResetTransformOrigin();
|
||||
|
|
@ -667,7 +655,8 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
InternalSetValue(CenterProperty, new Location(centerPoint.Y, centerPoint.X));
|
||||
centerPoint.X = Location.NormalizeLongitude(centerPoint.X);
|
||||
InternalSetValue(CenterProperty, MapTransform.Transform(centerPoint));
|
||||
ResetTransformOrigin();
|
||||
UpdateTransform();
|
||||
}
|
||||
|
|
@ -675,11 +664,9 @@ namespace MapControl
|
|||
|
||||
private void MinZoomLevelPropertyChanged(double minZoomLevel)
|
||||
{
|
||||
var coercedValue = Math.Min(Math.Max(minZoomLevel, 0d), MaxZoomLevel);
|
||||
|
||||
if (coercedValue != minZoomLevel)
|
||||
if (minZoomLevel < 0d || minZoomLevel > MaxZoomLevel)
|
||||
{
|
||||
minZoomLevel = coercedValue;
|
||||
minZoomLevel = Math.Min(Math.Max(minZoomLevel, 0d), MaxZoomLevel);
|
||||
InternalSetValue(MinZoomLevelProperty, minZoomLevel);
|
||||
}
|
||||
|
||||
|
|
@ -691,11 +678,9 @@ namespace MapControl
|
|||
|
||||
private void MaxZoomLevelPropertyChanged(double maxZoomLevel)
|
||||
{
|
||||
var coercedValue = Math.Min(Math.Max(maxZoomLevel, MinZoomLevel), 22d);
|
||||
|
||||
if (coercedValue != maxZoomLevel)
|
||||
if (maxZoomLevel < MinZoomLevel || maxZoomLevel > MaximumZoomLevel)
|
||||
{
|
||||
maxZoomLevel = coercedValue;
|
||||
maxZoomLevel = Math.Min(Math.Max(maxZoomLevel, MinZoomLevel), MaximumZoomLevel);
|
||||
InternalSetValue(MaxZoomLevelProperty, maxZoomLevel);
|
||||
}
|
||||
|
||||
|
|
@ -705,13 +690,11 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
private void CoerceZoomLevelProperty(DependencyProperty property, ref double zoomLevel)
|
||||
private void AdjustZoomLevelProperty(DependencyProperty property, ref double zoomLevel)
|
||||
{
|
||||
var coercedValue = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
|
||||
|
||||
if (coercedValue != zoomLevel)
|
||||
if (zoomLevel < MinZoomLevel || zoomLevel > MaxZoomLevel)
|
||||
{
|
||||
zoomLevel = coercedValue;
|
||||
zoomLevel = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
|
||||
InternalSetValue(property, zoomLevel);
|
||||
}
|
||||
}
|
||||
|
|
@ -720,7 +703,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceZoomLevelProperty(ZoomLevelProperty, ref zoomLevel);
|
||||
AdjustZoomLevelProperty(ZoomLevelProperty, ref zoomLevel);
|
||||
UpdateTransform();
|
||||
|
||||
if (zoomLevelAnimation == null)
|
||||
|
|
@ -734,7 +717,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceZoomLevelProperty(TargetZoomLevelProperty, ref targetZoomLevel);
|
||||
AdjustZoomLevelProperty(TargetZoomLevelProperty, ref targetZoomLevel);
|
||||
|
||||
if (targetZoomLevel != ZoomLevel)
|
||||
{
|
||||
|
|
@ -772,13 +755,11 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
private void CoerceHeadingProperty(DependencyProperty property, ref double heading)
|
||||
private void AdjustHeadingProperty(DependencyProperty property, ref double heading)
|
||||
{
|
||||
var coercedValue = (heading >= -180d && heading <= 360d) ? heading : (((heading % 360d) + 360d) % 360d);
|
||||
|
||||
if (coercedValue != heading)
|
||||
if (heading < -180d || heading > 360d)
|
||||
{
|
||||
heading = coercedValue;
|
||||
heading = ((heading % 360d) + 360d) % 360d;
|
||||
InternalSetValue(property, heading);
|
||||
}
|
||||
}
|
||||
|
|
@ -787,7 +768,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceHeadingProperty(HeadingProperty, ref heading);
|
||||
AdjustHeadingProperty(HeadingProperty, ref heading);
|
||||
UpdateTransform();
|
||||
|
||||
if (headingAnimation == null)
|
||||
|
|
@ -801,7 +782,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceHeadingProperty(TargetHeadingProperty, ref targetHeading);
|
||||
AdjustHeadingProperty(TargetHeadingProperty, ref targetHeading);
|
||||
|
||||
if (targetHeading != Heading)
|
||||
{
|
||||
|
|
@ -858,11 +839,18 @@ namespace MapControl
|
|||
{
|
||||
center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
|
||||
var coerced = CoerceLocation(ref center, 1e-3);
|
||||
var latitude = center.Latitude;
|
||||
center.Latitude = Math.Min(Math.Max(latitude, -mapTransform.MaxLatitude), mapTransform.MaxLatitude);
|
||||
|
||||
InternalSetValue(CenterProperty, center);
|
||||
|
||||
if (coerced)
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
InternalSetValue(TargetCenterProperty, center);
|
||||
InternalSetValue(CenterPointProperty, MapTransform.Transform(center));
|
||||
}
|
||||
|
||||
if (center.Latitude != latitude)
|
||||
{
|
||||
ResetTransformOrigin();
|
||||
scale = SetViewportTransform(center);
|
||||
|
|
|
|||
|
|
@ -179,9 +179,6 @@ namespace MapControl
|
|||
|
||||
if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
|
||||
{
|
||||
ParentMap.MapTransform.Transform(lineStart); // get lineStart.TransformedLatitude
|
||||
ParentMap.MapTransform.Transform(lineEnd); // get lineEnd.TransformedLatitude
|
||||
|
||||
graticuleStart = lineStart;
|
||||
graticuleEnd = lineEnd;
|
||||
|
||||
|
|
@ -216,14 +213,14 @@ namespace MapControl
|
|||
{
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = ParentMap.MapTransform.Transform(new Location(lineStart.TransformedLatitude, lineStart.Latitude, lon)),
|
||||
StartPoint = ParentMap.MapTransform.Transform(new Location(lineStart.Latitude, lon)),
|
||||
IsClosed = false,
|
||||
IsFilled = false
|
||||
};
|
||||
|
||||
figure.Segments.Add(new LineSegment
|
||||
{
|
||||
Point = ParentMap.MapTransform.Transform(new Location(lineEnd.TransformedLatitude, lineEnd.Latitude, lon)),
|
||||
Point = ParentMap.MapTransform.Transform(new Location(lineEnd.Latitude, lon)),
|
||||
});
|
||||
|
||||
geometry.Figures.Add(figure);
|
||||
|
|
|
|||
|
|
@ -12,28 +12,14 @@ namespace MapControl
|
|||
{
|
||||
public partial class MapGraticule : MapOverlay
|
||||
{
|
||||
private class LonLabel
|
||||
private class Label
|
||||
{
|
||||
public readonly double Longitude;
|
||||
public readonly double Position;
|
||||
public readonly string Text;
|
||||
|
||||
public LonLabel(double longitude, string text)
|
||||
public Label(double position, string text)
|
||||
{
|
||||
Longitude = longitude;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private class LatLabel
|
||||
{
|
||||
public readonly double TransformedLatitude;
|
||||
public readonly double Latitude;
|
||||
public readonly string Text;
|
||||
|
||||
public LatLabel(double transformedLatitude, double latitude, string text)
|
||||
{
|
||||
TransformedLatitude = transformedLatitude;
|
||||
Latitude = latitude;
|
||||
Position = position;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
|
@ -59,10 +45,8 @@ namespace MapControl
|
|||
if (ParentMap != null)
|
||||
{
|
||||
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(ParentMap.RenderSize));
|
||||
var startPoint = new Point(bounds.X, bounds.Y);
|
||||
var endPoint = new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height);
|
||||
var startLocation = ParentMap.MapTransform.Transform(startPoint);
|
||||
var endLocation = ParentMap.MapTransform.Transform(endPoint);
|
||||
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
|
||||
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
|
||||
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * TileSource.TileSize);
|
||||
var spacing = LineSpacings[LineSpacings.Length - 1];
|
||||
|
||||
|
|
@ -73,31 +57,28 @@ namespace MapControl
|
|||
|
||||
var labelFormat = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
var labelStart = new Location(
|
||||
Math.Ceiling(startLocation.Latitude / spacing) * spacing,
|
||||
Math.Ceiling(startLocation.Longitude / spacing) * spacing);
|
||||
Math.Ceiling(start.Latitude / spacing) * spacing,
|
||||
Math.Ceiling(start.Longitude / spacing) * spacing);
|
||||
|
||||
var latLabels = new List<LatLabel>((int)((endLocation.Latitude - labelStart.Latitude) / spacing) + 1);
|
||||
var lonLabels = new List<LonLabel>((int)((endLocation.Longitude - labelStart.Longitude) / spacing) + 1);
|
||||
var latLabels = new List<Label>((int)((end.Latitude - labelStart.Latitude) / spacing) + 1);
|
||||
var lonLabels = new List<Label>((int)((end.Longitude - labelStart.Longitude) / spacing) + 1);
|
||||
|
||||
for (var lat = labelStart.Latitude; lat <= endLocation.Latitude; lat += spacing)
|
||||
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
|
||||
{
|
||||
var location = new Location(lat, startLocation.Longitude);
|
||||
var p1 = ParentMap.LocationToViewportPoint(location);
|
||||
location.Longitude = endLocation.Longitude;
|
||||
var p2 = ParentMap.LocationToViewportPoint(location);
|
||||
|
||||
latLabels.Add(new LatLabel(location.TransformedLatitude, lat, CoordinateString(lat, labelFormat, "NS")));
|
||||
|
||||
drawingContext.DrawLine(Pen, p1, p2);
|
||||
}
|
||||
|
||||
for (var lon = labelStart.Longitude; lon <= endLocation.Longitude; lon += spacing)
|
||||
{
|
||||
lonLabels.Add(new LonLabel(lon, CoordinateString(Location.NormalizeLongitude(lon), labelFormat, "EW")));
|
||||
latLabels.Add(new Label(lat, CoordinateString(lat, labelFormat, "NS")));
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
ParentMap.LocationToViewportPoint(new Location(startPoint.Y, startLocation.Latitude, lon)),
|
||||
ParentMap.LocationToViewportPoint(new Location(endPoint.Y, endLocation.Latitude, lon)));
|
||||
ParentMap.LocationToViewportPoint(new Location(lat, start.Longitude)),
|
||||
ParentMap.LocationToViewportPoint(new Location(lat, end.Longitude)));
|
||||
}
|
||||
|
||||
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
{
|
||||
lonLabels.Add(new Label(lon, CoordinateString(Location.NormalizeLongitude(lon), labelFormat, "EW")));
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
ParentMap.LocationToViewportPoint(new Location(start.Latitude, lon)),
|
||||
ParentMap.LocationToViewportPoint(new Location(end.Latitude, lon)));
|
||||
}
|
||||
|
||||
if (Foreground != null && Foreground != Brushes.Transparent && latLabels.Count > 0 && lonLabels.Count > 0)
|
||||
|
|
@ -126,7 +107,7 @@ namespace MapControl
|
|||
glyphRuns.Add(lonLabel.Text, lonGlyphRun);
|
||||
}
|
||||
|
||||
var position = ParentMap.LocationToViewportPoint(new Location(latLabel.TransformedLatitude, latLabel.Latitude, lonLabel.Longitude));
|
||||
var position = ParentMap.LocationToViewportPoint(new Location(latLabel.Position, lonLabel.Position));
|
||||
|
||||
drawingContext.PushTransform(new MatrixTransform(
|
||||
transform.M11, transform.M12, transform.M21, transform.M22, position.X, position.Y));
|
||||
|
|
|
|||
|
|
@ -151,21 +151,8 @@ namespace MapControl
|
|||
|
||||
if (parentMap != null && location != null)
|
||||
{
|
||||
// transform location before checking longitude to keep location.TransformedLatitude
|
||||
var mapPosition = parentMap.MapTransform.Transform(location);
|
||||
mapPosition.X = Location.NormalizeLongitude(mapPosition.X);
|
||||
|
||||
var centerOffset = mapPosition.X - parentMap.Center.Longitude; // keep viewport position near map center
|
||||
|
||||
if (centerOffset > 180d)
|
||||
{
|
||||
mapPosition.X -= 360d;
|
||||
}
|
||||
else if (centerOffset < -180d)
|
||||
{
|
||||
mapPosition.X += 360d;
|
||||
}
|
||||
|
||||
// keep viewport position near map center
|
||||
var mapPosition = parentMap.MapTransform.Transform(location, parentMap.Center.Longitude);
|
||||
viewportPosition = parentMap.ViewportTransform.Transform(mapPosition);
|
||||
element.SetValue(ViewportPositionProperty, viewportPosition);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public partial class MapRectangle : MapPath
|
||||
{
|
||||
private const double geometryScale = 1e6;
|
||||
private const double GeometryScale = 1e6;
|
||||
|
||||
private static readonly ScaleTransform geometryScaleTransform = new ScaleTransform
|
||||
{
|
||||
ScaleX = 1d / geometryScale,
|
||||
ScaleY = 1d / geometryScale
|
||||
ScaleX = 1d / GeometryScale,
|
||||
ScaleY = 1d / GeometryScale
|
||||
};
|
||||
|
||||
public static readonly DependencyProperty SouthProperty = DependencyProperty.Register(
|
||||
|
|
@ -87,8 +87,8 @@ namespace MapControl
|
|||
// Create a scaled RectangleGeometry due to inaccurate hit testing in WPF.
|
||||
// See http://stackoverflow.com/a/19335624/1136211
|
||||
|
||||
geometry.Rect = new Rect(p1.X * geometryScale, p1.Y * geometryScale,
|
||||
(p2.X - p1.X) * geometryScale, (p2.Y - p1.Y) * geometryScale);
|
||||
geometry.Rect = new Rect(p1.X * GeometryScale, p1.Y * GeometryScale,
|
||||
(p2.X - p1.X) * GeometryScale, (p2.Y - p1.Y) * GeometryScale);
|
||||
|
||||
var transform = new TransformGroup();
|
||||
transform.Children.Add(geometryScaleTransform); // revert scaling
|
||||
|
|
|
|||
|
|
@ -39,5 +39,27 @@ namespace MapControl
|
|||
/// Transforms a cartesian coordinate point to a geographic location.
|
||||
/// </summary>
|
||||
public abstract Location Transform(Point point);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a geographic location to a cartesian coordinate point
|
||||
/// with minumum distance to the specified reference longitude value.
|
||||
/// </summary>
|
||||
public Point Transform(Location location, double referenceLongitude)
|
||||
{
|
||||
var p = Transform(location);
|
||||
|
||||
p.X = Location.NormalizeLongitude(p.X);
|
||||
|
||||
if (p.X > referenceLongitude + 180d)
|
||||
{
|
||||
p.X -= 360d;
|
||||
}
|
||||
else if (p.X < referenceLongitude - 180d)
|
||||
{
|
||||
p.X += 360d;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,29 +41,30 @@ namespace MapControl
|
|||
|
||||
public override Point Transform(Location location)
|
||||
{
|
||||
if (double.IsNaN(location.TransformedLatitude))
|
||||
double latitude;
|
||||
|
||||
if (location.Latitude <= -90d)
|
||||
{
|
||||
if (location.Latitude <= -90d)
|
||||
{
|
||||
location.TransformedLatitude = double.NegativeInfinity;
|
||||
}
|
||||
else if (location.Latitude >= 90d)
|
||||
{
|
||||
location.TransformedLatitude = double.PositiveInfinity;
|
||||
}
|
||||
else
|
||||
{
|
||||
var lat = location.Latitude * Math.PI / 180d;
|
||||
location.TransformedLatitude = Math.Log(Math.Tan(lat) + 1d / Math.Cos(lat)) / Math.PI * 180d;
|
||||
}
|
||||
latitude = double.NegativeInfinity;
|
||||
}
|
||||
else if (location.Latitude >= 90d)
|
||||
{
|
||||
latitude = double.PositiveInfinity;
|
||||
}
|
||||
else
|
||||
{
|
||||
latitude = location.Latitude * Math.PI / 180d;
|
||||
latitude = Math.Log(Math.Tan(latitude) + 1d / Math.Cos(latitude)) / Math.PI * 180d;
|
||||
}
|
||||
|
||||
return new Point(location.Longitude, location.TransformedLatitude);
|
||||
return new Point(location.Longitude, latitude);
|
||||
}
|
||||
|
||||
public override Location Transform(Point point)
|
||||
{
|
||||
return new Location(point.Y, Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d, point.X);
|
||||
var latitude = Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d;
|
||||
|
||||
return new Location(latitude, point.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ using System.Windows;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -94,11 +94,11 @@ namespace MapControl
|
|||
{
|
||||
if (!imageTileSource.CanLoadAsync) // call LoadImage in UI thread
|
||||
{
|
||||
var setImageAction = new Action<Tile, ImageTileSource>((t, ts) => t.SetImageSource(LoadImage(ts, t), animateOpacity));
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
dispatcher.BeginInvoke(
|
||||
(Action<Tile, ImageTileSource>)((t, ts) => t.SetImageSource(LoadImage(ts, t), animateOpacity)),
|
||||
DispatcherPriority.Background, tile, imageTileSource);
|
||||
dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, imageTileSource);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -110,44 +110,48 @@ namespace MapControl
|
|||
{
|
||||
// no caching here: use default asynchronous downloading and caching done by WPF
|
||||
|
||||
var setImageAction = new Action<Tile, TileSource>((t, ts) => t.SetImageSource(CreateImage(ts, t), animateOpacity));
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
dispatcher.BeginInvoke(
|
||||
(Action<Tile, TileSource>)((t, ts) => t.SetImageSource(CreateImage(ts, t), animateOpacity)),
|
||||
DispatcherPriority.Background, tile, tileSource);
|
||||
dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, tileSource);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var outdatedTiles = new List<Tile>(tiles.Count);
|
||||
|
||||
foreach (var tile in tiles)
|
||||
else
|
||||
{
|
||||
var key = GetCacheKey(sourceName, tile);
|
||||
var buffer = Cache.Get(key) as byte[];
|
||||
var image = CreateImage(buffer);
|
||||
var setImageAction = new Action<Tile, ImageSource>((t, i) => t.SetImageSource(i, animateOpacity));
|
||||
var outdatedTiles = new List<Tile>(tiles.Count);
|
||||
|
||||
if (image != null)
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
dispatcher.BeginInvoke(
|
||||
(Action<Tile, ImageSource>)((t, i) => t.SetImageSource(i, animateOpacity)),
|
||||
DispatcherPriority.Background, tile, image);
|
||||
var key = GetCacheKey(sourceName, tile);
|
||||
var buffer = Cache.Get(key) as byte[];
|
||||
var image = CreateImage(buffer);
|
||||
|
||||
long creationTime = BitConverter.ToInt64(buffer, 0);
|
||||
|
||||
if (DateTime.FromBinary(creationTime) + CacheUpdateAge < DateTime.UtcNow)
|
||||
if (image != null)
|
||||
{
|
||||
outdatedTiles.Add(tile); // update outdated cache
|
||||
var creationTime = BitConverter.ToInt64(buffer, 0);
|
||||
|
||||
if (DateTime.FromBinary(creationTime) + CacheUpdateAge < DateTime.UtcNow)
|
||||
{
|
||||
dispatcher.Invoke(setImageAction, DispatcherPriority.Render, tile, image); // synchronously before enqueuing
|
||||
outdatedTiles.Add(tile); // update outdated cache
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, image);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingTiles.Enqueue(tile); // not yet cached
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingTiles.Enqueue(tile); // not yet cached
|
||||
}
|
||||
}
|
||||
|
||||
tiles = outdatedTiles; // enqueue outdated tiles at last
|
||||
tiles = outdatedTiles; // enqueue outdated tiles at last
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var tile in tiles)
|
||||
|
|
@ -165,6 +169,7 @@ namespace MapControl
|
|||
|
||||
private void LoadPendingTiles(Dispatcher dispatcher, TileSource tileSource, string sourceName, bool animateOpacity)
|
||||
{
|
||||
var setImageAction = new Action<Tile, ImageSource>((t, i) => t.SetImageSource(i, animateOpacity));
|
||||
var imageTileSource = tileSource as ImageTileSource;
|
||||
Tile tile;
|
||||
|
||||
|
|
@ -197,9 +202,7 @@ namespace MapControl
|
|||
|
||||
if (image != null || !tile.HasImageSource) // do not set null if tile already has an image (from cache)
|
||||
{
|
||||
dispatcher.BeginInvoke(
|
||||
(Action<Tile, ImageSource>)((t, i) => t.SetImageSource(i, animateOpacity)),
|
||||
DispatcherPriority.Background, tile, image);
|
||||
dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, image);
|
||||
}
|
||||
|
||||
if (buffer != null && image != null)
|
||||
|
|
@ -308,7 +311,7 @@ namespace MapControl
|
|||
|
||||
using (var memoryStream = length > 0 ? new MemoryStream(length + sizeof(long)) : new MemoryStream())
|
||||
{
|
||||
long creationTime = DateTime.UtcNow.ToBinary();
|
||||
var creationTime = DateTime.UtcNow.ToBinary();
|
||||
|
||||
memoryStream.Write(BitConverter.GetBytes(creationTime), 0, sizeof(long));
|
||||
responseStream.CopyTo(memoryStream);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyVersion("1.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
<Compile Include="..\Common\ViewModel.cs">
|
||||
<Link>ViewModel.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="ImageTileSource.cs" />
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
|||
Loading…
Reference in a new issue