Last active
March 21, 2019 09:49
-
-
Save 0V/e928bd6368dddfa8f0e1e23c258934d5 to your computer and use it in GitHub Desktop.
template 3d vector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef RAYTRACER_VECTOR3D_ | |
#define RAYTRACER_VECTOR3D_ | |
#include <cstddef> | |
#include <cmath> | |
template <typename T> | |
class Vector3d | |
{ | |
private: | |
T X; | |
T Y; | |
T Z; | |
public: | |
//! Sets all members to zero | |
Vector3d(); | |
//! Explicitly converts from one type to another | |
template <typename R> | |
explicit Vector3d(const Vector3d<R> &other); | |
Vector3d(const T &x, const T &y, const T &z); | |
Vector3d(const T coords[3]); | |
// Get-Set methods | |
const T &getX() const; | |
void setX(const T &newX); | |
const T &getY() const; | |
void setY(const T &newY); | |
const T &getZ() const; | |
void setZ(const T &newZ); | |
void getv(T buffer[3]) const; | |
void setv(const T coords[3]); | |
void get(T &x, T &y, T &z) const; | |
void set(const T &x, const T &y, const T &z); | |
// Interface for indexing | |
const T &operator[](size_t index) const; | |
T &operator[](size_t index); | |
//! Considering vectors as matrices with one row | |
const T &operator()(size_t column) const; | |
T &operator()(size_t column); | |
// Standard operations | |
//! This does absolutely nothing, but it should be included for consistency | |
const Vector3d operator+() const; | |
const Vector3d operator+(const Vector3d &other) const; | |
Vector3d &operator+=(const Vector3d &other); | |
//! The same as multiplying *this by -1 | |
const Vector3d operator-() const; | |
const Vector3d operator-(const Vector3d &other) const; | |
Vector3d &operator-=(const Vector3d &other); | |
//! Multiplying *this by a scalar | |
const Vector3d operator*(const T &scalar) const; | |
Vector3d &operator*=(const T &scalar); | |
//! Same as multiplication by 1/scalar, maybe more accurate but also slower | |
const Vector3d operator/(const T &scalar) const; | |
Vector3d &operator/=(const T &scalar); | |
//! Calculate the dot/inner/scalar product | |
const T operator*(const Vector3d &other) const; | |
//! Calculate the cross/outer/vector product | |
const Vector3d operator%(const Vector3d &other) const; | |
Vector3d &operator%=(const Vector3d &other); | |
// Auxiliary methods | |
//! Returns the squared length of *this | |
const T getSqrLen() const; | |
//! Returns the length of *this | |
const T getLen() const; | |
//! Returns a vector with the same orientation, but with a length of 1 | |
const Vector3d getUnit() const; | |
//! Returns cross product | |
const Vector3d cross(const Vector3d &other) const; | |
//! Returns dot product | |
const T dot(const Vector3d &other) const; | |
//! Interpolates *this between another vector, by a ratio | |
const Vector3d getInterpolation(const Vector3d &other, const T &ratio) const; | |
//! Reflects *this according to a surface's normal | |
const Vector3d getReflection(const Vector3d &surfaceNormal) const; | |
//! Rotates *this about an origin, using Euler angles( X=pitch, Y=yaw, Z=roll) | |
const Vector3d getRotationEuler(const Vector3d &angles, | |
const Vector3d &origin = Vector3d(), bool degs = true, bool ccw = true) const; | |
//! Rotates *this about an origin, using an arbitrary axis( axis should be a unit vector ) | |
const Vector3d getRotationArbAxis(const Vector3d &axis, const T &amount, | |
const Vector3d &origin = Vector3d(), bool degs = true, bool ccw = true) const; | |
}; | |
template <typename T> | |
inline Vector3d<T>::Vector3d() | |
: X(0), Y(0), Z(0) | |
{ | |
} | |
template <typename T> | |
template <typename R> | |
inline Vector3d<T>::Vector3d(const Vector3d<R> &other) | |
: X(other.X), Y(other.Y), Z(other.Z) | |
{ | |
} | |
template <typename T> | |
inline Vector3d<T>::Vector3d(const T &x, const T &y, const T &z) | |
: X(x), Y(y), Z(z) | |
{ | |
} | |
template <typename T> | |
inline Vector3d<T>::Vector3d(const T coords[3]) | |
: X(coords[0]), Y(coords[1]), Z(coords[2]) | |
{ | |
} | |
template <typename T> | |
inline const T &Vector3d<T>::getX() const | |
{ | |
return X; | |
} | |
template <typename T> | |
inline void Vector3d<T>::setX(const T &newX) | |
{ | |
X = newX; | |
} | |
template <typename T> | |
inline const T &Vector3d<T>::getY() const | |
{ | |
return Y; | |
} | |
template <typename T> | |
inline void Vector3d<T>::setY(const T &newY) | |
{ | |
Y = newY; | |
} | |
template <typename T> | |
inline const T &Vector3d<T>::getZ() const | |
{ | |
return Z; | |
} | |
template <typename T> | |
inline void Vector3d<T>::setZ(const T &newZ) | |
{ | |
Z = newZ; | |
} | |
template <typename T> | |
inline void Vector3d<T>::getv(T buffer[3]) const | |
{ | |
buffer[0] = X; | |
buffer[1] = Y; | |
buffer[2] = Z; | |
} | |
template <typename T> | |
inline void Vector3d<T>::setv(const T coords[3]) | |
{ | |
X = coords[0]; | |
Y = coords[1]; | |
Z = coords[2]; | |
} | |
template <typename T> | |
inline void Vector3d<T>::get(T &x, T &y, T &z) const | |
{ | |
x = X; | |
y = Y; | |
z = Z; | |
} | |
template <typename T> | |
inline void Vector3d<T>::set(const T &x, const T &y, const T &z) | |
{ | |
X = x; | |
Y = y; | |
Z = z; | |
} | |
template <typename T> | |
inline const T &Vector3d<T>::operator[](size_t index) const | |
{ | |
switch (index) | |
{ | |
case 0: | |
return X; | |
case 1: | |
return Y; | |
case 2: | |
return Z; | |
} | |
return T(); | |
} | |
template <typename T> | |
inline T &Vector3d<T>::operator[](size_t index) | |
{ | |
switch (index) | |
{ | |
case 0: | |
return X; | |
case 1: | |
return Y; | |
case 2: | |
return Z; | |
} | |
return T(); | |
} | |
template <typename T> | |
inline const T &Vector3d<T>::operator()(size_t column) const | |
{ | |
switch (column) | |
{ | |
case 1: | |
return X; | |
case 2: | |
return Y; | |
case 3: | |
return Z; | |
} | |
return T(); | |
} | |
template <typename T> | |
inline T &Vector3d<T>::operator()(size_t column) | |
{ | |
switch (column) | |
{ | |
case 1: | |
return X; | |
case 2: | |
return Y; | |
case 3: | |
return Z; | |
} | |
return T(); | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator+() const | |
{ | |
return *this; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator+(const Vector3d &other) const | |
{ | |
return Vector3d(X + other.X, Y + other.Y, Z + other.Z); | |
} | |
template <typename T> | |
inline Vector3d<T> &Vector3d<T>::operator+=(const Vector3d &other) | |
{ | |
return *this = *this + other; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator-() const | |
{ | |
return Vector3d(-X, -Y, -Z); | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator-(const Vector3d &other) const | |
{ | |
return Vector3d(X - other.X, Y - other.Y, Z - other.Z); | |
} | |
template <typename T> | |
inline Vector3d<T> &Vector3d<T>::operator-=(const Vector3d &other) | |
{ | |
return *this = *this - other; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator*(const T &scalar) const | |
{ | |
return Vector3d(X * scalar, Y * scalar, Z * scalar); | |
} | |
template <typename T> | |
inline Vector3d<T> &Vector3d<T>::operator*=(const T &scalar) | |
{ | |
return *this = *this * scalar; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator/(const T &scalar) const | |
{ | |
return Vector3d(X / scalar, Y / scalar, Z / scalar); | |
} | |
template <typename T> | |
inline Vector3d<T> &Vector3d<T>::operator/=(const T &scalar) | |
{ | |
return *this = *this / scalar; | |
} | |
template <typename T> | |
inline const T Vector3d<T>::operator*(const Vector3d &other) const | |
{ | |
return X * other.X + Y * other.Y + Z * other.Z; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::operator%(const Vector3d &other) const | |
{ | |
return Vector3d(Y * other.Z - Z * other.Y, | |
Z * other.X - X * other.Z, | |
X * other.Y - Y * other.X); | |
} | |
template <typename T> | |
inline Vector3d<T> &Vector3d<T>::operator%=(const Vector3d &other) | |
{ | |
return *this = *this % other; | |
} | |
template <typename T> | |
inline const T Vector3d<T>::getSqrLen() const | |
{ | |
return X * X + Y * Y + Z * Z; | |
} | |
template <typename T> | |
inline const T Vector3d<T>::getLen() const | |
{ | |
return std::sqrt(getSqrLen()); | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::getUnit() const | |
{ | |
if (getSqrLen() != 0) | |
return *this / getLen(); | |
return *this; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::cross(const Vector3d &other) const | |
{ | |
return *this % other; | |
} | |
template <typename T> | |
inline const T Vector3d<T>::dot(const Vector3d &other) const | |
{ | |
return (*this) * other; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::getInterpolation(const Vector3d &other, const T &ratio) const | |
{ | |
return *this + (other - *this) * ratio; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>::getReflection(const Vector3d &surfaceNormal) const | |
{ | |
return *this - surfaceNormal * ((*this * surfaceNormal) * 2); | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>:: | |
getRotationEuler(const Vector3d &angles, const Vector3d &origin, bool degs, bool ccw) const | |
{ | |
T sin_phi, sin_theta, sin_psi; | |
T cos_phi, cos_theta, cos_psi; | |
if (degs) | |
{ | |
const T degToRad = T(M_PI) / 360; | |
sin_phi = std::sin(angles.getX() * degToRad); | |
sin_theta = std::sin(angles.getY() * degToRad); | |
sin_psi = std::sin(angles.getZ() * degToRad); | |
cos_phi = std::cos(angles.getX() * degToRad); | |
cos_theta = std::cos(angles.getY() * degToRad); | |
cos_psi = std::cos(angles.getZ() * degToRad); | |
} | |
else | |
{ | |
sin_phi = std::sin(angles.getX()); | |
sin_theta = std::sin(angles.getY()); | |
sin_psi = std::sin(angles.getZ()); | |
cos_phi = std::cos(angles.getX()); | |
cos_theta = std::cos(angles.getY()); | |
cos_psi = std::cos(angles.getZ()); | |
} | |
if (!ccw) | |
{ | |
sin_phi = -sin_phi; | |
sin_theta = -sin_theta; | |
sin_psi = -sin_psi; | |
} | |
Vector3d temp = *this - origin; | |
Vector3d result = temp; | |
result.setY(temp.getY() * cos_phi + temp.getZ() * sin_phi); | |
result.setZ(-temp.getY() * sin_phi + temp.getZ() * cos_phi); | |
temp = result; | |
result.setX(temp.getX() * cos_theta - temp.getZ() * sin_theta); | |
result.setZ(temp.getX() * sin_theta + temp.getZ() * cos_theta); | |
temp = result; | |
result.setX(temp.getX() * cos_psi + temp.getY() * sin_psi); | |
result.setY(-temp.getX() * sin_psi + temp.getY() * cos_psi); | |
return result + origin; | |
} | |
template <typename T> | |
inline const Vector3d<T> Vector3d<T>:: | |
getRotationArbAxis(const Vector3d &axis, const T &amount, const Vector3d &origin, bool degs, bool ccw) const | |
{ | |
T cos_theta, sin_theta; | |
if (degs) | |
{ | |
const T degToRad = T(M_PI) / 360; | |
cos_theta = std::cos(amount * degToRad); | |
sin_theta = std::sin(amount * degToRad); | |
} | |
else | |
{ | |
cos_theta = std::cos(amount); | |
sin_theta = std::sin(amount); | |
} | |
if (!ccw) | |
sin_theta = -sin_theta; | |
return *this * cos_theta + (axis % *this) * sin_theta + axis * ((axis * *this) * (1 - cos_theta)); | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef RAYTRACER_VECTOR_UTILITY_ | |
#define RAYTRACER_VECTOR_UTILITY_ | |
#include <iostream> | |
#include "vector3d.h" | |
using vec3 = Vector3d<double>; | |
template <typename Char, typename T> | |
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os, const Vector3d<T> &v) | |
{ | |
return os << Char('(') << v.getX() << Char(',') << v.getY() << Char(',') << v.getZ() << Char(')'); | |
} | |
#endif // RAYTRACER_VECTOR_UTILITY_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment