mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-01-01 06:10:02 +01:00
Avoid unnecessary Location and Point allocations
This commit is contained in:
parent
f44d2207e5
commit
e268be2948
|
|
@ -81,10 +81,7 @@ namespace MapControl
|
|||
|
||||
private void AddPolylinePoints(PathFigures figures, IEnumerable<Location> locations, double longitudeOffset, bool closed)
|
||||
{
|
||||
var points = locations
|
||||
.Select(location => LocationToView(location, longitudeOffset))
|
||||
.Where(point => point.HasValue)
|
||||
.Select(point => point.Value);
|
||||
var points = LocationsToView(locations, longitudeOffset);
|
||||
|
||||
if (points.Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,25 +28,25 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
Math.Cos(Center.Latitude * Math.PI / 180d) / Math.Cos(location.Latitude * Math.PI / 180d),
|
||||
Math.Cos(Center.Latitude * Math.PI / 180d) / Math.Cos(latitude * Math.PI / 180d),
|
||||
1d);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
Wgs84MeterPerDegree * (location.Longitude - Center.Longitude) * Math.Cos(Center.Latitude * Math.PI / 180d),
|
||||
Wgs84MeterPerDegree * location.Latitude);
|
||||
Wgs84MeterPerDegree * (longitude - Center.Longitude) * Math.Cos(Center.Latitude * Math.PI / 180d),
|
||||
Wgs84MeterPerDegree * latitude);
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
return new Location(
|
||||
point.Y / Wgs84MeterPerDegree,
|
||||
point.X / (Wgs84MeterPerDegree * Math.Cos(Center.Latitude * Math.PI / 180d)) + Center.Longitude);
|
||||
y / Wgs84MeterPerDegree,
|
||||
x / (Wgs84MeterPerDegree * Math.Cos(Center.Latitude * Math.PI / 180d)) + Center.Longitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,30 +26,30 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
if (location.Equals(Center))
|
||||
if (Location.Equals(latitude, Center.Latitude) &&
|
||||
Location.Equals(longitude, Center.Longitude))
|
||||
{
|
||||
return new Point();
|
||||
}
|
||||
|
||||
Center.GetAzimuthDistance(location, out double azimuth, out double distance);
|
||||
Center.GetAzimuthDistance(latitude, longitude, out double azimuth, out double distance);
|
||||
|
||||
var mapDistance = distance * Wgs84EquatorialRadius;
|
||||
|
||||
return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
if (point.X == 0d && point.Y == 0d)
|
||||
if (x == 0d && y == 0d)
|
||||
{
|
||||
return new Location(Center.Latitude, Center.Longitude);
|
||||
}
|
||||
|
||||
var azimuth = Math.Atan2(point.X, point.Y);
|
||||
var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
|
||||
|
||||
var azimuth = Math.Atan2(x, y);
|
||||
var mapDistance = Math.Sqrt(x * x + y * y);
|
||||
var distance = mapDistance / Wgs84EquatorialRadius;
|
||||
|
||||
return Center.GetLocation(azimuth, distance);
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ namespace MapControl
|
|||
public override BoundingBox MapToBoundingBox(Rect rect)
|
||||
{
|
||||
BoundingBox boundingBox = null;
|
||||
var rectCenter = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||
var center = MapToLocation(rectCenter);
|
||||
var center = MapToLocation(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||
|
||||
if (center != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,25 +28,19 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
1d / Math.Cos(location.Latitude * Math.PI / 180d),
|
||||
1d);
|
||||
return new Point(1d / Math.Cos(latitude * Math.PI / 180d), 1d);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
Wgs84MeterPerDegree * location.Longitude,
|
||||
Wgs84MeterPerDegree * location.Latitude);
|
||||
return new Point(Wgs84MeterPerDegree * longitude, Wgs84MeterPerDegree * latitude);
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
return new Location(
|
||||
point.Y / Wgs84MeterPerDegree,
|
||||
point.X / Wgs84MeterPerDegree);
|
||||
return new Location(y / Wgs84MeterPerDegree, x / Wgs84MeterPerDegree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,14 +26,15 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
if (location.Equals(Center))
|
||||
if (Location.Equals(latitude, Center.Latitude) &&
|
||||
Location.Equals(longitude, Center.Longitude))
|
||||
{
|
||||
return new Point();
|
||||
}
|
||||
|
||||
Center.GetAzimuthDistance(location, out double azimuth, out double distance);
|
||||
Center.GetAzimuthDistance(latitude, longitude, out double azimuth, out double distance);
|
||||
|
||||
var mapDistance = distance < Math.PI / 2d
|
||||
? Math.Tan(distance) * Wgs84EquatorialRadius
|
||||
|
|
@ -42,16 +43,15 @@ namespace MapControl
|
|||
return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
if (point.X == 0d && point.Y == 0d)
|
||||
if (x == 0d && y == 0d)
|
||||
{
|
||||
return new Location(Center.Latitude, Center.Longitude);
|
||||
}
|
||||
|
||||
var azimuth = Math.Atan2(point.X, point.Y);
|
||||
var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
|
||||
|
||||
var azimuth = Math.Atan2(x, y);
|
||||
var mapDistance = Math.Sqrt(x * x + y * y);
|
||||
var distance = Math.Atan(mapDistance / Wgs84EquatorialRadius);
|
||||
|
||||
return Center.GetLocation(azimuth, distance);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ namespace MapControl
|
|||
public bool Equals(Location location)
|
||||
{
|
||||
return location != null &&
|
||||
Math.Abs(location.Latitude - Latitude) < 1e-9 &&
|
||||
Math.Abs(location.Longitude - Longitude) < 1e-9;
|
||||
Equals(Latitude, location.Latitude) &&
|
||||
Equals(Longitude, location.Longitude);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
|
|
@ -52,6 +52,11 @@ namespace MapControl
|
|||
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", Latitude, Longitude);
|
||||
}
|
||||
|
||||
public static bool CoordinateEquals(double coordinate1, double coordinate2)
|
||||
{
|
||||
return Math.Abs(coordinate1 - coordinate2) < 1e-9;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Location instance from a string containing a comma-separated pair of floating point numbers.
|
||||
/// </summary>
|
||||
|
|
@ -87,12 +92,12 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Calculates great circle azimuth and distance in radians between this and the specified Location.
|
||||
/// </summary>
|
||||
public void GetAzimuthDistance(Location location, out double azimuth, out double distance)
|
||||
public void GetAzimuthDistance(double latitude, double longitude, out double azimuth, out double distance)
|
||||
{
|
||||
var lat1 = Latitude * Math.PI / 180d;
|
||||
var lon1 = Longitude * Math.PI / 180d;
|
||||
var lat2 = location.Latitude * Math.PI / 180d;
|
||||
var lon2 = location.Longitude * Math.PI / 180d;
|
||||
var lat2 = latitude * Math.PI / 180d;
|
||||
var lon2 = longitude * Math.PI / 180d;
|
||||
var cosLat1 = Math.Cos(lat1);
|
||||
var sinLat1 = Math.Sin(lat1);
|
||||
var cosLat2 = Math.Cos(lat2);
|
||||
|
|
@ -112,7 +117,7 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public double GetDistance(Location location, double earthRadius = MapProjection.Wgs84EquatorialRadius)
|
||||
{
|
||||
GetAzimuthDistance(location, out double _, out double distance);
|
||||
GetAzimuthDistance(location.Latitude, location.Longitude, out _, out double distance);
|
||||
|
||||
return earthRadius * distance;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,15 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public ViewTransform ViewTransform { get; } = new ViewTransform();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the map scale as horizontal and vertical scaling factors from meters to
|
||||
/// view coordinates at the specified geographic coordinates.
|
||||
/// </summary>
|
||||
public Point GetScale(double latitude, double longitude)
|
||||
{
|
||||
return ViewTransform.GetMapScale(MapProjection.GetRelativeScale(latitude, longitude));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the map scale as horizontal and vertical scaling factors from meters to
|
||||
/// view coordinates at the specified location.
|
||||
|
|
@ -187,7 +196,7 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Gets a transform Matrix from meters to view coordinates for scaling and rotating
|
||||
/// objects that are anchored at a Location.
|
||||
/// objects that are anchored at the specified Location.
|
||||
/// </summary>
|
||||
public Matrix GetMapTransform(Location location)
|
||||
{
|
||||
|
|
@ -195,11 +204,11 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
|
||||
/// Transforms geographic coordinates to a Point in view coordinates.
|
||||
/// </summary>
|
||||
public Point? LocationToView(Location location)
|
||||
public Point? LocationToView(double latitude, double longitude)
|
||||
{
|
||||
var point = MapProjection.LocationToMap(location);
|
||||
var point = MapProjection.LocationToMap(latitude, longitude);
|
||||
|
||||
if (point.HasValue)
|
||||
{
|
||||
|
|
@ -209,6 +218,14 @@ namespace MapControl
|
|||
return point;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
|
||||
/// </summary>
|
||||
public Point? LocationToView(Location location)
|
||||
{
|
||||
return LocationToView(location.Latitude, location.Longitude);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Point in view coordinates to a Location in geographic coordinates.
|
||||
/// </summary>
|
||||
|
|
@ -343,8 +360,9 @@ namespace MapControl
|
|||
|
||||
if (mapRect.HasValue)
|
||||
{
|
||||
var rectCenter = new Point(mapRect.Value.X + mapRect.Value.Width / 2d, mapRect.Value.Y + mapRect.Value.Height / 2d);
|
||||
var targetCenter = MapProjection.MapToLocation(rectCenter);
|
||||
var targetCenter = MapProjection.MapToLocation(
|
||||
mapRect.Value.X + mapRect.Value.Width / 2d,
|
||||
mapRect.Value.Y + mapRect.Value.Height / 2d);
|
||||
|
||||
if (targetCenter != null)
|
||||
{
|
||||
|
|
@ -428,7 +446,7 @@ namespace MapControl
|
|||
|
||||
if (projection.Type <= MapProjectionType.NormalCylindrical)
|
||||
{
|
||||
var maxLocation = projection.MapToLocation(new Point(0d, 180d * MapProjection.Wgs84MeterPerDegree));
|
||||
var maxLocation = projection.MapToLocation(0d, 180d * MapProjection.Wgs84MeterPerDegree);
|
||||
|
||||
if (maxLocation != null && maxLocation.Latitude < 90d)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace MapControl
|
|||
|
||||
private void SetLineDistance()
|
||||
{
|
||||
var minDistance = MinLineDistance / PixelPerLongitudeDegree(ParentMap.Center);
|
||||
var minDistance = MinLineDistance / PixelPerLongitudeDegree(ParentMap.Center.Latitude, ParentMap.Center.Longitude);
|
||||
var scale = minDistance < 1d / 60d ? 3600d : minDistance < 1d ? 60d : 1d;
|
||||
minDistance *= scale;
|
||||
|
||||
|
|
@ -98,11 +98,12 @@ namespace MapControl
|
|||
: lineDistance < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
}
|
||||
|
||||
private double PixelPerLongitudeDegree(Location location)
|
||||
private double PixelPerLongitudeDegree(double latitude, double longitude)
|
||||
{
|
||||
var scale = ParentMap.GetScale(latitude, longitude);
|
||||
|
||||
return Math.Max(1d, // a reasonable lower limit
|
||||
ParentMap.GetScale(location).X *
|
||||
Math.Cos(location.Latitude * Math.PI / 180d) * MapProjection.Wgs84MeterPerDegree);
|
||||
scale.X * Math.Cos(latitude * Math.PI / 180d) * MapProjection.Wgs84MeterPerDegree);
|
||||
}
|
||||
|
||||
private string GetLabelText(double value, string hemispheres)
|
||||
|
|
@ -121,7 +122,7 @@ namespace MapControl
|
|||
labelFormat, hemisphere, seconds / 3600, seconds / 60 % 60, seconds % 60);
|
||||
}
|
||||
|
||||
private void AddLabel(List<Label> labels, Location location, Point position, double? rotation = null)
|
||||
private void AddLabel(List<Label> labels, double latitude, double longitude, Point position, double? rotation = null)
|
||||
{
|
||||
if (position.X >= 0d && position.X <= ParentMap.ActualWidth &&
|
||||
position.Y >= 0d && position.Y <= ParentMap.ActualHeight)
|
||||
|
|
@ -130,8 +131,7 @@ namespace MapControl
|
|||
{
|
||||
// Get rotation from second location with same latitude.
|
||||
//
|
||||
var pos = ParentMap.LocationToView(
|
||||
new Location(location.Latitude, location.Longitude + 10d / PixelPerLongitudeDegree(location)));
|
||||
var pos = ParentMap.LocationToView(latitude, longitude + 10d / PixelPerLongitudeDegree(latitude, longitude));
|
||||
|
||||
if (pos.HasValue)
|
||||
{
|
||||
|
|
@ -142,8 +142,8 @@ namespace MapControl
|
|||
if (rotation.HasValue)
|
||||
{
|
||||
labels.Add(new Label(
|
||||
GetLabelText(location.Latitude, "NS"),
|
||||
GetLabelText(Location.NormalizeLongitude(location.Longitude), "EW"),
|
||||
GetLabelText(latitude, "NS"),
|
||||
GetLabelText(Location.NormalizeLongitude(longitude), "EW"),
|
||||
position.X, position.Y, rotation.Value));
|
||||
}
|
||||
}
|
||||
|
|
@ -177,8 +177,8 @@ namespace MapControl
|
|||
|
||||
for (var lat = latLabelStart; lat <= boundingBox.North; lat += lineDistance)
|
||||
{
|
||||
var p1 = ParentMap.LocationToView(new Location(lat, boundingBox.West));
|
||||
var p2 = ParentMap.LocationToView(new Location(lat, boundingBox.East));
|
||||
var p1 = ParentMap.LocationToView(lat, boundingBox.West);
|
||||
var p2 = ParentMap.LocationToView(lat, boundingBox.East);
|
||||
|
||||
if (p1.HasValue && p2.HasValue)
|
||||
{
|
||||
|
|
@ -188,8 +188,8 @@ namespace MapControl
|
|||
|
||||
for (var lon = lonLabelStart; lon <= boundingBox.East; lon += lineDistance)
|
||||
{
|
||||
var p1 = ParentMap.LocationToView(new Location(boundingBox.South, lon));
|
||||
var p2 = ParentMap.LocationToView(new Location(boundingBox.North, lon));
|
||||
var p1 = ParentMap.LocationToView(boundingBox.South, lon);
|
||||
var p2 = ParentMap.LocationToView(boundingBox.North, lon);
|
||||
|
||||
if (p1.HasValue && p2.HasValue)
|
||||
{
|
||||
|
|
@ -198,12 +198,11 @@ namespace MapControl
|
|||
|
||||
for (var lat = latLabelStart; lat <= boundingBox.North; lat += lineDistance)
|
||||
{
|
||||
var location = new Location(lat, lon);
|
||||
var position = ParentMap.LocationToView(location);
|
||||
var position = ParentMap.LocationToView(lat, lon);
|
||||
|
||||
if (position.HasValue)
|
||||
{
|
||||
AddLabel(labels, location, position.Value, ParentMap.ViewTransform.Rotation);
|
||||
AddLabel(labels, lat, lon, position.Value, ParentMap.ViewTransform.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -257,14 +256,13 @@ namespace MapControl
|
|||
{
|
||||
var lat = minLat + i * lineDistance;
|
||||
var lon = minLon;
|
||||
var location = new Location(lat, lon);
|
||||
var points = new List<Point>();
|
||||
var position = ParentMap.LocationToView(location);
|
||||
var position = ParentMap.LocationToView(lat, lon);
|
||||
|
||||
if (position.HasValue)
|
||||
{
|
||||
points.Add(position.Value);
|
||||
AddLabel(labels, location, position.Value);
|
||||
AddLabel(labels, lat, lon, position.Value);
|
||||
}
|
||||
|
||||
for (int j = 0; j < lonSegments; j++)
|
||||
|
|
@ -272,8 +270,7 @@ namespace MapControl
|
|||
for (int k = 1; k <= interpolationCount; k++)
|
||||
{
|
||||
lon = minLon + j * lineDistance + k * interpolationDistance;
|
||||
location = new Location(lat, lon);
|
||||
position = ParentMap.LocationToView(location);
|
||||
position = ParentMap.LocationToView(lat, lon);
|
||||
|
||||
if (position.HasValue)
|
||||
{
|
||||
|
|
@ -283,7 +280,7 @@ namespace MapControl
|
|||
|
||||
if (position.HasValue)
|
||||
{
|
||||
AddLabel(labels, location, position.Value);
|
||||
AddLabel(labels, lat, lon, position.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +299,7 @@ namespace MapControl
|
|||
|
||||
for (int i = 0; i <= numPoints; i++)
|
||||
{
|
||||
var p = ParentMap.LocationToView(new Location(startLatitude + i * deltaLatitude, longitude));
|
||||
var p = ParentMap.LocationToView(startLatitude + i * deltaLatitude, longitude);
|
||||
|
||||
if (p.HasValue)
|
||||
{
|
||||
|
|
@ -326,8 +323,8 @@ namespace MapControl
|
|||
{
|
||||
var width = ParentMap.ActualWidth;
|
||||
var height = ParentMap.ActualHeight;
|
||||
var northPole = ParentMap.LocationToView(new Location(90d, 0d));
|
||||
var southPole = ParentMap.LocationToView(new Location(-90d, 0d));
|
||||
var northPole = ParentMap.LocationToView(90d, 0d);
|
||||
var southPole = ParentMap.LocationToView(-90d, 0d);
|
||||
|
||||
if (northPole.HasValue &&
|
||||
northPole.Value.X >= 0d && northPole.Value.X <= width &&
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ namespace MapControl
|
|||
position.HasValue && !parentMap.InsideViewBounds(position.Value))
|
||||
{
|
||||
var coercedPosition = parentMap.LocationToView(
|
||||
new Location(location.Latitude, parentMap.CoerceLongitude(location.Longitude)));
|
||||
location.Latitude, parentMap.CoerceLongitude(location.Longitude));
|
||||
|
||||
if (coercedPosition.HasValue)
|
||||
{
|
||||
|
|
@ -230,7 +230,7 @@ namespace MapControl
|
|||
if (location != null)
|
||||
{
|
||||
var coercedPosition = parentMap.LocationToView(
|
||||
new Location(location.Latitude, parentMap.CoerceLongitude(location.Longitude)));
|
||||
location.Latitude, parentMap.CoerceLongitude(location.Longitude));
|
||||
|
||||
if (coercedPosition.HasValue)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#if WPF
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#if WPF
|
||||
using System.Windows;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml;
|
||||
|
|
@ -93,12 +95,7 @@ namespace MapControl
|
|||
|
||||
protected Point? LocationToMap(Location location, double longitudeOffset)
|
||||
{
|
||||
if (longitudeOffset != 0d)
|
||||
{
|
||||
location = new Location(location.Latitude, location.Longitude + longitudeOffset);
|
||||
}
|
||||
|
||||
var point = parentMap.MapProjection.LocationToMap(location);
|
||||
var point = parentMap.MapProjection.LocationToMap(location.Latitude, location.Longitude + longitudeOffset);
|
||||
|
||||
if (point.HasValue)
|
||||
{
|
||||
|
|
@ -126,5 +123,21 @@ namespace MapControl
|
|||
|
||||
return point;
|
||||
}
|
||||
|
||||
protected IEnumerable<Point> LocationsToMap(IEnumerable<Location> locations, double longitudeOffset)
|
||||
{
|
||||
return locations
|
||||
.Select(location => LocationToMap(location, longitudeOffset))
|
||||
.Where(point => point.HasValue)
|
||||
.Select(point => point.Value);
|
||||
}
|
||||
|
||||
protected IEnumerable<Point> LocationsToView(IEnumerable<Location> locations, double longitudeOffset)
|
||||
{
|
||||
return locations
|
||||
.Select(location => LocationToView(location, longitudeOffset))
|
||||
.Where(point => point.HasValue)
|
||||
.Select(point => point.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,21 +55,38 @@ namespace MapControl
|
|||
public virtual Location Center { get; protected internal set; } = new Location();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relative map scale at the specified Location.
|
||||
/// Gets the relative map scale at the specified geographic coordinates.
|
||||
/// </summary>
|
||||
public virtual Point GetRelativeScale(Location location) => new Point(1d, 1d);
|
||||
public virtual Point GetRelativeScale(double latitude, double longitude) => new Point(1d, 1d);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms geographic coordinates to a Point in projected map coordinates.
|
||||
/// Returns null when the location can not be transformed.
|
||||
/// </summary>
|
||||
public abstract Point? LocationToMap(double latitude, double longitude);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms projected map coordinates to a Location in geographic coordinates.
|
||||
/// Returns null when the coordinates can not be transformed.
|
||||
/// </summary>
|
||||
public abstract Location MapToLocation(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relative map scale at the specified geographic Location.
|
||||
/// </summary>
|
||||
public Point GetRelativeScale(Location location) => GetRelativeScale(location.Latitude, location.Longitude);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Location in geographic coordinates to a Point in projected map coordinates.
|
||||
/// Returns null when the Location can not be transformed.
|
||||
/// </summary>
|
||||
public abstract Point? LocationToMap(Location location);
|
||||
public Point? LocationToMap(Location location) => LocationToMap(location.Latitude, location.Longitude);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Point in projected map coordinates to a Location in geographic coordinates.
|
||||
/// Returns null when the Point can not be transformed.
|
||||
/// </summary>
|
||||
public abstract Location MapToLocation(Point point);
|
||||
public Location MapToLocation(Point point) => MapToLocation(point.X, point.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a BoundingBox in geographic coordinates to a Rect in projected map coordinates.
|
||||
|
|
@ -78,9 +95,8 @@ namespace MapControl
|
|||
public virtual Rect? BoundingBoxToMap(BoundingBox boundingBox)
|
||||
{
|
||||
Rect? rect = null;
|
||||
|
||||
var southWest = LocationToMap(new Location(boundingBox.South, boundingBox.West));
|
||||
var northEast = LocationToMap(new Location(boundingBox.North, boundingBox.East));
|
||||
var southWest = LocationToMap(boundingBox.South, boundingBox.West);
|
||||
var northEast = LocationToMap(boundingBox.North, boundingBox.East);
|
||||
|
||||
if (southWest.HasValue && northEast.HasValue)
|
||||
{
|
||||
|
|
@ -97,8 +113,8 @@ namespace MapControl
|
|||
public virtual BoundingBox MapToBoundingBox(Rect rect)
|
||||
{
|
||||
BoundingBox boundingBox = null;
|
||||
var southWest = MapToLocation(new Point(rect.X, rect.Y));
|
||||
var northEast = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
||||
var southWest = MapToLocation(rect.X, rect.Y);
|
||||
var northEast = MapToLocation(rect.X + rect.Width, rect.Y + rect.Height);
|
||||
|
||||
if (southWest != null && northEast != null)
|
||||
{
|
||||
|
|
@ -116,13 +132,14 @@ namespace MapControl
|
|||
{
|
||||
Tuple<Rect, double> rotatedRect = null;
|
||||
Point? center, north, south, west, east;
|
||||
var boxCenter = latLonBox.Center;
|
||||
var centerLatitude = latLonBox.Center.Latitude;
|
||||
var centerLongitude = latLonBox.Center.Longitude;
|
||||
|
||||
if ((center = LocationToMap(boxCenter)).HasValue &&
|
||||
(north = LocationToMap(new Location(latLonBox.North, boxCenter.Longitude))).HasValue &&
|
||||
(south = LocationToMap(new Location(latLonBox.South, boxCenter.Longitude))).HasValue &&
|
||||
(west = LocationToMap(new Location(boxCenter.Latitude, latLonBox.West))).HasValue &&
|
||||
(east = LocationToMap(new Location(boxCenter.Latitude, latLonBox.East))).HasValue)
|
||||
if ((center = LocationToMap(centerLatitude, centerLongitude)).HasValue &&
|
||||
(north = LocationToMap(latLonBox.North, centerLongitude)).HasValue &&
|
||||
(south = LocationToMap(latLonBox.South, centerLongitude)).HasValue &&
|
||||
(west = LocationToMap(centerLatitude, latLonBox.West)).HasValue &&
|
||||
(east = LocationToMap(centerLatitude, latLonBox.East)).HasValue)
|
||||
{
|
||||
var dx1 = east.Value.X - west.Value.X;
|
||||
var dy1 = east.Value.Y - west.Value.Y;
|
||||
|
|
|
|||
|
|
@ -26,16 +26,17 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
if (location.Equals(Center))
|
||||
if (Location.Equals(latitude, Center.Latitude) &&
|
||||
Location.Equals(longitude, Center.Longitude))
|
||||
{
|
||||
return new Point();
|
||||
}
|
||||
|
||||
var lat0 = Center.Latitude * Math.PI / 180d;
|
||||
var lat = location.Latitude * Math.PI / 180d;
|
||||
var dLon = (location.Longitude - Center.Longitude) * Math.PI / 180d;
|
||||
var lat = latitude * Math.PI / 180d;
|
||||
var dLon = (longitude - Center.Longitude) * Math.PI / 180d;
|
||||
|
||||
if (Math.Abs(lat - lat0) > Math.PI / 2d || Math.Abs(dLon) > Math.PI / 2d)
|
||||
{
|
||||
|
|
@ -47,15 +48,15 @@ namespace MapControl
|
|||
Wgs84EquatorialRadius * (Math.Cos(lat0) * Math.Sin(lat) - Math.Sin(lat0) * Math.Cos(lat) * Math.Cos(dLon)));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
if (point.X == 0d && point.Y == 0d)
|
||||
if (x == 0d && y == 0d)
|
||||
{
|
||||
return new Location(Center.Latitude, Center.Longitude);
|
||||
}
|
||||
|
||||
var x = point.X / Wgs84EquatorialRadius;
|
||||
var y = point.Y / Wgs84EquatorialRadius;
|
||||
x /= Wgs84EquatorialRadius;
|
||||
y /= Wgs84EquatorialRadius;
|
||||
var r2 = x * x + y * y;
|
||||
|
||||
if (r2 > 1d)
|
||||
|
|
|
|||
|
|
@ -26,50 +26,50 @@ namespace MapControl
|
|||
public double FalseNorthing { get; set; } = 2e6;
|
||||
public bool IsNorth { get; set; }
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
var lat = location.Latitude * Math.PI / 180d;
|
||||
latitude *= Math.PI / 180d;
|
||||
|
||||
if (!IsNorth)
|
||||
{
|
||||
lat = -lat;
|
||||
latitude = -latitude;
|
||||
}
|
||||
|
||||
var e = Math.Sqrt((2d - Flattening) * Flattening);
|
||||
var eSinLat = e * Math.Sin(lat);
|
||||
var eSinLat = e * Math.Sin(latitude);
|
||||
|
||||
var t = Math.Tan(Math.PI / 4d - lat / 2d)
|
||||
var t = Math.Tan(Math.PI / 4d - latitude / 2d)
|
||||
/ Math.Pow((1d - eSinLat) / (1d + eSinLat), e / 2d); // p.161 (15-9)
|
||||
var r = 2d * EquatorialRadius * ScaleFactor * t
|
||||
/ Math.Sqrt(Math.Pow(1d + e, 1d + e) * Math.Pow(1d - e, 1d - e)); // p.161 (21-33)
|
||||
|
||||
var m = Math.Cos(lat) / Math.Sqrt(1d - eSinLat * eSinLat); // p.160 (14-15)
|
||||
var m = Math.Cos(latitude) / Math.Sqrt(1d - eSinLat * eSinLat); // p.160 (14-15)
|
||||
var k = r / (EquatorialRadius * m); // p.161 (21-32)
|
||||
|
||||
return new Point(k, k);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
var lat = location.Latitude * Math.PI / 180d;
|
||||
var lon = location.Longitude * Math.PI / 180d;
|
||||
latitude *= Math.PI / 180d;
|
||||
longitude *= Math.PI / 180d;
|
||||
|
||||
if (!IsNorth)
|
||||
{
|
||||
lat = -lat;
|
||||
lon = -lon;
|
||||
latitude = -latitude;
|
||||
longitude = -longitude;
|
||||
}
|
||||
|
||||
var e = Math.Sqrt((2d - Flattening) * Flattening);
|
||||
var eSinLat = e * Math.Sin(lat);
|
||||
var eSinLat = e * Math.Sin(latitude);
|
||||
|
||||
var t = Math.Tan(Math.PI / 4d - lat / 2d)
|
||||
var t = Math.Tan(Math.PI / 4d - latitude / 2d)
|
||||
/ Math.Pow((1d - eSinLat) / (1d + eSinLat), e / 2d); // p.161 (15-9)
|
||||
var r = 2d * EquatorialRadius * ScaleFactor * t
|
||||
/ Math.Sqrt(Math.Pow(1d + e, 1d + e) * Math.Pow(1d - e, 1d - e)); // p.161 (21-33)
|
||||
|
||||
var x = r * Math.Sin(lon); // p.161 (21-30)
|
||||
var y = -r * Math.Cos(lon); // p.161 (21-31)
|
||||
var x = r * Math.Sin(longitude); // p.161 (21-30)
|
||||
var y = -r * Math.Cos(longitude); // p.161 (21-31)
|
||||
|
||||
if (!IsNorth)
|
||||
{
|
||||
|
|
@ -80,10 +80,10 @@ namespace MapControl
|
|||
return new Point(x + FalseEasting, y + FalseNorthing);
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
var x = point.X - FalseEasting;
|
||||
var y = point.Y - FalseNorthing;
|
||||
x -= FalseEasting;
|
||||
y -= FalseNorthing;
|
||||
|
||||
if (!IsNorth)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,30 +26,30 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
if (location.Equals(Center))
|
||||
if (Location.Equals(latitude, Center.Latitude) &&
|
||||
Location.Equals(longitude, Center.Longitude))
|
||||
{
|
||||
return new Point();
|
||||
}
|
||||
|
||||
Center.GetAzimuthDistance(location, out double azimuth, out double distance);
|
||||
Center.GetAzimuthDistance(latitude, longitude, out double azimuth, out double distance);
|
||||
|
||||
var mapDistance = Math.Tan(distance / 2d) * 2d * Wgs84EquatorialRadius;
|
||||
|
||||
return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
if (point.X == 0d && point.Y == 0d)
|
||||
if (x == 0d && y == 0d)
|
||||
{
|
||||
return new Location(Center.Latitude, Center.Longitude);
|
||||
}
|
||||
|
||||
var azimuth = Math.Atan2(point.X, point.Y);
|
||||
var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
|
||||
|
||||
var azimuth = Math.Atan2(x, y);
|
||||
var mapDistance = Math.Sqrt(x * x + y * y);
|
||||
var distance = 2d * Math.Atan(mapDistance / (2d * Wgs84EquatorialRadius));
|
||||
|
||||
return Center.GetLocation(azimuth, distance);
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ namespace MapControl
|
|||
Type = MapProjectionType.TransverseCylindrical;
|
||||
}
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
return new Point(ScaleFactor, ScaleFactor);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
#if NETFRAMEWORK || UWP
|
||||
double Atanh(double x) => Math.Log((1d + x) / (1d - x)) / 2d;
|
||||
static double Atanh(double x) => Math.Log((1d + x) / (1d - x)) / 2d;
|
||||
#else
|
||||
static double Atanh(double x) => Math.Atanh(x);
|
||||
#endif
|
||||
|
|
@ -48,10 +48,10 @@ namespace MapControl
|
|||
var alpha3 = n3 * 61d / 240d;
|
||||
|
||||
// φ
|
||||
var phi = location.Latitude * Math.PI / 180d;
|
||||
var phi = latitude * Math.PI / 180d;
|
||||
|
||||
// (λ - λ0)
|
||||
var lambda = (location.Longitude - CentralMeridian) * Math.PI / 180d;
|
||||
var lambda = (longitude - CentralMeridian) * Math.PI / 180d;
|
||||
|
||||
var s = 2d * Math.Sqrt(n) / (1d + n);
|
||||
var sinPhi = Math.Sin(phi);
|
||||
|
|
@ -80,7 +80,7 @@ namespace MapControl
|
|||
k0A * xi + FalseNorthing);
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
var n = Flattening / (2d - Flattening);
|
||||
var n2 = n * n;
|
||||
|
|
@ -98,10 +98,10 @@ namespace MapControl
|
|||
var delta3 = n3 * 56d / 15d;
|
||||
|
||||
// ξ
|
||||
var xi = (point.Y - FalseNorthing) / k0A;
|
||||
var xi = (y - FalseNorthing) / k0A;
|
||||
|
||||
// η
|
||||
var eta = (point.X - FalseEasting) / k0A;
|
||||
var eta = (x - FalseEasting) / k0A;
|
||||
|
||||
// ξ'
|
||||
var xi_ = xi
|
||||
|
|
|
|||
|
|
@ -27,25 +27,25 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
||||
var k = 1d / Math.Cos(latitude * Math.PI / 180d); // p.44 (7-3)
|
||||
|
||||
return new Point(k, k);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
Wgs84MeterPerDegree * location.Longitude,
|
||||
Wgs84MeterPerDegree * LatitudeToY(location.Latitude));
|
||||
Wgs84MeterPerDegree * longitude,
|
||||
Wgs84MeterPerDegree * LatitudeToY(latitude));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
return new Location(
|
||||
YToLatitude(point.Y / Wgs84MeterPerDegree),
|
||||
point.X / Wgs84MeterPerDegree);
|
||||
YToLatitude(y / Wgs84MeterPerDegree),
|
||||
x / Wgs84MeterPerDegree);
|
||||
}
|
||||
|
||||
public static double LatitudeToY(double latitude)
|
||||
|
|
|
|||
|
|
@ -27,27 +27,27 @@ namespace MapControl
|
|||
CrsId = crsId;
|
||||
}
|
||||
|
||||
public override Point GetRelativeScale(Location location)
|
||||
public override Point GetRelativeScale(double latitude, double longitude)
|
||||
{
|
||||
var lat = location.Latitude * Math.PI / 180d;
|
||||
var lat = latitude * Math.PI / 180d;
|
||||
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
||||
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
||||
|
||||
return new Point(k, k);
|
||||
}
|
||||
|
||||
public override Point? LocationToMap(Location location)
|
||||
public override Point? LocationToMap(double latitude, double longitude)
|
||||
{
|
||||
return new Point(
|
||||
Wgs84MeterPerDegree * location.Longitude,
|
||||
Wgs84MeterPerDegree * LatitudeToY(location.Latitude));
|
||||
Wgs84MeterPerDegree * longitude,
|
||||
Wgs84MeterPerDegree * LatitudeToY(latitude));
|
||||
}
|
||||
|
||||
public override Location MapToLocation(Point point)
|
||||
public override Location MapToLocation(double x, double y)
|
||||
{
|
||||
return new Location(
|
||||
YToLatitude(point.Y / Wgs84MeterPerDegree),
|
||||
point.X / Wgs84MeterPerDegree);
|
||||
YToLatitude(y / Wgs84MeterPerDegree),
|
||||
x / Wgs84MeterPerDegree);
|
||||
}
|
||||
|
||||
public static double LatitudeToY(double latitude)
|
||||
|
|
|
|||
|
|
@ -41,13 +41,11 @@ namespace MapControl
|
|||
}
|
||||
|
||||
UpdateData();
|
||||
InvalidateVisual(); // necessary for StreamGeometry
|
||||
}
|
||||
|
||||
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
|
||||
{
|
||||
UpdateData();
|
||||
InvalidateVisual(); // necessary for StreamGeometry
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -81,10 +79,7 @@ namespace MapControl
|
|||
|
||||
private void AddPolylinePoints(StreamGeometryContext context, IEnumerable<Location> locations, double longitudeOffset, bool closed)
|
||||
{
|
||||
var points = locations
|
||||
.Select(location => LocationToView(location, longitudeOffset))
|
||||
.Where(point => point.HasValue)
|
||||
.Select(point => point.Value);
|
||||
var points = LocationsToView(locations, longitudeOffset);
|
||||
|
||||
if (points.Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,10 +84,7 @@ namespace MapControl
|
|||
|
||||
private void AddPolylinePoints(PathFigureCollection figures, IEnumerable<Location> locations, double longitudeOffset, bool closed)
|
||||
{
|
||||
var points = locations
|
||||
.Select(location => LocationToView(location, longitudeOffset))
|
||||
.Where(point => point.HasValue)
|
||||
.Select(point => point.Value);
|
||||
var points = LocationsToView(locations, longitudeOffset);
|
||||
|
||||
if (points.Any())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue