#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2015 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_GEOMETRY_SOURCE 1 #include "Nuclex/Geometry/Vector3.h" #include #define EXPECT_ORTHOGONAL(v1, v2) { \ EXPECT_EQ( \ Math::Pi / 2.0f, \ Vector3::AngleBetween(Vector3::Normalize(v1), Vector3::Normalize(v2)) \ ); \ } namespace Nuclex { namespace Geometry { // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, ParameterConstructorAssignsValues) { EXPECT_EQ(1.2f, Vector3(1.2f, 3.4f, 5.6f).X); EXPECT_EQ(3.4f, Vector3(1.2f, 3.4f, 5.6f).Y); EXPECT_EQ(5.6f, Vector3(1.2f, 3.4f, 5.6f).Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, ZeroIsInitializedToAllZeroes) { EXPECT_EQ(0.0f, Vector3::Zero.X); EXPECT_EQ(0.0f, Vector3::Zero.Y); EXPECT_EQ(0.0f, Vector3::Zero.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, OneIsInitializedToAllOnes) { EXPECT_EQ(1.0f, Vector3::One.X); EXPECT_EQ(1.0f, Vector3::One.Y); EXPECT_EQ(1.0f, Vector3::One.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, LeftIsPointingTowardsNegativeX) { EXPECT_EQ(-1.0f, Vector3::Left.X); EXPECT_EQ(0.0f, Vector3::Left.Y); EXPECT_EQ(0.0f, Vector3::Left.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, RightIsPointingTowardsPositiveX) { EXPECT_EQ(1.0f, Vector3::Right.X); EXPECT_EQ(0.0f, Vector3::Right.Y); EXPECT_EQ(0.0f, Vector3::Right.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, BackwardIsPointingTowardsNegativeY) { EXPECT_EQ(0.0f, Vector3::Backward.X); EXPECT_EQ(-1.0f, Vector3::Backward.Y); EXPECT_EQ(0.0f, Vector3::Backward.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, ForwardIsPointingTowardsPositiveY) { EXPECT_EQ(0.0f, Vector3::Forward.X); EXPECT_EQ(1.0f, Vector3::Forward.Y); EXPECT_EQ(0.0f, Vector3::Forward.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, SquaredLengthCanBeCalculated) { const float X = 5.0f; const float Y = 10.0f; const float Z = 15.0f; EXPECT_EQ(X * X + Y * Y + Z * Z, Vector3(X, Y, Z).GetSquaredLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, SquaredLengthOfZeroVectorIsZero) { EXPECT_EQ(0.0f, Vector3::Zero.GetSquaredLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, LengthCanBeCalculated) { const float X = 5.0f; const float Y = 10.0f; const float Z = 15.0f; EXPECT_EQ(sqrtf(X * X + Y * Y + Z * Z), Vector3(X, Y, Z).GetLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, LengthOfZeroVectorIsZero) { EXPECT_EQ(0.0f, Vector3::Zero.GetLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeNormalized) { Vector3 right(2.0f, 0.0f, 0.0f); right.Normalize(); EXPECT_EQ(1.0f, right.X); EXPECT_EQ(0.0f, right.Y); EXPECT_EQ(0.0f, right.Z); Vector3 forward(0.0f, 2.0f, 0.0f); forward.Normalize(); EXPECT_EQ(0.0f, forward.X); EXPECT_EQ(1.0f, forward.Y); EXPECT_EQ(0.0f, forward.Z); Vector3 up(0.0f, 0.0f, 2.0f); up.Normalize(); EXPECT_EQ(0.0f, up.X); EXPECT_EQ(0.0f, up.Y); EXPECT_EQ(1.0f, up.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanProvideNormalizedCopies) { const Vector3 right(2.0f, 0.0f, 0.0f); Vector3 normalizedRight = Vector3::Normalize(right); EXPECT_EQ(1.0f, normalizedRight.X); EXPECT_EQ(0.0f, normalizedRight.Y); EXPECT_EQ(0.0f, normalizedRight.Z); const Vector3 forward(0.0f, 2.0f, 0.0f); Vector3 normalizedforward = Vector3::Normalize(forward); EXPECT_EQ(0.0f, normalizedforward.X); EXPECT_EQ(1.0f, normalizedforward.Y); EXPECT_EQ(0.0f, normalizedforward.Z); const Vector3 up(0.0f, 0.0f, 2.0f); Vector3 normalizedUp = Vector3::Normalize(up); EXPECT_EQ(0.0f, normalizedUp.X); EXPECT_EQ(0.0f, normalizedUp.Y); EXPECT_EQ(1.0f, normalizedUp.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, NormalizedCopyLeavesOriginalUntouched) { const Vector3 notNormalized(1.2f, 3.4f, 5.6f); Vector3 normalized = Vector3::Normalize(notNormalized); EXPECT_EQ(1.2f, notNormalized.X); EXPECT_EQ(3.4f, notNormalized.Y); EXPECT_EQ(5.6f, notNormalized.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, DotProductCanBeCalculated) { const Vector3 first(2.0f, 4.0f, 6.0f); const Vector3 second(8.0f, 10.0f, 12.0f); float dotProduct = (first.X * second.X) + (first.Y * second.Y) + (first.Z * second.Z); EXPECT_EQ(dotProduct, Vector3::Dot(first, second)); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, AbsoluteValueCanBeCalculated) { Vector3 test = Vector3::Abs(Vector3(-1.2f, -3.4f, 5.6f)); EXPECT_EQ(1.2f, test.X); EXPECT_EQ(3.4f, test.Y); EXPECT_EQ(5.6f, test.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, ComponentsCanBeAccessedByIndex) { const Vector3 test(1.2f, 3.4f, 5.6f); EXPECT_EQ(test.X, test[0]); EXPECT_EQ(test.X, test[Axis3::X]); EXPECT_EQ(test.Y, test[1]); EXPECT_EQ(test.Y, test[Axis3::Y]); EXPECT_EQ(test.Z, test[2]); EXPECT_EQ(test.Z, test[Axis3::Z]); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, AccessingComponentsByInvalidIndexThrowsException) { EXPECT_THROW(Vector3::Zero[3], std::out_of_range); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForRightVector) { const Vector3 nearlyRight(1.0f, 0.2f, 0.4f); const Vector3 orthogonalFromNearlyRight = nearlyRight.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyRight.Z > 0); EXPECT_EQ(Axis3::Z, orthogonalFromNearlyRight.GetLongestComponentIndex()); EXPECT_ORTHOGONAL(nearlyRight, orthogonalFromNearlyRight); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForLeftVector) { const Vector3 nearlyLeft(-1.0f, 0.2f, 0.4f); const Vector3 orthogonalFromNearlyLeft = nearlyLeft.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyLeft.Z > 0); EXPECT_EQ(Axis3::Z, orthogonalFromNearlyLeft.GetLongestComponentIndex()); EXPECT_ORTHOGONAL(nearlyLeft, orthogonalFromNearlyLeft); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForForwardVector) { const Vector3 nearlyForward(0.2f, 1.0f, 0.4f); const Vector3 orthogonalFromNearlyForward = nearlyForward.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyForward.Z > 0); EXPECT_EQ(Axis3::Z, orthogonalFromNearlyForward.GetLongestComponentIndex()); EXPECT_ORTHOGONAL(nearlyForward, orthogonalFromNearlyForward); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForBackwardVector) { const Vector3 nearlyBackward(0.2f, -1.0f, 0.4f); const Vector3 orthogonalFromNearlyBackward = nearlyBackward.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyBackward.Z > 0); EXPECT_EQ(Axis3::Z, orthogonalFromNearlyBackward.GetLongestComponentIndex()); EXPECT_ORTHOGONAL(nearlyBackward, orthogonalFromNearlyBackward); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForUpVector) { const Vector3 nearlyUp(0.2f, 0.4f, 1.0f); const Vector3 orthogonalFromNearlyUp = nearlyUp.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyUp.Z > 0); EXPECT_NE( static_cast(Axis3::Z), orthogonalFromNearlyUp.GetLongestComponentIndex() ); EXPECT_ORTHOGONAL(nearlyUp, orthogonalFromNearlyUp); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, CanObtainOrthogonalUpVectorForDownVector) { const Vector3 nearlyUp(0.2f, 0.4f, -1.0f); const Vector3 orthogonalFromNearlyUp = nearlyUp.GetOrthogonalUp(); EXPECT_TRUE(orthogonalFromNearlyUp.Z > 0); EXPECT_NE( static_cast(Axis3::Z), orthogonalFromNearlyUp.GetLongestComponentIndex() ); EXPECT_ORTHOGONAL(nearlyUp, orthogonalFromNearlyUp); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, AngleBetweenTwoVectorsCanBeDetermined) { float angle = Vector3::AngleBetween(Vector3::Up, Vector3::Right); EXPECT_EQ(Math::Pi / 2.0f, angle); angle = Vector3::AngleBetween(Vector3::Right, Vector3::Forward); EXPECT_EQ(Math::Pi / 2.0f, angle); angle = Vector3::AngleBetween(Vector3::Forward, Vector3::Up); EXPECT_EQ(Math::Pi / 2.0f, angle); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, AngleBetweenTwoVectorsIsAlwaysPositive) { float upAngle = Vector3::AngleBetween(Vector3::Left, Vector3::Up); float downAngle = Vector3::AngleBetween(Vector3::Left, Vector3::Down); EXPECT_EQ(upAngle, downAngle); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeNegated) { Vector3 negative = -Vector3(1.2f, 3.4f, 5.6f); EXPECT_EQ(-1.2f, negative.X); EXPECT_EQ(-3.4f, negative.Y); EXPECT_EQ(-5.6f, negative.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeSubtractedFromEachOther) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) - Vector3(10.0f, 20.0f, 30.0f); EXPECT_EQ(12.0f, result.X); EXPECT_EQ(24.0f, result.Y); EXPECT_EQ(36.0f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeSubtractAssigned) { Vector3 test(22.0f, 44.0f, 66.0f); test -= Vector3(10.0f, 20.0f, 30.0f); EXPECT_EQ(12.0f, test.X); EXPECT_EQ(24.0f, test.Y); EXPECT_EQ(36.0f, test.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeAddedTogether) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) + Vector3(10.0f, 20.0f, 30.0f); EXPECT_EQ(32.0f, result.X); EXPECT_EQ(64.0f, result.Y); EXPECT_EQ(96.0f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeAddAssigned) { Vector3 test(22.0f, 44.0f, 66.0f); test += Vector3(10.0f, 20.0f, 30.0f); EXPECT_EQ(32.0f, test.X); EXPECT_EQ(64.0f, test.Y); EXPECT_EQ(96.0f, test.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeMultipliedWithEachOther) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) * Vector3(5.0f, 10.0f, 15.0f); EXPECT_EQ(110.0f, result.X); EXPECT_EQ(440.0f, result.Y); EXPECT_EQ(990.0f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeMultiplyAssigned) { Vector3 test(22.0f, 44.0f, 66.0f); test *= Vector3(5.0f, 10.0f, 15.0f); EXPECT_EQ(110.0f, test.X); EXPECT_EQ(440.0f, test.Y); EXPECT_EQ(990.0f, test.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeDividedByEachOther) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) / Vector3(4.0f, 10.0f, 20.0f); EXPECT_EQ(5.5f, result.X); EXPECT_EQ(4.4f, result.Y); EXPECT_EQ(3.3f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeDivisionAssigned) { Vector3 test(22.0f, 44.0f, 66.0f); test /= Vector3(4.0f, 10.0f, 20.0f); EXPECT_EQ(5.5f, test.X); EXPECT_EQ(4.4f, test.Y); EXPECT_EQ(3.3f, test.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeMultipliedByFactors) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) * 3.0f; EXPECT_EQ(66.0f, result.X); EXPECT_EQ(132.0f, result.Y); EXPECT_EQ(198.0f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, FactorsCanBeMultipliedByVectors) { Vector3 result = 3.0f * Vector3(22.0f, 44.0f, 66.0f); EXPECT_EQ(66.0f, result.X); EXPECT_EQ(132.0f, result.Y); EXPECT_EQ(198.0f, result.Z); } // ------------------------------------------------------------------------------------------- // TEST(Vector3Test, VectorsCanBeDividedByDivisors) { Vector3 result = Vector3(22.0f, 44.0f, 66.0f) / 4.0f; EXPECT_EQ(5.5f, result.X); EXPECT_EQ(11.0f, result.Y); EXPECT_EQ(16.5f, result.Z); } // ------------------------------------------------------------------------------------------- // }} // namespace Nuclex::Geometry