2017-06-25 23:05:48 +02:00
|
|
|
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
2022-01-14 20:22:56 +01:00
|
|
|
|
// © 2022 Clemens Fischer
|
2017-06-25 23:05:48 +02:00
|
|
|
|
// Licensed under the Microsoft Public License (Ms-PL)
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
2021-11-17 23:17:11 +01:00
|
|
|
|
#if WINUI || UWP
|
2017-06-25 23:05:48 +02:00
|
|
|
|
using Windows.Foundation;
|
|
|
|
|
|
#else
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
namespace MapControl
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Base class for azimuthal map projections.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract class AzimuthalProjection : MapProjection
|
|
|
|
|
|
{
|
|
|
|
|
|
public override Rect BoundingBoxToRect(BoundingBox boundingBox)
|
|
|
|
|
|
{
|
2022-02-22 22:12:15 +01:00
|
|
|
|
var center = LocationToMap(boundingBox.Center);
|
2022-02-22 22:51:05 +01:00
|
|
|
|
var width = boundingBox.Width * Wgs84MetersPerDegree;
|
|
|
|
|
|
var height = boundingBox.Height * Wgs84MetersPerDegree;
|
2017-06-25 23:05:48 +02:00
|
|
|
|
|
2022-02-22 22:51:05 +01:00
|
|
|
|
return new Rect(center.X - width / 2d, center.Y - height / 2d, width, height);
|
2017-06-25 23:05:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override BoundingBox RectToBoundingBox(Rect rect)
|
|
|
|
|
|
{
|
2020-03-26 19:08:20 +01:00
|
|
|
|
var center = MapToLocation(new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d));
|
2022-02-22 22:51:05 +01:00
|
|
|
|
var width = rect.Width / Wgs84MetersPerDegree;
|
|
|
|
|
|
var height = rect.Height / Wgs84MetersPerDegree;
|
2017-06-25 23:05:48 +02:00
|
|
|
|
|
2022-02-22 22:51:05 +01:00
|
|
|
|
return new CenteredBoundingBox(center, width, height);
|
2017-06-25 23:05:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-12-20 21:55:12 +01:00
|
|
|
|
/// Calculates azimuth and spherical distance in radians from location1 to location2.
|
2017-06-25 23:05:48 +02:00
|
|
|
|
/// The returned distance has to be multiplied with an appropriate earth radius.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void GetAzimuthDistance(Location location1, Location location2, out double azimuth, out double distance)
|
|
|
|
|
|
{
|
|
|
|
|
|
var lat1 = location1.Latitude * Math.PI / 180d;
|
|
|
|
|
|
var lon1 = location1.Longitude * Math.PI / 180d;
|
|
|
|
|
|
var lat2 = location2.Latitude * Math.PI / 180d;
|
|
|
|
|
|
var lon2 = location2.Longitude * Math.PI / 180d;
|
|
|
|
|
|
var cosLat1 = Math.Cos(lat1);
|
|
|
|
|
|
var sinLat1 = Math.Sin(lat1);
|
|
|
|
|
|
var cosLat2 = Math.Cos(lat2);
|
|
|
|
|
|
var sinLat2 = Math.Sin(lat2);
|
|
|
|
|
|
var cosLon12 = Math.Cos(lon2 - lon1);
|
|
|
|
|
|
var sinLon12 = Math.Sin(lon2 - lon1);
|
|
|
|
|
|
var cosDistance = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosLon12;
|
|
|
|
|
|
|
|
|
|
|
|
azimuth = Math.Atan2(sinLon12, cosLat1 * sinLat2 / cosLat2 - sinLat1 * cosLon12);
|
2018-02-09 17:43:47 +01:00
|
|
|
|
distance = Math.Acos(Math.Min(Math.Max(cosDistance, -1d), 1d));
|
2017-06-25 23:05:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-12-20 21:55:12 +01:00
|
|
|
|
/// Calculates the Location of the point given by azimuth and spherical distance in radians from location.
|
2017-06-25 23:05:48 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static Location GetLocation(Location location, double azimuth, double distance)
|
|
|
|
|
|
{
|
2019-12-16 18:35:04 +01:00
|
|
|
|
var lat = location.Latitude;
|
|
|
|
|
|
var lon = location.Longitude;
|
|
|
|
|
|
|
|
|
|
|
|
if (distance > 0d)
|
|
|
|
|
|
{
|
|
|
|
|
|
var lat1 = lat * Math.PI / 180d;
|
|
|
|
|
|
var sinDistance = Math.Sin(distance);
|
|
|
|
|
|
var cosDistance = Math.Cos(distance);
|
|
|
|
|
|
var cosAzimuth = Math.Cos(azimuth);
|
|
|
|
|
|
var sinAzimuth = Math.Sin(azimuth);
|
|
|
|
|
|
var cosLat1 = Math.Cos(lat1);
|
|
|
|
|
|
var sinLat1 = Math.Sin(lat1);
|
|
|
|
|
|
var sinLat2 = sinLat1 * cosDistance + cosLat1 * sinDistance * cosAzimuth;
|
|
|
|
|
|
var lat2 = Math.Asin(Math.Min(Math.Max(sinLat2, -1d), 1d));
|
|
|
|
|
|
var dLon = Math.Atan2(sinDistance * sinAzimuth, cosLat1 * cosDistance - sinLat1 * sinDistance * cosAzimuth);
|
|
|
|
|
|
|
|
|
|
|
|
lat = lat2 * 180d / Math.PI;
|
|
|
|
|
|
lon += dLon * 180d / Math.PI;
|
|
|
|
|
|
}
|
2017-06-25 23:05:48 +02:00
|
|
|
|
|
2019-12-16 18:35:04 +01:00
|
|
|
|
return new Location(lat, lon);
|
2017-06-25 23:05:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|