ui基本完毕,修了一大把的bug
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b8da881646f8c04ab2fe5c6cd1bfc2f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,171 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
public class BinSortTests
|
||||
{
|
||||
[Test]
|
||||
public void BinNumber_SingleBin()
|
||||
{
|
||||
int n = 1;
|
||||
Assert.AreEqual(0, BinSort.GetBinNumber(0, 0, n));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BinNumber_EvenGrid()
|
||||
{
|
||||
int n = 2;
|
||||
Assert.AreEqual(0, BinSort.GetBinNumber(0, 0, n)); // Lower-left
|
||||
Assert.AreEqual(1, BinSort.GetBinNumber(0, 1, n)); // Lower-right
|
||||
Assert.AreEqual(2, BinSort.GetBinNumber(1, 1, n)); // Upper-right
|
||||
Assert.AreEqual(3, BinSort.GetBinNumber(1, 0, n)); // Upper-left
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BinNumber_OddGrid()
|
||||
{
|
||||
int n = 3;
|
||||
Assert.AreEqual(0, BinSort.GetBinNumber(0, 0, n));
|
||||
Assert.AreEqual(1, BinSort.GetBinNumber(0, 1, n));
|
||||
Assert.AreEqual(2, BinSort.GetBinNumber(0, 2, n));
|
||||
Assert.AreEqual(3, BinSort.GetBinNumber(1, 2, n));
|
||||
Assert.AreEqual(4, BinSort.GetBinNumber(1, 1, n));
|
||||
Assert.AreEqual(5, BinSort.GetBinNumber(1, 0, n));
|
||||
Assert.AreEqual(6, BinSort.GetBinNumber(2, 0, n));
|
||||
Assert.AreEqual(7, BinSort.GetBinNumber(2, 1, n));
|
||||
Assert.AreEqual(8, BinSort.GetBinNumber(2, 2, n));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_EmptyPointsList()
|
||||
{
|
||||
int binCount = 1;
|
||||
var input = new BinnedObjectMock[0];
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input, input.Length, binCount);
|
||||
|
||||
// Expect to get back reference to the input array
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_ZeroBinCount()
|
||||
{
|
||||
int binCount = 0;
|
||||
var input = new BinnedObjectMock[0];
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input, input.Length, binCount);
|
||||
|
||||
// Expect to get back reference to the input array
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_SingleBin()
|
||||
{
|
||||
int binCount = 1;
|
||||
var input = new BinnedObjectMock[] {
|
||||
new BinnedObjectMock(0)
|
||||
};
|
||||
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input, input.Length, binCount);
|
||||
|
||||
// Expect to get back reference to the input array
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_MultipleBinsFullSort()
|
||||
{
|
||||
var binCount = 10;
|
||||
var lastIndex = binCount;
|
||||
var input = new List<BinnedObjectMock>(binCount);
|
||||
|
||||
// Give each object a separate bin number.
|
||||
// Input array is in reverse order
|
||||
for (int i = 0; i < binCount; i++) {
|
||||
input.Insert(0, new BinnedObjectMock(i));
|
||||
};
|
||||
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input.ToArray(), input.Count, binCount);
|
||||
|
||||
// Input and output are different but have same # of elements
|
||||
Assert.AreNotEqual(input, output);
|
||||
Assert.AreEqual(input.Count, output.Length);
|
||||
|
||||
// Verify sort
|
||||
for (int i = 0; i < output.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(i, output[i].bin);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_MultipleBinsPartialSort()
|
||||
{
|
||||
var binCount = 10;
|
||||
var lastIndex = 5;
|
||||
var input = new List<BinnedObjectMock>(binCount);
|
||||
|
||||
// Give each object a separate bin number.
|
||||
// Input array is in reverse order
|
||||
for (int i = 0; i < binCount; i++) {
|
||||
input.Insert(0, new BinnedObjectMock(i));
|
||||
};
|
||||
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input.ToArray(), lastIndex, binCount);
|
||||
|
||||
// Input and output are different but have same # of elements
|
||||
Assert.AreNotEqual(input, output);
|
||||
Assert.AreEqual(input.Count, output.Length);
|
||||
|
||||
// Verify sort
|
||||
for (int i = 0; i < lastIndex; i++)
|
||||
{
|
||||
Assert.AreEqual(i + lastIndex, output[i].bin);
|
||||
}
|
||||
// Last elements should not be sorted since we only sorted up to lastIndex
|
||||
for (int i = lastIndex; i < output.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(output.Length - i - 1, output[i].bin);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Sort_LastIndexOutOfRange()
|
||||
{
|
||||
var binCount = 10;
|
||||
var lastIndex = binCount + 1;
|
||||
var input = new List<BinnedObjectMock>(binCount);
|
||||
|
||||
// Give each object a separate bin number.
|
||||
// Input array is in reverse order
|
||||
for (int i = 0; i < binCount; i++) {
|
||||
input.Insert(0, new BinnedObjectMock(i));
|
||||
};
|
||||
|
||||
var output = BinSort.Sort<BinnedObjectMock>(input.ToArray(), lastIndex, binCount);
|
||||
|
||||
// Input and output are different but have same # of elements
|
||||
Assert.AreNotEqual(input, output);
|
||||
Assert.AreEqual(input.Count, output.Length);
|
||||
|
||||
// Expect to get back reference to the input array
|
||||
for (int i = 0; i < output.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(i, output[i].bin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BinnedObjectMock: IBinSortable
|
||||
{
|
||||
public int bin { get; set; }
|
||||
|
||||
internal BinnedObjectMock(int bin)
|
||||
{
|
||||
this.bin = bin;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Bin = {bin}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4765fbb4b7c91f4f8a32eef007d3887
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class ConstrainedTriangulatorTests
|
||||
{
|
||||
[Test]
|
||||
public void TestNullInputPoints()
|
||||
{
|
||||
var triangulator = new ConstrainedTriangulator(null, new List<EdgeConstraint>(), Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNullConstraints()
|
||||
{
|
||||
var triangulator = new ConstrainedTriangulator(new List<MeshVertex>(), null, Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyInputPoints()
|
||||
{
|
||||
var triangulator = new ConstrainedTriangulator(new List<MeshVertex>(), new List<EdgeConstraint>(), Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLessThanThreeInputPoints()
|
||||
{
|
||||
List<MeshVertex> points = new List<MeshVertex>();
|
||||
points.Add(new MeshVertex(Vector3.zero));
|
||||
points.Add(new MeshVertex(Vector3.one));
|
||||
|
||||
var triangulator = new ConstrainedTriangulator(points, new List<EdgeConstraint>(), Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnconstrainedConvexPolygons()
|
||||
{
|
||||
// This test generates points for regular convex polygons of n = 3 to n = 20
|
||||
// and verifies the triangulation is correct. Each polygon has a vertex in its
|
||||
// center as well to ensure the triangulation is identical between runs.
|
||||
for (int n = 3; n <= 20; n++)
|
||||
{
|
||||
// Create the points of the polygon
|
||||
List<MeshVertex> points = new List<MeshVertex>();
|
||||
|
||||
// Add an additional center point
|
||||
points.Add(new MeshVertex(Vector3.zero));
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
float angle = ((float)i / (float)n) * 2f * Mathf.PI;
|
||||
points.Add(new MeshVertex(new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0f)));
|
||||
}
|
||||
|
||||
var triangulator = new ConstrainedTriangulator(points, new List<EdgeConstraint>(), Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
|
||||
// Verify the triangulation has the correct number of triangles
|
||||
Assert.AreEqual(3 * n, triangles.Length);
|
||||
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
// Verify each contains the origin point
|
||||
Assert.True(triangles[i] == 0 || triangles[i + 1] == 0 || triangles[i + 2] == 0);
|
||||
|
||||
// Verify the other two vertices are adjacent and wound clockwise
|
||||
if (triangles[i] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i + 2], GetAdjacentVertex(triangles[i + 1], points.Count));
|
||||
}
|
||||
else if (triangles[i + 1] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i], GetAdjacentVertex(triangles[i + 2], points.Count));
|
||||
}
|
||||
else if (triangles[i + 2] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i + 1], GetAdjacentVertex(triangles[i], points.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetAdjacentVertex(int i, int n)
|
||||
{
|
||||
if ((i + 1) < n)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If i == n, adjacent vertex is i == 1
|
||||
return ((i + 1) % n) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59dcbbc1aaeeb8c4cb1c2830e8dc5231
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
public class EdgeConstraintTests
|
||||
{
|
||||
[Test]
|
||||
public void IdenticalEdgesAreEqual()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(1, 2);
|
||||
|
||||
Assert.True(edgeA == edgeB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DifferentV1EdgesAreNotEqual()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(3, 2);
|
||||
Assert.False(edgeA == edgeB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DifferentV2EdgesAreNotEqual()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(1, 3);
|
||||
|
||||
Assert.False(edgeA == edgeB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EdgesInOppositeDirectionsAreEqual()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(2, 1);
|
||||
Assert.True(edgeA == edgeB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashCodeEqualEdges()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(1, 2);
|
||||
Assert.True(edgeA.GetHashCode() == edgeB.GetHashCode());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashCodeReversedEdges()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(2, 1);
|
||||
Assert.True(edgeA.GetHashCode() == edgeB.GetHashCode());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashCodeDifferentEdges()
|
||||
{
|
||||
EdgeConstraint edgeA = new EdgeConstraint(1, 2);
|
||||
EdgeConstraint edgeB = new EdgeConstraint(1, 3);
|
||||
Assert.False(edgeA.GetHashCode() == edgeB.GetHashCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cab166f639a71a49a926c8c9bd116c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,328 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
public class MathUtilsTests
|
||||
{
|
||||
#region IsPointOnRightSideOfLine Tests
|
||||
[Test]
|
||||
public void IsPointOnRightSideOfLine_PointOnRightSide()
|
||||
{
|
||||
var a = new Vector2(0, 0);
|
||||
var b = new Vector2(1, 1);
|
||||
var p = new Vector2(1, 0);
|
||||
Assert.True(MathUtils.IsPointOnRightSideOfLine(a, b, p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsPointOnRightSideOfLine_PointOnLeftSide()
|
||||
{
|
||||
var a = new Vector2(0, 0);
|
||||
var b = new Vector2(1, 1);
|
||||
var p = new Vector2(0, 1);
|
||||
Assert.False(MathUtils.IsPointOnRightSideOfLine(a, b, p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsPointOnRightSideOfLine_PointFirstEndpoint()
|
||||
{
|
||||
var a = new Vector2(0, 0);
|
||||
var b = new Vector2(1, 1);
|
||||
var p = a;
|
||||
Assert.True(MathUtils.IsPointOnRightSideOfLine(a, b, p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsPointOnRightSideOfLine_PointSecondEndpoint()
|
||||
{
|
||||
var a = new Vector2(0, 0);
|
||||
var b = new Vector2(1, 1);
|
||||
var p = b;
|
||||
Assert.True(MathUtils.IsPointOnRightSideOfLine(a, b, p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsPointOnRightSideOfLine_PointLineMidpoint()
|
||||
{
|
||||
var a = new Vector2(0, 0);
|
||||
var b = new Vector2(1, 1);
|
||||
var p = (a + b) / 2;
|
||||
Assert.True(MathUtils.IsPointOnRightSideOfLine(a, b, p));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LinePlaneIntersectionTests
|
||||
[Test]
|
||||
public void LinePlaneIntersection_DegenerateLine()
|
||||
{
|
||||
Vector3 a = Vector3.one;
|
||||
Vector3 b = Vector3.one;
|
||||
Vector3 n = Vector3.up;
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.False(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_ZeroLengthNormal()
|
||||
{
|
||||
Vector3 a = Vector3.zero;
|
||||
Vector3 b = Vector3.one;
|
||||
Vector3 n = Vector3.zero;
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.False(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_LineAbovePlane()
|
||||
{
|
||||
Vector3 a = new Vector3(0, 1, 0);
|
||||
Vector3 b = new Vector3(0, 2, 0);
|
||||
Vector3 n = new Vector3(0, 1, 0);
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.False(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_LineBelowPlane()
|
||||
{
|
||||
Vector3 a = new Vector3(0, -1, 0);
|
||||
Vector3 b = new Vector3(0, -2, 0);
|
||||
Vector3 n = new Vector3(0, 1, 0);
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.False(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_LineCrossingPlane()
|
||||
{
|
||||
Vector3 a = new Vector3(0, -1, 0);
|
||||
Vector3 b = new Vector3(0, 1, 0);
|
||||
Vector3 n = new Vector3(0, 1, 0);
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.True(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
|
||||
// Intersection point crosses the mid-point of the line
|
||||
Assert.AreEqual(Vector3.zero, x);
|
||||
Assert.AreEqual(0.5f, s);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_StartPointOnPlane()
|
||||
{
|
||||
Vector3 a = new Vector3(0, 0, 0);
|
||||
Vector3 b = new Vector3(0, 1, 0);
|
||||
Vector3 n = new Vector3(0, 1, 0);
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.True(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
|
||||
// Intersection point crosses the mid-point of the line
|
||||
Assert.AreEqual(Vector3.zero, x);
|
||||
Assert.AreEqual(0, s);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinePlaneIntersection_EndPointOnPlane()
|
||||
{
|
||||
Vector3 a = new Vector3(0, 1, 0);
|
||||
Vector3 b = new Vector3(0, 0, 0);
|
||||
Vector3 n = new Vector3(0, 1, 0);
|
||||
Vector3 p0 = Vector3.zero;
|
||||
Vector3 x;
|
||||
float s;
|
||||
Assert.True(MathUtils.LinePlaneIntersection(a, b, n, p0, out x, out s));
|
||||
|
||||
// Intersection point crosses the mid-point of the line
|
||||
Assert.AreEqual(Vector3.zero, x);
|
||||
Assert.AreEqual(1, s);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LinesIntersect General Tests
|
||||
[Test]
|
||||
public void LinesIntersect_True()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = new Vector2(0, 1);
|
||||
Vector2 b2 = new Vector2(1, 0);
|
||||
Assert.True(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_LineAOnLeftSideOfLineB()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(0.49f, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0f);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_LineAOnRightSideOfLineB()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0.51f, 0.5f);
|
||||
Vector2 a2 = new Vector2(1f, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0f);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_LineBOnTopSideOfLineA()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(1f, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0.51f);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_LineBOnBottomSideOfLineA()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(1f, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0f);
|
||||
Vector2 b2 = new Vector2(0.5f, 0.49f);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LinesIntersect Shared Vertex Tests
|
||||
[Test]
|
||||
public void LinesIntersect_A1B1Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = a1;
|
||||
Vector2 b2 = new Vector2(1, 0);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_A1B2Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = new Vector2(0, 1);
|
||||
Vector2 b2 = a1;
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_A2B1Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = a2;
|
||||
Vector2 b2 = new Vector2(1, 0);
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_A2B2Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = new Vector2(0, 1);
|
||||
Vector2 b2 = a2;
|
||||
Assert.False(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IsQuadConvex Shared Vertex Tests
|
||||
[Test]
|
||||
public void IsQuadConvex_A1B1Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = a1;
|
||||
Vector2 b2 = new Vector2(1, 0);
|
||||
Assert.True(MathUtils.IsQuadConvex(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsQuadConvex_A1B2Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = new Vector2(0, 1);
|
||||
Vector2 b2 = a1;
|
||||
Assert.True(MathUtils.IsQuadConvex(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsQuadConvex_A2B1Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = a2;
|
||||
Vector2 b2 = new Vector2(1, 0);
|
||||
Assert.True(MathUtils.IsQuadConvex(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsQuadConvex_A2B2Shared()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0);
|
||||
Vector2 a2 = new Vector2(1, 1);
|
||||
Vector2 b1 = new Vector2(0, 1);
|
||||
Vector2 b2 = a2;
|
||||
Assert.True(MathUtils.IsQuadConvex(a1, a2, b1, b2));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LinesIntersect Vertex on Line Tests
|
||||
[Test]
|
||||
public void LinesIntersect_A1OnBLine()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0.5f, 0.5f);
|
||||
Vector2 a2 = new Vector2(1, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.True(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_A2OnBLine()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(0.5f, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.True(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_B1OnALine()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(1, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0.5f);
|
||||
Vector2 b2 = new Vector2(0.5f, 1);
|
||||
Assert.True(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinesIntersect_B2OnALine()
|
||||
{
|
||||
Vector2 a1 = new Vector2(0, 0.5f);
|
||||
Vector2 a2 = new Vector2(1, 0.5f);
|
||||
Vector2 b1 = new Vector2(0.5f, 0);
|
||||
Vector2 b2 = new Vector2(0.5f, 0.5f);
|
||||
Assert.True(MathUtils.LinesIntersect(a1, a2, b1, b2));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2a8735b44707e84d97a6f0e76764430
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
public class MeshVertexTests
|
||||
{
|
||||
[Test]
|
||||
public void EqualPositionsEqual()
|
||||
{
|
||||
MeshVertex vertexA = new MeshVertex(new Vector3(1, 2, 3), Vector3.up, Vector2.zero);
|
||||
MeshVertex vertexB = new MeshVertex(new Vector3(1, 2, 3), Vector3.up, Vector2.zero);
|
||||
Assert.True(vertexA == vertexB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DifferentPositionsNotEqual()
|
||||
{
|
||||
MeshVertex vertexA = new MeshVertex(new Vector3(1, 2, 3), Vector3.up, Vector2.zero);
|
||||
MeshVertex vertexB = new MeshVertex(new Vector3(1, 2, 3), Vector3.up, Vector2.zero);
|
||||
Assert.True(vertexA == vertexB);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77e1a609db0f2454ba3f7188e6bcfa0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"RuntimeAssembly"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 890a6d949f4fba54a807db272232034c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
public class QuadTests
|
||||
{
|
||||
[Test]
|
||||
public void TestInit()
|
||||
{
|
||||
int q1 = 1;
|
||||
int q2 = 2;
|
||||
int q3 = 3;
|
||||
int q4 = 4;
|
||||
int t1 = 5;
|
||||
int t2 = 6;
|
||||
int t1L = 7;
|
||||
int t1R = 8;
|
||||
int t2L = 9;
|
||||
int t2R = 10;
|
||||
|
||||
Quad quad = new Quad(q1, q2, q3, q4, t1, t2, t1L, t1R, t2L, t2R);
|
||||
|
||||
Assert.AreEqual(q1, quad.q1);
|
||||
Assert.AreEqual(q2, quad.q2);
|
||||
Assert.AreEqual(q3, quad.q3);
|
||||
Assert.AreEqual(q4, quad.q4);
|
||||
Assert.AreEqual(t1, quad.t1);
|
||||
Assert.AreEqual(t2, quad.t2);
|
||||
Assert.AreEqual(t1L, quad.t1L);
|
||||
Assert.AreEqual(t1R, quad.t1R);
|
||||
Assert.AreEqual(t2L, quad.t2L);
|
||||
Assert.AreEqual(t2R, quad.t2R);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6baf3751b104d85409c5de8cf8f21b04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,383 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
public class FragmentDataTests
|
||||
{
|
||||
[Test]
|
||||
public void EmptyInit()
|
||||
{
|
||||
int vertexCount = 101;
|
||||
FragmentData data = new FragmentData(vertexCount, 0);
|
||||
|
||||
// Verify initialization
|
||||
Assert.AreEqual(vertexCount, data.Vertices.Capacity);
|
||||
Assert.AreEqual(vertexCount, data.IndexMap.Length);
|
||||
Assert.Zero(data.Vertices.Count);
|
||||
Assert.Zero(data.CutVertices.Count);
|
||||
Assert.Zero(data.Constraints.Count);
|
||||
Assert.Zero(data.triangleCount);
|
||||
Assert.Zero(data.vertexCount);
|
||||
|
||||
// Assume two submeshes for now
|
||||
Assert.AreEqual(data.Triangles.Length, 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MeshInit()
|
||||
{
|
||||
// Test mesh data
|
||||
var vertices = new Vector3[] {
|
||||
new Vector3(0, 0, 0),
|
||||
new Vector3(1, 0, 0),
|
||||
new Vector3(0, 1, 0),
|
||||
new Vector3(1, 1, 0)
|
||||
};
|
||||
var normals = new Vector3[] {
|
||||
new Vector3(-0.1f, -0.1f, 1).normalized,
|
||||
new Vector3(0.1f, -0.1f, 1).normalized,
|
||||
new Vector3(-0.1f, 0.1f, 1).normalized,
|
||||
new Vector3(0.1f, 0.1f, 1).normalized
|
||||
};
|
||||
var uv = new Vector2[] {
|
||||
new Vector3(0, 0),
|
||||
new Vector3(1, 0),
|
||||
new Vector3(0, 1),
|
||||
new Vector3(1, 1)
|
||||
};
|
||||
var triangles = new int[] { 0, 2, 1, 1, 2, 3 };
|
||||
|
||||
// Setup the test mesh
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.vertices = vertices;
|
||||
mesh.triangles = triangles;
|
||||
mesh.normals = normals;
|
||||
mesh.uv = uv;
|
||||
|
||||
// Generate the sliced mesh data from the mesh
|
||||
FragmentData meshData = new FragmentData(mesh);
|
||||
|
||||
// Verify sliced mesh data was initialized properly
|
||||
|
||||
// Check vertex data
|
||||
Assert.AreEqual(mesh.vertexCount, meshData.Vertices.Count);
|
||||
for(int i = 0; i < meshData.Vertices.Count; i++)
|
||||
{
|
||||
var vertex = meshData.Vertices[i];
|
||||
Assert.AreEqual(vertices[i], vertex.position);
|
||||
Assert.AreEqual(normals[i], vertex.normal);
|
||||
Assert.AreEqual(uv[i], vertex.uv);
|
||||
}
|
||||
|
||||
// Check triangle data
|
||||
Assert.AreEqual(mesh.triangles.Length, meshData.Triangles[0].Count);
|
||||
// Assume two submeshes for now
|
||||
Assert.AreEqual(2, meshData.Triangles.Length);
|
||||
|
||||
Assert.Zero(meshData.CutVertices.Count);
|
||||
Assert.Zero(meshData.Constraints.Count);
|
||||
Assert.AreEqual(mesh.vertexCount, meshData.IndexMap.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddCutFaceVertex()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
var meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
new Vector3(i + 4, i + 5, i + 6),
|
||||
new Vector2(i + 7, i + 8)
|
||||
);
|
||||
}
|
||||
|
||||
// Vertex add to both main vertex data and cut-face vertex data
|
||||
Assert.AreEqual(vertexCount, meshData.Vertices.Count);
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
|
||||
// Index map should be updated as well
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
Assert.AreEqual(new Vector3(i + 1, i + 2, i + 3), meshData.Vertices[i].position);
|
||||
Assert.AreEqual(new Vector3(i + 4, i + 5, i + 6), meshData.Vertices[i].normal);
|
||||
Assert.AreEqual(new Vector2(i + 7, i + 8), meshData.Vertices[i].uv);
|
||||
Assert.AreEqual(new Vector3(i + 1, i + 2, i + 3), meshData.CutVertices[i].position);
|
||||
Assert.AreEqual(new Vector3(i + 4, i + 5, i + 6), meshData.CutVertices[i].normal);
|
||||
Assert.AreEqual(new Vector2(i + 7, i + 8), meshData.CutVertices[i].uv);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddMappedVertex()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
var meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
MeshVertex vertex = new MeshVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
new Vector3(i + 4, i + 5, i + 6),
|
||||
new Vector2(i + 7, i + 8));
|
||||
|
||||
meshData.AddMappedVertex(vertex, i);
|
||||
}
|
||||
|
||||
// Vertex added only to main vertex data
|
||||
Assert.AreEqual(vertexCount, meshData.Vertices.Count);
|
||||
Assert.AreEqual(0, meshData.CutVertices.Count);
|
||||
|
||||
// Index map should be updated as well
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
Assert.AreEqual(new Vector3(i + 1, i + 2, i + 3), meshData.Vertices[i].position);
|
||||
Assert.AreEqual(new Vector3(i + 4, i + 5, i + 6), meshData.Vertices[i].normal);
|
||||
Assert.AreEqual(new Vector2(i + 7, i + 8), meshData.Vertices[i].uv);
|
||||
Assert.AreEqual(i, meshData.IndexMap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddTriangle()
|
||||
{
|
||||
FragmentData meshData = new FragmentData(0, 0);
|
||||
|
||||
int v1 = 1;
|
||||
int v2 = 2;
|
||||
int v3 = 3;
|
||||
|
||||
meshData.AddTriangle(v1, v2, v3, SlicedMeshSubmesh.Default);
|
||||
|
||||
Assert.AreEqual(3, meshData.Triangles[(int)SlicedMeshSubmesh.Default].Count);
|
||||
Assert.AreEqual(v1, meshData.Triangles[(int)SlicedMeshSubmesh.Default][0]);
|
||||
Assert.AreEqual(v2, meshData.Triangles[(int)SlicedMeshSubmesh.Default][1]);
|
||||
Assert.AreEqual(v3, meshData.Triangles[(int)SlicedMeshSubmesh.Default][2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddMappedTriangle()
|
||||
{
|
||||
int vertexCount = 46;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
// Indices of the vertices in the original mesh (arbitary indices)
|
||||
int v1 = 11;
|
||||
int v2 = 23;
|
||||
int v3 = 45;
|
||||
|
||||
// First, add the vertx data. v1, v2, v3 will be mapped to the indices
|
||||
// 0, 1, 2 (respectively) since that is the order they are added
|
||||
meshData.AddMappedVertex(new MeshVertex(Vector3.zero), v1);
|
||||
int v1Mapped = meshData.vertexCount - 1;
|
||||
meshData.AddMappedVertex(new MeshVertex(Vector3.zero), v2);
|
||||
int v2Mapped = meshData.vertexCount - 1;
|
||||
meshData.AddMappedVertex(new MeshVertex(Vector3.zero), v3);
|
||||
int v3Mapped = meshData.vertexCount - 1;
|
||||
|
||||
// Add the triangle, but map v1, v2, v3 to the indices for the sliced mesh
|
||||
meshData.AddMappedTriangle(v1, v2, v3, SlicedMeshSubmesh.Default);
|
||||
|
||||
Assert.AreEqual(3, meshData.Triangles[(int)SlicedMeshSubmesh.Default].Count);
|
||||
Assert.AreEqual(v1Mapped, meshData.Triangles[(int)SlicedMeshSubmesh.Default][0]);
|
||||
Assert.AreEqual(v2Mapped, meshData.Triangles[(int)SlicedMeshSubmesh.Default][1]);
|
||||
Assert.AreEqual(v3Mapped, meshData.Triangles[(int)SlicedMeshSubmesh.Default][2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeldCutFaceVertices_AllVerticesUnique()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
}
|
||||
|
||||
// Verify vertex count prior to weld
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
|
||||
meshData.WeldCutFaceVertices();
|
||||
|
||||
// # of cut vertices should remain unchanged after weld
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeldCutFaceVertices_OneDuplicateVertex()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
}
|
||||
|
||||
// Duplicate one of the vertices
|
||||
meshData.CutVertices[vertexCount - 1] = meshData.CutVertices[0];
|
||||
|
||||
// Verify vertex count prior to weld
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
|
||||
meshData.WeldCutFaceVertices();
|
||||
|
||||
// Expect two vertices welded, so final count is one less vertex
|
||||
Assert.AreEqual(vertexCount - 1, meshData.CutVertices.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeldCutFaceVertices_GreaterThanEpsilon()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
}
|
||||
|
||||
var magnitude = meshData.CutVertices[0].position.magnitude;
|
||||
|
||||
// According to Unity documentation, == comparison between two vectors
|
||||
// returns true if their magnitude is less than 1E-5. We make two vertices
|
||||
// differ by slightly larger than this amount so that they are not welded together.
|
||||
meshData.CutVertices[vertexCount - 1] = new MeshVertex(
|
||||
(magnitude + 1.1E-5f) * meshData.CutVertices[0].position.normalized,
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
|
||||
// Verify vertex count prior to weld
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
|
||||
meshData.WeldCutFaceVertices();
|
||||
|
||||
// Expect same vertex count since no vertices welded
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeldCutFaceVertices_LessThanEpsilon()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
}
|
||||
|
||||
var magnitude = meshData.CutVertices[0].position.magnitude;
|
||||
|
||||
// According to Unity documentation, == comparison between two vectors
|
||||
// returns true if their magnitude is less than 1E-5. We make two vertices
|
||||
// differ by slightly less than this amount so that they are welded together.
|
||||
meshData.CutVertices[vertexCount - 1] = new MeshVertex(
|
||||
(magnitude + 0.9E-5f) * meshData.CutVertices[0].position.normalized,
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
|
||||
// Verify vertex count prior to weld
|
||||
Assert.AreEqual(vertexCount, meshData.CutVertices.Count);
|
||||
|
||||
meshData.WeldCutFaceVertices();
|
||||
|
||||
// Expect two vertices welded, so final count is one less vertex
|
||||
Assert.AreEqual(vertexCount - 1, meshData.CutVertices.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeldCutFaceVertices_CutEdgeUpdate()
|
||||
{
|
||||
int vertexCount = 10;
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(
|
||||
new Vector3(i + 1, i + 2, i + 3),
|
||||
Vector3.zero,
|
||||
Vector2.zero
|
||||
);
|
||||
}
|
||||
|
||||
// Last vertex is equal to the first vertex
|
||||
meshData.CutVertices[vertexCount - 1] = meshData.CutVertices[0];
|
||||
|
||||
// Add cut edges that map to the duplicate vertex
|
||||
meshData.Constraints.Add(new EdgeConstraint(0, vertexCount - 1));
|
||||
|
||||
// Assert expected edge state prior to weld
|
||||
Assert.AreEqual(0, meshData.Constraints[0].v1);
|
||||
Assert.AreEqual(vertexCount - 1, meshData.Constraints[0].v2);
|
||||
|
||||
meshData.WeldCutFaceVertices();
|
||||
|
||||
// Assert expected edge state after the weld
|
||||
Assert.AreEqual(0, meshData.Constraints[0].v1);
|
||||
Assert.AreEqual(0, meshData.Constraints[0].v2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToMesh()
|
||||
{
|
||||
int vertexCount = 100;
|
||||
int cutVertexCount = 50;
|
||||
int triangleCount1 = 10;
|
||||
int triangleCount2 = 15;
|
||||
|
||||
FragmentData meshData = new FragmentData(vertexCount, 0);
|
||||
|
||||
// Add some fake data
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
meshData.AddMappedVertex(new MeshVertex(), 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < cutVertexCount; i++)
|
||||
{
|
||||
meshData.AddCutFaceVertex(Vector3.zero, Vector3.zero, Vector2.zero);
|
||||
}
|
||||
|
||||
for (int i = 0; i < triangleCount1; i++)
|
||||
{
|
||||
meshData.AddTriangle(0, 0, 0, SlicedMeshSubmesh.Default);
|
||||
}
|
||||
|
||||
for (int i = 0; i < triangleCount2; i++)
|
||||
{
|
||||
meshData.AddTriangle(0, 0, 0, SlicedMeshSubmesh.CutFace);
|
||||
}
|
||||
|
||||
Mesh mesh = meshData.ToMesh();
|
||||
|
||||
// Each time we add a cut face vertex, it adds two vertices, one for the
|
||||
// original sub mesh and another for the cut face sub mesh.
|
||||
Assert.AreEqual(vertexCount + 2 * cutVertexCount, mesh.vertexCount);
|
||||
Assert.AreEqual(2, mesh.subMeshCount);
|
||||
|
||||
// Three indices for each triangle
|
||||
Assert.AreEqual(3 * triangleCount1, mesh.GetTriangles(0).Length);
|
||||
Assert.AreEqual(3 * triangleCount2, mesh.GetTriangles(1).Length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6dd1fd6416560a4b9d99747bdefa187
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class TriangulationPointTests
|
||||
{
|
||||
[Test]
|
||||
public void TestInit()
|
||||
{
|
||||
int index = 1;
|
||||
Vector2 coords = new Vector2(0.5f, 0.75f);
|
||||
|
||||
var point = new TriangulationPoint(index, coords);
|
||||
|
||||
Assert.AreEqual(index, point.index);
|
||||
Assert.AreEqual(coords, point.coords);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4991ec602140c2429ceb10f5f27138a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class TriangulatorTests
|
||||
{
|
||||
[Test]
|
||||
public void TestNullInputPoints()
|
||||
{
|
||||
Triangulator triangulator = new Triangulator(null, Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyInputPoints()
|
||||
{
|
||||
Triangulator triangulator = new Triangulator(new List<MeshVertex>(), Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLessThanThreeInputPoints()
|
||||
{
|
||||
List<MeshVertex> points = new List<MeshVertex>();
|
||||
points.Add(new MeshVertex(Vector3.zero));
|
||||
points.Add(new MeshVertex(Vector3.one));
|
||||
|
||||
Triangulator triangulator = new Triangulator(points, Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
Assert.Zero(triangles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConvexPolygons()
|
||||
{
|
||||
// This test generates points for regular convex polygons of n = 3 to n = 20
|
||||
// and verifies the triangulation is correct. Each polygon has a vertex in its
|
||||
// center as well to ensure the triangulation is identical between runs.
|
||||
for (int n = 3; n <= 20; n++)
|
||||
{
|
||||
// Create the points of the polygon
|
||||
List<MeshVertex> points = new List<MeshVertex>();
|
||||
|
||||
// Add an additional center point
|
||||
points.Add(new MeshVertex(Vector3.zero));
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
float angle = ((float)i / (float)n) * 2f * Mathf.PI;
|
||||
points.Add(new MeshVertex(new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0f)));
|
||||
}
|
||||
|
||||
Triangulator triangulator = new Triangulator(points, Vector3.forward);
|
||||
int[] triangles = triangulator.Triangulate();
|
||||
|
||||
// Verify the triangulation has the correct number of triangles
|
||||
Assert.AreEqual(3 * n, triangles.Length);
|
||||
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
// Verify each contains the origin point
|
||||
Assert.True(triangles[i] == 0 || triangles[i + 1] == 0 || triangles[i + 2] == 0);
|
||||
|
||||
// Verify the other two vertices are adjacent and wound clockwise
|
||||
if (triangles[i] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i + 2], GetAdjacentVertex(triangles[i + 1], points.Count));
|
||||
}
|
||||
else if (triangles[i + 1] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i], GetAdjacentVertex(triangles[i + 2], points.Count));
|
||||
}
|
||||
else if (triangles[i + 2] == 0)
|
||||
{
|
||||
Assert.AreEqual(triangles[i + 1], GetAdjacentVertex(triangles[i], points.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetAdjacentVertex(int i, int n)
|
||||
{
|
||||
if ((i + 1) < n)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If i == n, adjacent vertex is i == 1
|
||||
return ((i + 1) % n) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90aa675abf691f247a4299a3a4defa44
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class Vector3Tests
|
||||
{
|
||||
[Test]
|
||||
public void PointAbovePlaneReturnsTrue()
|
||||
{
|
||||
var planeOrigin = Vector3.zero;
|
||||
var planeNormal = Vector3.up;
|
||||
var testPoint = Vector3.up;
|
||||
Assert.True(testPoint.IsAbovePlane(planeNormal, planeOrigin));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PointBelowPlaneReturnsFalse()
|
||||
{
|
||||
var planeOrigin = Vector3.zero;
|
||||
var planeNormal = Vector3.up;
|
||||
var testPoint = -Vector3.up;
|
||||
Assert.False(testPoint.IsAbovePlane(planeNormal, planeOrigin));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PointOnPlaneReturnsTrue()
|
||||
{
|
||||
var planeOrigin = Vector3.zero;
|
||||
var planeNormal = Vector3.up;
|
||||
var testPoint = Vector3.right;
|
||||
Assert.True(testPoint.IsAbovePlane(planeNormal, planeOrigin));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PointEqualToPlaneOriginReturnsTrue()
|
||||
{
|
||||
var planeOrigin = Vector3.one;
|
||||
var planeNormal = Vector3.up;
|
||||
var testPoint = planeOrigin;
|
||||
Assert.True(testPoint.IsAbovePlane(planeNormal, planeOrigin));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4c4528d3ed5484498a65a7404ed9839
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user