qstbak/Questionable.Model/Questionable.Model/LandingZoneMath.cs
2026-08-17 20:29:32 +10:00

164 lines
3.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Numerics;
using Questionable.Model.Questing;
namespace Questionable.Model;
public static class LandingZoneMath
{
private static readonly Random Rng = new Random();
public static Vector3 CalculateLandingLocation(IReadOnlyList<LandingZone> zones)
{
if (zones.Count == 0)
{
throw new ArgumentException("At least one landing zone is required.", "zones");
}
if (zones.Count == 1)
{
return RandomPointInConvexPolygon(zones[0].Vertices);
}
float num = 0f;
Span<float> span = stackalloc float[zones.Count];
for (int i = 0; i < zones.Count; i++)
{
span[i] = CalculatePolygonArea(zones[i].Vertices);
num += span[i];
}
float num2 = (float)(Rng.NextDouble() * (double)num);
float num3 = 0f;
for (int j = 0; j < zones.Count; j++)
{
num3 += span[j];
if (num2 <= num3)
{
return RandomPointInConvexPolygon(zones[j].Vertices);
}
}
return RandomPointInConvexPolygon(zones[zones.Count - 1].Vertices);
}
public static Vector3 RandomPointInConvexPolygon(IReadOnlyList<Vector3> vertices)
{
if (vertices.Count < 3)
{
throw new ArgumentException("Polygon must have at least 3 vertices.", "vertices");
}
if (vertices.Count == 3)
{
return RandomPointInTriangle(vertices[0], vertices[1], vertices[2]);
}
int num = vertices.Count - 2;
Span<float> span = stackalloc float[num];
float num2 = 0f;
for (int i = 0; i < num; i++)
{
span[i] = TriangleAreaXZ(vertices[0], vertices[i + 1], vertices[i + 2]);
num2 += span[i];
}
float num3 = (float)(Rng.NextDouble() * (double)num2);
float num4 = 0f;
for (int j = 0; j < num; j++)
{
num4 += span[j];
if (num3 <= num4)
{
return RandomPointInTriangle(vertices[0], vertices[j + 1], vertices[j + 2]);
}
}
return RandomPointInTriangle(vertices[0], vertices[vertices.Count - 2], vertices[vertices.Count - 1]);
}
private static Vector3 RandomPointInTriangle(Vector3 a, Vector3 b, Vector3 c)
{
float num = (float)Rng.NextDouble();
float num2 = (float)Rng.NextDouble();
if (num + num2 > 1f)
{
num = 1f - num;
num2 = 1f - num2;
}
return a + num * (b - a) + num2 * (c - a);
}
private static float TriangleAreaXZ(Vector3 a, Vector3 b, Vector3 c)
{
return MathF.Abs((b.X - a.X) * (c.Z - a.Z) - (c.X - a.X) * (b.Z - a.Z)) * 0.5f;
}
public static float CalculatePolygonArea(IReadOnlyList<Vector3> vertices)
{
if (vertices.Count < 3)
{
return 0f;
}
float num = 0f;
for (int i = 0; i < vertices.Count; i++)
{
int index = (i + 1) % vertices.Count;
num += vertices[i].X * vertices[index].Z;
num -= vertices[index].X * vertices[i].Z;
}
return MathF.Abs(num) * 0.5f;
}
public static bool IsConvex(IReadOnlyList<Vector3> vertices)
{
if (vertices.Count < 3)
{
return false;
}
bool? flag = null;
int count = vertices.Count;
for (int i = 0; i < count; i++)
{
Vector3 vector = vertices[i];
Vector3 vector2 = vertices[(i + 1) % count];
Vector3 vector3 = vertices[(i + 2) % count];
float num = (vector2.X - vector.X) * (vector3.Z - vector2.Z) - (vector2.Z - vector.Z) * (vector3.X - vector2.X);
if (!(MathF.Abs(num) < 1E-06f))
{
bool flag2 = num > 0f;
if (!flag.HasValue)
{
flag = flag2;
}
else if (flag != flag2)
{
return false;
}
}
}
return flag.HasValue;
}
public static bool IsPointInConvexPolygon(Vector2 point, IReadOnlyList<Vector3> vertices)
{
if (vertices.Count < 3)
{
return false;
}
bool? flag = null;
int count = vertices.Count;
for (int i = 0; i < count; i++)
{
Vector3 vector = vertices[i];
Vector3 vector2 = vertices[(i + 1) % count];
float num = (vector2.X - vector.X) * (point.Y - vector.Z) - (vector2.Z - vector.Z) * (point.X - vector.X);
if (!(MathF.Abs(num) < 1E-06f))
{
bool flag2 = num > 0f;
if (!flag.HasValue)
{
flag = flag2;
}
else if (flag != flag2)
{
return false;
}
}
}
return true;
}
}