Fixed moving transform center across dateline.

This commit is contained in:
ClemensFischer 2022-11-24 23:24:51 +01:00
parent 7fbbf66acb
commit afc93704d9
7 changed files with 63 additions and 55 deletions

View file

@ -30,12 +30,6 @@ namespace MapControl
East = east;
}
public BoundingBox(BoundingBox boundingBox, double longitudeOffset)
: this(boundingBox.South, boundingBox.West + longitudeOffset,
boundingBox.North, boundingBox.East + longitudeOffset)
{
}
public double West { get; set; }
public double East { get; set; }

View file

@ -272,7 +272,8 @@ namespace MapControl
/// <summary>
/// Sets a temporary center point in view coordinates for scaling and rotation transformations.
/// This center point is automatically reset when the Center property is set by application code.
/// This center point is automatically reset when the Center property is set by application code
/// or by the methods TranslateMap, TransformMap, ZoomMap and ZoomToBounds.
/// </summary>
public void SetTransformCenter(Point center)
{
@ -728,6 +729,7 @@ namespace MapControl
private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false)
{
var transformCenterChanged = false;
var viewScale = ViewTransform.ZoomLevelToScale(ZoomLevel);
var projection = MapProjection;
@ -762,6 +764,9 @@ namespace MapControl
if (resetTransformCenter)
{
// check if transform center moved across the dateline
transformCenterChanged = Math.Abs(center.Longitude - transformCenter.Longitude) > 180d;
ResetTransformCenter();
projection.Center = ProjectionCenter ?? Center;
@ -778,9 +783,11 @@ namespace MapControl
SetViewScale(ViewTransform.Scale);
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
// check if view center moved across the dateline
transformCenterChanged = transformCenterChanged || Math.Abs(Center.Longitude - centerLongitude) > 180d;
centerLongitude = Center.Longitude;
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, transformCenterChanged));
}
}

View file

@ -171,11 +171,11 @@ namespace MapControl
base.OnViewportChanged(e);
await UpdateImageAsync();
await UpdateImageAsync(); // update immediately
}
else
{
AdjustBoundingBox(e.LongitudeOffset);
ValidateBoundingBox();
base.OnViewportChanged(e);
@ -233,21 +233,30 @@ namespace MapControl
BoundingBox = ParentMap.ViewRectToBoundingBox(rect);
}
private void AdjustBoundingBox(double longitudeOffset)
private void ValidateBoundingBox()
{
if (Math.Abs(longitudeOffset) > 180d && BoundingBox != null)
if (BoundingBox != null)
{
var offset = 360d * Math.Sign(longitudeOffset);
var offset = ParentMap.Center.Longitude - BoundingBox.Center.Longitude;
BoundingBox = new BoundingBox(BoundingBox, offset);
foreach (var image in Children.OfType<Image>())
if (Math.Abs(offset) > 180d)
{
var imageBoundingBox = GetBoundingBox(image);
offset = 360d * Math.Sign(offset);
if (imageBoundingBox != null)
BoundingBox = new BoundingBox(
BoundingBox.South, BoundingBox.West + offset,
BoundingBox.North, BoundingBox.East + offset);
foreach (var image in Children.OfType<Image>())
{
SetBoundingBox(image, new BoundingBox(imageBoundingBox, offset));
var imageBbox = GetBoundingBox(image);
if (imageBbox != null)
{
SetBoundingBox(image, new BoundingBox(
imageBbox.South, imageBbox.West + offset,
imageBbox.North, imageBbox.East + offset));
}
}
}
}

View file

@ -3,6 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Linq;
using System.Threading.Tasks;
#if WINUI
using Windows.Foundation;
@ -125,11 +126,11 @@ namespace MapControl
protected override Task UpdateTileLayer()
{
var update = false;
var updateTiles = false;
if (ParentMap == null || ParentMap.MapProjection.Type != MapProjectionType.WebMercator)
{
update = TileMatrix != null;
updateTiles = TileMatrix != null;
TileMatrix = null;
}
else
@ -137,36 +138,33 @@ namespace MapControl
if (TileSource != TileImageLoader.TileSource)
{
Tiles = new TileCollection(); // clear all
update = true;
updateTiles = true;
}
if (SetTileMatrix())
{
SetRenderTransform();
update = true;
updateTiles = true;
}
SetRenderTransform();
}
if (update)
{
UpdateTiles();
return TileImageLoader.LoadTiles(Tiles, TileSource, SourceName);
}
return Task.CompletedTask;
return updateTiles ? UpdateTiles() : Task.CompletedTask;
}
protected override void SetRenderTransform()
{
// tile matrix origin in pixels
//
var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin);
if (TileMatrix != null)
{
// tile matrix origin in pixels
//
var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin);
var tileMatrixScale = ViewTransform.ZoomLevelToScale(TileMatrix.ZoomLevel);
var tileMatrixScale = ViewTransform.ZoomLevelToScale(TileMatrix.ZoomLevel);
((MatrixTransform)RenderTransform).Matrix =
ParentMap.ViewTransform.GetTileLayerTransform(tileMatrixScale, MapTopLeft, tileMatrixOrigin);
((MatrixTransform)RenderTransform).Matrix =
ParentMap.ViewTransform.GetTileLayerTransform(tileMatrixScale, MapTopLeft, tileMatrixOrigin);
}
}
private bool SetTileMatrix()
@ -199,7 +197,7 @@ namespace MapControl
return true;
}
private void UpdateTiles()
private Task UpdateTiles()
{
var tiles = new TileCollection();
@ -241,6 +239,8 @@ namespace MapControl
{
Children.Add(tile.Image);
}
return TileImageLoader.LoadTiles(tiles, TileSource, SourceName);
}
}
}

View file

@ -201,9 +201,9 @@ namespace MapControl
private async void OnViewportChanged(object sender, ViewportChangedEventArgs e)
{
if (Children.Count == 0 || e.ProjectionChanged || Math.Abs(e.LongitudeOffset) > 180d)
if (Children.Count == 0 || e.ProjectionChanged || e.TransformCenterChanged)
{
await Update(); // update immediately when projection has changed or center has moved across 180° longitude
await Update(); // update immediately
}
else
{

View file

@ -8,22 +8,23 @@ namespace MapControl
{
public class ViewportChangedEventArgs : EventArgs
{
public ViewportChangedEventArgs(bool projectionChanged = false, double longitudeOffset = 0d)
public ViewportChangedEventArgs(bool projectionChanged = false, bool transformCenterChanged = false)
{
ProjectionChanged = projectionChanged;
LongitudeOffset = longitudeOffset;
TransformCenterChanged = transformCenterChanged;
}
/// <summary>
/// Indicates if the map projection has changed. Used to control when a MapTileLayer or MapImageLayer
/// should be updated immediately, or MapPath Data in projected map coordinates should be recalculated.
/// Indicates that the map projection has changed. Used to control when
/// a MapTileLayer or a MapImageLayer should be updated immediately,
/// or MapPath Data in projected map coordinates should be recalculated.
/// </summary>
public bool ProjectionChanged { get; }
/// <summary>
/// Offset of the map center longitude value from the previous viewport.
/// Used to detect if the map center has moved across 180° longitude.
/// Indicates that the view transform center has moved across the dateline.
/// Used to control when a MapTileLayer should be updated immediately.
/// </summary>
public double LongitudeOffset { get; }
public bool TransformCenterChanged { get; }
}
}

View file

@ -94,14 +94,11 @@ namespace MapControl
return UpdateTiles(null);
}
if (UpdateChildLayers(tileMatrixSet))
{
SetRenderTransform();
var updateTiles = UpdateChildLayers(tileMatrixSet);
return UpdateTiles(tileMatrixSet);
}
SetRenderTransform();
return Task.CompletedTask;
return updateTiles ? UpdateTiles(tileMatrixSet) : Task.CompletedTask;
}
protected override void SetRenderTransform()