diff --git a/MapControl/Avalonia/MapControl.Avalonia.csproj b/MapControl/Avalonia/MapControl.Avalonia.csproj index 3a5231b1..cc123a41 100644 --- a/MapControl/Avalonia/MapControl.Avalonia.csproj +++ b/MapControl/Avalonia/MapControl.Avalonia.csproj @@ -12,7 +12,6 @@ - diff --git a/MapControl/Avalonia/ViewTransform.Avalonia.cs b/MapControl/Avalonia/ViewTransform.Avalonia.cs index d49776d6..139002a2 100644 --- a/MapControl/Avalonia/ViewTransform.Avalonia.cs +++ b/MapControl/Avalonia/ViewTransform.Avalonia.cs @@ -2,47 +2,10 @@ // Copyright © 2024 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) -using System; - namespace MapControl { - /// - /// Defines the transformation between projected map coordinates in meters - /// and view coordinates in pixels. - /// - public class ViewTransform + public partial class ViewTransform { - public static double ZoomLevelToScale(double zoomLevel) - { - return 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MeterPerDegree); - } - - public static double ScaleToZoomLevel(double scale) - { - return Math.Log(scale * 360d * MapProjection.Wgs84MeterPerDegree / 256d, 2d); - } - - /// - /// Gets the scaling factor from projected map coordinates to view coordinates, - /// as pixels per meter. - /// - public double Scale { get; private set; } - - /// - /// Gets the rotation angle of the transform matrix. - /// - public double Rotation { get; private set; } - - /// - /// Gets the transform matrix from projected map coordinates to view coordinates. - /// - public Matrix MapToViewMatrix { get; private set; } - - /// - /// Gets the transform matrix from view coordinates to projected map coordinates. - /// - public Matrix ViewToMapMatrix { get; private set; } - /// /// Initializes a ViewTransform from a map center point in projected coordinates, /// a view conter point, a scaling factor from projected coordinates to view coordinates @@ -62,31 +25,6 @@ namespace MapControl ViewToMapMatrix = MapToViewMatrix.Invert(); } - /// - /// Transforms a Point from projected map coordinates to view coordinates. - /// - public Point MapToView(Point point) - { - return MapToViewMatrix.Transform(point); - } - - /// - /// Transforms a Point from view coordinates to projected map coordinates. - /// - public Point ViewToMap(Point point) - { - return ViewToMapMatrix.Transform(point); - } - - /// - /// Transform relative to absolute map scale. Returns horizontal and vertical - /// scaling factors from meters to view coordinates. - /// - public Point GetMapScale(Point relativeScale) - { - return new Point(Scale * relativeScale.X, Scale * relativeScale.Y); - } - /// /// Gets a transform Matrix from meters to view coordinates for a relative map scale. /// diff --git a/MapControl/Shared/BoundingBox.cs b/MapControl/Shared/BoundingBox.cs index bbc2c0fe..c62836d1 100644 --- a/MapControl/Shared/BoundingBox.cs +++ b/MapControl/Shared/BoundingBox.cs @@ -17,7 +17,7 @@ namespace MapControl #endif public class BoundingBox { - public BoundingBox() + protected BoundingBox() { } @@ -34,15 +34,27 @@ namespace MapControl { } - public double South { get; } - public double North { get; } - public double West { get; } - public double East { get; } + public double South { get; private set; } + public double North { get; private set; } + public double West { get; private set; } + public double East { get; private set; } public virtual double Width => East - West; public virtual double Height => North - South; - public virtual Location Center => new Location((South + North) / 2d, (West + East) / 2d); + public virtual Location Center + { + get => new Location((South + North) / 2d, (West + East) / 2d); + set + { + var latOffset = value.Latitude - (South + North) / 2d; + var lonOffset = value.Longitude - (West + East) / 2d; + South += latOffset; + North += latOffset; + West += lonOffset; + East += lonOffset; + } + } /// /// Creates a BoundingBox instance from a string containing a comma-separated sequence of four floating point numbers. diff --git a/MapControl/Shared/CenteredBoundingBox.cs b/MapControl/Shared/CenteredBoundingBox.cs index 33799812..b8c06761 100644 --- a/MapControl/Shared/CenteredBoundingBox.cs +++ b/MapControl/Shared/CenteredBoundingBox.cs @@ -8,19 +8,15 @@ namespace MapControl { public class CenteredBoundingBox : BoundingBox { - private readonly Location center; - private readonly double width; - private readonly double height; - - public CenteredBoundingBox(Location c, double w, double h) + public CenteredBoundingBox(Location center, double width, double height) { - center = c; - width = Math.Max(w, 0d); - height = Math.Max(h, 0d); + Center = center; + Width = Math.Max(width, 0d); + Height = Math.Max(height, 0d); } - public override Location Center => center; - public override double Width => width; - public override double Height => height; + public override Location Center { get; set; } + public override double Width { get; } + public override double Height { get; } } } diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs index 10d7f488..b511766e 100644 --- a/MapControl/Shared/MapBase.cs +++ b/MapControl/Shared/MapBase.cs @@ -31,6 +31,10 @@ namespace MapControl /// public partial class MapBase : MapPanel { + public static double ZoomLevelToScale(double zoomLevel) => 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MeterPerDegree); + + public static double ScaleToZoomLevel(double scale) => Math.Log(scale * 360d * MapProjection.Wgs84MeterPerDegree / 256d, 2d); + public static TimeSpan ImageFadeDuration { get; set; } = TimeSpan.FromSeconds(0.1); public static readonly DependencyProperty AnimationDurationProperty = @@ -361,7 +365,7 @@ namespace MapControl { var scale = Math.Min(ActualWidth / rect.Value.Width, ActualHeight / rect.Value.Height); - TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale); + TargetZoomLevel = ScaleToZoomLevel(scale); TargetCenter = targetCenter; TargetHeading = 0d; } @@ -497,7 +501,7 @@ namespace MapControl private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false) { var transformCenterChanged = false; - var viewScale = ViewTransform.ZoomLevelToScale(ZoomLevel); + var viewScale = ZoomLevelToScale(ZoomLevel); var projection = MapProjection; projection.Center = ProjectionCenter ?? Center; diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index b27a6543..92458317 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -189,66 +189,53 @@ namespace MapControl protected Point? GetViewPosition(Location location) { - var position = parentMap.LocationToView(location); - - if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical && - position.HasValue && - !InsideViewport(position.Value)) + if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical) { - position = parentMap.LocationToView( - new Location(location.Latitude, parentMap.CoerceLongitude(location.Longitude))); + var longitude = parentMap.CoerceLongitude(location.Longitude); + + if (longitude != location.Longitude) + { + location = new Location(location.Latitude, longitude); + } } - return position; + return parentMap.LocationToView(location); } protected ViewRect? GetViewRect(BoundingBox boundingBox) { - var mapRect = parentMap.MapProjection.BoundingBoxToMap(boundingBox); - - if (!mapRect.HasValue) + if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical) { - return null; + var center = boundingBox.Center; + var longitude = parentMap.CoerceLongitude(center.Longitude); + + if (longitude != center.Longitude) + { + boundingBox.Center = new Location(center.Latitude, longitude); + } } - return GetViewRect(mapRect.Value); + var mapRect = parentMap.MapProjection.BoundingBoxToMap(boundingBox); + + if (mapRect.HasValue) + { + return GetViewRect(mapRect.Value); + } + + return null; } protected ViewRect GetViewRect(Rect mapRect) { + var transform = parentMap.ViewTransform; var center = new Point(mapRect.X + mapRect.Width / 2d, mapRect.Y + mapRect.Height / 2d); - var position = parentMap.ViewTransform.MapToView(center); - var projection = parentMap.MapProjection; - - if (projection.Type <= MapProjectionType.NormalCylindrical && - !InsideViewport(position)) - { - var location = projection.MapToLocation(center); - - if (location != null) - { - var pos = parentMap.LocationToView( - new Location(location.Latitude, parentMap.CoerceLongitude(location.Longitude))); - - if (pos.HasValue) - { - position = pos.Value; - } - } - } - - var width = mapRect.Width * parentMap.ViewTransform.Scale; - var height = mapRect.Height * parentMap.ViewTransform.Scale; + var position = transform.MapToView(center); + var width = mapRect.Width * transform.Scale; + var height = mapRect.Height * transform.Scale; var x = position.X - width / 2d; var y = position.Y - height / 2d; - return new ViewRect(x, y, width, height, parentMap.ViewTransform.Rotation); - } - - private bool InsideViewport(Point point) - { - return point.X >= 0d && point.X <= parentMap.ActualWidth - && point.Y >= 0d && point.Y <= parentMap.ActualHeight; + return new ViewRect(x, y, width, height, transform.Rotation); } private void ArrangeChildElement(FrameworkElement element, Size panelSize) @@ -263,7 +250,10 @@ namespace MapControl if (GetAutoCollapse(element)) { - SetVisible(element, position.HasValue && InsideViewport(position.Value)); + SetVisible(element, + position.HasValue && + position.Value.X >= 0d && position.Value.X <= parentMap.ActualWidth && + position.Value.Y >= 0d && position.Value.Y <= parentMap.ActualHeight); } if (position.HasValue) diff --git a/MapControl/Shared/MapPath.cs b/MapControl/Shared/MapPath.cs index 2a92db89..b6d77f3b 100644 --- a/MapControl/Shared/MapPath.cs +++ b/MapControl/Shared/MapPath.cs @@ -4,13 +4,10 @@ #if WPF using System.Windows; -using System.Windows.Media; #elif UWP using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; #elif WINUI using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Media; #endif namespace MapControl @@ -79,6 +76,18 @@ namespace MapControl MapPanel.SetLocation(this, Location); } + protected double GetLongitudeOffset(Location location) + { + var longitudeOffset = 0d; + + if (location != null && parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical) + { + longitudeOffset = parentMap.CoerceLongitude(location.Longitude) - location.Longitude; + } + + return longitudeOffset; + } + protected Point? LocationToMap(Location location, double longitudeOffset) { if (longitudeOffset != 0d) @@ -107,31 +116,12 @@ namespace MapControl { var point = LocationToMap(location, longitudeOffset); - if (!point.HasValue) + if (point.HasValue) { - return null; + point = parentMap.ViewTransform.MapToView(point.Value); } - return parentMap.ViewTransform.MapToView(point.Value); - } - - protected double GetLongitudeOffset(Location location) - { - var longitudeOffset = 0d; - - if (location != null && parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical) - { - var point = parentMap.LocationToView(location); - - if (point.HasValue && - (point.Value.X < 0d || point.Value.X > parentMap.ActualWidth || - point.Value.Y < 0d || point.Value.Y > parentMap.ActualHeight)) - { - longitudeOffset = parentMap.CoerceLongitude(location.Longitude) - location.Longitude; - } - } - - return longitudeOffset; + return point; } } } diff --git a/MapControl/Shared/MapTileLayer.cs b/MapControl/Shared/MapTileLayer.cs index 39eddf30..ffa4710a 100644 --- a/MapControl/Shared/MapTileLayer.cs +++ b/MapControl/Shared/MapTileLayer.cs @@ -156,7 +156,7 @@ namespace MapControl // var tileMatrixOrigin = new Point(TileSize * TileMatrix.XMin, TileSize * TileMatrix.YMin); - var tileMatrixScale = ViewTransform.ZoomLevelToScale(TileMatrix.ZoomLevel); + var tileMatrixScale = MapBase.ZoomLevelToScale(TileMatrix.ZoomLevel); ((MatrixTransform)RenderTransform).Matrix = ParentMap.ViewTransform.GetTileLayerTransform(tileMatrixScale, MapTopLeft, tileMatrixOrigin); @@ -169,7 +169,7 @@ namespace MapControl // var tileMatrixZoomLevel = (int)Math.Floor(ParentMap.ZoomLevel - ZoomLevelOffset + 0.001); - var tileMatrixScale = ViewTransform.ZoomLevelToScale(tileMatrixZoomLevel); + var tileMatrixScale = MapBase.ZoomLevelToScale(tileMatrixZoomLevel); // Bounds in tile pixels from view size. // diff --git a/MapControl/Shared/ViewTransform.cs b/MapControl/Shared/ViewTransform.cs index 1576c195..beeada3e 100644 --- a/MapControl/Shared/ViewTransform.cs +++ b/MapControl/Shared/ViewTransform.cs @@ -2,7 +2,6 @@ // Copyright © 2024 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) -using System; #if WPF using System.Windows; using System.Windows.Media; @@ -18,18 +17,8 @@ namespace MapControl /// Defines the transformation between projected map coordinates in meters /// and view coordinates in pixels. /// - public class ViewTransform + public partial class ViewTransform { - public static double ZoomLevelToScale(double zoomLevel) - { - return 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MeterPerDegree); - } - - public static double ScaleToZoomLevel(double scale) - { - return Math.Log(scale * 360d * MapProjection.Wgs84MeterPerDegree / 256d, 2d); - } - /// /// Gets the scaling factor from projected map coordinates to view coordinates, /// as pixels per meter. @@ -51,6 +40,32 @@ namespace MapControl /// public Matrix ViewToMapMatrix { get; private set; } + /// + /// Transforms a Point from projected map coordinates to view coordinates. + /// + public Point MapToView(Point point) + { + return MapToViewMatrix.Transform(point); + } + + /// + /// Transforms a Point from view coordinates to projected map coordinates. + /// + public Point ViewToMap(Point point) + { + return ViewToMapMatrix.Transform(point); + } + + /// + /// Transform relative to absolute map scale. Returns horizontal and vertical + /// scaling factors from meters to view coordinates. + /// + public Point GetMapScale(Point relativeScale) + { + return new Point(Scale * relativeScale.X, Scale * relativeScale.Y); + } + +#if WPF || UWP || WINUI /// /// Initializes a ViewTransform from a map center point in projected coordinates, /// a view conter point, a scaling factor from projected coordinates to view coordinates @@ -72,30 +87,6 @@ namespace MapControl ViewToMapMatrix = transform; } - /// - /// Transforms a Point from projected map coordinates to view coordinates. - /// - public Point MapToView(Point point) - { - return MapToViewMatrix.Transform(point); - } - - /// - /// Transforms a Point from view coordinates to projected map coordinates. - /// - public Point ViewToMap(Point point) - { - return ViewToMapMatrix.Transform(point); - } - - /// - /// Gets scaling factors from meters to view coordinates for a relative map scale. - /// - public Point GetMapScale(Point relativeScale) - { - return new Point(Scale * relativeScale.X, Scale * relativeScale.Y); - } - /// /// Gets a transform Matrix from meters to view coordinates for a relative map scale. /// @@ -170,5 +161,6 @@ namespace MapControl return transform; } +#endif } }