/* INFINITY CODE 2013-2019 */ /* http://www.infinity-code.com */ using System; using System.Collections.Generic; using UnityEngine; namespace InfinityCode.RealWorldTerrain { /// /// This class contains all the information about the terrain and Real World Terrain settings. /// public abstract class RealWorldTerrainMonoBase : MonoBehaviour { /// /// Coordinates borders of terrain /// // public Rect area; public Bounds bounds; public bool generateGrass; public bool generatedRivers; public bool generateRoads; /// /// Specifies whether to create textures /// public bool generateTextures; public bool generateTrees; /// /// Specifies whether to create buildings /// public bool generatedBuildings; /// /// Specifies whether to create grass /// public bool generatedGrass; /// /// Specifies whether to create textures /// public bool generatedTextures; /// /// Specifies whether to create trees /// public bool generatedTrees; /// /// Maximal value of elevation /// public double maxElevation; /// /// Minimal value of elevation /// public double minElevation; /// /// Reference to the preferences /// public RealWorldTerrainPrefsBase prefs; /// /// Scale of terrains /// public Vector3 scale; /// /// Size of terrains in world units /// public Vector3 size; /// /// Top latitude /// public double topLatitude; /// /// Top latitude in Mercator projection (0-1) /// public double topMercator; /// /// Left longitude /// public double leftLongitude; /// /// Left longitude in Mercator projection (0-1) /// public double leftMercator; /// /// Bottom latitude /// public double bottomLatitude; /// /// Bottom latitude in Mercator projection (0-1) /// public double bottomMercator; /// /// Right longitude /// public double rightLongitude; /// /// Right longitude in Mercator projection (0-1) /// public double rightMercator; /// /// Width. Right longitude - left longitude /// public double width; /// /// Height. Top latitude - bottom latitude /// public double height; #if BUILDR2 public List buildR2Facades; #endif private Dictionary customFields; public double mercatorWidth; public double mercatorHeight; public object this[string key] { get { if (customFields == null) return null; object value; if (!customFields.TryGetValue(key, out value)) return null; return value; } set { if (customFields == null) customFields = new Dictionary(); if (value != null) customFields[key] = value; else customFields.Remove(key); } } public void ClearCustomFields() { customFields = null; } /// /// Checks whether the coordinate in terrain area. /// /// Coordinate /// True - coordinate in area, False - otherwise. public bool Contains(Vector2 coordinates) { return Contains(coordinates.x, coordinates.y); } /// /// Checks whether the coordinate in terrain area. /// /// Longitude /// Latitude /// True - coordinate in area, False - otherwise. public bool Contains(double lng, double lat) { return leftLongitude <= lng && rightLongitude >= lng && topLatitude >= lat && bottomLatitude <= lat; } /// /// Get altitude by location (coordinates). /// /// Longitude /// Latitude /// Altitude (meters) public double GetAltitudeByCoordinates(double lng, double lat) { if (!Contains(lng, lat)) return 0; Vector3 worldPosition; GetWorldPosition(lng, lat, out worldPosition); Bounds b = new Bounds(bounds.center + transform.position, bounds.size); Vector3 offset = worldPosition - b.min; if (prefs.resultType == RealWorldTerrainResultType.terrain) { RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition); return offset.y / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation); } return worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation; } /// /// Get altitude by location (coordinates). /// /// Longitude /// Latitude /// Altitude (meters) [Obsolete("Use GetAltitudeByCoordinates")] public double GetAltitudeByLocation(double lng, double lat) { return GetAltitudeByCoordinates(lng, lat); } /// /// Get altitude by Unity World Position. /// /// Unity World Position /// Altitude (meters) public double GetAltitudeByWorldPosition(Vector3 worldPosition) { Bounds b = new Bounds(bounds.center + transform.position, bounds.size); Vector3 offset = worldPosition - b.min; if (offset.x < 0 || offset.z < 0) return 0; if (offset.x > b.size.x || offset.z > b.size.z) return 0; if (prefs.resultType == RealWorldTerrainResultType.terrain) { RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition); return offset.y / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation); } return worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation; } /// /// Get coordinates under mouse cursor /// /// Geographical coordinates /// Camera /// True - success, False - otherwise public bool GetCoordinatesUnderCursor(out Vector2 coordinates, Camera cam = null) { return GetCoordinatesByScreenPosition(Input.mousePosition, out coordinates, cam); } /// /// Converts the screen coordinates into geographic coordinates. /// /// Position in screen space /// Geographic coordinates /// Camera /// True - screen coordinates on terrains, False - otherwise public bool GetCoordinatesByScreenPosition(Vector2 screenPosition, out Vector2 coordinates, Camera cam = null) { if (cam == null) cam = Camera.main; coordinates = Vector2.zero; RaycastHit[] hits = Physics.RaycastAll(cam.ScreenPointToRay(screenPosition)); for (int i = 0; i < hits.Length; i++) { RaycastHit hit = hits[i]; if (hit.collider is TerrainCollider || hit.collider is MeshCollider) { RealWorldTerrainItem item = hit.transform.GetComponent(); if (item != null) return GetCoordinatesByWorldPosition(hit.point, out coordinates); } } return false; } /// /// Converts the screen coordinates into geographic coordinates. /// /// Position in screen space /// Longitude /// Latitude /// Altitude /// Camera /// True - screen coordinates on terrains, False - otherwise public bool GetCoordinatesByScreenPosition(Vector2 screenPosition, out double longitude, out double latitude, out double altitude, Camera cam = null) { if (cam == null) cam = Camera.main; longitude = latitude = altitude = 0; RaycastHit[] hits = Physics.RaycastAll(cam.ScreenPointToRay(screenPosition)); for (int i = 0; i < hits.Length; i++) { RaycastHit hit = hits[i]; if (hit.collider is TerrainCollider || hit.collider is MeshCollider) { RealWorldTerrainItem item = hit.transform.GetComponent(); if (item != null) return GetCoordinatesByWorldPosition(hit.point, out longitude, out latitude, out altitude); } } return false; } /// /// Converts the world coordinates into geographic coordinates. /// /// Position in Unity World Space /// Geographic coordinates /// True - world coordinates on terrains, False - otherwise public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out Vector2 coordinates) { coordinates = new Vector2(); double lng, lat; bool result = GetCoordinatesByWorldPosition(worldPosition, out lng, out lat); coordinates.x = (float)lng; coordinates.y = (float)lat; return result; } /// /// Converts the world coordinates into geographic coordinates. /// /// Position in Unity World Space /// Longitude /// Latitude /// True - world coordinates on terrains, False - otherwise public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out double longitude, out double latitude) { Bounds b = new Bounds(bounds.center + transform.position, bounds.size); double wrx = (worldPosition.x - b.min.x) / b.size.x; double wrz = (b.max.z - worldPosition.z) / b.size.z; double px = (rightMercator - leftMercator) * wrx + leftMercator; double pz = (bottomMercator - topMercator) * wrz + topMercator; RealWorldTerrainUtils.MercatToLatLong(px, pz, out longitude, out latitude); return b.Contains(worldPosition); } /// /// Converts the world coordinates into geographic coordinates. /// /// Position in Unity World Space /// Longitude /// Latitude /// Altitude /// True - world coordinates on terrains, False - otherwise public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out double longitude, out double latitude, out double altitude) { altitude = 0; Bounds b = new Bounds(bounds.center + transform.position, bounds.size); double wrx = (worldPosition.x - b.min.x) / b.size.x; double wrz = (b.max.z - worldPosition.z) / b.size.z; double px1 = (rightMercator - leftMercator) * wrx + leftMercator; double pz = (bottomMercator - topMercator) * wrz + topMercator; RealWorldTerrainUtils.MercatToLatLong(px1, pz, out longitude, out latitude); if (b.min.x > worldPosition.x || b.max.x < worldPosition.x || b.min.z > worldPosition.z || b.max.z < worldPosition.z) { return false; } Vector3 offset = worldPosition - b.min; if (prefs.resultType == RealWorldTerrainResultType.terrain) { RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition); altitude = (offset.y + currentItem.transform.position.y) / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation) + currentItem.minElevation; } else { altitude = worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation; } return true; } /// /// Get RealWorldTerrainItem by Unity World Position. /// /// Position in Unity World Space /// Instance of RealWorldTerrainItem public abstract RealWorldTerrainItem GetItemByWorldPosition(Vector3 worldPosition); /// /// Get Unity World Position by geographic coordinates. /// /// Longitude /// Latitde /// Position in Unity World Space /// True - success, False - otherwise public abstract bool GetWorldPosition(double lng, double lat, out Vector3 worldPosition); /// /// Get Unity World Position by geographic coordinates. /// /// Longitude /// Latitude /// Altitude /// Position in Unity World Space /// True - success, False - otherwise public bool GetWorldPosition(double lng, double lat, double altitude, out Vector3 worldPosition) { bool result = GetWorldPosition(lng, lat, out worldPosition); if (result) worldPosition.y = (float)(bounds.size.y * ((altitude - minElevation) / (maxElevation - minElevation))); return result; } /// /// Get Unity World Position by geographic coordinates. /// /// Geographic coordinates /// Position in Unity World Space /// public abstract bool GetWorldPosition(Vector2 coordinates, out Vector3 worldPosition); public void SetCoordinates(double x1, double y1, double x2, double y2, double tlx, double tly, double brx, double bry) { leftMercator = x1; topMercator = y1; rightMercator = x2; bottomMercator = y2; leftLongitude = tlx; rightLongitude = brx; topLatitude = tly; bottomLatitude = bry; width = rightLongitude - leftLongitude; height = bottomLatitude - topLatitude; mercatorWidth = rightMercator - leftMercator; mercatorHeight = bottomMercator - topMercator; } } }