164 lines
3.9 KiB
C#
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;
|
|
}
|
|
}
|