#pragma region CPL License /*10 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/Vector2.h" #include // for std::sqrt() #include namespace Nuclex { namespace Geometry { // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, ParameterConstructorAssignsValues) { EXPECT_EQ(12.34f, Vector2(12.34f, 56.78f).X); EXPECT_EQ(56.78f, Vector2(12.34f, 56.78f).Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeInitializedToAngles) { const float Tolerance = 1.e-007f; Vector2 right = Vector2::FromAngle(0.0f); EXPECT_NEAR(1.0f, right.X, Tolerance); EXPECT_NEAR(0.0f, right.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AngleInitializedVectorsGoCounterClockwise) { const float Tolerance = 1.e-007f; Vector2 up = Vector2::FromAngle(Math::Pi / 2.0f); EXPECT_NEAR(0.0f, up.X, Tolerance); EXPECT_NEAR(1.0f, up.Y, Tolerance); Vector2 left = Vector2::FromAngle(Math::Pi); EXPECT_NEAR(-1.0f, left.X, Tolerance); EXPECT_NEAR(0.0f, left.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, ZeroIsInitializedToAllZeroes) { EXPECT_EQ(0.0f, Vector2::Zero.X); EXPECT_EQ(0.0f, Vector2::Zero.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, OneIsInitializedToAllOnes) { EXPECT_EQ(1.0f, Vector2::One.X); EXPECT_EQ(1.0f, Vector2::One.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, LeftIsPointingTowardsNegativeX) { EXPECT_EQ(-1.0f, Vector2::Left.X); EXPECT_EQ(0.0f, Vector2::Left.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, RightIsPointingTowardsPositiveX) { EXPECT_EQ(1.0f, Vector2::Right.X); EXPECT_EQ(0.0f, Vector2::Right.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, DownIsPointingTowardsNegativeY) { EXPECT_EQ(0.0f, Vector2::Down.X); EXPECT_EQ(-1.0f, Vector2::Down.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, UpIsPointingTowardsPositiveY) { EXPECT_EQ(0.0f, Vector2::Up.X); EXPECT_EQ(1.0f, Vector2::Up.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, SquaredLengthCanBeCalculated) { const float X = 5.0f; const float Y = 10.0f; EXPECT_EQ(X * X + Y * Y, Vector2(X, Y).GetSquaredLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, SquaredLengthOfZeroVectorIsZero) { EXPECT_EQ(0.0f, Vector2::Zero.GetSquaredLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, LengthCanBeCalculated) { const float X = 5.0f; const float Y = 10.0f; EXPECT_EQ(std::sqrt(X * X + Y * Y), Vector2(X, Y).GetLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, LengthOfZeroVectorIsZero) { EXPECT_EQ(0.0f, Vector2::Zero.GetLength()); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeNormalized) { Vector2 right(2.0f, 0.0f); right.Normalize(); EXPECT_EQ(1.0f, right.X); EXPECT_EQ(0.0f, right.Y); Vector2 up(0.0f, 2.0f); up.Normalize(); EXPECT_EQ(0.0f, up.X); EXPECT_EQ(1.0f, up.Y); Vector2 diagonal(2.0f, 1.0f); diagonal.Normalize(); EXPECT_FLOAT_EQ(1.0, diagonal.GetSquaredLength()); // squared or non squared, 1.0 stays 1.0 } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanProvideNormalizedCopies) { const Vector2 right(2.0f, 0.0f); Vector2 normalizedRight = Vector2::Normalize(right); EXPECT_EQ(1.0f, normalizedRight.X); EXPECT_EQ(0.0f, normalizedRight.Y); const Vector2 up(0.0f, 2.0f); Vector2 normalizedUp = Vector2::Normalize(up); EXPECT_EQ(0.0f, normalizedUp.X); EXPECT_EQ(1.0f, normalizedUp.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, NormalizedCopyLeavesOriginalUntouched) { const Vector2 notNormalized(12.34f, 56.78f); Vector2 normalized = Vector2::Normalize(notNormalized); EXPECT_EQ(12.34f, notNormalized.X); EXPECT_EQ(56.78f, notNormalized.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, DotProductCanBeCalculated) { const Vector2 first(2.0f, 4.0f); const Vector2 second(6.0f, 8.0f); float dotProduct = (first.X * second.X) + (first.Y * second.Y); EXPECT_EQ(dotProduct, Vector2::Dot(first, second)); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AbsoluteValueCanBeCalculated) { Vector2 test = Vector2::Abs(Vector2(-12.34f, -56.78f)); EXPECT_EQ(12.34f, test.X); EXPECT_EQ(56.78f, test.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, ComponentsCanBeAccessedByIndex) { const Vector2 test(12.34f, 56.78f); EXPECT_EQ(test.X, test[0]); EXPECT_EQ(test.X, test[Axis2::X]); EXPECT_EQ(test.Y, test[1]); EXPECT_EQ(test.Y, test[Axis2::Y]); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AccessingComponentsByInvalidIndexThrowsException) { EXPECT_THROW(Vector2::Zero[2], std::out_of_range); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, CanObtainOrthogonalUpVectorForRightVector) { const Vector2 nearlyRight(1.0f, 0.1f); const Vector2 orthogonalFromNearlyRight = nearlyRight.GetOrthogonalUp(); EXPECT_EQ(-nearlyRight.Y, orthogonalFromNearlyRight.X); EXPECT_EQ(nearlyRight.X, orthogonalFromNearlyRight.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, CanObtainOrthogonalUpVectorForLeftVector) { const Vector2 nearlyLeft(-1.0f, 0.1f); const Vector2 orthogonalFromNearlyLeft = nearlyLeft.GetOrthogonalUp(); EXPECT_EQ(nearlyLeft.Y, orthogonalFromNearlyLeft.X); EXPECT_EQ(-nearlyLeft.X, orthogonalFromNearlyLeft.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, CanObtainOrthogonalUpVectorForUpVector) { const Vector2 nearlyUp(0.1f, 1.0f); const Vector2 orthogonalFromNearlyUp = nearlyUp.GetOrthogonalUp(); EXPECT_EQ(nearlyUp.Y, orthogonalFromNearlyUp.X); EXPECT_EQ(-nearlyUp.X, orthogonalFromNearlyUp.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, CanObtainOrthogonalUpVectorForDownVector) { const Vector2 nearlyDown(0.1f, -1.0f); const Vector2 orthogonalFromNearlyDown = nearlyDown.GetOrthogonalUp(); EXPECT_EQ(-nearlyDown.Y, orthogonalFromNearlyDown.X); EXPECT_EQ(nearlyDown.X, orthogonalFromNearlyDown.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AngleBetweenTwoVectorsCanBeDetermined) { float angle = Vector2::AngleBetween(Vector2::Up, Vector2::Right); EXPECT_EQ(Math::Pi / 2.0f, angle); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AngleBetweenTwoVectorsIsAlwaysPositive) { float upAngle = Vector2::AngleBetween(Vector2::Left, Vector2::Up); float downAngle = Vector2::AngleBetween(Vector2::Left, Vector2::Down); EXPECT_EQ(upAngle, downAngle); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeRotated) { const float Tolerance = 1.e-007f; Vector2 right = Vector2::Right; right.Rotate(Math::Pi / 2.0f); EXPECT_NEAR(0.0f, right.X, Tolerance); EXPECT_NEAR(1.0f, right.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanProvideRotatedCopies) { const float Tolerance = 1.e-007f; Vector2 right = Vector2::Right.GetRotated(Math::Pi / 2.0f); EXPECT_NEAR(0.0f, right.X, Tolerance); EXPECT_NEAR(1.0f, right.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, RotatedCopyLeavesOriginalUntouched) { const Vector2 notRotated(12.34f, 56.78f); Vector2 rotated = notRotated.GetRotated(Math::Pi / 2.0f); EXPECT_EQ(12.34f, notRotated.X); EXPECT_EQ(56.78f, notRotated.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, RotatedVectorsGoCounterClockwise) { const float Tolerance = 1.e-007f; Vector2 up = Vector2::Right.GetRotated(Math::Pi / 2.0f); EXPECT_NEAR(0.0f, up.X, Tolerance); EXPECT_NEAR(1.0f, up.Y, Tolerance); Vector2 left = Vector2::Right.GetRotated(Math::Pi); EXPECT_NEAR(-1.0f, left.X, Tolerance); EXPECT_NEAR(0.0f, left.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, AngleOfVectorCanBeDetermined) { const float Tolerance = 1.e-007f; EXPECT_NEAR(0.0f, Vector2::Right.GetAngle(), Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorAnglesGoCounterClockwise) { const float Tolerance = 1.e-007f; EXPECT_NEAR(Math::Pi / 2.0f, Vector2::Up.GetAngle(), Tolerance); EXPECT_NEAR(Math::Pi, Vector2::Left.GetAngle(), Tolerance); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeNegated) { Vector2 negative = -Vector2(12.34f, 56.78f); EXPECT_EQ(-12.34f, negative.X); EXPECT_EQ(-56.78f, negative.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeSubtractedFromEachOther) { Vector2 result = Vector2(22.0f, 44.0f) - Vector2(10.0f, 20.0f); EXPECT_EQ(12.0f, result.X); EXPECT_EQ(24.0f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeSubtractAssigned) { Vector2 test(22.0f, 44.0f); test -= Vector2(10.0f, 20.0f); EXPECT_EQ(12.0f, test.X); EXPECT_EQ(24.0f, test.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeAddedTogether) { Vector2 result = Vector2(22.0f, 44.0f) + Vector2(10.0f, 20.0f); EXPECT_EQ(32.0f, result.X); EXPECT_EQ(64.0f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeAddAssigned) { Vector2 test(22.0f, 44.0f); test += Vector2(10.0f, 20.0f); EXPECT_EQ(32.0f, test.X); EXPECT_EQ(64.0f, test.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeMultipliedWithEachOther) { Vector2 result = Vector2(22.0f, 44.0f) * Vector2(5.0f, 10.0f); EXPECT_EQ(110.0f, result.X); EXPECT_EQ(440.0f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeMultiplyAssigned) { Vector2 test(22.0f, 44.0f); test *= Vector2(5.0f, 10.0f); EXPECT_EQ(110.0f, test.X); EXPECT_EQ(440.0f, test.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeDividedByEachOther) { Vector2 result = Vector2(22.0f, 44.0f) / Vector2(4.0f, 10.0f); EXPECT_EQ(5.5f, result.X); EXPECT_EQ(4.4f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeDivisionAssigned) { Vector2 test(22.0f, 44.0f); test /= Vector2(4.0f, 10.0f); EXPECT_EQ(5.5f, test.X); EXPECT_EQ(4.4f, test.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeMultipliedByScalars) { Vector2 result = Vector2(22.0f, 44.0f) * 3.0f; EXPECT_EQ(66.0f, result.X); EXPECT_EQ(132.0f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, ScalarsCanBeMultipliedByVectors) { Vector2 result = 3.0f * Vector2(22.0f, 44.0f); EXPECT_EQ(66.0f, result.X); EXPECT_EQ(132.0f, result.Y); } // ------------------------------------------------------------------------------------------- // TEST(Vector2Test, VectorsCanBeDividedByScalars) { Vector2 result = Vector2(22.0f, 44.0f) / 4.0f; EXPECT_EQ(5.5f, result.X); EXPECT_EQ(11.0f, result.Y); } // ------------------------------------------------------------------------------------------- // }} // namespace Nuclex::Geometry