mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-05 14:37:01 +00:00
Version 1.9.0:
- added MapBase.ZoomToBounds method - fixed coercing property values in MapBase - improved Location property handling in MapPanel to keep viewport positions near map center - use common view model in sample applications
This commit is contained in:
parent
9f4ab0f3e3
commit
5eafa751f8
37 changed files with 391 additions and 571 deletions
|
|
@ -405,6 +405,27 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the TargetZoomLevel and TargetCenter properties such that the specified bounding box
|
||||
/// fits into the current viewport. The TargetHeading property is set to zero.
|
||||
/// </summary>
|
||||
public void ZoomToBounds(Location southWest, Location northEast)
|
||||
{
|
||||
if (southWest.Latitude < northEast.Latitude && southWest.Longitude < northEast.Longitude)
|
||||
{
|
||||
var p1 = MapTransform.Transform(southWest);
|
||||
var p2 = MapTransform.Transform(northEast);
|
||||
var lonScale = ActualWidth / (p2.X - p1.X) * 360d / TileSource.TileSize;
|
||||
var latScale = ActualHeight / (p2.Y - p1.Y) * 360d / TileSource.TileSize;
|
||||
var lonZoom = Math.Log(lonScale, 2d);
|
||||
var latZoom = Math.Log(latScale, 2d);
|
||||
|
||||
TargetZoomLevel = Math.Min(lonZoom, latZoom);
|
||||
TargetCenter = MapTransform.Transform(new Point((p1.X + p2.X) / 2d, (p1.Y + p2.Y) / 2d));
|
||||
TargetHeading = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
base.OnViewportChanged();
|
||||
|
|
@ -551,8 +572,14 @@ namespace MapControl
|
|||
internalPropertyChange = false;
|
||||
}
|
||||
|
||||
private bool CoerceLocation(Location location, double latitudeEpsilon = 0d)
|
||||
private bool CoerceLocation(ref Location location, double latitudeEpsilon = 0d)
|
||||
{
|
||||
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);
|
||||
|
|
@ -567,9 +594,9 @@ namespace MapControl
|
|||
return false;
|
||||
}
|
||||
|
||||
private void CoerceCenterProperty(DependencyProperty property, Location center)
|
||||
private void CoerceCenterProperty(DependencyProperty property, ref Location center)
|
||||
{
|
||||
if (CoerceLocation(center))
|
||||
if (CoerceLocation(ref center))
|
||||
{
|
||||
InternalSetValue(property, center);
|
||||
}
|
||||
|
|
@ -579,7 +606,7 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceCenterProperty(CenterProperty, center);
|
||||
CoerceCenterProperty(CenterProperty, ref center);
|
||||
ResetTransformOrigin();
|
||||
UpdateTransform();
|
||||
|
||||
|
|
@ -595,9 +622,9 @@ namespace MapControl
|
|||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceCenterProperty(TargetCenterProperty, targetCenter);
|
||||
CoerceCenterProperty(TargetCenterProperty, ref targetCenter);
|
||||
|
||||
if (!targetCenter.Equals(Center))
|
||||
if (targetCenter.Latitude != Center.Latitude || targetCenter.Longitude != Center.Longitude)
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
|
|
@ -652,9 +679,11 @@ namespace MapControl
|
|||
|
||||
if (coercedValue != minZoomLevel)
|
||||
{
|
||||
InternalSetValue(MinZoomLevelProperty, coercedValue);
|
||||
minZoomLevel = coercedValue;
|
||||
InternalSetValue(MinZoomLevelProperty, minZoomLevel);
|
||||
}
|
||||
else if (ZoomLevel < minZoomLevel)
|
||||
|
||||
if (ZoomLevel < minZoomLevel)
|
||||
{
|
||||
ZoomLevel = minZoomLevel;
|
||||
}
|
||||
|
|
@ -666,32 +695,32 @@ namespace MapControl
|
|||
|
||||
if (coercedValue != maxZoomLevel)
|
||||
{
|
||||
InternalSetValue(MaxZoomLevelProperty, coercedValue);
|
||||
maxZoomLevel = coercedValue;
|
||||
InternalSetValue(MaxZoomLevelProperty, maxZoomLevel);
|
||||
}
|
||||
else if (ZoomLevel > maxZoomLevel)
|
||||
|
||||
if (ZoomLevel > maxZoomLevel)
|
||||
{
|
||||
ZoomLevel = maxZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CoerceZoomLevelProperty(DependencyProperty property, ref double zoomLevel)
|
||||
private void CoerceZoomLevelProperty(DependencyProperty property, ref double zoomLevel)
|
||||
{
|
||||
var coercedValue = Math.Min(Math.Max(zoomLevel, MinZoomLevel), MaxZoomLevel);
|
||||
|
||||
if (coercedValue != zoomLevel)
|
||||
{
|
||||
InternalSetValue(property, coercedValue);
|
||||
return true;
|
||||
zoomLevel = coercedValue;
|
||||
InternalSetValue(property, zoomLevel);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ZoomLevelPropertyChanged(double zoomLevel)
|
||||
{
|
||||
if (!internalPropertyChange &&
|
||||
!CoerceZoomLevelProperty(ZoomLevelProperty, ref zoomLevel))
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
CoerceZoomLevelProperty(ZoomLevelProperty, ref zoomLevel);
|
||||
UpdateTransform();
|
||||
|
||||
if (zoomLevelAnimation == null)
|
||||
|
|
@ -703,25 +732,28 @@ namespace MapControl
|
|||
|
||||
private void TargetZoomLevelPropertyChanged(double targetZoomLevel)
|
||||
{
|
||||
if (!internalPropertyChange &&
|
||||
!CoerceZoomLevelProperty(TargetZoomLevelProperty, ref targetZoomLevel) &&
|
||||
targetZoomLevel != ZoomLevel)
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
CoerceZoomLevelProperty(TargetZoomLevelProperty, ref targetZoomLevel);
|
||||
|
||||
if (targetZoomLevel != ZoomLevel)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
}
|
||||
|
||||
zoomLevelAnimation = new DoubleAnimation
|
||||
{
|
||||
To = targetZoomLevel,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
FillBehavior = FillBehavior.HoldEnd
|
||||
};
|
||||
|
||||
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
|
||||
this.BeginAnimation(ZoomLevelProperty, zoomLevelAnimation);
|
||||
}
|
||||
|
||||
zoomLevelAnimation = new DoubleAnimation
|
||||
{
|
||||
To = targetZoomLevel,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
FillBehavior = FillBehavior.HoldEnd
|
||||
};
|
||||
|
||||
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
|
||||
this.BeginAnimation(ZoomLevelProperty, zoomLevelAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -742,12 +774,12 @@ namespace MapControl
|
|||
|
||||
private void CoerceHeadingProperty(DependencyProperty property, ref double heading)
|
||||
{
|
||||
var coercedValue = (heading >= -180d && heading <= 360d) ?
|
||||
heading : (((heading % 360d) + 360d) % 360d);
|
||||
var coercedValue = (heading >= -180d && heading <= 360d) ? heading : (((heading % 360d) + 360d) % 360d);
|
||||
|
||||
if (coercedValue != heading)
|
||||
{
|
||||
InternalSetValue(property, coercedValue);
|
||||
heading = coercedValue;
|
||||
InternalSetValue(property, heading);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -826,7 +858,7 @@ namespace MapControl
|
|||
{
|
||||
center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
|
||||
var coerced = CoerceLocation(center, 1e-3);
|
||||
var coerced = CoerceLocation(ref center, 1e-3);
|
||||
|
||||
InternalSetValue(CenterProperty, center);
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,6 @@ namespace MapControl
|
|||
{
|
||||
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
{
|
||||
var location = new Location(lat, lon);
|
||||
TextBlock label;
|
||||
|
||||
if (childIndex < Children.Count)
|
||||
|
|
@ -273,13 +272,17 @@ namespace MapControl
|
|||
{
|
||||
transformGroup.Children.Add(new TranslateTransform());
|
||||
transformGroup.Children.Add(ParentMap.RotateTransform);
|
||||
transformGroup.Children.Add(new TranslateTransform());
|
||||
}
|
||||
|
||||
var translateTransform = (TranslateTransform)transformGroup.Children[0];
|
||||
translateTransform.X = StrokeThickness / 2d + 2d;
|
||||
translateTransform.Y = -label.DesiredSize.Height / 2d;
|
||||
|
||||
MapPanel.SetLocation(label, location);
|
||||
var viewportPosition = ParentMap.LocationToViewportPoint(new Location(lat, lon));
|
||||
translateTransform = (TranslateTransform)transformGroup.Children[2];
|
||||
translateTransform.X = viewportPosition.X;
|
||||
translateTransform.Y = viewportPosition.Y;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,6 +151,23 @@ namespace MapControl
|
|||
|
||||
if (parentMap != null && location != null)
|
||||
{
|
||||
var longitude = Location.NormalizeLongitude(location.Longitude);
|
||||
var centerDistance = longitude - parentMap.Center.Longitude;
|
||||
|
||||
if (centerDistance > 180d)
|
||||
{
|
||||
longitude -= 360d;
|
||||
}
|
||||
else if (centerDistance < -180d)
|
||||
{
|
||||
longitude += 360d;
|
||||
}
|
||||
|
||||
if (location.Longitude != longitude) // keep viewport position near map center
|
||||
{
|
||||
location = new Location(location.Latitude, longitude);
|
||||
}
|
||||
|
||||
viewportPosition = parentMap.LocationToViewportPoint(location);
|
||||
element.SetValue(ViewportPositionProperty, viewportPosition);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ using System.Windows;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.8.0")]
|
||||
[assembly: AssemblyFileVersion("1.8.0")]
|
||||
[assembly: AssemblyVersion("1.9.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ namespace MapControl
|
|||
{
|
||||
internal partial class TileContainer : Panel
|
||||
{
|
||||
private Matrix GetViewportTransformMatrix(Matrix transform)
|
||||
private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY)
|
||||
{
|
||||
var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY);
|
||||
|
||||
return transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ namespace MapControl
|
|||
{
|
||||
internal partial class TileContainer : ContainerVisual
|
||||
{
|
||||
private Matrix GetViewportTransformMatrix(Matrix transform)
|
||||
private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY)
|
||||
{
|
||||
var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY);
|
||||
|
||||
transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
|
||||
|
||||
return transform;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ namespace MapControl
|
|||
tileLayerOffset.X = transformOffsetX - 180d * scale;
|
||||
tileLayerOffset.Y = transformOffsetY - 180d * scale;
|
||||
|
||||
ViewportTransform.Matrix = GetViewportTransformMatrix(new Matrix(scale, 0d, 0d, -scale, transformOffsetX, transformOffsetY));
|
||||
ViewportTransform.Matrix = GetViewportTransformMatrix(scale, transformOffsetX, transformOffsetY);
|
||||
|
||||
if (Math.Sign(mapOrigin.X) != Math.Sign(oldMapOriginX) && Math.Abs(mapOrigin.X) > 90d)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ namespace MapControl
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (!tileSource.UriFormat.StartsWith("file:")) // always load local image files asynchronously
|
||||
else if (!tileSource.UriFormat.StartsWith("file:")) // load local image files asynchronously, without caching
|
||||
{
|
||||
if (Cache == null || string.IsNullOrWhiteSpace(sourceName))
|
||||
{
|
||||
|
|
@ -183,7 +183,7 @@ namespace MapControl
|
|||
|
||||
if (uri != null)
|
||||
{
|
||||
if (uri.Scheme == "file")
|
||||
if (uri.Scheme == "file") // create from FileStream as creating from URI leaves the file open
|
||||
{
|
||||
image = CreateImage(uri.AbsolutePath);
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ namespace MapControl
|
|||
{
|
||||
try
|
||||
{
|
||||
using (var stream = new FileStream(path, FileMode.Open))
|
||||
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
image = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace MapControl
|
|||
|
||||
public TileLayer()
|
||||
{
|
||||
MinZoomLevel = 1;
|
||||
MinZoomLevel = 0;
|
||||
MaxZoomLevel = 18;
|
||||
MaxParallelDownloads = 8;
|
||||
LoadLowerZoomLevels = true;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,11 @@ namespace MapControl
|
|||
|
||||
private Uri GetQuadKeyUri(int x, int y, int zoomLevel)
|
||||
{
|
||||
if (zoomLevel < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var key = new StringBuilder { Length = zoomLevel };
|
||||
|
||||
for (var z = zoomLevel - 1; z >= 0; z--, x /= 2, y /= 2)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.8.0")]
|
||||
[assembly: AssemblyFileVersion("1.8.0")]
|
||||
[assembly: AssemblyVersion("1.9.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue