Program Listing for File vector3.hpp
↰ Return to documentation for file (rcppsw/math/vector3.hpp
)
#pragma once
/*******************************************************************************
* Includes
******************************************************************************/
#include <cmath>
#include <limits>
#include <string>
#include "rcppsw/math/radians.hpp"
#include "rcppsw/math/sphere_vector.hpp"
#include "rcppsw/math/vector2.hpp"
#include "rcppsw/rcppsw.hpp"
#include "rcppsw/types/discretize_ratio.hpp"
#include "rcppsw/er/stringizable.hpp"
/*******************************************************************************
* Namespaces/Decls
******************************************************************************/
namespace rcppsw::math {
/*******************************************************************************
* Class Definitions
******************************************************************************/
template <typename T>
class vector3 final : public rer::stringizable {
public:
using value_type = T;
struct key_compare {
template<typename U,
RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<U>::value)>
bool operator()(const vector3<U>& lhs, const vector3<U>& rhs) const {
/* Order based on X unless X's are equal, if so order on Y, etc. */
if (lhs.x() != rhs.x()) {
return lhs.x() < rhs.x();
}
if (lhs.y() != rhs.y()) {
return lhs.y() < rhs.y();
}
return lhs.z() < rhs.z();
}
template<typename U,
RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
bool operator()(const vector3<U>& lhs, const vector3<U>& rhs) const {
bool equal_x = std::fabs(lhs.x() - rhs.x()) <= kDOUBLE_EPSILON;
bool equal_y = std::fabs(lhs.y() - rhs.y()) <= kDOUBLE_EPSILON;
if (!equal_x) {
return lhs.x() < rhs.x();
}
if (!equal_y) {
return lhs.y() < rhs.y();
}
return lhs.z() < rhs.z();
}
};
struct componentwise_compare {
template <typename U>
bool operator()(const vector3<U>& lhs, const vector3<U>& rhs) const {
return lhs.x() <= rhs.x() && lhs.y() <= rhs.y() && lhs.z() <= rhs.z();
}
};
static constexpr size_t kDIMENSIONALITY = 3;
static const vector3<T> X; // NOLINT
static const vector3<T> Y; // NOLINT
static const vector3<T> Z; // NOLINT
vector3(void) noexcept = default;
constexpr vector3(const T& x, const T& y, const T& z)
: m_x(x), m_y(y), m_z(z) {}
explicit vector3(const vector2<T>& v) : vector3{v, T{0}} {}
vector3(const vector2<T>& v, const T& z) : vector3(v.x(), v.y(), z) {}
RCPPSW_NODISCARD T x(void) { return m_x; }
RCPPSW_NODISCARD T y(void) { return m_y; }
RCPPSW_NODISCARD T z(void) { return m_z; }
RCPPSW_NODISCARD const T& x(void) const { return m_x; }
RCPPSW_NODISCARD const T& y(void) const { return m_y; }
RCPPSW_NODISCARD const T& z(void) const { return m_z; }
void x(const T& x) { m_x = x; }
void y(const T& y) { m_y = y; }
void z(const T& z) { m_z = z; }
vector2<T> to_2D(void) const { return vector2<T>(x(), y()); }
void set(const T& x, const T& y, const T& z) {
m_x = x;
m_y = y;
m_z = z;
}
bool is_pd(void) const { return m_x > 0 && m_y > 0 && m_z > 0; }
bool is_psd(void) const { return m_x >= 0 && m_y >= 0 && m_z >= 0; }
RCPPSW_NODISCARD T square_length(void) const {
return (m_x * m_x) + (m_y * m_y) + (m_z * m_z);
}
RCPPSW_NODISCARD double length(void) const { return std::sqrt(square_length()); }
template <typename U = T,
RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
vector3& normalize(void) {
*this /= this->length();
return *this;
}
vector3 mask(const vector3& the_mask) const {
return vector3(m_x * the_mask.m_x, m_y * the_mask.m_y, m_z * the_mask.m_z);
}
radians xangle(void) const { return radians(std::atan2(m_z, m_y)); }
radians yangle(void) const { return radians(std::atan2(m_x, m_z)); }
radians zangle(void) const { return radians(std::atan2(m_y, m_x)); }
vector2<T> project_on_xy(void) const { return vector2<T>(m_x, m_y); }
vector2<T> project_on_yz(void) const { return vector2<T>(m_y, m_z); }
vector2<T> project_on_xz(void) const { return vector2<T>(m_x, m_z); }
template <typename U = T, RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
sphere_vector<T> to_spherical(void) const {
double radius = length();
return sphere_vector<T>(
radius, radians(std::acos(m_z / radius)), radians(std::atan2(m_y, m_x)));
}
vector3& scale(const T& scale_x, const T& scale_y, const T& scale_z) {
m_x *= scale_x;
m_y *= scale_y;
m_z *= scale_z;
return *this;
}
vector3& scale(const T& factor) { return scale(factor, factor, factor); }
/* Relational operators */
template <typename U = T, RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<U>::value)>
bool operator==(const vector3& other) const {
return (m_x == other.m_x && m_y == other.m_y && m_z == other.m_z);
}
template <typename U = T, RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
bool operator==(const vector3& other) const {
return (std::fabs(x() - other.x()) <= kDOUBLE_EPSILON) &&
(std::fabs(y() - other.y()) <= kDOUBLE_EPSILON) &&
(std::fabs(z() - other.z()) <= kDOUBLE_EPSILON);
}
template <typename U = T, RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<U>::value)>
bool operator>(const vector3& other) const {
return (m_x > other.m_x) || ((m_x == other.m_x) && (m_y > other.m_y)) ||
((m_x == other.m_x) && (m_y == other.m_y) && (m_z > other.m_z));
}
template <typename U = T, RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
bool operator>(const vector3& other) const {
bool equal_x = std::fabs(m_x - other.m_x) <= kDOUBLE_EPSILON;
bool equal_y = std::fabs(m_y - other.m_y) <= kDOUBLE_EPSILON;
return (m_x > other.m_x) || (equal_x && (m_y > other.m_y)) ||
(equal_x && equal_y && (m_z > other.m_z));
}
bool operator!=(const vector3& other) const { return !(*this == other); }
/* modifier operators */
vector3& operator+=(const vector3& other) {
m_x += other.m_x;
m_y += other.m_y;
m_z += other.m_z;
return *this;
}
vector3& operator-=(const vector3& other) {
m_x -= other.m_x;
m_y -= other.m_y;
m_z -= other.m_z;
return *this;
}
vector3& operator*=(const T& val) {
m_x *= val;
m_y *= val;
m_z *= val;
return *this;
}
vector3& operator/=(const T& val) {
m_x /= val;
m_y /= val;
m_z /= val;
return *this;
}
vector3 operator+(const vector3& other) const {
vector3 res(*this);
res += other;
return res;
}
vector3<T> operator-(const vector3& other) const {
vector3<T> res(*this);
res -= other;
return res;
}
vector3 operator*(const T& val) const {
vector3 res(*this);
res *= val;
return res;
}
vector3 operator/(const T& val) const {
vector3 res(*this);
res /= val;
return res;
}
vector3 operator-(void) const { return vector3(-m_x, -m_y, -m_z); }
friend std::ostream& operator<<(std::ostream& stream, const vector3& v) {
stream << v.to_str();
return stream;
}
friend std::istream& operator>>(std::istream& is, vector3<T>& v) {
T values[3] = { T(), T(), T() };
utils::parse_values<T>(is, 3, values, ',');
v.set(values[0], values[1], values[2]);
return is;
}
std::string to_str(void) const override {
return "(" + rcppsw::to_string(m_x) + "," + rcppsw::to_string(m_y) + "," +
rcppsw::to_string(m_z) + ")";
}
private:
/* clang-format off */
T m_x{0};
T m_y{0};
T m_z{0};
/* clang-format on */
};
/*******************************************************************************
* Template Specializations
******************************************************************************/
using vector3i = vector3<int>;
using vector3z = vector3<size_t>;
using vector3d = vector3<double>;
template<> const vector3i vector3i::X;
template<> const vector3i vector3i::Y;
template<> const vector3i vector3i::Z;
template<> const vector3z vector3z::X;
template<> const vector3z vector3z::Y;
template<> const vector3z vector3z::Z;
template<> const vector3d vector3d::X;
template<> const vector3d vector3d::Y;
template<> const vector3d vector3d::Z;
/*******************************************************************************
* Macros
******************************************************************************/
#define RCPPSW_MATH_VEC3_DIRECT_CONV2FLT(prefix) \
static inline vector3d prefix##vec2dvec(const vector3##prefix& other) { \
return vector3d(other.x(), other.y(), other.z()); \
}
#define RCPPSW_MATH_VEC3_SCALED_CONV2FLT(prefix) \
static inline vector3d prefix##vec2dvec(const vector3##prefix& other, \
double scale) { \
return vector3d(other.x() * scale, other.y() * scale, other.z() * scale); \
}
#define RCPPSW_MATH_VEC3_CONV2DISC(dest_prefix, dest_type) \
static inline vector3##dest_prefix dvec2##dest_prefix##vec( \
const vector3d& other, double scale) { \
return vector3##dest_prefix(static_cast<dest_type>(other.x() / scale), \
static_cast<dest_type>(other.y() / scale), \
static_cast<dest_type>(other.z() / scale)); \
}
/*******************************************************************************
* Conversion Functions
******************************************************************************/
RCPPSW_MATH_VEC3_DIRECT_CONV2FLT(i);
RCPPSW_MATH_VEC3_DIRECT_CONV2FLT(z);
RCPPSW_MATH_VEC3_SCALED_CONV2FLT(i);
RCPPSW_MATH_VEC3_SCALED_CONV2FLT(z);
RCPPSW_MATH_VEC3_CONV2DISC(z, size_t);
RCPPSW_MATH_VEC3_CONV2DISC(i, int);
/*******************************************************************************
* Free Functions
******************************************************************************/
template<typename U,
typename V,
RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<U>::value),
RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<V>::value)>
static inline size_t l1norm(const vector3<U>& v1, const vector3<V>& v2) {
return std::abs(static_cast<int>(v1.x() - v2.x())) +
std::abs(static_cast<int>(v1.y() - v2.y())) +
std::abs(static_cast<int>(v1.z() - v2.z()));
}
} /* namespace rcppsw::math */