#ifndef VECTEUR_HPP_INCLUDED
#define VECTEUR_HPP_INCLUDED
#include <cmath>
#include <initializer_list>
#include <string>
#include <regex>
#include <sstream>
#include <cstdlib>
#include <functional>
/**@class vecteur
*A class for mathematical vectors (both 2D and 3D)
*
*@author Voltra
*/
class vecteur{
private:
bool isTab(const std::string& str) const{
std::regex tabs("^(\\t)*$");
std::smatch matcher;
return std::regex_match(str, matcher, tabs);
}
template <class T>
std::string __stringstreamStringify(const T& arg) const{
std::stringstream ss;
ss << arg;
return ss.str();
}
public:
/***@@@CLASSattributes@@@***/
/*vecteur::PI*/
// constexpr static double PI = 3.141592653589793;
/**Custom value of PI for advanced calculations
*/
constexpr static double PI = 3.141592653589793238462643383279502884197169399375;
/*vecteur::angleUnit*/
/*vecteur::angleUnit::deg*/
/**@enum angleUnit
*Enum for angle units
*
*@brief enum for angle units
*/
enum class angleUnit{
/**unit to get values as degrees**/
deg = 1 << 0,
/**unit to get values as radians**/
rad = 1 << 1
};
/*vecteur::mode*/
/*vecteur::mode::origin*/
/**@enum mode
*Enum for the vecteur's mode
*
*@brief enum for the vecteur's mode
*@warning @ref mode::origin \> @ref mode::xyz \> @ref mode::xy \> @ref mode::xz \> @ref mode::yz \> @ref mode::undefined
*/
enum class mode{
/**designates {0,0,0}**/
origin = 1 << 0,
/**designates {x,y,0}**/
xy = 1 << 1,
/**designates {0,y,z}**/
yz = 1 << 2,
/**designates {x,0,z}**/
xz = 1 << 3,
/**designates {x,y,z}**/
xyz = 1 << 4,
/**designates errors/undefined behaviors**/
undefined = 1 << 5
};
/***@@@CLASSmethods@@@***/
/**Radian to Degree conversion
*@brief rad to deg
*/
static double radian2degree(const double& x)/* const*/{
return x*( (double)(180 / vecteur::PI) );
}
/**Degree to Radian conversion
*@brief deg to rad
*/
static double degree2radian(const double& x)/* const*/{
return x*( (double)(vecteur::PI / 180) );
}
/***@@@ATTRIBUTES@@@***/
/**The X-component of the vecteur**/
double x;
/**The Y-component of the vecteur**/
double y;
/**The Z-component of the vecteur**/
double z;
/***@@@CONSTRUCTORS@@@***/
/**Default constructor
*@param a being the x-component (default: 0)
*@param b being the y-component (default: 0)
*@param c being the z-component (default: 0)
*
*@brief default constructor
*/
vecteur(double a=0, double b=0, double c=0) : x(a),y(b),z(c){}
/**Copy constructor
*@param v being the vecteur to copy
*
*@brief copy constructor
*/
vecteur(const vecteur& v){
this->x = v.x;
this->y = v.y;
this->z = v.z;
}
/**Assignment operator : @ref vecteur
*@param v being the @ref vecteur to copy
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief assignment operator (from a @ref vecteur)
*/
vecteur& operator=(const vecteur& v){
this->x = v.x;
this->y = v.y;
this->z = v.z;
return (*this);
}
/**Assignment operator : initiliazer list {}
*@param init_list being the initializer list
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief assignment operator (from an initializer list)
*/
vecteur& operator=(const std::initializer_list<double>& init_list){
(*this) = vecteur(init_list);
return (*this);
}
/**Initializer list {} constructor
*@param init_list being the initializer list
*
*@warning if init_list.length == 1, then it'll set the value for x
*@warning if init_list.length == 2, then it'll set the value for x and y
*@warning if init_list.length==3 then it will set the values for x, y and z
*@warning else {0, 0, 0}
*
*@brief constructor from initializer list
*/
vecteur(const std::initializer_list<double>& init_list){
switch(init_list.size()){
case 1:
this->x = *( init_list.begin() );
this->y=0;
this->z=0;
break;
case 2:
this->x = *( init_list.begin() );
this->y = *( init_list.begin()+1 );
this->z = 0;
break;
case 3:
this->x = *( init_list.begin() );
this->y = *( init_list.begin()+1 );
this->z = *( init_list.begin()+2 );
break;
default:
(*this) = vecteur(0,0,0);
break;
}
}
/***@@@DESTRUCTORS@@@***/
/**Default destructor
*
*@brief default destructor
*/
~vecteur() = default;
/***@@@CALCULUSESoperators@@@***/
/**operator+ (binary) : Addition of vecteurs
*@param other being the second operand of the addition (this being the first operand)
*@return a vecteur being this+other
*
*@brief addition of @ref vecteur
*/
vecteur operator+(const vecteur& other) const{
return vecteur(x+other.x, y+other.y, z+other.z);
}
/**operator- (binary) : Subtraction of vecteurs
*@param other being the second operand of the subtraction (this being the first operand)
*@return a vecteur being this-other
*
*@brief subtraction of @ref vecteur
*/
vecteur operator-(const vecteur& other) const{
return vecteur(x-other.x, y-other.y, z-other.z);
}
/**operator* (binary) : Scaling
*@param scale_factor being the scaling factor
*@return a scaled vecteur being scale_factor*this
*
*@brief scaling of @ref vecteur
*/
vecteur operator*(const double& scale_factor) const{
return vecteur(x*scale_factor, y*scale_factor, z*scale_factor);
}
/**operator- (unary) :
*@return the opposite of the current @ref vecteur
*
*@brief opposite of a @ref vecteur
*/
vecteur operator-() const{
return (*this) * -1;
}
/**operator+= : self addition
*@param other being the other @ref vecteur
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief add to a @ref vecteur
*/
vecteur& operator+=(const vecteur& other){
(*this) = (*this) + other;
return (*this);
}
/**operator-= : self subtraction
*@param other being the other @ref vecteur
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief subtract from a @ref vecteur
*/
vecteur& operator-=(const vecteur& other){
(*this) = (*this) - other;
return (*this);
}
/**operator*= : self scaling
*@param scale_factor being the scaling factor
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief scaling of a @ref vecteur
*/
vecteur& operator*=(const double& scale_factor){
(*this) = (*this) * scale_factor;
return (*this);
}
/***@@@COMPARISONoperators@@@***/
/**operator== : Test if two vecteurs are equivalent
*@param other being the other @ref vecteur
*@return TRUE if equivalent, FALSE otherwise
*
*@brief equivalence check
*/
bool operator==(const vecteur& other) const{
if(this == &other)
return true;
return x==other.x && y==other.y && z==other.z;
}
/**operator!= : Test if two vecteurs are not equivalent
*@param other being the other @ref vecteur
*@return TRUE if not equivalent, FALSE otherwise
*
*@brief non equivalence check
*/
bool operator!=(const vecteur& other) const{
return !( this->operator==(other) );
}
/**operator< : Determines whether the @ref vecteur is closer to the origin (0,0,0) than the other
*@param other being the other @ref vecteur
*@return TRUE if this is closer than other, FALSE otherwise
*/
bool operator<(const vecteur& other) const{
return this->norm() < other.norm();
}
/**operator<= : Determines whether the @ref vecteur is closer to or at the same distance from the origin
*@param other being the other @ref vecteur
*@return TRUE if closer or same distance, FALSE otherwise
*/
bool operator<=(const vecteur& other) const{
return (*this) < other || (*this) == other;
}
/**operator> : Determines whether the @ref vecteur is further away from the origin
*@param other being the other @ref vecteur
*@return TRUE if further away, FALSE otherwise
*/
bool operator>(const vecteur& other) const{
return this->norm() > other.norm();
}
/**operator>= : Determines whether the @ref vecteur is further away from or at the same distance from the origin
*@param other being the other @ref vecteur
*@return TRUE if further away or same distance, FALSE otherwise
*/
bool operator>=(const vecteur& other) const{
return (*this) > other || (*this) == other;
}
/***@@@OPERATIONS@@@***/
/**Addition of vecteurs
*@param other being the second operand of the addition
*@return a @ref vecteur being this+other
*
*@brief addition of @ref vecteur
*/
vecteur plus(const vecteur& other) const{
return (*this) + other;
}
/**Subtraction of vecteurs
*@param other being the second operand of the subtraction
*@return a @ref vecteur being this-other
*
*@brief subtraction of @ref vecteur
*/
vecteur minus(const vecteur& other) const{
return (*this) - other;
}
/**Scaling
*@param scale_factor being the scaling factor
*@return a @ref vecteur being this*scale_factor
*
*@brief scale of @ref vecteur
*/
vecteur times(const double& scale_factor) const{
return (*this) * scale_factor;
}
/**Opposite of a @ref vecteur
*@return a @ref vecteur being -1*this
*
*@brief opposite of a @ref vecteur
*/
vecteur opposite() const{
return -(*this);
}
/**Self addition
*@param other being the @ref vecteur to add
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief add to a @ref vecteur
*/
vecteur& add(const vecteur& other){
(*this) += other;
return (*this);
}
/**Self subtraction
*@param other being the vecteur to subtract
*@return a reference to the current vecteur (allows chaining)
*
*@brief subtract from a @ref vecteur
*/
vecteur& sub(const vecteur& other){
(*this) -= other;
return (*this);
}
/**Self scaling
*@param scale_factor being the scaling factor
*@return a reference to the current @ref vecteur (allows chaining)
*
*@brief scale a @ref vecteur
*/
vecteur& scale(const double& scale_factor){
(*this) *= scale_factor;
return (*this);
}
/**Equivalence test
*@param other being the other @ref vecteur
*@return TRUE if equivalent, FALSE otherwise
*
*@brief equivalence test
*/
bool equals(const vecteur& other) const{
return (*this) == other;
}
/***@@@METHODS@@@***/
//@{
/**Calculation of the norm of the @ref vecteur
*@return the norm of the @ref vecteur as a double
*
*@brief norm calculation
*/
double norm() const{
return std::abs( std::sqrt(x*x + y*y + z*z) );
}
double norme() const{
return this->norm();
}
//@}
//@{
/**Determines whether the @ref vecteur is the @ref mode::origin or not
*@return TRUE if origin, FALSE otherwise
*
*@brief test if is the origin
*/
bool isOrigin() const{
return this->equals(vecteur(0,0,0));
}
bool isZero() const{
return this->isOrigin();
}
//@}
/**Determines whether the @ref vecteur is 2D or not
*@return TRUE if 2D, FALSE otherwise
*
*@warning the origin is 2D
*
*@brief test to know if 2D
*/
bool is2D() const{
return isOrigin() || x==0 || y==0 || z==0;
}
/**Determines whether the @ref vecteur is 3D or not
*@return TRUE if 3D, FALSE otherwise
*
*@warning the origin is 3D
*
*@brief test to know if 3D
*/
bool is3D() const{
return isOrigin() || !is2D();
}
//@{
/**Calculation of the scalar product
*@param other being the other @ref vecteur
*@return the scalar product between this and other as a double
*
*@brief calculation of the scalar product
*/
double scal_prod(const vecteur& other) const{
return x*other.x + y*other.y + z*other.z;
}
double prod_scal(const vecteur& other) const{
return this->scal_prod(other);
}
//@}
//@{
/**Determines whether two vecteurs are collinear or not
*@param other being the other @ref vecteur
*@return TRUE if collinear, FALSE otherwise
*
*@brief test if collinear
*/
bool collinear(const vecteur& other) const{
if( (is2D() && other.is2D()) || (is3D() && other.is3D()) ){
double b1b1 = this->scal_prod((*this));
double b1b2 = this->scal_prod(other);
double b2b2 = other.scal_prod(other);
if(b1b1!=0 && b2b2!=0)
if(b1b1*b2b2 == b1b2*b1b2)
return true;
}
return false;
}
bool isCollinearTo(const vecteur& other) const{
return this->collinear(other);
}
//@}
//@{
/**Determines whether two vecteurs are orthogonal
*@param other being the other @ref vecteur
*@return TRUE if orthogonal, FALSE otherwise
*
*@brief test if orthogonal
*/
bool orthogonal(const vecteur& other) const{
return prod_scal(other)==0.000;
}
bool isOrthogonalTo(const vecteur& other) const{
return this->isOrthogonalTo(other);
}
//@}
/**Calculation of the angle between two vecteurs
*@param other being the other @ref vecteur
*@param angleMode being the desired unit for the result (use the enum @ref vecteur::angleUnit)
(default: @ref angleUnit::deg)
*@return -404 if error, the angle as a double (unit corresponding to the @ref angleUnit)
*
*@brief angle between two vecteurs
*/
double angleFrom(const vecteur& other, const vecteur::angleUnit& angleMode = vecteur::angleUnit::deg) const{
if(is2D() && other.is2D()){
double a = this->norm();
double b = other.norm();
double ps = this->scal_prod(other);
double ab = a * b;
double res = std::acos(ps/ab);
/**@warning std::acos returns an angle as a radian, might need conversion**/
switch(angleMode){
case vecteur::angleUnit::deg :
return vecteur::radian2degree(res);
case vecteur::angleUnit::rad :
return res;
default:
return -404;
}
}
return -404.00;
}
//@{
/**Calculations of the vectorial product between two vecteurs
*@param other being the other @ref vecteur
*@return the vectorial product as a @ref vecteur
*
*@brief calculation of the vectorial product
*/
vecteur vect_prod(const vecteur& other) const{
double a,b,c;
/*
//a stands for the x-component
//b stands for the y-component
//c stands for the z-component
*/
c = (x * other.y) - (y * other.x);
a = (y * other.z) - (z * other.y);
b = (z * other.x) - (x * other.z);
return vecteur(a, b, c);
}
vecteur prod_vect(const vecteur& other) const{
return this->vect_prod(other);
}
//@}
/**Mode getter
*@return the current mode of the @ref vecteur
*
*@warning @ref mode::origin \> @ref mode::xyz \> @ref mode::xy \> @ref mode::xz \> @ref mode::yz \> @ref mode::undefined
*
*@brief get the @ref vecteur's mode
**/
vecteur::mode getMode() const{
if(isOrigin())
return vecteur::mode::origin;
if(is3D())
return vecteur::mode::xyz;
if(is2D()){
if(z==0)
return vecteur::mode::xy;
if(y==0)
return vecteur::mode::xz;
if(x==0)
return vecteur::mode::yz;
}
return vecteur::mode::undefined;
}
/**String representation of the @ref vecteur's current @ref mode
*@return a string representing the @ref vecteur's current @ref mode
*
*@brief get the @ref vecteur's mode as a string
*/
std::string getModeString() const{
vecteur::mode vm = this->getMode();
switch(vm){
case vecteur::mode::origin :
return "origin";
case vecteur::mode::xyz :
return "xyz";
case vecteur::mode::xy :
return "xy";
case vecteur::mode::xz :
return "xz";
case vecteur::mode::yz :
return "yz";
case vecteur::mode::undefined :
return "undefined";
default:
return "undefined";
}
}
/***@@@DEBUG@@@***/
/**Quick way of displaying info regarding a @ref vecteur
*@brief shorthand debug
*/
void debugDisplay() const{
std::cout << "<VECTEUR>" << '\n';
std::cout << '\t' << "x: " << x << '\n';
std::cout << '\t' << "y: " << y << '\n';
std::cout << '\t' << "z: " << z << '\n';
std::cout << "</VECTEUR>" << '\n';
}
/**Display all the informations regarding a @ref vecteur
*@param tab being a string made of tabulation characters only (tabulation level for display)
*
*@brief complete debug
*/
void disp(const std::string& tab = "") const{
std::cout << this->stringify(tab);
}
/**Creation of a string representation of the @ref vecteur
*@param tabu being a string made of tabulation characters only (tabulation level for display)
*@return a string representation of the @ref vecteur
*
*@brief stringifier
*/
std::string stringify(const std::string& tabu = "") const{
std::string tab = isTab(tabu) ? tabu : "";
std::string ret = "";
ret += tab + "<VECTEUR>" + '\n';
ret += (x!=0) ? tab + '\t' + "x: " + __stringstreamStringify(x) + '\n' : "";
ret += (y!=0) ? tab + '\t' + "y: " + __stringstreamStringify(y) + '\n' : "";
ret += (z!=0) ? tab + '\t' + "z: " + __stringstreamStringify(z) + '\n' : "";
ret += tab + '\t' + "mode: " + getModeString() + '\n';
ret += tab + '\t' + "norm: " + __stringstreamStringify(this->norm()) + " unit(s)" + '\n';
ret += tab + "</VECTEUR>" + '\n' +'\n';
return ret;
}
/**hashCode to string (std::string)
*@return a string representation of the @ref vecteur's hashcode
*
*@brief hashcode as a string
*/
std::string hashCodeString() const{
return __stringstreamStringify(this->hashCode());
}
/**hashCode calculation
*@return the @ref vecteur's hashcode as an integer
*
*@brief hashcode calculation
*/
int hashCode() const{
const int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
result = prime * result + z;
result = prime * result + (int)getMode();
result = prime * result + (int)norm();
char* ender;
result = prime * result + std::strtol(__stringstreamStringify(this).c_str(), &ender, 10);
return result;
}
};
#endif // VECTEUR_HPP_INCLUDED
A class that allows handling 2D and 3D vectors (mathematical ones) in a fancy c++ code style.
Easy to use, many calculation methods including the vectorial product and the calculus of the angle between two vectors.
( https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics)
EDITS:
#3 : Corrected typos, replaced PI with a better PI (lmao)
#4 : Few fixes + ready fo doxygen
Easy to use, many calculation methods including the vectorial product and the calculus of the angle between two vectors.
( https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics)
EDITS:
#3 : Corrected typos, replaced PI with a better PI (lmao)
#4 : Few fixes + ready fo doxygen
Be the first to comment
You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.