CoordTransform.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /* 引入Cesium */
  2. // import * as Cesium from 'Cesium';
  3. const BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0;
  4. const PI = 3.1415926535897932384626;
  5. const RADIUS = 6378245.0;
  6. const EE = 0.00669342162296594323;
  7. /**
  8. * 坐标转换
  9. */
  10. class CoordTransform {
  11. /**
  12. * 百度坐标系转||BD-09 To GCJ-02
  13. * @ignore 忽略注释,注释不生成Doc
  14. * @param lng
  15. * @param lat
  16. * @returns {number[]}
  17. */
  18. static BD09ToGCJ02(lng, lat) {
  19. let x = +lng - 0.0065
  20. let y = +lat - 0.006
  21. let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * BD_FACTOR)
  22. let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * BD_FACTOR)
  23. let gg_lng = z * Math.cos(theta)
  24. let gg_lat = z * Math.sin(theta)
  25. return [gg_lng, gg_lat];
  26. }
  27. /**
  28. * GCJ-02 To BD-09
  29. * @ignore 忽略注释,注释不生成Doc
  30. * @param lng
  31. * @param lat
  32. * @returns {number[]}
  33. * @constructor
  34. */
  35. static GCJ02ToBD09(lng, lat) {
  36. lat = +lat
  37. lng = +lng
  38. let z =
  39. Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * BD_FACTOR)
  40. let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * BD_FACTOR)
  41. let bd_lng = z * Math.cos(theta) + 0.0065
  42. let bd_lat = z * Math.sin(theta) + 0.006
  43. return [bd_lng, bd_lat]
  44. }
  45. /**
  46. * WGS-84 To GCJ-02
  47. * @ignore 忽略注释,注释不生成Doc
  48. * @param lng
  49. * @param lat
  50. * @returns {number[]}
  51. */
  52. static WGS84ToGCJ02(lng, lat) {
  53. lat = +lat
  54. lng = +lng
  55. if (this.out_of_china(lng, lat)) {
  56. return [lng, lat]
  57. } else {
  58. let d = this.delta(lng, lat)
  59. return [lng + d[0], lat + d[1]]
  60. }
  61. }
  62. /**
  63. * GCJ-02 To WGS-84
  64. * @ignore 忽略注释,注释不生成Doc
  65. * @param lng
  66. * @param lat
  67. * @returns {number[]}
  68. * @constructor
  69. */
  70. static GCJ02ToWGS84(lng, lat) {
  71. lat = +lat
  72. lng = +lng
  73. if (this.out_of_china(lng, lat)) {
  74. return [lng, lat]
  75. } else {
  76. let d = this.delta(lng, lat)
  77. let mgLng = lng + d[0]
  78. let mgLat = lat + d[1]
  79. return [lng * 2 - mgLng, lat * 2 - mgLat]
  80. }
  81. }
  82. /**
  83. * @ignore 忽略注释,注释不生成Doc
  84. * @param lng
  85. * @param lat
  86. * @returns {number[]}
  87. */
  88. static delta(lng, lat) {
  89. let dLng = this.transformLng(lng - 105, lat - 35)
  90. let dLat = this.transformLat(lng - 105, lat - 35)
  91. const radLat = (lat / 180) * PI
  92. let magic = Math.sin(radLat)
  93. magic = 1 - EE * magic * magic
  94. const sqrtMagic = Math.sqrt(magic)
  95. dLng = (dLng * 180) / ((RADIUS / sqrtMagic) * Math.cos(radLat) * PI)
  96. dLat = (dLat * 180) / (((RADIUS * (1 - EE)) / (magic * sqrtMagic)) * PI)
  97. return [dLng, dLat]
  98. }
  99. /**
  100. * @ignore 忽略注释,注释不生成Doc
  101. * @param lng
  102. * @param lat
  103. * @returns {number}
  104. */
  105. static transformLng(lng, lat) {
  106. lat = +lat
  107. lng = +lng
  108. let ret =
  109. 300.0 +
  110. lng +
  111. 2.0 * lat +
  112. 0.1 * lng * lng +
  113. 0.1 * lng * lat +
  114. 0.1 * Math.sqrt(Math.abs(lng))
  115. ret +=
  116. ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
  117. 2.0) /
  118. 3.0
  119. ret +=
  120. ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) /
  121. 3.0
  122. ret +=
  123. ((150.0 * Math.sin((lng / 12.0) * PI) +
  124. 300.0 * Math.sin((lng / 30.0) * PI)) *
  125. 2.0) /
  126. 3.0
  127. return ret
  128. }
  129. /**
  130. * @ignore 忽略注释,注释不生成Doc
  131. * @param lng
  132. * @param lat
  133. * @returns {number}
  134. */
  135. static transformLat(lng, lat) {
  136. lat = +lat
  137. lng = +lng
  138. let ret = -100.0 +
  139. 2.0 * lng +
  140. 3.0 * lat +
  141. 0.2 * lat * lat +
  142. 0.1 * lng * lat +
  143. 0.2 * Math.sqrt(Math.abs(lng))
  144. ret +=
  145. ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
  146. 2.0) /
  147. 3.0
  148. ret +=
  149. ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) /
  150. 3.0
  151. ret +=
  152. ((160.0 * Math.sin((lat / 12.0) * PI) +
  153. 320 * Math.sin((lat * PI) / 30.0)) *
  154. 2.0) /
  155. 3.0
  156. return ret
  157. }
  158. /**
  159. * @ignore 忽略注释,注释不生成Doc
  160. * @param lng
  161. * @param lat
  162. * @returns {boolean}
  163. */
  164. static out_of_china(lng, lat) {
  165. lat = +lat
  166. lng = +lng
  167. return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55)
  168. }
  169. /**
  170. * 获取Catesian3坐标
  171. */
  172. static getCatesian3FromPX(viewer, px) {
  173. let picks = viewer.scene.drillPick(px);
  174. let cartesian = null;
  175. let isOn3dtiles = false,
  176. isOnTerrain = false;
  177. // drillPick
  178. for (let i in picks) {
  179. let pick = picks[i];
  180. if (
  181. (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
  182. (pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
  183. (pick && pick.primitive instanceof Cesium.Model)
  184. ) {
  185. //模型上拾取
  186. isOn3dtiles = true;
  187. }
  188. // 3dtilset
  189. if (isOn3dtiles) {
  190. viewer.scene.pick(px); // pick
  191. cartesian = viewer.scene.pickPosition(px);
  192. if (cartesian) {
  193. let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  194. if (cartographic.height < 0) cartographic.height = 0;
  195. let lon = Cesium.Math.toDegrees(cartographic.longitude),
  196. lat = Cesium.Math.toDegrees(cartographic.latitude),
  197. height = cartographic.height;
  198. cartesian = this.transformWGS84ToCartesian({
  199. lng: lon,
  200. lat: lat,
  201. alt: height,
  202. });
  203. }
  204. }
  205. }
  206. // 地形
  207. let boolTerrain = viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
  208. // Terrain
  209. if (!isOn3dtiles && !boolTerrain) {
  210. let ray = viewer.scene.camera.getPickRay(px);
  211. if (!ray) return null;
  212. cartesian = viewer.scene.globe.pick(ray, viewer.scene);
  213. isOnTerrain = true;
  214. }
  215. // 地球
  216. if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
  217. cartesian = viewer.scene.camera.pickEllipsoid(
  218. px,
  219. viewer.scene.globe.ellipsoid
  220. );
  221. }
  222. if (cartesian) {
  223. let position = this.transformCartesianToWGS84(cartesian);
  224. if (position.alt < 0) {
  225. cartesian = this.transformWGS84ToCartesian(position, 0.1);
  226. }
  227. return cartesian;
  228. }
  229. return false;
  230. }
  231. /**
  232. * 坐标转换 84转笛卡尔
  233. * @ignore 忽略注释,注释不生成Doc
  234. * @param {object} position - {lng,lat,alt} 地理坐标
  235. * @param {number} alt - 高度
  236. * @returns {object} Cartesian3 笛卡尔坐标
  237. */
  238. static transformWGS84ToCartesian(position, alt) {
  239. return position ?
  240. Cesium.Cartesian3.fromDegrees(
  241. position.lng || position.lon,
  242. position.lat,
  243. (position.alt = alt || position.alt),
  244. Cesium.Ellipsoid.WGS84
  245. ) :
  246. Cesium.Cartesian3.ZERO
  247. }
  248. /**
  249. * 坐标转换 笛卡尔转84
  250. * @ignore 忽略注释,注释不生成Doc
  251. * @param {object} cartesian - 笛卡尔坐标
  252. * @returns {object} - {lng,lat,alt} 地理坐标
  253. */
  254. static transformCartesianToWGS84(cartesian) {
  255. let ellipsoid = Cesium.Ellipsoid.WGS84
  256. let cartographic = ellipsoid.cartesianToCartographic(cartesian)
  257. return {
  258. lng: Cesium.Math.toDegrees(cartographic.longitude),
  259. lat: Cesium.Math.toDegrees(cartographic.latitude),
  260. alt: cartographic.height
  261. }
  262. }
  263. /**
  264. * 笛卡尔坐标数组转WGS84
  265. * @param {Array} cartesianList 笛卡尔坐标数组
  266. * @returns {Array} WGS84经纬度坐标数组
  267. */
  268. static Cartesian3ListToWGS84(cartesianList) {
  269. let ellipsoid = Cesium.Ellipsoid.WGS84;
  270. let result = [];
  271. for (let index = 0; index < cartesianList.length; index++) {
  272. const cartesian = cartesianList[index];
  273. let cartographic = ellipsoid.cartesianToCartographic(cartesian);
  274. result.push({
  275. lng: Cesium.Math.toDegrees(cartographic.longitude),
  276. lat: Cesium.Math.toDegrees(cartographic.latitude),
  277. alt: cartographic.height,
  278. });
  279. }
  280. return result;
  281. }
  282. /**
  283. * 度(十进制)转度分秒
  284. * @param {Number} value 十进制度
  285. */
  286. static Degrees2DMS(value) {
  287. let degrees = Math.floor(value); //根据“floor”的字面意思“地板”去理解;舍小数位
  288. let rem = (value - degrees) * 60;
  289. let minutes = Math.floor(rem);
  290. let _second = (rem - minutes) * 60;
  291. // let seconds = Math.ceil(_second); //根据“ceil”的字面意思“天花板”去理解;进小数位
  292. let seconds = Math.round(_second); //(小数点后第一位)大于五全部加,等于五正数加,小于五全不加。
  293. var _radians = Cesium.Math.toRadians(value); //经纬度转弧度
  294. var _degrees = Cesium.Math.toDegrees(value); //弧度转经纬度
  295. console.log(_radians)
  296. console.log(_degrees)
  297. let DMS = {
  298. degrees: degrees,
  299. minutes: minutes,
  300. seconds: seconds
  301. };
  302. return DMS;
  303. }
  304. /**
  305. * 度分秒转度(十进制)
  306. * @param {Object} DMS 度分秒对象
  307. * @param {Object} DMS.degrees 度
  308. * @param {Object} DMS.minutes 分
  309. * @param {Object} DMS.seconds 秒
  310. */
  311. static DMS2Degrees(DMS) {
  312. let _double = parseFloat(DMS.degrees) + parseFloat(DMS.minutes) / 60 + parseFloat(DMS.seconds) / 3600;
  313. return parseFloat(_double).toFixed(6);
  314. }
  315. /**
  316. * 世界坐标转换为经纬度坐标
  317. * @ignore 生成方法时不对外公开
  318. * @param {Cesium.Cartesian3} position 点
  319. */
  320. static _cartesian3ToGeo(position) {
  321. let g = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
  322. return {
  323. longitude: Cesium.Math.toDegrees(g.longitude),
  324. latitude: Cesium.Math.toDegrees(g.latitude),
  325. height: g.height,
  326. }
  327. }
  328. /**
  329. * 弧度转度
  330. * @ignore
  331. * @param {Number} arc 弧度
  332. * @return {Number} 角度
  333. */
  334. static _arcToDegree(arc) {
  335. return arc / Math.PI * 180;
  336. }
  337. /**
  338. * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度
  339. * @ignore
  340. * @param {JSON} screenPoint 屏幕坐标
  341. * @param {Number} screenPoint.x 屏幕坐标x
  342. * @param {Number} screenPoint.y 屏幕坐标y
  343. * @return {JSON} 位置信息{lng,lat,height}
  344. */
  345. static _getScreenClickPositionAndHeight(viewer,screenPoint) {
  346. this._viewer=viewer;
  347. var lng = undefined,
  348. lat = undefined,
  349. height = undefined;
  350. /* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */
  351. var ray = this._viewer.scene.camera.getPickRay(screenPoint);
  352. /* 找到射线与渲染的地球表面之间的交点 */
  353. var position = this._viewer.scene.globe.pick(ray, this._viewer.scene);
  354. /* 获取地理位置的制图表达 */
  355. var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
  356. /* 查询屏幕位置的要素 */
  357. var feature = this._viewer.scene.pick(screenPoint);
  358. if (feature == undefined) {
  359. lng = this._arcToDegree(cartographic.longitude);
  360. lat = this._arcToDegree(cartographic.latitude);
  361. height = cartographic.height;
  362. } else {
  363. var cartesian = this._viewer.scene.pickPosition(screenPoint);
  364. if (Cesium.defined(cartesian)) {
  365. var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  366. lng = this._arcToDegree(cartographic.longitude);
  367. lat = this._arcToDegree(cartographic.latitude);
  368. height = cartographic.height;
  369. }
  370. }
  371. /* 返回结果 */
  372. return {
  373. lng: lng,
  374. lat: lat,
  375. height: height,
  376. }
  377. }
  378. /**
  379. * 屏幕位置转换为经纬度位置及空间位置
  380. * @ignore
  381. * @param {Object} viewer 三维场景
  382. * @param {Cesium.Cartesian2} screenPosition 屏幕位置
  383. * @return {JSON} 经纬度位置及空间位置
  384. */
  385. static _transfromFromScreenPoint(viewer,screenPosition) {
  386. /* 根据屏幕位置获取经度、纬度和高度信息 */
  387. let location = this._getScreenClickPositionAndHeight(viewer,screenPosition);
  388. /* 经纬度位置转换为三维坐标 */
  389. var cartesian = Cesium.Cartesian3.fromDegrees(location.lng, location.lat, location.height);
  390. /* 返回 */
  391. return {
  392. gLocation: location,
  393. sLocation: cartesian,
  394. }
  395. }
  396. }
  397. export default CoordTransform;