using System;
using UnityEngine;
namespace FunkySheep.Earth.Map
{
public static class Utils
{
///
/// Get the map tile position depending on zoom level and GPS postions
///
///
public static Vector2Int GpsToMap(int zoom, double latitude, double longitude)
{
return new Vector2Int(
LongitudeToX(zoom, longitude),
LatitudeToZ(zoom, latitude)
);
}
///
/// Get the map tile position depending on zoom level and GPS postions
/// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers
///
///
public static Vector2 GpsToMapReal(int zoom, double latitude, double longitude)
{
Vector2 p = new Vector2();
p.x = (float)((longitude + 180.0) / 360.0 * (1 << zoom));
p.y = (float)((1.0 - Math.Log(Math.Tan(latitude * Math.PI / 180.0) +
1.0 / Math.Cos(latitude * Math.PI / 180.0)) / Math.PI) / 2.0 * (1 << zoom));
return p;
}
///
/// Get the map tile position depending on zoom level and GPS postions
/// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers
///
///
public static Vector2 GpsToMapReal(int zoom, double latitude, double longitude, Vector2 offset)
{
Vector2 p = new Vector2();
p.x = (float)(((longitude + 180.0) / 360.0 * (1 << zoom)) - offset.x);
p.y = (float)(((1.0 - Math.Log(Math.Tan(latitude * Math.PI / 180.0) +
1.0 / Math.Cos(latitude * Math.PI / 180.0)) / Math.PI) / 2.0 * (1 << zoom)) - offset.y);
return p;
}
///
/// Get the X number of the tile relative to Longitude position
///
///
public static int LongitudeToX(int zoom, double longitude)
{
return (int)(Math.Floor((longitude + 180.0) / 360.0 * (1 << zoom)));
}
///
/// Get the X number of the tile relative to Longitude position
///
///
public static float LongitudeToXReal(int zoom, double longitude)
{
return (float)((longitude + 180.0) / 360.0 * (1 << zoom));
}
///
/// Get the Real X number inside the tile
///
///
public static float LongitudeToInsideX(int zoom, double longitude)
{
return (float)((longitude + 180.0) / 360.0 * (1 << zoom) - LongitudeToX(zoom, longitude));
}
///
/// /// Get the Y number of the tile relative to Latitude position
/// /// !!! The Y position is the reverse of the cartesian one !!!
///
///
public static int LatitudeToZ(int zoom, double latitude)
{
return (int)Math.Floor((1 - Math.Log(Math.Tan(Mathf.Deg2Rad * latitude) + 1 / Math.Cos(Mathf.Deg2Rad * latitude)) / Math.PI) / 2 * (1 << zoom));
}
///
/// /// Get the Y number of the tile relative to Latitude position
/// /// !!! The Y position is the reverse of the cartesian one !!!
///
///
public static float LatitudeToZReal(int zoom, double latitude)
{
return (float)((1 - Math.Log(Math.Tan(Mathf.Deg2Rad * latitude)) / Math.PI) / 2 * (1 << zoom));
}
///
/// /// Get the Real Y number inside of the tile
///
///
public static float LatitudeToInsideZ(int zoom, double latitude)
{
return (float)((1 - Math.Log(Math.Tan(Mathf.Deg2Rad * latitude) + 1 / Math.Cos(Mathf.Deg2Rad * latitude)) / Math.PI) / 2 * (1 << zoom)) - LatitudeToZ(zoom, latitude);
}
///
/// Get the Longitude of the tile relative to X position
///
///
public static double tileX2long(int zoom, float xPosition)
{
return xPosition / (double)(1 << zoom) * 360.0 - 180;
}
///
/// Get the latitude of the tile relative to Y position
///
///
public static double tileZ2lat(int zoom, float zposition)
{
double n = Math.PI - 2.0 * Math.PI * zposition / (double)(1 << zoom);
return 180.0 / Math.PI * Math.Atan(0.5 * (Math.Exp(n) - Math.Exp(-n)));
}
///
/// Calculate size of the OSM tile depending on the zoomValue level and latitude
///
///
public static double TileSize(int zoom, double latitude)
{
return 156543.03 / Math.Pow(2, zoom) * Math.Cos(Mathf.Deg2Rad * latitude) * 256;
}
///
/// Calculate size of the OSM tile depending on the zoomValue level.
///
///
public static double TileSize(int zoom)
{
return 156543.03 / Math.Pow(2, zoom) * 256;
}
///
/// Calculate the GPS boundaries of a tile depending on zoom size
///
/// A Double[4] containing [StartLatitude, StartLongitude, EndLatitude, EndLongitude]
public static Double[] CaclulateGpsBoundaries(int zoom, double latitude, double longitude)
{
Vector2Int mapPosition = GpsToMap(zoom, latitude, longitude);
double startlatitude = Utils.tileZ2lat(zoom, mapPosition.y + 1);
double startlongitude = Utils.tileX2long(zoom, mapPosition.x);
double endLatitude = Utils.tileZ2lat(zoom, mapPosition.y);
double endLongitude = Utils.tileX2long(zoom, mapPosition.x + 1);
Double[] boundaries = new Double[4];
boundaries[0] = startlatitude;
boundaries[1] = startlongitude;
boundaries[2] = endLatitude;
boundaries[3] = endLongitude;
return boundaries;
}
///
/// Calculate the GPS boundaries of a tile depending on zoom size and the position on the map
///
/// A Double[4] containing [StartLatitude, StartLongitude, EndLatitude, EndLongitude]
public static Double[] CaclulateGpsBoundaries(int zoom, Vector2Int mapPosition)
{
double startlatitude = Utils.tileZ2lat(zoom, mapPosition.y + 1);
double startlongitude = Utils.tileX2long(zoom, mapPosition.x);
double endLatitude = Utils.tileZ2lat(zoom, mapPosition.y);
double endLongitude = Utils.tileX2long(zoom, mapPosition.x + 1);
Double[] boundaries = new Double[4];
boundaries[0] = startlatitude;
boundaries[1] = startlongitude;
boundaries[2] = endLatitude;
boundaries[3] = endLongitude;
return boundaries;
}
///
/// Convert from color channel values in 0.0-1.0 range to elevation in meters:
/// 21768
///
///
///
///
public static float ColorToElevation(Color color)
{
float height = (Mathf.Floor(color.r * 256.0f) * 256.0f + Mathf.Floor(color.g * 256.0f) + color.b) - 32768.0f;
return height;
}
}
}