daily pastebin goal
1%
SHARE
TWEET

Vector_.h

mvaganov Jan 17th, 2015 (edited) 271 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2. /*
  3. math vector classes for 2, 3, and 4 dimensions, using some clever inheritance and C++11 features
  4. author: mvaganov@hotmail.com
  5. license: MIT (http://opensource.org/licenses/MIT). TL;DR - this is free software, I won't fix it for you!
  6. */
  7.  
  8. #define _USE_MATH_DEFINES
  9. #include <math.h>
  10.  
  11. // if compiling with a C++11 compiler, enable vardic templates and initializer lists
  12. #if _MSC_VER >= 1800 || __cplusplus >= 199711L
  13.         #define __INITIALIZER_LIST_SUPPORTED
  14. //      #define __VARDIC_ARGUMENTS_SUPPORTED
  15.         #include <initializer_list>
  16. #endif
  17.  
  18. /** multi-dimensional position structures */
  19. template<typename Scalar_t>
  20. struct _Dimensional {
  21.         typedef Scalar_t Scalar;
  22.         Scalar * v() { return (Scalar*)this; }
  23.         const Scalar * v() const { return (Scalar*)this; }
  24. };
  25.  
  26. template<typename Scalar_t>
  27. struct _2D : public _Dimensional<Scalar_t> {
  28.         Scalar x, y;
  29.         static const int DIMENSIONS = 2;
  30.  
  31.         _2D<Scalar>() : x(0), y(0) {}
  32.         _2D<Scalar>(const Scalar x, const Scalar y) : x(x), y(y) {}
  33.  
  34.         /** construct a vector that is orthogonal (perpendicular) to the given vector. Replaced by CrossProduct in 3 Dimensions. */
  35.        
  36.         /** @return a perpendicular vector */
  37.         _2D<Scalar> Orthogonal() const { return _2D(-y, x); }
  38.         _2D<Scalar> Perp() const { return Orthogonal(); }
  39.         /** @return turns this vector into it's perpendicular vector */
  40.         _2D<Scalar> SetPerp() { Scalar temp = x; x = -y; y = temp; return *this; }
  41. };
  42.  
  43. template<typename Scalar_t>
  44. struct _3D : public  _Dimensional<Scalar_t> {
  45.         Scalar x, y, z;
  46.         static const int DIMENSIONS = 3;
  47.  
  48.         _3D() : x(0), y(0), z(0) {}
  49.         _3D(const Scalar x, const Scalar y, const Scalar z) : x(x), y(y), z(z) {}
  50.  
  51.         /** Cross Product doesn't make sense in 2D space. In 4D+ space, many vectors can be perpendicular to a pair of Vectors. */
  52.         _3D Cross(const _3D& other) const {
  53.                 return _3D(
  54.                         y * other.z - other.y * z,
  55.                         z * other.x - other.z * x,
  56.                         x * other.y - other.x * y);
  57.         }
  58.         //_3D operator % (const _3D& other) const { return Cross(other); }
  59.  
  60.         _2D & AsVector2D()             { return *((_2D*)this); }
  61.         const _2D & AsVector2D() const { return *((_2D*)this); }
  62. };
  63.  
  64. template<typename Scalar_t>
  65. struct _4D : public  _Dimensional<Scalar_t> {
  66.         Scalar x, y, z, w;
  67.         static const int DIMENSIONS = 4;
  68.  
  69.         _4D() : x(0), y(0), z(0),w(0) {}
  70.         _4D(const Scalar x, const Scalar y, const Scalar z, const Scalar w) : x(x), y(y), z(z), w(w) {}
  71.  
  72.         _3D & AsVector3D()             { return *((_3D*)this); }
  73.         const _3D & AsVector3D() const { return *((_3D*)this); }
  74.         _2D & AsVector2D()             { return *((_2D*)this); }
  75.         const _2D & AsVector2D() const { return *((_2D*)this); }
  76. };
  77.  
  78. #define VEC Vector_<D>
  79.  
  80. /**
  81. * describes a general Vector, with DIMENSIONS number of dimensions.
  82. * @template D determines what kind of Vector this is (2D, 3D, or 4D), including the scalar data type. Must inherit _Dimensional
  83. */
  84. template <typename D>
  85. struct Vector_ : public D
  86. {
  87.         /** reference the scalar type from the base dimensions structure. without this, Scalar cannot be used in method signatures. */
  88.         typedef typename D::Scalar Scalar;
  89.  
  90.         void SetZero(const int startIndex) { for (int i = startIndex; i < DIMENSIONS; i++) v()[i] = 0; }
  91.         void SetZero() { SetZero(0); }
  92.  
  93.         /** templated copy function. will work on any type that inherits from _Dimensional */
  94.         template<typename OtherVectorType> void Copy(const OtherVectorType& other) {
  95.                 static_assert(OtherVectorType::DIMENSIONS, "explicit copy for vector being done with non-vector, somewhere");
  96.                 for (int i = 0; i < DIMENSIONS; ++i) {
  97.                         v()[i] = (D::Scalar)(other.v()[i]);
  98.                 }
  99.                 SetZero(DIMENSIONS); // set unset values to zero
  100.         }
  101.         /** assignment operator */
  102.         template<typename OtherVectorType> VEC& operator=(const OtherVectorType& other) {
  103.                 static_assert(OtherVectorType::DIMENSIONS, "vector being assigned to non-vector, somewhere");
  104.                 Copy(other); return *this;
  105.         }
  106.         /** single-parameter (copy) constructor. Made explicit to reduce confusion, especially for automatic type conversion for functions */
  107.         template<typename OtherVectorType> explicit Vector_(const OtherVectorType& other) {
  108.                 static_assert(OtherVectorType::DIMENSIONS, "non-vector passed into single-parameter constructor, somewhere");
  109.                 Copy<OtherVectorType>(other);
  110.         }
  111.  
  112.         /** initialize with an array */
  113.         Vector_(Scalar * element) {
  114.                 for (int i = 0; i < DIMENSIONS; i++) v()[i] = element[i];
  115.         }
  116.  
  117.         Vector_(const D& _d) { *this = _d; }
  118. #ifndef __VARDIC_ARGUMENTS_SUPPORTED
  119.         Vector_() { SetZero(); } // explicit default constructor, allows static
  120.  
  121.         Vector_(Scalar x, Scalar y) { Set(x, y); }
  122.         Vector_(Scalar x, Scalar y, Scalar z) { Set(x, y, z); }
  123.         Vector_(Scalar x, Scalar y, Scalar z, Scalar w) { Set(x, y, z, w); }
  124.  
  125.         void Set(const Scalar x, const Scalar y)                    { SetZero(2); v()[0] = x; v()[1] = y; }
  126.         void Set(const Scalar x, const Scalar y, const Scalar z)    { SetZero(3); v()[0] = x; v()[1] = y; v()[2] = z; }
  127.         void Set(const Scalar x, const Scalar y, const Scalar z, const Scalar w) { SetZero(4); v()[0] = x; v()[1] = y; v()[2] = z; v()[3] = w; }
  128. #endif
  129.  
  130.         /** use to both read and write elements, just like a static array */
  131.         Scalar& operator [] (const int index) { return v()[index]; }
  132.  
  133.         /** use to read elements from const vectors */
  134.         Scalar operator [] (int index) const { return v()[index]; }
  135.  
  136.         /** same as Magnitude() * Magnitude(), but calculated more quickly by avoiding sqrt */
  137.         Scalar MagnitudeSq() const {
  138.                 Scalar length = 0.0;
  139.                 for (int i = 0; i < DIMENSIONS; i++) length += v()[i] * v()[i];
  140.                 return length;
  141.         }
  142.         Scalar Magnitude() const { return sqrt(MagnitudeSq()); }
  143.         /** for people who prefer Length to Magnitude. C++ should optimize this away anyway. */
  144.         Scalar Length() const { return Magnitude(); }
  145.  
  146.         /** @return the distance between the two given points */
  147.         static Scalar Distance(const VEC& a, const VEC& b) { return (b - a).Magnitude(); }
  148.  
  149.         /** @return the distance this point and the given point */
  150.         Scalar Distance(const VEC& other) const { return Distance(*this, other); }
  151.        
  152.         /** rescale the vector to have a smaller magnitude (but the same ratio in it's members), but only if the magnitude is greater */
  153.         void Truncate(const Scalar maximumMagnitude) {
  154.                 Scalar m = Magnitude();
  155.                 if (m > maximumMagnitude) {
  156.                         for (int i = 0; i < DIMENSIONS; i++)
  157.                                 // "x = (x * a_maxLength) / m" is more precise than "x *= (a_maxLength / m)"
  158.                                 v()[i] = (v()[i] * maximumMagnitude) / m;
  159.                 }
  160.         }
  161.  
  162.         /** modifies the vector to be unit length */
  163.         void Normalize() { Scalar m; Normalize(m); }
  164.  
  165.         /** @param out_magnitude [out] the magnitude of the vector before it was normalized */
  166.         void Normalize(Scalar & out_magnitude) {
  167.                 if (!IsZero()) {
  168.                         out_magnitude = Magnitude();
  169.                         // do not divide is length is really small
  170.                         for (int i = 0; i < DIMENSIONS; i++)
  171.                                 v()[i] /= out_magnitude;
  172.                 } else out_magnitude = 0;
  173.         }
  174.  
  175.         /** @return a new vector that is this vector, but normalized */
  176.         VEC Normalized() const {
  177.                 VEC result(*this);
  178.                 result.Normalize();
  179.                 return result;
  180.         }
  181.         VEC Normalized(Scalar & out_magnitude) const {
  182.                 VEC result = *this;
  183.                 result.Normalize(out_magnitude);
  184.                 return result;
  185.         }
  186.  
  187.         /** @return negative of a vector */
  188.         VEC operator - ( void ) const { return *this * -1; }
  189.  
  190.         void operator *= (Scalar scalar) { for (int i = 0; i < DIMENSIONS; i++) v()[i] *= scalar; }
  191.         void operator /= (Scalar scalar) { for (int i = 0; i < DIMENSIONS; i++) v()[i] /= scalar; }
  192.  
  193.         /** @return scales a vector (multiplying). for the case when the operand order is Vector * Scalar */
  194.         VEC operator * (Scalar scalar) const {
  195.                 VEC result;
  196.                 for (int i = 0; i < DIMENSIONS; i++)
  197.                         result.v()[i] = v()[i] * scalar;
  198.                 return result;
  199.         }
  200.         /** @return scales a vector (dividing). for the case when the operand order is Vector * Scalar */
  201.         VEC operator / (const Scalar scalar) const {
  202.                 VEC result;
  203.                 for (int i = 0; i < DIMENSIONS; i++)
  204.                         result.v()[i] = v()[i] / scalar;
  205.                 return result;
  206.         }
  207.  
  208.         /** @return the sum of this vector and the given vector */
  209.         VEC operator + (const VEC& other) const { VEC result; for (int i = 0; i < DIMENSIONS; i++) { result.v()[i] = v()[i] + other.v()[i]; } return result; }
  210.         /** @return the difference between this vector and the given vector */
  211.         VEC operator - (const VEC& other) const { VEC result; for (int i = 0; i < DIMENSIONS; i++) { result.v()[i] = v()[i] - other.v()[i]; } return result; }
  212.         /** @return the product of this vector and the given vector */
  213.         VEC product (const VEC& other) const   { VEC result; for (int i = 0; i < DIMENSIONS; i++) { result.v()[i] = v()[i] * other.v()[i]; } return result; }
  214.         /** @return the quotient of this vector and the given vector */
  215.         VEC quotient(const VEC& other) const   { VEC result; for (int i = 0; i < DIMENSIONS; i++) { result.v()[i] = v()[i] / other.v()[i]; } return result; }
  216.  
  217.         VEC& operator += (const VEC& other) { for (int i = 0; i < DIMENSIONS; i++) v()[i] += other.v()[i]; return *this; }
  218.         VEC& operator -= (const VEC& other) { for (int i = 0; i < DIMENSIONS; i++) v()[i] -= other.v()[i]; return *this; }
  219.         VEC& multiply(const VEC& other)     { for (int i = 0; i < DIMENSIONS; i++) v()[i] *= other.v()[i]; return *this; }
  220.         VEC& divide(const VEC& other)       { for (int i = 0; i < DIMENSIONS; i++) v()[i] /= other.v()[i]; return *this; }
  221.  
  222.         /** @return Dot-Product of the given vectors */
  223.         static Scalar Dot(const VEC& a, const VEC& b) {
  224.                 Scalar dot_product = 0.0;
  225.                 for (int i = 0; i < DIMENSIONS; i++)
  226.                         dot_product += a.v()[i] * b.v()[i];
  227.                 return dot_product;
  228.         }
  229.  
  230.         //Scalar operator *  (const VEC& other) const{ return Dot(*this, other); }
  231.  
  232.         /** @return true if the given vector has the same values as this vector */
  233.         bool operator == (const VEC& other) const {
  234.                 for (int i = 0; i < DIMENSIONS; i++)
  235.                         if (v()[i] != other.v()[i])
  236.                                 return false;
  237.                 return true;
  238.         }
  239.         /** @return !operator==(other) */
  240.         bool operator != (const VEC& other) const { return !operator==(other); }
  241.  
  242.         /** it returns a reference to a constant static vector full of 0's, presumably at the origin of a system */
  243.         static const VEC& ZERO() { static VEC zero_vector; return zero_vector; }
  244.  
  245.         /** @return true if this vector is the ZERO vector */
  246.         bool IsZero() const {
  247.                 for (int i = 0; i < DIMENSIONS; i++) {
  248.                         if (v()[i] != 0)
  249.                                 return false;
  250.                 }
  251.                 return true;
  252.         }
  253.  
  254.         /** clamps this vector's values to be integral (disgarding decimal), in case this vector is being used for very digital row/col-type purposes */
  255.         void ClampToInt() {
  256.                 for (int i = 0; i < DIMENSIONS; i++) {
  257.                         v()[i] = (Scalar)((int)v()[i]);
  258.                 }
  259.         }
  260.  
  261.         /** rounds this vector's values to the nearest integer, in case this vector is being used for very digital row/col-type purposes */
  262.         void RoundToInt() {
  263.                 for (int i = 0; i < DIMENSIONS; i++) {
  264.                         v()[i] = (Scalar)((int)(v()[i]+ 0.5));
  265.                 }
  266.         }
  267.  
  268.         /**
  269.         * @param percentage 0 is a, 1 is b, .5 is between(a,b). any numeric value should work.
  270.         * @return an interpolated point between points a and b.
  271.         */
  272.         static VEC Lerp(const VEC& a, const VEC& b, const Scalar percentage) {
  273.                 VEC delta = b - a;
  274.                 delta *= percentage;
  275.                 return a + delta;
  276.         }
  277.  
  278.         /**
  279.         * @param p the point you are looking for neighbors to
  280.         * @param list multiple points
  281.         * @param listSize how many points are in list
  282.         * @return the index (from list) of the point that is closest to given point p
  283.         */
  284.         static int IndexOfClosest(const VEC& p, const VEC * const & list, const int listSize) {
  285.                 if (listSize < 0) return -1;
  286.                 int closestIndex = 0;
  287.                 VEC delta = list[0] - p;
  288.                 Scalar mag, closestSoFar = delta.Magnitude();
  289.                 for (int i = 1; i < listSize; ++i) {
  290.                         delta = list[i] - p;
  291.                         mag = delta.Magnitude();
  292.                         if (mag < closestSoFar) {
  293.                                 closestSoFar = mag;
  294.                                 closestIndex = i;
  295.                         }
  296.                 }
  297.                 return closestIndex;
  298.         }
  299.  
  300. #ifdef __INITIALIZER_LIST_SUPPORTED
  301.         /** initializer list constructor */
  302.         Vector_(const std::initializer_list <Scalar> & ilist) {
  303.                 auto it = ilist.begin();
  304.                 int index = 0;
  305.                 while (it != ilist.end()) {
  306.                         v()[index++] = *it;
  307.                         it++;
  308.                 }
  309.         }
  310. #endif
  311.  
  312. #ifdef __VARDIC_ARGUMENTS_SUPPORTED
  313.         template<int INDEX> void Set(const Scalar& a_value){ v()[INDEX] = (Scalar)a_value; }
  314.  
  315. private:
  316.         /** terminus for vardic template recursion */
  317.         template<int INDEX, typename... ARGS>
  318.         void SetVardic(){ /*static_assert((INDEX != DIMENSIONS - 1), "not enough arguments supplied");*/ }
  319.  
  320.         /** vardic template recursion */
  321.         template<int INDEX, typename ARGTYPE, typename... ARGS>
  322.         void SetVardic(const ARGTYPE a_value, const ARGS ... args) {
  323.                 static_assert((INDEX < DIMENSIONS), "too many arguments supplied");
  324.                 Set<INDEX>((const Scalar)a_value);
  325.                 // tail recursion, hopefully inline-able by the compiler
  326.                 SetVardic<INDEX + 1, ARGS...>(args...);
  327.         }
  328.  
  329. public:
  330.         /** sets the value of this vector using vardic arguments */
  331.         template<typename... ARGS>
  332.         void Set(const ARGS... args) {
  333.                 const int NUMARGS = sizeof...(ARGS)-1;
  334.                 static_assert((NUMARGS != DIMENSIONS), "wrong number of arguments supplied");
  335.                 SetVardic<0, ARGS...>(args...);
  336.         }
  337.  
  338.         /** explicit default constructor, allows static array allocation. otherwise, Microsoft Visual Studio 2013 has undocumented problems. */
  339.         Vector_() { SetZero(); }
  340.  
  341.         template<typename... ARGS>
  342.         /** complete constructor using vardic arguments. this is implicitly also a default constructor (when zero arguments are supplied) */
  343.         explicit Vector_(const ARGS... args) {
  344.                 const int NUMARGS = sizeof...(ARGS);
  345.                 if (NUMARGS < DIMENSIONS) { // set undefined scalar members to zero
  346.                         SetZero(NUMARGS);
  347.                 }
  348.                 if (NUMARGS > 0) {
  349.                         Set(args...);
  350.                 }
  351.         }
  352.  
  353. #endif
  354. };
  355.  
  356. #undef __INITIALIZER_LIST_SUPPORTED
  357. #undef __VARDIC_ARGUMENTS_SUPPORTED
  358.  
  359. #undef VEC
  360.  
  361. typedef Vector_<_2D<float>> V2f;
  362. typedef Vector_<_3D<float>> V3f;
  363. typedef Vector_<_4D<float>> V4f;
  364.  
  365. typedef Vector_<_2D<int>> V2i;
RAW Paste Data
Top