// Checks invariants for the return value of Plane.ToTrTransform() void CheckToTrTransformInvariants(Plane plane) { var reflect = plane.ToTrTransform(); // Basis vectors should map properly. Actually, we could use any 3 independent vectors. foreach (var basis in kBasisVectors) { Mtu.AssertAlmostEqual(plane.ReflectVector(basis), reflect.MultiplyVector(basis)); } // Det should be -1 Assert.AreEqual(-1, reflect.scale); // Points on plane should not move. We need to check at least 3 distinct points on the plane. // Any non-degenerate tetrahedron will project to at least 3 distinct points. foreach (var basis in kTetrahedron) { Vector3 v = plane.ClosestPointOnPlane(basis); Mtu.AssertAlmostEqual(v, reflect.MultiplyPoint(v)); } // Points not on the plane should move. // Specifically, they should be reflected. { Vector3 notOnPlane = plane.ClosestPointOnPlane(Vector3.zero) + plane.normal; Assert.IsTrue(!Mtu.AlmostEqual( notOnPlane, reflect.MultiplyPoint(notOnPlane), Mtu.ABSEPS, Mtu.RELEPS)); Mtu.AssertAlmostEqual(plane.ReflectPoint(notOnPlane), reflect.MultiplyPoint(notOnPlane)); } }
[TestCase(8, -8, -8, 3, -4, -5, 0, 0, 0)] // +x-y-z vert public void TestClosestPointOnBox( float px, float py, float pz, float spx, float spy, float spz, float nx, float ny, float nz) { var pos = new Vector3(px, py, pz); var halfWidth = new Vector3(3, 4, 5); var expectedSurfacePos = new Vector3(spx, spy, spz); var expectedSurfaceNorm = new Vector3(nx, ny, nz); Vector3 surfacePos, surfaceNorm; CubeStencil.FindClosestPointOnBoxSurface(pos, halfWidth, out surfacePos, out surfaceNorm); MathTestUtils.AssertAlmostEqual(expectedSurfacePos, surfacePos); if (expectedSurfaceNorm != Vector3.zero) { MathTestUtils.AssertAlmostEqual(expectedSurfaceNorm, surfaceNorm); } else { // Test case wants us to calculate it from scratch Vector3 diff = pos - expectedSurfacePos; if (diff != Vector3.zero) { MathTestUtils.AssertAlmostEqual(diff.normalized, surfaceNorm); } } }
public void TestClosestPointOnBoxEdgeCases() { var halfWidth = new Vector3(3, 4, 5); // Try all permutations of points directly on verts, faces, edges for (int xsign = -1; xsign <= 1; ++xsign) { for (int ysign = -1; ysign <= 1; ++ysign) { for (int zsign = -1; zsign <= 1; ++zsign) { int numFaces = Mathf.Abs(xsign) + Mathf.Abs(ysign) + Mathf.Abs(zsign); // Only care about running tests where the point is on 2 or 3 faces (ie edge, or vert) if (numFaces <= 1) { continue; } var pos = new Vector3(xsign * halfWidth.x, ysign * halfWidth.y, zsign * halfWidth.z); Vector3 surfacePos, surfaceNorm; CubeStencil.FindClosestPointOnBoxSurface(pos, halfWidth, out surfacePos, out surfaceNorm); MathTestUtils.AssertAlmostEqual(pos, surfacePos); MathTestUtils.AssertAlmostEqual(1, surfaceNorm.magnitude); for (int axis = 0; axis < 3; ++axis) { float p = pos[axis]; float h = halfWidth[axis]; float n = surfaceNorm[axis]; // The normal is not well defined, but it should at least point away from the box if (p == h) { Assert.GreaterOrEqual(n, 0, "Axis {0}", axis); } else if (p == -h) { Assert.LessOrEqual(n, 0, "Axis {0}", axis); } else if (-h < p & p < h) { // Should have no component parallel to the edge we're on Assert.AreEqual(n, 0, "Axis {0}", axis); } else { Assert.Fail("Bad test"); } } } } } }
// Checks invariants for the return value of Plane.ReflectPose(). void CheckReflectPoseInvariants(Plane plane, TrTransform pose0) { // Object -> world var pose1 = plane.ReflectPoseKeepHandedness(pose0); // Object x axis should be preserved. // Object y and z axes should be reflected. This can actually be checked for any 2 vectors // that are orthogonal to the preserved axis. Mtu.AssertAlmostEqual(-plane.ReflectVector(pose0.right), pose1.right); Mtu.AssertAlmostEqual(plane.ReflectVector(pose0.forward), pose1.forward); Mtu.AssertAlmostEqual(plane.ReflectVector(pose0.up), pose1.up); // pose.translation should be reflected. Mtu.AssertAlmostEqual(plane.ReflectPoint(pose0.translation), pose1.translation); // Handedness should not change (sign should be the same). // Magnitude should stay the same too. Assert.AreEqual(pose0.scale, pose1.scale); }
public void TestFbxQuaternion() { var uq = new Quaternion(1, 2, 3, 4); var fq = uq.ToFbxQuaternion(); // Basic round-tripping var uq2 = fq.ToUQuaternion(); MathTestUtils.AssertAlmostEqual(uq, uq2); // Check that [3] is w, the real part (docs don't say anything about this) var fqc = new FbxQuaternion(fq); fqc.Conjugate(); // [3] is the real part MathTestUtils.AssertAlmostEqual((float)fq.GetAt(3), (float)fqc.GetAt(3)); // and 0-2 are the imaginary part MathTestUtils.AssertAlmostEqual((float)fq.GetAt(1), -(float)fqc.GetAt(1)); }
static void TestReflectHelper(Plane plane, Vector3 v) { // There are 2 invariants for a point and its mirror: // - They have the same closest point on plane // - They have opposite signed distance to plane { Vector3 p2 = plane.ReflectPoint(v); Mtu.AssertAlmostEqual(plane.ClosestPointOnPlane(v), plane.ClosestPointOnPlane(p2)); Mtu.AssertAlmostEqual(plane.GetDistanceToPoint(v), -plane.GetDistanceToPoint(p2)); } // The invariants for reflecting a vector are similar; but they apply // to the plane with distance=0. { Vector3 v2 = plane.ReflectVector(v); Plane pO = plane; pO.distance = 0; Mtu.AssertAlmostEqual(pO.ClosestPointOnPlane(v), pO.ClosestPointOnPlane(v2)); Mtu.AssertAlmostEqual(pO.GetDistanceToPoint(v), -pO.GetDistanceToPoint(v2)); } }