diff --git a/.cursor/rules/rule-claude-sonnet-37.mdc b/.cursor/rules/rule-claude-sonnet-37.mdc deleted file mode 100644 index 6b2ff0e..0000000 --- a/.cursor/rules/rule-claude-sonnet-37.mdc +++ /dev/null @@ -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. diff --git a/.cursor/rules/threat-source-rule.mdc b/.cursor/rules/threat-source-rule.mdc deleted file mode 100644 index 44476ff..0000000 --- a/.cursor/rules/threat-source-rule.mdc +++ /dev/null @@ -1,16 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- -# 注释 -使用中文注释 - -# 坐标系约定 - -- 采用右手坐标系 -- Y 轴向上 -- 逆时针旋转为正方向 - -# 运行命令 -- 在运行命令前,先运行 pwd 命令,了解当前目录 \ No newline at end of file diff --git a/ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs b/ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs index abd4506..2929143 100644 --- a/ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs +++ b/ThreatSource.Tests/src/Jamming/SmokeGrenadeTests.cs @@ -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] diff --git a/ThreatSource.Tests/src/Jamming/TerminalSensitiveSubmunitionJammingTests.cs b/ThreatSource.Tests/src/Jamming/TerminalSensitiveSubmunitionJammingTests.cs index fc06291..19a8aa8 100644 --- a/ThreatSource.Tests/src/Jamming/TerminalSensitiveSubmunitionJammingTests.cs +++ b/ThreatSource.Tests/src/Jamming/TerminalSensitiveSubmunitionJammingTests.cs @@ -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", "子弹状态应该反映传感器恢复正常"); // 验证速度变化 diff --git a/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs b/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs index 1046f73..0d848b0 100644 --- a/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs +++ b/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs @@ -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); diff --git a/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs b/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs index f7a1fe9..3167e60 100644 --- a/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs +++ b/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs @@ -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}"); } /// diff --git a/ThreatSource.Tests/src/Utils/AtmosphereDllWrapperTests.cs b/ThreatSource.Tests/src/Utils/AtmosphereDllWrapperTests.cs index 6a49aeb..fa62296 100644 --- a/ThreatSource.Tests/src/Utils/AtmosphereDllWrapperTests.cs +++ b/ThreatSource.Tests/src/Utils/AtmosphereDllWrapperTests.cs @@ -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); diff --git a/ThreatSource/src/Data/ThreatSourceDataManager.cs b/ThreatSource/src/Data/ThreatSourceDataManager.cs index bd915c9..1a77dbe 100644 --- a/ThreatSource/src/Data/ThreatSourceDataManager.cs +++ b/ThreatSource/src/Data/ThreatSourceDataManager.cs @@ -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}"); } } } diff --git a/ThreatSource/src/Guidance/BaseGuidanceSystem.cs b/ThreatSource/src/Guidance/BaseGuidanceSystem.cs index 4e549bc..b82c458 100644 --- a/ThreatSource/src/Guidance/BaseGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/BaseGuidanceSystem.cs @@ -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}] 所有干扰已清除。"); } } diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs index 13b9708..a8cba8f 100644 --- a/ThreatSource/src/Guidance/InfraredImageGenerator.cs +++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs @@ -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"); } /// diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs index d2f2d77..6adfcce 100644 --- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs @@ -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} 度"); } /// @@ -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} 度"); } /// @@ -342,7 +342,7 @@ namespace ThreatSource.Guidance public void SwitchToLockMode() { currentMode = WorkMode.Lock; - Console.WriteLine("Switched to lock mode - target type confirmed"); + Debug.WriteLine("切换到锁定模式 - 目标类型确认"); } /// @@ -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}"); } } diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs index bf6d787..479d00c 100644 --- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs +++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs @@ -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 blobs = new List(); 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 filteredBlobs = new List(); @@ -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 /// 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; } diff --git a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs index d0f601a..564c28b 100644 --- a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs @@ -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"); } } diff --git a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs index 1828c17..94d966c 100644 --- a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs @@ -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"); diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs index 3b4099f..72ea37e 100644 --- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs @@ -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}度"); } /// @@ -183,7 +183,7 @@ namespace ThreatSource.Guidance currentMode = WorkMode.Track; lockConfirmationTimer = 0; HasGuidance = true; - Trace.WriteLine($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度"); + Trace.TraceInformation($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度"); } /// @@ -193,7 +193,7 @@ namespace ThreatSource.Guidance { currentMode = WorkMode.Lock; HasGuidance = true; - Trace.WriteLine("切换到锁定模式 - 目标锁定成功"); + Trace.TraceInformation("切换到锁定模式 - 目标锁定成功"); } /// @@ -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; } diff --git a/ThreatSource/src/Indicator/InfraredTracker.cs b/ThreatSource/src/Indicator/InfraredTracker.cs index 7d2fa48..1f170ab 100644 --- a/ThreatSource/src/Indicator/InfraredTracker.cs +++ b/ThreatSource/src/Indicator/InfraredTracker.cs @@ -132,7 +132,7 @@ namespace ThreatSource.Indicator if (_lastKnownTargetPosition != null) { currentTargetPosition = _lastKnownTargetPosition; - Console.WriteLine($"InfraredTracker {Id}: 目标被遮挡,使用最后已知位置 {currentTargetPosition}"); + Debug.WriteLine($"红外测角仪 {Id}: 目标被遮挡,使用最后已知位置 {currentTargetPosition}"); } else { diff --git a/ThreatSource/src/Indicator/LaserDesignator.cs b/ThreatSource/src/Indicator/LaserDesignator.cs index 9bff800..8f1e4da 100644 --- a/ThreatSource/src/Indicator/LaserDesignator.cs +++ b/ThreatSource/src/Indicator/LaserDesignator.cs @@ -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; } } diff --git a/ThreatSource/src/Jammable/JammableComponent.cs b/ThreatSource/src/Jammable/JammableComponent.cs index 0d41115..072adce 100644 --- a/ThreatSource/src/Jammable/JammableComponent.cs +++ b/ThreatSource/src/Jammable/JammableComponent.cs @@ -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; // 如果是非阻塞且通过了初步检查,则认为有效 } } diff --git a/ThreatSource/src/Jammer/BaseJammer.cs b/ThreatSource/src/Jammer/BaseJammer.cs index bc60eff..a1c0620 100644 --- a/ThreatSource/src/Jammer/BaseJammer.cs +++ b/ThreatSource/src/Jammer/BaseJammer.cs @@ -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"); } /// @@ -144,7 +144,7 @@ namespace ThreatSource.Jammer PublishJammingStoppedEvent(oldParameters); } - Console.WriteLine($"干扰器 {Id} 停止干扰"); + Debug.WriteLine($"干扰器 {Id} 停止干扰"); } /// @@ -187,7 +187,7 @@ namespace ThreatSource.Jammer /// 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 /// protected void PublishJammingStoppedEvent(JammingParameters parameters) { - Console.WriteLine($"干扰器 {Id} 发布干扰结束事件: {parameters}"); + Debug.WriteLine($"干扰器 {Id} 发布干扰结束事件: {parameters}"); var stoppedEvent = new JammingStoppedEvent { Parameters = parameters diff --git a/ThreatSource/src/Jammer/SmokeGrenade.cs b/ThreatSource/src/Jammer/SmokeGrenade.cs index 17d285e..83465a5 100644 --- a/ThreatSource/src/Jammer/SmokeGrenade.cs +++ b/ThreatSource/src/Jammer/SmokeGrenade.cs @@ -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; diff --git a/ThreatSource/src/MIssile/BaseMissile.cs b/ThreatSource/src/MIssile/BaseMissile.cs index 4e27e99..a8626ff 100644 --- a/ThreatSource/src/MIssile/BaseMissile.cs +++ b/ThreatSource/src/MIssile/BaseMissile.cs @@ -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(); } diff --git a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs index 64d4ea2..7b92fbb 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs @@ -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(); } diff --git a/ThreatSource/src/Sensor/QuadrantDetector.cs b/ThreatSource/src/Sensor/QuadrantDetector.cs index fc387da..34a1fc5 100644 --- a/ThreatSource/src/Sensor/QuadrantDetector.cs +++ b/ThreatSource/src/Sensor/QuadrantDetector.cs @@ -1,5 +1,5 @@ using ThreatSource.Utils; - +using System.Diagnostics; namespace ThreatSource.Sensor { /// @@ -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 { diff --git a/ThreatSource/src/Simulation/SimulationManager.cs b/ThreatSource/src/Simulation/SimulationManager.cs index ca03a14..74386e4 100644 --- a/ThreatSource/src/Simulation/SimulationManager.cs +++ b/ThreatSource/src/Simulation/SimulationManager.cs @@ -177,8 +177,8 @@ namespace ThreatSource.Simulation var activeTargets = entities.Values.OfType().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}"); } } /// /// 计算导弹造成的伤害 /// - 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 diff --git a/ThreatSource/src/Utils/AtmosphereDllWrapper.cs b/ThreatSource/src/Utils/AtmosphereDllWrapper.cs index 10a5d7e..3dc8d30 100644 --- a/ThreatSource/src/Utils/AtmosphereDllWrapper.cs +++ b/ThreatSource/src/Utils/AtmosphereDllWrapper.cs @@ -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; // 假设完全衰减 } } diff --git a/docs/articles/intro.md b/docs/articles/intro.md index 1ebf38d..496dc0b 100644 --- a/docs/articles/intro.md +++ b/docs/articles/intro.md @@ -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; } } diff --git a/docs/examples/Simulation/IRMissileSimulation.cs b/docs/examples/Simulation/IRMissileSimulation.cs index ce4c0ed..5014f7a 100644 --- a/docs/examples/Simulation/IRMissileSimulation.cs +++ b/docs/examples/Simulation/IRMissileSimulation.cs @@ -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}米"); } } } \ No newline at end of file diff --git a/docs/examples/Simulation/README.md b/docs/examples/Simulation/README.md index aec530a..468fcf2 100644 --- a/docs/examples/Simulation/README.md +++ b/docs/examples/Simulation/README.md @@ -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}秒"); } } ``` diff --git a/docs/project/develop_log.md b/docs/project/develop_log.md index a5a01b3..97b0fed 100644 --- a/docs/project/develop_log.md +++ b/docs/project/develop_log.md @@ -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 方法中 - 完善了指示器的烟幕遮挡计算逻辑 diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs index 7b76c51..18d734f 100644 --- a/tools/ComprehensiveMissileSimulator.cs +++ b/tools/ComprehensiveMissileSimulator.cs @@ -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; + /// /// 获取当前选中导弹的显示名称 /// @@ -66,6 +69,21 @@ namespace ThreatSource.Tools.MissileSimulation /// 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."); + } + } /// /// 初始化导弹-干扰映射关系 @@ -91,51 +126,51 @@ namespace ThreatSource.Tools.MissileSimulation missileJammingMap = new Dictionary>(); // 激光驾束导弹 - 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", "遮蔽", "子弹药") - }; + ]; } /// @@ -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); + } } } \ No newline at end of file diff --git a/tools/Program.cs b/tools/Program.cs index 64cc045..c8e56ca 100644 --- a/tools/Program.cs +++ b/tools/Program.cs @@ -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("无效输入,请输入数字。"); + } } } }