mvaganov

Vector_.h

Jan 17th, 2015
301
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×