diff --git a/include/SFML/System/Vector2.hpp b/include/SFML/System/Vector2.hpp index 76b08a0e8..c6be58f65 100644 --- a/include/SFML/System/Vector2.hpp +++ b/include/SFML/System/Vector2.hpp @@ -26,9 +26,8 @@ #define SFML_VECTOR2_HPP #include +#include #include -#include -#include namespace sf @@ -75,7 +74,7 @@ public: constexpr explicit Vector2(const Vector2& vector); //////////////////////////////////////////////////////////// - /// \brief Construct the vector from polar coordinates + /// \brief Construct the vector from polar coordinates (floating-point) /// /// \param r Length of vector (can be negative) /// \param phi Angle from X axis @@ -88,19 +87,19 @@ public: /// * Vector2(r, phi) == Vector2(r, phi + n * 360_deg) /// //////////////////////////////////////////////////////////// - Vector2(T r, Angle phi); - + SFML_SYSTEM_API Vector2(T r, Angle phi); + //////////////////////////////////////////////////////////// /// \brief Length of the vector (floating-point). /// /// If you are not interested in the actual length, but only in comparisons, consider using lengthSq(). /// //////////////////////////////////////////////////////////// - T length() const; + SFML_SYSTEM_API T length() const; //////////////////////////////////////////////////////////// /// \brief Square of vector's length. - /// + /// /// Suitable for comparisons, more efficient than length(). /// //////////////////////////////////////////////////////////// @@ -108,57 +107,57 @@ public: //////////////////////////////////////////////////////////// /// \brief Vector with same direction but length 1 (floating-point). - /// + /// /// \pre \c *this is no zero vector. /// //////////////////////////////////////////////////////////// - [[nodiscard]] Vector2 normalized() const; + [[nodiscard]] SFML_SYSTEM_API Vector2 normalized() const; //////////////////////////////////////////////////////////// /// \brief Signed angle from \c *this to \c rhs (floating-point). - /// + /// /// \return The smallest angle which rotates \c *this in positive /// or negative direction, until it has the same direction as \c rhs. /// The result has a sign and lies in the range [-180, 180) degrees. /// \pre Neither \c *this nor \c rhs is a zero vector. /// //////////////////////////////////////////////////////////// - Angle angleTo(const Vector2& rhs) const; + SFML_SYSTEM_API Angle angleTo(const Vector2& rhs) const; //////////////////////////////////////////////////////////// /// \brief Signed angle from +X or (1,0) vector (floating-point). - /// + /// /// For example, the vector (1,0) corresponds to 0 degrees, (0,1) corresponds to 90 degrees. - /// + /// /// \return Angle in the range [-180, 180) degrees. /// \pre This vector is no zero vector. /// //////////////////////////////////////////////////////////// - Angle angle() const; + SFML_SYSTEM_API Angle angle() const; //////////////////////////////////////////////////////////// /// \brief Rotate by angle \c phi (floating-point). - /// + /// /// Returns a vector with same length but different direction. /// /// In SFML's default coordinate system with +X right and +Y down, /// this amounts to a clockwise rotation by \c phi. - /// + /// //////////////////////////////////////////////////////////// - [[nodiscard]] Vector2 rotatedBy(Angle phi) const; + [[nodiscard]] SFML_SYSTEM_API Vector2 rotatedBy(Angle phi) const; //////////////////////////////////////////////////////////// /// \brief Projection of this vector onto \c axis (floating-point). - /// + /// /// \param axis Vector being projected onto. Need not be normalized. /// \pre \c axis must not have length zero. /// //////////////////////////////////////////////////////////// - [[nodiscard]] constexpr Vector2 projectedOnto(const Vector2& axis) const; + [[nodiscard]] SFML_SYSTEM_API Vector2 projectedOnto(const Vector2& axis) const; //////////////////////////////////////////////////////////// /// \brief Returns a perpendicular vector. - /// + /// /// Returns \c *this rotated by +90 degrees; (x,y) becomes (-y,x). /// For example, the vector (1,0) is transformed to (0,1). /// @@ -176,7 +175,7 @@ public: //////////////////////////////////////////////////////////// /// \brief Z component of the cross product of two 2D vectors. - /// + /// /// Treats the operands as 3D vectors, computes their cross product /// and returns the result's Z component (X and Y components are always zero). /// @@ -187,7 +186,7 @@ public: /// \brief Component-wise multiplication of \c *this and \c rhs. /// /// Computes (lhs.x*rhs.x, lhs.y*rhs.y). - /// + /// /// Scaling is the most common use case for component-wise multiplication/division. /// This operation is also known as the Hadamard or Schur product. /// @@ -196,11 +195,11 @@ public: //////////////////////////////////////////////////////////// /// \brief Component-wise division of \c *this and \c rhs. - /// + /// /// Computes (lhs.x/rhs.x, lhs.y/rhs.y). - /// + /// /// Scaling is the most common use case for component-wise multiplication/division. - /// + /// /// \pre Neither component of \c rhs is zero. /// //////////////////////////////////////////////////////////// @@ -417,7 +416,7 @@ template /// The API provides basic arithmetic (addition, subtraction, scale), as /// well as more advanced geometric operations, such as dot/cross products, /// length and angle computations, projections, rotations, etc. -/// +/// /// The template parameter T is the type of the coordinates. It /// can be any type that supports arithmetic operations (+, -, /, *) /// and comparisons (==, !=), for example int or float. @@ -425,7 +424,7 @@ template /// a floating point type (e.g. float or double), often because /// results cannot be represented accurately with integers. /// The method documentation mentions "(floating-point)" in those cases. -/// +/// /// You generally don't have to care about the templated form (sf::Vector2), /// the most common specializations have special type aliases: /// \li sf::Vector2 is sf::Vector2f diff --git a/include/SFML/System/Vector2.inl b/include/SFML/System/Vector2.inl index 1c6fdfd82..e29b3967f 100644 --- a/include/SFML/System/Vector2.inl +++ b/include/SFML/System/Vector2.inl @@ -53,26 +53,6 @@ y(static_cast(vector.y)) } -//////////////////////////////////////////////////////////// -template -Vector2::Vector2(T r, Angle phi) : -x(r * static_cast(std::cos(phi.asRadians()))), -y(r * static_cast(std::sin(phi.asRadians()))) -{ - static_assert(std::is_floating_point_v, "Vector2::Vector2(T, Angle) is only supported for floating point types"); -} - - -//////////////////////////////////////////////////////////// -template -T Vector2::length() const -{ - static_assert(std::is_floating_point_v, "Vector2::length() is only supported for floating point types"); - - return std::hypot(x, y); -} - - //////////////////////////////////////////////////////////// template constexpr T Vector2::lengthSq() const @@ -81,68 +61,6 @@ constexpr T Vector2::lengthSq() const } -//////////////////////////////////////////////////////////// -template -Vector2 Vector2::normalized() const -{ - static_assert(std::is_floating_point_v, "Vector2::normalized() is only supported for floating point types"); - - assert(*this != Vector2()); - return (*this) / length(); -} - - -//////////////////////////////////////////////////////////// -template -Angle Vector2::angleTo(const Vector2& rhs) const -{ - static_assert(std::is_floating_point_v, "Vector2::angleTo() is only supported for floating point types"); - - assert(*this != Vector2()); - assert(rhs != Vector2()); - return radians(std::atan2(cross(rhs), dot(rhs))); -} - - -//////////////////////////////////////////////////////////// -template -Angle Vector2::angle() const -{ - static_assert(std::is_floating_point_v, "Vector2::angle() is only supported for floating point types"); - - assert(*this != Vector2()); - return radians(std::atan2(y, x)); -} - - -//////////////////////////////////////////////////////////// -template -Vector2 Vector2::rotatedBy(Angle angle) const -{ - static_assert(std::is_floating_point_v, "Vector2::rotatedBy() is only supported for floating point types"); - - // No zero vector assert, because rotating a zero vector is well-defined (yields always itself) - T cos = std::cos(angle.asRadians()); - T sin = std::sin(angle.asRadians()); - - // Don't manipulate x and y separately, otherwise they're overwritten too early - return Vector2( - cos * x - sin * y, - sin * x + cos * y); -} - - -//////////////////////////////////////////////////////////// -template -constexpr Vector2 Vector2::projectedOnto(const Vector2& axis) const -{ - static_assert(std::is_floating_point_v, "Vector2::projectedOnto() is only supported for floating point types"); - - assert(axis != Vector2()); - return dot(axis) / axis.lengthSq() * axis; -} - - //////////////////////////////////////////////////////////// template constexpr Vector2 Vector2::perpendicular() const diff --git a/include/SFML/System/Vector3.hpp b/include/SFML/System/Vector3.hpp index 2a4af9ac1..a6ff96bf6 100644 --- a/include/SFML/System/Vector3.hpp +++ b/include/SFML/System/Vector3.hpp @@ -25,9 +25,8 @@ #ifndef SFML_VECTOR3_HPP #define SFML_VECTOR3_HPP +#include #include -#include -#include namespace sf { @@ -79,11 +78,11 @@ public: /// If you are not interested in the actual length, but only in comparisons, consider using lengthSq(). /// //////////////////////////////////////////////////////////// - T length() const; + SFML_SYSTEM_API T length() const; //////////////////////////////////////////////////////////// /// \brief Square of vector's length. - /// + /// /// Suitable for comparisons, more efficient than length(). /// //////////////////////////////////////////////////////////// @@ -91,11 +90,11 @@ public: //////////////////////////////////////////////////////////// /// \brief Vector with same direction but length 1 (floating-point). - /// + /// /// \pre \c *this is no zero vector. /// //////////////////////////////////////////////////////////// - [[nodiscard]] Vector3 normalized() const; + [[nodiscard]] SFML_SYSTEM_API Vector3 normalized() const; //////////////////////////////////////////////////////////// /// \brief Dot product of two 3D vectors. @@ -113,7 +112,7 @@ public: /// \brief Component-wise multiplication of \c *this and \c rhs. /// /// Computes (lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z). - /// + /// /// Scaling is the most common use case for component-wise multiplication/division. /// This operation is also known as the Hadamard or Schur product. /// @@ -122,11 +121,11 @@ public: //////////////////////////////////////////////////////////// /// \brief Component-wise division of \c *this and \c rhs. - /// + /// /// Computes (lhs.x/rhs.x, lhs.y/rhs.y, lhs.z/rhs.z). - /// + /// /// Scaling is the most common use case for component-wise multiplication/division. - /// + /// /// \pre Neither component of \c rhs is zero. /// //////////////////////////////////////////////////////////// @@ -360,7 +359,7 @@ using Vector3f = Vector3; /// /// float s = v.dot(w); /// sf::Vector3f t = v.cross(w); -/// +/// /// bool different = (v != u); /// \endcode /// diff --git a/include/SFML/System/Vector3.inl b/include/SFML/System/Vector3.inl index a23737f2d..077a4c434 100644 --- a/include/SFML/System/Vector3.inl +++ b/include/SFML/System/Vector3.inl @@ -56,15 +56,6 @@ z(static_cast(vector.z)) } -//////////////////////////////////////////////////////////// -template -T Vector3::length() const -{ - static_assert(std::is_floating_point_v, "Vector3::length() is only supported for floating point types"); - - return std::hypot(x, y, z); -} - //////////////////////////////////////////////////////////// template @@ -74,17 +65,6 @@ constexpr T Vector3::lengthSq() const } -//////////////////////////////////////////////////////////// -template -Vector3 Vector3::normalized() const -{ - static_assert(std::is_floating_point_v, "Vector3::normalized() is only supported for floating point types"); - - assert(*this != Vector3()); - return (*this) / length(); -} - - //////////////////////////////////////////////////////////// template constexpr T Vector3::dot(const Vector3& rhs) const diff --git a/src/SFML/System/CMakeLists.txt b/src/SFML/System/CMakeLists.txt index 7eef39522..dd21d9af1 100644 --- a/src/SFML/System/CMakeLists.txt +++ b/src/SFML/System/CMakeLists.txt @@ -22,8 +22,10 @@ set(SRC ${INCROOT}/Time.inl ${INCROOT}/Utf.hpp ${INCROOT}/Utf.inl + ${SRCROOT}/Vector2.cpp ${INCROOT}/Vector2.hpp ${INCROOT}/Vector2.inl + ${SRCROOT}/Vector3.cpp ${INCROOT}/Vector3.hpp ${INCROOT}/Vector3.inl ${SRCROOT}/FileInputStream.cpp diff --git a/src/SFML/System/Vector2.cpp b/src/SFML/System/Vector2.cpp new file mode 100644 index 000000000..a2b35bce4 --- /dev/null +++ b/src/SFML/System/Vector2.cpp @@ -0,0 +1,123 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +template +Vector2 Vector2::normalized() const +{ + static_assert(std::is_floating_point_v, "Vector2::normalized() is only supported for floating point types"); + + assert(*this != Vector2()); + return (*this) / length(); +} + + +//////////////////////////////////////////////////////////// +template +Angle Vector2::angleTo(const Vector2& rhs) const +{ + static_assert(std::is_floating_point_v, "Vector2::angleTo() is only supported for floating point types"); + + assert(*this != Vector2()); + assert(rhs != Vector2()); + return radians(static_cast(std::atan2(cross(rhs), dot(rhs)))); +} + + +//////////////////////////////////////////////////////////// +template +Angle Vector2::angle() const +{ + static_assert(std::is_floating_point_v, "Vector2::angle() is only supported for floating point types"); + + assert(*this != Vector2()); + return radians(static_cast(std::atan2(y, x))); +} + + +//////////////////////////////////////////////////////////// +template +Vector2 Vector2::rotatedBy(Angle angle) const +{ + static_assert(std::is_floating_point_v, "Vector2::rotatedBy() is only supported for floating point types"); + + // No zero vector assert, because rotating a zero vector is well-defined (yields always itself) + T cos = std::cos(static_cast(angle.asRadians())); + T sin = std::sin(static_cast(angle.asRadians())); + + // Don't manipulate x and y separately, otherwise they're overwritten too early + return Vector2( + cos * x - sin * y, + sin * x + cos * y); +} + + +//////////////////////////////////////////////////////////// +template +Vector2 Vector2::projectedOnto(const Vector2& axis) const +{ + static_assert(std::is_floating_point_v, "Vector2::projectedOnto() is only supported for floating point types"); + + assert(axis != Vector2()); + return dot(axis) / axis.lengthSq() * axis; +} + + +//////////////////////////////////////////////////////////// +template +Vector2::Vector2(T r, Angle phi) : +x(r * static_cast(std::cos(phi.asRadians()))), +y(r * static_cast(std::sin(phi.asRadians()))) +{ + static_assert(std::is_floating_point_v, "Vector2::Vector2(T, Angle) is only supported for floating point types"); +} + + +//////////////////////////////////////////////////////////// +template +T Vector2::length() const +{ + static_assert(std::is_floating_point_v, "Vector2::length() is only supported for floating point types"); + + return std::hypot(x, y); +} + +} + + +//////////////////////////////////////////////////////////// +// Explicit template instantiations +//////////////////////////////////////////////////////////// + +template class sf::Vector2; +template class sf::Vector2; +template class sf::Vector2; diff --git a/src/SFML/System/Vector3.cpp b/src/SFML/System/Vector3.cpp new file mode 100644 index 000000000..9ff43ab8a --- /dev/null +++ b/src/SFML/System/Vector3.cpp @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +template +Vector3 Vector3::normalized() const +{ + static_assert(std::is_floating_point_v, "Vector3::normalized() is only supported for floating point types"); + + assert(*this != Vector3()); + return (*this) / length(); +} + + +//////////////////////////////////////////////////////////// +template +T Vector3::length() const +{ + static_assert(std::is_floating_point_v, "Vector3::length() is only supported for floating point types"); + + return std::hypot(x, y, z); +} + +} + + +//////////////////////////////////////////////////////////// +// Explicit template instantiations +//////////////////////////////////////////////////////////// + +template class sf::Vector3; +template class sf::Vector3; +template class sf::Vector3; diff --git a/src/SFML/Window/Mouse.cpp b/src/SFML/Window/Mouse.cpp index 66f4a3d11..9589dad2f 100644 --- a/src/SFML/Window/Mouse.cpp +++ b/src/SFML/Window/Mouse.cpp @@ -27,7 +27,6 @@ //////////////////////////////////////////////////////////// #include #include -#include namespace sf diff --git a/test/System/Vector2.cpp b/test/System/Vector2.cpp index e9b66bd42..f4bca0880 100644 --- a/test/System/Vector2.cpp +++ b/test/System/Vector2.cpp @@ -1,6 +1,7 @@ #include #include "SystemUtil.hpp" #include +#include #include @@ -248,7 +249,7 @@ TEST_CASE("sf::Vector2 class template - [system]") CHECK(v.normalized() == Approx(sf::Vector2f(0.624695f, 0.780869f))); const sf::Vector2f w(-0.7f, -2.2f); - + CHECK(w.length() == Approx(2.30868f)); CHECK(w.lengthSq() == Approx(5.3300033f)); CHECK(w.normalized() == Approx(sf::Vector2f(-0.303204f, -0.952926f))); @@ -257,7 +258,7 @@ TEST_CASE("sf::Vector2 class template - [system]") SUBCASE("Rotations and angles") { const sf::Vector2f v(2.4f, 3.0f); - + CHECK(v.angle() == Approx(51.3402_deg)); CHECK(sf::Vector2f::UnitX.angleTo(v) == Approx(51.3402_deg)); CHECK(sf::Vector2f::UnitY.angleTo(v) == Approx(-38.6598_deg)); @@ -282,7 +283,7 @@ TEST_CASE("sf::Vector2 class template - [system]") CHECK(v.rotatedBy(27.14_deg) == Approx(sf::Vector2f(0.767248f, 3.76448f))); CHECK(v.rotatedBy(-36.11_deg) == Approx(sf::Vector2f(3.70694f, 1.00925f))); } - + SUBCASE("Products and quotients") { const sf::Vector2f v(2.4f, 3.0f); @@ -293,18 +294,18 @@ TEST_CASE("sf::Vector2 class template - [system]") CHECK(v.cross(w) == Approx(-3.18f)); CHECK(w.cross(v) == Approx(+3.18f)); - + CHECK(v.cwiseMul(w) == Approx(sf::Vector2f(-1.68f, -6.6f))); CHECK(w.cwiseMul(v) == Approx(sf::Vector2f(-1.68f, -6.6f))); CHECK(v.cwiseDiv(w) == Approx(sf::Vector2f(-3.428571f, -1.363636f))); CHECK(w.cwiseDiv(v) == Approx(sf::Vector2f(-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) == Approx(sf::Vector2f(1.087430f, 3.417636f))); CHECK(v.projectedOnto(w) == Approx(sf::Vector2f(-1.55347f * w))); diff --git a/test/TestUtilities/SystemUtil.hpp b/test/TestUtilities/SystemUtil.hpp index d744b6b8d..bed407efa 100644 --- a/test/TestUtilities/SystemUtil.hpp +++ b/test/TestUtilities/SystemUtil.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include