2021-01-13 21:19:27 +01:00
|
|
|
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
2024-02-03 21:01:53 +01:00
|
|
|
|
// Copyright © 2024 Clemens Fischer
|
2020-03-26 19:08:20 +01:00
|
|
|
|
// Licensed under the Microsoft Public License (Ms-PL)
|
|
|
|
|
|
|
2020-03-28 21:53:38 +01:00
|
|
|
|
using System;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#if WPF
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Media;
|
2021-11-17 23:17:11 +01:00
|
|
|
|
#elif UWP
|
2020-03-26 19:08:20 +01:00
|
|
|
|
using Windows.Foundation;
|
|
|
|
|
|
using Windows.UI.Xaml.Media;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#elif WINUI
|
|
|
|
|
|
using Windows.Foundation;
|
|
|
|
|
|
using Microsoft.UI.Xaml.Media;
|
2020-03-26 19:08:20 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
namespace MapControl
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Defines the transformation between projected map coordinates in meters
|
2020-03-28 21:53:38 +01:00
|
|
|
|
/// and view coordinates in pixels.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class ViewTransform
|
|
|
|
|
|
{
|
2020-04-01 18:04:39 +02:00
|
|
|
|
public static double ZoomLevelToScale(double zoomLevel)
|
|
|
|
|
|
{
|
2022-03-02 22:03:18 +01:00
|
|
|
|
return 256d * Math.Pow(2d, zoomLevel) / (360d * MapProjection.Wgs84MeterPerDegree);
|
2020-04-01 18:04:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static double ScaleToZoomLevel(double scale)
|
|
|
|
|
|
{
|
2022-03-02 22:03:18 +01:00
|
|
|
|
return Math.Log(scale * 360d * MapProjection.Wgs84MeterPerDegree / 256d, 2d);
|
2020-04-01 18:04:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Gets the scaling factor from projected map coordinates to view coordinates,
|
2022-11-07 21:10:10 +01:00
|
|
|
|
/// as pixels per meter.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
public double Scale { get; private set; }
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
/// Gets the rotation angle of the transform matrix.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
public double Rotation { get; private set; }
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Gets the transform matrix from projected map coordinates to view coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
public Matrix MapToViewMatrix { get; private set; }
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Gets the transform matrix from view coordinates to projected map coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
public Matrix ViewToMapMatrix { get; private set; }
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Initializes a ViewTransform from a map center point in projected coordinates,
|
|
|
|
|
|
/// a view conter point, a scaling factor from projected coordinates to view coordinates
|
|
|
|
|
|
/// and a rotation angle in degrees.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void SetTransform(Point mapCenter, Point viewCenter, double scale, double rotation)
|
|
|
|
|
|
{
|
|
|
|
|
|
Scale = scale;
|
|
|
|
|
|
Rotation = ((rotation % 360d) + 360d) % 360d;
|
|
|
|
|
|
|
|
|
|
|
|
var transform = new Matrix(scale, 0d, 0d, -scale, -scale * mapCenter.X, scale * mapCenter.Y);
|
|
|
|
|
|
transform.Rotate(Rotation);
|
|
|
|
|
|
transform.Translate(viewCenter.X, viewCenter.Y);
|
|
|
|
|
|
|
|
|
|
|
|
MapToViewMatrix = transform;
|
|
|
|
|
|
|
|
|
|
|
|
transform.Invert();
|
|
|
|
|
|
|
|
|
|
|
|
ViewToMapMatrix = transform;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Transforms a Point from projected map coordinates to view coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Point MapToView(Point point)
|
|
|
|
|
|
{
|
|
|
|
|
|
return MapToViewMatrix.Transform(point);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2022-11-05 17:32:29 +01:00
|
|
|
|
/// Transforms a Point from view coordinates to projected map coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Point ViewToMap(Point point)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ViewToMapMatrix.Transform(point);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets scaling factors from meters to view coordinates for a relative map scale.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Point GetMapScale(Point relativeScale)
|
2020-03-26 19:08:20 +01:00
|
|
|
|
{
|
2024-05-22 09:42:21 +02:00
|
|
|
|
return new Point(Scale * relativeScale.X, Scale * relativeScale.Y);
|
|
|
|
|
|
}
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets a transform Matrix from meters to view coordinates for a relative map scale.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Matrix GetMapTransform(Point relativeScale)
|
|
|
|
|
|
{
|
|
|
|
|
|
var scale = GetMapScale(relativeScale);
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
var transform = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d);
|
|
|
|
|
|
transform.Rotate(Rotation);
|
2020-03-26 19:08:20 +01:00
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
return transform;
|
2020-03-26 19:08:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the transform Matrix for the RenderTranform of a MapTileLayer.
|
|
|
|
|
|
/// </summary>
|
2020-03-26 19:08:20 +01:00
|
|
|
|
public Matrix GetTileLayerTransform(double tileMatrixScale, Point tileMatrixTopLeft, Point tileMatrixOrigin)
|
|
|
|
|
|
{
|
2022-11-30 22:18:45 +01:00
|
|
|
|
// Tile matrix origin in map coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
//
|
|
|
|
|
|
var mapOrigin = new Point(
|
|
|
|
|
|
tileMatrixTopLeft.X + tileMatrixOrigin.X / tileMatrixScale,
|
|
|
|
|
|
tileMatrixTopLeft.Y - tileMatrixOrigin.Y / tileMatrixScale);
|
|
|
|
|
|
|
2022-11-30 22:18:45 +01:00
|
|
|
|
// Tile matrix origin in view coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
//
|
|
|
|
|
|
var viewOrigin = MapToView(mapOrigin);
|
|
|
|
|
|
|
2024-05-18 22:03:22 +02:00
|
|
|
|
var transformScale = Scale / tileMatrixScale;
|
|
|
|
|
|
|
|
|
|
|
|
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
|
|
|
|
|
|
transform.Rotate(Rotation);
|
2020-03-26 19:08:20 +01:00
|
|
|
|
transform.Translate(viewOrigin.X, viewOrigin.Y);
|
|
|
|
|
|
|
|
|
|
|
|
return transform;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 09:42:21 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the index bounds of a tile matrix.
|
|
|
|
|
|
/// </summary>
|
2020-03-28 21:53:38 +01:00
|
|
|
|
public Rect GetTileMatrixBounds(double tileMatrixScale, Point tileMatrixTopLeft, Size viewSize)
|
2020-03-26 19:08:20 +01:00
|
|
|
|
{
|
2022-11-30 22:18:45 +01:00
|
|
|
|
// View origin in map coordinates.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
//
|
|
|
|
|
|
var origin = ViewToMap(new Point());
|
|
|
|
|
|
|
2024-05-18 22:03:22 +02:00
|
|
|
|
var transformScale = tileMatrixScale / Scale;
|
|
|
|
|
|
|
|
|
|
|
|
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
|
|
|
|
|
|
transform.Rotate(-Rotation);
|
|
|
|
|
|
|
2022-11-30 22:18:45 +01:00
|
|
|
|
// Translate origin to tile matrix origin in pixels.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
//
|
|
|
|
|
|
transform.Translate(
|
|
|
|
|
|
tileMatrixScale * (origin.X - tileMatrixTopLeft.X),
|
|
|
|
|
|
tileMatrixScale * (tileMatrixTopLeft.Y - origin.Y));
|
|
|
|
|
|
|
2022-11-30 22:18:45 +01:00
|
|
|
|
// Transform view bounds to tile pixel bounds.
|
2020-03-26 19:08:20 +01:00
|
|
|
|
//
|
|
|
|
|
|
return new MatrixTransform { Matrix = transform }
|
2020-03-28 21:53:38 +01:00
|
|
|
|
.TransformBounds(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
|
|
|
|
|
}
|
2024-05-22 09:42:21 +02:00
|
|
|
|
|
|
|
|
|
|
internal static Matrix CreateTransformMatrix(
|
|
|
|
|
|
double translation1X, double translation1Y,
|
|
|
|
|
|
double rotation,
|
|
|
|
|
|
double translation2X, double translation2Y)
|
|
|
|
|
|
{
|
|
|
|
|
|
var transform = new Matrix(1d, 0d, 0d, 1d, translation1X, translation1Y);
|
|
|
|
|
|
transform.Rotate(rotation);
|
|
|
|
|
|
transform.Translate(translation2X, translation2Y);
|
|
|
|
|
|
|
|
|
|
|
|
return transform;
|
|
|
|
|
|
}
|
2020-03-26 19:08:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|