// Copyright (c) 2014-2015 Robert Rouhani 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? /// /// A static class that generates an of using iterator blocks. /// public static class TriangleEnumerable { /// /// Iterates over an array of with a specified offset and length. /// /// An array of triangles. /// The index of the first triangle to be enumerated. /// The number of triangles to enumerate. /// An enumerable collection of triangles. public static IEnumerable FromTriangle(Triangle3[] triangles, int triOffset, int triCount) { for (int i = 0; i < triCount; i++) yield return triangles[triOffset + i]; } /// /// Iterates over an array of with a specified offset, stride, and length. /// /// An array of vertices. /// The index of the first vertex to be enumerated. /// The distance between the start of two triangles. A value of 0 means the data is tightly packed. /// The number of triangles to enumerate. /// An enumerable collection of triangles. public static IEnumerable 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; } } /// /// Iterates over an array of with a specified offset, stride, and length. /// /// An array of vertices. /// The index of the first float to be enumerated. /// The distance between the start of two vertices. A value of 0 means the data is tightly packed. /// The number of triangles to enumerate. /// An enumerable collection of triangles. public static IEnumerable 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; } } /// /// Iterates over an array of indexed by an array of with a specified offset, stride, and length. /// /// An array of vertices. /// An array of indices. /// The index of the first vertex to be enumerated. /// The distance between the start of two triangles. A value of 0 means the data is tightly packed. /// The index of the first index to be enumerated. /// The number of triangles to enumerate. /// An enumerable collection of triangles. public static IEnumerable 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; } } /// /// Iterates over an array of indexed by an array of with a specified offset, stride, and length. /// /// An array of vertices. /// An array of indices. /// The index of the first float to be enumerated. /// The distance between the start of two vertices. A value of 0 means the data is tightly packed. /// The index of the first index to be enumerated. /// The number of triangles to enumerate. /// An enumerable collection of triangles. public static IEnumerable 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; } } /// /// Generates a bounding box for a collection of triangles. /// /// The triangles to create a bounding box from. /// A bounding box containing every triangle. public static BBox3 GetBoundingBox(this IEnumerable tris) { return GetBoundingBox(tris, float.Epsilon * 2f); } /// /// Generates a bounding box for a collection of triangles. /// /// The triangles to create a bounding box from. /// Padding to the bounding box /// A bounding box containing every triangle. public static BBox3 GetBoundingBox(this IEnumerable 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; } /// /// Generates a bounding box for a collection of vectors. /// /// The vectors to create a bounding box from. /// A bounding box containing every vector. public static BBox3 GetBoundingBox(this IEnumerable 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; } /// /// Adjusts a bounding box to include a vertex. /// /// The vertex to include. /// The bounding box to adjust. 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; } /// /// Applies a padding to the bounding box. /// /// The amount to pad the bounding box on all sides. /// The bounding box to pad. 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; } } }