💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

652 lines
17 KiB

/*
* Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_MATH_VECTOR_FUNCTIONS_HPP
#define ANTKEEPER_MATH_VECTOR_FUNCTIONS_HPP
#include "math/vector-type.hpp"
#include <algorithm>
#include <cmath>
#include <type_traits>
#include <utility>
namespace math {
/// @addtogroup vector
/// @{
/**
* Adds two vectors.
*
* @param x First vector.
* @param y Second vector.
* @return Sum of the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y);
/**
* 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 <std::size_t N>
bool all(const vector<bool, N>& x);
/**
* 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 <std::size_t N>
bool any(const vector<bool, N>& x);
/**
* Reinterprets data as an `N`-dimensional vector of type `T`.
*
* @tparam N Number of vector dimensions.
* @tparam T Scalar type.
* @param data Data to reinterpret.
*/
template <std::size_t N, typename T>
vector<T, N>& as_vector(T& data);
/**
* Clamps the values of a vector's elements.
*
* @param x Vector to clamp.
* @param min_value Minimum element value.
* @param max_value Maximum element value.
* @return Clamped vector.
*/
template <class T, std::size_t N>
vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value);
/**
* Clamps the length of a vector.
*
* @param x Vector to clamp.
* @param max_length Maximum length.
* @return Length-clamped vector.
*/
template <class T, std::size_t N>
vector<T, N> clamp_length(const vector<T, N>& x, T max_length);
/**
* Calculate the cross product of two vectors.
*
* @param x First vector.
* @param y Second vector.
* @return Cross product of the two vectors.
*/
template <class T>
vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y);
/**
* 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 <class T, std::size_t N>
vector<T, N> distance(const vector<T, N>& p0, const vector<T, N>& p1);
/**
* Calculates the squared distance between two points. The squared 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 Squared distance between the two points.
*/
template <class T, std::size_t N>
vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1);
/**
* Divides a vector by another vector.
*
* @param x First vector.
* @param y Second vector.
* @return Result of the division.
*/
template <class T, std::size_t N>
vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y);
/**
* Divides a vector by a scalar.
*
* @param v Vector.
* @param s Scalar.
* @return Result of the division.
*/
template <class T, std::size_t N>
vector<T, N> div(const vector<T, N>& v, T s);
/**
* Calculates the dot product of two vectors.
*
* @param x First vector.
* @param y Second vector.
* @return Dot product of the two vectors.
*/
template <class T, std::size_t N>
T dot(const vector<T, N>& x, const vector<T, N>& y);
/**
* Compares two vectors for equality
*
* @param x First vector.
* @param y Second vector.
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-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 <class T, std::size_t N>
vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-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 <class T, std::size_t N>
vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Calculates the length of a vector.
*
* @param x Vector of which to calculate the length.
* @return Length of the vector.
*/
template <class T, std::size_t N>
T length(const vector<T, N>& x);
/**
* Calculates the squared length of a vector. The squared length can be calculated faster than the length because a call to `std::sqrt` is saved.
*
* @param x Vector of which to calculate the squared length.
* @return Squared length of the vector.
*/
template <class T, std::size_t N>
T length_squared(const vector<T, N>& x);
/**
* Performs a component-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 <class T, std::size_t N>
vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-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 <class T, std::size_t N>
vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Multiplies two vectors.
*
* @param x First vector.
* @param y Second vector.
* @return Product of the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y);
/**
* Multiplies a vector by a scalar.
*
* @param v Vector.
* @param s Scalar.
* @return Product of the vector and scalar.
*/
template <class T, std::size_t N>
vector<T, N> mul(const vector<T, N>& v, T s);
/**
* Negates a vector.
*
* @param x Vector to negate.
* @return Negated vector.
*/
template <class T, std::size_t N>
vector<T, N> negate(const vector<T, N>& x);
/**
* Calculates the unit vector in the same direction as the original vector.
*
* @param x Vector to normalize.
* @return Normalized vector.
*/
template <class T, std::size_t N>
vector<T, N> normalize(const vector<T, N>& x);
/**
* Logically inverts a boolean vector.
*
* @param x Vector to be inverted.
* @return Logically inverted vector.
*/
template <class T, std::size_t N>
vector<bool, N> not(const vector<T, N>& x);
/**
* Compares two vectors for inequality
*
* @param x First vector.
* @param y Second vector.
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Resizes a vector. Any new elements will be set to `0`.
*
* @param v Vector to resize.
* @return Resized vector.
*/
template <std::size_t N1, class T, std::size_t N0>
vector<T, N1> resize(const vector<T, N0>& v);
/**
* Subtracts a vector from another vector.
*
* @param x First vector.
* @param y Second vector.
* @return Difference between the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y);
/**
* Makes an m-dimensional vector by rearranging and/or duplicating elements of an n-dimensional vector.
*
* @tparam Indices List of indices of elements in the vector `v`.
* @tparam T Vector component type.
* @tparam N Number of dimensions in vector `v`.
* @return Vector containing elements from vector `v` in the order specified by `Indices`. The size of the returned vector is equivalent to the number of indices in `Indices`.
*/
template <std::size_t... Indices, class T, std::size_t N>
vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v);
/**
* Types casts each vector component and returns a vector of the casted type.
*
* @tparam T2 Target vector component type.
* @tparam T1 Source vector component type.
* @tparam N Number of dimensions.
* @param v Vector to type cast.
* @return Type-casted vector.
*/
template <class T2, class T1, std::size_t N>
vector<T2, N> type_cast(const vector<T1, N>& v);
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] + y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y)
{
return add(x, y, std::make_index_sequence<N>{});
}
/// @private
template <std::size_t N, std::size_t... I>
inline bool all(const vector<bool, N>& x, std::index_sequence<I...>)
{
return (x[I] && ...);
}
template <std::size_t N>
inline bool all(const vector<bool, N>& x)
{
return all(x, std::make_index_sequence<N>{});
}
/// @private
template <std::size_t N, std::size_t... I>
inline bool any(const vector<bool, N>& x, std::index_sequence<I...>)
{
return (x[I] || ...);
}
template <std::size_t N>
inline bool any(const vector<bool, N>& x)
{
return any(x, std::make_index_sequence<N>{});
}
template <std::size_t N, typename T>
inline vector<T, N>& as_vector(T& data)
{
static_assert(std::is_pod<vector<T, N>>::value);
return reinterpret_cast<vector<T, N>&>(data);
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value, std::index_sequence<I...>)
{
return {std::min<T>(max_value, std::max<T>(min_value, x[I]))...};
}
template <class T, std::size_t N>
inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value)
{
return clamp(x, min_value, max_value, std::make_index_sequence<N>{});
}
template <class T, std::size_t N>
vector<T, N> clamp_length(const vector<T, N>& x, T max_length)
{
T length2 = length_squared(x);
return (length2 > max_length * max_length) ? (x * max_length / std::sqrt(length2)) : x;
}
template <class T>
inline vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y)
{
return
{
x[1] * y[2] - y[1] * x[2],
x[2] * y[0] - y[2] * x[0],
x[0] * y[1] - y[0] * x[1]
};
}
template <class T, std::size_t N>
inline vector<T, N> distance(const vector<T, N>& p0, const vector<T, N>& p1)
{
static_assert(std::is_floating_point<T>::value);
return length(sub(p0, p1));
}
template <class T, std::size_t N>
inline vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1)
{
static_assert(std::is_floating_point<T>::value);
return length_squared(sub(p0, p1));
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] / y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y)
{
return div(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> div(const vector<T, N>& v, T s, std::index_sequence<I...>)
{
return {(v[I] / s)...};
}
template <class T, std::size_t N>
inline vector<T, N> div(const vector<T, N>& v, T s)
{
return div(v, s, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline T dot(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return ((x[I] * y[I]) + ...);
}
template <class T, std::size_t N>
inline T dot(const vector<T, N>& x, const vector<T, N>& y)
{
return dot(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] == y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y)
{
return equal(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] > y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y)
{
return greater_than(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] >= y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return greater_than_equal(x, y, std::make_index_sequence<N>{});
}
template <class T, std::size_t N>
inline T length(const vector<T, N>& x)
{
static_assert(std::is_floating_point<T>::value);
return std::sqrt(dot(x, x));
}
template <class T, std::size_t N>
inline T length_squared(const vector<T, N>& x)
{
static_assert(std::is_floating_point<T>::value);
return dot(x, x);
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] < y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y)
{
return less_than(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] <= y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return less_than_equal(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] * y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y)
{
return mul(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> mul(const vector<T, N>& v, T s, std::index_sequence<I...>)
{
return {(v[I] * s)...};
}
template <class T, std::size_t N>
inline vector<T, N> mul(const vector<T, N>& v, T s)
{
return mul(v, s, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> negate(const vector<T, N>& x, std::index_sequence<I...>)
{
return {(-x[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> negate(const vector<T, N>& x)
{
return negate(x, std::make_index_sequence<N>{});
}
template <class T, std::size_t N>
inline vector<T, N> normalize(const vector<T, N>& x)
{
static_assert(std::is_floating_point<T>::value);
return mul(x, T(1) / length(x));
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> not(const vector<T, N>& x, std::index_sequence<I...>)
{
return {!x[I]...};
}
template <class T, std::size_t N>
inline vector<bool, N> not(const vector<T, N>& x)
{
return not(x, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] != y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return not_equal(x, y, std::make_index_sequence<N>{});
}
template <std::size_t N1, class T, std::size_t N0>
vector<T, N1> resize(const vector<T, N0>& v)
{
vector<T, N1> resized;
for (std::size_t i = 0; i < N1; ++i)
{
resized[i] = (i < N0) ? v[i] : T(0);
}
return resized;
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] - y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y)
{
return sub(x, y, std::make_index_sequence<N>{});
}
template <std::size_t... Indices, class T, std::size_t N>
inline vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v)
{
return { v[Indices]... };
}
/// @private
template <class T2, class T1, std::size_t N, std::size_t... I>
inline vector<T2, N> type_cast(const vector<T1, N>& v, std::index_sequence<I...>)
{
return {static_cast<T2>(v[I])...};
}
template <class T2, class T1, std::size_t N>
inline vector<T2, N> type_cast(const vector<T1, N>& v)
{
return type_cast<T2>(v, std::make_index_sequence<N>{});
}
/// @}
} // namespace math
#endif // ANTKEEPER_MATH_VECTOR_FUNCTIONS_HPP