|
|
|
@ -212,7 +212,8 @@ export default { |
|
|
|
// 绘制相关 |
|
|
|
drawingMode: null, // 'point', 'line', 'polygon', 'rectangle', 'circle' |
|
|
|
drawingHandler: null, |
|
|
|
tempEntity: null, |
|
|
|
tempEntity: null, // 最终实体 |
|
|
|
tempPreviewEntity: null, // 预览实体(新增) |
|
|
|
drawingPoints: [], |
|
|
|
drawingStartPoint: null, |
|
|
|
isDrawing: false, |
|
|
|
@ -462,20 +463,26 @@ export default { |
|
|
|
|
|
|
|
stopDrawing() { |
|
|
|
if (this.drawingHandler) { |
|
|
|
this.drawingHandler.destroy() |
|
|
|
this.drawingHandler = null |
|
|
|
this.drawingHandler.destroy(); |
|
|
|
this.drawingHandler = null; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
this.tempEntity = null |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
// 确保也清理预览实体 |
|
|
|
if (this.tempPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
this.drawingPoints = [] |
|
|
|
this.drawingStartPoint = null |
|
|
|
this.isDrawing = false |
|
|
|
this.drawingPoints = []; |
|
|
|
this.drawingStartPoint = null; |
|
|
|
this.isDrawing = false; |
|
|
|
|
|
|
|
this.viewer.scene.canvas.style.cursor = 'default' |
|
|
|
this.viewer.scene.canvas.style.cursor = 'default'; |
|
|
|
}, |
|
|
|
// ******************************************************************** |
|
|
|
// 绘制点 |
|
|
|
@ -490,18 +497,66 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
// 绘制线 |
|
|
|
// 绘制线 |
|
|
|
startLineDrawing() { |
|
|
|
this.drawingPoints = []; |
|
|
|
// 记录当前鼠标的实时位置 |
|
|
|
let activeCursorPosition = null; |
|
|
|
|
|
|
|
// 清除可能存在的旧实体 |
|
|
|
if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); |
|
|
|
if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
|
|
|
|
// 1. 鼠标移动事件:仅更新坐标变量,不操作实体 |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
activeCursorPosition = newPosition; |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
|
|
|
|
// 2. 鼠标点击事件:确定点位 |
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
const position = this.getClickPosition(click.position) |
|
|
|
const position = this.getClickPosition(click.position); |
|
|
|
if (position) { |
|
|
|
this.drawingPoints.push(position) |
|
|
|
|
|
|
|
// 更新临时线 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
} |
|
|
|
|
|
|
|
if (this.drawingPoints.length > 1) { |
|
|
|
this.drawingPoints.push(position); |
|
|
|
|
|
|
|
// === 第一步:点击第一个点后,立即创建“动态虚线” === |
|
|
|
if (this.drawingPoints.length === 1) { |
|
|
|
activeCursorPosition = position; // 初始化鼠标位置 |
|
|
|
|
|
|
|
// 创建预览虚线(只创建这一次,之后它会自动随数据更新) |
|
|
|
this.tempPreviewEntity = this.viewer.entities.add({ |
|
|
|
polyline: { |
|
|
|
// 关键:使用 CallbackProperty 动态获取位置 |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
// 只有当有点且鼠标位置存在时才渲染 |
|
|
|
if (this.drawingPoints.length > 0 && activeCursorPosition) { |
|
|
|
// 获取最后一个已确认的点 |
|
|
|
const lastPoint = this.drawingPoints[this.drawingPoints.length - 1]; |
|
|
|
// 返回 [最后一个点, 当前鼠标位置] |
|
|
|
return [lastPoint, activeCursorPosition]; |
|
|
|
} |
|
|
|
return []; |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.line.width, |
|
|
|
// 虚线材质 |
|
|
|
material: new Cesium.PolylineDashMaterialProperty({ |
|
|
|
color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
dashLength: 16 |
|
|
|
}), |
|
|
|
clampToGround: true // 贴地 |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
// === 第二步:点击后续点时,绘制/延长“固定实线” === |
|
|
|
else { |
|
|
|
// 移除旧的实线,重新画包含新点的实线 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
} |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
polyline: { |
|
|
|
positions: this.drawingPoints, |
|
|
|
@ -509,95 +564,137 @@ export default { |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
|
|
|
|
|
|
|
// 右键完成绘制 |
|
|
|
// 3. 右键完成绘制 |
|
|
|
this.drawingHandler.setInputAction(() => { |
|
|
|
// 完成绘制前,移除那条动态虚线 |
|
|
|
if (this.tempPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.drawingPoints.length > 1) { |
|
|
|
this.finishLineDrawing() |
|
|
|
this.finishLineDrawing(); |
|
|
|
} else { |
|
|
|
this.cancelDrawing() |
|
|
|
this.cancelDrawing(); |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
|
|
|
|
|
|
|
// 重置局部变量 |
|
|
|
activeCursorPosition = null; |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
|
|
|
}, |
|
|
|
|
|
|
|
finishLineDrawing() { |
|
|
|
const positions = [...this.drawingPoints] |
|
|
|
const entity = this.addLineEntity(positions) |
|
|
|
|
|
|
|
// 计算长度 |
|
|
|
const length = this.calculateLineLength(positions) |
|
|
|
this.measurementResult = { |
|
|
|
distance: length, |
|
|
|
type: 'line' |
|
|
|
// 将预览线段转换为最终线段 |
|
|
|
if (this.drawingPoints.length > 1) { |
|
|
|
// 移除预览线段 |
|
|
|
if (this.tempPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
// 创建最终的实线实体 |
|
|
|
const entity = this.addLineEntity([...this.drawingPoints]); |
|
|
|
|
|
|
|
// 计算长度 |
|
|
|
const length = this.calculateLineLength([...this.drawingPoints]); |
|
|
|
this.measurementResult = { |
|
|
|
distance: length, |
|
|
|
type: 'line' |
|
|
|
}; |
|
|
|
|
|
|
|
this.stopDrawing(); |
|
|
|
return entity; |
|
|
|
} else { |
|
|
|
this.cancelDrawing(); |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
this.stopDrawing() |
|
|
|
return entity |
|
|
|
}, |
|
|
|
|
|
|
|
// 绘制多边形 |
|
|
|
startPolygonDrawing() { |
|
|
|
this.drawingPoints = []; |
|
|
|
let activeCursorPosition = null; // 存储鼠标实时位置 |
|
|
|
|
|
|
|
// 1. 清理旧实体 |
|
|
|
// 移除之前可能遗留的实体,确保干净的画布 |
|
|
|
if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); |
|
|
|
if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
|
|
|
|
// 2. 鼠标移动事件:只负责更新坐标变量,不涉及繁重的绘图逻辑 |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
activeCursorPosition = newPosition; |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
|
|
|
|
// 3. 鼠标点击事件:添加关键点 |
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
const position = this.getClickPosition(click.position) |
|
|
|
const position = this.getClickPosition(click.position); |
|
|
|
if (position) { |
|
|
|
this.drawingPoints.push(position) |
|
|
|
this.drawingPoints.push(position); |
|
|
|
|
|
|
|
// 更新临时多边形 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
} |
|
|
|
// === 关键逻辑:点击第一个点时,创建唯一的“动态多边形” === |
|
|
|
if (this.drawingPoints.length === 1) { |
|
|
|
activeCursorPosition = position; // 初始化鼠标位置 |
|
|
|
|
|
|
|
if (this.drawingPoints.length > 2) { |
|
|
|
// 闭合多边形 |
|
|
|
const polygonPoints = [...this.drawingPoints, this.drawingPoints[0]] |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
// --- 填充面配置 --- |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(polygonPoints), |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color) |
|
|
|
.withAlpha(this.defaultStyles.polygon.opacity), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), |
|
|
|
outlineWidth: this.defaultStyles.polygon.width |
|
|
|
} |
|
|
|
}) |
|
|
|
} else if (this.drawingPoints.length === 2) { |
|
|
|
// 只有两个点时显示线 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
// hierarchy 使用 CallbackProperty 实现动态填充 |
|
|
|
hierarchy: new Cesium.CallbackProperty(() => { |
|
|
|
// 组合:已确定的点 + 当前鼠标位置 |
|
|
|
if (activeCursorPosition) { |
|
|
|
return new Cesium.PolygonHierarchy([...this.drawingPoints, activeCursorPosition]); |
|
|
|
} |
|
|
|
return new Cesium.PolygonHierarchy(this.drawingPoints); |
|
|
|
}, false), |
|
|
|
// 使用半透明颜色,方便看到地图底图 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
// 确保贴地 |
|
|
|
perPositionHeight: false |
|
|
|
}, |
|
|
|
// --- 边框线配置 --- |
|
|
|
polyline: { |
|
|
|
positions: this.drawingPoints, |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), |
|
|
|
// positions 使用 CallbackProperty 实现动态闭合线 |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
if (activeCursorPosition) { |
|
|
|
// 闭合回路:[所有点, 鼠标位置, 回到起点] |
|
|
|
return [...this.drawingPoints, activeCursorPosition, this.drawingPoints[0]]; |
|
|
|
} |
|
|
|
return this.drawingPoints; |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.line.width, |
|
|
|
// 边框使用虚线,表示正在编辑中 |
|
|
|
material: new Cesium.PolylineDashMaterialProperty({ |
|
|
|
color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
dashLength: 16 |
|
|
|
}), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}) |
|
|
|
} else if (this.drawingPoints.length === 1) { |
|
|
|
// 只有一个点时显示点 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
position: this.drawingPoints[0], |
|
|
|
point: { |
|
|
|
pixelSize: 8, |
|
|
|
color: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color) |
|
|
|
} |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
|
|
|
|
|
|
|
// 双击完成绘制 |
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
if (this.drawingPoints.length > 2) { |
|
|
|
this.finishPolygonDrawing() |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) |
|
|
|
|
|
|
|
// 右键取消 |
|
|
|
// 4. 右键完成绘制 |
|
|
|
this.drawingHandler.setInputAction(() => { |
|
|
|
this.cancelDrawing() |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
|
|
|
if (this.drawingPoints.length >= 3) { |
|
|
|
this.finishPolygonDrawing(); // 调用原有的完成逻辑 |
|
|
|
} else { |
|
|
|
this.cancelDrawing(); // 点数不够则取消 |
|
|
|
} |
|
|
|
|
|
|
|
// 重置状态 |
|
|
|
activeCursorPosition = null; |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
|
|
|
}, |
|
|
|
|
|
|
|
finishPolygonDrawing() { |
|
|
|
@ -615,156 +712,255 @@ export default { |
|
|
|
return entity |
|
|
|
}, |
|
|
|
|
|
|
|
// 绘制矩形 |
|
|
|
// 绘制矩形(优化版:两点定矩形,实时预览) |
|
|
|
startRectangleDrawing() { |
|
|
|
let startPosition = null |
|
|
|
this.drawingPoints = []; // 存储起点和终点 |
|
|
|
let activeCursorPosition = null; // 实时鼠标位置 |
|
|
|
let startPoint = null; // 记录起点 |
|
|
|
|
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
startPosition = this.getClickPosition(click.position) |
|
|
|
if (startPosition) { |
|
|
|
this.drawingStartPoint = startPosition |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_DOWN) |
|
|
|
// 1. 清理旧实体 |
|
|
|
if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
|
|
|
|
// 2. 鼠标移动事件:更新鼠标位置 |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
if (startPosition) { |
|
|
|
const endPosition = this.getClickPosition(movement.endPosition) |
|
|
|
if (endPosition) { |
|
|
|
// 更新临时矩形 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
} |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
activeCursorPosition = newPosition; |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
|
|
|
|
const rectangle = this.calculateRectangle(startPosition, endPosition) |
|
|
|
// 3. 鼠标点击事件 |
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
const position = this.getClickPosition(click.position); |
|
|
|
if (position) { |
|
|
|
// --- 情况A:第一次点击(确定起点) --- |
|
|
|
if (!startPoint) { |
|
|
|
startPoint = position; |
|
|
|
this.drawingPoints.push(startPoint); |
|
|
|
activeCursorPosition = startPoint; // 初始化鼠标位置 |
|
|
|
|
|
|
|
// 创建动态预览矩形 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
rectangle: { |
|
|
|
coordinates: rectangle, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) |
|
|
|
.withAlpha(this.defaultStyles.rectangle.opacity), |
|
|
|
// 关键:使用 CallbackProperty 动态计算矩形范围 |
|
|
|
coordinates: new Cesium.CallbackProperty(() => { |
|
|
|
if (startPoint && activeCursorPosition) { |
|
|
|
// 使用 Cesium 内置工具,根据两个点(对角)自动计算矩形范围 |
|
|
|
return Cesium.Rectangle.fromCartesianArray([startPoint, activeCursorPosition]); |
|
|
|
} |
|
|
|
return Cesium.Rectangle.fromDegrees(0, 0, 0, 0); |
|
|
|
}, false), |
|
|
|
// 样式:半透明填充 + 边框 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), |
|
|
|
outlineWidth: this.defaultStyles.rectangle.width |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
outlineWidth: 2, |
|
|
|
clampToGround: true // 贴地 |
|
|
|
} |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
// --- 情况B:第二次点击(确定终点) --- |
|
|
|
else { |
|
|
|
this.drawingPoints.push(position); |
|
|
|
// 停止监听鼠标移动,因为形状已确定 |
|
|
|
activeCursorPosition = null; |
|
|
|
|
|
|
|
// 调用完成逻辑 |
|
|
|
this.finishRectangleDrawing(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE) |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
|
|
|
|
|
|
|
// 4. 右键取消 |
|
|
|
this.drawingHandler.setInputAction(() => { |
|
|
|
if (startPosition && this.tempEntity) { |
|
|
|
this.finishRectangleDrawing(startPosition) |
|
|
|
startPosition = null |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_UP) |
|
|
|
|
|
|
|
// 右键取消 |
|
|
|
this.drawingHandler.setInputAction(() => { |
|
|
|
this.cancelDrawing() |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
|
|
|
this.cancelDrawing(); |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
|
|
|
}, |
|
|
|
|
|
|
|
finishRectangleDrawing(startPosition) { |
|
|
|
if (!this.tempEntity) return |
|
|
|
|
|
|
|
const rectangleCoords = this.tempEntity.rectangle.coordinates.getValue() |
|
|
|
const entity = this.addRectangleEntity(rectangleCoords) |
|
|
|
finishRectangleDrawing() { |
|
|
|
// 1. 获取最终的矩形范围对象 |
|
|
|
const rect = Cesium.Rectangle.fromCartesianArray(this.drawingPoints); |
|
|
|
|
|
|
|
// 2. 移除动态预览的临时实体 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
// 计算面积 |
|
|
|
const area = this.calculateRectangleArea(rectangleCoords) |
|
|
|
// 3. 创建最终显示的静态实体 |
|
|
|
const finalEntity = this.viewer.entities.add({ |
|
|
|
id: 'rectangle-' + new Date().getTime(), // 给个唯一ID |
|
|
|
rectangle: { |
|
|
|
coordinates: rect, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
outlineWidth: 2, |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 4. 记录到实体列表 |
|
|
|
this.allEntities.push(finalEntity); |
|
|
|
|
|
|
|
// 5. 计算并显示面积 |
|
|
|
const area = this.calculateRectangleArea(rect); |
|
|
|
this.measurementResult = { |
|
|
|
area: area, |
|
|
|
type: 'rectangle' |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
this.stopDrawing() |
|
|
|
return entity |
|
|
|
// 6. 重置状态 |
|
|
|
this.stopDrawing(); |
|
|
|
}, |
|
|
|
|
|
|
|
// 计算矩形面积(辅助方法) |
|
|
|
calculateRectangleArea(rectangle) { |
|
|
|
// 获取地球椭球体对象 |
|
|
|
const ellipsoid = this.viewer.scene.globe.ellipsoid; |
|
|
|
|
|
|
|
// 方法一:使用 Cesium 几何管道计算(更精确,但需要特定模块支持) |
|
|
|
// const geometry = new Cesium.RectangleGeometry({ rectangle: rectangle }); |
|
|
|
// const geometryInstance = Cesium.RectangleGeometry.createGeometry(geometry); |
|
|
|
// ...比较复杂 |
|
|
|
|
|
|
|
// 方法二:使用采样估算(简单且足够精确) |
|
|
|
// 获取矩形的四个角(弧度) |
|
|
|
const west = rectangle.west; |
|
|
|
const south = rectangle.south; |
|
|
|
const east = rectangle.east; |
|
|
|
const north = rectangle.north; |
|
|
|
|
|
|
|
// 计算中心点的纬度 |
|
|
|
const centerLat = (south + north) / 2; |
|
|
|
|
|
|
|
// 计算宽度(东西向距离):使用余弦定理校正纬度影响 |
|
|
|
// 地球半径约为 6378137 米 |
|
|
|
const R = 6378137; |
|
|
|
const width = (east - west) * R * Math.cos(centerLat); |
|
|
|
|
|
|
|
// 计算高度(南北向距离) |
|
|
|
const height = (north - south) * R; |
|
|
|
|
|
|
|
// 面积 = 宽 * 高 |
|
|
|
const area = Math.abs(width * height); |
|
|
|
|
|
|
|
return area; |
|
|
|
}, |
|
|
|
// 绘制圆形 |
|
|
|
startCircleDrawing() { |
|
|
|
let centerPosition = null |
|
|
|
let radius = 0 |
|
|
|
this.drawingPoints = []; // 存储圆心 |
|
|
|
let activeCursorPosition = null; // 实时鼠标位置 |
|
|
|
let centerPoint = null; // 圆心坐标 |
|
|
|
|
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
centerPosition = this.getClickPosition(click.position) |
|
|
|
if (centerPosition) { |
|
|
|
this.drawingStartPoint = centerPosition |
|
|
|
|
|
|
|
// 创建中心点 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
} |
|
|
|
|
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
position: centerPosition, |
|
|
|
point: { |
|
|
|
pixelSize: 8, |
|
|
|
color: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_DOWN) |
|
|
|
// 1. 清理旧实体 |
|
|
|
if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
|
|
|
|
// 2. 鼠标移动事件 |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
if (centerPosition) { |
|
|
|
const currentPosition = this.getClickPosition(movement.endPosition) |
|
|
|
if (currentPosition) { |
|
|
|
radius = Cesium.Cartesian3.distance(centerPosition, currentPosition) |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
activeCursorPosition = newPosition; |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
|
|
|
|
// 更新临时圆形 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
} |
|
|
|
// 3. 鼠标点击事件 |
|
|
|
this.drawingHandler.setInputAction((click) => { |
|
|
|
const position = this.getClickPosition(click.position); |
|
|
|
if (position) { |
|
|
|
// --- 情况A:第一次点击(确定圆心) --- |
|
|
|
if (!centerPoint) { |
|
|
|
centerPoint = position; |
|
|
|
this.drawingPoints.push(centerPoint); |
|
|
|
activeCursorPosition = centerPoint; |
|
|
|
|
|
|
|
// 创建圆形多边形 |
|
|
|
const positions = this.calculateCircle(centerPosition, radius, 64) |
|
|
|
// 创建动态预览圆形 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(positions), |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) |
|
|
|
.withAlpha(this.defaultStyles.circle.opacity), |
|
|
|
position: centerPoint, // 圆心固定 |
|
|
|
ellipse: { |
|
|
|
// 关键:使用 CallbackProperty 动态计算半径(半长轴和半短轴) |
|
|
|
semiMajorAxis: new Cesium.CallbackProperty(() => { |
|
|
|
if (centerPoint && activeCursorPosition) { |
|
|
|
return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
}, false), |
|
|
|
semiMinorAxis: new Cesium.CallbackProperty(() => { |
|
|
|
if (centerPoint && activeCursorPosition) { |
|
|
|
return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
}, false), |
|
|
|
// 样式设置 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), |
|
|
|
outlineWidth: this.defaultStyles.circle.width |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
outlineWidth: 2, |
|
|
|
// height: 0, // 如果需要贴地可开启或使用 heightReference |
|
|
|
} |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
// --- 情况B:第二次点击(确定边缘/半径) --- |
|
|
|
else { |
|
|
|
// 记录边缘点(虽然圆只需要圆心和半径,但记录下来方便后续处理) |
|
|
|
this.drawingPoints.push(position); |
|
|
|
activeCursorPosition = null; // 停止动态更新 |
|
|
|
|
|
|
|
// 传递边缘点位置去结束绘制 |
|
|
|
this.finishCircleDrawing(position); |
|
|
|
} |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE) |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
|
|
|
|
|
|
|
// 4. 右键取消 |
|
|
|
this.drawingHandler.setInputAction(() => { |
|
|
|
if (centerPosition && radius > 0) { |
|
|
|
this.finishCircleDrawing(centerPosition, radius) |
|
|
|
centerPosition = null |
|
|
|
radius = 0 |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_UP) |
|
|
|
|
|
|
|
// 右键取消 |
|
|
|
// this.drawingHandler.setInputAction(() => { |
|
|
|
// this.cancelDrawing() |
|
|
|
// }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) |
|
|
|
this.cancelDrawing(); |
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK); |
|
|
|
}, |
|
|
|
|
|
|
|
finishCircleDrawing(center, radius) { |
|
|
|
const positions = this.calculateCircle(center, radius, 64) |
|
|
|
const entity = this.addCircleEntity(center, radius, positions) |
|
|
|
finishCircleDrawing(edgePosition) { |
|
|
|
const centerPoint = this.drawingPoints[0]; |
|
|
|
|
|
|
|
// 1. 计算最终半径 |
|
|
|
const radius = Cesium.Cartesian3.distance(centerPoint, edgePosition); |
|
|
|
|
|
|
|
// 2. 移除动态预览实体 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
} |
|
|
|
|
|
|
|
// 计算面积 |
|
|
|
const area = Math.PI * radius * radius |
|
|
|
// 3. 创建最终显示的静态实体 |
|
|
|
const finalEntity = this.viewer.entities.add({ |
|
|
|
id: 'circle-' + new Date().getTime(), |
|
|
|
position: centerPoint, |
|
|
|
ellipse: { |
|
|
|
semiMajorAxis: radius, |
|
|
|
semiMinorAxis: radius, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
outlineWidth: 2 |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 4. 记录实体 |
|
|
|
this.allEntities.push(finalEntity); |
|
|
|
|
|
|
|
// 5. 计算面积 (π * r²) 并显示 |
|
|
|
// 半径单位是米,面积单位是平方米 |
|
|
|
const area = Math.PI * Math.pow(radius, 2); |
|
|
|
|
|
|
|
this.measurementResult = { |
|
|
|
radius: radius, // 也可以额外显示半径 |
|
|
|
area: area, |
|
|
|
radius: radius, |
|
|
|
type: 'circle' |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
this.stopDrawing() |
|
|
|
return entity |
|
|
|
}, |
|
|
|
|
|
|
|
cancelDrawing() { |
|
|
|
this.stopDrawing() |
|
|
|
this.drawingMode = null |
|
|
|
// 6. 结束绘制状态 |
|
|
|
this.stopDrawing(); |
|
|
|
}, |
|
|
|
|
|
|
|
// ================== 实体创建方法 ================== |
|
|
|
@ -1522,3 +1718,5 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|
|
|
|
|
|
|
|
|