// 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
}
}