mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-01-30 12:24:27 +01:00
Version 1.9.2: Improved transformation from Location to viewport position in MapPanel and MapGraticule.
This commit is contained in:
parent
68d9351044
commit
b3474a3025
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace MapControl
|
|||
#if !SILVERLIGHT && !NETFX_CORE
|
||||
[NonSerialized]
|
||||
#endif
|
||||
internal double TransformedLatitude;
|
||||
internal double TransformedLatitude = double.NaN;
|
||||
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
|
|
@ -31,10 +31,16 @@ namespace MapControl
|
|||
{
|
||||
}
|
||||
|
||||
public Location(double lat, double lon)
|
||||
public Location(double latitude, double longitude)
|
||||
{
|
||||
Latitude = lat;
|
||||
Longitude = lon;
|
||||
this.latitude = Math.Min(Math.Max(latitude, -90d), 90d);
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
internal Location(double transformedLatitude, double latitude, double longitude)
|
||||
: this(latitude, longitude)
|
||||
{
|
||||
TransformedLatitude = transformedLatitude;
|
||||
}
|
||||
|
||||
public double Latitude
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#if NETFX_CORE
|
||||
using Windows.Foundation;
|
||||
|
|
@ -160,59 +161,69 @@ namespace MapControl
|
|||
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
|
||||
}
|
||||
|
||||
var labelsStart = new Location(
|
||||
var labelStart = new Location(
|
||||
Math.Ceiling(start.Latitude / spacing) * spacing,
|
||||
Math.Ceiling(start.Longitude / spacing) * spacing);
|
||||
|
||||
var labelsEnd = new Location(
|
||||
var labelEnd = new Location(
|
||||
Math.Floor(end.Latitude / spacing) * spacing,
|
||||
Math.Floor(end.Longitude / spacing) * spacing);
|
||||
|
||||
var linesStart = new Location(
|
||||
Math.Min(Math.Max(labelsStart.Latitude - spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
|
||||
labelsStart.Longitude - spacing);
|
||||
var lineStart = new Location(
|
||||
Math.Min(Math.Max(labelStart.Latitude - spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
|
||||
labelStart.Longitude - spacing);
|
||||
|
||||
var linesEnd = new Location(
|
||||
Math.Min(Math.Max(labelsEnd.Latitude + spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
|
||||
labelsEnd.Longitude + spacing);
|
||||
var lineEnd = new Location(
|
||||
Math.Min(Math.Max(labelEnd.Latitude + spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
|
||||
labelEnd.Longitude + spacing);
|
||||
|
||||
if (!linesStart.Equals(graticuleStart) || !linesEnd.Equals(graticuleEnd))
|
||||
if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
|
||||
{
|
||||
graticuleStart = linesStart;
|
||||
graticuleEnd = linesEnd;
|
||||
ParentMap.MapTransform.Transform(lineStart); // get lineStart.TransformedLatitude
|
||||
ParentMap.MapTransform.Transform(lineEnd); // get lineEnd.TransformedLatitude
|
||||
|
||||
graticuleStart = lineStart;
|
||||
graticuleEnd = lineEnd;
|
||||
|
||||
geometry.Figures.Clear();
|
||||
geometry.Transform = ParentMap.ViewportTransform;
|
||||
|
||||
for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing)
|
||||
var latLocations = new List<Location>((int)((end.Latitude - labelStart.Latitude) / spacing) + 1);
|
||||
|
||||
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
|
||||
{
|
||||
var location = new Location(lat, lineStart.Longitude);
|
||||
latLocations.Add(location);
|
||||
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = ParentMap.MapTransform.Transform(new Location(lat, linesStart.Longitude)),
|
||||
StartPoint = ParentMap.MapTransform.Transform(location),
|
||||
IsClosed = false,
|
||||
IsFilled = false
|
||||
};
|
||||
|
||||
location.Longitude = lineEnd.Longitude;
|
||||
|
||||
figure.Segments.Add(new LineSegment
|
||||
{
|
||||
Point = ParentMap.MapTransform.Transform(new Location(lat, linesEnd.Longitude)),
|
||||
Point = ParentMap.MapTransform.Transform(location),
|
||||
});
|
||||
|
||||
geometry.Figures.Add(figure);
|
||||
}
|
||||
|
||||
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
{
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = ParentMap.MapTransform.Transform(new Location(linesStart.Latitude, lon)),
|
||||
StartPoint = ParentMap.MapTransform.Transform(new Location(lineStart.TransformedLatitude, lineStart.Latitude, lon)),
|
||||
IsClosed = false,
|
||||
IsFilled = false
|
||||
};
|
||||
|
||||
figure.Segments.Add(new LineSegment
|
||||
{
|
||||
Point = ParentMap.MapTransform.Transform(new Location(linesEnd.Latitude, lon)),
|
||||
Point = ParentMap.MapTransform.Transform(new Location(lineEnd.TransformedLatitude, lineEnd.Latitude, lon)),
|
||||
});
|
||||
|
||||
geometry.Figures.Add(figure);
|
||||
|
|
@ -222,10 +233,12 @@ namespace MapControl
|
|||
var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
var measureSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||
|
||||
for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing)
|
||||
foreach (var location in latLocations)
|
||||
{
|
||||
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
{
|
||||
location.Longitude = lon;
|
||||
|
||||
TextBlock label;
|
||||
|
||||
if (childIndex < Children.Count)
|
||||
|
|
@ -261,8 +274,8 @@ namespace MapControl
|
|||
label.FontWeight = FontWeight;
|
||||
|
||||
label.Text = string.Format("{0}\n{1}",
|
||||
CoordinateString(lat, format, "NS"),
|
||||
CoordinateString(Location.NormalizeLongitude(lon), format, "EW"));
|
||||
CoordinateString(location.Latitude, format, "NS"),
|
||||
CoordinateString(Location.NormalizeLongitude(location.Longitude), format, "EW"));
|
||||
|
||||
label.Measure(measureSize);
|
||||
|
||||
|
|
@ -279,7 +292,7 @@ namespace MapControl
|
|||
translateTransform.X = StrokeThickness / 2d + 2d;
|
||||
translateTransform.Y = -label.DesiredSize.Height / 2d;
|
||||
|
||||
var viewportPosition = ParentMap.LocationToViewportPoint(new Location(lat, lon));
|
||||
var viewportPosition = ParentMap.LocationToViewportPoint(location);
|
||||
translateTransform = (TranslateTransform)transformGroup.Children[2];
|
||||
translateTransform.X = viewportPosition.X;
|
||||
translateTransform.Y = viewportPosition.Y;
|
||||
|
|
|
|||
|
|
@ -12,14 +12,28 @@ namespace MapControl
|
|||
{
|
||||
public partial class MapGraticule : MapOverlay
|
||||
{
|
||||
private class Label
|
||||
private class LonLabel
|
||||
{
|
||||
public readonly double Position;
|
||||
public readonly double Longitude;
|
||||
public readonly string Text;
|
||||
|
||||
public Label(double position, string text)
|
||||
public LonLabel(double longitude, string text)
|
||||
{
|
||||
Position = position;
|
||||
Longitude = longitude;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private class LatLabel
|
||||
{
|
||||
public readonly double TransformedLatitude;
|
||||
public readonly double Latitude;
|
||||
public readonly string Text;
|
||||
|
||||
public LatLabel(double transformedLatitude, double latitude, string text)
|
||||
{
|
||||
TransformedLatitude = transformedLatitude;
|
||||
Latitude = latitude;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,8 +59,10 @@ namespace MapControl
|
|||
if (ParentMap != null)
|
||||
{
|
||||
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(ParentMap.RenderSize));
|
||||
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
|
||||
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
|
||||
var startPoint = new Point(bounds.X, bounds.Y);
|
||||
var endPoint = new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height);
|
||||
var startLocation = ParentMap.MapTransform.Transform(startPoint);
|
||||
var endLocation = ParentMap.MapTransform.Transform(endPoint);
|
||||
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * TileSource.TileSize);
|
||||
var spacing = LineSpacings[LineSpacings.Length - 1];
|
||||
|
||||
|
|
@ -57,28 +73,31 @@ namespace MapControl
|
|||
|
||||
var labelFormat = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
var labelStart = new Location(
|
||||
Math.Ceiling(start.Latitude / spacing) * spacing,
|
||||
Math.Ceiling(start.Longitude / spacing) * spacing);
|
||||
Math.Ceiling(startLocation.Latitude / spacing) * spacing,
|
||||
Math.Ceiling(startLocation.Longitude / spacing) * spacing);
|
||||
|
||||
var latLabels = new List<Label>(16);
|
||||
var lonLabels = new List<Label>(16);
|
||||
var latLabels = new List<LatLabel>((int)((endLocation.Latitude - labelStart.Latitude) / spacing) + 1);
|
||||
var lonLabels = new List<LonLabel>((int)((endLocation.Longitude - labelStart.Longitude) / spacing) + 1);
|
||||
|
||||
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
|
||||
for (var lat = labelStart.Latitude; lat <= endLocation.Latitude; lat += spacing)
|
||||
{
|
||||
latLabels.Add(new Label(lat, CoordinateString(lat, labelFormat, "NS")));
|
||||
var location = new Location(lat, startLocation.Longitude);
|
||||
var p1 = ParentMap.LocationToViewportPoint(location);
|
||||
location.Longitude = endLocation.Longitude;
|
||||
var p2 = ParentMap.LocationToViewportPoint(location);
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
ParentMap.LocationToViewportPoint(new Location(lat, start.Longitude)),
|
||||
ParentMap.LocationToViewportPoint(new Location(lat, end.Longitude)));
|
||||
latLabels.Add(new LatLabel(location.TransformedLatitude, lat, CoordinateString(lat, labelFormat, "NS")));
|
||||
|
||||
drawingContext.DrawLine(Pen, p1, p2);
|
||||
}
|
||||
|
||||
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
|
||||
for (var lon = labelStart.Longitude; lon <= endLocation.Longitude; lon += spacing)
|
||||
{
|
||||
lonLabels.Add(new Label(lon, CoordinateString(Location.NormalizeLongitude(lon), labelFormat, "EW")));
|
||||
lonLabels.Add(new LonLabel(lon, CoordinateString(Location.NormalizeLongitude(lon), labelFormat, "EW")));
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
ParentMap.LocationToViewportPoint(new Location(start.Latitude, lon)),
|
||||
ParentMap.LocationToViewportPoint(new Location(end.Latitude, lon)));
|
||||
ParentMap.LocationToViewportPoint(new Location(startPoint.Y, startLocation.Latitude, lon)),
|
||||
ParentMap.LocationToViewportPoint(new Location(endPoint.Y, endLocation.Latitude, lon)));
|
||||
}
|
||||
|
||||
if (Foreground != null && Foreground != Brushes.Transparent && latLabels.Count > 0 && lonLabels.Count > 0)
|
||||
|
|
@ -107,7 +126,7 @@ namespace MapControl
|
|||
glyphRuns.Add(lonLabel.Text, lonGlyphRun);
|
||||
}
|
||||
|
||||
var position = ParentMap.LocationToViewportPoint(new Location(latLabel.Position, lonLabel.Position));
|
||||
var position = ParentMap.LocationToViewportPoint(new Location(latLabel.TransformedLatitude, latLabel.Latitude, lonLabel.Longitude));
|
||||
|
||||
drawingContext.PushTransform(new MatrixTransform(
|
||||
transform.M11, transform.M12, transform.M21, transform.M22, position.X, position.Y));
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Positions child elements on a Map, at a position specified by the attached property Location.
|
||||
/// The Location is transformed into a viewport position by the MapBase.LocationToViewportPoint
|
||||
/// method and applied to a child element's RenderTransform as an appropriate TranslateTransform.
|
||||
/// The Location is transformed to a viewport position by ParentMap.MapTransform and ParentMap.ViewportTransform
|
||||
/// and applied to a child element's RenderTransform as an appropriate TranslateTransform.
|
||||
/// </summary>
|
||||
public partial class MapPanel : Panel, IMapElement
|
||||
{
|
||||
|
|
@ -151,24 +151,22 @@ namespace MapControl
|
|||
|
||||
if (parentMap != null && location != null)
|
||||
{
|
||||
var longitude = Location.NormalizeLongitude(location.Longitude);
|
||||
var centerDistance = longitude - parentMap.Center.Longitude;
|
||||
// transform location before checking longitude to keep location.TransformedLatitude
|
||||
var mapPosition = parentMap.MapTransform.Transform(location);
|
||||
mapPosition.X = Location.NormalizeLongitude(mapPosition.X);
|
||||
|
||||
if (centerDistance > 180d)
|
||||
var centerOffset = mapPosition.X - parentMap.Center.Longitude; // keep viewport position near map center
|
||||
|
||||
if (centerOffset > 180d)
|
||||
{
|
||||
longitude -= 360d;
|
||||
mapPosition.X -= 360d;
|
||||
}
|
||||
else if (centerDistance < -180d)
|
||||
else if (centerOffset < -180d)
|
||||
{
|
||||
longitude += 360d;
|
||||
mapPosition.X += 360d;
|
||||
}
|
||||
|
||||
if (location.Longitude != longitude) // keep viewport position near map center
|
||||
{
|
||||
location = new Location(location.Latitude, longitude);
|
||||
}
|
||||
|
||||
viewportPosition = parentMap.LocationToViewportPoint(location);
|
||||
viewportPosition = parentMap.ViewportTransform.Transform(mapPosition);
|
||||
element.SetValue(ViewportPositionProperty, viewportPosition);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ namespace MapControl
|
|||
|
||||
public override Location Transform(Point point)
|
||||
{
|
||||
var location = new Location(Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d, point.X);
|
||||
location.TransformedLatitude = point.Y;
|
||||
return location;
|
||||
return new Location(point.Y, Math.Atan(Math.Sinh(point.Y * Math.PI / 180d)) / Math.PI * 180d, point.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ using System.Windows;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("Copyright © Clemens Fischer 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("1.9.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.1")]
|
||||
[assembly: AssemblyVersion("1.9.2")]
|
||||
[assembly: AssemblyFileVersion("1.9.2")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue