XAML-Map-Control/MapControl/MapGraticule.cs

106 lines
4.5 KiB
C#
Raw Normal View History

2012-05-04 12:52:20 +02:00
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
// Copyright © 2012 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
2012-04-25 22:02:53 +02:00
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace MapControl
{
2012-05-04 12:52:20 +02:00
/// <summary>
2012-10-25 08:42:51 +02:00
/// Draws a graticule overlay.
2012-05-04 12:52:20 +02:00
/// </summary>
2012-10-25 08:42:51 +02:00
public class MapGraticule : MapOverlay
2012-04-25 22:02:53 +02:00
{
2012-07-04 17:19:48 +02:00
public static readonly DependencyProperty MinLineSpacingProperty = DependencyProperty.Register(
"MinLineSpacing", typeof(double), typeof(MapGraticule), new FrameworkPropertyMetadata(100d));
2012-04-25 22:02:53 +02:00
2012-10-25 08:42:51 +02:00
/// <summary>
/// Graticule line spacings in degrees.
/// </summary>
public static double[] LineSpacings =
2012-04-25 22:02:53 +02:00
new double[] { 1d / 60d, 1d / 30d, 1d / 12d, 1d / 6d, 1d / 4d, 1d / 3d, 1d / 2d, 1d, 2d, 5d, 10d, 15d, 20d, 30d, 45d };
2012-07-04 17:19:48 +02:00
/// <summary>
/// Minimum spacing in pixels between adjacent graticule lines.
/// </summary>
public double MinLineSpacing
2012-04-25 22:02:53 +02:00
{
2012-07-04 17:19:48 +02:00
get { return (double)GetValue(MinLineSpacingProperty); }
set { SetValue(MinLineSpacingProperty, value); }
2012-04-25 22:02:53 +02:00
}
2012-10-25 08:42:51 +02:00
protected override void OnRender(DrawingContext drawingContext)
2012-04-25 22:02:53 +02:00
{
MapBase parentMap = ParentMap;
2012-05-04 12:52:20 +02:00
Rect bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize));
Location loc1 = parentMap.MapTransform.TransformBack(bounds.TopLeft);
Location loc2 = parentMap.MapTransform.TransformBack(bounds.BottomRight);
2012-07-04 17:19:48 +02:00
double minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d);
2012-10-25 08:42:51 +02:00
double spacing = LineSpacings[LineSpacings.Length - 1];
2012-04-25 22:02:53 +02:00
if (spacing >= minSpacing)
{
2012-10-25 08:42:51 +02:00
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
2012-04-25 22:02:53 +02:00
}
2012-05-04 12:52:20 +02:00
double latitudeStart = Math.Ceiling(loc1.Latitude / spacing) * spacing;
double longitudeStart = Math.Ceiling(loc1.Longitude / spacing) * spacing;
2012-04-25 22:02:53 +02:00
2012-10-25 08:42:51 +02:00
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
2012-04-25 22:02:53 +02:00
{
2012-10-25 08:42:51 +02:00
drawingContext.DrawLine(Pen,
parentMap.LocationToViewportPoint(new Location(lat, loc1.Longitude)),
parentMap.LocationToViewportPoint(new Location(lat, loc2.Longitude)));
2012-04-25 22:02:53 +02:00
}
2012-10-25 08:42:51 +02:00
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
2012-04-25 22:02:53 +02:00
{
2012-10-25 08:42:51 +02:00
drawingContext.DrawLine(Pen,
parentMap.LocationToViewportPoint(new Location(loc1.Latitude, lon)),
parentMap.LocationToViewportPoint(new Location(loc2.Latitude, lon)));
}
2012-04-25 22:02:53 +02:00
2012-10-25 08:42:51 +02:00
if (Foreground != null && Foreground != Brushes.Transparent)
{
string format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
2012-04-25 22:02:53 +02:00
2012-10-25 08:42:51 +02:00
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
2012-04-25 22:02:53 +02:00
{
2012-10-25 08:42:51 +02:00
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
2012-04-25 22:02:53 +02:00
{
2012-10-25 08:42:51 +02:00
double t = StrokeThickness / 2d;
Point p = parentMap.LocationToViewportPoint(new Location(lat, lon));
Point latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
Point lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
string latString = CoordinateString(lat, format, "NS");
string lonString = CoordinateString(Location.NormalizeLongitude(lon), format, "EW");
drawingContext.PushTransform(new RotateTransform(parentMap.Heading, p.X, p.Y));
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(latString, Typeface, FontSize, latPos));
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(lonString, Typeface, FontSize, lonPos));
drawingContext.Pop();
2012-04-25 22:02:53 +02:00
}
}
}
}
private static string CoordinateString(double value, string format, string hemispheres)
{
char hemisphere = hemispheres[0];
if (value < -1e-8) // ~1mm
{
value = -value;
hemisphere = hemispheres[1];
}
int minutes = (int)(value * 60d + 0.5);
return string.Format(format, hemisphere, minutes / 60, (double)(minutes % 60));
}
}
}