diff --git a/src/CounterDrone.Core/Models/SimEvent.cs b/src/CounterDrone.Core/Models/SimEvent.cs index 1ce81ea..4a6b138 100644 --- a/src/CounterDrone.Core/Models/SimEvent.cs +++ b/src/CounterDrone.Core/Models/SimEvent.cs @@ -3,7 +3,7 @@ using SQLite; namespace CounterDrone.Core.Models { - /// 仿真事件(时序图数据源)— 存主库 + /// 仿真事件(数据库记录) [Table("SimEvent")] public class SimEvent { diff --git a/src/CounterDrone.Core/Simulation/SimTypes.cs b/src/CounterDrone.Core/Simulation/SimTypes.cs index 56b8ad1..e28383e 100644 --- a/src/CounterDrone.Core/Simulation/SimTypes.cs +++ b/src/CounterDrone.Core/Simulation/SimTypes.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; namespace CounterDrone.Core.Simulation { - public enum SimulationState - { - Idle, Running, Paused, Stopped, Completed, - } + public enum SimulationState { Idle, Running, Paused, Stopped, Completed } public class SimEvent { @@ -17,16 +14,6 @@ namespace CounterDrone.Core.Simulation public string Description { get; set; } = string.Empty; } - public class EventQueue - { - private readonly Queue _queue = new(); - public void Enqueue(SimEvent e) => _queue.Enqueue(e); - public SimEvent Dequeue() => _queue.Dequeue(); - public int Count => _queue.Count; - public bool HasEvents => _queue.Count > 0; - public void Clear() => _queue.Clear(); - } - public class SimulationFrameResult { public List EntitySnapshots { get; set; } = new(); @@ -40,17 +27,9 @@ namespace CounterDrone.Core.Simulation { public string EntityId { get; set; } = string.Empty; public Models.EntityType EntityType { get; set; } - public float PosX { get; set; } - public float PosY { get; set; } - public float PosZ { get; set; } - public float RotX { get; set; } - public float RotY { get; set; } - public float RotZ { get; set; } + public float PosX, PosY, PosZ, RotX, RotY, RotZ; public string StateData { get; set; } = "{}"; } - public enum DroneStatus - { - Flying, Destroyed, ReachedTarget, ZoneIntruded, - } + public enum DroneStatus { Flying, Destroyed, ReachedTarget, ZoneIntruded } } diff --git a/test/reports/喷气拦截_20260611_084034.md b/test/reports/喷气拦截_20260611_084034.md new file mode 100644 index 0000000..1d24d50 --- /dev/null +++ b/test/reports/喷气拦截_20260611_084034.md @@ -0,0 +1,47 @@ +# 仿真评估报告 + +**任务名称**:喷气拦截 +**任务编号**:SIM-20260611-004 +**仿真耗时**:106.4 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 6 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | ActiveMaterial | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 92.2 | MunitionLaunched | 计划发射 mun_1 | +| 92.2 | MunitionLaunched | 计划发射 mun_2 | +| 92.2 | MunitionLaunched | 计划发射 mun_3 | +| 92.2 | MunitionLaunched | 计划发射 mun_4 | +| 92.2 | MunitionLaunched | 计划发射 mun_5 | +| 92.2 | MunitionLaunched | 计划发射 mun_6 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 106.4 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 1 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 6 | +| 云团生成次数 | 6 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/喷气拦截_20260611_084112.md b/test/reports/喷气拦截_20260611_084112.md new file mode 100644 index 0000000..1d24d50 --- /dev/null +++ b/test/reports/喷气拦截_20260611_084112.md @@ -0,0 +1,47 @@ +# 仿真评估报告 + +**任务名称**:喷气拦截 +**任务编号**:SIM-20260611-004 +**仿真耗时**:106.4 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 6 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | ActiveMaterial | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 92.2 | MunitionLaunched | 计划发射 mun_1 | +| 92.2 | MunitionLaunched | 计划发射 mun_2 | +| 92.2 | MunitionLaunched | 计划发射 mun_3 | +| 92.2 | MunitionLaunched | 计划发射 mun_4 | +| 92.2 | MunitionLaunched | 计划发射 mun_5 | +| 92.2 | MunitionLaunched | 计划发射 mun_6 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 106.4 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 1 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 6 | +| 云团生成次数 | 6 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/喷气拦截_20260611_084129.md b/test/reports/喷气拦截_20260611_084129.md new file mode 100644 index 0000000..1d24d50 --- /dev/null +++ b/test/reports/喷气拦截_20260611_084129.md @@ -0,0 +1,47 @@ +# 仿真评估报告 + +**任务名称**:喷气拦截 +**任务编号**:SIM-20260611-004 +**仿真耗时**:106.4 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 6 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | ActiveMaterial | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 92.2 | MunitionLaunched | 计划发射 mun_1 | +| 92.2 | MunitionLaunched | 计划发射 mun_2 | +| 92.2 | MunitionLaunched | 计划发射 mun_3 | +| 92.2 | MunitionLaunched | 计划发射 mun_4 | +| 92.2 | MunitionLaunched | 计划发射 mun_5 | +| 92.2 | MunitionLaunched | 计划发射 mun_6 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 106.4 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 1 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 6 | +| 云团生成次数 | 6 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/喷气拦截_20260611_084211.md b/test/reports/喷气拦截_20260611_084211.md new file mode 100644 index 0000000..1d24d50 --- /dev/null +++ b/test/reports/喷气拦截_20260611_084211.md @@ -0,0 +1,47 @@ +# 仿真评估报告 + +**任务名称**:喷气拦截 +**任务编号**:SIM-20260611-004 +**仿真耗时**:106.4 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 6 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | ActiveMaterial | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 92.2 | MunitionLaunched | 计划发射 mun_1 | +| 92.2 | MunitionLaunched | 计划发射 mun_2 | +| 92.2 | MunitionLaunched | 计划发射 mun_3 | +| 92.2 | MunitionLaunched | 计划发射 mun_4 | +| 92.2 | MunitionLaunched | 计划发射 mun_5 | +| 92.2 | MunitionLaunched | 计划发射 mun_6 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 101.8 | CloudGenerated | 云团生成 | +| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 106.4 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 1 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 6 | +| 云团生成次数 | 6 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/活塞拦截_20260611_084037.md b/test/reports/活塞拦截_20260611_084037.md new file mode 100644 index 0000000..7bfa144 --- /dev/null +++ b/test/reports/活塞拦截_20260611_084037.md @@ -0,0 +1,46 @@ +# 仿真评估报告 + +**任务名称**:活塞拦截 +**任务编号**:SIM-20260611-041 +**仿真耗时**:185.6 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 5 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | InertGas | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 167.4 | MunitionLaunched | 计划发射 mun_1 | +| 167.4 | MunitionLaunched | 计划发射 mun_2 | +| 167.4 | MunitionLaunched | 计划发射 mun_3 | +| 167.4 | MunitionLaunched | 计划发射 mun_4 | +| 167.4 | MunitionLaunched | 计划发射 mun_5 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 2 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 5 | +| 云团生成次数 | 5 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/活塞拦截_20260611_084115.md b/test/reports/活塞拦截_20260611_084115.md new file mode 100644 index 0000000..7bfa144 --- /dev/null +++ b/test/reports/活塞拦截_20260611_084115.md @@ -0,0 +1,46 @@ +# 仿真评估报告 + +**任务名称**:活塞拦截 +**任务编号**:SIM-20260611-041 +**仿真耗时**:185.6 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 5 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | InertGas | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 167.4 | MunitionLaunched | 计划发射 mun_1 | +| 167.4 | MunitionLaunched | 计划发射 mun_2 | +| 167.4 | MunitionLaunched | 计划发射 mun_3 | +| 167.4 | MunitionLaunched | 计划发射 mun_4 | +| 167.4 | MunitionLaunched | 计划发射 mun_5 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 2 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 5 | +| 云团生成次数 | 5 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/活塞拦截_20260611_084132.md b/test/reports/活塞拦截_20260611_084132.md new file mode 100644 index 0000000..7bfa144 --- /dev/null +++ b/test/reports/活塞拦截_20260611_084132.md @@ -0,0 +1,46 @@ +# 仿真评估报告 + +**任务名称**:活塞拦截 +**任务编号**:SIM-20260611-041 +**仿真耗时**:185.6 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 5 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | InertGas | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 167.4 | MunitionLaunched | 计划发射 mun_1 | +| 167.4 | MunitionLaunched | 计划发射 mun_2 | +| 167.4 | MunitionLaunched | 计划发射 mun_3 | +| 167.4 | MunitionLaunched | 计划发射 mun_4 | +| 167.4 | MunitionLaunched | 计划发射 mun_5 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 2 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 5 | +| 云团生成次数 | 5 | + +**对抗结果**:成功拦截 + diff --git a/test/reports/活塞拦截_20260611_084214.md b/test/reports/活塞拦截_20260611_084214.md new file mode 100644 index 0000000..7bfa144 --- /dev/null +++ b/test/reports/活塞拦截_20260611_084214.md @@ -0,0 +1,46 @@ +# 仿真评估报告 + +**任务名称**:活塞拦截 +**任务编号**:SIM-20260611-041 +**仿真耗时**:185.6 秒 + +## 一、仿真前 — 我方配置 + +| 配置项 | 值 | +|--------|-----| +| 目标数量 | 1 | +| 发射平台 | 5 台 | +| 探测设备 | 1 台 | +| 气溶胶类型 | InertGas | + +## 二、仿真中 — 关键事件时序 + +| 时间(s) | 事件 | 描述 | +|---------|------|------| +| 167.4 | MunitionLaunched | 计划发射 mun_1 | +| 167.4 | MunitionLaunched | 计划发射 mun_2 | +| 167.4 | MunitionLaunched | 计划发射 mun_3 | +| 167.4 | MunitionLaunched | 计划发射 mun_4 | +| 167.4 | MunitionLaunched | 计划发射 mun_5 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 177.0 | CloudGenerated | 云团生成 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 | +| 185.6 | SimulationEnd | | + +## 三、仿真后 — 数据统计 + +| 统计项 | 值 | +|--------|-----| +| 无人机总数 | 1 | +| 被摧毁 | 2 | +| 到达目标 | 0 | +| 侵入管控区 | 0 | +| 弹药发射次数 | 5 | +| 云团生成次数 | 5 | + +**对抗结果**:成功拦截 + diff --git a/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs b/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs index 7dc0b55..84c2736 100644 --- a/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs @@ -68,5 +68,26 @@ namespace CounterDrone.Core.Tests var deleted = _store.CleanupExpired(); Assert.Equal(0, deleted); } + + [Fact] + public void ReadFrames_ReturnsCorrectRange() + { + var db = _store.CreateOrOpen("task_read"); + var snapshots = new System.Collections.Generic.List + { + new EntitySnapshot { EntityId = "d1", EntityType = Models.EntityType.Drone, PosX = 100 }, + }; + + _store.WriteFrame(db, "task_read", 0, 0f, snapshots); + _store.WriteFrame(db, "task_read", 1, 0.05f, snapshots); + _store.WriteFrame(db, "task_read", 2, 0.10f, snapshots); + + var frames = _store.ReadFrames(db, "task_read", 1, 2); + Assert.Equal(2, frames.Count); + Assert.Equal(1, frames[0].FrameIndex); + Assert.Equal(2, frames[1].FrameIndex); + + db.Close(); + } } } diff --git a/test/unit/CounterDrone.Core.Tests/MunitionEntityTests.cs b/test/unit/CounterDrone.Core.Tests/MunitionEntityTests.cs index 545eefc..2cbfaf0 100644 --- a/test/unit/CounterDrone.Core.Tests/MunitionEntityTests.cs +++ b/test/unit/CounterDrone.Core.Tests/MunitionEntityTests.cs @@ -74,5 +74,26 @@ namespace CounterDrone.Core.Tests var dist = System.Math.Sqrt(m.PosX * m.PosX + m.PosZ * m.PosZ); Assert.True(dist > 100f, "1秒后炮弹应水平移动 > 100m"); } + + [Fact] + public void AirBased_DropsToReleaseAltitude() + { + var m = new MunitionEntity("m1", PlatformType.AirBased, + AerosolType.InertGas, + startX: 0, startY: 500, startZ: 0, + targetX: 1000, targetY: 300, targetZ: 0, + muzzleVelocity: 0, releaseAltitude: 300f); + + // 空基投放:自由落体 500m → 300m = 200m 下落 + // h = 0.5*g*t² → t = sqrt(2*200/9.81) ≈ 6.4s + for (int i = 0; i < 500; i++) + { + m.Update(0.05f); + if (m.HasArrived) break; + } + + Assert.True(m.HasArrived, "空基弹药应到达释放高度"); + Assert.True(m.PosY <= 300f + 1f); + } } } diff --git a/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs b/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs new file mode 100644 index 0000000..85f6d77 --- /dev/null +++ b/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using CounterDrone.Core; +using CounterDrone.Core.Models; +using CounterDrone.Core.Repository; +using Xunit; + +namespace CounterDrone.Core.Tests +{ + public class RepositoryEdgeTests : IDisposable + { + private readonly string _testDir; + private readonly SQLite.SQLiteConnection _db; + + public RepositoryEdgeTests() + { + _testDir = Path.Combine(Path.GetTempPath(), $"cd_repo_{Guid.NewGuid():N}"); + var paths = new TestPathProvider(_testDir); + _db = new DatabaseManager(paths).OpenMainDb(); + } + + public void Dispose() { _db?.Close(); if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true); } + + [Fact] + public void TargetConfig_DeleteByTaskId_RemovesAll() + { + var repo = new TargetConfigRepository(_db); + repo.Insert(new TargetConfig { Id = "t1", TaskId = "taskA", Quantity = 1 }); + repo.Insert(new TargetConfig { Id = "t2", TaskId = "taskA", Quantity = 2 }); + repo.Insert(new TargetConfig { Id = "t3", TaskId = "taskB", Quantity = 1 }); + + repo.DeleteByTaskId("taskA"); + + Assert.Empty(repo.GetByTaskId("taskA")); + Assert.Single(repo.GetByTaskId("taskB")); + } + + [Fact] + public void Waypoint_DeleteByTaskId_RemovesAll() + { + var repo = new WaypointRepository(_db); + repo.Insert(new Waypoint { TaskId = "w1", OrderIndex = 0 }); + repo.Insert(new Waypoint { TaskId = "w1", OrderIndex = 1 }); + repo.Insert(new Waypoint { TaskId = "w2", OrderIndex = 0 }); + + repo.DeleteByTaskId("w1"); + + Assert.Empty(repo.GetByTaskId("w1")); + Assert.Single(repo.GetByTaskId("w2")); + } + + [Fact] + public void EquipmentDeployment_DeleteByTaskId_Works() + { + var repo = new EquipmentDeploymentRepository(_db); + repo.Insert(new EquipmentDeployment { Id = "e1", TaskId = "eqA" }); + repo.Insert(new EquipmentDeployment { Id = "e2", TaskId = "eqA" }); + + repo.DeleteByTaskId("eqA"); + Assert.Empty(repo.GetByTaskId("eqA")); + } + } +}