Avoid unnecessary Location and Point allocations

This commit is contained in:
ClemensFischer 2025-12-12 21:28:45 +01:00
parent f44d2207e5
commit e268be2948
20 changed files with 205 additions and 172 deletions

View file

@ -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())
{

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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)
{

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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 &&

View file

@ -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)
{

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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)
{

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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())
{

View file

@ -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())
{