ui基本完毕,修了一大把的bug

This commit is contained in:
2026-07-13 02:28:39 +08:00
parent 1e20d73e90
commit fd22501f71
958 changed files with 378289 additions and 41038 deletions
@@ -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;
}
}
}
@@ -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: