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; 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 West { get; set; }
public double East { get; set; } public double East { get; set; }

View file

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

View file

@ -171,11 +171,11 @@ namespace MapControl
base.OnViewportChanged(e); base.OnViewportChanged(e);
await UpdateImageAsync(); await UpdateImageAsync(); // update immediately
} }
else else
{ {
AdjustBoundingBox(e.LongitudeOffset); ValidateBoundingBox();
base.OnViewportChanged(e); base.OnViewportChanged(e);
@ -233,21 +233,30 @@ namespace MapControl
BoundingBox = ParentMap.ViewRectToBoundingBox(rect); 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); if (Math.Abs(offset) > 180d)
{
offset = 360d * Math.Sign(offset);
BoundingBox = new BoundingBox(
BoundingBox.South, BoundingBox.West + offset,
BoundingBox.North, BoundingBox.East + offset);
foreach (var image in Children.OfType<Image>()) foreach (var image in Children.OfType<Image>())
{ {
var imageBoundingBox = GetBoundingBox(image); var imageBbox = GetBoundingBox(image);
if (imageBoundingBox != null) if (imageBbox != null)
{ {
SetBoundingBox(image, new BoundingBox(imageBoundingBox, offset)); 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) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
#if WINUI #if WINUI
using Windows.Foundation; using Windows.Foundation;
@ -125,11 +126,11 @@ namespace MapControl
protected override Task UpdateTileLayer() protected override Task UpdateTileLayer()
{ {
var update = false; var updateTiles = false;
if (ParentMap == null || ParentMap.MapProjection.Type != MapProjectionType.WebMercator) if (ParentMap == null || ParentMap.MapProjection.Type != MapProjectionType.WebMercator)
{ {
update = TileMatrix != null; updateTiles = TileMatrix != null;
TileMatrix = null; TileMatrix = null;
} }
else else
@ -137,27 +138,23 @@ namespace MapControl
if (TileSource != TileImageLoader.TileSource) if (TileSource != TileImageLoader.TileSource)
{ {
Tiles = new TileCollection(); // clear all Tiles = new TileCollection(); // clear all
update = true; updateTiles = true;
} }
if (SetTileMatrix()) if (SetTileMatrix())
{ {
updateTiles = true;
}
SetRenderTransform(); SetRenderTransform();
update = true;
}
} }
if (update) return updateTiles ? UpdateTiles() : Task.CompletedTask;
{
UpdateTiles();
return TileImageLoader.LoadTiles(Tiles, TileSource, SourceName);
}
return Task.CompletedTask;
} }
protected override void SetRenderTransform() protected override void SetRenderTransform()
{
if (TileMatrix != null)
{ {
// tile matrix origin in pixels // tile matrix origin in pixels
// //
@ -168,6 +165,7 @@ namespace MapControl
((MatrixTransform)RenderTransform).Matrix = ((MatrixTransform)RenderTransform).Matrix =
ParentMap.ViewTransform.GetTileLayerTransform(tileMatrixScale, MapTopLeft, tileMatrixOrigin); ParentMap.ViewTransform.GetTileLayerTransform(tileMatrixScale, MapTopLeft, tileMatrixOrigin);
} }
}
private bool SetTileMatrix() private bool SetTileMatrix()
{ {
@ -199,7 +197,7 @@ namespace MapControl
return true; return true;
} }
private void UpdateTiles() private Task UpdateTiles()
{ {
var tiles = new TileCollection(); var tiles = new TileCollection();
@ -241,6 +239,8 @@ namespace MapControl
{ {
Children.Add(tile.Image); 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) 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 else
{ {

View file

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

View file

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