cesium地图添加画空域的工具的编辑
This commit is contained in:
parent
e8b8d12623
commit
1a87cadb08
@ -177,7 +177,12 @@ const {
|
||||
importAirspaceData,
|
||||
importFromFile,
|
||||
importFromGeoJSON,
|
||||
getImportStatistics
|
||||
getImportStatistics,
|
||||
isEditing,
|
||||
editingDrawing,
|
||||
startEditing,
|
||||
finishEditing,
|
||||
cancelEditing,
|
||||
} = useDrawingManager(drawingTool);
|
||||
|
||||
|
||||
@ -300,6 +305,19 @@ const showMessage = (message: string, type: 'success' | 'error' | 'info' = 'info
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
if (isEditing.value) {
|
||||
cancelEditing();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
// 开始跟踪相机信息
|
||||
setTimeout(() => {
|
||||
startCameraTracking();
|
||||
|
@ -6,6 +6,29 @@
|
||||
<div class="drawing-status" :class="{ active: isDrawing }">
|
||||
{{ getDrawingStatus() }}
|
||||
</div>
|
||||
<div class="editing-status" v-if="isEditing">
|
||||
✏️ 编辑模式中
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑控制 -->
|
||||
<div class="panel-section" v-if="isEditing">
|
||||
<h4>✏️ 编辑控制</h4>
|
||||
<div class="edit-controls">
|
||||
<button @click="finishEditing" class="edit-btn save-btn">
|
||||
💾 保存
|
||||
</button>
|
||||
<button @click="cancelEditing" class="edit-btn cancel-btn">
|
||||
❌ 取消
|
||||
</button>
|
||||
<div class="edit-instructions">
|
||||
<p><strong>操作说明:</strong></p>
|
||||
<p>• 拖动控制点调整空域形状</p>
|
||||
<p>• 圆形: 拖动红点移动圆心,蓝点调整半径</p>
|
||||
<p>• 多边形: 拖动红点移动顶点</p>
|
||||
<p>• 按 ESC 键取消编辑</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮组 -->
|
||||
@ -41,7 +64,7 @@
|
||||
|
||||
<div class="panel-section">
|
||||
<h4>绘制工具</h4>
|
||||
<div class="drawing-buttons">
|
||||
<!-- <div class="drawing-buttons">
|
||||
<button
|
||||
class="drawing-btn circle-btn"
|
||||
:class="{ active: isDrawing && currentDrawingType === 'circle' }"
|
||||
@ -65,6 +88,29 @@
|
||||
>
|
||||
❌ 取消绘制
|
||||
</button>
|
||||
</div> -->
|
||||
<div class="drawing-tools">
|
||||
<button
|
||||
@click="startCircleDrawing"
|
||||
class="tool-btn circle-btn"
|
||||
:disabled="isDrawing || isEditing"
|
||||
>
|
||||
⭕ 绘制圆形
|
||||
</button>
|
||||
<button
|
||||
@click="startPolygonDrawing"
|
||||
class="tool-btn polygon-btn"
|
||||
:disabled="isDrawing || isEditing"
|
||||
>
|
||||
🔷 绘制多边形
|
||||
</button>
|
||||
<button
|
||||
@click="cancelDrawing"
|
||||
class="tool-btn cancel-btn"
|
||||
:disabled="!isDrawing"
|
||||
>
|
||||
❌ 取消绘制
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -94,6 +140,9 @@
|
||||
<button @click="handlePrintAllDrawingsInfo" class="action-btn" title="打印所有空域信息" :disabled="drawings.size === 0">
|
||||
🖨️
|
||||
</button>
|
||||
<button @click="exportAllToJSON" class="icon-btn" title="导出全部">
|
||||
📄
|
||||
</button>
|
||||
<button @click="clearAllDrawings" class="clear-btn" title="清除所有">
|
||||
🗑️
|
||||
</button>
|
||||
@ -103,15 +152,18 @@
|
||||
<div
|
||||
v-for="[id, drawing] in drawings"
|
||||
:key="id"
|
||||
:class="['drawing-item', { active: selectedDrawing === id }]"
|
||||
:class="['drawing-item', { active: selectedDrawing === id, editing: isEditing && editingDrawing?.id === id }]"
|
||||
@click="selectDrawing(id)"
|
||||
>
|
||||
<div class="drawing-info">
|
||||
<div class="drawing-type">
|
||||
{{ drawing.type === 'circle' ? '⭕' : '🔷' }}
|
||||
{{ drawing.type === 'circle' ? '圆形空域' : '多边形空域' }}
|
||||
<span class="icon">{{ drawing.type === 'circle' ? '⭕' : '🔷' }}</span>
|
||||
<span class="name">{{ drawing.type === 'circle' ? '圆形' : '多边形' }}</span>
|
||||
<span v-if="isEditing && editingDrawing?.id === id" class="editing-badge">
|
||||
编辑中
|
||||
</span>
|
||||
</div>
|
||||
<div class="drawing-props">
|
||||
<div class="drawing-details">
|
||||
<span v-if="drawing.type === 'circle'">
|
||||
半径: {{ (getCircleRadius(drawing) / 1000).toFixed(2) }}km
|
||||
</span>
|
||||
@ -121,7 +173,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="drawing-actions">
|
||||
<button
|
||||
@click.stop="toggleEdit(id)"
|
||||
class="action-btn edit-btn"
|
||||
:class="{ active: isEditing && editingDrawing?.id === id }"
|
||||
:title="isEditing && editingDrawing?.id === id ? '停止编辑' : '编辑'"
|
||||
>
|
||||
{{ isEditing && editingDrawing?.id === id ? '⏹️' : '✏️' }}
|
||||
</button>
|
||||
<button @click.stop="flyToDrawing(id)" title="飞向">✈️</button>
|
||||
<button @click.stop="exportDrawing(id)" class="action-btn" title="导出">📤</button>
|
||||
<button @click.stop="handlePrintDrawingInfo(id)" title="打印信息">🖨️</button>
|
||||
<button @click.stop="removeDrawing(id)" title="删除">🗑️</button>
|
||||
</div>
|
||||
@ -291,6 +352,19 @@ const props = defineProps<{
|
||||
drawingOptions: any;
|
||||
getDrawingStatus: () => string;
|
||||
getDrawingInfoText: () => string;
|
||||
isEditing: boolean;
|
||||
editingDrawing: any;
|
||||
startCircleDrawing: () => void;
|
||||
startPolygonDrawing: () => void;
|
||||
cancelDrawing: () => void;
|
||||
startEditing: (id: string) => void;
|
||||
finishEditing: () => void;
|
||||
cancelEditing: () => void;
|
||||
selectDrawing: (id: string) => void;
|
||||
removeDrawing: (id: string) => void;
|
||||
flyToDrawing: (id: string) => void;
|
||||
exportAllToJSON: () => void;
|
||||
clearAllDrawings: () => void;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -310,6 +384,10 @@ const emit = defineEmits<{
|
||||
'print-all-drawings-info': [];
|
||||
'print-drawing-info': [id: string];
|
||||
'export-drawing-info': [id: string];
|
||||
'export-drawing': [id: string];
|
||||
'start-editing': [id: string];
|
||||
'finish-editing': [];
|
||||
'cancel-editing': [];
|
||||
}>();
|
||||
|
||||
const activeTab = ref<'circle' | 'polygon'>('circle');
|
||||
@ -327,9 +405,9 @@ const cancelDrawing = () => {
|
||||
emit('cancel-drawing');
|
||||
};
|
||||
|
||||
const selectDrawing = (id: string) => {
|
||||
emit('select-drawing', id);
|
||||
};
|
||||
// const selectDrawing = (id: string) => {
|
||||
// emit('select-drawing', id);
|
||||
// };
|
||||
|
||||
const removeDrawing = (id: string) => {
|
||||
emit('remove-drawing', id);
|
||||
@ -342,7 +420,9 @@ const clearAllDrawings = () => {
|
||||
// 方法实现
|
||||
const flyToDrawing = (id: string) => {
|
||||
console.log('点击飞向空域按钮:', id);
|
||||
emit('fly-to-drawing', id);
|
||||
// emit('fly-to-drawing', id);
|
||||
console.log('点击飞向选中空域按钮');
|
||||
emit('fly-to-selected-drawing',id);
|
||||
};
|
||||
|
||||
|
||||
@ -385,6 +465,59 @@ const flyToSelectedDrawing = () => {
|
||||
emit('fly-to-selected-drawing');
|
||||
};
|
||||
|
||||
// 添加编辑控制方法
|
||||
const finishEditing = () => {
|
||||
emit('finish-editing');
|
||||
};
|
||||
|
||||
const cancelEditing = () => {
|
||||
emit('cancel-editing');
|
||||
};
|
||||
|
||||
// 修改所有编辑相关方法
|
||||
const toggleEdit = (id: string) => {
|
||||
if (props.isEditing && props.editingDrawing?.id === id) {
|
||||
emit('finish-editing');
|
||||
} else {
|
||||
emit('start-editing', id);
|
||||
}
|
||||
};
|
||||
|
||||
const selectDrawing = (id: string) => {
|
||||
if (props.isEditing) {
|
||||
if (props.editingDrawing?.id !== id) {
|
||||
emit('start-editing', id);
|
||||
}
|
||||
} else {
|
||||
emit('select-drawing', id);
|
||||
}
|
||||
};
|
||||
// // 切换编辑状态
|
||||
// const toggleEdit = (id: string) => {
|
||||
// if (props.isEditing && props.editingDrawing?.id === id) {
|
||||
// props.finishEditing();
|
||||
// } else {
|
||||
// props.startEditing(id);
|
||||
// }
|
||||
// };
|
||||
|
||||
// // 选择空域
|
||||
// const selectDrawing = (id: string) => {
|
||||
// if (props.isEditing) {
|
||||
// // 在编辑模式下,选择空域即开始编辑
|
||||
// if (props.editingDrawing?.id !== id) {
|
||||
// props.startEditing(id);
|
||||
// }
|
||||
// } else {
|
||||
// props.selectDrawing(id);
|
||||
// }
|
||||
// };
|
||||
|
||||
// 导出单个空域
|
||||
const exportDrawing = (id: string) => {
|
||||
emit('export-drawing', id);
|
||||
};
|
||||
|
||||
// 工具函数
|
||||
const getCircleRadius = (drawing: DrawingResult): number => {
|
||||
if (drawing.type !== 'circle' || drawing.positions.length < 2) return 0;
|
||||
@ -593,5 +726,249 @@ const hexToColor = (hex: string): Cesium.Color => {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
|
||||
.drawing-tool-panel {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
background: rgba(42, 42, 42, 0.95);
|
||||
color: white;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
min-width: 280px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.status-indicators {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.drawing-status, .editing-status {
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drawing-status {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.drawing-status.active {
|
||||
background: rgba(24, 144, 255, 0.3);
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.editing-status {
|
||||
background: rgba(255, 152, 0, 0.3);
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
.edit-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
background: rgba(76, 175, 80, 0.3);
|
||||
}
|
||||
|
||||
.save-btn:hover {
|
||||
background: rgba(76, 175, 80, 0.5);
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: rgba(244, 67, 54, 0.3);
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
background: rgba(244, 67, 54, 0.5);
|
||||
}
|
||||
|
||||
.edit-instructions {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.edit-instructions p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.icon-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.drawings-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.drawing-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
margin-bottom: 5px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.drawing-item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.drawing-item.active {
|
||||
background: rgba(24, 144, 255, 0.2);
|
||||
border: 1px solid #1890ff;
|
||||
}
|
||||
|
||||
.drawing-item.editing {
|
||||
background: rgba(255, 152, 0, 0.2);
|
||||
border: 1px solid #ff9800;
|
||||
}
|
||||
|
||||
.drawing-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.drawing-type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.drawing-type .icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.editing-badge {
|
||||
background: #ff9800;
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.drawing-details {
|
||||
font-size: 11px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.drawing-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.action-btn.edit-btn.active {
|
||||
background: rgba(255, 152, 0, 0.3);
|
||||
}
|
||||
|
||||
.action-btn.delete-btn:hover {
|
||||
background: rgba(244, 67, 54, 0.2);
|
||||
}
|
||||
|
||||
.drawing-tools {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tool-btn {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tool-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.tool-btn:not(:disabled):hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.circle-btn {
|
||||
background: rgba(255, 193, 7, 0.3);
|
||||
}
|
||||
|
||||
.circle-btn:not(:disabled):hover {
|
||||
background: rgba(255, 193, 7, 0.5);
|
||||
}
|
||||
|
||||
.polygon-btn {
|
||||
background: rgba(0, 188, 212, 0.3);
|
||||
}
|
||||
|
||||
.polygon-btn:not(:disabled):hover {
|
||||
background: rgba(0, 188, 212, 0.5);
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: rgba(244, 67, 54, 0.3);
|
||||
}
|
||||
|
||||
.cancel-btn:not(:disabled):hover {
|
||||
background: rgba(244, 67, 54, 0.5);
|
||||
}
|
||||
/* ... 其他样式代码保持不变 ... */
|
||||
</style>
|
388
src/views/cesiums/components/AirspaceEditor.ts
Normal file
388
src/views/cesiums/components/AirspaceEditor.ts
Normal file
@ -0,0 +1,388 @@
|
||||
// src/utils/cesium/AirspaceEditor.ts
|
||||
import * as Cesium from 'cesium';
|
||||
|
||||
export interface EditHandle {
|
||||
id: string;
|
||||
type: 'vertex' | 'center' | 'radius';
|
||||
position: Cesium.Cartesian3;
|
||||
entity: Cesium.Entity;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export class AirspaceEditor {
|
||||
private viewer: Cesium.Viewer;
|
||||
private handler: Cesium.ScreenSpaceEventHandler;
|
||||
|
||||
private isEditing: boolean = false;
|
||||
private currentDrawing: any = null;
|
||||
private editHandles: EditHandle[] = [];
|
||||
private originalPositions: Cesium.Cartesian3[] = [];
|
||||
|
||||
constructor(viewer: Cesium.Viewer) {
|
||||
this.viewer = viewer;
|
||||
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始编辑空域
|
||||
*/
|
||||
startEditing(drawing: any): void {
|
||||
console.log('开始编辑空域:', drawing);
|
||||
|
||||
if (this.isEditing) {
|
||||
this.finishEditing();
|
||||
}
|
||||
|
||||
this.isEditing = true;
|
||||
this.currentDrawing = drawing;
|
||||
this.originalPositions = [...drawing.positions];
|
||||
|
||||
// 创建编辑控制点
|
||||
this.createEditHandles(drawing);
|
||||
|
||||
// 设置事件监听
|
||||
this.setupEventListeners();
|
||||
|
||||
// 高亮显示编辑中的空域
|
||||
this.highlightDrawing(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建编辑控制点
|
||||
*/
|
||||
private createEditHandles(drawing: any): void {
|
||||
this.clearEditHandles();
|
||||
|
||||
if (drawing.type === 'circle') {
|
||||
this.createCircleHandles(drawing);
|
||||
} else if (drawing.type === 'polygon') {
|
||||
this.createPolygonHandles(drawing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建圆形控制点
|
||||
*/
|
||||
private createCircleHandles(drawing: any): void {
|
||||
const center = drawing.positions[0];
|
||||
|
||||
// 圆心控制点
|
||||
const centerHandle = this.createHandle(center, 'center', 'red', 15);
|
||||
this.editHandles.push(centerHandle);
|
||||
|
||||
// 半径控制点
|
||||
if (drawing.positions.length > 1) {
|
||||
const radiusPoint = drawing.positions[1];
|
||||
const radiusHandle = this.createHandle(radiusPoint, 'radius', 'blue', 12);
|
||||
this.editHandles.push(radiusHandle);
|
||||
} else {
|
||||
// 如果没有半径点,创建一个默认的
|
||||
const radius = drawing.properties?.radius || 1000;
|
||||
const radiusPoint = this.calculateRadiusPoint(center, radius);
|
||||
const radiusHandle = this.createHandle(radiusPoint, 'radius', 'blue', 12);
|
||||
this.editHandles.push(radiusHandle);
|
||||
drawing.positions[1] = radiusPoint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建多边形控制点
|
||||
*/
|
||||
private createPolygonHandles(drawing: any): void {
|
||||
drawing.positions.forEach((position: Cesium.Cartesian3, index: number) => {
|
||||
const handle = this.createHandle(position, 'vertex', 'red', 12, index);
|
||||
this.editHandles.push(handle);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建控制点实体
|
||||
*/
|
||||
private createHandle(
|
||||
position: Cesium.Cartesian3,
|
||||
type: 'vertex' | 'center' | 'radius',
|
||||
color: string,
|
||||
size: number,
|
||||
index?: number
|
||||
): EditHandle {
|
||||
const id = `handle_${type}_${Date.now()}_${Math.random()}`;
|
||||
|
||||
const entity = this.viewer.entities.add({
|
||||
id: id,
|
||||
position: position,
|
||||
point: {
|
||||
pixelSize: size,
|
||||
color: Cesium.Color.fromCssColorString(color),
|
||||
outlineColor: Cesium.Color.WHITE,
|
||||
outlineWidth: 2,
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
position,
|
||||
entity,
|
||||
index
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算圆形半径点
|
||||
*/
|
||||
private calculateRadiusPoint(center: Cesium.Cartesian3, radius: number): Cesium.Cartesian3 {
|
||||
const cartographic = Cesium.Cartographic.fromCartesian(center);
|
||||
const newLat = cartographic.latitude + (radius / 6371000.0);
|
||||
|
||||
return Cesium.Cartesian3.fromRadians(
|
||||
cartographic.longitude,
|
||||
newLat,
|
||||
cartographic.height
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置事件监听
|
||||
*/
|
||||
private setupEventListeners(): void {
|
||||
let draggedHandle: EditHandle | null = null;
|
||||
|
||||
// 鼠标按下
|
||||
this.handler.setInputAction((event: any) => {
|
||||
const pickedObject = this.viewer.scene.pick(event.position);
|
||||
if (!pickedObject?.id) return;
|
||||
|
||||
// 检查是否点击了控制点
|
||||
const handle = this.editHandles.find(h => h.entity === pickedObject.id);
|
||||
if (handle) {
|
||||
draggedHandle = handle;
|
||||
this.viewer.scene.screenSpaceCameraController.enableInputs = false;
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
|
||||
|
||||
// 鼠标移动
|
||||
this.handler.setInputAction((event: any) => {
|
||||
if (!draggedHandle) return;
|
||||
|
||||
const newPosition = this.viewer.scene.pickPosition(event.endPosition);
|
||||
if (!newPosition) return;
|
||||
|
||||
// 更新控制点位置
|
||||
draggedHandle.position = newPosition;
|
||||
draggedHandle.entity.position = newPosition;
|
||||
|
||||
// 更新空域几何
|
||||
this.updateDrawingGeometry(draggedHandle, newPosition);
|
||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
|
||||
// 鼠标释放
|
||||
this.handler.setInputAction(() => {
|
||||
if (draggedHandle) {
|
||||
this.viewer.scene.screenSpaceCameraController.enableInputs = true;
|
||||
draggedHandle = null;
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_UP);
|
||||
|
||||
// ESC键取消
|
||||
const escapeHandler = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
this.cancelEditing();
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', escapeHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新空域几何
|
||||
*/
|
||||
private updateDrawingGeometry(handle: EditHandle, newPosition: Cesium.Cartesian3): void {
|
||||
if (!this.currentDrawing) return;
|
||||
|
||||
if (this.currentDrawing.type === 'circle') {
|
||||
this.updateCircleGeometry(handle, newPosition);
|
||||
} else if (this.currentDrawing.type === 'polygon') {
|
||||
this.updatePolygonGeometry(handle, newPosition);
|
||||
}
|
||||
|
||||
// 更新空域实体
|
||||
this.updateDrawingEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新圆形几何
|
||||
*/
|
||||
private updateCircleGeometry(handle: EditHandle, newPosition: Cesium.Cartesian3): void {
|
||||
if (handle.type === 'center') {
|
||||
// 移动圆心
|
||||
this.currentDrawing.positions[0] = newPosition;
|
||||
} else if (handle.type === 'radius') {
|
||||
// 更新半径点
|
||||
this.currentDrawing.positions[1] = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新多边形几何
|
||||
*/
|
||||
private updatePolygonGeometry(handle: EditHandle, newPosition: Cesium.Cartesian3): void {
|
||||
if (handle.type === 'vertex' && handle.index !== undefined) {
|
||||
this.currentDrawing.positions[handle.index] = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新空域实体
|
||||
*/
|
||||
private updateDrawingEntity(): void {
|
||||
if (!this.currentDrawing?.entity) return;
|
||||
|
||||
if (this.currentDrawing.type === 'circle') {
|
||||
this.updateCircleEntity();
|
||||
} else if (this.currentDrawing.type === 'polygon') {
|
||||
this.updatePolygonEntity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新圆形实体
|
||||
*/
|
||||
private updateCircleEntity(): void {
|
||||
const center = this.currentDrawing.positions[0];
|
||||
let radius = 1000;
|
||||
|
||||
if (this.currentDrawing.positions.length > 1) {
|
||||
radius = Cesium.Cartesian3.distance(center, this.currentDrawing.positions[1]);
|
||||
}
|
||||
|
||||
this.currentDrawing.entity.position = center;
|
||||
|
||||
if (this.currentDrawing.entity.ellipse) {
|
||||
this.currentDrawing.entity.ellipse.semiMinorAxis = radius;
|
||||
this.currentDrawing.entity.ellipse.semiMajorAxis = radius;
|
||||
}
|
||||
|
||||
// 更新标签
|
||||
if (this.currentDrawing.entity.label) {
|
||||
this.currentDrawing.entity.label.text = `圆形空域\n半径: ${(radius / 1000).toFixed(2)}km`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新多边形实体
|
||||
*/
|
||||
private updatePolygonEntity(): void {
|
||||
if (this.currentDrawing.entity.polygon) {
|
||||
this.currentDrawing.entity.polygon.hierarchy = new Cesium.PolygonHierarchy(
|
||||
this.currentDrawing.positions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮显示编辑中的空域
|
||||
*/
|
||||
private highlightDrawing(highlight: boolean): void {
|
||||
if (!this.currentDrawing?.entity) return;
|
||||
|
||||
const color = highlight ? Cesium.Color.RED : Cesium.Color.YELLOW;
|
||||
|
||||
if (this.currentDrawing.entity.ellipse) {
|
||||
this.currentDrawing.entity.ellipse.outlineColor = color;
|
||||
this.currentDrawing.entity.ellipse.outlineWidth = highlight ? 4 : 2;
|
||||
} else if (this.currentDrawing.entity.polygon) {
|
||||
this.currentDrawing.entity.polygon.outlineColor = color;
|
||||
this.currentDrawing.entity.polygon.outlineWidth = highlight ? 4 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成编辑
|
||||
*/
|
||||
finishEditing(): void {
|
||||
if (!this.isEditing) return;
|
||||
|
||||
console.log('完成编辑');
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消编辑
|
||||
*/
|
||||
cancelEditing(): void {
|
||||
if (!this.isEditing) return;
|
||||
|
||||
console.log('取消编辑');
|
||||
|
||||
// 恢复原始位置
|
||||
if (this.currentDrawing) {
|
||||
this.currentDrawing.positions = [...this.originalPositions];
|
||||
this.updateDrawingEntity();
|
||||
}
|
||||
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
private cleanup(): void {
|
||||
this.clearEditHandles();
|
||||
this.removeEventListeners();
|
||||
this.highlightDrawing(false);
|
||||
|
||||
this.isEditing = false;
|
||||
this.currentDrawing = null;
|
||||
this.originalPositions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除编辑控制点
|
||||
*/
|
||||
private clearEditHandles(): void {
|
||||
this.editHandles.forEach(handle => {
|
||||
this.viewer.entities.remove(handle.entity);
|
||||
});
|
||||
this.editHandles = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除事件监听
|
||||
*/
|
||||
private removeEventListeners(): void {
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);
|
||||
|
||||
// 移除ESC键监听
|
||||
document.removeEventListener('keydown', this.escapeHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* ESC键处理函数
|
||||
*/
|
||||
private escapeHandler = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
this.cancelEditing();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取编辑状态
|
||||
*/
|
||||
getEditingState(): { isEditing: boolean; currentDrawing: any } {
|
||||
return {
|
||||
isEditing: this.isEditing,
|
||||
currentDrawing: this.currentDrawing
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁编辑器
|
||||
*/
|
||||
destroy(): void {
|
||||
this.cleanup();
|
||||
this.handler.destroy();
|
||||
}
|
||||
}
|
@ -50,7 +50,10 @@ export interface DrawingResult {
|
||||
info: DrawingInfo; // 新增信息字段
|
||||
}
|
||||
|
||||
import { AirspaceEditor } from './AirspaceEditor';
|
||||
|
||||
export class DrawingTool {
|
||||
private airspaceEditor: AirspaceEditor;
|
||||
private viewer: Cesium.Viewer;
|
||||
private handler: Cesium.ScreenSpaceEventHandler;
|
||||
private entities: Cesium.EntityCollection;
|
||||
@ -83,6 +86,7 @@ export class DrawingTool {
|
||||
this.viewer = viewer;
|
||||
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
||||
this.entities = viewer.entities;
|
||||
this.airspaceEditor = new AirspaceEditor(viewer);
|
||||
|
||||
// 初始化点击事件监听
|
||||
this.initClickHandler();
|
||||
@ -262,6 +266,55 @@ export class DrawingTool {
|
||||
return perimeter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始编辑空域
|
||||
*/
|
||||
startEditing(drawingId: string): void {
|
||||
console.log('开始编辑空域:', drawingId);
|
||||
|
||||
const drawing = this.drawingEntities.get(drawingId);
|
||||
if (!drawing) {
|
||||
console.error('未找到空域:', drawingId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.airspaceEditor.startEditing(drawing);
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成编辑
|
||||
*/
|
||||
finishEditing(): void {
|
||||
this.airspaceEditor.finishEditing();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消编辑
|
||||
*/
|
||||
cancelEditing(): void {
|
||||
this.airspaceEditor.cancelEditing();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取编辑状态
|
||||
*/
|
||||
getEditingState(): { isEditing: boolean; currentDrawing: any } {
|
||||
return this.airspaceEditor.getEditingState();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在编辑
|
||||
*/
|
||||
isEditing(): boolean {
|
||||
return this.airspaceEditor.getEditingState().isEditing;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前编辑的空域
|
||||
*/
|
||||
getCurrentEditingDrawing(): any {
|
||||
return this.airspaceEditor.getEditingState().currentDrawing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -8,6 +8,63 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
||||
const drawings = reactive(new Map<string, DrawingResult>());
|
||||
const selectedDrawing = ref<string | null>(null);
|
||||
const drawingInfo = ref<DrawingInfo | null>(null);
|
||||
const isEditing = ref(false);
|
||||
const editingDrawing = ref<any>(null);
|
||||
|
||||
/**
|
||||
* 开始编辑空域
|
||||
*/
|
||||
const startEditing = (drawingId: string): void => {
|
||||
console.log('开始编辑:', drawingId);
|
||||
|
||||
const tool = getTool();
|
||||
if (!tool) {
|
||||
console.error('绘图工具未初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
tool.startEditing(drawingId);
|
||||
|
||||
// 更新状态
|
||||
const editingState = tool.getEditingState();
|
||||
isEditing.value = editingState.isEditing;
|
||||
editingDrawing.value = editingState.currentDrawing;
|
||||
};
|
||||
|
||||
/**
|
||||
* 完成编辑
|
||||
*/
|
||||
const finishEditing = (): void => {
|
||||
const tool = getTool();
|
||||
if (tool) {
|
||||
tool.finishEditing();
|
||||
isEditing.value = false;
|
||||
editingDrawing.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消编辑
|
||||
*/
|
||||
const cancelEditing = (): void => {
|
||||
const tool = getTool();
|
||||
if (tool) {
|
||||
tool.cancelEditing();
|
||||
isEditing.value = false;
|
||||
editingDrawing.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取编辑状态
|
||||
*/
|
||||
const getEditingState = () => {
|
||||
const tool = getTool();
|
||||
if (tool) {
|
||||
return tool.getEditingState();
|
||||
}
|
||||
return { isEditing: false, currentDrawing: null };
|
||||
};
|
||||
|
||||
// 绘图选项
|
||||
const drawingOptions = reactive<{
|
||||
@ -571,6 +628,12 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
||||
importAirspaceData,
|
||||
importFromGeoJSON,
|
||||
importFromFile,
|
||||
getImportStatistics
|
||||
getImportStatistics,
|
||||
isEditing,
|
||||
editingDrawing,
|
||||
startEditing,
|
||||
finishEditing,
|
||||
cancelEditing,
|
||||
getEditingState
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user