| | |
| | | import AmapMercatorTilingScheme from '@/utils/cesium/AmapMercatorTilingScheme' |
| | | import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' |
| | | import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial' |
| | | import lineImg from '@/assets/images/arrow-right-blue.png'; |
| | | import Startingpointicon from '@/assets/images/Startingpointicon.png'; |
| | | import EndPointicon from '@/assets/images/EndPointicon.png'; |
| | | import lineImg from '@/assets/images/arrow-right-blue.png' |
| | | import Startingpointicon from '@/assets/images/Startingpointicon.png' |
| | | import EndPointicon from '@/assets/images/EndPointicon.png' |
| | | import uavImg from '@/assets/images/home/useUavHome/uavImg.png' |
| | | import { getCenterPoint } from '@/utils/cesium/mapUtil' |
| | | import { getWaylineByArea } from '@/api/home/task'; |
| | | import { useStore } from 'vuex'; |
| | | import { getWaylineByArea } from '@/api/home/task' |
| | | import { useStore } from 'vuex' |
| | | import { addBlueFilter } from '@/utils/cesium/common' |
| | | const store = useStore(); |
| | | const userAreaPosition = computed(() => store.state.home.userAreaPosition); |
| | | // 新图片 |
| | | import newStartPoint from '@/assets/images/newStartPoint.png' |
| | | import newEndPointImg from '@/assets/images/newEndPointicon.png' |
| | | import newlineImg from '@/assets/images/newarrow-right.png' |
| | | const store = useStore() |
| | | const userAreaPosition = computed(() => store.state.home.userAreaPosition) |
| | | |
| | | // 声明事件 |
| | | const emit = defineEmits(['clickPosition', 'saveWayline']); |
| | | const emit = defineEmits(['clickPosition', 'saveWayline']) |
| | | |
| | | const props = defineProps({ |
| | | wayLineFile: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | checkedTableData: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | type: String, |
| | | default: '', |
| | | }, |
| | | checkedTableData: { |
| | | type: Array, |
| | | default: () => [], |
| | | }, |
| | | waylineTypeTest: { |
| | | type: Number, |
| | | default: 3 |
| | | } |
| | | type: Number, |
| | | default: 3, |
| | | }, |
| | | }) |
| | | |
| | | const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({ |
| | |
| | | maximumLevel: 18, |
| | | tilingScheme: new AmapMercatorTilingScheme(), |
| | | credit: 'amap_SL', |
| | | }); |
| | | }) |
| | | |
| | | let viewer = null; |
| | | let currentEntity = null; |
| | | let connectLines = []; // 存储连接线实体 |
| | | let polygonPoints = []; // 存储多边形的点 |
| | | let polygonEntity = null; // 存储多边形实体 |
| | | let existingEntity = null; // 后端返回数据生成得面状线 |
| | | let viewer = null |
| | | let currentEntity = null |
| | | let connectLines = [] // 存储连接线实体 |
| | | let polygonPoints = [] // 存储多边形的点 |
| | | let polygonEntity = null // 存储多边形实体 |
| | | let existingEntity = null // 后端返回数据生成得面状线 |
| | | // 添加变量跟踪当前菜单 |
| | | let currentMenu = null; |
| | | |
| | | let currentMenu = null |
| | | |
| | | const init = () => { |
| | | viewer = new Viewer('taskMap', { |
| | |
| | | // sceneMode: Cesium.SceneMode.COLUMBUS_VIEW, |
| | | }) |
| | | const gdLayer = viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL) |
| | | const options = { |
| | | const options = { |
| | | bInvertColor: true, |
| | | bFilterColor: true, |
| | | filterColor: '#4e70a6' |
| | | filterColor: '#4e70a6', |
| | | } |
| | | // 添加蓝色滤镜 |
| | | addBlueFilter(options,viewer,gdLayer) |
| | | viewer.scene.morphTo2D(0); |
| | | // 添加蓝色滤镜 |
| | | addBlueFilter(options, viewer, gdLayer) |
| | | viewer.scene.morphTo2D(0) |
| | | //设置默认点 |
| | | const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {}; |
| | | const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {} |
| | | viewer.camera.setView({ |
| | | destination: Cartesian3.fromDegrees(longitude, latitude, height), |
| | | }); |
| | | }) |
| | | } |
| | | |
| | | // 单点左键点击事件 |
| | | const singlePointLeftClick = () => { |
| | | viewer.screenSpaceEventHandler.setInputAction((click) => { |
| | | viewer.screenSpaceEventHandler.setInputAction(click => { |
| | | if (props.waylineTypeTest !== 1) return |
| | | const cartesian = viewer.camera.pickEllipsoid( |
| | | click.position, |
| | | viewer.scene.globe.ellipsoid |
| | | ); |
| | | if (cartesian) { |
| | | // 清除之前的实体 |
| | | viewer.entities.removeAll(); |
| | | |
| | | // 添加新点 |
| | | const point = viewer.entities.add({ |
| | | position: cartesian, |
| | | point: { |
| | | pixelSize: 10, |
| | | color: Cesium.Color.WHITE |
| | | } |
| | | }); |
| | | |
| | | // 转换坐标 |
| | | const cartographic = Cesium.Cartographic.fromCartesian(cartesian); |
| | | const longitude = Cesium.Math.toDegrees(cartographic.longitude); |
| | | const latitude = Cesium.Math.toDegrees(cartographic.latitude); |
| | | |
| | | // 更新当前实体引用 |
| | | currentEntity = point; |
| | | |
| | | // 发送坐标 |
| | | emit('clickPosition', { longitude, latitude }); |
| | | } |
| | | }, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
| | | }; |
| | | const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid) |
| | | if (cartesian) { |
| | | // 清除之前的实体 |
| | | viewer.entities.removeAll() |
| | | |
| | | // 添加新点 |
| | | const point = viewer.entities.add({ |
| | | position: cartesian, |
| | | point: { |
| | | pixelSize: 10, |
| | | color: Cesium.Color.fromCssColorString('#1FFF69'), |
| | | }, |
| | | }) |
| | | |
| | | // 转换坐标 |
| | | const cartographic = Cesium.Cartographic.fromCartesian(cartesian) |
| | | const longitude = Cesium.Math.toDegrees(cartographic.longitude) |
| | | const latitude = Cesium.Math.toDegrees(cartographic.latitude) |
| | | |
| | | // 更新当前实体引用 |
| | | currentEntity = point |
| | | |
| | | // 发送坐标 |
| | | emit('clickPosition', { longitude, latitude }) |
| | | } |
| | | }, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | } |
| | | |
| | | // 智能规划航线 |
| | | const intelligentPlanning = () => { |
| | | // 添加点击事件监听 |
| | | viewer.screenSpaceEventHandler.setInputAction((click) => { |
| | | viewer.screenSpaceEventHandler.setInputAction(click => { |
| | | if (props.waylineTypeTest !== 2) return |
| | | const cartesian = viewer.camera.pickEllipsoid( |
| | | click.position, |
| | | viewer.scene.globe.ellipsoid |
| | | ); |
| | | |
| | | const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid) |
| | | |
| | | if (cartesian) { |
| | | // 添加新点 |
| | | const point = viewer.entities.add({ |
| | | position: cartesian, |
| | | point: { |
| | | pixelSize: 10, |
| | | color: Cesium.Color.WHITE |
| | | } |
| | | }); |
| | | |
| | | color: Cesium.Color.fromCssColorString('#1FFF69'), |
| | | }, |
| | | }) |
| | | |
| | | // 存储点位 |
| | | polygonPoints.push(cartesian); |
| | | |
| | | polygonPoints.push(cartesian) |
| | | |
| | | // 当点击超过2个点时绘制多边形 |
| | | if (polygonPoints.length > 2) { |
| | | // 移除旧的多边形 |
| | | if (polygonEntity) { |
| | | viewer.entities.remove(polygonEntity); |
| | | viewer.entities.remove(polygonEntity) |
| | | } |
| | | |
| | | |
| | | // 创建新的多边形 |
| | | polygonEntity = viewer.entities.add({ |
| | | polygon: { |
| | |
| | | outlineColor: new Cesium.Color(0, 0.5, 1, 1), // 蓝 |
| | | outlineWidth: 2, |
| | | height: 0, // Set explicit height |
| | | heightReference: Cesium.HeightReference.NONE // Disable terrain clamping |
| | | } |
| | | }); |
| | | heightReference: Cesium.HeightReference.NONE, // Disable terrain clamping |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | // 转换坐标并发送 |
| | | const cartographic = Cesium.Cartographic.fromCartesian(cartesian); |
| | | const longitude = Cesium.Math.toDegrees(cartographic.longitude); |
| | | const latitude = Cesium.Math.toDegrees(cartographic.latitude); |
| | | const cartographic = Cesium.Cartographic.fromCartesian(cartesian) |
| | | const longitude = Cesium.Math.toDegrees(cartographic.longitude) |
| | | const latitude = Cesium.Math.toDegrees(cartographic.latitude) |
| | | // emit('clickPosition', cartographic); |
| | | |
| | | } |
| | | }, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
| | | }, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | // 修改右键点击事件,添加菜单 |
| | | viewer.screenSpaceEventHandler.setInputAction((movement) => { |
| | | viewer.screenSpaceEventHandler.setInputAction(movement => { |
| | | if (props.waylineTypeTest !== 2) return |
| | | if (polygonPoints.length > 2) { |
| | | // 清除之前的菜单 |
| | | if (currentMenu) { |
| | | document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove()); |
| | | document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove()) |
| | | } |
| | | |
| | | const menuContainer = document.createElement('div'); |
| | | menuContainer.className = 'context-menu'; |
| | | const menuContainer = document.createElement('div') |
| | | menuContainer.className = 'context-menu' |
| | | |
| | | // 获取地图容器 |
| | | const mapContainer = document.getElementById('taskMap'); |
| | | const mapContainer = document.getElementById('taskMap') |
| | | // 使用鼠标右键点击的实际位置 |
| | | menuContainer.style.position = 'absolute'; |
| | | menuContainer.style.left = `${movement.position.x}px`; |
| | | menuContainer.style.top = `${movement.position.y}px`; |
| | | menuContainer.style.zIndex = '1000'; |
| | | menuContainer.style.position = 'absolute' |
| | | menuContainer.style.left = `${movement.position.x}px` |
| | | menuContainer.style.top = `${movement.position.y}px` |
| | | menuContainer.style.zIndex = '1000' |
| | | |
| | | menuContainer.innerHTML = ` |
| | | <div class="menu-item" id="saveWayline">保存航线</div> |
| | | <div class="menu-item" id="cancelDraw">取消绘制</div> |
| | | `; |
| | | |
| | | mapContainer.appendChild(menuContainer); |
| | | currentMenu = menuContainer; |
| | | ` |
| | | |
| | | mapContainer.appendChild(menuContainer) |
| | | currentMenu = menuContainer |
| | | |
| | | // 添加全局点击事件监听 |
| | | const handleClickOutside = (e) => { |
| | | if (!menuContainer) return; |
| | | const isClickInside = menuContainer.contains(e.target); |
| | | const handleClickOutside = e => { |
| | | if (!menuContainer) return |
| | | const isClickInside = menuContainer.contains(e.target) |
| | | if (!isClickInside) { |
| | | menuContainer.remove(); |
| | | document.removeEventListener('mousedown', handleClickOutside); |
| | | menuContainer.remove() |
| | | document.removeEventListener('mousedown', handleClickOutside) |
| | | } |
| | | }; |
| | | } |
| | | |
| | | // 延迟添加事件监听,避免右键点击立即触发 |
| | | setTimeout(() => { |
| | | document.addEventListener('mousedown', handleClickOutside); |
| | | }, 100); |
| | | document.addEventListener('mousedown', handleClickOutside) |
| | | }, 100) |
| | | |
| | | // 菜单按钮点击事件 |
| | | document.getElementById('saveWayline').onclick = () => { |
| | | const coordinates = polygonPoints.map(point => { |
| | | const cartographic = Cesium.Cartographic.fromCartesian(point); |
| | | const cartographic = Cesium.Cartographic.fromCartesian(point) |
| | | return { |
| | | longitude: Cesium.Math.toDegrees(cartographic.longitude), |
| | | latitude: Cesium.Math.toDegrees(cartographic.latitude) |
| | | }; |
| | | }); |
| | | emit('saveWayline', coordinates); |
| | | saveWaylineByArea(coordinates); |
| | | mapContainer.removeChild(menuContainer); |
| | | }; |
| | | |
| | | latitude: Cesium.Math.toDegrees(cartographic.latitude), |
| | | } |
| | | }) |
| | | emit('saveWayline', coordinates) |
| | | saveWaylineByArea(coordinates) |
| | | mapContainer.removeChild(menuContainer) |
| | | } |
| | | |
| | | document.getElementById('cancelDraw').onclick = () => { |
| | | polygonPoints = []; |
| | | viewer.entities.removeAll(); |
| | | mapContainer.removeChild(menuContainer); |
| | | }; |
| | | polygonPoints = [] |
| | | viewer.entities.removeAll() |
| | | mapContainer.removeChild(menuContainer) |
| | | } |
| | | } |
| | | }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
| | | }; |
| | | }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
| | | } |
| | | |
| | | // 保存航线并且获取线 |
| | | const saveWaylineByArea = (dataValue) => { |
| | | const polygonArray = dataValue.map(point => [point.longitude, point.latitude]); |
| | | const saveWaylineByArea = dataValue => { |
| | | const polygonArray = dataValue.map(point => [point.longitude, point.latitude]) |
| | | getWaylineByArea({ type: 2, polygon: polygonArray }).then(res => { |
| | | if (res.data.code !== 0) retrun; |
| | | drawResultWayline(res.data.data); |
| | | }); |
| | | if (res.data.code !== 0) retrun |
| | | drawResultWayline(res.data.data) |
| | | }) |
| | | } |
| | | |
| | | // 绘制后端生成得面状线 |
| | | const drawResultWayline = (dataValue) => { |
| | | const drawResultWayline = dataValue => { |
| | | // 先检查并删除已存在的航线 |
| | | existingEntity = viewer.entities.getById('result_wayline'); |
| | | if (existingEntity) { |
| | | viewer.entities.remove(existingEntity); |
| | | } |
| | | const cartesian3List = ref([]); |
| | | dataValue.forEach((lnglat) => { |
| | | existingEntity = viewer.entities.getById('result_wayline') |
| | | if (existingEntity) { |
| | | viewer.entities.remove(existingEntity) |
| | | } |
| | | const cartesian3List = ref([]) |
| | | dataValue.forEach(lnglat => { |
| | | const cartesian3 = Cesium.Cartesian3.fromDegrees( |
| | | Number(lnglat.x), |
| | | Number(lnglat.y), |
| | | Number(100), // 默认100 |
| | | Number(100) // 默认100 |
| | | ) |
| | | cartesian3List.value.push(cartesian3) |
| | | }); |
| | | }) |
| | | const setting = { |
| | | id: 'result_wayline', |
| | | polyline: { |
| | |
| | | polyline: setting.polyline, |
| | | id: setting.id, |
| | | }) |
| | | }; |
| | | } |
| | | |
| | | // 选中航线时调用 渲染线和点 type = 0 |
| | | const renderingLine = lineObj => { |
| | |
| | | const [lon, lat] = item.Point.coordinates.split(',') |
| | | return Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | }) |
| | | |
| | | |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | width: 4, |
| | | width: 5, |
| | | positions: positions, |
| | | material: new ImageTrailMaterial({ |
| | | color: { alpha: 1, blue: 1, green: 1, red: 1 }, |
| | | speed: 20, |
| | | image: lineImg, |
| | | repeat: { x: Math.floor(40), y: 1 }, |
| | | // material: new ImageTrailMaterial({ |
| | | // color: { alpha: 1, blue: 1, green: 1, red: 1 }, |
| | | // speed: 20, |
| | | // image: newlineImg, |
| | | // repeat: { x: Math.floor(40), y: 1 }, |
| | | // }), |
| | | material: new Cesium.PolylineGlowMaterialProperty({ |
| | | // color: Cesium.Color.GREEN, |
| | | image: newlineImg, |
| | | }), |
| | | clampToGround: false, |
| | | }, |
| | | }) |
| | | |
| | | positions.forEach((point, index) => { |
| | | let setting = {}; |
| | | // if (index === 0) { |
| | | // //TODO |
| | | // } |
| | | |
| | | positions.forEach((point, index) => { |
| | | let setting = {} |
| | | // if (index === 0) { |
| | | // //TODO |
| | | // } |
| | | // else if (index === 1) { |
| | | // setting = { |
| | | // position: point, |
| | | // id: `point_${index}`, |
| | | // billboard: { |
| | | // image: Startingpointicon, |
| | | // outlineWidth: 0, |
| | | // width: 20, |
| | | // height: 20, |
| | | // scale: 1.0, |
| | | // }, |
| | | // } |
| | | // } else |
| | | // setting = { |
| | | // position: point, |
| | | // id: `point_${index}`, |
| | | // billboard: { |
| | | // image: Startingpointicon, |
| | | // outlineWidth: 0, |
| | | // width: 20, |
| | | // height: 20, |
| | | // scale: 1.0, |
| | | // }, |
| | | // } |
| | | // } else |
| | | if (index === positions.length - 1) { |
| | | setting = { |
| | | position: point, |
| | | id: `point_${index}`, |
| | | billboard: { |
| | | image: EndPointicon, |
| | | outlineWidth: 0, |
| | | width: 20, |
| | | height: 20, |
| | | scale: 1.0, |
| | | }, |
| | | } |
| | | } else { |
| | | setting = { |
| | | position: point, |
| | | id: `point_${index}`, |
| | | label: { |
| | | text: `${index+1}`, |
| | | font: 'bold 14px serif', |
| | | style: Cesium.LabelStyle.FILL, |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中 |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中 |
| | | pixelOffset: new Cesium.Cartesian2(0, 0), // 根据需要调整偏移量 |
| | | eyeOffset: new Cesium.Cartesian3(0, 0, -10) // 使标签在点的上方 |
| | | }, |
| | | setting = { |
| | | position: point, |
| | | id: `point_${index}`, |
| | | billboard: { |
| | | image: newEndPointImg, |
| | | outlineWidth: 0, |
| | | width: 20, |
| | | height: 20, |
| | | scale: 1.0, |
| | | }, |
| | | } |
| | | } else { |
| | | setting = { |
| | | position: point, |
| | | id: `point_${index}`, |
| | | label: { |
| | | text: `${index + 1}`, |
| | | font: 'bold 14px serif', |
| | | fillColor: Cesium.Color.WHITE, |
| | | // style: Cesium.LabelStyle.FILL, |
| | | // verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中 |
| | | // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中 |
| | | pixelOffset: new Cesium.Cartesian2(2, 0), // 根据需要调整偏移量 |
| | | eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 使标签在点的上方 |
| | | }, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(newStartPoint), |
| | | width: 70, |
| | | height: 70, |
| | | }, |
| | | // point: { |
| | | // pixelSize: 24, |
| | | // color: new Cesium.Color.fromBytes(255, 186, 0, 255), |
| | | // }, |
| | | |
| | | point: { |
| | | pixelSize: 24, |
| | | color: new Cesium.Color.fromBytes(255, 186, 0, 255), |
| | | }, |
| | | |
| | | offset: new Cesium.Cartesian2(10, 30), |
| | | } |
| | | } |
| | | viewer.entities.add(setting) |
| | | }); |
| | | offset: new Cesium.Cartesian2(10, 30), |
| | | } |
| | | } |
| | | viewer.entities.add(setting) |
| | | }) |
| | | } |
| | | |
| | | // 飞到中心点 |
| | | function flyToPoints(lngLatArr) { |
| | | if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return |
| | | const positions = lngLatArr.map(([lon, lat]) => |
| | | Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | ) |
| | | const positions = lngLatArr.map(([lon, lat]) => Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat))) |
| | | // 计算包围盒 BoundingSphere(所有点的外接球) |
| | | const boundingSphere = Cesium.BoundingSphere.fromPoints(positions) |
| | | viewer.camera.flyToBoundingSphere(boundingSphere, { |
| | |
| | | }) |
| | | } |
| | | |
| | | |
| | | // 异步解析kmz文件 |
| | | const analysis = async url => { |
| | | return new Promise(async resolve => { |
| | | const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`); |
| | | const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`) |
| | | const templateXML = await res.fileInfoObj['wpmz/template.kml'] |
| | | const templateXMLJSON = XMLToJSON(templateXML)?.['Document'] |
| | | const templateXMLObj = removeTextKey(templateXMLJSON.Folder) |
| | |
| | | |
| | | // 绘制线和飞行 |
| | | const drawLine = async () => { |
| | | let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL+ props.wayLineFile); |
| | | const res = await analysis(prexUrl.value); |
| | | let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL + props.wayLineFile) |
| | | const res = await analysis(prexUrl.value) |
| | | if (!res.Placemark.length) return |
| | | renderingLine(res); |
| | | renderingLine(res) |
| | | const points = res.Placemark.map(item => item.Point.coordinates.split(',')) |
| | | flyToPoints(points) |
| | | } |
| | | |
| | | // 选择航线时,根据选择机巢连线 |
| | | const selectLineFile = (newVal) => { |
| | | const selectLineFile = newVal => { |
| | | // 清除之前的实体 |
| | | // viewer.entities.removeAll(); |
| | | // 重新绘制航线 |
| | |
| | | // } |
| | | // 添加选中点和连接线 |
| | | const positions = newVal.map(item => { |
| | | const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)); |
| | | const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)) |
| | | // 添加机巢点 |
| | | viewer.entities.add({ |
| | | position: position, |
| | |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | | }); |
| | | return position; |
| | | }); |
| | | }) |
| | | return position |
| | | }) |
| | | |
| | | // 添加连接线 |
| | | if (positions.length > 1) { |
| | |
| | | width: 2, |
| | | material: new Cesium.PolylineDashMaterialProperty({ |
| | | color: Cesium.Color.RED, |
| | | dashLength: 8.0 |
| | | }) |
| | | } |
| | | }); |
| | | dashLength: 8.0, |
| | | }), |
| | | }, |
| | | }) |
| | | } |
| | | // 飞到中心点 |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]); |
| | | flyToPoints(lngLatArr); |
| | | }; |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]) |
| | | flyToPoints(lngLatArr) |
| | | } |
| | | |
| | | // 单个点生成选择多个机巢生成航线 |
| | | const singlePointLines = (newVal) => { |
| | | const singlePointLines = newVal => { |
| | | // 清除之前的连接线 |
| | | connectLines.forEach(line => viewer.entities.remove(line)); |
| | | connectLines = []; |
| | | connectLines.forEach(line => viewer.entities.remove(line)) |
| | | connectLines = [] |
| | | |
| | | if (currentEntity) { |
| | | // 获取当前点的位置 |
| | | const currentPosition = currentEntity.position.getValue(); |
| | | |
| | | const currentPosition = currentEntity.position.getValue() |
| | | |
| | | // 为每个选中的机巢创建点和连接线 |
| | | newVal.forEach(item => { |
| | | // 创建机巢点 |
| | | const nestPosition = Cartesian3.fromDegrees( |
| | | Number(item.longitude), |
| | | Number(item.latitude) |
| | | ); |
| | | const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)) |
| | | viewer.entities.add({ |
| | | position: nestPosition, |
| | | billboard: { |
| | |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | | }); |
| | | }) |
| | | |
| | | // 创建连接线 |
| | | const line = viewer.entities.add({ |
| | |
| | | width: 2, |
| | | material: new Cesium.PolylineDashMaterialProperty({ |
| | | color: Cesium.Color.RED, |
| | | dashLength: 8.0 |
| | | }) |
| | | } |
| | | }); |
| | | connectLines.push(line); |
| | | }); |
| | | dashLength: 8.0, |
| | | }), |
| | | }, |
| | | }) |
| | | connectLines.push(line) |
| | | }) |
| | | |
| | | // 飞到所有点的中心位置 |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]); |
| | | flyToPoints(lngLatArr); |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]) |
| | | flyToPoints(lngLatArr) |
| | | } |
| | | }; |
| | | } |
| | | |
| | | // 智慧规划航线-面状航线 |
| | | const planarPointsLines = (newVal) => { |
| | | // 如果存在面状航线 |
| | | if (existingEntity) { |
| | | const waylinePositions = existingEntity.polyline.positions.getValue(); |
| | | |
| | | newVal.forEach(item => { |
| | | // 创建机巢点 |
| | | const nestPosition = Cartesian3.fromDegrees( |
| | | Number(item.longitude), |
| | | Number(item.latitude) |
| | | ); |
| | | |
| | | // 添加机巢图标 |
| | | viewer.entities.add({ |
| | | position: nestPosition, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(uavImg), |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | | }); |
| | | const planarPointsLines = newVal => { |
| | | // 如果存在面状航线 |
| | | if (existingEntity) { |
| | | const waylinePositions = existingEntity.polyline.positions.getValue() |
| | | |
| | | // 找到最近的航线点并连线 |
| | | let minDistance = Number.MAX_VALUE; |
| | | let closestPosition = null; |
| | | |
| | | waylinePositions.forEach(waylinePos => { |
| | | const distance = Cartesian3.distance(nestPosition, waylinePos); |
| | | if (distance < minDistance) { |
| | | minDistance = distance; |
| | | closestPosition = waylinePos; |
| | | } |
| | | }); |
| | | newVal.forEach(item => { |
| | | // 创建机巢点 |
| | | const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)) |
| | | |
| | | // 创建连接线 |
| | | if (closestPosition) { |
| | | const line = viewer.entities.add({ |
| | | polyline: { |
| | | positions: [nestPosition, closestPosition], |
| | | width: 2, |
| | | material: new Cesium.PolylineDashMaterialProperty({ |
| | | color: Cesium.Color.CHARTREUSE, |
| | | dashLength: 8.0 |
| | | }) |
| | | } |
| | | }); |
| | | connectLines.push(line); |
| | | } |
| | | }); |
| | | // 添加机巢图标 |
| | | viewer.entities.add({ |
| | | position: nestPosition, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(uavImg), |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | | }) |
| | | |
| | | // 飞到所有点的中心位置 |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]); |
| | | flyToPoints(lngLatArr); |
| | | } |
| | | }; |
| | | // 找到最近的航线点并连线 |
| | | let minDistance = Number.MAX_VALUE |
| | | let closestPosition = null |
| | | |
| | | waylinePositions.forEach(waylinePos => { |
| | | const distance = Cartesian3.distance(nestPosition, waylinePos) |
| | | if (distance < minDistance) { |
| | | minDistance = distance |
| | | closestPosition = waylinePos |
| | | } |
| | | }) |
| | | |
| | | // 创建连接线 |
| | | if (closestPosition) { |
| | | const line = viewer.entities.add({ |
| | | polyline: { |
| | | positions: [nestPosition, closestPosition], |
| | | width: 2, |
| | | material: new Cesium.PolylineDashMaterialProperty({ |
| | | color: Cesium.Color.CHARTREUSE, |
| | | dashLength: 8.0, |
| | | }), |
| | | }, |
| | | }) |
| | | connectLines.push(line) |
| | | } |
| | | }) |
| | | |
| | | // 飞到所有点的中心位置 |
| | | const lngLatArr = newVal.map(item => [item.longitude, item.latitude]) |
| | | flyToPoints(lngLatArr) |
| | | } |
| | | } |
| | | |
| | | // 监听选择航线文件事件 |
| | | watch(() => props.wayLineFile, async (newVal, oldValue) => { |
| | | await removeMap(); |
| | | if(newVal){ |
| | | await drawLine(); |
| | | } |
| | | }, { deep: true }); |
| | | watch( |
| | | () => props.wayLineFile, |
| | | async (newVal, oldValue) => { |
| | | await removeMap() |
| | | if (newVal) { |
| | | await drawLine() |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | // 监听表格选中数据变化 |
| | | watch(() => props.checkedTableData, (newVal) => { |
| | | if (newVal.length > 0 && props.waylineTypeTest === 0) { |
| | | selectLineFile(newVal); |
| | | } else if (newVal.length > 0 && props.waylineTypeTest === 1) { |
| | | singlePointLines(newVal); |
| | | } else if (newVal.length > 0 && props.waylineTypeTest === 2) { |
| | | planarPointsLines(newVal); |
| | | } |
| | | }, { deep: true }); |
| | | watch( |
| | | () => props.checkedTableData, |
| | | newVal => { |
| | | if (newVal.length > 0 && props.waylineTypeTest === 0) { |
| | | selectLineFile(newVal) |
| | | } else if (newVal.length > 0 && props.waylineTypeTest === 1) { |
| | | singlePointLines(newVal) |
| | | } else if (newVal.length > 0 && props.waylineTypeTest === 2) { |
| | | planarPointsLines(newVal) |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | // 监听航线类型 |
| | | watch(() => props.waylineTypeTest, async (newVal) => { |
| | | await removeMap(); |
| | | if (newVal === 1) { |
| | | await singlePointLeftClick(); |
| | | } else if (newVal === 2) { |
| | | await intelligentPlanning(); |
| | | } |
| | | }, { deep: true }); |
| | | watch( |
| | | () => props.waylineTypeTest, |
| | | async newVal => { |
| | | await removeMap() |
| | | if (newVal === 1) { |
| | | await singlePointLeftClick() |
| | | } else if (newVal === 2) { |
| | | await intelligentPlanning() |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | const removeEvent = () => { |
| | | // 清除事件监听器 |
| | | viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); |
| | | viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
| | | }; |
| | | |
| | | const removeMap = () => { |
| | | // 清除所有实体 |
| | | if (viewer) { |
| | | // 清除连接线 |
| | | connectLines.forEach(line => viewer.entities.remove(line)); |
| | | connectLines = []; |
| | | |
| | | // 清除多边形点和实体 |
| | | polygonPoints = []; |
| | | if (polygonEntity) { |
| | | viewer.entities.remove(polygonEntity); |
| | | } |
| | | |
| | | // 清除当前实体和面状航线 |
| | | if (currentEntity) { |
| | | viewer.entities.remove(currentEntity); |
| | | } |
| | | if (existingEntity) { |
| | | viewer.entities.remove(existingEntity); |
| | | } |
| | | |
| | | viewer.entities.removeAll(); |
| | | |
| | | // 重置所有变量 |
| | | currentEntity = null; |
| | | polygonEntity = null; |
| | | existingEntity = null; |
| | | } |
| | | viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
| | | } |
| | | |
| | | const removeMap = () => { |
| | | // 清除所有实体 |
| | | if (viewer) { |
| | | // 清除连接线 |
| | | connectLines.forEach(line => viewer.entities.remove(line)) |
| | | connectLines = [] |
| | | |
| | | // 清除多边形点和实体 |
| | | polygonPoints = [] |
| | | if (polygonEntity) { |
| | | viewer.entities.remove(polygonEntity) |
| | | } |
| | | |
| | | // 清除当前实体和面状航线 |
| | | if (currentEntity) { |
| | | viewer.entities.remove(currentEntity) |
| | | } |
| | | if (existingEntity) { |
| | | viewer.entities.remove(existingEntity) |
| | | } |
| | | |
| | | viewer.entities.removeAll() |
| | | |
| | | // 重置所有变量 |
| | | currentEntity = null |
| | | polygonEntity = null |
| | | existingEntity = null |
| | | } |
| | | } |
| | | |
| | | onBeforeUnmount(() => { |
| | | removeMap(); |
| | | removeEvent(); |
| | | removeMap() |
| | | removeEvent() |
| | | // 移除所有实体并销毁viewer |
| | | viewer.destroy(); |
| | | viewer = null; |
| | | viewer.destroy() |
| | | viewer = null |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | init() |
| | | }) |
| | | }); |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | #taskMap { |
| | |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | :deep(.context-menu) { |
| | | position: absolute; |
| | | background: rgba(0, 21, 41, 0.9);; |
| | | border-radius: 4px; |
| | | padding: 8px 0; |
| | | min-width: 120px; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); |
| | | |
| | | :deep(.context-menu) { |
| | | position: absolute; |
| | | background: rgba(0, 21, 41, 0.9); |
| | | border-radius: 4px; |
| | | padding: 8px 0; |
| | | min-width: 120px; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); |
| | | |
| | | .menu-item { |
| | | padding: 8px 16px; |
| | |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | font-size: 14px; |
| | | |
| | | |
| | | &:hover { |
| | | background: rgba(255, 255, 255, 0.1); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | </style> |