/*
* 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