完善了烟幕对于风向风速和扩散的影响,编写了测试
This commit is contained in:
parent
8e43a10c47
commit
538097f815
@ -10,7 +10,4 @@ alwaysApply: true
|
||||
- Y 轴为垂直轴
|
||||
|
||||
# 运行命令
|
||||
- 在运行命令前,先运行 pwd 命令,了解当前目录
|
||||
|
||||
# 测试
|
||||
- 项目使用 MSTest 测试框架,使用 MSTest 的方式运行测试
|
||||
- 在运行命令前,先运行 pwd 命令,了解当前目录
|
||||
13
ThreatSource.Tests/data/indicators/ir_trackers/ir_001.json
Normal file
13
ThreatSource.Tests/data/indicators/ir_trackers/ir_001.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "红外测角仪-001",
|
||||
"en": "IR Tracker-001"
|
||||
},
|
||||
"type": "InfraredTracker",
|
||||
"infraredTrackerConfig": {
|
||||
"maxTrackingRange": 10000.0,
|
||||
"fieldOfView": 0.2,
|
||||
"angleMeasurementAccuracy": 0.001,
|
||||
"updateFrequency": 10.0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "激光驾束仪-001",
|
||||
"en": "Laser Beam Rider-001"
|
||||
},
|
||||
"type": "LaserBeamRider",
|
||||
"beamRiderConfig": {
|
||||
"laserPower": 1000,
|
||||
"laserWavelength": 1.06,
|
||||
"controlFieldDiameter": 6.0,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1010
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "前视激光指示器-001",
|
||||
"en": "Forward Looking Laser Designator-001"
|
||||
},
|
||||
"type": "LaserDesignator",
|
||||
"designatorConfig": {
|
||||
"laserPower": 5000,
|
||||
"laserWavelength": 1.06,
|
||||
"laserDivergenceAngle": 0.0003,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1010
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "激光诱偏目标",
|
||||
"en": "Laser Decoy"
|
||||
},
|
||||
"type": "LaserDecoy",
|
||||
"LaserDecoyConfig": {
|
||||
"decoyPower": 25.0,
|
||||
"decoyLaserDivergenceAngle": 0.001,
|
||||
"reflectiveArea": 1.2,
|
||||
"reflectionCoefficient": 0.8,
|
||||
"lifeTime": 60.0
|
||||
}
|
||||
}
|
||||
18
ThreatSource.Tests/data/jammers/smoke_grenades/surround.json
Normal file
18
ThreatSource.Tests/data/jammers/smoke_grenades/surround.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "周边烟幕弹",
|
||||
"en": "Surround Smoke Grenade"
|
||||
},
|
||||
"type": "SmokeGrenade",
|
||||
"SmokeGrenadeConfig": {
|
||||
"smokeType": "Wall",
|
||||
"concentration": 0.2,
|
||||
"duration": 60.0,
|
||||
"wallWidth": 50.0,
|
||||
"wallHeight": 10.0,
|
||||
"cloudDiameter": 0.0,
|
||||
"thickness": 5.0,
|
||||
"formationDelay": 1.5,
|
||||
"expansionRate": 5.0
|
||||
}
|
||||
}
|
||||
18
ThreatSource.Tests/data/jammers/smoke_grenades/top.json
Normal file
18
ThreatSource.Tests/data/jammers/smoke_grenades/top.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "顶部烟幕弹",
|
||||
"en": "Top Smoke Grenade"
|
||||
},
|
||||
"type": "SmokeGrenade",
|
||||
"SmokeGrenadeConfig": {
|
||||
"smokeType": "Cloud",
|
||||
"concentration": 0.2,
|
||||
"duration": 60.0,
|
||||
"wallWidth": 0.0,
|
||||
"wallHeight": 0.0,
|
||||
"cloudDiameter": 20.0,
|
||||
"thickness": 5.0,
|
||||
"formationDelay": 1.5,
|
||||
"expansionRate": 5.0
|
||||
}
|
||||
}
|
||||
27
ThreatSource.Tests/data/missiles/ir_command/irc_001.json
Normal file
27
ThreatSource.Tests/data/missiles/ir_command/irc_001.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "红外指令导引导弹-001",
|
||||
"en": "IR Command Guided Missile-001"
|
||||
},
|
||||
"type": "InfraredCommandGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
"maxAcceleration": 100.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 23.5,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 0.0,
|
||||
"trackerSensitivity": null,
|
||||
"commandLatency": null,
|
||||
"irSignature": null
|
||||
},
|
||||
"infraredCommandGuidanceConfig": {
|
||||
"jammingResistanceThreshold": 1e-3
|
||||
}
|
||||
}
|
||||
34
ThreatSource.Tests/data/missiles/ir_imaging/itg_001.json
Normal file
34
ThreatSource.Tests/data/missiles/ir_imaging/itg_001.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "红外成像末制导导弹-001",
|
||||
"en": "IR Imaging Terminal Guided Missile-001"
|
||||
},
|
||||
"type": "InfraredImagingTerminalGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 250.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
"maxAcceleration": 100.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 25.0,
|
||||
"explosionRadius": 5.5,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 0.0
|
||||
},
|
||||
"infraredImagingGuidanceConfig": {
|
||||
"maxDetectionRange": 1000,
|
||||
"searchFieldOfView": 0.209,
|
||||
"trackFieldOfView": 0.052,
|
||||
"imageWidth": 640,
|
||||
"imageHeight": 512,
|
||||
"backgroundIntensity": 0.01,
|
||||
"searchRecognitionProbability": 0.6,
|
||||
"trackRecognitionProbability": 0.8,
|
||||
"targetLostTolerance": 0.2,
|
||||
"lockConfirmationTime": 0.3,
|
||||
"jammingResistanceThreshold": 1e-3
|
||||
}
|
||||
}
|
||||
41
ThreatSource.Tests/data/missiles/laser_beam_rider/hj10.json
Normal file
41
ThreatSource.Tests/data/missiles/laser_beam_rider/hj10.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "红箭-10",
|
||||
"en": "HJ-10"
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
"maxAcceleration": 100.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 24.5,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 0.0,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1010
|
||||
},
|
||||
"IsCodeEnabled": true,
|
||||
"IsCodeMatchRequired": true
|
||||
}
|
||||
},
|
||||
"LaserBeamRiderGuidanceConfig": {
|
||||
"minDetectablePower": 1e-10,
|
||||
"detectorDiameter": 0.03,
|
||||
"controlFieldDiameter": 20.0,
|
||||
"proportionalGain": 30.0,
|
||||
"integralGain": 0.05,
|
||||
"derivativeGain": 5.0,
|
||||
"nonlinearGain": 0.5,
|
||||
"maxGuidanceAcceleration": 50.0,
|
||||
"lowPassFilterCoefficient": 0.2,
|
||||
"jammingResistanceThreshold": 1e-3
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "科尔内特",
|
||||
"en": "Kornet"
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 70.0,
|
||||
"maxFlightDistance": 5500.0,
|
||||
"maxAcceleration": 110.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 12.0,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 27.0,
|
||||
"explosionRadius": 5.5,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 10.0,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ThreatSource.Tests/data/missiles/laser_beam_rider/tow.json
Normal file
27
ThreatSource.Tests/data/missiles/laser_beam_rider/tow.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "陶式导弹",
|
||||
"en": "TOW"
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 278.0,
|
||||
"maxFlightTime": 65.0,
|
||||
"maxFlightDistance": 4500.0,
|
||||
"maxAcceleration": 100.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 10.0,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 22.6,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 10.0,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1110
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "激光半主动制导导弹-001",
|
||||
"en": "Laser Semi-Active Guidance Missile-001"
|
||||
},
|
||||
"type": "LaserSemiActiveGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 800.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 4000.0,
|
||||
"maxAcceleration": 50.0,
|
||||
"proportionalNavigationCoefficient": 2.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 22.0,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 0.0,
|
||||
"laserCodeConfig": {
|
||||
"code": {
|
||||
"codeType": "PRF",
|
||||
"codeValue": 1010
|
||||
},
|
||||
"IsCodeEnabled": true,
|
||||
"IsCodeMatchRequired": true
|
||||
}
|
||||
},
|
||||
"laserSemiActiveGuidanceConfig": {
|
||||
"fieldOfViewAngle": 30.0,
|
||||
"lensDiameter": 0.1,
|
||||
"sensorDiameter": 0.03,
|
||||
"focusedSpotDiameter": 0.006,
|
||||
"reflectionCoefficient": 0.2,
|
||||
"targetReflectiveArea": 1.0,
|
||||
"lockThreshold": 1e-12,
|
||||
"spotOffsetSensitivity": 0.05,
|
||||
"jammingResistanceThreshold": 1e-3,
|
||||
"transmitterEfficiency": 0.85,
|
||||
"receiverEfficiency": 0.8,
|
||||
"laserWavelength": 1.06
|
||||
}
|
||||
}
|
||||
56
ThreatSource.Tests/data/missiles/mmw/mmw_001.json
Normal file
56
ThreatSource.Tests/data/missiles/mmw/mmw_001.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "毫米波末制导导弹-001",
|
||||
"en": "Millimeter Wave Terminal Guided Missile-001"
|
||||
},
|
||||
"type": "MillimeterWaveTerminalGuidance",
|
||||
"properties": {
|
||||
"maxSpeed": 250.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 8000.0,
|
||||
"maxAcceleration": 100.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 4.0,
|
||||
"mass": 28.0,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 0.0
|
||||
},
|
||||
"millimeterWaveGuidanceConfig": {
|
||||
"maxDetectionRange": 5000.0,
|
||||
"fieldOfViewAngle": 45.0,
|
||||
"targetRecognitionProbability": 0.95,
|
||||
"waveFrequency": 94e9,
|
||||
"pulseDuration": 1e-6,
|
||||
|
||||
"searchBeamWidth": 4.0,
|
||||
"trackBeamWidth": 2.0,
|
||||
"lockBeamWidth": 1.0,
|
||||
|
||||
"scanAngularSpeedDeg": 360.0,
|
||||
"scanRadiusGrowthRateDeg": 22.5,
|
||||
|
||||
"recognitionSNRThreshold": -25.0,
|
||||
"lockSNRThreshold": -10.0,
|
||||
|
||||
"targetLostTolerance": 0.2,
|
||||
"lockConfirmationTime": 0.3,
|
||||
|
||||
"pulseRepetitionFrequency": 1e-4,
|
||||
"transmitPower": 0.3,
|
||||
|
||||
"dopplerVelocityResolution": 1.0,
|
||||
"maxMeasurableVelocity": 1000.0,
|
||||
|
||||
"antennaGainDB": 23.0,
|
||||
"noiseFigureDB": 7.0,
|
||||
"systemLossDB": 6.0,
|
||||
"monopulseSensitivity": 1,
|
||||
|
||||
"yawControlEffectiveness": 120.0,
|
||||
"pitchControlEffectiveness": 150.0,
|
||||
"jammingResistanceThreshold": 1e-3
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "末敏导弹-001",
|
||||
"en": "Terminal Sensitive Missile-001"
|
||||
},
|
||||
"type": "TerminalSensitiveMissile",
|
||||
"properties": {
|
||||
"maxSpeed": 1000.0,
|
||||
"maxFlightTime": 100.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
"maxAcceleration": 200.0,
|
||||
"proportionalNavigationCoefficient": 3.0,
|
||||
"launchAcceleration": 100.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"cruiseTime": 5.0,
|
||||
"mass": 50.0,
|
||||
"explosionRadius": 5.0,
|
||||
"selfDestructHeight": 0.0
|
||||
},
|
||||
"submunitionProperties": {
|
||||
"maxSpeed": 2000.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 2000.0,
|
||||
"maxAcceleration": 300.0,
|
||||
"proportionalNavigationCoefficient": 4.0,
|
||||
"launchAcceleration": 10.0,
|
||||
"maxEngineBurnTime": 0.1,
|
||||
"mass": 10.0,
|
||||
"explosionRadius": 5.0,
|
||||
"hitProbability": 0.9,
|
||||
"selfDestructHeight": 20.0
|
||||
},
|
||||
"submunitionCount": 1,
|
||||
"submunitionConfig": {
|
||||
"separationHeight": 1000.0,
|
||||
"separationDistance": 1000.0,
|
||||
"submunitionSeparationAngle": 45.0,
|
||||
"separationRange": 50.0,
|
||||
"decelerationAcceleration": 250.0,
|
||||
"decelerationEndSpeed": 50.0,
|
||||
"parachuteDeploymentHeight": 400.0,
|
||||
"parachuteDeceleration": 140.0,
|
||||
"stableScanHeight": 200.0,
|
||||
"verticalDeclineSpeed": 10.0,
|
||||
"spiralRotationSpeed": 25.13,
|
||||
"scanAngle": 30.0,
|
||||
"targetDetectionDistance": 150.0,
|
||||
"selfDestructHeight": 20.0,
|
||||
"attackSpeed": 200.0
|
||||
}
|
||||
}
|
||||
32
ThreatSource.Tests/data/sensors/laser_warners/lw_001.json
Normal file
32
ThreatSource.Tests/data/sensors/laser_warners/lw_001.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "激光告警接收机-001",
|
||||
"en": "Laser Warning Receiver-001"
|
||||
},
|
||||
"type": "LaserWarner",
|
||||
"properties": {
|
||||
"detectionRange": 5000.0,
|
||||
"wavelengthRange": {
|
||||
"min": 0.4,
|
||||
"max": 1.7
|
||||
},
|
||||
"fieldOfView": 360.0,
|
||||
"responseTime": 0.001,
|
||||
"sensitivity": -60.0,
|
||||
"angularResolution": 7.5,
|
||||
"falseAlarmRate": 1e-6,
|
||||
"detectionProbability": 0.95,
|
||||
"spectralBands": [
|
||||
{
|
||||
"name": "Band1",
|
||||
"minWavelength": 0.4,
|
||||
"maxWavelength": 0.7
|
||||
},
|
||||
{
|
||||
"name": "Band2",
|
||||
"minWavelength": 0.7,
|
||||
"maxWavelength": 1.7
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
34
ThreatSource.Tests/data/targets/apcs/apc_001.json
Normal file
34
ThreatSource.Tests/data/targets/apcs/apc_001.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "装甲运兵车-001",
|
||||
"en": "Armored Personnel Carrier-001"
|
||||
},
|
||||
"type": "APC",
|
||||
"mass": 25000.0,
|
||||
"length": 7.0,
|
||||
"width": 3.2,
|
||||
"height": 2.8,
|
||||
"maxSpeed": 80.0,
|
||||
"armorThickness": 400.0,
|
||||
|
||||
"radarCrossSection": 12.0,
|
||||
"infraredRadiationIntensity": 2000.0,
|
||||
"ultravioletRadiationIntensity": 12.0,
|
||||
"millimeterWaveRadiationIntensity": 8.0,
|
||||
"millimeterWaveRadiationTemperature": 350.0,
|
||||
"laserReflectivity": 0.25,
|
||||
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[35, 40, 65],
|
||||
[30, 35, 70],
|
||||
[40, 40, 45]
|
||||
],
|
||||
"moving": [
|
||||
[40, 45, 70],
|
||||
[35, 40, 75],
|
||||
[50, 50, 55]
|
||||
]
|
||||
}
|
||||
}
|
||||
34
ThreatSource.Tests/data/targets/helicopters/heli_001.json
Normal file
34
ThreatSource.Tests/data/targets/helicopters/heli_001.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "武装直升机-001",
|
||||
"en": "Attack Helicopter-001"
|
||||
},
|
||||
"type": "Helicopter",
|
||||
"mass": 10000.0,
|
||||
"length": 17.0,
|
||||
"width": 3.0,
|
||||
"height": 4.5,
|
||||
"maxSpeed": 280.0,
|
||||
"armorThickness": 150.0,
|
||||
|
||||
"radarCrossSection": 8.0,
|
||||
"infraredRadiationIntensity": 3000.0,
|
||||
"ultravioletRadiationIntensity": 20.0,
|
||||
"millimeterWaveRadiationIntensity": 6.0,
|
||||
"millimeterWaveRadiationTemperature": 450.0,
|
||||
"laserReflectivity": 0.2,
|
||||
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[85, 110, 80],
|
||||
[35, 45, 40],
|
||||
[30, 35, 30]
|
||||
],
|
||||
"moving": [
|
||||
[90, 115, 85],
|
||||
[40, 50, 45],
|
||||
[35, 40, 35]
|
||||
]
|
||||
}
|
||||
}
|
||||
34
ThreatSource.Tests/data/targets/tanks/mbt_001.json
Normal file
34
ThreatSource.Tests/data/targets/tanks/mbt_001.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "主战坦克-001",
|
||||
"en": "Main Battle Tank-001"
|
||||
},
|
||||
"type": "Tank",
|
||||
"properties": {
|
||||
"mass": 50000.0,
|
||||
"length": 10.0,
|
||||
"width": 3.5,
|
||||
"height": 2.4,
|
||||
"maxSpeed": 70.0,
|
||||
"armorThickness": 800.0,
|
||||
"radarCrossSection": 15.0,
|
||||
"infraredRadiationIntensity": 2500.0,
|
||||
"ultravioletRadiationIntensity": 15.0,
|
||||
"millimeterWaveRadiationIntensity": 10.0,
|
||||
"millimeterWaveRadiationTemperature": 400.0,
|
||||
"laserReflectivity": 0.3,
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[40, 45, 80],
|
||||
[35, 40, 90],
|
||||
[50, 50, 60]
|
||||
],
|
||||
"moving": [
|
||||
[45, 50, 85],
|
||||
[40, 45, 95],
|
||||
[65, 65, 75]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/heavy_fog.json
Normal file
15
ThreatSource.Tests/data/weathers/heavy_fog.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "浓雾",
|
||||
"en": "Heavy Fog"
|
||||
},
|
||||
"type": "Fog",
|
||||
"temperature": 8.0,
|
||||
"relativeHumidity": 99.0,
|
||||
"visibility": 0.1,
|
||||
"precipitation": 0.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 998.0,
|
||||
"windSpeed": 0.0,
|
||||
"windDirection": 0.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/heavy_rain.json
Normal file
15
ThreatSource.Tests/data/weathers/heavy_rain.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "大雨",
|
||||
"en": "Heavy Rain"
|
||||
},
|
||||
"type": "Rain",
|
||||
"temperature": 16.0,
|
||||
"relativeHumidity": 95.0,
|
||||
"visibility": 2.0,
|
||||
"precipitation": 25.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 985.0,
|
||||
"windSpeed": 8.0,
|
||||
"windDirection": 180.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/heavy_snow.json
Normal file
15
ThreatSource.Tests/data/weathers/heavy_snow.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "大雪",
|
||||
"en": "Heavy Snow"
|
||||
},
|
||||
"type": "Snow",
|
||||
"temperature": -7.0,
|
||||
"relativeHumidity": 85.0,
|
||||
"visibility": 1.0,
|
||||
"precipitation": 8.0,
|
||||
"cO2Concentration": 410.0,
|
||||
"pressure": 990.0,
|
||||
"windSpeed": 6.0,
|
||||
"windDirection": 270.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/light_fog.json
Normal file
15
ThreatSource.Tests/data/weathers/light_fog.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "轻雾",
|
||||
"en": "Light Fog"
|
||||
},
|
||||
"type": "Fog",
|
||||
"temperature": 12.0,
|
||||
"relativeHumidity": 95.0,
|
||||
"visibility": 0.8,
|
||||
"precipitation": 0.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 1000.0,
|
||||
"windSpeed": 0.5,
|
||||
"windDirection": 20.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/light_rain.json
Normal file
15
ThreatSource.Tests/data/weathers/light_rain.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "小雨",
|
||||
"en": "Light Rain"
|
||||
},
|
||||
"type": "Rain",
|
||||
"temperature": 20.0,
|
||||
"relativeHumidity": 80.0,
|
||||
"visibility": 6.0,
|
||||
"precipitation": 5.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 1005.0,
|
||||
"windSpeed": 3.0,
|
||||
"windDirection": 180.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/light_snow.json
Normal file
15
ThreatSource.Tests/data/weathers/light_snow.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "小雪",
|
||||
"en": "Light Snow"
|
||||
},
|
||||
"type": "Snow",
|
||||
"temperature": -3.0,
|
||||
"relativeHumidity": 75.0,
|
||||
"visibility": 4.0,
|
||||
"precipitation": 2.0,
|
||||
"cO2Concentration": 410.0,
|
||||
"pressure": 1002.0,
|
||||
"windSpeed": 3.0,
|
||||
"windDirection": 270.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/medium_fog.json
Normal file
15
ThreatSource.Tests/data/weathers/medium_fog.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "中雾",
|
||||
"en": "Medium Fog"
|
||||
},
|
||||
"type": "Fog",
|
||||
"temperature": 10.0,
|
||||
"relativeHumidity": 98.0,
|
||||
"visibility": 0.4,
|
||||
"precipitation": 0.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 1000.0,
|
||||
"windSpeed": 0.2,
|
||||
"windDirection": 10.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/medium_rain.json
Normal file
15
ThreatSource.Tests/data/weathers/medium_rain.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "中雨",
|
||||
"en": "Medium Rain"
|
||||
},
|
||||
"type": "Rain",
|
||||
"temperature": 18.0,
|
||||
"relativeHumidity": 90.0,
|
||||
"visibility": 4.0,
|
||||
"precipitation": 15.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 995.0,
|
||||
"windSpeed": 6.0,
|
||||
"windDirection": 180.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/medium_snow.json
Normal file
15
ThreatSource.Tests/data/weathers/medium_snow.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "中雪",
|
||||
"en": "Medium Snow"
|
||||
},
|
||||
"type": "Snow",
|
||||
"temperature": -5.0,
|
||||
"relativeHumidity": 80.0,
|
||||
"visibility": 2.0,
|
||||
"precipitation": 4.0,
|
||||
"cO2Concentration": 410.0,
|
||||
"pressure": 1000.0,
|
||||
"windSpeed": 4.0,
|
||||
"windDirection": 270.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/sandstorm.json
Normal file
15
ThreatSource.Tests/data/weathers/sandstorm.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "沙尘",
|
||||
"en": "Sandstorm"
|
||||
},
|
||||
"type": "Dust",
|
||||
"temperature": 30.0,
|
||||
"relativeHumidity": 25.0,
|
||||
"visibility": 1.5,
|
||||
"precipitation": 0.0,
|
||||
"cO2Concentration": 430.0,
|
||||
"pressure": 1005.0,
|
||||
"windSpeed": 12.0,
|
||||
"windDirection": 315.0
|
||||
}
|
||||
15
ThreatSource.Tests/data/weathers/sunny.json
Normal file
15
ThreatSource.Tests/data/weathers/sunny.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "晴天",
|
||||
"en": "Sunny"
|
||||
},
|
||||
"type": "Clear",
|
||||
"temperature": 25.0,
|
||||
"relativeHumidity": 45.0,
|
||||
"visibility": 15.0,
|
||||
"precipitation": 0.0,
|
||||
"cO2Concentration": 415.0,
|
||||
"pressure": 1018.0,
|
||||
"windSpeed": 1.2,
|
||||
"windDirection": 90.0
|
||||
}
|
||||
293
ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs
Normal file
293
ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs
Normal file
@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using ThreatSource.Jammer;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation;
|
||||
using ThreatSource.Tests.Simulation;
|
||||
using ThreatSource.Data;
|
||||
using AirTransmission;
|
||||
using System.IO;
|
||||
|
||||
namespace ThreatSource.Tests.Jamming
|
||||
{
|
||||
public class SmokeGrenadeTests
|
||||
{
|
||||
private readonly TestSimulationAdapter _simulationAdapter;
|
||||
private readonly ISimulationManager _simulationManager;
|
||||
private readonly ThreatSourceFactory _threatSourceFactory;
|
||||
private readonly ThreatSourceDataManager _dataManager;
|
||||
|
||||
public SmokeGrenadeTests()
|
||||
{
|
||||
// 创建模拟管理器和适配器
|
||||
_simulationManager = new SimulationManager();
|
||||
_simulationAdapter = new TestSimulationAdapter(_simulationManager);
|
||||
_simulationManager.SetSimulationAdapter(_simulationAdapter);
|
||||
|
||||
// 创建数据管理器和工厂
|
||||
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string projectRoot = Path.GetFullPath(Path.Combine(baseDir, "../../../.."));
|
||||
string dataPath = Path.Combine(projectRoot, "ThreatSource/data");
|
||||
|
||||
_dataManager = new ThreatSourceDataManager(dataPath);
|
||||
_threatSourceFactory = new ThreatSourceFactory(_dataManager, _simulationManager);
|
||||
|
||||
// 显示可用的天气类型
|
||||
Console.WriteLine("可用的天气类型:");
|
||||
foreach (var weatherType in _dataManager.GetAvailableWeathers())
|
||||
{
|
||||
Console.WriteLine($" - {weatherType}");
|
||||
}
|
||||
|
||||
// 创建并设置天气
|
||||
var weather = _threatSourceFactory.CreateWeather("sunny");
|
||||
_simulationManager.SetWeather(weather);
|
||||
Console.WriteLine("已添加并设置晴天天气环境");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Initialize_WithWallSmokeConfig_SetsCorrectParameters()
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Wall,
|
||||
Concentration = 0.2,
|
||||
Duration = 60.0,
|
||||
WallWidth = 50.0,
|
||||
WallHeight = 10.0,
|
||||
Thickness = 5.0,
|
||||
ExpansionRate = 5.0,
|
||||
FormationDelay = 1.5
|
||||
};
|
||||
|
||||
// Act
|
||||
var smokeGrenade = new SmokeGrenade("test_wall", config, new MotionParameters(), _simulationManager);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SmokeScreenType.Wall, config.SmokeType);
|
||||
Assert.Equal(50.0, config.WallWidth);
|
||||
Assert.Equal(10.0, config.WallHeight);
|
||||
Assert.False(smokeGrenade.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Initialize_WithCloudSmokeConfig_SetsCorrectParameters()
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Cloud,
|
||||
Concentration = 0.2,
|
||||
Duration = 60.0,
|
||||
CloudDiameter = 20.0,
|
||||
Thickness = 5.0,
|
||||
ExpansionRate = 5.0,
|
||||
FormationDelay = 1.5
|
||||
};
|
||||
|
||||
// Act
|
||||
var smokeGrenade = new SmokeGrenade("test_cloud", config, new MotionParameters(), _simulationManager);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SmokeScreenType.Cloud, config.SmokeType);
|
||||
Assert.Equal(20.0, config.CloudDiameter);
|
||||
Assert.False(smokeGrenade.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_SetsIsActiveTrue()
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Wall,
|
||||
Concentration = 0.2,
|
||||
Duration = 60.0
|
||||
};
|
||||
var smokeGrenade = new SmokeGrenade("test", config, new MotionParameters(), _simulationManager);
|
||||
|
||||
// Act
|
||||
smokeGrenade.Activate();
|
||||
|
||||
// Assert
|
||||
Assert.True(smokeGrenade.IsActive);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)] // 初始时刻
|
||||
[InlineData(30)] // 中间时刻
|
||||
[InlineData(60)] // 结束时刻
|
||||
public void Update_ConcentrationDecaysOverTime(double elapsedTime)
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Wall,
|
||||
Concentration = 0.2,
|
||||
Duration = 60.0,
|
||||
WallWidth = 50.0,
|
||||
WallHeight = 10.0,
|
||||
Thickness = 5.0
|
||||
};
|
||||
|
||||
var motionParams = new MotionParameters
|
||||
{
|
||||
Position = Vector3D.Zero,
|
||||
Orientation = Orientation.FromVector(Vector3D.UnitZ) // 使用Z轴单位向量设置朝向
|
||||
};
|
||||
|
||||
var smokeGrenade = new SmokeGrenade("test", config, motionParams, _simulationManager);
|
||||
smokeGrenade.Activate();
|
||||
|
||||
// Act
|
||||
for (int i = 0; i < elapsedTime; i++)
|
||||
{
|
||||
smokeGrenade.Update(1.0); // 每次更新1秒
|
||||
}
|
||||
|
||||
// 计算预期浓度(使用半衰期公式)
|
||||
double expectedConcentration = config.Concentration * Math.Exp(-Math.Log(2) * elapsedTime / config.Duration);
|
||||
|
||||
// 获取实际浓度(通过测试一个穿过烟幕中心的视线)
|
||||
Vector3D observer = new(0, 0, -10);
|
||||
Vector3D target = new(0, 0, 10);
|
||||
double thickness = smokeGrenade.GetSmokeThicknessOnLine(observer, target);
|
||||
|
||||
// Assert
|
||||
if (elapsedTime >= 60)
|
||||
{
|
||||
Assert.False(smokeGrenade.IsActive); // 到达持续时间后应该自动禁用
|
||||
Assert.Equal(0, thickness); // 禁用后厚度应该为0
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(thickness > 0); // 未到持续时间时应该有烟幕
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)] // 无风
|
||||
[InlineData(5, 0)] // 北风
|
||||
[InlineData(5, 90)] // 东风
|
||||
[InlineData(5, 180)] // 南风
|
||||
[InlineData(5, 270)] // 西风
|
||||
public void Update_SmokePositionChangesWithWind(double windSpeed, double windDirection)
|
||||
{
|
||||
// Arrange
|
||||
var weather = _threatSourceFactory.CreateWeather("sunny");
|
||||
weather.WindSpeed = windSpeed;
|
||||
weather.WindDirection = windDirection;
|
||||
_simulationManager.SetWeather(weather);
|
||||
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Cloud,
|
||||
Concentration = 0.2,
|
||||
Duration = 60.0,
|
||||
CloudDiameter = 20.0
|
||||
};
|
||||
var initialPosition = new Vector3D(0, 0, 0);
|
||||
var motionParams = new MotionParameters { Position = initialPosition };
|
||||
var smokeGrenade = new SmokeGrenade("test", config, motionParams, _simulationManager);
|
||||
smokeGrenade.Activate();
|
||||
|
||||
// Act
|
||||
double updateTime = 10.0; // 更新10秒
|
||||
smokeGrenade.Update(updateTime);
|
||||
|
||||
// 计算预期位移
|
||||
double windDirectionRad = windDirection * Math.PI / 180.0;
|
||||
double expectedX = windSpeed * updateTime * Math.Sin(windDirectionRad);
|
||||
double expectedZ = windSpeed * updateTime * Math.Cos(windDirectionRad);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedX, smokeGrenade.Position.X, 2); // 允许2米的误差
|
||||
Assert.Equal(expectedZ, smokeGrenade.Position.Z, 2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 10, true)] // 正对墙面中心
|
||||
[InlineData(20, 0, 10, true)] // 斜向墙面但在宽度范围内
|
||||
[InlineData(-50, 0, -10, false)] // 在墙外(观察者和目标都在墙外)
|
||||
[InlineData(0, 15, 0, false)] // 高度超出范围
|
||||
public void GetSmokeThicknessOnLine_WallSmoke_ReturnsCorrectThickness(
|
||||
double observerX, double observerY, double expectedThickness, bool shouldIntersect)
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Wall,
|
||||
WallWidth = 50.0,
|
||||
WallHeight = 10.0,
|
||||
Thickness = 5.0
|
||||
};
|
||||
|
||||
// 设置烟墙朝向为Z轴正方向
|
||||
var motionParams = new MotionParameters
|
||||
{
|
||||
Position = Vector3D.Zero,
|
||||
Orientation = Orientation.FromVector(Vector3D.UnitZ) // 使用Z轴单位向量设置朝向
|
||||
};
|
||||
|
||||
var smokeGrenade = new SmokeGrenade("test", config, motionParams, _simulationManager);
|
||||
smokeGrenade.Activate();
|
||||
|
||||
Vector3D observer = new(observerX, observerY, -10);
|
||||
Vector3D target = new(observerX, observerY, 10);
|
||||
|
||||
// Act
|
||||
double thickness = smokeGrenade.GetSmokeThicknessOnLine(observer, target);
|
||||
|
||||
// Assert
|
||||
if (shouldIntersect)
|
||||
{
|
||||
Assert.True(thickness > 0);
|
||||
Assert.True(thickness >= config.Thickness); // 斜向穿透时厚度会更大
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(0, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)] // 穿过云中心
|
||||
[InlineData(8, 0, true)] // 穿过云边缘
|
||||
[InlineData(15, 0, false)] // 未穿过云
|
||||
[InlineData(0, 10, false)] // 高度超出范围
|
||||
public void GetSmokeThicknessOnLine_CloudSmoke_ReturnsCorrectThickness(
|
||||
double offsetX, double offsetY, bool shouldIntersect)
|
||||
{
|
||||
// Arrange
|
||||
var config = new SmokeGrenadeConfig
|
||||
{
|
||||
SmokeType = SmokeScreenType.Cloud,
|
||||
CloudDiameter = 20.0,
|
||||
Thickness = 5.0
|
||||
};
|
||||
var smokeGrenade = new SmokeGrenade("test", config, new MotionParameters(), _simulationManager);
|
||||
smokeGrenade.Activate();
|
||||
|
||||
Vector3D observer = new(offsetX, offsetY, -10);
|
||||
Vector3D target = new(offsetX, offsetY, 10);
|
||||
|
||||
// Act
|
||||
double thickness = smokeGrenade.GetSmokeThicknessOnLine(observer, target);
|
||||
|
||||
// Assert
|
||||
if (shouldIntersect)
|
||||
{
|
||||
Assert.True(thickness > 0);
|
||||
if (offsetX == 0) // 中心穿透
|
||||
{
|
||||
Assert.Equal(config.CloudDiameter, thickness, 1); // 允许1米误差
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(0, thickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ThreatSource.Simulation;
|
||||
using ThreatSource.Utils;
|
||||
using AirTransmission;
|
||||
|
||||
namespace ThreatSource.Tests.Simulation
|
||||
{
|
||||
@ -20,13 +20,15 @@ namespace ThreatSource.Tests.Simulation
|
||||
private Dictionary<string, SimulationEnvironmentData> _environmentData = new();
|
||||
// 当前仿真时间
|
||||
private double _currentTime = 0;
|
||||
// 当前天气
|
||||
private Weather? _currentWeather;
|
||||
private readonly object _eventLock = new object();
|
||||
|
||||
// 添加事件声明
|
||||
public event EventHandler<SimulationEvent>? EventPublished;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,初始化测试适配器
|
||||
/// 带仿真管理器的构造函数
|
||||
/// </summary>
|
||||
/// <param name="simulationManager">仿真管理器</param>
|
||||
public TestSimulationAdapter(ISimulationManager simulationManager)
|
||||
@ -34,6 +36,21 @@ namespace ThreatSource.Tests.Simulation
|
||||
_simulationManager = simulationManager ?? throw new ArgumentNullException(nameof(simulationManager));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前天气
|
||||
/// </summary>
|
||||
public Weather? CurrentWeather => _currentWeather;
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前天气
|
||||
/// </summary>
|
||||
/// <param name="weather">天气条件</param>
|
||||
public void SetWeather(Weather weather)
|
||||
{
|
||||
_currentWeather = weather;
|
||||
Console.WriteLine($"已设置天气:{weather.Type}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实体
|
||||
/// </summary>
|
||||
|
||||
@ -73,28 +73,16 @@ namespace ThreatSource.Data
|
||||
try
|
||||
{
|
||||
var jsonContent = File.ReadAllText(file);
|
||||
Console.WriteLine($"读取导弹文件内容:{jsonContent}");
|
||||
Console.WriteLine($"序列化选项:");
|
||||
Console.WriteLine($"- PropertyNameCaseInsensitive: {_jsonOptions.PropertyNameCaseInsensitive}");
|
||||
Console.WriteLine($"- WriteIndented: {_jsonOptions.WriteIndented}");
|
||||
Console.WriteLine($"- PropertyNamingPolicy: {_jsonOptions.PropertyNamingPolicy}");
|
||||
|
||||
var data = JsonSerializer.Deserialize<MissileData>(jsonContent, _jsonOptions);
|
||||
if (data != null)
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_missiles[model] = data;
|
||||
Console.WriteLine($"已加载导弹数据:{model}");
|
||||
Console.WriteLine($"导弹类型:{data.Type}");
|
||||
Console.WriteLine($"毫米波导引配置:{(data.MillimeterWaveGuidanceConfig != null ? "已加载" : "未加载")}");
|
||||
if (data.MillimeterWaveGuidanceConfig != null)
|
||||
if (data.MillimeterWaveGuidanceConfig != null)
|
||||
{
|
||||
var config = data.MillimeterWaveGuidanceConfig;
|
||||
Console.WriteLine($"- 最大探测范围:{config.MaxDetectionRange}");
|
||||
Console.WriteLine($"- 视场角:{config.FieldOfViewAngle}");
|
||||
Console.WriteLine($"- 目标识别概率:{config.TargetRecognitionProbability}");
|
||||
}
|
||||
//Console.WriteLine($"读取到的完整数据:{JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true })}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -121,16 +109,13 @@ namespace ThreatSource.Data
|
||||
try
|
||||
{
|
||||
var jsonContent = File.ReadAllText(file);
|
||||
//Console.WriteLine($"读取指示器文件内容:{jsonContent}");
|
||||
|
||||
var data = JsonSerializer.Deserialize<IndicatorData>(jsonContent, _jsonOptions);
|
||||
if (data != null)
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_indicators[model] = data;
|
||||
Console.WriteLine($"已加载指示器数据:{model}");
|
||||
//Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -156,15 +141,12 @@ namespace ThreatSource.Data
|
||||
try
|
||||
{
|
||||
var jsonContent = File.ReadAllText(file);
|
||||
//Console.WriteLine($"读取传感器文件内容:{jsonContent}");
|
||||
|
||||
var data = JsonSerializer.Deserialize<SensorData>(jsonContent, _jsonOptions);
|
||||
if (data != null)
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_sensors[model] = data;
|
||||
Console.WriteLine($"已加载传感器数据:{model}");
|
||||
//Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -191,15 +173,12 @@ namespace ThreatSource.Data
|
||||
try
|
||||
{
|
||||
var jsonContent = File.ReadAllText(file);
|
||||
//Console.WriteLine($"读取目标文件内容:{jsonContent}");
|
||||
|
||||
var data = JsonSerializer.Deserialize<EquipmentData>(jsonContent, _jsonOptions);
|
||||
if (data != null)
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_targets[model] = data;
|
||||
Console.WriteLine($"正在加载目标数据:{file}");
|
||||
//Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -232,7 +211,6 @@ namespace ThreatSource.Data
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_weathers[model] = data;
|
||||
Console.WriteLine($"已加载天气数据:{model}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -264,7 +242,6 @@ namespace ThreatSource.Data
|
||||
{
|
||||
string model = Path.GetFileNameWithoutExtension(file);
|
||||
_jammers[model] = data;
|
||||
Console.WriteLine($"已加载干扰机数据:{model}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@ -89,6 +89,31 @@ namespace ThreatSource.Jammer
|
||||
/// 烟幕厚度,单位:米
|
||||
/// </summary>
|
||||
public double? SmokeThickness { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕直径,单位:米
|
||||
/// </summary>
|
||||
public double? SmokeDiameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕墙宽,单位:米
|
||||
/// </summary>
|
||||
public double? SmokeWallWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕墙高,单位:米
|
||||
/// </summary>
|
||||
public double? SmokeWallHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕形成延迟,单位:秒
|
||||
/// </summary>
|
||||
public double? FormationDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕扩散速率,单位:米/秒
|
||||
/// </summary>
|
||||
public double? ExpansionRate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -51,6 +51,7 @@ namespace ThreatSource.Jammer
|
||||
public override void Activate()
|
||||
{
|
||||
IsActive = true;
|
||||
_elapsedTime = 0;
|
||||
if (!IsJamming)
|
||||
{
|
||||
var parameters = CreateJammingParameters();
|
||||
@ -86,17 +87,73 @@ namespace ThreatSource.Jammer
|
||||
StartTime = DateTime.UtcNow,
|
||||
SmokeType = config.SmokeType,
|
||||
SmokeConcentration = config.Concentration,
|
||||
SmokeThickness = config.Thickness
|
||||
SmokeThickness = config.Thickness,
|
||||
SmokeDiameter = config.CloudDiameter,
|
||||
SmokeWallWidth = config.WallWidth,
|
||||
SmokeWallHeight = config.WallHeight,
|
||||
FormationDelay = config.FormationDelay,
|
||||
ExpansionRate = config.ExpansionRate
|
||||
};
|
||||
}
|
||||
|
||||
private double _elapsedTime = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 更新烟幕效果
|
||||
/// </summary>
|
||||
protected override void UpdateJamming(double deltaTime)
|
||||
{
|
||||
// 发布烟幕状态更新事件
|
||||
PublishSmokeEvent();
|
||||
var weather = SimulationManager?.CurrentWeather;
|
||||
if (weather != null && IsActive && CurrentParameters != null)
|
||||
{
|
||||
// 更新累计时间
|
||||
_elapsedTime += deltaTime;
|
||||
|
||||
// 风力移动部分
|
||||
double windSpeed = weather.WindSpeed;
|
||||
double windDirectionDeg = weather.WindDirection;
|
||||
double windDirectionRad = windDirectionDeg * Math.PI / 180.0;
|
||||
|
||||
Vector3D windVector = new(
|
||||
Math.Sin(windDirectionRad),
|
||||
0,
|
||||
Math.Cos(windDirectionRad)
|
||||
);
|
||||
|
||||
// 烟雾位置随风移动
|
||||
Position += windVector * windSpeed * deltaTime;
|
||||
|
||||
// 计算浓度衰减
|
||||
double decayRate = Math.Log(2) / config.Duration;
|
||||
CurrentParameters.SmokeConcentration *= Math.Exp(-decayRate * deltaTime);
|
||||
|
||||
// 计算扩散
|
||||
double expansionAmount = config.ExpansionRate * deltaTime;
|
||||
CurrentParameters.SmokeThickness = config.Thickness + expansionAmount;
|
||||
|
||||
if (config.SmokeType == SmokeScreenType.Cloud)
|
||||
{
|
||||
CurrentParameters.SmokeDiameter = config.CloudDiameter + expansionAmount;
|
||||
CurrentParameters.SmokeWallWidth = null;
|
||||
CurrentParameters.SmokeWallHeight = null;
|
||||
}
|
||||
else // Wall
|
||||
{
|
||||
CurrentParameters.SmokeWallWidth = config.WallWidth + expansionAmount;
|
||||
CurrentParameters.SmokeWallHeight = config.WallHeight + expansionAmount;
|
||||
CurrentParameters.SmokeDiameter = null;
|
||||
}
|
||||
|
||||
// 发布烟幕状态更新事件
|
||||
PublishSmokeEvent();
|
||||
|
||||
// 检查是否需要停止烟幕效果
|
||||
if (_elapsedTime >= config.Duration ||
|
||||
CurrentParameters.SmokeConcentration < config.Concentration * 0.1)
|
||||
{
|
||||
Deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -150,13 +207,157 @@ namespace ThreatSource.Jammer
|
||||
PublishEvent(evt);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 判断给定点是否在烟幕范围内
|
||||
/// 计算观察者到目标的视线穿过烟雾的厚度
|
||||
/// </summary>
|
||||
/// <param name="point">要检测的点</param>
|
||||
/// <returns>点是否在烟幕范围内</returns>
|
||||
public bool IsPointInSmoke(Vector3D point)
|
||||
/// <param name="observerPosition">观察者位置</param>
|
||||
/// <param name="targetPosition">目标位置</param>
|
||||
/// <returns>穿过的烟雾厚度(米),如果没有穿过烟雾则返回0</returns>
|
||||
public double GetSmokeThicknessOnLine(Vector3D observerPosition, Vector3D targetPosition)
|
||||
{
|
||||
if (!IsActive || !IsJamming) return 0;
|
||||
|
||||
// 计算视线向量
|
||||
Vector3D lineDirection = (targetPosition - observerPosition).Normalize();
|
||||
double lineLength = (targetPosition - observerPosition).Magnitude();
|
||||
|
||||
if (config.SmokeType == SmokeScreenType.Cloud)
|
||||
{
|
||||
// 对于云状烟幕,计算视线与圆柱体的交点
|
||||
return CalculateCloudIntersection(observerPosition, lineDirection, lineLength);
|
||||
}
|
||||
else // SmokeScreenType.Wall
|
||||
{
|
||||
// 对于墙状烟幕,计算视线与平面的交点
|
||||
return CalculateWallIntersection(observerPosition, lineDirection, lineLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算视线与云状烟幕的交点并返回穿过的厚度
|
||||
/// </summary>
|
||||
private double CalculateCloudIntersection(Vector3D origin, Vector3D direction, double maxDistance)
|
||||
{
|
||||
if (!IsActive || !IsJamming || CurrentParameters == null) return 0;
|
||||
|
||||
// 将视线转换到烟幕局部坐标系
|
||||
Vector3D localOrigin = origin - Position;
|
||||
|
||||
// 检查高度约束
|
||||
double currentThickness = CurrentParameters.SmokeThickness ?? config.Thickness;
|
||||
if (Math.Abs(localOrigin.Y) > currentThickness &&
|
||||
Math.Abs(localOrigin.Y + direction.Y * maxDistance) > currentThickness)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算视线与圆柱体的交点
|
||||
// 将问题简化为2D平面上的圆与线段相交
|
||||
Vector3D originXZ = new Vector3D(localOrigin.X, 0, localOrigin.Z);
|
||||
Vector3D directionXZ = new Vector3D(direction.X, 0, direction.Z).Normalize();
|
||||
|
||||
double radius = config.CloudDiameter / 2;
|
||||
double a = Vector3D.DotProduct(directionXZ, directionXZ);
|
||||
double b = 2 * Vector3D.DotProduct(originXZ, directionXZ);
|
||||
double c = Vector3D.DotProduct(originXZ, originXZ) - radius * radius;
|
||||
|
||||
double discriminant = b * b - 4 * a * c;
|
||||
if (discriminant < 0)
|
||||
{
|
||||
return 0; // 没有交点
|
||||
}
|
||||
|
||||
// 计算交点参数
|
||||
double t1 = (-b - Math.Sqrt(discriminant)) / (2 * a);
|
||||
double t2 = (-b + Math.Sqrt(discriminant)) / (2 * a);
|
||||
|
||||
// 检查交点是否在视线段上
|
||||
if (t2 < 0 || t1 > maxDistance)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 限制交点在视线段范围内
|
||||
t1 = Math.Max(0, t1);
|
||||
t2 = Math.Min(maxDistance, t2);
|
||||
|
||||
// 计算实际穿过的厚度
|
||||
return (t2 - t1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算视线与墙状烟幕的交点并返回穿过的厚度
|
||||
/// </summary>
|
||||
private double CalculateWallIntersection(Vector3D origin, Vector3D direction, double maxDistance)
|
||||
{
|
||||
if (!IsActive || !IsJamming || CurrentParameters == null) return 0;
|
||||
|
||||
// 将视线转换到烟幕局部坐标系
|
||||
Vector3D localOrigin = origin - Position;
|
||||
|
||||
// 获取墙面法向量(与烟幕朝向一致)
|
||||
Vector3D wallNormal = Orientation.ToVector();
|
||||
|
||||
// 计算视线与墙面的夹角余弦
|
||||
double cosAngle = Vector3D.DotProduct(direction, wallNormal);
|
||||
if (Math.Abs(cosAngle) < 1e-6)
|
||||
{
|
||||
return 0; // 视线平行于墙面
|
||||
}
|
||||
|
||||
// 计算观察点到墙面中心的距离
|
||||
double distToWallCenter = Vector3D.DotProduct(localOrigin, wallNormal);
|
||||
double currentThickness = CurrentParameters.SmokeThickness ?? config.Thickness;
|
||||
|
||||
// 如果观察点距离墙面中心的距离超过厚度的一半,且视线方向背向墙面,则不可能相交
|
||||
if (Math.Abs(distToWallCenter) > currentThickness / 2 &&
|
||||
Math.Sign(distToWallCenter) == Math.Sign(cosAngle))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算视线与中心平面的交点参数
|
||||
double t = -Vector3D.DotProduct(localOrigin, wallNormal) / cosAngle;
|
||||
if (t < 0 || t > maxDistance)
|
||||
{
|
||||
return 0; // 交点不在视线段上
|
||||
}
|
||||
|
||||
// 计算交点位置
|
||||
Vector3D intersection = localOrigin + direction * t;
|
||||
|
||||
// 检查交点是否在墙面范围内
|
||||
// 1. 检查高度
|
||||
double currentHeight = CurrentParameters.SmokeWallHeight ?? config.WallHeight;
|
||||
if (Math.Abs(intersection.Y) > currentHeight / 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 2. 检查宽度(沿墙面方向)
|
||||
Vector3D wallParallel = Vector3D.CrossProduct(wallNormal, Vector3D.UnitY);
|
||||
double distAlongWall = Math.Abs(Vector3D.DotProduct(intersection, wallParallel));
|
||||
double currentWidth = CurrentParameters.SmokeWallWidth ?? config.WallWidth;
|
||||
if (distAlongWall > currentWidth / 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 3. 检查交点到墙面中心的距离是否在厚度范围内
|
||||
double distFromWallCenter = Math.Abs(Vector3D.DotProduct(intersection, wallNormal));
|
||||
if (distFromWallCenter > currentThickness / 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 如果交点在墙面范围内,返回穿过的厚度
|
||||
return currentThickness / Math.Abs(cosAngle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断给定点是否在烟幕范围内(内部辅助方法)
|
||||
/// </summary>
|
||||
private bool IsPointInSmoke(Vector3D point)
|
||||
{
|
||||
if (!IsActive || !IsJamming) return false;
|
||||
|
||||
@ -177,7 +378,7 @@ namespace ThreatSource.Jammer
|
||||
}
|
||||
|
||||
// 计算水平面内的位置
|
||||
Vector3D planePos = new Vector3D(relativePos.X, 0, relativePos.Z);
|
||||
Vector3D planePos = new(relativePos.X, 0, relativePos.Z);
|
||||
double radiusComponent = planePos.Magnitude();
|
||||
|
||||
// 检查径向距离是否在圆柱体范围内
|
||||
|
||||
Loading…
Reference in New Issue
Block a user