From 263deb5fd692ee055eb4373a54281d1434e36b4d Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Sat, 13 Dec 2025 18:28:07 +0100 Subject: [PATCH] Added MapBase.MapBounds and MapBase.GeoBounds --- MapControl/Avalonia/ViewTransform.Avalonia.cs | 32 ++++---- MapControl/Shared/MapBase.cs | 80 ++++++++++++++----- MapControl/Shared/MapGraticule.cs | 22 ++--- MapControl/Shared/MapImageLayer.cs | 2 +- MapControl/Shared/MapPanel.cs | 2 +- MapControl/Shared/MapPath.cs | 2 +- MapControl/Shared/MapProjection.cs | 16 +--- MapControl/Shared/MapScale.cs | 2 +- MapControl/Shared/ViewTransform.cs | 33 +------- MapControl/Shared/WmsImageLayer.cs | 4 +- 10 files changed, 95 insertions(+), 100 deletions(-) diff --git a/MapControl/Avalonia/ViewTransform.Avalonia.cs b/MapControl/Avalonia/ViewTransform.Avalonia.cs index aa6ebd04..75406511 100644 --- a/MapControl/Avalonia/ViewTransform.Avalonia.cs +++ b/MapControl/Avalonia/ViewTransform.Avalonia.cs @@ -14,11 +14,10 @@ namespace MapControl Scale = scale; Rotation = ((rotation % 360d) + 360d) % 360d; - MapToViewMatrix - = Matrix.CreateTranslation(-mapCenter.X, -mapCenter.Y) - * Matrix.CreateScale(scale, -scale) - * Matrix.CreateRotation(Matrix.ToRadians(Rotation)) - * Matrix.CreateTranslation(viewCenter.X, viewCenter.Y); + MapToViewMatrix = Matrix.CreateTranslation(-mapCenter.X, -mapCenter.Y) + * Matrix.CreateScale(scale, -scale) + * Matrix.CreateRotation(Matrix.ToRadians(Rotation)) + * Matrix.CreateTranslation(viewCenter.X, viewCenter.Y); ViewToMapMatrix = MapToViewMatrix.Invert(); } @@ -28,10 +27,8 @@ namespace MapControl /// public Matrix GetMapTransform(Point relativeScale) { - var scale = GetMapScale(relativeScale); - - return Matrix.CreateScale(scale.X, scale.Y) - * Matrix.CreateRotation(Matrix.ToRadians(Rotation)); + return Matrix.CreateScale(Scale * relativeScale.X, Scale * relativeScale.Y) + * Matrix.CreateRotation(Matrix.ToRadians(Rotation)); } /// @@ -47,13 +44,13 @@ namespace MapControl // Tile matrix origin in view coordinates. // - var viewOrigin = MapToView(mapOrigin); + var viewOrigin = MapToViewMatrix.Transform(mapOrigin); var transformScale = Scale / tileMatrixScale; return Matrix.CreateScale(transformScale, transformScale) - * Matrix.CreateRotation(Matrix.ToRadians(Rotation)) - * Matrix.CreateTranslation(viewOrigin.X, viewOrigin.Y); + * Matrix.CreateRotation(Matrix.ToRadians(Rotation)) + * Matrix.CreateTranslation(viewOrigin.X, viewOrigin.Y); } /// @@ -63,13 +60,12 @@ namespace MapControl { // View origin in map coordinates. // - var origin = ViewToMap(new Point()); + var origin = ViewToMapMatrix.Transform(new Point()); var transformScale = tileMatrixScale / Scale; - var transform - = Matrix.CreateScale(transformScale, transformScale) - * Matrix.CreateRotation(Matrix.ToRadians(-Rotation)); + var transform = Matrix.CreateScale(transformScale, transformScale) + * Matrix.CreateRotation(Matrix.ToRadians(-Rotation)); // Translate origin to tile matrix origin in pixels. // @@ -88,8 +84,8 @@ namespace MapControl double translation2X, double translation2Y) { return Matrix.CreateTranslation(translation1X, translation1Y) - * Matrix.CreateRotation(Matrix.ToRadians(rotation)) - * Matrix.CreateTranslation(translation2X, translation2Y); + * Matrix.CreateRotation(Matrix.ToRadians(rotation)) + * Matrix.CreateTranslation(translation2X, translation2Y); } } } diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs index 2b3a2328..71bfc6b3 100644 --- a/MapControl/Shared/MapBase.cs +++ b/MapControl/Shared/MapBase.cs @@ -49,6 +49,8 @@ namespace MapControl private Location transformCenter; private Point viewCenter; + private Rect? mapBounds; + private BoundingBox geoBounds; private double centerLongitude; private double maxLatitude = 85.05112878; // default WebMercatorProjection private bool internalPropertyChange; @@ -170,6 +172,27 @@ namespace MapControl set => SetValue(TargetHeadingProperty, value); } + /// + /// Gets the map viewport bounds in projected map coordinates. + /// + public Rect MapBounds + { + get + { + if (!mapBounds.HasValue) + { + mapBounds = ViewRectToMap(0d, 0d, ActualWidth, ActualHeight); + } + + return mapBounds.Value; + } + } + + /// + /// Gets the map viewport bounds in geographic coordinates. + /// + public BoundingBox GeoBounds => geoBounds ??= MapProjection.MapToBoundingBox(MapBounds); + /// /// Gets the ViewTransform instance that is used to transform between projected /// map coordinates and view coordinates. @@ -180,18 +203,22 @@ namespace MapControl /// Gets the map scale as horizontal and vertical scaling factors from meters to /// view coordinates at the specified geographic coordinates. /// - public Point GetScale(double latitude, double longitude) + public Point GetMapScale(double latitude, double longitude) { - return ViewTransform.GetMapScale(MapProjection.GetRelativeScale(latitude, longitude)); + var relativeScale = MapProjection.GetRelativeScale(latitude, longitude); + + return new Point(ViewTransform.Scale * relativeScale.X, ViewTransform.Scale * relativeScale.Y); } /// /// Gets the map scale as horizontal and vertical scaling factors from meters to /// view coordinates at the specified location. /// - public Point GetScale(Location location) + public Point GetMapScale(Location location) { - return ViewTransform.GetMapScale(MapProjection.GetRelativeScale(location)); + var relativeScale = MapProjection.GetRelativeScale(location); + + return new Point(ViewTransform.Scale * relativeScale.X, ViewTransform.Scale * relativeScale.Y); } /// @@ -212,7 +239,7 @@ namespace MapControl if (point.HasValue) { - point = ViewTransform.MapToView(point.Value); + point = ViewTransform.MapToViewMatrix.Transform(point.Value); } return point; @@ -231,25 +258,35 @@ namespace MapControl /// public Location ViewToLocation(Point point) { - return MapProjection.MapToLocation(ViewTransform.ViewToMap(point)); + return MapProjection.MapToLocation(ViewTransform.ViewToMapMatrix.Transform(point)); } /// - /// Gets a BoundingBox in geographic coordinates that covers a Rect in view coordinates. + /// Gets a Rect in projected map coordinates that covers a rectangle in view coordinates. /// - public BoundingBox ViewRectToBoundingBox(Rect rect) + public Rect ViewRectToMap(double x, double y, double width, double height) { - var p1 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y)); - var p2 = ViewTransform.ViewToMap(new Point(rect.X, rect.Y + rect.Height)); - var p3 = ViewTransform.ViewToMap(new Point(rect.X + rect.Width, rect.Y)); - var p4 = ViewTransform.ViewToMap(new Point(rect.X + rect.Width, rect.Y + rect.Height)); + var viewToMap = ParentMap.ViewTransform.ViewToMapMatrix; + + var p1 = viewToMap.Transform(new Point(x, y)); + var p2 = viewToMap.Transform(new Point(x, y + height)); + var p3 = viewToMap.Transform(new Point(x + width, y)); + var p4 = viewToMap.Transform(new Point(x + width, y + height)); var x1 = Math.Min(p1.X, Math.Min(p2.X, Math.Min(p3.X, p4.X))); var y1 = Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y))); var x2 = Math.Max(p1.X, Math.Max(p2.X, Math.Max(p3.X, p4.X))); var y2 = Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y))); - return MapProjection.MapToBoundingBox(new Rect(x1, y1, x2 - x1, y2 - y1)); + return new Rect(x1, y1, x2 - x1, y2 - y1); + } + + /// + /// Gets a BoundingBox in geographic coordinates that covers a rectangle in view coordinates. + /// + public BoundingBox ViewRectToBoundingBox(double x, double y, double width, double height) + { + return MapProjection.MapToBoundingBox(ViewRectToMap(x, y, width, height)); } /// @@ -354,9 +391,9 @@ namespace MapControl /// Sets the TargetZoomLevel and TargetCenter properties so that the specified BoundingBox /// fits into the current view. The TargetHeading property is set to zero. /// - public void ZoomToBounds(BoundingBox boundingBox) + public void ZoomToBounds(BoundingBox bounds) { - var mapRect = MapProjection.BoundingBoxToMap(boundingBox); + var mapRect = MapProjection.BoundingBoxToMap(bounds); if (mapRect.HasValue) { @@ -486,16 +523,16 @@ namespace MapControl if (center != null) { - var centerLatitude = center.Latitude; - var centerLongitude = Location.NormalizeLongitude(center.Longitude); + var centerLat = center.Latitude; + var centerLon = Location.NormalizeLongitude(center.Longitude); - if (centerLatitude < -maxLatitude || centerLatitude > maxLatitude) + if (centerLat < -maxLatitude || centerLat > maxLatitude) { - centerLatitude = Math.Min(Math.Max(centerLatitude, -maxLatitude), maxLatitude); + centerLat = Math.Min(Math.Max(centerLat, -maxLatitude), maxLatitude); resetTransformCenter = true; } - center = new Location(centerLatitude, centerLongitude); + center = new Location(centerLat, centerLon); SetValueInternal(CenterProperty, center); @@ -539,6 +576,9 @@ namespace MapControl { base.OnViewportChanged(e); + mapBounds = null; + geoBounds = null; + ViewportChanged?.Invoke(this, e); } } diff --git a/MapControl/Shared/MapGraticule.cs b/MapControl/Shared/MapGraticule.cs index 3544d6e5..ed4b7073 100644 --- a/MapControl/Shared/MapGraticule.cs +++ b/MapControl/Shared/MapGraticule.cs @@ -100,7 +100,7 @@ namespace MapControl private double PixelPerLongitudeDegree(double latitude, double longitude) { - var scale = ParentMap.GetScale(latitude, longitude); + var scale = ParentMap.GetMapScale(latitude, longitude); return Math.Max(1d, // a reasonable lower limit scale.X * Math.Cos(latitude * Math.PI / 180d) * MapProjection.Wgs84MeterPerDegree); @@ -171,14 +171,14 @@ namespace MapControl private void DrawCylindricalGraticule(PathFigureCollection figures, List public virtual Rect? BoundingBoxToMap(BoundingBox boundingBox) { - Rect? rect = null; var southWest = LocationToMap(boundingBox.South, boundingBox.West); var northEast = LocationToMap(boundingBox.North, boundingBox.East); - if (southWest.HasValue && northEast.HasValue) - { - rect = new Rect(southWest.Value, northEast.Value); - } - - return rect; + return southWest.HasValue && northEast.HasValue ? new Rect(southWest.Value, northEast.Value) : null; } /// @@ -112,16 +106,10 @@ namespace MapControl /// public virtual BoundingBox MapToBoundingBox(Rect rect) { - BoundingBox boundingBox = null; var southWest = MapToLocation(rect.X, rect.Y); var northEast = MapToLocation(rect.X + rect.Width, rect.Y + rect.Height); - if (southWest != null && northEast != null) - { - boundingBox = new BoundingBox(southWest, northEast); - } - - return boundingBox; + return southWest != null && northEast != null ? new BoundingBox(southWest, northEast) : null; } /// diff --git a/MapControl/Shared/MapScale.cs b/MapControl/Shared/MapScale.cs index 7e714660..6b3a7baf 100644 --- a/MapControl/Shared/MapScale.cs +++ b/MapControl/Shared/MapScale.cs @@ -90,7 +90,7 @@ namespace MapControl { double scale; - if (ParentMap == null || (scale = ParentMap.GetScale(ParentMap.Center).X) <= 0d) + if (ParentMap == null || (scale = ParentMap.GetMapScale(ParentMap.Center).X) <= 0d) { return new Size(); } diff --git a/MapControl/Shared/ViewTransform.cs b/MapControl/Shared/ViewTransform.cs index 9cb673d9..09d92b09 100644 --- a/MapControl/Shared/ViewTransform.cs +++ b/MapControl/Shared/ViewTransform.cs @@ -38,31 +38,6 @@ 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, @@ -90,9 +65,7 @@ namespace MapControl /// public Matrix GetMapTransform(Point relativeScale) { - var scale = GetMapScale(relativeScale); - - var transform = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d); + var transform = new Matrix(Scale * relativeScale.X, 0d, 0d, Scale * relativeScale.Y, 0d, 0d); transform.Rotate(Rotation); return transform; @@ -111,7 +84,7 @@ namespace MapControl // Tile matrix origin in view coordinates. // - var viewOrigin = MapToView(mapOrigin); + var viewOrigin = MapToViewMatrix.Transform(mapOrigin); var transformScale = Scale / tileMatrixScale; @@ -129,7 +102,7 @@ namespace MapControl { // View origin in map coordinates. // - var origin = ViewToMap(new Point()); + var origin = ViewToMapMatrix.Transform(new Point()); var transformScale = tileMatrixScale / Scale; diff --git a/MapControl/Shared/WmsImageLayer.cs b/MapControl/Shared/WmsImageLayer.cs index acec2a42..7ae97c8b 100644 --- a/MapControl/Shared/WmsImageLayer.cs +++ b/MapControl/Shared/WmsImageLayer.cs @@ -170,9 +170,7 @@ namespace MapControl ParentMap.ActualWidth > 0d && ParentMap.ActualHeight > 0d) { - var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, ParentMap.ActualWidth, ParentMap.ActualHeight)); - - var uri = GetFeatureInfoRequestUri(boundingBox, position, format); + var uri = GetFeatureInfoRequestUri(ParentMap.GeoBounds, position, format); if (uri != null) {