/*
|
|
* Copyright (C) 2021 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
|
|
|