7 files modified
4 files added
| | |
| | | :payloads="osdVisible.payloads"> |
| | | </DroneControlPanel> |
| | | </div> |
| | | <waylineTool /> |
| | | <!-- <waylineTool /> --> |
| | | <routeProfile /> |
| | | </div> |
| | | <div class="event-wrapper" v-if="false"> |
| | |
| | | if (pick && (pick.id._id === sid || pick.id._id.includes(sid))) { |
| | | cb(click, pick, viewer, handler) |
| | | } |
| | | if (sid === '') { |
| | | cb(click, pick, viewer, handler) |
| | | } |
| | | }, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | } |
| | | // 移除左键事件 |
| New file |
| | |
| | | <template> |
| | | <Teleport to="body"> |
| | | <div class="tip-container">点击地图设置参考起飞点</div> |
| | | </Teleport> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { onMounted, onUnmounted } from 'vue' |
| | | import { cesiumOperation } from '/@/hooks/use-cesium-tsa' |
| | | import * as Cesium from 'cesium' |
| | | import useKmzTsa, { template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa' |
| | | import useMapDraw, { kmlEntities as globalEntities } from '/@/utils/cesium/use-map-draw' |
| | | const { appContext }: any = getCurrentInstance() |
| | | const global = appContext.config.globalProperties |
| | | const kmzUtils = useKmzTsa() |
| | | const mapDraw = useMapDraw('', [], '', global) |
| | | |
| | | const { addClickEvent, removeClickEvent } = cesiumOperation() |
| | | |
| | | const getResource = (name: string) => { |
| | | return new URL(`/src/assets/icons/${name}`, import.meta.url).href |
| | | } |
| | | |
| | | const createInitialPoint = () => { |
| | | const cesiumDom: any = document.querySelector('#cesiumContainer') |
| | | cesiumDom.style.cursor = `url(${getResource('waylinetool/cursor.png')}), auto` |
| | | addClickEvent('', addSettingEvent) |
| | | } |
| | | |
| | | const addSettingEvent = (click: { position: Cesium.Cartesian2 }) => { |
| | | const { position } = click |
| | | const c3Position = global.$viewer.scene.globe.pick(global.$viewer.camera.getPickRay(position), global.$viewer.scene) |
| | | const ellipsoid = global.$viewer.scene.globe.ellipsoid |
| | | const c2Postion = ellipsoid.cartesianToCartographic(c3Position) |
| | | const longitude = Cesium.Math.toDegrees(c2Postion.longitude) |
| | | const latitude = Cesium.Math.toDegrees(c2Postion.latitude) |
| | | const height = 6 |
| | | const takeOffPoint = [latitude, longitude, height] |
| | | xmlTemplate.value.missionConfig.takeOffRefPoint['#text'] = takeOffPoint.join(',') |
| | | const xmlStr = kmzUtils.generateXML(xmlTemplate.value) |
| | | mapDraw.drawWayline(globalEntities.value, xmlStr) |
| | | } |
| | | |
| | | const delSettingEvent = () => { |
| | | const cesiumDom: any = document.querySelector('#cesiumContainer') |
| | | cesiumDom.style.cursor = 'auto' |
| | | removeClickEvent() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | createInitialPoint() |
| | | }) |
| | | onUnmounted(() => { |
| | | delSettingEvent() |
| | | }) |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .tip-container { |
| | | width: 60%; |
| | | position: fixed; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | background-color: rgba(0, 0, 0, 0.5); |
| | | padding: 20px; |
| | | color: #fff; |
| | | text-align: center; |
| | | font-weight: bold; |
| | | pointer-events: none; |
| | | } |
| | | </style> |
| | |
| | | <a-popover placement="bottom" trigger="click" :getPopupContainer="(triggerNode: any) => triggerNode.parentNode"> |
| | | <template #content> |
| | | <div class="setting-content"> |
| | | <div class="start-point common"> |
| | | <div class="start-point common" v-if="xmlTemplate.missionConfig?.takeOffRefPoint['#text']"> |
| | | <div class="title">起飞点</div> |
| | | <div class="value"> |
| | | {{ xmlTemplate.missionConfig?.takeOffRefPoint['#text'] !== '' ? '已设置' : '未设置' }} |
| | | </div> |
| | | </div> |
| | | <div class="no-start-point" v-else> |
| | | <img :src="getResource('waylinetool/无人机起降场.png')" alt="icon"> |
| | | <span>参考起飞点未设置</span> |
| | | </div> |
| | | <div class="photo-setting common"> |
| | | <div class="title">拍照设置</div> |
| | |
| | | {{ item.title }}照片 |
| | | </li> |
| | | </ul> |
| | | <!-- <div class="auto-low-light"> |
| | | <div class="title">自动低光</div> |
| | | <a-tooltip |
| | | placement="right" |
| | | :title="tipDescriptionEnums.rowLightModeTip"> |
| | | <a-switch |
| | | v-model:checked="setting.orientedPhotoMode" |
| | | checkedValue="lowLightSmartShooting" |
| | | unCheckedValue="normalPhoto" /> |
| | | </a-tooltip> |
| | | </div> --> |
| | | </div> |
| | | <!-- 爬升 --> |
| | | <div class="climb-mode common"> |
| | |
| | | return new URL(`/src/assets/svg/${name}`, import.meta.url).href |
| | | } |
| | | |
| | | const getResource = (name: string) => { |
| | | return new URL(`/src/assets/icons/${name}`, import.meta.url).href |
| | | } |
| | | |
| | | const climbImage = getSvgResource('climb.svg') |
| | | const imgs = [] |
| | | |
| | |
| | | |
| | | // 拍照选择 |
| | | const selectPhotoSetting = (value: string) => { |
| | | if (!xmlTemplate.value.Folder.payloadParam) { |
| | | xmlTemplate.value.Folder.payloadParam = { |
| | | imageFormat: { |
| | | '#text': '', |
| | | }, |
| | | } |
| | | } |
| | | const imageFormat = xmlTemplate.value.Folder.payloadParam.imageFormat |
| | | const imageFormatArr = imageFormat['#text'].split(',') |
| | | if (imageFormatArr.includes(value)) { |
| | |
| | | margin-left: auto; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .no-setting { |
| | | &__value { |
| | | width: 100%; |
| | | text-align: center; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | .no-start-point { |
| | | border-radius: 10px; |
| | | padding: 15px; |
| | | margin-bottom: 16px; |
| | | background-color: #409eff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-weight: bold; |
| | | img { |
| | | width: 18px; |
| | | height: 18px; |
| | | margin-right: 5px; |
| | | } |
| | | } |
| | | |
| | | .photo-setting { |
| | |
| | | <div v-for="(event, index) in item.eventList" :key="index" class="s-event-icon"> |
| | | <a-tooltip placement="top"> |
| | | <template #title> |
| | | {{ event.name }} |
| | | {{ event?.name }} |
| | | </template> |
| | | <img :src="event.icon" alt="icon" /> |
| | | <img :src="event?.icon" alt="icon" /> |
| | | </a-tooltip> |
| | | </div> |
| | | </div> |
| | | </contextMenu> |
| | | </li> |
| | | </ul> |
| | | <startPointTips v-if="xmlTemplate.missionConfig?.takeOffRefPoint['#text'] === ''" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { useMyStore } from '/@/store' |
| | | import useMapDraw, { kmlEntities as globalEntities, selectPointIndex as pointIdx } from '/@/utils/cesium/use-map-draw' |
| | | import contextMenu from './components/content-menu.vue' |
| | | import startPointTips from './components/setting-point-tip.vue' |
| | | const store = useMyStore() |
| | | const { appContext }: any = getCurrentInstance() |
| | | const global = appContext.config.globalProperties |
| | |
| | | // 新建航线初始化 |
| | | const initCreateRoute = () => { |
| | | mapDraw = useMapDraw('', [], '', global) |
| | | const xml = kmzUtils.generateXML(xmlTemplate.value) |
| | | mapDraw.drawWayline([], xml) |
| | | const { |
| | | drawWayline, |
| | | waylineDetails: details, |
| | | waylinePointsEvent, |
| | | kmlEntities: entities, |
| | | clearWaylineData |
| | | } = mapDraw |
| | | clearWaylineData() |
| | | drawWayline() |
| | | waylineDetails.value = details |
| | | tragetPointArr.value = waylinePointsEvent.value |
| | | watch( |
| | | () => waylinePointsEvent.value, |
| | | (val) => { |
| | | tragetPointArr.value = val |
| | | }, |
| | | { |
| | | deep: true, |
| | | }, |
| | | ) |
| | | kmlEntities.value = entities.value |
| | | // const xml = kmzUtils.generateXML(xmlTemplate.value) |
| | | // mapDraw.drawWayline([], xml) |
| | | if (!mouseRightClickEvent) { |
| | | // 添加右键事件 |
| | | addMapPointEvent() |
| | | } |
| | | } |
| | | |
| | | // 创建广告牌 |
| | |
| | | removeCesiumChildDom(popupDom) |
| | | const { position } = click |
| | | const { x, y } = position |
| | | const createTakeOffPointEvent = [{ class: 'start-point', title: '设置参考起飞点' }] |
| | | const pointEvents = [ |
| | | { |
| | | class: 'add-prev-point', |
| | |
| | | }, |
| | | ] |
| | | const defaultEvents = [{ class: 'finally-point', title: '在最后航点新增航点' }] |
| | | const events = selectPointIndex.value !== null ? [...defaultEvents, ...pointEvents] : defaultEvents |
| | | let events = [] |
| | | if (xmlTemplate.value.missionConfig?.takeOffRefPoint['#text'] === '') { |
| | | events = createTakeOffPointEvent |
| | | } else { |
| | | events = selectPointIndex.value !== null ? [...defaultEvents, ...pointEvents] : defaultEvents |
| | | } |
| | | popupDom = createPointPopupDom(events) |
| | | global.$viewer.container.appendChild(popupDom) |
| | | popupDom.style.transform = `translate3d(${x}px, ${y}px, 0)` |
| | |
| | | }, |
| | | isRisky: { '#text': 0 }, |
| | | } |
| | | // 添加参考点 |
| | | if (className === 'start-point') { |
| | | // 默认高度为6 |
| | | const height = 6 |
| | | const takeOffPoint = [latitude, longitude, height] |
| | | xmlTemplate.value.missionConfig.takeOffRefPoint['#text'] = takeOffPoint.join(',') |
| | | } |
| | | // 添加航点 |
| | | if (className === 'finally-point') { |
| | | globalEntities.value.push(entity) |
| | | xmlTemplate.value.Folder.Placemark.push(setting) |
| | |
| | | onMounted(() => { |
| | | // 清空画布 |
| | | clearCesiumMap() |
| | | console.log(!!filePath.value) |
| | | if (filePath.value) { |
| | | initDrawRoute() |
| | | } else { |
| | |
| | | <SelectOutlined /> |
| | | </a-button> |
| | | </a-upload> |
| | | <a-button type="text" style="color: white" @click="addWaylineDialogShow = true"> |
| | | <a-button type="text" v-if="!isPointListOpen" style="color: white" @click="addWaylineDialogShow = true"> |
| | | <template #icon> |
| | | <PlusOutlined /> |
| | | </template> |
| | |
| | | createWayline(values).then((createRes: any) => { |
| | | if (createRes) { |
| | | store.commit('SET_WAYLINE_KMZPATH', '') |
| | | isPointListOpen.value = !isPointListOpen.value |
| | | isPointListOpen.value = true |
| | | closeAddWaylineDialog() |
| | | addWaylineDialogShow.value = false |
| | | } else { |
| | | message.error('创建航线失败,错误码:', createRes) |
| | | } |
| | |
| | | 81: '1', |
| | | } as const |
| | | const templateJson = { |
| | | author, |
| | | createTime, |
| | | updateTime: createTime, |
| | | author: { '#text': author }, |
| | | createTime: { '#text': createTime }, |
| | | updateTime: { '#text': createTime }, |
| | | missionConfig: { |
| | | flyToWaylineMode: 'safely', |
| | | finishAction: 'goHome', |
| | | exitOnRCLost: 'goContinue', |
| | | executeRCLostAction: 'goBack', |
| | | takeOffSecurityHeight: 20, |
| | | takeOffRefPoint: '0.000000,0.000000,0.000000', |
| | | takeOffRefPointAGLHeight: 0, |
| | | globalTransitionalSpeed: 15, |
| | | globalRTHHeight: 80, |
| | | flyToWaylineMode: { '#text': 'safely' }, |
| | | finishAction: { '#text': 'goHome' }, |
| | | exitOnRCLost: { '#text': 'goContinue' }, |
| | | executeRCLostAction: { '#text': 'goBack' }, |
| | | takeOffSecurityHeight: { '#text': 20 }, |
| | | takeOffRefPoint: { '#text': '' }, |
| | | takeOffRefPointAGLHeight: { '#text': 0 }, |
| | | globalTransitionalSpeed: { '#text': 15 }, |
| | | globalRTHHeight: { '#text': 80 }, |
| | | droneInfo: { |
| | | droneEnumValue, |
| | | droneSubEnumValue: droneModel[payloadEnumValue], |
| | | droneEnumValue: { '#text': droneEnumValue }, |
| | | droneSubEnumValue: { '#text': droneModel[payloadEnumValue] }, |
| | | }, |
| | | payloadInfo: { |
| | | payloadEnumValue, |
| | | payloadSubEnumValue: droneModel[payloadEnumValue], |
| | | payloadPositionIndex: 0, |
| | | payloadEnumValue: { '#text': payloadEnumValue }, |
| | | payloadSubEnumValue: { '#text': droneModel[payloadEnumValue] }, |
| | | payloadPositionIndex: { '#text': 0 }, |
| | | }, |
| | | }, |
| | | Folder: { |
| | | templateType: 'waypoint', |
| | | useGlobalTransitionalSpeed: 0, |
| | | templateId: 0, |
| | | templateType: { '#text': 'waypoint' }, |
| | | useGlobalTransitionalSpeed: { '#text': 0 }, |
| | | templateId: { '#text': 0 }, |
| | | waylineCoordinateSysParam: { |
| | | coordinateMode: 'WGS84', |
| | | heightMode: 'EGM96', |
| | | globalShootHeight: 50, |
| | | positioningType: 'GPS', |
| | | surfaceFollowModeEnable: 1, |
| | | surfaceRelativeHeight: 100, |
| | | coordinateMode: { '#text': 'WGS84' }, |
| | | heightMode: { '#text': 'EGM96' }, |
| | | globalShootHeight: { '#text': 50 }, |
| | | positioningType: { '#text': 'GPS' }, |
| | | surfaceFollowModeEnable: { '#text': 1 }, |
| | | surfaceRelativeHeight: { '#text': 100 }, |
| | | }, |
| | | autoFlightSpeed: 7, |
| | | gimbalPitchMode: 'usePointSetting', |
| | | autoFlightSpeed: { '#text': 7 }, |
| | | gimbalPitchMode: { '#text': 'usePointSetting' }, |
| | | globalHeight: { '#text': '100' }, |
| | | globalWaypointHeadingParam: { |
| | | waypointHeadingMode: 'followWayline', |
| | | waypointHeadingAngle: 0, |
| | | waypointPoiPoint: '0.000000,0.000000,0.000000', |
| | | waypointHeadingPathMode: 'followBadArc', |
| | | waypointHeadingMode: { '#text': 'followWayline' }, |
| | | waypointHeadingAngle: { '#text': 0 }, |
| | | waypointPoiPoint: { '#text': '0.000000,0.000000,0.000000' }, |
| | | waypointHeadingPathMode: { '#text': 'followBadArc' }, |
| | | }, |
| | | globalWaypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature', |
| | | globalUseStraightLine: 0, |
| | | globalWaypointTurnMode: { '#text': 'toPointAndStopWithDiscontinuityCurvature' }, |
| | | globalUseStraightLine: { '#text': 0 }, |
| | | Placemark: [], |
| | | }, |
| | | } |
| | |
| | | import { ref } from 'vue' |
| | | import { cesiumOperation } from '/@/hooks/use-cesium-tsa' |
| | | import { XMLToJSON } from './kmz' |
| | | import _ from 'lodash' |
| | | const { addPolyline, getEntityById, removeAllDataSource, removeAllPoint } = cesiumOperation() |
| | | |
| | | const getResource = (name: string) => { |
| | |
| | | |
| | | // 绘制路线 |
| | | const drawWayline = async (entities?: Cesium.Entity[], kmlStr?: string) => { |
| | | if (!entities && !kmlStr) { |
| | | // if (!entities && !kmlStr) { |
| | | // dataSource.show = false |
| | | // } |
| | | if (dataSource) { |
| | | dataSource.show = false |
| | | } |
| | | let kmlEntityArr = entities || [...entitiesList] |
| | |
| | | } |
| | | const kmlJson = XMLToJSON(kmlRes) |
| | | // 所有航点 |
| | | const kmlPoints = kmlJson.Document.Folder.Placemark |
| | | const kmlPoints = Array.isArray(kmlJson.Document.Folder.Placemark) |
| | | ? kmlJson.Document.Folder.Placemark |
| | | : [kmlJson.Document.Folder.Placemark] |
| | | // 起飞点 |
| | | let btmStartPoint = null |
| | | // 获取文件中的起飞点 |
| | |
| | | kmlRes = await fileRes.fileInfoObj['wpmz/template.kml'] |
| | | } |
| | | const kmlJson = XMLToJSON(kmlRes).Document |
| | | const points = kmlJson.Folder?.Placemark |
| | | const points = Array.isArray(kmlJson.Folder?.Placemark) ? kmlJson.Folder.Placemark : [kmlJson.Folder.Placemark] |
| | | let takePhotoNum = 0 |
| | | points?.forEach((point: { actionGroup: any }, index: number) => { |
| | | if (point !== undefined) { |
| | | if (Reflect.has(point, 'actionGroup')) { |
| | | const action = point.actionGroup.action |
| | | if (Array.isArray(action)) { |
| | |
| | | waylinePointsEvent.value[index].eventList?.push(actionObj) |
| | | }) |
| | | } else { |
| | | const { actionActuatorFunc } = action |
| | | actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++ |
| | | const actionObj: eventParmas | any = actionList.find((item) => actionActuatorFunc['#text'] === item.key) |
| | | action?.actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++ |
| | | const actionObj: eventParmas | any = actionList.find( |
| | | (item) => action?.actionActuatorFunc['#text'] === item.key, |
| | | ) |
| | | waylinePointsEvent.value[index].eventList?.push(actionObj) |
| | | } |
| | | } |
| | | } |
| | | }) |
| | |
| | | const clearWaylineData = () => { |
| | | kmlEntities.value = [] |
| | | waylinePointsEvent.value = [] |
| | | _.transform(waylineDetails, (_result, value) => { |
| | | value.value = 0 |
| | | }) |
| | | } |
| | | |
| | | return { |