1326 lines
40 KiB
TypeScript
1326 lines
40 KiB
TypeScript
// src/utils/cesium/DrawingTool.ts
|
||
import * as Cesium from 'cesium';
|
||
|
||
export interface DrawingOptions {
|
||
color?: Cesium.Color;
|
||
outlineColor?: Cesium.Color;
|
||
outlineWidth?: number;
|
||
fill?: boolean;
|
||
classificationType?: Cesium.ClassificationType;
|
||
height?: number;
|
||
extrudedHeight?: number;
|
||
}
|
||
|
||
export interface CircleOptions extends DrawingOptions {
|
||
radius?: number;
|
||
}
|
||
|
||
export interface PolygonOptions extends DrawingOptions {
|
||
closePath?: boolean;
|
||
}
|
||
|
||
|
||
|
||
export interface DrawingInfo {
|
||
id: string;
|
||
type: 'circle' | 'polygon';
|
||
positions: Cesium.Cartesian3[];
|
||
center?: Cesium.Cartesian3; // 圆心(仅圆形)
|
||
radius?: number; // 半径(仅圆形)
|
||
bounds?: { // 边界信息(仅多边形)
|
||
north: number;
|
||
south: number;
|
||
east: number;
|
||
west: number;
|
||
};
|
||
area: number;
|
||
properties: any;
|
||
}
|
||
|
||
export interface DrawingResult {
|
||
id: string;
|
||
type: 'circle' | 'polygon';
|
||
positions: Cesium.Cartesian3[];
|
||
entity: Cesium.Entity;
|
||
properties: any;
|
||
info: DrawingInfo; // 新增信息字段
|
||
}
|
||
|
||
export class DrawingTool {
|
||
private viewer: Cesium.Viewer;
|
||
private handler: Cesium.ScreenSpaceEventHandler;
|
||
private entities: Cesium.EntityCollection;
|
||
|
||
private isDrawing: boolean = false;
|
||
private currentType: 'circle' | 'polygon' | null = null;
|
||
private currentPositions: Cesium.Cartesian3[] = [];
|
||
private tempEntities: Cesium.Entity[] = [];
|
||
private drawingEntities: Map<string, DrawingResult> = new Map();
|
||
|
||
private defaultOptions: DrawingOptions = {
|
||
color: Cesium.Color.YELLOW.withAlpha(0.3),
|
||
outlineColor: Cesium.Color.YELLOW,
|
||
outlineWidth: 2,
|
||
fill: true,
|
||
classificationType: Cesium.ClassificationType.BOTH,
|
||
height: 0,
|
||
extrudedHeight: 1000
|
||
};
|
||
|
||
private drawingCallbacks: {
|
||
onStart?: () => void;
|
||
onPointAdd?: (position: Cesium.Cartesian3) => void;
|
||
onComplete?: (result: DrawingResult) => void;
|
||
onCancel?: () => void;
|
||
onClick?: (result: DrawingResult, info: DrawingInfo) => void; // 新增点击回调
|
||
} = {};
|
||
|
||
constructor(viewer: Cesium.Viewer) {
|
||
this.viewer = viewer;
|
||
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
||
this.entities = viewer.entities;
|
||
|
||
// 初始化点击事件监听
|
||
this.initClickHandler();
|
||
}
|
||
|
||
/**
|
||
* 初始化点击事件处理器
|
||
*/
|
||
private initClickHandler(): void {
|
||
this.handler.setInputAction((event: any) => {
|
||
this.handleEntityClick(event.position);
|
||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
}
|
||
|
||
/**
|
||
* 处理实体点击事件
|
||
*/
|
||
private handleEntityClick(position: Cesium.Cartesian2): void {
|
||
const pickedObject = this.viewer.scene.pick(position);
|
||
if (!pickedObject || !pickedObject.id) return;
|
||
|
||
const clickedEntity = pickedObject.id;
|
||
const drawingResult = this.findDrawingByEntity(clickedEntity);
|
||
|
||
if (drawingResult) {
|
||
const drawingInfo = this.generateDrawingInfo(drawingResult);
|
||
this.drawingCallbacks.onClick?.(drawingResult, drawingInfo);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据实体查找绘图结果
|
||
*/
|
||
private findDrawingByEntity(entity: Cesium.Entity): DrawingResult | undefined {
|
||
for (const drawing of this.drawingEntities.values()) {
|
||
if (drawing.entity === entity) {
|
||
return drawing;
|
||
}
|
||
}
|
||
return undefined;
|
||
}
|
||
|
||
/**
|
||
* 生成绘图信息
|
||
*/
|
||
private generateDrawingInfo(drawing: DrawingResult): DrawingInfo {
|
||
if (drawing.type === 'circle') {
|
||
return this.generateCircleInfo(drawing);
|
||
} else {
|
||
return this.generatePolygonInfo(drawing);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成圆形信息
|
||
*/
|
||
private generateCircleInfo(drawing: DrawingResult): DrawingInfo {
|
||
const center = drawing.positions[0];
|
||
const radius = drawing.positions.length > 1 ?
|
||
Cesium.Cartesian3.distance(center, drawing.positions[1]) :
|
||
(drawing.properties.options.radius || 1000);
|
||
|
||
const centerCartographic = Cesium.Cartographic.fromCartesian(center);
|
||
const centerLongitude = Cesium.Math.toDegrees(centerCartographic.longitude);
|
||
const centerLatitude = Cesium.Math.toDegrees(centerCartographic.latitude);
|
||
const centerHeight = centerCartographic.height;
|
||
|
||
return {
|
||
id: drawing.id,
|
||
type: 'circle',
|
||
positions: drawing.positions,
|
||
center: center,
|
||
radius: radius,
|
||
area: drawing.properties.area,
|
||
properties: {
|
||
...drawing.properties,
|
||
center: {
|
||
longitude: centerLongitude,
|
||
latitude: centerLatitude,
|
||
height: centerHeight
|
||
},
|
||
radius: radius,
|
||
circumference: 2 * Math.PI * radius,
|
||
diameter: 2 * radius
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 生成多边形信息
|
||
*/
|
||
private generatePolygonInfo(drawing: DrawingResult): DrawingInfo {
|
||
// 计算边界
|
||
let minLon = Infinity, maxLon = -Infinity;
|
||
let minLat = Infinity, maxLat = -Infinity;
|
||
let minHeight = Infinity, maxHeight = -Infinity;
|
||
|
||
const boundaryPoints = drawing.positions.map(position => {
|
||
const cartographic = Cesium.Cartographic.fromCartesian(position);
|
||
const lon = Cesium.Math.toDegrees(cartographic.longitude);
|
||
const lat = Cesium.Math.toDegrees(cartographic.latitude);
|
||
const height = cartographic.height;
|
||
|
||
// 更新边界
|
||
minLon = Math.min(minLon, lon);
|
||
maxLon = Math.max(maxLon, lon);
|
||
minLat = Math.min(minLat, lat);
|
||
maxLat = Math.max(maxLat, lat);
|
||
minHeight = Math.min(minHeight, height);
|
||
maxHeight = Math.max(maxHeight, height);
|
||
|
||
return {
|
||
longitude: lon,
|
||
latitude: lat,
|
||
height: height
|
||
};
|
||
});
|
||
|
||
// 计算中心点
|
||
const centerLon = (minLon + maxLon) / 2;
|
||
const centerLat = (minLat + maxLat) / 2;
|
||
const centerHeight = (minHeight + maxHeight) / 2;
|
||
|
||
return {
|
||
id: drawing.id,
|
||
type: 'polygon',
|
||
positions: drawing.positions,
|
||
bounds: {
|
||
north: maxLat,
|
||
south: minLat,
|
||
east: maxLon,
|
||
west: minLon
|
||
},
|
||
area: drawing.properties.area,
|
||
properties: {
|
||
...drawing.properties,
|
||
boundaryPoints: boundaryPoints,
|
||
bounds: {
|
||
north: maxLat,
|
||
south: minLat,
|
||
east: maxLon,
|
||
west: minLon
|
||
},
|
||
center: {
|
||
longitude: centerLon,
|
||
latitude: centerLat,
|
||
height: centerHeight
|
||
},
|
||
width: this.calculateDistance(minLon, minLat, maxLon, minLat), // 东西宽度
|
||
height: this.calculateDistance(minLon, minLat, minLon, maxLat), // 南北高度
|
||
perimeter: this.calculatePerimeter(drawing.positions)
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 计算两点间距离
|
||
*/
|
||
private calculateDistance(lon1: number, lat1: number, lon2: number, lat2: number): number {
|
||
const cartesian1 = Cesium.Cartesian3.fromDegrees(lon1, lat1);
|
||
const cartesian2 = Cesium.Cartesian3.fromDegrees(lon2, lat2);
|
||
return Cesium.Cartesian3.distance(cartesian1, cartesian2);
|
||
}
|
||
|
||
/**
|
||
* 计算多边形周长
|
||
*/
|
||
private calculatePerimeter(positions: Cesium.Cartesian3[]): number {
|
||
let perimeter = 0;
|
||
const n = positions.length;
|
||
|
||
for (let i = 0; i < n; i++) {
|
||
const j = (i + 1) % n;
|
||
perimeter += Cesium.Cartesian3.distance(positions[i], positions[j]);
|
||
}
|
||
|
||
return perimeter;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
* 开始绘制圆形
|
||
*/
|
||
startDrawingCircle(options: CircleOptions = {}): void {
|
||
this.startDrawing('circle', options);
|
||
}
|
||
|
||
/**
|
||
* 开始绘制多边形
|
||
*/
|
||
startDrawingPolygon(options: PolygonOptions = {}): void {
|
||
this.startDrawing('polygon', options);
|
||
}
|
||
|
||
/**
|
||
* 开始绘制
|
||
*/
|
||
private startDrawing(type: 'circle' | 'polygon', options: DrawingOptions = {}): void {
|
||
if (this.isDrawing) {
|
||
this.cancelDrawing();
|
||
}
|
||
|
||
this.isDrawing = true;
|
||
this.currentType = type;
|
||
this.currentPositions = [];
|
||
this.tempEntities = [];
|
||
|
||
const mergedOptions = { ...this.defaultOptions, ...options };
|
||
|
||
// 设置鼠标样式
|
||
this.viewer.scene.canvas.style.cursor = 'crosshair';
|
||
|
||
// 左键点击添加点
|
||
this.handler.setInputAction((event: any) => {
|
||
this.handleLeftClick(event.position, mergedOptions);
|
||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
|
||
// 鼠标移动预览
|
||
this.handler.setInputAction((event: any) => {
|
||
this.handleMouseMove(event.endPosition, mergedOptions);
|
||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||
|
||
// 右键完成绘制
|
||
this.handler.setInputAction(() => {
|
||
this.completeDrawing(mergedOptions);
|
||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||
|
||
// 取消绘制
|
||
const cancelHandler = (event: KeyboardEvent) => {
|
||
if (event.key === 'Escape') {
|
||
this.cancelDrawing();
|
||
}
|
||
};
|
||
document.addEventListener('keydown', cancelHandler);
|
||
(this as any).cancelHandler = cancelHandler;
|
||
|
||
this.drawingCallbacks.onStart?.();
|
||
}
|
||
|
||
/**
|
||
* 处理左键点击
|
||
*/
|
||
private handleLeftClick(position: Cesium.Cartesian2, options: DrawingOptions): void {
|
||
const cartesian = this.pickCoordinate(position);
|
||
if (!cartesian) return;
|
||
|
||
this.currentPositions.push(cartesian);
|
||
|
||
// 添加临时点标记
|
||
const pointEntity = this.entities.add({
|
||
position: cartesian,
|
||
point: {
|
||
pixelSize: 8,
|
||
color: Cesium.Color.RED,
|
||
outlineColor: Cesium.Color.WHITE,
|
||
outlineWidth: 2,
|
||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||
}
|
||
});
|
||
this.tempEntities.push(pointEntity);
|
||
|
||
this.drawingCallbacks.onPointAdd?.(cartesian);
|
||
|
||
// 如果是圆形,第一个点确定圆心,第二个点确定半径
|
||
if (this.currentType === 'circle' && this.currentPositions.length === 2) {
|
||
this.completeDrawing(options);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理鼠标移动
|
||
*/
|
||
private handleMouseMove(position: Cesium.Cartesian2, options: DrawingOptions): void {
|
||
if (this.currentPositions.length === 0) return;
|
||
|
||
const cartesian = this.pickCoordinate(position);
|
||
if (!cartesian) return;
|
||
|
||
// 清除之前的临时图形
|
||
this.clearTempShapes();
|
||
|
||
if (this.currentType === 'circle') {
|
||
this.drawTempCircle(cartesian, options);
|
||
} else if (this.currentType === 'polygon') {
|
||
this.drawTempPolygon(cartesian, options);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绘制临时圆形
|
||
*/
|
||
private drawTempCircle(mousePosition: Cesium.Cartesian3, options: CircleOptions): void {
|
||
const center = this.currentPositions[0];
|
||
const radius = Cesium.Cartesian3.distance(center, mousePosition);
|
||
|
||
const circleEntity = this.entities.add({
|
||
position: center,
|
||
ellipse: {
|
||
semiMinorAxis: radius,
|
||
semiMajorAxis: radius,
|
||
material: options.color || this.defaultOptions.color,
|
||
outline: true,
|
||
outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
height: options.height || this.defaultOptions.height,
|
||
extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
}
|
||
});
|
||
this.tempEntities.push(circleEntity);
|
||
|
||
// 绘制半径线
|
||
if (this.currentPositions.length === 1) {
|
||
const radiusLine = this.entities.add({
|
||
polyline: {
|
||
positions: [center, mousePosition],
|
||
width: 2,
|
||
material: Cesium.Color.WHITE.withAlpha(0.7)
|
||
}
|
||
});
|
||
this.tempEntities.push(radiusLine);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绘制临时多边形
|
||
*/
|
||
private drawTempPolygon(mousePosition: Cesium.Cartesian3, options: PolygonOptions): void {
|
||
const positions = [...this.currentPositions, mousePosition];
|
||
|
||
// 绘制临时多边形
|
||
const polygonEntity = this.entities.add({
|
||
polygon: {
|
||
hierarchy: new Cesium.PolygonHierarchy(positions),
|
||
material: options.color || this.defaultOptions.color,
|
||
outline: true,
|
||
outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
height: options.height || this.defaultOptions.height,
|
||
extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
}
|
||
});
|
||
this.tempEntities.push(polygonEntity);
|
||
|
||
// 绘制临时边线
|
||
if (positions.length > 1) {
|
||
const linePositions = [...positions];
|
||
if (positions.length > 2) {
|
||
linePositions.push(positions[0]); // 闭合多边形
|
||
}
|
||
|
||
const lineEntity = this.entities.add({
|
||
polyline: {
|
||
positions: linePositions,
|
||
width: 3,
|
||
material: options.outlineColor || this.defaultOptions.outlineColor
|
||
}
|
||
});
|
||
this.tempEntities.push(lineEntity);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 完成绘制
|
||
*/
|
||
// private completeDrawing(options: DrawingOptions): void {
|
||
// if (this.currentPositions.length < 2) {
|
||
// this.cancelDrawing();
|
||
// return;
|
||
// }
|
||
|
||
// const id = `drawing_${Date.now()}`;
|
||
// let entity: Cesium.Entity;
|
||
|
||
// if (this.currentType === 'circle') {
|
||
// entity = this.createCircleEntity(id, this.currentPositions, options as CircleOptions);
|
||
// } else {
|
||
// entity = this.createPolygonEntity(id, this.currentPositions, options as PolygonOptions);
|
||
// }
|
||
|
||
// const result: DrawingResult = {
|
||
// id,
|
||
// type: this.currentType!,
|
||
// positions: this.currentPositions,
|
||
// entity,
|
||
// properties: {
|
||
// area: this.calculateArea(this.currentPositions, this.currentType!),
|
||
// options
|
||
// }
|
||
// };
|
||
|
||
// this.drawingEntities.set(id, result);
|
||
// this.cleanupDrawing();
|
||
|
||
// this.drawingCallbacks.onComplete?.(result);
|
||
// }
|
||
|
||
/**
|
||
* 完成绘制
|
||
*/
|
||
private completeDrawing(options: DrawingOptions): void {
|
||
if (this.currentPositions.length < 2) {
|
||
this.cancelDrawing();
|
||
return;
|
||
}
|
||
|
||
const id = `drawing_${Date.now()}`;
|
||
let entity: Cesium.Entity;
|
||
|
||
if (this.currentType === 'circle') {
|
||
entity = this.createCircleEntity(id, this.currentPositions, options as CircleOptions);
|
||
} else {
|
||
entity = this.createPolygonEntity(id, this.currentPositions, options as PolygonOptions);
|
||
}
|
||
|
||
// 生成绘图信息
|
||
const drawingInfo = this.currentType === 'circle' ?
|
||
this.generateCircleInfo({ id, type: 'circle', positions: this.currentPositions, entity, properties: { options, area: 0 } } as DrawingResult) :
|
||
this.generatePolygonInfo({ id, type: 'polygon', positions: this.currentPositions, entity, properties: { options, area: 0 } } as DrawingResult);
|
||
|
||
// 计算面积
|
||
const area = this.calculateArea(this.currentPositions, this.currentType!);
|
||
|
||
const result: DrawingResult = {
|
||
id,
|
||
type: this.currentType!,
|
||
positions: this.currentPositions,
|
||
entity,
|
||
properties: {
|
||
area: area,
|
||
options
|
||
},
|
||
info: {
|
||
...drawingInfo,
|
||
area: area
|
||
}
|
||
};
|
||
|
||
this.drawingEntities.set(id, result);
|
||
this.cleanupDrawing();
|
||
|
||
this.drawingCallbacks.onComplete?.(result);
|
||
}
|
||
|
||
/**
|
||
* 创建圆形实体
|
||
*/
|
||
// private createCircleEntity(id: string, positions: Cesium.Cartesian3[], options: CircleOptions): Cesium.Entity {
|
||
// const center = positions[0];
|
||
// const radius = positions.length > 1 ? Cesium.Cartesian3.distance(center, positions[1]) : (options.radius || 1000);
|
||
|
||
// return this.entities.add({
|
||
// id,
|
||
// position: center,
|
||
// ellipse: {
|
||
// semiMinorAxis: radius,
|
||
// semiMajorAxis: radius,
|
||
// material: options.color || this.defaultOptions.color,
|
||
// outline: true,
|
||
// outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
// outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
// height: options.height || this.defaultOptions.height,
|
||
// extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
// classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
// },
|
||
// label: {
|
||
// text: `圆形空域\n半径: ${(radius / 1000).toFixed(2)}km`,
|
||
// font: '14pt sans-serif',
|
||
// pixelOffset: new Cesium.Cartesian2(0, -50),
|
||
// fillColor: Cesium.Color.WHITE,
|
||
// outlineColor: Cesium.Color.BLACK,
|
||
// outlineWidth: 2,
|
||
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||
// }
|
||
// });
|
||
// }
|
||
|
||
/**
|
||
* 创建圆形实体
|
||
*/
|
||
private createCircleEntity(id: string, positions: Cesium.Cartesian3[], options: CircleOptions): Cesium.Entity {
|
||
const center = positions[0];
|
||
const radius = positions.length > 1 ? Cesium.Cartesian3.distance(center, positions[1]) : (options.radius || 1000);
|
||
const centerCartographic = Cesium.Cartographic.fromCartesian(center);
|
||
|
||
return this.entities.add({
|
||
id,
|
||
position: center,
|
||
ellipse: {
|
||
semiMinorAxis: radius,
|
||
semiMajorAxis: radius,
|
||
material: options.color || this.defaultOptions.color,
|
||
outline: true,
|
||
outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
height: options.height || this.defaultOptions.height,
|
||
extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
},
|
||
label: {
|
||
text: `圆形空域\n半径: ${(radius / 1000).toFixed(2)}km`,
|
||
font: '14pt sans-serif',
|
||
pixelOffset: new Cesium.Cartesian2(0, -50),
|
||
fillColor: Cesium.Color.WHITE,
|
||
outlineColor: Cesium.Color.BLACK,
|
||
outlineWidth: 2,
|
||
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||
},
|
||
// 添加自定义属性便于识别
|
||
drawingType: 'circle',
|
||
drawingId: id
|
||
});
|
||
console.log("圆形空域:",)
|
||
}
|
||
|
||
/**
|
||
* 创建多边形实体
|
||
*/
|
||
private createPolygonEntity(id: string, positions: Cesium.Cartesian3[], options: PolygonOptions): Cesium.Entity {
|
||
const hierarchy = new Cesium.PolygonHierarchy(positions);
|
||
const area = this.calculateArea(positions, 'polygon');
|
||
|
||
return this.entities.add({
|
||
id,
|
||
polygon: {
|
||
hierarchy,
|
||
material: options.color || this.defaultOptions.color,
|
||
outline: true,
|
||
outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
height: options.height || this.defaultOptions.height,
|
||
extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
},
|
||
label: {
|
||
text: `多边形空域\n面积: ${(area / 1000000).toFixed(2)}km²`,
|
||
font: '14pt sans-serif',
|
||
pixelOffset: new Cesium.Cartesian2(0, -50),
|
||
fillColor: Cesium.Color.WHITE,
|
||
outlineColor: Cesium.Color.BLACK,
|
||
outlineWidth: 2,
|
||
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||
},
|
||
// 添加自定义属性便于识别
|
||
drawingType: 'polygon',
|
||
drawingId: id
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 创建多边形实体
|
||
*/
|
||
// private createPolygonEntity(id: string, positions: Cesium.Cartesian3[], options: PolygonOptions): Cesium.Entity {
|
||
// const hierarchy = new Cesium.PolygonHierarchy(positions);
|
||
// const area = this.calculateArea(positions, 'polygon');
|
||
|
||
// return this.entities.add({
|
||
// id,
|
||
// polygon: {
|
||
// hierarchy,
|
||
// material: options.color || this.defaultOptions.color,
|
||
// outline: true,
|
||
// outlineColor: options.outlineColor || this.defaultOptions.outlineColor,
|
||
// outlineWidth: options.outlineWidth || this.defaultOptions.outlineWidth,
|
||
// height: options.height || this.defaultOptions.height,
|
||
// extrudedHeight: options.extrudedHeight || this.defaultOptions.extrudedHeight,
|
||
// classificationType: options.classificationType || this.defaultOptions.classificationType
|
||
// },
|
||
// label: {
|
||
// text: `多边形空域\n面积: ${(area / 1000000).toFixed(2)}km²`,
|
||
// font: '14pt sans-serif',
|
||
// pixelOffset: new Cesium.Cartesian2(0, -50),
|
||
// fillColor: Cesium.Color.WHITE,
|
||
// outlineColor: Cesium.Color.BLACK,
|
||
// outlineWidth: 2,
|
||
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||
// }
|
||
// });
|
||
// }
|
||
|
||
|
||
/**
|
||
* 打印空域基本信息
|
||
*/
|
||
printDrawingInfo(drawingId: string): void {
|
||
const drawing = this.drawingEntities.get(drawingId);
|
||
if (!drawing) {
|
||
console.warn(`未找到ID为 ${drawingId} 的空域`);
|
||
return;
|
||
}
|
||
|
||
const info = this.generateDrawingInfo(drawing);
|
||
this.printFormattedInfo(info);
|
||
}
|
||
|
||
/**
|
||
* 打印所有空域信息
|
||
*/
|
||
printAllDrawingsInfo(): void {
|
||
if (this.drawingEntities.size === 0) {
|
||
console.log('当前没有绘制任何空域');
|
||
return;
|
||
}
|
||
|
||
console.log(`=== 空域信息汇总 (共 ${this.drawingEntities.size} 个) ===`);
|
||
this.drawingEntities.forEach((drawing, id) => {
|
||
const info = this.generateDrawingInfo(drawing);
|
||
this.printFormattedInfo(info);
|
||
console.log('---'); // 分隔线
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 格式化打印信息
|
||
*/
|
||
private printFormattedInfo(info: DrawingInfo): void {
|
||
const { id, type, area, properties } = info;
|
||
|
||
console.log(`🛡️ 空域ID: ${id}`);
|
||
console.log(`📝 类型: ${type === 'circle' ? '圆形空域' : '多边形空域'}`);
|
||
console.log(`📊 面积: ${(area / 1000000).toFixed(3)} km²`);
|
||
|
||
if (type === 'circle') {
|
||
const center = properties.center;
|
||
console.log(`📍 圆心坐标:`);
|
||
console.log(` 经度: ${center.longitude.toFixed(6)}°`);
|
||
console.log(` 纬度: ${center.latitude.toFixed(6)}°`);
|
||
console.log(` 高程: ${center.height.toFixed(2)} 米`);
|
||
console.log(`📏 半径: ${(info.radius! / 1000).toFixed(3)} km`);
|
||
console.log(`📐 直径: ${(info.radius! * 2 / 1000).toFixed(3)} km`);
|
||
console.log(`🔄 周长: ${(properties.circumference / 1000).toFixed(3)} km`);
|
||
} else {
|
||
const center = properties.center;
|
||
const bounds = properties.bounds;
|
||
const boundaryPoints = properties.boundaryPoints;
|
||
|
||
console.log(`📍 中心点坐标:`);
|
||
console.log(` 经度: ${center.longitude.toFixed(6)}°`);
|
||
console.log(` 纬度: ${center.latitude.toFixed(6)}°`);
|
||
console.log(` 高程: ${center.height.toFixed(2)} 米`);
|
||
|
||
console.log(`🗺️ 边界范围:`);
|
||
console.log(` 北: ${bounds.north.toFixed(6)}°`);
|
||
console.log(` 南: ${bounds.south.toFixed(6)}°`);
|
||
console.log(` 东: ${bounds.east.toFixed(6)}°`);
|
||
console.log(` 西: ${bounds.west.toFixed(6)}°`);
|
||
|
||
console.log(`📏 尺寸信息:`);
|
||
console.log(` 宽度: ${(properties.width / 1000).toFixed(3)} km`);
|
||
console.log(` 高度: ${(properties.height / 1000).toFixed(3)} km`);
|
||
console.log(` 周长: ${(properties.perimeter / 1000).toFixed(3)} km`);
|
||
|
||
console.log(`📍 边界顶点 (${boundaryPoints.length}个):`);
|
||
boundaryPoints.forEach((point, index) => {
|
||
console.log(` 顶点${index + 1}: ${point.longitude.toFixed(6)}°, ${point.latitude.toFixed(6)}°, ${point.height.toFixed(2)}米`);
|
||
});
|
||
}
|
||
|
||
console.log(`🎨 样式设置:`);
|
||
console.log(` 填充颜色: ${properties.options.color}`);
|
||
console.log(` 边框颜色: ${properties.options.outlineColor}`);
|
||
console.log(` 边框宽度: ${properties.options.outlineWidth}px`);
|
||
console.log(` 拉伸高度: ${properties.options.extrudedHeight}米`);
|
||
}
|
||
|
||
/**
|
||
* 获取空域信息的JSON格式
|
||
*/
|
||
getDrawingInfoJSON(drawingId: string): any {
|
||
const drawing = this.drawingEntities.get(drawingId);
|
||
if (!drawing) return null;
|
||
|
||
const info = this.generateDrawingInfo(drawing);
|
||
return this.formatInfoToJSON(info);
|
||
}
|
||
|
||
/**
|
||
* 获取所有空域信息的JSON格式
|
||
*/
|
||
getAllDrawingsInfoJSON(): any[] {
|
||
const result = [];
|
||
for (const [id, drawing] of this.drawingEntities) {
|
||
const info = this.generateDrawingInfo(drawing);
|
||
result.push(this.formatInfoToJSON(info));
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 格式化信息为JSON
|
||
*/
|
||
private formatInfoToJSON(info: DrawingInfo): any {
|
||
const jsonInfo: any = {
|
||
id: info.id,
|
||
type: info.type,
|
||
area: {
|
||
squareMeters: info.area,
|
||
squareKilometers: info.area / 1000000
|
||
},
|
||
properties: {
|
||
...info.properties,
|
||
options: {
|
||
color: info.properties.options.color?.toCssColorString(),
|
||
outlineColor: info.properties.options.outlineColor?.toCssColorString(),
|
||
outlineWidth: info.properties.options.outlineWidth,
|
||
extrudedHeight: info.properties.options.extrudedHeight
|
||
}
|
||
}
|
||
};
|
||
|
||
// 移除循环引用
|
||
delete jsonInfo.properties.boundaryPoints;
|
||
delete jsonInfo.properties.center;
|
||
|
||
if (info.type === 'circle') {
|
||
jsonInfo.circle = {
|
||
center: info.properties.center,
|
||
radius: info.radius,
|
||
diameter: info.radius! * 2,
|
||
circumference: info.properties.circumference
|
||
};
|
||
} else {
|
||
jsonInfo.polygon = {
|
||
center: info.properties.center,
|
||
bounds: info.properties.bounds,
|
||
dimensions: {
|
||
width: info.properties.width,
|
||
height: info.properties.height,
|
||
perimeter: info.properties.perimeter
|
||
},
|
||
vertexCount: info.properties.boundaryPoints.length,
|
||
vertices: info.properties.boundaryPoints
|
||
};
|
||
}
|
||
|
||
return jsonInfo;
|
||
}
|
||
|
||
/**
|
||
* 导出空域信息为文本
|
||
*/
|
||
exportDrawingInfoAsText(drawingId: string): string {
|
||
const drawing = this.drawingEntities.get(drawingId);
|
||
if (!drawing) return '';
|
||
|
||
const info = this.generateDrawingInfo(drawing);
|
||
return this.formatInfoAsText(info);
|
||
}
|
||
|
||
/**
|
||
* 格式化信息为文本
|
||
*/
|
||
private formatInfoAsText(info: DrawingInfo): string {
|
||
let text = '';
|
||
|
||
if (info.type === 'circle') {
|
||
const center = info.properties.center;
|
||
text = `圆形空域信息
|
||
空域ID: ${info.id}
|
||
圆心坐标: 经度${center.longitude.toFixed(6)}°, 纬度${center.latitude.toFixed(6)}°, 高程${center.height.toFixed(2)}米
|
||
半径: ${(info.radius! / 1000).toFixed(3)} km
|
||
直径: ${(info.radius! * 2 / 1000).toFixed(3)} km
|
||
周长: ${(info.properties.circumference / 1000).toFixed(3)} km
|
||
面积: ${(info.area / 1000000).toFixed(3)} km²`;
|
||
} else {
|
||
const center = info.properties.center;
|
||
const bounds = info.properties.bounds;
|
||
text = `多边形空域信息
|
||
空域ID: ${info.id}
|
||
中心点: 经度${center.longitude.toFixed(6)}°, 纬度${center.latitude.toFixed(6)}°, 高程${center.height.toFixed(2)}米
|
||
边界范围: 北${bounds.north.toFixed(6)}° 南${bounds.south.toFixed(6)}° 东${bounds.east.toFixed(6)}° 西${bounds.west.toFixed(6)}°
|
||
尺寸: 宽度${(info.properties.width / 1000).toFixed(3)}km 高度${(info.properties.height / 1000).toFixed(3)}km
|
||
周长: ${(info.properties.perimeter / 1000).toFixed(3)} km
|
||
面积: ${(info.area / 1000000).toFixed(3)} km²
|
||
顶点数量: ${info.properties.boundaryPoints.length}`;
|
||
|
||
// 添加顶点信息
|
||
info.properties.boundaryPoints.forEach((point, index) => {
|
||
text += `\n顶点${index + 1}: 经度${point.longitude.toFixed(6)}°, 纬度${point.latitude.toFixed(6)}°, 高程${point.height.toFixed(2)}米`;
|
||
});
|
||
}
|
||
|
||
return text;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
* 计算面积
|
||
*/
|
||
private calculateArea(positions: Cesium.Cartesian3[], type: 'circle' | 'polygon'): number {
|
||
if (type === 'circle') {
|
||
const center = positions[0];
|
||
console.log("圆形的圆心:",center)
|
||
const radius = positions.length > 1 ? Cesium.Cartesian3.distance(center, positions[1]) : 0;
|
||
console.log("圆形的半径:",radius)
|
||
return Math.PI * radius * radius;
|
||
} else {
|
||
// 计算多边形面积
|
||
// const cartographics = positions.map(pos =>
|
||
// Cesium.Cartographic.fromCartesian(pos)
|
||
// );
|
||
// return Cesium.PolygonGeometry.computeArea(cartographics);
|
||
|
||
// 修正:使用正确的多边形面积计算方法
|
||
const area = this.computePolygonAreaSimple(positions);
|
||
console.log(`Polygon area: ${area} m², vertices: ${positions.length}`);
|
||
return area;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 简化但有效的多边形面积计算
|
||
*/
|
||
private computePolygonAreaSimple(positions: Cesium.Cartesian3[]): number {
|
||
if (positions.length < 3) return 0;
|
||
|
||
// 将3D坐标转换为2D平面坐标(使用第一个点作为参考平面)
|
||
const normal = new Cesium.Cartesian3();
|
||
Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(positions[0], normal);
|
||
|
||
let area = 0;
|
||
const n = positions.length;
|
||
|
||
for (let i = 0; i < n; i++) {
|
||
const j = (i + 1) % n;
|
||
|
||
const p1 = positions[i];
|
||
const p2 = positions[j];
|
||
|
||
// 计算两个向量在切平面上的投影
|
||
const v1 = Cesium.Cartesian3.subtract(p1, positions[0], new Cesium.Cartesian3());
|
||
const v2 = Cesium.Cartesian3.subtract(p2, positions[0], new Cesium.Cartesian3());
|
||
|
||
// 计算叉积的模长(平行四边形面积)
|
||
const cross = Cesium.Cartesian3.cross(v1, v2, new Cesium.Cartesian3());
|
||
const parallelogramArea = Cesium.Cartesian3.magnitude(cross);
|
||
|
||
area += parallelogramArea;
|
||
}
|
||
|
||
// 三角形面积是平行四边形面积的一半
|
||
return Math.abs(area) / 2;
|
||
}
|
||
|
||
|
||
/**
|
||
* 取消绘制
|
||
*/
|
||
cancelDrawing(): void {
|
||
this.cleanupDrawing();
|
||
this.drawingCallbacks.onCancel?.();
|
||
}
|
||
|
||
/**
|
||
* 清理绘制状态
|
||
*/
|
||
private cleanupDrawing(): void {
|
||
this.isDrawing = false;
|
||
this.currentType = null;
|
||
this.currentPositions = [];
|
||
|
||
// 清除临时实体
|
||
this.tempEntities.forEach(entity => this.entities.remove(entity));
|
||
this.tempEntities = [];
|
||
|
||
// 移除事件监听
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||
|
||
// 移除键盘事件
|
||
if ((this as any).cancelHandler) {
|
||
document.removeEventListener('keydown', (this as any).cancelHandler);
|
||
(this as any).cancelHandler = null;
|
||
}
|
||
|
||
// 恢复鼠标样式
|
||
this.viewer.scene.canvas.style.cursor = '';
|
||
}
|
||
|
||
/**
|
||
* 清除临时图形
|
||
*/
|
||
private clearTempShapes(): void {
|
||
this.tempEntities.forEach(entity => this.entities.remove(entity));
|
||
this.tempEntities = [];
|
||
}
|
||
|
||
/**
|
||
* 拾取坐标
|
||
*/
|
||
private pickCoordinate(position: Cesium.Cartesian2): Cesium.Cartesian3 | null {
|
||
const ray = this.viewer.camera.getPickRay(position);
|
||
if (!ray) return null;
|
||
|
||
const cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene) ||
|
||
this.viewer.scene.camera.pickEllipsoid(position, this.viewer.scene.globe.ellipsoid);
|
||
return cartesian;
|
||
}
|
||
|
||
/**
|
||
* 设置绘图回调
|
||
*/
|
||
setCallbacks(callbacks: typeof this.drawingCallbacks): void {
|
||
this.drawingCallbacks = { ...this.drawingCallbacks, ...callbacks };
|
||
}
|
||
|
||
/**
|
||
* 获取所有绘制的图形
|
||
*/
|
||
getAllDrawings(): DrawingResult[] {
|
||
return Array.from(this.drawingEntities.values());
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取图形
|
||
*/
|
||
getDrawing(id: string): DrawingResult | undefined {
|
||
return this.drawingEntities.get(id);
|
||
}
|
||
|
||
/**
|
||
* 移除图形
|
||
*/
|
||
removeDrawing(id: string): boolean {
|
||
const drawing = this.drawingEntities.get(id);
|
||
if (drawing) {
|
||
this.entities.remove(drawing.entity);
|
||
this.drawingEntities.delete(id);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 清除所有图形
|
||
*/
|
||
clearAllDrawings(): void {
|
||
this.drawingEntities.forEach(drawing => {
|
||
this.entities.remove(drawing.entity);
|
||
});
|
||
this.drawingEntities.clear();
|
||
}
|
||
|
||
/**
|
||
* 高亮显示图形
|
||
*/
|
||
highlightDrawing(id: string, highlight: boolean = true): void {
|
||
const drawing = this.drawingEntities.get(id);
|
||
if (!drawing) return;
|
||
|
||
if (drawing.type === 'circle' && drawing.entity.ellipse) {
|
||
drawing.entity.ellipse.outlineColor = highlight ?
|
||
Cesium.Color.RED :
|
||
(drawing.properties.options.outlineColor || this.defaultOptions.outlineColor);
|
||
drawing.entity.ellipse.outlineWidth = highlight ? 4 : 2;
|
||
} else if (drawing.entity.polygon) {
|
||
drawing.entity.polygon.outlineColor = highlight ?
|
||
Cesium.Color.RED :
|
||
(drawing.properties.options.outlineColor || this.defaultOptions.outlineColor);
|
||
drawing.entity.polygon.outlineWidth = highlight ? 4 : 2;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 飞向图形
|
||
*/
|
||
// flyToDrawing(id: string, duration: number = 2): void {
|
||
// console.log("飞飞飞非法欸")
|
||
// const drawing = this.drawingEntities.get(id);
|
||
// console.log("飞飞飞非111")
|
||
// if (drawing) {
|
||
// console.log("飞飞飞222")
|
||
// this.viewer.flyTo(drawing.entity, {
|
||
// duration: duration,
|
||
// offset: new Cesium.HeadingPitchRange(0, -0.5, 0)
|
||
// });
|
||
// }
|
||
// }
|
||
|
||
|
||
/**
|
||
* 飞向图形
|
||
*/
|
||
flyToDrawing(id: string, duration: number = 2): void {
|
||
console.log('=== flyToDrawing 开始执行 ===');
|
||
console.log('目标空域ID:', id);
|
||
|
||
const drawing = this.drawingEntities.get(id);
|
||
if (!drawing) {
|
||
console.error('❌ 未找到空域:', id);
|
||
return;
|
||
}
|
||
|
||
console.log('找到空域:', drawing);
|
||
|
||
try {
|
||
if (drawing.type === 'circle') {
|
||
// 对于圆形,飞到圆心上方
|
||
const center = drawing.positions[0];
|
||
const radius = drawing.positions.length > 1 ?
|
||
Cesium.Cartesian3.distance(center, drawing.positions[1]) :
|
||
(drawing.properties.options.radius || 1000);
|
||
|
||
const height = radius * 2 + 500; // 在半径2倍高度加上500米
|
||
|
||
console.log('圆形空域 - 圆心:', center);
|
||
console.log('圆形空域 - 半径:', radius);
|
||
console.log('圆形空域 - 飞行高度:', height);
|
||
|
||
this.viewer.camera.flyTo({
|
||
destination: center,
|
||
orientation: {
|
||
heading: 0,
|
||
pitch: -Math.PI/4,
|
||
roll: 0
|
||
},
|
||
duration: duration,
|
||
complete: () => {
|
||
console.log('✅ 飞向圆形空域完成');
|
||
},
|
||
cancel: () => {
|
||
console.log('❌ 飞向圆形空域取消');
|
||
}
|
||
});
|
||
|
||
} else {
|
||
// 对于多边形,飞到边界框
|
||
console.log('多边形空域 - 实体:', drawing.entity);
|
||
|
||
this.viewer.flyTo(drawing.entity, {
|
||
duration: duration,
|
||
offset: new Cesium.HeadingPitchRange(0, -Math.PI/4, 0),
|
||
complete: () => {
|
||
console.log('✅ 飞向多边形空域完成');
|
||
},
|
||
cancel: () => {
|
||
console.log('❌ 飞向多边形空域取消');
|
||
}
|
||
});
|
||
}
|
||
|
||
console.log('✅ flyTo 命令已发送');
|
||
|
||
} catch (error) {
|
||
console.error('❌ 飞向空域时发生错误:', error);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 飞向图形(改进版本)
|
||
*/
|
||
flyToDrawingImproved(id: string, duration: number = 2): void {
|
||
console.log('=== flyToDrawingImproved 开始执行 ===');
|
||
|
||
const drawing = this.drawingEntities.get(id);
|
||
if (!drawing) {
|
||
console.error('❌ 未找到空域:', id);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 计算实体的边界球
|
||
const boundingSphere = this.computeEntityBoundingSphere(drawing.entity);
|
||
if (!boundingSphere) {
|
||
console.error('❌ 无法计算边界球');
|
||
return;
|
||
}
|
||
|
||
console.log('边界球:', boundingSphere);
|
||
|
||
// 飞到边界球
|
||
this.viewer.camera.flyToBoundingSphere(boundingSphere, {
|
||
duration: duration,
|
||
offset: new Cesium.HeadingPitchRange(0, -Math.PI/4, boundingSphere.radius * 3),
|
||
complete: () => {
|
||
console.log('✅ 飞向空域完成');
|
||
},
|
||
cancel: () => {
|
||
console.log('❌ 飞向空域取消');
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ 飞向空域时发生错误:', error);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 计算实体的边界球
|
||
*/
|
||
private computeEntityBoundingSphere(entity: Cesium.Entity): Cesium.BoundingSphere | null {
|
||
try {
|
||
// 方法1: 使用 Cesium 的 computeBoundingSphere
|
||
if (entity.polygon || entity.ellipse) {
|
||
const boundingSphere = entity.computeBoundingSphere();
|
||
if (boundingSphere) {
|
||
return boundingSphere;
|
||
}
|
||
}
|
||
|
||
// 方法2: 手动计算边界球
|
||
if (entity.polygon && entity.polygon.hierarchy) {
|
||
const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now());
|
||
if (hierarchy && hierarchy.positions) {
|
||
return Cesium.BoundingSphere.fromPoints(hierarchy.positions);
|
||
}
|
||
}
|
||
|
||
// 方法3: 对于椭圆,使用位置和半径
|
||
if (entity.ellipse && entity.position) {
|
||
const position = entity.position.getValue(Cesium.JulianDate.now());
|
||
const semiMajorAxis = entity.ellipse.semiMajorAxis?.getValue(Cesium.JulianDate.now()) || 1000;
|
||
const semiMinorAxis = entity.ellipse.semiMinorAxis?.getValue(Cesium.JulianDate.now()) || 1000;
|
||
const radius = Math.max(semiMajorAxis, semiMinorAxis);
|
||
|
||
return new Cesium.BoundingSphere(position, radius);
|
||
}
|
||
|
||
return null;
|
||
} catch (error) {
|
||
console.error('计算边界球时发生错误:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 飞向图形的简单方法
|
||
*/
|
||
flyToDrawingSimple(id: string, duration: number = 2): void {
|
||
console.log('=== flyToDrawingSimple 开始执行 ===');
|
||
|
||
const drawing = this.drawingEntities.get(id);
|
||
if (!drawing) {
|
||
console.error('❌ 未找到空域:', id);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 获取实体的位置
|
||
const position = drawing.entity.position?.getValue(Cesium.JulianDate.now());
|
||
if (!position) {
|
||
console.error('❌ 无法获取实体位置');
|
||
return;
|
||
}
|
||
|
||
console.log('实体位置:', position);
|
||
|
||
// 转换到经纬度
|
||
const cartographic = Cesium.Cartographic.fromCartesian(position);
|
||
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
|
||
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
|
||
const height = cartographic.height + 2000; // 在实体高度上加2000米
|
||
|
||
console.log('目标位置 - 经度:', longitude, '纬度:', latitude, '高度:', height);
|
||
|
||
// 飞到该位置
|
||
this.viewer.camera.flyTo({
|
||
destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
|
||
orientation: {
|
||
heading: 0,
|
||
pitch: -Math.PI/3, // -60度俯角
|
||
roll: 0
|
||
},
|
||
duration: duration,
|
||
complete: () => {
|
||
console.log('✅ 飞向空域完成');
|
||
},
|
||
cancel: () => {
|
||
console.log('❌ 飞向空域取消');
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ 飞向空域时发生错误:', error);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 导出图形数据
|
||
*/
|
||
exportDrawings(): any[] {
|
||
return this.getAllDrawings().map(drawing => ({
|
||
id: drawing.id,
|
||
type: drawing.type,
|
||
positions: drawing.positions.map(pos => {
|
||
const cartographic = Cesium.Cartographic.fromCartesian(pos);
|
||
return {
|
||
longitude: Cesium.Math.toDegrees(cartographic.longitude),
|
||
latitude: Cesium.Math.toDegrees(cartographic.latitude),
|
||
height: cartographic.height
|
||
};
|
||
}),
|
||
properties: drawing.properties
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* 导入图形数据
|
||
*/
|
||
importDrawings(data: any[]): void {
|
||
data.forEach(item => {
|
||
const positions = item.positions.map((pos: any) =>
|
||
Cesium.Cartesian3.fromDegrees(pos.longitude, pos.latitude, pos.height)
|
||
);
|
||
|
||
let entity: Cesium.Entity;
|
||
if (item.type === 'circle') {
|
||
entity = this.createCircleEntity(item.id, positions, item.properties.options);
|
||
} else {
|
||
entity = this.createPolygonEntity(item.id, positions, item.properties.options);
|
||
}
|
||
|
||
const drawing: DrawingResult = {
|
||
id: item.id,
|
||
type: item.type,
|
||
positions,
|
||
entity,
|
||
properties: item.properties
|
||
};
|
||
|
||
this.drawingEntities.set(item.id, drawing);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 销毁
|
||
*/
|
||
destroy(): void {
|
||
this.cancelDrawing();
|
||
this.clearAllDrawings();
|
||
this.handler.destroy();
|
||
}
|
||
}
|