Unity 经纬度转空间坐标及墨卡托坐标转经纬度等

注:此案例中有用到Mapbox相关库

1. 创建由于Vector2d 结构体

原因:由于Unity中自带的Vector2是float类型,而我们需要用一个结构体来储存精度需求比较高的经纬度数据,故创建Vector2d 及double类型的来储存经纬度数据

namespace Mapbox.Utils
{
    
    
    using Mapbox.Json; //此处用到的是Mapbox的Json库
    using System;
	using System.Globalization;

	[Serializable]
	public struct Vector2d
	{
    
    
		public const double kEpsilon = 1E-05d;
		public double x;
		public double y;

		public double this[int index]
		{
    
    
			get
			{
    
    
				switch (index)
				{
    
    
					case 0:
						return this.x;
					case 1:
						return this.y;
					default:
						throw new IndexOutOfRangeException("Invalid Vector2d index!");
				}
			}
			set
			{
    
    
				switch (index)
				{
    
    
					case 0:
						this.x = value;
						break;
					case 1:
						this.y = value;
						break;
					default:
						throw new IndexOutOfRangeException("Invalid Vector2d index!");
				}
			}
		}

		[JsonIgnore]
		public Vector2d normalized
		{
    
    
			get
			{
    
    
				Vector2d vector2d = new Vector2d(this.x, this.y);
				vector2d.Normalize();
				return vector2d;
			}
		}

		[JsonIgnore]
		public double magnitude
		{
    
    
			get
			{
    
    
				return Mathd.Sqrt(this.x * this.x + this.y * this.y);
			}
		}

		[JsonIgnore]
		public double sqrMagnitude
		{
    
    
			get
			{
    
    
				return this.x * this.x + this.y * this.y;
			}
		}

		public static Vector2d zero
		{
    
    
			get
			{
    
    
				return new Vector2d(0.0d, 0.0d);
			}
		}

		public static Vector2d one
		{
    
    
			get
			{
    
    
				return new Vector2d(1d, 1d);
			}
		}

		public static Vector2d up
		{
    
    
			get
			{
    
    
				return new Vector2d(0.0d, 1d);
			}
		}

		public static Vector2d right
		{
    
    
			get
			{
    
    
				return new Vector2d(1d, 0.0d);
			}
		}

        public static Vector2d ChongMingLatLon
        {
    
    
            get
            {
    
    
                return new Vector2d(Constants.ChongMingLatitude,Constants.ChongMingLongitude);
            }
        }

		public Vector2d(double x, double y)
		{
    
    
			this.x = x;
			this.y = y;
		}

		public static Vector2d operator +(Vector2d a, Vector2d b)
		{
    
    
			return new Vector2d(a.x + b.x, a.y + b.y);
		}

		public static Vector2d operator -(Vector2d a, Vector2d b)
		{
    
    
			return new Vector2d(a.x - b.x, a.y - b.y);
		}

		public static Vector2d operator -(Vector2d a)
		{
    
    
			return new Vector2d(-a.x, -a.y);
		}

		public static Vector2d operator *(Vector2d a, double d)
		{
    
    
			return new Vector2d(a.x * d, a.y * d);
		}

		public static Vector2d operator *(float d, Vector2d a)
		{
    
    
			return new Vector2d(a.x * d, a.y * d);
		}

		public static Vector2d operator /(Vector2d a, double d)
		{
    
    
			return new Vector2d(a.x / d, a.y / d);
		}

		public static bool operator ==(Vector2d lhs, Vector2d rhs)
		{
    
    
			return Vector2d.SqrMagnitude(lhs - rhs) < 0.0 / 1.0;
		}

		public static bool operator !=(Vector2d lhs, Vector2d rhs)
		{
    
    
			return (double)Vector2d.SqrMagnitude(lhs - rhs) >= 0.0 / 1.0;
		}

		public void Set(double new_x, double new_y)
		{
    
    
			this.x = new_x;
			this.y = new_y;
		}

		public static Vector2d Lerp(Vector2d from, Vector2d to, double t)
		{
    
    
			t = Mathd.Clamp01(t);
			return new Vector2d(from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t);
		}

		public static Vector2d MoveTowards(Vector2d current, Vector2d target, double maxDistanceDelta)
		{
    
    
			Vector2d vector2 = target - current;
			double magnitude = vector2.magnitude;
			if (magnitude <= maxDistanceDelta || magnitude == 0.0d)
				return target;
			else
				return current + vector2 / magnitude * maxDistanceDelta;
		}

		public static Vector2d Scale(Vector2d a, Vector2d b)
		{
    
    
			return new Vector2d(a.x * b.x, a.y * b.y);
		}

		public void Scale(Vector2d scale)
		{
    
    
			this.x *= scale.x;
			this.y *= scale.y;
		}

		public void Normalize()
		{
    
    
			double magnitude = this.magnitude;
			if (magnitude > 9.99999974737875E-06)
				this = this / magnitude;
			else
				this = Vector2d.zero;
		}

		public override string ToString()
		{
    
    
			return string.Format(NumberFormatInfo.InvariantInfo, "{0:F5},{1:F5}", this.y, this.x);
		}

		public override int GetHashCode()
		{
    
    
			return this.x.GetHashCode() ^ this.y.GetHashCode() << 2;
		}

		public override bool Equals(object other)
		{
    
    
			if (!(other is Vector2d))
				return false;
			Vector2d vector2d = (Vector2d)other;
			if (this.x.Equals(vector2d.x))
				return this.y.Equals(vector2d.y);
			else
				return false;
		}

		public static double Dot(Vector2d lhs, Vector2d rhs)
		{
    
    
			return lhs.x * rhs.x + lhs.y * rhs.y;
		}

		public static double Angle(Vector2d from, Vector2d to)
		{
    
    
			return Mathd.Acos(Mathd.Clamp(Vector2d.Dot(from.normalized, to.normalized), -1d, 1d)) * 57.29578d;
		}

		public static double Distance(Vector2d a, Vector2d b)
		{
    
    
			return (a - b).magnitude;
		}

		public static Vector2d ClampMagnitude(Vector2d vector, double maxLength)
		{
    
    
			if (vector.sqrMagnitude > maxLength * maxLength)
				return vector.normalized * maxLength;
			else
				return vector;
		}

		public static double SqrMagnitude(Vector2d a)
		{
    
    
			return (a.x * a.x + a.y * a.y);
		}

		public double SqrMagnitude()
		{
    
    
			return (this.x * this.x + this.y * this.y);
		}

		public static Vector2d Min(Vector2d lhs, Vector2d rhs)
		{
    
    
			return new Vector2d(Mathd.Min(lhs.x, rhs.x), Mathd.Min(lhs.y, rhs.y));
		}

		public static Vector2d Max(Vector2d lhs, Vector2d rhs)
		{
    
    
			return new Vector2d(Mathd.Max(lhs.x, rhs.x), Mathd.Max(lhs.y, rhs.y));
		}

		public double[] ToArray()
		{
    
    
			double[] array =
			{
    
    
					this.x,
					this.y
				};

			return array;
		}
	}
}

RectD 结构体

namespace Mapbox.Utils
{
    
    
    /// <summary>
    /// 存放的是最小值、最大值、大小、以及中心点
    /// </summary>
    public struct RectD
    {
    
    
        public Vector2d Min {
    
     get; private set; }
        public Vector2d Max {
    
     get; private set; }
        //size is absolute width&height so Min+size != max
        public Vector2d Size {
    
     get; private set; }
        public Vector2d Center {
    
     get; private set; }
        
        public RectD(Vector2d min, Vector2d size)
        {
    
    
            Min = min;
            Max = min + size;
            Center = new Vector2d(Min.x + size.x / 2, Min.y + size.y / 2);
            Size = new Vector2d(Mathd.Abs(size.x), Mathd.Abs(size.y));
        }

        public bool Contains(Vector2d point)
        {
    
    
            bool flag = Size.x < 0.0 && point.x <= Min.x && point.x > (Min.x + Size.x) || Size.x >= 0.0 && point.x >= Min.x && point.x < (Min.x + Size.x);
            return flag && (Size.y < 0.0 && point.y <= Min.y && point.y > (Min.y + Size.y) || Size.y >= 0.0 && point.y >= Min.y && point.y < (Min.y + Size.y));
        }
    }
}

以下为坐标转换代码(此代码中包含与MapBox Tile 相关转换方法,如没有用到Tile可忽略):

namespace Mapbox.Unity.Utilities
{
    
    
	using System;
    using Mapbox.Utils; // Vector2d 所在的库需要引用进来
	using UnityEngine;
	using System.Globalization;

    /// <summary>
    /// A set of Geo and Terrain Conversion utils.
    /// </summary>
    public static class Conversions
	{
    
    
		private const int TileSize = 256;
		/// <summary>according to https://wiki.openstreetmap.org/wiki/Zoom_levels</summary>
		private const int EarthRadius = 6378137; //no seams with globe example
		private const double InitialResolution = 2 * Math.PI * EarthRadius / TileSize;
		private const double OriginShift = 2 * Math.PI * EarthRadius / 2;
        private const double EARTH_RADIUS = 6378137.0;//地球半径

        /// <summary>
        /// Converts <see cref="T:Mapbox.Utils.Vector2d"/> struct, WGS84
        /// lat/lon to Spherical Mercator EPSG:900913 xy meters.
        /// </summary>
        /// <param name="v"> The <see cref="T:Mapbox.Utils.Vector2d"/>. </param>
        /// <returns> A <see cref="T:UnityEngine.Vector2d"/> of coordinates in meters. </returns>
        public static Vector2d LatLonToMeters(Vector2d v)
        {
    
    
            return LatLonToMeters(v.x, v.y);
        }

        /// <summary>
        /// Convert a simple string to a latitude longitude.
        /// Expects format: latitude, longitude
        /// </summary>
        /// <returns>The lat/lon as Vector2d.</returns>
        /// <param name="s">string.</param>
        public static Vector2d StringToLatLon(string s)
		{
    
    
			var latLonSplit = s.Split(',');
			if (latLonSplit.Length != 2)
			{
    
    
				throw new ArgumentException("Wrong number of arguments");
			}

			double latitude = 0;
			double longitude = 0;

			if (!double.TryParse(latLonSplit[0], NumberStyles.Any, NumberFormatInfo.InvariantInfo, out latitude))
			{
    
    
				throw new Exception(string.Format("Could not convert latitude to double: {0}", latLonSplit[0]));
			}

			if (!double.TryParse(latLonSplit[1], NumberStyles.Any, NumberFormatInfo.InvariantInfo, out longitude))
			{
    
    
				throw new Exception(string.Format("Could not convert longitude to double: {0}", latLonSplit[1]));
			}

			return new Vector2d(latitude, longitude);
		}

		/// <summary>
		/// Converts WGS84 lat/lon to Spherical Mercator EPSG:900913 xy meters.
		/// SOURCE: http://stackoverflow.com/questions/12896139/geographic-coordinates-converter.
		/// </summary>
		/// <param name="lat"> The latitude. </param>
		/// <param name="lon"> The longitude. </param>
		/// <returns> A <see cref="T:UnityEngine.Vector2d"/> of xy meters. </returns>
		public static Vector2d LatLonToMeters(double lat, double lon)
		{
    
    
			var posx = lon * OriginShift / 180;
			var posy = Math.Log(Math.Tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
			posy = posy * OriginShift / 180;
			return new Vector2d(posx, posy);
		}

		/// <summary>
		/// Converts WGS84 lat/lon to x/y meters in reference to a center point
		/// </summary>
		/// <param name="lat"> The latitude. </param>
		/// <param name="lon"> The longitude. </param>
		/// <param name="refPoint"> A <see cref="T:UnityEngine.Vector2d"/> center point to offset resultant xy, this is usually map's center mercator</param>
		/// <param name="scale"> Scale in meters. (default scale = 1) </param>
		/// <returns> A <see cref="T:UnityEngine.Vector2d"/> xy tile ID. </returns>
		/// <example>
		/// Converts a Lat/Lon of (37.7749, 122.4194) into Unity coordinates for a map centered at (10,10) and a scale of 2.5 meters for every 1 Unity unit 
		/// <code>
		/// var worldPosition = Conversions.GeoToWorldPosition(37.7749, 122.4194, new Vector2d(10, 10), (float)2.5);
		/// // worldPosition = ( 11369163.38585, 34069138.17805 )
		/// </code>
		/// </example>
		public static Vector2d GeoToWorldPosition(double lat, double lon, Vector2d refPoint, float scale = 1)
		{
    
    
			var posx = lon * OriginShift / 180;
			var posy = Math.Log(Math.Tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
			posy = posy * OriginShift / 180;
			return new Vector2d((posx - refPoint.x) * scale, (posy - refPoint.y) * scale);
		}

		public static Vector2d GeoToWorldPosition(Vector2d latLong, Vector2d refPoint, float scale = 1)
		{
    
    
			return GeoToWorldPosition(latLong.x, latLong.y, refPoint, scale);
		}

		public static Vector3 GeoToWorldGlobePosition(double lat, double lon, float radius)
		{
    
    
			double xPos = (radius) * Math.Cos(Mathf.Deg2Rad * lat) * Math.Cos(Mathf.Deg2Rad * lon);
			double zPos = (radius) * Math.Cos(Mathf.Deg2Rad * lat) * Math.Sin(Mathf.Deg2Rad * lon);
			double yPos = (radius) * Math.Sin(Mathf.Deg2Rad * lat);

			return new Vector3((float)xPos, (float)yPos, (float)zPos);
		}


		public static Vector3 GeoToWorldGlobePosition(Vector2d latLong, float radius)
		{
    
    
			return GeoToWorldGlobePosition(latLong.x, latLong.y, radius);
		}

		public static Vector2d GeoFromGlobePosition(Vector3 point, float radius)
		{
    
    
			float latitude = Mathf.Asin(point.y / radius);
			float longitude = Mathf.Atan2(point.z, point.x);
			return new Vector2d(latitude * Mathf.Rad2Deg, longitude * Mathf.Rad2Deg);
		}

		/// <summary>
		/// Converts Spherical Mercator EPSG:900913 in xy meters to WGS84 lat/lon. 
		/// Inverse of LatLonToMeters.
		/// </summary>
		/// <param name="m"> A <see cref="T:UnityEngine.Vector2d"/> of coordinates in meters.  </param>
		/// <returns> The <see cref="T:Mapbox.Utils.Vector2d"/> in lat/lon. </returns>

		/// <example>
		/// Converts EPSG:900913 xy meter coordinates to lat lon 
		/// <code>
		/// var worldPosition =  new Vector2d (4547675.35434,13627665.27122);
		/// var latlon = Conversions.MetersToLatLon(worldPosition);
		/// // latlon = ( 37.77490, 122.41940 )
		/// </code>
		/// </example>
		public static Vector2d MetersToLatLon(Vector2d m)
		{
    
    
			var vx = (m.x / OriginShift) * 180;
			var vy = (m.y / OriginShift) * 180;
			vy = 180 / Math.PI * (2 * Math.Atan(Math.Exp(vy * Math.PI / 180)) - Math.PI / 2);
			return new Vector2d(vy, vx);
		}

		/// <summary>
		/// Gets the xy tile ID from Spherical Mercator EPSG:900913 xy coords.
		/// </summary>
		/// <param name="m"> <see cref="T:UnityEngine.Vector2d"/> XY coords in meters. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> A <see cref="T:UnityEngine.Vector2d"/> xy tile ID. </returns>
		/// 
		/// <example>
		/// Converts EPSG:900913 xy meter coordinates to web mercator tile XY coordinates at zoom 12.
		/// <code>
		/// var meterXYPosition = new Vector2d (4547675.35434,13627665.27122);
		/// var tileXY = Conversions.MetersToTile (meterXYPosition, 12);
		/// // tileXY = ( 655, 2512 )
		/// </code>
		/// </example>
		public static Vector2 MetersToTile(Vector2d m, int zoom)
		{
    
    
			var p = MetersToPixels(m, zoom);
			return PixelsToTile(p);
		}

		/// <summary>
		/// Gets the tile bounds in Spherical Mercator EPSG:900913 meters from an xy tile ID.
		/// </summary>
		/// <param name="tileCoordinate"> XY tile ID. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> A <see cref="T:UnityEngine.Rect"/> in meters. </returns>
		public static RectD TileBounds(Vector2 tileCoordinate, int zoom)
		{
    
    
			var min = PixelsToMeters(new Vector2d(tileCoordinate.x * TileSize, tileCoordinate.y * TileSize), zoom);
			var max = PixelsToMeters(new Vector2d((tileCoordinate.x + 1) * TileSize, (tileCoordinate.y + 1) * TileSize), zoom);
			return new RectD(min, max - min);
		}

		public static Vector2 LatitudeLongitudeToUnityTilePosition(Vector2d coordinate, UnityTile tile, ulong layerExtent = 4096)
		{
    
    
			return LatitudeLongitudeToUnityTilePosition(coordinate, tile.CurrentZoom, tile.TileScale, layerExtent);
		}

		/// <summary>
		/// Get coordinates for a given latitude/longitude in tile-space. Useful when comparing feature geometry to lat/lon coordinates.
		/// </summary>
		/// <returns>The longitude to tile position.</returns>
		/// <param name="coordinate">Coordinate.</param>
		/// <param name="tileZoom">The zoom level of the tile.</param>
		/// <param name="tileScale">Tile scale. Optional, but recommended. Defaults to a scale of 1.</param>
		/// <param name="layerExtent">Layer extent. Optional, but recommended. Defaults to 4096, the standard for Mapbox Tiles</param>
		public static Vector2 LatitudeLongitudeToUnityTilePosition(Vector2d coordinate, int tileZoom, float tileScale, ulong layerExtent = 4096)
		{
    
    
			var coordinateTileId = Conversions.LatitudeLongitudeToTileId(
				coordinate.x, coordinate.y, tileZoom);
			var _rect = Conversions.TileBounds(coordinateTileId);

			//vectortile space point (0 - layerExtent)
			var vectorTilePoint = LatitudeLongitudeToVectorTilePosition(coordinate, tileZoom, layerExtent);

			//UnityTile space
			var unityTilePoint = new Vector2((float)(vectorTilePoint.x / layerExtent * _rect.Size.x - (_rect.Size.x / 2)) * tileScale,
			                                 (float)((layerExtent - vectorTilePoint.y) / layerExtent * _rect.Size.y - (_rect.Size.y / 2)) * tileScale);

			return unityTilePoint;
		}

		/// <summary>
		/// Gets the WGS84 longitude of the northwest corner from a tile's X position and zoom level.
		/// See: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames.
		/// </summary>
		/// <param name="x"> Tile X position. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> NW Longitude. </returns>
		public static double TileXToNWLongitude(int x, int zoom)
		{
    
    
			var n = Math.Pow(2.0, zoom);
			var lon_deg = x / n * 360.0 - 180.0;
			return lon_deg;
		}

		/// <summary>
		/// Gets the WGS84 latitude of the northwest corner from a tile's Y position and zoom level.
		/// See: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames.
		/// </summary>
		/// <param name="y"> Tile Y position. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> NW Latitude. </returns>
		public static double TileYToNWLatitude(int y, int zoom)
		{
    
    
			var n = Math.Pow(2.0, zoom);
			var lat_rad = Math.Atan(Math.Sinh(Math.PI * (1 - 2 * y / n)));
			var lat_deg = lat_rad * 180.0 / Math.PI;
			return lat_deg;
		}

		/// <summary>
		/// Gets the <see cref="T:Mapbox.Utils.Vector2dBounds"/> of a tile.
		/// </summary>
		/// <param name="x"> Tile X position. </param>
		/// <param name="y"> Tile Y position. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> The <see cref="T:Mapbox.Utils.Vector2dBounds"/> of the tile. </returns>
		public static Vector2dBounds TileIdToBounds(int x, int y, int zoom)
		{
    
    
			var sw = new Vector2d(TileYToNWLatitude(y, zoom), TileXToNWLongitude(x + 1, zoom));
			var ne = new Vector2d(TileYToNWLatitude(y + 1, zoom), TileXToNWLongitude(x, zoom));
			return new Vector2dBounds(sw, ne);
		}

		/// <summary>
		/// Gets the WGS84 lat/lon of the center of a tile.
		/// </summary>
		/// <param name="x"> Tile X position. </param>
		/// <param name="y"> Tile Y position. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns>A <see cref="T:UnityEngine.Vector2d"/> of lat/lon coordinates.</returns>
		public static Vector2d TileIdToCenterLatitudeLongitude(int x, int y, int zoom)
		{
    
    
			var bb = TileIdToBounds(x, y, zoom);
			var center = bb.Center;
			return new Vector2d(center.x, center.y);
		}


		/// <summary>
		/// Gets the Web Mercator x/y of the center of a tile.
		/// </summary>
		/// <param name="x"> Tile X position. </param>
		/// <param name="y"> Tile Y position. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns>A <see cref="T:UnityEngine.Vector2d"/> of lat/lon coordinates.</returns>
		public static Vector2d TileIdToCenterWebMercator(int x, int y, int zoom)
		{
    
    
			double tileCnt = Math.Pow(2, zoom);
			double centerX = x + 0.5;
			double centerY = y + 0.5;

			centerX = ((centerX / tileCnt * 2) - 1) * Constants.WebMercMax;
			centerY = (1 - (centerY / tileCnt * 2)) * Constants.WebMercMax;
			return new Vector2d(centerX, centerY);
		}

		/// <summary>
		/// Gets the meters per pixels at given latitude and zoom level for a 256x256 tile.
		/// See: http://wiki.openstreetmap.org/wiki/Zoom_levels.
		/// </summary>
		/// <param name="latitude"> The latitude. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> Meters per pixel. </returns>
		public static float GetTileScaleInMeters(float latitude, int zoom)
		{
    
    
			return (float)(40075016.685578d * Math.Cos(Mathf.Deg2Rad * latitude) / Math.Pow(2f, zoom + 8));
		}

		/// <summary>
		/// Gets the degrees per tile at given zoom level for Web Mercator tile.
		/// See: http://wiki.openstreetmap.org/wiki/Zoom_levels.
		/// </summary>
		/// <param name="latitude"> The latitude. </param>
		/// <param name="zoom"> Zoom level. </param>
		/// <returns> Degrees per tile. </returns>
		public static float GetTileScaleInDegrees(float latitude, int zoom)
		{
    
    
			return (float)(360.0f / Math.Pow(2f, zoom + 8));
		}

		/// <summary>
		/// Gets height from terrain-rgb adjusted for a given scale.
		/// </summary>
		/// <param name="color"> The <see cref="T:UnityEngine.Color"/>. </param>
		/// <param name="relativeScale"> Relative scale. </param>
		/// <returns> Adjusted height in meters. </returns>
		public static float GetRelativeHeightFromColor(Color color, float relativeScale)
		{
    
    
			return GetAbsoluteHeightFromColor(color) * relativeScale;
		}

		/// <summary>
		/// Specific formula for mapbox.terrain-rgb to decode height values from pixel values.
		/// See: https://www.mapbox.com/blog/terrain-rgb/.
		/// </summary>
		/// <param name="color"> The <see cref="T:UnityEngine.Color"/>. </param>
		/// <returns> Height in meters. </returns>
		public static float GetAbsoluteHeightFromColor(Color color)
		{
    
    
			return (float)(-10000 + ((color.r * 255 * 256 * 256 + color.g * 255 * 256 + color.b * 255) * 0.1));
		}

		public static float GetAbsoluteHeightFromColor32(Color32 color)
		{
    
    
			return (float)(-10000 + ((color.r * 256 * 256 + color.g * 256 + color.b) * 0.1));
		}

		public static float GetAbsoluteHeightFromColor(float r, float g, float b)
		{
    
    
			return (float)(-10000 + ((r * 256 * 256 + g * 256 + b) * 0.1));
		}

		private static double Resolution(int zoom)
		{
    
    
			return InitialResolution / Math.Pow(2, zoom);
		}

		private static Vector2d PixelsToMeters(Vector2d p, int zoom)
		{
    
    
			var res = Resolution(zoom);
			var met = new Vector2d();
			met.x = (p.x * res - OriginShift);
			met.y = -(p.y * res - OriginShift);
			return met;
		}

		private static Vector2d MetersToPixels(Vector2d m, int zoom)
		{
    
    
			var res = Resolution(zoom);
			var pix = new Vector2d(((m.x + OriginShift) / res), ((-m.y + OriginShift) / res));
			return pix;
		}

		private static Vector2 PixelsToTile(Vector2d p)
		{
    
    
			var t = new Vector2((int)Math.Ceiling(p.x / (double)TileSize) - 1, (int)Math.Ceiling(p.y / (double)TileSize) - 1);
			return t;
		}



        /// <summary>
        /// 经纬度转空间坐标点(2D地图加载完成之后)
        /// </summary>
        /// <param name="centerLatLon">经纬度</param>
        /// <returns>墨卡托(空间)坐标点</returns>
        public static Vector3 LatLonToWorldPosition(Vector2d centerLatLon)
        {
    
    

            //撒的点的经纬度转换为墨卡托空间坐标点(空间坐标点)    撒点的转换问题 先转化为墨卡托坐标点然后进行位置偏移运算
            //转换经纬度坐标为空间墨卡托坐标
            Vector2d centerMetersLatLon = LatLonToMeters(centerLatLon);
            //Debug.Log("墨卡托坐标X轴:" + centerMetersLatLon.x + "墨卡托坐标Y轴:" + centerMetersLatLon.y);

            //Debug.Log("AbstractMap X轴:" + AbstractMap.Instance.CenterMercator.x + "AbstractMap Y轴" + AbstractMap.Instance.CenterMercator.y);
            //和设定的中心点位置进行对比,得到相对偏移位置
            var offsetX = (float)(centerMetersLatLon.x - AbstractMap.Instance.CenterMercator.x);
            var offsetY = (float)(centerMetersLatLon.y - AbstractMap.Instance.CenterMercator.y);

            //Debug.Log("偏移的X轴位置:" + offsetX + "偏移的Y轴位置:" + offsetY);
            //Debug.Log("MapBox的世界相对坐标的值:" + (double)AbstractMap.Instance.WorldRelativeScale);
            //现实计算: U3D 比例尺  直接使用MapBox的世界相对缩放的值
            var px = (float)offsetX /** 0.02044166*/* AbstractMap.Instance.WorldRelativeScale;
            var pz = (float)offsetY /** 0.02044166*/* AbstractMap.Instance.WorldRelativeScale;

            return new Vector3(px, 0, pz);
        }

        /// <summary>
        /// 将地图空间中的位置转换为经纬度(2D地图加载完成之后)
        /// </summary>
        /// <param name="realworldPoint">空间中的点</param>
        /// <returns>空间中点的经纬度</returns>
        public static Vector2d WorldPosToLatLonPosition(Vector3 realworldPoint)
        {
    
    
            return AbstractMap.Instance.WorldToGeoPosition(realworldPoint);
        }

        /// <summary>
        /// 经纬度转空间坐标点(2D地图加载完成之后) 进行了缩放值计算的
        /// </summary>
        /// <param name="centerLatLon">经纬度</param>
        /// <returns>墨卡托(空间)坐标点</returns>
        public static Vector3 CenterLatLonToPosition(Vector2d centerLatLon)
        {
    
    
            //撒的点的经纬度转换为墨卡托空间坐标点(空间坐标点)    撒点的转换问题 先转化为墨卡托坐标点然后进行位置偏移运算
            //转换经纬度坐标为空间墨卡托坐标
            Vector2d centerMetersLatLon = LatLonToMeters(centerLatLon);
            //Debug.Log("墨卡托坐标X轴:" + centerMetersLatLon.x + "墨卡托坐标Y轴:" + centerMetersLatLon.y);

            //Debug.Log("AbstractMap X轴:" + AbstractMap.Instance.CenterMercator.x + "AbstractMap Y轴" + AbstractMap.Instance.CenterMercator.y);
            //和设定的中心点位置进行对比,得到相对偏移位置
            var offsetX = (float)(centerMetersLatLon.x - AbstractMap.Instance.CenterMercator.x);
            var offsetY = (float)(centerMetersLatLon.y - AbstractMap.Instance.CenterMercator.y);

            //Debug.Log("偏移的X轴位置:" + offsetX + "偏移的Y轴位置:" + offsetY);
            //Debug.Log("MapBox的世界相对坐标的值:" + (double)AbstractMap.Instance.WorldRelativeScale);
            //现实计算: U3D 比例尺  直接使用MapBox的世界相对缩放的值
            var px = (float)offsetX /** 0.02044166*/* AbstractMap.Instance.WorldRelativeScale;
            var pz = (float)offsetY /** 0.02044166*/* AbstractMap.Instance.WorldRelativeScale;

            //Debug.Log("在世界坐标系中的X和Z值 PX:" + px + "PZ:"+ pz);

            //return new Vector3(px, 0, pz);
           // Debug.Log("值:" + Mathf.Abs(AbstractMap.Instance.Zoom - AbstractMap.Instance.AbsoluteZoom) >= 1);
            //if (Mathf.Abs(AbstractMap.Instance.Zoom - AbstractMap.Instance.AbsoluteZoom) >= 1)
            //{
    
    
            //    var worldx = px / (AbstractMap.Instance.transform.localScale.x/2);
            //    var worldz = pz / (AbstractMap.Instance.transform.localScale.z/2);
            //    return new Vector3(px, 0, pz);
            //}
            //Debug.Log("PX:" + px + "PZ:" + pz);
            //Debug.Log("当前2D地图的缩放值:" + AbstractMap.Instance.transform.localScale);
            var worldPx = px * AbstractMap.Instance.transform.localScale.x;
            var worldPz = pz * AbstractMap.Instance.transform.localScale.z;
            //Debug.Log("改变前的值。。。。。worldPx:" + worldPx +"  其中Abstract的值和AbsMap的值:" + AbstractZoom + "地图缩放层级的值:" + AbstractMap.Instance.AbsoluteZoom);

            //if (AbstractZoom != AbstractMap.Instance.AbsoluteZoom)
            //{
    
    
            //    AbstractZoom = AbstractMap.Instance.AbsoluteZoom;
            //    worldPx = worldPx * 2f;
            //    worldPz = worldPz * 2f;
            //    Debug.Log("改变后的值worldPx:" + worldPx);
            //}

            //Debug.Log("当前经纬度转空间坐标点:" + worldPx + "当前的经纬度Z值:" + worldPz);

            return new Vector3(worldPx, 0, worldPz);
        }

        /// <summary>
        /// MapBox里面的经纬度转空间坐标点的方法
        /// </summary>
        /// <param name="centerlatLon">经纬度</param>
        /// <returns>空间坐标点</returns>
        public static Vector3 LatLonToPositionWorld(Vector2d centerlatLon)
        {
    
    
            return AbstractMap.Instance.GeoToWorldPosition(centerlatLon);
        }

        /// <summary>
        /// 地图2D瓦片更新
        /// </summary>
        public static void UpdateMap(Vector2d latLon, float zoom)
        {
    
    
            AbstractMap.Instance.UpdateMap(latLon,zoom);
        }

        /// <summary>
        /// 将地图空间中的位置转换为经纬度(2D地图加载完成之后)
        /// </summary>
        /// <param name="realworldPoint">空间中的点</param>
        /// <returns>空间中点的经纬度</returns>
        public static Vector2d WorldToGeoPosition(Vector3 realworldPoint)
        {
    
    
            float scale = AbstractMap.Instance.transform.localScale.x;
            Vector3 worldPoint = new Vector3(realworldPoint.x*scale,realworldPoint.y*scale,realworldPoint.z*scale);
            //return AbstractMap.Instance.WorldToGeoPosition(realworldPoint);
            return AbstractMap.Instance.WorldToGeoPosition(worldPoint);
        }

        /// <summary>
        /// 计算两个经纬度之间的距离(单位为米)
        /// </summary>
        /// <param name="longitude1">当前点的经度</param>
        /// <param name="latitude1">当前点的纬度</param>
        /// <param name="longitude2">下一个点的经度</param>
        /// <param name="latitude2">下一个点的纬度</param>
        /// <returns>返回的是两个点之间的距离</returns>
        public static double GetDistance(double longitude1, double latitude1,
                double longitude2, double latitude2)
        {
    
    

            double Lat1 = rad(latitude1);
            double Lat2 = rad(latitude2);
            double a = Lat1 - Lat2;
            double b = rad(longitude1) - rad(longitude2);
            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2)
                    + Math.Cos(Lat1) * Math.Cos(Lat2)
                    * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * EARTH_RADIUS;
            s = Math.Round(s * 10000) / 10000;
            return s;
        }

        private static double rad(double d)
        {
    
    
            return d * Math.PI / 180.0;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42855293/article/details/118756340