创建航点航线

main
徐景良 4 weeks ago
parent 9836661532
commit ab2124c654

@ -36,6 +36,8 @@ import {ref,watch,onMounted,defineEmits} from 'vue';
import airLineList from '../workplan/components/airLineList.vue';
import createAirLine from '../workplan/components/createAirLine.vue'
import importAirLine from '../workplan/components/importAirLine.vue'
import Map from '../workplan/components/map.vue'
import AirPolygon from './components/airPolygon.vue';
import {getAirLine} from '@/api/sys/workplan';
@ -47,10 +49,19 @@ import { XMLParser, XMLBuilder } from 'fast-xml-parser';
const emits = defineEmits(["updateAirLineLise"])
// add edit detail
//
const currentFolder = ref(null);
//
const setCurrentFolder = (folder)=>{
currentFolder.value = folder;
importAirLineShow.value = true;
}
// 线 add edit detail
const editMode = ref("add");
// airLine form
// 线
const airLineForm = ref({
"id": null,
"airLineName": null,
@ -74,197 +85,11 @@ const airLineForm = ref({
// "lineData":null,
});
// template.kml
const templateKmlConfig = ref({
"author": 17861857725,
"createTime": 1749689844431,
"updateTime": 1753241338101,
"missionConfig": {
"flyToWaylineMode": "pointToPoint",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"takeOffRefPoint": "",
"takeOffRefPointAGLHeight": 4.169064385,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"autoRerouteInfo": {
"transitionalAutoRerouteMode": 1,
"missionAutoRerouteMode": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 0,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateType": "mapping2d",
"templateId": 0,
"waylineCoordinateSysParam": {
"coordinateMode": "WGS84",
"heightMode": "EGM96",
"globalShootHeight": 90,
"surfaceFollowModeEnable": 1,
"isRealtimeSurfaceFollow": 0,
"surfaceRelativeHeight": 90,
"dsmFile": "wpmz/res/dsm/wgs84_ASTGTMV003_N35E118_dem_7.tif"
},
"autoFlightSpeed": 12.7,
"Placemark": {
"caliFlightEnable": 0,
"elevationOptimizeEnable": 1,
"smartObliqueEnable": 0,
"quickOrthoMappingEnable": 0,
"facadeWaylineEnable": 0,
"isLookAtSceneSet": 0,
"shootType": "time",
"direction": 83,
"margin": 0,
"efficiencyFlightModeEnable": 0,
"overlap": {
"orthoCameraOverlapH": 80,
"orthoCameraOverlapW": 70,
"inclinedCameraOverlapH": 80,
"inclinedCameraOverlapW": 70
},
"Polygon": {
"outerBoundaryIs": {
"LinearRing": {
"coordinates": "118.293794766158,35.1353688096117,0\n 118.295429169407,35.1353304409052,0\n 118.295487507293,35.1332925168381,0\n 118.293672196844,35.1331918267775,0"
}
}
},
"ellipsoidHeight": 90,
"height": 90
},
"payloadParam": {
"payloadPositionIndex": 0,
"focusMode": "firstPoint",
"meteringMode": "average",
"returnMode": "singleReturnStrongest",
"samplingRate": 240000,
"scanningMode": "repetitive",
"imageFormat": "visable",
"photoSize": ""
}
}
})
// wayline.wpml
const waylineWpmlConfig = ref({
"missionConfig": {
"flyToWaylineMode": "pointToPoint",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"autoRerouteInfo": {
"transitionalAutoRerouteMode": 1,
"missionAutoRerouteMode": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 0,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateId": 0,
"executeHeightMode": "WGS84",
"waylineId": 0,
"distance": 1259.17163085938,
"duration": 145.652896165848,
"autoFlightSpeed": 12.7,
"startActionGroup": {
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -90,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 1,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 1,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 0.5
}
},
{
"actionId": 2,
"actionActuatorFunc": "setFocusType",
"actionActuatorFuncParam": {
"cameraFocusType": "manual",
"payloadPositionIndex": 0
}
},
{
"actionId": 3,
"actionActuatorFunc": "focus",
"actionActuatorFuncParam": {
"focusX": 0,
"focusY": 0,
"focusRegionWidth": 0,
"focusRegionHeight": 0,
"isPointFocus": 0,
"isInfiniteFocus": 1,
"payloadPositionIndex": 0,
"isCalibrationFocus": 0
}
},
{
"actionId": 4,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 1
}
}
]
},
"Placemark": []
}
})
//
const currentFolder = ref(null);
//
const setCurrentFolder = (folder)=>{
currentFolder.value = folder;
importAirLineShow.value = true;
}
// 线template.kml
const templateKmlConfig = ref({})
const flyToTherePosition = ref({
lng:null,
lat:null,
alt:null,
})
// 线wayline.wpml
const waylineWpmlConfig = ref({})
const flyToThere = (e)=>{
@ -278,22 +103,6 @@ const aircraftShow = ref(false);
const createAirLineShow = ref(false);
const importAirLineShow = ref(false);
const selectAriLine = ()=> {
ariLineShow.value = true;
aircraftShow.value = false;
}
const selectAircraft = ()=>{
aircraftShow.value = true;
ariLineShow.value = false;
}
const cancleCraete = ()=>{
workPlanFormShow.value = false;
ariLineShow.value = false;
aircraftShow.value = false;
planListShow.value = true;
}
const checkedAriLine = ref({});
@ -306,23 +115,11 @@ const checkAriLine = (item)=>{
const checkedDronePort = ref({});
const checkDronePort = (item)=>{
if(item){
aircraftShow.value = false;
checkedDronePort.value = item;
}
}
const formData = ref(null);
const toCreateWorkPlan = (data)=> {
formData.value = data;
planListShow.value = false;
workPlanFormShow.value = true;
}
// 线
const globalFolder = ref(null);
const handlerCreateAirLine = (folder)=>{
globalFolder.value = folder;
createAirLineShow.value = true;
@ -337,21 +134,33 @@ const cancleImportAirLine = ()=>{
importAirLineShow.value = false;
}
const handlerCreateAirLineForm = (form)=>{
// 线
const handlerCreateAirLineForm =async (form)=>{
console.log("form",form);
// 线template.kmlwayline.wpml
if(form.airLineType == 'waypoint'){
const {templateKml,waylineWpml} = await import("../workplan/waylineConfig/waypointConfig");
templateKmlConfig.value = templateKml;
waylineWpmlConfig.value = waylineWpml;
}else if(form.airLineType == 'mapping2d'){
const {templateKml,waylineWpml} = await import("../workplan/waylineConfig/mapping2dConfig");
templateKmlConfig.value = templateKml;
waylineWpmlConfig.value = waylineWpml;
}
console.log("templateKmlConfig999",templateKmlConfig.value);
//
workPlanFormShow.value = false;
ariLineShow.value = false;
aircraftShow.value = false;
planListShow.value = false;
createAirLineShow.value = false;
// 线
airLineForm.value = form
airLineForm.value.folder = globalFolder.value;
console.log("airLineFor121m",airLineForm.value);
// 线
airLineForm.value = form
//
airLineForm.value.folder = globalFolder.value ? globalFolder.value : "";
}
const successCreatePlan = ()=>{
@ -370,8 +179,6 @@ const exitDraw = ()=>{
}
// 线
const wayline = ref({});
const waylineInfo = ref(null)
@ -400,7 +207,6 @@ const planDetail =async (item) => {
// wpml
const currentPreviewWayLine = ref(null);
const airLineDetail =async (item) => {
@ -441,10 +247,8 @@ const extractKmz = async (kmzBlob)=>{
}
onMounted(()=>{
let element = window.document.getElementsByClassName("mars3d-locationbar")[0] as HTMLElement;
element.style.bottom = '40px';
let element = window.document.getElementsByClassName("mars3d-locationbar")[0] as HTMLElement;
element.style.bottom = '40px';
})
@ -483,6 +287,7 @@ const importSuccess = () => {
airLineListRef.value.getAirList();
importAirLineShow.value = false;
}
</script>
<style scoped>
.map-out-container{

@ -2,7 +2,11 @@
<div class="params-item">
<div class="params-label">俯仰角度</div>
<div class="params-value">
<a-slider v-model:value="props.params.gimbalPitchRotateAngle" :min="-180" :max="180" :step="0.01" />
<a-slider
v-model:value="props.params.gimbalPitchRotateAngle"
:min="-90" :max="30" :step="0.01"
@change="paramChagne"
/>
</div>
<div class="params-value-text">
{{ props.params.gimbalPitchRotateAngle }} °
@ -14,13 +18,16 @@
import {defineProps,defineComponent,defineOptions} from 'vue';
const props = defineProps(["params"])
const props = defineProps(["params","info"])
const emits = defineEmits(["paramChagne"])
defineComponent({
name: 'gimbalRotate'
})
const paramChagne = ()=> {
emits("paramChagne",props.info);
}
</script>

@ -4,6 +4,7 @@
<div class="params-value">
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
</div>
<div class="params-unit"></div>
</div>
</template>
@ -35,6 +36,10 @@ defineComponent({
flex:1;
}
.params-item .params-unit{
line-height:30px;
padding:0px 5px 0px 15px;
}
::v-deep .ant-input-number{
color:#fff!important;

@ -0,0 +1,55 @@
<template>
<div class="params-item">
<div class="params-label">间隔时间</div>
<div class="params-value">
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
</div>
<div class="params-unit"></div>
</div>
</template>
<script lang="ts" setup>
import {defineProps,defineComponent,defineOptions} from 'vue';
const props = defineProps(["params"])
defineComponent({
name: 'multipleTiming'
})
</script>
<style scoped>
.params-item{
width:100%;
display: flex;
gap:20px;
}
.params-item .params-label{
line-height:30px;
}
.params-item .params-value{
flex:1;
}
.params-item .params-unit{
line-height:30px;
padding:0px 5px 0px 15px;
}
::v-deep .ant-input-number{
color:#fff!important;
background:#3F4150!important;
border:0px !important;
}
::v-deep .ant-input-number-input{
color:#fff!important;
border:0px !important;
}
</style>

@ -1,8 +1,11 @@
<template>
<div class="params-item">
<div class="params-label">偏航角度</div>
<div class="params-label">偏航角度</div>
<div class="params-value">
<a-slider v-model:value="props.params.aircraftHeading" :min="-180" :max="180" :step="0.01" />
<a-slider
v-model:value="props.params.aircraftHeading"
:min="-180" :max="180" :step="0.01"
@change="paramChagne" />
</div>
<div class="params-value-text">
{{ props.params.aircraftHeading }} °
@ -12,16 +15,20 @@
<script lang="ts" setup>
import {defineProps,defineComponent,defineOptions} from 'vue';
const props = defineProps(["params"])
import {defineProps,defineComponent,defineEmits} from 'vue';
const props = defineProps(["params","info"])
const emits = defineEmits(["paramChagne"])
defineComponent({
name: 'rotateYaw'
})
const paramChagne = ()=> {
emits("paramChagne",props.info);
}
</script>
<style scoped>

@ -153,7 +153,9 @@
</div>
</div>
<div class="pagenation">
<a-pagination v-model:current="pageQuery.page" :total="ariLineCount" show-less-items @change="onPageChange" />
<a-pagination size="small" v-model:current="pageQuery.page"
v-model:page-size="pageQuery.limit" :total="ariLineCount"
:defaultPageSize="10" show-less-items show-size-changer @change="onPageChange" />
</div>
</div>
</div>
@ -245,7 +247,7 @@
const props = defineProps(["title"])
import {templateTypeOptions} from '../waylineConfig/index';
import {templateTypeOptions} from '../waylineConfig/waylineParamsOptions';
import JSZip from 'jszip';
import axios from 'axios';

@ -2,18 +2,16 @@
<div class="container">
<div class="title">
<LeftOutlined @click="backPage" />
<div>航点航线</div>
<SaveOutlined @click="saveAirLine"/>
<div style="flex:1;">
<a-input v-model:value="props.airLineForm.airLineName" size="middle" placeholder="航线名称" />
</div>
<a-button type="primary" size="middle" @click="areaOptionsShow = !areaOptionsShow">
航线设置
<ControlOutlined />
</a-button>
<div style="flex:1;">
<a-input v-model:value="props.airLineForm.airLineName" size="middle" placeholder="航线名称" />
</div>
<SaveOutlined @click="saveAirLine" style="font-size:20px;" />
</div>
<!-- 航线信息 -->
@ -165,7 +163,7 @@
<div class="item">
<div class="label">全局航线飞行速度</div>
<div class="content">
<a-input style="width:100px;" placeholder="" v-model:value="missionConfig.globalTransitionalSpeed"></a-input>
<a-input style="width:100px;" placeholder="" v-model:value="props.templateKmlConfig.Folder.autoFlightSpeed"></a-input>
</div>
<div class="unit"> m/s</div>
</div>
@ -343,12 +341,14 @@ import {ref,defineEmits,defineProps} from 'vue'
import { SaveOutlined,LeftOutlined,AppstoreOutlined,DownOutlined,ControlOutlined,InfoCircleOutlined} from '@ant-design/icons-vue';
//
import { airPointActions } from '../waylineConfig/action'
import { airPointActions } from '../waylineConfig/actionConfig'
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
import {uploadXmlFile,addAirLine} from '@/api/sys/workplan';
import {uploadXmlFile,addAirLine,editAirLine} from '@/api/sys/workplan';
import { Modal, message } from 'ant-design-vue';
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/index.ts';
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/waylineParamsOptions.ts';
import JSZip from "jszip";
import { saveAs } from "file-saver";
const emits = defineEmits(["setTakeOffPoint","checkPoint","exitDraw","addAction"])
@ -520,93 +520,11 @@ const pointInfo = ref({
//
const handlerPointInfo = ()=>{
if(props.airPoints?.length<=0){
message.warning("请添加航点!");
return null;
}
props.airPoints?.forEach((item,index)=>{
console.log("item123",item);
let point = {
"Point": {
"coordinates": item.lng+","+item.lat
},
"index": index,
"executeHeight": item.alt,
"waypointSpeed": 10,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline", //
"waypointHeadingAngle": item.aircraftHorizontalAngle, // [-180, 180] wpml:waypointHeadingModesmoothTransition
"waypointPoiPoint": "0.000000,0.000000,0.000000", // wpml:waypointHeadingModetowardPOI
"waypointHeadingAngleEnable": 0,
"waypointHeadingPathMode": "followBadArc", //
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": {
"actionGroupId": 0,
"actionGroupStartIndex": 0,
"actionGroupEndIndex": 0,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "rotateYaw",
"actionActuatorFuncParam": {
"aircraftHeading": 0,
"aircraftPathMode": "counterClockwise"
}
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "north",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": 0,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 0,
"payloadPositionIndex": 0
}
},
{
"actionId": 2,
"actionActuatorFunc": "zoom",
"actionActuatorFuncParam": {
"focalLength": 24,
"isUseFocalFactor": 0,
"payloadPositionIndex": 0
}
}
]
},
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": item.cameraVerticalAngle, // [-90, -30]
"waypointGimbalYawAngle": 0 //
},
"isRisky": 0,
"waypointWorkType": 0
}
folder.value.Placemark.push(point);
})
return true;
}
// waylines.json
@ -626,52 +544,194 @@ const waylinesJson = ref(
// 线
const saveAirLine = ()=>{
// template.json
handlerTemplateKml();
//
handlerWaylineWpml();
let handlerResult = handlerPointInfo();
if(handlerResult){
const builder = new XMLBuilder();
let lineData = {...waylinesJson.value}
// template missionConfig wayline
props.waylineWpmlConfig.missionConfig = JSON.parse(JSON.stringify(props.templateKmlConfig.missionConfig))
const builder = new XMLBuilder({
format: true, //
indentBy: " ", // 2 \t
suppressEmptyNode: true, //
});
// wpml template json
let templateJson = {kml:{Document:props.templateKmlConfig}}
let templateWpmlJson = handlerPrefixWpml(templateJson);
let templateXmlStr = builder.build(templateWpmlJson);
let templateXmlStrTemp = templateXmlStr.replace(/<\/?\d+>/g, "")
let templateXml = templateXmlStrTemp.replace("<kml>",`<?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.6">`)
// wpml wayline json
// delete props.waylineWpmlConfig.missionConfig.takeOffRefPoint
// delete props.waylineWpmlConfig.missionConfig.takeOffRefPointAGLHeight
// delete props.waylineWpmlConfig.missionConfig.autoRerouteInfo
let waylineJosn = {kml:{Document:props.waylineWpmlConfig}}
let waylienWpmlJson = handlerPrefixWpml(waylineJosn);
let waylineXmlStr = builder.build(waylienWpmlJson);
let waylineXmlStrTemp = waylineXmlStr.replace(/<\/?\d+>/g, "")
let waylineXml = waylineXmlStrTemp.replace("<kml>",`<?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.6">`)
//
handlerCreateFile(templateXml,waylineXml);
}
}
let obj = handlerPrefixWpml(lineData);
// template.json
const handlerTemplateKml = () => {
let xmlString = builder.build(obj);
//
handlerCreateOrUpdateTime();
let xmlString2 = xmlString.replace(/<\/?\d+>/g, "")
//
// handlerAirLineHeight();
let xmlString3 = xmlString2.replace("<kml>",`<?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.6">`)
console.log("xmlString3",xmlString3);
return null;
handlerCreateFile(xmlString3);
}
}
//
const handlerCreateOrUpdateTime = () => {
let date = new Date();
if(props.editModel == 'add'){
props.templateKmlConfig.createTime = date.getTime();
props.templateKmlConfig.updateTime = date.getTime();
}else if(props.editModel == 'edit'){
props.templateKmlConfig.updateTime = date.getTime();
}
}
// wmpl:
// wayline.json
const handlerWaylineWpml = () => {
//
props.waylineWpmlConfig.missionConfig = JSON.parse(JSON.stringify(props.templateKmlConfig.missionConfig));
//
handlerStatistics();
//
handelrAirPoint();
}
const handlerStatistics = () => {
}
//
const handelrAirPoint = () => {
props.airPoints?.forEach((item,index)=>{
let point = {
"Point": {
"coordinates": item.lng+","+item.lat
},
"index": index,
"executeHeight": 172.948304450636,
"waypointSpeed": props.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": 0,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 0,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
if(item.actions.length>0){
point.actionGroup = {
"actionGroupId": 0,
"actionGroupStartIndex": index,
"actionGroupEndIndex": index,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": []
};
item.actions.forEach((action,idx)=>{
let actor = action.config;
actor.actionId = idx
point.actionGroup.action.push(actor);
})
}
props.waylineWpmlConfig.Folder.Placemark.push(point);
props.templateKmlConfig.Folder.Placemark.push(point);
})
}
// wpml:
const handlerPrefixWpml = (obj) => {
for (const key in obj) {
//
if (typeof obj[key] === 'object' && obj[key] !== null) {
for (const key in obj) {
handlerPrefixWpml(obj[key]); //
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { //
const newAttrs = {};
for (const attrName in obj[key]) {
//
if (/^[a-z]/.test(attrName)) {
newAttrs[`wmpl:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
handlerPrefixWpml(obj[key]); //
const newAttrs = {};
for (const attrName in obj[key] ) {
//
if (/^[a-z]/.test(attrName) && attrName != 'outerBoundaryIs' && attrName != 'coordinates') {
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
}
}
obj[key] = newAttrs;
}else if(typeof obj[key] === 'object' && obj[key] !== null && Array.isArray(obj[key])){ //
handlerPrefixWpml(obj[key]); //
const newAttrs = [];
for (const attrName in obj[key]) {
//
if (/^[a-z]/.test(attrName)) {
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
}
}
obj[key] = newAttrs;
}
obj[key] = newAttrs;
}
}
return obj;
return obj;
}
@ -695,15 +755,35 @@ const submitForm = ref({
})
// xml线
const handlerCreateFile =async (content)=>{
const blob = new Blob([content], { type: 'wmpl/plain' });
const handlerCreateFile =async (templateXml,waylineXml)=>{
console.log("waylineXml",templateXml,waylineXml);
const blob =await convertXmlToKmz(templateXml,waylineXml);
// FormData
const formData = new FormData();
formData.append('xmlFile', blob);
let res = await uploadXmlFile(formData);
formData.append('xmlFile', blob,"航点航线.kmz");
let res = await uploadXmlFile(props.airLineForm.folder,formData);
if(res){
submitForm.value.wpml = res.path;
let addAirLineRes =await addAirLine(submitForm.value);
props.airLineForm.wpml = res.path;
// props.airLineForm.lineData = {type:2}
let addAirLineRes = null;
if(props.editModel == 'add'){
addAirLineRes =await addAirLine(props.airLineForm);
}else if(props.editModel == 'edit'){
addAirLineRes =await editAirLine(props.airLineForm);
}
if(addAirLineRes){
message.success("操作成功!");
backPage();
@ -715,6 +795,28 @@ const handlerCreateFile =async (content)=>{
}
}
// xmlwpmlkml
const convertXmlToKmz =async (templateXml,waylineXml)=>{
const zip = new JSZip();
// 1. "wmpz"
const wmpzFolder = zip.folder("wpmz");
// 2.
wmpzFolder.file("waylines.wpml", waylineXml);
wmpzFolder.file("template.kml", templateXml);
// 3. KMZ (ZIP)
const kmzBlob = await zip.generateAsync({ type: "blob" });
// 线
// saveAs(kmzBlob, "output.kmz");
return kmzBlob;
}
// 退
const backPage = ()=>{
@ -727,7 +829,6 @@ const addAirPointAction = (action) => {
//
emits("addAction",action);
if(action.value == ""){

@ -127,19 +127,23 @@
</div>
</div>
<div class="item-content">
<component :is="componentMap[item.value]" :params="item.config.actionActuatorFuncParam" :key="index"></component>
<component
:is="componentMap[item.value]"
:params="item.config.actionActuatorFuncParam"
:info="item"
:key="index"
@paramChagne="paramChagne"
></component>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref,defineProps,watch,shallowRef,defineAsyncComponent,defineOptions } from 'vue';
import {ref,defineProps,watch,shallowRef,defineAsyncComponent,defineOptions,defineEmits} from 'vue';
import { DeleteOutlined,LeftOutlined,RightOutlined } from '@ant-design/icons-vue'
@ -163,8 +167,11 @@ const componentMap = {
};
const props = defineProps(['currentAirPoint','airPoints'])
const emits = defineEmits(["paramChagne"])
const paramChagne = (info) => {
emits("paramChagne",info);
}
watch(
()=>props.currentAirPoint,

@ -250,7 +250,7 @@
<script lang="ts" setup>
import {ref,defineEmits,defineProps,watch} from 'vue'
import { SaveOutlined,LeftOutlined,InfoCircleOutlined } from '@ant-design/icons-vue';
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/index.ts';
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/waylineParamsOptions.ts';
import {uploadXmlFile,addAirLine,editAirLine} from '@/api/sys/workplan';
import { message } from 'ant-design-vue';
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
@ -771,7 +771,6 @@ const handlerPrefixWpml = (obj) => {
//
if (/^[a-z]/.test(attrName) && attrName != 'outerBoundaryIs' && attrName != 'coordinates') {
console.log("attrName",attrName);
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
@ -814,7 +813,7 @@ const handlerCreateFile =async (templateXml,waylineXml)=>{
formData.append('xmlFile', blob,"面状航线.kmz");
let res = await uploadXmlFile("默认文件夹/面状航线",formData);
let res = await uploadXmlFile(props.airLineForm.folder,formData);
if(res){
props.airLineForm.wpml = res.path;

@ -33,7 +33,7 @@
</div>
</a-form-item> -->
<a-form-item ref="workspaceId" label="选择项目" name="workspaceId">
<!-- <a-form-item ref="workspaceId" label="选择项目" name="workspaceId">
<div class="">
<a-select
v-model:value="submitForm.workspaceId"
@ -46,7 +46,7 @@
</a-select>
</div>
</a-form-item>
</a-form-item> -->
<a-form-item ref="name" label="选择航线" name="name">

@ -44,6 +44,7 @@
<airPointConfig
:currentAirPoint="currentAirPoint"
:airPoints="airPoints"
@paramChagne="paramChagne"
></airPointConfig>
</div>
@ -65,7 +66,6 @@
import airPolygon from './airPolygon.vue';
import airPointConfig from './airPointConfig.vue';
// const props = defineProps([
// 'airLineForm',
// 'flyToTherePosition',
@ -295,12 +295,11 @@
watch(
() => props.waylineInfo,
(newVal,oldVal) => {
}
)
// 线
const generatePreviewPoint = (placemark)=>{
@ -357,24 +356,30 @@ const generatePreviewPoint = (placemark)=>{
let moveTool: mars3d.thing.MatrixMove2;
//
watch(
currentAirPoint,
(newVal, oldVal) => {
//
updateAirPoint(newVal);
//
handlerDrawCamera(newVal);
},
{ deep: true },
);
// watch(
// currentAirPoint,
// (newVal, oldVal) => {
// // console.log("newVal123",newVal);
// //
// // updateAirPoint(newVal);
// //
// // handlerDrawCamera(newVal);
// },
// { deep: true },
// );
const clickPoint = (id) => {
airPoints.value?.forEach((item, index) => {
if (item.id == id) {
currentAirPoint.value = item;
//
handlerDrawCamera(currentAirPoint.value);
airPointConfigShow.value = true;
}
});
};
const checkPoint = (e) => {
@ -685,7 +690,6 @@ const initMap = () => {
// 线
graphicLayer.on(mars3d.EventType.click, (e) => {
//
clickPoint(e.graphic.options.id);
});
@ -1574,7 +1578,8 @@ const handlerDrawLine = () => {
// let lineString = turf.lineString(positions);
// lineInfo.value.length = turf.length(lineString).toFixed(2);
};
//
const uavPoints = ref([]);
//
@ -1583,40 +1588,32 @@ const handlerDrawPoint = (e) => {
moveTool.destroy();
moveTool = null;
}
// 线
let position = mars3d.LngLatPoint.fromCartesian(e.position);
let uuid = buildUUID();
// 线
let globalHeight = props.templateKmlConfig.Folder.globalHeight;
//
let uavAngleGraphic = new mars3d.graphic.ModelEntity({
id:uuid,
name: "航向",
position: [position._lng, position._lat, position._alt],
position: [position._lng, position._lat, globalHeight],
style: {
url: "/map/uav-angle.gltf",
scale: 0.1,
heading: 90,
heading:90,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 0,
distanceDisplayPoint: {
color: "#00ff00",
pixelSize: 8
},
label: {
text: "",
font_size: 18,
color: "#ffffff",
pixelOffsetY: -50,
distanceDisplayCondition: true,
distanceDisplayCondition_far: 10000,
distanceDisplayCondition_near: 0
}
},
attr: { remark: "示例1" }
}
})
graphicLayer.addGraphic(uavAngleGraphic)
//
let stickGraphic = new mars3d.graphic.PointEntity({
id: 'stick' + uuid,
@ -1631,13 +1628,13 @@ const handlerDrawPoint = (e) => {
},
});
stickGroundPointLayer.addGraphic(stickGraphic);
// 线
let lineGraphic = new mars3d.graphic.PolylineEntity({
id: 'line' + uuid,
positions: [
[position._lng, position._lat, position._alt],
[position._lng, position._lat, 0],
[position._lng, position._lat, globalHeight],
[position._lng, position._lat, 0],
],
style: {
color: '#f5f5f5',
@ -1645,34 +1642,83 @@ const handlerDrawPoint = (e) => {
},
});
lineGroundPointLayer.addGraphic(lineGraphic);
//
let airPointInfo = {
id: uuid,
name: '航点',
lng: position._lng,
lat: position._lat,
alt: position._alt,
alt: globalHeight,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 2,
actions:[],
actions:[
{ //
"name":"飞行器偏航角",
"value":"rotateYaw",
"type":"action",
"config":{
"actionId": null,
"actionActuatorFunc": "rotateYaw",
"actionActuatorFuncParam": {
"aircraftHeading": 0,
"aircraftPathMode": "counterClockwise"
}
},
},{ //
"name":"云台俯仰角",
"value":"gimbalRotate",
"type":"action",
"config":{
"actionId": 3,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "north",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": 0,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 0,
"payloadPositionIndex": 0
}
}
},{ //
"name":"相机焦距",
"value":"zoom",
"type":"action",
"config":{
"actionId": null,
"actionActuatorFunc": "zoom",
"actionActuatorFuncParam": {
"focalLength": 24,
"isUseFocalFactor": 0,
"payloadPositionIndex": 0
}
}
}
],
};
airPoints.value?.push(airPointInfo);
uavPoints.value.push(graphic);
//
currentAirPoint.value = airPoints.value[airPoints.value?.length - 1];
//
handlerDrawCamera(airPointInfo);
// 线
handlerDrawLine();
};
//
const handlerDrawCamera = (e) => {
//
const graphic = graphicLayer.getGraphicById("cameraGraphic");
if(graphic){ //
@ -1691,8 +1737,8 @@ const handlerDrawCamera = (e) => {
topSteps: 2,
flat: true,
cameraHpr: true,
heading:e.aircraftHorizontalAngle,
pitch: e.cameraVerticalAngle+90, // 0 - 360
heading:e.aircraftHorizontalAngle - 90, //
pitch: e.cameraVerticalAngle - 90, // 0 - 360
roll: 0,
}
})
@ -1711,8 +1757,8 @@ const handlerDrawCamera = (e) => {
topShow: true,
topSteps: 2,
cameraHpr: true,
heading:e.aircraftHorizontalAngle,
pitch: e.cameraVerticalAngle+90, // 0 - 360
heading:e.aircraftHorizontalAngle - 90,
pitch: e.cameraVerticalAngle - 90, // 0 - 360
roll: 0,
}
})
@ -1732,24 +1778,14 @@ const updateAirPoint = (e) => {
style: {
url: "/map/uav-angle.gltf",
scale: 0.1,
heading: e.aircraftHorizontalAngle,
heading: e.aircraftHorizontalAngle + 90,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 0,
distanceDisplayPoint: {
color: "#00ff00",
pixelSize: 8
},
label: {
text: "",
font_size: 18,
color: "#ffffff",
pixelOffsetY: -50,
distanceDisplayCondition: true,
distanceDisplayCondition_far: 10000,
distanceDisplayCondition_near: 0
}
},
attr: { remark: "示例1" }
}
}
);
}
@ -1815,27 +1851,73 @@ const updateAirPoint = (e) => {
handlerDrawLine();
};
//
const paramChagne = (info) => {
console.log("info1232",info);
//
if(info.value == 'rotateYaw'){ //
//
currentAirPoint.value.aircraftHorizontalAngle = info.config.actionActuatorFuncParam.aircraftHeading;
//
handlerDrawCamera(currentAirPoint.value);
//
updateAirPoint(currentAirPoint.value);
}
if(info.value == "gimbalRotate"){ //
//
currentAirPoint.value.cameraVerticalAngle = info.config.actionActuatorFuncParam.gimbalPitchRotateAngle
//
handlerDrawCamera(currentAirPoint.value);
}
}
//
const updateCamera = () => {
}
//
const deleteAirPoint = (e) => {
let id = e.graphic.id;
//
let point = graphicLayer.getGraphicById(id);
if (point) {
graphicLayer.removeGraphic(point);
let uavModel = graphicLayer.getGraphicById(id);
if (uavModel) {
graphicLayer.removeGraphic(uavModel);
}
//
let camera = graphicLayer.getGraphicById('camera' + id);
let camera = graphicLayer.getGraphicById("cameraGraphic");
if (camera) {
graphicLayer.removeGraphic(camera);
graphicLayer.removeGraphic(camera);
}
//
let point = lineGroundPointLayer.getGraphicById("line"+id);
if (point) {
lineGroundPointLayer.removeGraphic(point);
}
// 线
let line = stickGroundPointLayer.getGraphicById("stick"+id);
if (line) {
stickGroundPointLayer.removeGraphic(line);
}
//
airPoints.value?.forEach((item, index) => {
if (item.id == id) {
airPoints.value?.splice(index, 1);
}
if (item.id == id) {
airPoints.value?.splice(index, 1);
}
});
// 线
@ -2404,11 +2486,9 @@ const setUAVPosition = () => {
///////////////////////////////////////////////////////////////////////
const addAction = (action) => {
//
console.log("action",action);
currentAirPoint.value.actions.push(action);
console.log("currentAirPoint",currentAirPoint.value)
currentAirPoint.value.actions.push(JSON.parse(JSON.stringify(action)));
}

@ -0,0 +1,55 @@
<template>
<div class="params-item">
<div class="params-label">间隔距离</div>
<div class="params-value">
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
</div>
<div class="params-unit"></div>
</div>
</template>
<script lang="ts" setup>
import {defineProps,defineComponent,defineOptions} from 'vue';
const props = defineProps(["params"])
defineComponent({
name: 'multipleDistance'
})
</script>
<style scoped>
.params-item{
width:100%;
display: flex;
gap:20px;
}
.params-item .params-label{
line-height:30px;
}
.params-item .params-value{
flex:1;
}
.params-item .params-unit{
line-height:30px;
padding:0px 5px 0px 15px;
}
::v-deep .ant-input-number{
color:#fff!important;
background:#3F4150!important;
border:0px !important;
}
::v-deep .ant-input-number-input{
color:#fff!important;
border:0px !important;
}
</style>

@ -225,14 +225,12 @@
}
]
)
const onPageChange = (e)=>{
pageQuery.value.page = e;
getTaskList();
}
//
const planStatusOptions = ref([
{

@ -16,11 +16,10 @@ export const calculateHeight = (gsd,uavModel) => {
// 飞行高度= GSD(cm)×实际焦距(mm)/像元尺寸(um)
let abc = (gsd * uavModel['focalLength'] / uavModel['pixelLength']);
height = (gsd * uavModel['focalLength'] / uavModel['pixelLength']);
console.log("abc",abc);
height = ( (gsd / 100) * (uavModel['focalLength'] / 1000) * uavModel['imageWidth'] ) / ( uavModel['sensorLength'] / 1000 );
// height = ( (gsd / 100) * (uavModel['focalLength'] / 1000) * uavModel['imageWidth'] ) / ( uavModel['sensorLength'] / 1000 );
return height.toFixed(2);
}
@ -30,8 +29,16 @@ export const calculateHeight = (gsd,uavModel) => {
// 输入高度计算gsd
export const calculateGsd = (height,uavModel) => {
let gsd = 0;
gsd = ( (height*1000) * uavModel['sensorLength'] ) / (uavModel['focalLength'] * uavModel['imageWidth']) / 10;
gsd = (uavModel['pixelLength'] * height) / uavModel['focalLength'] ;
// gsd = ( (height*1000) * uavModel['sensorLength'] ) / (uavModel['focalLength'] * uavModel['imageWidth']) / 10;
return gsd.toFixed(2);
}

@ -25,7 +25,7 @@ export const airPointActions = {
"gimbalHeadingYawBase": "north",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -65.7,
"gimbalPitchRotateAngle": 0,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,

@ -0,0 +1,176 @@
// 面状航线默认template.kml数据
export const templateKml = {
"author": 17861857725,
"createTime": 1749689844431,
"updateTime": 1753241338101,
"missionConfig": {
"flyToWaylineMode": "pointToPoint",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"takeOffRefPoint": "",
"takeOffRefPointAGLHeight": 4.169064385,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"autoRerouteInfo": {
"transitionalAutoRerouteMode": 1,
"missionAutoRerouteMode": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 0,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateType": "mapping2d",
"templateId": 0,
"waylineCoordinateSysParam": {
"coordinateMode": "WGS84",
"heightMode": "EGM96",
"globalShootHeight": 90,
"surfaceFollowModeEnable": 1,
"isRealtimeSurfaceFollow": 0,
"surfaceRelativeHeight": 90,
"dsmFile": "wpmz/res/dsm/wgs84_ASTGTMV003_N35E118_dem_7.tif"
},
"autoFlightSpeed": 12.7,
"Placemark": {
"caliFlightEnable": 0,
"elevationOptimizeEnable": 1,
"smartObliqueEnable": 0,
"quickOrthoMappingEnable": 0,
"facadeWaylineEnable": 0,
"isLookAtSceneSet": 0,
"shootType": "time",
"direction": 83,
"margin": 0,
"efficiencyFlightModeEnable": 0,
"overlap": {
"orthoCameraOverlapH": 80,
"orthoCameraOverlapW": 70,
"inclinedCameraOverlapH": 80,
"inclinedCameraOverlapW": 70
},
"Polygon": {
"outerBoundaryIs": {
"LinearRing": {
"coordinates": "118.293794766158,35.1353688096117,0\n 118.295429169407,35.1353304409052,0\n 118.295487507293,35.1332925168381,0\n 118.293672196844,35.1331918267775,0"
}
}
},
"ellipsoidHeight": 90,
"height": 90
},
"payloadParam": {
"payloadPositionIndex": 0,
"focusMode": "firstPoint",
"meteringMode": "average",
"returnMode": "singleReturnStrongest",
"samplingRate": 240000,
"scanningMode": "repetitive",
"imageFormat": "visable",
"photoSize": ""
}
}
}
// 面状航线默认wayline.wpml数据
export const waylineWpml = {
"missionConfig": {
"flyToWaylineMode": "pointToPoint",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"autoRerouteInfo": {
"transitionalAutoRerouteMode": 1,
"missionAutoRerouteMode": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 0,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateId": 0,
"executeHeightMode": "WGS84",
"waylineId": 0,
"distance": 1259.17163085938,
"duration": 145.652896165848,
"autoFlightSpeed": 12.7,
"startActionGroup": {
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -90,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 1,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 1,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 0.5
}
},
{
"actionId": 2,
"actionActuatorFunc": "setFocusType",
"actionActuatorFuncParam": {
"cameraFocusType": "manual",
"payloadPositionIndex": 0
}
},
{
"actionId": 3,
"actionActuatorFunc": "focus",
"actionActuatorFuncParam": {
"focusX": 0,
"focusY": 0,
"focusRegionWidth": 0,
"focusRegionHeight": 0,
"isPointFocus": 0,
"isInfiniteFocus": 1,
"payloadPositionIndex": 0,
"isCalibrationFocus": 0
}
},
{
"actionId": 4,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 1
}
}
]
},
"Placemark": []
}
}

@ -97,6 +97,18 @@ export const missionConfigOptions = {
label:"悬停",
value:"hover"
}
],
globalWaypointTurnMode:[
{
label:"不过点,提前转弯",
value:"coordinateTurn"
},{
label:"直线飞行,到点停",
value:"toPointAndStopWithDiscontinuityCurvature"
},{
label:"平滑过点,提前转弯",
value:"toPointAndStopWithContinuityCurvature"
}
]
}

@ -0,0 +1,92 @@
// 航点航线默认template.kml数据
export const templateKml = {
"author": 17861857725,
"createTime": 1753927747220,
"updateTime": 1753928575789,
"missionConfig": {
"flyToWaylineMode": "safely",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"takeOffRefPoint": "35.134614,118.296656,77.867669",
"takeOffRefPointAGLHeight": 0,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 2,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateType": "waypoint",
"templateId": 0,
"waylineCoordinateSysParam": {
"coordinateMode": "WGS84",
"heightMode": "EGM96"
},
"autoFlightSpeed": 10,
"globalHeight": 124,
"caliFlightEnable": 0,
"gimbalPitchMode": "manual",
"globalWaypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": 0,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"globalWaypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"globalUseStraightLine": 1,
"Placemark": [],
"payloadParam": {
"payloadPositionIndex": 0,
"focusMode": "firstPoint",
"meteringMode": "average",
"returnMode": "singleReturnStrongest",
"samplingRate": 240000,
"scanningMode": "repetitive",
"imageFormat": "visable,ir",
"photoSize": ""
}
}
}
// 航点航线默认wayline.wpml数据
export const waylineWpml = {
"missionConfig": {
"flyToWaylineMode": "safely",
"finishAction": "goHome",
"exitOnRCLost": "goContinue",
"executeRCLostAction": "goBack",
"takeOffSecurityHeight": 20,
"globalTransitionalSpeed": 15,
"globalRTHHeight": 100,
"droneInfo": {
"droneEnumValue": 100,
"droneSubEnumValue": 1
},
"waylineAvoidLimitAreaMode": 0,
"payloadInfo": {
"payloadEnumValue": 99,
"payloadSubEnumValue": 2,
"payloadPositionIndex": 0
}
},
"Folder": {
"templateId": 0,
"executeHeightMode": "WGS84",
"waylineId": 0,
"distance": 4453.73876953125,
"duration": 636.023902893066,
"autoFlightSpeed": 10,
"Placemark": []
}
}
Loading…
Cancel
Save