CoordinateConverter.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public static class CoordinateConverter
  6. {
  7. // 计算两个经纬度之间的距离,返回值为公里
  8. public static double Haversine(double lat1, double lon1, double lat2, double lon2)
  9. {
  10. // 将纬度和经度从度转换为弧度
  11. double R = 6371.0; // 地球半径,单位为公里
  12. double dLat = ToRadians(lat2 - lat1);
  13. double dLon = ToRadians(lon2 - lon1);
  14. lat1 = ToRadians(lat1);
  15. lat2 = ToRadians(lat2);
  16. // Haversine 公式
  17. double a = Mathf.Sin((float)dLat / 2) * Mathf.Sin((float)dLat / 2) +
  18. Mathf.Cos((float)lat1) * Mathf.Cos((float)lat2) *
  19. Mathf.Sin((float)dLon / 2) * Mathf.Sin((float)dLon / 2);
  20. double c = 2 * Mathf.Atan2(Mathf.Sqrt((float)a), Mathf.Sqrt((float)(1 - a)));
  21. // 计算距离
  22. double distance = R * c;
  23. return distance;
  24. }
  25. // 将角度转换为弧度
  26. private static double ToRadians(double angle)
  27. {
  28. return angle * Mathf.Deg2Rad;
  29. }
  30. // 将经纬度转换为Unity坐标
  31. public static Vector3 GeoToUnity(double longitude, double latitude)
  32. {
  33. float x = (float)(96151.617 * longitude - 10938527.4823);
  34. float z = (float)(111468.3949 * latitude - 3339986.2697);
  35. return new Vector3(x, 0, z);
  36. }
  37. // 将Unity坐标转换为经纬度
  38. public static (double Longitude, double Latitude) UnityToGeo(Vector3 unityCoord)
  39. {
  40. double longitude = (unityCoord.x + 10938527.4823)/ 96151.617;
  41. double latitude = (unityCoord.z + 3339986.2697)/ 111468.3949;
  42. // 这里我们忽略了截距,因为我们假设Unity坐标的原点对应于经纬度的截距
  43. // 如果需要考虑截距,可以在这里添加相应的计算
  44. return (longitude, latitude);
  45. }
  46. public static Vector3 GeoToUGUI(double longitude, double latitude)
  47. {
  48. float x = (float)(355.53f * longitude - 40339.8622f);
  49. float y = (float)(409.37f * latitude - 12420.05f);
  50. return new Vector3(x, y, 0);
  51. }
  52. public static Vector3 GeoToUGUISmall(double longitude,double latitude)
  53. {
  54. float x = (float)(80.124f * longitude - 9118.032f);
  55. float y = (float)(92.467f * latitude - 2775.33f);
  56. return new Vector3(x, y, -0.400f);
  57. }
  58. public static (double longitude, double latitude) UGUISmallToGeo(Vector3 uiCoord)
  59. {
  60. double longitude = (uiCoord.x + 8607.658) / 75.642;
  61. double latitude = (uiCoord.y + 2640.548) / 87.990;
  62. // 这里我们忽略了截距,因为我们假设Unity坐标的原点对应于经纬度的截距
  63. // 如果需要考虑截距,可以在这里添加相应的计算
  64. return (longitude, latitude);
  65. }
  66. public static (double latitude, double longitude) UGUIToGeo(Vector3 ugui)
  67. {
  68. float x = ugui.x;
  69. float y = ugui.y;
  70. double latitude = (x + 40339.8622f) / 355.53f;
  71. double longitude = (y + 12420.05f) / 409.37f;
  72. return (latitude, longitude);
  73. }
  74. const double PI = Math.PI;
  75. const double AXIS = 6378245.0; // a
  76. const double EE = 0.00669342162296594323; // e^2
  77. const double EARTH_RADIUS = 20037508.34; // 墨卡托投影最大值
  78. /// <summary>
  79. /// 判断是否在中国范围外
  80. /// </summary>
  81. static bool OutOfChina(double lon, double lat)
  82. {
  83. return (lon < 72.004 || lon > 137.8347 || lat < 0.8293 || lat > 55.8271);
  84. }
  85. static double TransformLat(double x, double y)
  86. {
  87. double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y
  88. + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x));
  89. ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
  90. ret += (20.0 * Math.Sin(y * PI) + 40.0 * Math.Sin(y / 3.0 * PI)) * 2.0 / 3.0;
  91. ret += (160.0 * Math.Sin(y / 12.0 * PI) + 320 * Math.Sin(y * PI / 30.0)) * 2.0 / 3.0;
  92. return ret;
  93. }
  94. static double TransformLon(double x, double y)
  95. {
  96. double ret = 300.0 + x + 2.0 * y + 0.1 * x * x
  97. + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));
  98. ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
  99. ret += (20.0 * Math.Sin(x * PI) + 40.0 * Math.Sin(x / 3.0 * PI)) * 2.0 / 3.0;
  100. ret += (150.0 * Math.Sin(x / 12.0 * PI) + 300.0 * Math.Sin(x / 30.0 * PI)) * 2.0 / 3.0;
  101. return ret;
  102. }
  103. /// <summary>
  104. /// GCJ-02(火星坐标,高德坐标) → WGS84
  105. /// </summary>
  106. public static Vector2 GCJ02ToWGS84(double lon, double lat)
  107. {
  108. if (OutOfChina(lon, lat))
  109. {
  110. return new Vector2((float)lon, (float)lat);
  111. }
  112. double dLat = TransformLat(lon - 105.0, lat - 35.0);
  113. double dLon = TransformLon(lon - 105.0, lat - 35.0);
  114. double radLat = lat / 180.0 * PI;
  115. double magic = Math.Sin(radLat);
  116. magic = 1 - EE * magic * magic;
  117. double sqrtMagic = Math.Sqrt(magic);
  118. dLat = (dLat * 180.0) / ((AXIS * (1 - EE)) / (magic * sqrtMagic) * PI);
  119. dLon = (dLon * 180.0) / (AXIS / sqrtMagic * Math.Cos(radLat) * PI);
  120. double mgLat = lat + dLat;
  121. double mgLon = lon + dLon;
  122. return new Vector2((float)(lon * 2 - mgLon), (float)(lat * 2 - mgLat));
  123. }
  124. /// <summary>
  125. /// WGS84 → WebMercator (EPSG:3857)
  126. /// </summary>
  127. public static Vector2 WGS84ToWebMercator(double lon, double lat)
  128. {
  129. double x = lon * EARTH_RADIUS / 180.0;
  130. double y = Math.Log(Math.Tan((90.0 + lat) * PI / 360.0)) / (PI / 180.0);
  131. y = y * EARTH_RADIUS / 180.0;
  132. return new Vector2((float)x, (float)y);
  133. }
  134. /// <summary>
  135. /// 一步到位: GCJ-02 → WebMercator
  136. /// </summary>
  137. public static Vector2 GCJ02ToWebMercator(double lon, double lat)
  138. {
  139. Vector2 wgs84 = GCJ02ToWGS84(lon, lat);
  140. return WGS84ToWebMercator(wgs84.x, wgs84.y);
  141. }
  142. }