// World Political Map - Globe Edition for Unity - Main Script // Created by Ramiro Oliva (Kronnect) // Don't modify this script - changes could be lost if you upgrade to a more recent version of WPM // *************************************************************************** // This is the public API file - every property or public method belongs here // *************************************************************************** using UnityEngine; using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Text; using WPM.Poly2Tri; namespace WPM { public static class Conversion { const float EARTH_RADIUS = 6371000f; #region Public Conversion API area /// /// Returns UV texture coordinates from latitude and longitude /// public static Vector2 GetUVFromLatLon(float lat, float lon) { Vector2 p; p.x = (lon + 180f) / 360f; p.y = (lat + 90f) / 180f; return p; } /// /// Returns UV texture coordinates from sphere coordinates /// public static Vector2 GetUVFromSpherePoint(Vector3 p) { float lat, lon; GetLatLonFromSpherePoint(p, out lat, out lon); return GetUVFromLatLon(lat, lon); } /// /// Converts latitude/longitude/altitude to sphere coordinates, optionally passing altitude in meters. /// Altitude is given in real world meters (Earth radius is 6371000 meters) /// /// In meters public static Vector3 GetSpherePointFromLatLon(double lat, double lon, double altitude = 0) { double phi = lat * 0.0174532924; //Mathf.Deg2Rad; double theta = (lon + 90.0) * 0.0174532924; //Mathf.Deg2Rad; double cosPhi = Math.Cos(phi); double h = 0.5 * (altitude + EARTH_RADIUS) / EARTH_RADIUS; double x = cosPhi * Math.Cos(theta) * h; double y = Math.Sin(phi) * h; double z = cosPhi * Math.Sin(theta) * h; return new Vector3((float)x, (float)y, (float)z); } /// /// Converts latitude/longitude/altitude to sphere coordinates, optionally passing altitude in meters. /// Altitude is given in real world meters (Earth radius is 6371000 meters) /// /// In meters public static Vector3 GetSpherePointFromLatLon(float lat, float lon, float altitude = 0f) { float phi = lat * Mathf.Deg2Rad; float theta = (lon + 90.0f) * Mathf.Deg2Rad; float cosPhi = Mathf.Cos(phi); float h = 0.5f * (altitude + EARTH_RADIUS) / EARTH_RADIUS; float x = cosPhi * Mathf.Cos(theta) * h; float y = Mathf.Sin(phi) * h; float z = cosPhi * Mathf.Sin(theta) * h; return new Vector3(x, y, z); } /// /// Converts latitude/longitude/altitude to sphere coordinates /// /// In meters public static Vector3 GetSpherePointFromLatLon(Vector2 latLon, float altitude = 0) { return GetSpherePointFromLatLon(latLon.x, latLon.y, altitude); } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out double lat, out double lon) { double phi = Math.Asin(p.y * 2.0); double theta = Math.Atan2(p.x, p.z); lat = phi * Mathf.Rad2Deg; lon = -theta * Mathf.Rad2Deg; } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out float lat, out float lon) { p.Normalize(); float phi = Mathf.Asin(p.y); float theta = Mathf.Atan2(p.x, p.z); lat = phi * Mathf.Rad2Deg; lon = -theta * Mathf.Rad2Deg; } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out Vector2 latLon) { float lat, lon; GetLatLonFromSpherePoint(p, out lat, out lon); latLon = new Vector2(lat, lon); } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out double lat, out double lon, out double altitude) { double h = p.magnitude; altitude = EARTH_RADIUS * (2.0 * h - 1.0); double px = p.x / h; double py = p.y / h; double pz = p.z / h; double phi = Math.Asin(py * 2.0); double theta = Math.Atan2(px, pz); lat = phi * Mathf.Rad2Deg; lon = -theta * Mathf.Rad2Deg; } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out float lat, out float lon, out float altitude) { float h = p.magnitude; altitude = EARTH_RADIUS * (2f * h - 1); float px = p.x / h; float py = p.y / h; float pz = p.z / h; float phi = Mathf.Asin(py); float theta = Mathf.Atan2(px, pz); lat = phi * Mathf.Rad2Deg; lon = -theta * Mathf.Rad2Deg; } /// /// Convertes sphere to latitude/longitude coordinates /// public static void GetLatLonFromSpherePoint(Vector3 p, out Vector2 latLon, out float altitude) { float lat, lon; GetLatLonFromSpherePoint(p, out lat, out lon, out altitude); latLon = new Vector2(lat, lon); } public static Vector2 GetLatLonFromBillboard(Vector2 position) { const float mapWidth = 200.0f; const float mapHeight = 100.0f; float lon = (position.x + mapWidth * 0.5f) * 360f / mapWidth - 180f; float lat = position.y * 180f / mapHeight; return new Vector2(lat, lon); } /// /// Gets the lat lon from UV coordinates (UV ranges from 0 to 1) /// /// The lat lon from U. /// Uv. public static Vector2 GetLatLonFromUV(Vector2 uv) { float lon = uv.x * 360f - 180f; float lat = (uv.y - 0.5f) * 2f * 90f; return new Vector2(lat, lon); } public static Vector2 GetBillboardPointFromLatLon(Vector2 latlon) { Vector2 p; float mapWidth = 200.0f; float mapHeight = 100.0f; p.x = (latlon.y + 180) * (mapWidth / 360f) - mapWidth * 0.5f; p.y = latlon.x * (mapHeight / 180f); return p; } public static Rect GetBillboardRectFromLatLonRect(Rect latlonRect) { Vector2 min = GetBillboardPointFromLatLon(latlonRect.min); Vector2 max = GetBillboardPointFromLatLon(latlonRect.max); return new Rect(min.x, min.y, Math.Abs(max.x - min.x), Mathf.Abs(max.y - min.y)); } public static Rect GetUVRectFromLatLonRect(Rect latlonRect) { Vector2 min = GetUVFromLatLon(latlonRect.min.x, latlonRect.min.y); Vector2 max = GetUVFromLatLon(latlonRect.max.x, latlonRect.max.y); return new Rect(min.x, min.y, Math.Abs(max.x - min.x), Mathf.Abs(max.y - min.y)); } /// /// Converts latitude/longitude to sphere coordinates /// public static Vector3 GetSpherePointFromLatLon(PolygonPoint point) { return GetSpherePointFromLatLon(point.X, point.Y, 0); } /// /// Converts latitude/longitude/altitude to sphere coordinates /// Altitude is given in real world meters (Earth radius is 6371000 meters) /// public static Vector3 GetSpherePointFromLatLon(PolygonPoint point, float altitude) { return GetSpherePointFromLatLon(point.X, point.Y, altitude); } /// /// Convertes sphere to latitude/longitude coordinates /// public static Vector2 GetLatLonFromSpherePoint(Vector3 p) { p.Normalize(); float phi = Mathf.Asin(p.y); float theta = Mathf.Atan2(p.x, p.z); return new Vector2(phi * Mathf.Rad2Deg, -theta * Mathf.Rad2Deg); } /// /// Converts unit sphere coordinate (-0.5 to 0.5 range in all x/y/z) to latitude/longitude coordinates /// public static Vector2 GetLatLonFromUnitSpherePoint(Vector3 p) { float phi = Mathf.Asin(p.y * 2f); float theta = Mathf.Atan2(p.x * 2f, p.z * 2f); return new Vector2(phi * Mathf.Rad2Deg, -theta * Mathf.Rad2Deg); } public static Vector2 ConvertToTextureCoordinates(Vector3 p, int width, int height) { float phi = Mathf.Asin(p.y * 2f); float theta = Mathf.Atan2(p.x, p.z); float lonDec = -theta * Mathf.Rad2Deg; float latDec = phi * Mathf.Rad2Deg; Vector2 o; o.x = (lonDec + 180) * width / 360.0f; o.y = latDec * (height / 180.0f) + height / 2.0f; return o; } public static int ConvertToTextureColorIndex(Vector3 p, int widthMinusOne, int heightMinusOne) { const float invPI = 1.0f / Mathf.PI; const float PI2 = Mathf.PI * 2.0f; float phi = Mathf.Asin(p.y * 2.0f); float theta = Mathf.Atan2(p.x, p.z); float tx = (-theta + Mathf.PI) / PI2; float ty = phi * invPI + 0.5f; return ((int)(ty * heightMinusOne)) * (widthMinusOne + 1) + (int)(tx * widthMinusOne); } public static Vector2 GetBillboardPosFromSpherePoint(Vector3 p) { float u = 1.25f - (Mathf.Atan2(p.z, -p.x) / (2.0f * Mathf.PI) + 0.5f); if (u > 1) u -= 1.0f; float v = Mathf.Asin(p.y * 2.0f) / Mathf.PI; return new Vector2(u * 2.0f - 1.0f, v) * 100.0f; } /// /// Returns the distance in meters between two sphere positions /// /// Position1. /// Position2. public static float Distance(Vector3 position1, Vector3 position2) { Vector2 latlon1 = GetLatLonFromSpherePoint(position1); Vector2 latlon2 = GetLatLonFromSpherePoint(position2); return Distance(latlon1.x, latlon1.y, latlon2.x, latlon2.y); } /// /// Returns distance in meters between two lat/lon coordinates /// public static float Distance(float latDec1, float lonDec1, float latDec2, float lonDec2) { float phi1 = latDec1 * Mathf.Deg2Rad; float phi2 = latDec2 * Mathf.Deg2Rad; float deltaPhi = (latDec2 - latDec1) * Mathf.Deg2Rad; float deltaLambda = (lonDec2 - lonDec1) * Mathf.Deg2Rad; float a = Mathf.Sin(deltaPhi / 2) * Mathf.Sin(deltaPhi / 2) + Mathf.Cos(phi1) * Mathf.Cos(phi2) * Mathf.Sin(deltaLambda / 2) * Mathf.Sin(deltaLambda / 2); float c = 2.0f * Mathf.Atan2(Mathf.Sqrt(a), Mathf.Sqrt(1.0f - a)); return c * EARTH_RADIUS; } /// /// Get tile coordinate which contains a given latitude/longitude /// /// Zoom level. /// Lat. /// Lon. /// Xtile. /// Ytile. public static void GetTileFromLatLon(int zoomLevel, float lat, float lon, out int xtile, out int ytile) { lat = Mathf.Clamp(lat, -85.051128f, 85.051128f); xtile = (int)((lon + 180.0) / 360.0 * (1 << zoomLevel)); ytile = (int)((1.0 - Math.Log(Math.Tan(lat * Math.PI / 180.0) + 1.0 / Math.Cos(lat * Math.PI / 180.0)) / Math.PI) / 2.0 * (1 << zoomLevel)); } /// /// Gets latitude/longitude of top/left corner for a given map tile /// /// The lat lon from tile. /// The x coordinate. /// The y coordinate. /// Zoom level. public static Vector2 GetLatLonFromTile(float x, float y, int zoomLevel) { double n = Math.PI - 2.0 * Math.PI * y / (1 << zoomLevel); double lat = 180.0 / Math.PI * Math.Atan(Math.Sinh(n)); double lon = x / (double)(1 << zoomLevel) * 360.0 - 180.0; return new Vector2((float)lat, (float)lon); } #endregion } }