/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_MATH_VECTOR_HPP #define ANTKEEPER_MATH_VECTOR_HPP #include #include #include #include #include #include #include #include #include namespace math { /** * *n*-dimensional vector. * * @tparam T Element type. * @tparam N Number of elements. */ template struct vector { /// Element type. using element_type = T; /// Number of elements. static constexpr std::size_t element_count = N; /// Array of elements. element_type elements[N]; /// @name Conversion /// @{ /// @private template [[nodiscard]] inline constexpr vector type_cast(std::index_sequence) const noexcept { return {static_cast(elements[I])...}; } /** * Type-casts the elements of this vector using `static_cast`. * * @tparam U Target element type. * * @return Vector containing the type-casted elements. */ template [[nodiscard]] inline constexpr explicit operator vector() const noexcept { return type_cast(std::make_index_sequence{}); } /// @private template [[nodiscard]] inline constexpr vector size_cast(std::index_sequence) const noexcept { return {(I < N) ? elements[I] : T{0} ...}; } /** * Size-casts this vector to a vector with a different number of elements. Casting to a greater number of elements causes new elements to be set to zero. * * @tparam M Target number of elements. * * @return *m*-dimensional vector. */ template [[nodiscard]] inline constexpr explicit operator vector() const noexcept { return size_cast(std::make_index_sequence{}); } /// @} /// @name Element access /// @{ /** * Returns a reference to the element at a given index. * * @param i Index of an element. * * @return Reference to the element at index @p i. */ /// @{ [[nodiscard]] inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; } [[nodiscard]] inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; } /// @} /** * Returns a reference to the first element. */ /// @{ [[nodiscard]] inline constexpr element_type& front() noexcept { return elements[0]; } [[nodiscard]] inline constexpr const element_type& front() const noexcept { return elements[0]; } /// @} /** * Returns a reference to the last element. */ /// @{ [[nodiscard]] inline constexpr element_type& back() noexcept { return elements[N - 1]; } [[nodiscard]] inline constexpr const element_type& back() const noexcept { return elements[N - 1]; } /// @} /** * Returns a pointer to the element array. */ /// @{ [[nodiscard]] inline constexpr element_type* data() noexcept { return elements; }; [[nodiscard]] inline constexpr const element_type* data() const noexcept { return elements; }; /// @} /// Returns a reference to the first element. /// @{ [[nodiscard]] inline constexpr element_type& x() noexcept { static_assert(N > 0, "Vector does not contain an x element."); return elements[0]; } [[nodiscard]] inline constexpr const element_type& x() const noexcept { static_assert(N > 0, "Vector does not contain an x element."); return elements[0]; } /// @} /** * Returns a reference to the second element. */ /// @{ [[nodiscard]] inline constexpr element_type& y() noexcept { static_assert(N > 1, "Vector does not contain a y element."); return elements[1]; } [[nodiscard]] inline constexpr const element_type& y() const noexcept { static_assert(N > 1, "Vector does not contain a y element."); return elements[1]; } /// @} /** * Returns a reference to the third element. */ /// @{ [[nodiscard]] inline constexpr element_type& z() noexcept { static_assert(N > 2, "Vector does not contain a z element."); return elements[2]; } [[nodiscard]] inline constexpr const element_type& z() const noexcept { static_assert(N > 2, "Vector does not contain a z element."); return elements[2]; } /// @} /// @} /// @name Iterators /// @{ /** * Returns an iterator to the first element. */ /// @{ [[nodiscard]] inline constexpr element_type* begin() noexcept { return elements; } [[nodiscard]] inline constexpr const element_type* begin() const noexcept { return elements; } [[nodiscard]] inline constexpr const element_type* cbegin() const noexcept { return elements; } /// @} /** * Returns an iterator to the element following the last element. */ /// @{ [[nodiscard]] inline constexpr element_type* end() noexcept { return elements + N; } [[nodiscard]] inline constexpr const element_type* end() const noexcept { return elements + N; } [[nodiscard]] inline constexpr const element_type* cend() const noexcept { return elements + N; } /// @} /** * Returns a reverse iterator to the first element of the reversed vector. */ /// @{ [[nodiscard]] inline constexpr std::reverse_iterator rbegin() noexcept { return std::reverse_iterator(elements + N); } [[nodiscard]] inline constexpr std::reverse_iterator rbegin() const noexcept { return std::reverse_iterator(elements + N); } [[nodiscard]] inline constexpr std::reverse_iterator crbegin() const noexcept { return std::reverse_iterator(elements + N); } /// @} /** * Returns a reverse iterator to the element following the last element of the reversed vector. */ /// @{ [[nodiscard]] inline constexpr std::reverse_iterator rend() noexcept { return std::reverse_iterator(elements); } [[nodiscard]] inline constexpr std::reverse_iterator rend() const noexcept { return std::reverse_iterator(elements); } [[nodiscard]] inline constexpr std::reverse_iterator crend() const noexcept { return std::reverse_iterator(elements); } /// @} /// @} /// @name Capacity /// @{ /** * Returns the number of elements in the vector. */ [[nodiscard]] inline constexpr std::size_t size() const noexcept { return N; }; /// @} /// @name Constants /// @{ /** * Returns a zero vector, where every element is equal to zero. */ [[nodiscard]] inline static constexpr vector zero() noexcept { return {}; } /// @private template [[nodiscard]] inline static constexpr vector one(std::index_sequence) noexcept { //return {element_type{1}...}; // MSVC bug workaround (I must be referenced for parameter pack expansion) return {(I ? element_type{1} : element_type{1})...}; } /** * Returns a vector of ones, where every element is equal to one. */ [[nodiscard]] inline static constexpr vector one() noexcept { return one(std::make_index_sequence{}); } /// @private template [[nodiscard]] inline static constexpr vector infinity(std::index_sequence) noexcept { //return {element_type{1}...}; // MSVC bug workaround (I must be referenced for parameter pack expansion) return {(I ? std::numeric_limits::infinity() : std::numeric_limits::infinity())...}; } /** * Returns a vector of infinities, where every element is equal to infinity. */ [[nodiscard]] inline static constexpr vector infinity() noexcept { return infinity(std::make_index_sequence{}); } /// @} }; /// Vector types. namespace vector_types { /** * 2-dimensional vector. * * @tparam T Element type. */ template using vec2 = vector; /** * 3-dimensional vector. * * @tparam T Element type. */ template using vec3 = vector; /** * 4-dimensional vector. * * @tparam T Element type. */ template using vec4 = vector; /** * *n*-dimensional vector of Boolean values. * * @tparam N Number of elements */ /// @{ template using bvec = vector; using bvec2 = bvec<2>; using bvec3 = bvec<3>; using bvec4 = bvec<4>; /// @} /** * *n*-dimensional vector of signed integers. * * @tparam N Number of elements */ /// @{ template using ivec = vector; using ivec2 = ivec<2>; using ivec3 = ivec<3>; using ivec4 = ivec<4>; /// @} /** * *n*-dimensional vector of unsigned integers. * * @tparam N Number of elements */ /// @{ template using uvec = vector; using uvec2 = uvec<2>; using uvec3 = uvec<3>; using uvec4 = uvec<4>; /// @} /** * *n*-dimensional vector of single-precision floating-point numbers. * * @tparam N Number of elements */ /// @{ template using fvec = vector; using fvec2 = fvec<2>; using fvec3 = fvec<3>; using fvec4 = fvec<4>; /// @} /** * *n*-dimensional vector of double-precision floating-point numbers. * * @tparam N Number of elements */ /// @{ template using dvec = vector; using dvec2 = dvec<2>; using dvec3 = dvec<3>; using dvec4 = dvec<4>; /// @} } // namespace vector_types // Bring vector types into math namespace using namespace vector_types; // Bring vector types into math::types namespace namespace types { using namespace math::vector_types; } /** * Returns the absolute values of each element. * * @param x Input vector. * * @return Absolute values of input vector elements. */ template [[nodiscard]] constexpr vector abs(const vector& x); /** * Adds two values. * * @param x First value. * @param y Second value. * * @return Sum of the two values. */ /// @{ template [[nodiscard]] constexpr vector add(const vector& x, const vector& y) noexcept; template [[nodiscard]] constexpr vector add(const vector& x, T y) noexcept; /// @} /** * Checks if all elements of a boolean vector are `true`. * * @param x Vector to be tested for truth. * * @return `true` if all elements are `true`, `false` otherwise. */ template [[nodiscard]] constexpr bool all(const vector& x) noexcept; /** * Calculates the angle between two direction vectors. * * @param from First direction vector. * @param to Second direction vector. * * @return Angle between the two direction vectors, in radians. */ template [[nodiscard]] T angle(const vector& from, const vector& to); /** * Checks if any elements of a boolean vector are `true`. * * @param x Vector to be tested for truth. * * @return `true` if any elements are `true`, `false` otherwise. */ template [[nodiscard]] constexpr bool any(const vector& x) noexcept; /** * Performs an element-wise ceil operation. * * @param x Input vector. * * @return Component-wise ceil of input vector. */ template [[nodiscard]] constexpr vector ceil(const vector& x); /** * Clamps the values of a vector's elements. * * @param x Vector to clamp. * @param min Minimum value. * @param max Maximum value. * * @return Clamped vector. */ /// @{ template [[nodiscard]] constexpr vector clamp(const vector& x, const vector& min, const vector& max); template [[nodiscard]] constexpr vector clamp(const vector& x, T min, T max); /// @} /** * Clamps the length of a vector. * * @param x Vector to clamp. * @param max_length Maximum length. * * @return Length-clamped vector. */ template [[nodiscard]] vector clamp_length(const vector& x, T max_length); /** * Calculates the cross product of two vectors. * * @param x First vector. * @param y Second vector. * * @return Cross product of the two vectors. */ template [[nodiscard]] constexpr vector cross(const vector& x, const vector& y) noexcept; /** * Calculates the distance between two points. * * @param p0 First of two points. * @param p1 Second of two points. * * @return Distance between the two points. */ template [[nodiscard]] T distance(const vector& p0, const vector& p1); /** * Divides a vector by a value. * * @param x First value. * @param y Second value. * * @return Result of the division. */ /// @{ template [[nodiscard]] constexpr vector div(const vector& x, const vector& y) noexcept; template [[nodiscard]] constexpr vector div(const vector& x, T y) noexcept; template [[nodiscard]] constexpr vector div(T x, const vector& y) noexcept; /// @} /** * Calculates the dot product of two vectors. * * @param x First vector. * @param y Second vector. * * @return Dot product of the two vectors. */ template [[nodiscard]] constexpr T dot(const vector& x, const vector& y) noexcept; /** * Compares two vectors for equality * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector equal(const vector& x, const vector& y) noexcept; /** * Performs a element-wise floor operation. * * @param x Input vector. * * @return Component-wise floor of input vector. */ template [[nodiscard]] constexpr vector floor(const vector& x); /** * Performs a multiply-add operation. * * @param x Input vector * @param y Value to multiply. * @param z Value to add. * * @return Vector containing the multiply-add results. */ /// @{ template [[nodiscard]] constexpr vector fma(const vector& x, const vector& y, const vector& z); template [[nodiscard]] constexpr vector fma(const vector& x, T y, T z); /// @} /** * Returns a vector containing the fractional part of each element. * * @param x Input vector. * * @return Fractional parts of input vector. */ template [[nodiscard]] constexpr vector fract(const vector& x); /** * Extracts the Ith element from a vector. * * @tparam I Index of an element. * @tparam T Element type. * @tparam N Number of elements. * * @param v Vector from which to extract an element. * * @return Reference to the Ith element of @p v. */ /// @{ template [[nodiscard]] constexpr T& get(math::vector& v) noexcept; template [[nodiscard]] constexpr T&& get(math::vector&& v) noexcept; template [[nodiscard]] constexpr const T& get(const math::vector& v) noexcept; template [[nodiscard]] constexpr const T&& get(const math::vector&& v) noexcept; /// @} /** * Performs a element-wise greater-than comparison of two vectors. * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector greater_than(const vector& x, const vector& y) noexcept; /** * Performs a element-wise greater-than or equal-to comparison of two vectors. * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector greater_than_equal(const vector& x, const vector& y) noexcept; /** * Calculates the inverse length of a vector. * * @param x Vector of which to calculate the inverse length. * * @return Inverse length of the vector. */ template [[nodiscard]] T inv_length(const vector& x); /** * Calculates the length of a vector. * * @param x Vector of which to calculate the length. * * @return Length of the vector. */ template [[nodiscard]] T length(const vector& x); /** * Performs a element-wise less-than comparison of two vectors. * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector less_than(const vector& x, const vector& y) noexcept; /** * Performs a element-wise less-than or equal-to comparison of two vectors. * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector less_than_equal(const vector& x, const vector& y) noexcept; /** * Returns a vector containing the maximum elements of two vectors. * * @param x First vector. * @param y Second vector. * * @return Maximum elements of the two vectors. */ template [[nodiscard]] constexpr vector max(const vector& x, const vector& y); /** * Returns the value of the greatest element in a vector. * * @param x Input vector. * * @return Value of the greatest element in the input vector. */ template [[nodiscard]] constexpr T max(const vector& x); /** * Returns a vector containing the minimum elements of two vectors. * * @param x First vector. * @param y Second vector. * * @return Minimum elements of the two vectors. */ template [[nodiscard]] constexpr vector min(const vector& x, const vector& y); /** * Returns the value of the smallest element in a vector. * * @param x Input vector. * * @return Value of the smallest element in the input vector. */ template [[nodiscard]] constexpr T min(const vector& x); /** * Calculates the element-wise remainder of the division operation `x / y`. * * @param x First vector. * @param y Second vector. * * @return Remainders of `x / y`. */ /// @{ template [[nodiscard]] constexpr vector mod(const vector& x, const vector& y); template [[nodiscard]] constexpr vector mod(const vector& x, T y); /// @} /** * Multiplies two values. * * @param x First value. * @param y Second value. * * @return Product of the two values. */ /// @{ template [[nodiscard]] constexpr vector mul(const vector& x, const vector& y) noexcept; template [[nodiscard]] constexpr vector mul(const vector& x, T y) noexcept; /// @} /** * Negates a vector. * * @param x Vector to negate. * * @return Negated vector. */ template [[nodiscard]] constexpr vector negate(const vector& x) noexcept; /** * Calculates the unit vector in the same direction as the original vector. * * @param x Vector to normalize. * * @return Unit vector. */ template [[nodiscard]] vector normalize(const vector& x); /** * Logically inverts a boolean vector. * * @param x Vector to be inverted. * * @return Logically inverted vector. */ template [[nodiscard]] constexpr vector logical_not(const vector& x) noexcept; /** * Compares two vectors for inequality * * @param x First vector. * @param y Second vector. * * @return Boolean vector containing the result of the element comparisons. */ template [[nodiscard]] constexpr vector not_equal(const vector& x, const vector& y) noexcept; /** * Raises each element to a power. * * @param x Input vector * @param y Exponent. * * @return Vector with its elements raised to the given power. */ /// @{ template [[nodiscard]] vector pow(const vector& x, const vector& y); template [[nodiscard]] vector pow(const vector& x, T y); /// @} /** * Performs a element-wise round operation. * * @param x Input vector * * @return Component-wise round of input vector. */ template [[nodiscard]] constexpr vector round(const vector& x); /** * Returns a vector containing the signs of each element. * * @param x Input vector * @return Signs of input vector elements. */ template [[nodiscard]] constexpr vector sign(const vector& x); /** * Calculates the signed angle between two direction vectors about axis. * * @param from First direction vector. * @param to Second direction vector. * @param axis Axis direction vector. * * @return Signed angle between @p from and @p to about @p axis, in radians. */ template [[nodiscard]] T signed_angle(const vector& x, const vector& y, const vector& n); /** * Calculates the square distance between two points. The square distance can be calculated faster than the distance because a call to `std::sqrt` is saved. * * @param p0 First of two points. * @param p1 Second of two points. * * @return Square distance between the two points. */ template [[nodiscard]] constexpr T sqr_distance(const vector& p0, const vector& p1) noexcept; /** * Calculates the square length of a vector. The square length can be calculated faster than the length because a call to `std::sqrt` is saved. * * @param x Vector of which to calculate the square length. * * @return Square length of the vector. */ template [[nodiscard]] constexpr T sqr_length(const vector& x) noexcept; /** * Takes the square root of each element. * * @param x Input vector * * @return Square roots of the input vector elements. */ template [[nodiscard]] vector sqrt(const vector& x); /** * Subtracts a value by another value. * * @param x First value. * @param y Second value. * * @return Difference between the two values. */ /// @{ template [[nodiscard]] constexpr vector sub(const vector& x, const vector& y) noexcept; template [[nodiscard]] constexpr vector sub(const vector& x, T y) noexcept; template [[nodiscard]] constexpr vector sub(T x, const vector& y) noexcept; /// @} /** * Calculates the sum of all elements in a vector. * * @param x Vector to sum. * @return Sum of the vector's elements. */ template [[nodiscard]] constexpr T sum(const vector& x) noexcept; /** * Makes an *m*-dimensional vector by rearranging and/or duplicating elements of an *n*-dimensional vector. * * @tparam Indices List of indices of elements in @p x. * @tparam T Vector element type. * @tparam N Number of dimensions in @p x. * * @param x Vector to swizzle. * * @return Vector containing elements from @p x in the order specified by @p Indices. The size of the returned vector is equivalent to the number of indices in @p Indices. */ template [[nodiscard]] constexpr vector swizzle(const vector& x) noexcept; /** * Calculates the triple product of three vectors. * * @param x First vector. * @param y Second vector. * @param z Third vector. * * @return Triple product of the three vectors (`dot(x, cross(y, z)`). */ template [[nodiscard]] constexpr T triple(const vector& x, const vector& y, const vector& z) noexcept; /** * Performs a element-wise trunc operation. * * @param x Input vector * @return Component-wise trunc of input vector. */ template [[nodiscard]] constexpr vector trunc(const vector& x); /// @private template inline constexpr vector abs(const vector& x, std::index_sequence) { return {std::abs(x[I])...}; } template inline constexpr vector abs(const vector& x) { return abs(x, std::make_index_sequence{}); } /// @private template inline constexpr vector add(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] + y[I])...}; } template inline constexpr vector add(const vector& x, const vector& y) noexcept { return add(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector add(const vector& x, T y, std::index_sequence) noexcept { return {(x[I] + y)...}; } template inline constexpr vector add(const vector& x, T y) noexcept { return add(x, y, std::make_index_sequence{}); } /// @private template inline constexpr bool all(const vector& x, std::index_sequence) noexcept { return (x[I] && ...); } template inline constexpr bool all(const vector& x) noexcept { return all(x, std::make_index_sequence{}); } template T angle(const vector& from, const vector& to) { return std::acos(std::min(std::max(dot(from, to), T{-1}), T{1})); } /// @private template inline constexpr bool any(const vector& x, std::index_sequence) noexcept { return (x[I] || ...); } template inline constexpr bool any(const vector& x) noexcept { return any(x, std::make_index_sequence{}); } /// @private template inline constexpr vector ceil(const vector& x, std::index_sequence) { return {std::ceil(x[I])...}; } template inline constexpr vector ceil(const vector& x) { return ceil(x, std::make_index_sequence{}); } /// @private template inline constexpr vector clamp(const vector& x, const vector& min_val, const vector& max_val, std::index_sequence) { return {std::min(max_val[I], std::max(min_val[I], x[I]))...}; } template inline constexpr vector clamp(const vector& x, const vector& min, const vector& max) { return clamp(x, min, max, std::make_index_sequence{}); } /// @private template inline constexpr vector clamp(const vector& x, T min, T max, std::index_sequence) { return {std::min(max, std::max(min, x[I]))...}; } template inline constexpr vector clamp(const vector& x, T min, T max) { return clamp(x, min, max, std::make_index_sequence{}); } template vector clamp_length(const vector& x, T max_length) { const auto length2 = sqr_length(x); return (length2 > max_length * max_length) ? (x * (max_length / std::sqrt(length2))) : x; } template inline constexpr vector cross(const vector& x, const vector& y) noexcept { return { x[1] * y[2] - x[2] * y[1], x[2] * y[0] - x[0] * y[2], x[0] * y[1] - x[1] * y[0] }; } template inline T distance(const vector& p0, const vector& p1) { return length(sub(p0, p1)); } /// @private template inline constexpr vector div(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] / y[I])...}; } template inline constexpr vector div(const vector& x, const vector& y) noexcept { return div(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector div(const vector& x, T y, std::index_sequence) noexcept { return {(x[I] / y)...}; } template inline constexpr vector div(const vector& x, T y) noexcept { return div(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector div(T x, const vector& y, std::index_sequence) noexcept { return {(x / y[I])...}; } template inline constexpr vector div(T x, const vector& y) noexcept { return div(x, y, std::make_index_sequence{}); } /// @private template inline constexpr T dot(const vector& x, const vector& y, std::index_sequence) noexcept { return ((x[I] * y[I]) + ...); } template inline constexpr T dot(const vector& x, const vector& y) noexcept { return dot(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector equal(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] == y[I])...}; } template inline constexpr vector equal(const vector& x, const vector& y) noexcept { return equal(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector floor(const vector& x, std::index_sequence) { return {std::floor(x[I])...}; } template inline constexpr vector floor(const vector& x) { return floor(x, std::make_index_sequence{}); } /// @private template inline constexpr vector fma(const vector& x, const vector& y, const vector& z, std::index_sequence) { return {std::fma(x[I], y[I], z[I])...}; } template inline constexpr vector fma(const vector& x, const vector& y, const vector& z) { return fma(x, y, z, std::make_index_sequence{}); } /// @private template inline constexpr vector fma(const vector& x, T y, T z, std::index_sequence) { return {std::fma(x[I], y, z)...}; } template inline constexpr vector fma(const vector& x, T y, T z) { return fma(x, y, z, std::make_index_sequence{}); } /// @private template inline constexpr vector fract(const vector& x, std::index_sequence) { return {x[I] - std::floor(x[I])...}; } template inline constexpr vector fract(const vector& x) { return fract(x, std::make_index_sequence{}); } template inline constexpr T& get(math::vector& v) noexcept { static_assert(I < N); return v.elements[I]; } template inline constexpr T&& get(math::vector&& v) noexcept { static_assert(I < N); return std::move(v.elements[I]); } template inline constexpr const T& get(const math::vector& v) noexcept { static_assert(I < N); return v.elements[I]; } template inline constexpr const T&& get(const math::vector&& v) noexcept { static_assert(I < N); return std::move(v.elements[I]); } /// @private template inline constexpr vector greater_than(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] > y[I])...}; } template inline constexpr vector greater_than(const vector& x, const vector& y) noexcept { return greater_than(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector greater_than_equal(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] >= y[I])...}; } template inline constexpr vector greater_than_equal(const vector& x, const vector& y) noexcept { return greater_than_equal(x, y, std::make_index_sequence{}); } template inline T inv_length(const vector& x) { return T{1} / length(x); } template inline T length(const vector& x) { return std::sqrt(sqr_length(x)); } /// @private template inline constexpr vector less_than(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] < y[I])...}; } template inline constexpr vector less_than(const vector& x, const vector& y) noexcept { return less_than(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector less_than_equal(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] <= y[I])...}; } template inline constexpr vector less_than_equal(const vector& x, const vector& y) noexcept { return less_than_equal(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector max(const vector& x, const vector& y, std::index_sequence) { return {std::max(x[I], y[I])...}; } template constexpr vector max(const vector& x, const vector& y) { return max(x, y, std::make_index_sequence{}); } template inline constexpr T max(const vector& x) { return *std::max_element(x.elements, x.elements + N); } /// @private template inline constexpr vector min(const vector& x, const vector& y, std::index_sequence) { return {std::min(x[I], y[I])...}; } template constexpr vector min(const vector& x, const vector& y) { return min(x, y, std::make_index_sequence{}); } template inline constexpr T min(const vector& x) { return *std::min_element(x.elements, x.elements + N); } /// @private template inline constexpr vector mod(const vector& x, const vector& y, std::index_sequence) { return {std::fmod(x[I], y[I])...}; } template inline constexpr vector mod(const vector& x, const vector& y) { return mod(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector mod(const vector& x, T y, std::index_sequence) { return {std::fmod(x[I], y)...}; } template inline constexpr vector mod(const vector& x, T y) { return mod(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector mul(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] * y[I])...}; } template inline constexpr vector mul(const vector& x, const vector& y) noexcept { return mul(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector mul(const vector& x, T y, std::index_sequence) noexcept { return {(x[I] * y)...}; } template inline constexpr vector mul(const vector& x, T y) noexcept { return mul(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector negate(const vector& x, std::index_sequence) noexcept { return {(-x[I])...}; } template inline constexpr vector negate(const vector& x) noexcept { return negate(x, std::make_index_sequence{}); } template inline vector normalize(const vector& x) { return mul(x, inv_length(x)); } /// @private template inline constexpr vector logical_not(const vector& x, std::index_sequence) noexcept { return {!x[I]...}; } template inline constexpr vector logical_not(const vector& x) noexcept { return logical_not(x, std::make_index_sequence{}); } /// @private template inline constexpr vector not_equal(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] != y[I])...}; } template inline constexpr vector not_equal(const vector& x, const vector& y) noexcept { return not_equal(x, y, std::make_index_sequence{}); } /// @private template inline vector pow(const vector& x, const vector& y, std::index_sequence) { return {std::pow(x[I], y[I])...}; } template inline vector pow(const vector& x, const vector& y) { return pow(x, y, std::make_index_sequence{}); } /// @private template inline vector pow(const vector& x, T y, std::index_sequence) { return {std::pow(x[I], y)...}; } template inline vector pow(const vector& x, T y) { return pow(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector round(const vector& x, std::index_sequence) { return {std::round(x[I])...}; } template inline constexpr vector round(const vector& x) { return round(x, std::make_index_sequence{}); } /// @private template inline constexpr vector sign(const vector& x, std::index_sequence) { return {std::copysign(T{1}, x[I])...}; } template inline constexpr vector sign(const vector& x) { return sign(x, std::make_index_sequence{}); } template T signed_angle(const vector& from, const vector& to, const vector& axis) { return std::atan2(triple(axis, from, to), dot(from, to)); } template inline constexpr T sqr_distance(const vector& p0, const vector& p1) noexcept { return sqr_length(sub(p0, p1)); } template inline constexpr T sqr_length(const vector& x) noexcept { return dot(x, x); } /// @private template inline vector sqrt(const vector& x, std::index_sequence) { return {std::sqrt(x[I])...}; } template inline vector sqrt(const vector& x, const vector& y) { return sqrt(x, std::make_index_sequence{}); } /// @private template inline constexpr vector sub(const vector& x, const vector& y, std::index_sequence) noexcept { return {(x[I] - y[I])...}; } template inline constexpr vector sub(const vector& x, const vector& y) noexcept { return sub(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector sub(const vector& x, T y, std::index_sequence) noexcept { return {(x[I] - y)...}; } template inline constexpr vector sub(const vector& x, T y) noexcept { return sub(x, y, std::make_index_sequence{}); } /// @private template inline constexpr vector sub(T x, const vector& y, std::index_sequence) noexcept { return {(x - y[I])...}; } template inline constexpr vector sub(T x, const vector& y) noexcept { return sub(x, y, std::make_index_sequence{}); } /// @private template inline constexpr T sum(const vector& x, std::index_sequence) noexcept { return (x[I] + ...); } template inline constexpr T sum(const vector& x) noexcept { return sum(x, std::make_index_sequence{}); } template inline constexpr vector swizzle(const vector& x) noexcept { return {x[Indices]...}; } template inline constexpr T triple(const vector& x, const vector& y, const vector& z) noexcept { return dot(x, cross(y, z)); } /// @private template inline constexpr vector trunc(const vector& x, std::index_sequence) { return {std::trunc(x[I])...}; } template inline constexpr vector trunc(const vector& x) { return trunc(x, std::make_index_sequence{}); } namespace operators { /// @copydoc add(const vector&, const vector&) template [[nodiscard]] inline constexpr vector operator+(const vector& x, const vector& y) noexcept { return add(x, y); } /// @copydoc add(const vector&, T) /// @{ template [[nodiscard]] inline constexpr vector operator+(const vector& x, T y) noexcept { return add(x, y); } template [[nodiscard]] inline constexpr vector operator+(T x, const vector& y) noexcept { return add(y, x); } /// @} /// @copydoc div(const vector&, const vector&) template [[nodiscard]] inline constexpr vector operator/(const vector& x, const vector& y) noexcept { return div(x, y); } /// @copydoc div(const vector&, T) template [[nodiscard]] inline constexpr vector operator/(const vector& x, T y) noexcept { return div(x, y); } /// @copydoc div(T, const vector&) template [[nodiscard]] inline constexpr vector operator/(T x, const vector& y) noexcept { return div(x, y); } /// @copydoc mul(const vector&, const vector&) template [[nodiscard]] inline constexpr vector operator*(const vector& x, const vector& y) noexcept { return mul(x, y); } /// @copydoc mul(const vector&, T) /// @{ template [[nodiscard]] inline constexpr vector operator*(const vector& x, T y) noexcept { return mul(x, y); } template [[nodiscard]] inline constexpr vector operator*(T x, const vector& y) noexcept { return mul(y, x); } /// @} /// @copydoc negate(const vector&) template [[nodiscard]] inline constexpr vector operator-(const vector& x) noexcept { return negate(x); } /// @copydoc sub(const vector&, const vector&) template [[nodiscard]] inline constexpr vector operator-(const vector& x, const vector& y) noexcept { return sub(x, y); } /// @copydoc sub(const vector&, T) template [[nodiscard]] inline constexpr vector operator-(const vector& x, T y) noexcept { return sub(x, y); } /// @copydoc sub(T, const vector&) template [[nodiscard]] inline constexpr vector operator-(T x, const vector& y) noexcept { return sub(x, y); } /** * Adds two values and stores the result in the first value. * * @param x First value. * @param y Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr vector& operator+=(vector& x, const vector& y) noexcept { return (x = x + y); } template inline constexpr vector& operator+=(vector& x, T y) noexcept { return (x = x + y); } /// @} /** * Subtracts the first value by the second value and stores the result in the first value. * * @param x First value. * @param y Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr vector& operator-=(vector& x, const vector& y) noexcept { return (x = x - y); } template inline constexpr vector& operator-=(vector& x, T y) noexcept { return (x = x - y); } /// @} /** * Multiplies two values and stores the result in the first value. * * @param x First value. * @param y Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr vector& operator*=(vector& x, const vector& y) noexcept { return (x = x * y); } template inline constexpr vector& operator*=(vector& x, T y) noexcept { return (x = x * y); } /// @} /** * Divides the first value by the second value and stores the result in the first value. * * @param x First value. * @param y Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr vector& operator/=(vector& x, const vector& y) noexcept { return (x = x / y); } template inline constexpr vector& operator/=(vector& x, T y) noexcept { return (x = x / y); } /// @} } // namespace operators } // namespace math // Bring vector operators into global namespace using namespace math::operators; namespace std { /** * Provides access to the number of elements in a math::vector as a compile-time constant expression. * * @tparam T Element type. * @tparam N Number of elements. */ template struct tuple_size> { /// Number of elements in the vector. static constexpr std::size_t value = math::vector::element_count; }; /** * Provides compile-time indexed access to the type of the elements in a math::vector using a tuple-like interface. * * @tparam I Index of an element. * @tparam T Element type. * @tparam N Number of elements. */ template struct tuple_element> { /// Type of elements in the vector. using type = math::vector::element_type; }; /** * Specialization of std::formatter for math::vector. * * @tparam T Element type. * @tparam N Number of elements. */ template struct formatter>: formatter { auto format(const math::vector& t, format_context& fc) const { auto&& out = fc.out(); format_to(out, "{{"); for (std::size_t i = 0; i < N; ++i) { formatter::format(t[i], fc); if (i < N - 1) { format_to(out, ", "); } } return format_to(out, "}}"); } }; } // Ensure vectors are POD types static_assert(std::is_standard_layout_v); static_assert(std::is_trivial_v); #endif // ANTKEEPER_MATH_VECTOR_HPP