diff --git a/MapControl/Shared/AzimuthalProjection.cs b/MapControl/Shared/AzimuthalProjection.cs index 986dd1dd..e5cfcb5f 100644 --- a/MapControl/Shared/AzimuthalProjection.cs +++ b/MapControl/Shared/AzimuthalProjection.cs @@ -30,21 +30,23 @@ namespace MapControl var width = boundingBox.Width * Wgs84MeterPerDegree; var height = boundingBox.Height * Wgs84MeterPerDegree; + var x = center.Value.X - width / 2d; + var y = center.Value.Y - height / 2d; - return new MapRect(center.Value.X - width / 2d, center.Value.Y - height / 2d, width, height); + return new MapRect(x, y, x + width, y + height); } - public override BoundingBox MapRectToBoundingBox(MapRect rect) + public override BoundingBox MapRectToBoundingBox(MapRect mapRect) { - var center = MapToLocation(new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d)); + var center = MapToLocation(mapRect.Center); if (center == null) { return null; } - var width = rect.Width / Wgs84MeterPerDegree; - var height = rect.Height / Wgs84MeterPerDegree; + var width = mapRect.Width / Wgs84MeterPerDegree; + var height = mapRect.Height / Wgs84MeterPerDegree; return new CenteredBoundingBox(center, width, height); } diff --git a/MapControl/Shared/BoundingBox.cs b/MapControl/Shared/BoundingBox.cs index 47d5b190..73325094 100644 --- a/MapControl/Shared/BoundingBox.cs +++ b/MapControl/Shared/BoundingBox.cs @@ -15,23 +15,32 @@ namespace MapControl #endif public class BoundingBox { - private double south = double.NaN; - private double north = double.NaN; + private double south; + private double north; public BoundingBox() { + south = double.NaN; + north = double.NaN; + West = double.NaN; + East = double.NaN; } - public BoundingBox(double south, double west, double north, double east) + public BoundingBox(double latitude1, double longitude1, double latitude2, double longitude2) { - South = south; - West = west; - North = north; - East = east; + South = Math.Min(latitude1, latitude2); + North = Math.Max(latitude1, latitude2); + West = Math.Min(longitude1, longitude2); + East = Math.Max(longitude1, longitude2); } - public double West { get; set; } = double.NaN; - public double East { get; set; } = double.NaN; + public BoundingBox(Location location1, Location location2) + : this(location1.Latitude, location1.Longitude, location2.Latitude, location2.Longitude) + { + } + + public double West { get; set; } + public double East { get; set; } public double South { diff --git a/MapControl/Shared/EquirectangularProjection.cs b/MapControl/Shared/EquirectangularProjection.cs index 0ad0ac15..2c4127bd 100644 --- a/MapControl/Shared/EquirectangularProjection.cs +++ b/MapControl/Shared/EquirectangularProjection.cs @@ -46,12 +46,14 @@ namespace MapControl point.X / Wgs84MeterPerDegree); } - public override string GetBboxValue(MapRect rect) + public override string GetBboxValue(MapRect mapRect) { return string.Format(CultureInfo.InvariantCulture, CrsId == "CRS:84" ? "{0},{1},{2},{3}" : "{1},{0},{3},{2}", - rect.X / Wgs84MeterPerDegree, rect.Y / Wgs84MeterPerDegree, - (rect.X + rect.Width) / Wgs84MeterPerDegree, (rect.Y + rect.Height) / Wgs84MeterPerDegree); + mapRect.XMin / Wgs84MeterPerDegree, + mapRect.YMin / Wgs84MeterPerDegree, + mapRect.XMax / Wgs84MeterPerDegree, + mapRect.YMax / Wgs84MeterPerDegree); } } } diff --git a/MapControl/Shared/GeoImage.cs b/MapControl/Shared/GeoImage.cs index 58aa1d46..c544178f 100644 --- a/MapControl/Shared/GeoImage.cs +++ b/MapControl/Shared/GeoImage.cs @@ -100,11 +100,10 @@ namespace MapControl transform.M21 = 0; } - var rect = new MapRect( - transform.Transform(new Point()), - transform.Transform(new Point(bitmap.PixelWidth, bitmap.PixelHeight))); + var p1 = transform.Transform(new Point()); + var p2 = transform.Transform(new Point(bitmap.PixelWidth, bitmap.PixelHeight)); - boundingBox = new BoundingBox(rect.Y, rect.X, rect.Y + rect.Height, rect.X + rect.Width); + boundingBox = new BoundingBox(p1.Y, p1.X, p2.Y, p2.X); // Y=Latitude, X=Longitude } Content = image; diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs index 032f9eea..5e53baaa 100644 --- a/MapControl/Shared/MapBase.cs +++ b/MapControl/Shared/MapBase.cs @@ -270,11 +270,11 @@ namespace MapControl var p4 = ViewTransform.ViewToMap(new Point(rect.X + rect.Width, rect.Y + rect.Height)); var x1 = Math.Min(p1.X, Math.Min(p2.X, Math.Min(p3.X, p4.X))); - var x2 = Math.Max(p1.X, Math.Max(p2.X, Math.Max(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.MapRectToBoundingBox(new MapRect(x1, y1, x2 - x1, y2 - y1)); + return MapProjection.MapRectToBoundingBox(new MapRect(x1, y1, x2, y2)); } /// @@ -380,13 +380,12 @@ namespace MapControl /// public void ZoomToBounds(BoundingBox boundingBox) { - var rect = MapProjection.BoundingBoxToMapRect(boundingBox); - var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d); - var targetCenter = MapProjection.MapToLocation(center); + var mapRect = MapProjection.BoundingBoxToMapRect(boundingBox); + var targetCenter = MapProjection.MapToLocation(mapRect.Center); if (targetCenter != null) { - var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height); + var scale = Math.Min(RenderSize.Width / mapRect.Width, RenderSize.Height / mapRect.Height); TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale); TargetCenter = targetCenter; diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index e5972ecc..1e942e3b 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -223,15 +223,14 @@ namespace MapControl return GetViewRect(parentMap.MapProjection.BoundingBoxToMapRect(boundingBox)); } - protected ViewRect GetViewRect(MapRect rect) + protected ViewRect GetViewRect(MapRect mapRect) { - var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d); - var position = parentMap.ViewTransform.MapToView(center); + var position = parentMap.ViewTransform.MapToView(mapRect.Center); if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical && IsOutsideViewport(position)) { - var location = parentMap.MapProjection.MapToLocation(center); + var location = parentMap.MapProjection.MapToLocation(mapRect.Center); if (location != null) { @@ -245,8 +244,8 @@ namespace MapControl } } - var width = rect.Width * parentMap.ViewTransform.Scale; - var height = rect.Height * parentMap.ViewTransform.Scale; + var width = mapRect.Width * parentMap.ViewTransform.Scale; + var height = mapRect.Height * parentMap.ViewTransform.Scale; var x = position.X - width / 2d; var y = position.Y - height / 2d; diff --git a/MapControl/Shared/MapProjection.cs b/MapControl/Shared/MapProjection.cs index f3850eb9..0909bb08 100644 --- a/MapControl/Shared/MapProjection.cs +++ b/MapControl/Shared/MapProjection.cs @@ -82,14 +82,12 @@ namespace MapControl /// Transforms a MapRect in projected map coordinates to a BoundingBox in geographic coordinates. /// Returns null when the MapRect can not be transformed. /// - public virtual BoundingBox MapRectToBoundingBox(MapRect rect) + public virtual BoundingBox MapRectToBoundingBox(MapRect mapRect) { - var sw = MapToLocation(new Point(rect.X, rect.Y)); - var ne = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height)); + var sw = MapToLocation(new Point(mapRect.XMin, mapRect.YMin)); + var ne = MapToLocation(new Point(mapRect.XMax, mapRect.YMax)); - return sw != null && ne != null - ? new BoundingBox(sw.Latitude, sw.Longitude, ne.Latitude, ne.Longitude) - : null; + return sw != null && ne != null ? new BoundingBox(sw, ne) : null; } /// @@ -105,10 +103,17 @@ namespace MapControl /// /// Gets the BBOX parameter value for a WMS GetMap request. /// - public virtual string GetBboxValue(MapRect rect) + public virtual string GetBboxValue(MapRect mapRect) { - return string.Format(CultureInfo.InvariantCulture, - "{0},{1},{2},{3}", rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height)); + // Truncate bounding box to 1 cm precision. + // + const double p = 0.01; + + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", + p * Math.Ceiling(mapRect.XMin / p), + p * Math.Ceiling(mapRect.YMin / p), + p * Math.Floor(mapRect.XMax / p), + p * Math.Floor(mapRect.YMax / p)); } } } diff --git a/MapControl/Shared/MapRect.cs b/MapControl/Shared/MapRect.cs index d91b03ee..5176388e 100644 --- a/MapControl/Shared/MapRect.cs +++ b/MapControl/Shared/MapRect.cs @@ -15,31 +15,29 @@ namespace MapControl /// public class MapRect { - public MapRect(double x, double y, double width, double height) + public MapRect(double x1, double y1, double x2, double y2) { - X = x; - Y = y; - Width = width; - Height = height; + XMin = Math.Min(x1, x2); + YMin = Math.Min(y1, y2); + XMax = Math.Max(x1, x2); + YMax = Math.Max(y1, y2); } - public MapRect(Point p1, Point p2) + public MapRect(Point point1, Point point2) + : this(point1.X, point1.Y, point2.X, point2.Y) { - X = Math.Min(p1.X, p2.X); - Y = Math.Min(p1.Y, p2.Y); - Width = Math.Max(p1.X, p2.X) - X; - Height = Math.Max(p1.Y, p2.Y) - Y; } - public double X { get; } - public double Y { get; } - public double Width { get; } - public double Height { get; } + public double XMin { get; } + public double YMin { get; } + public double XMax { get; } + public double YMax { get; } - public bool Contains(Point p) - { - return p.X >= X && p.X <= X + Width - && p.Y >= Y && p.Y <= Y + Height; - } + public double Width => XMax - XMin; + public double Height => YMax - YMin; + + public Point Center => new Point((XMin + XMax) / 2d, (YMin + YMax) / 2d); + + public bool Contains(Point p) => p.X >= XMin && p.X <= XMax && p.Y >= YMin && p.Y <= YMax; } } diff --git a/MapControl/WPF/MapItemsImageLayer.WPF.cs b/MapControl/WPF/MapItemsImageLayer.WPF.cs index b0bba648..f0393372 100644 --- a/MapControl/WPF/MapItemsImageLayer.WPF.cs +++ b/MapControl/WPF/MapItemsImageLayer.WPF.cs @@ -63,8 +63,8 @@ namespace MapControl for (int i = 0; i < points.Count; i++) { points[i] = new Point( - scale * (points[i].X - mapRect.X), - scale * (mapRect.Height + mapRect.Y - points[i].Y)); + scale * (points[i].X - mapRect.XMin), + scale * (mapRect.YMax - points[i].Y)); } drawings.Children.Add(item.GetDrawing(points, scale, rotation)); diff --git a/MapProjections/Shared/GeoApiProjection.cs b/MapProjections/Shared/GeoApiProjection.cs index 22996be3..ac236d35 100644 --- a/MapProjections/Shared/GeoApiProjection.cs +++ b/MapProjections/Shared/GeoApiProjection.cs @@ -150,8 +150,10 @@ namespace MapControl.Projections public override string GetBboxValue(MapRect rect) { return string.Format(CultureInfo.InvariantCulture, bboxFormat, - rect.X / scaleFactor, rect.Y / scaleFactor, - (rect.X + rect.Width) / scaleFactor, (rect.Y + rect.Height) / scaleFactor); + rect.XMin / scaleFactor, + rect.YMin / scaleFactor, + rect.XMax / scaleFactor, + rect.YMax / scaleFactor); } } }