Updated ViewTransform

This commit is contained in:
ClemensFischer 2026-01-05 21:27:00 +01:00
parent 9e1c72fda9
commit 03e0258f18
8 changed files with 49 additions and 80 deletions

View file

@ -83,9 +83,11 @@ namespace MapControl
var y1 = -StrokeThickness / 2d - latText.Height;
var y2 = StrokeThickness / 2d;
using var pushState = drawingContext.PushTransform(
Matrix.CreateRotation(Matrix.ToRadians(label.Rotation)) *
Matrix.CreateTranslation(label.X, label.Y));
var transform = new Matrix(1d, 0d, 0d, 1d, 0d, 0d);
transform.Rotate(label.Rotation);
transform.Translate(label.X, label.Y);
using var pushState = drawingContext.PushTransform(transform);
drawingContext.DrawText(latText, new Point(x, y1));
drawingContext.DrawText(lonText, new Point(x, y2));

View file

@ -238,32 +238,12 @@ namespace MapControl
return MapProjection.MapToLocation(ViewTransform.ViewToMapMatrix.Transform(point));
}
/// <summary>
/// Gets a Rect in projected map coordinates that covers a rectangle in view coordinates.
/// </summary>
public Rect ViewRectToMap(double x, double y, double width, double height)
{
var viewToMap = 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 new Rect(x1, y1, x2 - x1, y2 - y1);
}
/// <summary>
/// Gets a BoundingBox in geographic coordinates that covers a rectangle in view coordinates.
/// </summary>
public BoundingBox ViewRectToBoundingBox(double x, double y, double width, double height)
public BoundingBox ViewToBoundingBox(Rect rect)
{
return MapProjection.MapToBoundingBox(ViewRectToMap(x, y, width, height));
return MapProjection.MapToBoundingBox(ViewTransform.ViewToMapMatrix.TransformBounds(rect));
}
/// <summary>

View file

@ -171,7 +171,7 @@ namespace MapControl
private void DrawCylindricalGraticule(PathFigureCollection figures, List<Label> labels)
{
var boundingBox = ParentMap.ViewRectToBoundingBox(0d, 0d, ParentMap.ActualWidth, ParentMap.ActualHeight);
var boundingBox = ParentMap.ViewToBoundingBox(new Rect(0d, 0d, ParentMap.ActualWidth, ParentMap.ActualHeight));
var latLabelStart = Math.Ceiling(boundingBox.South / lineDistance) * lineDistance;
var lonLabelStart = Math.Ceiling(boundingBox.West / lineDistance) * lineDistance;

View file

@ -191,8 +191,7 @@ namespace MapControl
var height = ParentMap.ActualHeight * RelativeImageSize;
var x = (ParentMap.ActualWidth - width) / 2d;
var y = (ParentMap.ActualHeight - height) / 2d;
var mapRect = ParentMap.ViewRectToMap(x, y, width, height);
var mapRect = ParentMap.ViewTransform.ViewToMapMatrix.TransformBounds(new Rect(x, y, width, height));
boundingBox = ParentMap.MapProjection.MapToBoundingBox(mapRect);
if (boundingBox != null)

View file

@ -1,14 +1,17 @@
using System;
#if UWP
using WindowsUI = Windows.UI;
#else
using WindowsUI = Microsoft.UI;
using PlatformMatrix = Windows.UI.Xaml.Media.Matrix;
#elif WINUI
using PlatformMatrix = Microsoft.UI.Xaml.Media.Matrix;
#elif AVALONIA
using Avalonia;
using PlatformMatrix = Avalonia.Matrix;
#endif
namespace MapControl
{
/// <summary>
/// Replaces Windows.UI.Xaml.Media.Matrix for double floating point precision.
/// Replaces Windows/Microsoft.UI.Xaml.Media.Matrix to expose manipulation methods.
/// </summary>
public struct Matrix(double m11, double m12, double m21, double m22, double offsetX, double offsetY)
{
@ -19,14 +22,18 @@ namespace MapControl
public double OffsetX { get; private set; } = offsetX;
public double OffsetY { get; private set; } = offsetY;
public static implicit operator WindowsUI.Xaml.Media.Matrix(Matrix m)
public static implicit operator Matrix(PlatformMatrix m)
{
return new WindowsUI.Xaml.Media.Matrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
#if AVALONIA
return new Matrix(m.M11, m.M12, m.M21, m.M22, m.M31, m.M32);
#else
return new Matrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
#endif
}
public static implicit operator Matrix(WindowsUI.Xaml.Media.Matrix m)
public static implicit operator PlatformMatrix(Matrix m)
{
return new Matrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
return new PlatformMatrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
}
public readonly Point Transform(Point p)
@ -44,15 +51,13 @@ namespace MapControl
public void Rotate(double angle)
{
angle = (angle % 360d) / 180d * Math.PI;
if (angle != 0d)
{
var cos = Math.Cos(angle);
var sin = Math.Sin(angle);
// Multiply(new Matrix(cos, sin, -sin, cos, 0d, 0d));
var cos = Math.Cos(angle * Math.PI / 180d);
var sin = Math.Sin(angle * Math.PI / 180d);
// equivalent to Multiply(new Matrix(cos, sin, -sin, cos, 0d, 0d));
//
SetMatrix(
cos * M11 - sin * M12,
sin * M11 + cos * M12,

View file

@ -49,20 +49,12 @@ namespace MapControl
Rotation = ((rotation % 360d) + 360d) % 360d;
var transform = new Matrix(scale, 0d, 0d, -scale, -scale * mapCenter.X, scale * mapCenter.Y);
#if AVALONIA
MapToViewMatrix = transform
* Matrix.CreateRotation(Matrix.ToRadians(Rotation))
* Matrix.CreateTranslation(viewCenter.X, viewCenter.Y);
ViewToMapMatrix = MapToViewMatrix.Invert();
#else
transform.Rotate(Rotation);
transform.Translate(viewCenter.X, viewCenter.Y);
MapToViewMatrix = transform;
transform.Invert();
ViewToMapMatrix = transform;
#endif
}
/// <summary>
@ -71,12 +63,8 @@ namespace MapControl
public Matrix GetMapTransform(Point relativeScale)
{
var transform = new Matrix(Scale * relativeScale.X, 0d, 0d, Scale * relativeScale.Y, 0d, 0d);
#if AVALONIA
return transform * Matrix.CreateRotation(Matrix.ToRadians(Rotation));
#else
transform.Rotate(Rotation);
return transform;
#endif
}
/// <summary>
@ -94,17 +82,11 @@ namespace MapControl
//
var viewOrigin = MapToViewMatrix.Transform(mapOrigin);
var transformScale = Scale / tileMatrixScale;
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
#if AVALONIA
return transform
* Matrix.CreateRotation(Matrix.ToRadians(Rotation))
* Matrix.CreateTranslation(viewOrigin.X, viewOrigin.Y);
#else
var scale = Scale / tileMatrixScale;
var transform = new Matrix(scale, 0d, 0d, scale, 0d, 0d);
transform.Rotate(Rotation);
transform.Translate(viewOrigin.X, viewOrigin.Y);
return transform;
#endif
}
/// <summary>
@ -121,20 +103,25 @@ namespace MapControl
var originOffsetX = tileMatrixScale * (origin.X - tileMatrixTopLeft.X);
var originOffsetY = tileMatrixScale * (tileMatrixTopLeft.Y - origin.Y);
var transformScale = tileMatrixScale / Scale;
var transform = new Matrix(transformScale, 0d, 0d, transformScale, 0d, 0d);
var viewRect = new Rect(0d, 0d, viewWidth, viewHeight);
#if AVALONIA
return viewRect.TransformToAABB(transform
* Matrix.CreateRotation(Matrix.ToRadians(-Rotation))
* Matrix.CreateTranslation(originOffsetX, originOffsetY));
#else
var scale = tileMatrixScale / Scale;
var transform = new Matrix(scale, 0d, 0d, scale, 0d, 0d);
transform.Rotate(-Rotation);
transform.Translate(originOffsetX, originOffsetY);
// Transform view bounds to tile pixel bounds.
//
return new MatrixTransform { Matrix = transform }.TransformBounds(viewRect);
return transform.TransformBounds(new Rect(0d, 0d, viewWidth, viewHeight));
}
}
public static class MatrixExtension
{
public static Rect TransformBounds(this Matrix transform, Rect rect)
{
#if AVALONIA
return rect.TransformToAABB(transform);
#else
return new MatrixTransform { Matrix = transform }.TransformBounds(rect);
#endif
}
}

View file

@ -211,7 +211,6 @@ namespace MapControl
var width2 = bbox.Width - width1;
var bbox1 = new Rect(x, bbox.Y, width1, bbox.Height);
var bbox2 = new Rect(xMin, bbox.Y, width2, bbox.Height);
var uri1 = GetMapRequestUri(bbox1);
var uri2 = GetMapRequestUri(bbox2);
@ -265,21 +264,17 @@ namespace MapControl
{
var width = ParentMap.ActualWidth;
var height = ParentMap.ActualHeight;
var bbox = ParentMap.ViewRectToMap(0d, 0d, width, height);
var bbox = ParentMap.ViewTransform.ViewToMapMatrix.TransformBounds(new Rect(0d, 0d, width, height));
if (ParentMap.ViewTransform.Rotation != 0d)
{
var transform = new Matrix(1d, 0d, 0d, 1d, -width / 2d, -height / 2d);
width = ParentMap.ViewTransform.Scale * bbox.Width;
height = ParentMap.ViewTransform.Scale * bbox.Height;
#if AVALONIA
transform = transform
* Matrix.CreateRotation(Matrix.ToRadians(-ParentMap.ViewTransform.Rotation))
* Matrix.CreateTranslation(width / 2d, height / 2d);
#else
var transform = new Matrix(1d, 0d, 0d, 1d, -ParentMap.ActualWidth / 2d, -ParentMap.ActualHeight / 2d);
transform.Rotate(-ParentMap.ViewTransform.Rotation);
transform.Translate(width / 2d, height / 2d);
#endif
position = transform.Transform(position);
}

View file

@ -17,6 +17,7 @@
</ItemGroup>
<ItemGroup>
<Compile Remove="..\Shared\Matrix.cs" />
<Compile Remove="..\Shared\PolygonCollection.cs" />
</ItemGroup>