public void Move() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList<int> intList = new RawList<int>(); intList.AddRange(testArray); intList.Move(0, 3, 1); CollectionAssert.AreEqual(new int[] { 0, 0, 1, 2, 4, 5, 6, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(0, 3, 3); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 0, 1, 2, 6, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(0, 3, 5); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 4, 0, 1, 2, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -1); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 4, 5, 7, 8, 9, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -3); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 7, 8, 9, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -5); CollectionAssert.AreEqual(new int[] { 0, 1, 7, 8, 9, 5, 6, 7, 8, 9 }, intList); intList.Clear(); }
[Test] public void Basics() { RawList <int> intList = new RawList <int>(); intList.Add(10); intList.AddRange(new int[] { 17, 42, 94 }); Assert.AreEqual(4, intList.Count); Assert.IsTrue(intList.Contains(42)); Assert.AreEqual(2, intList.IndexOf(42)); CollectionAssert.AreEqual(new int[] { 10, 17, 42, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 17, 42, 94 }, intList.Data.Take(4)); intList.ShrinkToFit(); Assert.AreEqual(intList.Count, intList.Capacity); intList.Remove(42); Assert.AreEqual(3, intList.Count); Assert.IsTrue(!intList.Contains(42)); Assert.AreEqual(-1, intList.IndexOf(42)); CollectionAssert.AreEqual(new int[] { 10, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 17, 94 }, intList.Data.Take(3)); intList.Insert(1, 100); CollectionAssert.AreEqual(new int[] { 10, 100, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 100, 17, 94 }, intList.Data.Take(4)); intList.InsertRange(2, new int[] { 150, 200, 250, 300 }); CollectionAssert.AreEqual(new int[] { 10, 100, 150, 200, 250, 300, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 100, 150, 200, 250, 300, 17, 94 }, intList.Data.Take(8)); intList.Clear(); Assert.AreEqual(0, intList.Count); Assert.IsTrue(!intList.Contains(94)); }
[Test] public void Basics() { RawList<int> intList = new RawList<int>(); intList.Add(10); intList.AddRange(new int[] { 17, 42, 94 }); Assert.AreEqual(4, intList.Count); Assert.IsTrue(intList.Contains(42)); Assert.AreEqual(2, intList.IndexOf(42)); CollectionAssert.AreEqual(new int[] { 10, 17, 42, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 17, 42, 94 }, intList.Data.Take(4)); intList.ShrinkToFit(); Assert.AreEqual(intList.Count, intList.Capacity); intList.Remove(42); Assert.AreEqual(3, intList.Count); Assert.IsTrue(!intList.Contains(42)); Assert.AreEqual(-1, intList.IndexOf(42)); CollectionAssert.AreEqual(new int[] { 10, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 17, 94 }, intList.Data.Take(3)); intList.Insert(1, 100); CollectionAssert.AreEqual(new int[] { 10, 100, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 100, 17, 94 }, intList.Data.Take(4)); intList.InsertRange(2, new int[] { 150, 200, 250, 300 }); CollectionAssert.AreEqual(new int[] { 10, 100, 150, 200, 250, 300, 17, 94 }, intList); CollectionAssert.AreEqual(new int[] { 10, 100, 150, 200, 250, 300, 17, 94 }, intList.Data.Take(8)); intList.Clear(); Assert.AreEqual(0, intList.Count); Assert.IsTrue(!intList.Contains(94)); }
/// <summary> /// Identifies the points on the surface of hull. /// </summary> /// <param name="points">List of points in the set.</param> /// <param name="outputSurfacePoints">Unique points on the surface of the convex hull.</param> public static void GetConvexHull(IList <Vector3> points, IList <Vector3> outputSurfacePoints) { RawList <Vector3> rawPoints = CommonResources.GetVectorList(); rawPoints.AddRange(points); GetConvexHull(rawPoints, outputSurfacePoints); CommonResources.GiveBack(rawPoints); }
[Test] public void Sort() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList <int> intList = new RawList <int>(); intList.AddRange(testArray.Reverse().ToArray()); CollectionAssert.AreEqual(testArray.Reverse(), intList); intList.Sort(); CollectionAssert.AreEqual(testArray, intList); }
[Test] public void Move() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList <int> intList = new RawList <int>(); intList.AddRange(testArray); intList.Move(0, 3, 1); CollectionAssert.AreEqual(new int[] { 0, 0, 1, 2, 4, 5, 6, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(0, 3, 3); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 0, 1, 2, 6, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(0, 3, 5); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 4, 0, 1, 2, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -1); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 4, 5, 7, 8, 9, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -3); CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 7, 8, 9, 7, 8, 9 }, intList); intList.Clear(); intList.AddRange(testArray); intList.Move(7, 3, -5); CollectionAssert.AreEqual(new int[] { 0, 1, 7, 8, 9, 5, 6, 7, 8, 9 }, intList); intList.Clear(); }
/// <summary> /// Removes redundant points. Two points are redundant if they occupy the same hash grid cell. /// </summary> /// <param name="points">List of points to prune.</param> /// <param name="cellSize">Size of cells to determine redundancy.</param> public static void RemoveRedundantPoints(IList<Vector3> points, double cellSize) { RawList<Vector3> rawPoints = CommonResources.GetVectorList(); rawPoints.AddRange(points); RemoveRedundantPoints(rawPoints, cellSize); points.Clear(); for (int i = 0; i < rawPoints.Count; ++i) { points.Add(rawPoints.Elements[i]); } CommonResources.GiveBack(rawPoints); }
/// <summary> /// Identifies the indices of points in a set which are on the outer convex hull of the set. /// </summary> /// <param name="points">List of points in the set.</param> /// <param name="outputTriangleIndices">List of indices into the input point set composing the triangulated surface of the convex hull. /// Each group of 3 indices represents a triangle on the surface of the hull.</param> public static void GetConvexHull(IList <Vector3> points, IList <int> outputTriangleIndices) { RawList <Vector3> rawPoints = CommonResources.GetVectorList(); RawList <int> rawIndices = CommonResources.GetIntList(); rawPoints.AddRange(points); GetConvexHull(rawPoints, rawIndices); CommonResources.GiveBack(rawPoints); for (int i = 0; i < rawIndices.Count; i++) { outputTriangleIndices.Add(rawIndices[i]); } CommonResources.GiveBack(rawIndices); }
[Test] public void Resize() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList <int> intList = new RawList <int>(); intList.AddRange(testArray); CollectionAssert.AreEqual(testArray, intList); intList.Count = 20; Assert.IsTrue(intList.Count == 20); CollectionAssert.AreEqual(testArray.Concat(new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), intList); intList[19] = 19; Assert.IsTrue(intList[19] == 19); Assert.IsTrue(intList.Data[19] == 19); }
[Test] public void Sort() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList <int> intList = new RawList <int>(); // Sorting an empty array is a no-op, but entirely valid. No exceptions expected. intList.Sort(); // Insert the reversed data intList.AddRange(testArray.Reverse().ToArray()); CollectionAssert.AreEqual(testArray.Reverse(), intList); // Sort it and check if its equal to the original data intList.Sort(); CollectionAssert.AreEqual(testArray, intList); }
private static void RemoveInsidePoints(RawList <Vector3> points, RawList <int> triangleIndices, RawList <int> outsidePoints) { RawList <int> insidePoints = CommonResources.GetIntList(); //We're going to remove points from this list as we go to prune it down to the truly inner points. insidePoints.AddRange(outsidePoints); outsidePoints.Clear(); for (int i = 0; i < triangleIndices.Count && insidePoints.Count > 0; i += 3) { //Compute the triangle's plane in point-normal representation to test other points against. Vector3 normal; FindNormal(triangleIndices, points, i, out normal); Vector3 p = points.Elements[triangleIndices.Elements[i]]; for (int j = insidePoints.Count - 1; j >= 0; --j) { //Offset from the triangle to the current point, tested against the normal, determines if the current point is visible //from the triangle face. Vector3 offset; Vector3.Subtract(ref points.Elements[insidePoints.Elements[j]], ref p, out offset); float dot; Vector3.Dot(ref offset, ref normal, out dot); //If it's visible, then it's outside! if (dot > 0) { //This point is known to be on the outside; put it on the outside! outsidePoints.Add(insidePoints.Elements[j]); insidePoints.FastRemoveAt(j); } } } CommonResources.GiveBack(insidePoints); }
/// <summary> /// Identifies the indices of points in a set which are on the outer convex hull of the set. /// </summary> /// <param name="points">List of points in the set.</param> /// <param name="outputTriangleIndices">List of indices into the input point set composing the triangulated surface of the convex hull. /// Each group of 3 indices represents a triangle on the surface of the hull.</param> public static void GetConvexHull(RawList <Vector3> points, RawList <int> outputTriangleIndices) { if (points.Count == 0) { throw new ArgumentException("Point set must have volume."); } RawList <int> outsidePoints = CommonResources.GetIntList(); if (outsidePoints.Capacity < points.Count - 4) { outsidePoints.Capacity = points.Count - 4; } //Build the initial tetrahedron. //It will also give us the location of a point which is guaranteed to be within the //final convex hull. We can use this point to calibrate the winding of triangles. //A set of outside point candidates (all points other than those composing the tetrahedron) will be returned in the outsidePoints list. //That list will then be further pruned by the RemoveInsidePoints call. Vector3 insidePoint; ComputeInitialTetrahedron(points, outsidePoints, outputTriangleIndices, out insidePoint); //Compute outside points. RemoveInsidePoints(points, outputTriangleIndices, outsidePoints); var edges = CommonResources.GetIntList(); var toRemove = CommonResources.GetIntList(); var newTriangles = CommonResources.GetIntList(); //We're now ready to begin the main loop. while (outsidePoints.Count > 0) { //While the convex hull is incomplete... for (int k = 0; k < outputTriangleIndices.Count; k += 3) { //Find the normal of the triangle Vector3 normal; FindNormal(outputTriangleIndices, points, k, out normal); //Get the furthest point in the direction of the normal. int maxIndexInOutsideList = GetExtremePoint(ref normal, points, outsidePoints); int maxIndex = outsidePoints.Elements[maxIndexInOutsideList]; Vector3 maximum = points.Elements[maxIndex]; //If the point is beyond the current triangle, continue. Vector3 offset; Vector3.Subtract(ref maximum, ref points.Elements[outputTriangleIndices.Elements[k]], out offset); float dot; Vector3.Dot(ref normal, ref offset, out dot); if (dot > 0) { //It's been picked! Remove the maximum point from the outside. outsidePoints.FastRemoveAt(maxIndexInOutsideList); //Remove any triangles that can see the point, including itself! edges.Clear(); toRemove.Clear(); for (int n = outputTriangleIndices.Count - 3; n >= 0; n -= 3) { //Go through each triangle, if it can be seen, delete it and use maintainEdge on its edges. if (IsTriangleVisibleFromPoint(outputTriangleIndices, points, n, ref maximum)) { //This triangle can see it! //TODO: CONSIDER CONSISTENT WINDING HAPPYTIMES MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 1], edges); MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 2], edges); MaintainEdge(outputTriangleIndices[n + 1], outputTriangleIndices[n + 2], edges); //Because fast removals are being used, the order is very important. //It's pulling indices in from the end of the list in order, and also ensuring //that we never issue a removal order beyond the end of the list. outputTriangleIndices.FastRemoveAt(n + 2); outputTriangleIndices.FastRemoveAt(n + 1); outputTriangleIndices.FastRemoveAt(n); } } //Create new triangles. for (int n = 0; n < edges.Count; n += 2) { //For each edge, create a triangle with the extreme point. newTriangles.Add(edges[n]); newTriangles.Add(edges[n + 1]); newTriangles.Add(maxIndex); } //Only verify the windings of the new triangles. VerifyWindings(newTriangles, points, ref insidePoint); outputTriangleIndices.AddRange(newTriangles); newTriangles.Clear(); //Remove all points from the outsidePoints if they are inside the polyhedron RemoveInsidePoints(points, outputTriangleIndices, outsidePoints); //The list has been significantly messed with, so restart the loop. break; } } } CommonResources.GiveBack(outsidePoints); CommonResources.GiveBack(edges); CommonResources.GiveBack(toRemove); CommonResources.GiveBack(newTriangles); }
[Test] public void Resize() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList<int> intList = new RawList<int>(); intList.AddRange(testArray); CollectionAssert.AreEqual(testArray, intList); intList.Count = 20; Assert.IsTrue(intList.Count == 20); CollectionAssert.AreEqual(testArray.Concat(new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), intList); intList[19] = 19; Assert.IsTrue(intList[19] == 19); Assert.IsTrue(intList.Data[19] == 19); }
[Test] public void Sort() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList<int> intList = new RawList<int>(); // Sorting an empty array is a no-op, but entirely valid. No exceptions expected. intList.Sort(); // Insert the reversed data intList.AddRange(testArray.Reverse().ToArray()); CollectionAssert.AreEqual(testArray.Reverse(), intList); // Sort it and check if its equal to the original data intList.Sort(); CollectionAssert.AreEqual(testArray, intList); }
/// <summary> /// Identifies the indices of points in a set which are on the outer convex hull of the set. /// </summary> /// <param name="points">List of points in the set.</param> /// <param name="outputTriangleIndices">List of indices composing the triangulated surface of the convex hull. /// Each group of 3 indices represents a triangle on the surface of the hull.</param> public static void GetConvexHull(RawList<Vector3> points, RawList<int> outputTriangleIndices) { if (points.Count == 0) { throw new ArgumentException("Point set must have volume."); } RawList<int> outsidePoints = CommonResources.GetIntList(); if (outsidePoints.Capacity < points.Count - 4) outsidePoints.Capacity = points.Count - 4; //Build the initial tetrahedron. //It will also give us the location of a point which is guaranteed to be within the //final convex hull. We can use this point to calibrate the winding of triangles. //A set of outside point candidates (all points other than those composing the tetrahedron) will be returned in the outsidePoints list. //That list will then be further pruned by the RemoveInsidePoints call. Vector3 insidePoint; ComputeInitialTetrahedron(points, outsidePoints, outputTriangleIndices, out insidePoint); //Compute outside points. RemoveInsidePoints(points, outputTriangleIndices, outsidePoints); var edges = CommonResources.GetIntList(); var toRemove = CommonResources.GetIntList(); var newTriangles = CommonResources.GetIntList(); //We're now ready to begin the main loop. while (outsidePoints.Count > 0) { //While the convex hull is incomplete... for (int k = 0; k < outputTriangleIndices.Count; k += 3) { //Find the normal of the triangle Vector3 normal; FindNormal(outputTriangleIndices, points, k, out normal); //Get the furthest point in the direction of the normal. int maxIndexInOutsideList = GetExtremePoint(ref normal, points, outsidePoints); int maxIndex = outsidePoints.Elements[maxIndexInOutsideList]; Vector3 maximum = points.Elements[maxIndex]; //If the point is beyond the current triangle, continue. Vector3 offset; Vector3.Subtract(ref maximum, ref points.Elements[outputTriangleIndices.Elements[k]], out offset); float dot; Vector3.Dot(ref normal, ref offset, out dot); if (dot > 0) { //It's been picked! Remove the maximum point from the outside. outsidePoints.FastRemoveAt(maxIndexInOutsideList); //Remove any triangles that can see the point, including itself! edges.Clear(); toRemove.Clear(); for (int n = outputTriangleIndices.Count - 3; n >= 0; n -= 3) { //Go through each triangle, if it can be seen, delete it and use maintainEdge on its edges. if (IsTriangleVisibleFromPoint(outputTriangleIndices, points, n, ref maximum)) { //This triangle can see it! //TODO: CONSIDER CONSISTENT WINDING HAPPYTIMES MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 1], edges); MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 2], edges); MaintainEdge(outputTriangleIndices[n + 1], outputTriangleIndices[n + 2], edges); //Because fast removals are being used, the order is very important. //It's pulling indices in from the end of the list in order, and also ensuring //that we never issue a removal order beyond the end of the list. outputTriangleIndices.FastRemoveAt(n + 2); outputTriangleIndices.FastRemoveAt(n + 1); outputTriangleIndices.FastRemoveAt(n); } } //Create new triangles. for (int n = 0; n < edges.Count; n += 2) { //For each edge, create a triangle with the extreme point. newTriangles.Add(edges[n]); newTriangles.Add(edges[n + 1]); newTriangles.Add(maxIndex); } //Only verify the windings of the new triangles. VerifyWindings(newTriangles, points, ref insidePoint); outputTriangleIndices.AddRange(newTriangles); newTriangles.Clear(); //Remove all points from the outsidePoints if they are inside the polyhedron RemoveInsidePoints(points, outputTriangleIndices, outsidePoints); //The list has been significantly messed with, so restart the loop. break; } } } CommonResources.GiveBack(outsidePoints); CommonResources.GiveBack(edges); CommonResources.GiveBack(toRemove); CommonResources.GiveBack(newTriangles); }
public void Sort() { int[] testArray = Enumerable.Range(0, 10).ToArray(); RawList<int> intList = new RawList<int>(); intList.AddRange(testArray.Reverse().ToArray()); CollectionAssert.AreEqual(testArray.Reverse(), intList); intList.Sort(); CollectionAssert.AreEqual(testArray, intList); }