Advertisement
mvaganov

Vector_.h

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