This commit is contained in:
xyy
2026-05-14 13:38:20 +08:00
parent d48db94d33
commit ba10a081b9
2 changed files with 96 additions and 40 deletions

View File

@@ -19,12 +19,6 @@ namespace 头罩视野.Services
//空白视野面积计算
public static readonly double _standardTotalArea = (Math.PI * R * R) / 100;
public static double GetBlankViewArea(double binocularTotalArea)
{
// 公式:空白 = 标准总面积 - 双目总视野
return _standardTotalArea - binocularTotalArea;
}
//计算双目视野
public static double CalculateBinocularArea(
@@ -44,50 +38,112 @@ namespace 头罩视野.Services
return CalculateEllipseArea(binocularData, lightPositions);
}
//下方视野 下方视野角度 = 人眼到「最低亮灯条」的夹角
////下方视野 下方视野角度 = 人眼到「最低亮灯条」的夹角
//public static double CalculateBottomViewAngle(int[] lightData, List<(int m, int n)> lightPositions)
//{
// List<double> bottomAngles = new List<double>();
// for (int i = 0; i < lightData.Length; i++)
// {
// // 只处理亮灯的情况
// if (lightData[i] == 1)
// {
// if (lightPositions.Count < lightData.Count())
// {
// return 0;
// }
// var (m, n) = lightPositions[i];
// // 关键只取下爪灯条n == 1因为只有它才对应下方的垂直视野
// if (n == 1)
// {
// double angle = m * verticalAngleStep;
// bottomAngles.Add(angle);
// }
// }
// }
// // 没有亮灯返回0
// if (bottomAngles.Count == 0)
// return 0;
// // 最大角度 = 最下方的亮灯条,也就是下方视野的边界
// return bottomAngles.Max();
//}
/// <summary>
/// 下方视野角度 = 从正下方90°向顶部扫描第一个被遮挡的边界角度
/// 使用下爪灯条n==1的径向数据
/// </summary>
public static double CalculateBottomViewAngle(int[] lightData, List<(int m, int n)> lightPositions)
{
List<double> bottomAngles = new List<double>();
for (int i = 0; i < lightData.Length; i++)
// 提取下爪灯条n==1的数据共81个灯
int radialCount = 81;
int[] radialData = new int[radialCount];
int idx = 0;
for (int i = 0; i < lightData.Length && idx < radialCount; i++)
{
// 只处理亮灯的情况
if (lightData[i] == 1)
var (m, n) = lightPositions[i];
if (n == 1)
{
if (lightPositions.Count < lightData.Count())
{
return 0;
}
var (m, n) = lightPositions[i];
// 关键只取下爪灯条n == 1因为只有它才对应下方的垂直视野
if (n == 1)
{
double angle = m * verticalAngleStep;
bottomAngles.Add(angle);
}
radialData[idx++] = lightData[i];
}
}
// 没有亮灯返回0
if (bottomAngles.Count == 0)
return 0;
if (idx != radialCount) return 0; // 数据不完整
// 最大角度 = 最下方的亮灯条,也就是下方视野的边界
return bottomAngles.Max();
// 反转数组使索引0对应物理底部90°索引80对应顶部0°
Array.Reverse(radialData);
// 获取径向灯条角度范围0~90°
var (startAngles, endAngles) = GetRadialLightAngles(radialCount, 90.0);
double boundary = ComputeBoundaryAngle(radialData, startAngles, endAngles);
// 转换为从顶部开始的极角(即标准下方视野角度)
return 90 - boundary;
}
//视野保存率
public static double CalcVisionRate(double binocularRate)
/// <summary>
/// 根据灯条0/1状态计算径向边界角度
/// </summary>
public static double ComputeBoundaryAngle(int[] lightStates, double[] startAngles, double[] endAngles)
{
if (lightStates == null || startAngles == null || endAngles == null) return 0;
int n = lightStates.Length;
if (n == 0 || startAngles.Length != n || endAngles.Length != n) return 0;
// 1. 总视野保存率
double ratioTotal = binocularRate / _standardTotalArea;
double gammaTotal = GetVisionGamma(ratioTotal);
double totalRate = gammaTotal * ratioTotal * 100;
return (totalRate);
// 全亮
bool allOne = true;
for (int i = 0; i < n; i++) if (lightStates[i] == 0) { allOne = false; break; }
if (allOne) return endAngles[n - 1];
// 全灭
bool allZero = true;
for (int i = 0; i < n; i++) if (lightStates[i] == 1) { allZero = false; break; }
if (allZero) return startAngles[0];
// 找到第一个0
int firstZero = -1;
for (int i = 0; i < n; i++) if (lightStates[i] == 0) { firstZero = i; break; }
int lastOne = firstZero - 1;
if (lastOne < 0 || firstZero >= n) return startAngles[0];
return (endAngles[lastOne] + startAngles[firstZero]) / 2.0;
}
/// <summary>
/// 获取径向灯条的角度范围等分0~maxAngle灯条数为lightCount
/// </summary>
public static (double[] start, double[] end) GetRadialLightAngles(int lightCount, double maxAngle = 90.0)
{
double step = maxAngle / (lightCount - 1);
double[] start = new double[lightCount];
double[] end = new double[lightCount];
for (int i = 0; i < lightCount; i++)
{
start[i] = i * step;
end[i] = (i + 1) * step;
}
end[lightCount - 1] = maxAngle;
return (start, end);
}
/// <summary>