00001
00002
00003
00004
00005
00006
00007 #ifndef BALL_MATHS_VECTOR3_H
00008 #define BALL_MATHS_VECTOR3_H
00009
00010 #ifndef BALL_COMMON_EXCEPTION_H
00011 # include <BALL/COMMON/exception.h>
00012 #endif
00013
00014 #ifndef BALL_CONCEPT_PERSISTENCEMANAGER_H
00015 # include <BALL/CONCEPT/persistenceManager.h>
00016 #endif
00017
00018 #ifndef BALL_MATHS_ANGLE_H
00019 # include <BALL/MATHS/angle.h>
00020 #endif
00021
00022 #ifndef BALL_MATHS_COMMON_H
00023 # include <BALL/MATHS/common.h>
00024 #endif
00025
00026 #ifdef BALL_HAS_IEEEFP_H
00027 # include <ieeefp.h>
00028 #endif
00029
00030
00031 namespace BALL
00032 {
00038
00039 template <typename T>
00040 class TVector3;
00041
00045
00049 template <typename T>
00050 BALL_INLINE
00051 TVector3<T> operator * (const T& a, const TVector3<T>& b)
00052 ;
00053
00058 template <typename T>
00059 std::istream& operator >> (std::istream& s, TVector3<T>& vector)
00060 ;
00061
00066 template <typename T>
00067 std::ostream& operator << (std::ostream& s, const TVector3<T>& vector)
00068 ;
00069
00071
00074 template <typename T>
00075 class TVector3
00076 {
00077 public:
00078
00082
00087 TVector3()
00088 ;
00089
00096 TVector3(const T* ptr)
00097 throw(Exception::NullPointer);
00098
00104 explicit TVector3(const T& value)
00105 ;
00106
00113 TVector3(const T& vx, const T& vy, const T& vz)
00114 ;
00115
00120 TVector3(const TVector3& vector)
00121 ;
00122
00132 TVector3(const T& r, const TAngle<T>& phi, const TAngle<T>& theta)
00133 ;
00134
00139 ~TVector3()
00140 ;
00141
00145 void clear()
00146 ;
00147
00149
00153
00160 void set(const T* ptr)
00161 throw(Exception::NullPointer);
00162
00167 void set(const T& value)
00168 ;
00169
00175 void set(const T& vx, const T& vy, const T& vz)
00176 ;
00177
00181 void set(const TVector3& vector)
00182 ;
00183
00196 void set(const T& r, const TAngle<T>& phi, const TAngle<T>& theta)
00197 ;
00198
00203 TVector3& operator = (const TVector3& v)
00204 ;
00205
00210 TVector3& operator = (T value)
00211 ;
00212
00218 TVector3& operator = (const T* ptr)
00219 throw(Exception::NullPointer);
00220
00227 void get(T* ptr) const
00228 throw(Exception::NullPointer);
00229
00235 void get(T& x, T& y, T& z) const
00236 ;
00237
00242 void get(TVector3& vector) const
00243 ;
00244
00252 void get(T& r, TAngle<T>& phi, TAngle<T>& theta) const
00253 ;
00254
00258 void swap(TVector3& vector)
00259 ;
00260
00266 T getLength() const
00267 ;
00268
00274 T getSquareLength() const
00275 ;
00276
00283 TVector3& normalize()
00284 throw(Exception::DivisionByZero);
00285
00290 TVector3& negate()
00291 ;
00292
00295 static const TVector3& getZero()
00296 ;
00297
00301 static const TVector3& getUnit()
00302 ;
00303
00307 T& operator [] (Position position)
00308 throw(Exception::IndexOverflow);
00309
00313 const T& operator [] (Position position) const
00314 throw(Exception::IndexOverflow);
00316
00320
00323 const TVector3& operator + () const
00324 ;
00325
00328 TVector3 operator - () const
00329 ;
00330
00333 TVector3 operator + (const TVector3& b) const
00334 ;
00335
00338 TVector3 operator - (const TVector3& b) const
00339 ;
00340
00346 TVector3& operator += (const TVector3& vector)
00347 ;
00348
00353 TVector3& operator -= (const TVector3& vector)
00354 ;
00355
00361 TVector3 operator * (const T& scalar) const
00362 ;
00363
00369 TVector3& operator *= (const T& scalar)
00370 ;
00371
00378 TVector3 operator / (const T& lambda) const
00379 throw(Exception::DivisionByZero);
00380
00386 TVector3& operator /= (const T& lambda)
00387 throw(Exception::DivisionByZero);
00388
00392 T operator * (const TVector3& vector) const
00393 ;
00394
00398 TVector3 operator % (const TVector3& vector) const
00399 ;
00400
00404 TVector3& operator %= (const TVector3& vector)
00405 ;
00406
00408
00412
00415 T getDistance(const TVector3& vector) const
00416 ;
00417
00420 T getSquareDistance(const TVector3& vector) const
00421 ;
00422
00427 TAngle<T> getAngle(const TVector3& vector) const
00428 throw(Exception::DivisionByZero);
00429
00433 TVector3 getOrthogonalProjection(const TVector3& direction) const
00434 ;
00435
00442 static TVector3 getPerpendicularNormalization
00443 (const TVector3& a, const TVector3& b, const TVector3& c)
00444 ;
00445
00453 static T getTripleProduct (const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& c)
00454 ;
00455
00457
00461
00467 bool operator == (const TVector3& vector) const
00468 ;
00469
00475 bool operator != (const TVector3& vector) const
00476 ;
00477
00479 bool operator < (const TVector3& vector) const
00480 ;
00481
00482
00487 bool isZero() const
00488 ;
00489
00492 bool isOrthogonalTo(const TVector3& vector) const
00493 ;
00494
00496
00497
00501
00504 void write(PersistenceManager& pm) const
00505 ;
00506
00509 bool read(PersistenceManager& pm)
00510 ;
00511
00513
00517
00524 void dump(std::ostream& s = std::cout, Size depth = 0) const
00525 ;
00526
00531 bool isValid() const
00532 ;
00533
00535
00536
00542
00545 T x;
00546
00549 T y;
00550
00553 T z;
00555
00556 private:
00557
00558 TAngle<T> getAngle_(const T& a, const T& b) const
00559
00560 {
00561 TAngle<T> angle;
00562
00563 if (Maths::isNotZero(a))
00564 {
00565 angle = atan(b / a);
00566 }
00567 else
00568 {
00569 angle = BALL_SGN(b) * Constants::PI / 2;
00570 }
00571
00572 if (Maths::isLess(a, 0))
00573 {
00574 angle += Constants::PI;
00575 }
00576
00577 if (Maths::isLess(angle.value, 0))
00578 {
00579 return (Angle)(angle.value += 2.0 * Constants::PI);
00580 }
00581 else
00582 {
00583 return angle;
00584 }
00585 }
00586 };
00588
00589 template <typename T>
00590 BALL_INLINE
00591 TVector3<T>::TVector3()
00592
00593 : x(0),
00594 y(0),
00595 z(0)
00596 {
00597 }
00598
00599 template <typename T>
00600 BALL_INLINE
00601 TVector3<T>::TVector3(const T* ptr)
00602 throw(Exception::NullPointer)
00603 {
00604 if (ptr == 0)
00605 {
00606 throw Exception::NullPointer(__FILE__, __LINE__);
00607 }
00608
00609 x = *ptr++;
00610 y = *ptr++;
00611 z = *ptr;
00612 }
00613
00614 template <typename T>
00615 BALL_INLINE
00616 TVector3<T>::TVector3(const T& value)
00617
00618 : x(value),
00619 y(value),
00620 z(value)
00621 {
00622 }
00623
00624 template <typename T>
00625 BALL_INLINE
00626 TVector3<T>::TVector3(const T& vx, const T& vy, const T& vz)
00627
00628 : x(vx),
00629 y(vy),
00630 z(vz)
00631 {
00632 }
00633
00634 template <typename T>
00635 BALL_INLINE
00636 TVector3<T>::TVector3(const TVector3& vector)
00637
00638 : x(vector.x),
00639 y(vector.y),
00640 z(vector.z)
00641 {
00642 }
00643
00644 template <typename T>
00645 BALL_INLINE
00646 TVector3<T>::TVector3(const T& r, const TAngle<T>& phi, const TAngle<T>& theta)
00647
00648 : x(r * cos(phi) * sin(theta)),
00649 y(r * sin(phi) * sin(theta)),
00650 z(r * cos(theta))
00651 {
00652 }
00653
00654 template <typename T>
00655 BALL_INLINE
00656 TVector3<T>::~TVector3()
00657
00658 {
00659 }
00660
00661 template <typename T>
00662 BALL_INLINE
00663 void TVector3<T>::clear()
00664
00665 {
00666 x = y = z = (T)0;
00667 }
00668
00669 template <typename T>
00670 BALL_INLINE
00671 void TVector3<T>::set(const T* ptr)
00672 throw(Exception::NullPointer)
00673 {
00674 if (ptr == 0)
00675 throw Exception::NullPointer(__FILE__, __LINE__);
00676
00677 x = *ptr++;
00678 y = *ptr++;
00679 z = *ptr;
00680 }
00681
00682 template <typename T>
00683 BALL_INLINE
00684 void TVector3<T>::set(const T& value)
00685
00686 {
00687 x = value;
00688 y = value;
00689 z = value;
00690 }
00691
00692 template <typename T>
00693 BALL_INLINE
00694 void TVector3<T>::set(const T& vx, const T& vy, const T& vz)
00695
00696 {
00697 x = vx;
00698 y = vy;
00699 z = vz;
00700 }
00701
00702 template <typename T>
00703 BALL_INLINE
00704 void TVector3<T>::set(const TVector3<T>& vector)
00705
00706 {
00707 x = vector.x;
00708 y = vector.y;
00709 z = vector.z;
00710 }
00711
00712 template <typename T>
00713 BALL_INLINE
00714 void TVector3<T>::set(const T& r, const TAngle<T> &phi, const TAngle<T> &theta)
00715
00716 {
00717 x = r * cos(phi) * sin(theta);
00718 y = r * sin(phi) * sin(theta);
00719 z = r * cos(theta);
00720 }
00721
00722 template <typename T>
00723 BALL_INLINE
00724 TVector3<T>& TVector3<T>::operator = (const T* ptr)
00725 throw(Exception::NullPointer)
00726 {
00727 if (ptr == 0)
00728 {
00729 throw Exception::NullPointer(__FILE__, __LINE__);
00730 }
00731
00732 x = *ptr++;
00733 y = *ptr++;
00734 z = *ptr;
00735
00736 return *this;
00737 }
00738
00739 template <typename T>
00740 BALL_INLINE
00741 TVector3<T>& TVector3<T>::operator = (const TVector3<T>& vector)
00742
00743 {
00744 x = vector.x;
00745 y = vector.y;
00746 z = vector.z;
00747
00748 return *this;
00749 }
00750
00751 template <typename T>
00752 BALL_INLINE
00753 TVector3<T>& TVector3<T>::operator = (T value)
00754
00755 {
00756 x = y = z = value;
00757
00758 return *this;
00759 }
00760
00761 template <typename T>
00762 BALL_INLINE
00763 void TVector3<T>::get(T* ptr) const
00764 throw(Exception::NullPointer)
00765 {
00766 if (ptr == 0)
00767 {
00768 throw Exception::NullPointer(__FILE__, __LINE__);
00769 }
00770
00771 *ptr++ = x;
00772 *ptr++ = y;
00773 *ptr = z;
00774 }
00775
00776 template <typename T>
00777 BALL_INLINE
00778 void TVector3<T>::get(T& new_x, T& new_y, T& new_z) const
00779
00780 {
00781 new_x = x;
00782 new_y = y;
00783 new_z = z;
00784 }
00785
00786 template <typename T>
00787 BALL_INLINE
00788 void TVector3<T>::get(TVector3<T>& vector) const
00789
00790 {
00791 vector.x = x;
00792 vector.y = y;
00793 vector.z = z;
00794 }
00795
00796 template <typename T>
00797 BALL_INLINE
00798 void TVector3<T>::get(T& r, TAngle<T>& phi, TAngle<T>& theta) const
00799
00800 {
00801 r = sqrt(x * x + y * y + z * z);
00802 phi = (Angle)getAngle_(x, y);
00803 theta = getAngle_(z, sqrt(x * x + y * y));
00804 }
00805
00806 template <typename T>
00807 BALL_INLINE
00808 void TVector3<T>::swap(TVector3<T>& vector)
00809
00810 {
00811 T temp = x;
00812 x = vector.x;
00813 vector.x = temp;
00814
00815 temp = y;
00816 y = vector.y;
00817 vector.y = temp;
00818
00819 temp = z;
00820 z = vector.z;
00821 vector.z = temp;
00822 }
00823
00824 template <typename T>
00825 BALL_INLINE
00826 T TVector3<T>::getLength() const
00827
00828 {
00829 return (T)sqrt(x * x + y * y + z * z);
00830 }
00831
00832 template <typename T>
00833 BALL_INLINE
00834 T TVector3<T>::getSquareLength() const
00835
00836 {
00837 return (x * x + y * y + z * z);
00838 }
00839
00840 template <typename T>
00841 TVector3<T>& TVector3<T>::normalize()
00842 throw(Exception::DivisionByZero)
00843 {
00844 T len = sqrt(x * x + y * y + z * z);
00845
00846 if (Maths::isZero(len))
00847 {
00848 throw Exception::DivisionByZero(__FILE__, __LINE__);
00849 }
00850
00851 x /= len;
00852 y /= len;
00853 z /= len;
00854
00855 return *this;
00856 }
00857
00858 template <typename T>
00859 BALL_INLINE
00860 TVector3<T>& TVector3<T>::negate()
00861
00862 {
00863 x *= -1;
00864 y *= -1;
00865 z *= -1;
00866 return *this;
00867 }
00868
00869 template <typename T>
00870 BALL_INLINE
00871 const TVector3<T>& TVector3<T>::getZero()
00872
00873 {
00874 static TVector3<T> null_vector(0, 0, 0);
00875 return null_vector;
00876 }
00877
00878 template <typename T>
00879 BALL_INLINE
00880 const TVector3<T>& TVector3<T>::getUnit()
00881
00882 {
00883 static TVector3<T> unit_vector(1, 1, 1);
00884 return unit_vector;
00885 }
00886
00887 template <typename T>
00888 BALL_INLINE
00889 T& TVector3<T>::operator [] (Position position)
00890 throw(Exception::IndexOverflow)
00891 {
00892 if (position > 2)
00893 {
00894 throw Exception::IndexOverflow(__FILE__, __LINE__, position);
00895 }
00896 switch (position)
00897 {
00898 case 0: return x;
00899 case 1: return y;
00900 case 2:
00901 default:
00902 return z;
00903 }
00904 }
00905
00906 template <typename T>
00907 BALL_INLINE
00908 const T& TVector3<T>::operator [] (Position position) const
00909 throw(Exception::IndexOverflow)
00910 {
00911 if (position > 2)
00912 {
00913 throw Exception::IndexOverflow(__FILE__, __LINE__);
00914 }
00915 switch (position)
00916 {
00917 case 0: return x;
00918 case 1: return y;
00919 case 2:
00920 default:
00921 return z;
00922 }
00923 }
00924
00925 template <typename T>
00926 BALL_INLINE
00927 const TVector3<T>& TVector3<T>::operator + () const
00928
00929 {
00930 return *this;
00931 }
00932
00933 template <typename T>
00934 BALL_INLINE
00935 TVector3<T> TVector3<T>::operator - () const
00936
00937 {
00938 return TVector3<T>(-x, -y, -z);
00939 }
00940
00941 template <typename T>
00942 BALL_INLINE
00943 TVector3<T>& TVector3<T>::operator += (const TVector3<T>& vector)
00944
00945 {
00946 x += vector.x;
00947 y += vector.y;
00948 z += vector.z;
00949
00950 return *this;
00951 }
00952
00953 template <typename T>
00954 BALL_INLINE
00955 TVector3<T>& TVector3<T>::operator -= (const TVector3<T>& vector)
00956
00957 {
00958 x -= vector.x;
00959 y -= vector.y;
00960 z -= vector.z;
00961
00962 return *this;
00963 }
00964
00965 template <typename T>
00966 BALL_INLINE
00967 TVector3<T> TVector3<T>::operator * (const T& scalar) const
00968
00969 {
00970 return TVector3<T>(x * scalar, y * scalar, z * scalar);
00971 }
00972
00973 template <typename T>
00974 BALL_INLINE
00975 TVector3<T>& TVector3<T>::operator *= (const T &scalar)
00976
00977 {
00978 x *= scalar;
00979 y *= scalar;
00980 z *= scalar;
00981
00982 return *this;
00983 }
00984
00985 template <typename T>
00986 TVector3<T> TVector3<T>::operator / (const T& lambda) const
00987 throw(Exception::DivisionByZero)
00988 {
00989 if (lambda == (T)0)
00990 {
00991 throw Exception::DivisionByZero(__FILE__, __LINE__);
00992 }
00993 return TVector3<T>(x / lambda, y / lambda, z / lambda);
00994 }
00995
00996 template <typename T>
00997 TVector3<T>& TVector3<T>::operator /= (const T& lambda)
00998 throw(Exception::DivisionByZero)
00999 {
01000 if (lambda == (T)0)
01001 {
01002 throw Exception::DivisionByZero(__FILE__, __LINE__);
01003 }
01004 x /= lambda;
01005 y /= lambda;
01006 z /= lambda;
01007
01008 return *this;
01009 }
01010
01011 template <typename T>
01012 BALL_INLINE
01013 T TVector3<T>::operator * (const TVector3<T>& vector) const
01014
01015 {
01016 return (x * vector.x + y * vector.y + z * vector.z);
01017 }
01018
01019 template <typename T>
01020 TVector3<T> TVector3<T>::operator % (const TVector3<T>& v) const
01021
01022 {
01023 return TVector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
01024 }
01025
01026 template <typename T>
01027 BALL_INLINE
01028 TVector3<T>& TVector3<T>::operator %= (const TVector3<T>& v)
01029
01030 {
01031 set(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
01032 return *this;
01033 }
01034
01035 template <typename T>
01036 BALL_INLINE
01037 T TVector3<T>::getDistance(const TVector3<T>& v) const
01038
01039 {
01040 T dx = x - v.x;
01041 T dy = y - v.y;
01042 T dz = z - v.z;
01043
01044 return (T)sqrt(dx * dx + dy * dy + dz * dz);
01045 }
01046
01047 template <typename T>
01048 BALL_INLINE T
01049 TVector3<T>::getSquareDistance(const TVector3<T>& v) const
01050
01051 {
01052 T dx = x - v.x;
01053 T dy = y - v.y;
01054 T dz = z - v.z;
01055
01056 return (dx * dx + dy * dy + dz * dz);
01057 }
01058
01059 template <typename T>
01060 BALL_INLINE
01061 TAngle<T> TVector3<T>::getAngle(const TVector3<T>& vector) const
01062 throw(Exception::DivisionByZero)
01063 {
01064 T length_product = getSquareLength() * vector.getSquareLength();
01065
01066 if (length_product == (T)0)
01067 {
01068 throw Exception::DivisionByZero(__FILE__, __LINE__);
01069 }
01070
01071 T acos_arg = ((*this) * vector) / sqrt(length_product);
01072
01073
01074
01075
01076 if (fabs(acos_arg) > 1.0)
01077 {
01078 return (TAngle<T>)0.0;
01079 }
01080
01081 return (TAngle<T>)acos(acos_arg);
01082 }
01083
01084 template <typename T>
01085 BALL_INLINE
01086 TVector3<T> TVector3<T>::getOrthogonalProjection(const TVector3<T>& direction) const
01087
01088 {
01089 return ((direction * (*this)) / (direction * direction) * direction);
01090 }
01091
01092 template <typename T>
01093 TVector3<T> TVector3<T>::getPerpendicularNormalization
01094 (const TVector3<T> &a, const TVector3<T> &b, const TVector3<T> &c)
01095
01096 {
01097 TVector3 diff1(b.x - a.x, b.y - a.y, b.z - a.z);
01098 TVector3 diff2(b.x - c.x, b.y - c.y, b.z - c.z);
01099
01100 return TVector3
01101 (diff1.y * diff2.z - diff1.z * diff2.y,
01102 diff1.z * diff2.x - diff1.x * diff2.z,
01103 diff1.x * diff2.y - diff1.y * diff2.x);
01104 }
01105
01106 template <typename T>
01107 BALL_INLINE
01108 T TVector3<T>::getTripleProduct
01109 (const TVector3<T>& a,
01110 const TVector3<T>& b,
01111 const TVector3<T>& c)
01112
01113 {
01114 return ( a.x * (b.y * c.z - b.z * c.y)
01115 + a.y * (b.z * c.x - b.x * c.z)
01116 + a.z * (b.x * c.y - b.y * c.x));
01117 }
01118
01119 template <typename T>
01120 BALL_INLINE
01121 bool TVector3<T>::operator == (const TVector3<T>& v) const
01122
01123 {
01124 return (Maths::isEqual(x, v.x) && Maths::isEqual(y, v.y) && Maths::isEqual(z, v.z));
01125 }
01126
01127 template <typename T>
01128 BALL_INLINE
01129 bool TVector3<T>::operator < (const TVector3<T>& v) const
01130
01131 {
01132 return (x < v.x || y < v.y || z < v.z);
01133 }
01134
01135
01136 template <typename T>
01137 BALL_INLINE
01138 bool TVector3<T>::operator != (const TVector3<T>& v) const
01139
01140 {
01141 return (Maths::isNotEqual(x, v.x) || Maths::isNotEqual(y, v.y) || Maths::isNotEqual(z, v.z));
01142 }
01143
01144 template <typename T>
01145 BALL_INLINE
01146 bool TVector3<T>::isOrthogonalTo(const TVector3<T>& v) const
01147
01148 {
01149 return Maths::isZero((*this) * v);
01150 }
01151
01152 template <typename T>
01153 BALL_INLINE
01154 bool TVector3<T>::isValid() const
01155
01156 {
01157 return true;
01158 }
01159
01160 template <typename T>
01161 BALL_INLINE
01162 bool TVector3<T>::isZero() const
01163
01164 {
01165 return (Maths::isZero(x) && Maths::isZero(y) && Maths::isZero(z));
01166 }
01167
01168 template <typename T>
01169 void TVector3<T>::dump(std::ostream& s, Size depth) const
01170
01171 {
01172 BALL_DUMP_STREAM_PREFIX(s);
01173
01174 BALL_DUMP_HEADER(s, this, this);
01175
01176 BALL_DUMP_DEPTH(s, depth);
01177 s << " (x = " << x << ", y = " << y << ", z = " << z << ")" << std::endl;
01178
01179 BALL_DUMP_STREAM_SUFFIX(s);
01180 }
01181
01185 typedef TVector3<float> Vector3;
01186
01187 template <typename T>
01188 BALL_INLINE
01189 TVector3<T> TVector3<T>::operator + (const TVector3<T>& b) const
01190
01191 {
01192 return TVector3<T>(x + b.x, y + b.y, z + b.z);
01193 }
01194
01195 template <typename T>
01196 BALL_INLINE
01197 TVector3<T> TVector3<T>::operator - (const TVector3<T>& b) const
01198
01199 {
01200 return TVector3<T>(x - b.x, y - b.y, z - b.z);
01201 }
01202
01203 template <typename T>
01204 void TVector3<T>::write(PersistenceManager& pm) const
01205
01206 {
01207 pm.writePrimitive(x, "x");
01208 pm.writePrimitive(y, "y");
01209 pm.writePrimitive(z, "z");
01210 }
01211
01212 template <typename T>
01213 bool TVector3<T>::read(PersistenceManager& pm)
01214
01215 {
01216 pm.readPrimitive(x, "x");
01217 pm.readPrimitive(y, "y");
01218 pm.readPrimitive(z, "z");
01219
01220 return true;
01221 }
01222
01223
01224 template <typename T>
01225 BALL_INLINE
01226 TVector3<T> operator * (const T& scalar, const TVector3<T>& vector)
01227
01228 {
01229 return TVector3<T>(scalar * vector.x, scalar * vector.y, scalar * vector.z);
01230 }
01231
01232 template <typename T>
01233 std::istream& operator >> (std::istream& s, TVector3<T>& v)
01234
01235 {
01236 char c;
01237 s >> c >> v.x >> v.y >> v.z >> c;
01238
01239 return s;
01240 }
01241
01242 template <typename T>
01243 std::ostream& operator << (std::ostream& s, const TVector3<T>& v)
01244
01245 {
01246 s << "(" << v.x << ' ' << v.y << ' ' << v.z << ')';
01247
01248 return s;
01249 }
01250
01251 }
01252
01253 #endif // BALL_MATHS_VECTOR3_H