import * as Cesium from 'cesium' import * as turf from '@turf/turf' export const getLngLatDistance = (lat1, lng1, lat2, lng2) => { const radLat1 = (lat1 * Math.PI) / 180.0 const radLat2 = (lat2 * Math.PI) / 180.0 const a = radLat1 - radLat2 const b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0 let s = 2 * Math.asin( Math.sqrt( Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2) ) ) s = s * 6378.137 // EARTH_RADIUS; s = Math.round(s * 10000) / 10000 return s * 1000 } // 获取限polyline长度 export const getPolylineLength = entity => { let length = 0 // 获取Polyline的所有顶点位置 const positions = entity.polyline.positions.getValue() for (let i = 0; i < positions.length - 1; ++i) { const startPosition = positions[i] const endPosition = positions[i + 1] // 使用Cesium提供的distanceBetween函数计算两个顶点之间的距离 const distance = Cesium.Cartesian3.distance(startPosition, endPosition) // 将每个顶点之间的距离相加得到总长度 length += distance } return length } // 创建三角广告牌 export const createTriangleMarker = (title, color) => { // 创建canvas绘制广告牌 const billboard = document.createElement('canvas') billboard.width = 30 billboard.height = 30 const ctx = billboard.getContext('2d') ctx.beginPath() ctx.moveTo(0, 0) ctx.lineTo(30, 0) ctx.lineTo(15, 22) ctx.fillStyle = color ctx.fill() ctx.font = '18px serif' ctx.fillStyle = '#ffffff' ctx.fillText(title, 10, 15) ctx.closePath() return billboard } export const createCircleBillboard = (title, color) => { const billboard = document.createElement('canvas') const ctx = billboard.getContext('2d') ctx.beginPath() ctx.ellipse(150, 90, 11, 11, 0, 0, Math.PI * 2) ctx.fillStyle = color ctx.fill() ctx.font = 'bold 15px serif' ctx.textAlign = 'center' ctx.fillStyle = '#ffffff' ctx.fillText(title, 150, 95) ctx.closePath() return billboard } // 获取当前经纬度海拔 export const getHaeHeight = (start, end) => { const ellipsoid = Cesium.Ellipsoid.WGS84 // 选择合适的椭圆体模型 // const { longitude, latitude, height } = start // const { longitude: endLng, latitude: endLat, height: endHeight } = end // const startC3Position = new Cesium.Cartographic(longitude, latitude, height) // const endC3Position = new Cesium.Cartographic(endLng, endLat, endHeight) // const startCartesianPosition = ellipsoid.cartographicToCartesian(startC3Position) // const endCartesianPosition = ellipsoid.cartographicToCartesian(endC3Position) // // 计算两个位置之间的距离 // const distance = new Cesium.EllipsoidGeodesic(startCartesianPosition, endCartesianPosition, ellipsoid) // return distance const { longitude, latitude, height } = end const cartographic = Cesium.Cartographic.fromDegrees(longitude, latitude, height) const cartesianPosition = ellipsoid.cartographicToCartesian(cartographic) const haeHeight = ellipsoid.cartesianToCartographic(cartesianPosition).height return haeHeight } // Cesium Cartesian3 转正常经纬度 export const cartesian3Convert = (cartesian3Position, viewer) => { // 转换为经纬度 const ellipsoid = viewer.scene.globe.ellipsoid const cartographicPosition = Cesium.Cartographic.fromCartesian(cartesian3Position, ellipsoid) const longitude = Cesium.Math.toDegrees(cartographicPosition.longitude) const latitude = Cesium.Math.toDegrees(cartographicPosition.latitude) const height = cartographicPosition.height // console.log('经度: ' + longitude); // console.log('纬度: ' + latitude); // console.log('高度: ' + height); return { longitude, latitude, height, } } // Cesium Cartesian2 转正常经纬度 export const cartesian2Convert = (position, viewer) => { const ellipsoid = viewer.scene.globe.ellipsoid const c3Position = viewer.scene.globe.pick(viewer.camera.getPickRay(position), viewer.scene) const c2Postion = ellipsoid.cartesianToCartographic(c3Position) const longitude = Cesium.Math.toDegrees(c2Postion.longitude) const latitude = Cesium.Math.toDegrees(c2Postion.latitude) return { longitude, latitude } } // 根据经纬度获取距离 export const getLnglatDist = (lng1, lat1, lng2, lat2) => { const start = new Cesium.Cartesian3.fromDegrees(Number(lng1), Number(lat1), 0) const end = new Cesium.Cartesian3.fromDegrees(Number(lng2), Number(lat2), 0) return Cesium.Cartesian3.distance(start, end) } /** * 地点坐标计算中心点 * @param coordinateList {Array>} [[{lat, lng}]] * @return { Object } {lat lng} */ export const getCenterPoint = coordinateList => { coordinateList = coordinateList.map(item => { const [lng, lat] = item return [{ lat, lng }] }) const geoCoordinateListFlat = coordinateList.reduce((s, v) => { return (s = s.concat(v)) }, []) const total = geoCoordinateListFlat.length let X = 0 let Y = 0 let Z = 0 for (const g of geoCoordinateListFlat) { const lat = (g.lat * Math.PI) / 180 const lon = (g.lng * Math.PI) / 180 const x = Math.cos(lat) * Math.cos(lon) const y = Math.cos(lat) * Math.sin(lon) const z = Math.sin(lat) X += x Y += y Z += z } X = X / total Y = Y / total Z = Z / total const Lon = Math.atan2(Y, X) const Hyp = Math.sqrt(X * X + Y * Y) const Lat = Math.atan2(Z, Hyp) return { lng: (Lon * 180) / Math.PI, lat: (Lat * 180) / Math.PI } } /** * @description: 计算两组经纬度中距离最短的两个点 * @param {*} lnglat1 [[xxx,xxx]] * @param {*} lnglat2 [[xxx,xxx]] * @return {*} { index: 1 } */ export const getShortestDistance = (lnglat1, lnglat2) => { const arr = [] lnglat1.forEach((v, i) => { const [lng, lat] = v lnglat2.forEach((s, i2) => { const [vLng, vLat] = s const distance = getLnglatDist(lng, lat, vLng, vLat) arr.push({ distance, index: [i, i2], lnglat: [v, s], }) }) }) const newArr = arr.sort((a, b) => a.distance - b.distance) return newArr[0] } // 获取当前经纬度地形数据 export const getLnglatAltitude = (longitude, latitude, viewer) => { return new Promise((resolve, reject) => { // 假设 viewer 已经初始化并且 terrainProvider 是有效的 const terrainProvider = viewer?.terrainProvider // 创建 Cartographic 对象 const cartographic = Cesium.Cartographic.fromDegrees(longitude, latitude) // 获取地形数据的Promise const promise = Cesium.sampleTerrainMostDetailed(terrainProvider, [cartographic]) // 使用 Cesium.when 处理 Promise promise .then(function (updatedPositions) { // updatedPositions 是一个数组,包含更新后的 Cartographic 对象 const updatedPosition = updatedPositions[0] const height = updatedPosition.height resolve({ longitude, latitude, height, }) // 在这里,你可以使用 height 值进行后续操作 }) .catch(function (error) { // console.error('获取高程时发生错误:', error); reject(error) }) }) } // 批量获取经纬度对应高度信息 export const getPositionsHeight = (data, viewer, droneHeight = null) => { return new Promise((resolve, reject) => { if (!data || !data.length) { resolve([]) return } // 假设 viewer 已经初始化并且 terrainProvider 是有效的 const terrainProvider = viewer?.terrainProvider // 创建 Cartographic 对象 const cartographics = data.map(item => { const [lng, lat] = item?.['Point']?.['coordinates']?.['#text'].split(',') return Cesium.Cartographic.fromDegrees(Number(lng), Number(lat)) }) // 获取地形数据的Promise const promise = Cesium.sampleTerrainMostDetailed(terrainProvider, cartographics) // 使用 Cesium.when 处理 Promise promise .then(function (updatedPositions) { // updatedPositions 是一个数组,包含更新后的 Cartographic 对象 const newPosition = updatedPositions.map((item, index) => { const longitude = Cesium.Math.toDegrees(item.longitude) const latitude = Cesium.Math.toDegrees(item.latitude) let FinalHeight = Number(data[index]?.['ellipsoidHeight']?.['#text']) + Number(item.height) if (droneHeight) { FinalHeight = Number(data[index]?.['ellipsoidHeight']?.['#text']) + droneHeight } return { ...data[index], longitude, latitude, FinalHeight, customHeight: Number(item.height), } }) resolve(newPosition) // 在这里,你可以使用 height 值进行后续操作 }) .catch(function (error) { // console.error('获取高程时发生错误:', error); reject(error) }) }) } // 获取面中最高点 export const getPolygonMaxHeight = (turfPolygon, viewer) => { return new Promise((resolve, reject) => { const turfExtent = turf.bbox(turfPolygon) const turfSamplePoints = turf.pointGrid(turfExtent, 0.01, { units: 'kilometers', mask: turfPolygon, }) // 假设 viewer 已经初始化并且 terrainProvider 是有效的 const terrainProvider = viewer?.terrainProvider const cesiumSamplePoints = [] for (let i = 0; i < turfSamplePoints.features.length; i++) { const coord = turfSamplePoints.features[i].geometry.coordinates cesiumSamplePoints.push(Cesium.Cartographic.fromDegrees(coord[0], coord[1])) } // 获取地形数据的Promise const promise = Cesium.sampleTerrainMostDetailed(terrainProvider, cesiumSamplePoints) promise .then(function (updatedPositions) { const newPosition = updatedPositions.map(item => Number(item.height)) resolve(Math.max(...newPosition)) }) .catch(function (error) { reject(error) }) }) } // 展示当前的高度 export const getWaylineShowHeight = positions => { const { lng, lat } = getCenterPoint(positions) let maxDist = 0 positions.forEach(item => { const [lng1, lat1] = item let pointsDist = getLnglatDist(lng1, lat1, lng, lat) if (pointsDist > maxDist) { maxDist = pointsDist } }) return { lng, lat, showHeight: maxDist * 8, } } // 获取当前面是否有交叉点 export const isIntersection = coordinates => { const polyDikuai = turf.polygon([coordinates]) const result = turf.kinks(polyDikuai) const resultFeatures = result.features if (resultFeatures.length == 0) { //无相交 return false } else { //有相交 return true } } /** * 飞到中心点并且所有点在可视范围 * @param lngLatArr * @param viewer * @param rangeMultiple 范围倍数越大飞的越高默认2 */ export function flyVisual(lngLatArr,viewer,rangeMultiple = 2) { if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return const positions = lngLatArr.map(([lon, lat]) => Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)) ) // 计算包围盒 BoundingSphere(所有点的外接球) const boundingSphere = Cesium.BoundingSphere.fromPoints(positions) viewer.camera.flyToBoundingSphere(boundingSphere, { duration: 0, offset: new Cesium.HeadingPitchRange(0, 0, boundingSphere.radius * rangeMultiple), }) } // 获取视口地图中心点 export function getMapCenterPoint(viewer) { const centerResult = viewer.camera.pickEllipsoid( new Cesium.Cartesian2( viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2 ) ); const curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(centerResult); const longitude = (curPosition.longitude * 180) / Math.PI; const latitude = (curPosition.latitude * 180) / Math.PI; return { longitude, latitude }; }