统一了跟踪信息输出方式,合理使用 Debug.WriteLine 和 Trace类

This commit is contained in:
Tian jianyong 2025-05-12 15:01:04 +08:00
parent 56eafa392f
commit e1d2ea4eac
31 changed files with 587 additions and 432 deletions

View File

@ -1,40 +0,0 @@
---
description: Base Guidelines for Sonnet-3.7 + Cursor Agent
globs: *,**/*
alwaysApply: true
---
# prompts-claude-sonnet-37-rule-claude-sonnet-37.md
# ---------------------------------------------------------------
# DESCRIPTION:
# this rule helps to better control sonnet-3.7 + cursor. (like doing to much, creating unnecessary new files e.g.).
# especially the first two rules give the cursor agent already the most important instructions that worked for me.
#
# ❗ ATTENTION:
# 1. this does not work so easily for large codebases
# 2. remove everything from these rules that you do not need
# 3. also remove this comments
# ---------------------------------------------------------------
# Instructions
1. Always use codebase_search with target_directories="{{ThreatSource/src}}" first to find existing core files
2. Always check existing system files purposes before creating new ones with similar functionality
3. Always list the cursor rules youre using
# Optional
- If a prompt or request specifies certain behaviors, languages, or output formats, you must obey them without deviation.
- Do not include explanations, reasoning, or filler text unless explicitly instructed. Stick strictly to the requested output.
- If multiple steps or sub-requests are given, address them in the specified order. Provide answers in the exact format or sequence requested.
- Pay close attention to all stated constraints (e.g., language choice, performance goals, coding style). Do not ignore any requirement or best practice stated.
- Only produce output relevant to the question or instructions. Do not add features, code, or details beyond what is explicitly asked.
- Deliver the response in a minimal yet complete form. Avoid unnecessary verbosity and tangential remarks.
- If the prompt requests a specific output format (e.g., a fenced code block, bullet points, JSON), follow that format exactly.
- If a prompt includes a pre-seeded answer structure (e.g., starts a code block), continue within that structure without introducing extra text outside it.
- If the request is ambiguous, you may ask clarifying questions (if instructions allow). Otherwise, state briefly that more information is needed.
- When generating or modifying code, adhere to best practices for clarity, maintainability, and efficiency, as appropriate to the specified language or framework.
- Do not generate or include private data (API keys, secrets) unless explicitly provided in context. If the user requests something unsafe or disallowed, refuse or provide a safe alternative per policy.

View File

@ -1,16 +0,0 @@
---
description:
globs:
alwaysApply: true
---
# 注释
使用中文注释
# 坐标系约定
- 采用右手坐标系
- Y 轴向上
- 逆时针旋转为正方向
# 运行命令
- 在运行命令前,先运行 pwd 命令,了解当前目录

View File

@ -1,4 +1,3 @@
using System;
using Xunit;
using ThreatSource.Jammer;
using ThreatSource.Utils;
@ -6,6 +5,7 @@ using ThreatSource.Simulation;
using ThreatSource.Tests.Simulation;
using ThreatSource.Data;
using Xunit.Abstractions;
using System.Diagnostics;
namespace ThreatSource.Tests.Jamming
{
@ -34,16 +34,16 @@ namespace ThreatSource.Tests.Jamming
_threatSourceFactory = new ThreatSourceFactory(_dataManager, _simulationManager);
// 显示可用的天气类型
Console.WriteLine("可用的天气类型:");
Debug.WriteLine("可用的天气类型:");
foreach (var weatherType in _dataManager.GetAvailableWeathers())
{
Console.WriteLine($" - {weatherType}");
Debug.WriteLine($" - {weatherType}");
}
// 创建并设置天气
var weather = _threatSourceFactory.CreateWeather("sunny");
_simulationManager.SetWeather(weather);
Console.WriteLine("已添加并设置晴天天气环境");
Debug.WriteLine("已添加并设置晴天天气环境");
}
[Fact]

View File

@ -6,6 +6,7 @@ using ThreatSource.Simulation;
using ThreatSource.Tests.Simulation;
using ThreatSource.Equipment;
using ThreatSource.Utils;
using System.Diagnostics;
namespace ThreatSource.Tests.Jamming
{
@ -309,10 +310,10 @@ namespace ThreatSource.Tests.Jamming
submunition.Update(0.02);
// 输出调试信息
Console.WriteLine($"更新 {i}:");
Console.WriteLine($"子弹位置: {submunition.KState.Position}");
Console.WriteLine($"目标位置: {tank.KState.Position}");
Console.WriteLine($"距离: {(tank.KState.Position - submunition.KState.Position).Magnitude()}");
Debug.WriteLine($"更新 {i}:");
Debug.WriteLine($"子弹位置: {submunition.KState.Position}");
Debug.WriteLine($"目标位置: {tank.KState.Position}");
Debug.WriteLine($"距离: {(tank.KState.Position - submunition.KState.Position).Magnitude()}");
if ((tank.KState.Position - submunition.KState.Position).Magnitude() < 5)
{
@ -513,7 +514,7 @@ namespace ThreatSource.Tests.Jamming
double? initialAltitude = ((AltimeterSensorData)altimeter.GetSensorData()).Altitude;
Assert.IsTrue(initialAltitude.HasValue, "无法获取初始高度");
var initialStatus = submunition.GetStatus();
Console.WriteLine($"初始状态:{initialStatus}");
Debug.WriteLine($"初始状态:{initialStatus}");
// 更新几次状态,使子弹进入开伞阶段
for (int i = 0; i < 10; i++)
@ -530,7 +531,7 @@ namespace ThreatSource.Tests.Jamming
// 验证干扰效果
Assert.IsTrue(altimeter.IsJammed, "测高仪应该处于被干扰状态");
ElementStatusInfo status = submunition.GetStatusInfo();
Console.WriteLine($"干扰后状态:{status}");
Debug.WriteLine($"干扰后状态:{status}");
Assert.IsTrue(status.ExtendedProperties["IsSensorsJammed"].ToString() == "True", "子弹状态应该反映传感器受到干扰");
// 记录干扰时的位置
@ -544,7 +545,7 @@ namespace ThreatSource.Tests.Jamming
// 验证在干扰期间的行为
var currentPosition = submunition.KState.Position;
Console.WriteLine($"干扰期间位置变化:从 {jammedPosition} 到 {currentPosition}");
Debug.WriteLine($"干扰期间位置变化:从 {jammedPosition} 到 {currentPosition}");
// 清除干扰
altimeter.ClearJamming(millimeterWaveJamming);
@ -553,7 +554,7 @@ namespace ThreatSource.Tests.Jamming
// 验证恢复效果
Assert.IsFalse(altimeter.IsJammed, "测高仪应该恢复正常工作");
status = submunition.GetStatusInfo();
Console.WriteLine($"恢复后状态:{status}");
Debug.WriteLine($"恢复后状态:{status}");
Assert.IsFalse(status.ExtendedProperties["IsSensorsJammed"].ToString() == "True", "子弹状态应该反映传感器恢复正常");
// 验证速度变化

View File

@ -5,6 +5,7 @@ using ThreatSource.Simulation;
using ThreatSource.Tests.Simulation;
using ThreatSource.Guidance;
using System;
using System.Diagnostics;
namespace ThreatSource.Tests.Sensor
{
@ -148,8 +149,8 @@ namespace ThreatSource.Tests.Sensor
Vector3D result = _detector.GetTargetDirection(currentDirection, sensitivity);
// 输出调试信息
Console.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Console.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
Debug.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Debug.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
// Assert
Assert.True(_detector.IsTargetLocked);
@ -171,8 +172,8 @@ namespace ThreatSource.Tests.Sensor
Vector3D result = _detector.GetTargetDirection(currentDirection, sensitivity);
// 输出调试信息
Console.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Console.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
Debug.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Debug.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
// Assert
Assert.True(_detector.IsTargetLocked);
@ -233,9 +234,9 @@ namespace ThreatSource.Tests.Sensor
Vector3D resultMedium = _detector.GetTargetDirection(currentDirection, mediumSensitivity);
// 输出调试信息
Console.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Console.WriteLine($"标准灵敏度结果: X={resultStandard.X}, Y={resultStandard.Y}, Z={resultStandard.Z}");
Console.WriteLine($"中等灵敏度结果: X={resultMedium.X}, Y={resultMedium.Y}, Z={resultMedium.Z}");
Debug.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Debug.WriteLine($"标准灵敏度结果: X={resultStandard.X}, Y={resultStandard.Y}, Z={resultStandard.Z}");
Debug.WriteLine($"中等灵敏度结果: X={resultMedium.X}, Y={resultMedium.Y}, Z={resultMedium.Z}");
// Assert
Assert.Equal(1.0, resultStandard.Magnitude(), 0.001); // 确保是单位向量
@ -266,10 +267,10 @@ namespace ThreatSource.Tests.Sensor
Vector3D result = _detector.GetTargetDirection(currentDirection, sensitivity);
// 输出测试条件和结果
Console.WriteLine($"测试条件: {testCondition}");
Console.WriteLine($"灵敏度: {sensitivity}, 光斑偏移: {spotOffset}");
Console.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Console.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
Debug.WriteLine($"测试条件: {testCondition}");
Debug.WriteLine($"灵敏度: {sensitivity}, 光斑偏移: {spotOffset}");
Debug.WriteLine($"水平误差: {_detector.HorizontalError}, 垂直误差: {_detector.VerticalError}");
Debug.WriteLine($"结果向量: X={result.X}, Y={result.Y}, Z={result.Z}");
// Assert
Assert.True(_detector.IsTargetLocked);

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using ThreatSource.Simulation;
using AirTransmission;
using System.Diagnostics;
namespace ThreatSource.Tests.Simulation
{
@ -48,7 +49,7 @@ namespace ThreatSource.Tests.Simulation
public void SetWeather(Weather weather)
{
_currentWeather = weather;
Console.WriteLine($"已设置天气:{weather.Type}");
Debug.WriteLine($"已设置天气:{weather.Type}");
}
/// <summary>

View File

@ -2,6 +2,7 @@ using System;
using Xunit;
using ThreatSource.Utils;
using AirTransmission;
using System.Diagnostics;
namespace ThreatSource.Tests.Utils
{
@ -32,7 +33,7 @@ namespace ThreatSource.Tests.Utils
);
// Assert - 验证结果在合理范围内
Console.WriteLine($"激光透过率: {transmittance:F6}");
Debug.WriteLine($"激光透过率: {transmittance:F6}");
Assert.True(transmittance >= 0.0);
Assert.True(transmittance <= 1.0);
Assert.NotEqual(0.0, transmittance); // 确保不是0
@ -63,7 +64,7 @@ namespace ThreatSource.Tests.Utils
);
// Assert - 验证结果在合理范围内
Console.WriteLine($"红外透过率: {transmittance:F6}");
Debug.WriteLine($"红外透过率: {transmittance:F6}");
Assert.True(transmittance >= 0.0);
Assert.True(transmittance <= 1.0);
Assert.NotEqual(0.0, transmittance); // 确保不是0
@ -94,7 +95,7 @@ namespace ThreatSource.Tests.Utils
);
// Assert - 验证结果在合理范围内
Console.WriteLine($"湍流效应: {turbulenceEffect:F6}");
Debug.WriteLine($"湍流效应: {turbulenceEffect:F6}");
Assert.True(turbulenceEffect >= 0.0);
Assert.True(turbulenceEffect <= 1.0);
Assert.NotEqual(0.0, turbulenceEffect); // 确保不是0
@ -115,7 +116,7 @@ namespace ThreatSource.Tests.Utils
);
// Assert - 验证结果在合理范围内
Console.WriteLine($"烟幕透过率: {smokeTransmittance:F6}");
Debug.WriteLine($"烟幕透过率: {smokeTransmittance:F6}");
Assert.True(smokeTransmittance >= 0.0);
Assert.True(smokeTransmittance <= 1.0);
}
@ -163,9 +164,9 @@ namespace ThreatSource.Tests.Utils
distance * 1000, radiationType, wavelength, rainyWeather); // 转换为米
// Assert - 验证不同天气条件对透过率有影响
Console.WriteLine($"晴天透过率: {clearTransmittance:F6}");
Console.WriteLine($"雾天透过率: {foggyTransmittance:F6}");
Console.WriteLine($"雨天透过率: {rainyTransmittance:F6}");
Debug.WriteLine($"晴天透过率: {clearTransmittance:F6}");
Debug.WriteLine($"雾天透过率: {foggyTransmittance:F6}");
Debug.WriteLine($"雨天透过率: {rainyTransmittance:F6}");
// 验证所有值在有效范围内
Assert.True(clearTransmittance >= 0.0 && clearTransmittance <= 1.0);

View File

@ -2,6 +2,7 @@ using System.IO;
using Tomlyn;
using Tomlyn.Model; // Required for TomlModelOptions
using System;
using System.Diagnostics;
// No longer need Tomlyn.Syntax for exceptions if ConvertTo is removed
namespace ThreatSource.Data
@ -66,7 +67,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"导弹数据目录不存在:{path}");
Trace.TraceError($"导弹数据目录不存在:{path}");
return;
}
@ -88,8 +89,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载导弹数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载导弹数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
@ -101,7 +102,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"指示器数据目录不存在:{path}");
Trace.TraceError($"指示器数据目录不存在:{path}");
return;
}
@ -119,8 +120,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载指示器数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载指示器数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
@ -132,7 +133,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"传感器数据目录不存在:{path}");
Trace.TraceError($"传感器数据目录不存在:{path}");
return;
}
@ -150,8 +151,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载传感器数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载传感器数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
@ -163,7 +164,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"目标数据目录不存在:{path}");
Trace.TraceError($"目标数据目录不存在:{path}");
return;
}
@ -181,8 +182,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载目标数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载目标数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
@ -195,7 +196,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"天气数据目录不存在:{path}");
Trace.TraceError($"天气数据目录不存在:{path}");
return;
}
@ -213,8 +214,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载天气数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载天气数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
@ -226,7 +227,7 @@ namespace ThreatSource.Data
{
if (!Directory.Exists(path))
{
Console.WriteLine($"干扰机数据目录不存在:{path}");
Trace.TraceError($"干扰机数据目录不存在:{path}");
return;
}
@ -244,8 +245,8 @@ namespace ThreatSource.Data
}
catch (Exception ex)
{
Console.WriteLine($"加载干扰机数据文件失败:{file},错误:{ex.Message}");
Console.WriteLine($"异常堆栈:{ex.StackTrace}");
Trace.TraceError($"加载干扰机数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}

View File

@ -331,7 +331,7 @@ namespace ThreatSource.Guidance
if (parameters.Mode == JammingMode.Blocking)
{
HasGuidance = false; // 硬干扰立即停止制导
Trace.WriteLine($"[{this.GetType().Name}] 硬干扰已应用: {parameters.Type}");
Trace.TraceInformation($"[{this.GetType().Name}] 硬干扰已应用: {parameters.Type}");
}
}
@ -345,7 +345,7 @@ namespace ThreatSource.Guidance
if (!_jammingComponent.IsJammed)
{
HasGuidance = true;
Trace.WriteLine($"[{GetType().Name}] 所有干扰已清除。");
Trace.TraceInformation($"[{GetType().Name}] 所有干扰已清除。");
}
}

View File

@ -4,7 +4,8 @@ using ThreatSource.Equipment;
using ThreatSource.Utils;
using AirTransmission;
using ThreatSource.Jammer; // 添加引用
using ThreatSource.Simulation; // Add Simulation namespace
using ThreatSource.Simulation;
using System.Diagnostics; // Add Simulation namespace
namespace ThreatSource.Guidance
{
@ -101,7 +102,7 @@ namespace ThreatSource.Guidance
// 计算视线方向
forward = (targetPosition - missilePosition).Normalize();
Console.WriteLine($"视线方向: {forward}");
Debug.WriteLine($"视线方向: {forward}");
// 选择合适的上方向
Vector3D worldUp = Math.Abs(Vector3D.DotProduct(forward, Vector3D.UnitZ)) > 0.99
@ -129,7 +130,7 @@ namespace ThreatSource.Guidance
double angleX = Math.Atan2(x, z);
double angleY = Math.Atan2(y, z);
Console.WriteLine($"投影角度: X={angleX:F6} 弧度, Y={angleY:F6} 弧度");
Debug.WriteLine($"投影角度: X={angleX:F6} 弧度, Y={angleY:F6} 弧度");
return (angleX, angleY);
}
@ -207,7 +208,7 @@ namespace ThreatSource.Guidance
if (smokeCenterX < -imageWidth/4 || smokeCenterX >= imageWidth*1.25 ||
smokeCenterY < -imageHeight/4 || smokeCenterY >= imageHeight*1.25)
{
Console.WriteLine($"烟幕 {smoke.Id} 投影中心 ({smokeCenterX}, {smokeCenterY}) 远离图像范围,跳过");
Debug.WriteLine($"烟幕 {smoke.Id} 投影中心 ({smokeCenterX}, {smokeCenterY}) 远离图像范围,跳过");
continue;
}
@ -227,7 +228,7 @@ namespace ThreatSource.Guidance
double wallHeight = smoke.config.WallHeight; // Y轴上的高度
double wallThickness = smoke.config.Thickness; // X轴上的厚度
Console.WriteLine($"烟幕墙朝向: {smokeForward}, 与视线夹角: {angleToViewLine * 180 / Math.PI:F2}度");
Debug.WriteLine($"烟幕墙朝向: {smokeForward}, 与视线夹角: {angleToViewLine * 180 / Math.PI:F2}度");
// 计算墙面的有效投影宽度(考虑朝向)
// 当墙面垂直于视线时,宽度投影最大;平行时,宽度投影最小
@ -237,7 +238,7 @@ namespace ThreatSource.Guidance
int pixelWidth = (int)Math.Max(minPixelSize, (effectiveWidth / distance) * imageWidth / fieldOfView);
int pixelHeight = (int)Math.Max(minPixelSize, (wallHeight / distance) * imageHeight / fieldOfView);
Console.WriteLine($"烟幕墙实际宽度: {wallWidth}m, 有效投影宽度: {effectiveWidth:F2}m");
Debug.WriteLine($"烟幕墙实际宽度: {wallWidth}m, 有效投影宽度: {effectiveWidth:F2}m");
int halfPixelWidth = pixelWidth / 2;
int halfPixelHeight = pixelHeight / 2;
@ -256,7 +257,7 @@ namespace ThreatSource.Guidance
smokeIntensityLayer[y, x] = Math.Max(smokeIntensityLayer[y, x], smokeIntensity);
}
}
Console.WriteLine($"记录遮蔽烟幕(Wall): 中心({smokeCenterX},{smokeCenterY}), 尺寸{pixelWidth}x{pixelHeight}px, 强度{smokeIntensity:F6}");
Debug.WriteLine($"记录遮蔽烟幕(Wall): 中心({smokeCenterX},{smokeCenterY}), 尺寸{pixelWidth}x{pixelHeight}px, 强度{smokeIntensity:F6}");
break;
case SmokeScreenType.Cloud:
@ -285,7 +286,7 @@ namespace ThreatSource.Guidance
}
}
}
Console.WriteLine($"记录遮蔽烟幕(Cloud): 中心({smokeCenterX},{smokeCenterY}), 半径{pixelRadius}px, 强度{smokeIntensity:F6}");
Debug.WriteLine($"记录遮蔽烟幕(Cloud): 中心({smokeCenterX},{smokeCenterY}), 半径{pixelRadius}px, 强度{smokeIntensity:F6}");
break;
}
}
@ -348,11 +349,11 @@ namespace ThreatSource.Guidance
pixelLength = Math.Max(1, pixelLength);
pixelWidth = Math.Max(1, pixelWidth);
Console.WriteLine($"生成目标 {target.Id} 的图像,尺寸: {pixelLength}x{pixelWidth} 像素,目标中心: ({centerX}, {centerY})");
Debug.WriteLine($"生成目标 {target.Id} 的图像,尺寸: {pixelLength}x{pixelWidth} 像素,目标中心: ({centerX}, {centerY})");
// 计算大气和衰减型烟幕的总透过率
double transmittance = CalculateAtmosphericTransmittance(distance, simulationManager.CurrentWeather, smokeAttenuation);
Console.WriteLine($"大气及衰减烟幕透过率: {transmittance},烟幕衰减: {smokeAttenuation}");
Debug.WriteLine($"大气及衰减烟幕透过率: {transmittance},烟幕衰减: {smokeAttenuation}");
// 生成目标图像强度,考虑遮蔽烟幕覆盖
GenerateTargetIntensity(image, smokeIntensityLayer, centerX, centerY, pixelLength, pixelWidth, target, distance, transmittance);
@ -392,7 +393,7 @@ namespace ThreatSource.Guidance
double[,] thermalPattern = target.GetCurrentThermalPattern();
if (thermalPattern == null)
{
Console.WriteLine($"警告: 目标 {target.Id} 未提供 ThermalPattern无法生成基于模式的强度。");
Trace.TraceError($"警告: 目标 {target.Id} 未提供 ThermalPattern无法生成基于模式的强度。");
return;
}
@ -441,7 +442,7 @@ namespace ThreatSource.Guidance
// 计算烟幕覆盖率
double smokeCoverageRatio = totalTargetPixels > 0 ? (double)smokeCoveredPixels / totalTargetPixels : 0.0;
Console.WriteLine($"Blob {target.Id} 烟幕覆盖率: {smokeCoverageRatio:P2} ({smokeCoveredPixels}/{totalTargetPixels})");
Debug.WriteLine($"Blob {target.Id} 烟幕覆盖率: {smokeCoverageRatio:P2} ({smokeCoveredPixels}/{totalTargetPixels})");
// 第二遍:根据覆盖率调整目标亮度
// 遍历目标在图像中的包围盒
@ -511,7 +512,7 @@ namespace ThreatSource.Guidance
}
}
Console.WriteLine($"目标基于ThermalPattern强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
Debug.WriteLine($"目标基于ThermalPattern强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
}
/// <summary>

View File

@ -261,7 +261,7 @@ namespace ThreatSource.Guidance
{
HasGuidance = false;
// 切换回搜索模式
Console.WriteLine($"Target lost for {targetLostTimer:F3}s, switching back to search mode");
Debug.WriteLine($"目标丢失 {targetLostTimer:F3}s, 切换回搜索模式");
SwitchToSearchMode();
}
}
@ -302,7 +302,7 @@ namespace ThreatSource.Guidance
backgroundIntensity: config.BackgroundIntensity,
wavelength: config.Wavelength
);
Console.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView * 180 / Math.PI} 度");
Debug.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView * 180 / Math.PI} 度");
}
/// <summary>
@ -327,7 +327,7 @@ namespace ThreatSource.Guidance
backgroundIntensity: config.BackgroundIntensity,
wavelength: config.Wavelength
);
Console.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView * 180 / Math.PI} 度");
Debug.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView * 180 / Math.PI} 度");
}
/// <summary>
@ -342,7 +342,7 @@ namespace ThreatSource.Guidance
public void SwitchToLockMode()
{
currentMode = WorkMode.Lock;
Console.WriteLine("Switched to lock mode - target type confirmed");
Debug.WriteLine("切换到锁定模式 - 目标类型确认");
}
/// <summary>
@ -388,7 +388,7 @@ namespace ThreatSource.Guidance
bool isTargetGeometricallyObscured = CheckIfTargetObscuredBySmoke(missilePosition, target);
if (isTargetGeometricallyObscured)
{
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕几何遮挡,跳过图像生成");
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕几何遮挡,跳过图像生成");
continue; // 如果目标被完全遮挡,跳过此目标
}
@ -518,18 +518,18 @@ namespace ThreatSource.Guidance
targetCenter, targetDims, targetOrient // 目标数据(背景)
);
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡比例: {overlapRatio:P2}");
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡比例: {overlapRatio:P2}");
// 如果任何一个烟幕的遮挡比例超过阈值,则认为目标被遮挡
if (overlapRatio >= ObscurationThreshold)
{
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡超过阈值 {ObscurationThreshold:P0},视为完全遮挡");
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡超过阈值 {ObscurationThreshold:P0},视为完全遮挡");
return true;
}
}
catch (Exception ex)
{
Console.WriteLine($"[红外成像制导系统] 计算烟幕遮挡时出错: {ex.Message}");
Debug.WriteLine($"[红外成像制导系统] 计算烟幕遮挡时出错: {ex.Message}");
}
}

View File

@ -1,4 +1,5 @@
using ThreatSource.Equipment;
using System.Diagnostics;
using ThreatSource.Simulation;
using System.Collections.Generic; // For Queue and List
using System.Linq; // For OrderByDescending
@ -104,7 +105,7 @@ namespace ThreatSource.Guidance
var segment = SegmentTarget(image);
if (!segment.IsValid)
{
Console.WriteLine("没有有效的分割区域");
Debug.WriteLine("没有有效的分割区域");
return new RecognitionResult(EquipmentType.Unknown, 0.0, (0, 0), (0, 0));
}
@ -113,17 +114,17 @@ namespace ThreatSource.Guidance
int minRequiredHeight = 5;
if (segment.Size.Width < minRequiredWidth && segment.Size.Height < minRequiredHeight)
{
Console.WriteLine($"目标区域过小: {segment.Size.Width}x{segment.Size.Height} 像素,低于最小要求 {minRequiredWidth}x{minRequiredHeight}");
Debug.WriteLine($"目标区域过小: {segment.Size.Width}x{segment.Size.Height} 像素,低于最小要求 {minRequiredWidth}x{minRequiredHeight}");
return new RecognitionResult(EquipmentType.Unknown, 0.0, segment.Center, segment.Size);
}
// 提取目标特征
var features = ExtractFeatures(image, segment, target);
Console.WriteLine($"提取的特征: 长宽比={features.AspectRatio:F2}, 尺寸={features.Size:F2}, 强度模式={features.IntensityPattern:F2}, 温度梯度={features.TemperatureGradient:F2}");
Debug.WriteLine($"提取的特征: 长宽比={features.AspectRatio:F2}, 尺寸={features.Size:F2}, 强度模式={features.IntensityPattern:F2}, 温度梯度={features.TemperatureGradient:F2}");
// 特征匹配和分类
var (type, confidence) = ClassifyTarget(features);
Console.WriteLine($"分类结果: 类型={type}, 置信度={confidence:F2}");
Debug.WriteLine($"分类结果: 类型={type}, 置信度={confidence:F2}");
// 返回识别结果
return new RecognitionResult(
@ -146,7 +147,7 @@ namespace ThreatSource.Guidance
List<Blob> blobs = new List<Blob>();
Queue<(int x, int y)> queue = new Queue<(int x, int y)>();
Console.WriteLine($"开始连通区域分析,阈值: {threshold:F6}");
Debug.WriteLine($"开始连通区域分析,阈值: {threshold:F6}");
// 1. 查找所有连通区域 (Blobs)
for (int y = 0; y < height; y++)
@ -195,12 +196,12 @@ namespace ThreatSource.Guidance
}
}
blobs.Add(currentBlob);
Console.WriteLine($" 发现 Blob {currentBlob.Label}: 面积={currentBlob.Area}, 边界=({currentBlob.MinX},{currentBlob.MinY})-({currentBlob.MaxX},{currentBlob.MaxY})");
Debug.WriteLine($" 发现 Blob {currentBlob.Label}: 面积={currentBlob.Area}, 边界=({currentBlob.MinX},{currentBlob.MinY})-({currentBlob.MaxX},{currentBlob.MaxY})");
}
}
}
Console.WriteLine($"发现 {blobs.Count} 个 Blobs");
Debug.WriteLine($"发现 {blobs.Count} 个 Blobs");
// 2. 过滤 Blobs
List<Blob> filteredBlobs = new List<Blob>();
@ -213,7 +214,7 @@ namespace ThreatSource.Guidance
// 检查面积
if (blob.Area < minArea || blob.Area > maxArea)
{
Console.WriteLine($" Blob {blob.Label} 因面积 ({blob.Area}) 不符被过滤 (允许范围: {minArea}-{maxArea})");
Debug.WriteLine($" Blob {blob.Label} 因面积 ({blob.Area}) 不符被过滤 (允许范围: {minArea}-{maxArea})");
continue;
}
@ -239,29 +240,29 @@ namespace ThreatSource.Guidance
if (totalPixelsInBox > 0)
{
double smokeCoverageRatio = (double)smokeCoveredPixelsInBox / totalPixelsInBox;
Console.WriteLine($" Blob {blob.Label} 烟幕覆盖率: {smokeCoverageRatio:P2} ({smokeCoveredPixelsInBox}/{totalPixelsInBox})");
Debug.WriteLine($" Blob {blob.Label} 烟幕覆盖率: {smokeCoverageRatio:P2} ({smokeCoveredPixelsInBox}/{totalPixelsInBox})");
if (smokeCoverageRatio >= SMOKE_COVERAGE_THRESHOLD)
{
Console.WriteLine($" Blob {blob.Label} 因烟幕覆盖率过高被过滤");
Debug.WriteLine($" Blob {blob.Label} 因烟幕覆盖率过高被过滤");
continue;
}
}
// 通过所有检查,添加到过滤后的列表
filteredBlobs.Add(blob);
Console.WriteLine($" Blob {blob.Label} 通过过滤");
Debug.WriteLine($" Blob {blob.Label} 通过过滤");
}
// 3. 选择最佳 Blob
if (filteredBlobs.Count == 0)
{
Console.WriteLine("没有找到有效的 Blob");
Debug.WriteLine("没有找到有效的 Blob");
return new ImageSegment(); // 返回无效分割
}
// 选择面积最大的 Blob 作为目标
Blob targetBlob = filteredBlobs.OrderByDescending(b => b.Area).First();
Console.WriteLine($"选择 Blob {targetBlob.Label} 作为目标 (面积: {targetBlob.Area})");
Debug.WriteLine($"选择 Blob {targetBlob.Label} 作为目标 (面积: {targetBlob.Area})");
// 4. 返回基于选定 Blob 的 ImageSegment
return new ImageSegment(
@ -300,7 +301,7 @@ namespace ThreatSource.Guidance
// Handle case where image is entirely black or has no valid pixels
if (count == 0 || maxIntensity <= minIntensity)
{
Console.WriteLine("图像全黑或无有效强度信息无法计算阈值返回0");
Debug.WriteLine("图像全黑或无有效强度信息无法计算阈值返回0");
return 0; // Or handle appropriately
}
@ -313,13 +314,13 @@ namespace ThreatSource.Guidance
double threshold = minIntensity + dynamicRange * thresholdFactor;
Console.WriteLine($"图像统计:");
Console.WriteLine($" 最大强度: {maxIntensity:F6}");
Console.WriteLine($" 最小强度: {minIntensity:F6}");
Console.WriteLine($" 平均强度: {mean:F6}");
Console.WriteLine($" 动态范围: {dynamicRange:F6}");
Console.WriteLine($" 动态阈值因子: {thresholdFactor:P1}");
Console.WriteLine($" 最终阈值: {threshold:F6}");
Debug.WriteLine($"图像统计:");
Debug.WriteLine($" 最大强度: {maxIntensity:F6}");
Debug.WriteLine($" 最小强度: {minIntensity:F6}");
Debug.WriteLine($" 平均强度: {mean:F6}");
Debug.WriteLine($" 动态范围: {dynamicRange:F6}");
Debug.WriteLine($" 动态阈值因子: {thresholdFactor:P1}");
Debug.WriteLine($" 最终阈值: {threshold:F6}");
return threshold;
}
@ -396,27 +397,7 @@ namespace ThreatSource.Guidance
/// </summary>
private double CalculateTemperatureGradient(InfraredImage image, ImageSegment segment, IEquipment target)
{
// -- 移除直接从目标获取理想温度分布数据的逻辑 --
// double[,] thermalPattern = target.GetCurrentThermalPattern(); // 错误:这会绕过烟幕遮蔽效果
// if (thermalPattern == null)
// {
// Console.WriteLine("没有温度分布数据, 使用图像计算梯度");
// return CalculateImageBasedGradient(image, segment);
// }
//
// var pattern = new ThermalPattern(thermalPattern, thermalPattern);
//
// // 判断目标是否在运动 (这个判断可能仍然有用,但基于图像的梯度计算目前不使用它)
// bool isMoving = IsTargetMoving(image, segment);
// Console.WriteLine($"目标运动状态: {(isMoving ? "移动" : "静止")}");
//
// // 使用理想温度分布模式计算梯度特征 (错误)
// double gradientFeature = pattern.CalculateGradientFeature(isMoving);
//
// return gradientFeature;
// **修正:始终基于传入的红外图像计算梯度特征**
Console.WriteLine("计算基于图像的温度梯度特征");
Debug.WriteLine("计算基于图像的温度梯度特征");
return CalculateImageBasedGradient(image, segment);
}
@ -643,7 +624,7 @@ namespace ThreatSource.Guidance
foreach (var kvp in targetFeatures)
{
double score = CalculateMatchScore(features, kvp.Value, weights);
Console.WriteLine($"匹配得分: {kvp.Key}: {score:F2}");
Debug.WriteLine($"匹配得分: {kvp.Key}: {score:F2}");
if (score > bestScore)
{
bestScore = score;
@ -653,7 +634,7 @@ namespace ThreatSource.Guidance
// 使用自适应阈值
double threshold = CalculateAdaptiveThreshold(features);
Console.WriteLine($"自适应阈值: {threshold:F2}");
Debug.WriteLine($"自适应阈值: {threshold:F2}");
return bestScore > threshold ?
(bestMatch, bestScore) :
@ -708,11 +689,11 @@ namespace ThreatSource.Guidance
double gradientScore = 1 - Math.Min(1, Math.Abs(features.TemperatureGradient - template.TemperatureGradient));
// 输出详细的匹配分数
Console.WriteLine($"特征匹配得分:");
Console.WriteLine($" 长宽比: {aspectRatioScore:F2} (权重: {weights[0]:F2})");
Console.WriteLine($" 尺寸: {sizeScore:F2} (权重: {weights[1]:F2})");
Console.WriteLine($" 模式: {patternScore:F2} (权重: {weights[2]:F2})");
Console.WriteLine($" 梯度: {gradientScore:F2} (权重: {weights[3]:F2})");
Debug.WriteLine($"特征匹配得分:");
Debug.WriteLine($" 长宽比: {aspectRatioScore:F2} (权重: {weights[0]:F2})");
Debug.WriteLine($" 尺寸: {sizeScore:F2} (权重: {weights[1]:F2})");
Debug.WriteLine($" 模式: {patternScore:F2} (权重: {weights[2]:F2})");
Debug.WriteLine($" 梯度: {gradientScore:F2} (权重: {weights[3]:F2})");
// 加权平均
double totalScore = aspectRatioScore * weights[0] +
@ -720,7 +701,7 @@ namespace ThreatSource.Guidance
patternScore * weights[2] +
gradientScore * weights[3];
Console.WriteLine($" 总得分: {totalScore:F2}");
Debug.WriteLine($" 总得分: {totalScore:F2}");
return totalScore;
}

View File

@ -391,7 +391,7 @@ namespace ThreatSource.Guidance
if (LaserSourcePosition == null)
{
HasGuidance = false;
Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 激光源位置未知");
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 激光源位置未知");
return;
}
@ -401,7 +401,7 @@ namespace ThreatSource.Guidance
if (shortestDistance > config.ControlFieldDiameter / 2)
{
HasGuidance = false;
Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance}");
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance}");
return;
}
@ -420,7 +420,7 @@ namespace ThreatSource.Guidance
else
{
HasGuidance = false;
Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 接收到的激光功率低于最小可探测功率,{LaserPower:E} W/{receivedPower:E} W");
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 接收到的激光功率低于最小可探测功率,{LaserPower:E} W/{receivedPower:E} W");
}
}

View File

@ -220,7 +220,7 @@ namespace ThreatSource.Guidance
{
if (evt?.LaserDesignatorId == null || evt?.TargetId == null || evt?.SpotPosition == null)
{
Console.WriteLine("接收到无效的激光照射更新事件");
Trace.TraceInformation("接收到无效的激光照射更新事件");
return;
}
@ -230,19 +230,19 @@ namespace ThreatSource.Guidance
if (!CheckLaserCode(evt.LaserCodeConfig)) // 使用辅助方法检查编码
{
PublishCodeMismatchEvent(evt.LaserDesignatorId, evt.LaserCodeConfig);
Console.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 接收到编码不匹配的激光照射事件,忽略。预期: {InternalLaserCodeConfig}, 收到: {evt.LaserCodeConfig}");
Trace.TraceInformation($"[LASER_SEMI_ACTIVE] {Id} 接收到编码不匹配的激光照射事件,忽略。预期: {InternalLaserCodeConfig}, 收到: {evt.LaserCodeConfig}");
// 编码不匹配,不处理此事件,也不设置 LaserIlluminationOn
return;
}
Console.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 激光编码匹配。");
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 激光编码匹配。");
}
else
{
Console.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 未配置编码检查或不要求匹配。");
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 未配置编码检查或不要求匹配。");
}
// 2. 编码匹配或无需检查,处理事件
Console.WriteLine($"[LASER_SEMI_ACTIVE] 处理激光照射更新事件: 指示器ID: {evt.LaserDesignatorId}, 目标ID: {evt.TargetId}");
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 处理激光照射更新事件: 指示器ID: {evt.LaserDesignatorId}, 目标ID: {evt.TargetId}");
try
{
LaserDesignator laserDesignator = SimulationManager.GetEntityById(evt.LaserDesignatorId) as LaserDesignator ?? throw new Exception("激光指示器不存在");
@ -261,7 +261,7 @@ namespace ThreatSource.Guidance
}
catch (Exception ex)
{
Console.WriteLine($"处理激光照射更新事件时出错: {ex.Message}");
Trace.TraceError($"处理激光照射更新事件时出错: {ex.Message}");
}
}
@ -304,7 +304,7 @@ namespace ThreatSource.Guidance
}
else if (parameters.Type == JammingType.LaserDecoy)
{
Console.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光诱偏干扰。JammerId: {parameters.JammerId}, SourceId: {parameters.SourceId}");
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光诱偏干扰。JammerId: {parameters.JammerId}, SourceId: {parameters.SourceId}");
if (parameters.JammerId != null && parameters.SourceId != null)
{
LaserDecoy decoyTarget = SimulationManager.GetEntityById(parameters.JammerId) as LaserDecoy ?? throw new Exception("诱偏目标不存在");
@ -313,7 +313,7 @@ namespace ThreatSource.Guidance
if (!laserTargets.Any(t => t.Target.Id == decoyTarget.Id))
{
laserTargets.Add((decoyTarget, decoyTarget.KState.Position, decoySource));
Console.WriteLine($"[LASER_SEMI_ACTIVE] 诱偏目标添加到激光目标列表。当前激光目标数量: {laserTargets.Count}");
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 诱偏目标添加到激光目标列表。当前激光目标数量: {laserTargets.Count}");
}
}
}
@ -416,7 +416,7 @@ namespace ThreatSource.Guidance
{
try
{
Console.WriteLine($"处理激光信号: 激光目标数量={laserTargets.Count}");
Debug.WriteLine($"处理激光信号: 激光目标数量={laserTargets.Count}");
// 如果没有激光源,返回
if (laserTargets.Count == 0)
@ -435,7 +435,7 @@ namespace ThreatSource.Guidance
double angleDeviation = CalculateAngleDeviation(target.SpotPosition);
if (angleDeviation > config.FieldOfViewAngleInRadians / 2)
{
Console.WriteLine($"处理激光信号: 目标超出视野范围目标ID: {target.Target.Id}, 角度偏差: {angleDeviation:F2}弧度, 视野范围: {config.FieldOfViewAngleInRadians:F2}弧度");
Debug.WriteLine($"处理激光信号: 目标超出视野范围目标ID: {target.Target.Id}, 角度偏差: {angleDeviation:F2}弧度, 视野范围: {config.FieldOfViewAngleInRadians:F2}弧度");
continue; // 目标超出视野范围
}
@ -444,13 +444,13 @@ namespace ThreatSource.Guidance
{
// 计算接收功率
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, decoy.config.Power, decoy.config.DivergenceAngle);
Console.WriteLine($"处理激光信号: 诱偏目标接收功率={receivedPower:E}W, 诱偏目标ID: {target.Target.Id}, 诱偏目标位置: {target.SpotPosition}");
Debug.WriteLine($"处理激光信号: 诱偏目标接收功率={receivedPower:E}W, 诱偏目标ID: {target.Target.Id}, 诱偏目标位置: {target.SpotPosition}");
}
else if (target.Source is LaserDesignator laserDesignator)
{
// 计算接收功率
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, laserDesignator.config.Power, laserDesignator.config.DivergenceAngle);
Console.WriteLine($"处理激光信号: 真实目标接收功率={receivedPower:E}W, 真实目标ID: {target.Target.Id}, 真实目标位置: {target.SpotPosition}");
Debug.WriteLine($"处理激光信号: 真实目标接收功率={receivedPower:E}W, 真实目标ID: {target.Target.Id}, 真实目标位置: {target.SpotPosition}");
}
// 累加功率
@ -458,7 +458,7 @@ namespace ThreatSource.Guidance
// 加权位置
weightedPosition += target.SpotPosition * receivedPower;
Console.WriteLine($"处理激光信号: 累加功率={ReceivedLaserPower:E}W, 加权位置={weightedPosition}");
Debug.WriteLine($"处理激光信号: 累加功率={ReceivedLaserPower:E}W, 加权位置={weightedPosition}");
}
// 如果总功率为0表示没有在视野范围内的激光源
@ -471,7 +471,7 @@ namespace ThreatSource.Guidance
// 计算加权平均位置
TargetPosition = weightedPosition / ReceivedLaserPower;
Console.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E}W, 加权平均目标位置={TargetPosition}");
Debug.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E}W, 加权平均目标位置={TargetPosition}");
// 更新激光照射参数
LaserIlluminationOn = true;
@ -485,7 +485,7 @@ namespace ThreatSource.Guidance
}
catch (Exception ex)
{
Trace.WriteLine($"处理激光信号时出错: {ex.Message}");
Trace.TraceError($"处理激光信号时出错: {ex.Message}");
}
}
@ -540,7 +540,7 @@ namespace ThreatSource.Guidance
double lensArea = Math.PI * Math.Pow(config.LensDiameter / 2, 2);
double finalReceivedPower = powerDensityAtMissileAperture * lensArea * config.ReceiverEfficiency;
Console.WriteLine($"激光功率计算: S2T D={distanceSourceToTarget:F1}m (Path1 T={totalTransmittance_S2T:F3}), " +
Debug.WriteLine($"激光功率计算: S2T D={distanceSourceToTarget:F1}m (Path1 T={totalTransmittance_S2T:F3}), " +
$"T2M D={distanceTargetToMissile:F1}m (Path2 T={totalTransmittance_T2M:F3}), " +
$"最终功率={finalReceivedPower:E}W");

View File

@ -172,7 +172,7 @@ namespace ThreatSource.Guidance
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
LastTargetPosition = null;
LastTargetVelocity = null;
Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
Trace.TraceInformation($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
}
/// <summary>
@ -183,7 +183,7 @@ namespace ThreatSource.Guidance
currentMode = WorkMode.Track;
lockConfirmationTimer = 0;
HasGuidance = true;
Trace.WriteLine($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
Trace.TraceInformation($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
}
/// <summary>
@ -193,7 +193,7 @@ namespace ThreatSource.Guidance
{
currentMode = WorkMode.Lock;
HasGuidance = true;
Trace.WriteLine("切换到锁定模式 - 目标锁定成功");
Trace.TraceInformation("切换到锁定模式 - 目标锁定成功");
}
/// <summary>
@ -322,7 +322,7 @@ namespace ThreatSource.Guidance
currentScanAngle -= 2 * Math.PI;
}
Console.WriteLine($"扫描参数 - 半径: {currentScanRadius * 180/Math.PI:F2}度, 角度: {currentScanAngle * 180/Math.PI:F2}度");
Debug.WriteLine($"扫描参数 - 半径: {currentScanRadius * 180/Math.PI:F2}度, 角度: {currentScanAngle * 180/Math.PI:F2}度");
}
else
{
@ -419,14 +419,14 @@ namespace ThreatSource.Guidance
).Normalize();
// 调试输出
Console.WriteLine($"导弹前进方向: {xAxis}");
Console.WriteLine($"目标方向: {toTarget.Normalize()}");
Console.WriteLine($"扫描方向: {scanDirection}");
Debug.WriteLine($"导弹前进方向: {xAxis}");
Debug.WriteLine($"目标方向: {toTarget.Normalize()}");
Debug.WriteLine($"扫描方向: {scanDirection}");
// 计算目标夹角
double angle = Vector3D.AngleBetween(scanDirection, toTarget.Normalize());
Console.WriteLine($"目标夹角: {angle * 180/Math.PI:F2}度");
Console.WriteLine($"波束宽度: {currentBeamWidth * 180/Math.PI:F2}度SNR阈值: {config.RecognitionSNRThreshold}dB");
Debug.WriteLine($"目标夹角: {angle * 180/Math.PI:F2}度");
Debug.WriteLine($"波束宽度: {currentBeamWidth * 180/Math.PI:F2}度SNR阈值: {config.RecognitionSNRThreshold}dB");
return angle <= currentBeamWidth;
}
@ -434,8 +434,8 @@ namespace ThreatSource.Guidance
{
// 跟踪/锁定模式使用单脉冲测角
var (azError, elError) = ProcessMonopulse(toTarget.Normalize(), missileVelocity);
Console.WriteLine($"[单脉冲测角] 方位误差: {azError * 180/Math.PI:F3}度, 俯仰误差: {elError * 180/Math.PI:F3}度");
Console.WriteLine($"[波束宽度检查] 当前阈值: {currentBeamWidth * 180/Math.PI:F3}度,实际误差: {Math.Sqrt(azError*azError + elError*elError) * 180/Math.PI:F3}度");
Debug.WriteLine($"[单脉冲测角] 方位误差: {azError * 180/Math.PI:F3}度, 俯仰误差: {elError * 180/Math.PI:F3}度");
Debug.WriteLine($"[波束宽度检查] 当前阈值: {currentBeamWidth * 180/Math.PI:F3}度,实际误差: {Math.Sqrt(azError*azError + elError*elError) * 180/Math.PI:F3}度");
return Math.Sqrt(azError*azError + elError*elError) < currentBeamWidth;
}
}
@ -496,7 +496,7 @@ namespace ThreatSource.Guidance
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
}
Console.WriteLine($"制导加速度: {GuidanceAcceleration}");
Debug.WriteLine($"制导加速度: {GuidanceAcceleration}");
HasGuidance = true;
}
else
@ -507,7 +507,7 @@ namespace ThreatSource.Guidance
if (targetLostTimer >= config.TargetLostTolerance)
{
HasGuidance = false;
Trace.WriteLine($"目标丢失 {targetLostTimer:F3}秒,切换回搜索模式");
Trace.TraceInformation($"目标丢失 {targetLostTimer:F3}秒,切换回搜索模式");
SwitchToSearchMode();
}
}
@ -736,7 +736,7 @@ namespace ThreatSource.Guidance
if (snr_linear <= 0) return -100.0;
double snr_dB_no_smoke = 10 * Math.Log10(snr_linear);
Console.WriteLine($"[SNR_CALC] SNR_dB (before smoke): {snr_dB_no_smoke:F2} dB. Incoming SmokeTransmittance_Linear: {smokeTransmittanceLinear:F6}");
Debug.WriteLine($"[SNR计算] SNR_dB (烟幕前): {snr_dB_no_smoke:F2} dB. Incoming SmokeTransmittance_Linear: {smokeTransmittanceLinear:F6}");
// 应用当前生效的烟幕衰减 (通过存储的透过率) - REMOVED _currentSmokeTransmittance FIELD USAGE
// signalPower *= _currentSmokeTransmittance; // This line is now handled by the parameter
@ -744,7 +744,7 @@ namespace ThreatSource.Guidance
// 应用烟幕透过率 (smokeTransmittanceLinear is already linear 0-1)
if (smokeTransmittanceLinear <= 0.000001) // Threshold to prevent log(0) or very large negative numbers
{
Console.WriteLine($"[SNR_CALC] Smoke transmittance too low. Final_SNR_dB: -100.0 dB");
Debug.WriteLine($"[SNR计算] 烟幕透过率太低. Final_SNR_dB: -100.0 dB");
return -100.0; // Effectively zero signal due to smoke
}
@ -752,7 +752,7 @@ namespace ThreatSource.Guidance
// SNR_final_dB = SNR_original_dB - Loss_smoke_dB = SNR_original_dB + 10 * log10(T_smoke_linear)
double smokeEffect_dB = 10 * Math.Log10(smokeTransmittanceLinear);
double final_snr_dB = snr_dB_no_smoke + smokeEffect_dB;
Console.WriteLine($"[SNR_CALC] SmokeEffect: {smokeEffect_dB:F2} dB. Final_SNR_dB (after smoke): {final_snr_dB:F2} dB");
Debug.WriteLine($"[SNR计算] 烟幕影响: {smokeEffect_dB:F2} dB. 最终SNR_dB (烟幕后): {final_snr_dB:F2} dB");
return final_snr_dB;
}
@ -768,7 +768,7 @@ namespace ThreatSource.Guidance
double totalTransmittance = 1.0;
if (SimulationManager == null)
{
Trace.WriteLineIf(SimulationManager == null, "[MMW_GUIDANCE] SimulationManager is null in CalculateLiveSmokeTransmittance. Assuming no smoke.", "Warning");
Trace.TraceWarning("[毫米波制导] 仿真管理器是 null, 假设没有烟幕.");
return 1.0;
}
@ -784,7 +784,7 @@ namespace ThreatSource.Guidance
double wavelength_um = SpeedOfLight / config.WaveFrequency * 1e6;
if (wavelength_um <= 0) {
Trace.WriteLine("[MMW_GUIDANCE] Calculated wavelength in meters is invalid in CalculateLiveSmokeTransmittance. Assuming no smoke effect.", "Error");
Trace.TraceInformation("[毫米波制导] 计算波长为米时无效. 假设没有烟幕影响.");
return 1.0;
}
@ -793,7 +793,7 @@ namespace ThreatSource.Guidance
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(observerPosition, targetEndPosition, wavelength_um);
totalTransmittance *= transmittanceForThisSmoke;
if (totalTransmittance < 0.000001) // Use a smaller threshold for early exit if transmittance is effectively zero
if (totalTransmittance < 0.000001) // 使用更小的阈值提前退出,如果透过率几乎为零
{
return 0.0;
}

View File

@ -132,7 +132,7 @@ namespace ThreatSource.Indicator
if (_lastKnownTargetPosition != null)
{
currentTargetPosition = _lastKnownTargetPosition;
Console.WriteLine($"InfraredTracker {Id}: 目标被遮挡,使用最后已知位置 {currentTargetPosition}");
Debug.WriteLine($"红外测角仪 {Id}: 目标被遮挡,使用最后已知位置 {currentTargetPosition}");
}
else
{

View File

@ -137,7 +137,7 @@ namespace ThreatSource.Indicator
KState.Orientation = new Orientation(yaw, pitch, 0);
_lastKnownTargetPosition = target.KState.Position;
Console.WriteLine($"激光指示器 {Id} 更新朝向: {KState.Orientation}, _lastKnownTargetPosition: {_lastKnownTargetPosition}");
Debug.WriteLine($"激光指示器 {Id} 更新朝向: {KState.Orientation}, _lastKnownTargetPosition: {_lastKnownTargetPosition}");
}
}
}
@ -191,7 +191,7 @@ namespace ThreatSource.Indicator
// 实现激光指示器的干扰效果
if (parameters.Type == JammingType.Laser)
{
Console.WriteLine($"[LaserDesignator] {Id} 受到激光干扰,停止照射。", "Jamming");
Debug.WriteLine($"[激光指示器] {Id} 受到激光干扰,停止照射。", "Jamming");
// 停止激光照射
StopLaserIllumination();
}
@ -208,7 +208,7 @@ namespace ThreatSource.Indicator
// 添加子类特定响应:如果是激光干扰清除,并且设备仍激活,尝试启动照射
if (parameters.Type == JammingType.Laser)
{
Console.WriteLine($"[LaserDesignator] {Id} 激光干扰已清除。", "Jamming");
Debug.WriteLine($"[激光指示器] {Id} 激光干扰已清除。", "Jamming");
// 如果设备仍处于激活状态,并且没有其他阻塞性干扰,恢复激光照射
if (IsActive && !IsBlockingJammed)
{
@ -336,7 +336,7 @@ namespace ThreatSource.Indicator
// 检查波长匹配 (单位: 微米)
if (Math.Abs((parameters.Wavelength ?? 0) - config.Wavelength) > 1e-6) // 使用配置的波长
{
Console.WriteLine($"[LaserDesignator] {Id} 忽略激光干扰:波长 {parameters.Wavelength}um 与工作波长 {config.Wavelength}um 不匹配。", "Jamming");
Debug.WriteLine($"[激光指示器] {Id} 忽略激光干扰:波长 {parameters.Wavelength}um 与工作波长 {config.Wavelength}um 不匹配。", "Jamming");
return false;
}
}

View File

@ -151,7 +151,7 @@ namespace ThreatSource.Jammable
}
else
{
Console.WriteLine($"[JammableComponent] Unsupported jamming type: {parameters.Type}");
Trace.TraceWarning($"[可干扰组件] 不支持的干扰类型: {parameters.Type}");
}
}
@ -174,7 +174,7 @@ namespace ThreatSource.Jammable
// 1. 检查是否支持该干扰类型 (这个检查保持在最前面)
if (!_supportedJammingTypes.Contains(parameters.Type))
{
Console.WriteLine($"[干扰有效性检查] 不支持的干扰类型: {parameters.Type}");
Trace.TraceWarning($"[干扰有效性检查] 不支持的干扰类型: {parameters.Type}");
return false;
}
@ -188,10 +188,10 @@ namespace ThreatSource.Jammable
{
distance = 0.1; // 设置最小距离
isDistanceNearZero = true;
Console.WriteLine($"干扰计算 - 调整近零距离为 {distance}m");
Debug.WriteLine($"干扰计算 - 调整近零距离为 {distance}m");
}
Console.WriteLine($"干扰计算 - 设备位置: {devicePosition}, 干扰源位置: {parameters.SourcePosition}");
Console.WriteLine($"干扰计算 - 相对位置: {relativePosition}, 距离: {distance:F2}m");
Debug.WriteLine($"干扰计算 - 设备位置: {devicePosition}, 干扰源位置: {parameters.SourcePosition}");
Debug.WriteLine($"干扰计算 - 相对位置: {relativePosition}, 距离: {distance:F2}m");
// 2. 选择性角度约束检查
@ -209,14 +209,14 @@ namespace ThreatSource.Jammable
if (performAngleCheck)
{
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:需要进行角度检查。");
Debug.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:需要进行角度检查。");
Vector3D jammerDirection = parameters.Direction.Normalize();
// 如果距离非常近,避免对零向量进行归一化
Vector3D jammerToDeviceDirection = !isDistanceNearZero ? relativePosition.Normalize() : Vector3D.Zero;
// 如果距离非常近,我们可能认为它总是在波束内,跳过角度比较。
if (isDistanceNearZero) {
Console.WriteLine($"干扰计算 - 距离过近,跳过角度约束比较。");
Debug.WriteLine($"干扰计算 - 距离过近,跳过角度约束比较。");
}
else // 距离不近,执行角度比较
{
@ -225,21 +225,21 @@ namespace ThreatSource.Jammable
dotProduct = Math.Max(-1.0, Math.Min(1.0, dotProduct));
double angle = Math.Acos(dotProduct); // 角度(弧度)
Console.WriteLine($"干扰计算 - 干扰器方向: {jammerDirection}, 到设备方向: {jammerToDeviceDirection}");
Console.WriteLine($"干扰计算 - 点积: {dotProduct:F2}, 夹角: {angle * 180 / Math.PI:F2} 度, 波束范围: {parameters.AngleRange:F2} 度");
Debug.WriteLine($"干扰计算 - 干扰器方向: {jammerDirection}, 到设备方向: {jammerToDeviceDirection}");
Debug.WriteLine($"干扰计算 - 点积: {dotProduct:F2}, 夹角: {angle * 180 / Math.PI:F2} 度, 波束范围: {parameters.AngleRange:F2} 度");
// AngleRange 是总锥角,与半角进行比较
if (angle > (parameters.AngleRange * Math.PI / 360.0))
{
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:超出波束角度。判定无效。");
Debug.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:超出波束角度。判定无效。");
return false; // 未通过角度约束
}
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:通过角度检查。");
Debug.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:通过角度检查。");
}
}
else
{
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:无需角度检查 (AngleRange={parameters.AngleRange})。");
Debug.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:无需角度检查 (AngleRange={parameters.AngleRange})。");
}
// 3. 针对阻塞模式的检查
@ -248,26 +248,26 @@ namespace ThreatSource.Jammable
// 对阻塞干扰进行功率阈值检查
if (!_jammingThresholds.TryGetValue(parameters.Type, out double threshold))
{
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} 未找到阈值。判定无效。");
Debug.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} 未找到阈值。判定无效。");
return false;
}
// 使用已计算的距离
double receivedPower = parameters.Power / (4 * Math.PI * distance * distance);
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} - 发射功率: {parameters.Power}W, 接收功率: {receivedPower:E6}W, 阈值: {threshold:E6}W, 距离: {distance:F2}m");
Debug.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} - 发射功率: {parameters.Power}W, 接收功率: {receivedPower:E6}W, 阈值: {threshold:E6}W, 距离: {distance:F2}m");
if (receivedPower < threshold)
{
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:接收功率低于阈值。判定无效。");
Debug.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:接收功率低于阈值。判定无效。");
return false; // 未通过功率阈值检查
}
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:通过所有检查。判定有效。");
Debug.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:通过所有检查。判定有效。");
return true; // 通过了阻塞模式的所有检查
}
else // 非阻塞模式 (Deception, Compensation, 等)
{
Console.WriteLine($"[干扰有效性检查] 非阻塞干扰 {parameters.Type}:通过检查。判定有效。");
Debug.WriteLine($"[干扰有效性检查] 非阻塞干扰 {parameters.Type}:通过检查。判定有效。");
return true; // 如果是非阻塞且通过了初步检查,则认为有效
}
}

View File

@ -99,14 +99,14 @@ namespace ThreatSource.Jammer
// 检查是否是该类型的干扰
if (JammingType != parameters.Type)
{
Console.WriteLine($"干扰器 {Id} 不支持 {parameters.Type} 类型的干扰");
Trace.TraceWarning($"干扰器 {Id} 不支持 {parameters.Type} 类型的干扰");
return;
}
// 检查当前状态是否允许启动干扰
if (State == JammerState.Fault || State == JammerState.Cooling)
{
Console.WriteLine($"干扰器 {Id} 当前状态 {State} 不允许启动干扰");
Trace.TraceWarning($"干扰器 {Id} 当前状态 {State} 不允许启动干扰");
return;
}
@ -118,7 +118,7 @@ namespace ThreatSource.Jammer
// 发布干扰开始事件
PublishJammingEvent(parameters);
Console.WriteLine($"干扰器 {Id} 开始 {parameters.Type} 类型的干扰,功率:{parameters.Power}W");
Debug.WriteLine($"干扰器 {Id} 开始 {parameters.Type} 类型的干扰,功率:{parameters.Power}W");
}
/// <summary>
@ -144,7 +144,7 @@ namespace ThreatSource.Jammer
PublishJammingStoppedEvent(oldParameters);
}
Console.WriteLine($"干扰器 {Id} 停止干扰");
Debug.WriteLine($"干扰器 {Id} 停止干扰");
}
/// <summary>
@ -187,7 +187,7 @@ namespace ThreatSource.Jammer
/// </summary>
protected void PublishJammingEvent(JammingParameters parameters)
{
Console.WriteLine($"干扰器 {Id} 发布干扰事件: {parameters}");
Debug.WriteLine($"干扰器 {Id} 发布干扰事件: {parameters}");
var jammingEvent = new JammingEvent
{
Parameters = parameters
@ -206,7 +206,7 @@ namespace ThreatSource.Jammer
/// </summary>
protected void PublishJammingStoppedEvent(JammingParameters parameters)
{
Console.WriteLine($"干扰器 {Id} 发布干扰结束事件: {parameters}");
Debug.WriteLine($"干扰器 {Id} 发布干扰结束事件: {parameters}");
var stoppedEvent = new JammingStoppedEvent
{
Parameters = parameters

View File

@ -1,6 +1,6 @@
using ThreatSource.Utils;
using ThreatSource.Simulation;
using System.Numerics;
using System.Diagnostics;
namespace ThreatSource.Jammer
{
@ -163,7 +163,7 @@ namespace ThreatSource.Jammer
if (thickness > 0.1 && config.IsObscuring)
{
effectiveTransmittance = physicalTransmittance * 1e-3;
Console.WriteLine($"[烟幕透过率计算] 屏蔽型烟幕生效,透射率调整为: {effectiveTransmittance:F5} (物理透射率: {physicalTransmittance:F5})");
Debug.WriteLine($"[烟幕透过率计算] 屏蔽型烟幕生效,透射率调整为: {effectiveTransmittance:F5} (物理透射率: {physicalTransmittance:F5})");
}
return effectiveTransmittance;

View File

@ -230,7 +230,7 @@ namespace ThreatSource.Missile
// 合成总加速度(制导加速度 + 推力加速度 + 空气阻力加速度)
Vector3D totalAcceleration = GuidanceAcceleration + ThrustAcceleration + dragAcceleration;
Console.WriteLine($"导弹 {Id} 的加速度: {totalAcceleration}, 制导加速度: {GuidanceAcceleration}, " +
Debug.WriteLine($"导弹 {Id} 的加速度: {totalAcceleration}, 制导加速度: {GuidanceAcceleration}, " +
$"推力加速度: {ThrustAcceleration}, 空气阻力加速度(含风影响): {dragAcceleration}");
if (totalAcceleration.Magnitude() > Properties.MaxAcceleration)
@ -413,7 +413,7 @@ namespace ThreatSource.Missile
reason = "未知原因触发自毁";
}
Trace.WriteLine($"导弹 {Id} 自毁。原因: {reason}");
Trace.TraceInformation($"导弹 {Id} 自毁。原因: {reason}");
OnSelfDestruct();
Deactivate();
}

View File

@ -320,12 +320,12 @@ namespace ThreatSource.Missile
);
SimulationManager.RegisterEntity(submunitions[i].Id, submunitions[i]);
Debug.WriteLine($"注册末敏弹子弹 {submunitions[i].Id}");
Trace.TraceInformation($"注册末敏弹子弹 {submunitions[i].Id}");
submunitions[i].Activate();
Debug.WriteLine($"激活末敏弹子弹 {submunitions[i].Id}");
Trace.TraceInformation($"激活末敏弹子弹 {submunitions[i].Id}");
Console.WriteLine($"[末敏弹分离] 母弹 KS: Pos={KState.Position}, Orient={KState.Orientation}, Speed={KState.Speed}, Vel={KState.Velocity}");
Console.WriteLine($"[末敏弹分离] 子弹 {i} KS: Pos={submunitions[i].KState.Position}, Orient={submunitions[i].KState.Orientation}, Speed={submunitions[i].KState.Speed}, Vel={submunitions[i].KState.Velocity}");
Trace.TraceInformation($"[末敏弹分离] 母弹 KS: Pos={KState.Position}, Orient={KState.Orientation}, Speed={KState.Speed}, Vel={KState.Velocity}");
Trace.TraceInformation($"[末敏弹分离] 子弹 {i} KS: Pos={submunitions[i].KState.Position}, Orient={submunitions[i].KState.Orientation}, Speed={submunitions[i].KState.Speed}, Vel={submunitions[i].KState.Velocity}");
submunitions[i].Fire();
}

View File

@ -1,5 +1,5 @@
using ThreatSource.Utils;
using System.Diagnostics;
namespace ThreatSource.Sensor
{
/// <summary>
@ -302,7 +302,7 @@ namespace ThreatSource.Sensor
VerticalError = filteredVerticalError;
// 增强调试输出,同时显示水平和垂直误差
Console.WriteLine($"原始误差: 水平={rawHorizontalError:F6}, 垂直={rawVerticalError:F6}, 滤波后: 水平={HorizontalError:F6}, 垂直={VerticalError:F6}");
Debug.WriteLine($"原始误差: 水平={rawHorizontalError:F6}, 垂直={rawVerticalError:F6}, 滤波后: 水平={HorizontalError:F6}, 垂直={VerticalError:F6}");
}
else
{

View File

@ -177,8 +177,8 @@ namespace ThreatSource.Simulation
var activeTargets = entities.Values.OfType<Tank>().Where(e => e.IsActive).ToList();
var hitEvents = new List<(Tank tank, BaseMissile missile, double damage)>();
Console.WriteLine($"活动导弹数量: {activeMissiles.Count}");
Console.WriteLine($"活动目标数量: {activeTargets.Count}");
Debug.WriteLine($"活动导弹数量: {activeMissiles.Count}");
Debug.WriteLine($"活动目标数量: {activeTargets.Count}");
// 收集所有的命中信息
foreach (var missile in activeMissiles)
@ -186,7 +186,7 @@ namespace ThreatSource.Simulation
foreach (var target in activeTargets)
{
double distance = Vector3D.Distance(missile.KState.Position, target.KState.Position);
Console.WriteLine($"导弹 {missile.Id} 和目标 {target.Id} 之间的距离: {distance:F2}");
Debug.WriteLine($"导弹 {missile.Id} 和目标 {target.Id} 之间的距离: {distance:F2}");
if (distance <= missile.Properties.ExplosionRadius)
{
double damage = CalculateMissileDamage(missile);
@ -202,7 +202,7 @@ namespace ThreatSource.Simulation
if (tank.IsActive)
{
tank.TakeDamage(damage);
Console.WriteLine($"目标 {tank.Id} 被导弹 {missile.Id} 击中,造成 {damage} 点伤害");
Debug.WriteLine($"目标 {tank.Id} 被导弹 {missile.Id} 击中,造成 {damage} 点伤害");
}
}
@ -215,20 +215,20 @@ namespace ThreatSource.Simulation
}
catch (Exception ex)
{
Console.WriteLine($"发布命中事件时发生错误: {ex.Message}");
Debug.WriteLine($"发布命中事件时发生错误: {ex.Message}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"处理命中事件时发生错误: {ex.Message}");
Debug.WriteLine($"处理命中事件时发生错误: {ex.Message}");
}
}
/// <summary>
/// 计算导弹造成的伤害
/// </summary>
private double CalculateMissileDamage(BaseMissile missile)
private static double CalculateMissileDamage(BaseMissile missile)
{
// 这里可以根据导弹类型、速度等因素计算伤害
// 现在我们简单地返回一个固定值
@ -543,7 +543,7 @@ namespace ThreatSource.Simulation
public void SetWeather(Weather weather)
{
_currentWeather = weather;
Console.WriteLine($"已设置天气:{weather.Type}");
Debug.WriteLine($"已设置天气:{weather.Type}");
// 通知其他实体天气已变化
var evt = new WeatherChangedEvent

View File

@ -1,5 +1,5 @@
using AirTransmission; // 引用 .NET DLL 的命名空间
using System;
using System.Diagnostics;
namespace ThreatSource.Utils
{
@ -53,13 +53,13 @@ namespace ThreatSource.Utils
distanceInKm, // 使用公里单位
parameters);
Console.WriteLine($"[透过率] 类型: {radiationType}, 波长: {wavelength:F2}um, 距离: {distance:F1}m -> {transmittance:F3}");
Debug.WriteLine($"[透过率] 类型: {radiationType}, 波长: {wavelength:F2}um, 距离: {distance:F1}m -> {transmittance:F3}");
return Math.Clamp(transmittance, 0.0, 1.0);
}
catch (Exception ex)
{
Console.WriteLine($"调用AirTransmission计算透过率时出错 (类型: {radiationType}, 波长: {wavelength}um, 距离: {distance}m): {ex.Message}");
Debug.WriteLine($"调用AirTransmission计算透过率时出错 (类型: {radiationType}, 波长: {wavelength}um, 距离: {distance}m): {ex.Message}");
// 发生错误时返回一个保守的默认值
return 0.8;
}
@ -117,12 +117,12 @@ namespace ThreatSource.Utils
parameters,
height); // 使用米单位
Console.WriteLine($"[湍流效应] 波长: {wavelength:F2}um, 距离: {distance:F1}m, 高度: {height:F1}m -> {turbulenceEffect:F3}");
Debug.WriteLine($"[湍流效应] 波长: {wavelength:F2}um, 距离: {distance:F1}m, 高度: {height:F1}m -> {turbulenceEffect:F3}");
return turbulenceEffect;
}
catch (Exception ex)
{
Console.WriteLine($"计算湍流效应时出错 (波长: {wavelength}um, 距离: {distance}m, 高度: {height}m): {ex.Message}");
Debug.WriteLine($"计算湍流效应时出错 (波长: {wavelength}um, 距离: {distance}m, 高度: {height}m): {ex.Message}");
return 1.0; // 假设无影响
}
}
@ -144,12 +144,12 @@ namespace ThreatSource.Utils
smokeConcentration,
smokeThickness); // 使用米单位
Console.WriteLine($"[烟幕透过率] 波长: {wavelength:F2}um, 浓度: {smokeConcentration:F1}g/m³, 厚度: {smokeThickness:F1}m -> {smokeTransmittance:F3}");
Debug.WriteLine($"[烟幕透过率] 波长: {wavelength:F2}um, 浓度: {smokeConcentration:F1}g/m³, 厚度: {smokeThickness:F1}m -> {smokeTransmittance:F3}");
return smokeTransmittance;
}
catch (Exception ex)
{
Console.WriteLine($"计算烟幕透过率时出错 (波长: {wavelength}um, 浓度: {smokeConcentration}g/m³, 厚度: {smokeThickness}m): {ex.Message}");
Debug.WriteLine($"计算烟幕透过率时出错 (波长: {wavelength}um, 浓度: {smokeConcentration}g/m³, 厚度: {smokeThickness}m): {ex.Message}");
return 0.0; // 假设完全衰减
}
}

View File

@ -64,7 +64,7 @@ class Program
}
catch (Exception ex)
{
Trace.WriteLine($"Error: {ex.Message}");
Trace.TraceError($"Error: {ex.Message}");
}
}
}
@ -185,7 +185,7 @@ int main() {
return 0;
}
catch (Exception^ e) {
Trace::WriteLine("Error: {0}", e->Message);
Trace::TraceError("Error: {0}", e->Message);
return 1;
}
}
@ -311,7 +311,7 @@ public:
}
catch (Exception^ e)
{
Trace::WriteLine("错误: {0}", e->Message);
Trace::TraceError("错误: {0}", e->Message);
}
}
};
@ -330,7 +330,7 @@ int main()
}
catch (Exception^ e)
{
Trace::WriteLine("错误: {0}", e->Message);
Trace::TraceError("错误: {0}", e->Message);
return 1;
}
}

View File

@ -90,22 +90,22 @@ namespace ThreatSource.Examples
// 步骤9获取仿真结果
var results = await _adapter.GetSimulationResults();
Console.WriteLine($"仿真结束,命中精度: {results.MissDistance:F2}米");
Trace.TraceInformation($"仿真结束,命中精度: {results.MissDistance:F2}米");
}
catch (Exception ex)
{
Console.WriteLine($"仿真过程出错: {ex.Message}");
Trace.TraceError($"仿真过程出错: {ex.Message}");
}
}
private void OnEntityUpdated(SimulationEntity entity)
{
Console.WriteLine($"实体 {entity.Id} 位置更新: ({entity.Position.X:F2}, {entity.Position.Y:F2}, {entity.Position.Z:F2})");
Trace.TraceInformation($"实体 {entity.Id} 位置更新: ({entity.Position.X:F2}, {entity.Position.Y:F2}, {entity.Position.Z:F2})");
}
private void OnGuidanceUpdate(GuidanceInfo info)
{
Console.WriteLine($"制导更新: 距离目标 {info.DistanceToTarget:F2}米");
Trace.TraceInformation($"制导更新: 距离目标 {info.DistanceToTarget:F2}米");
}
}
}

View File

@ -134,9 +134,9 @@ public class IRMissileSimulation
private void ProcessResults(SimulationResults results)
{
// 处理仿真结果
Console.WriteLine($"仿真完成时间: {results.CompletionTime}秒");
Console.WriteLine($"命中精度: {results.HitAccuracy}米");
Console.WriteLine($"导引头跟踪时间: {results.TrackingTime}秒");
Trace.TraceInformation($"仿真完成时间: {results.CompletionTime}秒");
Trace.TraceInformation($"命中精度: {results.HitAccuracy}米");
Trace.TraceInformation($"导引头跟踪时间: {results.TrackingTime}秒");
}
}
```

View File

@ -7,6 +7,36 @@
- 事件描述
- 分析处理
## 2025-05-12 规范了调试信息的输出
- 规范了调试信息的输出,使用 Debug 和 Trace 输出日志
- 修改了集成测试程序的菜单,增加了日志级别设置
System.Diagnostics 命名空间提供了用于日志记录的类:
- Debug.WriteLine(...):用于开发阶段,详细的内部调试信息。
- Trace.WriteLine(...):用于开发和发布阶段,跟踪应用程序的执行流程,记录重要的事件、错误或状态信息。
- Trace.TraceInformation(...):用于一般的操作信息。
- Trace.TraceWarning(...):用于潜在问题。
- Trace.TraceError(...):用于已发生的错误。
System.Diagnostics.Debug.WriteLine 和 System.Diagnostics.Trace.WriteLine 之间, 在用途和行为上有一些关键的不同:
1. 编译条件与用途:
Debug.WriteLine (以及 Debug 类的其他方法):
编译条件: 这些方法调用通常只在定义了 DEBUG 编译常量时才会被编译到程序中。在 Visual Studio 或 dotnet build 中,"Debug" 配置默认会定义 DEBUG (和 TRACE) 常量。"Release" 配置默认只定义 TRACE 常量。
用途: 主要用于开发和调试阶段。这些日志信息帮助开发者理解代码执行流程、变量状态等,通常不应出现在最终的发布版本中,因为它们可能会暴露过多内部信息或影响性能。
Trace.WriteLine (以及 Trace 类的其他方法):
编译条件: 这些方法调用通常在定义了 TRACE 编译常量时被编译。如上所述,"Debug" 和 "Release" 配置默认都会定义 TRACE。
用途: 用于跟踪应用程序的执行流程,记录重要的事件、错误或状态信息,这些信息在应用程序的发布版本中也可能是有用的。例如,记录关键操作的开始和结束,或者记录发生的异常。
总结编译与用途:
用 Debug.WriteLine 输出只在开发调试时需要看的信息。
用 Trace.WriteLine (推荐使用更具体的 Trace.TraceInformation, Trace.TraceWarning, Trace.TraceError) 输出在发布后也可能需要查看的跟踪信息。
在模拟器中,您可以设置日志级别来控制哪些日志信息会被输出。
例如,在模拟器启动时,您可以设置日志级别:
## 2025-05-09 完善了各组件的干扰功能
- 把各组件的烟幕透过率计算移到 update 方法中
- 完善了指示器的烟幕遮挡计算逻辑

View File

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Diagnostics;
using ThreatSource.Missile;
using ThreatSource.Simulation;
using ThreatSource.Utils;
@ -14,6 +9,9 @@ using ThreatSource.Guidance;
using ThreatSource.Indicator;
using ThreatSource.Data;
using AirTransmission;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace ThreatSource.Tools.MissileSimulation
{
@ -25,6 +23,9 @@ namespace ThreatSource.Tools.MissileSimulation
// 定义仿真结束事件
public event EventHandler? SimulationEnded;
private ConsoleTraceListener consoleListener;
private EventTypeFilter logLevelFilter;
private readonly SimulationManager simulationManager;
private readonly ThreatSourceFactory _threatSourceFactory;
private readonly ThreatSourceDataManager _dataManager;
@ -41,6 +42,8 @@ namespace ThreatSource.Tools.MissileSimulation
// 当前选中的导弹ID
public string SelectedMissileId { get; private set; }
private List<(JammingType Type, string DisplayName, string JammerId, string Mode, string Target)> activeJammings;
/// <summary>
/// 获取当前选中导弹的显示名称
/// </summary>
@ -66,6 +69,21 @@ namespace ThreatSource.Tools.MissileSimulation
/// </summary>
public ComprehensiveMissileSimulator()
{
// Initialize filter and listener first
this.logLevelFilter = new EventTypeFilter(SourceLevels.Verbose); // Default to Verbose
this.consoleListener = new ConsoleTraceListener();
this.consoleListener.Filter = this.logLevelFilter;
// Clear any existing ConsoleTraceListeners and add our controlled instance
for (int i = Trace.Listeners.Count - 1; i >= 0; i--)
{
if (Trace.Listeners[i] is ConsoleTraceListener)
{
Trace.Listeners.RemoveAt(i);
}
}
Trace.Listeners.Add(this.consoleListener);
simulationManager = new SimulationManager();
_dataManager = new ThreatSourceDataManager("../ThreatSource/data");
_threatSourceFactory = new ThreatSourceFactory(_dataManager, simulationManager);
@ -77,11 +95,28 @@ namespace ThreatSource.Tools.MissileSimulation
missileJammingMap = [];
SelectedMissileId = "";
this.activeJammings = new List<(JammingType Type, string DisplayName, string JammerId, string Mode, string Target)>();
// 初始化导弹-干扰映射
InitializeMissileJammingMap();
InitializeSimulation();
}
public SourceLevels CurrentLogLevel => logLevelFilter?.EventType ?? SourceLevels.Off;
public void SetLogLevel(SourceLevels level)
{
if (logLevelFilter != null)
{
logLevelFilter.EventType = level;
Console.WriteLine($"[Simulator] 日志输出级别已设置为: {level}");
}
else
{
Console.WriteLine("[Simulator] Error: Log level filter not initialized.");
}
}
/// <summary>
/// 初始化导弹-干扰映射关系
@ -91,51 +126,51 @@ namespace ThreatSource.Tools.MissileSimulation
missileJammingMap = new Dictionary<string, List<(JammingType, string, string, string, string)>>();
// 激光驾束导弹
missileJammingMap["LBRM_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["LBRM_1"] =
[
(JammingType.Laser, "激光干扰", "LaserJammer_Designator", "阻塞", "驾束仪"),
(JammingType.SmokeGrenade, "烟幕弹", "SG_1", "遮蔽", "驾束仪")
};
];
// 激光半主动制导导弹
missileJammingMap["LSGM_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["LSGM_1"] =
[
(JammingType.Laser, "激光干扰(指示器)", "LaserJammer_Designator", "阻塞", "指示器"),
(JammingType.Laser, "激光干扰(导弹)", "LaserJammer_Missile", "阻塞", "导弹"),
(JammingType.LaserDecoy, "激光诱偏目标", "LDY_1", "欺骗", "导弹"),
(JammingType.SmokeGrenade, "烟幕弹", "SG_1", "遮蔽", "两者")
};
];
// 红外指令制导导弹
missileJammingMap["ICGM_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["ICGM_1"] =
[
(JammingType.Infrared, "红外干扰", "InfraredJammer_Designator", "阻塞", "指示器"),
(JammingType.SmokeGrenade, "烟幕弹", "SG_2", "遮蔽", "指示器")
};
];
// 红外成像末制导导弹
missileJammingMap["ITGM_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["ITGM_1"] =
[
(JammingType.Infrared, "红外干扰", "InfraredJammer_Missile", "阻塞", "导弹"),
(JammingType.SmokeGrenade, "红外烟幕弹", "SG_2", "遮蔽", "导弹")
};
];
// 毫米波末制导导弹
missileJammingMap["MMWG_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["MMWG_1"] =
[
(JammingType.MillimeterWave, "毫米波干扰", "MillimeterWaveJammer_Missile", "阻塞", "导弹"),
(JammingType.SmokeGrenade, "烟幕弹", "SG_3", "遮蔽", "导弹")
};
];
// 末敏子弹药
missileJammingMap["TSM_1"] = new List<(JammingType, string, string, string, string)>
{
missileJammingMap["TSM_1"] =
[
(JammingType.Laser, "激光干扰", "LaserJammer_Submunition", "阻塞", "子弹药"),
(JammingType.Infrared, "红外干扰", "InfraredJammer_Submunition", "阻塞", "子弹药"),
(JammingType.MillimeterWave, "毫米波干扰", "MillimeterWaveJammer_Submunition", "阻塞", "子弹药"),
(JammingType.MillimeterWave, "毫米波假信号", "MillimeterWaveCompensationJammer_Submunition", "欺骗", "子弹药"),
(JammingType.SmokeGrenade, "烟幕弹", "SG_4", "遮蔽", "子弹药")
};
];
}
/// <summary>
@ -214,8 +249,7 @@ namespace ThreatSource.Tools.MissileSimulation
Speed = 0.0
};
string laserDecoyId = "LDY_1";
var laserDecoy = _threatSourceFactory.CreateJammer(laserDecoyId, "laser_decoy", motionParameters, "Tank_1") as LaserDecoy;
if (laserDecoy != null)
if (_threatSourceFactory.CreateJammer(laserDecoyId, "laser_decoy", motionParameters, "Tank_1") is LaserDecoy laserDecoy)
{
simulationManager.RegisterEntity(laserDecoyId, laserDecoy);
jammers[laserDecoyId] = laserDecoy as BaseJammer;
@ -692,16 +726,20 @@ namespace ThreatSource.Tools.MissileSimulation
// 检查并激活干扰器
if (jammers.ContainsKey(jammerId))
{
var jammer = jammers[jammerId];
// 激活干扰器实例
jammer.Activate();
var jammerToActivate = jammers[jammerId];
jammerToActivate.Activate();
Console.WriteLine($"激活干扰器并开始干扰: {jammerId}: {displayName} (模式: {mode}, 作用: {target})");
// Add to activeJammings list if not already present
var jammingTuple = (Type: type, DisplayName: displayName, JammerId: jammerId, Mode: mode, Target: target);
if (!this.activeJammings.Any(j => j.JammerId == jammerId && j.Type == type)) // Simple check to avoid duplicates
{
this.activeJammings.Add(jammingTuple);
}
}
else
{
Console.WriteLine($"警告:找不到干扰器 {jammerId},可用干扰器: {string.Join(", ", jammers.Keys)}");
Console.WriteLine($"警告:找不到干扰器 {jammerId}...");
PrintAllJammers();
}
@ -939,6 +977,9 @@ namespace ThreatSource.Tools.MissileSimulation
{
jammers[jammerId].Deactivate();
Console.WriteLine($"关闭干扰器 {jammerId}: {displayName}");
// Remove from activeJammings list
this.activeJammings.RemoveAll(j => j.JammerId == jammerId && j.Type == type);
}
}
@ -1314,5 +1355,20 @@ namespace ThreatSource.Tools.MissileSimulation
Console.WriteLine($"风速: {newWeather.WindSpeed}米/秒");
Console.WriteLine($"风向: {newWeather.WindDirection}°");
}
public string GetActiveJammingDescription()
{
if (this.activeJammings == null || !this.activeJammings.Any())
{
return "(无干扰)";
}
return $"(已激活: {this.activeJammings.First().DisplayName})";
}
public List<(JammingType Type, string DisplayName, string JammerId, string Mode, string Target)> GetCurrentlyActiveJammings()
{
// Return a new list to prevent external modification of the internal list
return new List<(JammingType Type, string DisplayName, string JammerId, string Mode, string Target)>(this.activeJammings);
}
}
}

View File

@ -2,6 +2,8 @@ using ThreatSource.Utils;
using ThreatSource.Jammer;
using System;
using System.Threading;
using System.Diagnostics;
using System.Linq;
namespace ThreatSource.Tools.MissileSimulation
{
@ -11,97 +13,187 @@ namespace ThreatSource.Tools.MissileSimulation
{
Console.WriteLine("综合导弹模拟程序启动...");
var simulator = new ComprehensiveMissileSimulator();
// 标记是否收到仿真结束事件
var simulationEndedEvent = new ManualResetEvent(false);
// 订阅仿真结束事件
simulator.SimulationEnded += (sender, e) => {
simulationEndedEvent.Set();
};
while (true)
{
// 显示主菜单如果返回false则退出程序
if (!ShowMainMenu(simulator))
{
break;
}
// 重置事件状态
simulationEndedEvent.Reset();
// 开始仿真
var simulationThread = new Thread(simulator.Start);
simulationThread.Start();
// 等待退出命令
Console.WriteLine("\n仿真已开始运行。输入 'exit' 退出程序。");
bool exitProgram = false;
while (true)
{
if (Console.KeyAvailable)
{
var input = Console.ReadLine();
if (input?.ToLower() == "exit")
{
simulator.Stop();
exitProgram = true;
break;
}
}
// 检查仿真是否结束
if (simulationEndedEvent.WaitOne(100)) // 等待100ms
{
break;
}
}
if (exitProgram)
{
break;
}
// 等待仿真线程完全结束
simulationThread.Join();
// 显示分隔线和新的仿真选项
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("当前导弹仿真结束。");
Console.WriteLine("按任意键返回主菜单,或输入 'exit' 退出程序...");
Console.WriteLine(new string('=', 50) + "\n");
string userInput = Console.ReadLine()?.ToLower() ?? string.Empty;
if (userInput == "exit")
{
break;
}
}
// Set a default log level on startup if desired, or rely on Simulator's default
// simulator.SetLogLevel(SourceLevels.Information);
ApplicationHostLoop(simulator);
Console.WriteLine("\n程序已退出。");
}
static bool ShowMainMenu(ComprehensiveMissileSimulator simulator)
static void ApplicationHostLoop(ComprehensiveMissileSimulator simulator)
{
Console.WriteLine("=== 导弹仿真系统主菜单 ===\n");
// 第一步:选择导弹
if (!SelectMissile(simulator))
return false;
// 第二步:配置传感器
if (!ConfigureSensors(simulator))
return false;
// 第三步:配置干扰
if (!ConfigureJamming(simulator))
return false;
bool exitProgram = false;
while (!exitProgram)
{
Console.WriteLine("\n=== 导弹仿真系统主菜单 ===");
string missileStatus = string.IsNullOrEmpty(simulator.SelectedMissileId) ? "未选择" : $"已选: {simulator.SelectedMissileDisplayName}";
return true;
string sensorStatusString = "";
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
{
var indicators = simulator.GetActiveIndicators();
var firstActiveIndicator = indicators.FirstOrDefault(ind => ind.IsActive);
if (firstActiveIndicator.Name != null) // Name is a string, check for null if tuple might not be found
{
sensorStatusString = $"(已激活: {firstActiveIndicator.Name})";
}
else
{
sensorStatusString = "(无默认激活指示器)"; // Or "(配置)" or similar
}
}
else
{
sensorStatusString = "(需先选导弹)";
}
Console.WriteLine($"1. 选择导弹 ({missileStatus})");
Console.WriteLine($"2. 配置传感器 {sensorStatusString}");
Console.WriteLine($"3. 配置干扰 {simulator.GetActiveJammingDescription()} {(string.IsNullOrEmpty(simulator.SelectedMissileId) ? "()" : "")}");
Console.WriteLine($"4. 设置日志级别 (当前级别: {simulator.CurrentLogLevel})");
Console.WriteLine($"5. 开始仿真 {(string.IsNullOrEmpty(simulator.SelectedMissileId) ? "()" : "")}");
Console.WriteLine("0. 退出程序");
Console.Write("\n请选择: ");
string choice = Console.ReadLine()?.ToLower() ?? string.Empty;
switch (choice)
{
case "1":
SelectMissile(simulator);
break;
case "2":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
ConfigureSensors(simulator);
else
Console.WriteLine("请先选择导弹。");
break;
case "3":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
ConfigureJamming(simulator);
else
Console.WriteLine("请先选择导弹。");
break;
case "4":
ShowLogLevelMenu(simulator);
break;
case "5":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
{
RunSimulationInstance(simulator);
}
else
{
Console.WriteLine("请先选择导弹并完成基本配置 (选择导弹是启动仿真的最低要求)。");
}
break;
case "0":
exitProgram = true;
break;
default:
Console.WriteLine("无效选择,请重试。");
break;
}
}
}
static bool SelectMissile(ComprehensiveMissileSimulator simulator)
// Placeholder for ShowLogLevelMenu - to be implemented next
static void ShowLogLevelMenu(ComprehensiveMissileSimulator simulator)
{
bool backToMainMenu = false;
while (!backToMainMenu)
{
Console.WriteLine("\n--- 设置日志级别 ---");
Console.WriteLine("1. Off (关闭所有Trace/Debug输出)");
Console.WriteLine("2. Error (仅错误信息)");
Console.WriteLine("3. Warning (警告及错误)");
Console.WriteLine("4. Information (普通信息、警告、错误)");
Console.WriteLine("5. Verbose (所有信息包括Debug.WriteLine)");
Console.WriteLine("0. 返回主菜单");
Console.Write("请选择日志级别: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
SourceLevels currentLevel = simulator.CurrentLogLevel; // Use the new public property
SourceLevels selectedLevel = currentLevel; // Default to current if invalid choice
bool levelSet = false;
switch (input)
{
case "1": selectedLevel = SourceLevels.Off; levelSet = true; break;
case "2": selectedLevel = SourceLevels.Error; levelSet = true; break;
case "3": selectedLevel = SourceLevels.Warning; levelSet = true; break;
case "4": selectedLevel = SourceLevels.Information; levelSet = true; break;
case "5": selectedLevel = SourceLevels.Verbose; levelSet = true; break;
case "0": backToMainMenu = true; break;
default: Console.WriteLine("无效选择,请重试。"); break;
}
if (levelSet)
{
simulator.SetLogLevel(selectedLevel);
// Confirmation is printed by SetLogLevel in simulator
return; // Return to main menu after setting level
}
}
}
// Placeholder for RunSimulationInstance - to be implemented next
static void RunSimulationInstance(ComprehensiveMissileSimulator simulator)
{
Console.WriteLine("\n--- 开始仿真 --- ");
var simulationEndedEvent = new ManualResetEvent(false);
simulator.SimulationEnded += (sender, e) => {
simulationEndedEvent.Set();
// Unsubscribe to prevent issues if RunSimulationInstance is called again
if (sender is ComprehensiveMissileSimulator sim) // C# 7.0 pattern matching
{
sim.SimulationEnded -= (s, args) => simulationEndedEvent.Set(); // Attempt to unsubscribe, exact lambda match is tricky
}
};
var simulationThread = new Thread(simulator.Start);
simulationThread.Start();
Console.WriteLine("仿真已开始运行。在主菜单输入 '0' 可在下次返回主菜单时退出程序。");
Console.WriteLine("仿真过程中,您可以随时按 Enter 键尝试提前中止当前仿真实例并返回主菜单。");
bool simulationForceStopped = false;
while (!simulationEndedEvent.WaitOne(100)) // Check every 100ms if simulation ended naturally
{
if (Console.KeyAvailable)
{
// Read the key, but don't wait if it was just a check.
// We want to allow Enter to break, not necessarily other typed commands during active sim.
// A simple Console.ReadLine() here would block until Enter.
// If user presses Enter, ReadLine will return empty or the character if it was typed fast enough.
var keyInfo = Console.ReadKey(intercept: true); // Intercept to prevent display
if (keyInfo.Key == ConsoleKey.Enter)
{
Console.WriteLine("\n用户请求中止当前仿真实例...");
simulator.Stop(); // Request simulator to stop
simulationForceStopped = true;
break; // Exit the wait loop
}
// If other keys are pressed, we can choose to ignore them or buffer them for a potential command parser later.
// For now, only Enter is an active interrupt.
}
}
// Wait for the simulation thread to actually finish, especially if force stopped.
simulationThread.Join();
if (simulationForceStopped)
{
Console.WriteLine("当前仿真实例已被用户中止。");
}
else
{
Console.WriteLine("当前导弹仿真自然结束。");
}
Console.WriteLine("按任意键返回主菜单...");
Console.ReadKey(); // Wait for user to acknowledge before returning to main menu
}
static void SelectMissile(ComprehensiveMissileSimulator simulator)
{
var missiles = new[]
{
@ -115,100 +207,146 @@ namespace ThreatSource.Tools.MissileSimulation
while (true)
{
Console.WriteLine("\n第一步:请选择导弹类型:");
Console.WriteLine("\n--- 选择导弹类型 ---");
for (int i = 0; i < missiles.Length; i++)
{
Console.WriteLine($" {i + 1}. {missiles[i].Item2}");
}
Console.WriteLine(" exit. 退出程序");
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择: ");
var input = Console.ReadLine()?.ToLower();
if (input == "exit")
return false;
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice) &&
choice >= 1 && choice <= missiles.Length)
{
simulator.SelectMissile(missiles[choice - 1].Item1);
return true;
Console.WriteLine($"已选择: {simulator.SelectedMissileDisplayName}");
return;
}
Console.WriteLine("无效选择,请重试");
Console.WriteLine("无效选择,请重试");
}
}
static bool ConfigureSensors(ComprehensiveMissileSimulator simulator)
static void ConfigureSensors(ComprehensiveMissileSimulator simulator)
{
while (true)
{
Console.WriteLine("\n第二步:配置传感器和指示器");
Console.WriteLine("\n--- 配置传感器和指示器 ---");
Console.WriteLine("当前传感器状态:");
var indicators = simulator.GetActiveIndicators();
for (int i = 0; i < indicators.Length; i++)
if (indicators.Length == 0)
{
Console.WriteLine($" {i + 1}. {indicators[i].Name} [{(indicators[i].IsActive ? "" : "")}]");
Console.WriteLine("当前导弹类型没有可配置的独立传感器/指示器,或未实现获取接口。");
}
Console.WriteLine(" 0. 继续下一步");
Console.WriteLine(" exit. 退出程序");
else
{
for (int i = 0; i < indicators.Length; i++)
{
Console.WriteLine($" {i + 1}. {indicators[i].Name} [{(indicators[i].IsActive ? "" : "")}]");
}
}
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择切换状态的传感器,或返回: ");
var input = Console.ReadLine()?.ToLower();
if (input == "exit")
return false;
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice))
{
if (choice == 0) return true;
if (choice >= 1 && choice <= indicators.Length)
{
simulator.ToggleIndicator(indicators[choice - 1].Id);
continue;
// Loop continues to show updated status
return; // Return to main menu after toggling sensor
}
else
{
Console.WriteLine("无效选择,请重试。");
}
}
Console.WriteLine("无效选择,请重试");
else
{
Console.WriteLine("无效输入,请输入数字。");
}
}
}
static bool ConfigureJamming(ComprehensiveMissileSimulator simulator)
static void ConfigureJamming(ComprehensiveMissileSimulator simulator)
{
var availableJammingOptions = simulator.GetAvailableJammingOptions();
var currentlyActiveJammingsFromSimulator = simulator.GetCurrentlyActiveJammings();
var jammingStatus = new bool[availableJammingOptions.Length];
for (int i = 0; i < availableJammingOptions.Length; i++)
{
var currentOptionForLoop = availableJammingOptions[i]; // Renamed to avoid conflict
if (currentlyActiveJammingsFromSimulator.Any(activeJam => activeJam.JammerId == currentOptionForLoop.JammerId && activeJam.Type == currentOptionForLoop.Type))
{
jammingStatus[i] = true;
}
else
{
jammingStatus[i] = false;
}
}
while (true)
{
Console.WriteLine("\n第三步配置干扰方式");
Console.WriteLine("\n--- 配置干扰方式 ---");
Console.WriteLine($"当前导弹: {simulator.SelectedMissileDisplayName}");
Console.WriteLine("可用干扰方式:");
for (int i = 0; i < availableJammingOptions.Length; i++)
if (availableJammingOptions.Length == 0)
{
var option = availableJammingOptions[i];
Console.WriteLine($" {i + 1}. {option.DisplayName} [{(jammingStatus[i] ? "" : "")}] " +
$"(干扰模式: {option.Mode}, 作用对象: {option.Target})");
Console.WriteLine("当前导弹类型没有可配置的干扰选项。");
}
else
{
Console.WriteLine("可用干扰方式:");
for (int i = 0; i < availableJammingOptions.Length; i++)
{
var option = availableJammingOptions[i];
// To get actual status, you'd query simulator: e.g., simulator.IsJammerActive(option.JammerId)
// For now, we use local `jammingStatus` which is temporary for this menu session.
Console.WriteLine($" {i + 1}. {option.DisplayName} [{(jammingStatus[i] ? "" : "")}] " +
$"(干扰模式: {option.Mode}, 作用对象: {option.Target})");
}
}
Console.WriteLine(" 0. 开始仿真");
Console.WriteLine(" exit. 退出程序");
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择切换状态的干扰项,或返回: ");
var input = Console.ReadLine()?.ToLower();
if (input == "exit")
return false;
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice))
{
if (choice == 0) return true;
if (choice >= 1 && choice <= availableJammingOptions.Length)
{
var option = availableJammingOptions[choice - 1];
jammingStatus[choice - 1] = !jammingStatus[choice - 1];
jammingStatus[choice - 1] = !jammingStatus[choice - 1]; // Toggle local status for display
if (jammingStatus[choice - 1])
simulator.ApplyJamming(option.Type, option.DisplayName, option.JammerId, option.Mode, option.Target);
else
simulator.ClearJamming(option.Type, option.DisplayName, option.JammerId);
continue;
// Loop continues
return; // Return to main menu after applying/clearing jamming
}
else
{
Console.WriteLine("无效选择,请重试。");
}
}
Console.WriteLine("无效选择,请重试");
else
{
Console.WriteLine("无效输入,请输入数字。");
}
}
}
}