1819 lines
50 KiB
Vue
1819 lines
50 KiB
Vue
<template>
|
||
<div ref="vChartRef" id="mars3d-container" class="mars3d-container">
|
||
<!-- 航点航线 -->
|
||
<div v-if="props.airRoute.airLineType == '航点航线'" class="air-container">
|
||
<airPoint
|
||
:wayline="props.wayline"
|
||
:airPoints="airPoints"
|
||
@setFlyPoint="setFlyPoint"
|
||
@exitDraw="exitDraw"
|
||
:airInfo="lineInfo"
|
||
:airRoute="props.airRoute"
|
||
:polygonAirForm="polygonAirForm"
|
||
@checkPoint="checkPoint"
|
||
></airPoint>
|
||
</div>
|
||
|
||
<!-- 航面航线 -->
|
||
<div v-if="props.airRoute.airLineType == '面状航线'" class="airpolygon-container">
|
||
<airPolygon
|
||
@setFlyPoint="setFlyPoint"
|
||
:airInfo="airInfo"
|
||
:polygonAirForm="polygonAirForm"
|
||
:airRoute="props.airRoute"
|
||
@calculatParamChange="calculatParamChange"
|
||
@exitDraw="exitDraw"
|
||
></airPolygon>
|
||
</div>
|
||
|
||
<!-- 航点航线配置 -->
|
||
<div class="airpoint-config-container" v-if="airPointConfigShow">
|
||
<airPointConfig :currentAirPoint="currentAirPoint" ></airPointConfig>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script lang="ts" setup>
|
||
import { ref, onMounted, defineProps, watch, defineEmits } from 'vue';
|
||
import { message } from 'ant-design-vue';
|
||
import { GeojsonToWkt } 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 'mars3d-space';
|
||
|
||
import * as Cesium from 'mars3d-cesium';
|
||
import * as turf from '@turf/turf';
|
||
import airPolygon from './airPolygon.vue';
|
||
import airPointConfig from './airPointConfig.vue';
|
||
|
||
const props = defineProps([
|
||
'airRoute',
|
||
'flyToTherePosition',
|
||
'wayline',
|
||
'waylineInfo',
|
||
'workPlanFormShow',
|
||
'airPort',
|
||
'uavTrack',
|
||
'homeAirport'
|
||
]);
|
||
|
||
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.airRoute,
|
||
(newVal, oldVal) => {},
|
||
);
|
||
watch(
|
||
() => props.wayline,
|
||
(newVal, oldVal) => {
|
||
generatePreviewPoint(newVal?.Folder?.Placemark);
|
||
},
|
||
);
|
||
watch(
|
||
()=>props.wayline,
|
||
(newVal,oldVal)=>{
|
||
generatePreviewPoint(newVal?.Folder?.Placemark);
|
||
}
|
||
)
|
||
|
||
// 航线预览:生成点
|
||
const generatePreviewPoint = (placemark)=>{
|
||
|
||
// 设置默认起飞点
|
||
startPosition.value = [props.waylineInfo?.taskOffLng, props.waylineInfo?.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.waylineInfo?.airLineType == 'waypoint') {
|
||
// 航点航线
|
||
|
||
airPoints.value?.forEach((item, index) => {
|
||
let drawPoint = {
|
||
_lng: item.lng,
|
||
_lat: item.lat,
|
||
_alt: item.alt,
|
||
};
|
||
preViewPointWayLine(drawPoint);
|
||
});
|
||
} else if (props.waylineInfo?.airLineType == 'mapping2d') {
|
||
let coordinates = [];
|
||
|
||
airPoints.value?.forEach((item, index) => {
|
||
coordinates.push([item.lng, item.lat]);
|
||
});
|
||
|
||
console.log('coordinates', coordinates);
|
||
|
||
let line = turf.lineString(coordinates);
|
||
|
||
preViewPolygonWayLine(line);
|
||
}
|
||
};
|
||
|
||
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort']);
|
||
|
||
const airPoints = ref([]);
|
||
const currentAirPoint = ref({});
|
||
const airPointConfigShow = ref(false);
|
||
|
||
// 全局平移工具
|
||
let moveTool: mars3d.thing.MatrixMove2;
|
||
|
||
// 监听航点变化
|
||
watch(
|
||
currentAirPoint,
|
||
(newVal, oldVal) => {
|
||
// 更新航点
|
||
updateAirPoint(newVal);
|
||
// 更新镜头
|
||
handlerDrawCamera(newVal);
|
||
},
|
||
{ deep: true },
|
||
);
|
||
|
||
const clickPoint = (id) => {
|
||
airPoints.value?.forEach((item, index) => {
|
||
if (item.id == id) {
|
||
currentAirPoint.value = item;
|
||
airPointConfigShow.value = true;
|
||
}
|
||
});
|
||
};
|
||
|
||
const checkPoint = (e) => {
|
||
currentAirPoint.value = e;
|
||
airPointConfigShow.value = true;
|
||
};
|
||
|
||
let map: mars3d.Map; // 地图对象
|
||
let graphicLayer: mars3d.layer.GraphicLayer;
|
||
|
||
let drawGraphicLayer:mars3d.layer.GraphicLayer;
|
||
|
||
let uavGraphicLayer: mars3d.layer.GraphicLayer;
|
||
|
||
// 面航线图层
|
||
let polygonGraphicLayer: mars3d.layer.GraphicLayer;
|
||
|
||
let polygonLineGraphicLayer: mars3d.layer.GeoJsonLayer;
|
||
|
||
// 航点地面投影点
|
||
let stickGroundPointLayer: mars3d.layer.GraphicLayer;
|
||
|
||
// 航点连接线
|
||
let lineGroundPointLayer: mars3d.layer.GraphicLayer;
|
||
|
||
// 项目首页机场位置
|
||
let homeStartGraphic;
|
||
|
||
let graphic = null;
|
||
|
||
const exitDraw = () => {
|
||
// 清空数据
|
||
graphicLayer ? graphicLayer.clear() : null;
|
||
drawGraphicLayer ? drawGraphicLayer.clear() : null;
|
||
stickGroundPointLayer ? stickGroundPointLayer.clear() : null;
|
||
lineGroundPointLayer ? lineGroundPointLayer.clear() : null;
|
||
|
||
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
|
||
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
|
||
airPoints.value = [];
|
||
|
||
props.airRoute.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(() => {
|
||
initMap();
|
||
EventBus.on('closeTranslation', (val: any) => {
|
||
if (moveTool) {
|
||
moveTool.destroy();
|
||
moveTool = null;
|
||
}
|
||
});
|
||
});
|
||
|
||
const initMap = () => {
|
||
map = new mars3d.Map(vChartRef.value, {
|
||
scene: {
|
||
center: { lat: 35.132103, lng: 118.296315, alt: 260.9, heading: 357.9, pitch: -32 },
|
||
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, // 是否自动激活编辑
|
||
});
|
||
|
||
drawGraphicLayer = 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;
|
||
console.log('moveTool', moveTool);
|
||
}
|
||
},
|
||
},
|
||
{
|
||
text: '删除',
|
||
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
|
||
callback: (e) => {
|
||
deleteAirPoint(e);
|
||
},
|
||
},
|
||
]);
|
||
|
||
map.addLayer(graphicLayer);
|
||
map.addLayer(drawGraphicLayer);
|
||
|
||
// 航点地面投影点
|
||
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);
|
||
});
|
||
|
||
// 绘制起点
|
||
// handlerDrawStartPoint();
|
||
|
||
if (props.airPort) {
|
||
setAirportPosition();
|
||
}
|
||
if (props.uavTrack) {
|
||
setUAVPosition();
|
||
}
|
||
// 加载长光高清影像
|
||
// loadChangGuangLayer();
|
||
emits('mapOnLoad',map)
|
||
});
|
||
};
|
||
|
||
// 加载长光卫星高分影像
|
||
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);
|
||
}
|
||
|
||
// 绑定地图右键菜单
|
||
const handlerBindMapMenus = () => {
|
||
const mapContextmenuItems = [
|
||
{
|
||
text: '飞行到此处',
|
||
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
|
||
callback: (e) => {
|
||
flyToThere(e);
|
||
},
|
||
},
|
||
{
|
||
text: '添加航点',
|
||
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
|
||
callback: (e) => {
|
||
if (!startPosition.value) {
|
||
message.warning('请先设置起飞点');
|
||
return null;
|
||
}
|
||
handlerDrawPoint(e);
|
||
},
|
||
},
|
||
{
|
||
text: '添加面区域',
|
||
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
|
||
callback: (e) => {
|
||
if (!polygonAirForm.value.startingPoint) {
|
||
message.warning('请先设置起飞点');
|
||
return null;
|
||
}
|
||
handlerDrawPolygon();
|
||
},
|
||
},
|
||
];
|
||
map.bindContextMenu(mapContextmenuItems);
|
||
};
|
||
|
||
|
||
|
||
// 航点移动
|
||
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([startPosition.value[0], startPosition.value[1], airPoints.value[0].alt]);
|
||
|
||
positions.unshift([startPosition.value[0], startPosition.value[1], startPosition.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 startPosition = ref(null);
|
||
|
||
// 设置起飞点
|
||
const setFlyPoint = async () => {
|
||
|
||
drawGraphicLayer ? drawGraphicLayer.clear : null;
|
||
|
||
const graphic = await drawGraphicLayer.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,
|
||
},
|
||
},
|
||
});
|
||
|
||
startPosition.value = graphic.toJSON().position;
|
||
|
||
polygonAirForm.value.startingPoint = graphic.toJSON().position;
|
||
};
|
||
|
||
// 全局区域
|
||
const polygonGeoJson = ref();
|
||
|
||
// 绘制面状
|
||
const handlerDrawPolygon = async () => {
|
||
if (polygonGraphicLayer == null) {
|
||
polygonGraphicLayer = new mars3d.layer.GraphicLayer({
|
||
isAutoEditing: false, // 是否自动激活编辑
|
||
});
|
||
|
||
polygonGraphicLayer.bindContextMenu([
|
||
{
|
||
text: '删除测区',
|
||
icon: 'fa fa-camera-retro', // 支持 font-class 的字体方式图标
|
||
callback: (e) => {
|
||
handlerRemovePolygonArea(e);
|
||
},
|
||
},
|
||
]);
|
||
map.addLayer(polygonGraphicLayer);
|
||
}
|
||
|
||
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 lines = generateScanLines(polygon, 0.005, 0);
|
||
|
||
// 绘制区域转存wkt
|
||
// let wkt = GeojsonToWkt(polygon.geometry);
|
||
|
||
CalculateAreaInfo(polygon, lines);
|
||
|
||
// 绘制面航线
|
||
handlerDrawPolygonLine(lines);
|
||
};
|
||
|
||
// 绘制面航线
|
||
const handlerDrawPolygonLine = (lines) => {
|
||
|
||
let nodeGraphic = polygonGraphicLayer.getGraphicById("polygon-node-1");
|
||
|
||
if(nodeGraphic){
|
||
nodeGraphic.setOptions({
|
||
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,
|
||
},
|
||
},
|
||
})
|
||
}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] + 20,
|
||
]);
|
||
|
||
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',
|
||
// clampToGround: true,
|
||
},
|
||
},
|
||
flyTo: true,
|
||
});
|
||
map.addLayer(polygonLineGraphicLayer);
|
||
}
|
||
};
|
||
|
||
// 删除面 和 面航线
|
||
const handlerRemovePolygonArea = () => {
|
||
if (polygonGraphicLayer) {
|
||
polygonGraphicLayer.clear();
|
||
}
|
||
if (polygonLineGraphicLayer) {
|
||
polygonLineGraphicLayer.clear();
|
||
}
|
||
|
||
airInfo.value = {
|
||
area: 0,
|
||
length: 0,
|
||
time: 0,
|
||
picture: '- -',
|
||
};
|
||
};
|
||
|
||
// 计算面航线
|
||
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.1 - spacing * 0.1;
|
||
lines.push(
|
||
turf.lineString([
|
||
[bbox[0] - spacing, y],
|
||
[bbox[2] + spacing, y],
|
||
]),
|
||
);
|
||
}
|
||
|
||
// 旋转线条到指定角度
|
||
const rotatedLines = lines.map((line) => turf.transformRotate(line, angle, { 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));
|
||
console.log('connectedLine', connectedLine);
|
||
return connectedLine;
|
||
}
|
||
|
||
// 连接线段
|
||
const connectLinesManual = (lines) => {
|
||
// 确保输入是FeatureCollection
|
||
if (lines.type !== 'FeatureCollection') {
|
||
lines = turf.featureCollection([lines]);
|
||
}
|
||
|
||
// 收集所有坐标点
|
||
let allCoords = [];
|
||
lines.features.forEach((line, index) => {
|
||
console.log('line.geometry.coordinates', line.geometry.coordinates);
|
||
line.geometry.coordinates?.forEach((item, idx) => {
|
||
line.geometry.coordinates[idx].push(180);
|
||
});
|
||
|
||
if (line.geometry.type === 'LineString' && index % 2 == 0) {
|
||
allCoords = allCoords.concat(line.geometry.coordinates.reverse());
|
||
} else {
|
||
allCoords = allCoords.concat(line.geometry.coordinates);
|
||
}
|
||
});
|
||
|
||
console.log('allCoords', allCoords);
|
||
// 移除连续重复的点
|
||
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 uavPoints = ref([]);
|
||
|
||
|
||
|
||
// 绘制航点
|
||
const handlerDrawPoint = (e) => {
|
||
if (moveTool) {
|
||
moveTool.destroy();
|
||
moveTool = null;
|
||
}
|
||
|
||
let position = mars3d.LngLatPoint.fromCartesian(e.position);
|
||
|
||
let uuid = buildUUID();
|
||
|
||
// 航点
|
||
// 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 uavAngleGraphic = new mars3d.graphic.ModelEntity({
|
||
id:uuid,
|
||
name: "航向",
|
||
position: [position._lng, position._lat, position._alt],
|
||
style: {
|
||
url: "/map/uav-angle.gltf",
|
||
scale: 0.1,
|
||
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,
|
||
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);
|
||
|
||
// 航点列表
|
||
let airPointInfo = {
|
||
id: uuid,
|
||
name: '航点',
|
||
lng: position._lng,
|
||
lat: position._lat,
|
||
alt: position._alt,
|
||
aircraftHorizontalAngle: 0,
|
||
cameraHorizontalAngle: 0,
|
||
cameraVerticalAngle: 0,
|
||
focalLength: 2,
|
||
};
|
||
airPoints.value?.push(airPointInfo);
|
||
|
||
uavPoints.value.push(graphic);
|
||
|
||
// 当前航点
|
||
currentAirPoint.value = airPoints.value[airPoints.value?.length - 1];
|
||
|
||
// 绘制航线
|
||
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,
|
||
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,
|
||
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,
|
||
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" }
|
||
}
|
||
);
|
||
}
|
||
|
||
// 更新贴地点
|
||
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 deleteAirPoint = (e) => {
|
||
let id = e.graphic.id;
|
||
|
||
// 删除航点
|
||
let point = graphicLayer.getGraphicById(id);
|
||
if (point) {
|
||
graphicLayer.removeGraphic(point);
|
||
}
|
||
|
||
// 删除相机
|
||
let camera = graphicLayer.getGraphicById('camera' + id);
|
||
if (camera) {
|
||
graphicLayer.removeGraphic(camera);
|
||
}
|
||
|
||
// 删除数据
|
||
airPoints.value?.forEach((item, index) => {
|
||
if (item.id == id) {
|
||
airPoints.value?.splice(index, 1);
|
||
}
|
||
});
|
||
|
||
// 更新航线
|
||
handlerDrawLine();
|
||
};
|
||
|
||
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) => {
|
||
return null;
|
||
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: startPosition.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;
|
||
airPoints.value = [];
|
||
};
|
||
|
||
// 设置机场位置
|
||
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];
|
||
// 更新航点
|
||
if (homeStartGraphic) {
|
||
homeStartGraphic.position = position
|
||
} else {
|
||
homeStartGraphic = new mars3d.graphic.BillboardEntity({
|
||
id: 'set-home-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,
|
||
},
|
||
},
|
||
});
|
||
homeStartGraphic.on(mars3d.EventType.click, function (event) {
|
||
emits('clickAirPort')
|
||
});
|
||
graphicLayer.addGraphic(homeStartGraphic);
|
||
}
|
||
}
|
||
// 设置无人机轨迹
|
||
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);
|
||
}
|
||
if (props.uavTrack.longitude) {
|
||
const positionVal = Cesium.Cartesian3.fromDegrees(
|
||
props.uavTrack.longitude,
|
||
props.uavTrack.latitude,
|
||
props.uavTrack.height,
|
||
);
|
||
route.addTimePosition(positionVal);
|
||
}
|
||
};
|
||
|
||
|
||
// 参数改变
|
||
const calculatParamChange = (params) => {
|
||
console.log("params",params);
|
||
|
||
let spceing = parseFloat(params.spacing) / 10000;
|
||
|
||
console.log("spceing",spceing);
|
||
|
||
if(polygonGeoJson.value){
|
||
let polygon = turf.polygon([polygonGeoJson.value]);
|
||
let lines = generateScanLines(polygon, spceing, 0);
|
||
|
||
// 计算面积 长度
|
||
CalculateAreaInfo(polygon, lines);
|
||
|
||
// 绘制面航线
|
||
handlerDrawPolygonLine(lines);
|
||
}
|
||
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.mars3d-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.air-container {
|
||
width: 400px;
|
||
background: #0d0e15c1;
|
||
overflow-y: hidden;
|
||
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;
|
||
}
|
||
</style>
|