DiKongGanZhiPingTai/src/views/demo/workmanagement/workplan/components/map.vue

1819 lines
50 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode 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" 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>