mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Replaced MapRect and Scale by Rect and Point
This commit is contained in:
parent
dd62545b41
commit
7e18b6b984
|
|
@ -3,6 +3,9 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
#if !WINUI && !UWP
|
||||||
|
using System.Windows;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
|
@ -16,12 +19,13 @@ namespace MapControl
|
||||||
Type = MapProjectionType.Azimuthal;
|
Type = MapProjectionType.Azimuthal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundingBox MapRectToBoundingBox(MapRect mapRect)
|
public override BoundingBox MapToBoundingBox(Rect rect)
|
||||||
{
|
{
|
||||||
var center = MapToLocation(mapRect.Center);
|
var rectCenter = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
|
var center = MapToLocation(rectCenter);
|
||||||
|
|
||||||
return center != null
|
return center != null
|
||||||
? new CenteredBoundingBox(center, mapRect.Width / Wgs84MeterPerDegree, mapRect.Height / Wgs84MeterPerDegree)
|
? new CenteredBoundingBox(center, rect.Width / Wgs84MeterPerDegree, rect.Height / Wgs84MeterPerDegree)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
return new Scale(
|
return new Point(
|
||||||
1d / Math.Cos(location.Latitude * Math.PI / 180d),
|
1d / Math.Cos(location.Latitude * Math.PI / 180d),
|
||||||
1d);
|
1d);
|
||||||
}
|
}
|
||||||
|
|
@ -47,14 +47,14 @@ namespace MapControl
|
||||||
point.X / Wgs84MeterPerDegree);
|
point.X / Wgs84MeterPerDegree);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetBboxValue(MapRect mapRect)
|
public override string GetBboxValue(Rect rect)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.InvariantCulture,
|
return string.Format(CultureInfo.InvariantCulture,
|
||||||
CrsId == "CRS:84" ? "{0},{1},{2},{3}" : "{1},{0},{3},{2}",
|
CrsId == "CRS:84" ? "{0},{1},{2},{3}" : "{1},{0},{3},{2}",
|
||||||
mapRect.XMin / Wgs84MeterPerDegree,
|
rect.X / Wgs84MeterPerDegree,
|
||||||
mapRect.YMin / Wgs84MeterPerDegree,
|
rect.Y / Wgs84MeterPerDegree,
|
||||||
mapRect.XMax / Wgs84MeterPerDegree,
|
(rect.X + rect.Width) / Wgs84MeterPerDegree,
|
||||||
mapRect.YMax / Wgs84MeterPerDegree);
|
(rect.Y + rect.Height) / Wgs84MeterPerDegree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,15 +119,15 @@ namespace MapControl
|
||||||
|
|
||||||
var p1 = transform.Transform(new Point());
|
var p1 = transform.Transform(new Point());
|
||||||
var p2 = transform.Transform(new Point(geoBitmap.Bitmap.PixelWidth, geoBitmap.Bitmap.PixelHeight));
|
var p2 = transform.Transform(new Point(geoBitmap.Bitmap.PixelWidth, geoBitmap.Bitmap.PixelHeight));
|
||||||
var mapRect = new MapRect(p1, p2);
|
var rect = new Rect(p1, p2);
|
||||||
|
|
||||||
if (geoBitmap.Projection != null)
|
if (geoBitmap.Projection != null)
|
||||||
{
|
{
|
||||||
boundingBox = geoBitmap.Projection.MapRectToBoundingBox(mapRect);
|
boundingBox = geoBitmap.Projection.MapToBoundingBox(rect);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boundingBox = new BoundingBox(mapRect.YMin, mapRect.XMin, mapRect.YMax, mapRect.XMax);
|
boundingBox = new BoundingBox(rect.Y, rect.X, rect.Y + rect.Height, rect.X + rect.Width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
int epsgCode = geoKeyDirectory[i + 3];
|
int epsgCode = geoKeyDirectory[i + 3];
|
||||||
|
|
||||||
projection = MapProjection.Factory.GetProjection(epsgCode) ??
|
projection = MapProjectionFactory.Instance.GetProjection(epsgCode) ??
|
||||||
throw new ArgumentException($"Can not create projection EPSG:{epsgCode} in {sourcePath}.");
|
throw new ArgumentException($"Can not create projection EPSG:{epsgCode} in {sourcePath}.");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,14 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
#if WINUI
|
#if AVALONIA
|
||||||
|
using ImageSource = Avalonia.Media.IImage;
|
||||||
|
#elif WINUI
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
|
||||||
#elif UWP
|
#elif UWP
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
|
||||||
#else
|
#else
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
|
|
@ -43,11 +42,7 @@ namespace MapControl
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!uri.IsAbsoluteUri || uri.IsFile)
|
if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||||
{
|
|
||||||
image = await LoadImageAsync(uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString);
|
|
||||||
}
|
|
||||||
else if (uri.Scheme == "http" || uri.Scheme == "https")
|
|
||||||
{
|
{
|
||||||
var response = await GetHttpResponseAsync(uri, progress);
|
var response = await GetHttpResponseAsync(uri, progress);
|
||||||
|
|
||||||
|
|
@ -56,9 +51,13 @@ namespace MapControl
|
||||||
image = await LoadImageAsync(response.Buffer);
|
image = await LoadImageAsync(response.Buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (uri.IsFile || !uri.IsAbsoluteUri)
|
||||||
|
{
|
||||||
|
image = await LoadImageAsync(uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
image = new BitmapImage(uri);
|
image = LoadImage(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if WINUI || UWP
|
#if !WINUI && !UWP
|
||||||
using Windows.Foundation;
|
|
||||||
#else
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -50,30 +48,30 @@ namespace MapControl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var topLeft = new Point(rect.Left, rect.Top);
|
var topLeft = new Point(rect.X, rect.Y);
|
||||||
var topRight = new Point(rect.Right, rect.Top);
|
var topRight = new Point(rect.X + rect.Width, rect.Y);
|
||||||
var bottomLeft = new Point(rect.Left, rect.Bottom);
|
var bottomLeft = new Point(rect.X, rect.Y + rect.Height);
|
||||||
var bottomRight = new Point(rect.Right, rect.Bottom);
|
var bottomRight = new Point(rect.X + rect.Width, rect.Y + rect.Height);
|
||||||
var numIntersections = 0;
|
var numIntersections = 0;
|
||||||
|
|
||||||
if (GetIntersection(ref p1, ref p2, topLeft, bottomLeft, p => p.X <= rect.Left)) // left edge
|
if (GetIntersection(ref p1, ref p2, topLeft, bottomLeft, p => p.X <= rect.X)) // left edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetIntersection(ref p1, ref p2, topLeft, topRight, p => p.Y <= rect.Top)) // top edge
|
if (GetIntersection(ref p1, ref p2, topLeft, topRight, p => p.Y <= rect.Y)) // top edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numIntersections < 2 &&
|
if (numIntersections < 2 &&
|
||||||
GetIntersection(ref p1, ref p2, topRight, bottomRight, p => p.X >= rect.Right)) // right edge
|
GetIntersection(ref p1, ref p2, topRight, bottomRight, p => p.X >= rect.X + rect.Width)) // right edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numIntersections < 2 &&
|
if (numIntersections < 2 &&
|
||||||
GetIntersection(ref p1, ref p2, bottomLeft, bottomRight, p => p.Y >= rect.Bottom)) // bottom edge
|
GetIntersection(ref p1, ref p2, bottomLeft, bottomRight, p => p.Y >= rect.Y + rect.Height)) // bottom edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,9 +231,11 @@ namespace MapControl
|
||||||
/// Gets the map scale as the horizontal and vertical scaling factors from geographic
|
/// Gets the map scale as the horizontal and vertical scaling factors from geographic
|
||||||
/// coordinates to view coordinates at the specified location, as pixels per meter.
|
/// coordinates to view coordinates at the specified location, as pixels per meter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Scale GetScale(Location location)
|
public Point GetScale(Location location)
|
||||||
{
|
{
|
||||||
return ViewTransform.Scale * MapProjection.GetRelativeScale(location);
|
var relativeScale = MapProjection.GetRelativeScale(location);
|
||||||
|
|
||||||
|
return new Point(ViewTransform.Scale * relativeScale.X, ViewTransform.Scale * relativeScale.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -286,7 +288,7 @@ namespace MapControl
|
||||||
var x2 = Math.Max(p1.X, Math.Max(p2.X, Math.Max(p3.X, p4.X)));
|
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)));
|
var y2 = Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y)));
|
||||||
|
|
||||||
return MapProjection.MapRectToBoundingBox(new MapRect(x1, y1, x2, y2));
|
return MapProjection.MapToBoundingBox(new Rect(x1, y1, x2 - x1, y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -342,8 +344,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
SetTransformCenter(center);
|
SetTransformCenter(center);
|
||||||
|
|
||||||
viewCenter.X += translation.X;
|
viewCenter = new Point(viewCenter.X + translation.X, viewCenter.Y + translation.Y);
|
||||||
viewCenter.Y += translation.Y;
|
|
||||||
|
|
||||||
if (rotation != 0d)
|
if (rotation != 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -392,15 +393,16 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomToBounds(BoundingBox boundingBox)
|
public void ZoomToBounds(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var mapRect = MapProjection.BoundingBoxToMapRect(boundingBox);
|
var rect = MapProjection.BoundingBoxToMap(boundingBox);
|
||||||
|
|
||||||
if (mapRect != null)
|
if (rect.HasValue)
|
||||||
{
|
{
|
||||||
var targetCenter = MapProjection.MapToLocation(mapRect.Center);
|
var rectCenter = new Point(rect.Value.X + rect.Value.Width / 2d, rect.Value.Y + rect.Value.Height / 2d);
|
||||||
|
var targetCenter = MapProjection.MapToLocation(rectCenter);
|
||||||
|
|
||||||
if (targetCenter != null)
|
if (targetCenter != null)
|
||||||
{
|
{
|
||||||
var scale = Math.Min(RenderSize.Width / mapRect.Width, RenderSize.Height / mapRect.Height);
|
var scale = Math.Min(RenderSize.Width / rect.Value.Width, RenderSize.Height / rect.Value.Height);
|
||||||
|
|
||||||
TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
|
TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
|
||||||
TargetCenter = targetCenter;
|
TargetCenter = targetCenter;
|
||||||
|
|
|
||||||
|
|
@ -183,9 +183,9 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var viewRect = GetViewRect(boundingBox);
|
var viewRect = GetViewRect(boundingBox);
|
||||||
|
|
||||||
if (viewRect != null)
|
if (viewRect.HasValue)
|
||||||
{
|
{
|
||||||
ArrangeElement(element, viewRect);
|
ArrangeElement(element, viewRect.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -214,21 +214,27 @@ namespace MapControl
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ViewRect GetViewRect(BoundingBox boundingBox)
|
protected ViewRect? GetViewRect(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var mapRect = parentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
|
var rect = parentMap.MapProjection.BoundingBoxToMap(boundingBox);
|
||||||
|
|
||||||
return mapRect != null ? GetViewRect(mapRect) : null;
|
if (!rect.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ViewRect GetViewRect(MapRect mapRect)
|
return GetViewRect(rect.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ViewRect GetViewRect(Rect rect)
|
||||||
{
|
{
|
||||||
var position = parentMap.ViewTransform.MapToView(mapRect.Center);
|
var rectCenter = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
|
var position = parentMap.ViewTransform.MapToView(rectCenter);
|
||||||
|
|
||||||
if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical &&
|
if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical &&
|
||||||
IsOutsideViewport(position))
|
IsOutsideViewport(position))
|
||||||
{
|
{
|
||||||
var location = parentMap.MapProjection.MapToLocation(mapRect.Center);
|
var location = parentMap.MapProjection.MapToLocation(rectCenter);
|
||||||
|
|
||||||
if (location != null)
|
if (location != null)
|
||||||
{
|
{
|
||||||
|
|
@ -242,8 +248,8 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var width = mapRect.Width * parentMap.ViewTransform.Scale;
|
var width = rect.Width * parentMap.ViewTransform.Scale;
|
||||||
var height = mapRect.Height * parentMap.ViewTransform.Scale;
|
var height = rect.Height * parentMap.ViewTransform.Scale;
|
||||||
var x = position.X - width / 2d;
|
var x = position.X - width / 2d;
|
||||||
var y = position.Y - height / 2d;
|
var y = position.Y - height / 2d;
|
||||||
|
|
||||||
|
|
@ -259,16 +265,17 @@ namespace MapControl
|
||||||
private static void ArrangeElement(FrameworkElement element, Point position)
|
private static void ArrangeElement(FrameworkElement element, Point position)
|
||||||
{
|
{
|
||||||
var size = GetDesiredSize(element);
|
var size = GetDesiredSize(element);
|
||||||
var rect = new Rect(position.X, position.Y, size.Width, size.Height);
|
var x = position.X;
|
||||||
|
var y = position.Y;
|
||||||
|
|
||||||
switch (element.HorizontalAlignment)
|
switch (element.HorizontalAlignment)
|
||||||
{
|
{
|
||||||
case HorizontalAlignment.Center:
|
case HorizontalAlignment.Center:
|
||||||
rect.X -= rect.Width / 2d;
|
x -= size.Width / 2d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HorizontalAlignment.Right:
|
case HorizontalAlignment.Right:
|
||||||
rect.X -= rect.Width;
|
x -= size.Width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -278,37 +285,40 @@ namespace MapControl
|
||||||
switch (element.VerticalAlignment)
|
switch (element.VerticalAlignment)
|
||||||
{
|
{
|
||||||
case VerticalAlignment.Center:
|
case VerticalAlignment.Center:
|
||||||
rect.Y -= rect.Height / 2d;
|
y -= size.Height / 2d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VerticalAlignment.Bottom:
|
case VerticalAlignment.Bottom:
|
||||||
rect.Y -= rect.Height;
|
y -= size.Height;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrangeElement(element, rect);
|
ArrangeElement(element, new Rect(x, y, size.Width, size.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ArrangeElement(FrameworkElement element, Size parentSize)
|
private static void ArrangeElement(FrameworkElement element, Size parentSize)
|
||||||
{
|
{
|
||||||
var size = GetDesiredSize(element);
|
var size = GetDesiredSize(element);
|
||||||
var rect = new Rect(0d, 0d, size.Width, size.Height);
|
var x = 0d;
|
||||||
|
var y = 0d;
|
||||||
|
var width = size.Width;
|
||||||
|
var height = size.Height;
|
||||||
|
|
||||||
switch (element.HorizontalAlignment)
|
switch (element.HorizontalAlignment)
|
||||||
{
|
{
|
||||||
case HorizontalAlignment.Center:
|
case HorizontalAlignment.Center:
|
||||||
rect.X = (parentSize.Width - rect.Width) / 2d;
|
x = (parentSize.Width - size.Width) / 2d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HorizontalAlignment.Right:
|
case HorizontalAlignment.Right:
|
||||||
rect.X = parentSize.Width - rect.Width;
|
x = parentSize.Width - size.Width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HorizontalAlignment.Stretch:
|
case HorizontalAlignment.Stretch:
|
||||||
rect.Width = parentSize.Width;
|
width = parentSize.Width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -318,30 +328,30 @@ namespace MapControl
|
||||||
switch (element.VerticalAlignment)
|
switch (element.VerticalAlignment)
|
||||||
{
|
{
|
||||||
case VerticalAlignment.Center:
|
case VerticalAlignment.Center:
|
||||||
rect.Y = (parentSize.Height - rect.Height) / 2d;
|
y = (parentSize.Height - size.Height) / 2d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VerticalAlignment.Bottom:
|
case VerticalAlignment.Bottom:
|
||||||
rect.Y = parentSize.Height - rect.Height;
|
y = parentSize.Height - size.Height;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VerticalAlignment.Stretch:
|
case VerticalAlignment.Stretch:
|
||||||
rect.Height = parentSize.Height;
|
height = parentSize.Height;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrangeElement(element, rect);
|
ArrangeElement(element, new Rect(x, y, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ArrangeElement(FrameworkElement element, ViewRect rect)
|
private static void ArrangeElement(FrameworkElement element, ViewRect rect)
|
||||||
{
|
{
|
||||||
element.Width = rect.Width;
|
element.Width = rect.Rect.Width;
|
||||||
element.Height = rect.Height;
|
element.Height = rect.Rect.Height;
|
||||||
|
|
||||||
ArrangeElement(element, new Rect(rect.X, rect.Y, rect.Width, rect.Height));
|
ArrangeElement(element, rect.Rect);
|
||||||
|
|
||||||
if (element.RenderTransform is RotateTransform rotateTransform)
|
if (element.RenderTransform is RotateTransform rotateTransform)
|
||||||
{
|
{
|
||||||
|
|
@ -359,10 +369,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (element.UseLayoutRounding)
|
if (element.UseLayoutRounding)
|
||||||
{
|
{
|
||||||
rect.X = Math.Round(rect.X);
|
rect = new Rect(Math.Round(rect.X), Math.Round(rect.Y), Math.Round(rect.Width), Math.Round(rect.Height));
|
||||||
rect.Y = Math.Round(rect.Y);
|
|
||||||
rect.Width = Math.Round(rect.Width);
|
|
||||||
rect.Height = Math.Round(rect.Height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
element.Arrange(rect);
|
element.Arrange(rect);
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ namespace MapControl
|
||||||
public const double Wgs84Flattening = 1d / 298.257223563;
|
public const double Wgs84Flattening = 1d / 298.257223563;
|
||||||
public static readonly double Wgs84Eccentricity = Math.Sqrt((2d - Wgs84Flattening) * Wgs84Flattening);
|
public static readonly double Wgs84Eccentricity = Math.Sqrt((2d - Wgs84Flattening) * Wgs84Flattening);
|
||||||
|
|
||||||
public static MapProjectionFactory Factory { get; set; } = new MapProjectionFactory();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the projection.
|
/// Gets the type of the projection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -49,7 +47,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the relative map scale at the specified Location.
|
/// Gets the relative map scale at the specified Location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Scale GetRelativeScale(Location location) => new Scale(1d, 1d);
|
public virtual Point GetRelativeScale(Location location) => new Point(1d, 1d);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Location in geographic coordinates to a Point in projected map coordinates.
|
/// Transforms a Location in geographic coordinates to a Point in projected map coordinates.
|
||||||
|
|
@ -64,12 +62,12 @@ namespace MapControl
|
||||||
public abstract Location MapToLocation(Point point);
|
public abstract Location MapToLocation(Point point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a BoundingBox in geographic coordinates to a MapRect in projected map coordinates.
|
/// Transforms a BoundingBox in geographic coordinates to a Rect in projected map coordinates.
|
||||||
/// Returns null when the BoundingBox can not be transformed.
|
/// Returns null when the BoundingBox can not be transformed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual MapRect BoundingBoxToMapRect(BoundingBox boundingBox)
|
public virtual Rect? BoundingBoxToMap(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
MapRect mapRect = null;
|
Rect? rect = null;
|
||||||
|
|
||||||
if (boundingBox.South < boundingBox.North && boundingBox.West < boundingBox.East)
|
if (boundingBox.South < boundingBox.North && boundingBox.West < boundingBox.East)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +76,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (p1.HasValue && p2.HasValue)
|
if (p1.HasValue && p2.HasValue)
|
||||||
{
|
{
|
||||||
mapRect = new MapRect(p1.Value, p2.Value);
|
rect = new Rect(p1.Value, p2.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (boundingBox.Center != null)
|
else if (boundingBox.Center != null)
|
||||||
|
|
@ -94,21 +92,21 @@ namespace MapControl
|
||||||
var x = center.Value.X - width / 2d;
|
var x = center.Value.X - width / 2d;
|
||||||
var y = center.Value.Y - height / 2d;
|
var y = center.Value.Y - height / 2d;
|
||||||
|
|
||||||
mapRect = new MapRect(x, y, x + width, y + height);
|
rect = new Rect(x, y, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapRect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a MapRect in projected map coordinates to a BoundingBox in geographic coordinates.
|
/// Transforms a Rect in projected map coordinates to a BoundingBox in geographic coordinates.
|
||||||
/// Returns null when the MapRect can not be transformed.
|
/// Returns null when the MapRect can not be transformed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual BoundingBox MapRectToBoundingBox(MapRect mapRect)
|
public virtual BoundingBox MapToBoundingBox(Rect rect)
|
||||||
{
|
{
|
||||||
var southWest = MapToLocation(new Point(mapRect.XMin, mapRect.YMin));
|
var southWest = MapToLocation(new Point(rect.X, rect.Y));
|
||||||
var northEast = MapToLocation(new Point(mapRect.XMax, mapRect.YMax));
|
var northEast = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
||||||
|
|
||||||
return southWest != null && northEast != null
|
return southWest != null && northEast != null
|
||||||
? new BoundingBox(southWest, northEast)
|
? new BoundingBox(southWest, northEast)
|
||||||
|
|
@ -128,16 +126,16 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the BBOX parameter value for a WMS GetMap request.
|
/// Gets the BBOX parameter value for a WMS GetMap request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string GetBboxValue(MapRect mapRect)
|
public virtual string GetBboxValue(Rect rect)
|
||||||
{
|
{
|
||||||
// Truncate values for seamless stitching of two WMS images at 180° longitude,
|
// Truncate values for seamless stitching of two WMS images at 180° longitude,
|
||||||
// as done in WmsImageLayer.GetImageAsync.
|
// as done in WmsImageLayer.GetImageAsync.
|
||||||
//
|
//
|
||||||
return string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F2}",
|
return string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F2}",
|
||||||
0.01 * Math.Ceiling(100d * mapRect.XMin),
|
0.01 * Math.Ceiling(100d * rect.X),
|
||||||
0.01 * Math.Ceiling(100d * mapRect.YMin),
|
0.01 * Math.Ceiling(100d * rect.Y),
|
||||||
0.01 * Math.Floor(100d * mapRect.XMax),
|
0.01 * Math.Floor(100d * (rect.X + rect.Width)),
|
||||||
0.01 * Math.Floor(100d * mapRect.YMax));
|
0.01 * Math.Floor(100d * (rect.Y + rect.Height)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,14 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public class MapProjectionFactory
|
public class MapProjectionFactory
|
||||||
{
|
{
|
||||||
|
private static MapProjectionFactory instance;
|
||||||
|
|
||||||
|
public static MapProjectionFactory Instance
|
||||||
|
{
|
||||||
|
get => instance ?? (instance = new MapProjectionFactory());
|
||||||
|
set => instance = value;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual MapProjection GetProjection(int epsgCode)
|
public virtual MapProjection GetProjection(int epsgCode)
|
||||||
{
|
{
|
||||||
MapProjection projection = null;
|
MapProjection projection = null;
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// Copyright © 2024 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
#if !WINUI && !UWP
|
|
||||||
using System.Windows;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Map rectangle with double floating point precision, in contrast to Windows.Foundation.Rect.
|
|
||||||
/// Used by MapProjection when converting geographic bounding boxes to/from projected map coordinates.
|
|
||||||
/// </summary>
|
|
||||||
public class MapRect
|
|
||||||
{
|
|
||||||
public MapRect(double x1, double y1, double x2, double y2)
|
|
||||||
{
|
|
||||||
XMin = Math.Min(x1, x2);
|
|
||||||
YMin = Math.Min(y1, y2);
|
|
||||||
XMax = Math.Max(x1, x2);
|
|
||||||
YMax = Math.Max(y1, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapRect(Point point1, Point point2)
|
|
||||||
: this(point1.X, point1.Y, point2.X, point2.Y)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public double XMin { get; }
|
|
||||||
public double YMin { get; }
|
|
||||||
public double XMax { get; }
|
|
||||||
public double YMax { get; }
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -23,11 +23,6 @@ using System.Windows.Threading;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public interface ITileImageLoader
|
|
||||||
{
|
|
||||||
Task LoadTilesAsync(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class MapTileLayerBase : Panel, IMapLayer
|
public abstract class MapTileLayerBase : Panel, IMapLayer
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register(
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace MapControl
|
||||||
public double FalseNorthing { get; set; } = 2e6;
|
public double FalseNorthing { get; set; } = 2e6;
|
||||||
public bool IsNorth { get; set; }
|
public bool IsNorth { get; set; }
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var lat = location.Latitude * Math.PI / 180d;
|
var lat = location.Latitude * Math.PI / 180d;
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace MapControl
|
||||||
var m = Math.Cos(lat) / Math.Sqrt(1d - eSinLat * eSinLat); // p.160 (14-15)
|
var m = Math.Cos(lat) / Math.Sqrt(1d - eSinLat * eSinLat); // p.160 (14-15)
|
||||||
var k = r / (EquatorialRadius * m); // p.161 (21-32)
|
var k = r / (EquatorialRadius * m); // p.161 (21-32)
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point? LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// Copyright © 2024 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public readonly struct Scale
|
|
||||||
{
|
|
||||||
public Scale(double x, double y)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double X { get; }
|
|
||||||
public double Y { get; }
|
|
||||||
|
|
||||||
public static Scale operator *(double f, Scale v)
|
|
||||||
{
|
|
||||||
return new Scale(f * v.X, f * v.Y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,21 +3,19 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if WINUI
|
#if AVALONIA
|
||||||
using Microsoft.UI.Xaml;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using ImageSource = Avalonia.Media.IImage;
|
||||||
|
#elif WINUI
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
|
||||||
#elif UWP
|
#elif UWP
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Animation;
|
|
||||||
#else
|
#else
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Animation;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
|
|
@ -56,16 +54,5 @@ namespace MapControl
|
||||||
AnimateImageOpacity();
|
AnimateImageOpacity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BeginOpacityAnimation()
|
|
||||||
{
|
|
||||||
Image.BeginAnimation(UIElement.OpacityProperty,
|
|
||||||
new DoubleAnimation
|
|
||||||
{
|
|
||||||
From = 0d,
|
|
||||||
Duration = MapBase.ImageFadeDuration,
|
|
||||||
FillBehavior = FillBehavior.Stop
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -19,6 +18,11 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads and optionally caches map tile images for a MapTileLayer.
|
/// Loads and optionally caches map tile images for a MapTileLayer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
public interface ITileImageLoader
|
||||||
|
{
|
||||||
|
Task LoadTilesAsync(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress);
|
||||||
|
}
|
||||||
|
|
||||||
public partial class TileImageLoader : ITileImageLoader
|
public partial class TileImageLoader : ITileImageLoader
|
||||||
{
|
{
|
||||||
private class TileQueue : ConcurrentStack<Tile>
|
private class TileQueue : ConcurrentStack<Tile>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
#if WINUI
|
#if AVALONIA
|
||||||
|
using ImageSource = Avalonia.Media.IImage;
|
||||||
|
#elif WINUI
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace MapControl
|
||||||
public double FalseEasting { get; set; }
|
public double FalseEasting { get; set; }
|
||||||
public double FalseNorthing { get; set; }
|
public double FalseNorthing { get; set; }
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var k = ScaleFactor;
|
var k = ScaleFactor;
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace MapControl
|
||||||
+ (61d - 148d * T + 16d * T_2) * A_6 / 720d); // p.61 (8-11)
|
+ (61d - 148d * T + 16d * T_2) * A_6 / 720d); // p.61 (8-11)
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point? LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,24 @@
|
||||||
// Copyright © 2024 Clemens Fischer
|
// Copyright © 2024 Clemens Fischer
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
#if !WINUI && !UWP
|
||||||
|
using System.Windows;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rotated rectangle used to arrange and rotate an element with a BoundingBox.
|
/// Rotated rectangle used to arrange and rotate an element with a BoundingBox.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ViewRect
|
public readonly struct ViewRect
|
||||||
{
|
{
|
||||||
public ViewRect(double x, double y, double width, double height, double rotation)
|
public ViewRect(double x, double y, double width, double height, double rotation)
|
||||||
{
|
{
|
||||||
X = x;
|
Rect = new Rect(x, y, width, height);
|
||||||
Y = y;
|
|
||||||
Width = width;
|
|
||||||
Height = height;
|
|
||||||
Rotation = rotation;
|
Rotation = rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double X { get; }
|
public Rect Rect { get; }
|
||||||
public double Y { get; }
|
|
||||||
public double Width { get; }
|
|
||||||
public double Height { get; }
|
|
||||||
public double Rotation { get; }
|
public double Rotation { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point? LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
|
|
|
||||||
|
|
@ -239,9 +239,9 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual string GetMapRequestUri(BoundingBox boundingBox)
|
protected virtual string GetMapRequestUri(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
|
var rect = ParentMap.MapProjection.BoundingBoxToMap(boundingBox);
|
||||||
|
|
||||||
if (mapRect == null)
|
if (!rect.HasValue)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -257,9 +257,9 @@ namespace MapControl
|
||||||
{ "STYLES", Styles ?? "" },
|
{ "STYLES", Styles ?? "" },
|
||||||
{ "FORMAT", "image/png" },
|
{ "FORMAT", "image/png" },
|
||||||
{ "CRS", GetCrsValue() },
|
{ "CRS", GetCrsValue() },
|
||||||
{ "BBOX", GetBboxValue(mapRect) },
|
{ "BBOX", GetBboxValue(rect.Value) },
|
||||||
{ "WIDTH", Math.Round(viewScale * mapRect.Width).ToString("F0") },
|
{ "WIDTH", Math.Round(viewScale * rect.Value.Width).ToString("F0") },
|
||||||
{ "HEIGHT", Math.Round(viewScale * mapRect.Height).ToString("F0") }
|
{ "HEIGHT", Math.Round(viewScale * rect.Value.Height).ToString("F0") }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,18 +270,18 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var viewSize = ParentMap.RenderSize;
|
var viewSize = ParentMap.RenderSize;
|
||||||
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
||||||
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
|
var rect = ParentMap.MapProjection.BoundingBoxToMap(boundingBox);
|
||||||
|
|
||||||
if (mapRect == null)
|
if (!rect.HasValue)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewRect = GetViewRect(mapRect);
|
var viewRect = GetViewRect(rect.Value);
|
||||||
|
|
||||||
var transform = new Matrix(1, 0, 0, 1, -viewSize.Width / 2, -viewSize.Height / 2);
|
var transform = new Matrix(1d, 0d, 0d, 1d, -viewSize.Width / 2d, -viewSize.Height / 2d);
|
||||||
transform.Rotate(-viewRect.Rotation);
|
transform.Rotate(-viewRect.Rotation);
|
||||||
transform.Translate(viewRect.Width / 2, viewRect.Height / 2);
|
transform.Translate(viewRect.Rect.Width / 2d, viewRect.Rect.Height / 2d);
|
||||||
|
|
||||||
var imagePos = transform.Transform(position);
|
var imagePos = transform.Transform(position);
|
||||||
|
|
||||||
|
|
@ -295,9 +295,9 @@ namespace MapControl
|
||||||
{ "FORMAT", "image/png" },
|
{ "FORMAT", "image/png" },
|
||||||
{ "INFO_FORMAT", format },
|
{ "INFO_FORMAT", format },
|
||||||
{ "CRS", GetCrsValue() },
|
{ "CRS", GetCrsValue() },
|
||||||
{ "BBOX", GetBboxValue(mapRect) },
|
{ "BBOX", GetBboxValue(rect.Value) },
|
||||||
{ "WIDTH", Math.Round(viewRect.Width).ToString("F0") },
|
{ "WIDTH", Math.Round(viewRect.Rect.Width).ToString("F0") },
|
||||||
{ "HEIGHT", Math.Round(viewRect.Height).ToString("F0") },
|
{ "HEIGHT", Math.Round(viewRect.Rect.Height).ToString("F0") },
|
||||||
{ "I", Math.Round(imagePos.X).ToString("F0") },
|
{ "I", Math.Round(imagePos.X).ToString("F0") },
|
||||||
{ "J", Math.Round(imagePos.Y).ToString("F0") }
|
{ "J", Math.Round(imagePos.Y).ToString("F0") }
|
||||||
};
|
};
|
||||||
|
|
@ -310,9 +310,9 @@ namespace MapControl
|
||||||
return ParentMap.MapProjection.GetCrsValue();
|
return ParentMap.MapProjection.GetCrsValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string GetBboxValue(MapRect mapRect)
|
protected virtual string GetBboxValue(Rect rect)
|
||||||
{
|
{
|
||||||
return ParentMap.MapProjection.GetBboxValue(mapRect);
|
return ParentMap.MapProjection.GetBboxValue(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string GetRequestUri(IDictionary<string, string> queryParameters)
|
protected string GetRequestUri(IDictionary<string, string> queryParameters)
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var lat = location.Latitude * Math.PI / 180d;
|
var lat = location.Latitude * Math.PI / 180d;
|
||||||
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
||||||
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point? LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
|
|
|
||||||
|
|
@ -140,9 +140,6 @@
|
||||||
<Compile Include="..\Shared\MapProjectionFactory.cs">
|
<Compile Include="..\Shared\MapProjectionFactory.cs">
|
||||||
<Link>MapProjectionFactory.cs</Link>
|
<Link>MapProjectionFactory.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\Shared\MapRect.cs">
|
|
||||||
<Link>MapRect.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Shared\MapScale.cs">
|
<Compile Include="..\Shared\MapScale.cs">
|
||||||
<Link>MapScale.cs</Link>
|
<Link>MapScale.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -164,9 +161,6 @@
|
||||||
<Compile Include="..\Shared\PushpinBorder.cs">
|
<Compile Include="..\Shared\PushpinBorder.cs">
|
||||||
<Link>PushpinBorder.cs</Link>
|
<Link>PushpinBorder.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\Shared\Scale.cs">
|
|
||||||
<Link>Scale.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Shared\StereographicProjection.cs">
|
<Compile Include="..\Shared\StereographicProjection.cs">
|
||||||
<Link>StereographicProjection.cs</Link>
|
<Link>StereographicProjection.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -272,6 +266,9 @@
|
||||||
<Compile Include="..\WinUI\PushpinBorder.WinUI.cs">
|
<Compile Include="..\WinUI\PushpinBorder.WinUI.cs">
|
||||||
<Link>PushpinBorder.WinUI.cs</Link>
|
<Link>PushpinBorder.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\WinUI\Rect.WinUI.cs">
|
||||||
|
<Link>Rect.WinUI.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\WinUI\Tile.WinUI.cs">
|
<Compile Include="..\WinUI\Tile.WinUI.cs">
|
||||||
<Link>Tile.WinUI.cs</Link>
|
<Link>Tile.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public static partial class ImageLoader
|
public static partial class ImageLoader
|
||||||
{
|
{
|
||||||
|
public static ImageSource LoadImage(Uri uri)
|
||||||
|
{
|
||||||
|
return new BitmapImage(uri);
|
||||||
|
}
|
||||||
|
|
||||||
public static ImageSource LoadImage(Stream stream)
|
public static ImageSource LoadImage(Stream stream)
|
||||||
{
|
{
|
||||||
var image = new BitmapImage();
|
var image = new BitmapImage();
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,18 @@ namespace MapControl
|
||||||
|
|
||||||
if (projection != null && items != null)
|
if (projection != null && items != null)
|
||||||
{
|
{
|
||||||
var mapRect = projection.BoundingBoxToMapRect(boundingBox);
|
var rect = projection.BoundingBoxToMap(boundingBox);
|
||||||
|
|
||||||
if (mapRect != null)
|
if (rect.HasValue)
|
||||||
{
|
{
|
||||||
image = await Task.Run(() => GetImage(projection, mapRect, items));
|
image = await Task.Run(() => GetImage(projection, rect.Value, items));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DrawingImage GetImage(MapProjection projection, MapRect mapRect, IEnumerable<IMapDrawingItem> items)
|
private DrawingImage GetImage(MapProjection projection, Rect rect, IEnumerable<IMapDrawingItem> items)
|
||||||
{
|
{
|
||||||
var scale = ParentMap.ViewTransform.Scale;
|
var scale = ParentMap.ViewTransform.Scale;
|
||||||
var rotation = ParentMap.ViewTransform.Rotation;
|
var rotation = ParentMap.ViewTransform.Rotation;
|
||||||
|
|
@ -62,13 +62,13 @@ namespace MapControl
|
||||||
.Select(point => point.Value)
|
.Select(point => point.Value)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (points.Any(point => mapRect.Contains(point)))
|
if (points.Any(point => rect.Contains(point)))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < points.Count; i++)
|
for (int i = 0; i < points.Count; i++)
|
||||||
{
|
{
|
||||||
points[i] = new Point(
|
points[i] = new Point(
|
||||||
scale * (points[i].X - mapRect.XMin),
|
scale * (points[i].X - rect.X),
|
||||||
scale * (mapRect.YMax - points[i].Y));
|
scale * ((rect.Y + rect.Height) - points[i].Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawings.Children.Add(item.GetDrawing(points, scale, rotation));
|
drawings.Children.Add(item.GetDrawing(points, scale, rotation));
|
||||||
|
|
@ -79,7 +79,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
Drawing = drawings,
|
Drawing = drawings,
|
||||||
ViewboxUnits = BrushMappingMode.Absolute,
|
ViewboxUnits = BrushMappingMode.Absolute,
|
||||||
Viewbox = new Rect(0, 0, scale * mapRect.Width, scale * mapRect.Height),
|
Viewbox = new Rect(0, 0, scale * rect.Width, scale * rect.Height),
|
||||||
};
|
};
|
||||||
|
|
||||||
var drawing = new GeometryDrawing(
|
var drawing = new GeometryDrawing(
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,27 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
|
private void BeginOpacityAnimation()
|
||||||
|
{
|
||||||
|
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||||
|
new DoubleAnimation
|
||||||
|
{
|
||||||
|
From = 0d,
|
||||||
|
Duration = MapBase.ImageFadeDuration,
|
||||||
|
FillBehavior = FillBehavior.Stop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void AnimateImageOpacity()
|
private void AnimateImageOpacity()
|
||||||
{
|
{
|
||||||
if (Image.Source is BitmapSource bitmap && bitmap.IsDownloading && !bitmap.IsFrozen)
|
if (Image.Source is BitmapSource bitmap && bitmap.IsDownloading && !bitmap.IsFrozen)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public static partial class ImageLoader
|
public static partial class ImageLoader
|
||||||
{
|
{
|
||||||
|
public static ImageSource LoadImage(Uri uri)
|
||||||
|
{
|
||||||
|
return new BitmapImage(uri);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<WriteableBitmap> LoadImageAsync(BitmapDecoder decoder)
|
public static async Task<WriteableBitmap> LoadImageAsync(BitmapDecoder decoder)
|
||||||
{
|
{
|
||||||
var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
|
var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces Windows.Foundation.Point for double floating point precision.
|
/// Replaces Windows.Foundation.Point for double floating point precision.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct Point
|
public readonly struct Point
|
||||||
{
|
{
|
||||||
public Point(double x, double y)
|
public Point(double x, double y)
|
||||||
{
|
{
|
||||||
|
|
@ -15,8 +15,8 @@ namespace MapControl
|
||||||
Y = y;
|
Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double X { get; set; }
|
public double X { get; }
|
||||||
public double Y { get; set; }
|
public double Y { get; }
|
||||||
|
|
||||||
public static implicit operator Windows.Foundation.Point(Point p)
|
public static implicit operator Windows.Foundation.Point(Point p)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
43
MapControl/WinUI/Rect.WinUI.cs
Normal file
43
MapControl/WinUI/Rect.WinUI.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// Copyright © 2024 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces Windows.Foundation.Rect for double floating point precision.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct Rect
|
||||||
|
{
|
||||||
|
public Rect(double x, double y, double width, double height)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Rect(Point p1, Point p2)
|
||||||
|
: this(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public double X { get; }
|
||||||
|
public double Y { get; }
|
||||||
|
public double Width { get; }
|
||||||
|
public double Height { get; }
|
||||||
|
|
||||||
|
public bool Contains(Point p) => p.X >= X && p.X <= X + Width && p.Y >= Y && p.Y <= Y + Height;
|
||||||
|
|
||||||
|
public static implicit operator Windows.Foundation.Rect(Rect r)
|
||||||
|
{
|
||||||
|
return new Windows.Foundation.Rect(r.X, r.Y, r.Width, r.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Rect(Windows.Foundation.Rect r)
|
||||||
|
{
|
||||||
|
return new Rect(r.X, r.Y, r.Width, r.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
|
|
||||||
#if WINUI
|
#if WINUI
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
#else
|
#else
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Media.Animation;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -14,6 +16,17 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
|
private void BeginOpacityAnimation()
|
||||||
|
{
|
||||||
|
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||||
|
new DoubleAnimation
|
||||||
|
{
|
||||||
|
From = 0d,
|
||||||
|
Duration = MapBase.ImageFadeDuration,
|
||||||
|
FillBehavior = FillBehavior.Stop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void AnimateImageOpacity()
|
private void AnimateImageOpacity()
|
||||||
{
|
{
|
||||||
if (Image.Source is BitmapImage bitmap && bitmap.UriSource != null)
|
if (Image.Source is BitmapImage bitmap && bitmap.UriSource != null)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
using ProjNet.CoordinateSystems;
|
using ProjNet.CoordinateSystems;
|
||||||
using System;
|
using System;
|
||||||
|
#if !WINUI && !UWP
|
||||||
|
using System.Windows;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MapControl.Projections
|
namespace MapControl.Projections
|
||||||
{
|
{
|
||||||
|
|
@ -20,11 +23,11 @@ namespace MapControl.Projections
|
||||||
CoordinateSystem = ProjectedCoordinateSystem.WebMercator;
|
CoordinateSystem = ProjectedCoordinateSystem.WebMercator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
#if !WINUI && !UWP
|
||||||
|
using System.Windows;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MapControl.Projections
|
namespace MapControl.Projections
|
||||||
{
|
{
|
||||||
|
|
@ -41,13 +44,13 @@ namespace MapControl.Projections
|
||||||
+ "AUTHORITY[\"EPSG\",\"3395\"]]";
|
+ "AUTHORITY[\"EPSG\",\"3395\"]]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Scale GetRelativeScale(Location location)
|
public override Point GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var lat = location.Latitude * Math.PI / 180d;
|
var lat = location.Latitude * Math.PI / 180d;
|
||||||
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
||||||
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
||||||
|
|
||||||
return new Scale(k, k);
|
return new Point(k, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ namespace MapControl.UiTools
|
||||||
if (selectedProjection != projection)
|
if (selectedProjection != projection)
|
||||||
{
|
{
|
||||||
selectedProjection = projection;
|
selectedProjection = projection;
|
||||||
Map.MapProjection = MapProjection.Factory.GetProjection(selectedProjection);
|
Map.MapProjection = MapProjectionFactory.Instance.GetProjection(selectedProjection);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateCheckedStates();
|
UpdateCheckedStates();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue