ZeroVR/ZeroPacientVR/Assets/CodeRespawn/DungeonArchitect/ThirdParty/SharpNav/Geometry/TriangleEnumerable.cs

256 lines
8.9 KiB
C#

// Copyright (c) 2014-2015 Robert Rouhani <robert.rouhani@gmail.com> and other contributors (see CONTRIBUTORS file).
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
using System.Collections.Generic;
#if MONOGAME
using Vector3 = Microsoft.Xna.Framework.Vector3;
#elif OPENTK
using Vector3 = OpenTK.Vector3;
#elif SHARPDX
using Vector3 = SharpDX.Vector3;
#endif
namespace SharpNav.Geometry
{
//TODO array bounds checking to catch out of bounds exceptions early.
//TODO index arrays of other integral types (byte, sbyte, short, ushort, uint) - possibly make generic?
/// <summary>
/// A static class that generates an <see cref="IEnumerable{T}"/> of <see cref="Triangle3"/> using iterator blocks.
/// </summary>
public static class TriangleEnumerable
{
/// <summary>
/// Iterates over an array of <see cref="Triangle3"/> with a specified offset and length.
/// </summary>
/// <param name="triangles">An array of triangles.</param>
/// <param name="triOffset">The index of the first triangle to be enumerated.</param>
/// <param name="triCount">The number of triangles to enumerate.</param>
/// <returns>An enumerable collection of triangles.</returns>
public static IEnumerable<Triangle3> FromTriangle(Triangle3[] triangles, int triOffset, int triCount)
{
for (int i = 0; i < triCount; i++)
yield return triangles[triOffset + i];
}
/// <summary>
/// Iterates over an array of <see cref="Vector3"/> with a specified offset, stride, and length.
/// </summary>
/// <param name="vertices">An array of vertices.</param>
/// <param name="vertOffset">The index of the first vertex to be enumerated.</param>
/// <param name="vertStride">The distance between the start of two triangles. A value of 0 means the data is tightly packed.</param>
/// <param name="triCount">The number of triangles to enumerate.</param>
/// <returns>An enumerable collection of triangles.</returns>
public static IEnumerable<Triangle3> FromVector3(Vector3[] vertices, int vertOffset, int vertStride, int triCount)
{
Triangle3 tri;
if (vertStride == 0)
vertStride = 3;
for (int i = 0; i < triCount; i++)
{
tri.A = vertices[i * vertStride + vertOffset];
tri.B = vertices[i * vertStride + vertOffset + 1];
tri.C = vertices[i * vertStride + vertOffset + 2];
yield return tri;
}
}
/// <summary>
/// Iterates over an array of <see cref="float"/> with a specified offset, stride, and length.
/// </summary>
/// <param name="vertices">An array of vertices.</param>
/// <param name="floatOffset">The index of the first float to be enumerated.</param>
/// <param name="floatStride">The distance between the start of two vertices. A value of 0 means the data is tightly packed.</param>
/// <param name="triCount">The number of triangles to enumerate.</param>
/// <returns>An enumerable collection of triangles.</returns>
public static IEnumerable<Triangle3> FromFloat(float[] vertices, int floatOffset, int floatStride, int triCount)
{
Triangle3 tri;
if (floatStride == 0)
floatStride = 3;
for (int i = 0; i < triCount; i++)
{
int indA = i * (floatStride * 3) + floatOffset;
int indB = indA + floatStride;
int indC = indB + floatStride;
tri.A.X = vertices[indA];
tri.A.Y = vertices[indA + 1];
tri.A.Z = vertices[indA + 2];
tri.B.X = vertices[indB];
tri.B.Y = vertices[indB + 1];
tri.B.Z = vertices[indB + 2];
tri.C.X = vertices[indC];
tri.C.Y = vertices[indC + 1];
tri.C.Z = vertices[indC + 2];
yield return tri;
}
}
/// <summary>
/// Iterates over an array of <see cref="Vector3"/> indexed by an array of <see cref="int"/> with a specified offset, stride, and length.
/// </summary>
/// <param name="vertices">An array of vertices.</param>
/// <param name="indices">An array of indices.</param>
/// <param name="vertOffset">The index of the first vertex to be enumerated.</param>
/// <param name="vertStride">The distance between the start of two triangles. A value of 0 means the data is tightly packed.</param>
/// <param name="indexOffset">The index of the first index to be enumerated.</param>
/// <param name="triCount">The number of triangles to enumerate.</param>
/// <returns>An enumerable collection of triangles.</returns>
public static IEnumerable<Triangle3> FromIndexedVector3(Vector3[] vertices, int[] indices, int vertOffset, int vertStride, int indexOffset, int triCount)
{
Triangle3 tri;
for (int i = 0; i < triCount; i++)
{
int indA = vertOffset + indices[i * 3 + indexOffset] * vertStride;
int indB = vertOffset + indices[i * 3 + indexOffset + 1] * vertStride;
int indC = vertOffset + indices[i * 3 + indexOffset + 2] * vertStride;
tri.A = vertices[indA];
tri.B = vertices[indB];
tri.C = vertices[indC];
yield return tri;
}
}
/// <summary>
/// Iterates over an array of <see cref="float"/> indexed by an array of <see cref="int"/> with a specified offset, stride, and length.
/// </summary>
/// <param name="vertices">An array of vertices.</param>
/// <param name="indices">An array of indices.</param>
/// <param name="floatOffset">The index of the first float to be enumerated.</param>
/// <param name="floatStride">The distance between the start of two vertices. A value of 0 means the data is tightly packed.</param>
/// <param name="indexOffset">The index of the first index to be enumerated.</param>
/// <param name="triCount">The number of triangles to enumerate.</param>
/// <returns>An enumerable collection of triangles.</returns>
public static IEnumerable<Triangle3> FromIndexedFloat(float[] vertices, int[] indices, int floatOffset, int floatStride, int indexOffset, int triCount)
{
Triangle3 tri;
for (int i = 0; i < triCount; i++)
{
int indA = floatOffset + indices[i * 3 + indexOffset] * floatStride;
int indB = floatOffset + indices[i * 3 + indexOffset + 1] * floatStride;
int indC = floatOffset + indices[i * 3 + indexOffset + 2] * floatStride;
tri.A.X = vertices[indA];
tri.A.Y = vertices[indA + 1];
tri.A.Z = vertices[indA + 2];
tri.B.X = vertices[indB];
tri.B.Y = vertices[indB + 1];
tri.B.Z = vertices[indB + 2];
tri.C.X = vertices[indC];
tri.C.Y = vertices[indC + 1];
tri.C.Z = vertices[indC + 2];
yield return tri;
}
}
/// <summary>
/// Generates a bounding box for a collection of triangles.
/// </summary>
/// <param name="tris">The triangles to create a bounding box from.</param>
/// <returns>A bounding box containing every triangle.</returns>
public static BBox3 GetBoundingBox(this IEnumerable<Triangle3> tris)
{
return GetBoundingBox(tris, float.Epsilon * 2f);
}
/// <summary>
/// Generates a bounding box for a collection of triangles.
/// </summary>
/// <param name="tris">The triangles to create a bounding box from.</param>
/// <param name="padding">Padding to the bounding box</param>
/// <returns>A bounding box containing every triangle.</returns>
public static BBox3 GetBoundingBox(this IEnumerable<Triangle3> tris, float padding)
{
BBox3 bounds = new BBox3();
Vector3 va, vb, vc;
foreach (Triangle3 tri in tris)
{
va = tri.A;
vb = tri.B;
vc = tri.C;
ApplyVertexToBounds(ref va, ref bounds);
ApplyVertexToBounds(ref vb, ref bounds);
ApplyVertexToBounds(ref vc, ref bounds);
}
//pad the bounding box a bit to make sure outer triangles are fully contained.
ApplyPaddingToBounds(padding, ref bounds);
return bounds;
}
/// <summary>
/// Generates a bounding box for a collection of vectors.
/// </summary>
/// <param name="vecs">The vectors to create a bounding box from.</param>
/// <returns>A bounding box containing every vector.</returns>
public static BBox3 GetBoundingBox(this IEnumerable<Vector3> vecs)
{
BBox3 bounds = new BBox3();
Vector3 v;
foreach (Vector3 vec in vecs)
{
v = vec;
ApplyVertexToBounds(ref v, ref bounds);
}
ApplyPaddingToBounds(1.0f, ref bounds);
return bounds;
}
/// <summary>
/// Adjusts a bounding box to include a vertex.
/// </summary>
/// <param name="v">The vertex to include.</param>
/// <param name="b">The bounding box to adjust.</param>
private static void ApplyVertexToBounds(ref Vector3 v, ref BBox3 b)
{
if (v.X < b.Min.X)
b.Min.X = v.X;
if (v.Y < b.Min.Y)
b.Min.Y = v.Y;
if (v.Z < b.Min.Z)
b.Min.Z = v.Z;
if (v.X > b.Max.X)
b.Max.X = v.X;
if (v.Y > b.Max.Y)
b.Max.Y = v.Y;
if (v.Z > b.Max.Z)
b.Max.Z = v.Z;
}
/// <summary>
/// Applies a padding to the bounding box.
/// </summary>
/// <param name="pad">The amount to pad the bounding box on all sides.</param>
/// <param name="b">The bounding box to pad.</param>
private static void ApplyPaddingToBounds(float pad, ref BBox3 b)
{
b.Min.X -= pad;
b.Min.Y -= pad;
b.Min.Z -= pad;
b.Max.X += pad;
b.Max.Y += pad;
b.Max.Z += pad;
}
}
}