/* 引入Cesium */ // import * as Cesium from 'Cesium'; const BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0; const PI = 3.1415926535897932384626; const RADIUS = 6378245.0; const EE = 0.00669342162296594323; /** * 坐标转换 */ class CoordTransform { /** * 百度坐标系转||BD-09 To GCJ-02 * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number[]} */ static BD09ToGCJ02(lng, lat) { let x = +lng - 0.0065 let y = +lat - 0.006 let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * BD_FACTOR) let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * BD_FACTOR) let gg_lng = z * Math.cos(theta) let gg_lat = z * Math.sin(theta) return [gg_lng, gg_lat]; } /** * GCJ-02 To BD-09 * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number[]} * @constructor */ static GCJ02ToBD09(lng, lat) { lat = +lat lng = +lng let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * BD_FACTOR) let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * BD_FACTOR) let bd_lng = z * Math.cos(theta) + 0.0065 let bd_lat = z * Math.sin(theta) + 0.006 return [bd_lng, bd_lat] } /** * WGS-84 To GCJ-02 * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number[]} */ static WGS84ToGCJ02(lng, lat) { lat = +lat lng = +lng if (this.out_of_china(lng, lat)) { return [lng, lat] } else { let d = this.delta(lng, lat) return [lng + d[0], lat + d[1]] } } /** * GCJ-02 To WGS-84 * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number[]} * @constructor */ static GCJ02ToWGS84(lng, lat) { lat = +lat lng = +lng if (this.out_of_china(lng, lat)) { return [lng, lat] } else { let d = this.delta(lng, lat) let mgLng = lng + d[0] let mgLat = lat + d[1] return [lng * 2 - mgLng, lat * 2 - mgLat] } } /** * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number[]} */ static delta(lng, lat) { let dLng = this.transformLng(lng - 105, lat - 35) let dLat = this.transformLat(lng - 105, lat - 35) const radLat = (lat / 180) * PI let magic = Math.sin(radLat) magic = 1 - EE * magic * magic const sqrtMagic = Math.sqrt(magic) dLng = (dLng * 180) / ((RADIUS / sqrtMagic) * Math.cos(radLat) * PI) dLat = (dLat * 180) / (((RADIUS * (1 - EE)) / (magic * sqrtMagic)) * PI) return [dLng, dLat] } /** * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number} */ static transformLng(lng, lat) { lat = +lat lng = +lng let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)) ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0 ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0 ret += ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) / 3.0 return ret } /** * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {number} */ static transformLat(lng, lat) { lat = +lat lng = +lng 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)) ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0 ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0 ret += ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0 return ret } /** * @ignore 忽略注释,注释不生成Doc * @param lng * @param lat * @returns {boolean} */ static out_of_china(lng, lat) { lat = +lat lng = +lng return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55) } /** * 获取Catesian3坐标 */ static getCatesian3FromPX(viewer, px) { let picks = viewer.scene.drillPick(px); let cartesian = null; let isOn3dtiles = false, isOnTerrain = false; // drillPick for (let i in picks) { let pick = picks[i]; if ( (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) || (pick && pick.primitive instanceof Cesium.Cesium3DTileset) || (pick && pick.primitive instanceof Cesium.Model) ) { //模型上拾取 isOn3dtiles = true; } // 3dtilset if (isOn3dtiles) { viewer.scene.pick(px); // pick cartesian = viewer.scene.pickPosition(px); if (cartesian) { let cartographic = Cesium.Cartographic.fromCartesian(cartesian); if (cartographic.height < 0) cartographic.height = 0; let lon = Cesium.Math.toDegrees(cartographic.longitude), lat = Cesium.Math.toDegrees(cartographic.latitude), height = cartographic.height; cartesian = this.transformWGS84ToCartesian({ lng: lon, lat: lat, alt: height, }); } } } // 地形 let boolTerrain = viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider; // Terrain if (!isOn3dtiles && !boolTerrain) { let ray = viewer.scene.camera.getPickRay(px); if (!ray) return null; cartesian = viewer.scene.globe.pick(ray, viewer.scene); isOnTerrain = true; } // 地球 if (!isOn3dtiles && !isOnTerrain && boolTerrain) { cartesian = viewer.scene.camera.pickEllipsoid( px, viewer.scene.globe.ellipsoid ); } if (cartesian) { let position = this.transformCartesianToWGS84(cartesian); if (position.alt < 0) { cartesian = this.transformWGS84ToCartesian(position, 0.1); } return cartesian; } return false; } /** * 坐标转换 84转笛卡尔 * @ignore 忽略注释,注释不生成Doc * @param {object} position - {lng,lat,alt} 地理坐标 * @param {number} alt - 高度 * @returns {object} Cartesian3 笛卡尔坐标 */ static transformWGS84ToCartesian(position, alt) { return position ? Cesium.Cartesian3.fromDegrees( position.lng || position.lon, position.lat, (position.alt = alt || position.alt), Cesium.Ellipsoid.WGS84 ) : Cesium.Cartesian3.ZERO } /** * 坐标转换 笛卡尔转84 * @ignore 忽略注释,注释不生成Doc * @param {object} cartesian - 笛卡尔坐标 * @returns {object} - {lng,lat,alt} 地理坐标 */ static transformCartesianToWGS84(cartesian) { let ellipsoid = Cesium.Ellipsoid.WGS84 let cartographic = ellipsoid.cartesianToCartographic(cartesian) return { lng: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude), alt: cartographic.height } } /** * 笛卡尔坐标数组转WGS84 * @param {Array} cartesianList 笛卡尔坐标数组 * @returns {Array} WGS84经纬度坐标数组 */ static Cartesian3ListToWGS84(cartesianList) { let ellipsoid = Cesium.Ellipsoid.WGS84; let result = []; for (let index = 0; index < cartesianList.length; index++) { const cartesian = cartesianList[index]; let cartographic = ellipsoid.cartesianToCartographic(cartesian); result.push({ lng: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude), alt: cartographic.height, }); } return result; } /** * 度(十进制)转度分秒 * @param {Number} value 十进制度 */ static Degrees2DMS(value) { let degrees = Math.floor(value); //根据“floor”的字面意思“地板”去理解;舍小数位 let rem = (value - degrees) * 60; let minutes = Math.floor(rem); let _second = (rem - minutes) * 60; // let seconds = Math.ceil(_second); //根据“ceil”的字面意思“天花板”去理解;进小数位 let seconds = Math.round(_second); //(小数点后第一位)大于五全部加,等于五正数加,小于五全不加。 var _radians = Cesium.Math.toRadians(value); //经纬度转弧度 var _degrees = Cesium.Math.toDegrees(value); //弧度转经纬度 console.log(_radians) console.log(_degrees) let DMS = { degrees: degrees, minutes: minutes, seconds: seconds }; return DMS; } /** * 度分秒转度(十进制) * @param {Object} DMS 度分秒对象 * @param {Object} DMS.degrees 度 * @param {Object} DMS.minutes 分 * @param {Object} DMS.seconds 秒 */ static DMS2Degrees(DMS) { let _double = parseFloat(DMS.degrees) + parseFloat(DMS.minutes) / 60 + parseFloat(DMS.seconds) / 3600; return parseFloat(_double).toFixed(6); } /** * 世界坐标转换为经纬度坐标 * @ignore 生成方法时不对外公开 * @param {Cesium.Cartesian3} position 点 */ static _cartesian3ToGeo(position) { let g = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position); return { longitude: Cesium.Math.toDegrees(g.longitude), latitude: Cesium.Math.toDegrees(g.latitude), height: g.height, } } /** * 弧度转度 * @ignore * @param {Number} arc 弧度 * @return {Number} 角度 */ static _arcToDegree(arc) { return arc / Math.PI * 180; } /** * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度 * @ignore * @param {JSON} screenPoint 屏幕坐标 * @param {Number} screenPoint.x 屏幕坐标x * @param {Number} screenPoint.y 屏幕坐标y * @return {JSON} 位置信息{lng,lat,height} */ static _getScreenClickPositionAndHeight(viewer,screenPoint) { this._viewer=viewer; var lng = undefined, lat = undefined, height = undefined; /* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */ var ray = this._viewer.scene.camera.getPickRay(screenPoint); /* 找到射线与渲染的地球表面之间的交点 */ var position = this._viewer.scene.globe.pick(ray, this._viewer.scene); /* 获取地理位置的制图表达 */ var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position); /* 查询屏幕位置的要素 */ var feature = this._viewer.scene.pick(screenPoint); if (feature == undefined) { lng = this._arcToDegree(cartographic.longitude); lat = this._arcToDegree(cartographic.latitude); height = cartographic.height; } else { var cartesian = this._viewer.scene.pickPosition(screenPoint); if (Cesium.defined(cartesian)) { var cartographic = Cesium.Cartographic.fromCartesian(cartesian); lng = this._arcToDegree(cartographic.longitude); lat = this._arcToDegree(cartographic.latitude); height = cartographic.height; } } /* 返回结果 */ return { lng: lng, lat: lat, height: height, } } /** * 屏幕位置转换为经纬度位置及空间位置 * @ignore * @param {Object} viewer 三维场景 * @param {Cesium.Cartesian2} screenPosition 屏幕位置 * @return {JSON} 经纬度位置及空间位置 */ static _transfromFromScreenPoint(viewer,screenPosition) { /* 根据屏幕位置获取经度、纬度和高度信息 */ let location = this._getScreenClickPositionAndHeight(viewer,screenPosition); /* 经纬度位置转换为三维坐标 */ var cartesian = Cesium.Cartesian3.fromDegrees(location.lng, location.lat, location.height); /* 返回 */ return { gLocation: location, sLocation: cartesian, } } } export default CoordTransform;