diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development index 0e7127a..4d098ba 100644 --- a/ruoyi-ui/.env.development +++ b/ruoyi-ui/.env.development @@ -8,7 +8,7 @@ ENV = 'development' VUE_APP_BASE_API = '/dev-api' # 访问地址(绕过 /dev-api 代理,用于解决静态资源/图片访问 401 认证问题) -VUE_APP_BACKEND_URL = 'http://127.0.0.1:8080' +VUE_APP_BACKEND_URL = 'http://localhost:8080' # 路由懒加载 VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/ruoyi-ui/src/views/cesiumMap/ContextMenu.vue b/ruoyi-ui/src/views/cesiumMap/ContextMenu.vue index 65487ff..796c828 100644 --- a/ruoyi-ui/src/views/cesiumMap/ContextMenu.vue +++ b/ruoyi-ui/src/views/cesiumMap/ContextMenu.vue @@ -148,7 +148,7 @@
@@ -307,7 +307,7 @@ export default { ], presetWidths: [1, 2, 3, 4, 5, 6, 8, 10, 12], presetSizes: [6, 8, 10, 12, 14, 16, 18, 20, 24], - presetOpacities: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], + presetOpacities: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], presetFontSizes: [8, 10, 12, 14, 16, 18, 20, 24, 28, 32] } }, diff --git a/ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue b/ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue index d09f8d4..703075d 100644 --- a/ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue +++ b/ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue @@ -8,7 +8,7 @@
面积: - {{ result.area.toFixed(2) }} 平方米 + {{ (result.area / 1000000).toFixed(2) }} 平方千米
半径: diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 552d41d..9843259 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -156,10 +156,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 } @@ -200,60 +200,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 @@ -264,19 +264,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, @@ -1375,15 +1375,28 @@ export default { 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 - } - }; + // 根据工具模式决定显示格式 + if (this.toolMode === 'ranging') { + // 测距模式:使用千米,简化格式 + this.hoverTooltip = { + visible: true, + content: `${(cumulativeLength / 1000).toFixed(1)}km ,${bearingType === 'magnetic' ? '磁' : '真'}:${bearing.toFixed(1)}°`, + position: { + x: movement.endPosition.x + 10, + y: movement.endPosition.y - 10 + } + }; + } else { + // 空域模式:使用米,完整格式 + 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; @@ -1669,15 +1682,28 @@ export default { const length = this.calculateLineLength(tempPositions); // 默认为真方位,因为绘制过程中还没有bearingType属性 const bearing = this.calculateTrueBearing(tempPositions); - // 更新小框提示,显示实时长度和真方位角 - this.hoverTooltip = { - visible: true, - content: `长度:${length.toFixed(2)} 米\n真方位:${bearing.toFixed(2)}°`, - position: { - x: movement.endPosition.x + 10, - y: movement.endPosition.y - 10 - } - }; + // 根据工具模式决定显示格式 + if (this.toolMode === 'ranging') { + // 测距模式:使用千米,简化格式 + this.hoverTooltip = { + visible: true, + content: `${(length / 1000).toFixed(1)}km ,真:${bearing.toFixed(1)}°`, + position: { + x: movement.endPosition.x + 10, + y: movement.endPosition.y - 10 + } + }; + } else { + // 空域模式:使用米,完整格式 + this.hoverTooltip = { + visible: true, + content: `长度:${length.toFixed(2)} 米\n真方位:${bearing.toFixed(2)}°`, + position: { + x: movement.endPosition.x + 10, + y: movement.endPosition.y - 10 + } + }; + } } else { // 如果没有点,隐藏提示 this.hoverTooltip.visible = false; @@ -1833,8 +1859,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 }, @@ -1848,12 +1874,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 } }); @@ -1912,6 +1935,7 @@ export default { this.activeCursorPosition = position; // 初始化鼠标位置 // 创建动态预览矩形 this.tempEntity = this.viewer.entities.add({ + // 填充部分 rectangle: { // 关键:使用 CallbackProperty 动态计算矩形范围 coordinates: new Cesium.CallbackProperty(() => { @@ -1921,11 +1945,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 // 贴地 } }); @@ -1956,14 +2004,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 } }); @@ -1974,9 +2044,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); @@ -2108,12 +2179,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 } }); } @@ -2152,16 +2244,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. 记录实体 @@ -2171,9 +2275,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}` }; @@ -2267,6 +2372,7 @@ export default { } // 创建动态预览扇形 this.tempEntity = this.viewer.entities.add({ + // 填充部分 polygon: { hierarchy: new Cesium.CallbackProperty(() => { if (this.drawingPoints.length > 1 && this.activeCursorPosition) { @@ -2282,10 +2388,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 } }); } @@ -2319,13 +2444,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. 记录实体 @@ -2339,7 +2470,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}` @@ -2348,6 +2480,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); @@ -2397,7 +2558,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++) { @@ -2822,16 +2983,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 = { @@ -2841,7 +3009,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}` } @@ -2860,8 +3029,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 @@ -2884,8 +3053,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 @@ -2907,6 +3076,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) @@ -2980,20 +3156,45 @@ export default { let declination; if (lngDeg >= 73 && lngDeg <= 135 && latDeg >= 18 && latDeg <= 53) { - // 中国地区简化磁偏角模型 - // 基于2020年数据,每年约变化0.1度 + // 中国地区简化磁偏角模型(基于WMM2025模型数据) + // 注意:中国大部分地区磁偏角偏西(负值),只有新疆、西藏等少数地区偏东(正值) + // 数据来源:NOAA WMM-2025模型 const year = new Date().getFullYear(); - const yearOffset = (year - 2020) * 0.1; + const yearOffset = (year - 2025) * 0.04; if (lngDeg < 100) { - // 西部地区 - declination = 2.0 - yearOffset; + // 西部地区(新疆、西藏等) + if (latDeg > 40) { + // 西北地区(新疆北部) + declination = 3.0 - yearOffset; + } else if (latDeg > 32) { + // 西南地区(四川、重庆等) + declination = -2.0 - yearOffset; + } else { + // 西藏地区 + declination = 1.0 - yearOffset; + } } else if (lngDeg < 115) { - // 中部地区 - declination = 1.0 - yearOffset; + // 中部地区(华北、华中) + if (latDeg > 38) { + // 华北地区(北京等) + declination = -7.5 - yearOffset; + } else if (latDeg > 32) { + // 华中北部 + declination = -5.0 - yearOffset; + } else { + // 华中南部 + declination = -3.5 - yearOffset; + } } else { - // 东部地区 - declination = 0.5 - yearOffset; + // 东部地区(华东、华南) + if (latDeg > 35) { + // 华东地区(上海等) + declination = -5.5 - yearOffset; + } else { + // 华南地区(广州、深圳等) + declination = -2.5 - yearOffset; + } } } else { // 其他地区默认磁偏角为0 @@ -3020,8 +3221,8 @@ export default { // 计算磁偏角 const declination = this.calculateMagneticDeclination(startLat, startLng); - // 计算磁方位角(真方位角加上磁偏角) - let magneticBearing = trueBearing + declination; + // 计算磁方位角(真方位角减去磁偏角) + let magneticBearing = trueBearing - declination; // 调整到0-360范围 return (magneticBearing + 360) % 360; @@ -3078,22 +3279,28 @@ 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 'ellipse': @@ -3114,8 +3321,10 @@ export default { 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': @@ -3166,6 +3375,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) // 隐藏右键菜单 @@ -3203,49 +3416,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) { @@ -3540,7 +3806,7 @@ export default { }, duration: 2 }) - this.$message.success(`已定位到经度 ${lng.toFixed(4)},纬度 ${lat.toFixed(4)}`) + this.$message.success(`已定位到经度 ${this.degreesToDMS(lng)},纬度 ${this.degreesToDMS(lat)}`) } }, @@ -3812,7 +4078,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 = '经度: --, 纬度: --' } @@ -3820,7 +4086,7 @@ export default { }, destroyViewer() { this.stopDrawing() - this.clearAll() + this.clearAll(false) if (this.pointMovementHandler) { this.pointMovementHandler.destroy() diff --git a/ruoyi-ui/src/views/childRoom/RightPanel.vue b/ruoyi-ui/src/views/childRoom/RightPanel.vue index 3187dc1..17eaaa0 100644 --- a/ruoyi-ui/src/views/childRoom/RightPanel.vue +++ b/ruoyi-ui/src/views/childRoom/RightPanel.vue @@ -375,13 +375,6 @@ export default { if (plan) { this.$emit('select-plan', plan) } - // 仅加载并显示当前新方案的航线 - const planRoutes = this.routes.filter(r => r.scenarioId === planId) - planRoutes.forEach(route => { - if (!this.activeRouteIds.includes(route.id)) { - this.handleSelectRoute(route) - } - }) } }, diff --git a/ruoyi-ui/src/views/childRoom/index.vue b/ruoyi-ui/src/views/childRoom/index.vue index ba97f03..25b46c6 100644 --- a/ruoyi-ui/src/views/childRoom/index.vue +++ b/ruoyi-ui/src/views/childRoom/index.vue @@ -423,13 +423,13 @@ export default { showScaleDialog: false, currentScale: { scaleNumerator: 1, - scaleDenominator: 1000, - unit: 'm' + scaleDenominator: 20, + unit: 'km' }, scaleConfig: { scaleNumerator: 1, - scaleDenominator: 1000, - unit: 'm' + scaleDenominator: 20, + unit: 'km' }, showExternalParamsDialog: false, currentExternalParams: {}, diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index 462f379..daef08e 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -15,14 +15,13 @@ const CompressionPlugin = require('compression-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 -const baseUrl = 'http://127.0.0.1:8080' // 后端接口 +const baseUrl = 'http://localhost:8080' // 后端接口 const port = process.env.port || process.env.npm_config_port || 80 // 端口 // 定义 Cesium 源码路径 const cesiumSource = 'node_modules/cesium/Build/Cesium' module.exports = { - // 部署生产环境和开发环境下的URL。 publicPath: process.env.NODE_ENV === "production" ? "/" : "/", outputDir: 'dist',