diff --git a/Models/.DS_Store b/Models/.DS_Store deleted file mode 100644 index 1212d97..0000000 Binary files a/Models/.DS_Store and /dev/null differ diff --git a/Models/BasicGuidanceSystem.cs b/Models/BasicGuidanceSystem.cs deleted file mode 100644 index 00f3a87..0000000 --- a/Models/BasicGuidanceSystem.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; - -namespace ActiveProtect.Models -{ - /// - /// 制导系统接口 - /// - public interface IGuidanceSystem - { - bool HasGuidance { get; } - void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity); - Vector3D GetGuidanceAcceleration(); - } - - /// - /// 基础制导系统 - /// - public class BasicGuidanceSystem : IGuidanceSystem - { - /// - /// 是否有制导 - /// - public bool HasGuidance { get; protected set; } - - /// - /// 最大加速度 - /// - public double MaxAcceleration { get; set; } - - /// - /// 制导系数 - /// - public double ProportionalNavigationCoefficient { get; set; } - - /// - /// 导弹位置 - /// - protected Vector3D Position { get; set; } - - /// - /// 导弹速度 - /// - protected Vector3D Velocity { get; set; } - - /// - /// 制导加速度 - /// - protected Vector3D GuidanceAcceleration { get; set; } - - public BasicGuidanceSystem(double maxAcceleration, double proportionalNavigationCoefficient) - { - HasGuidance = false; - GuidanceAcceleration = Vector3D.Zero; - Position = Vector3D.Zero; - Velocity = Vector3D.Zero; - MaxAcceleration = maxAcceleration; - ProportionalNavigationCoefficient = proportionalNavigationCoefficient; - } - - /// - /// 更新制导系统 - /// - /// 时间步长 - /// 导弹位置 - /// 导弹速度 - public virtual void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity) - { - Position = missilePosition; - Velocity = missileVelocity; - } - - /// - /// 获取制导加速度 - /// - /// 制导加速度 - public Vector3D GetGuidanceAcceleration() - { - return GuidanceAcceleration; - } - - /// - /// 计算制导加速度 - /// - /// 时间步长 - protected virtual void CalculateGuidanceAcceleration(double deltaTime) - { - // 基础制导系统不计算制导指令 - // 派生类应该重写这个方法来实现特定的制导逻辑 - } - - /// - /// 计算比例导引加速度 - /// - /// 比例导引系数 - /// 导弹位置 - /// 导弹速度 - /// 目标位置 - /// 目标速度 - /// 比例导引加速度 - protected static Vector3D CalculateProportionalNavigation(double proportionalNavigationCoefficient, Vector3D missilePosition, Vector3D missileVelocity, Vector3D targetPosition, Vector3D targetVelocity) - { - // 预测时间(预测目标前进方向该时间后到达的位置,可以调整) - double predictionTime = 0.01; - - // 预测目标位置 - Vector3D predictedTargetPosition = targetPosition + targetVelocity * predictionTime; - - Vector3D r = predictedTargetPosition - missilePosition; - Vector3D v = targetVelocity - missileVelocity; - - Vector3D LOS = r.Normalize(); - Vector3D LOSRate = (v - (LOS * Vector3D.DotProduct(v, LOS))) / r.Magnitude(); - - Vector3D acceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), missileVelocity.Normalize()) * proportionalNavigationCoefficient * missileVelocity.Magnitude(); - - return acceleration; - } - - /// - /// 四阶龙格库塔法计算导弹运动状态 - /// - /// 时间步长 - /// 导弹位置 - /// 导弹速度 - /// 导弹加速度 - /// 新的位置和速度 - public static (Vector3D newPosition, Vector3D newVelocity) RungeKutta4(double deltaTime, Vector3D position, Vector3D velocity, Vector3D acceleration) - { - // 定义一个局部函数来计算加速度 - Vector3D AccelerationFunction(Vector3D pos, Vector3D vel) - { - // 这里可以添加更复杂的加速度计算,比如考虑空气阻力等 - return acceleration; - } - - // 第一步 - Vector3D k1v = AccelerationFunction(position, velocity) * deltaTime; - Vector3D k1r = velocity * deltaTime; - - // 第二步 - Vector3D k2v = AccelerationFunction(position + k1r * 0.5, velocity + k1v * 0.5) * deltaTime; - Vector3D k2r = (velocity + k1v * 0.5) * deltaTime; - - // 第三步 - Vector3D k3v = AccelerationFunction(position + k2r * 0.5, velocity + k2v * 0.5) * deltaTime; - Vector3D k3r = (velocity + k2v * 0.5) * deltaTime; - - // 第四步 - Vector3D k4v = AccelerationFunction(position + k3r, velocity + k3v) * deltaTime; - Vector3D k4r = (velocity + k3v) * deltaTime; - - // 计算新的位置和速度 - Vector3D newPosition = position + (k1r + k2r * 2 + k3r * 2 + k4r) / 6; - Vector3D newVelocity = velocity + (k1v + k2v * 2 + k3v * 2 + k4v) / 6; - - return (newPosition, newVelocity); - } - - /// - /// 获取制导系统状态 - /// - /// 制导系统状态 - public virtual string GetStatus() - { - return $" 导引头状态: 有制导={HasGuidance}, 位置={Position}, 速度={Velocity}, 制导加速度={GuidanceAcceleration}"; - } - } -} diff --git a/Models/Sensors.cs b/Models/Sensors.cs deleted file mode 100644 index 314f235..0000000 --- a/Models/Sensors.cs +++ /dev/null @@ -1,366 +0,0 @@ -using System; -using ActiveProtect.SimulationEnvironment; - -namespace ActiveProtect.Models -{ - /// - /// 定义传感器的基本接口 - /// - public interface ISensor - { - /// - /// 获取或设置传感器是否处于激活状态 - /// - bool IsActive { get; set; } - - /// - /// 激活传感器 - /// - void Activate(); - - /// - /// 停用传感器 - /// - void Deactivate(); - - /// - /// 更新传感器状态 - /// - /// 自上次更新以来的时间间隔 - void Update(double deltaTime); - - /// - /// 获取传感器数据 - /// - /// 传感器采集的数据 - SensorData GetSensorData(); - } - - /// - /// 传感器的抽象基类,实现了ISensor接口的基本功能 - /// - public abstract class Sensor : ISensor - { - /// - /// 获取或设置传感器是否处于激活状态 - /// - public bool IsActive { get; set; } - - /// - /// 传感器的位置 - /// - protected Vector3D Position { get; set; } - - /// - /// 传感器的朝向 - /// - protected Orientation Orientation { get; set; } - - /// - /// 构造函数 - /// - /// 传感器的初始位置 - /// 传感器的初始朝向 - protected Sensor(Vector3D position, Orientation orientation) - { - Position = position; - Orientation = orientation; - IsActive = false; - } - - /// - /// 激活传感器 - /// - public virtual void Activate() - { - IsActive = true; - } - - /// - /// 停用传感器 - /// - public virtual void Deactivate() - { - IsActive = false; - } - - /// - /// 更新传感器状态(需要在子类中实现) - /// - /// 自上次更新以来的时间间隔 - public abstract void Update(double deltaTime); - - /// - /// 获取传感器数据(需要在子类中实现) - /// - /// 传感器采集的数据 - public abstract SensorData GetSensorData(); - } - - /// - /// 红外探测器类 - /// - public class InfraredDetector : Sensor - { - /// - /// 探测范围 - /// - public double DetectionRange { get; set; } - - /// - /// 视场角 - /// - public double FieldOfView { get; set; } - - /// - /// 构造函数 - /// - /// 探测器的位置 - /// 探测器的朝向 - /// 探测范围 - /// 视场角 - public InfraredDetector(Vector3D position, Orientation orientation, double detectionRange, double fieldOfView) - : base(position, orientation) - { - DetectionRange = detectionRange; - FieldOfView = fieldOfView; - } - - /// - /// 更新红外探测器的状态 - /// - /// 自上次更新以来的时间间隔 - public override void Update(double deltaTime) - { - // 实现红外探测器的更新逻辑 - } - - /// - /// 获取红外探测器的数据 - /// - /// 红外探测器采集的数据 - public override SensorData GetSensorData() - { - // 返回红外探测器的数据 - return new InfraredSensorData(); - } - } - - /// - /// 毫米波辐射计类 - /// - public class MillimeterWaveRadiometer : Sensor - { - /// - /// 工作频率(3mm 或 8mm) - /// - public double Frequency { get; set; } - - /// - /// 辐射温度差检测阈值,辐射计高温物体与低温物体的检测温差,单位K,默认 50K - /// - public double DetectionTemperatureDifferenceThreshold { get; set; } = 50; - - /// - /// 构造函数 - /// - /// 辐射计的位置 - /// 辐射计的朝向 - /// 工作频率 - /// 辐射温差检测阈值 - public MillimeterWaveRadiometer(Vector3D position, Orientation orientation, double frequency, double detectionTemperatureDifferenceThreshold) - : base(position, orientation) - { - Frequency = frequency; - DetectionTemperatureDifferenceThreshold = detectionTemperatureDifferenceThreshold; - } - - /// - /// 更新毫米波辐射计的状态 - /// - /// 自上次更新以来的时间间隔 - public override void Update(double deltaTime) - { - // 实现毫米波辐射计的更新逻辑 - } - - /// - /// 获取毫米波辐射计的数据 - /// - /// 毫米波辐射计采集的数据 - public override SensorData GetSensorData() - { - // 返回毫米波辐射计的数据 - return new RadiometerSensorData(); - } - } - - /// - /// 毫米波测高雷达类 - /// - public class MillimeterWaveAltimeter : Sensor - { - private double currentAltitude; - - private readonly TerminalSensitiveSubmunition submunition; - - /// - /// 最大测量高度 - /// - public double MaxAltitude { get; set; } - - /// - /// 测量精度 - /// - public double Accuracy { get; set; } - - /// - /// 构造函数 - /// - /// 测高雷达的位置 - /// 测高雷达的朝向 - /// 最大测量高度 - /// 测量精度 - public MillimeterWaveAltimeter(TerminalSensitiveSubmunition submunition, double maxAltitude, double accuracy) - : base(submunition.Position, submunition.Orientation) - { - MaxAltitude = maxAltitude; - Accuracy = accuracy; - currentAltitude = 0; - this.submunition = submunition; - } - - /// - /// 更新毫米波测高雷达的状态 - /// - /// 自上次更新以来的时间间隔 - public override void Update(double deltaTime) - { - // 更新当前高度,考虑测量精度 - currentAltitude = submunition.Position.Y + Accuracy * new Random().NextDouble(); - } - - /// - /// 获取毫米波测高雷达的数据 - /// - /// 毫米波测高雷达采集的数据 - public override SensorData GetSensorData() - { - // 返回毫米波测高雷达的数据 - AltimeterSensorData altimeterSensorData = new AltimeterSensorData - { - Altitude = currentAltitude - }; - return altimeterSensorData; - } - } - - /// - /// 激光测距仪类 - /// - public class LaserRangefinder : Sensor - { - /// - /// 最大测量距离 - /// - public double MaxRange { get; set; } - - /// - /// 脉冲频率 - /// - public double PulseRate { get; set; } - - /// - /// 构造函数 - /// - /// 测距仪的位置 - /// 测距仪的朝向 - /// 最大测量距离 - /// 脉冲频率 - public LaserRangefinder(Vector3D position, Orientation orientation, double maxRange, double pulseRate) - : base(position, orientation) - { - MaxRange = maxRange; - PulseRate = pulseRate; - } - - /// - /// 更新激光测距仪的状态 - /// - /// 自上次更新以来的时间间隔 - public override void Update(double deltaTime) - { - // 实现激光测距仪的更新逻辑 - } - - /// - /// 获取激光测距仪的数据 - /// - /// 激光测距仪采集的数据 - public override SensorData GetSensorData() - { - // 返回激光测距仪的数据 - return new RangefinderSensorData(); - } - } - - /// - /// 传感器数据的抽象基类 - /// - public abstract class SensorData - { - /// - /// 数据采集的时间戳 - /// - public DateTime Timestamp { get; set; } - } - - /// - /// 红外传感器数据类 - /// - public class InfraredSensorData : SensorData - { - /// - /// 探测到的温度 - /// - public double Temperature { get; set; } - - /// - /// 目标方向(如果检测到目标) - /// - public Vector3D? TargetDirection { get; set; } - } - - /// - /// 辐射计传感器数据类 - /// - public class RadiometerSensorData : SensorData - { - /// - /// 探测到的辐射强度 - /// - public double RadiationIntensity { get; set; } - } - - /// - /// 测高仪传感器数据类 - /// - public class AltimeterSensorData : SensorData - { - /// - /// 测量的高度 - /// - public double Altitude { get; set; } - } - - /// - /// 测距仪传感器数据类 - /// - public class RangefinderSensorData : SensorData - { - /// - /// 测量的距离 - /// - public double Distance { get; set; } - } -} diff --git a/Program.cs b/Program.cs index b39336f..5a9853c 100644 --- a/Program.cs +++ b/Program.cs @@ -1,8 +1,8 @@ using System; using System.Threading; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using ActiveProtect.Models; -using Model; +using ActiveProtect.Utility; using System.Collections.Generic; namespace ActiveProtect @@ -114,8 +114,8 @@ namespace ActiveProtect // 末敏弹配置 new() { Id = "TSM_1", - InitialPosition = new Vector3D(4000, 0, 100), // 发射位置 - InitialOrientation = new Orientation(Math.PI, Math.PI/8, 0), // 使用计算得到的发射角度 + InitialPosition = new Vector3D(3000, 0, 100), // 发射位置 + InitialOrientation = new Orientation(Math.PI, 0, 0), // 使用计算得到的发射角度 InitialSpeed = 800, MaxSpeed = 1000, TargetIndex = 0, @@ -125,6 +125,7 @@ namespace ActiveProtect MaxEngineBurnTime = 0, MaxAcceleration = 10, ProportionalNavigationCoefficient = 3, + ExplosionRadius = 5, Mass = 50, Type = MissileType.TerminalSensitiveMissile }, diff --git a/Docs/Design.md b/src/Docs/Design.md similarity index 100% rename from Docs/Design.md rename to src/Docs/Design.md diff --git a/Docs/DesignMissile.md b/src/Docs/DesignMissile.md similarity index 100% rename from Docs/DesignMissile.md rename to src/Docs/DesignMissile.md diff --git a/Docs/DesignSeeker.md b/src/Docs/DesignSeeker.md similarity index 100% rename from Docs/DesignSeeker.md rename to src/Docs/DesignSeeker.md diff --git a/Models/Tank.cs b/src/Models/Equipment/Tank.cs similarity index 85% rename from Models/Tank.cs rename to src/Models/Equipment/Tank.cs index aa0eb7c..e56ed7f 100644 --- a/Models/Tank.cs +++ b/src/Models/Equipment/Tank.cs @@ -1,5 +1,6 @@ -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -38,6 +39,11 @@ namespace ActiveProtect.Models /// public double RadarCrossSection { get; set; } + /// + /// 坦克配置 + /// + public TankConfig TankConfig { get; private set; } + /// /// 构造函数 /// @@ -46,12 +52,13 @@ namespace ActiveProtect.Models public Tank(TankConfig tankConfig, ISimulationManager simulationManager) : base(tankConfig.Id, tankConfig.InitialPosition, tankConfig.InitialOrientation, tankConfig.InitialSpeed, simulationManager) { - Speed = tankConfig.InitialSpeed; - MaxSpeed = tankConfig.MaxSpeed; - MaxArmor = tankConfig.MaxArmor; - CurrentArmor = tankConfig.MaxArmor; - InfraredRadiationIntensity = tankConfig.InfraredRadiationIntensity; - RadarCrossSection = tankConfig.RadarCrossSection; + TankConfig = tankConfig; + Speed = TankConfig.InitialSpeed; + MaxSpeed = TankConfig.MaxSpeed; + MaxArmor = TankConfig.MaxArmor; + CurrentArmor = TankConfig.MaxArmor; + InfraredRadiationIntensity = TankConfig.InfraredRadiationIntensity; + RadarCrossSection = TankConfig.RadarCrossSection; IsActive = false; } diff --git a/src/Models/Guidance/BasicGuidanceSystem.cs b/src/Models/Guidance/BasicGuidanceSystem.cs new file mode 100644 index 0000000..bf98be3 --- /dev/null +++ b/src/Models/Guidance/BasicGuidanceSystem.cs @@ -0,0 +1,101 @@ +using System; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 制导系统接口 + /// + public interface IGuidanceSystem + { + bool HasGuidance { get; } + void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity); + Vector3D GetGuidanceAcceleration(); + } + + /// + /// 基础制导系统 + /// + public class BasicGuidanceSystem : IGuidanceSystem + { + /// + /// 是否有制导 + /// + public bool HasGuidance { get; protected set; } + + /// + /// 最大加速度 + /// + public double MaxAcceleration { get; set; } + + /// + /// 制导系数 + /// + public double ProportionalNavigationCoefficient { get; set; } + + /// + /// 导弹位置 + /// + protected Vector3D Position { get; set; } + + /// + /// 导弹速度 + /// + protected Vector3D Velocity { get; set; } + + /// + /// 制导加速度 + /// + protected Vector3D GuidanceAcceleration { get; set; } + + public BasicGuidanceSystem(double maxAcceleration, double proportionalNavigationCoefficient) + { + HasGuidance = false; + GuidanceAcceleration = Vector3D.Zero; + Position = Vector3D.Zero; + Velocity = Vector3D.Zero; + MaxAcceleration = maxAcceleration; + ProportionalNavigationCoefficient = proportionalNavigationCoefficient; + } + + /// + /// 更新制导系统 + /// + /// 时间步长 + /// 导弹位置 + /// 导弹速度 + public virtual void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity) + { + Position = missilePosition; + Velocity = missileVelocity; + } + + /// + /// 获取制导加速度 + /// + /// 制导加速度 + public Vector3D GetGuidanceAcceleration() + { + return GuidanceAcceleration; + } + + /// + /// 计算制导加速度 + /// + /// 时间步长 + protected virtual void CalculateGuidanceAcceleration(double deltaTime) + { + // 基础制导系统不计算制导指令 + // 派生类应该重写这个方法来实现特定的制导逻辑 + } + + /// + /// 获取制导系统状态 + /// + /// 制导系统状态 + public virtual string GetStatus() + { + return $" 导引头状态: 有制导={HasGuidance}, 位置={Position}, 速度={Velocity}, 制导加速度={GuidanceAcceleration}"; + } + } +} diff --git a/Models/InfraredCommandGuidanceSystem.cs b/src/Models/Guidance/InfraredCommandGuidanceSystem.cs similarity index 98% rename from Models/InfraredCommandGuidanceSystem.cs rename to src/Models/Guidance/InfraredCommandGuidanceSystem.cs index ad3462c..ece9b4f 100644 --- a/Models/InfraredCommandGuidanceSystem.cs +++ b/src/Models/Guidance/InfraredCommandGuidanceSystem.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/InfraredImagingGuidanceSystem.cs b/src/Models/Guidance/InfraredImagingGuidanceSystem.cs similarity index 94% rename from Models/InfraredImagingGuidanceSystem.cs rename to src/Models/Guidance/InfraredImagingGuidanceSystem.cs index 8dc5864..9ae7d25 100644 --- a/Models/InfraredImagingGuidanceSystem.cs +++ b/src/Models/Guidance/InfraredImagingGuidanceSystem.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -38,7 +39,7 @@ namespace ActiveProtect.Models lastTargetPosition = tankPosition; // 使用基类的比例控制算法 - GuidanceAcceleration = CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity); + GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity); // 限制最大加速度 if (GuidanceAcceleration.Magnitude() > MaxAcceleration) { diff --git a/Models/LaserBeamRiderGuidanceSystem.cs b/src/Models/Guidance/LaserBeamRiderGuidanceSystem.cs similarity index 99% rename from Models/LaserBeamRiderGuidanceSystem.cs rename to src/Models/Guidance/LaserBeamRiderGuidanceSystem.cs index 80ca862..a6145a5 100644 --- a/Models/LaserBeamRiderGuidanceSystem.cs +++ b/src/Models/Guidance/LaserBeamRiderGuidanceSystem.cs @@ -1,4 +1,5 @@ using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/LaserSemiActiveGuidanceSystem.cs b/src/Models/Guidance/LaserSemiActiveGuidanceSystem.cs similarity index 97% rename from Models/LaserSemiActiveGuidanceSystem.cs rename to src/Models/Guidance/LaserSemiActiveGuidanceSystem.cs index 990f7db..cea0fdd 100644 --- a/Models/LaserSemiActiveGuidanceSystem.cs +++ b/src/Models/Guidance/LaserSemiActiveGuidanceSystem.cs @@ -1,4 +1,5 @@ using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -161,7 +162,7 @@ namespace ActiveProtect.Models protected override void CalculateGuidanceAcceleration(double deltaTime) { // 计算比例导引加速度 - GuidanceAcceleration = CalculateProportionalNavigation(ProportionalNavigationCoefficient, Position, Velocity, TargetPosition, TargetVelocity); + GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(ProportionalNavigationCoefficient, Position, Velocity, TargetPosition, TargetVelocity); // 限制最大加速度 double maxAcceleration = 100; // 根据实际情况调整 diff --git a/Models/MillimeterWaveGuidanceSystem.cs b/src/Models/Guidance/MillimeterWaveGuidanceSystem.cs similarity index 85% rename from Models/MillimeterWaveGuidanceSystem.cs rename to src/Models/Guidance/MillimeterWaveGuidanceSystem.cs index 64bdc35..c95b6da 100644 --- a/Models/MillimeterWaveGuidanceSystem.cs +++ b/src/Models/Guidance/MillimeterWaveGuidanceSystem.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -17,6 +18,8 @@ namespace ActiveProtect.Models private readonly Random random = new(); private Vector3D lastTargetPosition; + private bool isJammed = false; + private double jammingPower = 0; public ISimulationManager SimulationManager { get; set; } @@ -27,6 +30,15 @@ namespace ActiveProtect.Models { SimulationManager = simulationManager; lastTargetPosition = Vector3D.Zero; + + // 订阅干扰事件 + simulationManager.SubscribeToEvent(HandleJammingEvent); + } + + private void HandleJammingEvent(MillimeterWaveJammingEvent evt) + { + isJammed = true; + jammingPower = evt.JammingPower; } /// @@ -43,7 +55,7 @@ namespace ActiveProtect.Models lastTargetPosition = tankPosition; // 使用基类的比例控制算法 - GuidanceAcceleration = CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity); + GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity); if (GuidanceAcceleration.Magnitude() > MaxAcceleration) { @@ -65,6 +77,13 @@ namespace ActiveProtect.Models { targetPosition = Vector3D.Zero; + // 如果被干扰,直接返回false + if (isJammed) + { + Console.WriteLine($"毫米波导引头受到干扰,干扰功率: {jammingPower:F2}W"); + return false; + } + foreach (var element in SimulationManager.GetElements()) { if (element is Tank tank) diff --git a/Models/InfraredTracker.cs b/src/Models/Indicator/InfraredTracker.cs similarity index 98% rename from Models/InfraredTracker.cs rename to src/Models/Indicator/InfraredTracker.cs index d1ba957..8f4f0b2 100644 --- a/Models/InfraredTracker.cs +++ b/src/Models/Indicator/InfraredTracker.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/LaserBeamRider.cs b/src/Models/Indicator/LaserBeamRider.cs similarity index 98% rename from Models/LaserBeamRider.cs rename to src/Models/Indicator/LaserBeamRider.cs index b7935b8..510f8f7 100644 --- a/Models/LaserBeamRider.cs +++ b/src/Models/Indicator/LaserBeamRider.cs @@ -1,5 +1,6 @@ -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/LaserDesignator.cs b/src/Models/Indicator/LaserDesignator.cs similarity index 99% rename from Models/LaserDesignator.cs rename to src/Models/Indicator/LaserDesignator.cs index 1fbe6c2..d92536e 100644 --- a/Models/LaserDesignator.cs +++ b/src/Models/Indicator/LaserDesignator.cs @@ -1,5 +1,6 @@ -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/src/Models/Jammer/IJammer.cs b/src/Models/Jammer/IJammer.cs new file mode 100644 index 0000000..2f4131a --- /dev/null +++ b/src/Models/Jammer/IJammer.cs @@ -0,0 +1,34 @@ + +namespace ActiveProtect.Models +{ + /// + /// 干扰设备接口 + /// + public interface IJammer + { + /// + /// 是否正在干扰 + /// + bool IsJamming { get; } + + /// + /// 当前干扰功率 + /// + double CurrentJammingPower { get; } + + /// + /// 开始干扰 + /// + void StartJamming(); + + /// + /// 停止干扰 + /// + void StopJamming(); + + /// + /// 获取干扰状态 + /// + string GetJammingStatus(); + } +} \ No newline at end of file diff --git a/src/Models/Jammer/JammerBase.cs b/src/Models/Jammer/JammerBase.cs new file mode 100644 index 0000000..133161d --- /dev/null +++ b/src/Models/Jammer/JammerBase.cs @@ -0,0 +1,120 @@ +using System; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 干扰设备基类 + /// + public abstract class JammerBase : SimulationElement, IJammer + { + /// + /// 是否正在干扰 + /// + public bool IsJamming { get; protected set; } + + /// + /// 当前干扰功率 + /// + public double CurrentJammingPower { get; protected set; } + + /// + /// 最大干扰功率 + /// + protected double MaxJammingPower { get; set; } + + /// + /// 功率增长率 + /// + protected double PowerIncreaseRate { get; set; } + + /// + /// 最大冷却时间 + /// + protected double MaxCooldownTime { get; set; } + + /// + /// 当前冷却时间 + /// + protected double CurrentCooldownTime { get; set; } + + /// + /// 所属坦克ID + /// + protected string TankId { get; set; } + + protected JammerBase(string id, Vector3D position, Orientation orientation, + ISimulationManager manager, string tankId, double maxJammingPower, + double initialJammingPower, double powerIncreaseRate, double maxCooldownTime) + : base(id, position, orientation, 0, manager) + { + TankId = tankId; + MaxJammingPower = maxJammingPower; + CurrentJammingPower = initialJammingPower; + PowerIncreaseRate = powerIncreaseRate; + MaxCooldownTime = maxCooldownTime; + CurrentCooldownTime = 0; + IsJamming = false; + } + + public virtual void StartJamming() + { + if (CurrentCooldownTime <= 0 && !IsJamming) + { + IsJamming = true; + Console.WriteLine($"干扰器 {Id} 开始干扰"); + } + } + + public virtual void StopJamming() + { + if (IsJamming) + { + IsJamming = false; + CurrentCooldownTime = MaxCooldownTime; + CurrentJammingPower = MaxJammingPower * 0.4; // 重置为最大功率的40% + Console.WriteLine($"干扰器 {Id} 停止干扰,进入冷却"); + } + } + + public abstract string GetJammingStatus(); + + public override void Update(double deltaTime) + { + if (!IsActive) return; + + if (IsJamming) + { + UpdateJammingPower(deltaTime); + PublishJammingEvent(); + } + else if (CurrentCooldownTime > 0) + { + CurrentCooldownTime = Math.Max(0, CurrentCooldownTime - deltaTime); + } + + // 更新位置(跟随坦克) + if (SimulationManager.GetEntityById(TankId) is Tank tank) + { + Position = tank.Position; + Orientation = tank.Orientation; + } + } + + public override void Activate() + { + base.Activate(); + StartJamming(); + } + + public override void Deactivate() + { + StopJamming(); + base.Deactivate(); + } + + protected abstract void UpdateJammingPower(double deltaTime); + protected abstract void PublishJammingEvent(); + } +} \ No newline at end of file diff --git a/Models/LaserJammer.cs b/src/Models/Jammer/LaserJammer.cs similarity index 99% rename from Models/LaserJammer.cs rename to src/Models/Jammer/LaserJammer.cs index 2674088..d390827 100644 --- a/Models/LaserJammer.cs +++ b/src/Models/Jammer/LaserJammer.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/src/Models/Jammer/MillimeterWaveJammer.cs b/src/Models/Jammer/MillimeterWaveJammer.cs new file mode 100644 index 0000000..26dad38 --- /dev/null +++ b/src/Models/Jammer/MillimeterWaveJammer.cs @@ -0,0 +1,151 @@ +using System; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 毫米波干扰器 + /// + public class MillimeterWaveJammer : SimulationElement + { + /// + /// 最大干扰功率(瓦特) + /// + private readonly double maxJammingPower; + + /// + /// 当前干扰功率(瓦特) + /// + private double currentJammingPower; + + /// + /// 干扰功率增长率(瓦特/秒) + /// + private readonly double powerIncreaseRate; + + /// + /// 最大干扰冷却时间(秒) + /// + private readonly double maxJammingCooldown; + + /// + /// 当前冷却时间(秒) + /// + private double currentCooldown; + + /// + /// 是否正在干扰 + /// + private bool isJamming; + + /// + /// 所属坦克ID + /// + private readonly string tankId; + + /// + /// 干扰器构造函数 + /// + public MillimeterWaveJammer(string id, Vector3D position, Orientation orientation, + ISimulationManager manager, string tankId, MillimeterWaveJammerConfig config) + : base(id, position, orientation, 0, manager) + { + this.tankId = tankId; + maxJammingPower = config.MaxJammingPower; + currentJammingPower = config.InitialJammingPower; + powerIncreaseRate = config.PowerIncreaseRate; + maxJammingCooldown = config.MaxJammingCooldown; + currentCooldown = 0; + isJamming = false; + } + + /// + /// 更新干扰器状态 + /// + public override void Update(double deltaTime) + { + if (!IsActive) return; + + if (isJamming) + { + // 增加干扰功率 + currentJammingPower = Math.Min(maxJammingPower, + currentJammingPower + powerIncreaseRate * deltaTime); + + // 发布干扰事件 + SimulationManager.PublishEvent(new MillimeterWaveJammingEvent + { + SenderId = Id, + Timestamp = SimulationManager.CurrentTime, + TargetId = tankId, + JammingPower = currentJammingPower + }); + } + else if (currentCooldown > 0) + { + // 更新冷却时间 + currentCooldown = Math.Max(0, currentCooldown - deltaTime); + } + + // 更新位置(跟随坦克) + if (SimulationManager.GetEntityById(tankId) is Tank tank) + { + Position = tank.Position; + Orientation = tank.Orientation; + } + } + + /// + /// 开始干扰 + /// + public void StartJamming() + { + if (currentCooldown <= 0 && !isJamming) + { + isJamming = true; + Console.WriteLine($"毫米波干扰器 {Id} 开始干扰"); + } + } + + /// + /// 停止干扰 + /// + public void StopJamming() + { + if (isJamming) + { + isJamming = false; + currentCooldown = maxJammingCooldown; + currentJammingPower = maxJammingPower * 0.4; // 重置为最大功率的40% + Console.WriteLine($"毫米波干扰器 {Id} 停止干扰,进入冷却"); + } + } + public override void Activate() + { + base.Activate(); + StartJamming(); + } + + /// + /// 销毁干扰器 + /// + public override void Deactivate() + { + StopJamming(); + base.Deactivate(); + } + + /// + /// 获取干扰器状态 + /// + public override string GetStatus() + { + return $"毫米波干扰器 {Id}:\n" + + $" 位置: {Position}\n" + + $" 干扰功率: {currentJammingPower:F2}/{maxJammingPower:F2}\n" + + $" 冷却时间: {currentCooldown:F2}/{maxJammingCooldown:F2}\n" + + $" 状态: {(isJamming ? "干扰中" : "待机中")}"; + } + } +} diff --git a/Models/InfraredCommandGuidedMissile.cs b/src/Models/MIssile/InfraredCommandGuidedMissile.cs similarity index 98% rename from Models/InfraredCommandGuidedMissile.cs rename to src/Models/MIssile/InfraredCommandGuidedMissile.cs index f9dd932..e9ce256 100644 --- a/Models/InfraredCommandGuidedMissile.cs +++ b/src/Models/MIssile/InfraredCommandGuidedMissile.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/InfraredImagingTerminalGuidedMissile.cs b/src/Models/MIssile/InfraredImagingTerminalGuidedMissile.cs similarity index 98% rename from Models/InfraredImagingTerminalGuidedMissile.cs rename to src/Models/MIssile/InfraredImagingTerminalGuidedMissile.cs index 398c250..774377b 100644 --- a/Models/InfraredImagingTerminalGuidedMissile.cs +++ b/src/Models/MIssile/InfraredImagingTerminalGuidedMissile.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/LaserBeamRiderMissile.cs b/src/Models/MIssile/LaserBeamRiderMissile.cs similarity index 99% rename from Models/LaserBeamRiderMissile.cs rename to src/Models/MIssile/LaserBeamRiderMissile.cs index f634873..5d6bb56 100644 --- a/Models/LaserBeamRiderMissile.cs +++ b/src/Models/MIssile/LaserBeamRiderMissile.cs @@ -1,5 +1,5 @@ -using ActiveProtect.SimulationEnvironment; - +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { public class LaserBeamRiderMissile : MissileBase diff --git a/Models/LaserSemiActiveGuidedMissile.cs b/src/Models/MIssile/LaserSemiActiveGuidedMissile.cs similarity index 99% rename from Models/LaserSemiActiveGuidedMissile.cs rename to src/Models/MIssile/LaserSemiActiveGuidedMissile.cs index a479ef3..3a2e3c4 100644 --- a/Models/LaserSemiActiveGuidedMissile.cs +++ b/src/Models/MIssile/LaserSemiActiveGuidedMissile.cs @@ -1,5 +1,6 @@ -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/MillimeterWaveTerminalGuidedMissile.cs b/src/Models/MIssile/MillimeterWaveTerminalGuidedMissile.cs similarity index 98% rename from Models/MillimeterWaveTerminalGuidedMissile.cs rename to src/Models/MIssile/MillimeterWaveTerminalGuidedMissile.cs index fa555bf..c1189a7 100644 --- a/Models/MillimeterWaveTerminalGuidedMissile.cs +++ b/src/Models/MIssile/MillimeterWaveTerminalGuidedMissile.cs @@ -1,5 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/Models/MissileBase.cs b/src/Models/MIssile/MissileBase.cs similarity index 94% rename from Models/MissileBase.cs rename to src/Models/MIssile/MissileBase.cs index 3ec1080..84be168 100644 --- a/Models/MissileBase.cs +++ b/src/Models/MIssile/MissileBase.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using ActiveProtect.SimulationEnvironment; -using Model; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -98,7 +98,7 @@ namespace ActiveProtect.Models /// /// 是否有制导 /// - public bool HasGuidance { get; protected set; } = false; + public bool HasGuidance { get; protected set; } /// /// 失去制导的时间(秒) @@ -109,16 +109,11 @@ namespace ActiveProtect.Models /// 最后已知的速度向量 /// protected Vector3D LastKnownVelocity = Vector3D.Zero; - - /// - /// 发射速度(米/秒) - /// - public const double LAUNCH_SPEED = 10; /// /// 导弹质量(千克) /// - public double Mass { get; protected set; } = 100; + public double Mass { get; protected set; } /// /// 制导加速度 @@ -143,6 +138,7 @@ namespace ActiveProtect.Models InitializeFromConfig(); IsActive = false; + HasGuidance = false; FlightTime = 0; FlightDistance = 0; EngineBurnTime = 0; @@ -189,8 +185,19 @@ namespace ActiveProtect.Models Vector3D acceleration = GuidanceAcceleration; - // 使用四阶龙格-库塔方法更新导弹的位置和速度 - (Position, Velocity) = BasicGuidanceSystem.RungeKutta4(deltaTime, Position, Velocity, acceleration); + if (HasGuidance) + { + // 制导条件下,使用四阶龙格-库塔方法更新导弹的位置和速度 + (Position, Velocity) = MotionAlgorithm.RungeKutta4(deltaTime, Position, Velocity, acceleration); + } + else + { + Console.WriteLine($"无制导条件下,使用运动学方程更新导弹的位置和速度"); + // 无制导条件下,使用运动学方程更新导弹的位置和速度 + (Position, Velocity) = MotionAlgorithm.CalculateBallisticMotion(Position, Velocity, acceleration, deltaTime); + } + + // 限制速度不超过最大速度 if (Velocity.Magnitude() > MaxSpeed) diff --git a/Models/MissileClass.cs b/src/Models/MIssile/MissileClass.cs similarity index 96% rename from Models/MissileClass.cs rename to src/Models/MIssile/MissileClass.cs index 410f13e..270b621 100644 --- a/Models/MissileClass.cs +++ b/src/Models/MIssile/MissileClass.cs @@ -1,6 +1,6 @@ using System; -namespace Model +namespace ActiveProtect.Models { /// /// 坦克消息结构 diff --git a/Models/TerminalSensitiveMissile.cs b/src/Models/MIssile/TerminalSensitiveMissile.cs similarity index 79% rename from Models/TerminalSensitiveMissile.cs rename to src/Models/MIssile/TerminalSensitiveMissile.cs index b133cca..87f184a 100644 --- a/Models/TerminalSensitiveMissile.cs +++ b/src/Models/MIssile/TerminalSensitiveMissile.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { @@ -11,9 +12,9 @@ namespace ActiveProtect.Models // 分离点距离目标水平距离,默认 1000 米 private const double SeparationDistance = 1000; // 分离时距离分离点的距离阈值,默认 50米 - private const double SeparationRange = 50; - // 分离时距目标距离阈值,默认 1400 米 - private const double SeparationTargetDistance = 1400; + private const double SeparationRange = 0.5; + // 分离时距目标距离阈值,默认 1200 米 + private const double SeparationTargetDistance = 1200; // 子弹数量, 155 口径母弹,默认 2 个 private const int SubmunitionCount = 1; // 子弹数组 @@ -28,6 +29,22 @@ namespace ActiveProtect.Models //计算分离点坐标,高度为SeparationHeight,距离目标的距离为SeparationDistance separationPoint = Vector3D.PointOnLine(base.SimulationManager.GetEntityById(TargetId).Position, base.Position, SeparationDistance) + new Vector3D(0, SeparationHeight, 0); + + //计算导弹发射角度 + (Orientation? launchOrientation, Vector3D? launchVelocity) = MotionAlgorithm.CalculateBestLaunchOrientation(Position, separationPoint, Speed); + if (!launchOrientation.HasValue || launchVelocity is null) + { + // 处理错误情况 + throw new InvalidOperationException("无法计算发射方向"); + } + else + { + Orientation = launchOrientation.Value; + Velocity = launchVelocity; + Console.WriteLine($"发射方向: {launchOrientation}"); + } + + GuidanceAcceleration = new Vector3D(0, -9.81, 0); } /// @@ -36,9 +53,8 @@ namespace ActiveProtect.Models /// 时间步长 public override void Update(double deltaTime) { - base.Update(deltaTime); - GuidanceAcceleration = new Vector3D(0, -9.8, 0); + base.Update(deltaTime); Console.WriteLine($"分离点距离: {(separationPoint - Position).Magnitude()}"); @@ -61,7 +77,7 @@ namespace ActiveProtect.Models // 获取目标位置 Vector3D targetPosition = SimulationManager.GetEntityById(TargetId).Position; - // 创建并释放子弹 + // 创建并释子弹 for (int i = 0; i < SubmunitionCount; i++) { // 计算子弹朝向目标的方向 @@ -82,7 +98,7 @@ namespace ActiveProtect.Models MaxAcceleration = 50, ProportionalNavigationCoefficient = 3, Mass = 10, - ExplosionRadius = 10 + ExplosionRadius = this.ExplosionRadius }, SimulationManager); diff --git a/Models/TerminalSensitiveSubmunition.cs b/src/Models/MIssile/TerminalSensitiveSubmunition.cs similarity index 96% rename from Models/TerminalSensitiveSubmunition.cs rename to src/Models/MIssile/TerminalSensitiveSubmunition.cs index 499cca1..ab869f6 100644 --- a/Models/TerminalSensitiveSubmunition.cs +++ b/src/Models/MIssile/TerminalSensitiveSubmunition.cs @@ -1,6 +1,6 @@ using System; -using ActiveProtect.SimulationEnvironment; - +using ActiveProtect.Simulation; +using ActiveProtect.Utility; namespace ActiveProtect.Models { public class TerminalSensitiveSubmunition : MissileBase @@ -30,6 +30,9 @@ namespace ActiveProtect.Models // 减速高度 400米 private const double DecelerationHeight = 400; + // 减速加速度 50 m/s^2 + private const double DecelerationAcceleration = 50; + // 扫描高度 200米 private const double ScanningHeight = 200; @@ -141,14 +144,15 @@ namespace ActiveProtect.Models /// private void UpdateDecelerationStage(double deltaTime) { + HasGuidance = true; // 减速减旋,垂直速度减小 - Vector3D deceleration = new Vector3D(0, 9.8, 0) - Velocity.Normalize() * 50; // 假设减速度为5m/s^2 - Console.WriteLine($"降落伞打开,减速速度: {deceleration}"); + Vector3D deceleration = - Velocity.Normalize() * DecelerationAcceleration; Velocity += deceleration * deltaTime; if (Velocity.Magnitude() <= VerticalDescentSpeed) { Velocity = new Vector3D(0, -VerticalDescentSpeed, 0); + GuidanceAcceleration = Vector3D.Zero; } if (((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= ScanningHeight) @@ -162,6 +166,7 @@ namespace ActiveProtect.Models /// private void UpdateSpiralScanStage(double deltaTime) { + Velocity = new Vector3D(0, -VerticalDescentSpeed, 0); GuidanceAcceleration = Vector3D.Zero; // 更新螺旋角度 diff --git a/src/Models/Sensor/ISensor.cs b/src/Models/Sensor/ISensor.cs new file mode 100644 index 0000000..373f6ff --- /dev/null +++ b/src/Models/Sensor/ISensor.cs @@ -0,0 +1,35 @@ +namespace ActiveProtect.Models +{ + /// + /// 定义传感器的基本接口 + /// + public interface ISensor + { + /// + /// 获取或设置传感器是否处于激活状态 + /// + bool IsActive { get; set; } + + /// + /// 激活传感器 + /// + void Activate(); + + /// + /// 停用传感器 + /// + void Deactivate(); + + /// + /// 更新传感器状态 + /// + /// 自上次更新以来的时间间隔 + void Update(double deltaTime); + + /// + /// 获取传感器数据 + /// + /// 传感器采集的数据 + SensorData GetSensorData(); + } +} diff --git a/src/Models/Sensor/InfraredDetector.cs b/src/Models/Sensor/InfraredDetector.cs new file mode 100644 index 0000000..686cbff --- /dev/null +++ b/src/Models/Sensor/InfraredDetector.cs @@ -0,0 +1,54 @@ +using ActiveProtect.Utility; +using System; +namespace ActiveProtect.Models +{ + /// + /// 红外探测器类 + /// + public class InfraredDetector : Sensor + { + /// + /// 探测范围 + /// + public double DetectionRange { get; set; } + + /// + /// 视场角 + /// + public double FieldOfView { get; set; } + + /// + /// 构造函数 + /// + /// 探测器的位置 + /// 探测器的朝向 + /// 探测范围 + /// 视场角 + public InfraredDetector(Vector3D position, Orientation orientation, double detectionRange, double fieldOfView) + : base(position, orientation) + { + DetectionRange = detectionRange; + FieldOfView = fieldOfView; + } + + /// + /// 更新红外探测器的状态 + /// + /// 自上次更新以来的时间间隔 + public override void Update(double deltaTime) + { + // 实现红外探测器的更新逻辑 + } + + /// + /// 获取红外探测器的数据 + /// + /// 红外探测器采集的数据 + public override SensorData GetSensorData() + { + // 返回红外探测器的数据 + return new InfraredSensorData(); + } + } + +} \ No newline at end of file diff --git a/src/Models/Sensor/LaserRangefinder.cs b/src/Models/Sensor/LaserRangefinder.cs new file mode 100644 index 0000000..6a45b74 --- /dev/null +++ b/src/Models/Sensor/LaserRangefinder.cs @@ -0,0 +1,54 @@ +using System; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 激光测距仪类 + /// + public class LaserRangefinder : Sensor + { + /// + /// 最大测量距离 + /// + public double MaxRange { get; set; } + + /// + /// 脉冲频率 + /// + public double PulseRate { get; set; } + + /// + /// 构造函数 + /// + /// 测距仪的位置 + /// 测距仪的朝向 + /// 最大测量距离 + /// 脉冲频率 + public LaserRangefinder(Vector3D position, Orientation orientation, double maxRange, double pulseRate) + : base(position, orientation) + { + MaxRange = maxRange; + PulseRate = pulseRate; + } + + /// + /// 更新激光测距仪的状态 + /// + /// 自上次更新以来的时间间隔 + public override void Update(double deltaTime) + { + // 实现激光测距仪的更新逻辑 + } + + /// + /// 获取激光测距仪的数据 + /// + /// 激光测距仪采集的数据 + public override SensorData GetSensorData() + { + // 返回激光测距仪的数据 + return new RangefinderSensorData(); + } + } +} \ No newline at end of file diff --git a/src/Models/Sensor/MillimeterWaveAltimeter.cs b/src/Models/Sensor/MillimeterWaveAltimeter.cs new file mode 100644 index 0000000..8ab9e84 --- /dev/null +++ b/src/Models/Sensor/MillimeterWaveAltimeter.cs @@ -0,0 +1,70 @@ +using System; + +namespace ActiveProtect.Models +{ + /// + /// 毫米波测高雷达类 + /// + public class MillimeterWaveAltimeter : Sensor + { + private double currentAltitude; + + private readonly TerminalSensitiveSubmunition submunition; + + /// + /// 最大测量高度 + /// + public double MaxAltitude { get; set; } + + /// + /// 测量精度 + /// + public double Accuracy { get; set; } + + /// + /// 构造函数 + /// + /// 测高雷达的位置 + /// 测高雷达的朝向 + /// 最大测量高度 + /// 测量精度 + public MillimeterWaveAltimeter(TerminalSensitiveSubmunition submunition, double maxAltitude, double accuracy) + : base(submunition.Position, submunition.Orientation) + { + MaxAltitude = maxAltitude; + Accuracy = accuracy; + currentAltitude = 0; + this.submunition = submunition; + } + + /// + /// 更新毫米波测高雷达的状态 + /// + /// 自上次更新以来的时间间隔 + public override void Update(double deltaTime) + { + // 更新当前高度,考虑测量精度 + currentAltitude = submunition.Position.Y + Accuracy * new Random().NextDouble(); + } + + //监听毫米波干扰事件 + public void OnMillimeterWaveJamming(object sender, EventArgs e) + { + Console.WriteLine("毫米波测高雷达受到干扰"); + } + + /// + /// 获取毫米波测高雷达的数据 + /// + /// 毫米波测高雷达采集的数据 + public override SensorData GetSensorData() + { + // 返回毫米波测高雷达的数据 + AltimeterSensorData altimeterSensorData = new AltimeterSensorData + { + Altitude = currentAltitude + }; + return altimeterSensorData; + } + } +} \ No newline at end of file diff --git a/src/Models/Sensor/MillimeterWaveRadiometer.cs b/src/Models/Sensor/MillimeterWaveRadiometer.cs new file mode 100644 index 0000000..c25fe62 --- /dev/null +++ b/src/Models/Sensor/MillimeterWaveRadiometer.cs @@ -0,0 +1,52 @@ +using ActiveProtect.Utility; +namespace ActiveProtect.Models +{ + /// + /// 毫米波辐射计类 + /// + public class MillimeterWaveRadiometer : Sensor + { + /// + /// 工作频率(3mm 或 8mm) + /// + public double Frequency { get; set; } + + /// + /// 辐射温度差检测阈值,辐射计高温物体与低温物体的检测温差,单位K,默认 50K + /// + public double DetectionTemperatureDifferenceThreshold { get; set; } = 50; + + /// + /// 构造函数 + /// + /// 辐射计的位置 + /// 辐射计的朝向 + /// 工作频率 + /// 辐射温差检测阈值 + public MillimeterWaveRadiometer(Vector3D position, Orientation orientation, double frequency, double detectionTemperatureDifferenceThreshold) + : base(position, orientation) + { + Frequency = frequency; + DetectionTemperatureDifferenceThreshold = detectionTemperatureDifferenceThreshold; + } + + /// + /// 更新毫米波辐射计的状态 + /// + /// 自上次更新以来的时间间隔 + public override void Update(double deltaTime) + { + // 实现毫米波辐射计的更新逻辑 + } + + /// + /// 获取毫米波辐射计的数据 + /// + /// 毫米波辐射计采集的数据 + public override SensorData GetSensorData() + { + // 返回毫米波辐射计的数据 + return new RadiometerSensorData(); + } + } +} \ No newline at end of file diff --git a/src/Models/Sensor/SensorData.cs b/src/Models/Sensor/SensorData.cs new file mode 100644 index 0000000..28f7dfc --- /dev/null +++ b/src/Models/Sensor/SensorData.cs @@ -0,0 +1,65 @@ +using System; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 传感器数据的抽象基类 + /// + public abstract class SensorData + { + /// + /// 数据采集的时间戳 + /// + public DateTime Timestamp { get; set; } + } + + /// + /// 红外传感器数据类 + /// + public class InfraredSensorData : SensorData + { + /// + /// 探测到的温度 + /// + public double Temperature { get; set; } + + /// + /// 目标方向(如果检测到目标) + /// + public Vector3D? TargetDirection { get; set; } + } + + /// + /// 辐射计传感器数据类 + /// + public class RadiometerSensorData : SensorData + { + /// + /// 探测到的辐射强度 + /// + public double RadiationIntensity { get; set; } + } + + /// + /// 测高仪传感器数据类 + /// + public class AltimeterSensorData : SensorData + { + /// + /// 测量的高度 + /// + public double Altitude { get; set; } + } + + /// + /// 测距仪传感器数据类 + /// + public class RangefinderSensorData : SensorData + { + /// + /// 测量的距离 + /// + public double Distance { get; set; } + } +} diff --git a/src/Models/Sensor/Sensors.cs b/src/Models/Sensor/Sensors.cs new file mode 100644 index 0000000..83c0821 --- /dev/null +++ b/src/Models/Sensor/Sensors.cs @@ -0,0 +1,67 @@ +using System; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 传感器的抽象基类,实现了ISensor接口的基本功能 + /// + public abstract class Sensor : ISensor + { + /// + /// 获取或设置传感器是否处于激活状态 + /// + public bool IsActive { get; set; } + + /// + /// 传感器的位置 + /// + protected Vector3D Position { get; set; } + + /// + /// 传感器的朝向 + /// + protected Orientation Orientation { get; set; } + + /// + /// 构造函数 + /// + /// 传感器的初始位置 + /// 传感器的初始朝向 + protected Sensor(Vector3D position, Orientation orientation) + { + Position = position; + Orientation = orientation; + IsActive = false; + } + + /// + /// 激活传感器 + /// + public virtual void Activate() + { + IsActive = true; + } + + /// + /// 停用传感器 + /// + public virtual void Deactivate() + { + IsActive = false; + } + + /// + /// 更新传感器状态(需要在子类中实现) + /// + /// 自上次更新以来的时间间隔 + public abstract void Update(double deltaTime); + + /// + /// 获取传感器数据(需要在子类中实现) + /// + /// 传感器采集的数据 + public abstract SensorData GetSensorData(); + } +} diff --git a/src/Models/Wanner/IWarner.cs b/src/Models/Wanner/IWarner.cs new file mode 100644 index 0000000..396e8f9 --- /dev/null +++ b/src/Models/Wanner/IWarner.cs @@ -0,0 +1,28 @@ +namespace ActiveProtect.Models +{ + /// + /// 告警设备接口 + /// + public interface IWarner + { + /// + /// 是否处于告警状态 + /// + bool IsWarning { get; } + + /// + /// 开始告警 + /// + void StartWarning(); + + /// + /// 停止告警 + /// + void StopWarning(); + + /// + /// 获取告警状态 + /// + string GetWarningStatus(); + } +} \ No newline at end of file diff --git a/Models/LaserWarner.cs b/src/Models/Wanner/LaserWarner.cs similarity index 98% rename from Models/LaserWarner.cs rename to src/Models/Wanner/LaserWarner.cs index 2e6cfe2..e73f99b 100644 --- a/Models/LaserWarner.cs +++ b/src/Models/Wanner/LaserWarner.cs @@ -1,5 +1,6 @@ -using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Simulation; using System; +using ActiveProtect.Utility; namespace ActiveProtect.Models { diff --git a/src/Models/Wanner/WarnerBase.cs b/src/Models/Wanner/WarnerBase.cs new file mode 100644 index 0000000..2e21a4c --- /dev/null +++ b/src/Models/Wanner/WarnerBase.cs @@ -0,0 +1,98 @@ +using System; +using ActiveProtect.Simulation; +using ActiveProtect.Utility; + +namespace ActiveProtect.Models +{ + /// + /// 告警设备基类 + /// + public abstract class WarnerBase : SimulationElement, IWarner + { + /// + /// 是否处于告警状态 + /// + public bool IsWarning { get; protected set; } + + /// + /// 告警持续时间(秒) + /// + protected double WarningDuration { get; set; } + + /// + /// 当前告警时间(秒) + /// + protected double CurrentWarningTime { get; set; } + + /// + /// 所属坦克ID + /// + protected string TankId { get; set; } + + protected WarnerBase(string id, Vector3D position, Orientation orientation, + ISimulationManager manager, string tankId, double warningDuration) + : base(id, position, orientation, 0, manager) + { + TankId = tankId; + WarningDuration = warningDuration; + CurrentWarningTime = 0; + IsWarning = false; + } + + public virtual void StartWarning() + { + if (!IsWarning) + { + IsWarning = true; + CurrentWarningTime = 0; + Console.WriteLine($"告警器 {Id} 开始告警"); + } + } + + public virtual void StopWarning() + { + if (IsWarning) + { + IsWarning = false; + CurrentWarningTime = 0; + Console.WriteLine($"告警器 {Id} 停止告警"); + } + } + + public abstract string GetWarningStatus(); + + public override void Update(double deltaTime) + { + if (!IsActive) return; + + if (IsWarning) + { + CurrentWarningTime += deltaTime; + if (CurrentWarningTime >= WarningDuration) + { + StopWarning(); + } + } + + // 更新位置(跟随坦克) + if (SimulationManager.GetEntityById(TankId) is Tank tank) + { + Position = tank.Position; + Orientation = tank.Orientation; + } + } + + public override void Activate() + { + base.Activate(); + Console.WriteLine($"告警器 {Id} 已激活"); + } + + public override void Deactivate() + { + StopWarning(); + base.Deactivate(); + Console.WriteLine($"告警器 {Id} 已停用"); + } + } +} \ No newline at end of file diff --git a/SimulationEnvironment/SimulationConfig.cs b/src/Simulation/SimulationConfig.cs similarity index 89% rename from SimulationEnvironment/SimulationConfig.cs rename to src/Simulation/SimulationConfig.cs index 3c71e63..d8d837b 100644 --- a/SimulationEnvironment/SimulationConfig.cs +++ b/src/Simulation/SimulationConfig.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; +using ActiveProtect.Utility; using ActiveProtect.Models; -using Model; -namespace ActiveProtect.SimulationEnvironment +namespace ActiveProtect.Simulation { /// /// 仿真配置类,包含整个仿真所需的所有配置信息 @@ -40,6 +40,11 @@ namespace ActiveProtect.SimulationEnvironment /// public LaserJammerConfig LaserJammerConfig { get; set; } + /// + /// 毫米波干扰器配置 + /// + public MillimeterWaveJammerConfig MillimeterWaveJammerConfig { get; set; } + /// /// 仿真时间步长(秒) /// @@ -61,6 +66,7 @@ namespace ActiveProtect.SimulationEnvironment LaserBeamRiderConfig = new LaserBeamRiderConfig(); LaserWarnerConfig = new LaserWarnerConfig(); LaserJammerConfig = new LaserJammerConfig(); + MillimeterWaveJammerConfig = new MillimeterWaveJammerConfig(); InfraredTrackerConfig = new InfraredTrackerConfig(); SimulationTimeStep = 0.1; // 默认时间步长为0.1秒 } @@ -121,6 +127,11 @@ namespace ActiveProtect.SimulationEnvironment /// public bool HasLaserJammer { get; set; } + /// + /// 是否装备毫米波干扰器 + /// + public bool HasMillimeterWaveJammer { get; set; } + /// /// 构造函数,设置默认值 /// @@ -147,6 +158,7 @@ namespace ActiveProtect.SimulationEnvironment MaxArmor = 0; HasLaserWarner = false; HasLaserJammer = false; + HasMillimeterWaveJammer = false; InfraredRadiationIntensity = 0; } @@ -521,4 +533,47 @@ namespace ActiveProtect.SimulationEnvironment UpdateFrequency = 10; // 10赫兹 } } + + /// + /// 毫米波干扰器配置类 + /// + public class MillimeterWaveJammerConfig + { + /// + /// 干扰器ID + /// + public string Id { get; set; } + + /// + /// 最大干扰功率(瓦特) + /// + public double MaxJammingPower { get; set; } + + /// + /// 初始干扰功率(瓦特) + /// + public double InitialJammingPower { get; set; } + + /// + /// 功率增长率(瓦特/秒) + /// + public double PowerIncreaseRate { get; set; } + + /// + /// 最大冷却时间(秒) + /// + public double MaxJammingCooldown { get; set; } + + /// + /// 构造函数 + /// + public MillimeterWaveJammerConfig() + { + Id = ""; + MaxJammingPower = 1000; + InitialJammingPower = 400; + PowerIncreaseRate = 200; + MaxJammingCooldown = 5; + } + } } diff --git a/SimulationEnvironment/SimulationElement.cs b/src/Simulation/SimulationElement.cs similarity index 97% rename from SimulationEnvironment/SimulationElement.cs rename to src/Simulation/SimulationElement.cs index 658a214..846f096 100644 --- a/SimulationEnvironment/SimulationElement.cs +++ b/src/Simulation/SimulationElement.cs @@ -1,7 +1,7 @@ using System; -using ActiveProtect.Models; +using ActiveProtect.Utility; -namespace ActiveProtect.SimulationEnvironment +namespace ActiveProtect.Simulation { /// /// 仿真元素的抽象基类,所有仿真中的实体都继承自此类 diff --git a/SimulationEnvironment/SimulationEvents.cs b/src/Simulation/SimulationEvents.cs similarity index 91% rename from SimulationEnvironment/SimulationEvents.cs rename to src/Simulation/SimulationEvents.cs index 5d626aa..5b328c8 100644 --- a/SimulationEnvironment/SimulationEvents.cs +++ b/src/Simulation/SimulationEvents.cs @@ -1,6 +1,7 @@ +using ActiveProtect.Utility; using ActiveProtect.Models; -namespace ActiveProtect.SimulationEnvironment +namespace ActiveProtect.Simulation { /// /// 仿真事件的基类 @@ -61,7 +62,7 @@ namespace ActiveProtect.SimulationEnvironment public SimulationElement? Target { get; set; } } - /// /// 激光照射停止事件 /// public class LaserIlluminationStopEvent : SimulationEvent @@ -205,4 +206,20 @@ namespace ActiveProtect.SimulationEnvironment public class InfraredGuidanceMissileLightOffEvent : SimulationEvent { } + + /// + /// 毫米波干扰事件 + /// + public class MillimeterWaveJammingEvent : SimulationEvent + { + /// + /// 目标ID + /// + public string? TargetId { get; set; } + + /// + /// 干扰功率(瓦特) + /// + public double JammingPower { get; set; } + } } diff --git a/SimulationEnvironment/SimulationManager.cs b/src/Simulation/SimulationManager.cs similarity index 93% rename from SimulationEnvironment/SimulationManager.cs rename to src/Simulation/SimulationManager.cs index 66f1356..195d25b 100644 --- a/SimulationEnvironment/SimulationManager.cs +++ b/src/Simulation/SimulationManager.cs @@ -2,8 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using ActiveProtect.Models; +using ActiveProtect.Utility; -namespace ActiveProtect.SimulationEnvironment +namespace ActiveProtect.Simulation { /// /// 仿真管理器接口,定义了仿真管理器的基本功能 @@ -131,6 +132,20 @@ namespace ActiveProtect.SimulationEnvironment ); Elements.Add(laserJammer); } + + // 为坦克创建毫米波干扰器 + if (tankConfig.HasMillimeterWaveJammer) + { + var millimeterWaveJammer = new MillimeterWaveJammer( + $"MMWJ_{i}", + tank.Position, + tank.Orientation, + this, + tank.Id, + config.MillimeterWaveJammerConfig + ); + Elements.Add(millimeterWaveJammer); + } } @@ -208,10 +223,10 @@ namespace ActiveProtect.SimulationEnvironment Elements.Add(infraredTracker); // 激活所有元素 - ActivateAllElements(); + //ActivateAllElements(); // 激活部分元素 - //ActivateSomeElements(); + ActivateSomeElements(); } //激活所有元素 @@ -245,18 +260,21 @@ namespace ActiveProtect.SimulationEnvironment //Elements.FindAll(e => e.Id == "LBR_1").ForEach(e => e.Activate()); // 激活红外指令制导导弹 - Elements.FindAll(e => e.Id == "ICGM_1").ForEach(e => e.Activate()); + //Elements.FindAll(e => e.Id == "ICGM_1").ForEach(e => e.Activate()); // 激活红外测角仪 - Elements.FindAll(e => e.Id == "IT_1").ForEach(e => e.Activate()); + //Elements.FindAll(e => e.Id == "IT_1").ForEach(e => e.Activate()); // 激活红外成像末制导导弹 - Elements.FindAll(e => e.Id == "ITGM_1").ForEach(e => e.Activate()); + //Elements.FindAll(e => e.Id == "ITGM_1").ForEach(e => e.Activate()); // 激活毫米波末制导导弹 //Elements.FindAll(e => e.Id == "MMWG_1").ForEach(e => e.Activate()); // 激活末敏弹 - //Elements.FindAll(e => e.Id == "TSM_1").ForEach(e => e.Activate()); + Elements.FindAll(e => e.Id == "TSM_1").ForEach(e => e.Activate()); + + // 激活毫米波干扰器 + //Elements.FindAll(e => e.Id == "MMWJ_1").ForEach(e => e.Activate()); } /// diff --git a/Models/Common.cs b/src/Utility/Common.cs similarity index 99% rename from Models/Common.cs rename to src/Utility/Common.cs index f5ff502..c5c5ae7 100644 --- a/Models/Common.cs +++ b/src/Utility/Common.cs @@ -1,7 +1,7 @@ using System; using System.Numerics; -namespace ActiveProtect.Models +namespace ActiveProtect.Utility { /// /// 表示三维空间中的向量 @@ -392,4 +392,6 @@ namespace ActiveProtect.Models /// public static Vector2D Zero => new Vector2D(0, 0); } + + } diff --git a/src/Utility/MotionAlgorithm.cs b/src/Utility/MotionAlgorithm.cs new file mode 100644 index 0000000..f59a7d5 --- /dev/null +++ b/src/Utility/MotionAlgorithm.cs @@ -0,0 +1,173 @@ +using System; +using System.Numerics; + + +namespace ActiveProtect.Utility +{ + public static class MotionAlgorithm + { + /// + /// 计算抛物线弹道最佳发射方向(选择较小的仰角) + /// + /// 发射位置 + /// 目标位置 + /// 初始速度 + /// 最佳发射方向,如果无解则返回null + public static (Orientation? orientation, Vector3D? velocity) CalculateBestLaunchOrientation(Vector3D startPos, Vector3D targetPos, double initialSpeed) + { + // 计算水平距离 + double dx = targetPos.X - startPos.X; + double dz = targetPos.Z - startPos.Z; + double horizontalDistance = Math.Sqrt(dx * dx + dz * dz); + + // 计算高度差 + double dy = targetPos.Y - startPos.Y; + + double[]? angles = CalculateLaunchAngles(initialSpeed, horizontalDistance, dy); + + if (angles == null) + { + Console.WriteLine("无法计算发射角度"); + return (null, null); + } + + double bestAngle = Math.Min(angles[0], angles[1]); + double azimuth = Math.Atan2(dz, dx); + // 计算初始速度分量 + double vx = initialSpeed * Math.Cos(bestAngle) * Math.Cos(azimuth); + double vy = initialSpeed * Math.Sin(bestAngle); + double vz = initialSpeed * Math.Cos(bestAngle) * Math.Sin(azimuth); + + // 返回方向和速度 + return (new Orientation(bestAngle, azimuth, 0), new Vector3D(vx, vy, vz)); + } + + /// + /// 计算抛物线弹道发射角度 + /// + /// 初始速度(m/s) + /// 目标点x坐标(m) + /// 目标点y坐标(m) + /// 重力加速度(m/s²) + /// 两个可能的发射角度(弧度),如果无解则返回null + public static double[]? CalculateLaunchAngles(double v0, double x, double y, double g = 9.81) + { + double v0_2 = v0 * v0; + double v0_4 = v0_2 * v0_2; + + double discriminant = v0_4 - g * (g * x * x + 2 * y * v0_2); + + Console.WriteLine($"判别式: {discriminant}"); + + if (discriminant < 0) + { + Console.WriteLine("无实数解 - 目标不可达"); + return null; + } + + double angle1 = Math.Atan((v0_2 + Math.Sqrt(discriminant)) / (g * x)); + double angle2 = Math.Atan((v0_2 - Math.Sqrt(discriminant)) / (g * x)); + + //Console.WriteLine($"计算得到的两个角度: {angle1 * 180 / Math.PI:F2}° 和 {angle2 * 180 / Math.PI:F2}°"); + + return new[] { angle1, angle2 }; + } + + /// + /// 使用运动学定律计算导弹运动状态,用于无制导状态(无制导时,使用该方法可以降低计算量) + /// + /// 当前位置 + /// 当前速度 + /// 加速度(通常包含重力加速度) + /// 时间步长 + /// 包含新位置和新速度的元组 + public static (Vector3D newPosition, Vector3D newVelocity) CalculateBallisticMotion( + Vector3D currentPosition, + Vector3D currentVelocity, + Vector3D acceleration, + double deltaTime) + { + // 使用标准运动学方程 + Vector3D newPosition = new( + currentPosition.X + currentVelocity.X * deltaTime + 0.5 * acceleration.X * deltaTime * deltaTime, + currentPosition.Y + currentVelocity.Y * deltaTime + 0.5 * acceleration.Y * deltaTime * deltaTime, + currentPosition.Z + currentVelocity.Z * deltaTime + 0.5 * acceleration.Z * deltaTime * deltaTime + ); + + Vector3D newVelocity = new( + currentVelocity.X + acceleration.X * deltaTime, + currentVelocity.Y + acceleration.Y * deltaTime, + currentVelocity.Z + acceleration.Z * deltaTime + ); + + return (newPosition, newVelocity); + } + + /// + /// 使用四阶龙格库塔法计算物体运动状态,用于有制导状态 + /// + /// 时间步长 + /// 导弹位置 + /// 导弹速度 + /// 导弹加速度 + /// 新的位置和速度 + public static (Vector3D newPosition, Vector3D newVelocity) RungeKutta4(double deltaTime, Vector3D position, Vector3D velocity, Vector3D acceleration) + { + // 定义一个局部函数来计算加速度 + Vector3D AccelerationFunction(Vector3D pos, Vector3D vel) + { + // 这里可以添加更复杂的加速度计算,比如考虑空气阻力等 + return acceleration; + } + + // 第一步 + Vector3D k1v = AccelerationFunction(position, velocity) * deltaTime; + Vector3D k1r = velocity * deltaTime; + + // 第二步 + Vector3D k2v = AccelerationFunction(position + k1r * 0.5, velocity + k1v * 0.5) * deltaTime; + Vector3D k2r = (velocity + k1v * 0.5) * deltaTime; + + // 第三步 + Vector3D k3v = AccelerationFunction(position + k2r * 0.5, velocity + k2v * 0.5) * deltaTime; + Vector3D k3r = (velocity + k2v * 0.5) * deltaTime; + + // 第四步 + Vector3D k4v = AccelerationFunction(position + k3r, velocity + k3v) * deltaTime; + Vector3D k4r = (velocity + k3v) * deltaTime; + + // 计算新的位置和速度 + Vector3D newPosition = position + (k1r + k2r * 2 + k3r * 2 + k4r) / 6; + Vector3D newVelocity = velocity + (k1v + k2v * 2 + k3v * 2 + k4v) / 6; + + return (newPosition, newVelocity); + } + /// + /// 计算比例导引加速度 + /// + /// 比例导引系数 + /// 导弹位置 + /// 导弹速度 + /// 目标位置 + /// 目标速度 + /// 比例导引加速度 + public static Vector3D CalculateProportionalNavigation(double proportionalNavigationCoefficient, Vector3D missilePosition, Vector3D missileVelocity, Vector3D targetPosition, Vector3D targetVelocity) + { + // 预测时间(预测目标前进方向该时间后到达的位置,可以调整) + double predictionTime = 0.01; + + // 预测目标位置 + Vector3D predictedTargetPosition = targetPosition + targetVelocity * predictionTime; + + Vector3D r = predictedTargetPosition - missilePosition; + Vector3D v = targetVelocity - missileVelocity; + + Vector3D LOS = r.Normalize(); + Vector3D LOSRate = (v - (LOS * Vector3D.DotProduct(v, LOS))) / r.Magnitude(); + + Vector3D acceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), missileVelocity.Normalize()) * proportionalNavigationCoefficient * missileVelocity.Magnitude(); + + return acceleration; + } + } +}