cesium地图空域的导入导出及定位
This commit is contained in:
parent
838d0878aa
commit
e8b8d12623
1
auto-imports.d.ts
vendored
1
auto-imports.d.ts
vendored
@ -2,7 +2,6 @@
|
|||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: typeof import('vue')['computed']
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue')['createApp']
|
||||||
const customRef: typeof import('vue')['customRef']
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
|||||||
@ -74,6 +74,17 @@
|
|||||||
@print-drawing-info="handlePrintDrawingInfo"
|
@print-drawing-info="handlePrintDrawingInfo"
|
||||||
@export-drawing-info="handleExportDrawingInfo"
|
@export-drawing-info="handleExportDrawingInfo"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 导入工具面板 -->
|
||||||
|
<ImportToolPanel
|
||||||
|
v-if="isInitialized"
|
||||||
|
:import-from-file="importFromFile"
|
||||||
|
:import-airspace-data="importAirspaceData"
|
||||||
|
:get-import-statistics="getImportStatistics"
|
||||||
|
@import-complete="handleImportComplete"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -88,6 +99,7 @@ import { useDrawingManager } from './components/useDrawingManager';
|
|||||||
import ModelControlPanel from './ModelControlPanel.vue';
|
import ModelControlPanel from './ModelControlPanel.vue';
|
||||||
import CoordinatePickerPanel from './CoordinatePickerPanel.vue';
|
import CoordinatePickerPanel from './CoordinatePickerPanel.vue';
|
||||||
import DrawingToolPanel from './DrawingToolPanel.vue';
|
import DrawingToolPanel from './DrawingToolPanel.vue';
|
||||||
|
import ImportToolPanel from './ImportToolPanel.vue';
|
||||||
|
|
||||||
|
|
||||||
const cesiumContainer = ref<HTMLElement>();
|
const cesiumContainer = ref<HTMLElement>();
|
||||||
@ -161,7 +173,11 @@ const {
|
|||||||
printSelectedDrawingInfo,
|
printSelectedDrawingInfo,
|
||||||
printAllDrawingsInfo,
|
printAllDrawingsInfo,
|
||||||
printDrawingInfo,
|
printDrawingInfo,
|
||||||
exportSelectedDrawingAsText
|
exportSelectedDrawingAsText,
|
||||||
|
importAirspaceData,
|
||||||
|
importFromFile,
|
||||||
|
importFromGeoJSON,
|
||||||
|
getImportStatistics
|
||||||
} = useDrawingManager(drawingTool);
|
} = useDrawingManager(drawingTool);
|
||||||
|
|
||||||
|
|
||||||
@ -267,6 +283,22 @@ const flyToSelectedDrawing = () => {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
// 处理导入完成
|
||||||
|
const handleImportComplete = (result: any) => {
|
||||||
|
console.log('导入完成:', result);
|
||||||
|
// 可以在这里添加导入完成后的处理逻辑
|
||||||
|
if (result.success) {
|
||||||
|
showMessage(`成功导入 ${result.importedIds.length} 个空域`, 'success');
|
||||||
|
} else {
|
||||||
|
showMessage('导入失败', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 消息提示函数
|
||||||
|
const showMessage = (message: string, type: 'success' | 'error' | 'info' = 'info') => {
|
||||||
|
// 实现消息提示...
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 开始跟踪相机信息
|
// 开始跟踪相机信息
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
532
src/views/cesiums/ImportToolPanel.vue
Normal file
532
src/views/cesiums/ImportToolPanel.vue
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
<!-- src/components/ImportToolPanel.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="import-tool-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<h3>📥 空域导入工具</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-section">
|
||||||
|
<h4>文件导入</h4>
|
||||||
|
<div class="file-import">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
ref="fileInput"
|
||||||
|
@change="handleFileSelect"
|
||||||
|
accept=".json,.geojson"
|
||||||
|
style="display: none"
|
||||||
|
/>
|
||||||
|
<button @click="triggerFileInput" class="import-btn file-btn">
|
||||||
|
📁 选择文件导入
|
||||||
|
</button>
|
||||||
|
<div class="file-info" v-if="selectedFile">
|
||||||
|
<span>已选择: {{ selectedFile.name }}</span>
|
||||||
|
<button @click="clearFile" class="clear-file-btn">×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="import-options">
|
||||||
|
<label class="option-checkbox">
|
||||||
|
<input type="checkbox" v-model="importOptions.autoZoom" />
|
||||||
|
导入后自动缩放
|
||||||
|
</label>
|
||||||
|
<label class="option-checkbox">
|
||||||
|
<input type="checkbox" v-model="importOptions.mergeExisting" />
|
||||||
|
合并现有空域
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click="executeFileImport"
|
||||||
|
class="import-btn execute-btn"
|
||||||
|
:disabled="!selectedFile || isImporting"
|
||||||
|
>
|
||||||
|
{{ isImporting ? '⏳ 导入中...' : '🚀 执行导入' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-section">
|
||||||
|
<h4>数据导入</h4>
|
||||||
|
<div class="data-import">
|
||||||
|
<textarea
|
||||||
|
v-model="jsonInput"
|
||||||
|
placeholder="在此粘贴JSON或GeoJSON数据..."
|
||||||
|
class="json-input"
|
||||||
|
rows="8"
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
@click="executeJsonImport"
|
||||||
|
class="import-btn json-btn"
|
||||||
|
:disabled="!jsonInput.trim() || isImporting"
|
||||||
|
>
|
||||||
|
{{ isImporting ? '⏳ 导入中...' : '📋 导入JSON数据' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-section" v-if="importResult">
|
||||||
|
<h4>导入结果</h4>
|
||||||
|
<div class="import-result" :class="importResult.success ? 'success' : 'error'">
|
||||||
|
<div class="result-icon">
|
||||||
|
{{ importResult.success ? '✅' : '❌' }}
|
||||||
|
</div>
|
||||||
|
<div class="result-content">
|
||||||
|
<div class="result-message">{{ importResult.message }}</div>
|
||||||
|
<div v-if="importResult.importedIds" class="result-details">
|
||||||
|
导入ID: {{ importResult.importedIds.join(', ') }}
|
||||||
|
</div>
|
||||||
|
<div v-if="importResult.statistics" class="result-statistics">
|
||||||
|
圆形: {{ importResult.statistics.circles }}个,
|
||||||
|
多边形: {{ importResult.statistics.polygons }}个,
|
||||||
|
总计: {{ importResult.statistics.total }}个
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-section">
|
||||||
|
<h4>示例数据</h4>
|
||||||
|
<div class="sample-data">
|
||||||
|
<button @click="loadSampleData" class="sample-btn">
|
||||||
|
🎯 加载示例数据
|
||||||
|
</button>
|
||||||
|
<div class="sample-description">
|
||||||
|
加载示例圆形和多边形空域数据用于测试
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-section help-section">
|
||||||
|
<h4>支持格式</h4>
|
||||||
|
<ul class="format-list">
|
||||||
|
<li>✅ <strong>JSON数组</strong>: 包含空域对象的数组</li>
|
||||||
|
<li>✅ <strong>GeoJSON</strong>: 标准的GeoJSON格式</li>
|
||||||
|
<li>✅ <strong>文件类型</strong>: .json, .geojson</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>数据格式示例</h4>
|
||||||
|
<pre class="format-example">{{ formatExample }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
importFromFile: (file: File, options: any) => Promise<string[]>;
|
||||||
|
importAirspaceData: (data: any[], options: any) => string[];
|
||||||
|
getImportStatistics: () => { total: number; circles: number; polygons: number };
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'import-complete': [result: any];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const fileInput = ref<HTMLInputElement>();
|
||||||
|
const selectedFile = ref<File | null>(null);
|
||||||
|
const jsonInput = ref('');
|
||||||
|
const isImporting = ref(false);
|
||||||
|
const importResult = ref<any>(null);
|
||||||
|
|
||||||
|
const importOptions = ref({
|
||||||
|
autoZoom: true,
|
||||||
|
mergeExisting: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// 触发文件选择
|
||||||
|
const triggerFileInput = () => {
|
||||||
|
fileInput.value?.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理文件选择
|
||||||
|
const handleFileSelect = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
if (target.files && target.files[0]) {
|
||||||
|
selectedFile.value = target.files[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除文件选择
|
||||||
|
const clearFile = () => {
|
||||||
|
selectedFile.value = null;
|
||||||
|
if (fileInput.value) {
|
||||||
|
fileInput.value.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行文件导入
|
||||||
|
const executeFileImport = async () => {
|
||||||
|
if (!selectedFile.value) return;
|
||||||
|
|
||||||
|
isImporting.value = true;
|
||||||
|
importResult.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const importedIds = await props.importFromFile(selectedFile.value, importOptions.value);
|
||||||
|
|
||||||
|
const statistics = props.getImportStatistics();
|
||||||
|
importResult.value = {
|
||||||
|
success: true,
|
||||||
|
message: `成功导入 ${importedIds.length} 个空域`,
|
||||||
|
importedIds,
|
||||||
|
statistics
|
||||||
|
};
|
||||||
|
|
||||||
|
emit('import-complete', importResult.value);
|
||||||
|
} catch (error) {
|
||||||
|
importResult.value = {
|
||||||
|
success: false,
|
||||||
|
message: `导入失败: ${error}`
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
isImporting.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行JSON导入
|
||||||
|
const executeJsonImport = () => {
|
||||||
|
if (!jsonInput.value.trim()) return;
|
||||||
|
|
||||||
|
isImporting.value = true;
|
||||||
|
importResult.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(jsonInput.value);
|
||||||
|
const importedIds = props.importAirspaceData(data, importOptions.value);
|
||||||
|
|
||||||
|
const statistics = props.getImportStatistics();
|
||||||
|
importResult.value = {
|
||||||
|
success: true,
|
||||||
|
message: `成功导入 ${importedIds.length} 个空域`,
|
||||||
|
importedIds,
|
||||||
|
statistics
|
||||||
|
};
|
||||||
|
|
||||||
|
emit('import-complete', importResult.value);
|
||||||
|
} catch (error) {
|
||||||
|
importResult.value = {
|
||||||
|
success: false,
|
||||||
|
message: `JSON解析失败: ${error}`
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
isImporting.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载示例数据
|
||||||
|
const loadSampleData = () => {
|
||||||
|
const sampleData = [
|
||||||
|
{
|
||||||
|
id: 'sample_circle_1',
|
||||||
|
type: 'circle',
|
||||||
|
coordinates: {
|
||||||
|
center: {
|
||||||
|
longitude: 106.5516,
|
||||||
|
latitude: 29.5630,
|
||||||
|
height: 500
|
||||||
|
},
|
||||||
|
radius: 2000
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: '示例圆形空域1',
|
||||||
|
color: '#FF6B6B',
|
||||||
|
outlineColor: '#C44D4D'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sample_circle_2',
|
||||||
|
type: 'circle',
|
||||||
|
coordinates: {
|
||||||
|
center: {
|
||||||
|
longitude: 106.5716,
|
||||||
|
latitude: 29.5730,
|
||||||
|
height: 500
|
||||||
|
},
|
||||||
|
radius: 1500
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: '示例圆形空域2',
|
||||||
|
color: '#4ECDC4',
|
||||||
|
outlineColor: '#3AA39C'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sample_polygon_1',
|
||||||
|
type: 'polygon',
|
||||||
|
coordinates: [
|
||||||
|
{ longitude: 106.5400, latitude: 29.5500, height: 300 },
|
||||||
|
{ longitude: 106.5600, latitude: 29.5500, height: 300 },
|
||||||
|
{ longitude: 106.5600, latitude: 29.5700, height: 300 },
|
||||||
|
{ longitude: 106.5400, latitude: 29.5700, height: 300 }
|
||||||
|
],
|
||||||
|
properties: {
|
||||||
|
name: '示例多边形空域1',
|
||||||
|
color: '#45B7D1',
|
||||||
|
outlineColor: '#368EA6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
jsonInput.value = JSON.stringify(sampleData, null, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式示例
|
||||||
|
const formatExample = computed(() => {
|
||||||
|
return `{
|
||||||
|
"id": "airspace_001",
|
||||||
|
"type": "circle",
|
||||||
|
"coordinates": {
|
||||||
|
"center": {
|
||||||
|
"longitude": 106.5516,
|
||||||
|
"latitude": 29.5630,
|
||||||
|
"height": 500
|
||||||
|
},
|
||||||
|
"radius": 2000
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"name": "禁飞区",
|
||||||
|
"color": "#FF0000"
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.import-tool-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 220px;
|
||||||
|
background: rgba(42, 42, 42, 0.95);
|
||||||
|
color: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
min-width: 320px;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header h3 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-section h4 {
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-import {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-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.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-btn:not(:disabled):hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-btn {
|
||||||
|
background: rgba(76, 175, 80, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-btn:hover:not(:disabled) {
|
||||||
|
background: rgba(76, 175, 80, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-btn {
|
||||||
|
background: rgba(156, 39, 176, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-btn:hover:not(:disabled) {
|
||||||
|
background: rgba(156, 39, 176, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.execute-btn {
|
||||||
|
background: rgba(255, 152, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.execute-btn:hover:not(:disabled) {
|
||||||
|
background: rgba(255, 152, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-file-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #ff4d4f;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox input {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-import {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-input {
|
||||||
|
padding: 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-input::placeholder {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-result {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-result.success {
|
||||||
|
background: rgba(76, 175, 80, 0.2);
|
||||||
|
border: 1px solid rgba(76, 175, 80, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-result.error {
|
||||||
|
background: rgba(244, 67, 54, 0.2);
|
||||||
|
border: 1px solid rgba(244, 67, 54, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-message {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-details,
|
||||||
|
.result-statistics {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #ccc;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sample-data {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sample-btn {
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: rgba(33, 150, 243, 0.3);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sample-btn:hover {
|
||||||
|
background: rgba(33, 150, 243, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sample-description {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #ccc;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-section {
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-list li {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: #ccc;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-list strong {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-example {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #fff;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -19,7 +19,11 @@ export interface PolygonOptions extends DrawingOptions {
|
|||||||
closePath?: boolean;
|
closePath?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ImportOptions {
|
||||||
|
autoZoom?: boolean;
|
||||||
|
mergeExisting?: boolean;
|
||||||
|
coordinateSystem?: 'wgs84' | 'gcj02' | 'bd09';
|
||||||
|
}
|
||||||
|
|
||||||
export interface DrawingInfo {
|
export interface DrawingInfo {
|
||||||
id: string;
|
id: string;
|
||||||
@ -64,7 +68,7 @@ export class DrawingTool {
|
|||||||
fill: true,
|
fill: true,
|
||||||
classificationType: Cesium.ClassificationType.BOTH,
|
classificationType: Cesium.ClassificationType.BOTH,
|
||||||
height: 0,
|
height: 0,
|
||||||
extrudedHeight: 1000
|
extrudedHeight: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
private drawingCallbacks: {
|
private drawingCallbacks: {
|
||||||
@ -668,6 +672,467 @@ export class DrawingTool {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入空域数据
|
||||||
|
*/
|
||||||
|
importAirspaceData(data: any[], options: ImportOptions = {}): string[] {
|
||||||
|
console.log('=== 开始导入空域数据 ===');
|
||||||
|
console.log('导入数据:', data);
|
||||||
|
console.log('导入选项:', options);
|
||||||
|
|
||||||
|
const defaultOptions: ImportOptions = {
|
||||||
|
autoZoom: true,
|
||||||
|
mergeExisting: false,
|
||||||
|
coordinateSystem: 'wgs84'
|
||||||
|
};
|
||||||
|
const mergedOptions = { ...defaultOptions, ...options };
|
||||||
|
|
||||||
|
const importedIds: string[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 如果不合并现有数据,先清除所有
|
||||||
|
if (!mergedOptions.mergeExisting) {
|
||||||
|
this.clearAllDrawings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理每个空域数据
|
||||||
|
data.forEach((item, index) => {
|
||||||
|
try {
|
||||||
|
const entity = this.importSingleAirspace(item, mergedOptions);
|
||||||
|
if (entity) {
|
||||||
|
importedIds.push(item.id || `imported_${Date.now()}_${index}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`导入第 ${index + 1} 个空域时发生错误:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`✅ 成功导入 ${importedIds.length} 个空域`);
|
||||||
|
|
||||||
|
// 自动缩放显示所有导入的空域
|
||||||
|
if (mergedOptions.autoZoom && importedIds.length > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.zoomToImportedAirspaces(importedIds);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return importedIds;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 导入空域数据时发生错误:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入单个空域
|
||||||
|
*/
|
||||||
|
private importSingleAirspace(data: any, options: ImportOptions): Cesium.Entity | null {
|
||||||
|
try {
|
||||||
|
// 验证数据
|
||||||
|
if (!this.validateAirspaceData(data)) {
|
||||||
|
console.error('空域数据验证失败:', data);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { type, coordinates, properties = {} } = data;
|
||||||
|
const id = data.id || `imported_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
console.log(`导入空域 ${id}, 类型: ${type}`);
|
||||||
|
|
||||||
|
let positions: Cesium.Cartesian3[];
|
||||||
|
let entity: Cesium.Entity;
|
||||||
|
|
||||||
|
if (type === 'circle') {
|
||||||
|
entity = this.importCircleAirspace(id, coordinates, properties, options);
|
||||||
|
} else if (type === 'polygon') {
|
||||||
|
entity = this.importPolygonAirspace(id, coordinates, properties, options);
|
||||||
|
} else {
|
||||||
|
console.error('不支持的空域类型:', type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
// 生成绘图信息
|
||||||
|
const drawingInfo = this.generateDrawingInfo({
|
||||||
|
id,
|
||||||
|
type: type as 'circle' | 'polygon',
|
||||||
|
positions,
|
||||||
|
entity,
|
||||||
|
properties: {
|
||||||
|
...properties,
|
||||||
|
options: properties.options || this.defaultOptions,
|
||||||
|
area: properties.area || 0
|
||||||
|
}
|
||||||
|
} as DrawingResult);
|
||||||
|
|
||||||
|
// 保存到绘图实体集合
|
||||||
|
const drawingResult: DrawingResult = {
|
||||||
|
id,
|
||||||
|
type: type as 'circle' | 'polygon',
|
||||||
|
positions,
|
||||||
|
entity,
|
||||||
|
properties: {
|
||||||
|
...properties,
|
||||||
|
imported: true, // 标记为导入的空域
|
||||||
|
importTime: new Date().toISOString()
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
...drawingInfo,
|
||||||
|
area: properties.area || this.calculateArea(positions, type as 'circle' | 'polygon')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.drawingEntities.set(id, drawingResult);
|
||||||
|
console.log(`✅ 成功导入空域: ${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导入单个空域时发生错误:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入圆形空域
|
||||||
|
*/
|
||||||
|
private importCircleAirspace(
|
||||||
|
id: string,
|
||||||
|
coordinates: any,
|
||||||
|
properties: any,
|
||||||
|
options: ImportOptions
|
||||||
|
): Cesium.Entity {
|
||||||
|
const { center, radius } = coordinates;
|
||||||
|
|
||||||
|
// 坐标转换
|
||||||
|
const convertedCenter = this.convertCoordinates(
|
||||||
|
center.longitude,
|
||||||
|
center.latitude,
|
||||||
|
center.height || 0,
|
||||||
|
options.coordinateSystem
|
||||||
|
);
|
||||||
|
|
||||||
|
const centerCartesian = Cesium.Cartesian3.fromDegrees(
|
||||||
|
convertedCenter.longitude,
|
||||||
|
convertedCenter.latitude,
|
||||||
|
convertedCenter.height
|
||||||
|
);
|
||||||
|
|
||||||
|
const positions = [centerCartesian];
|
||||||
|
if (radius > 0) {
|
||||||
|
const edgePoint = this.calculateCircleEdgePoint(convertedCenter, radius);
|
||||||
|
positions.push(edgePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
const entityOptions = {
|
||||||
|
color: properties.color ? Cesium.Color.fromCssColorString(properties.color) : this.defaultOptions.color,
|
||||||
|
outlineColor: properties.outlineColor ? Cesium.Color.fromCssColorString(properties.outlineColor) : this.defaultOptions.outlineColor,
|
||||||
|
outlineWidth: properties.outlineWidth || this.defaultOptions.outlineWidth,
|
||||||
|
height: properties.height || this.defaultOptions.height,
|
||||||
|
extrudedHeight: properties.extrudedHeight || this.defaultOptions.extrudedHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.createCircleEntity(id, positions, entityOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入多边形空域
|
||||||
|
*/
|
||||||
|
private importPolygonAirspace(
|
||||||
|
id: string,
|
||||||
|
coordinates: any,
|
||||||
|
properties: any,
|
||||||
|
options: ImportOptions
|
||||||
|
): Cesium.Entity {
|
||||||
|
const positions = coordinates.map((coord: any) => {
|
||||||
|
const convertedCoord = this.convertCoordinates(
|
||||||
|
coord.longitude,
|
||||||
|
coord.latitude,
|
||||||
|
coord.height || 0,
|
||||||
|
options.coordinateSystem
|
||||||
|
);
|
||||||
|
|
||||||
|
return Cesium.Cartesian3.fromDegrees(
|
||||||
|
convertedCoord.longitude,
|
||||||
|
convertedCoord.latitude,
|
||||||
|
convertedCoord.height
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const entityOptions = {
|
||||||
|
color: properties.color ? Cesium.Color.fromCssColorString(properties.color) : this.defaultOptions.color,
|
||||||
|
outlineColor: properties.outlineColor ? Cesium.Color.fromCssColorString(properties.outlineColor) : this.defaultOptions.outlineColor,
|
||||||
|
outlineWidth: properties.outlineWidth || this.defaultOptions.outlineWidth,
|
||||||
|
height: properties.height || this.defaultOptions.height,
|
||||||
|
extrudedHeight: properties.extrudedHeight || this.defaultOptions.extrudedHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.createPolygonEntity(id, positions, entityOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证空域数据
|
||||||
|
*/
|
||||||
|
private validateAirspaceData(data: any): boolean {
|
||||||
|
if (!data) {
|
||||||
|
console.error('空域数据为空');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.type) {
|
||||||
|
console.error('空域类型未定义');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.coordinates) {
|
||||||
|
console.error('空域坐标未定义');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.type === 'circle') {
|
||||||
|
if (!data.coordinates.center || !data.coordinates.radius) {
|
||||||
|
console.error('圆形空域缺少中心点或半径');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (data.type === 'polygon') {
|
||||||
|
if (!Array.isArray(data.coordinates) || data.coordinates.length < 3) {
|
||||||
|
console.error('多边形空域坐标无效');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('不支持的空域类型:', data.type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 坐标转换(支持不同坐标系)
|
||||||
|
*/
|
||||||
|
private convertCoordinates(
|
||||||
|
longitude: number,
|
||||||
|
latitude: number,
|
||||||
|
height: number,
|
||||||
|
coordinateSystem: string = 'wgs84'
|
||||||
|
): { longitude: number; latitude: number; height: number } {
|
||||||
|
// 这里可以添加坐标转换逻辑
|
||||||
|
// 目前只支持WGS84,可以扩展支持GCJ02、BD09等
|
||||||
|
switch (coordinateSystem) {
|
||||||
|
case 'wgs84':
|
||||||
|
return { longitude, latitude, height };
|
||||||
|
case 'gcj02':
|
||||||
|
// 这里可以添加GCJ02到WGS84的转换
|
||||||
|
console.warn('GCJ02坐标转换暂未实现,使用原始坐标');
|
||||||
|
return { longitude, latitude, height };
|
||||||
|
case 'bd09':
|
||||||
|
// 这里可以添加BD09到WGS84的转换
|
||||||
|
console.warn('BD09坐标转换暂未实现,使用原始坐标');
|
||||||
|
return { longitude, latitude, height };
|
||||||
|
default:
|
||||||
|
console.warn(`不支持的坐标系: ${coordinateSystem},使用WGS84`);
|
||||||
|
return { longitude, latitude, height };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算圆形边缘点(用于确定半径)
|
||||||
|
*/
|
||||||
|
private calculateCircleEdgePoint(center: any, radius: number): Cesium.Cartesian3 {
|
||||||
|
const earthRadius = 6371000; // 地球半径(米)
|
||||||
|
const angularDistance = radius / earthRadius;
|
||||||
|
|
||||||
|
// 在正北方向计算边缘点
|
||||||
|
const edgeLat = center.latitude + (angularDistance * 180 / Math.PI);
|
||||||
|
|
||||||
|
return Cesium.Cartesian3.fromDegrees(
|
||||||
|
center.longitude,
|
||||||
|
edgeLat,
|
||||||
|
center.height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩放显示导入的空域
|
||||||
|
*/
|
||||||
|
private zoomToImportedAirspaces(importedIds: string[]): void {
|
||||||
|
try {
|
||||||
|
const entities: Cesium.Entity[] = [];
|
||||||
|
|
||||||
|
importedIds.forEach(id => {
|
||||||
|
const drawing = this.drawingEntities.get(id);
|
||||||
|
if (drawing) {
|
||||||
|
entities.push(drawing.entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entities.length > 0) {
|
||||||
|
this.viewer.zoomTo(entities, new Cesium.HeadingPitchRange(0, -Math.PI/4, 0));
|
||||||
|
console.log('✅ 已缩放显示导入的空域');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('缩放显示导入空域时发生错误:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从GeoJSON导入空域
|
||||||
|
*/
|
||||||
|
importFromGeoJSON(geoJSON: any, options: ImportOptions = {}): string[] {
|
||||||
|
console.log('=== 从GeoJSON导入空域 ===');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!geoJSON || !geoJSON.features) {
|
||||||
|
console.error('无效的GeoJSON数据');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const airspaceData: any[] = [];
|
||||||
|
|
||||||
|
geoJSON.features.forEach((feature: any, index: number) => {
|
||||||
|
try {
|
||||||
|
const airspace = this.convertGeoJSONToAirspace(feature, index);
|
||||||
|
if (airspace) {
|
||||||
|
airspaceData.push(airspace);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`转换GeoJSON要素 ${index} 时发生错误:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.importAirspaceData(airspaceData, options);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导入GeoJSON时发生错误:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将GeoJSON要素转换为空域数据
|
||||||
|
*/
|
||||||
|
private convertGeoJSONToAirspace(feature: any, index: number): any {
|
||||||
|
const { geometry, properties } = feature;
|
||||||
|
|
||||||
|
if (!geometry || !geometry.coordinates) {
|
||||||
|
console.error('GeoJSON要素缺少几何数据');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const airspace: any = {
|
||||||
|
id: feature.id || `geojson_${Date.now()}_${index}`,
|
||||||
|
type: '',
|
||||||
|
coordinates: null,
|
||||||
|
properties: properties || {}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (geometry.type) {
|
||||||
|
case 'Polygon':
|
||||||
|
airspace.type = 'polygon';
|
||||||
|
// GeoJSON多边形坐标是三维数组,取第一个环(外环)
|
||||||
|
airspace.coordinates = geometry.coordinates[0].map((coord: number[]) => ({
|
||||||
|
longitude: coord[0],
|
||||||
|
latitude: coord[1],
|
||||||
|
height: coord[2] || 0
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Point':
|
||||||
|
airspace.type = 'circle';
|
||||||
|
// 将点转换为圆形,默认半径1000米
|
||||||
|
airspace.coordinates = {
|
||||||
|
center: {
|
||||||
|
longitude: geometry.coordinates[0],
|
||||||
|
latitude: geometry.coordinates[1],
|
||||||
|
height: geometry.coordinates[2] || 0
|
||||||
|
},
|
||||||
|
radius: properties?.radius || 1000
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.warn(`不支持的GeoJSON几何类型: ${geometry.type}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return airspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文件导入空域
|
||||||
|
*/
|
||||||
|
async importFromFile(file: File, options: ImportOptions = {}): Promise<string[]> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
console.log('=== 从文件导入空域 ===');
|
||||||
|
console.log('文件:', file);
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = (e) => {
|
||||||
|
try {
|
||||||
|
const content = e.target?.result as string;
|
||||||
|
let data;
|
||||||
|
|
||||||
|
// 根据文件类型解析
|
||||||
|
if (file.name.endsWith('.json')) {
|
||||||
|
data = JSON.parse(content);
|
||||||
|
} else if (file.name.endsWith('.geojson')) {
|
||||||
|
data = JSON.parse(content);
|
||||||
|
resolve(this.importFromGeoJSON(data, options));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.error('不支持的文件格式:', file.name);
|
||||||
|
resolve([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断数据格式
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
resolve(this.importAirspaceData(data, options));
|
||||||
|
} else if (data.features) {
|
||||||
|
resolve(this.importFromGeoJSON(data, options));
|
||||||
|
} else {
|
||||||
|
console.error('无法识别的数据格式');
|
||||||
|
resolve([]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析文件时发生错误:', error);
|
||||||
|
resolve([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = () => {
|
||||||
|
console.error('读取文件时发生错误');
|
||||||
|
resolve([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导入的空域统计信息
|
||||||
|
*/
|
||||||
|
getImportStatistics(): { total: number; circles: number; polygons: number } {
|
||||||
|
let circles = 0;
|
||||||
|
let polygons = 0;
|
||||||
|
|
||||||
|
this.drawingEntities.forEach((drawing) => {
|
||||||
|
if (drawing.properties.imported) {
|
||||||
|
if (drawing.type === 'circle') {
|
||||||
|
circles++;
|
||||||
|
} else {
|
||||||
|
polygons++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
total: circles + polygons,
|
||||||
|
circles,
|
||||||
|
polygons
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印空域基本信息
|
* 打印空域基本信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
|||||||
outlineWidth: 2,
|
outlineWidth: 2,
|
||||||
fill: true,
|
fill: true,
|
||||||
height: 0,
|
height: 0,
|
||||||
extrudedHeight: 1000
|
extrudedHeight: 0
|
||||||
},
|
},
|
||||||
polygon: {
|
polygon: {
|
||||||
color: Cesium.Color.CYAN.withAlpha(0.3),
|
color: Cesium.Color.CYAN.withAlpha(0.3),
|
||||||
@ -28,7 +28,7 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
|||||||
outlineWidth: 2,
|
outlineWidth: 2,
|
||||||
fill: true,
|
fill: true,
|
||||||
height: 0,
|
height: 0,
|
||||||
extrudedHeight: 1000,
|
extrudedHeight: 0,
|
||||||
closePath: true
|
closePath: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -302,6 +302,61 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
|||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入空域数据
|
||||||
|
*/
|
||||||
|
const importAirspaceData = (data: any[], options: ImportOptions = {}): string[] => {
|
||||||
|
const tool = getTool();
|
||||||
|
if (!tool) {
|
||||||
|
console.error('❌ 绘图工具未初始化');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('开始导入空域数据,数量:', data.length);
|
||||||
|
return tool.importAirspaceData(data, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从GeoJSON导入空域
|
||||||
|
*/
|
||||||
|
const importFromGeoJSON = (geoJSON: any, options: ImportOptions = {}): string[] => {
|
||||||
|
const tool = getTool();
|
||||||
|
if (!tool) {
|
||||||
|
console.error('❌ 绘图工具未初始化');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tool.importFromGeoJSON(geoJSON, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文件导入空域
|
||||||
|
*/
|
||||||
|
const importFromFile = async (file: File, options: ImportOptions = {}): Promise<string[]> => {
|
||||||
|
const tool = getTool();
|
||||||
|
if (!tool) {
|
||||||
|
console.error('❌ 绘图工具未初始化');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return await tool.importFromFile(file, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导入统计
|
||||||
|
*/
|
||||||
|
const getImportStatistics = (): { total: number; circles: number; polygons: number } => {
|
||||||
|
const tool = getTool();
|
||||||
|
if (!tool) {
|
||||||
|
return { total: 0, circles: 0, polygons: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
return tool.getImportStatistics();
|
||||||
|
};
|
||||||
|
|
||||||
// 更新绘图选项
|
// 更新绘图选项
|
||||||
const updateDrawingOptions = (type: 'circle' | 'polygon', options: Partial<DrawingOptions>): void => {
|
const updateDrawingOptions = (type: 'circle' | 'polygon', options: Partial<DrawingOptions>): void => {
|
||||||
drawingOptions[type] = { ...drawingOptions[type], ...options };
|
drawingOptions[type] = { ...drawingOptions[type], ...options };
|
||||||
@ -512,6 +567,10 @@ export function useDrawingManager(drawingTool: any) { // 修改参数类型为 a
|
|||||||
getSelectedDrawingJSON,
|
getSelectedDrawingJSON,
|
||||||
getAllDrawingsJSON,
|
getAllDrawingsJSON,
|
||||||
exportSelectedDrawingAsText,
|
exportSelectedDrawingAsText,
|
||||||
flyToSelectedDrawing
|
flyToSelectedDrawing,
|
||||||
|
importAirspaceData,
|
||||||
|
importFromGeoJSON,
|
||||||
|
importFromFile,
|
||||||
|
getImportStatistics
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user