新增载荷的删除、和俯仰角辐射距离等参数、修改轨迹曲线、jb分类和颜色等

This commit is contained in:
严争鸣 2025-02-25 10:43:57 +08:00
parent 2cf73646a7
commit de9d1a4db5
30 changed files with 521 additions and 140 deletions

11
package-lock.json generated
View File

@ -21,6 +21,7 @@
"chroma-js": "^3.1.2", "chroma-js": "^3.1.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"echarts": "^5.5.1", "echarts": "^5.5.1",
"es-toolkit": "^1.32.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"maplibre-gl": "^5.0.1", "maplibre-gl": "^5.0.1",
"moment-timezone": "^0.5.46", "moment-timezone": "^0.5.46",
@ -10047,6 +10048,16 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/es-toolkit": {
"version": "1.32.0",
"resolved": "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.32.0.tgz",
"integrity": "sha512-ZfSfHP1l6ubgW/B/FRtqb9bYdMvI6jizbOSfbwwJNcOQ1QE6TFsC3jpQkZ900uUPSR3t3SU5Ds7UWKnYz+uP8Q==",
"license": "MIT",
"workspaces": [
"docs",
"benchmarks"
]
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.24.2", "version": "0.24.2",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz",

View File

@ -24,6 +24,7 @@
"chroma-js": "^3.1.2", "chroma-js": "^3.1.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"echarts": "^5.5.1", "echarts": "^5.5.1",
"es-toolkit": "^1.32.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"maplibre-gl": "^5.0.1", "maplibre-gl": "^5.0.1",
"moment-timezone": "^0.5.46", "moment-timezone": "^0.5.46",

View File

@ -24,21 +24,27 @@ window['settings'] = {
model: './models/雷达.glb', model: './models/雷达.glb',
}, },
}, },
mbCountryDict: {
美国: '#fff',
中国: '#d00',
日本: '#dd0',
韩国: '#00d',
},
mbDict: { mbDict: {
: { : {
icon: './images/icons/飞机.png', icon: './images/icons/10-7600-0-侦察机.svg',
color: '#d00', color: '#d00',
model: './models/IDF.glb', model: './models/IDF.glb',
payload: 'conic', payload: 'airplaneConic',
}, },
: { : {
icon: './images/icons/舰船.png', icon: './images/icons/10-5900-0-航空母舰.svg',
color: '#dd0', color: '#ff0',
model: './models/驱逐舰2.glb', model: './models/驱逐舰2.glb',
payload: 'radar', payload: 'radar',
}, },
: { : {
icon: './images/icons/舰船.png', icon: './images/icons/10-6100-0-驱逐舰.svg',
color: '#dd0', color: '#dd0',
model: './models/驱逐舰2.glb', model: './models/驱逐舰2.glb',
payload: 'radar', payload: 'radar',

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
<svg width="756" height="352" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created with imagetracer.js version 1.2.5"><path fill="rgb(255, 102, 102)" stroke="#f66" stroke-width="0" opacity="1" d="M 278 40 L 280 52 L 728 52 L 728 308 L 282 308 L 280 314 L 274 312 L 28 178 L 278 40 Z M 280 84 L 280 162 L 282 164 L 696 164 L 696 86 L 694 84 L 280 84 Z M 242 96 L 96 178 L 248 260 L 248 98 L 242 96 Z M 280 196 L 280 274 L 282 276 L 696 276 L 696 198 L 694 196 L 280 196 Z "></path></svg>

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
<svg width="756" height="352" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created with imagetracer.js version 1.2.5"><path fill="rgb(255, 102, 102)" stroke="#f66" stroke-width="0" opacity="1" d="M 278 44 L 280 56 L 728 56 L 728 312 L 282 312 L 280 318 L 274 316 L 28 182 L 278 44 Z M 280 88 L 280 278 L 282 280 L 304 280 L 304 90 L 302 88 L 280 88 Z M 336 88 L 336 280 L 696 280 L 696 88 L 336 88 Z M 242 100 L 96 182 L 248 264 L 248 102 L 242 100 Z "></path></svg>

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
<svg width="756" height="364" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created with imagetracer.js version 1.2.5"><path fill="rgb(255, 102, 102)" stroke="#f66" stroke-width="0" opacity="1" d="M 278 48 L 280 60 L 728 60 L 728 316 L 282 316 L 280 322 L 274 320 L 28 186 L 278 48 Z M 280 92 L 280 284 L 696 284 L 696 92 L 280 92 Z M 242 104 L 96 186 L 248 268 L 248 106 L 242 104 Z "></path></svg>

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1 @@
<svg width="408" height="564" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created with imagetracer.js version 1.2.5"><path fill="rgb(255, 102, 102)" stroke="#f66" stroke-width="0" opacity="1" d="M 184 28 L 214 28 L 216 30 L 216 170 L 372 326 L 350 348 L 216 218 L 216 470 L 260 518 L 238 536 L 202 500 L 166 536 L 144 518 L 184 474 L 184 222 L 54 348 L 32 326 L 184 174 L 184 28 Z "></path></svg>

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1 @@
<svg width="408" height="520" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created with imagetracer.js version 1.2.5"><path fill="rgb(255, 102, 102)" stroke="#f66" stroke-width="0" opacity="1" d="M 184 28 L 214 28 L 216 30 L 216 170 L 372 326 L 350 348 L 216 218 L 216 458 L 232 460 L 232 492 L 172 492 L 172 460 L 184 458 L 184 222 L 54 348 L 32 326 L 184 174 L 184 28 Z "></path></svg>

After

Width:  |  Height:  |  Size: 397 B

View File

@ -77,17 +77,21 @@ async function getHisTraj({
return { points, posArray, timeArray } return { points, posArray, timeArray }
} }
function getMBEntityOpt({ async function getMBEntityOpt({
id, id,
targetType, targetType,
country,
extendInfo, extendInfo,
}: { }: {
id: string id: string
targetType: string targetType: string
country: string
extendInfo?: { detectingPayload: Record<string, number> } extendInfo?: { detectingPayload: Record<string, number> }
}) { }) {
const mubiaoDict = window.settings.mbDict[targetType] const mubiaoDict = window.settings.mbDict[targetType]
const countryColor = window.settings.mbCountryDict[country]
// console.log(country, countryColor)
let ellipsoid let ellipsoid
if (extendInfo) { if (extendInfo) {
const { const {
@ -98,7 +102,7 @@ function getMBEntityOpt({
maximumClock, maximumClock,
radius, radius,
} = extendInfo.detectingPayload } = extendInfo.detectingPayload
if (radius) { if (maximumClock || minimumClock || minimumCone) {
ellipsoid = { ellipsoid = {
ellipsoid: { ellipsoid: {
show: mbPayloadShowMap.get(id)?.detectingPayload?.show || false, show: mbPayloadShowMap.get(id)?.detectingPayload?.show || false,
@ -122,11 +126,17 @@ function getMBEntityOpt({
} }
} }
} }
const image = await getImageByColor({
img: mubiaoDict.icon,
color: countryColor,
})
// console.log(image.img, (+image.height / +image.width) * 30)
return { return {
label: { label: {
text: `${id}`, text: `${id}`,
font: '12pt sans-serif', font: '12pt sans-serif',
fillColor: Cesium.Color.YELLOW, fillColor: Cesium.Color.fromCssColorString(countryColor),
// fillColor: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.BLACK, outlineColor: Cesium.Color.BLACK,
outlineWidth: 2, outlineWidth: 2,
style: Cesium.LabelStyle.FILL_AND_OUTLINE, style: Cesium.LabelStyle.FILL_AND_OUTLINE,
@ -141,10 +151,12 @@ function getMBEntityOpt({
}, },
billboard: { billboard: {
show: !iconOrModel.value, show: !iconOrModel.value,
image: mubiaoDict.icon, image: image.img,
width: 30, // image: mubiaoDict.icon,
height: 30, width: 35,
color: Cesium.Color.fromCssColorString(mubiaoDict.color), height: (+image.height / +image.width) * 35,
// height: 30,
color: Cesium.Color.fromCssColorString(countryColor),
scaleByDistance: new Cesium.NearFarScalar(7000000, 1.0, 18000000, 0.4), scaleByDistance: new Cesium.NearFarScalar(7000000, 1.0, 18000000, 0.4),
}, },
model: { model: {
@ -157,19 +169,64 @@ function getMBEntityOpt({
} }
} }
async function getImageByColor({ img: url, color: newColor }) {
// 步骤 1: 获取 SVG 内容
const svg = await fetch(url)
const svgContent = await svg.text()
// 步骤 2: 修改 SVG 的颜色
const parser = new DOMParser()
const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml')
// 修改所有路径、圆形、矩形等元素的填充颜色
const elements = svgDoc.querySelectorAll('path, circle, rect, polygon, line')
elements.forEach(element => {
// 修改 fill 属性
element.setAttribute('fill', newColor)
// 也可以修改 stroke 颜色,防止可能的边框颜色问题
element.setAttribute('stroke', newColor)
})
const svgElement = svgDoc.documentElement
// console.log(svgElement)
// const transformValue = `rotate(${90}, 50, 50)`
// svgElement.setAttribute('transform', transformValue)
// 获取 SVG 的宽度和高度
const width = svgElement.getAttribute('width')
const height = svgElement.getAttribute('height')
// 步骤 3: 转换为 Base64 编码
const serializer = new XMLSerializer()
const modifiedSVG = serializer.serializeToString(svgDoc.documentElement)
// 输出修改后的 SVG确保颜色正确
const base64SVG = 'data:image/svg+xml;base64,' + btoa(modifiedSVG)
console.log(base64SVG)
return { img: base64SVG, width, height }
}
function createMBConicSensor({ function createMBConicSensor({
entity, entity,
angle, angle,
show, show,
radius,
heading,
pitch,
}: { }: {
entity: Cesium.Entity entity: Cesium.Entity
angle: number angle: number
show: boolean show: boolean
radius: number
heading: number
pitch: number
}) { }) {
console.log('entity', angle) console.log('entity', angle, radius, heading, pitch)
const conicSensor = new CesiumSensorVolumes.ConicSensorGraphics({ const conicSensor = new CesiumSensorVolumes.ConicSensorGraphics({
show, show,
radius: 2e7, radius: radius * 1000,
innerHalfAngle: 0, innerHalfAngle: 0,
outerHalfAngle: Cesium.Math.toRadians(angle / 2), outerHalfAngle: Cesium.Math.toRadians(angle / 2),
minimumClockAngle: 0, minimumClockAngle: 0,
@ -186,9 +243,11 @@ function createMBConicSensor({
Cesium.Transforms.headingPitchRollQuaternion( Cesium.Transforms.headingPitchRollQuaternion(
entity.position._value, entity.position._value,
new Cesium.HeadingPitchRoll( new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(90), // Cesium.Math.toRadians(heading),
0, Cesium.Math.toRadians(heading),
Cesium.Math.toRadians(180) Cesium.Math.toRadians(pitch),
0
// Cesium.Math.toRadians(pitch)
) // 初始朝向 ) // 初始朝向
), ),
conicSensor: conicSensor, conicSensor: conicSensor,
@ -214,7 +273,7 @@ watch([mbPayloadShowMap, satellitePayloadShowMap], ([newMb, newSatellite]) => {
show = newMb.get(key).detectingPayload.show show = newMb.get(key).detectingPayload.show
} }
if (mubiaoMap.has(key)) { if (mubiaoMap.has(key)) {
// if(console.log(mubiaoMap.get(key).ellipsoid) // console.log(mubiaoMap.get(key).ellipsoid)
mubiaoMap.get(key).ellipsoid && (mubiaoMap.get(key).ellipsoid.show = show) mubiaoMap.get(key).ellipsoid && (mubiaoMap.get(key).ellipsoid.show = show)
mubiaoConicMap.get(key)?.conicSensor && mubiaoConicMap.get(key)?.conicSensor &&
@ -237,6 +296,7 @@ function changeShowOrHideLoad() {
// ;[...mubiaoMap.values()].forEach(entity => { // ;[...mubiaoMap.values()].forEach(entity => {
// entity.ellipsoid.show = !entity.ellipsoid.show._value // entity.ellipsoid.show = !entity.ellipsoid.show._value
// }) // })
console.log(showOrHideLoad.value)
for (const [key] of mbPayloadShowMap.entries()) { for (const [key] of mbPayloadShowMap.entries()) {
mbPayloadShowMap.get(key).detectingPayload.show = showOrHideLoad.value mbPayloadShowMap.get(key).detectingPayload.show = showOrHideLoad.value
} }

98
src/js/Wave.js Normal file
View File

@ -0,0 +1,98 @@
class WavePrimitiveMaterialProperty {
constructor(option) {
this.opts = {
color: Cesium.Color.RED,
duration: 2000,
time: new Date().getTime(),
repeat: 30,
offset: 0,
thickness: 0.3,
}
this.opts = Object.assign(this.opts, option)
this._definitionChanged = new Cesium.Event()
this._color = undefined
this._colorSubscription = undefined
this.color = this.opts.color
this.duration = this.opts.duration
this._time = this.opts.time
}
}
Object.defineProperties(WavePrimitiveMaterialProperty.prototype, {
isConstant: {
get: function () {
return false
},
},
definitionChanged: {
get: function () {
return this._definitionChanged
},
},
})
WavePrimitiveMaterialProperty.prototype.getType = function (time) {
return 'WavePrimitive'
}
WavePrimitiveMaterialProperty.prototype.getValue = function (time, result) {
if (!Cesium.defined(result)) {
result = {}
}
result.color = Cesium.Property.getValueOrClonedDefault(
this._color,
time,
Cesium.Color.WHITE,
result.color
)
result.time =
((new Date().getTime() - this._time) % this.duration) / this.duration / 10
result.repeat = this.opts.repeat
result.offset = this.opts.offset
result.thickness = this.opts.thickness
return result
}
WavePrimitiveMaterialProperty.prototype.equals = function (other) {
return (
this === other ||
(other instanceof WavePrimitiveMaterialProperty &&
Cesium.Property.equals(this._color, other._color))
)
}
Cesium.wavePrimitiveProperty = WavePrimitiveMaterialProperty
Cesium.Material.wavePrimitiveType = 'WavePrimitive'
Cesium.Material.wavePrimitiveSource =
'uniform vec4 color;\n\
uniform float repeat;\n\
uniform float offset;\n\
uniform float thickness;\n\
czm_material czm_getMaterial(czm_materialInput materialInput){\n\
czm_material material = czm_getDefaultMaterial(materialInput);\n\
float sp = 1.0/repeat;\n\
vec2 st = materialInput.st;\n\
float dis = distance(st, vec2(0.5));\n\
float m = mod(dis + offset-time, sp);\n\
float a = step(sp*(1.0-thickness), m); \n\
material.diffuse = color.rgb;\n\
material.alpha = a * color.a;\n\
return material;\n\
}'
Cesium.Material._materialCache.addMaterial(Cesium.Material.wavePrimitiveType, {
fabric: {
type: Cesium.Material.wavePrimitiveType,
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
time: 0,
repeat: 30,
offset: 0,
thickness: 0.3,
},
source: Cesium.Material.wavePrimitiveSource,
},
translucent: function (material) {
return true
},
})

View File

@ -22,6 +22,7 @@ class SatelliteEntity {
this.entity = null this.entity = null
this._underPoint = false this._underPoint = false
this.underPointEntity = null this.underPointEntity = null
this._sensorRadius = 200
this._sensorAngle = 30 this._sensorAngle = 30
this._sensorType = 'conic' this._sensorType = 'conic'
this._listener = null this._listener = null
@ -38,11 +39,13 @@ class SatelliteEntity {
set sensor(showSensor) { set sensor(showSensor) {
// console.log(showSensor, 'showSensor') // console.log(showSensor, 'showSensor')
this._sensor = showSensor this._sensor = showSensor
if (showSensor && !this.sensorEntity) { if (showSensor) {
if (this._sensorType === 'conic') { if (!this.sensorEntity) {
this.createConicSensor(this.entity) if (this._sensorType === 'conic') {
} else if (this._sensorType === 'rectangle') { this.createConicSensor(this.entity)
this.createRectangleSensor(this.entity) } else if (this._sensorType === 'rectangle') {
this.createRectangleSensor(this.entity)
}
} }
} else { } else {
// if(this.sensorEntity) { // if(this.sensorEntity) {
@ -61,6 +64,16 @@ class SatelliteEntity {
} }
} }
get sensorRadius() {
return this._sensorRadius
}
set sensorRadius(radius) {
this._sensorRadius = radius
if (this._sensorEntity) {
this._sensorEntity.radius = radius * 1000
}
}
get underPoint() { get underPoint() {
return this._underPoint return this._underPoint
} }
@ -353,7 +366,7 @@ class SatelliteEntity {
) )
const conicSensor = new CesiumSensorVolumes.ConicSensorGraphics({ const conicSensor = new CesiumSensorVolumes.ConicSensorGraphics({
show: true, show: true,
radius: 2e7, radius: this._sensorRadius * 1000,
innerHalfAngle: 0, innerHalfAngle: 0,
outerHalfAngle: Cesium.Math.toRadians(this._sensorAngle / 2), outerHalfAngle: Cesium.Math.toRadians(this._sensorAngle / 2),
minimumClockAngle: 0, minimumClockAngle: 0,

View File

@ -11,6 +11,7 @@ import 'normalize.css'
import 'virtual:windi.css' import 'virtual:windi.css'
import './js/polylineTrail.js' import './js/polylineTrail.js'
import './js/Wave.js'
import Loading from '@/components/Loading/Loading' import Loading from '@/components/Loading/Loading'
// import { Viewer } from "cesium"; // import { Viewer } from "cesium";

View File

@ -1,3 +1,5 @@
import { lineString, bezierSpline } from '@turf/turf'
export function cartesian32LonLat(cartesian3) { export function cartesian32LonLat(cartesian3) {
const cartographic = const cartographic =
viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3) viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3)
@ -8,3 +10,28 @@ export function cartesian32LonLat(cartesian3) {
const height = cartographic.height const height = cartographic.height
return [lon, lat, height] return [lon, lat, height]
} }
export function getPositionFromTime(
startTime,
pos,
totalAnimationTime,
interval = 100
) {
const points = []
for (let i = 0; i <= totalAnimationTime / interval; i++) {
const time = Cesium.JulianDate.addSeconds(
startTime,
i,
new Cesium.JulianDate()
)
const point = pos.getValue(time)
point && points.push(point)
}
return points
}
export function getBezierSpline(points) {
return bezierSpline(lineString(points))
}

View File

@ -60,7 +60,7 @@ const types = [
{ name: 'XW', value: 'wzbXw' }, { name: 'XW', value: 'wzbXw' },
] ]
const showPanelName = ref('wx') const showPanelName = ref('zb')
const panelList = [ const panelList = [
// { // {

View File

@ -1,9 +1,10 @@
import { ref, toRaw } from 'vue' import { ref, toRaw } from 'vue'
import { useDaodan } from '../../ddHooks' import { useDaodan } from '../../ddHooks'
import { cartesian32LonLat } from '@/utils/pos' import { cartesian32LonLat, getPositionFromTime } from '@/utils/pos'
import ExplosionEffect from '@/js/Explosion' import ExplosionEffect from '@/js/Explosion'
import { generateId } from '@/utils/id' import { generateId } from '@/utils/id'
import store from 'store2' import store from 'store2'
// import { getPositionFromTime } from '@/utils/pos'
// import { useDaodan } from '../../ddHooks' // import { useDaodan } from '../../ddHooks'
const trajData = ref({ const trajData = ref({
@ -611,21 +612,21 @@ function createLine({ totalAnimationTime, startTime, positionProperty, type }) {
}, },
}) })
} }
function getPositionFromTime(startTime, pos, totalAnimationTime) { // function getPositionFromTime(startTime, pos, totalAnimationTime) {
const points = [] // const points = []
for (let i = 0; i <= totalAnimationTime / 100; i++) { // for (let i = 0; i <= totalAnimationTime / 100; i++) {
const time = Cesium.JulianDate.addSeconds( // const time = Cesium.JulianDate.addSeconds(
startTime, // startTime,
i, // i,
new Cesium.JulianDate() // new Cesium.JulianDate()
) // )
const point = pos.getValue(time) // const point = pos.getValue(time)
point && points.push(point) // point && points.push(point)
} // }
return points // return points
} // }
function modelAnimationController(controller) { function modelAnimationController(controller) {
const { type, initVal, maxVal, fn, step, minVal, primitive } = controller const { type, initVal, maxVal, fn, step, minVal, primitive } = controller

View File

@ -52,8 +52,8 @@ const useGantt = ({ router, route }: GanttParams) => {
}, },
// verticalSplitLineHighlight: { // verticalSplitLineHighlight: {
// lineColor: 'green', // lineColor: 'green',
// lineWidth: 3 // lineWidth: 3,
// } // },
}, },
grid: { grid: {
// backgroundColor: bgColor, // backgroundColor: bgColor,
@ -61,11 +61,11 @@ const useGantt = ({ router, route }: GanttParams) => {
lineWidth: 1, lineWidth: 1,
lineColor: textColorWithOp, lineColor: textColorWithOp,
}, },
verticalLine: { // verticalLine: {
lineWidth: 1, // lineWidth: 1,
lineColor: textColorWithOp, // lineColor: textColorWithOp,
lineDash: [4, 8], // lineDash: [4, 8],
}, // },
}, },
taskList: { taskList: {
// backgroundColor: bgColor, // backgroundColor: bgColor,
@ -83,21 +83,39 @@ const useGantt = ({ router, route }: GanttParams) => {
timelineHeader: { timelineHeader: {
backgroundColor: headerBgColor, backgroundColor: headerBgColor,
colWidth: 140, colWidth: 140,
verticalLine: { // colWidth: 1040,
lineColor: textColorWithOp, // verticalLine: {
lineWidth: 1, // lineColor: textColorWithOp,
lineDash: [4, 2], // lineWidth: 1,
}, // lineDash: [4, 2],
// },
horizontalLine: { horizontalLine: {
lineColor: textColorWithOp, lineColor: textColorWithOp,
lineWidth: 1, lineWidth: 1,
lineDash: [4, 2], lineDash: [4, 2],
}, },
scales: getTimeScales('day'), scales: getTimeScales('month'),
}, },
minDate: '2024-11-14', minDate: '2023-11-14',
maxDate: '2024-12-30', maxDate: '2024-12-30',
markLine: [
// {
// date: '2024-07-29',
// style: {
// lineWidth: 1,
// lineColor: 'blue',
// lineDash: [8, 4],
// },
// },
// {
// date: '2024-08-17',
// style: {
// lineWidth: 2,
// lineColor: 'red',
// lineDash: [8, 4],
// },
// },
],
scrollStyle: { scrollStyle: {
scrollRailColor: 'RGBA(246,246,246,0)', scrollRailColor: 'RGBA(246,246,246,0)',
visible: 'focus', visible: 'focus',
@ -343,10 +361,10 @@ const useGantt = ({ router, route }: GanttParams) => {
}) })
const day = new Text({ const day = new Text({
text: text: startDate.toLocaleDateString(),
scale === 'day' // scale === 'day'
? startDate.toLocaleDateString() // ? startDate.toLocaleDateString()
: startDate.toLocaleTimeString(), // : startDate.toLocaleTimeString(),
fontSize: 14, fontSize: 14,
fontWeight: 'bold', fontWeight: 'bold',
fontFamily: 'sans-serif', fontFamily: 'sans-serif',

View File

@ -2,6 +2,7 @@ import { ref } from 'vue'
import { point, bearing } from '@turf/turf' import { point, bearing } from '@turf/turf'
import { cartesian32LonLat } from '@/utils/pos' import { cartesian32LonLat } from '@/utils/pos'
import { useEntity } from '@/hooks/entity' import { useEntity } from '@/hooks/entity'
import { getPositionFromTime } from '@/utils/pos'
type TPoints = { time: number; position: Cesium.Cartesian3 }[] type TPoints = { time: number; position: Cesium.Cartesian3 }[]
@ -51,7 +52,7 @@ export const useMBTrajectory = () => {
removeEntities() removeEntities()
} }
function createTarget(points: TPoints, posArray: number[]) { async function createTarget(points: TPoints, posArray: number[]) {
const totalAnimationTime = points[points.length - 1].time const totalAnimationTime = points[points.length - 1].time
// console.log('totalAnimationTime', totalAnimationTime) // console.log('totalAnimationTime', totalAnimationTime)
@ -59,8 +60,8 @@ export const useMBTrajectory = () => {
const startTime = Cesium.JulianDate.now() const startTime = Cesium.JulianDate.now()
// 添加路径点到位置属性 // 添加路径点到位置属性
points.forEach(point => { points.forEach(point => {
const pointEntity = createPoint(point.position) // const pointEntity = createPoint(point.position)
entities.push(pointEntity) // entities.push(pointEntity)
const time = Cesium.JulianDate.addSeconds( const time = Cesium.JulianDate.addSeconds(
Cesium.JulianDate.now(), Cesium.JulianDate.now(),
point.time, point.time,
@ -68,13 +69,12 @@ export const useMBTrajectory = () => {
) )
positionProperty.addSample(time, point.position) positionProperty.addSample(time, point.position)
}) })
// positionProperty.setInterpolationOptions({ positionProperty.setInterpolationOptions({
// //二次多项式进行插值。二次多项式插值相较于线性插值会更光滑,但不如高阶多项式平滑 interpolationDegree: 5,
// interpolationDegree: 2, interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
// //赫尔米特多项式插值算法。使得插值曲线能够平滑过渡,并且可以更好地控制运动的速度和方向变化 })
// interpolationAlgorithm: Cesium.HermitePolynomialApproximation, console.log(positionProperty, 'getValue')
// }) // positionProperty._time.map(time => {
// positionProperty._time.map(time => {
// console.log(positionProperty.getValue(time), 'getValue') // console.log(positionProperty.getValue(time), 'getValue')
// }) // })
// 获取 line 插值后的值 // 获取 line 插值后的值
@ -91,9 +91,16 @@ export const useMBTrajectory = () => {
// now = Cesium.JulianDate.addSeconds(now, 30, new Cesium.JulianDate()) // now = Cesium.JulianDate.addSeconds(now, 30, new Cesium.JulianDate())
// } // }
// console.log(linePositions) // console.log(linePositions)
const positionList = getPositionFromTime(
const mbEntityOpt = getMBEntityOpt({ startTime,
positionProperty,
totalAnimationTime,
1
)
console.log(positionList, '====')
const mbEntityOpt = await getMBEntityOpt({
id: mbData.value.id, id: mbData.value.id,
country: mbData.value.country,
targetType: mbData.value.targetType, targetType: mbData.value.targetType,
}) })
// 创建实体 // 创建实体
@ -107,8 +114,8 @@ export const useMBTrajectory = () => {
}, false), }, false),
// point: { pixelSize: 10, color: Cesium.Color.RED }, // point: { pixelSize: 10, color: Cesium.Color.RED },
polyline: { polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(posArray), // positions: Cesium.Cartesian3.fromDegreesArrayHeights(posArray),
// positions: linePositions, positions: positionList,
width: 5, width: 5,
// material: new Cesium.PolylineTrailLinkMaterialProperty({ // material: new Cesium.PolylineTrailLinkMaterialProperty({
// color: Cesium.Color.YELLOW, // color: Cesium.Color.YELLOW,

View File

@ -1,11 +1,16 @@
import { ref } from 'vue' import { ref } from 'vue'
import { getPositionFromTime } from '@/utils/pos'
import { useEntity } from '@/hooks/entity' import { useEntity } from '@/hooks/entity'
import { useMubiao } from '../../../hooks/mubiao'
import { useTree } from '@/utils/tree'
type TPoints = { time: number; position: Cesium.Cartesian3 }[] type TPoints = { time: number; position: Cesium.Cartesian3 }[]
const { mubiaoMap, showEntity, getHisTraj, getMBEntityOpt } = useEntity() const { mubiaoMap, showEntity, getHisTraj, getMBEntityOpt } = useEntity()
const showMultiHisTrajCom = ref(false) const showMultiHisTrajCom = ref(false)
const { filterTreeNodeByField, getLeafNode } = useTree()
export const useMultiMBTrajectory = () => { export const useMultiMBTrajectory = () => {
let pointsEntities: Cesium.Entity[] = [] let pointsEntities: Cesium.Entity[] = []
@ -25,11 +30,17 @@ export const useMultiMBTrajectory = () => {
async function loadMultiHisTraj(timeRange: string[]) { async function loadMultiHisTraj(timeRange: string[]) {
removeEntities() removeEntities()
const { data: mbTree } = useMubiao()
const mbIds = [...mubiaoMap.keys()] const mbIds = [...mubiaoMap.keys()]
showEntity(false) showEntity(false)
if (mbIds.length === 0) { if (mbIds.length === 0) {
return return
} }
const nodes = filterTreeNodeByField({
treeData: mbTree.value,
params: mbIds,
paramName: 'dataId',
})
for (const mbId of mbIds) { for (const mbId of mbIds) {
const { points, posArray, timeArray } = await getHisTraj({ const { points, posArray, timeArray } = await getHisTraj({
id: mbId, id: mbId,
@ -41,8 +52,10 @@ export const useMultiMBTrajectory = () => {
continue continue
} }
const mbData = nodes.find(node => node.dataId === mbId).data
const color = Cesium.Color.fromRandom({ alpha: 1 }) const color = Cesium.Color.fromRandom({ alpha: 1 })
createTarget(mbId, points, posArray as number[], color, timeArray) createTarget(mbId, mbData, points, posArray as number[], color, timeArray)
} }
const allTime = [...timesMap.value.values()].flat() const allTime = [...timesMap.value.values()].flat()
@ -62,8 +75,9 @@ export const useMultiMBTrajectory = () => {
} }
} }
function createTarget( async function createTarget(
mbId: string, mbId: string,
mbData: Record<string, string | number>,
points: TPoints, points: TPoints,
posArray: number[], posArray: number[],
color: Cesium.Color, color: Cesium.Color,
@ -73,19 +87,38 @@ export const useMultiMBTrajectory = () => {
// console.log('totalAnimationTime', totalAnimationTime) // console.log('totalAnimationTime', totalAnimationTime)
const positionProperty = new Cesium.SampledPositionProperty() const positionProperty = new Cesium.SampledPositionProperty()
// const startTime = Cesium.JulianDate.now() // const startTime = Cesium.JulianDate.now()
const startTime = Cesium.JulianDate.fromDate(new Date(timeArray[0]))
const totalAnimationTime = timeArray[timeArray.length - 1] - timeArray[0]
// const bezierPoints = getBezierSpline(chunk(posArray, 3))
// console.log(bezierPoints)
// 添加路径点到位置属性 // 添加路径点到位置属性
points.forEach((point, index) => { points.forEach((point, index) => {
const pointEntity = createPoint(point.position, color) // const pointEntity = createPoint(point.position, color)
pointsEntities.push(pointEntity) // pointsEntities.push(pointEntity)
const time = Cesium.JulianDate.fromDate(new Date(timeArray[index])) const time = Cesium.JulianDate.fromDate(new Date(timeArray[index]))
// console.log(new Date(timeArray[index]).toLocaleString()) // console.log(new Date(timeArray[index]).toLocaleString())
positionProperty.addSample(time, point.position) positionProperty.addSample(time, point.position)
}) })
positionProperty.setInterpolationOptions({
const mbEntityOpt = getMBEntityOpt({ interpolationDegree: 5,
id: mbId, interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
targetType: '甲',
}) })
console.log(mbData, 'mbData')
const mbEntityOpt = await getMBEntityOpt({
id: mbId,
targetType: mbData.targetType,
country: mbData.country,
})
const positionList = getPositionFromTime(
startTime,
positionProperty,
totalAnimationTime,
1000
)
// console.log(positionList)
// console.log(mbEntityOpt) // console.log(mbEntityOpt)
// 创建实体 // 创建实体
const mbTarget = viewer.entities.add({ const mbTarget = viewer.entities.add({
@ -93,7 +126,8 @@ export const useMultiMBTrajectory = () => {
position: positionProperty, position: positionProperty,
// point: { pixelSize: 10, color: Cesium.Color.RED }, // point: { pixelSize: 10, color: Cesium.Color.RED },
polyline: { polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(posArray), // positions: Cesium.Cartesian3.fromDegreesArrayHeights(posArray),
positions: positionList,
width: 5, width: 5,
material: new Cesium.PolylineGlowMaterialProperty({ material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.1, glowPower: 0.1,

View File

@ -76,15 +76,16 @@ export const useMubiao = () => {
// console.log('mbPos', mbPos) // console.log('mbPos', mbPos)
nodes.forEach(({ data, dataId: id }: IMubiao) => { nodes.forEach(async ({ data, dataId: id }: IMubiao) => {
const { target_time, target_geom } = const { target_time, target_geom } =
mbPos.find(item => item.target_id === id) ?? {} mbPos.find(item => item.target_id === id) ?? {}
const pos = parseWKT(target_geom).coordinates const pos = parseWKT(target_geom).coordinates
const mbEntity = addMubiaoEntity({ const mbEntity = await addMubiaoEntity({
id, id,
position: pos, position: pos,
target_time, target_time,
country: data.country,
targetType: data.targetType, targetType: data.targetType,
extendInfo: data.extendInfo, extendInfo: data.extendInfo,
}) })
@ -101,16 +102,22 @@ export const useMubiao = () => {
const res = await sendCheckedTargetIds(ids) const res = await sendCheckedTargetIds(ids)
} }
const addMubiaoEntity = ({ const addMubiaoEntity = async ({
id, id,
position, position,
country,
target_time, target_time,
targetType, targetType,
extendInfo, extendInfo,
}: Record<string, string | number | number[]>) => { }: Record<string, string | number | number[]>) => {
// 添加目标实体 // 添加目标实体
// console.log(window.settings, targetType, '-----') // console.log(window.settings, targetType, '-----')
const mbEntityOpt = getMBEntityOpt({ id, targetType, extendInfo }) const mbEntityOpt = await getMBEntityOpt({
id,
country,
targetType,
extendInfo,
})
const mubiaoEntity = viewer.entities.add({ const mubiaoEntity = viewer.entities.add({
name: id, name: id,
@ -124,7 +131,11 @@ export const useMubiao = () => {
if (extendInfo?.detectingPayload?.angle) { if (extendInfo?.detectingPayload?.angle) {
const conic = createMBConicSensor({ const conic = createMBConicSensor({
entity: mubiaoEntity, entity: mubiaoEntity,
radius: extendInfo?.detectingPayload?.radius,
angle: extendInfo?.detectingPayload?.angle, angle: extendInfo?.detectingPayload?.angle,
heading: extendInfo?.detectingPayload?.heading,
pitch: extendInfo?.detectingPayload?.pitch,
show: mbPayloadShowMap.get(id).detectingPayload.show, show: mbPayloadShowMap.get(id).detectingPayload.show,
}) })
mubiaoConicMap.set(id, conic) mubiaoConicMap.set(id, conic)

View File

@ -6,6 +6,7 @@ import Communication from '@/views/Payload/Communication.jsx'
import { updateMbPayload } from '@/api/Mubiao' import { updateMbPayload } from '@/api/Mubiao'
import { useEntity } from '@/hooks/entity' import { useEntity } from '@/hooks/entity'
import { useMubiao } from './mubiao' import { useMubiao } from './mubiao'
import { isNull, isUndefined } from 'es-toolkit'
const { openDetailsModal } = useModal() const { openDetailsModal } = useModal()
export const useMubiaoDetail = () => { export const useMubiaoDetail = () => {
@ -27,16 +28,23 @@ export const useMubiaoDetail = () => {
show: false, show: false,
}, },
] ]
} else if (payLoadType === 'conic') { } else if (payLoadType === 'airplaneConic') {
payloadData.value = [ payloadData.value = [
{ {
id, id,
angle: null, angle: 30,
radius: 10,
heading: 90,
pitch: 180,
show: false, show: false,
}, },
] ]
} }
} }
function removeCommunicationPayload() {
payloadData.value = []
}
const { mbPayloadShowMap } = useEntity() const { mbPayloadShowMap } = useEntity()
function renderMubiaoDetailsContent(mbData) { function renderMubiaoDetailsContent(mbData) {
@ -72,13 +80,21 @@ export const useMubiaoDetail = () => {
*/} */}
<div class="flex justify-between"> <div class="flex justify-between">
<div class="detail-item-title">探测载荷</div> <div class="detail-item-title">探测载荷</div>
{payloadData.value.length === 0 && ( {payloadData.value.length === 0 ? (
<NButton <NButton
quaternary quaternary
type="primary" type="primary"
onClick={() => addCommunicationPayload(mbData)} onClick={() => addCommunicationPayload(mbData)}
> >
添加 添加载荷
</NButton>
) : (
<NButton
quaternary
type="error"
onClick={() => removeCommunicationPayload()}
>
删除载荷
</NButton> </NButton>
)} )}
</div> </div>
@ -113,6 +129,15 @@ export const useMubiaoDetail = () => {
function updateMbLoad({ mbData, detection }) { function updateMbLoad({ mbData, detection }) {
const { getMubiaoData } = useMubiao() const { getMubiaoData } = useMubiao()
const { id, show, ...detectionData } = detection[0] const { id, show, ...detectionData } = detection[0]
if (
Object.values(detectionData).some(
item => isNull(item) || isUndefined(item)
)
) {
window.$message.error('探测载荷信息不完整')
return
}
const payloadData = { const payloadData = {
id: mbData.id, id: mbData.id,
extendInfo: { extendInfo: {

View File

@ -83,6 +83,7 @@ export default defineComponent({
<NInputNumber <NInputNumber
v-model:value={row.radius} v-model:value={row.radius}
// disabled={['', ''].includes(row.type)} // disabled={['', ''].includes(row.type)}
min={0}
></NInputNumber> ></NInputNumber>
) )
}, },
@ -102,22 +103,6 @@ export default defineComponent({
}, },
], ],
conic: [ conic: [
// {
// title: '',
// key: 'type',
// render(row) {
// return (
// <NSelect
// v-model:value={row.type}
// options={[
// { label: '', value: '' },
// { label: '', value: '' },
// { label: '', value: '' },
// ]}
// ></NSelect>
// )
// },
// },
{ {
title: '开合角', title: '开合角',
key: 'angle', key: 'angle',
@ -127,41 +112,83 @@ export default defineComponent({
v-model:value={row.angle} v-model:value={row.angle}
max={120} max={120}
min={0} min={0}
// disabled={['', ''].includes(row.type)}
></NInputNumber> ></NInputNumber>
) )
}, },
}, },
// { {
// title: '', title: '辐射距离(km)',
// key: 'xHalfAngle', key: 'radius',
// width: 120, render(row) {
// render(row) { return (
// return ( <NInputNumber v-model:value={row.radius} min={0}></NInputNumber>
// <NInputNumber )
// v-model:value={row.angle} },
// max={120} },
// min={0} {
// disabled={[''].includes(row.type)} title: '是否开启',
// ></NInputNumber> key: 'show',
// ) width: 120,
// }, render(row) {
// }, return (
// { <NSwitch
// title: '', v-model:value={row.show}
// key: 'yHalfAngle', onUpdate:value={() => changePayloadStatus(row)}
// width: 120, ></NSwitch>
// render(row) { )
// return ( },
// <NInputNumber },
// v-model:value={row.angle} ],
// max={120} airplaneConic: [
// min={0} {
// disabled={[''].includes(row.type)} title: '开合角',
// ></NInputNumber> key: 'angle',
// ) render(row) {
// }, return (
// }, <NInputNumber
v-model:value={row.angle}
max={120}
min={0}
></NInputNumber>
)
},
},
{
title: '偏航角',
key: 'heading',
render(row) {
return (
<NInputNumber
v-model:value={row.heading}
max={180}
min={-180}
></NInputNumber>
)
},
},
{
title: '俯仰角',
key: 'pitch',
render(row) {
return (
<NInputNumber
v-model:value={row.pitch}
max={180}
min={-180}
></NInputNumber>
)
},
},
{
title: '辐射距离(km)',
key: 'radius',
render(row) {
return (
<NInputNumber v-model:value={row.radius} min={0}></NInputNumber>
)
},
},
{ {
title: '是否开启', title: '是否开启',
key: 'show', key: 'show',

View File

@ -6,6 +6,8 @@ import Communication from '@/views/Payload/Communication.jsx'
import { useEntity } from '@/hooks/entity' import { useEntity } from '@/hooks/entity'
import { updateSatellitePayload } from '@/api/Satellite' import { updateSatellitePayload } from '@/api/Satellite'
import { useSatellite } from '../hooks/satellite' import { useSatellite } from '../hooks/satellite'
import { isNull, isUndefined } from 'es-toolkit'
const { openDetailsModal } = useModal() const { openDetailsModal } = useModal()
export function showDetailsSatellite(option) { export function showDetailsSatellite(option) {
@ -16,9 +18,13 @@ export function showDetailsSatellite(option) {
detectingPayload.value.push({ detectingPayload.value.push({
id, id,
angle: null, angle: null,
radius: null,
show: false, show: false,
}) })
} }
function removeDetectingPayload() {
detectingPayload.value = []
}
const communicationPayload = ref([]) const communicationPayload = ref([])
function addCommunicationPayload() { function addCommunicationPayload() {
communicationPayload.value.push({ communicationPayload.value.push({
@ -27,12 +33,16 @@ export function showDetailsSatellite(option) {
show: false, show: false,
}) })
} }
function removeCommunicationPayload() {
detectingPayload.value = []
}
const { satellitePayloadShowMap } = useEntity() const { satellitePayloadShowMap } = useEntity()
if (extendInfo?.detectingPayload) { if (extendInfo?.detectingPayload) {
detectingPayload.value.push({ detectingPayload.value.push({
id, id,
angle: extendInfo.detectingPayload.angle, angle: extendInfo.detectingPayload.angle,
radius: extendInfo.detectingPayload.radius,
show: satellitePayloadShowMap.get(id).detectingPayload.show, show: satellitePayloadShowMap.get(id).detectingPayload.show,
}) })
} }
@ -63,9 +73,13 @@ export function showDetailsSatellite(option) {
{/* <div class="detail-item-title">探测载荷</div> */} {/* <div class="detail-item-title">探测载荷</div> */}
<div class="flex justify-between"> <div class="flex justify-between">
<div class="detail-item-title">探测载荷</div> <div class="detail-item-title">探测载荷</div>
{detectingPayload.value.length === 0 && ( {detectingPayload.value.length === 0 ? (
<NButton quaternary type="primary" onClick={addDetectingPayload}> <NButton quaternary type="primary" onClick={addDetectingPayload}>
添加 添加载荷
</NButton>
) : (
<NButton quaternary type="error" onClick={removeDetectingPayload}>
删除载荷
</NButton> </NButton>
)} )}
</div> </div>
@ -78,13 +92,21 @@ export function showDetailsSatellite(option) {
)} )}
<div class="flex justify-between"> <div class="flex justify-between">
<div class="detail-item-title">通信载荷</div> <div class="detail-item-title">通信载荷</div>
{communicationPayload.value.length === 0 && ( {communicationPayload.value.length === 0 ? (
<NButton <NButton
quaternary quaternary
type="primary" type="primary"
onClick={addCommunicationPayload} onClick={addCommunicationPayload}
> >
添加 添加载荷
</NButton>
) : (
<NButton
quaternary
type="error"
onClick={removeCommunicationPayload}
>
删除载荷
</NButton> </NButton>
)} )}
</div> </div>
@ -115,6 +137,18 @@ function updateSatelliteLoad({ sat: sateData, detection, communication }) {
if (!detection[0] && !communication[0]) { if (!detection[0] && !communication[0]) {
return return
} }
if (
detection[0] &&
Object.values(detection[0]).some(item => isNull(item) || isUndefined(item))
) {
window.$message.error('探测载荷信息不完整')
return
}
if (communication[0] && communication[0].target.length > 0) {
window.$message.error('通信载荷信息不完整')
return
}
const { getSatelliteList } = useSatellite() const { getSatelliteList } = useSatellite()
const payloadData = { const payloadData = {
id: sateData.id, id: sateData.id,

View File

@ -66,6 +66,8 @@ export function useSatellite() {
// satellite.sensorType = Math.random() > 0.5 ? 'conic' : 'rectangle' // satellite.sensorType = Math.random() > 0.5 ? 'conic' : 'rectangle'
const satPayload = satellitePayloadShowMap.get(id) const satPayload = satellitePayloadShowMap.get(id)
if (satPayload && satPayload.detectingPayload) { if (satPayload && satPayload.detectingPayload) {
satPayload.detectingPayload.radius &&
(satellite.sensorRadius = satPayload.detectingPayload.radius)
satPayload.detectingPayload.angle && satPayload.detectingPayload.angle &&
(satellite.sensorAngle = satPayload.detectingPayload.angle) (satellite.sensorAngle = satPayload.detectingPayload.angle)
satPayload.detectingPayload.show && (satellite.sensor = true) satPayload.detectingPayload.show && (satellite.sensor = true)