mirror of
https://github.com/SFML/SFML.git
synced 2024-11-29 06:41:05 +08:00
b2ab6d6ab3
Includes relevant tests and updates TestUtilities to feature ApproxVec2 & ApproxVec3
286 lines
7.7 KiB
C++
286 lines
7.7 KiB
C++
#include <SFML/System/Vector2.hpp>
|
|
#include "SystemUtil.hpp"
|
|
#include <type_traits>
|
|
|
|
#include <doctest.h>
|
|
|
|
using namespace sf::Literals;
|
|
using doctest::Approx;
|
|
|
|
// Use sf::Vector2i for tests (except for float vector algebra).
|
|
// Test coverage is given, as there are no template specializations.
|
|
|
|
|
|
TEST_CASE("sf::Vector2 class template - [system]")
|
|
{
|
|
SUBCASE("Construction")
|
|
{
|
|
SUBCASE("Default constructor")
|
|
{
|
|
sf::Vector2i vector;
|
|
CHECK(vector.x == 0);
|
|
CHECK(vector.y == 0);
|
|
}
|
|
|
|
SUBCASE("(x, y) coordinate constructor")
|
|
{
|
|
sf::Vector2i vector(1, 2);
|
|
CHECK(vector.x == 1);
|
|
CHECK(vector.y == 2);
|
|
}
|
|
|
|
SUBCASE("Conversion constructor")
|
|
{
|
|
const sf::Vector2f sourceVector(1.0f, 2.0f);
|
|
const sf::Vector2i vector(sourceVector);
|
|
|
|
CHECK(vector.x == static_cast<int>(sourceVector.x));
|
|
CHECK(vector.y == static_cast<int>(sourceVector.y));
|
|
}
|
|
}
|
|
|
|
SUBCASE("Unary operations")
|
|
{
|
|
SUBCASE("-vector")
|
|
{
|
|
const sf::Vector2i vector(1, 2);
|
|
const sf::Vector2i negatedVector = -vector;
|
|
|
|
CHECK(negatedVector.x == -1);
|
|
CHECK(negatedVector.y == -2);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Arithmetic operations between two vectors")
|
|
{
|
|
sf::Vector2i firstVector(2, 5);
|
|
const sf::Vector2i secondVector(8, 3);
|
|
|
|
SUBCASE("vector += vector")
|
|
{
|
|
firstVector += secondVector;
|
|
|
|
CHECK(firstVector.x == 10);
|
|
CHECK(firstVector.y == 8);
|
|
}
|
|
|
|
SUBCASE("vector -= vector")
|
|
{
|
|
firstVector -= secondVector;
|
|
|
|
CHECK(firstVector.x == -6);
|
|
CHECK(firstVector.y == 2);
|
|
}
|
|
|
|
SUBCASE("vector + vector")
|
|
{
|
|
const sf::Vector2i result = firstVector + secondVector;
|
|
|
|
CHECK(result.x == 10);
|
|
CHECK(result.y == 8);
|
|
}
|
|
|
|
SUBCASE("vector - vector")
|
|
{
|
|
const sf::Vector2i result = firstVector - secondVector;
|
|
|
|
CHECK(result.x == -6);
|
|
CHECK(result.y == 2);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Arithmetic operations between vector and scalar value")
|
|
{
|
|
sf::Vector2i vector(26, 12);
|
|
int scalar = 2;
|
|
|
|
SUBCASE("vector * scalar")
|
|
{
|
|
const sf::Vector2i result = vector * scalar;
|
|
|
|
CHECK(result.x == 52);
|
|
CHECK(result.y == 24);
|
|
}
|
|
|
|
SUBCASE("scalar * vector")
|
|
{
|
|
const sf::Vector2i result = scalar * vector;
|
|
|
|
CHECK(result.x == 52);
|
|
CHECK(result.y == 24);
|
|
}
|
|
|
|
SUBCASE("vector *= scalar")
|
|
{
|
|
vector *= scalar;
|
|
|
|
CHECK(vector.x == 52);
|
|
CHECK(vector.y == 24);
|
|
}
|
|
|
|
SUBCASE("vector / scalar")
|
|
{
|
|
const sf::Vector2i result = vector / scalar;
|
|
|
|
CHECK(result.x == 13);
|
|
CHECK(result.y == 6);
|
|
}
|
|
|
|
SUBCASE("vector /= scalar")
|
|
{
|
|
vector /= scalar;
|
|
|
|
CHECK(vector.x == 13);
|
|
CHECK(vector.y == 6);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Comparison operations (two equal and one different vector)")
|
|
{
|
|
const sf::Vector2i firstEqualVector(1, 5);
|
|
const sf::Vector2i secondEqualVector(1, 5);
|
|
const sf::Vector2i differentVector(6, 9);
|
|
|
|
SUBCASE("vector == vector")
|
|
{
|
|
CHECK(firstEqualVector == secondEqualVector);
|
|
CHECK_FALSE(firstEqualVector == differentVector);
|
|
}
|
|
|
|
SUBCASE("vector != vector")
|
|
{
|
|
CHECK(firstEqualVector != differentVector);
|
|
CHECK_FALSE(firstEqualVector != secondEqualVector);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Structured bindings")
|
|
{
|
|
sf::Vector2i vector(1, 2);
|
|
|
|
SUBCASE("destructure by value")
|
|
{
|
|
auto [x, y] = vector;
|
|
|
|
CHECK(x == 1);
|
|
CHECK(y == 2);
|
|
|
|
static_assert(std::is_same_v<decltype(x), decltype(vector.x)>);
|
|
|
|
x = 3;
|
|
|
|
CHECK(x == 3);
|
|
CHECK(vector.x == 1);
|
|
}
|
|
|
|
SUBCASE("destructure by ref")
|
|
{
|
|
auto& [x, y] = vector;
|
|
|
|
CHECK(x == 1);
|
|
CHECK(y == 2);
|
|
|
|
static_assert(std::is_same_v<decltype(x), decltype(vector.x)>);
|
|
|
|
x = 3;
|
|
|
|
CHECK(x == 3);
|
|
CHECK(vector.x == 3);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Length and normalization")
|
|
{
|
|
const sf::Vector2f v(2.4f, 3.0f);
|
|
|
|
CHECK(v.length() == Approx(3.84187));
|
|
CHECK(v.lengthSq() == Approx(14.7599650969));
|
|
CHECK(v.normalized() == ApproxVec2(0.624695f, 0.780869f));
|
|
|
|
const sf::Vector2f w(-0.7f, -2.2f);
|
|
|
|
CHECK(w.length() == Approx(2.30868));
|
|
CHECK(w.lengthSq() == Approx(5.3300033));
|
|
CHECK(w.normalized() == ApproxVec2(-0.303204f, -0.952926f));
|
|
}
|
|
|
|
SUBCASE("Rotations and angles")
|
|
{
|
|
const sf::Vector2f v(2.4f, 3.0f);
|
|
|
|
CHECK(v.angle() == ApproxDeg(51.3402f));
|
|
CHECK(sf::Vector2f::UnitX.angleTo(v) == ApproxDeg(51.3402f));
|
|
CHECK(sf::Vector2f::UnitY.angleTo(v) == ApproxDeg(-38.6598f));
|
|
|
|
const sf::Vector2f w(-0.7f, -2.2f);
|
|
|
|
CHECK(w.angle() == ApproxDeg(-107.65f));
|
|
CHECK(sf::Vector2f::UnitX.angleTo(w) == ApproxDeg(-107.65f));
|
|
CHECK(sf::Vector2f::UnitY.angleTo(w) == ApproxDeg(162.35f));
|
|
|
|
CHECK(v.angleTo(w) == ApproxDeg(-158.9902f));
|
|
CHECK(w.angleTo(v) == ApproxDeg(158.9902f));
|
|
|
|
const float ratio = w.length() / v.length();
|
|
CHECK(v.rotatedBy(-158.9902_deg) * ratio == ApproxVec2(w));
|
|
CHECK(w.rotatedBy(158.9902_deg) / ratio == ApproxVec2(v));
|
|
|
|
CHECK(v.perpendicular() == sf::Vector2f(-3.0f, 2.4f));
|
|
CHECK(v.perpendicular().perpendicular().perpendicular().perpendicular() == v);
|
|
|
|
CHECK(v.rotatedBy(90_deg) == ApproxVec2(-3.0f, 2.4f));
|
|
CHECK(v.rotatedBy(27.14_deg) == ApproxVec2(0.767248f, 3.76448f));
|
|
CHECK(v.rotatedBy(-36.11_deg) == ApproxVec2(3.70694f, 1.00925f));
|
|
}
|
|
|
|
SUBCASE("Products and quotients")
|
|
{
|
|
const sf::Vector2f v(2.4f, 3.0f);
|
|
const sf::Vector2f w(-0.7f, -2.2f);
|
|
|
|
CHECK(v.dot(w) == Approx(-8.28));
|
|
CHECK(w.dot(v) == Approx(-8.28));
|
|
|
|
CHECK(v.cross(w) == Approx(-3.18));
|
|
CHECK(w.cross(v) == Approx(+3.18));
|
|
|
|
CHECK(v.cwiseMul(w) == ApproxVec2(-1.68f, -6.6f));
|
|
CHECK(w.cwiseMul(v) == ApproxVec2(-1.68f, -6.6f));
|
|
CHECK(v.cwiseDiv(w) == ApproxVec2(-3.428571f, -1.363636f));
|
|
CHECK(w.cwiseDiv(v) == ApproxVec2(-0.291666f, -0.733333f));
|
|
}
|
|
|
|
SUBCASE("Projection")
|
|
{
|
|
const sf::Vector2f v(2.4f, 3.0f);
|
|
const sf::Vector2f w(-0.7f, -2.2f);
|
|
|
|
CHECK(v.projectedOnto(w) == ApproxVec2(1.087430f, 3.417636f));
|
|
CHECK(v.projectedOnto(w) == ApproxVec2(-1.55347f * w));
|
|
|
|
CHECK(w.projectedOnto(v) == ApproxVec2(-1.346342f, -1.682927f));
|
|
CHECK(w.projectedOnto(v) == ApproxVec2(-0.560976f * v));
|
|
|
|
CHECK(v.projectedOnto(sf::Vector2f::UnitX) == ApproxVec2(2.4f, 0.0f));
|
|
CHECK(v.projectedOnto(sf::Vector2f::UnitY) == ApproxVec2(0.0f, 3.0f));
|
|
}
|
|
|
|
SUBCASE("Constexpr support")
|
|
{
|
|
constexpr sf::Vector2i v(1, 2);
|
|
constexpr sf::Vector2i w(2, -3);
|
|
|
|
static_assert(v.x == 1);
|
|
static_assert(v.y == 2);
|
|
static_assert(v + w == sf::Vector2i(3, -1));
|
|
|
|
static_assert(v.lengthSq() == 5);
|
|
static_assert(v.perpendicular() == sf::Vector2i(-2, 1));
|
|
|
|
static_assert(v.dot(w) == -4);
|
|
static_assert(v.cross(w) == -7);
|
|
static_assert(v.cwiseMul(w) == sf::Vector2i(2, -6));
|
|
static_assert(w.cwiseDiv(v) == sf::Vector2i(2, -1));
|
|
}
|
|
}
|