Mathematical Vector (V2) (can do 2D and 3D)

#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

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.