mirror of
https://github.com/farcasclaudiu/myfriendsaround.git
synced 2026-06-22 09:01:43 +03:00
144 lines
6.3 KiB
C#
144 lines
6.3 KiB
C#
//------------------------------------------------------------------------------
|
|
// Code source adopted from: http://msdn.microsoft.com/en-us/library/bb259689.aspx
|
|
//
|
|
// <copyright company="Microsoft">
|
|
// Copyright (c) 2006-2009 Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Text;
|
|
using System.Windows;
|
|
|
|
namespace GpsEmulator.Utilities
|
|
{
|
|
static class MapUtils
|
|
{
|
|
private const double EarthRadius = 6378137;
|
|
private const double MinLatitude = -85.05112878;
|
|
private const double MaxLatitude = 85.05112878;
|
|
private const double MinLongitude = -180;
|
|
private const double MaxLongitude = 180;
|
|
|
|
|
|
/// <summary>
|
|
/// Clips a number to the specified minimum and maximum values.
|
|
/// </summary>
|
|
/// <param name="n">The number to clip.</param>
|
|
/// <param name="minValue">Minimum allowable value.</param>
|
|
/// <param name="maxValue">Maximum allowable value.</param>
|
|
/// <returns>The clipped value.</returns>
|
|
public static double Clip(double n, double minValue, double maxValue)
|
|
{
|
|
return Math.Min(Math.Max(n, minValue), maxValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the map width and height (in pixels) at a specified level
|
|
/// of detail.
|
|
/// </summary>
|
|
/// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
|
|
/// to 23 (highest detail).</param>
|
|
/// <returns>The map width and height in pixels.</returns>
|
|
public static uint MapSize(int levelOfDetail)
|
|
{
|
|
return (uint) 256 << levelOfDetail;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the distance (in meters) between two points using the
|
|
/// Haversine formula.
|
|
/// </summary>
|
|
/// <param name="point1"></param>
|
|
/// <param name="point2"></param>
|
|
/// <returns></returns>
|
|
public static double GetDistance(Point point1, Point point2)
|
|
{
|
|
double dLat1InRad = point1.X * (Math.PI / 180);
|
|
double dLong1InRad = point1.Y * (Math.PI / 180);
|
|
double dLat2InRad = point2.X * (Math.PI / 180);
|
|
double dLong2InRad = point2.Y * (Math.PI / 180);
|
|
double dLongitude = dLong2InRad - dLong1InRad;
|
|
double dLatitude = dLat2InRad - dLat1InRad;
|
|
double a = Math.Pow(Math.Sin(dLatitude / 2), 2) + Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) * Math.Pow(Math.Sin(dLongitude / 2), 2);
|
|
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
|
double dDistance = EarthRadius * c;
|
|
return dDistance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a point from latitude/longitude WGS-84 coordinates (in degrees)
|
|
/// into pixel XY coordinates at a specified level of detail.
|
|
/// </summary>
|
|
/// <param name="latitude">Latitude of the point, in degrees.</param>
|
|
/// <param name="longitude">Longitude of the point, in degrees.</param>
|
|
/// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
|
|
/// to 23 (highest detail).</param>
|
|
/// <param name="pixelX">Output parameter receiving the X coordinate in pixels.</param>
|
|
/// <param name="pixelY">Output parameter receiving the Y coordinate in pixels.</param>
|
|
public static void LatLongToPixelXY(double latitude, double longitude, int levelOfDetail, out int pixelX, out int pixelY)
|
|
{
|
|
latitude = Clip(latitude, MinLatitude, MaxLatitude);
|
|
longitude = Clip(longitude, MinLongitude, MaxLongitude);
|
|
|
|
double x = (longitude + 180) / 360;
|
|
double sinLatitude = Math.Sin(latitude * Math.PI / 180);
|
|
double y = 0.5 - Math.Log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
|
|
|
|
uint mapSize = MapSize(levelOfDetail);
|
|
pixelX = (int) Clip(x * mapSize + 0.5, 0, mapSize - 1);
|
|
pixelY = (int) Clip(y * mapSize + 0.5, 0, mapSize - 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a pixel from pixel XY coordinates at a specified level of detail
|
|
/// into latitude/longitude WGS-84 coordinates (in degrees).
|
|
/// </summary>
|
|
/// <param name="pixelX">X coordinate of the point, in pixels.</param>
|
|
/// <param name="pixelY">Y coordinates of the point, in pixels.</param>
|
|
/// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
|
|
/// to 23 (highest detail).</param>
|
|
/// <param name="latitude">Output parameter receiving the latitude in degrees.</param>
|
|
/// <param name="longitude">Output parameter receiving the longitude in degrees.</param>
|
|
public static void PixelXYToLatLong(int pixelX, int pixelY, int levelOfDetail, out double latitude, out double longitude)
|
|
{
|
|
double mapSize = MapSize(levelOfDetail);
|
|
double x = (Clip(pixelX, 0, mapSize - 1) / mapSize) - 0.5;
|
|
double y = 0.5 - (Clip(pixelY, 0, mapSize - 1) / mapSize);
|
|
|
|
latitude = 90 - 360 * Math.Atan(Math.Exp(-y * 2 * Math.PI)) / Math.PI;
|
|
longitude = 360 * x;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts tile XY coordinates into a QuadKey at a specified level of detail.
|
|
/// </summary>
|
|
/// <param name="tileX">Tile X coordinate.</param>
|
|
/// <param name="tileY">Tile Y coordinate.</param>
|
|
/// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
|
|
/// to 23 (highest detail).</param>
|
|
/// <returns>A string containing the QuadKey.</returns>
|
|
public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
|
|
{
|
|
StringBuilder quadKey = new StringBuilder();
|
|
for (int i = levelOfDetail; i > 0; i--)
|
|
{
|
|
char digit = '0';
|
|
int mask = 1 << (i - 1);
|
|
if ((tileX & mask) != 0)
|
|
{
|
|
digit++;
|
|
}
|
|
if ((tileY & mask) != 0)
|
|
{
|
|
digit++;
|
|
digit++;
|
|
}
|
|
quadKey.Append(digit);
|
|
}
|
|
return quadKey.ToString();
|
|
}
|
|
|
|
}
|
|
}
|