You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3166 lines
87 KiB
Vue

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<!-- 地图 -->
<div ref="vChartRef " :id="'mars3d-container_' + mapId" class="mars3d-container">
<!-- 航点航线 -->
<div
v-if="props.airLineForm.airLineType == 'waypoint'"
v-show="props.editMode != 'detail'"
class="air-container"
>
<airPoint
:airInfo="lineInfo"
:editModel="props.editMode"
:polygonAirForm="polygonAirForm"
:airLineForm="props.airLineForm"
:wayline="props.wayline"
:airPoints="airPoints"
:waylineInfo="props.waylineInfo"
:templateKmlConfig="props.templateKmlConfig"
:waylineWpmlConfig="props.waylineWpmlConfig"
@setTakeOffPoint="setTakeOffPoint"
@exitDraw="exitDraw"
@addAction="addAction"
@checkPoint="checkPoint"
></airPoint>
</div>
<!-- 航面航线 -->
<div v-if="props.airLineForm.airLineType == 'mapping2d'" v-show="props.editMode != 'detail'" class="airpolygon-container">
<airPolygon
:airInfo="airInfo"
:editModel="props.editMode"
:polygonAirForm="polygonAirForm"
:airLineForm="props.airLineForm"
:waylineInfo="props.waylineInfo"
:airPoints="airPoints"
:polygon="polygonGeoJson"
:templateKmlConfig="props.templateKmlConfig"
:waylineWpmlConfig="props.waylineWpmlConfig"
@setTakeOffPoint="setTakeOffPoint"
@calculatParamChange="calculatParamChange"
@exitDraw="exitDraw"
></airPolygon>
</div>
<!-- 航点航线配置 -->
<div class="airpoint-config-container" v-if="airPointConfigShow">
<airPointConfig
:currentAirPoint="currentAirPoint"
:airPoints="airPoints"
@paramChagne="paramChagne"
@pointChange="pointChange"
@positionChange="positionChange"
></airPointConfig>
</div>
<!-- 航线预览信息 -->
<div class="airline-preview-container" v-if="props.editMode == 'detail'">
<div class="info-item">
<div class="info-value">46461m²</div>
<div class="info-label">区域面积</div>
</div>
<div class="info-item">
<div class="info-value">46461m²</div>
<div class="info-label">航线长度</div>
</div>
<div class="info-item">
<div class="info-value">34分钟</div>
<div class="info-label">预计时间</div>
</div>
<div class="info-item">
<div class="info-value">78张</div>
<div class="info-label">照片数量</div>
</div>
<div class="info-item">
<div>
<a-button type="primary" danger size="small" @click="exitDraw">
<CloseOutlined />
</a-button>
</div>
<div>关闭</div>
</div>
</div>
<!-- 面绘制 -->
<div class="draw-polygon-patrol" title="绘制面区域" v-if="props.drawArea" @click="handlerDrawPolygonPatrol">
<EditOutlined />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineProps, watch, defineEmits, reactive } from 'vue';
import { message } from 'ant-design-vue';
import { CloseOutlined } from '@ant-design/icons-vue';
import { GeojsonToWkt, WktToGeojson } from '@/components/MapboxMaps/src/WktGeojsonTransform';
import { buildUUID } from '@/utils/uuid';
import airPoint from './airPoint.vue';
import * as mars3d from 'mars3d';
import { EventBus } from '@/utils/eventBus';
import { airPortStore } from '@/store/modules/airport';
import { airPointActions } from '../waylineConfig/actionConfig';
import 'mars3d-space';
import { EditOutlined } from '@ant-design/icons-vue';
import * as Cesium from 'mars3d-cesium';
// import * as turf from '@turf/turf';
import airPolygon from './airPolygon.vue';
import airPointConfig from './airPointConfig.vue';
import { uuid } from '@/utils/uuid';
// const props = defineProps([
// 'airLineForm',
// 'flyToTherePosition',
// 'wayline',
// 'waylineInfo',
// 'workPlanFormShow',
// 'airPort',
// 'uavTrack',
// 'homeAirport'
// ]);
const mapId = ref(uuid(6, 14));
const props = defineProps({
editMode: {
type: String,
default: 'add',
},
airLineForm: {
type: Object,
default: () => ({
id: null,
airLineName: null,
airLineType: null,
uavId: null,
flyToFirstPointMode: null,
safeTakeoffAltitude: 0,
safeTakeoffSpeed: 0,
globalRouteSpeed: 0,
taskCompletionAction: null,
outOfControlOption: null,
typeOfOutOfControlAction: null,
globalWayPointType: null,
ptzControlMode: null,
aircraftYawAngleMode: null,
createTime: null,
wpml: null,
taskOffLng: 0,
taskOffLat: 0,
folder: null,
}),
},
wayline: {
type: Object,
},
waylineInfo: {
type: Object,
default: () => ({
missionConfig: {
flyToWaylineMode: 'safely', // 爬升模式 safely pointToPoint
finishAction: 'goHome', // 航线结束动作
exitOnRCLost: 'executeLostAction', // 失控是否继续执行航线
executeRCLostAction: 'goBack', // 失控动作类型
takeOffSecurityHeight: 20, // 安全起飞高度
globalTransitionalSpeed: 15, // 全局航线过渡速度
globalRTHHeight: 100, // 全局返航高度
droneInfo: {
// 飞行器机型信息
droneEnumValue: 100,
droneSubEnumValue: 1,
},
autoRerouteInfo: {
// 航线绕行
transitionalAutoRerouteMode: 1,
missionAutoRerouteMode: 1,
},
waylineAvoidLimitAreaMode: 0,
payloadInfo: {
// 负载机型信息
payloadEnumValue: 99, // 负载机型主类型
payloadSubEnumValue: 2,
payloadPositionIndex: 0, // 负载挂载位置
},
},
Folder: {
templateId: 0,
executeHeightMode: 'WGS84',
waylineId: 0,
distance: 1391.755859375,
duration: 200.941531419754,
autoFlightSpeed: 8.2, // 全局航线飞行速度
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: [],
},
}),
},
workPlanFormShow: {
type: Boolean,
},
airPort: {
type: Object,
},
uavTrack: {
type: Object,
},
homeAirport: {
type: Object,
},
templateKmlConfig: {
type: Object,
},
waylineWpmlConfig: {
type: Object,
},
drawArea: {
type: Boolean,
default: false,
},
polygonArea: {
type: Object,
},
});
const centerObj = reactive({
lat: 260.9,
heading: 357.9,
pitch: -32,
});
watch(
() => props.editMode,
(newVal,oldVal)=>{
if(newVal == 'edit' || newVal == 'detail'){
if(props.airLineForm.airLineType == 'waypoint'){
handlerEditWaypointAirLine();
}else if(props.airLineForm.airLineType == 'mapping2d'){
handlerEditPolygonAirLine();
}
}
}
)
watch(
() => props.polygonArea,
(newVal, oldVal) => {
if (newVal) {
handlerReportPolygonAirLine();
}
},
);
watch(
() => props.uavTrack,
(val) => {
setUAVPosition();
},
{ deep: true },
);
watch(
() => props.airPort,
(val) => {
setAirportPosition();
},
{ deep: true },
);
watch(
() => props.homeAirport,
(val) => {
homeSetAirportPosition();
},
{ deep: true },
);
watch(
() => props.workPlanFormShow,
(newVal, oldVal) => {
if (!newVal) {
clearAllLayer();
}
},
);
// 航线表单
watch(
() => props.airLineForm,
(newVal, oldVal) => {
// 根据编辑模式更新地图右键菜单
handlerBindMapMenus();
},
{
deep: true,
},
);
// 航线文件
watch(
() => props.wayline,
(newVal, oldVal) => {
// generatePreviewPoint(newVal?.Folder?.Placemark);
},
);
watch(
() => props.waylineInfo,
(newVal, oldVal) => {},
);
// 航线预览:生成点
const generatePreviewPoint = (placemark) => {
// 设置默认起飞点
takeOffPointPosition.value = [props.airLineForm?.taskOffLng, props.airLineForm?.taskOffLat, 70];
// 先清空所有数据
clearAllLayer();
placemark?.forEach((item, index) => {
let coordinate = item.Point.coordinates.split(',');
let airPointInfo = {
id: item.index,
name: '航点',
lng: coordinate[0],
lat: coordinate[1],
alt: item.executeHeight,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 2,
};
airPoints.value?.push(airPointInfo);
});
if (props.airLineForm?.airLineType == 'waypoint') {
// 航点航线
airPoints.value?.forEach((item, index) => {
let drawPoint = {
_lng: item.lng,
_lat: item.lat,
_alt: item.alt,
};
preViewPointWayLine(drawPoint);
});
} else if (props.airLineForm?.airLineType == 'mapping2d') {
let coordinates = [];
airPoints.value?.forEach((item, index) => {
coordinates.push([item.lng, item.lat]);
});
let line = turf.lineString(coordinates);
preViewPolygonWayLine(line);
}
};
const emits = defineEmits([
'exitDraw',
'flyToThere',
'mapOnLoad',
'clickAirPort',
'changeAirportLive',
'changeUAVLive',
'areaData',
]);
const airPoints = ref([]);
const currentAirPoint = ref({});
const airPointConfigShow = ref(false);
// 全局平移工具
let moveTool: mars3d.thing.MatrixMove2;
// 监听航点变化
// 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) => {
currentAirPoint.value = e;
airPointConfigShow.value = true;
handlerDrawCamera(currentAirPoint.value);
};
///////////////////////////////图层中心////////////////////////////////////////////
let map: mars3d.Map; // 地图对象
let graphicLayer: mars3d.layer.GraphicLayer;
let uavGraphicLayer: mars3d.layer.GraphicLayer;
// 设置参考起飞点图层
let takeOffPointGraphicLayer: mars3d.layer.GraphicLayer;
// 测区面图层
let polygonGraphicLayer: mars3d.layer.GraphicLayer;
// 监测区域面图层
let patrolPolygonGraphicLayer: mars3d.layer.GraphicLayer;
// 面航线图层
let polygonLineGraphicLayer: mars3d.layer.GeoJsonLayer;
// 文本标注图层
let textLabelGraphicLayer: mars3d.layer.GraphicLayer;
// 航点地面投影点图层
let stickGroundPointLayer: mars3d.layer.GraphicLayer;
// 航点连接线
let lineGroundPointLayer: mars3d.layer.GraphicLayer;
// 飞行结果图片贴地点
let imageStickGroundPointLayer: mars3d.layer.GraphicLayer;
// 飞行结果图片连接线
let imageLineGroundPointLayer: mars3d.layer.GraphicLayer;
// 飞行结果图片
let imageResultPointLayer: mars3d.layer.GraphicLayer;
// 飞行结果选中图层照片
// 项目首页机场位置
let homeStartGraphic;
let homeStartGraphicLive;
let graphic = null;
// // 清空所有数据
const exitDraw = () => {
graphicLayer ? graphicLayer.clear() : null;
takeOffPointGraphicLayer ? takeOffPointGraphicLayer.clear() : null;
stickGroundPointLayer ? stickGroundPointLayer.clear() : null;
lineGroundPointLayer ? lineGroundPointLayer.clear() : null;
textLabelGraphicLayer ? textLabelGraphicLayer.clear() : null;
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
airPoints.value = [];
props.airLineForm.airLineType = null;
airPointConfigShow.value = false;
emits('exitDraw');
};
// 航点航线信息
const lineInfo = ref({
count: 0,
length: 0,
time: 0,
picture: '- -',
});
// 面航线信息
const airInfo = ref({
area: 0,
length: 0,
time: 0,
picture: '- -',
});
const polygonAirForm = ref({
startingPoint: null,
lensMode: 1,
gatherMode: 1,
heightMode: 1,
height: 120,
speed: 15,
angle: 0,
complete: 1,
});
const vChartRef = ref<HTMLElement>();
onMounted(() => {
if (props.drawArea) {
centerObj.lat = 835.9;
centerObj.heading = 2;
centerObj.pitch = -86;
}
initMap();
EventBus.on('closeTranslation', (val: any) => {
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
});
});
// center: { lat: 35.132103, lng: 118.296315, alt: 260.9, heading: 357.9, pitch: -32 },
// 初始化地图
const initMap = () => {
map = new mars3d.Map('mars3d-container_' + mapId.value, {
scene: {
center: {
lat: 35.132103,
lng: 118.296315,
alt: centerObj.lat,
heading: centerObj.heading,
pitch: centerObj.pitch,
},
scene3DOnly: false,
shadows: false,
removeDblClick: true,
sceneMode: 3,
showSun: true,
showMoon: true,
showSkyBox: true,
showSkyAtmosphere: true,
fog: true,
fxaa: true,
requestRenderMode: true,
contextOptions: {
requestWebgl1: false,
webgl: {
preserveDrawingBuffer: true,
alpha: false,
stencil: true,
powerPreference: 'high-performance',
},
},
globe: {
depthTestAgainstTerrain: true,
baseColor: '#546a53',
showGroundAtmosphere: true,
enableLighting: false,
},
cameraController: {
zoomFactor: 3,
minimumZoomDistance: 1,
maximumZoomDistance: 50000000,
enableRotate: true,
enableTranslate: true,
enableTilt: true,
enableZoom: true,
enableCollisionDetection: true,
minimumCollisionTerrainHeight: 15000,
},
},
control: {
homeButton: true,
baseLayerPicker: false,
sceneModePicker: true,
vrButton: false,
fullscreenButton: true,
navigationHelpButton: true,
animation: false,
timeline: false,
infoBox: false,
geocoder: false,
selectionIndicator: false,
showRenderLoopErrors: true,
contextmenu: {
hasDefault: true,
},
mouseDownView: true,
zoom: {
insertIndex: 1,
},
compass: {
bottom: 'toolbar',
left: '5px',
rotation: true,
},
distanceLegend: {
left: '10px',
bottom: '2px',
},
locationBar: {
crs: 'CGCS2000_GK_Zone_3',
crsDecimal: 0,
template:
"<div>经度:{lng}</div> <div>纬度:{lat}</div> <div class='hide1000'>横{crsx} 纵{crsy}</div> <div>海拔:{alt}米</div> <div class='hide700'>层级:{level}</div><div>方向:{heading}°</div> <div>俯仰角:{pitch}°</div><div class='hide700'>视高:{cameraHeight}米</div>",
cacheTime: 50,
},
},
method: {
templateValues: {
dataServer: '//data.mars3d.cn',
gltfServerUrl: '//data.mars3d.cn/gltf',
},
},
terrain: {
url: '//data.mars3d.cn/terrain',
show: true,
clip: true,
},
basemaps: [
{
id: 10,
name: '地图底图',
type: 'group',
},
{
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
zIndex: 20,
},
],
zIndex: 20,
show: true,
},
],
layers: [],
});
map.on(mars3d.EventType.load, function (event) {
// 地图右键菜单
handlerBindMapMenus();
graphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false, // 是否自动激活编辑
});
graphicLayer.bindContextMenu([
{
text: '按轴平移',
icon: 'fa fa-pencil',
callback: (event) => {
const graphic = event.graphic;
let id = event.graphic.options.id;
if (moveTool) {
return null;
}
// 按轴移动
moveTool = new mars3d.thing.MatrixMove2({
position: graphic.position,
});
map.addThing(moveTool);
moveTool.on(mars3d.EventType.change, (event) => {
graphic.position = event.position;
pointMove(event, id);
});
},
},
{
text: '停止平移',
icon: 'fa fa-pencil',
callback: (event) => {
const graphic = event.graphic;
if (moveTool) {
map.removeThing(moveTool);
moveTool.destroy();
moveTool = null;
}
},
},
{
text: '删除',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
deleteAirPoint(e);
},
},
]);
map.addLayer(graphicLayer);
// 参考起飞点图层
takeOffPointGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true,
});
takeOffPointGraphicLayer.on(mars3d.EventType.editMovePoint, function (event) {
takeOffPointMove(event);
});
map.addLayer(takeOffPointGraphicLayer);
// 航点地面投影点
stickGroundPointLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false, // 是否自动激活编辑
});
map.addLayer(stickGroundPointLayer);
// 航点连接线
lineGroundPointLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false, // 是否自动激活编辑
});
map.addLayer(lineGroundPointLayer);
// 绘制航线
graphicLayer.on(mars3d.EventType.click, (e) => {
// 设置当前选中点
clickPoint(e.graphic.options.id);
});
// 面测区图层
polygonGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true, // 是否自动激活编辑
});
// 监测面区域
patrolPolygonGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true, // 是否自动激活编辑
});
polygonGraphicLayer.bindContextMenu([
{
text: '删除测区',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
handlerClearPolygonGraphicLayer(e);
},
},
]);
patrolPolygonGraphicLayer.bindContextMenu([
{
text: '删除测区',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
handlerClearPolygonGraphicLayer(e);
},
},
]);
polygonGraphicLayer.on(mars3d.EventType.editMovePoint, (event) => {
onPolygonGraphicLayerEdit(event);
});
patrolPolygonGraphicLayer.on(mars3d.EventType.editMovePoint, (event) => {
console.log(event);
onPatrolPolygonGraphicLayerEdit(event);
});
map.addLayer(polygonGraphicLayer);
map.addLayer(patrolPolygonGraphicLayer);
// 绘制起点
// handlerDrawStartPoint();
if (props.airPort) {
setAirportPosition();
}
if (props.uavTrack) {
// setUAVPosition();
}
// 加载长光高清影像
// loadChangGuangLayer();
// 图层回显
if (props.editMode == 'edit' || props.editMode == 'detail') {
// 判断航线类型进行加载编辑
if (props.airLineForm.airLineType == 'waypoint') {
handlerEditWaypointAirLine();
} else if (props.airLineForm.airLineType == 'mapping2d') {
handlerEditPolygonAirLine();
}
}else if(props.editMode == 'autoAdd'){ // 自动航线规划
// handlerEditPolygonAirLine();
let geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[118.30155473, 35.13429214999999],
[118.30155473, 35.135213541900015],
[118.30068670230001, 35.135213541900015],
[118.30068670230001, 35.13429214999999],
[118.30155473, 35.13429214999999]
]
]
}
}
]
};
handlerDrawPolygon(geojson);
// console.log("templateKmlConfig123",props.templateKmlConfig)
}
// 监测面区域回显
if (props.polygonArea) {
handlerReportPolygonAirLine();
}
emits('mapOnLoad', map);
});
};
// 绑定地图右键菜单
const handlerBindMapMenus = () => {
let mapContextmenuItems = [];
if (props.airLineForm.airLineType == null) {
mapContextmenuItems = [
{
text: '飞行到此处',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
flyToThere(e);
},
},
];
} else if (props.airLineForm.airLineType == 'waypoint') {
mapContextmenuItems = [
{
text: '飞行到此处',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
flyToThere(e);
},
},
{
text: '添加航点',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
if (!takeOffPointPosition.value) {
message.warning('请先设置起飞点');
return null;
}
handlerDrawPoint(e);
},
},
];
} else if (props.airLineForm.airLineType == 'mapping2d') {
mapContextmenuItems = [
{
text: '飞行到此处',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
flyToThere(e);
},
},
{
text: '添加面区域',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
if (!polygonAirForm.value.startingPoint) {
message.warning('请先设置起飞点');
return null;
}
handlerDrawPolygon();
},
},
];
}
// if (props.drawArea) {
// mapContextmenuItems = [
// {
// text: '添加面区域',
// icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
// callback: (e) => {
// handlerDrawPolygonPatrol();
// },
// },
// ];
// }
map.bindContextMenu(mapContextmenuItems);
};
///////////////////////////////图层和影像加载////////////////////////////////////////////
// 加载长光卫星高分影像
const loadChangGuangLayer = () => {
var layer = new mars3d.layer.XyzLayer({
url: 'https://api.jl1mall.com/getMap/{z}/{x}/{reverseY}',
queryParameters: {
mk: '73ad26c4aa6957eef051ecc5a15308b4',
tk: '5538f710dfc641048a8bdf1a7f705cd1',
pro: '9297426cbe4c4ac2a01ca228a4ad30f7',
vf: 0,
},
minimumLevel: 1,
maximumLevel: 18,
zIndex: 2,
});
map.addLayer(layer);
};
///////////////////////////////飞行结果加载//////////////////////////////////////////
///////////////////////////////参考起飞点////////////////////////////////////////////
// 全局参考起飞点 数据格式:[lng,lat,alt]
const takeOffPointPosition = ref(null);
// 设置起飞点
const setTakeOffPoint = async () => {
takeOffPointGraphicLayer ? takeOffPointGraphicLayer.clear() : null;
const graphic = await takeOffPointGraphicLayer.startDraw({
type: 'billboardP',
style: {
image: '/map/start.png',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '参考起飞点',
font_size: 16,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -50,
},
},
});
takeOffPointPosition.value = graphic.toJSON().position;
props.templateKmlConfig.missionConfig.takeOffRefPoint =
takeOffPointPosition.value[1] +
',' +
takeOffPointPosition.value[0] +
',' +
takeOffPointPosition.value[2];
polygonAirForm.value.startingPoint = graphic.toJSON().position;
// 设置表单数据
props.airLineForm.taskOffLng = takeOffPointPosition.value[0];
props.airLineForm.taskOffLat = takeOffPointPosition.value[1];
// 更新航线
updatePolygonLineByParams();
};
// 参考起飞点移动
const takeOffPointMove = (e) => {
let res = handlerGetLngLatHeight(e);
takeOffPointPosition.value = [res.lng, res.lat, res.alt];
polygonAirForm.value.startingPoint = [res.lng, res.lat, res.alt];
// 设置表单数据
props.airLineForm.taskOffLng = takeOffPointPosition.value[0];
props.airLineForm.taskOffLat = takeOffPointPosition.value[1];
props.templateKmlConfig.missionConfig.takeOffRefPoint =
takeOffPointPosition.value[1].toFixed(8) +
',' +
takeOffPointPosition.value[0].toFixed(8) +
',' +
takeOffPointPosition.value[2].toFixed(2);
// 根据航线类型更新航线
if (props.airLineForm.airLineType == 'mapping2d') {
updatePolygonLineByParams();
} else if (props.airLineForm.airLineType == 'waypoint') {
handlerDrawLine();
}
};
// 处理Graphic鼠标事件返回信息
const handlerGetLngLatHeight = (e) => {
let cartographic = mars3d.Cesium.Cartographic.fromCartesian(e.cartesian);
let longitude = mars3d.Cesium.Math.toDegrees(cartographic.longitude);
let latitude = mars3d.Cesium.Math.toDegrees(cartographic.latitude);
let height = cartographic.height;
let res = {
lng: longitude,
lat: latitude,
alt: height,
};
return res;
};
///////////////////////////////面状航线计算////////////////////////////////////////////
// 全局面状测区
const polygonGeoJson = ref();
// 计算参数
const polygonCalculateParams = ref({
gsd: 0,
overlapY: 70,
overlapX: 80,
overlapAngle: 0,
height: 0,
spacing: 0,
safeyFlyHeight: 20,
});
// 绘制面状测区
const handlerDrawPolygon = async (geojson:any = null) => {
if(geojson!=null){
// 解析和设置参考起飞点
let takeoffArray = props.templateKmlConfig.missionConfig.takeOffRefPoint.split(',');
takeOffPointPosition.value = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
polygonAirForm.value.startingPoint = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
takeOffPointGraphicLayer ? takeOffPointGraphicLayer.clear() : null;
let startFlyGraphic = new mars3d.graphic.BillboardEntity({
position: takeOffPointPosition.value,
style: {
image: '/map/start.png',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '参考起飞点',
font_size: 16,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -50,
},
clampToGround: true,
},
});
takeOffPointGraphicLayer.addGraphic(startFlyGraphic);
polygonGraphicLayer.loadGeoJSON(geojson, {
type: 'polygon',
flyTo: true,
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
});
let coordinates = geojson.features[0].geometry[0];
polygonGeoJson.value = coordinates;
let polygon = turf.polygon([coordinates]);
let polygonWkt = GeojsonToWkt(polygon['geometry']);
// props.airLineForm.flyToFirstPointMode = polygonWkt;
// // 航线间距
// let spceing = parseFloat(polygonCalculateParams.value?.spacing) / 10000;
// // 初始化角度
// let direction = props.templateKmlConfig.Folder.Placemark.direction ? props.templateKmlConfig.Folder.Placemark.direction : 0;
// // 计算航线
// let lines = generateScanLines(polygon, spceing, direction);
// // 计算测区面积、航线长度
// CalculateAreaInfo(polygon, lines);
// // 绘制面航线
// handlerDrawPolygonLine(lines);
// // 计算边长等信息
// handlerGetPolygonBorderInfo(polygonGeoJson.value);
} else {
const graphic = await polygonGraphicLayer.startDraw({
type: 'polygon',
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
});
let coordinates = graphic.toJSON().positions;
coordinates.push(coordinates[0]);
polygonGeoJson.value = coordinates;
let polygon = turf.polygon([coordinates]);
let polygonWkt = GeojsonToWkt(polygon['geometry']);
props.airLineForm.flyToFirstPointMode = polygonWkt;
// 航线间距
let spceing = parseFloat(polygonCalculateParams.value?.spacing) / 10000;
// 初始化角度
let direction = props.templateKmlConfig.Folder.Placemark.direction ? props.templateKmlConfig.Folder.Placemark.direction : 0;
// 计算航线
let lines = generateScanLines(polygon, spceing, direction);
// 计算测区面积、航线长度
CalculateAreaInfo(polygon, lines);
// 绘制面航线
handlerDrawPolygonLine(lines);
// 计算边长等信息
handlerGetPolygonBorderInfo(polygonGeoJson.value);
}
};
// 绘制监测区域
const handlerDrawPolygonPatrol = async () => {
const graphic = await patrolPolygonGraphicLayer.startDraw({
type: 'polygon',
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
});
let coordinates = graphic.toJSON().positions;
coordinates.push(coordinates[0]);
polygonGeoJson.value = coordinates;
emits('areaData', polygonGeoJson.value);
};
// 测区编辑后重新计算航线
const onPolygonGraphicLayerEdit = (e) => {
let coordinates = e.graphic.toJSON().positions;
if (props.editMode == 'add') {
coordinates.push(coordinates[0]);
}
polygonGeoJson.value = coordinates;
let polygon = turf.polygon([coordinates]);
let polygonWkt = GeojsonToWkt(polygon['geometry']);
props.airLineForm.flyToFirstPointMode = polygonWkt;
let spceing = parseFloat(polygonCalculateParams.value?.spacing) / 10000;
let direction = props.templateKmlConfig.Folder.Placemark.direction;
let lines = generateScanLines(polygon, spceing, direction);
// 计算面积
CalculateAreaInfo(polygon, lines);
// 绘制面航线
handlerDrawPolygonLine(lines);
// 计算边长等信息
handlerGetPolygonBorderInfo(polygonGeoJson.value);
};
// 监测区域编辑后重新赋值
const onPatrolPolygonGraphicLayerEdit = (e) => {
let coordinates = e.graphic.toJSON().positions;
if (props.editMode == 'add') {
coordinates.push(coordinates[0]);
}
polygonGeoJson.value = coordinates;
emits('areaData', polygonGeoJson.value);
};
// 绘制面航线
const handlerDrawPolygonLine = (lines) => {
// 设置首航点
let firstAirLinePoint = polygonGraphicLayer.getGraphicById('polygon-node-1');
if (firstAirLinePoint) {
firstAirLinePoint.setOptions({
position: lines.geometry.coordinates[0],
});
} else {
const graphic = new mars3d.graphic.BillboardEntity({
id: 'polygon-node-1',
name: '航点',
position: lines.geometry.coordinates[0],
style: {
image: '/map/node.png',
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -35,
},
},
});
polygonGraphicLayer.addGraphic(graphic);
}
// 判断飞行模式 设置航点高度
lines.geometry.coordinates.unshift([
polygonAirForm.value.startingPoint[0],
polygonAirForm.value.startingPoint[1],
polygonAirForm.value.startingPoint[2] +
parseFloat(polygonCalculateParams.value.safeyFlyHeight),
]);
// 链接起点
lines.geometry.coordinates.unshift(polygonAirForm.value.startingPoint);
if (polygonLineGraphicLayer) {
polygonLineGraphicLayer.clear();
polygonLineGraphicLayer.loadGeoJSON(lines);
} else {
polygonLineGraphicLayer = new mars3d.layer.GeoJsonLayer({
name: '面航线',
data: lines,
symbol: {
type: 'polyline',
styleOptions: {
arcType: Cesium.ArcType.GEODESIC, // 使用大地线
width: 2.0,
color: '#0aed8b',
},
},
flyTo: true,
});
map.addLayer(polygonLineGraphicLayer);
}
};
// 计算面航线
function generateScanLines(polygon, spacing, angle = 0) {
if (!turf.booleanValid(polygon)) throw new Error('无效的多边形');
spacing = Math.abs(spacing);
// 获取多边形的旋转边界框
const bbox = turf.bbox(polygon);
const center = turf.center(polygon).geometry.coordinates;
// 计算需要生成的线数量(加缓冲确保完全覆盖)
const diagLength = turf.distance(
turf.point([bbox[0], bbox[1]]),
turf.point([bbox[2], bbox[3]]),
);
const lineCount = Math.ceil(diagLength / spacing) + 2;
// 生成基础水平线
const lines = [];
for (let i = -1; i <= lineCount; i++) {
const y = bbox[1] + i * spacing * 0.11 - spacing * 0.11;
lines.push(
turf.lineString([
[bbox[0] - spacing, y],
[bbox[2] + spacing, y],
]),
);
}
// 旋转线条到指定角度
const rotatedLines = lines.map((line) =>
turf.transformRotate(line, angle - 90, { pivot: center }),
);
// 裁剪线条到多边形内并处理结果
const coverageLines = [];
rotatedLines.forEach((line) => {
try {
const intersection = turf.lineIntersect(line, polygon);
if (intersection.features.length >= 2) {
// 按与线起点距离排序交点
const sortedPoints = intersection.features
.map((f) => f.geometry.coordinates)
.sort(
(a, b) =>
turf.distance(line.geometry.coordinates[0], turf.point(a)) -
turf.distance(line.geometry.coordinates[0], turf.point(b)),
);
// 创建连接最远两个交点的线段
coverageLines.push(
turf.lineString([sortedPoints[0], sortedPoints[sortedPoints.length - 1]]),
);
}
} catch (e) {
console.warn('处理线段时出错:', e);
}
});
let connectedLine = connectLinesManual(turf.featureCollection(coverageLines));
// 将航点提取并添加到airPoints
airPoints.value = [];
connectedLine.geometry.coordinates?.forEach((item, index) => {
let point = {
id: index,
lng: item[0],
lat: item[1],
alt: item[2],
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 1,
};
airPoints.value?.push(point);
});
// 倒数第2个点
let penultimatePoint = JSON.parse(JSON.stringify(airPoints.value[airPoints.value.length - 1]));
penultimatePoint.id = penultimatePoint.id + 1;
airPoints.value?.push(penultimatePoint);
// 添加测区中心点 最后1个点
let turfPolygon = turf.polygon([polygonGeoJson.value]);
let polygonCenter = turf.centroid(turfPolygon);
let lastPoint = {
id: airPoints.value[airPoints.value.length - 1].id + 1,
lng: polygonCenter.geometry.coordinates[0],
lat: polygonCenter.geometry.coordinates[1],
alt: airPoints.value[airPoints.value.length - 1].alt,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 1,
};
airPoints.value?.push(lastPoint);
// 添加最后一个点到线数据中
connectedLine.geometry.coordinates.push([lastPoint.lng, lastPoint.lat, lastPoint.alt]);
return connectedLine;
}
// 处理面航线
const connectLinesManual = (lines) => {
// 确保输入是FeatureCollection
if (lines.type !== 'FeatureCollection') {
lines = turf.featureCollection([lines]);
}
// 收集所有坐标点
let allCoords = [];
lines.features.forEach((line, index) => {
// 相对起飞点高度
let relativeHeight =
takeOffPointPosition.value[2] + parseFloat(polygonCalculateParams.value.height);
line.geometry.coordinates?.forEach((item, idx) => {
line.geometry.coordinates[idx].push(relativeHeight);
});
if (line.geometry.type === 'LineString' && index % 2 == 0) {
allCoords = allCoords.concat(line.geometry.coordinates.reverse());
} else {
allCoords = allCoords.concat(line.geometry.coordinates);
}
});
// 移除连续重复的点
const cleanedCoords = [];
if (allCoords.length > 0) {
cleanedCoords.push(allCoords[0]);
for (let i = 1; i < allCoords.length; i++) {
const prev = cleanedCoords[cleanedCoords.length - 1];
if (prev[0] !== allCoords[i][0] || prev[1] !== allCoords[i][1]) {
cleanedCoords.push(allCoords[i]);
}
}
}
return turf.lineString(cleanedCoords);
};
// 标绘面状航线起点
const handlerDrawStartPoint = async () => {
graphic = await graphicLayer.startDraw({
type: 'billboard',
style: {
image: '/map/start.png',
scale: 0.7,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '无人机起始位置',
font_size: 16,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -60,
},
},
});
// 设置贴地点 和 连接线
};
// 计算面状测区面积、长度、完成用时、拍摄数量
const CalculateAreaInfo = (polygon, lines) => {
// 测区面积
airInfo.value.area = turf.area(polygon).toFixed(2);
// 航线长度
airInfo.value.length = turf.length(lines).toFixed(2);
// 预计用时
airInfo.value.time = ((airInfo.value.length * 1000) / polygonAirForm.value.speed / 60).toFixed(
2,
);
// 照片数量
};
// 删除面状测区 和 面状航线
const handlerClearPolygonGraphicLayer = () => {
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
textLabelGraphicLayer ? textLabelGraphicLayer.clear() : null;
polygonGeoJson.value = null;
airInfo.value = {
area: 0,
length: 0,
time: 0,
picture: '- -',
};
};
// 面状航线测区、参数改变
const calculatParamChange = (params) => {
polygonCalculateParams.value = params;
if (polygonGeoJson.value) {
let polygon = turf.polygon([polygonGeoJson.value]);
let spceing = parseFloat(params.spacing) / 10000;
let angle = parseFloat(params.overlapAngle);
// 生成航线
let lines = generateScanLines(polygon, spceing, angle);
// 计算面积 长度
CalculateAreaInfo(polygon, lines);
// 绘制面航线
handlerDrawPolygonLine(lines);
// 计算边长等信息
handlerGetPolygonBorderInfo(polygonGeoJson.value);
}
};
// 根据参数更新面状航线
const updatePolygonLineByParams = () => {
if (polygonGeoJson.value && polygonCalculateParams.value) {
let polygon = turf.polygon([polygonGeoJson.value]);
let spceing = parseFloat(polygonCalculateParams.value.spacing) / 10000;
let angle = parseFloat(polygonCalculateParams.value.overlapAngle);
// 生成航线
let lines = generateScanLines(polygon, spceing, angle);
// 计算面积 长度
CalculateAreaInfo(polygon, lines);
// 绘制面航线
handlerDrawPolygonLine(lines);
// 计算边长等信息
handlerGetPolygonBorderInfo(polygonGeoJson.value);
}
};
// 计算绘制的多边形每条线的长度和中心点
const polygonBorderInfo = ref([]);
// 计算测区各边长
const handlerGetPolygonBorderInfo = (polygonCoords) => {
// 创建Turf多边形对象
let polygon = turf.polygon([polygonCoords]);
// 1. 计算边长
let coordinates = polygon.geometry.coordinates[0];
let edgeLengths = [];
for (let i = 0; i < coordinates.length - 1; i++) {
let start = coordinates[i];
let end = coordinates[i + 1];
let distance = turf.distance(turf.point(start), turf.point(end), { units: 'meters' });
let midpoint = turf.midpoint(start, end);
edgeLengths.push({
length: distance.toFixed(2),
center: midpoint?.geometry?.coordinates,
});
}
handlerLoadtextLabelGraphicLayer(edgeLengths);
return edgeLengths;
};
// 绘制文本标注
const handlerLoadtextLabelGraphicLayer = (info) => {
if (textLabelGraphicLayer == null) {
textLabelGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false,
});
map.addLayer(textLabelGraphicLayer);
} else {
textLabelGraphicLayer.clear();
}
// 绘制文本标注
const handlerLoadtextLabelGraphicLayer = (info) => {
if(textLabelGraphicLayer == null){
textLabelGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing:false
})
map.addLayer(textLabelGraphicLayer);
}else{
textLabelGraphicLayer.clear();
}
info?.forEach((item,index)=>{
const graphic = new mars3d.graphic.LabelEntity({
position: [item.center[0], item.center[1], 0],
style: {
text: item.length+"m",
font_size: 15,
scale: 1,
font_family: "微软雅黑",
color: "#ffffff",
outline: true,
outlineColor: "#000000",
outlineWidth: 2,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
visibleDepth: false,
clampToGround:true,
},
attr: { remark: "示例1" }
})
textLabelGraphicLayer.addGraphic(graphic)
})
}
}
// 编辑回显面状航线
// 编辑回显航线
const handlerEditPolygonAirLine = async () => {
// 解析和设置参考起飞点
let takeoffArray = props.templateKmlConfig.missionConfig.takeOffRefPoint.split(',');
takeOffPointPosition.value = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
polygonAirForm.value.startingPoint = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
takeOffPointGraphicLayer ? takeOffPointGraphicLayer.clear() : null;
let startFlyGraphic = new mars3d.graphic.BillboardEntity({
position: takeOffPointPosition.value,
style: {
image: '/map/start.png',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '参考起飞点',
font_size: 16,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -50,
},
clampToGround: true,
},
});
takeOffPointGraphicLayer.addGraphic(startFlyGraphic);
// 处理 和 加载测区数据
let coordinateArray =
props.templateKmlConfig.Folder.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates.split(
'\n',
);
let geomtryCoorinate = [];
coordinateArray.forEach((item, index) => {
let trimStr = item.trim();
let arr = trimStr.split(',');
for (let i = 0; i < arr.length; i++) {
arr[i] = parseFloat(arr[i]);
}
geomtryCoorinate.push(arr);
});
geomtryCoorinate.push(geomtryCoorinate[0]);
let geometry = {
type: 'Polygon',
coordinates: [geomtryCoorinate],
};
// let areaJson = WktToGeojson(props.airLineForm.flyToFirstPointMode)
polygonGeoJson.value = geometry.coordinates[0];
let geojsonData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: geometry,
},
],
};
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
polygonGraphicLayer.loadGeoJSON(geojsonData, {
type: 'polygon',
flyTo: true,
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
});
// 加载文本标注
handlerGetPolygonBorderInfo(geometry.coordinates[0]);
// 加载航线
// let placemark = props.waylineInfo?.Folder?.Placemark
// placemark?.forEach((item, index) => {
// let coordinate = item.Point.coordinates.split(',');
// let airPointInfo = {
// id: item.index,
// name: '航点',
// lng: coordinate[0],
// lat: coordinate[1],
// alt: item.executeHeight,
// aircraftHorizontalAngle: 0,
// cameraHorizontalAngle: 0,
// cameraVerticalAngle: 0,
// focalLength: 2,
// };
// airPoints.value?.push(airPointInfo);
// });
// let coordinates = [];
// airPoints.value?.forEach((item, index) => {
// coordinates.push([item.lng, item.lat]);
// });
// let line = turf.lineString(coordinates);
// handlerDrawPolygonLine(line);
};
// 监测区域面图层回显
const handlerReportPolygonAirLine = () => {
let geometry = {
type: 'Polygon',
coordinates: [props.polygonArea],
};
let geojsonData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: geometry,
},
],
};
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
patrolPolygonGraphicLayer.loadGeoJSON(geojsonData, {
type: 'polygon',
flyTo: true,
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
});
};
///////////////////////////////航点航线计算////////////////////////////////////////////
// 航点移动
const pointMove = (e, id) => {
const cartographic = mars3d.Cesium.Cartographic.fromCartesian(e.position);
const longitude = mars3d.Cesium.Math.toDegrees(cartographic.longitude);
const latitude = mars3d.Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height; // 高度(米)
let stickGraphic = stickGroundPointLayer.getGraphicById('stick' + id);
if (stickGraphic) {
stickGraphic.setOptions({
position: [longitude, latitude],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
}
let lineGraphic = lineGroundPointLayer.getGraphicById('line' + id);
if (lineGraphic) {
lineGraphic.setOptions({
positions: [
[longitude, latitude, height],
[longitude, latitude, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
}
// 更新坐标数据
airPoints.value?.forEach((item, index) => {
if (item.id == id) {
airPoints.value[index].lng = longitude;
airPoints.value[index].lat = latitude;
airPoints.value[index].alt = height;
}
});
// 更新航线
handlerDrawLine();
};
// 绘制航线
const handlerDrawLine = () => {
let positions = [];
airPoints.value?.forEach((item, index) => {
positions.push([item.lng, item.lat, item.alt]);
});
positions.unshift([
takeOffPointPosition.value[0],
takeOffPointPosition.value[1],
airPoints.value[0].alt,
]);
positions.unshift([
takeOffPointPosition.value[0],
takeOffPointPosition.value[1],
takeOffPointPosition.value[2],
]);
// 判断是否已经绘制
if (positions.length > 1) {
let lineGraphic = graphicLayer.getGraphicById('pointsLine');
if (lineGraphic) {
lineGraphic.setOptions({
id: 'pointsLine',
positions: positions,
style: {
width: 2,
color: '#3388ff',
},
});
} else {
const graphic = new mars3d.graphic.PolylineEntity({
id: 'pointsLine',
positions: positions,
style: {
width: 2,
color: '#3388ff',
},
});
graphicLayer.addGraphic(graphic);
}
}
// 计算航线长度
// let lineString = turf.lineString(positions);
// lineInfo.value.length = turf.length(lineString).toFixed(2);
};
// 全局航点数组
const uavPoints = ref([]);
// 绘制航点
const handlerDrawPoint = (e) => {
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
// 设置航线默认高度
let position = mars3d.LngLatPoint.fromCartesian(e.position);
let uuid = airPoints.value.length + 1;
// 获取默认航线高度
let globalHeight = props.templateKmlConfig.Folder.globalHeight;
// 航点三维模型
let uavAngleGraphic = new mars3d.graphic.ModelEntity({
id: uuid,
name: '航向',
position: [position._lng, position._lat, globalHeight],
style: {
url: '/map/uav-angle.gltf',
scale: 0.1,
heading: 90,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 0,
distanceDisplayPoint: {
color: '#00ff00',
pixelSize: 8,
},
},
});
graphicLayer.addGraphic(uavAngleGraphic);
// 地面投影点
let stickGraphic = new mars3d.graphic.PointEntity({
id: 'stick' + uuid,
position: [position._lng, position._lat],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
stickGroundPointLayer.addGraphic(stickGraphic);
// 航点 投影点连接线
let lineGraphic = new mars3d.graphic.PolylineEntity({
id: 'line' + uuid,
positions: [
[position._lng, position._lat, globalHeight],
[position._lng, position._lat, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
lineGroundPointLayer.addGraphic(lineGraphic);
// 航点列表
let airPointInfo = {
id: uuid,
name: '航点',
lng: position._lng,
lat: position._lat,
alt: globalHeight,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 2,
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) {
// 如果存在更新数据
graphic.setOptions({
id: 'cameraGraphic',
position: [e.lng, e.lat, e.alt],
show: true,
style: {
angle1: 30, // 椎体夹角1
angle2: 30, // 椎体夹角2
length: 100, // 椎体长度
rayEllipsoid: false,
color: 'rgba(0,255,255,0.3)',
outline: true,
topShow: true,
topSteps: 2,
flat: true,
cameraHpr: true,
heading: e.aircraftHorizontalAngle - 90, // 偏航角
pitch: e.cameraVerticalAngle - 90, // 俯仰角 0 - 360度
roll: 0,
},
});
} else {
let satelliteSensor = new mars3d.graphic.RectSensor({
id: 'cameraGraphic',
position: [e.lng, e.lat, e.alt],
style: {
flat: true,
angle1: 30, // 椎体夹角1
angle2: 30, // 椎体夹角2
length: 100, // 椎体长度
rayEllipsoid: false,
color: 'rgba(0,255,255,0.3)',
outline: true,
topShow: true,
topSteps: 2,
cameraHpr: true,
heading: e.aircraftHorizontalAngle - 90,
pitch: e.cameraVerticalAngle - 90, // 俯仰角 0 - 360度
roll: 0,
},
});
graphicLayer.addGraphic(satelliteSensor);
}
};
// 更新航点
const updateAirPoint = (e) => {
// 更新航点
let graphic = graphicLayer.getGraphicById(e.id);
if (graphic) {
graphic.setOptions({
name: '航向',
position: [e.lng, e.lat, e.alt],
style: {
url: '/map/uav-angle.gltf',
scale: 0.1,
heading: e.aircraftHorizontalAngle + 90,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 0,
distanceDisplayPoint: {
color: '#00ff00',
pixelSize: 8,
},
},
});
}
// 更新贴地点
let stickGraphic = stickGroundPointLayer.getGraphicById('stick' + e.id);
if (stickGraphic) {
stickGraphic.setOptions({
position: [e.lng, e.lat],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
}
// 更新投影点连线
let lineGraphic = lineGroundPointLayer.getGraphicById('line' + e.id);
if (lineGraphic) {
lineGraphic.setOptions({
positions: [
[e.lng, e.lat, e.alt],
[e.lng, e.lat, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
}
let cameraGraphic = graphicLayer.getGraphicById('camera' + e.id);
if (cameraGraphic) {
cameraGraphic.setOptions({
position: [e.lng, e.lat, e.alt],
// style: {
// angle1: 30, // 椎体夹角1
// angle2: 30, // 椎体夹角2
// length: 50, // 椎体长度
// rayEllipsoid: true,
// color: "rgba(0,255,255,0.3)",
// outline: true,
// topShow: true,
// topSteps: 2,
// flat: true,
// cameraHpr: true,
// heading: 0,
// pitch: 180,
// roll: 0, //
// clippingPlanes: [{
// distance: 0, // 设置裁剪平面在地表0高度
// normal: new Cesium.Cartesian3(0, 0, -1) // 法向量向下(隐藏地表以下部分)
// }]
// }
});
}
// 更新航线
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);
}
if (info.value == 'position') {
// 坐标高度改变
}
};
// 航点位置参数改变
const positionChange = () => {
// 更新航点
updateAirPoint(currentAirPoint.value);
// 更新镜头
handlerDrawCamera(currentAirPoint.value);
};
// 切换航点
const pointChange = (id, type) => {
if (type == 'next') {
if (id == airPoints.value.length) {
currentAirPoint.value = airPoints.value[0];
} else {
currentAirPoint.value = airPoints.value[id];
}
} else if (type == 'last') {
if (id == 1) {
currentAirPoint.value = airPoints.value[airPoints.value.length - 1];
} else {
currentAirPoint.value = airPoints.value[id - 2];
}
}
// 更新镜头
handlerDrawCamera(currentAirPoint.value);
};
// 删除航点
const deleteAirPoint = (e) => {
let id = e.graphic.id;
// 删除航点
let uavModel = graphicLayer.getGraphicById(id);
if (uavModel) {
graphicLayer.removeGraphic(uavModel);
}
// 删除相机
let camera = graphicLayer.getGraphicById('cameraGraphic');
if (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);
}
});
// 更新航线
handlerDrawLine();
};
// 编辑回显航点航线
const handlerEditWaypointAirLine = async () => {
// 解析和设置参考起飞点
let takeoffArray = props.templateKmlConfig.missionConfig.takeOffRefPoint.split(',');
takeOffPointPosition.value = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
polygonAirForm.value.startingPoint = [
parseFloat(takeoffArray[1]),
parseFloat(takeoffArray[0]),
parseFloat(takeoffArray[2]),
];
takeOffPointGraphicLayer ? takeOffPointGraphicLayer.clear() : null;
let startFlyGraphic = new mars3d.graphic.BillboardEntity({
position: takeOffPointPosition.value,
style: {
image: '/map/start.png',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '参考起飞点',
font_size: 16,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -50,
},
clampToGround: true,
},
});
takeOffPointGraphicLayer.addGraphic(startFlyGraphic);
// 处理和加载航点
if (props.waylineWpmlConfig.Folder.Placemark.length > 0) {
props.waylineWpmlConfig.Folder.Placemark?.forEach((item, index) => {
let coordinate = item.Point.coordinates.split(',');
// 处理航点
let airPointInfo = {
id: item.index + 1,
lng: coordinate[0],
lat: coordinate[1],
alt: item.executeHeight,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 24,
actions: [],
};
// 处理动作
item.actionGroup.action?.forEach((action, idx) => {
let actionConfig = JSON.parse(JSON.stringify(airPointActions[action.actionActuatorFunc]));
actionConfig.config = JSON.parse(JSON.stringify(action));
console.log('123', action);
// 处理航偏角和俯仰角
if (action.actionActuatorFunc == 'rotateYaw') {
airPointInfo.aircraftHorizontalAngle = action.actionActuatorFuncParam.aircraftHeading;
}
if (action.actionActuatorFunc == 'gimbalRotate') {
airPointInfo.cameraVerticalAngle =
action.actionActuatorFuncParam.gimbalPitchRotateAngle;
}
airPointInfo.actions.push(actionConfig);
});
airPoints.value?.push(airPointInfo);
// 回显航点
displayWaypointAirLine(airPointInfo);
});
// 更新航线
handlerDrawLine();
}
};
// 回显航点航线信息
const displayWaypointAirLine = (position) => {
console.log('position123', position);
// 设置航线默认高度
let uuid = buildUUID();
// 获取默认航线高度
// 航点三维模型
let uavAngleGraphic = new mars3d.graphic.ModelEntity({
id: position.id,
name: '航向',
position: [position.lng, position.lat, position.alt],
style: {
url: '/map/uav-angle.gltf',
scale: 0.1,
heading: position.aircraftHorizontalAngle + 90,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 0,
distanceDisplayPoint: {
color: '#00ff00',
pixelSize: 8,
},
},
});
graphicLayer.addGraphic(uavAngleGraphic);
// 地面投影点
let stickGraphic = new mars3d.graphic.PointEntity({
id: 'stick' + position.id,
position: [position.lng, position.lat],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
stickGroundPointLayer.addGraphic(stickGraphic);
// 航点 投影点连接线
let lineGraphic = new mars3d.graphic.PolylineEntity({
id: 'line' + position.id,
positions: [
[position.lng, position.lat, position.alt],
[position.lng, position.lat, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
lineGroundPointLayer.addGraphic(lineGraphic);
};
let stickGraphicLayer: mars3d.layer.GraphicLayer;
// 飞行到此处
const flyToThere = (e) => {
if (!uavGraphicLayer) {
uavGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false, // 是否自动激活编辑
});
uavGraphicLayer.bindContextMenu([
{
text: '按轴平移',
icon: 'fa fa-pencil',
callback: (event) => {
const graphic = event.graphic;
if (moveTool) {
return null;
}
// 按轴移动
moveTool = new mars3d.thing.MatrixMove2({
position: graphic.position,
});
map.addThing(moveTool);
moveTool.on(mars3d.EventType.change, (event) => {
graphic.position = event.position;
uavGraphicMove(event);
});
},
},
{
text: '停止平移',
icon: 'fa fa-pencil',
callback: (event) => {
const graphic = event.graphic;
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
},
},
{
text: '删除',
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
callback: (e) => {
deleteFlyToThere(e);
},
},
]);
map.addLayer(uavGraphicLayer);
uavGraphicLayer.on(mars3d.EventType.editMouseMove, (e) => {});
}
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
if (!stickGraphicLayer) {
stickGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: false, // 是否自动激活编辑
});
map.addLayer(stickGraphicLayer);
}
uavGraphicLayer.clear();
stickGraphicLayer.clear();
let position = mars3d.LngLatPoint.fromCartesian(e.position);
let mark = graphicLayer.getGraphicById('flytothere');
if (mark) {
graphicLayer.removeGraphic(mark);
}
// 无人机点
const graphic = new mars3d.graphic.BillboardEntity({
id: 'flytothere-uav',
name: '标点',
position: [position._lng, position._lat, position._alt + 80],
style: {
image: '/map/uav-mark.png',
scale: 0.3,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -40,
},
},
});
// 贴地点
const stickGraphic = new mars3d.graphic.PointEntity({
id: 'flytothere-stick',
position: [position._lng, position._lat],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
stickGraphic.on(mars3d.EventType.editMouseMove, (e) => {
const cartographic = mars3d.Cesium.Cartographic.fromCartesian(e.cartesian);
// 弧度转度数
const longitude = mars3d.Cesium.Math.toDegrees(cartographic.longitude);
const latitude = mars3d.Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height; // 高度(米)
stickGraphicMove([longitude, latitude, height]);
});
// 连接线
let connectLine = new mars3d.graphic.PolylineEntity({
id: 'flytothere-line',
positions: [
[position._lng, position._lat, position._alt + 80],
[position._lng, position._lat, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
uavGraphicLayer.addGraphic(graphic);
stickGraphicLayer.addGraphic(stickGraphic);
uavGraphicLayer.addGraphic(connectLine);
// 获取无人机的坐标并返回
let flyToPosition = mars3d.LngLatPoint.fromCartesian(graphic.position);
emits('flyToThere', flyToPosition);
};
// 移动贴地点
const stickGraphicMove = (e) => {
let uav = uavGraphicLayer.getGraphicById('flytothere-uav');
if (uav) {
uav.setOptions({
id: 'flytothere-uav',
name: '标点',
position: [e[0], e[1], 200],
style: {
image: '/map/uav-mark.png',
scale: 0.3,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -40,
},
},
});
}
let line = uavGraphicLayer.getGraphicById('flytothere-line');
if (line) {
line.setOptions({
id: 'flytothere-line',
positions: [
[e[0], e[1], 200],
[e[0], e[1], 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
}
};
// 删除飞行到此处
const deleteFlyToThere = (e) => {
let id = e.graphic.id;
let uavGraphic = uavGraphicLayer.getGraphicById(id);
if (uavGraphic) {
uavGraphicLayer.removeGraphic(uavGraphic);
}
let lineGraphic = uavGraphicLayer.getGraphicById('flytothere-line');
if (lineGraphic) {
uavGraphicLayer.removeGraphic(lineGraphic);
}
let stickGraphic = stickGraphicLayer.getGraphicById('flytothere-stick');
if (stickGraphic) {
stickGraphicLayer.removeGraphic(stickGraphic);
}
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
emits('flyToThere', { _lng: null, _lat: null, _alt: null });
};
// 无人机点按轴移动
const uavGraphicMove = (e) => {
const cartographic = mars3d.Cesium.Cartographic.fromCartesian(e.position);
// 弧度转度数
const longitude = mars3d.Cesium.Math.toDegrees(cartographic.longitude);
const latitude = mars3d.Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height; // 高度(米)
emits('flyToThere', { _lng: longitude, _lat: latitude, _alt: height });
let line = uavGraphicLayer.getGraphicById('flytothere-line');
if (line) {
line.setOptions({
id: 'flytothere-line',
positions: [
[longitude, latitude, height],
[longitude, latitude, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
}
let stick = stickGraphicLayer.getGraphicById('flytothere-stick');
if (stick) {
stick.setOptions({
id: 'flytothere-stick',
position: [longitude, latitude],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
}
};
// 预览航点航线
const preViewPointWayLine = (position) => {
if (moveTool) {
moveTool.destroy();
moveTool = null;
}
let uuid = buildUUID();
// 参考起飞点
let startGraphic = new mars3d.graphic.BillboardEntity({
id: 'start-graphic',
position: takeOffPointPosition.value,
style: {
image: '/map/start.png',
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '参考起飞点',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -35,
},
},
});
graphicLayer.addGraphic(startGraphic);
// 航点
let graphic = new mars3d.graphic.BillboardEntity({
id: uuid,
name: '航点',
position: [position._lng, position._lat, position._alt],
style: {
image: '/map/node.png',
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '航点',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -35,
},
},
});
graphicLayer.addGraphic(graphic);
// 地面投影点
let stickGraphic = new mars3d.graphic.PointEntity({
id: 'stick' + uuid,
position: [position._lng, position._lat],
style: {
color: '#f5f5f5',
pixelSize: 8,
outline: true,
outlineColor: '#f5f5f5',
outlineWidth: 1,
clampToGround: true,
},
});
stickGroundPointLayer.addGraphic(stickGraphic);
// 航点 投影点连接线
let lineGraphic = new mars3d.graphic.PolylineEntity({
id: 'line' + uuid,
positions: [
[position._lng, position._lat, position._alt],
[position._lng, position._lat, 0],
],
style: {
color: '#f5f5f5',
width: 1,
},
});
lineGroundPointLayer.addGraphic(lineGraphic);
graphicLayer.flyTo();
// 绘制航线
handlerDrawLine();
};
// 预览面状航线
const preViewPolygonWayLine = (lines) => {
handlerDrawLine();
};
// 清空所有图层
const clearAllLayer = () => {
graphicLayer ? graphicLayer.clear() : null;
stickGroundPointLayer ? stickGroundPointLayer.clear() : null;
lineGroundPointLayer ? lineGroundPointLayer.clear() : null;
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
// 面状航线
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
// 文字标注
textLabelGraphicLayer ? textLabelGraphicLayer.clear() : null;
airPoints.value = [];
polygonGeoJson.value = null;
};
//////////////////////////////项目、机场、无人机////////////////////////////////////////////
// 设置机场位置
const setAirportPosition = async () => {
if (!graphicLayer) {
return;
}
if (props.airPort.longitude == null) {
return;
}
let point = graphicLayer.getGraphicById('set-airport');
// // 创建点的经纬度信息
let position = [props.airPort.longitude, props.airPort.latitude, 70];
// 更新航点
if (point) {
// point.setOptions({
// id: 'set-airport',
// name: '机场位置',
// position: position,
// style: {
// image: '/projecthome/airport.png',
// width: 35,
// height: 59,
// scale: 1,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// label: {
// text: '机场',
// font_size: 14,
// color: '#ffffff',
// outline: true,
// outlineColor: '#000000',
// pixelOffsetY: -70,
// },
// },
// });
} else {
let startGraphic = new mars3d.graphic.BillboardEntity({
id: 'set-airport',
position: position,
style: {
image: '/projecthome/airport.png',
width: 35,
height: 59,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '机场',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -70,
},
},
});
graphicLayer.addGraphic(startGraphic);
}
};
// 项目首页设置机场位置
const homeSetAirportPosition = () => {
if (!graphicLayer) {
return;
}
// // 创建点的经纬度信息
let position = [props.homeAirport.longitude, props.homeAirport.latitude, 70];
let airportImg =
props.homeAirport.mode_code == 4
? '/projecthome/work_airport.png'
: '/projecthome/standby_airport.png';
let airportLiveImg =
props.homeAirport.mode_code == 4
? '/projecthome/work_airport_live.png'
: '/projecthome/standby_airport_live.png';
// 更新航点
if (homeStartGraphic && homeStartGraphicLive) {
homeStartGraphic.position = position;
homeStartGraphic.image = airportImg;
homeStartGraphicLive.position = position;
homeStartGraphicLive.image = airportLiveImg;
} else {
homeStartGraphic = new mars3d.graphic.BillboardEntity({
id: 'set-home-airport',
position: position,
style: {
image: airportImg,
width: 118,
height: 133,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: '机场',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -70,
},
},
});
homeStartGraphicLive = new mars3d.graphic.BillboardEntity({
id: 'set-home-airport-live',
position: position,
style: {
image: airportLiveImg,
width: 21,
height: 21,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(45, -107),
label: {
text: '机场',
font_size: 14,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
pixelOffsetY: -70,
},
},
});
homeStartGraphic.on(mars3d.EventType.click, function (event) {
emits('clickAirPort');
});
homeStartGraphicLive.on(mars3d.EventType.click, function (event) {
emits('changeAirportLive', true);
if (props.homeAirport.mode_code == 4) {
emits('changeUAVLive', true);
}
});
graphicLayer.addGraphic(homeStartGraphic);
graphicLayer.addGraphic(homeStartGraphicLive);
}
};
// 设置无人机轨迹
const setUAVPosition = () => {
let point = graphicLayer.getGraphicById('set-uav');
const position = [props.uavTrack.longitude, props.uavTrack.latitude, props.uavTrack.height];
// 更新航点
if (point) {
point.setOptions({
id: 'set-uav',
name: '飞行器位置',
position: position,
style: {
url: '/projecthome/dajiang.gltf',
scale: 0.1,
minimumPixelSize: 100,
},
frameRate: 1,
});
} else {
const graphicModel = new mars3d.graphic.ModelPrimitive({
id: 'set-uav',
name: '飞行器位置',
position: position,
style: {
url: '/projecthome/dajiang.gltf',
scale: 0.1,
minimumPixelSize: 100,
},
frameRate: 1,
});
graphicLayer.addGraphic(graphicModel);
}
let route = graphicLayer.getGraphicById('uav-route');
if (!route) {
route = new mars3d.graphic.Route({
id: 'uav-route',
polyline: {
color: '#3388ff',
width: 2,
},
flyTo: true,
});
graphicLayer.addGraphic(route);
// 是与route绑定的矢量对象放在route构造时一起构造
addGroundLine(route, 'uav-route');
addRectSensor(route, 'uav-route');
}
if (props.uavTrack.longitude) {
const positionVal = Cesium.Cartesian3.fromDegrees(
props.uavTrack.longitude,
props.uavTrack.latitude,
props.uavTrack.height,
);
route.addTimePosition(positionVal, Cesium.JulianDate.fromDate(new Date()));
const airPortStoreVal = airPortStore();
const uav = airPortStoreVal.getUAV;
const type_subtype_gimbalindex = props.uavTrack[uav.camera_index];
if (type_subtype_gimbalindex) {
const rectSensor = graphicLayer.getGraphicById('uav-route-rectSensor');
rectSensor.heading = type_subtype_gimbalindex.gimbal_yaw; //四周方向角0至360度角度值
rectSensor.pitch = type_subtype_gimbalindex.gimbal_pitch; //俯仰角上下摇摆的角度0至360度角度值
rectSensor.roll = type_subtype_gimbalindex.gimbal_roll + 90; //滚转角左右摆动的角度0至360度角度值
rectSensor.angle1 = 10; //夹角1半场角度取值范围 0.1-89.9
rectSensor.angle2 = 10; //夹角2半场角度取值范围 0.1-89.9
}
}
};
// 绘制连接地面线
function addGroundLine(route) {
const groundPoint = new mars3d.graphic.PointPrimitive({
id: route.id + '-groundPoint',
position: route.position,
style: {
color: '#ff0000',
pixelSize: 6,
},
});
graphicLayer.addGraphic(groundPoint);
const linePositions = [];
const groundLine = new mars3d.graphic.PolylineEntity({
id: route.id + '-groundLine',
positions: new Cesium.CallbackProperty(function (time) {
return linePositions;
}, false),
style: {
width: 1,
materialType: mars3d.MaterialType.PolylineDash,
materialOptions: {
color: Cesium.Color.WHITE,
dashLength: 20,
},
},
});
graphicLayer.addGraphic(groundLine);
route.on(mars3d.EventType.change, function (event) {
const wrjPt = route.position;
const wrjCarto = Cesium.Cartographic.fromCartesian(wrjPt);
const dmHeight = mars3d.PointUtil.getHeight(map?.scene, wrjCarto, { max: wrjCarto.height });
const pt2 = Cesium.Cartesian3.fromRadians(wrjCarto.longitude, wrjCarto.latitude, dmHeight);
// 更新竖直线坐标
linePositions[0] = wrjPt;
linePositions[1] = pt2;
// 更新其他矢量对象
groundPoint.position = pt2;
if (route.label) {
// const wrjHeight = wrjCarto.height - dmHeight // 相对地面高度AGL: 飞行海拔-地面海拔
// fixedRoute.label.text = `火星无人机\nAGL:${mars3d.Util.formatNum(wrjHeight, 2)}m`
// 绝对高度ASL: 飞行海拔
route.label.text = `火星无人机\nASL:${mars3d.Util.formatNum(wrjCarto.height, 2)}m`;
}
});
}
// 绘制 相机视锥体
function addRectSensor(route) {
const rectSensor = new mars3d.graphic.RectSensor({
id: route.id + '-rectSensor',
position: route.property,
style: {
angle1: 10,
angle2: 10,
length: 10,
rayEllipsoid: true,
color: 'rgba(0,255,255,0.3)',
outline: true,
topShow: true,
topSteps: 2,
flat: true,
cameraHpr: true,
heading: 0,
pitch: 0,
roll: 90,
},
});
graphicLayer.addGraphic(rectSensor);
// 连接线
const rectLine = new mars3d.graphic.PolylineEntity({
id: route.id + '-rectLine',
positions: new Cesium.CallbackProperty(function (time) {
const localEnd = rectSensor?.rayPosition;
if (!localEnd) {
return [];
}
return [rectSensor.position, localEnd];
}, false),
style: {
arcType: Cesium.ArcType.NONE,
materialType: mars3d.MaterialType.PolylineDash,
materialOptions: {
color: '#ff0000',
},
width: 1,
},
});
graphicLayer.addGraphic(rectLine);
}
/////////////////////////////////动作处理//////////////////////////////////////
const addAction = (action) => {
// 需要特殊处理拍照动作
if (action.value == 'takePhoto') {
currentAirPoint.value.actions.push(JSON.parse(JSON.stringify(airPointActions['focus'])));
}
// 当前航点添加动作
currentAirPoint.value.actions.push(JSON.parse(JSON.stringify(action)));
};
</script>
<style scoped>
.mars3d-container {
width: 100%;
height: 100%;
position: relative;
}
.air-container {
width: 400px;
background: #0d0e15c1;
position: absolute;
height: calc(100vh - 80px);
top: 40px;
left: 40px;
z-index: 999;
}
.airpolygon-container {
width: 400px;
background: #0d0e15c1;
overflow-y: hidden;
position: absolute;
height: calc(100vh - 80px);
top: 40px;
left: 40px;
z-index: 999;
}
.airpoint-config-container {
width: 400px;
background: #0d0e15c1;
overflow-y: hidden;
position: absolute;
height: calc(100vh - 80px);
top: 40px;
right: 40px;
z-index: 999;
}
.draw-polygon-patrol {
cursor: pointer;
position: absolute;
top: 20px;
right: 20px;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: #fff;
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #25436c 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
border-image: linear-gradient(180deg, #3661a4, rgba(61, 109, 171, 0.68)) 1 1;
z-index: 2;
}
.airline-preview-container{
width:500px;
background:rgba(0,0,0,0.6);
position: absolute;
bottom:100px;
left:50%;
transform: translate(0%,0);
z-index:999;
border-radius: 10px;
display: flex;
padding:20px;
font-size:18px;
color:#fff;
}
.airline-preview-container .info-item{
flex:1;
text-align: center;
}
.airline-preview-container .info-item .info-label{
font-size:14px;
margin-top:12px;
}
</style>