test: DamageAssessment 5项单元测试验证路径积分正确

- 单云穿心/两云相邻/9云链/两云有间隙/两点跨云
This commit is contained in:
tian 2026-06-13 19:09:29 +08:00
parent a3bf6720c6
commit 48368e0fe8
2 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,79 @@
using System;
using CounterDrone.Core.Algorithms;
using Xunit;
namespace CounterDrone.Core.Tests
{
public class DamageAssessmentTests
{
[Fact]
public void SingleSegment_ThroughCenter_DiameterExposure()
{
// 无人机穿过球心:路径=2R
float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 20, 0, 0, 20);
Assert.Equal(40, len, 1);
}
[Fact]
public void TwoAdjacentClouds_FullCoverage()
{
// 20段×4m步长=80m经过R=20的两朵相邻云中心在20和60
float total = 0;
float prevX = 0;
for (int s = 0; s < 20; s++)
{
float nextX = prevX + 4;
total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 20, 0, 0, 20);
total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 60, 0, 0, 20);
prevX = nextX;
}
// 每朵云直径40m两朵共80m
Assert.True(Math.Abs(total - 80f) < 1f, $"total={total:F2}, expected=80");
}
[Fact]
public void NineCloudChain_CoverageMatchesTheory()
{
// 9朵云间距40mR=20m无人机段长22.2m(55.6m/s×0.4s)
float[] cloudX = { 9840, 9880, 9920, 9960, 10000, 10040, 10080, 10120, 10160 };
float radius = 20;
float total = 0;
float prevX = 9800;
for (int t = 0; t < 20; t++)
{
float nextX = prevX + 22.22f;
foreach (float cx in cloudX)
total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, cx, 0, 0, radius);
prevX = nextX;
}
// 理论: 9×40m = 360m
Assert.True(Math.Abs(total - 360f) < 10f, $"total={total:F1}, expected=360");
}
[Fact]
public void TwoCloudsWithGap_GapYieldsNoExposure()
{
// 两朵云中心在20和80, R=20: 云1=[0,40], 云2=[60,100], 间隙=[40,60]
float total = 0;
float prevX = 0;
for (int s = 0; s < 25; s++) // 100m / 4m = 25段
{
float nextX = prevX + 4;
total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 20, 0, 0, 20);
total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 80, 0, 0, 20);
prevX = nextX;
}
// 每朵云直径40m两朵共80m间隙无暴露
Assert.True(Math.Abs(total - 80f) < 1f, $"total={total:F2}, expected=80");
}
[Fact]
public void TwoPointsInDifferentClouds_GapExcluded()
{
// 两朵云R=10, 边间距50: 云1中心(0), 云2中心(70)
// 两点: 云1内(0)→云2内(70)
float len1 = DamageAssessment.PathInSphere(0, 0, 0, 70, 0, 0, 0, 0, 0, 10);
float len2 = DamageAssessment.PathInSphere(0, 0, 0, 70, 0, 0, 70, 0, 0, 10);
float total = len1 + len2;
Assert.True(Math.Abs(total - 20f) < 1f, $"total={total:F2}, expected=20 (10+10)");
}
}
}

View File

@ -134,5 +134,54 @@ namespace CounterDrone.Core.Tests
var vertices = new (float X, float Z)[] { (0, 0), (10, 0), (10, 10), (0, 10) };
Assert.False(Kinematics.PointInPolygon(20, 5, vertices));
}
[Fact]
public void PathInSphere_CenterPass_ReturnsFullDiameter()
{
// 无人机穿过球心: 路径长度 = 2R
float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 20, 0, 0, 20);
Assert.Equal(40, len, 1);
}
[Fact]
public void PathInSphere_EdgePass_ReturnsCorrectChord()
{
// 从(0)→(40), 球心(30), R=20: 进入t=0.25(x=10), 段尾在球内(t=1,x=40), 路径=30m
float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 30, 0, 0, 20);
Assert.True(System.Math.Abs(len - 30f) < 1f, $"len={len:F2}");
}
[Fact]
public void PathInSphere_Miss_ReturnsZero()
{
float len = DamageAssessment.PathInSphere(0, 0, 0, 10, 0, 0, 50, 0, 0, 20);
Assert.Equal(0, len, 1);
}
[Fact]
public void PathInSphere_PartialEntry_ReturnsCorrectSegment()
{
// 从球外(0)到球内(20), R=20, 球心(30): 进入点在10, 段长=10
float len = DamageAssessment.PathInSphere(0, 0, 0, 20, 0, 0, 30, 0, 0, 20);
Assert.True(System.Math.Abs(len - 10f) < 1f, $"len={len:F2}");
}
[Fact]
public void PathInSphere_TwoClouds_AccumulatesCorrectly()
{
// 一段经过两个云: (0→100), 云1(20,R20), 云2(80,R20)
float len1 = DamageAssessment.PathInSphere(0, 0, 0, 100, 0, 0, 20, 0, 0, 20);
float len2 = DamageAssessment.PathInSphere(0, 0, 0, 100, 0, 0, 80, 0, 0, 20);
Assert.True(System.Math.Abs(len1 - 40f) < 1f, $"cloud1 len={len1:F2}");
Assert.True(System.Math.Abs(len2 - 40f) < 1f, $"cloud2 len={len2:F2}");
}
[Fact]
public void PathInSphere_AdjacentClouds_SumCorrectly()
{
// 无人机从云1中心(0)到云2中心(40)两云R=20间距=40边碰边
// 两个云在段内路径云1=20m(中心→右边缘), 云2=20m(左边缘→中心)
float len1 = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 0, 0, 0, 20);
float len2 = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 40, 0, 0, 20);
float total = len1 + len2;
Assert.True(System.Math.Abs(total - 40f) < 1f, $"total={total:F2} (cloud1={len1:F2} + cloud2={len2:F2})");
}
}
}