| 20 | /// \ingroup VectorGroup |
| 21 | template <typename T> |
| 22 | struct Vector4 |
| 23 | { |
| 24 | using ValueType = T; |
| 25 | using MatrixType = Matrix4<T>; |
| 26 | using SymMatrixType = SymMatrix4<T>; |
| 27 | static constexpr int elements = 4; |
| 28 | |
| 29 | T x, y, z, w; |
| 30 | |
| 31 | constexpr Vector4() noexcept : x( 0 ), y( 0 ), z( 0 ), w( 0 ) |
| 32 | { |
| 33 | static_assert( sizeof( Vector4<ValueType> ) == elements * sizeof( ValueType ), "Struct size invalid" ); |
| 34 | static_assert( elements == 4, "Invalid number of elements" ); |
| 35 | } |
| 36 | explicit Vector4( NoInit ) noexcept { } |
| 37 | constexpr Vector4( T x, T y, T z, T w ) noexcept : x( x ), y( y ), z( z ), w( w ) { } |
| 38 | static constexpr Vector4 diagonal( T a ) noexcept |
| 39 | { |
| 40 | return Vector4( a, a, a, a ); |
| 41 | } |
| 42 | |
| 43 | // Here `T == U` doesn't seem to cause any issues in the C++ code, but we're still disabling it because it somehow gets emitted |
| 44 | // when generating the bindings, and looks out of place there. Specifically for Vector4, it only gets emitted on Windows (but not on Linux) for some reason. |
| 45 | template <typename U> MR_REQUIRES_IF_SUPPORTED( !std::is_same_v<T, U> ) |
| 46 | constexpr explicit Vector4( const Vector4<U> & v ) noexcept : x( T( v.x ) ), y( T( v.y ) ), z( T( v.z ) ), w( T( v.w ) ) |
| 47 | { |
| 48 | } |
| 49 | |
| 50 | constexpr const T & operator []( int e ) const noexcept { return *( ( ValueType *)this + e ); } |
| 51 | constexpr T & operator []( int e ) noexcept { return *( ( ValueType* )this + e ); } |
| 52 | |
| 53 | T lengthSq() const |
| 54 | { |
| 55 | return x * x + y * y + z * z + w * w; |
| 56 | } |
| 57 | auto length() const |
| 58 | { |
| 59 | // Calling `sqrt` this way to hopefully support boost.multiprecision numbers. |
| 60 | // Returning `auto` to not break on integral types. |
| 61 | using std::sqrt; |
| 62 | return sqrt( lengthSq() ); |
| 63 | } |
| 64 | |
| 65 | Vector4 normalized() const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> ) |
| 66 | { |
| 67 | auto len = length(); |
| 68 | if ( len <= 0 ) |
| 69 | return {}; |
| 70 | return ( 1 / len ) * ( *this ); |
| 71 | } |
| 72 | |
| 73 | /// assuming this is a point represented in homogeneous 4D coordinates, returns the point as 3D-vector |
| 74 | Vector3<T> proj3d() const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> ) |
| 75 | { |
| 76 | return { x / w, y / w, z / w }; |
| 77 | } |
| 78 | |
| 79 | [[nodiscard]] bool isFinite() const MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> ) |