|
|
|
@ -153,10 +153,10 @@ export default { |
|
|
|
defaultStyles: { |
|
|
|
point: { color: '#FF0000', size: 12 }, |
|
|
|
line: { color: '#00FF00', width: 3 }, |
|
|
|
polygon: { color: '#0000FF', opacity: 0.5, width: 2 }, |
|
|
|
rectangle: { color: '#FFA500', opacity: 0.3, width: 2 }, |
|
|
|
circle: { color: '#800080', opacity: 0.4, width: 2 }, |
|
|
|
sector: { color: '#FF6347', opacity: 0.5, width: 2 }, |
|
|
|
polygon: { color: '#0000FF', opacity: 0, width: 4 }, |
|
|
|
rectangle: { color: '#FFA500', opacity: 0, width: 4 }, |
|
|
|
circle: { color: '#800080', opacity: 0, width: 4 }, |
|
|
|
sector: { color: '#FF6347', opacity: 0, width: 3 }, |
|
|
|
arrow: { color: '#FF0000', width: 6 }, |
|
|
|
text: { color: '#000000', font: '48px Microsoft YaHei, PingFang SC, sans-serif', backgroundColor: 'rgba(255, 255, 255, 0.8)' }, |
|
|
|
image: { width: 150, height: 150 } |
|
|
|
@ -197,60 +197,60 @@ export default { |
|
|
|
methods: { |
|
|
|
updateScaleFromConfig(config) { |
|
|
|
if (!config || !this.viewer) return |
|
|
|
|
|
|
|
|
|
|
|
const { scaleNumerator, scaleDenominator, unit } = config |
|
|
|
if (!scaleDenominator || scaleDenominator <= 0) return |
|
|
|
|
|
|
|
|
|
|
|
let displayValue = '' |
|
|
|
let metersPerPixel = 0 |
|
|
|
|
|
|
|
|
|
|
|
const standardDPI = 96 |
|
|
|
const pixelsPerCm = standardDPI * 0.393701 |
|
|
|
|
|
|
|
|
|
|
|
const scaleFactor = scaleDenominator / scaleNumerator |
|
|
|
|
|
|
|
|
|
|
|
switch (unit) { |
|
|
|
case 'm': |
|
|
|
displayValue = `1:${scaleDenominator}` |
|
|
|
displayValue = `${scaleDenominator}` |
|
|
|
metersPerPixel = scaleFactor / pixelsPerCm |
|
|
|
break |
|
|
|
case 'km': |
|
|
|
displayValue = `1:${scaleDenominator}` |
|
|
|
displayValue = `${scaleDenominator}` |
|
|
|
metersPerPixel = (scaleFactor * 1000) / pixelsPerCm |
|
|
|
break |
|
|
|
default: |
|
|
|
displayValue = `1:${scaleDenominator}` |
|
|
|
displayValue = `${scaleDenominator}` |
|
|
|
metersPerPixel = scaleFactor / pixelsPerCm |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log('比例尺设置:', displayValue, '每像素米数:', metersPerPixel.toFixed(4)) |
|
|
|
|
|
|
|
|
|
|
|
this.isApplyingScale = true |
|
|
|
this.useCustomScale = true |
|
|
|
this.customScaleText = displayValue |
|
|
|
this.currentScaleUnit = unit |
|
|
|
|
|
|
|
|
|
|
|
this.applyScaleToCamera(metersPerPixel) |
|
|
|
this.updateScaleBar() |
|
|
|
this.$forceUpdate() |
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
this.isApplyingScale = false |
|
|
|
}, 1000) |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
applyScaleToCamera(metersPerPixel) { |
|
|
|
if (!this.viewer || !this.viewer.camera) return |
|
|
|
|
|
|
|
|
|
|
|
const canvas = this.viewer.scene.canvas |
|
|
|
const width = canvas.clientWidth |
|
|
|
const height = canvas.clientHeight |
|
|
|
|
|
|
|
|
|
|
|
if (width <= 0 || height <= 0) return |
|
|
|
|
|
|
|
|
|
|
|
const camera = this.viewer.camera |
|
|
|
const scene = this.viewer.scene |
|
|
|
|
|
|
|
|
|
|
|
if (scene.mode === Cesium.SceneMode.SCENE2D) { |
|
|
|
const frustumWidth = width * metersPerPixel |
|
|
|
camera.frustum.right = frustumWidth / 2 |
|
|
|
@ -261,19 +261,19 @@ export default { |
|
|
|
} else { |
|
|
|
const cameraPosition = camera.positionCartographic |
|
|
|
const groundWidth = width * metersPerPixel |
|
|
|
|
|
|
|
|
|
|
|
const fov = camera.frustum.fov || Cesium.Math.PI_OVER_THREE |
|
|
|
const aspectRatio = width / height |
|
|
|
const verticalFov = fov / aspectRatio |
|
|
|
|
|
|
|
|
|
|
|
const targetHeight = (groundWidth / 2) / Math.tan(fov / 2) |
|
|
|
|
|
|
|
|
|
|
|
const destination = Cesium.Cartesian3.fromRadians( |
|
|
|
cameraPosition.longitude, |
|
|
|
cameraPosition.latitude, |
|
|
|
targetHeight |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
camera.flyTo({ |
|
|
|
destination: destination, |
|
|
|
duration: 0.5, |
|
|
|
@ -948,36 +948,21 @@ export default { |
|
|
|
} |
|
|
|
// 如果是线实体,显示长度信息 |
|
|
|
if (entityData && entityData.type === 'line') { |
|
|
|
// 找到鼠标悬停在线段的哪一段 |
|
|
|
const segmentIndex = this.findClosestSegment(entityData.positions, movement.endPosition); |
|
|
|
if (segmentIndex !== -1) { |
|
|
|
// 计算累计长度(前segmentIndex+1段的长度) |
|
|
|
let cumulativeLength = 0; |
|
|
|
for (let i = 0; i < segmentIndex + 1; i++) { |
|
|
|
if (i < entityData.positions.length - 1) { |
|
|
|
cumulativeLength += Cesium.Cartesian3.distance(entityData.positions[i], entityData.positions[i + 1]); |
|
|
|
} |
|
|
|
const length = this.calculateLineLength(entityData.positions) |
|
|
|
// 根据当前方位角类型计算方位角 |
|
|
|
const bearingType = entityData.bearingType || 'true'; |
|
|
|
const bearing = bearingType === 'magnetic' |
|
|
|
? this.calculateMagneticBearing(entityData.positions) |
|
|
|
: this.calculateTrueBearing(entityData.positions); |
|
|
|
// 显示小框提示 |
|
|
|
this.hoverTooltip = { |
|
|
|
visible: true, |
|
|
|
content: `${(length / 1000).toFixed(1)}km ,${bearingType === 'magnetic' ? '磁' : '真'}:${bearing.toFixed(1)}°`, |
|
|
|
position: { |
|
|
|
x: movement.endPosition.x + 10, |
|
|
|
y: movement.endPosition.y - 10 |
|
|
|
} |
|
|
|
// 计算当前段的方位角 |
|
|
|
const currentSegmentPositions = [entityData.positions[segmentIndex], entityData.positions[segmentIndex + 1]]; |
|
|
|
// 根据当前方位角类型计算方位角 |
|
|
|
const bearingType = entityData.bearingType || 'true'; |
|
|
|
const bearing = bearingType === 'magnetic' |
|
|
|
? this.calculateMagneticBearing(currentSegmentPositions) |
|
|
|
: this.calculateTrueBearing(currentSegmentPositions); |
|
|
|
// 显示小框提示 |
|
|
|
this.hoverTooltip = { |
|
|
|
visible: true, |
|
|
|
content: `累计长度:${cumulativeLength.toFixed(2)} 米\n${bearingType === 'magnetic' ? '磁方位' : '真方位'}:${bearing.toFixed(2)}°`, |
|
|
|
position: { |
|
|
|
x: movement.endPosition.x + 10, |
|
|
|
y: movement.endPosition.y - 10 |
|
|
|
} |
|
|
|
}; |
|
|
|
} else { |
|
|
|
// 如果没有找到对应的段,隐藏信息 |
|
|
|
this.hoverTooltip.visible = false; |
|
|
|
} |
|
|
|
}; |
|
|
|
} else { |
|
|
|
// 如果不是线实体,隐藏信息 |
|
|
|
this.hoverTooltip.visible = false; |
|
|
|
@ -1416,8 +1401,8 @@ export default { |
|
|
|
} |
|
|
|
return new Cesium.PolygonHierarchy(this.drawingPoints); |
|
|
|
}, false), |
|
|
|
// 使用半透明颜色,方便看到地图底图 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
// 不填充颜色 |
|
|
|
material: Cesium.Color.TRANSPARENT, |
|
|
|
// 确保贴地 |
|
|
|
perPositionHeight: false |
|
|
|
}, |
|
|
|
@ -1431,12 +1416,9 @@ export default { |
|
|
|
} |
|
|
|
return this.drawingPoints; |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.line.width, |
|
|
|
// 边框使用虚线,表示正在编辑中 |
|
|
|
material: new Cesium.PolylineDashMaterialProperty({ |
|
|
|
color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
dashLength: 16 |
|
|
|
}), |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
// 边框使用实线,表示正在编辑中 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
@ -1495,6 +1477,7 @@ export default { |
|
|
|
this.activeCursorPosition = position; // 初始化鼠标位置 |
|
|
|
// 创建动态预览矩形 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
// 填充部分 |
|
|
|
rectangle: { |
|
|
|
// 关键:使用 CallbackProperty 动态计算矩形范围 |
|
|
|
coordinates: new Cesium.CallbackProperty(() => { |
|
|
|
@ -1504,11 +1487,35 @@ export default { |
|
|
|
} |
|
|
|
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.line.color), |
|
|
|
outlineWidth: 2, |
|
|
|
// 设置填充颜色 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color).withAlpha(this.defaultStyles.rectangle.opacity), |
|
|
|
clampToGround: true // 贴地 |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
// 关键:使用 CallbackProperty 动态计算矩形边框线 |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
if (this.drawingPoints.length > 0 && this.activeCursorPosition) { |
|
|
|
// 计算矩形的四个角点 |
|
|
|
const rect = Cesium.Rectangle.fromCartesianArray([this.drawingPoints[0], this.activeCursorPosition]); |
|
|
|
const west = rect.west; |
|
|
|
const south = rect.south; |
|
|
|
const east = rect.east; |
|
|
|
const north = rect.north; |
|
|
|
|
|
|
|
// 创建四个角点的笛卡尔坐标 |
|
|
|
const southwest = Cesium.Cartesian3.fromRadians(west, south); |
|
|
|
const southeast = Cesium.Cartesian3.fromRadians(east, south); |
|
|
|
const northeast = Cesium.Cartesian3.fromRadians(east, north); |
|
|
|
const northwest = Cesium.Cartesian3.fromRadians(west, north); |
|
|
|
|
|
|
|
// 返回闭合的边框线位置数组 |
|
|
|
return [southwest, southeast, northeast, northwest, southwest]; |
|
|
|
} |
|
|
|
return []; |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.rectangle.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), |
|
|
|
clampToGround: true // 贴地 |
|
|
|
} |
|
|
|
}); |
|
|
|
@ -1539,14 +1546,36 @@ export default { |
|
|
|
// 3. 创建最终显示的静态实体 |
|
|
|
this.entityCounter++; |
|
|
|
const id = `rectangle_${this.entityCounter}`; |
|
|
|
|
|
|
|
// 计算矩形的四个角点 |
|
|
|
const west = rect.west; |
|
|
|
const south = rect.south; |
|
|
|
const east = rect.east; |
|
|
|
const north = rect.north; |
|
|
|
|
|
|
|
// 创建四个角点的笛卡尔坐标 |
|
|
|
const southwest = Cesium.Cartesian3.fromRadians(west, south); |
|
|
|
const southeast = Cesium.Cartesian3.fromRadians(east, south); |
|
|
|
const northeast = Cesium.Cartesian3.fromRadians(east, north); |
|
|
|
const northwest = Cesium.Cartesian3.fromRadians(west, north); |
|
|
|
|
|
|
|
// 创建边框线的位置数组(闭合) |
|
|
|
const borderPositions = [southwest, southeast, northeast, northwest, southwest]; |
|
|
|
|
|
|
|
// 创建一个复合实体,包含填充和边框 |
|
|
|
const finalEntity = this.viewer.entities.add({ |
|
|
|
id: id, |
|
|
|
// 填充部分 |
|
|
|
rectangle: { |
|
|
|
coordinates: rect, |
|
|
|
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, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color).withAlpha(this.defaultStyles.rectangle.opacity), |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
positions: borderPositions, |
|
|
|
width: this.defaultStyles.rectangle.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
@ -1557,9 +1586,10 @@ export default { |
|
|
|
points: this.drawingPoints.map(p => this.cartesianToLatLng(p)), |
|
|
|
positions: this.drawingPoints, |
|
|
|
entity: finalEntity, |
|
|
|
color: this.defaultStyles.polygon.color, |
|
|
|
opacity: this.defaultStyles.polygon.opacity, |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
color: this.defaultStyles.rectangle.color, // 填充颜色 |
|
|
|
borderColor: this.defaultStyles.rectangle.color, // 边框颜色 |
|
|
|
opacity: this.defaultStyles.rectangle.opacity, |
|
|
|
width: this.defaultStyles.rectangle.width, |
|
|
|
label: `矩形 ${this.entityCounter}` |
|
|
|
}; |
|
|
|
this.allEntities.push(entityData); |
|
|
|
@ -1691,12 +1721,33 @@ export default { |
|
|
|
return initialRadius; |
|
|
|
} |
|
|
|
}, false), |
|
|
|
// 样式设置 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), |
|
|
|
outlineWidth: 2, |
|
|
|
// height: 0, // 如果需要贴地可开启或使用 heightReference |
|
|
|
// 设置填充颜色 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color).withAlpha(this.defaultStyles.circle.opacity), |
|
|
|
// 移除 outline 属性,改用 polyline 绘制边框 |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
// 关键:使用 CallbackProperty 动态计算圆形边框线 |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
try { |
|
|
|
if (this.activeCursorPosition && this.drawingPoints.length > 0 && this.drawingPoints[0]) { |
|
|
|
const center = this.drawingPoints[0]; |
|
|
|
const edge = this.activeCursorPosition; |
|
|
|
if (center && edge && typeof center.x === 'number' && typeof edge.x === 'number') { |
|
|
|
const radius = Cesium.Cartesian3.distance(center, edge); |
|
|
|
const validRadius = isFinite(radius) && radius > 0 ? radius : initialRadius; |
|
|
|
return this.generateCirclePositions(center, validRadius); |
|
|
|
} |
|
|
|
} |
|
|
|
return []; |
|
|
|
} catch (e) { |
|
|
|
return []; |
|
|
|
} |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.circle.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -1735,16 +1786,28 @@ export default { |
|
|
|
// 3. 创建最终显示的静态实体 |
|
|
|
this.entityCounter++; |
|
|
|
const id = `circle_${this.entityCounter}`; |
|
|
|
|
|
|
|
// 生成圆形的点,用于绘制边框线 |
|
|
|
const circlePositions = this.generateCirclePositions(centerPoint, radius); |
|
|
|
|
|
|
|
// 创建一个复合实体,包含填充和边框 |
|
|
|
const finalEntity = this.viewer.entities.add({ |
|
|
|
id: id, |
|
|
|
position: centerPoint, |
|
|
|
// 填充部分 |
|
|
|
ellipse: { |
|
|
|
semiMajorAxis: radius, |
|
|
|
semiMinorAxis: radius, |
|
|
|
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 |
|
|
|
// 设置填充颜色 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color).withAlpha(this.defaultStyles.circle.opacity), |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
positions: circlePositions, |
|
|
|
width: this.defaultStyles.circle.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
// 4. 记录实体 |
|
|
|
@ -1754,9 +1817,10 @@ export default { |
|
|
|
points: [centerPoint, edgePosition].map(p => this.cartesianToLatLng(p)), |
|
|
|
positions: [centerPoint, edgePosition], |
|
|
|
entity: finalEntity, |
|
|
|
color: this.defaultStyles.polygon.color, |
|
|
|
opacity: this.defaultStyles.polygon.opacity, |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
color: this.defaultStyles.circle.color, // 填充颜色 |
|
|
|
borderColor: this.defaultStyles.circle.color, // 边框颜色 |
|
|
|
opacity: this.defaultStyles.circle.opacity, |
|
|
|
width: this.defaultStyles.circle.width, |
|
|
|
radius: radius, |
|
|
|
label: `圆形 ${this.entityCounter}` |
|
|
|
}; |
|
|
|
@ -1829,6 +1893,7 @@ export default { |
|
|
|
} |
|
|
|
// 创建动态预览扇形 |
|
|
|
this.tempEntity = this.viewer.entities.add({ |
|
|
|
// 填充部分 |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.CallbackProperty(() => { |
|
|
|
if (this.drawingPoints.length > 1 && this.activeCursorPosition) { |
|
|
|
@ -1844,10 +1909,29 @@ export default { |
|
|
|
} |
|
|
|
return new Cesium.PolygonHierarchy([]); |
|
|
|
}, false), |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), |
|
|
|
outlineWidth: this.defaultStyles.sector.width |
|
|
|
// 设置填充颜色 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(this.defaultStyles.sector.opacity), |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
if (this.drawingPoints.length > 1 && this.activeCursorPosition) { |
|
|
|
const centerPoint = this.drawingPoints[0]; |
|
|
|
const radiusPoint = this.drawingPoints[1]; |
|
|
|
if (!isFinite(fixedRadius) || fixedRadius === 0) { |
|
|
|
return []; |
|
|
|
} |
|
|
|
const startAngle = this.calculatePointAngle(centerPoint, radiusPoint); |
|
|
|
const endAngle = this.calculatePointAngle(centerPoint, this.activeCursorPosition); |
|
|
|
const positions = this.generateSectorPositions(centerPoint, fixedRadius, startAngle, endAngle); |
|
|
|
return positions; |
|
|
|
} |
|
|
|
return []; |
|
|
|
}, false), |
|
|
|
width: this.defaultStyles.sector.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -1881,13 +1965,19 @@ export default { |
|
|
|
const finalEntity = this.viewer.entities.add({ |
|
|
|
id: 'sector-' + new Date().getTime(), |
|
|
|
name: `扇形 ${this.entityCounter}`, |
|
|
|
// 填充部分 |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(positions), |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), |
|
|
|
outlineWidth: this.defaultStyles.sector.width, |
|
|
|
perPositionHeight: false |
|
|
|
// 设置填充颜色 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(this.defaultStyles.sector.opacity), |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
positions: positions, |
|
|
|
width: this.defaultStyles.sector.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}); |
|
|
|
// 4. 记录实体 |
|
|
|
@ -1901,7 +1991,8 @@ export default { |
|
|
|
endAngle: endAngle, |
|
|
|
positions: positions, |
|
|
|
entity: finalEntity, |
|
|
|
color: this.defaultStyles.sector.color, |
|
|
|
color: this.defaultStyles.sector.color, // 填充颜色 |
|
|
|
borderColor: this.defaultStyles.sector.color, // 边框颜色 |
|
|
|
opacity: 0.5, |
|
|
|
width: this.defaultStyles.sector.width, |
|
|
|
label: `扇形 ${this.entityCounter}` |
|
|
|
@ -1910,6 +2001,35 @@ export default { |
|
|
|
// 5. 重置状态,保持绘制状态以继续绘制 |
|
|
|
this.drawingPoints = []; |
|
|
|
}, |
|
|
|
// 生成圆形的点,用于绘制边框线 |
|
|
|
generateCirclePositions(center, radius, numPoints = 128) { |
|
|
|
const positions = []; |
|
|
|
const ellipsoid = this.viewer.scene.globe.ellipsoid; |
|
|
|
|
|
|
|
// 计算圆心的经纬度 |
|
|
|
const centerCartographic = Cesium.Cartographic.fromCartesian(center); |
|
|
|
const centerLatitude = centerCartographic.latitude; |
|
|
|
const centerLongitude = centerCartographic.longitude; |
|
|
|
|
|
|
|
// 生成圆形的点 |
|
|
|
for (let i = 0; i <= numPoints; i++) { |
|
|
|
const angle = (i / numPoints) * Math.PI * 2; |
|
|
|
|
|
|
|
// 计算点的经纬度 |
|
|
|
// 注意:这里使用简单的方法计算,实际应该考虑地球曲率 |
|
|
|
const deltaLatitude = (radius / ellipsoid.maximumRadius) * Math.sin(angle); |
|
|
|
const deltaLongitude = (radius / ellipsoid.maximumRadius) * Math.cos(angle) / Math.cos(centerLatitude); |
|
|
|
|
|
|
|
const latitude = centerLatitude + deltaLatitude; |
|
|
|
const longitude = centerLongitude + deltaLongitude; |
|
|
|
|
|
|
|
// 转换为笛卡尔坐标 |
|
|
|
const position = Cesium.Cartesian3.fromRadians(longitude, latitude); |
|
|
|
positions.push(position); |
|
|
|
} |
|
|
|
|
|
|
|
return positions; |
|
|
|
}, |
|
|
|
// 计算角度 |
|
|
|
calculateAngle(center, start, end) { |
|
|
|
const startLL = Cesium.Cartographic.fromCartesian(start); |
|
|
|
@ -1959,7 +2079,7 @@ export default { |
|
|
|
// 确保角度差不为零 |
|
|
|
angleDiff = Math.max(0.01, angleDiff); |
|
|
|
// 计算扇形的顶点数(根据角度差确定,确保平滑) |
|
|
|
const numPoints = Math.max(5, Math.ceil(angleDiff * 180 / Math.PI / 10)); |
|
|
|
const numPoints = Math.max(10, Math.ceil(angleDiff * 180 / Math.PI / 5)); |
|
|
|
const angleStep = angleDiff / (numPoints - 1); |
|
|
|
// 生成扇形的顶点(顺时针方向) |
|
|
|
for (let i = 0; i < numPoints; i++) { |
|
|
|
@ -2384,16 +2504,23 @@ export default { |
|
|
|
const id = `polygon_${this.entityCounter}` |
|
|
|
// 闭合多边形 |
|
|
|
const polygonPositions = [...positions, positions[0]] |
|
|
|
// 创建一个复合实体,包含填充和边框 |
|
|
|
const entity = this.viewer.entities.add({ |
|
|
|
id: id, |
|
|
|
name: `面 ${this.entityCounter}`, |
|
|
|
// 填充部分 |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(polygonPositions), |
|
|
|
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 |
|
|
|
// 初始无填充 |
|
|
|
material: Cesium.Color.TRANSPARENT, |
|
|
|
clampToGround: true |
|
|
|
}, |
|
|
|
// 边框部分 |
|
|
|
polyline: { |
|
|
|
positions: polygonPositions, |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), |
|
|
|
clampToGround: true |
|
|
|
} |
|
|
|
}) |
|
|
|
const entityData = { |
|
|
|
@ -2403,7 +2530,8 @@ export default { |
|
|
|
positions: polygonPositions, |
|
|
|
entity: entity, |
|
|
|
color: this.defaultStyles.polygon.color, |
|
|
|
opacity: this.defaultStyles.polygon.opacity, |
|
|
|
borderColor: this.defaultStyles.polygon.color, |
|
|
|
opacity: 0, |
|
|
|
width: this.defaultStyles.polygon.width, |
|
|
|
label: `面 ${this.entityCounter}` |
|
|
|
} |
|
|
|
@ -2422,8 +2550,8 @@ export default { |
|
|
|
name: `矩形 ${this.entityCounter}`, |
|
|
|
rectangle: { |
|
|
|
coordinates: coordinates, |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) |
|
|
|
.withAlpha(this.defaultStyles.rectangle.opacity), |
|
|
|
// 移除填充颜色,只显示边框 |
|
|
|
material: Cesium.Color.TRANSPARENT, |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), |
|
|
|
outlineWidth: this.defaultStyles.rectangle.width |
|
|
|
@ -2446,8 +2574,8 @@ export default { |
|
|
|
ellipse: { |
|
|
|
semiMinorAxis: validRadius, // 半短轴 = 半径 |
|
|
|
semiMajorAxis: validRadius, // 半长轴 = 半径 |
|
|
|
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) |
|
|
|
.withAlpha(this.defaultStyles.circle.opacity), |
|
|
|
// 移除填充颜色,只显示边框 |
|
|
|
material: Cesium.Color.TRANSPARENT, |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), |
|
|
|
outlineWidth: this.defaultStyles.circle.width |
|
|
|
@ -2469,6 +2597,13 @@ export default { |
|
|
|
lng: Cesium.Math.toDegrees(cartographic.longitude) |
|
|
|
} |
|
|
|
}, |
|
|
|
degreesToDMS(decimalDegrees) { |
|
|
|
const degrees = Math.floor(decimalDegrees) |
|
|
|
const minutesDecimal = (decimalDegrees - degrees) * 60 |
|
|
|
const minutes = Math.floor(minutesDecimal) |
|
|
|
const seconds = ((minutesDecimal - minutes) * 60).toFixed(2) |
|
|
|
return `${degrees}°${minutes}'${seconds}"` |
|
|
|
}, |
|
|
|
calculateRectangle(start, end) { |
|
|
|
const startLL = this.cartesianToLatLng(start) |
|
|
|
const endLL = this.cartesianToLatLng(end) |
|
|
|
@ -2640,29 +2775,37 @@ export default { |
|
|
|
case 'polygon': |
|
|
|
if (entity.polygon) { |
|
|
|
entity.polygon.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) |
|
|
|
entity.polygon.outlineColor = Cesium.Color.fromCssColorString(data.color) |
|
|
|
entity.polygon.outlineWidth = data.width |
|
|
|
} |
|
|
|
if (entity.polyline) { |
|
|
|
entity.polyline.material = Cesium.Color.fromCssColorString(data.borderColor || data.color) |
|
|
|
entity.polyline.width = data.width |
|
|
|
} |
|
|
|
break |
|
|
|
case 'rectangle': |
|
|
|
if (entity.rectangle) { |
|
|
|
entity.rectangle.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) |
|
|
|
entity.rectangle.outlineColor = Cesium.Color.fromCssColorString(data.color) |
|
|
|
entity.rectangle.outlineWidth = data.width |
|
|
|
} |
|
|
|
if (entity.polyline) { |
|
|
|
entity.polyline.material = Cesium.Color.fromCssColorString(data.borderColor || data.color) |
|
|
|
entity.polyline.width = data.width |
|
|
|
} |
|
|
|
break |
|
|
|
case 'circle': |
|
|
|
if (entity.ellipse) { |
|
|
|
entity.ellipse.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) |
|
|
|
entity.ellipse.outlineColor = Cesium.Color.fromCssColorString(data.color) |
|
|
|
entity.ellipse.outlineWidth = data.width |
|
|
|
} |
|
|
|
if (entity.polyline) { |
|
|
|
entity.polyline.material = Cesium.Color.fromCssColorString(data.borderColor || data.color) |
|
|
|
entity.polyline.width = data.width |
|
|
|
} |
|
|
|
break |
|
|
|
case 'sector': |
|
|
|
if (entity.polygon) { |
|
|
|
entity.polygon.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) |
|
|
|
entity.polygon.outlineColor = Cesium.Color.fromCssColorString(data.color) |
|
|
|
entity.polygon.outlineWidth = data.width |
|
|
|
} |
|
|
|
if (entity.polyline) { |
|
|
|
entity.polyline.material = Cesium.Color.fromCssColorString(data.borderColor || data.color) |
|
|
|
entity.polyline.width = data.width |
|
|
|
} |
|
|
|
break |
|
|
|
case 'arrow': |
|
|
|
@ -2713,6 +2856,10 @@ export default { |
|
|
|
const entityData = this.contextMenu.entityData |
|
|
|
// 更新实体数据 |
|
|
|
entityData[property] = value |
|
|
|
// 当修改填充色时,默认设置透明度为 20% |
|
|
|
if (property === 'color' && (entityData.type === 'polygon' || entityData.type === 'rectangle' || entityData.type === 'circle' || entityData.type === 'sector')) { |
|
|
|
entityData.opacity = 0.2 |
|
|
|
} |
|
|
|
// 更新实体样式 |
|
|
|
this.updateEntityStyle(entityData) |
|
|
|
// 隐藏右键菜单 |
|
|
|
@ -2750,49 +2897,102 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
clearAll() { |
|
|
|
// 1. 检查数组是否有内容 |
|
|
|
if (this.allEntities && this.allEntities.length > 0) { |
|
|
|
// 2. 遍历每一个对象进行删除 |
|
|
|
this.allEntities.forEach(item => { |
|
|
|
try { |
|
|
|
// 情况 A: 数组里存的是原生的 Cesium Entity (点、线通常是这种情况) |
|
|
|
if (item instanceof Cesium.Entity) { |
|
|
|
this.viewer.entities.remove(item); |
|
|
|
} |
|
|
|
// 情况 B: 数组里存的是包装对象 (你的矩形、圆可能是这种 { entity: ... }) |
|
|
|
else if (item.entity && item.entity instanceof Cesium.Entity) { |
|
|
|
this.viewer.entities.remove(item.entity); |
|
|
|
} |
|
|
|
// 情况 C: 兜底方案,尝试通过 ID 删除 |
|
|
|
else if (item.id) { |
|
|
|
this.viewer.entities.removeById(item.id); |
|
|
|
} |
|
|
|
// 移除线实体相关的点实体 |
|
|
|
if (item.type === 'line' && item.pointEntities) { |
|
|
|
item.pointEntities.forEach(pointEntity => { |
|
|
|
this.viewer.entities.remove(pointEntity); |
|
|
|
}); |
|
|
|
clearAll(showConfirm = true) { |
|
|
|
if (showConfirm) { |
|
|
|
this.$confirm('是否清除所有编辑内容?', '提示', { |
|
|
|
confirmButtonText: '确定', |
|
|
|
cancelButtonText: '取消', |
|
|
|
type: 'warning' |
|
|
|
}).then(() => { |
|
|
|
this.executeClearAll(); |
|
|
|
}).catch(() => { |
|
|
|
// 用户点击取消,不做任何操作 |
|
|
|
}); |
|
|
|
} else { |
|
|
|
this.executeClearAll(); |
|
|
|
} |
|
|
|
}, |
|
|
|
executeClearAll() { |
|
|
|
// 1. 检查数组是否有内容 |
|
|
|
if (this.allEntities && this.allEntities.length > 0) { |
|
|
|
// 2. 遍历每一个对象进行删除 |
|
|
|
this.allEntities.forEach(item => { |
|
|
|
try { |
|
|
|
let entity = null; |
|
|
|
|
|
|
|
// 情况 A: 数组里存的是原生的 Cesium Entity (点、线通常是这种情况) |
|
|
|
if (item instanceof Cesium.Entity) { |
|
|
|
entity = item; |
|
|
|
} |
|
|
|
// 情况 B: 数组里存的是包装对象 (你的矩形、圆可能是这种 { entity: ... }) |
|
|
|
else if (item.entity && item.entity instanceof Cesium.Entity) { |
|
|
|
entity = item.entity; |
|
|
|
} |
|
|
|
// 情况 C: 兜底方案,尝试通过 ID 删除 |
|
|
|
else if (item.id) { |
|
|
|
entity = this.viewer.entities.getById(item.id); |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否是航线实体,如果是则跳过删除 |
|
|
|
if (entity && entity.properties) { |
|
|
|
const isMissionWaypoint = entity.properties.isMissionWaypoint; |
|
|
|
const isMissionRouteLine = entity.properties.isMissionRouteLine; |
|
|
|
if (isMissionWaypoint || isMissionRouteLine) { |
|
|
|
return; // 跳过航线相关实体 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 删除非航线实体 |
|
|
|
if (entity) { |
|
|
|
this.viewer.entities.remove(entity); |
|
|
|
} |
|
|
|
|
|
|
|
// 移除线实体相关的点实体 |
|
|
|
if (item.type === 'line' && item.pointEntities) { |
|
|
|
item.pointEntities.forEach(pointEntity => { |
|
|
|
this.viewer.entities.remove(pointEntity); |
|
|
|
}); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.warn('删除实体失败:', e); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.warn('删除实体失败:', e); |
|
|
|
}); |
|
|
|
} |
|
|
|
// 3. 清空数组(只保留航线实体) |
|
|
|
this.allEntities = this.allEntities.filter(item => { |
|
|
|
let entity = null; |
|
|
|
if (item instanceof Cesium.Entity) { |
|
|
|
entity = item; |
|
|
|
} else if (item.entity && item.entity instanceof Cesium.Entity) { |
|
|
|
entity = item.entity; |
|
|
|
} else if (item.id) { |
|
|
|
entity = this.viewer.entities.getById(item.id); |
|
|
|
} |
|
|
|
|
|
|
|
if (entity && entity.properties) { |
|
|
|
const isMissionWaypoint = entity.properties.isMissionWaypoint; |
|
|
|
const isMissionRouteLine = entity.properties.isMissionRouteLine; |
|
|
|
return isMissionWaypoint || isMissionRouteLine; |
|
|
|
} |
|
|
|
return false; |
|
|
|
}); |
|
|
|
// 4. 清理可能残留的绘制过程中的临时图形 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
} |
|
|
|
if (this.tempPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
} |
|
|
|
// 5. 重置其他状态(如测量面板、绘制状态) |
|
|
|
this.measurementResult = null; |
|
|
|
this.stopDrawing(); |
|
|
|
|
|
|
|
this.$message({ |
|
|
|
type: 'success', |
|
|
|
message: '清除成功!' |
|
|
|
}); |
|
|
|
} |
|
|
|
// 3. 清空数组 |
|
|
|
this.allEntities = []; |
|
|
|
// 4. 清理可能残留的绘制过程中的临时图形 |
|
|
|
if (this.tempEntity) { |
|
|
|
this.viewer.entities.remove(this.tempEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
} |
|
|
|
if (this.tempPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
} |
|
|
|
// 5. 重置其他状态(如测量面板、绘制状态) |
|
|
|
this.measurementResult = null; |
|
|
|
this.stopDrawing(); |
|
|
|
}, |
|
|
|
// ================== 其他方法 ================== |
|
|
|
getTypeName(type) { |
|
|
|
@ -3012,7 +3212,7 @@ export default { |
|
|
|
}, |
|
|
|
duration: 2 |
|
|
|
}) |
|
|
|
this.$message.success(`已定位到经度 ${lng.toFixed(4)},纬度 ${lat.toFixed(4)}`) |
|
|
|
this.$message.success(`已定位到经度 ${this.degreesToDMS(lng)},纬度 ${this.degreesToDMS(lat)}`) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -3284,7 +3484,7 @@ export default { |
|
|
|
const cartographic = Cesium.Cartographic.fromCartesian(cartesian) |
|
|
|
const longitude = Cesium.Math.toDegrees(cartographic.longitude) |
|
|
|
const latitude = Cesium.Math.toDegrees(cartographic.latitude) |
|
|
|
this.coordinatesText = `经度: ${longitude.toFixed(6)}, 纬度: ${latitude.toFixed(6)}` |
|
|
|
this.coordinatesText = `经度: ${this.degreesToDMS(longitude)}, 纬度: ${this.degreesToDMS(latitude)}` |
|
|
|
} else { |
|
|
|
this.coordinatesText = '经度: --, 纬度: --' |
|
|
|
} |
|
|
|
@ -3292,7 +3492,7 @@ export default { |
|
|
|
}, |
|
|
|
destroyViewer() { |
|
|
|
this.stopDrawing() |
|
|
|
this.clearAll() |
|
|
|
this.clearAll(false) |
|
|
|
|
|
|
|
if (this.pointMovementHandler) { |
|
|
|
this.pointMovementHandler.destroy() |
|
|
|
|