Update map grids

This commit is contained in:
ClemensFischer 2026-02-08 17:18:32 +01:00
parent 80252cbfd0
commit a7e7442d44
6 changed files with 113 additions and 52 deletions

View file

@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.Media;
using System;
using System.Collections.Generic;
@ -80,8 +81,20 @@ namespace MapControl
{
var text = new FormattedText(label.Text,
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground);
var x = label.X + StrokeThickness / 2d + 2d;
var y = label.Y - text.Height / 2d;
var x = label.X +
label.HorizontalAlignment switch
{
HorizontalAlignment.Left => 2d,
HorizontalAlignment.Right => -text.Width - 2d,
_ => -text.Width / 2d
};
var y = label.Y +
label.VerticalAlignment switch
{
VerticalAlignment.Top => 0,
VerticalAlignment.Bottom => -text.Height,
_ => -text.Height / 2d
};
if (label.Rotation != 0d)
{

View file

@ -6,11 +6,14 @@ using System.Linq;
using System.Windows;
using System.Windows.Media;
#elif UWP
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#elif WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
#elif AVALONIA
using Avalonia;
using Avalonia.Layout;
using PathFigureCollection = Avalonia.Media.PathFigures;
#endif
@ -74,6 +77,13 @@ namespace MapControl
var p1 = ParentMap.LocationToView(lat, southWest.Longitude);
var p2 = ParentMap.LocationToView(lat, northEast.Longitude);
figures.Add(CreateLineFigure(p1, p2));
if (ParentMap.ViewTransform.Rotation == 0d)
{
var text = GetLatitudeLabelText(lat, labelFormat);
labels.Add(new Label(text, p1.X, p1.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Bottom));
labels.Add(new Label(text, p2.X, p2.Y, 0d, HorizontalAlignment.Right, VerticalAlignment.Bottom));
}
}
for (var lon = minLon; lon <= northEast.Longitude; lon += lineDistance)
@ -82,9 +92,18 @@ namespace MapControl
var p2 = ParentMap.LocationToView(northEast.Latitude, lon);
figures.Add(CreateLineFigure(p1, p2));
for (var lat = minLat; lat <= northEast.Latitude; lat += lineDistance)
if (ParentMap.ViewTransform.Rotation == 0d)
{
AddLabel(labels, labelFormat, lat, lon, ParentMap.LocationToView(lat, lon), 0d);
var text = GetLongitudeLabelText(lon, labelFormat);
labels.Add(new Label(text, p1.X, p1.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Bottom));
labels.Add(new Label(text, p2.X, p2.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Top));
}
else
{
for (var lat = minLat; lat <= northEast.Latitude; lat += lineDistance)
{
AddLabel(labels, labelFormat, lat, lon, ParentMap.LocationToView(lat, lon), 0d);
}
}
}
}
@ -125,8 +144,14 @@ namespace MapControl
maxLon += lineDistance;
}
minLat = Math.Ceiling(minLat / lineDistance) * lineDistance;
maxLat = Math.Floor(maxLat / lineDistance) * lineDistance;
if (pointDistance < lineDistance)
{
minLat = Math.Ceiling(minLat / lineDistance - 1e-6) * lineDistance;
maxLat = Math.Floor(maxLat / lineDistance + 1e-6) * lineDistance;
}
maxLat += 1e-6;
maxLon += 1e-6;
for (var lat = minLat; lat <= maxLat; lat += lineDistance)
{
@ -209,27 +234,37 @@ namespace MapControl
rotation -= 180d;
}
var text = GetLabelText(lat, labelFormat, "NS") +
"\n" + GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW");
var text = GetLatitudeLabelText(lat, labelFormat) +
"\n" + GetLongitudeLabelText(lon, labelFormat);
labels.Add(new Label(text, position.X, position.Y, rotation));
}
}
static string GetLabelText(double value, string labelFormat, string hemispheres)
private static string GetLatitudeLabelText(double value, string labelFormat)
{
return GetLabelText(value, labelFormat, "NS");
}
private static string GetLongitudeLabelText(double value, string labelFormat)
{
return GetLabelText(Location.NormalizeLongitude(value), labelFormat, "EW");
}
private static string GetLabelText(double value, string labelFormat, string hemispheres)
{
var hemisphere = hemispheres[0];
if (value < -1e-8) // ~1 mm
{
var hemisphere = hemispheres[0];
if (value < -1e-8) // ~1 mm
{
value = -value;
hemisphere = hemispheres[1];
}
var seconds = (int)Math.Round(value * 3600d);
return string.Format(CultureInfo.InvariantCulture,
labelFormat, hemisphere, seconds / 3600, seconds / 60 % 60, seconds % 60);
value = -value;
hemisphere = hemispheres[1];
}
var seconds = (int)Math.Round(value * 3600d);
return string.Format(CultureInfo.InvariantCulture,
labelFormat, hemisphere, seconds / 3600, seconds / 60 % 60, seconds % 60);
}
}
}

View file

@ -11,6 +11,7 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
#elif AVALONIA
using Avalonia;
using Avalonia.Layout;
using Avalonia.Media;
using Brush = Avalonia.Media.IBrush;
using PathFigureCollection = Avalonia.Media.PathFigures;
@ -23,12 +24,16 @@ namespace MapControl
/// </summary>
public abstract partial class MapGrid
{
protected class Label(string text, double x, double y, double rotation)
protected class Label(string text, double x, double y, double rotation,
HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment verticalAlignment = VerticalAlignment.Center)
{
public string Text => text;
public double X => x;
public double Y => y;
public double Rotation => rotation;
public HorizontalAlignment HorizontalAlignment => horizontalAlignment;
public VerticalAlignment VerticalAlignment => verticalAlignment;
}
public static readonly DependencyProperty MinLineDistanceProperty =

View file

@ -4,11 +4,14 @@ using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
#elif UWP
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#elif WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
#elif AVALONIA
using Avalonia;
using Avalonia.Layout;
using PathFigureCollection = Avalonia.Media.PathFigures;
#endif
@ -43,6 +46,10 @@ namespace MapControl
var p1 = ParentMap.ViewTransform.MapToView(new Point(x, mapRect.Y));
var p2 = ParentMap.ViewTransform.MapToView(new Point(x, mapRect.Y + mapRect.Height));
figures.Add(CreateLineFigure(p1, p2));
var text = string.Format("{0:F0}", x);
labels.Add(new Label(text, p1.X, p1.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Bottom));
labels.Add(new Label(text, p2.X, p2.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Top));
}
for (var y = minY; y <= mapRect.Y + mapRect.Height; y += lineDistance)
@ -51,33 +58,9 @@ namespace MapControl
var p2 = ParentMap.ViewTransform.MapToView(new Point(mapRect.X + mapRect.Width, y));
figures.Add(CreateLineFigure(p1, p2));
for (var x = minX; x <= mapRect.X + mapRect.Width; x += lineDistance)
{
AddLabel(labels, x, y);
}
}
}
private void AddLabel(List<Label> labels, double x, double y)
{
var position = ParentMap.ViewTransform.MapToView(new Point(x, y));
if (ParentMap.InsideViewBounds(position))
{
var rotation = ParentMap.ViewTransform.Rotation;
if (rotation < -90d)
{
rotation += 180d;
}
else if (rotation > 90d)
{
rotation -= 180d;
}
var text = string.Format("{0:F0}\n{1:F0}", y, x);
labels.Add(new Label(text, position.X, position.Y, rotation));
var text = string.Format("{0:F0}", y);
labels.Add(new Label(text, p1.X, p1.Y, 0d, HorizontalAlignment.Left, VerticalAlignment.Bottom));
labels.Add(new Label(text, p2.X, p2.Y, 0d, HorizontalAlignment.Right, VerticalAlignment.Bottom));
}
}
}

View file

@ -74,8 +74,20 @@ namespace MapControl
{
var text = new FormattedText(label.Text,
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, FontSize, Foreground, pixelsPerDip);
var x = label.X + StrokeThickness / 2d + 2d;
var y = label.Y - text.Height / 2d;
var x = label.X +
label.HorizontalAlignment switch
{
HorizontalAlignment.Left => 2d,
HorizontalAlignment.Right => -text.Width - 2d,
_ => -text.Width / 2d
};
var y = label.Y +
label.VerticalAlignment switch
{
VerticalAlignment.Top => 0,
VerticalAlignment.Bottom => -text.Height,
_ => -text.Height / 2d
};
if (label.Rotation != 0d)
{

View file

@ -96,8 +96,21 @@ namespace MapControl
textBlock.Text = label.Text;
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var x = label.HorizontalAlignment switch
{
HorizontalAlignment.Left => 2d,
HorizontalAlignment.Right => -textBlock.DesiredSize.Width - 2d,
_ => -textBlock.DesiredSize.Width / 2d
};
var y = label.VerticalAlignment switch
{
VerticalAlignment.Top => 0d,
VerticalAlignment.Bottom => -textBlock.DesiredSize.Height,
_ => -textBlock.DesiredSize.Height / 2d,
};
var matrix = new Matrix(1, 0, 0, 1, 0, 0);
matrix.Translate(StrokeThickness / 2d + 2d, -textBlock.DesiredSize.Height / 2d);
matrix.Translate(x, y);
matrix.Rotate(label.Rotation);
matrix.Translate(label.X, label.Y);