From 46442b030db95ae97b754711c6dc786376c3a6e1 Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Thu, 14 Mar 2024 17:28:36 +0800
Subject: [PATCH] update: kmz修改保持方式修改
---
src/utils/cesium/use-map-draw.ts | 12
vite.config.ts | 50 ++-
env/.env.dev | 2
src/pages/page-web/projects/components/route-edit/index.vue | 76 ++++-
src/utils/cesium/use-kmz-tsa.ts | 185 +------------
package.json | 4
src/utils/cesium/kmz.ts | 148 +++++++----
env/.env.production | 2
src/pages/page-web/projects/components/route-edit/components/setting.vue | 272 ++++++--------------
9 files changed, 292 insertions(+), 459 deletions(-)
diff --git a/env/.env.dev b/env/.env.dev
index b88ea9c..d850688 100644
--- a/env/.env.dev
+++ b/env/.env.dev
@@ -1,5 +1,5 @@
VITE_API_URL = 'http://139.196.74.78:6789'
-VITE_MEDIAPANEL_API_URL = 'https://dev.jxpskj.com:8026/cloud-bucket',
+VITE_MEDIAPANEL_API_URL = 'https://dev.jxpskj.com:9000/cloud-bucket'
VITE_WS_API_URL = 'ws://139.196.74.78:6789/api/v1/ws'
VITE_APP_ENVIRONMENT=DEV
VITE_BASE_API = '/drone-api'
\ No newline at end of file
diff --git a/env/.env.production b/env/.env.production
index 57d71b4..264399c 100644
--- a/env/.env.production
+++ b/env/.env.production
@@ -1,6 +1,6 @@
VITE_APP_ENVIRONMENT=PROD
VITE_APP_APIGATEWAY_BACKEND_HOST=''
VITE_API_URL = 'https://dev.jxpskj.com:36789'
-VITE_MEDIAPANEL_API_URL = 'https://dev.jxpskj.com:8026/cloud-bucket',
+VITE_MEDIAPANEL_API_URL = 'https://dev.jxpskj.com:9000/cloud-bucket'
VITE_WS_API_URL = 'wss://dev.jxpskj.com:36789/api/v1/ws'
VITE_BASE_API = '/drone-api'
\ No newline at end of file
diff --git a/package.json b/package.json
index 7836add..b61f6c0 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,6 @@
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@ant-design/icons-vue": "^6.0.1",
- "@mapbox/togeojson": "^0.16.2",
"@turf/turf": "^6.5.0",
"@vitejs/plugin-legacy": "^1.6.2",
"agora-rtc-sdk-ng": "^4.12.1",
@@ -42,7 +41,8 @@
"vue-i18n": "^9.1.6",
"vue-router": "4",
"vuex": "^4.0.2",
- "vuex-persistedstate": "^4.1.0"
+ "vuex-persistedstate": "^4.1.0",
+ "xml-js": "^1.6.11"
},
"devDependencies": {
"@types/crypto-js": "^4.1.1",
diff --git a/src/pages/page-web/projects/components/route-edit/components/setting.vue b/src/pages/page-web/projects/components/route-edit/components/setting.vue
index 86560dc..05a641d 100644
--- a/src/pages/page-web/projects/components/route-edit/components/setting.vue
+++ b/src/pages/page-web/projects/components/route-edit/components/setting.vue
@@ -5,19 +5,20 @@
<div class="setting-content">
<div class="start-point common">
<div class="title">起飞点</div>
- <div class="value">{{ missionConfigSetting.takeOffRefPoint ? '已设置' : '未设置' }}</div>
+ <div class="value">
+ {{ xmlTemplate.missionConfig?.takeOffRefPoint['#text'] !== '' ? '已设置' : '未设置' }}
+ </div>
</div>
<div class="photo-setting common">
<div class="title">拍照设置</div>
<ul class="select-box">
- <li
- class="select-item"
- :style="{
- '--settingColor': folderSetting.payloadParam.imageFormat.includes(item.value) ? '#409eff' : '#3c3c3c',
- }"
- v-for="item in photoSetting"
- :key="item.value"
- @click="selectPhotoSetting(item.value)">
+ <li class="select-item" v-for="item in photoSetting" :key="item.value" :style="{
+ '--settingColor': xmlTemplate.Folder.payloadParam?.imageFormat['#text']
+ .split(',')
+ .includes(item.value)
+ ? '#409eff'
+ : '#3c3c3c',
+ }" @click="selectPhotoSetting(item.value)">
{{ item.title }}照片
</li>
</ul>
@@ -37,7 +38,7 @@
<div class="climb-mode common">
<a-tooltip placement="right" :title="tipDescriptionEnums.climbModeTip">
<div class="mode-box">
- <a-radio-group v-model:value="missionConfigSetting.flyToWaylineMode" button-style="solid">
+ <a-radio-group v-model:value="xmlTemplate.missionConfig.flyToWaylineMode['#text']" button-style="solid">
<a-radio-button value="safely">垂直爬升</a-radio-button>
<a-radio-button value="pointToPoint">倾斜爬升</a-radio-button>
</a-radio-group>
@@ -49,9 +50,9 @@
<ul class="parameter-btn">
<li @click="numberControls(true, 100, 'takeOffSecurityHeight')">+100</li>
<li @click="numberControls(true, 10, 'takeOffSecurityHeight')">+10</li>
- <li>
- <span>{{ missionConfigSetting.takeOffSecurityHeight }}</span
- >m
+ <li class="parameter-input">
+ <a-input-number :min="2" :max="1500"
+ v-model:value="xmlTemplate.missionConfig.takeOffSecurityHeight['#text']"></a-input-number>m
</li>
<li @click="numberControls(false, 100, 'takeOffSecurityHeight')">-100</li>
<li @click="numberControls(false, 10, 'takeOffSecurityHeight')">-10</li>
@@ -61,32 +62,27 @@
</div>
<!-- 高度模式 -->
<div class="height-mode common">
- <a-tooltip
- placement="right"
- :title="tipDescriptionEnums[folderSetting.waylineCoordinateSysParam.heightMode]">
+ <a-tooltip placement="right"
+ :title="tipDescriptionEnums[xmlTemplate.Folder.waylineCoordinateSysParam.heightMode['#text']]">
<div class="title">航线高度模式</div>
<div class="mode-box">
- <a-radio-group v-model:value="folderSetting.waylineCoordinateSysParam.heightMode" button-style="solid">
+ <a-radio-group v-model:value="xmlTemplate.Folder.waylineCoordinateSysParam.heightMode['#text']"
+ button-style="solid">
<a-radio-button v-for="item in heightModeSetting" :key="item.value" :value="item.value">{{
- item.title
- }}</a-radio-button>
+ item.title
+ }}</a-radio-button>
</a-radio-group>
</div>
<div class="parameter-tool">
<div class="example-img">
- <img
- :src="
- folderSetting.waylineCoordinateSysParam.heightMode === heightModeSetting[0].value
- ? heightModeSetting[0].img
- : heightModeSetting[1].img
- "
- alt="height-img" />
+ <img :src="true ? heightModeSetting[0].img : heightModeSetting[1].img" alt="height-img" />
</div>
<div class="parameter-btn">
<li @click="numberControls(true, 100, 'globalHeight')">+100</li>
<li @click="numberControls(true, 10, 'globalHeight')">+10</li>
- <li>
- <span>{{ Math.round(folderSetting.globalHeight) }}</span> m
+ <li class="parameter-input">
+ <a-input-number :min="0" :max="10000"
+ v-model:value="xmlTemplate.Folder.globalHeight['#text']"></a-input-number>m
</li>
<li @click="numberControls(false, 100, 'globalHeight')">-100</li>
<li @click="numberControls(false, 10, 'globalHeight')">-10</li>
@@ -100,11 +96,9 @@
<div class="speed-box">
<div class="subtract" @click="numberControls(false, 1, 'autoFlightSpeed')">-</div>
<div class="text">
- <a-input-number
- :min="1"
- :max="15"
- class="value"
- v-model:value="folderSetting.autoFlightSpeed"></a-input-number>
+ <a-input-number v-model:value="xmlTemplate.Folder.autoFlightSpeed['#text']" :min="1" :max="15"
+ class="value">
+ </a-input-number>
m / s
</div>
<div class="add" @click="numberControls(true, 1, 'autoFlightSpeed')">+</div>
@@ -120,7 +114,7 @@
<script setup lang="ts">
import { reactive, defineProps } from 'vue'
import { tipDescriptionEnums } from './enums'
-import useKmzTsa, { kmlStr } from '/@/utils/cesium/use-kmz-tsa'
+import useKmzTsa, { kmlStr, template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
import useMapDraw from '/@/utils/cesium/use-map-draw'
import { getKmlParams } from '/@/utils/cesium/kmz'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
@@ -132,15 +126,14 @@
const mapDraw = useMapDraw('', '', '', global)
const { removeAllDataSource, removeAllPoint } = cesiumOperation()
-const kmzUtils = useKmzTsa()
+interface setting {
+ imageFormat: string[]
+}
const props = defineProps({
loadCompleted: Boolean,
})
-const getResource = (name: string) => {
- return new URL(`/src/assets/icons/${name}`, import.meta.url).href
-}
const getSvgResource = (name: string) => {
return new URL(`/src/assets/svg/${name}`, import.meta.url).href
}
@@ -148,37 +141,12 @@
const climbImage = getSvgResource('climb.svg')
const imgs = []
-const missionConfigSetting = reactive<missionConfig | any>({
- flyToWaylineMode: 'safely',
- // 航线结束动作
- finishAction: 'goHome',
- // 失控是否继续执行航线
- exitOnRCLost: 'goContinue',
- // 失控动作
- executeRCLostAction: 'goBack',
- // 安全起飞高度
- takeOffSecurityHeight: 20,
- // 全局航线速度
- globalTransitionalSpeed: 10,
- // 参考起飞点
- takeOffRefPoint: '',
- // 参考起飞点海拔高度
- takeOffRefPointAGLHeight: 0,
- // 全局返航高度
- globalRTHHeight: 100,
- droneInfo: {
- droneEnumValue: 67,
- droneSubEnumValue: 0,
- },
- payloadInfo: {
- payloadEnumValue: 52,
- payloadSubEnumValue: 1,
- payloadPositionIndex: 0,
- },
-})
-
// 拍照设置
-const photoSetting = reactive([
+interface photoSetting {
+ title: string
+ value: string
+}
+const photoSetting = reactive<photoSetting[]>([
{ title: '广角', value: 'wide' },
{ title: '变焦', value: 'zoom' },
{ title: '红外', value: 'ir' },
@@ -198,128 +166,38 @@
},
])
-// folder设置
-const folderSetting = reactive<Folder | any>({
- templateType: 'waypoint',
- templateId: 0,
- waylineCoordinateSysParam: {
- coordinateMode: 'WGS84',
- heightMode: 'EGM96',
- },
- autoFlightSpeed: 10,
- globalHeight: 100,
- payloadParam: {
- payloadPositionIndex: 0,
- imageFormat: '',
- },
- caliFlightEnable: 0,
- gimbalPitchMode: 'manual',
-})
-
// 计算
const numberControls = (isAdd: boolean, computeVal: number, key: string) => {
- if (isAdd) {
- if (missionConfigSetting[key]) {
- missionConfigSetting[key] += computeVal
- } else {
- folderSetting[key] += computeVal
- }
- } else {
- if (missionConfigSetting[key]) {
- missionConfigSetting[key] -= computeVal
- } else {
- if (folderSetting[key] - computeVal <= 0) {
- return message.warn('飞行高度较低!!!!')
- }
- folderSetting[key] -= computeVal
- }
+ let obj = { '#text': 0 }
+ if (key === 'takeOffSecurityHeight') {
+ obj = xmlTemplate.value.missionConfig.takeOffSecurityHeight
}
-
if (key === 'globalHeight') {
- const entities = mapDraw.kmlEntities.value
- removeAllDataSource()
- removeAllPoint()
- mapDraw.drawWayline(entities, kmlStr.value)
+ obj = xmlTemplate.value.Folder.globalHeight
}
-}
-
-// 获取机场默认值
-watch(
- () => props.loadCompleted,
- (val) => {
- if (val) {
- getDefaultValue(missionConfigSetting)
- getDefaultValue(folderSetting)
- }
- },
-)
-const getDefaultValue = (setting: any) => {
- Object.keys(setting).forEach((key: string) => {
- const param: RegExpMatchArray | any = getKmlParams(kmlStr.value, true, {
- name: key,
- findRegx: '([\\s\\S]*?)',
- })
- if (Object.prototype.toString.call(setting[key]) === '[object Object]') {
- const value: RegExpMatchArray | any = getKmlParams(param[0], true, {
- name: key,
- findRegx: '([\\s\\S]*?)',
- })
- Object.keys(setting[key]).forEach((v) => {
- const keyValue: RegExpMatchArray | any = getKmlParams(value[1], true, {
- name: v,
- findRegx: '([\\s\\S]*?)',
- })
- if (!Number(keyValue[1])) {
- setting[key][v] = keyValue[1]
- } else {
- setting[key][v] = Number(keyValue[1])
- }
- })
- } else {
- if (!Number(param[1])) {
- setting[key] = param[1]
- } else {
- setting[key] = Number(param[1])
- }
- }
- })
- return setting
-}
-
-// 全局设置写入kmz文件
-watch(
- () => missionConfigSetting,
- (settingVal) => {
- if (!props.loadCompleted) return
- kmzUtils.edit(settingVal, 'missionConfig', true)
- },
- {
- deep: true,
- },
-)
-
-// folder设置写入kmz文件
-watch(
- () => folderSetting,
- (newVal) => {
- if (!props.loadCompleted) return
- kmzUtils.edit(newVal, 'Folder', true)
- },
- {
- deep: true,
- },
-)
-
-// 拍照设置
-const selectPhotoSetting = (value: string) => {
- const arr: string[] = folderSetting.payloadParam.imageFormat.split(',')
- const index: number = arr.findIndex((item) => item === value)
- if (index !== -1) {
- arr.splice(index, 1)
+ if (key === 'autoFlightSpeed') {
+ obj = xmlTemplate.value.Folder.autoFlightSpeed
+ }
+ let value = Number(obj['#text'])
+ if (isAdd) {
+ value += computeVal
} else {
- arr.push(value)
+ value -= computeVal
}
- folderSetting.payloadParam.imageFormat = arr.join(',')
+ obj['#text'] = value
+}
+
+// 拍照选择
+const selectPhotoSetting = (value: string) => {
+ const imageFormat = xmlTemplate.value.Folder.payloadParam.imageFormat
+ const imageFormatArr = imageFormat['#text'].split(',')
+ if (imageFormatArr.includes(value)) {
+ const index = imageFormatArr.findIndex((item: string) => item === value)
+ imageFormatArr.splice(index, 1)
+ } else {
+ imageFormatArr.push(value)
+ }
+ xmlTemplate.value.Folder.payloadParam.imageFormat['#text'] = imageFormatArr.join(',')
}
</script>
@@ -349,6 +227,7 @@
.start-point {
display: flex;
justify-content: flex-start;
+
.value {
margin-left: auto;
color: #409eff;
@@ -472,6 +351,31 @@
}
}
}
+
+ .parameter-input {
+ display: flex;
+ align-items: center;
+
+ :deep() {
+ .ant-input-number {
+ background-color: transparent;
+ color: #409eff;
+ font-size: 23px;
+ border: 0;
+
+ .ant-input-number-handler-wrap {
+ display: none;
+ }
+
+ .ant-input-number-input-wrap {
+ input {
+ font-weight: bold;
+ text-align: center;
+ }
+ }
+ }
+ }
+ }
}
}
}
@@ -526,8 +430,10 @@
}
}
}
+
:deep() {
.ant-popover-content {
+
.ant-popover-arrow,
.ant-popover-inner {
background-color: #101010;
diff --git a/src/pages/page-web/projects/components/route-edit/index.vue b/src/pages/page-web/projects/components/route-edit/index.vue
index e3a05a0..ba5110c 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -73,16 +73,16 @@
</template>
<script setup lang="ts">
-import _ from 'lodash'
+import _, { template } from 'lodash'
import * as Cesium from 'cesium'
import setting from './components/setting.vue'
-import useKmzTsa, { kmlStr } from '/@/utils/cesium/use-kmz-tsa'
+import useKmzTsa, { kmlStr, template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
import { ref, reactive, defineEmits, defineProps, watch, onMounted } from 'vue'
import { ArrowLeftOutlined, CaretDownOutlined, SaveOutlined } from '@ant-design/icons-vue'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
import { useMyStore } from '/@/store'
import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
-import useMapDraw, { kmlEntities as globalEntities } from '/@/utils/cesium/use-map-draw'
+import useMapDraw, { kmlEntities as globalEntities, selectPointIndex as pointIdx } from '/@/utils/cesium/use-map-draw'
import { getKmlParams } from '/@/utils/cesium/kmz'
import { getHaeHeight } from '/@/utils/cesium/mapUtils'
const store = useMyStore()
@@ -207,8 +207,10 @@
global.$viewer.entities.remove(nextPointEntity)
kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
entity.billboard.image = createBillboard(i + 1, '#61d396')
+ entity.label.show = false
})
selectPointIndex.value = null
+ pointIdx.value = null
return
}
if (prevPointEntity) {
@@ -242,11 +244,14 @@
kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
if (i === index) {
entity.billboard.image = createBillboard(index + 1, '#f3be4f')
+ entity.label.show = true
} else {
entity.billboard.image = createBillboard(i + 1, '#61d396')
+ entity.label.show = false
}
})
selectPointIndex.value = index
+ pointIdx.value = index
}
// 添加右键事件,弹出窗口
@@ -331,59 +336,82 @@
const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
// 获取全局高度
- const globalHeight: any = getKmlParams(kmlStr.value, true, {
- name: 'globalHeight',
- findRegx: '([\\s\\S]*?)',
- })
- const height = Number(globalHeight[1])
+ const globalHeight: string = xmlTemplate.value.Folder.globalHeight['#text']
+ const height = Number(globalHeight)
+ // 右键点击的位置
const createPointPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
const entity: Cesium.Entity = global.$viewer.entities.add({
position: createPointPosition,
})
- const posterHeightRegStr = getKmlParams(kmlStr.value, true, {
- name: 'takeOffRefPointAGLHeight',
- findRegx: '([\\s\\S]*?)',
- }) || ['', 0]
- const posterHeight = Number(posterHeightRegStr[1])
- // 加入kml文件中
+ // 起飞点海拔
+ const takeOffRefPointAGLHeight = xmlTemplate.value.missionConfig.takeOffRefPointAGLHeight
+ const posterHeight = Number(takeOffRefPointAGLHeight['#text'])
+ // 当前点位个数
+ const points = xmlTemplate.value.Folder.Placemark
+ // 加入到解析的JSON对象中
const setting = {
Point: {
- coordinates: `${longitude},${latitude}`,
+ coordinates: { '#text': `${longitude.toFixed(6)},${latitude.toFixed(6)}` },
},
- index: tragetPointArr.value.length,
- height,
- ellipsoidHeight: height - posterHeight,
+ index: { '#text': points.length },
+ height: { '#text': height },
+ ellipsoidHeight: { '#text': height - posterHeight },
+ isRisky: { '#text': 0 },
+ useGlobalHeadingParam: { '#text': 1 },
+ useGlobalHeight: { '#text': 1 },
+ useGlobalSpeed: { '#text': 1 },
+ useGlobalTurnParam: { '#text': 1 },
+ useStraightLine: { '#text': 1 },
+ waypointHeadingParam: {
+ waypointHeadingAngle: { '#text': 0 },
+ waypointHeadingMode: { '#text': 'followWayline' },
+ waypointHeadingPathMode: { '#text': 'followBadArc' },
+ waypointHeadingPoiIndex: { '#text': 0 },
+ waypointPoiPoint: { '#text': '0.000000,0.000000,0.000000' },
+ },
+ waypointSpeed: { '#text': 10 },
+ waypointTurnParam: {
+ waypointTurnDampingDist: { '#text': 0.2 },
+ waypointTurnMode: { '#text': 'toPointAndStopWithDiscontinuityCurvature' },
+ },
}
removeAllDataSource()
removeAllPoint()
if (className === 'finally-point') {
- kmzUtils.writePoint(setting, 'add')
globalEntities.value.push(entity)
+ xmlTemplate.value.Folder.Placemark.push(setting)
tragetPointArr.value.push({
position: createPointPosition,
eventList: [],
+ isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
})
}
if (className === 'add-prev-point') {
- kmzUtils.writePoint(setting, 'prev', selectPointIndex.value)
globalEntities.value.splice(selectPointIndex.value, 0, entity)
+ xmlTemplate.value.Folder.Placemark.splice(selectPointIndex.value, 0, setting)
tragetPointArr.value.splice(selectPointIndex.value, 0, {
position: createPointPosition,
eventList: [],
+ isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
})
}
if (className === 'add-next-point') {
- kmzUtils.writePoint(setting, 'next', selectPointIndex.value)
const index = _.cloneDeep(selectPointIndex.value + 1)
globalEntities.value.splice(index, 0, entity)
+ xmlTemplate.value.Folder.Placemark.splice(index, 0, setting)
tragetPointArr.value.splice(index, 0, {
position: createPointPosition,
eventList: [],
+ isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
})
}
- mapDraw.drawWayline(globalEntities.value, kmlStr.value)
- // clearCesiumMap()
- // createMapMarker(undefined, [...kmlEntities.value, entity])
+ // 更新点位序号
+ xmlTemplate.value.Folder.Placemark.forEach((placemark: { index: { [x: string]: number } }, index: number) => {
+ placemark.index['#text'] = index
+ })
+
+ const xmlStr = kmzUtils.generateXML(xmlTemplate.value)
+ mapDraw.drawWayline(globalEntities.value, xmlStr)
})
}
diff --git a/src/utils/cesium/kmz.ts b/src/utils/cesium/kmz.ts
index 1c3440f..cf481bc 100644
--- a/src/utils/cesium/kmz.ts
+++ b/src/utils/cesium/kmz.ts
@@ -1,10 +1,7 @@
import axios from 'axios'
import JsZip from 'jszip'
-import toGeoJson from '@mapbox/togeojson'
-// import Xml2Json from 'xml2json'
-// const xmlJson = new Xml2Json()
-const noWmpl: string[] = ['Folder', 'Placemark', 'Point', 'coordinates']
+const noWmpl: string[] = ['Document', 'Folder', 'Placemark', 'Point', 'coordinates']
/**
* @description: 读取kmz文件解析出kml文件
@@ -73,16 +70,6 @@
return paramGroup
}
-export const insertChar = (str: string, index: number, char: string) => {
- if (index > str.length) {
- return str + char
- } else if (index < 0) {
- return char + str
- } else {
- return str.slice(0, index) + char + str.slice(index)
- }
-}
-
export const getTagNameFromXml = (xmlString: string): string | null => {
const parser = new DOMParser()
const xmlDoc = parser.parseFromString(xmlString, 'text/xml')
@@ -94,61 +81,110 @@
}
// 将xml转为json
-const deepParse = (xmlDoc: Document, tagName: string) => {
- const xmlObj: { [key: string]: any } = {}
- const rootDom = xmlDoc.getElementsByTagName(tagName)[0]
- for (let i = 0; i < rootDom.children.length; i++) {
- const child = rootDom.children[i]
- const childName = child.nodeName.replace('wpml:', '')
- if (child.children.length > 0) {
- xmlObj[childName] = deepParse(xmlDoc, child.nodeName)
- } else {
- if (xmlObj[childName] !== undefined) {
- if (!Array.isArray(xmlObj[childName])) {
- xmlObj[childName] = [xmlObj[childName]]
+const deepParse = (
+ xml:
+ | {
+ nodeType: number
+ childNodes: string | any[]
+ nodeValue: string
+ attributes: { length: number; item: (arg0: number) => any }
+ }
+ | any,
+) => {
+ let obj: any = {}
+ // 如果是文档节点,遍历其子节点
+ if (xml.nodeType === 1) {
+ // element node
+ // 处理子节点
+ if (xml.childNodes.length > 0) {
+ for (let i = 0; i < xml.childNodes.length; i++) {
+ const item = xml.childNodes[i]
+ const nodeName = item.nodeName.replace('wpml:', '')
+
+ // 检查是否是文本节点
+ if (item.nodeType === 3) {
+ // text node
+ // 处理文本节点的内容
+ if (item.nodeValue.trim() !== '') {
+ obj[nodeName] = item.nodeValue.trim()
+ }
+ } else if (item.nodeType === 1) {
+ // element node
+ // 递归调用处理子节点
+ if (obj[nodeName] === undefined) {
+ obj[nodeName] = deepParse(item)
+ } else {
+ if (!obj[nodeName].push) {
+ const old = obj[nodeName]
+ obj[nodeName] = []
+ obj[nodeName].push(old)
+ }
+ obj[nodeName].push(deepParse(item))
+ }
}
- xmlObj[childName].push(child.textContent)
- } else {
- const value = child.textContent?.split('\n').join('').split(' ').join('')
- xmlObj[childName.replace('wpml:', '')] = value
}
}
+ } else if (xml.nodeType === 3) {
+ // text node
+ // 处理文本节点的内容
+ obj = xml.nodeValue.trim()
}
- return xmlObj
+ return obj
}
-export const XMLToJSON = (xmlStr: string, tagName: string) => {
+
+/**
+ * @description: XML转JSON
+ * @param {string} xmlStr xml字符串
+ * @return {*} string
+ */
+export const XMLToJSON = (xmlStr: string) => {
const parser = new DOMParser()
const xmlDoc = parser.parseFromString(xmlStr, 'text/xml')
- const xmlObj = deepParse(xmlDoc, tagName)
- delete xmlObj.parsererror
+ const xmlObj = deepParse(xmlDoc.documentElement)
return xmlObj
}
// json转xml
-export const JSONToXML = (JSONData = {}) => {
- if (!JSONData) return ''
- let res = ''
- const JSONParse = (obj: { [x: string]: any }) => {
- for (const key in obj) {
- if (Array.isArray(obj[key])) {
- obj[key].forEach((item: any, index: any) => {
- let xmlTag = ''
- if (noWmpl.includes(key)) {
- xmlTag = `<${key} rowNum="${index}">${item}</${key}>`
+/**
+ * @description: JSON转XML
+ * @param {any} obj 要转换的对象
+ * @param {string} rootName xml根节点名称
+ * @return {*} string
+ */
+export const JSONToXML = (obj: any, rootName?: string | undefined) => {
+ let xml = ''
+
+ const buildXml = (obj: string | any[], rootName?: string | undefined) => {
+ let xml = ''
+ if (Array.isArray(obj)) {
+ obj.forEach((item) => {
+ xml += `<${rootName}>${buildXml(item)}</${rootName}>`
+ })
+ } else if (typeof obj === 'object') {
+ Object.keys(obj).forEach((key) => {
+ if (key === '#text') {
+ xml += obj[key]
+ } else {
+ if (key === 'Placemark') {
+ xml += `${buildXml(obj[key], key)}`
} else {
- xmlTag = `<wpml:${key} rowNum="${index}">${item}</wpml:${key}>`
+ const str = !noWmpl.includes(key) ? 'wpml:' : ''
+ xml += `<${str}${key}>${buildXml(obj[key], key)}</${str}${key}>`
}
- res += xmlTag
- })
- } else if (typeof obj[key] === 'object') {
- res += (noWmpl.includes(key) ? `<${key}>` : `<wpml:${key}>`)
- JSONParse(obj[key])
- res += (noWmpl.includes(key) ? `</${key}>` : `</wpml:${key}>`)
- } else {
- res += (noWmpl.includes(key) ? `<${key}>${obj[key] || ''}</${key}>` : `<wpml:${key}>${obj[key] || ''}</wpml:${key}>`)
- }
+ }
+ })
+ } else {
+ xml += obj
}
+ return xml
}
- JSONParse(JSONData)
- return res
+
+ xml += `
+ <?xml version="1.0" encoding="UTF-8"?>
+ <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.5">
+ ${buildXml(obj, rootName)}
+ </kml>
+ `
+
+ return xml
}
diff --git a/src/utils/cesium/use-kmz-tsa.ts b/src/utils/cesium/use-kmz-tsa.ts
index 665aa36..f6671a9 100644
--- a/src/utils/cesium/use-kmz-tsa.ts
+++ b/src/utils/cesium/use-kmz-tsa.ts
@@ -1,8 +1,6 @@
-import { ref, getCurrentInstance } from 'vue'
+import { ref } from 'vue'
import {
analyzeKmzFile,
- getKmlParams,
- generateKmlFormat,
XMLToJSON,
JSONToXML
} from '/@/utils/cesium/kmz'
@@ -18,7 +16,7 @@
const kmlStr = ref('')
const kmzFile = ref<any>(null)
-const template = ref({
+const template = ref<any>({
author: '',
createTime: '',
updateTime: '',
@@ -91,7 +89,7 @@
],
},
})
-const waylines = ref({
+const waylines = ref<any>({
missionConfig: {
flyToWaylineMode: 'safely',
finishAction: 'goHome',
@@ -138,34 +136,6 @@
},
})
-// 点位参数
-const placemark: any = {
- Point: {
- coordinates: '',
- },
- index: 0,
- executeHeight: 80,
- height: 80,
- waypointSpeed: 10,
- waypointHeadingParam: {
- waypointHeadingMode: 'followWayline',
- waypointHeadingAngle: 0,
- waypointPoiPoint: '0.000000,0.000000,0.000000',
- waypointHeadingPathMode: 'followBadArc',
- waypointHeadingPoiIndex: 0,
- },
- waypointTurnParam: {
- waypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature',
- waypointTurnDampingDist: 0.2,
- },
- useGlobalHeight: 1,
- useGlobalSpeed: 1,
- useGlobalHeadingParam: 1,
- useGlobalTurnParam: 1,
- useStraightLine: 1,
- actionGroup: {},
-}
-
const useKmzTsa = () => {
const init = async (fileUrl: string, fileContent?: string) => {
const fileRes = await analyzeKmzFile(fileUrl)
@@ -176,151 +146,36 @@
return false
}
kmlStr.value = kmzRes
+ const tplXmlJson = XMLToJSON(kmzRes)
+ template.value = tplXmlJson.Document
return kmzRes
}
const create = () => {
- const nowTime = new Date().getTime()
- const str = `
- <?xml version="1.0" encoding="UTF-8"?>
- <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.5">
- <Document>
- <wpml:author>17304076412</wpml:author>
- <wpml:createTime>${nowTime}</wpml:createTime>
- <wpml:updateTime>${nowTime}</wpml:updateTime>
- <wpml:missionConfig>
- </wpml:missionConfig>
- <Folder>
- </Folder>
- </Document>
- </kml>
- `
- kmlStr.value = str
- }
- const writePoint = (settingParmas: any = {}, place: string, pointNumber: number = 0) => {
- Object.keys(settingParmas).forEach((key: string) => {
- placemark[key] = settingParmas[key]
- })
- const Placemark = `<Placemark>${generateKmlFormat(placemark)}</Placemark>`
- const points: RegExpMatchArray = getKmlParams(kmlStr.value, false, {
- name: 'Placemark',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- }) || ['']
- if (place === 'add') {
- const lastPoint = points[points.length - 1]
- const index = kmlStr.value.indexOf(lastPoint)
- const beforeStr = kmlStr.value.slice(0, index)
- const afterStr = kmlStr.value.slice(index + lastPoint.length)
- kmlStr.value = beforeStr + lastPoint + Placemark + afterStr
- }
- if (place === 'prev') {
- const currentPoint: string = points[pointNumber]
- const index = kmlStr.value.indexOf(currentPoint)
- const beforeStr = kmlStr.value.slice(0, index)
- const afterStr = kmlStr.value.slice(index + currentPoint.length)
- kmlStr.value = beforeStr + Placemark + currentPoint + afterStr
- // 更新点位序号
- const pointIndexList = getKmlParams(kmlStr.value, true, {
- name: 'index',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- })
- pointIndexList?.forEach((pintIndex: string, index: number) => {
- kmlStr.value.replace(pintIndex, `<wpml:index>${index}</wpml:index>`)
- })
- }
- if (place === 'next') {
- const currentPoint: string = points[pointNumber + 1]
- const index = kmlStr.value.indexOf(currentPoint)
- const beforeStr = kmlStr.value.slice(0, index)
- const currentPointLength = currentPoint?.length || 0
- const afterStr = kmlStr.value.slice(index + currentPointLength)
- kmlStr.value = beforeStr + Placemark + currentPoint + afterStr
- // 更新点位序号
- const pointIndexList = getKmlParams(kmlStr.value, true, {
- name: 'index',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- })
- pointIndexList?.forEach((pintIndex: string, index: number) => {
- kmlStr.value.replace(pintIndex, `<wpml:index>${index}</wpml:index>`)
- })
- }
- }
- const edit = (settingParmas: any = {}, keyName?: string, isKeyWpml: boolean = false) => {
- Object.keys(settingParmas).forEach((key: string) => {
- const regxVal: any = getKmlParams(kmlStr.value, true, {
- name: key,
- findRegx: '([\\s\\S]*?)',
- })
- const str = regxVal[1]
- if (str) {
- if (key === 'globalHeight') {
- const regxVal: any = getKmlParams(kmlStr.value, true, {
- name: 'height',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- })
- const ellipsoidHeightRegx = getKmlParams(kmlStr.value, true, {
- name: 'ellipsoidHeight',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- }) || ['']
- // 文件中的海拔高度
- const takeOffRefPointAGLHeightRegxStr = getKmlParams(kmlStr.value, true, {
- name: 'takeOffRefPointAGLHeight',
- findRegx: '([\\s\\S]*?)',
- }) || ['', '0']
- const posterHeight = Number(takeOffRefPointAGLHeightRegxStr[1])
- // 获取每个点是否使用全局高度
- const useGlobalHeightRegStr = getKmlParams(kmlStr.value, true, {
- name: 'useGlobalHeight',
- findRegx: '([\\s\\S]*?)',
- mode: 'g',
- }) || ['', '0']
- regxVal.forEach((heightStr: string, index: number) => {
- // 使用正则取值
- const getUseGlobalHeightValStr = getKmlParams(useGlobalHeightRegStr[index], true, {
- name: 'useGlobalHeight',
- findRegx: '([\\s\\S]*?)',
- }) || ['', '0']
- const isGlobalHeight = Boolean(Number(getUseGlobalHeightValStr[1]))
- if (isGlobalHeight) {
- // 替换height
- const rstr = generateKmlFormat({ height: settingParmas[key] })
- const rEllipsoidHeightStr = generateKmlFormat({ ellipsoidHeight: settingParmas[key] - posterHeight })
- kmlStr.value = kmlStr.value.replace(heightStr, rstr)
- kmlStr.value = kmlStr.value.replace(ellipsoidHeightRegx[index], rEllipsoidHeightStr)
- // 替换
- } else {
- const heightRegxVal: any = getKmlParams(heightStr, true, {
- name: 'height',
- findRegx: '([\\s\\S]*?)',
- })
- }
- })
- }
- const replaceStr = generateKmlFormat({ [key]: settingParmas[key] })
- kmlStr.value = kmlStr.value.replace(regxVal[0], replaceStr)
- } else {
- console.warn('没有找到对应的属性')
- }
- })
- }
+ }
const save = () => {
console.log('存在问题')
}
+ const generateXML = <T>(xmlJson: T) => {
+ return JSONToXML(xmlJson)
+ }
+
+ // 将wpmz/template.kml解析传来json转换回去,重新复制以便于后续绘制
+ watch(() => template.value, (newobj) => {
+ const xmlString = JSONToXML(newobj)
+ kmlStr.value = xmlString
+ }, {
+ deep: true
+ })
+
return {
init,
create,
- // write,
- writePoint,
- edit,
save,
+ generateXML
}
}
-export { kmlStr, fileAuthor }
+export { kmlStr, fileAuthor, template, waylines }
export default useKmzTsa
diff --git a/src/utils/cesium/use-map-draw.ts b/src/utils/cesium/use-map-draw.ts
index 1ae9c37..bc339a0 100644
--- a/src/utils/cesium/use-map-draw.ts
+++ b/src/utils/cesium/use-map-draw.ts
@@ -4,6 +4,7 @@
import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
import { ref } from 'vue'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
+import { template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
const { addPolyline, getEntityById } = cesiumOperation()
const getResource = (name: string) => {
@@ -22,7 +23,7 @@
}
interface tragetPoint {
position: Cesium.Cartesian3
- isUseGlobalHeight: boolean,
+ isUseGlobalHeight: boolean
eventList: eventParmas[]
}
@@ -110,6 +111,8 @@
// kml中的全部实体
const kmlEntities = ref<Cesium.Entity[]>([])
+const selectPointIndex = ref<number | null>(null)
+
const useMapDraw = (
dataSource: Cesium.DataSource | any,
entitiesList: Cesium.Entity[] | any,
@@ -160,7 +163,7 @@
btmStartPoint = Cesium.Cartesian3.fromDegrees(
Number(startPointPosition[1]),
Number(startPointPosition[0]),
- Number(startPointPosition[2])
+ Number(startPointPosition[2]),
)
// 参考起飞点“海拔高度,与“参考起飞点”中的椭球高度对应
// const posterHeightRegStr = getKmlParams(kmlRes, true, {
@@ -223,7 +226,10 @@
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
pixelOffset: new Cesium.Cartesian2(0, -40),
+ show: false
})
+ // 广告牌隐藏
+ // entity.label._show = false
// 修改点的信息
entity.point = new Cesium.PointGraphics({
pixelSize: 20,
@@ -412,5 +418,5 @@
}
}
-export { waylinePointsEvent, waylineDetails, kmlEntities }
+export { waylinePointsEvent, waylineDetails, kmlEntities, selectPointIndex }
export default useMapDraw
diff --git a/vite.config.ts b/vite.config.ts
index a754a27..3e4c986 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -23,13 +23,13 @@
vue(),
cesium(),
eslintPlugin({
- fix: true
+ fix: true,
}),
ViteComponents({
customComponentResolvers: [AntDesignVueResolver()],
}),
viteSvgIcons({
- // 指定需要缓存的图标文件夹
+ // 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
@@ -38,25 +38,26 @@
entry: path.resolve(__dirname, './src/main.ts'), // 入口文件
localEnabled: command === 'serve', // serve开发环境下
// enabled: command !== 'serve' || mode === 'test', // 打包环境下/发布测试包,
- config: { // vconsole 配置项
+ config: {
+ // vconsole 配置项
maxLogNumber: 1000,
- theme: 'light'
- }
+ theme: 'light',
+ },
}),
AutoImport({
dts: 'types/auto-imports.d.ts',
imports: ['vue', 'vue-router'],
// 解决eslint报错问题
eslintrc: {
- // 这里先设置成true然后npm run dev 运行之后会生成 .eslintrc-auto-import.json 文件之后,在改为false
+ // 这里先设置成true然后npm run dev 运行之后会生成 .eslintrc-auto-import.json 文件之后,在改为false
enabled: false,
filepath: './.eslintrc-auto-import.json', // 生成的文件路径
globalsPropValue: true,
},
}),
PkgConfig(),
- OptimizationPersist()
- // [svgBuilder('./src/assets/icons/')] // All svg under src/icons/svg/ have been imported here, no need to import separately
+ OptimizationPersist(),
+ // [svgBuilder('./src/assets/icons/')] // All svg under src/icons/svg/ have been imported here, no need to import separately
],
server: {
open: true,
@@ -66,35 +67,36 @@
[env.VITE_BASE_API]: {
// 代理请求之后的请求地址(你的真实接口地址)
target: env.VITE_API_URL,
- rewrite: path => path.replace(new RegExp(`^${env.VITE_BASE_API}`), ''),
+ rewrite: (path) => path.replace(new RegExp(`^${env.VITE_BASE_API}`), ''),
// 跨域
- changeOrigin: true
- }
- }
+ changeOrigin: true,
+ },
+ },
},
envDir: './env',
resolve: {
- alias: [{
- // https://github.com/vitejs/vite/issues/279#issuecomment-635646269
- find: '/@',
- replacement: path.resolve(__dirname, './src'),
- }
- ]
+ alias: [
+ {
+ // https://github.com/vitejs/vite/issues/279#issuecomment-635646269
+ find: '/@',
+ replacement: path.resolve(__dirname, './src'),
+ },
+ ],
},
css: {
preprocessorOptions: {
scss: {
- // example : additionalData: `@import "./src/design/styles/variables";`
- // dont need include file extend .scss
- additionalData: '@import "./src/styles/variables";'
+ // example : additionalData: `@import "./src/design/styles/variables";`
+ // dont need include file extend .scss
+ additionalData: '@import "./src/styles/variables";',
},
- }
+ },
},
base: './',
build: {
target: ['es2015'], // 最低支持 es2015
- sourcemap: true
- }
+ sourcemap: true,
+ },
}
})
// export default ({ command, mode }: ConfigEnv): UserConfigExport => defineConfig({
--
Gitblit v1.9.3