/////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas // Digital Ltd. LLC // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Industrial Light & Magic nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_IMATHVEC_H #define INCLUDED_IMATHVEC_H //---------------------------------------------------- // // 2D, 3D and 4D point/vector class templates // //---------------------------------------------------- #include "ImathExc.h" #include "ImathLimits.h" #include "ImathMath.h" #include #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER // suppress exception specification warnings #pragma warning(push) #pragma warning(disable:4290) #endif namespace Imath { template class Vec2; template class Vec3; template class Vec4; enum InfException {INF_EXCEPTION}; template class Vec2 { public: //------------------- // Access to elements //------------------- T x, y; T & operator [] (int i); const T & operator [] (int i) const; //------------- // Constructors //------------- Vec2 (); // no initialization explicit Vec2 (T a); // (a a) Vec2 (T a, T b); // (a b) //--------------------------------- // Copy constructors and assignment //--------------------------------- Vec2 (const Vec2 &v); template Vec2 (const Vec2 &v); const Vec2 & operator = (const Vec2 &v); //---------------------- // Compatibility with Sb //---------------------- template void setValue (S a, S b); template void setValue (const Vec2 &v); template void getValue (S &a, S &b) const; template void getValue (Vec2 &v) const; T * getValue (); const T * getValue () const; //--------- // Equality //--------- template bool operator == (const Vec2 &v) const; template bool operator != (const Vec2 &v) const; //----------------------------------------------------------------------- // Compare two vectors and test if they are "approximately equal": // // equalWithAbsError (v, e) // // Returns true if the coefficients of this and v are the same with // an absolute error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e // // equalWithRelError (v, e) // // Returns true if the coefficients of this and v are the same with // a relative error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e * abs (this[i]) //----------------------------------------------------------------------- bool equalWithAbsError (const Vec2 &v, T e) const; bool equalWithRelError (const Vec2 &v, T e) const; //------------ // Dot product //------------ T dot (const Vec2 &v) const; T operator ^ (const Vec2 &v) const; //------------------------------------------------ // Right-handed cross product, i.e. z component of // Vec3 (this->x, this->y, 0) % Vec3 (v.x, v.y, 0) //------------------------------------------------ T cross (const Vec2 &v) const; T operator % (const Vec2 &v) const; //------------------------ // Component-wise addition //------------------------ const Vec2 & operator += (const Vec2 &v); Vec2 operator + (const Vec2 &v) const; //--------------------------- // Component-wise subtraction //--------------------------- const Vec2 & operator -= (const Vec2 &v); Vec2 operator - (const Vec2 &v) const; //------------------------------------ // Component-wise multiplication by -1 //------------------------------------ Vec2 operator - () const; const Vec2 & negate (); //------------------------------ // Component-wise multiplication //------------------------------ const Vec2 & operator *= (const Vec2 &v); const Vec2 & operator *= (T a); Vec2 operator * (const Vec2 &v) const; Vec2 operator * (T a) const; //------------------------ // Component-wise division //------------------------ const Vec2 & operator /= (const Vec2 &v); const Vec2 & operator /= (T a); Vec2 operator / (const Vec2 &v) const; Vec2 operator / (T a) const; //---------------------------------------------------------------- // Length and normalization: If v.length() is 0.0, v.normalize() // and v.normalized() produce a null vector; v.normalizeExc() and // v.normalizedExc() throw a NullVecExc. // v.normalizeNonNull() and v.normalizedNonNull() are slightly // faster than the other normalization routines, but if v.length() // is 0.0, the result is undefined. //---------------------------------------------------------------- T length () const; T length2 () const; const Vec2 & normalize (); // modifies *this const Vec2 & normalizeExc () throw (Iex::MathExc); const Vec2 & normalizeNonNull (); Vec2 normalized () const; // does not modify *this Vec2 normalizedExc () const throw (Iex::MathExc); Vec2 normalizedNonNull () const; //-------------------------------------------------------- // Number of dimensions, i.e. number of elements in a Vec2 //-------------------------------------------------------- static unsigned int dimensions() {return 2;} //------------------------------------------------- // Limitations of type T (see also class limits) //------------------------------------------------- static T baseTypeMin() {return limits::min();} static T baseTypeMax() {return limits::max();} static T baseTypeSmallest() {return limits::smallest();} static T baseTypeEpsilon() {return limits::epsilon();} //-------------------------------------------------------------- // Base type -- in templates, which accept a parameter, V, which // could be either a Vec2, a Vec3, or a Vec4 you can // refer to T as V::BaseType //-------------------------------------------------------------- typedef T BaseType; private: T lengthTiny () const; }; template class Vec3 { public: //------------------- // Access to elements //------------------- T x, y, z; T & operator [] (int i); const T & operator [] (int i) const; //------------- // Constructors //------------- Vec3 (); // no initialization explicit Vec3 (T a); // (a a a) Vec3 (T a, T b, T c); // (a b c) //--------------------------------- // Copy constructors and assignment //--------------------------------- Vec3 (const Vec3 &v); template Vec3 (const Vec3 &v); const Vec3 & operator = (const Vec3 &v); //--------------------------------------------------------- // Vec4 to Vec3 conversion, divides x, y and z by w: // // The one-argument conversion function divides by w even // if w is zero. The result depends on how the environment // handles floating-point exceptions. // // The two-argument version thows an InfPointExc exception // if w is zero or if division by w would overflow. //--------------------------------------------------------- template explicit Vec3 (const Vec4 &v); template explicit Vec3 (const Vec4 &v, InfException); //---------------------- // Compatibility with Sb //---------------------- template void setValue (S a, S b, S c); template void setValue (const Vec3 &v); template void getValue (S &a, S &b, S &c) const; template void getValue (Vec3 &v) const; T * getValue(); const T * getValue() const; //--------- // Equality //--------- template bool operator == (const Vec3 &v) const; template bool operator != (const Vec3 &v) const; //----------------------------------------------------------------------- // Compare two vectors and test if they are "approximately equal": // // equalWithAbsError (v, e) // // Returns true if the coefficients of this and v are the same with // an absolute error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e // // equalWithRelError (v, e) // // Returns true if the coefficients of this and v are the same with // a relative error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e * abs (this[i]) //----------------------------------------------------------------------- bool equalWithAbsError (const Vec3 &v, T e) const; bool equalWithRelError (const Vec3 &v, T e) const; //------------ // Dot product //------------ T dot (const Vec3 &v) const; T operator ^ (const Vec3 &v) const; //--------------------------- // Right-handed cross product //--------------------------- Vec3 cross (const Vec3 &v) const; const Vec3 & operator %= (const Vec3 &v); Vec3 operator % (const Vec3 &v) const; //------------------------ // Component-wise addition //------------------------ const Vec3 & operator += (const Vec3 &v); Vec3 operator + (const Vec3 &v) const; //--------------------------- // Component-wise subtraction //--------------------------- const Vec3 & operator -= (const Vec3 &v); Vec3 operator - (const Vec3 &v) const; //------------------------------------ // Component-wise multiplication by -1 //------------------------------------ Vec3 operator - () const; const Vec3 & negate (); //------------------------------ // Component-wise multiplication //------------------------------ const Vec3 & operator *= (const Vec3 &v); const Vec3 & operator *= (T a); Vec3 operator * (const Vec3 &v) const; Vec3 operator * (T a) const; //------------------------ // Component-wise division //------------------------ const Vec3 & operator /= (const Vec3 &v); const Vec3 & operator /= (T a); Vec3 operator / (const Vec3 &v) const; Vec3 operator / (T a) const; //---------------------------------------------------------------- // Length and normalization: If v.length() is 0.0, v.normalize() // and v.normalized() produce a null vector; v.normalizeExc() and // v.normalizedExc() throw a NullVecExc. // v.normalizeNonNull() and v.normalizedNonNull() are slightly // faster than the other normalization routines, but if v.length() // is 0.0, the result is undefined. //---------------------------------------------------------------- T length () const; T length2 () const; const Vec3 & normalize (); // modifies *this const Vec3 & normalizeExc () throw (Iex::MathExc); const Vec3 & normalizeNonNull (); Vec3 normalized () const; // does not modify *this Vec3 normalizedExc () const throw (Iex::MathExc); Vec3 normalizedNonNull () const; //-------------------------------------------------------- // Number of dimensions, i.e. number of elements in a Vec3 //-------------------------------------------------------- static unsigned int dimensions() {return 3;} //------------------------------------------------- // Limitations of type T (see also class limits) //------------------------------------------------- static T baseTypeMin() {return limits::min();} static T baseTypeMax() {return limits::max();} static T baseTypeSmallest() {return limits::smallest();} static T baseTypeEpsilon() {return limits::epsilon();} //-------------------------------------------------------------- // Base type -- in templates, which accept a parameter, V, which // could be either a Vec2, a Vec3, or a Vec4 you can // refer to T as V::BaseType //-------------------------------------------------------------- typedef T BaseType; private: T lengthTiny () const; }; template class Vec4 { public: //------------------- // Access to elements //------------------- T x, y, z, w; T & operator [] (int i); const T & operator [] (int i) const; //------------- // Constructors //------------- Vec4 (); // no initialization explicit Vec4 (T a); // (a a a a) Vec4 (T a, T b, T c, T d); // (a b c d) //--------------------------------- // Copy constructors and assignment //--------------------------------- Vec4 (const Vec4 &v); template Vec4 (const Vec4 &v); const Vec4 & operator = (const Vec4 &v); //------------------------------------- // Vec3 to Vec4 conversion, sets w to 1 //------------------------------------- template explicit Vec4 (const Vec3 &v); //--------- // Equality //--------- template bool operator == (const Vec4 &v) const; template bool operator != (const Vec4 &v) const; //----------------------------------------------------------------------- // Compare two vectors and test if they are "approximately equal": // // equalWithAbsError (v, e) // // Returns true if the coefficients of this and v are the same with // an absolute error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e // // equalWithRelError (v, e) // // Returns true if the coefficients of this and v are the same with // a relative error of no more than e, i.e., for all i // // abs (this[i] - v[i]) <= e * abs (this[i]) //----------------------------------------------------------------------- bool equalWithAbsError (const Vec4 &v, T e) const; bool equalWithRelError (const Vec4 &v, T e) const; //------------ // Dot product //------------ T dot (const Vec4 &v) const; T operator ^ (const Vec4 &v) const; //----------------------------------- // Cross product is not defined in 4D //----------------------------------- //------------------------ // Component-wise addition //------------------------ const Vec4 & operator += (const Vec4 &v); Vec4 operator + (const Vec4 &v) const; //--------------------------- // Component-wise subtraction //--------------------------- const Vec4 & operator -= (const Vec4 &v); Vec4 operator - (const Vec4 &v) const; //------------------------------------ // Component-wise multiplication by -1 //------------------------------------ Vec4 operator - () const; const Vec4 & negate (); //------------------------------ // Component-wise multiplication //------------------------------ const Vec4 & operator *= (const Vec4 &v); const Vec4 & operator *= (T a); Vec4 operator * (const Vec4 &v) const; Vec4 operator * (T a) const; //------------------------ // Component-wise division //------------------------ const Vec4 & operator /= (const Vec4 &v); const Vec4 & operator /= (T a); Vec4 operator / (const Vec4 &v) const; Vec4 operator / (T a) const; //---------------------------------------------------------------- // Length and normalization: If v.length() is 0.0, v.normalize() // and v.normalized() produce a null vector; v.normalizeExc() and // v.normalizedExc() throw a NullVecExc. // v.normalizeNonNull() and v.normalizedNonNull() are slightly // faster than the other normalization routines, but if v.length() // is 0.0, the result is undefined. //---------------------------------------------------------------- T length () const; T length2 () const; const Vec4 & normalize (); // modifies *this const Vec4 & normalizeExc () throw (Iex::MathExc); const Vec4 & normalizeNonNull (); Vec4 normalized () const; // does not modify *this Vec4 normalizedExc () const throw (Iex::MathExc); Vec4 normalizedNonNull () const; //-------------------------------------------------------- // Number of dimensions, i.e. number of elements in a Vec4 //-------------------------------------------------------- static unsigned int dimensions() {return 4;} //------------------------------------------------- // Limitations of type T (see also class limits) //------------------------------------------------- static T baseTypeMin() {return limits::min();} static T baseTypeMax() {return limits::max();} static T baseTypeSmallest() {return limits::smallest();} static T baseTypeEpsilon() {return limits::epsilon();} //-------------------------------------------------------------- // Base type -- in templates, which accept a parameter, V, which // could be either a Vec2, a Vec3, or a Vec4 you can // refer to T as V::BaseType //-------------------------------------------------------------- typedef T BaseType; private: T lengthTiny () const; }; //-------------- // Stream output //-------------- template std::ostream & operator << (std::ostream &s, const Vec2 &v); template std::ostream & operator << (std::ostream &s, const Vec3 &v); template std::ostream & operator << (std::ostream &s, const Vec4 &v); //---------------------------------------------------- // Reverse multiplication: S * Vec2 and S * Vec3 //---------------------------------------------------- template Vec2 operator * (T a, const Vec2 &v); template Vec3 operator * (T a, const Vec3 &v); template Vec4 operator * (T a, const Vec4 &v); //------------------------- // Typedefs for convenience //------------------------- typedef Vec2 V2s; typedef Vec2 V2i; typedef Vec2 V2f; typedef Vec2 V2d; typedef Vec3 V3s; typedef Vec3 V3i; typedef Vec3 V3f; typedef Vec3 V3d; typedef Vec4 V4s; typedef Vec4 V4i; typedef Vec4 V4f; typedef Vec4 V4d; //------------------------------------------- // Specializations for VecN, VecN //------------------------------------------- // Vec2 template <> short Vec2::length () const; template <> const Vec2 & Vec2::normalize (); template <> const Vec2 & Vec2::normalizeExc () throw (Iex::MathExc); template <> const Vec2 & Vec2::normalizeNonNull (); template <> Vec2 Vec2::normalized () const; template <> Vec2 Vec2::normalizedExc () const throw (Iex::MathExc); template <> Vec2 Vec2::normalizedNonNull () const; // Vec2 template <> int Vec2::length () const; template <> const Vec2 & Vec2::normalize (); template <> const Vec2 & Vec2::normalizeExc () throw (Iex::MathExc); template <> const Vec2 & Vec2::normalizeNonNull (); template <> Vec2 Vec2::normalized () const; template <> Vec2 Vec2::normalizedExc () const throw (Iex::MathExc); template <> Vec2 Vec2::normalizedNonNull () const; // Vec3 template <> short Vec3::length () const; template <> const Vec3 & Vec3::normalize (); template <> const Vec3 & Vec3::normalizeExc () throw (Iex::MathExc); template <> const Vec3 & Vec3::normalizeNonNull (); template <> Vec3 Vec3::normalized () const; template <> Vec3 Vec3::normalizedExc () const throw (Iex::MathExc); template <> Vec3 Vec3::normalizedNonNull () const; // Vec3 template <> int Vec3::length () const; template <> const Vec3 & Vec3::normalize (); template <> const Vec3 & Vec3::normalizeExc () throw (Iex::MathExc); template <> const Vec3 & Vec3::normalizeNonNull (); template <> Vec3 Vec3::normalized () const; template <> Vec3 Vec3::normalizedExc () const throw (Iex::MathExc); template <> Vec3 Vec3::normalizedNonNull () const; // Vec4 template <> short Vec4::length () const; template <> const Vec4 & Vec4::normalize (); template <> const Vec4 & Vec4::normalizeExc () throw (Iex::MathExc); template <> const Vec4 & Vec4::normalizeNonNull (); template <> Vec4 Vec4::normalized () const; template <> Vec4 Vec4::normalizedExc () const throw (Iex::MathExc); template <> Vec4 Vec4::normalizedNonNull () const; // Vec4 template <> int Vec4::length () const; template <> const Vec4 & Vec4::normalize (); template <> const Vec4 & Vec4::normalizeExc () throw (Iex::MathExc); template <> const Vec4 & Vec4::normalizeNonNull (); template <> Vec4 Vec4::normalized () const; template <> Vec4 Vec4::normalizedExc () const throw (Iex::MathExc); template <> Vec4 Vec4::normalizedNonNull () const; //------------------------ // Implementation of Vec2: //------------------------ template inline T & Vec2::operator [] (int i) { return (&x)[i]; } template inline const T & Vec2::operator [] (int i) const { return (&x)[i]; } template inline Vec2::Vec2 () { // empty } template inline Vec2::Vec2 (T a) { x = y = a; } template inline Vec2::Vec2 (T a, T b) { x = a; y = b; } template inline Vec2::Vec2 (const Vec2 &v) { x = v.x; y = v.y; } template template inline Vec2::Vec2 (const Vec2 &v) { x = T (v.x); y = T (v.y); } template inline const Vec2 & Vec2::operator = (const Vec2 &v) { x = v.x; y = v.y; return *this; } template template inline void Vec2::setValue (S a, S b) { x = T (a); y = T (b); } template template inline void Vec2::setValue (const Vec2 &v) { x = T (v.x); y = T (v.y); } template template inline void Vec2::getValue (S &a, S &b) const { a = S (x); b = S (y); } template template inline void Vec2::getValue (Vec2 &v) const { v.x = S (x); v.y = S (y); } template inline T * Vec2::getValue() { return (T *) &x; } template inline const T * Vec2::getValue() const { return (const T *) &x; } template template inline bool Vec2::operator == (const Vec2 &v) const { return x == v.x && y == v.y; } template template inline bool Vec2::operator != (const Vec2 &v) const { return x != v.x || y != v.y; } template bool Vec2::equalWithAbsError (const Vec2 &v, T e) const { for (int i = 0; i < 2; i++) if (!Imath::equalWithAbsError ((*this)[i], v[i], e)) return false; return true; } template bool Vec2::equalWithRelError (const Vec2 &v, T e) const { for (int i = 0; i < 2; i++) if (!Imath::equalWithRelError ((*this)[i], v[i], e)) return false; return true; } template inline T Vec2::dot (const Vec2 &v) const { return x * v.x + y * v.y; } template inline T Vec2::operator ^ (const Vec2 &v) const { return dot (v); } template inline T Vec2::cross (const Vec2 &v) const { return x * v.y - y * v.x; } template inline T Vec2::operator % (const Vec2 &v) const { return x * v.y - y * v.x; } template inline const Vec2 & Vec2::operator += (const Vec2 &v) { x += v.x; y += v.y; return *this; } template inline Vec2 Vec2::operator + (const Vec2 &v) const { return Vec2 (x + v.x, y + v.y); } template inline const Vec2 & Vec2::operator -= (const Vec2 &v) { x -= v.x; y -= v.y; return *this; } template inline Vec2 Vec2::operator - (const Vec2 &v) const { return Vec2 (x - v.x, y - v.y); } template inline Vec2 Vec2::operator - () const { return Vec2 (-x, -y); } template inline const Vec2 & Vec2::negate () { x = -x; y = -y; return *this; } template inline const Vec2 & Vec2::operator *= (const Vec2 &v) { x *= v.x; y *= v.y; return *this; } template inline const Vec2 & Vec2::operator *= (T a) { x *= a; y *= a; return *this; } template inline Vec2 Vec2::operator * (const Vec2 &v) const { return Vec2 (x * v.x, y * v.y); } template inline Vec2 Vec2::operator * (T a) const { return Vec2 (x * a, y * a); } template inline const Vec2 & Vec2::operator /= (const Vec2 &v) { x /= v.x; y /= v.y; return *this; } template inline const Vec2 & Vec2::operator /= (T a) { x /= a; y /= a; return *this; } template inline Vec2 Vec2::operator / (const Vec2 &v) const { return Vec2 (x / v.x, y / v.y); } template inline Vec2 Vec2::operator / (T a) const { return Vec2 (x / a, y / a); } template T Vec2::lengthTiny () const { T absX = (x >= T (0))? x: -x; T absY = (y >= T (0))? y: -y; T max = absX; if (max < absY) max = absY; if (max == T (0)) return T (0); // // Do not replace the divisions by max with multiplications by 1/max. // Computing 1/max can overflow but the divisions below will always // produce results less than or equal to 1. // absX /= max; absY /= max; return max * Math::sqrt (absX * absX + absY * absY); } template inline T Vec2::length () const { T length2 = dot (*this); if (length2 < T (2) * limits::smallest()) return lengthTiny(); return Math::sqrt (length2); } template inline T Vec2::length2 () const { return dot (*this); } template const Vec2 & Vec2::normalize () { T l = length(); if (l != T (0)) { // // Do not replace the divisions by l with multiplications by 1/l. // Computing 1/l can overflow but the divisions below will always // produce results less than or equal to 1. // x /= l; y /= l; } return *this; } template const Vec2 & Vec2::normalizeExc () throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); x /= l; y /= l; return *this; } template inline const Vec2 & Vec2::normalizeNonNull () { T l = length(); x /= l; y /= l; return *this; } template Vec2 Vec2::normalized () const { T l = length(); if (l == T (0)) return Vec2 (T (0)); return Vec2 (x / l, y / l); } template Vec2 Vec2::normalizedExc () const throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); return Vec2 (x / l, y / l); } template inline Vec2 Vec2::normalizedNonNull () const { T l = length(); return Vec2 (x / l, y / l); } //----------------------- // Implementation of Vec3 //----------------------- template inline T & Vec3::operator [] (int i) { return (&x)[i]; } template inline const T & Vec3::operator [] (int i) const { return (&x)[i]; } template inline Vec3::Vec3 () { // empty } template inline Vec3::Vec3 (T a) { x = y = z = a; } template inline Vec3::Vec3 (T a, T b, T c) { x = a; y = b; z = c; } template inline Vec3::Vec3 (const Vec3 &v) { x = v.x; y = v.y; z = v.z; } template template inline Vec3::Vec3 (const Vec3 &v) { x = T (v.x); y = T (v.y); z = T (v.z); } template inline const Vec3 & Vec3::operator = (const Vec3 &v) { x = v.x; y = v.y; z = v.z; return *this; } template template inline Vec3::Vec3 (const Vec4 &v) { x = T (v.x / v.w); y = T (v.y / v.w); z = T (v.z / v.w); } template template Vec3::Vec3 (const Vec4 &v, InfException) { T vx = T (v.x); T vy = T (v.y); T vz = T (v.z); T vw = T (v.w); T absW = (vw >= T (0))? vw: -vw; if (absW < 1) { T m = baseTypeMax() * absW; if (vx <= -m || vx >= m || vy <= -m || vy >= m || vz <= -m || vz >= m) throw InfPointExc ("Cannot normalize point at infinity."); } x = vx / vw; y = vy / vw; z = vz / vw; } template template inline void Vec3::setValue (S a, S b, S c) { x = T (a); y = T (b); z = T (c); } template template inline void Vec3::setValue (const Vec3 &v) { x = T (v.x); y = T (v.y); z = T (v.z); } template template inline void Vec3::getValue (S &a, S &b, S &c) const { a = S (x); b = S (y); c = S (z); } template template inline void Vec3::getValue (Vec3 &v) const { v.x = S (x); v.y = S (y); v.z = S (z); } template inline T * Vec3::getValue() { return (T *) &x; } template inline const T * Vec3::getValue() const { return (const T *) &x; } template template inline bool Vec3::operator == (const Vec3 &v) const { return x == v.x && y == v.y && z == v.z; } template template inline bool Vec3::operator != (const Vec3 &v) const { return x != v.x || y != v.y || z != v.z; } template bool Vec3::equalWithAbsError (const Vec3 &v, T e) const { for (int i = 0; i < 3; i++) if (!Imath::equalWithAbsError ((*this)[i], v[i], e)) return false; return true; } template bool Vec3::equalWithRelError (const Vec3 &v, T e) const { for (int i = 0; i < 3; i++) if (!Imath::equalWithRelError ((*this)[i], v[i], e)) return false; return true; } template inline T Vec3::dot (const Vec3 &v) const { return x * v.x + y * v.y + z * v.z; } template inline T Vec3::operator ^ (const Vec3 &v) const { return dot (v); } template inline Vec3 Vec3::cross (const Vec3 &v) const { return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } template inline const Vec3 & Vec3::operator %= (const Vec3 &v) { T a = y * v.z - z * v.y; T b = z * v.x - x * v.z; T c = x * v.y - y * v.x; x = a; y = b; z = c; return *this; } template inline Vec3 Vec3::operator % (const Vec3 &v) const { return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } template inline const Vec3 & Vec3::operator += (const Vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; } template inline Vec3 Vec3::operator + (const Vec3 &v) const { return Vec3 (x + v.x, y + v.y, z + v.z); } template inline const Vec3 & Vec3::operator -= (const Vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; } template inline Vec3 Vec3::operator - (const Vec3 &v) const { return Vec3 (x - v.x, y - v.y, z - v.z); } template inline Vec3 Vec3::operator - () const { return Vec3 (-x, -y, -z); } template inline const Vec3 & Vec3::negate () { x = -x; y = -y; z = -z; return *this; } template inline const Vec3 & Vec3::operator *= (const Vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; } template inline const Vec3 & Vec3::operator *= (T a) { x *= a; y *= a; z *= a; return *this; } template inline Vec3 Vec3::operator * (const Vec3 &v) const { return Vec3 (x * v.x, y * v.y, z * v.z); } template inline Vec3 Vec3::operator * (T a) const { return Vec3 (x * a, y * a, z * a); } template inline const Vec3 & Vec3::operator /= (const Vec3 &v) { x /= v.x; y /= v.y; z /= v.z; return *this; } template inline const Vec3 & Vec3::operator /= (T a) { x /= a; y /= a; z /= a; return *this; } template inline Vec3 Vec3::operator / (const Vec3 &v) const { return Vec3 (x / v.x, y / v.y, z / v.z); } template inline Vec3 Vec3::operator / (T a) const { return Vec3 (x / a, y / a, z / a); } template T Vec3::lengthTiny () const { T absX = (x >= T (0))? x: -x; T absY = (y >= T (0))? y: -y; T absZ = (z >= T (0))? z: -z; T max = absX; if (max < absY) max = absY; if (max < absZ) max = absZ; if (max == T (0)) return T (0); // // Do not replace the divisions by max with multiplications by 1/max. // Computing 1/max can overflow but the divisions below will always // produce results less than or equal to 1. // absX /= max; absY /= max; absZ /= max; return max * Math::sqrt (absX * absX + absY * absY + absZ * absZ); } template inline T Vec3::length () const { T length2 = dot (*this); if (length2 < T (2) * limits::smallest()) return lengthTiny(); return Math::sqrt (length2); } template inline T Vec3::length2 () const { return dot (*this); } template const Vec3 & Vec3::normalize () { T l = length(); if (l != T (0)) { // // Do not replace the divisions by l with multiplications by 1/l. // Computing 1/l can overflow but the divisions below will always // produce results less than or equal to 1. // x /= l; y /= l; z /= l; } return *this; } template const Vec3 & Vec3::normalizeExc () throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); x /= l; y /= l; z /= l; return *this; } template inline const Vec3 & Vec3::normalizeNonNull () { T l = length(); x /= l; y /= l; z /= l; return *this; } template Vec3 Vec3::normalized () const { T l = length(); if (l == T (0)) return Vec3 (T (0)); return Vec3 (x / l, y / l, z / l); } template Vec3 Vec3::normalizedExc () const throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); return Vec3 (x / l, y / l, z / l); } template inline Vec3 Vec3::normalizedNonNull () const { T l = length(); return Vec3 (x / l, y / l, z / l); } //----------------------- // Implementation of Vec4 //----------------------- template inline T & Vec4::operator [] (int i) { return (&x)[i]; } template inline const T & Vec4::operator [] (int i) const { return (&x)[i]; } template inline Vec4::Vec4 () { // empty } template inline Vec4::Vec4 (T a) { x = y = z = w = a; } template inline Vec4::Vec4 (T a, T b, T c, T d) { x = a; y = b; z = c; w = d; } template inline Vec4::Vec4 (const Vec4 &v) { x = v.x; y = v.y; z = v.z; w = v.w; } template template inline Vec4::Vec4 (const Vec4 &v) { x = T (v.x); y = T (v.y); z = T (v.z); w = T (v.w); } template inline const Vec4 & Vec4::operator = (const Vec4 &v) { x = v.x; y = v.y; z = v.z; w = v.w; return *this; } template template inline Vec4::Vec4 (const Vec3 &v) { x = T (v.x); y = T (v.y); z = T (v.z); w = T (1); } template template inline bool Vec4::operator == (const Vec4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; } template template inline bool Vec4::operator != (const Vec4 &v) const { return x != v.x || y != v.y || z != v.z || w != v.w; } template bool Vec4::equalWithAbsError (const Vec4 &v, T e) const { for (int i = 0; i < 4; i++) if (!Imath::equalWithAbsError ((*this)[i], v[i], e)) return false; return true; } template bool Vec4::equalWithRelError (const Vec4 &v, T e) const { for (int i = 0; i < 4; i++) if (!Imath::equalWithRelError ((*this)[i], v[i], e)) return false; return true; } template inline T Vec4::dot (const Vec4 &v) const { return x * v.x + y * v.y + z * v.z + w * v.w; } template inline T Vec4::operator ^ (const Vec4 &v) const { return dot (v); } template inline const Vec4 & Vec4::operator += (const Vec4 &v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } template inline Vec4 Vec4::operator + (const Vec4 &v) const { return Vec4 (x + v.x, y + v.y, z + v.z, w + v.w); } template inline const Vec4 & Vec4::operator -= (const Vec4 &v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } template inline Vec4 Vec4::operator - (const Vec4 &v) const { return Vec4 (x - v.x, y - v.y, z - v.z, w - v.w); } template inline Vec4 Vec4::operator - () const { return Vec4 (-x, -y, -z, -w); } template inline const Vec4 & Vec4::negate () { x = -x; y = -y; z = -z; w = -w; return *this; } template inline const Vec4 & Vec4::operator *= (const Vec4 &v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } template inline const Vec4 & Vec4::operator *= (T a) { x *= a; y *= a; z *= a; w *= a; return *this; } template inline Vec4 Vec4::operator * (const Vec4 &v) const { return Vec4 (x * v.x, y * v.y, z * v.z, w * v.w); } template inline Vec4 Vec4::operator * (T a) const { return Vec4 (x * a, y * a, z * a, w * a); } template inline const Vec4 & Vec4::operator /= (const Vec4 &v) { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } template inline const Vec4 & Vec4::operator /= (T a) { x /= a; y /= a; z /= a; w /= a; return *this; } template inline Vec4 Vec4::operator / (const Vec4 &v) const { return Vec4 (x / v.x, y / v.y, z / v.z, w / v.w); } template inline Vec4 Vec4::operator / (T a) const { return Vec4 (x / a, y / a, z / a, w / a); } template T Vec4::lengthTiny () const { T absX = (x >= T (0))? x: -x; T absY = (y >= T (0))? y: -y; T absZ = (z >= T (0))? z: -z; T absW = (w >= T (0))? w: -w; T max = absX; if (max < absY) max = absY; if (max < absZ) max = absZ; if (max < absW) max = absW; if (max == T (0)) return T (0); // // Do not replace the divisions by max with multiplications by 1/max. // Computing 1/max can overflow but the divisions below will always // produce results less than or equal to 1. // absX /= max; absY /= max; absZ /= max; absW /= max; return max * Math::sqrt (absX * absX + absY * absY + absZ * absZ + absW * absW); } template inline T Vec4::length () const { T length2 = dot (*this); if (length2 < T (2) * limits::smallest()) return lengthTiny(); return Math::sqrt (length2); } template inline T Vec4::length2 () const { return dot (*this); } template const Vec4 & Vec4::normalize () { T l = length(); if (l != T (0)) { // // Do not replace the divisions by l with multiplications by 1/l. // Computing 1/l can overflow but the divisions below will always // produce results less than or equal to 1. // x /= l; y /= l; z /= l; w /= l; } return *this; } template const Vec4 & Vec4::normalizeExc () throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); x /= l; y /= l; z /= l; w /= l; return *this; } template inline const Vec4 & Vec4::normalizeNonNull () { T l = length(); x /= l; y /= l; z /= l; w /= l; return *this; } template Vec4 Vec4::normalized () const { T l = length(); if (l == T (0)) return Vec4 (T (0)); return Vec4 (x / l, y / l, z / l, w / l); } template Vec4 Vec4::normalizedExc () const throw (Iex::MathExc) { T l = length(); if (l == T (0)) throw NullVecExc ("Cannot normalize null vector."); return Vec4 (x / l, y / l, z / l, w / l); } template inline Vec4 Vec4::normalizedNonNull () const { T l = length(); return Vec4 (x / l, y / l, z / l, w / l); } //----------------------------- // Stream output implementation //----------------------------- template std::ostream & operator << (std::ostream &s, const Vec2 &v) { return s << '(' << v.x << ' ' << v.y << ')'; } template std::ostream & operator << (std::ostream &s, const Vec3 &v) { return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ')'; } template std::ostream & operator << (std::ostream &s, const Vec4 &v) { return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ' ' << v.w << ')'; } //----------------------------------------- // Implementation of reverse multiplication //----------------------------------------- template inline Vec2 operator * (T a, const Vec2 &v) { return Vec2 (a * v.x, a * v.y); } template inline Vec3 operator * (T a, const Vec3 &v) { return Vec3 (a * v.x, a * v.y, a * v.z); } template inline Vec4 operator * (T a, const Vec4 &v) { return Vec4 (a * v.x, a * v.y, a * v.z, a * v.w); } #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER #pragma warning(pop) #endif } // namespace Imath #endif