/** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ #include #include #pragma once #include #ifdef ETK_BUILD_LINEARMATH #include #include #include #include #else namespace etk { template class Vector3D; }; //! @brief compatibility with bullet lib typedef etk::Vector3D btVector3; #endif namespace etk { /** * @brief Vectorial 3-dimention vector (x/y/z) */ template class Vector3D { public: T m_floats[4]; //!< all internal values public: /** * @brief No initialization constructor (faster ...) */ Vector3D() { #if 0 #ifdef DEBUG // in debug mode we set supid value to prevent forget of the inits ... m_floats[0] = (T)34673363; m_floats[1] = (T)34523535; m_floats[2] = (T)43523424; m_floats[3] = (T)23452345; #endif #if ( !defined(__TARGET_OS__MacOs) \ && !defined(__TARGET_OS__IOs) \ && defined(ETK_BUILD_LINEARMATH)) // hide a bullet warning (void)btInfinityMask; #endif #else m_floats[0] = 0; m_floats[1] = 0; m_floats[2] = 0; m_floats[3] = 0; #endif } /** * @brief Constructor from scalars * @param[in] _xxx X value * @param[in] _yyy Y value * @param[in] _zzz Z value */ Vector3D(const T& _xxx, const T& _yyy, const T& _zzz) { m_floats[0] = _xxx; m_floats[1] = _yyy; m_floats[2] = _zzz; m_floats[3] = 0; } /** * @brief Add a vector to this one * @param[in] _obj The vector to add to this one * @return Local reference of the vector */ Vector3D& operator+=(const Vector3D& _obj) { m_floats[0] += _obj.m_floats[0]; m_floats[1] += _obj.m_floats[1]; m_floats[2] += _obj.m_floats[2]; return *this; } /** * @brief Add a vector to this one * @param[in] _obj The vector to add to this one * @return New vector containing the value */ Vector3D operator+(const Vector3D& _obj) const { return Vector3D(m_floats[0] + _obj.m_floats[0], m_floats[1] + _obj.m_floats[1], m_floats[2] + _obj.m_floats[2]); } /** * @brief Subtract a vector from this one * @param[in] _obj The vector to subtract * @return Local reference of the vector */ Vector3D& operator-=(const Vector3D& _obj) { m_floats[0] -= _obj.m_floats[0]; m_floats[1] -= _obj.m_floats[1]; m_floats[2] -= _obj.m_floats[2]; return *this; } /** * @brief Subtract a vector from this one * @param[in] _obj The vector to subtract * @return New vector containing the value */ Vector3D operator-(const Vector3D& _obj) const { return Vector3D(m_floats[0] - _obj.m_floats[0], m_floats[1] - _obj.m_floats[1], m_floats[2] - _obj.m_floats[2]); } /** * @brief Scale the vector * @param[in] _val Scale factor * @return Local reference of the vector */ Vector3D& operator*=(const T& _val) { m_floats[0] *= _val; m_floats[1] *= _val; m_floats[2] *= _val; return *this; } /** * @brief Scale the vector * @param[in] _val Scale factor * @return New vector containing the value */ Vector3D operator*(const T& _val) const { return Vector3D(m_floats[0] * _val, m_floats[1] * _val, m_floats[2] * _val); } /** * @brief Inversely scale the vector * @param[in] _val Scale factor to divide by * @return Local reference of the vector */ Vector3D& operator/=(const Vector3D& _val) { if (_val != 0.0f) { return *this *= 1.0f / _val; } return *this; } /** * @brief Inversely scale the vector * @param[in] _val Scale factor to divide by * @return Local reference of the vector */ Vector3D& operator/=(const T& _val) { if (_val != 0.0f) { float tmpVal = 1.0f / _val; m_floats[0] *= tmpVal; m_floats[1] *= tmpVal; m_floats[2] *= tmpVal; return *this; } return *this; } /** * @brief Return the dot product * @param[in] _obj The other vector in the dot product * @return Dot product value */ float dot(const Vector3D& _obj) const { return m_floats[0] * _obj.m_floats[0] + m_floats[1] * _obj.m_floats[1] + m_floats[2] * _obj.m_floats[2]; } /** * @brief Get the length of the vector squared * @return Squared length value. */ float length2() const { return dot(*this); } /** * @brief Get the length of the vector * @return Length value */ float length() const { #if __CPP_VERSION__ >= 2011 && !defined(__STDCPP_LLVM__) return std::sqrt(length2()); #else return sqrt(length2()); #endif } /** * @brief Return the distance squared between the ends of this and another vector * This is symantically treating the vector like a point * @param[in] _obj The other vector to compare distance * @return the square distance of the 2 points */ float distance2(const Vector3D& _obj) const { return (_obj - *this).length2(); } /** * @brief Return the distance between the ends of this and another vector * This is symantically treating the vector like a point * @param[in] _obj The other vector to compare distance * @return the distance of the 2 points */ float distance(const Vector3D& _obj) const { return (_obj - *this).length(); } /** * @brief Normalize this vector x^2 + y^2 + z^2 = 1 (check if not deviding by 0, if it is the case ==> return (1,0,0)) * @return Local reference of the vector normalized */ Vector3D& safeNormalize() { float lenght = length(); if (lenght != 0.0f) { return *this /= length(); } setValue(1,0,0); return *this; } /** * @brief Normalize this vector x^2 + y^2 + z^2 = 1 * @return Local reference of the vector normalized */ Vector3D& normalize() { TK_ASSERT(length() != 0.0f, "Normalisation error"); return *this /= length(); } /** * @brief Return a normalized version of this vector * @return New vector containing the value */ Vector3D normalized() const { Vector3D out = *this; return out.normalize(); } /** * @brief Return a normalized version of this vector (check if not deviding by 0, if it is the case ==> return (1,0,0)) * @return New vector containing the value */ Vector3D safeNormalized() const { Vector3D out = *this; return out.safeNormalize(); } /** * @brief Return a rotated version of this vector * @param[in] _wAxis The axis to rotate about * @param[in] _angle The angle to rotate by * @return New vector containing the value */ Vector3D rotate( const Vector3D& _wAxis, const float _angle ) const { Vector3D o = _wAxis * _wAxis.dot( *this ); Vector3D x = *this - o; Vector3D y; y = _wAxis.cross( *this ); return ( o + x * cosf(_angle) + y * sinf(_angle) ); } /** * @brief Calculate the angle between this and another vector * @param[in] _obj The other vector * @return Angle in radian */ float angle(const Vector3D& _obj) const { float s = sqrtf(length2() * _obj.length2()); if (0!=s) { return acosf(dot(_obj) / s); } return 0; } /** * @brief Return a vector will the absolute values of each element * @return New vector containing the value */ Vector3D absolute() const { return Vector3D( std::abs(m_floats[0]), std::abs(m_floats[1]), std::abs(m_floats[2])); } /** * @brief Return the cross product between this and another vector * @param[in] _obj The other vector * @return Vector with the result of the cross product */ Vector3D cross(const Vector3D& _obj) const { return Vector3D(m_floats[1] * _obj.m_floats[2] - m_floats[2] * _obj.m_floats[1], m_floats[2] * _obj.m_floats[0] - m_floats[0] * _obj.m_floats[2], m_floats[0] * _obj.m_floats[1] - m_floats[1] * _obj.m_floats[0]); } /** * @brief Return the triple product between this and another vector and another * @param[in] _obj1 The other vector 1 * @param[in] _obj2 The other vector 2 * @return Value with the result of the triple product */ T triple(const Vector3D& _obj1, const Vector3D& _obj2) const { return m_floats[0] * (_obj1.m_floats[1] * _obj2.m_floats[2] - _obj1.m_floats[2] * _obj2.m_floats[1]) + m_floats[1] * (_obj1.m_floats[2] * _obj2.m_floats[0] - _obj1.m_floats[0] * _obj2.m_floats[2]) + m_floats[2] * (_obj1.m_floats[0] * _obj2.m_floats[1] - _obj1.m_floats[1] * _obj2.m_floats[0]); } /** * @brief Return the axis with the smallest value * @return values 0,1,2 for x, y, or z */ int32_t minAxis() const { if (m_floats[0] < m_floats[1]) { return m_floats[0] < m_floats[2] ? 0 : 2; } return m_floats[1] < m_floats[2] ? 1 : 2; } /** * @brief Return the axis with the largest value * @return values 0,1,2 for x, y, or z */ int32_t maxAxis() const { if (m_floats[0] < m_floats[1]) { return m_floats[1] < m_floats[2] ? 2 : 1; } return m_floats[0] < m_floats[2] ? 2 : 0; } /** * @brief Return the axis with the smallest ABSOLUTE value * @return values 0,1,2 for x, y, or z */ int32_t furthestAxis() const { return absolute().minAxis(); } /** * @brief Return the axis with the largest ABSOLUTE value * @return values 0,1,2 for x, y, or z */ int32_t closestAxis() const { return absolute().maxAxis(); } /** * @brief Interpolate the vector with a ration between 2 others * @param[in] _obj0 First vector * @param[in] _obj1 Second vector * @param[in] _ratio Ratio between _obj0 and _obj1 */ void setInterpolate3(const Vector3D& _obj0, const Vector3D& _obj1, T _ratio) { float inverse = 1.0 - _ratio; m_floats[0] = inverse * _obj0.m_floats[0] + _ratio * _obj1.m_floats[0]; m_floats[1] = inverse * _obj0.m_floats[1] + _ratio * _obj1.m_floats[1]; m_floats[2] = inverse * _obj0.m_floats[2] + _ratio * _obj1.m_floats[2]; // m_co[3] = s * v0[3] + rt * v1[3]; } /** * @brief Return the linear interpolation between this and another vector * @param[in] _obj The other vector * @param[in] _ratio The ratio of this to _obj (_ratio = 0 => return copy of this, _ratio=1 => return other) * @return New vector containing the value */ Vector3D lerp(const Vector3D& _obj, const float& _ratio) const { return Vector3D(m_floats[0] + (_obj.m_floats[0] - m_floats[0]) * _ratio, m_floats[1] + (_obj.m_floats[1] - m_floats[1]) * _ratio, m_floats[2] + (_obj.m_floats[2] - m_floats[2]) * _ratio); } /** * @brief Elementwise multiply this vector by the other * @param _obj The other vector * @return Local reference of the vector normalized */ Vector3D& operator*=(const Vector3D& _obj) { m_floats[0] *= _obj.m_floats[0]; m_floats[1] *= _obj.m_floats[1]; m_floats[2] *= _obj.m_floats[2]; return *this; } /** * @brief Elementwise multiply this vector by the other * @param _obj The other vector * @return New vector containing the value */ Vector3D operator*(const Vector3D& _obj) const { return Vector3D(m_floats[0] * _obj.m_floats[0], m_floats[1] * _obj.m_floats[1], m_floats[2] * _obj.m_floats[2]); } /** * @brief Get X value * @return the x value */ const T& getX() const { return m_floats[0]; } /** * @brief Get Y value * @return the y value */ const T& getY() const { return m_floats[1]; } /** * @brief Get Z value * @return the z value */ const T& getZ() const { return m_floats[2]; } /** * @brief Set the x value * @param[in] _x New value */ void setX(T _x) { m_floats[0] = _x; } /** * @brief Set the y value * @param[in] _y New value */ void setY(T _y) { m_floats[1] = _y; } /** * @brief Set the z value * @param[in] _z New value */ void setZ(T _z) { m_floats[2] = _z; } /** * @brief Get X value * @return the x value */ const T& x() const { return m_floats[0]; } /** * @brief Get Y value * @return the y value */ const T& y() const { return m_floats[1]; } /** * @brief Get Z value * @return the z value */ const T& z() const { return m_floats[2]; } /** * @brief Cast the vector in the type T* requested. * @return Pointer on the data */ operator T *() { return &m_floats[0]; } /** * @brief Cast the vector in the type const T* requested. * @return Pointer on the const data */ operator const T *() const { return &m_floats[0]; } /** * @brief Equality compare operator with an other object. * @param[in] _obj Reference on the comparing object * @return true The Objects are identical * @return false The Objects are NOT identical */ bool operator==(const Vector3D& _obj) const { return ( (m_floats[2] == _obj.m_floats[2]) && (m_floats[1] == _obj.m_floats[1]) && (m_floats[0] == _obj.m_floats[0])); } /** * @brief In-Equality compare operator with an other object. * @param[in] _obj Reference on the comparing object * @return true The Objects are NOT identical * @return false The Objects are identical */ bool operator!=(const Vector3D& _obj) const { return ( (m_floats[2] != _obj.m_floats[2]) || (m_floats[1] != _obj.m_floats[1]) || (m_floats[0] != _obj.m_floats[0])); } /** * @brief Set each element to the max of the current values and the values of another Vector3D * @param _obj The other Vector3D to compare with */ void setMax(const Vector3D& _obj) { m_floats[0] = std::max(m_floats[0], _obj.m_floats[0]); m_floats[1] = std::max(m_floats[1], _obj.m_floats[1]); m_floats[2] = std::max(m_floats[2], _obj.m_floats[2]); } /** * @brief Set each element to the min of the current values and the values of another Vector3D * @param _obj The other Vector3D to compare with */ void setMin(const Vector3D& _obj) { m_floats[0] = std::min(m_floats[0], _obj.m_floats[0]); m_floats[1] = std::min(m_floats[1], _obj.m_floats[1]); m_floats[2] = std::min(m_floats[2], _obj.m_floats[2]); } /** * @brief Get the minimum value of the vector (x, y, z) * @return The min value */ T getMin() const { return std::min(std::min(m_floats[0], m_floats[1]), m_floats[2]); } /** * @brief Get the maximum value of the vector (x, y, z) * @return The max value */ T getMax() const { return std::max(std::max(m_floats[0], m_floats[1]), m_floats[2]); } /** * @brief Set Value on the vector * @param[in] _xxx X value. * @param[in] _yyy Y value. * @param[in] _zzz Z value. */ void setValue(const T& _xxx, const T& _yyy, const T& _zzz) { m_floats[0]=_xxx; m_floats[1]=_yyy; m_floats[2]=_zzz; m_floats[3] = 0; } /** * @brief Create a skew matrix of the object * @param[out] _obj0 Vector matric first line * @param[out] _obj1 Vector matric second line * @param[out] _obj2 Vector matric third line */ void getSkewSymmetricMatrix(Vector3D* _obj0,Vector3D* _obj1,Vector3D* _obj2) const { _obj0->setValue(0. ,-z() ,y()); _obj1->setValue(z() ,0. ,-x()); _obj2->setValue(-y() ,x() ,0.); } /** * @brief Set 0 value on all the vector */ void setZero() { setValue(0,0,0); } /** * @brief Check if the vector is equal to (0,0,0) * @return true The value is equal to (0,0,0) * @return false The value is NOT equal to (0,0,0) */ bool isZero() const { return m_floats[0] == 0 && m_floats[1] == 0 && m_floats[2] == 0; } /** * @brief Get the Axis id with the minimum value * @return Axis ID 0,1,2 */ int32_t getMinAxis() const { return (m_floats[0] < m_floats[1] ? (m_floats[0] < m_floats[2] ? 0 : 2) : (m_floats[1] < m_floats[2] ? 1 : 2)); } /** * @brief Get the Axis id with the maximum value * @return Axis ID 0,1,2 */ int32_t getMaxAxis() const { return (m_floats[0] < m_floats[1] ? (m_floats[1] < m_floats[2] ? 2 : 1) : (m_floats[0] < m_floats[2] ? 2 : 0)); } /** * @breif Get the orthogonalm vector of the current vector * @return The ortho vector */ Vector3D getOrthoVector() const { Vector3D vectorAbs(std::abs(m_floats[0]), std::abs(m_floats[1]), std::abs(m_floats[2])); int32_t minElement = vectorAbs.getMinAxis(); if (minElement == 0) { float devider = 1.0f / std::sqrt(m_floats[1]*m_floats[1] + m_floats[2]*m_floats[2]); return Vector3D(0.0f, -m_floats[2]*devider, m_floats[1]*devider); } else if (minElement == 1) { float devider = 1.0f / std::sqrt(m_floats[0]*m_floats[0] + m_floats[2]*m_floats[2]); return Vector3D(-m_floats[2]*devider, 0.0f, m_floats[0]*devider); } float devider = 1.0f / std::sqrt(m_floats[0]*m_floats[0] + m_floats[1]*m_floats[1]); return Vector3D(-m_floats[1]*devider, m_floats[0]*devider, 0.0f); } }; //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const etk::Vector3D& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const etk::Vector3D& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const etk::Vector3D& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const etk::Vector3D& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const std::vector>& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const std::vector>& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const std::vector>& _obj); //! @not_in_doc std::ostream& operator <<(std::ostream& _os, const std::vector>& _obj); } // To siplify the writing of the code ==> this permit to have the same name with the glsl language... #ifdef ETK_BUILD_LINEARMATH using vec3 = btVector3; //!< wrapper on etk::Vector3D to have the same naming has OpenGL shader #else using vec3 = etk::Vector3D; //!< wrapper on etk::Vector3D to have the same naming has OpenGL shader #endif using ovec3 = etk::Vector3D; //!< wrapper on etk::Vector3D to be complient all time with openGL internal mode (instead of vec3) using ivec3 = etk::Vector3D; //!< wrapper on etk::Vector3D to have the same naming has OpenGL shader // not compatible with glsl ... but it is better to have a same writing using uivec3 = etk::Vector3D; //!< wrapper on etk::Vector3D to have the same naming has OpenGL shader using bvec3 = etk::Vector3D; //!< wrapper on etk::Vector3D to have the same naming has OpenGL shader #ifdef ETK_BUILD_LINEARMATH std::ostream& operator <<(std::ostream& _os, const btVector3& _obj); std::ostream& operator <<(std::ostream& _os, const std::vector& _obj); vec3 quaternionToEulerXYZ(const btQuaternion& quat); #endif /** * @brief Limit at integer value the input vector: vec3(1.2, 5.6, -2.9) ==> vec3(1.0, 5.0, -2.0) * @param _val input vector to limit * @return reduced range of vector */ inline vec3 vec3ClipInt32(const vec3& _val) { return vec3(int32_t(_val.x()), int32_t(_val.y()), int32_t(_val.z())); } /** * @brief Limit at integer value the input vector: vec3(1.2, 5.6, -2.9) ==> vec3(1.0, 5.0, -2.0) * @param _val input vector to limit * @return reduced range of vector */ inline vec3 vec3ClipInt64(const vec3& _val) { return vec3(int64_t(_val.x()), int64_t(_val.y()), int64_t(_val.z())); } #ifdef ETK_BUILD_LINEARMATH namespace etk { inline btVector3 min(const btVector3& _val1, const btVector3& _val2) { return btVector3(std::min(_val1.x(), _val2.x()), std::min(_val1.y(), _val2.y()), std::min(_val1.z(), _val2.z())); } inline btVector3 max(const btVector3& _val1, const btVector3& _val2) { return btVector3(std::max(_val1.x(), _val2.x()), std::max(_val1.y(), _val2.y()), std::max(_val1.z(), _val2.z())); } } #endif namespace etk { template inline etk::Vector3D min(const etk::Vector3D& _val1, const etk::Vector3D& _val2) { return etk::Vector3D(std::min(_val1.x(), _val2.x()), std::min(_val1.y(), _val2.y()), std::min(_val1.z(), _val2.z())); } template inline etk::Vector3D max(const etk::Vector3D& _val1, const etk::Vector3D& _val2) { return etk::Vector3D(std::max(_val1.x(), _val2.x()), std::max(_val1.y(), _val2.y()), std::max(_val1.z(), _val2.z())); } } template inline etk::Vector3D operator+(const etk::Vector3D& _vect1, const etk::Vector3D& _vect2) { return etk::Vector3D(_vect1.x() + _vect2.x(), _vect1.y() + _vect2.y(), _vect1.z() + _vect2.z()); } template inline etk::Vector3D operator-(const etk::Vector3D& _vect1, const etk::Vector3D& _vect2) { return etk::Vector3D(_vect1.x() - _vect2.x(), _vect1.y() + _vect2.y(), _vect1.z() + _vect2.z()); } template inline etk::Vector3D operator-(const etk::Vector3D& _vect) { return etk::Vector3D(-_vect.x(), -_vect.y(), -_vect.z()); } template inline etk::Vector3D operator*(const etk::Vector3D& _vect, ETK_TYPE _value) { return etk::Vector3D(_value * _vect.x(), _value * _vect.y(), _value * _vect.z()); } template inline etk::Vector3D operator*(const etk::Vector3D& _vect1, const etk::Vector3D& _vect2) { return etk::Vector3D(_vect1.x() * _vect2.x(), _vect1.y() * _vect2.y(), _vect1.z() * _vect2.z()); } template inline etk::Vector3D operator/(const etk::Vector3D& _vect, ETK_TYPE _value) { //assert(_value > MACHINE_EPSILON); return etk::Vector3D(_vect.x() / _value, _vect.y() / _value, _vect.z() / _value); } template inline etk::Vector3D operator/(const etk::Vector3D& _vect1, const etk::Vector3D& _vect2) { //assert(_vect2.x() > MACHINE_EPSILON); //assert(_vect2.y() > MACHINE_EPSILON); //assert(_vect2.z() > MACHINE_EPSILON); return etk::Vector3D(_vect1.x() / _vect2.x(), _vect1.y() / _vect2.y(), _vect1.z() / _vect2.z()); } template inline etk::Vector3D operator*(ETK_TYPE _value, const etk::Vector3D& _vect) { return _vect * _value; }