设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间01 现在时间01 缓存数据 当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

查看: 345|回复: 0

Java实现经纬度坐标转换的示例代码

[复制链接]

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
32
主题
28
精华
0
金钱
98
积分
60
注册时间
2023-10-3
最后登录
2025-8-27

发表于 2025-8-27 20:08:05 | 显示全部楼层 |阅读模式

一、坐标系统简介

坐标系统,是描述物质存在的空间位置(坐标)的参照系,通过定义特定基准及其参数形式来实现。

坐标是描述位置的一组数值,按坐标的维度一般分为一维坐标(公路里程碑)和二维坐标(笛卡尔平面直角坐标、高斯平面直角坐标)、三维坐标(大地坐标、空间直角坐标)。

为了描述或确定位置,必须建立坐标系统,坐标只有存在于某个坐标系统才有实际的意义与具体的位置。

地球是一个球体,球面上的位置,是以经纬度来表示,它称为“球面坐标系统”或“地理坐标系统”。
在球面上计算角度距离十分麻烦,而且地图是印刷在平面纸张上,要将球面上的物体画到纸上,就必须展平,这种将球面转化为平面的过程,称为“投影”。

1、经纬度坐标系

经纬度坐标系是一种地理坐标系统,用于描述地球表面上任意位置的坐标。它是基于地球的自转和赤道的划分而建立的。

  • 经度(Longitude):表示地球表面上一个点相对于本初子午线的东西方向的位置。经度的度量单位是度(°),范围从0°到180°,以东经为正值,西经为负值。本初子午线位于英国伦敦的皇家格林尼治天文台,它被定义为经度0°。
  • 纬度(Latitude):表示地球表面上一个点相对于赤道的北南方向的位置。纬度的度量单位也是度(°),范围从0°到90°,以北纬为正值,南纬为负值。赤道位于纬度0°。

经纬度坐标系统是全球通用的地理坐标系统。

经纬度坐标系统使用经度和纬度的组合来确定地球表面上的特定位置。一个点的经纬度坐标表示为两个数值的组合,例如:40°N,120°E 表示北纬40度,东经120度的位置。

2、坐标系统

(1)WGS84(World Geodetic System 1984,GPS标准)

  • 定义:WWGS84,全称“世界大地坐标系统1984”,是一个国际广泛接受的地心地固坐标系统,也是全球定位系统(GPS)的标准坐标系。WGS84是基于地球椭球体模型,提供全球统一的地理坐标框架,是开放和透明的,适用于全球范围内的导航、定位和地图制作。
  • 历史:经历了多次精化,包括WGS84(G730)、WGS84(G873)和WGS84(G1150)。
  • 参数:长半轴为6378137.0米,扁率为1/298.257223563。
  • 应用场景:全球范围内的GPS定位、地图绘制等。

(2)GCJ-02(国测局坐标系,也被称为火星坐标系)

  • 定义:GCJ-02,全称“中国国测局坐标系统”,也称为“火星坐标”或“火星加密算法”。它是中国国家测绘局制定的一种地理坐标系,用于对中国大陆的地理位置进行偏移加密处理。
  • 特点:它是中国政府为了安全而对公开的WGS84坐标数据进行了加密处理,使得在未授权的情况下难以直接使用全球定位系统(GPS)获得精确的位置信息。相对于WGS84坐标系进行了加密处理,用于保护安全。
  • 应用场景:在国内的地图服务、导航系统、地理信息系统等应用中得到广泛使用,例如高德地图、腾讯地图等。手机上的地图导航软件利用GCJ-02坐标系实现了高精度的定位和导航功能。

(3)BD-09(Baidu Coordinate System)

  • 定义:BD-09是百度地图使用的一种坐标系。
  • BD-09是百度地图使用的坐标系统,它是在GCJ-02的基础上进行的二次加密。
  • 特点:由于百度地图在中国提供服务,它需要遵守GCJ-02的加密规则,但为了增强定位精度和防止第三方直接解密GCJ-02坐标,百度在其服务中采用了更复杂的加密算法。即基于GCJ-02坐标系进行了加密偏移,提供了更好的数据保护性能。因此,从WGS84到BD-09,需要经过两次转换,先由WGS84转为GCJ-02,然后再转为BD-09。
  • 应用场景:主要用于中国境内各种位置服务应用,如百度地图的定位和导航服务。

(4)CGCS2000(中国2000国家大地坐标系)

  • 定义:CGCS2000,全称“2000国家大地坐标系统”,是中国最新的地心地固坐标系统,替代了之前的北京54和西安80坐标系。以ITRF 97为参考框架,以2000.0作为参考历元。
  • 特点:原点设定在地球的质量中心,Z轴指向IERS参考极,X轴和Y轴通过右手规则确定。
  • CGCS2000基于地球椭球体模型,与国际标准兼容,尤其与北斗卫星导航系统配合使用时,提供高精度的定位服务。它是中国自主的全球定位系统,与WGS84类似,但更适合中国的地理特性。
  • 与WGS84的关系:在定义上与WGS84非常相似,包括原点、尺度和定向。但在扁率上的差异会导致椭球面上的纬度和高度产生微小的变化。
  • 应用场景:作为国家基础坐标系,用于各种测绘和地理信息系统工作。

3、坐标转换简介

在地图应用中,不同的地图服务商通常使用不同的坐标系,坐标转换就是将一个地图服务商的坐标系转换为另一个地图服务商的坐标系,以便在不同的地图上显示相同的位置信息。

GPS(谷歌地图)|高德|百度地图对坐标系统的使用:

  • WGS84:地理坐标系统,GPS仪器记录的经纬度信息。Google Earth采用,Google Map中国范围外使用,高德地图中国范围外使用。
  • GCJ-02:投影坐标系统,火星坐标系,中国国家测绘局制定的坐标系统,由 WGS-84加密后的坐标。适用于高德地图。
  • BD-09:投影坐标系统,百度坐标系,GCJ-02加密后的坐标系,只适用于百度地图。
  • CS2000:中国2000国家大地坐标系统,与WG-S84类似,只适用于北斗卫星。

注意:

  • WGS84、GCJ-02和BD-09之间通过转换算法或者API可以实现互转。
  • GCS2000与GCJ-02和BD-09之间没有直接的转换关系,通常需要将 GCS2000转换为 WGS84,然后通过这个中间坐标系(WGS84)来进行间接转换。
  • 在国内是不允许直接用 WGS84坐标系标注经纬度的,必须经过加密后才能用。所以必须至少使用 GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的 BD-09坐标系。

不同地图服务商有提供其丰富的 API文档功能,包括经纬度坐标转换功能。有的地图服务商API需要收费。

二、地图经纬度转换工具类

对于 CGCS2000 需要引入 proj4j依赖:

  1. <dependency>
  2. <groupId>org.locationtech.proj4j</groupId>
  3. <artifactId>proj4j</artifactId>
  4. <version>1.3.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.locationtech.proj4j</groupId>
  8. <artifactId>proj4j-epsg</artifactId>
  9. <version>1.3.0</version>
  10. </dependency>
复制代码
  1. /**
  2. * 坐标转换工具类
  3. * <p>
  4. * 参考文章-实现的Java版本:https://github.com/wandergis/coordtransform
  5. */
  6. @Slf4j
  7. public class CoordinateTransformUtil {
  8. static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  9. // π
  10. static double pi = 3.1415926535897932384626;
  11. // 长半轴
  12. static double a = 6378245.0;
  13. // 扁率
  14. static double ee = 0.00669342162296594323;
  15. /**
  16. * WGS84 转 GCJ-02
  17. *
  18. * @param lng WGS84经度
  19. * @param lat WGS84纬度
  20. * @return
  21. */
  22. public static Coordinate wgs84ToGcj02(double lng, double lat) {
  23. if (outOfChina(lng, lat)) {
  24. return new Coordinate(lng, lat);
  25. }
  26. double dlat = transformlat(lng - 105.0, lat - 35.0);
  27. double dlng = transformlng(lng - 105.0, lat - 35.0);
  28. double radlat = lat / 180.0 * pi;
  29. double magic = Math.sin(radlat);
  30. magic = 1 - ee * magic * magic;
  31. double sqrtmagic = Math.sqrt(magic);
  32. dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
  33. dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
  34. double mgLat = lat + dlat;
  35. double mgLng = lng + dlng;
  36. return new Coordinate(mgLng, mgLat);
  37. }
  38. /**
  39. * GCJ-02 转 WGS84
  40. *
  41. * @param lng GCJ-02经度
  42. * @param lat GCJ-02纬度
  43. * @return
  44. */
  45. public static Coordinate gcj02ToWgs84(double lng, double lat) {
  46. if (outOfChina(lng, lat)) {
  47. return new Coordinate(lng, lat);
  48. }
  49. double dlat = transformlat(lng - 105.0, lat - 35.0);
  50. double dlng = transformlng(lng - 105.0, lat - 35.0);
  51. double radlat = lat / 180.0 * pi;
  52. double magic = Math.sin(radlat);
  53. magic = 1 - ee * magic * magic;
  54. double sqrtmagic = Math.sqrt(magic);
  55. dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
  56. dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
  57. double mgLat = lat + dlat;
  58. double mgLng = lng + dlng;
  59. return new Coordinate(lng * 2 - mgLng, lat * 2 - mgLat);
  60. }
  61. /**
  62. * GCJ-02 转 BD-09
  63. *
  64. * @param lng GCJ-02经度
  65. * @param lat GCJ-02纬度
  66. * @return
  67. */
  68. public static Coordinate gcj02ToBd09(double lng, double lat) {
  69. double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_pi);
  70. double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi);
  71. double bd_lng = z * Math.cos(theta) + 0.0065;
  72. double bd_lat = z * Math.sin(theta) + 0.006;
  73. return new Coordinate(bd_lng, bd_lat);
  74. }
  75. /**
  76. * BD-09 转 GCJ-02
  77. *
  78. * @param lng BD-09经度
  79. * @param lat BD-09纬度
  80. */
  81. public static Coordinate bd09ToGcj02(double lng, double lat) {
  82. double x = lng - 0.0065;
  83. double y = lat - 0.006;
  84. double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
  85. double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
  86. double gg_lng = z * Math.cos(theta);
  87. double gg_lat = z * Math.sin(theta);
  88. return new Coordinate(gg_lng, gg_lat);
  89. }
  90. /**
  91. * BD-09 转 WGS84
  92. *
  93. * @param lng BD-09经度
  94. * @param lat BD-09纬度
  95. * @return
  96. */
  97. public static Coordinate bd09ToWgs84(double lng, double lat) {
  98. Coordinate gcj02 = bd09ToGcj02(lng, lat);
  99. Coordinate wgs84 = gcj02ToWgs84(gcj02.longitude, gcj02.latitude);
  100. return wgs84;
  101. }
  102. /**
  103. * WGS84 转 BD-09
  104. *
  105. * @param lng WGS84经度
  106. * @param lat WGS84纬度
  107. * @return
  108. */
  109. public static Coordinate wgs84ToBd09(double lng, double lat) {
  110. Coordinate gcj02 = wgs84ToGcj02(lng, lat);
  111. Coordinate bd09 = gcj02ToBd09(gcj02.longitude, gcj02.latitude);
  112. return bd09;
  113. }
  114. /**
  115. * 纬度转换
  116. *
  117. * @param lng
  118. * @param lat
  119. * @return
  120. */
  121. public static double transformlat(double lng, double lat) {
  122. double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
  123. ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0;
  124. ret += (20.0 * Math.sin(lat * pi) + 40.0 * Math.sin(lat / 3.0 * pi)) * 2.0 / 3.0;
  125. ret += (160.0 * Math.sin(lat / 12.0 * pi) + 320 * Math.sin(lat * pi / 30.0)) * 2.0 / 3.0;
  126. return ret;
  127. }
  128. /**
  129. * 经度转换
  130. *
  131. * @param lng
  132. * @param lat
  133. * @return
  134. */
  135. public static double transformlng(double lng, double lat) {
  136. double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
  137. ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0;
  138. ret += (20.0 * Math.sin(lng * pi) + 40.0 * Math.sin(lng / 3.0 * pi)) * 2.0 / 3.0;
  139. ret += (150.0 * Math.sin(lng / 12.0 * pi) + 300.0 * Math.sin(lng / 30.0 * pi)) * 2.0 / 3.0;
  140. return ret;
  141. }
  142. /**
  143. * 判断是否在国内,不在国内不做偏移
  144. *
  145. * @param lng
  146. * @param lat
  147. * @return
  148. */
  149. public static boolean outOfChina(double lng, double lat) {
  150. if (lng < 72.004 || lng > 137.8347) {
  151. return true;
  152. } else if (lat < 0.8293 || lat > 55.8271) {
  153. return true;
  154. }
  155. return false;
  156. }
  157. /**
  158. * 坐标类
  159. */
  160. @Data
  161. public static class Coordinate {
  162. /**
  163. * 经度
  164. */
  165. private double longitude;
  166. /**
  167. * 维度
  168. */
  169. private double latitude;
  170. public Coordinate(double longitude, double latitude) {
  171. // 保留6位小数,四舍五入模式
  172. //BigDecimal latBigDecimal = new BigDecimal(latitude).setScale(6, RoundingMode.HALF_UP);
  173. //BigDecimal lonBigDecimal = new BigDecimal(longitude).setScale(6, RoundingMode.HALF_UP);
  174. //this.longitude = lonBigDecimal.doubleValue();
  175. //this.latitude = latBigDecimal.doubleValue();
  176. this.longitude = longitude;
  177. this.latitude = latitude;
  178. }
  179. }
  180. // 定义CGCS2000的坐标系
  181. private final static String CGCS2000 = "EPSG:4490";
  182. // 定义WGS84的坐标系
  183. final static String WGS84 = "EPSG:4326";
  184. /**
  185. * CGCS2000 转 WGS84
  186. *
  187. * @param lng CGCS2000经度
  188. * @param lat CGCS2000纬度
  189. * @return
  190. */
  191. public static Coordinate cgcs2000ToWgs84(double lng, double lat) {
  192. CRSFactory crsFactory = new CRSFactory();
  193. // 创建CGCS2000的坐标参考系统
  194. CoordinateReferenceSystem sourceCRS = crsFactory.createFromName(CGCS2000);
  195. // 创建WGS84的坐标参考系统
  196. CoordinateReferenceSystem targetCRS = crsFactory.createFromName(WGS84);
  197. // 定义坐标转换器
  198. CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
  199. // 创建转换器
  200. CoordinateTransform transform = ctFactory.createTransform(sourceCRS, targetCRS);
  201. // 执行坐标转换
  202. ProjCoordinate srcCoord = new ProjCoordinate(lng, lat);
  203. ProjCoordinate targetCoord = new ProjCoordinate();
  204. transform.transform(srcCoord, targetCoord);
  205. // 4. 输出转换后的正常经纬度坐标
  206. return new Coordinate(targetCoord.x, targetCoord.y);
  207. }
  208. /**
  209. * WGS84 转 CGCS2000
  210. *
  211. * @param lng WGS84经度
  212. * @param lat WGS84纬度
  213. * @return
  214. */
  215. public static Coordinate wgs84ToCgcs2000(double lng, double lat) {
  216. CRSFactory crsFactory = new CRSFactory();
  217. // 定义源和目标投影
  218. CoordinateReferenceSystem sourceCRS = crsFactory.createFromName(WGS84);
  219. CoordinateReferenceSystem targetCRS = crsFactory.createFromName(CGCS2000);
  220. // 定义坐标转换器
  221. CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
  222. // 创建转换器
  223. CoordinateTransform transform = ctFactory.createTransform(sourceCRS, targetCRS);
  224. // 执行坐标转换
  225. ProjCoordinate srcCoord = new ProjCoordinate(lng, lat);
  226. ProjCoordinate targetCoord = new ProjCoordinate();
  227. transform.transform(srcCoord, targetCoord);
  228. // 输出转换后的正常经纬度坐标
  229. return new Coordinate(targetCoord.x, targetCoord.y);
  230. }
  231. public static void main(String[] args) {
  232. double GPSLon = 108.876152;
  233. double GPSLat = 34.226685;
  234. CoordinateTransformUtil.Coordinate wgs84ToGcj02 = CoordinateTransformUtil.wgs84ToGcj02(GPSLon, GPSLat);
  235. CoordinateTransformUtil.Coordinate wgs84ToBd09 = CoordinateTransformUtil.wgs84ToBd09(GPSLon, GPSLat);
  236. log.info("GPS wgs84ToGcj02 : longitude={}, latitude={}", wgs84ToGcj02.longitude, wgs84ToGcj02.latitude);
  237. log.info("GPS wgs84ToBd09 : longitude={}, latitude={}", wgs84ToBd09.longitude, wgs84ToBd09.latitude);
  238. double aMapLon2 = 108.880753;
  239. double aMapLat2 = 34.225075;
  240. CoordinateTransformUtil.Coordinate gcj02ToWgs84 = CoordinateTransformUtil.gcj02ToWgs84(aMapLon2, aMapLat2);
  241. CoordinateTransformUtil.Coordinate gcj02ToBd09 = CoordinateTransformUtil.gcj02ToBd09(aMapLon2, aMapLat2);
  242. log.info("高德 gcj02ToWgs84 : longitude={}, latitude={}", gcj02ToWgs84.longitude, gcj02ToWgs84.latitude);
  243. log.info("高德 gcj02ToBd09 : longitude={}, latitude={}", gcj02ToBd09.longitude, gcj02ToBd09.latitude);
  244. double baiduLon3 = 108.887314;
  245. double baiduLat3 = 34.230897;
  246. CoordinateTransformUtil.Coordinate bd09ToWgs84 = CoordinateTransformUtil.bd09ToWgs84(baiduLon3, baiduLat3);
  247. CoordinateTransformUtil.Coordinate bd09ToGcj02 = CoordinateTransformUtil.bd09ToGcj02(baiduLon3, baiduLat3);
  248. log.info("百度 gcj02ToWgs84 : longitude={}, latitude={}", bd09ToWgs84.longitude, bd09ToWgs84.latitude);
  249. log.info("百度 gcj02ToBd09 : longitude={}, latitude={}", bd09ToGcj02.longitude, bd09ToGcj02.latitude);
  250. /**
  251. * CGCS2000
  252. */
  253. double CGCS2000Lon4 = 108.887314;
  254. double CGCS2000Lat4 = 34.230897;
  255. CoordinateTransformUtil.Coordinate CGCS2000ToWgs84 = CoordinateTransformUtil.cgcs2000ToWgs84(CGCS2000Lon4, CGCS2000Lat4);
  256. CoordinateTransformUtil.Coordinate CGCS2000ToBd09 = CoordinateTransformUtil.wgs84ToCgcs2000(CGCS2000Lon4, CGCS2000Lat4);
  257. log.info("中国2000 CGCS2000ToWgs84 : longitude={}, latitude={}", CGCS2000ToWgs84.longitude, CGCS2000ToWgs84.latitude);
  258. log.info("中国2000 CGCS2000ToBd09 : longitude={}, latitude={}", CGCS2000ToBd09.longitude, CGCS2000ToBd09.latitude);
  259. }
  260. }
复制代码

1.png

三、方法补充

Java实现WGS84、百度、腾讯、高德等主流的地理坐标转换

主要是WGS84(大地坐标系)、GCJ02(国测局坐标系,如高德地图、腾讯地图、谷歌中国范围地图)、BD09(百度坐标系)三种主流坐标系之间的转换。

注意:如果经纬度8位数字的需要进行转换:例如:69857065/600000=“116.428441” 即是真实的WGS84坐标

完整代码

  1. import java.util.ArrayList;
  2. import java.util.HashMap;
  3. import java.util.List;
  4. import java.util.Map;
  5. /**
  6. * 常用地图转换工具类(各个地图API采用的坐标系(WGS84坐标系:即地球坐标系,国际上通用的坐标系。谷歌地图用此坐标))
  7. * 百度地图API 百度坐标 (BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。)
  8. * 腾讯搜搜地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。)
  9. * 阿里云地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。)
  10. * 高德MapABC地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。)
  11. */
  12. public class MapUtils {
  13. public static final double r2d = 57.2957795131;
  14. public static final double PI = 3.1415926535897932384626433832795;
  15. public static final double rearth = 6371006.84;
  16. /**
  17. * wgs84坐标转上海城市坐标
  18. * @param lat 维度
  19. * @param lon 经度
  20. * @return
  21. */
  22. public static Map<String, Double> wgs84Tosh(Double lat, Double lon) {
  23. double tolat = (31 + (14.0 + 7.55996 / 60.0) / 60.0) / r2d;
  24. double tolon = (121.0 + (28.0 + 1.80651 / 60.0) / 60) / r2d;
  25. Double frlat = lat / r2d;
  26. Double frlon = lon / r2d;
  27. Double clatt = Math.cos(frlat);
  28. Double clatf = Math.cos(tolat);
  29. Double slatt = Math.sin(frlat);
  30. Double slatf = Math.sin(tolat);
  31. Double dlon = frlon - tolon;
  32. Double cdlon = Math.cos(dlon);
  33. Double sdlon = Math.sin(dlon);
  34. Double cdist = slatf * slatt + clatf * clatt * cdlon;
  35. Double temp = (clatt * sdlon) * (clatt * sdlon) + (clatf * slatt - slatf * clatt * cdlon) * (clatf * slatt - slatf * clatt * cdlon);
  36. Double sdist = Math.sqrt(Math.abs(temp));
  37. Double gcdist = 0.0;
  38. if ((Math.abs(sdist) > 1e-7) || (Math.abs(cdist) > 1e-7))
  39. gcdist = Math.atan2(sdist, cdist);
  40. Double sbrg = sdlon * clatt;
  41. Double cbrg = (clatf * slatt - slatf * clatt * cdlon);
  42. if ((Math.abs(sbrg) > 1e-7) || (Math.abs(cbrg) > 1e-7)) {
  43. temp = Math.atan2(sbrg, cbrg);
  44. while (temp < 0) {
  45. temp = temp + 2 * PI;
  46. }
  47. }
  48. Double hor = gcdist * rearth;
  49. Double xx = hor * Math.sin(temp);
  50. Double yy = hor * Math.cos(temp);
  51. Map<String,Double> model = new HashMap<String,Double>();
  52. model.put("lat", xx);
  53. model.put("lon", yy);
  54. return model;
  55. }
  56. public static final Double m_pNorthMove = -3457000.0;
  57. public static final Double m_pSHa = 6378245.0;
  58. public static final double m_pSHf = 298.3;
  59. public static final double m_pWGS84a = 6371006.84;
  60. public static final double m_pWGS84f = 298.25722356300003;
  61. /**
  62. * 上海城市坐标转WGS84坐标
  63. * @param East 经(东部)
  64. * @param North 纬(北部)
  65. * @param InH 内部高度(默认可以用 0.0)
  66. * @return
  67. */
  68. public static Map<String, Double> ShToWGS84(Double East, Double North, Double InH) {
  69. North = North - m_pNorthMove;
  70. List<Double> a = AntiGaussProjectionConst(m_pSHa, m_pSHf, East, North);
  71. Double rB = a.get(0);
  72. Double rl = a.get(1);
  73. Double m_pCenterL = DMSToDegree(121.0, 28.0, 0.0);
  74. Double dL = RadianToDegree(rl) + m_pCenterL;
  75. Double tB = rB;
  76. Double tL = DegreeToRadian(dL);
  77. Double tH = InH;
  78. /* Double sB = 0.0;
  79. Double sL = 0.0;
  80. Double sH = 0.0;*/
  81. ArrayList<Double> m_pPara = new ArrayList<Double>();
  82. m_pPara.add(-39.208938);
  83. m_pPara.add(65.046547);
  84. m_pPara.add(49.410739);
  85. m_pPara.add(SecondToRadian(6.125483));
  86. m_pPara.add(SecondToRadian(-1.281548));
  87. m_pPara.add(SecondToRadian(-0.861599));
  88. m_pPara.add(2.916036 * 1e-6);
  89. List<Double> b = LBH7ParameterSelf(tL, tB, tH, m_pSHa, 1.0 / m_pSHf, m_pPara.get(0),
  90. m_pPara.get(1), m_pPara.get(2), m_pPara.get(3),
  91. m_pPara.get(4), m_pPara.get(5), m_pPara.get(6),
  92. m_pWGS84a, 1.0 / m_pWGS84f);
  93. ArrayList<Double> a1 = RadianToDMS(b.get(0));
  94. ArrayList<Double> a2 = RadianToDMS(b.get(1));
  95. Double b1 = a1.get(0) + a1.get(1) / 60 + a1.get(2) / 3600;
  96. Double b2 = a2.get(0) + a2.get(1) / 60 + a2.get(2) / 3600;
  97. /*百度偏移*/
  98. /*谷歌偏移*/
  99. b1 = b1 + 0.000935;
  100. b2 = b2 + 0.002651;
  101. Map<String,Double> model = new HashMap<String,Double>();
  102. model.put("lat", b1);
  103. model.put("lon", b2);
  104. return model;
  105. }
  106. /**
  107. * WGS-84转GCJ坐标
  108. * @param wgsLat
  109. * @param wgsLon
  110. * @return
  111. */
  112. public static Map<String, Double> gcj_encrypt(Double wgsLat, Double wgsLon) {
  113. Map<String,Double> model = new HashMap<String,Double>();
  114. if (outOfChina(wgsLat, wgsLon)) {
  115. model.put("lat", wgsLat);
  116. model.put("lon", wgsLon);
  117. return model;
  118. }
  119. Map<String, Double> d = delta(wgsLat, wgsLon);
  120. model.put("lat", wgsLat + (Double) d.get("lat"));
  121. model.put("lon", wgsLon + (Double) d.get("lon"));
  122. return model;
  123. }
  124. /**
  125. * GCJ坐标转WGS-84坐标
  126. * @param gcjLat
  127. * @param gcjLon
  128. * @return
  129. */
  130. public static Map<String, Double> gcj_decrypt(Double gcjLat, Double gcjLon) {
  131. Map<String, Double> model = new HashMap<String, Double>();
  132. if (outOfChina(gcjLat, gcjLon)) {
  133. model.put("lat", gcjLat);
  134. model.put("lon", gcjLon);
  135. return model;
  136. }
  137. Map<String, Double> d = delta(gcjLat, gcjLon);
  138. model.put("lat", gcjLat - (Double) d.get("lat"));
  139. model.put("lon", gcjLon - (Double) d.get("lon"));
  140. return model;
  141. }
  142. public static final double x_pi = PI * 3000.0 / 180.0;
  143. /**
  144. * GCJ-02坐标转百度BD-09坐标
  145. * @param gcjLat
  146. * @param gcjLon
  147. * @return
  148. */
  149. public static Map<String, Double> bd_encrypt(Double gcjLat, Double gcjLon) {
  150. Map<String, Double> model = new HashMap<String, Double>();
  151. Double x = gcjLon, y = gcjLat;
  152. Double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
  153. Double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
  154. Double bdLon = z * Math.cos(theta) + 0.0065;
  155. Double bdLat = z * Math.sin(theta) + 0.006;
  156. model.put("lat", bdLat);
  157. model.put("lon", bdLon);
  158. return model;
  159. }
  160. /**
  161. * 百度BD-09坐标转GCJ-02坐标
  162. * @param bdLat
  163. * @param bdLon
  164. * @return
  165. */
  166. public static Map<String, Double> bd_decrypt(Double bdLat, Double bdLon) {
  167. Map<String, Double> model = new HashMap<String, Double>();
  168. Double x = bdLon - 0.0065, y = bdLat - 0.006;
  169. Double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
  170. Double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
  171. Double gcjLon = z * Math.cos(theta);
  172. Double gcjLat = z * Math.sin(theta);
  173. model.put("lat", gcjLat);
  174. model.put("lon", gcjLon);
  175. return model;
  176. }
  177. public static Boolean outOfChina(Double lat, Double lon) {
  178. if (lon < 72.004 || lon > 137.8347)
  179. return true;
  180. if (lat < 0.8293 || lat > 55.8271)
  181. return true;
  182. return false;
  183. }
  184. public static Map<String, Double> delta(Double lat, Double lon) {
  185. Double a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
  186. Double ee = 0.00669342162296594323; // ee: 椭球的偏心率。
  187. Double dLat = transformLat(lon - 105.0, lat - 35.0);
  188. Double dLon = transformLon(lon - 105.0, lat - 35.0);
  189. Double radLat = lat / 180.0 * PI;
  190. Double magic = Math.sin(radLat);
  191. magic = 1 - ee * magic * magic;
  192. Double sqrtMagic = Math.sqrt(magic);
  193. dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  194. dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
  195. Map<String,Double> model = new HashMap<String,Double>();
  196. model.put("lat", dLat);
  197. model.put("lon", dLon);
  198. return model;
  199. }
  200. public static Double transformLat(Double x, Double y) {
  201. Double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
  202. ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
  203. ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
  204. ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
  205. return ret;
  206. }
  207. public static Double transformLon(Double x, Double y) {
  208. Double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
  209. ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
  210. ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
  211. ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
  212. return ret;
  213. }
  214. public static final double MPD = 60.0;
  215. public static final double SPD = 3600.0;
  216. public static final double SPM = 60.0;
  217. public static ArrayList<Double> RadianToDMS(Double radian) {
  218. Boolean isNegative;
  219. Double degree = 0.0;
  220. Double minute = 0.0;
  221. Double second = 0.0;
  222. isNegative = false;
  223. if (radian < 0.0) {
  224. isNegative = false;
  225. radian = Math.abs(radian);
  226. } else {
  227. isNegative = false;
  228. degree = radian * DPR;
  229. minute = (degree - Math.floor(degree)) * MPD;
  230. degree = Math.floor(degree);
  231. second = (minute - Math.floor(minute)) * SPM;
  232. minute = Math.floor(minute);
  233. if (isNegative) {
  234. degree = -degree;
  235. minute = -minute;
  236. second = -second;
  237. }
  238. }
  239. ArrayList<Double> datalist = new ArrayList<Double>();
  240. datalist.add(degree);
  241. datalist.add(minute);
  242. datalist.add(second);
  243. return datalist;
  244. }
  245. public static ArrayList<Double> LBH7ParameterSelf(Double Ls, Double Bs, Double Hs, Double fA, Double fF, Double dX,
  246. Double dY, Double dZ, Double ex, Double ey, Double ez, Double m, Double at, Double ft) {
  247. Double Xs, Ys, Zs, Xt, Yt, Zt, Lt, Bt, Ht;
  248. ArrayList<Double> datalist = new ArrayList<Double>();
  249. ArrayList<Double> a = LBHToXYZ(fA, 1.0 / fF, Ls, Bs, Hs);
  250. Xs = a.get(0);
  251. Ys = a.get(1);
  252. Zs = a.get(2);
  253. ArrayList<Double> b = XYZ7Parameter(Xs, Ys, Zs, dX, dY, dZ, ex, ey, ez, m);
  254. Xt = b.get(0);
  255. Yt = b.get(1);
  256. Zt = b.get(2);
  257. ArrayList<Double> c = XYZToLBHBowring(at, 1.0 / ft, Xt, Yt, Zt);
  258. Lt = c.get(0);
  259. Bt = c.get(1);
  260. Ht = c.get(2);
  261. datalist.add(Lt);
  262. datalist.add(Bt);
  263. datalist.add(Ht);
  264. return datalist;
  265. }
  266. public static final double EQUALDE = 0.00000000000001;
  267. public static ArrayList<Double> AntiGaussProjectionConst(Double curra, Double currinvf, Double East, Double North) {
  268. Double currf, currb, curre12, curre22, curre14, curre16, curre18, currAp, currBp, currCp, currDp, currEp;
  269. Double A2, A4, A6, A8, currB2, currB4, currB6, currB8, phi, Bf, Nf, tf, cosBf, etaf2;
  270. Double B, l;
  271. ArrayList<Double> datalist = new ArrayList<Double>();
  272. if ((Math.abs(East) < EQUALDE) && (Math.abs(North) < EQUALDE)) {
  273. B = 0.0;
  274. l = 0.0;
  275. }
  276. currf = 1 / currinvf;
  277. currb = curra * (1 - currf);
  278. curre12 = (curra * curra - currb * currb) / (curra * curra);
  279. curre22 = (curra * curra - currb * currb) / (currb * currb);
  280. curre14 = curre12 * curre12;
  281. curre16 = curre14 * curre12;
  282. curre18 = curre14 * curre14;
  283. currAp = 1 + 3.0 / 4.0 * curre12 + 45.0 / 64.0 * curre14 + 175.0 / 256.0 * curre16 + 11025.0 / 16384.0 * curre18;
  284. currBp = 3.0 / 4.0 * curre12 + 15.0 / 16.0 * curre14 + 525.0 / 512.0 * curre16 + 2205.0 / 2048.0 * curre18;
  285. currCp = 15.0 / 64.0 * curre14 + 105.0 / 256.0 * curre16 + 2205.0 / 4096.0 * curre18;
  286. currDp = 35.0 / 512.0 * curre16 + 315.0 / 2048.0 * curre18;
  287. currEp = 315.0 / 16384.0 * curre18;
  288. A2 = currBp / (2 * currAp);
  289. A4 = -currCp / (4 * currAp);
  290. A6 = currDp / (6 * currAp);
  291. A8 = -currEp / (8 * currAp);
  292. currB2 = A2 - A2 * A4 - A4 * A6 - 0.5 * A2 * A2 * A2 - A2 * A4 * A4 + 0.5 * A2 * A2 * A6 - 18.3 * A2 * A2 * A2 * A4;
  293. currB4 = A4 + A2 * A2 - 2.0 * A2 * A6 - 4.0 * A2 * A2 * A4 - 1.3 * A2 * A2 * A2 * A2;
  294. currB6 = A6 + 3.0 * A2 * A4 - 3.0 * A2 * A8 + 1.5 * A2 * A2 * A2 - 4.5 * A2 * A4 * A4 - 9.0 * A2 * A2 * A6 - 12.5 * A2 * A2 * A2 * A4;
  295. currB8 = A8 + 2.0 * A4 * A4 + 4.0 * A2 * A6 + 8.0 * A2 * A2 * A4 + 2.7 * A2 * A2 * A2 * A2;
  296. phi = North / (curra * (1 - curre12) * currAp);
  297. Bf = phi + currB2 * Math.sin(2 * phi) + currB4 * Math.sin(4 * phi) + currB6 * Math.sin(6 * phi) + currB8 * Math.sin(8 * phi);
  298. if (Math.abs(Math.abs(Bf) - PI / 2.0) < EQUALDE) {
  299. B = Bf;
  300. l = 0.0;
  301. datalist.add(B);
  302. datalist.add(l);
  303. return datalist;
  304. }
  305. Nf = curra / Math.sqrt(1 - curre12 * Math.sin(Bf) * Math.sin(Bf));
  306. tf = Math.tan(Bf);
  307. cosBf = Math.cos(Bf);
  308. etaf2 = curre22 * cosBf * cosBf;
  309. B = Bf + tf * (-1 - etaf2) * East * East / (2 * Nf * Nf)
  310. + tf * (5 + 3 * tf * tf + 6 * etaf2 - 6 * tf * tf * etaf2 - 3 * etaf2 * etaf2 - 9 * tf * tf * etaf2 * etaf2) * East * East * East * East / (24 * Nf * Nf * Nf * Nf)
  311. + tf * (-61 - 90 * tf * tf - 45 * tf * tf * tf * tf - 107 * etaf2 + 162 * tf * tf * etaf2 + 45 * tf * tf * tf * tf * etaf2) * East * East * East * East * East * East / (720 * Nf * Nf * Nf * Nf * Nf * Nf);
  312. l = East / (Nf * cosBf)
  313. + (-1 - 2 * tf * tf - etaf2) * East * East * East / (6 * Nf * Nf * Nf * cosBf)
  314. + (5 + 28 * tf * tf + 24 * tf * tf * tf * tf + 6 * etaf2 + 8 * tf * tf * etaf2) * East * East * East * East * East / (120 * Nf * Nf * Nf * Nf * Nf * cosBf);
  315. datalist.add(B);
  316. datalist.add(l);
  317. return datalist;
  318. }
  319. public static final double DPM = 0.016666666666666666666666666666667;
  320. public static final double DPS = 0.00027777777777777777777777777777778;
  321. public static Double DMSToDegree(Double degree, Double minute, Double second) {
  322. Boolean isNegative;
  323. if ((degree < 0.0) || (minute < 0.0) || (second < 0.0)) {
  324. isNegative = true;
  325. degree = Math.abs(degree);
  326. minute = Math.abs(minute);
  327. second = Math.abs(second);
  328. } else
  329. isNegative = false;
  330. degree = degree + minute * DPM + second * DPS;
  331. if (isNegative) {
  332. return -degree;
  333. } else
  334. return degree;
  335. }
  336. public static final double DPR = 57.295779513082320876798154814105;
  337. public static final double RPD = 0.017453292519943295769236907684886;
  338. public static final double RPS = 0.0000048481368110953599358991410235795;
  339. public static Double RadianToDegree(Double radian) {
  340. return radian * DPR;
  341. }
  342. public static Double DegreeToRadian(Double degree) {
  343. return degree * RPD;
  344. }
  345. public static Double SecondToRadian(Double second) {
  346. return second * RPS;
  347. }
  348. public static ArrayList<Double> XYZToLBHBowring(Double curra, Double currinvf, Double X, Double Y, Double Z) {
  349. Double L, B, H;
  350. Double Rxy, f, e12, e22, tanu, cosu, sinu, temp;
  351. Double sinB;
  352. ArrayList<Double> datalist = new ArrayList<Double>();
  353. if ((X == 0) && (Y == 0)) {
  354. if (Z < 0) {
  355. L = 0.0;
  356. B = -PI / 2;
  357. H = -(Z + curra * (1 - 1 / currinvf));
  358. } else if (Z > 0) {
  359. L = 0.0;
  360. B = PI / 2;
  361. H = Z - curra * (1 - 1 / currinvf);
  362. } else {
  363. L = 0.0;
  364. B = 0.0;
  365. H = -curra;
  366. }
  367. }
  368. Rxy = Math.sqrt(X * X + Y * Y);
  369. //Get L
  370. L = Math.acos(X / Rxy);
  371. if (Y < 0) L = -L;
  372. //Get B
  373. f = 1 / currinvf;
  374. e12 = (2 - f) * f;
  375. e22 = e12 / (1 - e12);
  376. tanu = Z * Math.sqrt(1 + e22) / Rxy;
  377. cosu = 1 / Math.sqrt(1 + tanu * tanu);
  378. sinu = tanu * cosu;
  379. temp = Rxy - curra * e12 * cosu * cosu * cosu;
  380. if (temp == 0) {
  381. if (Z < 0)
  382. B = -PI / 2;
  383. else
  384. B = PI / 2;
  385. } else
  386. B = Math.atan((Z + curra * (1 - f) * e22 * sinu * sinu * sinu) / temp);
  387. //Get H
  388. sinB = Math.sin(B);
  389. if (Math.abs(B) < 4.8e-10)
  390. H = Rxy / Math.cos(B) - curra / Math.sqrt(1 - e12 * sinB * sinB);
  391. else
  392. H = Z / sinB - curra / Math.sqrt(1 - e12 * sinB * sinB) * (1 - e12);
  393. datalist.add(L);
  394. datalist.add(B);
  395. datalist.add(H);
  396. return datalist;
  397. }
  398. public static ArrayList<Double> LBHToXYZ(Double curra, Double currinvf, Double L, Double B, Double H) {
  399. Double e12, N, X, Y, Z;
  400. ArrayList<Double> datalist = new ArrayList<Double>();
  401. e12 = (2.0 - 1.0 / currinvf) / currinvf;
  402. N = curra / Math.sqrt(1 - e12 * Math.sin(B) * Math.sin(B));
  403. X = (N + H) * Math.cos(B) * Math.cos(L);
  404. Y = (N + H) * Math.cos(B) * Math.sin(L);
  405. Z = (N * (1 - e12) + H) * Math.sin(B);
  406. datalist.add(X);
  407. datalist.add(Y);
  408. datalist.add(Z);
  409. return datalist;
  410. }
  411. public static ArrayList<Double> XYZ7Parameter(Double Xs, Double Ys, Double Zs, Double dX, Double dY, Double dZ, Double ex,
  412. Double ey, Double ez, Double m) {
  413. Double Xt, Yt, Zt;
  414. ArrayList<Double> datalist = new ArrayList<Double>();
  415. Xt = Xs * (1 + m) + Ys * ez - Zs * ey + dX;
  416. Yt = Ys * (1 + m) - Xs * ez + Zs * ex + dY;
  417. Zt = Zs * (1 + m) + Xs * ey - Ys * ex + dZ;
  418. datalist.add(Xt);
  419. datalist.add(Yt);
  420. datalist.add(Zt);
  421. return datalist;
  422. }
  423. }
复制代码

以上就是Java实现经纬度坐标转换的示例代码的详细内容,更多关于Java坐标转换的资料请关注晓枫资讯其它相关文章!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表