/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SE_INCL_VECTOR_H #define SE_INCL_VECTOR_H #ifdef PRAGMA_ONCE #pragma once #endif #include #include #include #include #include /* * Template class for vector of arbitrary dimensions and arbitrary type of members */ template class Vector { public: Type vector[iDimensions]; // array that holds the members public: /* Default constructor. */ __forceinline Vector(void); /* Constructor from coordinates. */ __forceinline Vector(Type x1); __forceinline Vector(Type x1, Type x2); __forceinline Vector(Type x1, Type x2, Type x3); __forceinline Vector(Type x1, Type x2, Type x3, Type x4); /* Clear function */ __forceinline void Clear(void) {}; /* Conversion into scalar -- length of vector (Euclidian norm). */ __forceinline Type Length(void) const; /* Conversion into scalar -- Manhattan norm of vector. */ __forceinline Type ManhattanNorm(void) const; /* Conversion into scalar -- Max norm of vector. */ __forceinline Type MaxNorm(void) const; /* Reference vector member by it's index (1-based indices!). */ __forceinline Type &operator()(int i); __forceinline const Type &operator()(int i) const; /* Normalize vector, i.e. make it a unit vector. */ __forceinline Vector &Normalize(void); __forceinline Vector &SafeNormalize(void); // gives vector with (0,0,0) orientation if input is too small /* Mathematical operators. */ // unary minus __forceinline Vector &Flip(void); __forceinline Vector operator-(void) const; // between two vectors __forceinline Vector operator+(const Vector &vector2) const; __forceinline Vector &operator+=(const Vector &vector2); __forceinline Vector operator-(const Vector &vector2) const; __forceinline Vector &operator-=(const Vector &vector2); // multiplication with scalar __forceinline Vector &operator*=(const Type scalar); __forceinline Vector operator*(const Type scalar) const; // division with scalar __forceinline Vector &operator/=(const Type scalar); __forceinline Vector operator/(const Type scalar) const; // multiplication by a square matrix (sides swapped -- see implementation for notes) __forceinline Vector &operator*=(const Matrix &matrix2); __forceinline Vector operator*(const Matrix &matrix2) const; // scalar product - dot product, inner product __forceinline Type operator%(const Vector &vector2) const; // vector product - cross product, outer product __forceinline Vector &operator*=(const Vector &vector2); __forceinline Vector operator*(const Vector &vector2) const; // comparing vectors __forceinline BOOL operator==(const Vector &vector2) const; __forceinline BOOL operator!=(const Vector &vector2) const; /* Stream operations */ friend __forceinline CTStream &operator>>(CTStream &strm, Vector &vector) { for (SLONG i = 0; i < iDimensions; i++) strm>>vector.vector[i]; return strm; } friend __forceinline CTStream &operator<<(CTStream &strm, const Vector &vector) { for (SLONG i = 0; i < iDimensions; i++) strm< __forceinline Vector::Vector(void) {} /* * Constructor from coordinates. */ template __forceinline Vector::Vector(Type x1) { ASSERT(iDimensions==1); (*this)(1)=x1; } template __forceinline Vector::Vector(Type x1, Type x2) { ASSERT(iDimensions==2); (*this)(1)=x1; (*this)(2)=x2; } template __forceinline Vector::Vector(Type x1, Type x2, Type x3) { ASSERT(iDimensions==3); (*this)(1)=x1; (*this)(2)=x2; (*this)(3)=x3; } template __forceinline Vector::Vector(Type x1, Type x2, Type x3, Type x4) { ASSERT(iDimensions==4); (*this)(1)=x1; (*this)(2)=x2; (*this)(3)=x3; (*this)(4)=x4; } /* * Conversion into scalar -- length of vector. */ template<> __forceinline FLOAT Vector::Length(void) const { return (FLOAT)sqrt( (DOUBLE)((*this)(1)*(*this)(1) + (*this)(2)*(*this)(2) + (*this)(3)*(*this)(3))); } template<> __forceinline DOUBLE Vector::Length(void) const { return (DOUBLE)sqrt( (DOUBLE)((*this)(1)*(*this)(1) + (*this)(2)*(*this)(2) + (*this)(3)*(*this)(3))); } template __forceinline Type Vector::Length(void) const { Type result=(Type)0; for(int i=1; i<=iDimensions; i++) { result += (*this)(i) * (*this)(i); } return (Type)sqrt((DOUBLE)result); } /* * Conversion into scalar -- Manhattan norm of vector. */ template __forceinline Type Vector::ManhattanNorm(void) const { Type result=(Type)0; for(int i=1; i<=iDimensions; i++) { result += Abs((*this)(i)); } return result; } /* * Conversion into scalar -- Max norm of vector. */ template __forceinline Type Vector::MaxNorm(void) const { Type result=(Type)0; for(int i=1; i<=iDimensions; i++) { result = Max(result, Abs((*this)(i))); } return result; } /* * Reference vector member by it's index (1-based indices!). */ template __forceinline Type &Vector::operator()(int i) { // check boundaries (indices start at 1, not at 0) ASSERT(i>=1 && i<=iDimensions); // return vector member reference return vector[i-1]; } template __forceinline const Type &Vector::operator()(int i) const { // check boundaries (indices start at 1, not at 0) ASSERT(i>=1 && i<=iDimensions); // return vector member reference return vector[i-1]; } /* * Normalize vector, i.e. make it a unit vector. */ template __forceinline Vector &Vector::Normalize(void) { // Normalizing a vector of a very small length can be very unprecise! // ASSERT(((Type)*this) > 0.001); *this/=Length(); return *this; } // gives vector with (0,0,0) orientation if input is too small template __forceinline Vector &Vector::SafeNormalize(void) { Type tLen = Length(); if (tLen<1E-6f) { if (iDimensions==2) { *this = Vector(1,0); } else { *this = Vector(0,0,-1); } } else { *this/=tLen; } return *this; } // unary minus FLOAT3D template<> __forceinline Vector &Vector::Flip(void) { (*this)(1) = -(*this)(1); (*this)(2) = -(*this)(2); (*this)(3) = -(*this)(3); return *this; } // unary minus DOUBLE3D template<> __forceinline Vector &Vector::Flip(void) { (*this)(1) = -(*this)(1); (*this)(2) = -(*this)(2); (*this)(3) = -(*this)(3); return *this; } // unary minus template __forceinline Vector &Vector::Flip(void) { // flip member by member ASSERT( iDimensions!=3); // 3 is optimized special case for(int iDimension=1; iDimension<=iDimensions; iDimension++) { (*this)(iDimension) = -(*this)(iDimension); } return *this; } template __forceinline Vector Vector::operator-(void) const { return Vector(*this).Flip(); } // sum of two vectors FLOAT3D template<> __forceinline Vector &Vector::operator+=(const Vector &vector2) { // add member by member (*this)(1) += vector2(1); (*this)(2) += vector2(2); (*this)(3) += vector2(3); return *this; } // sum of two vectors DOUBLE3D template<> __forceinline Vector &Vector::operator+=(const Vector &vector2) { // add member by member (*this)(1) += vector2(1); (*this)(2) += vector2(2); (*this)(3) += vector2(3); return *this; } // sum of two vectors template __forceinline Vector &Vector::operator+=(const Vector &vector2) { // add member by member ASSERT( iDimensions!=3); // 3 is optimized special case for(int iDimension=1; iDimension<=iDimensions; iDimension++) { (*this)(iDimension) += vector2(iDimension); } return *this; } template __forceinline Vector Vector::operator+(const Vector &vector2) const { return Vector(*this)+=vector2; } // difference of two vectors FLOAT3D template<> __forceinline Vector &Vector::operator-=(const Vector &vector2) { // add member by member (*this)(1) -= vector2(1); (*this)(2) -= vector2(2); (*this)(3) -= vector2(3); return *this; } // difference of two vectors DOUBLE3D template<> __forceinline Vector &Vector::operator-=(const Vector &vector2) { // add member by member (*this)(1) -= vector2(1); (*this)(2) -= vector2(2); (*this)(3) -= vector2(3); return *this; } // difference of two vectors template __forceinline Vector &Vector::operator-=(const Vector &vector2) { // sub member by member ASSERT( iDimensions!=3); // 3 is optimized special case for(int iDimension=1; iDimension<=iDimensions; iDimension++) { (*this)(iDimension) -= vector2(iDimension); } return *this; } template __forceinline Vector Vector::operator-(const Vector &vector2) const { return Vector(*this)-=vector2; } // multiplication with scalar FLOAT3D template<> __forceinline Vector &Vector::operator*=(const FLOAT scalar) { (*this)(1) *= scalar; (*this)(2) *= scalar; (*this)(3) *= scalar; return *this; } // multiplication with scalar DOUBLE3D template<> __forceinline Vector &Vector::operator*=(const DOUBLE scalar) { (*this)(1) *= scalar; (*this)(2) *= scalar; (*this)(3) *= scalar; return *this; } // multiplication with scalar template __forceinline Vector &Vector::operator*=(const Type scalar) { ASSERT( iDimensions!=3); // 3 is optimized special case for( int i=1; i<=iDimensions; i++) (*this)(i) *= scalar; return *this; } template __forceinline Vector Vector::operator*(const Type scalar) const { return Vector(*this) *= scalar; } // division with scalar FLOAT3D template<> __forceinline Vector &Vector::operator/=(const FLOAT scalar) { const FLOAT rcp = 1.0f/scalar; (*this)(1) *= rcp; (*this)(2) *= rcp; (*this)(3) *= rcp; return *this; } // division with scalar DOUBLE3D template<> __forceinline Vector &Vector::operator/=(const DOUBLE scalar) { const DOUBLE rcp = 1.0/scalar; (*this)(1) *= rcp; (*this)(2) *= rcp; (*this)(3) *= rcp; return *this; } // division with scalar template __forceinline Vector &Vector::operator/=(const Type scalar) { ASSERT( iDimensions!=3); // 3 is optimized special case for( int i=1; i<=iDimensions; i++) (*this)(i) /= scalar; return *this; } template __forceinline Vector Vector::operator/(const Type scalar) const { return Vector(*this) /= scalar; } /* * Multiplication of a vector by a square matrix. */ // NOTE: The matrix should have been on the left side of the vector, but the template syntax wouldn't allow that. template<> __forceinline Vector Vector::operator*(const Matrix &matrix2) const { Vector result; result(1) = matrix2(1,1) * (*this)(1) + matrix2(1,2) * (*this)(2) + matrix2(1,3) * (*this)(3); result(2) = matrix2(2,1) * (*this)(1) + matrix2(2,2) * (*this)(2) + matrix2(2,3) * (*this)(3); result(3) = matrix2(3,1) * (*this)(1) + matrix2(3,2) * (*this)(2) + matrix2(3,3) * (*this)(3); return result; } template<> __forceinline Vector Vector::operator*(const Matrix &matrix2) const { Vector result; result(1) = matrix2(1,1) * (*this)(1) + matrix2(1,2) * (*this)(2) + matrix2(1,3) * (*this)(3); result(2) = matrix2(2,1) * (*this)(1) + matrix2(2,2) * (*this)(2) + matrix2(2,3) * (*this)(3); result(3) = matrix2(3,1) * (*this)(1) + matrix2(3,2) * (*this)(2) + matrix2(3,3) * (*this)(3); return result; } template __forceinline Vector &Vector::operator*=(const Matrix &matrix2) { (*this) = (*this) * matrix2; return *this; } template __forceinline Vector Vector::operator*(const Matrix &matrix2) const { ASSERT( iDimensions!=3); // 3 is optimized special case Vector result; for(int iRow=1; iRow<=iDimensions; iRow++) { result(iRow) = (Type)0; for(int s=1; s<=iDimensions; s++) { result(iRow) += matrix2(iRow, s) * (*this)(s); } } return result; } // scalar product - dot product, inner product for FLOAT3D template<> __forceinline FLOAT Vector::operator%(const Vector &vector2) const { return (FLOAT)((*this)(1)*vector2(1) + (*this)(2)*vector2(2) + (*this)(3)*vector2(3)); } // scalar product - dot product, inner product for DOUBLE3D template<> __forceinline DOUBLE Vector::operator%(const Vector &vector2) const { return (DOUBLE)((*this)(1)*vector2(1) + (*this)(2)*vector2(2) + (*this)(3)*vector2(3)); } // scalar product - dot product, inner product template __forceinline Type Vector::operator%(const Vector &vector2) const { ASSERT( iDimensions!=3); // 3 is optimized special case Type result=(Type)0; for(int i=1; i<=iDimensions; i++) { result += (*this)(i) * vector2(i); } return result; } // vector product - cross product, outer product /* Formula: C=A*B Cx = Ay*Bz - Az*By Cy = Az*Bx - Ax*Bz Cz = Ax*By - Ay*Bx */ template __forceinline Vector &Vector::operator*=(const Vector &vector2) { (*this) = (*this) * vector2; return *this; } template __forceinline Vector Vector::operator*(const Vector &vector2) const { Vector result; ASSERT(iDimensions==3); // cross product is defined only for 3D vectors result(1) = (*this)(2)*vector2(3) - (*this)(3)*vector2(2); result(2) = (*this)(3)*vector2(1) - (*this)(1)*vector2(3); result(3) = (*this)(1)*vector2(2) - (*this)(2)*vector2(1); return result; } // comparation FLOAT3D template<> __forceinline BOOL Vector::operator==(const Vector &vector2) const { return( (*this)(1)==vector2(1) && (*this)(2)==vector2(2) && (*this)(3)==vector2(3)); } // comparation DOUBLE3D template<> __forceinline BOOL Vector::operator==(const Vector &vector2) const { return( (*this)(1)==vector2(1) && (*this)(2)==vector2(2) && (*this)(3)==vector2(3)); } // comparation template __forceinline BOOL Vector::operator==(const Vector &vector2) const { ASSERT( iDimensions!=3); // 3 is optimized special case for(int i=1; i<=iDimensions; i++) { if( (*this)(i) != vector2(i)) return FALSE; } return TRUE; } template __forceinline BOOL Vector::operator!=(const Vector &vector2) const { return !(*this == vector2); } // helper functions for converting between FLOAT and DOUBLE vectors __forceinline DOUBLE3D FLOATtoDOUBLE(const FLOAT3D &vf) { return DOUBLE3D(FLOATtoDOUBLE(vf(1)), FLOATtoDOUBLE(vf(2)), FLOATtoDOUBLE(vf(3))); } __forceinline FLOAT3D DOUBLEtoFLOAT(const DOUBLE3D &vd) { return FLOAT3D(DOUBLEtoFLOAT(vd(1)), DOUBLEtoFLOAT(vd(2)), DOUBLEtoFLOAT(vd(3))); } #endif /* include-once check. */