update:kmz/json转换、kmz打包后无法解析等
8 files modified
2 files added
| | |
| | | "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", |
| | |
| | | watch( |
| | | () => route, |
| | | (val) => { |
| | | console.log(val) |
| | | if (val.name === ERouterName.WAYLINE) { |
| | | isWaylineRoute.value = true |
| | | } else { |
| | |
| | | <template> |
| | | <div class="project-wayline-wrapper height-100"> |
| | | <a-spin :spinning="loading" :delay="300" tip="加载中" size="large"> |
| | | <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;"> |
| | | <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450"> |
| | | <a-row> |
| | | <a-col :span="1"></a-col> |
| | | <a-col :span="15">历史航线</a-col> |
| | |
| | | <div :style="{ height: height + 'px' }" class="scrollbar"> |
| | | <div id="data" class="height-100 uranus-scrollbar" v-if="routeLine.length !== 0" @scroll="onScroll"> |
| | | <div v-for="wayline in routeLine" :key="wayline.id"> |
| | | <div class="wayline-panel" style="padding-top: 5px;" @click="selectRoute(wayline)"> |
| | | <div class="wayline-panel" style="padding-top: 5px" @click="selectRoute(wayline)"> |
| | | <div class="title"> |
| | | <a-tooltip :title="wayline.title"> |
| | | <div class="pr10">{{ wayline.title }}</div> |
| | |
| | | </a-tooltip> |
| | | <div class="fz20"></div> |
| | | </div> |
| | | <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);"> |
| | | </div> |
| | | <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);"> |
| | | <div class="ml10 mt5" style="color: hsla(0, 0%, 100%, 0.65)"></div> |
| | | <div class="mt5 ml10" style="color: hsla(0, 0%, 100%, 0.35)"> |
| | | <span class="mr10">开始时间: {{ convertTimestampToDate(wayline.start_time) }}</span> |
| | | </div> |
| | | <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);"> |
| | | <div class="mt5 ml10" style="color: hsla(0, 0%, 100%, 0.35)"> |
| | | <span class="mr10">结束时间: {{ convertTimestampToDate(wayline.end_time) }}</span> |
| | | </div> |
| | | </div> |
| | |
| | | <span @click="closePopUp">×</span> |
| | | </div> |
| | | <div class="PopUp"> |
| | | <img :src="currentWayline.photo_url" alt="photo"> |
| | | <img :src="currentWayline.photo_url" alt="photo" /> |
| | | <div> |
| | | <div>云台偏航角:{{ currentWayline.gimbal_yaw_degree }}</div> |
| | | <div>拍摄绝对高度:{{ currentWayline.absolute_altitude }}</div> |
| | |
| | | import * as Cesium from 'cesium' |
| | | import { convertTimestampToDate } from '/@/utils/time' |
| | | import { cesiumOperation } from '/@/hooks/use-cesium-tsa' |
| | | import { NONAME } from 'dns' |
| | | import CustomerSportLine from '/@/utils/cesium/customerSportLine' |
| | | |
| | | const getResource = (name: string) => { |
| | | return new URL(`/src/assets/icons/${name}`, import.meta.url).href |
| | | } |
| | | |
| | | const loading = ref(false) |
| | | const { appContext } = getCurrentInstance() |
| | |
| | | const pagination: IPage = { |
| | | page: 1, |
| | | total: -1, |
| | | page_size: 10 |
| | | page_size: 10, |
| | | } |
| | | const routeLine = ref([]) |
| | | const workspaceId = computed(() => store.state.common.projectId || localStorage.getItem(ELocalStorageKey.WorkspaceId)) |
| | | const canRefresh = ref(true) |
| | | const height = ref() |
| | | const { addPoint, addClickEvent, removeClickEvent, removeById, addPolyline, getEntityById, flyTo, removeAllPoint, removeAllDataSource } = cesiumOperation() |
| | | const { |
| | | addPoint, |
| | | addClickEvent, |
| | | removeClickEvent, |
| | | removeById, |
| | | addPolyline, |
| | | getEntityById, |
| | | flyTo, |
| | | removeAllPoint, |
| | | removeAllDataSource, |
| | | } = cesiumOperation() |
| | | const isShowPopUp = ref<boolean>(false) |
| | | const popup = ref(null) |
| | | const currentWayline = ref({ |
| | |
| | | gimbal_yaw_degree: '', |
| | | absolute_altitude: '', |
| | | relative_altitude: '', |
| | | created_time: '' |
| | | created_time: '', |
| | | }) |
| | | |
| | | onMounted(() => { |
| | |
| | | |
| | | async function selectRoute (wayline: { start_time: string; id: string }) { |
| | | currentWayline.value = { |
| | | photo_url: 'https://dev.jxpskj.com:8026/cloud-bucket/5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_202311171122_004_5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_20231117112319_0001_W_%E8%88%AA%E7%82%B91.jpeg', |
| | | photo_url: |
| | | 'https://dev.jxpskj.com:8026/cloud-bucket/5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_202311171122_004_5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_20231117112319_0001_W_%E8%88%AA%E7%82%B91.jpeg', |
| | | gimbal_yaw_degree: '81°', |
| | | absolute_altitude: '120m', |
| | | relative_altitude: '120m', |
| | | created_time: new Date(wayline.start_time).toLocaleString() |
| | | created_time: new Date(wayline.start_time).toLocaleString(), |
| | | } |
| | | // currentWayline.value = wayline |
| | | // 判断是否有历史航线的id实体 |
| | |
| | | }) |
| | | const pointOption = { |
| | | longitude: routeLine[0], |
| | | latitude: routeLine[1] |
| | | latitude: routeLine[1], |
| | | } |
| | | routeLine = Cesium.Cartesian3.fromDegreesArray(routeLine) |
| | | // 添加起飞点图片 |
| | | const billboardSetting = { |
| | | ...pointOption, |
| | | billboard: { |
| | | image: 'https://dev.jxpskj.com:8026/cloud-bucket/5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_202311171122_004_5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_20231117112319_0001_W_%E8%88%AA%E7%82%B91.jpeg', |
| | | image: |
| | | 'https://dev.jxpskj.com:8026/cloud-bucket/5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_202311171122_004_5abb3b6e-cb42-40e4-b086-9c24db0e8765/DJI_20231117112319_0001_W_%E8%88%AA%E7%82%B91.jpeg', |
| | | width: 40, |
| | | height: 40, |
| | | pixelOffset: new Cesium.Cartesian2(0, -10), |
| | |
| | | pixelSize: 5, |
| | | color: Cesium.Color.RED, |
| | | outlineColor: Cesium.Color.WHITE, |
| | | outlineWidth: 2 |
| | | outlineWidth: 2, |
| | | }, |
| | | label: { |
| | | text: '起飞点', |
| | |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | outlineWidth: 1, |
| | | verticalOrigin: Cesium.VerticalOrigin.TOP, |
| | | pixelOffset: new Cesium.Cartesian2(0, 10) |
| | | pixelOffset: new Cesium.Cartesian2(0, 10), |
| | | }, |
| | | id: 'start_point_billboard' |
| | | id: 'start_point_billboard', |
| | | } |
| | | addPoint(billboardSetting) |
| | | // 添加广告牌点击事件 |
| | | addClickEvent('start_point_billboard', addBillboard) |
| | | function addBillboard (_click: any, _pick: any, viewer: { container: { append: (arg0: any) => void }; scene: Cesium.Scene }) { |
| | | function addBillboard ( |
| | | _click: any, |
| | | _pick: any, |
| | | viewer: { container: { append: (arg0: any) => void }; scene: Cesium.Scene }, |
| | | ) { |
| | | viewer.scene.postRender.removeEventListener(addBillboard) |
| | | viewer.container.append(element) |
| | | if (isShowPopUp.value) { |
| | |
| | | viewer.scene.postRender.addEventListener(() => { |
| | | const windowCoord = Cesium.SceneTransforms.wgs84ToWindowCoordinates( |
| | | viewer.scene, |
| | | Cesium.Cartesian3.fromDegrees(longitude, latitude, 0) |
| | | Cesium.Cartesian3.fromDegrees(longitude, latitude, 0), |
| | | ) |
| | | const x = windowCoord.x + 40 |
| | | const y = windowCoord.y - (element.offsetHeight / 2) - 40 |
| | | const y = windowCoord.y - element.offsetHeight / 2 - 40 |
| | | element.style.transform = ` |
| | | translate3d(${Math.round(x)}px,${Math.round(y)}px, 0) |
| | | ` |
| | |
| | | latitude: 28.62452712442823, |
| | | id: 'drone_route_history', |
| | | polyline: { |
| | | width: 5, |
| | | width: 10, |
| | | positions: routeLine, |
| | | material: Cesium.Color.BLUE |
| | | // material: Cesium.Color.BLUE |
| | | material: new CustomerSportLine({ |
| | | color: Cesium.Color.WHITE, |
| | | speed: 20, |
| | | image: getResource('arrow.png'), |
| | | repeat: { x: 15, y: 0 }, |
| | | }), |
| | | clampToGround: false, // 关闭贴地效果,保留高度 |
| | | }, |
| | | } |
| | | addPolyline(routeTrajectory) |
| | |
| | | |
| | | function onScroll (e: any) { |
| | | const element = e.srcElement |
| | | if (element.scrollTop + element.clientHeight >= element.scrollHeight - 5 && Math.ceil(pagination.total / pagination.page_size) > pagination.page && canRefresh.value) { |
| | | if ( |
| | | element.scrollTop + element.clientHeight >= element.scrollHeight - 5 && |
| | | Math.ceil(pagination.total / pagination.page_size) > pagination.page && |
| | | canRefresh.value |
| | | ) { |
| | | pagination.page++ |
| | | getHistoryWay() |
| | | } |
| | |
| | | // removeById('drone_route_history') |
| | | removeAllPoint() |
| | | }) |
| | | |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | background-color: #fff; |
| | | padding-top: 0; |
| | | border-radius: 5px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1); |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | .popup-title { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | |
| | | cursor: pointer; |
| | | font-weight: bolder; |
| | | display: block; |
| | | width: 25px |
| | | width: 25px; |
| | | } |
| | | } |
| | | |
| | |
| | | overflow: auto; |
| | | scrollbar-width: thin; |
| | | scrollbar-color: #c5c8cc transparent; |
| | | }</style> |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="project-wayline-wrapper height-100" ref="projectWayLine"> |
| | | <a-spin :spinning="loading" :delay="300" tip="加载中" size="large"> |
| | | <div |
| | | style=" |
| | | height: 50px; |
| | | line-height: 50px; |
| | | border-bottom: 1px solid #4f4f4f; |
| | | font-weight: 450; |
| | | "> |
| | | <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450"> |
| | | <a-row> |
| | | <a-col :span="1"></a-col> |
| | | <a-col :span="15">{{ |
| | | isPointListOpen ? '航点列表' : '航线库' |
| | | }}</a-col> |
| | | <a-col |
| | | :span="8" |
| | | v-if="importVisible" |
| | | class="flex-row flex-justify-end flex-align-center"> |
| | | <a-col :span="15">{{ isPointListOpen ? '航点列表' : '航线库' }}</a-col> |
| | | <a-col :span="8" v-if="importVisible" class="flex-row flex-justify-end flex-align-center"> |
| | | <a-upload |
| | | name="file" |
| | | :multiple="false" |
| | |
| | | <SelectOutlined /> |
| | | </a-button> |
| | | </a-upload> |
| | | <a-button |
| | | type="text" |
| | | style="color: white" |
| | | @click="addWaylineDialog"> |
| | | <a-button type="text" style="color: white" @click="addWaylineDialog"> |
| | | <template #icon> |
| | | <PlusOutlined /> |
| | | </template> |
| | |
| | | </a-col> |
| | | </a-row> |
| | | </div> |
| | | <div |
| | | :style="{ height: height + 'px' }" |
| | | class="scrollbar" |
| | | v-if="!isPointListOpen"> |
| | | <div |
| | | id="data" |
| | | class="height-100 uranus-scrollbar" |
| | | v-if="waylinesData.data.length !== 0" |
| | | @scroll="onScroll"> |
| | | <div |
| | | v-for="wayline in waylinesData.data" |
| | | :key="wayline.id" |
| | | @click="selectRoute(wayline)"> |
| | | <div :style="{ height: height + 'px' }" class="scrollbar" v-if="!isPointListOpen"> |
| | | <div id="data" class="height-100 uranus-scrollbar" v-if="waylinesData.data.length !== 0" @scroll="onScroll"> |
| | | <div v-for="wayline in waylinesData.data" :key="wayline.id" @click="selectRoute(wayline)"> |
| | | <div class="wayline-panel" style="padding-top: 5px"> |
| | | <div class="title"> |
| | | <a-tooltip :title="wayline.name"> |
| | | <div |
| | | class="pr10" |
| | | style=" |
| | | width: 120px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | "> |
| | | style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden"> |
| | | {{ wayline.name }} |
| | | </div> |
| | | </a-tooltip> |
| | |
| | | <a-tooltip :title="wayline.user_name"> |
| | | <div |
| | | class="ml5 pr10" |
| | | style=" |
| | | width: 80px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | "> |
| | | style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden"> |
| | | {{ wayline.user_name }} |
| | | </div> |
| | | </a-tooltip> |
| | | <div class="fz20 tools"> |
| | | <span style="margin-right: 10px"> |
| | | <EditOutlined |
| | | style="font-size: 15px" |
| | | @click.stop="routeEventEdit(wayline)" /> |
| | | <EditOutlined style="font-size: 15px" @click.stop="routeEventEdit(wayline)" /> |
| | | </span> |
| | | <a-dropdown> |
| | | <a style="color: white"> |
| | | <EllipsisOutlined /> |
| | | </a> |
| | | <template #overlay> |
| | | <a-menu |
| | | theme="dark" |
| | | class="more" |
| | | style="background: #3c3c3c"> |
| | | <a-menu theme="dark" class="more" style="background: #3c3c3c"> |
| | | <a-menu-item @click="openEditModal(wayline)"> |
| | | <span>重命名</span> |
| | | </a-menu-item> |
| | | <a-menu-item |
| | | @click="downloadWayline(wayline.id, wayline.name)"> |
| | | <a-menu-item @click="downloadWayline(wayline.id, wayline.name)"> |
| | | <span>下载</span> |
| | | </a-menu-item> |
| | | <a-menu-item @click="showWaylineTip(wayline.id)"> |
| | |
| | | <RocketOutlined /> |
| | | </span> |
| | | <span class="ml5">{{ |
| | | Object.keys(EDeviceType)[ |
| | | Object.values(EDeviceType).indexOf(wayline.drone_model_key) |
| | | ] |
| | | Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(wayline.drone_model_key)] |
| | | }}</span> |
| | | <span class="ml10"> |
| | | <CameraFilled |
| | | style="border-top: 1px solid; padding-top: -3px" /> |
| | | <CameraFilled style="border-top: 1px solid; padding-top: -3px" /> |
| | | </span> |
| | | <span |
| | | class="ml5" |
| | | v-for="payload in wayline.payload_model_keys" |
| | | :key="payload.id"> |
| | | {{ |
| | | Object.keys(EDeviceType)[ |
| | | Object.values(EDeviceType).indexOf(payload) |
| | | ] |
| | | }} |
| | | <span class="ml5" v-for="payload in wayline.payload_model_keys" :key="payload.id"> |
| | | {{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(payload)] }} |
| | | </span> |
| | | </div> |
| | | <div class="mt5 ml10" style="color: hsla(0, 0%, 100%, 0.35)"> |
| | | <span class="mr10" |
| | | >更新时间: |
| | | {{ new Date(wayline.update_time).toLocaleString() }}</span |
| | | > |
| | | <span class="mr10">更新时间: {{ new Date(wayline.update_time).toLocaleString() }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | :cancel-button-props="{ ghost: true }" |
| | | @ok="handleEditName"> |
| | | <div class="wayline-title">航线名称</div> |
| | | <a-input |
| | | v-model:value="currentWayLine.name" |
| | | placeholder="请输入航线名称" /> |
| | | <a-input v-model:value="currentWayLine.name" placeholder="请输入航线名称" /> |
| | | </a-modal> |
| | | </div> |
| | | <!-- 航线编辑 --> |
| | | <div |
| | | class="targt-point scrollbar" |
| | | :style="{ height: height + 'px' }" |
| | | v-else> |
| | | <route-edit |
| | | v-model:isCreateWayline="isCreateWayline" |
| | | @back-fn="backPage" /> |
| | | <div class="targt-point scrollbar" :style="{ height: height + 'px' }" v-else> |
| | | <route-edit v-model:isCreateWayline="isCreateWayline" @back-fn="backPage" /> |
| | | </div> |
| | | <!-- 新建航线 --> |
| | | <a-modal |
| | |
| | | <a-form-item label="选择飞行器与负载"> |
| | | <a-select></a-select> |
| | | <div class="drone-box"> |
| | | <img :src="getResource('wrj.png')" alt="" srcset="" class="drone-img"> |
| | | <img :src="getResource('wrj.png')" alt="" srcset="" class="drone-img" /> |
| | | </div> |
| | | </a-form-item> |
| | | </a-form> |
| | |
| | | import routeEdit from './components/route-edit/index.vue' |
| | | import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial' |
| | | import { getPolylineLength } from '/@/utils/cesium/mapUtils' |
| | | import { |
| | | deleteWaylineFile, |
| | | downloadWaylineFile, |
| | | getWaylineFiles, |
| | | importKmzFile, |
| | | getWayLineFile, |
| | | } from '/@/api/wayline' |
| | | import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile, getWayLineFile } from '/@/api/wayline' |
| | | import EventBus from '/@/event-bus/' |
| | | import { ELocalStorageKey, ERouterName } from '/@/types' |
| | | import { EDeviceType } from '/@/types/device' |
| | |
| | | const { appContext }: any = getCurrentInstance() |
| | | const global = appContext.config.globalProperties |
| | | const store = useMyStore() |
| | | let kmlDataSource: |
| | | | { entities: { values: { _children: any }[] }; show: boolean } |
| | | | null |
| | | | any = null |
| | | let kmlDataSource: { entities: { values: { _children: any }[] }; show: boolean } | null | any = null |
| | | const pagination: IPage = { |
| | | page: 1, |
| | | total: -1, |
| | |
| | | const currentWayLine = ref<any>({}) |
| | | |
| | | const root = getRoot() |
| | | const workspaceId = computed( |
| | | () => |
| | | store.state.common.projectId || |
| | | localStorage.getItem(ELocalStorageKey.WorkspaceId), |
| | | ) |
| | | const workspaceId = computed(() => store.state.common.projectId || localStorage.getItem(ELocalStorageKey.WorkspaceId)) |
| | | const deleteTip = ref(false) |
| | | const deleteWaylineId = ref<string>('') |
| | | const canRefresh = ref(true) |
| | | const importVisible = ref<boolean>( |
| | | root.$router.currentRoute.value.name === ERouterName.WAYLINE, |
| | | ) |
| | | const importVisible = ref<boolean>(root.$router.currentRoute.value.name === ERouterName.WAYLINE) |
| | | const editVisible = ref<boolean>(false) |
| | | const height = ref() |
| | | const { |
| | | removeById, |
| | | addClickEvent, |
| | | getEntityById, |
| | | addPolyline, |
| | | removeAllPoint, |
| | | } = cesiumOperation() |
| | | const { removeById, addClickEvent, getEntityById, addPolyline, removeAllPoint } = cesiumOperation() |
| | | |
| | | const isPointListOpen = ref<boolean>(false) |
| | | |
| | | onMounted(() => { |
| | | const parent = document.getElementsByClassName('scrollbar').item(0) |
| | | ?.parentNode as HTMLDivElement |
| | | height.value = |
| | | document.body.clientHeight - parent.firstElementChild!.clientHeight |
| | | const parent = document.getElementsByClassName('scrollbar').item(0)?.parentNode as HTMLDivElement |
| | | height.value = document.body.clientHeight - parent.firstElementChild!.clientHeight |
| | | getWaylines() |
| | | |
| | | const key = setInterval(() => { |
| | | const data = document.getElementById('data') |
| | | ?.lastElementChild as HTMLDivElement |
| | | const data = document.getElementById('data')?.lastElementChild as HTMLDivElement |
| | | if ( |
| | | pagination.total === 0 || |
| | | Math.ceil(pagination.total / pagination.page_size) <= pagination.page || |
| | |
| | | if (kmlDataSource) { |
| | | global.$viewer.dataSources.remove(kmlDataSource) |
| | | } |
| | | global.$viewer.dataSources |
| | | .add(Cesium.KmlDataSource.load(file, options)) |
| | | .then((res: any) => { |
| | | kmlDataSource = res |
| | | const mapDraw = useMapDraw(kmlDataSource, [], file, global) |
| | | mapDraw.drawWayline() |
| | | }) |
| | | global.$viewer.dataSources.add(Cesium.KmlDataSource.load(file, options)).then((res: any) => { |
| | | kmlDataSource = res |
| | | const mapDraw = useMapDraw(kmlDataSource, [], file, global) |
| | | mapDraw.drawWayline() |
| | | }) |
| | | } |
| | | |
| | | // 返回上一页 |
| | |
| | | |
| | | // 新建航线 |
| | | interface waylineFormState { |
| | | fileName: string, |
| | | droneType: string, |
| | | fileName: string |
| | | droneType: string |
| | | payloadType: string |
| | | } |
| | | const addWaylineDialogShow = ref<boolean>(false) |
| | |
| | | const waylineFormState = reactive<UnwrapRef<waylineFormState>>({ |
| | | fileName: '', |
| | | droneType: '', |
| | | payloadType: '' |
| | | payloadType: '', |
| | | }) |
| | | const addWaylineDialog = () => { |
| | | addWaylineDialogShow.value = true |
| New file |
| | |
| | | declare module '@mapbox/togeojson' |
| | |
| | | animation: false, |
| | | duration: 30, |
| | | time: 0, |
| | | repeat: new Cesium.Cartesian2(1, 1), |
| | | }, |
| | | // source编写glsl,可以使用uniforms参数,值来自getValue方法的result |
| | | source: ` |
| | | #extension GL_OES_standard_derivatives : enable |
| | | czm_material czm_getMaterial(czm_materialInput materialInput) |
| | | { |
| | | czm_material material = czm_getDefaultMaterial(materialInput); |
| | | vec2 st = materialInput.st; |
| | | float s = st.s/ (abs(fwidth(st.s)) * imageW * czm_pixelRatio); |
| | | vec2 st = repeat * materialInput.st; |
| | | float s = st.s / (abs(fwidth(st.s)) * imageW * czm_pixelRatio); |
| | | if(animation==true){ |
| | | s = s-time;//增加运动效果 |
| | | } |
| | |
| | | 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'] |
| | | |
| | |
| | | .get(filePath, { responseType: 'arraybuffer' }) |
| | | .then((fileRes) => fileRes.data) |
| | | .then((kmzData) => JsZip.loadAsync(kmzData)) // 解压kmz文件 |
| | | .then((kmzZip) => { |
| | | // 通过文件名找到 KML 文件 |
| | | const kmlFile = kmzZip.file(/\.kml$/i)[0] |
| | | .then((zipFile) => { |
| | | const files: { [key: string]: Promise<string> } = {} |
| | | Object.keys(zipFile.files).forEach((key: string) => { |
| | | files[key] = zipFile.files[key].async('text') |
| | | }) |
| | | return { |
| | | file: kmzZip, |
| | | content: kmlFile.async('text') |
| | | zip: zipFile, |
| | | fileInfoObj: files, |
| | | } |
| | | }) |
| | | } |
| | |
| | | if (Object.prototype.toString.call(settingParmas[key]) === '[object Object]') { |
| | | let parmaStr = '' |
| | | Object.keys(settingParmas[key]).forEach((v) => { |
| | | const xml = noWmpl.includes(key) ? `<${v}>${settingParmas[key][v]}</${v}>` : `<wpml:${v}>${settingParmas[key][v]}</wpml:${v}>` |
| | | const xml = noWmpl.includes(key) |
| | | ? `<${v}>${settingParmas[key][v]}</${v}>` |
| | | : `<wpml:${v}>${settingParmas[key][v]}</wpml:${v}>` |
| | | parmaStr += xml |
| | | }) |
| | | const xml = noWmpl.includes(key) ? `<${key}>${parmaStr}</${key}>` : `<wpml:${key}>${parmaStr}</wpml:${key}>` |
| | | paramGroup += xml |
| | | } else { |
| | | const xml = noWmpl.includes(key) ? `<${key}>${settingParmas[key]}</${key}>` : `<wpml:${key}>${settingParmas[key]}</wpml:${key}>` |
| | | const xml = noWmpl.includes(key) |
| | | ? `<${key}>${settingParmas[key]}</${key}>` |
| | | : `<wpml:${key}>${settingParmas[key]}</wpml:${key}>` |
| | | paramGroup += xml |
| | | } |
| | | }) |
| | |
| | | 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') |
| | | const element = xmlDoc.documentElement |
| | | if (element && element.tagName) { |
| | | return element.tagName // 返回的是类似 "WPML:USEGLOBALHEADINGPARAM" 的全大写形式 |
| | | } |
| | | return null |
| | | } |
| | | |
| | | // 将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]] |
| | | } |
| | | xmlObj[childName].push(child.textContent) |
| | | } else { |
| | | const value = child.textContent?.split('\n').join('').split(' ').join('') |
| | | xmlObj[childName.replace('wpml:', '')] = value |
| | | } |
| | | } |
| | | } |
| | | return xmlObj |
| | | } |
| | | export const XMLToJSON = (xmlStr: string, tagName: string) => { |
| | | const parser = new DOMParser() |
| | | const xmlDoc = parser.parseFromString(xmlStr, 'text/xml') |
| | | const xmlObj = deepParse(xmlDoc, tagName) |
| | | delete xmlObj.parsererror |
| | | 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}>` |
| | | } else { |
| | | xmlTag = `<wpml:${key} rowNum="${index}">${item}</wpml:${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}>`) |
| | | } |
| | | } |
| | | } |
| | | JSONParse(JSONData) |
| | | return res |
| | | } |
| | |
| | | import { ref, getCurrentInstance } from 'vue' |
| | | import { analyzeKmzFile, getKmlParams, generateKmlFormat } from '/@/utils/cesium/kmz' |
| | | import { |
| | | analyzeKmzFile, |
| | | getKmlParams, |
| | | generateKmlFormat, |
| | | XMLToJSON, |
| | | JSONToXML |
| | | } from '/@/utils/cesium/kmz' |
| | | import JSZIP from 'jszip' |
| | | import { saveAs } from 'file-saver' |
| | | import { point } from '@turf/turf' |
| | | |
| | | const JsZip = new JSZIP() |
| | | |
| | |
| | | }) |
| | | const kmlStr = ref('') |
| | | const kmzFile = ref<any>(null) |
| | | |
| | | const template = ref({ |
| | | author: '', |
| | | createTime: '', |
| | | updateTime: '', |
| | | missionConfig: { |
| | | flyToWaylineMode: 'safely', |
| | | finishAction: 'goHome', |
| | | exitOnRCLost: 'goContinue', |
| | | executeRCLostAction: 'goBack', |
| | | takeOffSecurityHeight: 20, |
| | | takeOffRefPoint: '0.000000,0.000000,0.000000', |
| | | takeOffRefPointAGLHeight: 0, |
| | | globalTransitionalSpeed: 15, |
| | | globalRTHHeight: 80, |
| | | droneInfo: { |
| | | droneEnumValue: 0, |
| | | droneSubEnumValue: 0, |
| | | }, |
| | | payloadInfo: { |
| | | payloadEnumValue: 0, |
| | | payloadSubEnumValue: 0, |
| | | payloadPositionIndex: 0, |
| | | }, |
| | | }, |
| | | Folder: { |
| | | templateType: 'waypoint', |
| | | useGlobalTransitionalSpeed: 0, |
| | | templateId: 0, |
| | | waylineCoordinateSysParam: { |
| | | coordinateMode: 'WGS84', |
| | | heightMode: 'EGM96', |
| | | globalShootHeight: 50, |
| | | positioningType: 'GPS', |
| | | surfaceFollowModeEnable: 1, |
| | | surfaceRelativeHeight: 100, |
| | | }, |
| | | autoFlightSpeed: 7, |
| | | gimbalPitchMode: 'usePointSetting', |
| | | globalWaypointHeadingParam: { |
| | | waypointHeadingMode: 'followWayline', |
| | | waypointHeadingAngle: 0, |
| | | waypointPoiPoint: '0.000000,0.000000,0.000000', |
| | | waypointHeadingPathMode: 'followBadArc', |
| | | }, |
| | | globalWaypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature', |
| | | globalUseStraightLine: 0, |
| | | Placemark: [ |
| | | { |
| | | Point: { |
| | | coordinates: '', |
| | | }, |
| | | index: 0, |
| | | ellipsoidHeight: 0, |
| | | height: 0, |
| | | useGlobalHeight: 0, |
| | | useGlobalSpeed: 0, |
| | | useGlobalHeadingParam: 1, |
| | | useGlobalTurnParam: 0, |
| | | gimbalPitchAngle: 0, |
| | | actionGroup: { |
| | | actionGroupId: 0, |
| | | actionGroupStartIndex: 1, |
| | | actionGroupEndIndex: 1, |
| | | actionGroupMode: 'sequence', |
| | | actionTrigger: { |
| | | actionTriggerType: 'reachPoint', |
| | | }, |
| | | action: [], |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | }) |
| | | const waylines = ref({ |
| | | missionConfig: { |
| | | flyToWaylineMode: 'safely', |
| | | finishAction: 'goHome', |
| | | exitOnRCLost: 'goContinue', |
| | | executeRCLostAction: 'hover', |
| | | takeOffSecurityHeight: 20, |
| | | globalTransitionalSpeed: 10, |
| | | distance: 0, |
| | | duration: 0, |
| | | droneInfo: { |
| | | droneEnumValue: 67, |
| | | droneSubEnumValue: 0, |
| | | }, |
| | | payloadInfo: { |
| | | payloadEnumValue: 52, |
| | | payloadSubEnumValue: 0, |
| | | payloadPositionIndex: 0, |
| | | }, |
| | | }, |
| | | Folder: { |
| | | templateId: 0, |
| | | executeHeightMode: 'WGS84', |
| | | waylineId: 0, |
| | | autoFlightSpeed: 10, |
| | | Placemark: [ |
| | | { |
| | | Point: { |
| | | coordinates: '0.000000, 0.000000', |
| | | }, |
| | | index: 0, |
| | | executeHeight: 116.57, |
| | | waypointSpeed: 10, |
| | | waypointHeadingParam: { |
| | | waypointHeadingMode: 'followWayline', |
| | | }, |
| | | waypointTurnParam: { |
| | | waypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature', |
| | | waypointTurnDampingDist: 0, |
| | | }, |
| | | useStraightLine: 1, |
| | | actionGroup: [], |
| | | }, |
| | | ], |
| | | }, |
| | | }) |
| | | |
| | | // 点位参数 |
| | | const placemark: any = { |
| | |
| | | const useKmzTsa = () => { |
| | | const init = async (fileUrl: string, fileContent?: string) => { |
| | | const fileRes = await analyzeKmzFile(fileUrl) |
| | | kmzFile.value = fileRes.file |
| | | const kmzRes = await fileRes.content |
| | | kmzFile.value = fileRes.zip |
| | | const kmzRes = await fileRes.fileInfoObj['wpmz/template.kml'] |
| | | if (fileContent) { |
| | | kmlStr.value = fileContent |
| | | return false |
| | |
| | | kmlStr.value = kmzRes |
| | | return kmzRes |
| | | } |
| | | |
| | | const create = () => { |
| | | const nowTime = new Date().getTime() |
| | | const str = ` |
| | |
| | | ` |
| | | kmlStr.value = str |
| | | } |
| | | |
| | | // const write = (settingParmas: any = {}, name: string) => { |
| | | // } |
| | | const writePoint = (settingParmas: any = {}, place: string, pointNumber: number = 0) => { |
| | | Object.keys(settingParmas).forEach((key: string) => { |
| | | placemark[key] = settingParmas[key] |
| | |
| | | }) |
| | | } |
| | | } |
| | | |
| | | const del = () => {} |
| | | |
| | | const edit = (settingParmas: any = {}, keyName?: string, isKeyWpml: boolean = false) => { |
| | | Object.keys(settingParmas).forEach((key: string) => { |
| | | const regxVal: any = getKmlParams(kmlStr.value, true, { |
| | |
| | | // 文件中的海拔高度 |
| | | const takeOffRefPointAGLHeightRegxStr = getKmlParams(kmlStr.value, true, { |
| | | name: 'takeOffRefPointAGLHeight', |
| | | findRegx: '([\\s\\S]*?)' |
| | | findRegx: '([\\s\\S]*?)', |
| | | }) || ['', '0'] |
| | | const posterHeight = Number(takeOffRefPointAGLHeightRegxStr[1]) |
| | | // 获取每个点是否使用全局高度 |
| | |
| | | name: 'height', |
| | | findRegx: '([\\s\\S]*?)', |
| | | }) |
| | | console.log(heightRegxVal) |
| | | } |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | const save = () => { |
| | | JsZip.file('wpmz/template.kml', kmlStr.value) |
| | | kmzFile.value.file('wpmz/template.kml', kmlStr.value) |
| | | JsZip.generateAsync({ type: 'blob' }).then((content) => { |
| | | saveAs(content, '新建航线-' + new Date().toLocaleString() + '.kmz') |
| | | }) |
| | | console.log('存在问题') |
| | | } |
| | | |
| | | return { |
| | |
| | | create, |
| | | // write, |
| | | writePoint, |
| | | del, |
| | | edit, |
| | | save, |
| | | } |
| | |
| | | kmlRes = kmlStr |
| | | } else { |
| | | const fileRes = await analyzeKmzFile(fileUrl) |
| | | kmlRes = await fileRes.content |
| | | kmlRes = await fileRes.fileInfoObj['wpmz/template.kml'] |
| | | } |
| | | // 所有航点 |
| | | kmlPoints = getKmlParams(kmlRes, false, { |
| | |
| | | kmlRes = kmlStr |
| | | } else { |
| | | const fileRes = await analyzeKmzFile(fileUrl) |
| | | kmlRes = await fileRes.content |
| | | kmlRes = await fileRes.fileInfoObj['wpmz/template.kml'] |
| | | } |
| | | // 所有航点 |
| | | const points = getKmlParams(kmlRes, false, { |