Browse Source

Merge branch 'lbj' of http://124.70.32.114:3100/woka/cesium-map-object into ctw

# Conflicts:
#	ruoyi-ui/src/views/cesiumMap/ContextMenu.vue
#	ruoyi-ui/src/views/cesiumMap/index.vue
master
cuitw 2 months ago
parent
commit
c65594e84b
  1. 12
      ruoyi-ui/src/views/cesiumMap/ContextMenu.vue
  2. 95
      ruoyi-ui/src/views/cesiumMap/LocateDialog.vue
  3. 187
      ruoyi-ui/src/views/cesiumMap/index.vue
  4. 8
      ruoyi-ui/src/views/childRoom/index.vue
  5. 13
      ruoyi-ui/src/views/dialogs/RadiusDialog.vue

12
ruoyi-ui/src/views/cesiumMap/ContextMenu.vue

@ -126,6 +126,11 @@
<!-- 多边形特有选项 -->
<div class="menu-section" v-if="entityData.type === 'polygon' || entityData.type === 'rectangle' || entityData.type === 'circle' || entityData.type === 'sector' || entityData.type === 'powerZone'">
<div class="menu-title">填充属性</div>
<div class="menu-item" @click="editName" v-if="entityData.type === 'powerZone'">
<span class="menu-icon">📝</span>
<span>名称</span>
<span class="menu-value">{{ entityData.name || '' }}</span>
</div>
<div class="menu-item" @click="toggleColorPicker('color')">
<span class="menu-icon">🎨</span>
<span>填充色</span>
@ -384,6 +389,13 @@ export default {
this.$emit('toggle-route-label')
},
editName() {
const newName = prompt('请输入威力区名称:', this.entityData.name || '')
if (newName !== null && newName.trim() !== '') {
this.$emit('update-property', 'name', newName.trim())
}
},
handleToggleRouteLock() {
this.$emit('toggle-route-lock')
},

95
ruoyi-ui/src/views/cesiumMap/LocateDialog.vue

@ -61,7 +61,7 @@
<el-option
v-for="item in waypointList"
:key="item.id"
:label="`${item.name} (${degreesToDMS(item.lng)}, ${degreesToDMS(item.lat)})`"
:label="`${item.name} (${formatCoordinate(item.lng)}, ${formatCoordinate(item.lat)})`"
:value="item.id"
/>
</el-select>
@ -70,7 +70,7 @@
<el-form-item label="经度:">
<el-input
v-model="formData.lng"
placeholder="例如 116°23'48.64""
:placeholder="coordinateFormat === 'dms' ? '例如 116°23\'48.64&quot;' : '例如 116.396844'"
clearable
/>
</el-form-item>
@ -78,7 +78,7 @@
<el-form-item label="纬度:">
<el-input
v-model="formData.lat"
placeholder="例如 39°54'33.48""
:placeholder="coordinateFormat === 'dms' ? '例如 39°54\'33.48&quot;' : '例如 39.909289'"
clearable
/>
</el-form-item>
@ -107,6 +107,10 @@ export default {
visible: {
type: Boolean,
default: false
},
coordinateFormat: {
type: String,
default: 'dms' // 'decimal' 'dms'
}
},
data() {
@ -137,9 +141,44 @@ export default {
this.loadScenarios()
}
this.$emit('update:visible', newVal)
},
coordinateFormat: {
handler(newVal) {
this.updateCoordinateFormat(newVal)
}
}
},
},
methods: {
updateCoordinateFormat(newFormat) {
if (!this.formData.lng || !this.formData.lat) return
let lngDegrees, latDegrees
if (this.coordinateFormat === 'dms') {
lngDegrees = this.dmsToDegrees(this.formData.lng)
latDegrees = this.dmsToDegrees(this.formData.lat)
} else {
lngDegrees = parseFloat(this.formData.lng)
latDegrees = parseFloat(this.formData.lat)
}
if (lngDegrees !== null && latDegrees !== null && !isNaN(lngDegrees) && !isNaN(latDegrees)) {
if (newFormat === 'dms') {
this.formData.lng = this.degreesToDMS(lngDegrees)
this.formData.lat = this.degreesToDMS(latDegrees)
} else {
this.formData.lng = lngDegrees.toFixed(6)
this.formData.lat = latDegrees.toFixed(6)
}
}
},
formatCoordinate(value) {
if (this.coordinateFormat === 'dms') {
return this.degreesToDMS(value)
} else {
return value.toFixed(6)
}
},
degreesToDMS(decimalDegrees) {
const degrees = Math.floor(decimalDegrees)
const minutesDecimal = (decimalDegrees - degrees) * 60
@ -157,12 +196,22 @@ export default {
return sign * (Math.abs(degrees) + minutes / 60 + seconds / 3600)
},
resetForm() {
this.formData = {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116°23\'48.64"',
lat: '39°54\'33.48"'
if (this.coordinateFormat === 'dms') {
this.formData = {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116°23\'48.64"',
lat: '39°54\'33.48"'
}
} else {
this.formData = {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116.396844',
lat: '39.909289'
}
}
this.routeList = []
this.waypointList = []
@ -214,8 +263,8 @@ export default {
if (value) {
const waypoint = this.waypointList.find(w => w.id === value)
if (waypoint) {
this.formData.lng = this.degreesToDMS(waypoint.lng)
this.formData.lat = this.degreesToDMS(waypoint.lat)
this.formData.lng = this.formatCoordinate(waypoint.lng)
this.formData.lat = this.formatCoordinate(waypoint.lat)
}
}
},
@ -233,12 +282,24 @@ export default {
return
}
const lngDegrees = this.dmsToDegrees(lng)
const latDegrees = this.dmsToDegrees(lat)
let lngDegrees, latDegrees
if (lngDegrees === null || latDegrees === null || isNaN(lngDegrees) || isNaN(latDegrees)) {
this.$message.error('请输入有效的度分秒格式!格式:116°23\'48.64"')
return
if (this.coordinateFormat === 'dms') {
lngDegrees = this.dmsToDegrees(lng)
latDegrees = this.dmsToDegrees(lat)
if (lngDegrees === null || latDegrees === null || isNaN(lngDegrees) || isNaN(latDegrees)) {
this.$message.error('请输入有效的度分秒格式!格式:116°23\'48.64"')
return
}
} else {
lngDegrees = parseFloat(lng)
latDegrees = parseFloat(lat)
if (isNaN(lngDegrees) || isNaN(latDegrees)) {
this.$message.error('请输入有效的十进制格式!')
return
}
}
if (lngDegrees < -180 || lngDegrees > 180 || latDegrees < -90 || latDegrees > 90) {

187
ruoyi-ui/src/views/cesiumMap/index.vue

@ -45,6 +45,7 @@
<!-- 定位弹窗 -->
<locate-dialog
:visible="locateDialogVisible"
:coordinateFormat="coordinateFormat"
@update:visible="locateDialogVisible = $event"
@confirm="handleLocateConfirm"
@cancel="handleLocateCancel"
@ -116,6 +117,10 @@ export default {
unit: 'km',
position: 'bottom-right'
})
},
coordinateFormat: {
type: String,
default: 'dms' // 'decimal' 'dms'
}
},
watch: {
@ -135,6 +140,11 @@ export default {
this.updateScaleFromConfig(newVal)
}
}
},
coordinateFormat: {
handler(newVal) {
this.updateCoordinatesDisplay()
}
}
},
data() {
@ -189,6 +199,7 @@ export default {
},
//
coordinatesText: '经度: --, 纬度: --',
currentCoordinates: null,
//
scaleBarText: '--',
scaleBarWidthPx: 80,
@ -1689,10 +1700,12 @@ export default {
// canvas readPixels false
contextOptions: {
preserveDrawingBuffer: true,
antialias: true // WebGL 齿
},
// 齿WebGL2 8 线
msaaSamples: 8
webgl: {
antialias: true,
msaa: true,
msaaSamples: 4
}
}
})
this.viewer.cesiumWidget.creditContainer.style.display = "none"
// 80% 线齿
@ -1733,6 +1746,7 @@ export default {
console.log('Cesium离线二维地图已加载')
// 1.
this.viewer.scene.postProcessStages.fxaa.enabled = true
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((click) => {
//
@ -2279,10 +2293,18 @@ export default {
addCoordinateLabels() {
for (let lon = -180; lon <= 180; lon += 30) {
for (let lat = -90; lat <= 90; lat += 30) {
let latText, lonText
if (this.coordinateFormat === 'dms') {
latText = `${this.degreesToDMS(lat)}N`
lonText = `${this.degreesToDMS(lon)}E`
} else {
latText = `${lat.toFixed(2)}°N`
lonText = `${lon.toFixed(2)}°E`
}
this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lon, lat),
label: {
text: `${this.degreesToDMS(lat)}N\n${this.degreesToDMS(lon)}E`,
text: `${latText}\n${lonText}`,
font: '12px sans-serif',
fillColor: Cesium.Color.BLACK,
outlineColor: Cesium.Color.WHITE,
@ -2540,7 +2562,10 @@ export default {
return this.drawingPoints.length > 0 ? [this.drawingPoints[this.drawingPoints.length - 1]] : [];
}, false),
width: this.defaultStyles.line.width,
material: this.getPolylineSolidMaterial(this.defaultStyles.line.color),
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color),
dashLength: 16
}),
clampToGround: true
}
});
@ -3792,113 +3817,6 @@ export default {
return entity
},
// ================== ==================
/** 生成普通纯色折线材质(无轮廓/发光) */
getPolylineSolidMaterial(cssColor) {
const color = Cesium.Color.fromCssColorString(cssColor)
return new Cesium.ColorMaterialProperty(color)
},
/** 根据浏览器缩放比例设置渲染分辨率,减轻 80% 等缩放下线条锯齿 */
applyResolutionScale() {
if (!this.viewer || !this.viewer.cesiumWidget) return
const vv = window.visualViewport
const scale = (vv && typeof vv.scale === 'number') ? vv.scale : 1
// 使 2.0 80% 2.5齿
let resolutionScale = 2.0
if (scale > 0 && scale < 1) {
resolutionScale = Math.min(2.5, 1 / scale)
if (resolutionScale < 2.0) resolutionScale = 2.0
}
this.viewer.resolutionScale = resolutionScale
try {
if (typeof this.viewer.cesiumWidget.resize === 'function') {
this.viewer.cesiumWidget.resize()
}
} catch (e) { /* 忽略 resize 异常 */ }
if (this.viewer.scene.requestRenderMode) this.viewer.scene.requestRender()
},
/** 监听浏览器缩放/窗口变化,更新 resolutionScale;返回取消监听的函数 */
setupResolutionScaleListener() {
const onResize = () => {
this.applyResolutionScale()
}
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', onResize)
window.visualViewport.addEventListener('scroll', onResize)
}
window.addEventListener('resize', onResize)
return () => {
if (window.visualViewport) {
window.visualViewport.removeEventListener('resize', onResize)
window.visualViewport.removeEventListener('scroll', onResize)
}
window.removeEventListener('resize', onResize)
}
},
/** 按等经度/等纬度采样矩形边框,使在 2D 地图缩小时仍显示为直线(避免测地线弯弧) */
getRectangleBorderPositions(rect, segmentsPerEdge = 48) {
const west = rect.west
const south = rect.south
const east = rect.east
const north = rect.north
const positions = []
const n = Math.max(2, segmentsPerEdge)
for (let i = 0; i <= n; i++) {
const lon = west + (east - west) * (i / n)
positions.push(Cesium.Cartesian3.fromRadians(lon, south))
}
for (let i = 1; i <= n; i++) {
const lat = south + (north - south) * (i / n)
positions.push(Cesium.Cartesian3.fromRadians(east, lat))
}
for (let i = 1; i <= n; i++) {
const lon = east - (east - west) * (i / n)
positions.push(Cesium.Cartesian3.fromRadians(lon, north))
}
for (let i = 1; i < n; i++) {
const lat = north - (north - south) * (i / n)
positions.push(Cesium.Cartesian3.fromRadians(west, lat))
}
return positions
},
/** 在 2D 墨卡托下将一段线采样为“直线”(避免测地线弯弧);返回 Cartesian3 数组含起点到终点 */
sampleSegmentStraightIn2D(cartesianA, cartesianB, numSegments = 32) {
const cgA = Cesium.Cartographic.fromCartesian(cartesianA)
const cgB = Cesium.Cartographic.fromCartesian(cartesianB)
const lonA = cgA.longitude
const latA = cgA.latitude
const lonB = cgB.longitude
const latB = cgB.latitude
const yA = Math.log(Math.tan(Math.PI / 4 + latA / 2))
const yB = Math.log(Math.tan(Math.PI / 4 + latB / 2))
const n = Math.max(1, numSegments)
const positions = []
for (let i = 0; i <= n; i++) {
const t = i / n
const x = lonA + t * (lonB - lonA)
const y = yA + t * (yB - yA)
const lat = 2 * Math.atan(Math.exp(y)) - Math.PI / 2
positions.push(Cesium.Cartesian3.fromRadians(x, lat))
}
return positions
},
/** 将折线/多边形顶点按 2D 墨卡托“直线”采样,使缩放小时仍显示为直;closed 为 true 表示多边形闭合 */
getPolylinePositionsStraightIn2D(positions, closed = false, segmentsPerEdge = 32) {
if (!positions || positions.length < 2) return positions
const n = positions.length
const result = []
const segs = closed ? n : n - 1
for (let seg = 0; seg < segs; seg++) {
const i = seg
const j = closed ? (seg + 1) % n : seg + 1
const sampled = this.sampleSegmentStraightIn2D(positions[i], positions[j], segmentsPerEdge)
if (seg === 0) {
result.push(...sampled)
} else {
for (let k = 1; k < sampled.length; k++) result.push(sampled[k])
}
}
return result
},
getClickPosition(pixelPosition) {
const cartesian = this.viewer.camera.pickEllipsoid(pixelPosition, this.viewer.scene.globe.ellipsoid)
return cartesian
@ -4160,6 +4078,9 @@ export default {
entity.polyline.material = this.getPolylineSolidMaterial(data.borderColor || data.color)
entity.polyline.width = data.width
}
if (data.name && data.centerEntity && data.centerEntity.label) {
data.centerEntity.label.text = data.name
}
break
case 'sector':
if (entity.polygon) {
@ -4747,7 +4668,13 @@ export default {
},
duration: 2
})
this.$message.success(`已定位到经度 ${this.degreesToDMS(lng)},纬度 ${this.degreesToDMS(lat)}`)
let coordinateText
if (this.coordinateFormat === 'dms') {
coordinateText = `${this.degreesToDMS(lng)}${this.degreesToDMS(lat)}`
} else {
coordinateText = `${lng.toFixed(6)}${lat.toFixed(6)}`
}
this.$message.success(`已定位到经度 ${coordinateText}`)
}
},
@ -5018,12 +4945,26 @@ export default {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
const longitude = Cesium.Math.toDegrees(cartographic.longitude)
const latitude = Cesium.Math.toDegrees(cartographic.latitude)
this.coordinatesText = `经度: ${this.degreesToDMS(longitude)}, 纬度: ${this.degreesToDMS(latitude)}`
this.currentCoordinates = { longitude, latitude }
this.updateCoordinatesDisplay()
} else {
this.coordinatesText = '经度: --, 纬度: --'
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
},
//
updateCoordinatesDisplay() {
if (!this.currentCoordinates) {
this.coordinatesText = '经度: --, 纬度: --'
return
}
const { longitude, latitude } = this.currentCoordinates
if (this.coordinateFormat === 'dms') {
this.coordinatesText = `经度: ${this.degreesToDMS(longitude)}, 纬度: ${this.degreesToDMS(latitude)}`
} else {
this.coordinatesText = `经度: ${longitude.toFixed(6)}, 纬度: ${latitude.toFixed(6)}`
}
},
destroyViewer() {
this.stopDrawing()
this.clearAll(false)
@ -5162,6 +5103,17 @@ export default {
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
disableDepthTestDistance: Number.POSITIVE_INFINITY
},
label: {
text: '',
font: '14px Microsoft YaHei',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.TOP,
pixelOffset: new Cesium.Cartesian2(0, -20),
disableDepthTestDistance: Number.POSITIVE_INFINITY
}
});
@ -5202,12 +5154,17 @@ export default {
centerEntity: this.powerZoneCenterEntity,
center: this.powerZoneCenter,
radius: radiusInMeters,
name: radiusData.name,
color: '#FF0000',
opacity: 0,
borderColor: '#FF0000',
width: 2
});
if (this.powerZoneCenterEntity && this.powerZoneCenterEntity.label) {
this.powerZoneCenterEntity.label.text = radiusData.name;
}
this.isDrawing = false;
this.viewer.canvas.style.cursor = 'default';

8
ruoyi-ui/src/views/childRoom/index.vue

@ -12,6 +12,7 @@
<cesiumMap ref="cesiumMap" :drawDomClick="drawDom || airspaceDrawDom"
:tool-mode="drawDom ? 'ranging' : (airspaceDrawDom ? 'airspace' : 'airspace')"
:scaleConfig="scaleConfig"
:coordinateFormat="coordinateFormat"
@draw-complete="handleMapDrawComplete"
@drawing-points-update="missionDrawingPointsCount = $event"
@open-waypoint-dialog="handleOpenWaypointEdit"
@ -563,6 +564,9 @@ export default {
showLandmark: true,
showRoute: true,
//
coordinateFormat: 'dms', // 'decimal' 'dms'
menuItems: [],
//
@ -1794,8 +1798,8 @@ export default {
},
coordinateConversion() {
this.$message.success('坐标换算');
//
this.coordinateFormat = this.coordinateFormat === 'decimal' ? 'dms' : 'decimal'
this.$message.success(`坐标格式已切换为:${this.coordinateFormat === 'decimal' ? '十进制' : '度分秒'}`)
},
//

13
ruoyi-ui/src/views/dialogs/RadiusDialog.vue

@ -8,6 +8,14 @@
<div class="dialog-body">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="80px" size="small">
<el-form-item label="名称" prop="name">
<el-input
v-model="formData.name"
placeholder="请输入威力区名称"
style="width: 100%;"
></el-input>
</el-form-item>
<el-form-item label="半径" prop="radius">
<el-input-number
v-model="formData.radius"
@ -47,10 +55,14 @@ export default {
data() {
return {
formData: {
name: '',
radius: 50,
unit: 'km'
},
rules: {
name: [
{ required: true, message: '请输入威力区名称', trigger: 'blur' }
],
radius: [
{ required: true, message: '请输入半径', trigger: 'blur' }
]
@ -65,6 +77,7 @@ export default {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$emit('confirm', {
name: this.formData.name,
radius: this.formData.radius,
unit: this.formData.unit
})

Loading…
Cancel
Save