coordTransform.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /**
  2. * WGS84 → GCJ-02 → BD-09 坐标转换工具
  3. * 百度地图需要使用 BD-09 坐标系
  4. */
  5. const PI = Math.PI
  6. const X_PI = (PI * 3000.0) / 180.0
  7. const A = 6378245.0
  8. const EE = 0.00669342162296594323
  9. function transformLat(lng, lat) {
  10. let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng))
  11. ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0
  12. ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0
  13. ret += ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0
  14. return ret
  15. }
  16. function transformLng(lng, lat) {
  17. let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng))
  18. ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0
  19. ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0
  20. ret += ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) / 3.0
  21. return ret
  22. }
  23. /** WGS84 → GCJ-02 (火星坐标) */
  24. function wgs84ToGcj02(lng, lat) {
  25. let dLat = transformLat(lng - 105.0, lat - 35.0)
  26. let dLng = transformLng(lng - 105.0, lat - 35.0)
  27. const radLat = (lat / 180.0) * PI
  28. let magic = Math.sin(radLat)
  29. magic = 1 - EE * magic * magic
  30. const sqrtMagic = Math.sqrt(magic)
  31. dLat = (dLat * 180.0) / (((A * (1 - EE)) / (magic * sqrtMagic)) * PI)
  32. dLng = (dLng * 180.0) / ((A / sqrtMagic) * Math.cos(radLat) * PI)
  33. return [lng + dLng, lat + dLat]
  34. }
  35. /** GCJ-02 → BD-09 (百度坐标) */
  36. function gcj02ToBd09(lng, lat) {
  37. const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * X_PI)
  38. const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * X_PI)
  39. return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006]
  40. }
  41. /** WGS84 → BD-09 一步转换 */
  42. export function wgs84ToBd09(lng, lat) {
  43. const [gcjLng, gcjLat] = wgs84ToGcj02(lng, lat)
  44. return gcj02ToBd09(gcjLng, gcjLat)
  45. }
  46. /** 百度 BD-09 → WGS84,用于地图选点回填业务坐标 */
  47. export function bd09ToWgs84(lng, lat) {
  48. const x = Number(lng) - 0.0065
  49. const y = Number(lat) - 0.006
  50. const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI)
  51. const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI)
  52. const gcjLng = z * Math.cos(theta)
  53. const gcjLat = z * Math.sin(theta)
  54. const [wgsLng, wgsLat] = wgs84ToGcj02Inverse(gcjLng, gcjLat)
  55. return [wgsLng, wgsLat]
  56. }
  57. function wgs84ToGcj02Inverse(lng, lat) {
  58. const [forwardLng, forwardLat] = wgs84ToGcj02(lng, lat)
  59. return [lng * 2 - forwardLng, lat * 2 - forwardLat]
  60. }
  61. /** 转换管线数据中的坐标数组 */
  62. export function convertPipeline(pipeline) {
  63. return {
  64. ...pipeline,
  65. path: pipeline.path ? pipeline.path.map(([lng, lat]) => wgs84ToBd09(lng, lat)) : undefined,
  66. points: pipeline.points
  67. ? (Array.isArray(pipeline.points[0])
  68. ? pipeline.points.map(([lng, lat]) => wgs84ToBd09(lng, lat))
  69. : pipeline.points.map(p => ({ ...p, lng: wgs84ToBd09(p.lng, p.lat)[0], lat: wgs84ToBd09(p.lng, p.lat)[1] })))
  70. : undefined
  71. }
  72. }
  73. /** 转换单个坐标点 */
  74. export function convertCoord(lng, lat) {
  75. return wgs84ToBd09(lng, lat)
  76. }
  77. /** 批量转换点数组中的 lng/lat */
  78. export function convertPoints(points) {
  79. return points.map(p => {
  80. const [lng, lat] = wgs84ToBd09(p.lng, p.lat)
  81. return { ...p, lng, lat }
  82. })
  83. }