2026-05-25 13:56:11 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
2026-04-27 16:45:06 +08:00
|
|
|
|
namespace 头罩视野.Services
|
|
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
public static class GetArea
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
// 灯条参数
|
|
|
|
|
|
public const int totalLights = 81; // 每条灯条81个灯
|
|
|
|
|
|
public static double verticalAngleStep = 90.0 / (totalLights - 1); // 1.125°
|
2026-05-23 19:59:49 +08:00
|
|
|
|
|
2026-05-04 17:42:39 +08:00
|
|
|
|
public static double CalculateBottomViewAngle(int[] lightData, List<(int m, int n)> lightPositions)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
int bottomLampCount = 0;
|
|
|
|
|
|
for (int i = 0; i < lightData.Length && i < lightPositions.Count; i++)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (lightPositions[i].n == 1 && lightData[i] == 1)
|
|
|
|
|
|
bottomLampCount++;
|
2026-04-27 16:45:06 +08:00
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
return (double)bottomLampCount / 81 * 90.0;
|
2026-04-27 16:45:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// 根据径向灯条0/1数据计算边界角度(极角,度)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
/// </summary>
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// <param name="lightStates">从上到下的灯条状态,索引0=顶部0°,索引80=底部90°</param>
|
|
|
|
|
|
public static double ComputeBoundaryAngle(int[] lightStates)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (lightStates == null || lightStates.Length != totalLights) return 0;
|
|
|
|
|
|
int firstZero = -1;
|
|
|
|
|
|
for (int i = 0; i < totalLights; i++)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (lightStates[i] == 0)
|
2026-04-27 16:45:06 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
firstZero = i;
|
|
|
|
|
|
break;
|
2026-04-27 16:45:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (firstZero == -1) return 90.0; // 全亮
|
|
|
|
|
|
if (firstZero == 0) return 0.0; // 顶部即被遮
|
|
|
|
|
|
// 边界角度 = 上一个灯条的结束角 = (firstZero) * verticalAngleStep
|
|
|
|
|
|
return firstZero * verticalAngleStep;
|
2026-04-27 16:45:06 +08:00
|
|
|
|
}
|
2026-04-30 08:46:44 +08:00
|
|
|
|
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 极坐标梯形法积分面积(半径数组单位:度,步长单位:度)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static double IntegrateArea(double[] radiiDeg, double deltaThetaDeg)
|
2026-05-06 19:52:40 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (radiiDeg == null || radiiDeg.Length < 2) return 0;
|
|
|
|
|
|
double deltaRad = deltaThetaDeg * Math.PI / 180.0;
|
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
|
for (int i = 0; i < radiiDeg.Length - 1; i++)
|
2026-05-06 19:52:40 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
double r1 = radiiDeg[i];
|
|
|
|
|
|
double r2 = radiiDeg[i + 1];
|
|
|
|
|
|
double avgRSq = (r1 * r1 + r2 * r2) / 2.0;
|
|
|
|
|
|
sum += avgRSq * deltaRad;
|
2026-05-06 19:52:40 +08:00
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
return 0.5 * sum;
|
2026-05-06 19:52:40 +08:00
|
|
|
|
}
|
2026-05-06 20:01:54 +08:00
|
|
|
|
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据左右眼边界半径数组,计算总视野(并集)和双目视野(交集)面积
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static (double totalArea, double biArea) ComputeTotalAndBinocularArea(double[] leftRadii, double[] rightRadii, double deltaThetaDeg)
|
2026-04-30 08:46:44 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
int len = Math.Min(leftRadii.Length, rightRadii.Length);
|
|
|
|
|
|
double[] totalRadii = new double[len];
|
|
|
|
|
|
double[] biRadii = new double[len];
|
|
|
|
|
|
for (int i = 0; i < len; i++)
|
2026-05-04 10:25:31 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
totalRadii[i] = Math.Max(leftRadii[i], rightRadii[i]);
|
|
|
|
|
|
biRadii[i] = Math.Min(leftRadii[i], rightRadii[i]);
|
2026-05-04 10:25:31 +08:00
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
double totalArea = IntegrateArea(totalRadii, deltaThetaDeg);
|
|
|
|
|
|
double biArea = IntegrateArea(biRadii, deltaThetaDeg);
|
|
|
|
|
|
return (totalArea, biArea);
|
2026-04-30 08:46:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 保存率计算公式(带γ校正)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static double ComputePreservation(double measuredArea, double standardArea, double gamma)
|
2026-05-06 15:00:54 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (standardArea <= 0) return 0;
|
|
|
|
|
|
return gamma * (measuredArea / standardArea) * 100.0;
|
|
|
|
|
|
}
|
2026-04-30 08:46:44 +08:00
|
|
|
|
|
2026-05-25 13:56:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据面积比获取γ校正系数(GB 2890-2022 图D.4)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static double GetGammaByRatio(double ratio)
|
|
|
|
|
|
{
|
|
|
|
|
|
double[] x = { 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
|
|
|
|
|
|
double[] y = { 1.22, 1.18, 1.14, 1.10, 1.06, 1.03, 1.02, 1.01, 1.00 };
|
|
|
|
|
|
if (ratio <= x[0]) return y[0];
|
|
|
|
|
|
if (ratio >= x.Last()) return y.Last();
|
|
|
|
|
|
for (int i = 0; i < x.Length - 1; i++)
|
2026-05-06 15:00:54 +08:00
|
|
|
|
{
|
2026-05-25 13:56:11 +08:00
|
|
|
|
if (ratio >= x[i] && ratio <= x[i + 1])
|
|
|
|
|
|
{
|
|
|
|
|
|
double t = (ratio - x[i]) / (x[i + 1] - x[i]);
|
|
|
|
|
|
return y[i] + t * (y[i + 1] - y[i]);
|
|
|
|
|
|
}
|
2026-05-06 15:00:54 +08:00
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
return 1.0;
|
2026-04-30 08:46:44 +08:00
|
|
|
|
}
|
2026-05-04 10:25:31 +08:00
|
|
|
|
}
|
2026-05-25 13:56:11 +08:00
|
|
|
|
}
|