/* INFINITY CODE */ /* https://infinity-code.com */ using System; using System.Text; using UnityEngine; namespace InfinityCode.RealWorldTerrain { /// /// Provides utility methods for geographic and Mercator coordinate conversions. /// public static class RealWorldTerrainGeo { /// /// The radius of the Earth. /// public const float EARTH_RADIUS = 6371; /// /// The length of the equator. /// public const int EQUATOR_LENGTH = 40075; /// /// The maximum elevation in the world. /// public const int MAX_ELEVATION = 15000; /// /// Converts geographic coordinates to SRTM data index. /// /// Geographic coordinates /// SRTM data index public static Vector2 LanLongToFlat(Vector2 pos) { return new Vector2(Mathf.FloorToInt(pos.x / 5.0f) * 5 + 180, 90 - Mathf.FloorToInt(pos.y / 5.0f) * 5); } /// /// Converts geographic coordinates to Mercator coordinates. /// /// Longitude /// Latitude public static void LatLongToMercat(ref double x, ref double y) { double sy = Math.Sin(y * RealWorldTerrainMath.DEG2RAD); x = (x + 180) / 360; y = 0.5 - Math.Log((1 + sy) / (1 - sy)) / (Math.PI * 4); } /// /// Converts geographic coordinates to Mercator coordinates. /// /// Longitude /// Latitude /// Output Mercator X /// Output Mercator Y public static void LatLongToMercat(double x, double y, out double mx, out double my) { double sy = Math.Sin(y * RealWorldTerrainMath.DEG2RAD); mx = (x + 180) / 360; my = 0.5 - Math.Log((1 + sy) / (1 - sy)) / (Math.PI * 4); } /// /// Converts geographic coordinates to the index of the tile. /// What is the tiles, and how it works, you can read here: /// https://developers.google.com/maps/documentation/javascript/v2/overlays?csw=1#Google_Maps_Coordinates /// /// Longitude /// Latitude /// Zoom /// Output tile X /// Output tile Y public static void LatLongToTile(double dx, double dy, int zoom, out double tx, out double ty) { LatLongToMercat(ref dx, ref dy); uint mapSize = (uint)RealWorldTerrainUtils.TILE_SIZE << zoom; double px = RealWorldTerrainMath.Clamp(dx * mapSize + 0.5, 0, mapSize - 1); double py = RealWorldTerrainMath.Clamp(dy * mapSize + 0.5, 0, mapSize - 1); tx = px / RealWorldTerrainUtils.TILE_SIZE; ty = py / RealWorldTerrainUtils.TILE_SIZE; } /// /// Converts Mercator coordinates to geographic coordinates. /// /// Mercator X /// Mercator Y /// Output longitude /// Output latitude public static void MercatToLatLong(double mx, double my, out double x, out double y) { uint mapSize = (uint)RealWorldTerrainUtils.TILE_SIZE << 20; double px = RealWorldTerrainMath.Clamp(mx * mapSize + 0.5, 0, mapSize - 1); double py = RealWorldTerrainMath.Clamp(my * mapSize + 0.5, 0, mapSize - 1); mx = px / RealWorldTerrainUtils.TILE_SIZE; my = py / RealWorldTerrainUtils.TILE_SIZE; TileToLatLong(mx, my, 20, out x, out y); } /// /// Converts tile coordinates to geographic coordinates. /// /// Tile X /// Tile Y /// Zoom level /// Output longitude /// Output latitude public static void TileToLatLong(double tx, double ty, int zoom, out double lx, out double ly) { double mapSize = RealWorldTerrainUtils.TILE_SIZE << zoom; lx = 360 * (RealWorldTerrainMath.Repeat(tx * RealWorldTerrainUtils.TILE_SIZE, 0, mapSize - 1) / mapSize - 0.5); ly = 90 - 360 * Math.Atan(Math.Exp(-(0.5 - RealWorldTerrainMath.Clamp(ty * RealWorldTerrainUtils.TILE_SIZE, 0, mapSize - 1) / mapSize) * 2 * Math.PI)) / Math.PI; } /// /// Converts tile index to quadkey. /// What is the tiles and quadkey, and how it works, you can read here: /// http://msdn.microsoft.com/en-us/library/bb259689.aspx /// /// Tile X /// Tile Y /// Zoom /// Quadkey public static string TileToQuadKey(int x, int y, int zoom) { StringBuilder quadKey = new StringBuilder(); for (int i = zoom; i > 0; i--) { char digit = '0'; int mask = 1 << (i - 1); if ((x & mask) != 0) digit++; if ((y & mask) != 0) { digit++; digit++; } quadKey.Append(digit); } return quadKey.ToString(); } } }