Compare commits

...

3 Commits

8 changed files with 200 additions and 29 deletions

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using CounterDrone.Core; using CounterDrone.Core;
using CounterDrone.Core.Models; using CounterDrone.Core.Models;
@ -88,12 +88,6 @@ namespace CounterDrone.Core.Algorithms
} }
} }
/// <summary>三维向量(纯 C#,不依赖 UnityEngine</summary>
public struct Vector3
{
public float X, Y, Z;
public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
}
/// <summary>粒子渲染参数</summary> /// <summary>粒子渲染参数</summary>
public class ParticleParams public class ParticleParams
@ -137,25 +131,6 @@ namespace CounterDrone.Core.Algorithms
public List<FireEvent> FireEvents { get; set; } = new(); public List<FireEvent> FireEvents { get; set; } = new();
} }
/// <summary>探测源(独立探测设备或火力单元自带探测的统一表达)。
/// planner 基于探测源估算威胁的最早发现点,而非上帝视角的航路起点。</summary>
public class DetectionSource
{
public Vector3 Position { get; set; }
/// <summary>雷达探测距离 m不受能见度影响</summary>
public float RadarRange { get; set; }
/// <summary>光电探测距离 m受 Visibility 衰减)</summary>
public float EORange { get; set; }
/// <summary>红外探测距离 m不受能见度影响</summary>
public float IRRange { get; set; }
/// <summary>探测精度 m位置误差影响抛撒散布范围</summary>
public float Accuracy { get; set; }
public float MinElevation { get; set; } = float.MaxValue;
public float MaxElevation { get; set; } = float.MaxValue;
public float MinDetectAlt { get; set; } = float.MaxValue;
public float MaxDetectAlt { get; set; } = float.MaxValue;
public string? ModelId { get; set; }
}
/// <summary>规划方案</summary> /// <summary>规划方案</summary>
public class DefensePlan public class DefensePlan

View File

@ -0,0 +1,17 @@
namespace CounterDrone.Core.Algorithms
{
/// <summary>探测源(独立探测设备或火力单元自带探测能力)</summary>
public class DetectionSource
{
public Vector3 Position { get; set; }
public float RadarRange { get; set; }
public float EORange { get; set; }
public float IRRange { get; set; }
public float Accuracy { get; set; }
public float MinElevation { get; set; } = float.MaxValue;
public float MaxElevation { get; set; } = float.MaxValue;
public float MinDetectAlt { get; set; } = float.MaxValue;
public float MaxDetectAlt { get; set; } = float.MaxValue;
public string? ModelId { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace CounterDrone.Core.Algorithms
{
/// <summary>三维向量(纯 C#,不依赖 UnityEngine</summary>
public struct Vector3
{
public float X, Y, Z;
public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
}
}

View File

@ -1,10 +1,13 @@
using CounterDrone.Core.Models; using CounterDrone.Core.Models;
using SQLite;
namespace CounterDrone.Core.Models namespace CounterDrone.Core.Models
{ {
/// <summary>编队模板</summary> /// <summary>编队模板</summary>
[Table("FormationTemplate")]
public class FormationTemplate public class FormationTemplate
{ {
[PrimaryKey]
public string Id { get; set; } = ""; public string Id { get; set; } = "";
public string Name { get; set; } = ""; public string Name { get; set; } = "";
public int FormationMode { get; set; } public int FormationMode { get; set; }

View File

@ -50,8 +50,6 @@ namespace CounterDrone.Core.Simulation
// 空基投放:继承载机速度 // 空基投放:继承载机速度
private readonly float _carrierVelX, _carrierVelY, _carrierVelZ; private readonly float _carrierVelX, _carrierVelY, _carrierVelZ;
// 地基:标记是否已超过释放高度
private bool _hasExceededReleaseAltitude;
// 发射点高于释放高度时,炮弹下降到达 // 发射点高于释放高度时,炮弹下降到达
private bool _arrivesDescending; private bool _arrivesDescending;
private bool _useTimeArrival; private bool _useTimeArrival;
@ -122,7 +120,6 @@ namespace CounterDrone.Core.Simulation
if (_useTimeArrival ? _time >= FlightDuration : if (_useTimeArrival ? _time >= FlightDuration :
((y >= ReleaseAltitude && !_arrivesDescending) || (y <= ReleaseAltitude && _arrivesDescending))) ((y >= ReleaseAltitude && !_arrivesDescending) || (y <= ReleaseAltitude && _arrivesDescending)))
{ {
_hasExceededReleaseAltitude = true;
float tPrev = _time - deltaTime; float tPrev = _time - deltaTime;
var (px0, py0, pz0) = Kinematics.ParabolicPosition( var (px0, py0, pz0) = Kinematics.ParabolicPosition(
_startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, tPrev); _startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, tPrev);

View File

@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CounterDrone.Core;
using CounterDrone.Core.Models;
using CounterDrone.Core.Repository;
using CounterDrone.Core.Services;
using Xunit;
namespace CounterDrone.Core.Tests
{
public class DataServiceTests : IDisposable
{
private readonly string _testDir;
private readonly SQLite.SQLiteConnection _db;
private readonly IDataService _service;
public DataServiceTests()
{
_testDir = Path.Combine(Path.GetTempPath(), $"cd_ds_{Guid.NewGuid():N}");
var paths = new TestPathProvider(_testDir);
_db = new DatabaseManager(paths).OpenMainDb();
_service = new DataService(
new AmmunitionSpecRepository(_db),
new FireUnitSpecRepository(_db),
new DroneSpecRepository(_db),
new SensorSpecRepository(_db),
new EnvironmentSpecRepository(_db),
new FormationTemplateRepository(_db),
new RouteTemplateRepository(_db));
}
public void Dispose()
{
_db?.Close();
if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
}
// ══════════════════════════════ DroneSpec ══════════════════════════════
[Fact]
public void DroneSpec_SaveAndGet()
{
var spec = new DroneSpec
{
Id = "test-drone", Name = "Test Drone", DroneType = (int)DroneType.FixedWing,
PowerType = (int)PowerType.Piston, TypicalSpeed = 150, TypicalAltitude = 500,
};
_service.SaveDrone(spec);
var result = _service.GetDrone("test-drone");
Assert.NotNull(result);
Assert.Equal("Test Drone", result.Name);
Assert.Equal(150, result.TypicalSpeed);
}
[Fact]
public void DroneSpec_Save_UpdateExisting()
{
_service.SaveDrone(new DroneSpec { Id = "test-drone", Name = "Old", TypicalSpeed = 100 });
_service.SaveDrone(new DroneSpec { Id = "test-drone", Name = "New", TypicalSpeed = 200 });
var result = _service.GetDrone("test-drone");
Assert.Equal("New", result.Name);
Assert.Equal(200, result.TypicalSpeed);
}
[Fact]
public void DroneSpec_Delete()
{
_service.SaveDrone(new DroneSpec { Id = "test-drone", Name = "ToDelete" });
_service.DeleteDrone("test-drone");
Assert.Null(_service.GetDrone("test-drone"));
}
[Fact]
public void DroneSpec_GetAll()
{
_service.SaveDrone(new DroneSpec { Id = "d1", Name = "D1" });
_service.SaveDrone(new DroneSpec { Id = "d2", Name = "D2" });
var all = _service.GetAllDrones();
Assert.True(all.Count >= 2);
}
// ══════════════════════════════ FireUnitSpec ═══════════════════════════
[Fact]
public void FireUnitSpec_SaveAndGet()
{
var spec = new FireUnitSpec
{
Id = "test-fu", Name = "Test Unit", PlatformType = (int)PlatformType.GroundBased,
GunCount = 4, MuzzleVelocity = 800,
};
_service.SaveFireUnit(spec);
var result = _service.GetFireUnit("test-fu");
Assert.NotNull(result);
Assert.Equal("Test Unit", result.Name);
Assert.Equal(800, result.MuzzleVelocity);
}
[Fact]
public void FireUnitSpec_Delete()
{
_service.SaveFireUnit(new FireUnitSpec { Id = "test-fu", Name = "ToDelete" });
_service.DeleteFireUnit("test-fu");
Assert.Null(_service.GetFireUnit("test-fu"));
}
[Fact]
public void FireUnitSpec_GetAll()
{
_service.SaveFireUnit(new FireUnitSpec { Id = "f1", Name = "F1" });
_service.SaveFireUnit(new FireUnitSpec { Id = "f2", Name = "F2" });
var all = _service.GetAllFireUnits();
Assert.True(all.Count >= 2);
}
// ══════════════════════════════ SensorSpec ═════════════════════════════
[Fact]
public void SensorSpec_SaveAndGet()
{
var spec = new SensorSpec { Id = "test-sensor", Name = "Test Sensor", RadarRange = 5000 };
_service.SaveSensor(spec);
var result = _service.GetSensor("test-sensor");
Assert.Equal(5000, result.RadarRange);
}
[Fact]
public void SensorSpec_Delete()
{
_service.SaveSensor(new SensorSpec { Id = "test-sensor", Name = "Del" });
_service.DeleteSensor("test-sensor");
Assert.Null(_service.GetSensor("test-sensor"));
}
// ══════════════════════════════ EnvironmentSpec ════════════════════════
[Fact]
public void EnvironmentSpec_SaveAndGet()
{
var spec = new EnvironmentSpec { Id = "test-env", Name = "Fog", WeatherType = 2, Visibility = 500 };
_service.SaveEnvironment(spec);
var result = _service.GetEnvironment("test-env");
Assert.Equal(500, result.Visibility);
}
// ══════════════════════════════ FormationTemplate ══════════════════════
[Fact]
public void FormationTemplate_SaveAndGet()
{
var spec = new FormationTemplate { Id = "test-fmt", Name = "Test Formation", FormationMode = 1, LateralCount = 3 };
_service.SaveFormation(spec);
var result = _service.GetFormation("test-fmt");
Assert.Equal(3, result.LateralCount);
}
// ══════════════════════════════ RouteTemplate ══════════════════════════
[Fact]
public void RouteTemplate_SaveAndGet()
{
var spec = new RouteTemplate { Id = "test-route", Name = "Test Route" };
_service.SaveRoute(spec);
var result = _service.GetRoute("test-route");
Assert.Equal("Test Route", result.Name);
}
}
}

Binary file not shown.