mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-06 15:05:50 +00:00
Updated ViewTransform
This commit is contained in:
parent
9e1c72fda9
commit
03e0258f18
8 changed files with 49 additions and 80 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
107
MapControl/Shared/Matrix.cs
Normal file
107
MapControl/Shared/Matrix.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
#if UWP
|
||||
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/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)
|
||||
{
|
||||
public double M11 { get; private set; } = m11;
|
||||
public double M12 { get; private set; } = m12;
|
||||
public double M21 { get; private set; } = m21;
|
||||
public double M22 { get; private set; } = m22;
|
||||
public double OffsetX { get; private set; } = offsetX;
|
||||
public double OffsetY { get; private set; } = offsetY;
|
||||
|
||||
public static implicit operator Matrix(PlatformMatrix m)
|
||||
{
|
||||
#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 PlatformMatrix(Matrix m)
|
||||
{
|
||||
return new PlatformMatrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
|
||||
}
|
||||
|
||||
public readonly Point Transform(Point p)
|
||||
{
|
||||
return new Point(
|
||||
M11 * p.X + M21 * p.Y + OffsetX,
|
||||
M12 * p.X + M22 * p.Y + OffsetY);
|
||||
}
|
||||
|
||||
public void Translate(double x, double y)
|
||||
{
|
||||
OffsetX += x;
|
||||
OffsetY += y;
|
||||
}
|
||||
|
||||
public void Rotate(double angle)
|
||||
{
|
||||
if (angle != 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,
|
||||
cos * M21 - sin * M22,
|
||||
sin * M21 + cos * M22,
|
||||
cos * OffsetX - sin * OffsetY,
|
||||
sin * OffsetX + cos * OffsetY);
|
||||
}
|
||||
}
|
||||
|
||||
public void Invert()
|
||||
{
|
||||
var invDet = 1d / (M11 * M22 - M12 * M21);
|
||||
|
||||
if (double.IsInfinity(invDet))
|
||||
{
|
||||
throw new InvalidOperationException("Matrix is not invertible.");
|
||||
}
|
||||
|
||||
SetMatrix(
|
||||
invDet * M22, invDet * -M12, invDet * -M21, invDet * M11,
|
||||
invDet * (M21 * OffsetY - M22 * OffsetX),
|
||||
invDet * (M12 * OffsetX - M11 * OffsetY));
|
||||
}
|
||||
|
||||
public void Multiply(Matrix m)
|
||||
{
|
||||
SetMatrix(
|
||||
M11 * m.M11 + M12 * m.M21,
|
||||
M11 * m.M12 + M12 * m.M22,
|
||||
M21 * m.M11 + M22 * m.M21,
|
||||
M21 * m.M12 + M22 * m.M22,
|
||||
OffsetX * m.M11 + OffsetY * m.M21 + m.OffsetX,
|
||||
OffsetX * m.M12 + OffsetY * m.M22 + m.OffsetY);
|
||||
}
|
||||
|
||||
private void SetMatrix(double m11, double m12, double m21, double m22, double offsetX, double offsetY)
|
||||
{
|
||||
M11 = m11;
|
||||
M12 = m12;
|
||||
M21 = m21;
|
||||
M22 = m22;
|
||||
OffsetX = offsetX;
|
||||
OffsetY = offsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue