ctw 2 months ago
parent
commit
9a35aa9218
  1. 2
      ruoyi-ui/.env.development
  2. 4
      ruoyi-ui/src/views/cesiumMap/ContextMenu.vue
  3. 2
      ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue
  4. 584
      ruoyi-ui/src/views/cesiumMap/index.vue
  5. 7
      ruoyi-ui/src/views/childRoom/RightPanel.vue
  6. 8
      ruoyi-ui/src/views/childRoom/index.vue
  7. 3
      ruoyi-ui/vue.config.js

2
ruoyi-ui/.env.development

@ -8,7 +8,7 @@ ENV = 'development'
VUE_APP_BASE_API = '/dev-api' VUE_APP_BASE_API = '/dev-api'
# 访问地址(绕过 /dev-api 代理,用于解决静态资源/图片访问 401 认证问题) # 访问地址(绕过 /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 VUE_CLI_BABEL_TRANSPILE_MODULES = true

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

@ -148,7 +148,7 @@
<div class="menu-item" @click="toggleColorPicker('borderColor')"> <div class="menu-item" @click="toggleColorPicker('borderColor')">
<span class="menu-icon">🖌</span> <span class="menu-icon">🖌</span>
<span>边框色</span> <span>边框色</span>
<span class="menu-preview" :style="{backgroundColor: entityData.color}"></span> <span class="menu-preview" :style="{backgroundColor: entityData.borderColor || entityData.color}"></span>
</div> </div>
<!-- 边框颜色选择器 --> <!-- 边框颜色选择器 -->
<div class="color-picker-container" v-if="showColorPickerFor === 'borderColor'"> <div class="color-picker-container" v-if="showColorPickerFor === 'borderColor'">
@ -307,7 +307,7 @@ export default {
], ],
presetWidths: [1, 2, 3, 4, 5, 6, 8, 10, 12], presetWidths: [1, 2, 3, 4, 5, 6, 8, 10, 12],
presetSizes: [6, 8, 10, 12, 14, 16, 18, 20, 24], 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] presetFontSizes: [8, 10, 12, 14, 16, 18, 20, 24, 28, 32]
} }
}, },

2
ruoyi-ui/src/views/cesiumMap/MeasurementPanel.vue

@ -8,7 +8,7 @@
</div> </div>
<div class="measurement-item" v-if="result.area"> <div class="measurement-item" v-if="result.area">
<span>面积</span> <span>面积</span>
<strong>{{ result.area.toFixed(2) }} 平方米</strong> <strong>{{ (result.area / 1000000).toFixed(2) }} 平方</strong>
</div> </div>
<div class="measurement-item" v-if="result.radius"> <div class="measurement-item" v-if="result.radius">
<span>半径</span> <span>半径</span>

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

@ -156,10 +156,10 @@ export default {
defaultStyles: { defaultStyles: {
point: { color: '#FF0000', size: 12 }, point: { color: '#FF0000', size: 12 },
line: { color: '#00FF00', width: 3 }, line: { color: '#00FF00', width: 3 },
polygon: { color: '#0000FF', opacity: 0.5, width: 2 }, polygon: { color: '#0000FF', opacity: 0, width: 4 },
rectangle: { color: '#FFA500', opacity: 0.3, width: 2 }, rectangle: { color: '#FFA500', opacity: 0, width: 4 },
circle: { color: '#800080', opacity: 0.4, width: 2 }, circle: { color: '#800080', opacity: 0, width: 4 },
sector: { color: '#FF6347', opacity: 0.5, width: 2 }, sector: { color: '#FF6347', opacity: 0, width: 3 },
arrow: { color: '#FF0000', width: 6 }, arrow: { color: '#FF0000', width: 6 },
text: { color: '#000000', font: '48px Microsoft YaHei, PingFang SC, sans-serif', backgroundColor: 'rgba(255, 255, 255, 0.8)' }, text: { color: '#000000', font: '48px Microsoft YaHei, PingFang SC, sans-serif', backgroundColor: 'rgba(255, 255, 255, 0.8)' },
image: { width: 150, height: 150 } image: { width: 150, height: 150 }
@ -200,60 +200,60 @@ export default {
methods: { methods: {
updateScaleFromConfig(config) { updateScaleFromConfig(config) {
if (!config || !this.viewer) return if (!config || !this.viewer) return
const { scaleNumerator, scaleDenominator, unit } = config const { scaleNumerator, scaleDenominator, unit } = config
if (!scaleDenominator || scaleDenominator <= 0) return if (!scaleDenominator || scaleDenominator <= 0) return
let displayValue = '' let displayValue = ''
let metersPerPixel = 0 let metersPerPixel = 0
const standardDPI = 96 const standardDPI = 96
const pixelsPerCm = standardDPI * 0.393701 const pixelsPerCm = standardDPI * 0.393701
const scaleFactor = scaleDenominator / scaleNumerator const scaleFactor = scaleDenominator / scaleNumerator
switch (unit) { switch (unit) {
case 'm': case 'm':
displayValue = `1:${scaleDenominator}` displayValue = `${scaleDenominator}`
metersPerPixel = scaleFactor / pixelsPerCm metersPerPixel = scaleFactor / pixelsPerCm
break break
case 'km': case 'km':
displayValue = `1:${scaleDenominator}` displayValue = `${scaleDenominator}`
metersPerPixel = (scaleFactor * 1000) / pixelsPerCm metersPerPixel = (scaleFactor * 1000) / pixelsPerCm
break break
default: default:
displayValue = `1:${scaleDenominator}` displayValue = `${scaleDenominator}`
metersPerPixel = scaleFactor / pixelsPerCm metersPerPixel = scaleFactor / pixelsPerCm
} }
console.log('比例尺设置:', displayValue, '每像素米数:', metersPerPixel.toFixed(4)) console.log('比例尺设置:', displayValue, '每像素米数:', metersPerPixel.toFixed(4))
this.isApplyingScale = true this.isApplyingScale = true
this.useCustomScale = true this.useCustomScale = true
this.customScaleText = displayValue this.customScaleText = displayValue
this.currentScaleUnit = unit this.currentScaleUnit = unit
this.applyScaleToCamera(metersPerPixel) this.applyScaleToCamera(metersPerPixel)
this.updateScaleBar() this.updateScaleBar()
this.$forceUpdate() this.$forceUpdate()
setTimeout(() => { setTimeout(() => {
this.isApplyingScale = false this.isApplyingScale = false
}, 1000) }, 1000)
}, },
applyScaleToCamera(metersPerPixel) { applyScaleToCamera(metersPerPixel) {
if (!this.viewer || !this.viewer.camera) return if (!this.viewer || !this.viewer.camera) return
const canvas = this.viewer.scene.canvas const canvas = this.viewer.scene.canvas
const width = canvas.clientWidth const width = canvas.clientWidth
const height = canvas.clientHeight const height = canvas.clientHeight
if (width <= 0 || height <= 0) return if (width <= 0 || height <= 0) return
const camera = this.viewer.camera const camera = this.viewer.camera
const scene = this.viewer.scene const scene = this.viewer.scene
if (scene.mode === Cesium.SceneMode.SCENE2D) { if (scene.mode === Cesium.SceneMode.SCENE2D) {
const frustumWidth = width * metersPerPixel const frustumWidth = width * metersPerPixel
camera.frustum.right = frustumWidth / 2 camera.frustum.right = frustumWidth / 2
@ -264,19 +264,19 @@ export default {
} else { } else {
const cameraPosition = camera.positionCartographic const cameraPosition = camera.positionCartographic
const groundWidth = width * metersPerPixel const groundWidth = width * metersPerPixel
const fov = camera.frustum.fov || Cesium.Math.PI_OVER_THREE const fov = camera.frustum.fov || Cesium.Math.PI_OVER_THREE
const aspectRatio = width / height const aspectRatio = width / height
const verticalFov = fov / aspectRatio const verticalFov = fov / aspectRatio
const targetHeight = (groundWidth / 2) / Math.tan(fov / 2) const targetHeight = (groundWidth / 2) / Math.tan(fov / 2)
const destination = Cesium.Cartesian3.fromRadians( const destination = Cesium.Cartesian3.fromRadians(
cameraPosition.longitude, cameraPosition.longitude,
cameraPosition.latitude, cameraPosition.latitude,
targetHeight targetHeight
) )
camera.flyTo({ camera.flyTo({
destination: destination, destination: destination,
duration: 0.5, duration: 0.5,
@ -1375,15 +1375,28 @@ export default {
const bearing = bearingType === 'magnetic' const bearing = bearingType === 'magnetic'
? this.calculateMagneticBearing(currentSegmentPositions) ? this.calculateMagneticBearing(currentSegmentPositions)
: this.calculateTrueBearing(currentSegmentPositions); : this.calculateTrueBearing(currentSegmentPositions);
// //
this.hoverTooltip = { if (this.toolMode === 'ranging') {
visible: true, // 使
content: `累计长度:${cumulativeLength.toFixed(2)}\n${bearingType === 'magnetic' ? '磁方位' : '真方位'}${bearing.toFixed(2)}°`, this.hoverTooltip = {
position: { visible: true,
x: movement.endPosition.x + 10, content: `${(cumulativeLength / 1000).toFixed(1)}km ,${bearingType === 'magnetic' ? '磁' : '真'}${bearing.toFixed(1)}°`,
y: movement.endPosition.y - 10 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 { } else {
// //
this.hoverTooltip.visible = false; this.hoverTooltip.visible = false;
@ -1669,15 +1682,28 @@ export default {
const length = this.calculateLineLength(tempPositions); const length = this.calculateLineLength(tempPositions);
// bearingType // bearingType
const bearing = this.calculateTrueBearing(tempPositions); const bearing = this.calculateTrueBearing(tempPositions);
// //
this.hoverTooltip = { if (this.toolMode === 'ranging') {
visible: true, // 使
content: `长度:${length.toFixed(2)}\n真方位:${bearing.toFixed(2)}°`, this.hoverTooltip = {
position: { visible: true,
x: movement.endPosition.x + 10, content: `${(length / 1000).toFixed(1)}km ,真:${bearing.toFixed(1)}°`,
y: movement.endPosition.y - 10 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 { } else {
// //
this.hoverTooltip.visible = false; this.hoverTooltip.visible = false;
@ -1833,8 +1859,8 @@ export default {
} }
return new Cesium.PolygonHierarchy(this.drawingPoints); return new Cesium.PolygonHierarchy(this.drawingPoints);
}, false), }, false),
// 使便 //
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), material: Cesium.Color.TRANSPARENT,
// //
perPositionHeight: false perPositionHeight: false
}, },
@ -1848,12 +1874,9 @@ export default {
} }
return this.drawingPoints; return this.drawingPoints;
}, false), }, false),
width: this.defaultStyles.line.width, width: this.defaultStyles.polygon.width,
// 使线 // 使线
material: new Cesium.PolylineDashMaterialProperty({ material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color),
color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color),
dashLength: 16
}),
clampToGround: true clampToGround: true
} }
}); });
@ -1912,6 +1935,7 @@ export default {
this.activeCursorPosition = position; // this.activeCursorPosition = position; //
// //
this.tempEntity = this.viewer.entities.add({ this.tempEntity = this.viewer.entities.add({
//
rectangle: { rectangle: {
// 使 CallbackProperty // 使 CallbackProperty
coordinates: new Cesium.CallbackProperty(() => { coordinates: new Cesium.CallbackProperty(() => {
@ -1921,11 +1945,35 @@ export default {
} }
return Cesium.Rectangle.fromDegrees(0, 0, 0, 0); return Cesium.Rectangle.fromDegrees(0, 0, 0, 0);
}, false), }, false),
// + //
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color).withAlpha(this.defaultStyles.rectangle.opacity),
outline: true, clampToGround: true //
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), },
outlineWidth: 2, //
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 // clampToGround: true //
} }
}); });
@ -1956,14 +2004,36 @@ export default {
// 3. // 3.
this.entityCounter++; this.entityCounter++;
const id = `rectangle_${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({ const finalEntity = this.viewer.entities.add({
id: id, id: id,
//
rectangle: { rectangle: {
coordinates: rect, coordinates: rect,
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(this.defaultStyles.polygon.opacity), material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color).withAlpha(this.defaultStyles.rectangle.opacity),
outline: true, clampToGround: true
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), },
outlineWidth: this.defaultStyles.polygon.width, //
polyline: {
positions: borderPositions,
width: this.defaultStyles.rectangle.width,
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color),
clampToGround: true clampToGround: true
} }
}); });
@ -1974,9 +2044,10 @@ export default {
points: this.drawingPoints.map(p => this.cartesianToLatLng(p)), points: this.drawingPoints.map(p => this.cartesianToLatLng(p)),
positions: this.drawingPoints, positions: this.drawingPoints,
entity: finalEntity, entity: finalEntity,
color: this.defaultStyles.polygon.color, color: this.defaultStyles.rectangle.color, //
opacity: this.defaultStyles.polygon.opacity, borderColor: this.defaultStyles.rectangle.color, //
width: this.defaultStyles.polygon.width, opacity: this.defaultStyles.rectangle.opacity,
width: this.defaultStyles.rectangle.width,
label: `矩形 ${this.entityCounter}` label: `矩形 ${this.entityCounter}`
}; };
this.allEntities.push(entityData); this.allEntities.push(entityData);
@ -2108,12 +2179,33 @@ export default {
return initialRadius; return initialRadius;
} }
}, false), }, false),
// //
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color).withAlpha(this.defaultStyles.circle.opacity),
outline: true, // outline polyline
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), clampToGround: true
outlineWidth: 2, },
// height: 0, // 使 heightReference //
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. // 3.
this.entityCounter++; this.entityCounter++;
const id = `circle_${this.entityCounter}`; const id = `circle_${this.entityCounter}`;
// 线
const circlePositions = this.generateCirclePositions(centerPoint, radius);
//
const finalEntity = this.viewer.entities.add({ const finalEntity = this.viewer.entities.add({
id: id, id: id,
position: centerPoint, position: centerPoint,
//
ellipse: { ellipse: {
semiMajorAxis: radius, semiMajorAxis: radius,
semiMinorAxis: radius, semiMinorAxis: radius,
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(this.defaultStyles.polygon.opacity), //
outline: true, material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color).withAlpha(this.defaultStyles.circle.opacity),
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), clampToGround: true
outlineWidth: this.defaultStyles.polygon.width },
//
polyline: {
positions: circlePositions,
width: this.defaultStyles.circle.width,
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color),
clampToGround: true
} }
}); });
// 4. // 4.
@ -2171,9 +2275,10 @@ export default {
points: [centerPoint, edgePosition].map(p => this.cartesianToLatLng(p)), points: [centerPoint, edgePosition].map(p => this.cartesianToLatLng(p)),
positions: [centerPoint, edgePosition], positions: [centerPoint, edgePosition],
entity: finalEntity, entity: finalEntity,
color: this.defaultStyles.polygon.color, color: this.defaultStyles.circle.color, //
opacity: this.defaultStyles.polygon.opacity, borderColor: this.defaultStyles.circle.color, //
width: this.defaultStyles.polygon.width, opacity: this.defaultStyles.circle.opacity,
width: this.defaultStyles.circle.width,
radius: radius, radius: radius,
label: `圆形 ${this.entityCounter}` label: `圆形 ${this.entityCounter}`
}; };
@ -2267,6 +2372,7 @@ export default {
} }
// //
this.tempEntity = this.viewer.entities.add({ this.tempEntity = this.viewer.entities.add({
//
polygon: { polygon: {
hierarchy: new Cesium.CallbackProperty(() => { hierarchy: new Cesium.CallbackProperty(() => {
if (this.drawingPoints.length > 1 && this.activeCursorPosition) { if (this.drawingPoints.length > 1 && this.activeCursorPosition) {
@ -2282,10 +2388,29 @@ export default {
} }
return new Cesium.PolygonHierarchy([]); return new Cesium.PolygonHierarchy([]);
}, false), }, false),
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(0.5), //
outline: true, material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(this.defaultStyles.sector.opacity),
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), clampToGround: true
outlineWidth: this.defaultStyles.sector.width },
//
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({ const finalEntity = this.viewer.entities.add({
id: 'sector-' + new Date().getTime(), id: 'sector-' + new Date().getTime(),
name: `扇形 ${this.entityCounter}`, name: `扇形 ${this.entityCounter}`,
//
polygon: { polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions), hierarchy: new Cesium.PolygonHierarchy(positions),
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(0.5), //
outline: true, material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color).withAlpha(this.defaultStyles.sector.opacity),
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color), clampToGround: true
outlineWidth: this.defaultStyles.sector.width, },
perPositionHeight: false //
polyline: {
positions: positions,
width: this.defaultStyles.sector.width,
material: Cesium.Color.fromCssColorString(this.defaultStyles.sector.color),
clampToGround: true
} }
}); });
// 4. // 4.
@ -2339,7 +2470,8 @@ export default {
endAngle: endAngle, endAngle: endAngle,
positions: positions, positions: positions,
entity: finalEntity, entity: finalEntity,
color: this.defaultStyles.sector.color, color: this.defaultStyles.sector.color, //
borderColor: this.defaultStyles.sector.color, //
opacity: 0.5, opacity: 0.5,
width: this.defaultStyles.sector.width, width: this.defaultStyles.sector.width,
label: `扇形 ${this.entityCounter}` label: `扇形 ${this.entityCounter}`
@ -2348,6 +2480,35 @@ export default {
// 5. // 5.
this.drawingPoints = []; 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) { calculateAngle(center, start, end) {
const startLL = Cesium.Cartographic.fromCartesian(start); const startLL = Cesium.Cartographic.fromCartesian(start);
@ -2397,7 +2558,7 @@ export default {
// //
angleDiff = Math.max(0.01, angleDiff); 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); const angleStep = angleDiff / (numPoints - 1);
// //
for (let i = 0; i < numPoints; i++) { for (let i = 0; i < numPoints; i++) {
@ -2822,16 +2983,23 @@ export default {
const id = `polygon_${this.entityCounter}` const id = `polygon_${this.entityCounter}`
// //
const polygonPositions = [...positions, positions[0]] const polygonPositions = [...positions, positions[0]]
//
const entity = this.viewer.entities.add({ const entity = this.viewer.entities.add({
id: id, id: id,
name: `${this.entityCounter}`, name: `${this.entityCounter}`,
//
polygon: { polygon: {
hierarchy: new Cesium.PolygonHierarchy(polygonPositions), hierarchy: new Cesium.PolygonHierarchy(polygonPositions),
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color) //
.withAlpha(this.defaultStyles.polygon.opacity), material: Cesium.Color.TRANSPARENT,
outline: true, clampToGround: true
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), },
outlineWidth: this.defaultStyles.polygon.width //
polyline: {
positions: polygonPositions,
width: this.defaultStyles.polygon.width,
material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color),
clampToGround: true
} }
}) })
const entityData = { const entityData = {
@ -2841,7 +3009,8 @@ export default {
positions: polygonPositions, positions: polygonPositions,
entity: entity, entity: entity,
color: this.defaultStyles.polygon.color, color: this.defaultStyles.polygon.color,
opacity: this.defaultStyles.polygon.opacity, borderColor: this.defaultStyles.polygon.color,
opacity: 0,
width: this.defaultStyles.polygon.width, width: this.defaultStyles.polygon.width,
label: `${this.entityCounter}` label: `${this.entityCounter}`
} }
@ -2860,8 +3029,8 @@ export default {
name: `矩形 ${this.entityCounter}`, name: `矩形 ${this.entityCounter}`,
rectangle: { rectangle: {
coordinates: coordinates, coordinates: coordinates,
material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) //
.withAlpha(this.defaultStyles.rectangle.opacity), material: Cesium.Color.TRANSPARENT,
outline: true, outline: true,
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color),
outlineWidth: this.defaultStyles.rectangle.width outlineWidth: this.defaultStyles.rectangle.width
@ -2884,8 +3053,8 @@ export default {
ellipse: { ellipse: {
semiMinorAxis: validRadius, // = semiMinorAxis: validRadius, // =
semiMajorAxis: validRadius, // = semiMajorAxis: validRadius, // =
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) //
.withAlpha(this.defaultStyles.circle.opacity), material: Cesium.Color.TRANSPARENT,
outline: true, outline: true,
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color),
outlineWidth: this.defaultStyles.circle.width outlineWidth: this.defaultStyles.circle.width
@ -2907,6 +3076,13 @@ export default {
lng: Cesium.Math.toDegrees(cartographic.longitude) 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) { calculateRectangle(start, end) {
const startLL = this.cartesianToLatLng(start) const startLL = this.cartesianToLatLng(start)
const endLL = this.cartesianToLatLng(end) const endLL = this.cartesianToLatLng(end)
@ -2980,20 +3156,45 @@ export default {
let declination; let declination;
if (lngDeg >= 73 && lngDeg <= 135 && latDeg >= 18 && latDeg <= 53) { if (lngDeg >= 73 && lngDeg <= 135 && latDeg >= 18 && latDeg <= 53) {
// // WMM2025
// 20200.1 // 西西
// NOAA WMM-2025
const year = new Date().getFullYear(); const year = new Date().getFullYear();
const yearOffset = (year - 2020) * 0.1; const yearOffset = (year - 2025) * 0.04;
if (lngDeg < 100) { 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) { } 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 { } else {
// //
declination = 0.5 - yearOffset; if (latDeg > 35) {
//
declination = -5.5 - yearOffset;
} else {
// 广
declination = -2.5 - yearOffset;
}
} }
} else { } else {
// 0 // 0
@ -3020,8 +3221,8 @@ export default {
// //
const declination = this.calculateMagneticDeclination(startLat, startLng); const declination = this.calculateMagneticDeclination(startLat, startLng);
// //
let magneticBearing = trueBearing + declination; let magneticBearing = trueBearing - declination;
// 0-360 // 0-360
return (magneticBearing + 360) % 360; return (magneticBearing + 360) % 360;
@ -3078,22 +3279,28 @@ export default {
case 'polygon': case 'polygon':
if (entity.polygon) { if (entity.polygon) {
entity.polygon.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) 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 break
case 'rectangle': case 'rectangle':
if (entity.rectangle) { if (entity.rectangle) {
entity.rectangle.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) 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 break
case 'circle': case 'circle':
if (entity.ellipse) { if (entity.ellipse) {
entity.ellipse.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) 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 break
case 'ellipse': case 'ellipse':
@ -3114,8 +3321,10 @@ export default {
case 'sector': case 'sector':
if (entity.polygon) { if (entity.polygon) {
entity.polygon.material = Cesium.Color.fromCssColorString(data.color).withAlpha(data.opacity) 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 break
case 'arrow': case 'arrow':
@ -3166,6 +3375,10 @@ export default {
const entityData = this.contextMenu.entityData const entityData = this.contextMenu.entityData
// //
entityData[property] = value 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) this.updateEntityStyle(entityData)
// //
@ -3203,49 +3416,102 @@ export default {
} }
} }
}, },
clearAll() { clearAll(showConfirm = true) {
// 1. if (showConfirm) {
if (this.allEntities && this.allEntities.length > 0) { this.$confirm('是否清除所有编辑内容?', '提示', {
// 2. confirmButtonText: '确定',
this.allEntities.forEach(item => { cancelButtonText: '取消',
try { type: 'warning'
// A: Cesium Entity (线) }).then(() => {
if (item instanceof Cesium.Entity) { this.executeClearAll();
this.viewer.entities.remove(item); }).catch(() => {
} //
// B: ( { entity: ... }) });
else if (item.entity && item.entity instanceof Cesium.Entity) { } else {
this.viewer.entities.remove(item.entity); this.executeClearAll();
} }
// C: ID },
else if (item.id) { executeClearAll() {
this.viewer.entities.removeById(item.id); // 1.
} if (this.allEntities && this.allEntities.length > 0) {
// 线 // 2.
if (item.type === 'line' && item.pointEntities) { this.allEntities.forEach(item => {
item.pointEntities.forEach(pointEntity => { try {
this.viewer.entities.remove(pointEntity); 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) { getTypeName(type) {
@ -3540,7 +3806,7 @@ export default {
}, },
duration: 2 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 cartographic = Cesium.Cartographic.fromCartesian(cartesian)
const longitude = Cesium.Math.toDegrees(cartographic.longitude) const longitude = Cesium.Math.toDegrees(cartographic.longitude)
const latitude = Cesium.Math.toDegrees(cartographic.latitude) const latitude = Cesium.Math.toDegrees(cartographic.latitude)
this.coordinatesText = `经度: ${longitude.toFixed(6)}, 纬度: ${latitude.toFixed(6)}` this.coordinatesText = `经度: ${this.degreesToDMS(longitude)}, 纬度: ${this.degreesToDMS(latitude)}`
} else { } else {
this.coordinatesText = '经度: --, 纬度: --' this.coordinatesText = '经度: --, 纬度: --'
} }
@ -3820,7 +4086,7 @@ export default {
}, },
destroyViewer() { destroyViewer() {
this.stopDrawing() this.stopDrawing()
this.clearAll() this.clearAll(false)
if (this.pointMovementHandler) { if (this.pointMovementHandler) {
this.pointMovementHandler.destroy() this.pointMovementHandler.destroy()

7
ruoyi-ui/src/views/childRoom/RightPanel.vue

@ -375,13 +375,6 @@ export default {
if (plan) { if (plan) {
this.$emit('select-plan', 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)
}
})
} }
}, },

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

@ -423,13 +423,13 @@ export default {
showScaleDialog: false, showScaleDialog: false,
currentScale: { currentScale: {
scaleNumerator: 1, scaleNumerator: 1,
scaleDenominator: 1000, scaleDenominator: 20,
unit: 'm' unit: 'km'
}, },
scaleConfig: { scaleConfig: {
scaleNumerator: 1, scaleNumerator: 1,
scaleDenominator: 1000, scaleDenominator: 20,
unit: 'm' unit: 'km'
}, },
showExternalParamsDialog: false, showExternalParamsDialog: false,
currentExternalParams: {}, currentExternalParams: {},

3
ruoyi-ui/vue.config.js

@ -15,14 +15,13 @@ const CompressionPlugin = require('compression-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin')
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 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 // 端口 const port = process.env.port || process.env.npm_config_port || 80 // 端口
// 定义 Cesium 源码路径 // 定义 Cesium 源码路径
const cesiumSource = 'node_modules/cesium/Build/Cesium' const cesiumSource = 'node_modules/cesium/Build/Cesium'
module.exports = { module.exports = {
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/", publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
outputDir: 'dist', outputDir: 'dist',

Loading…
Cancel
Save