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