/***************************************************************************** ** ** ** Neversoft Entertainment ** ** ** ** Copyright (C) 1999 - All Rights Reserved ** ** ** ****************************************************************************** ** ** ** Project: Core Library ** ** ** ** Module: Vector (MTH) ** ** ** ** File name: vector.cpp ** ** ** ** Created by: 11/24/99 - Mick ** ** ** ** Description: Math Library code ** ** ** *****************************************************************************/ /***************************************************************************** ** Includes ** *****************************************************************************/ #include #include //#include #include #include #include #include #include #include /***************************************************************************** ** DBG Information ** *****************************************************************************/ namespace Mth { /***************************************************************************** ** DBG Information ** *****************************************************************************/ // /***************************************************************************** ** Externals ** *****************************************************************************/ /***************************************************************************** ** Defines ** *****************************************************************************/ /***************************************************************************** ** Private Types ** *****************************************************************************/ /***************************************************************************** ** Private Data ** *****************************************************************************/ /***************************************************************************** ** Public Data ** *****************************************************************************/ /***************************************************************************** ** Private Prototypes ** *****************************************************************************/ /***************************************************************************** ** Private Functions ** *****************************************************************************/ /***************************************************************************** ** Public Functions ** *****************************************************************************/ Vector& Vector::RotateY90( ERot90 angle ) { float temp; switch (angle) { case ROT_0: break; case ROT_90: temp = col[X]; col[X] = col[Z]; col[Z] = -temp; break; case ROT_180: col[X] = -col[X]; col[Z] = -col[Z]; break; case ROT_270: temp = col[X]; col[X] = -col[Z]; col[Z] = temp; break; default: Dbg_MsgAssert(0, ("Vector::RotateY90() out of range: %d", angle)); break; } return *this; } /***************************************************************************** // Project the vector onto the plane define by a normal *****************************************************************************/ Vector& Vector::ProjectToPlane(const Vector& normal) { float perp_component = Mth::DotProduct(*this,normal); *this -= normal * perp_component; return *this; } Vector& Vector::RotateToPlane(const Vector& normal) { // get the length of the vector float length = Length(); // Project the vector onto the plane ProjectToPlane(normal); // now we've projected it ontot he plane // we need to handle the case where it dissapears into a point // which would indicate that we were perpendicular to the plane // so need to get an arbitary vector in the plane float projected_length = Length(); if (projected_length == 0.0f) // is this a valid comparision? { // Rotate vector through -90 degrees about Y then +90 about X col[X] = -normal[Z]; col[Y] = normal[X]; col[Z] = -normal[Y]; } // get unit vector in this direction Normalize(); // multiply by original speed to rotate velocity onto plane *this *= length; col[W] = 0.0f; // clean up W, otherwise multilications will accumelate over time... return *this; } Vector& Vector::RotateToNormal(const Vector& normal) { *this = normal*Length(); return *this; } Vector& Vector::ProjectToNormal(const Vector& normal) { float dot = Mth::DotProduct(*this,normal); *this = normal * dot; return *this; } /* Finds the largest contributor to the length of the vector... If you pass in whichAxis, it will fill it in with which axis is the max... */ float Vector::GetMaxAxis( int *whichAxis ) { int which_axis; if ( !whichAxis ) { whichAxis = &which_axis; } *whichAxis = X; if ( Abs( this->col[ Y ] ) > Abs( this->col[ X ] ) ) { if ( Abs( this->col[ Z ] ) > Abs( this->col[ Y ] ) ) *whichAxis = Z; else *whichAxis = Y; } else if ( Abs( this->col[ Z ] ) > Abs( this->col[ X ] ) ) { *whichAxis = Z; } return ( this->col[ *whichAxis ] ); } void Vector::DegreesToRadians( void ) { this->col[ X ] = DEGREES_TO_RADIANS( this->col[ X ] ); this->col[ Y ] = DEGREES_TO_RADIANS( this->col[ Y ] ); this->col[ Z ] = DEGREES_TO_RADIANS( this->col[ Z ] ); } void Vector::RadiansToDegrees( void ) { this->col[ X ] = RADIANS_TO_DEGREES( this->col[ X ] ); this->col[ Y ] = RADIANS_TO_DEGREES( this->col[ Y ] ); this->col[ Z ] = RADIANS_TO_DEGREES( this->col[ Z ] ); } void Vector::FeetToInches( void ) { this->col[ X ] = FEET_TO_INCHES( this->col[ X ] ); this->col[ Y ] = FEET_TO_INCHES( this->col[ Y ] ); this->col[ Z ] = FEET_TO_INCHES( this->col[ Z ] ); } // convert to 3d studio max coords ( Z+ up, Y- forward, X to the right... ) void Vector::ConvertToMaxCoords( void ) { this->col[ X ] = -this->col[ X ]; float temp = this->col[ Y ]; this->col[ Y ] = -this->col[ Z ]; this->col[ Z ] = temp; } // convert to 3d studio max coords ( Z+ up, Y- forward, X to the right... ) void Vector::ConvertFromMaxCoords( void ) { this->col[ X ] = -this->col[ X ]; float temp = this->col[ Y ]; this->col[ Y ] = this->col[ Z ]; this->col[ Z ] = -temp; } float GetAngle( const Matrix ¤tOrientation, const Vector &desiredHeading, int headingAxis, int rotAxis ) { Dbg_MsgAssert( headingAxis == X || headingAxis == Y || headingAxis == Z,( "Improper heading axis." )); Dbg_MsgAssert( rotAxis == X || rotAxis == Y || rotAxis == Z,( "Improper rot axis." )); Dbg_MsgAssert( rotAxis != headingAxis,( "Can't use heading axis as rot axis." )); Mth::Vector tempHeading = desiredHeading; tempHeading.ProjectToPlane( currentOrientation[ rotAxis ] ); if ( !tempHeading.Length( ) ) { // If our rot axis is along Y, for example, the // target heading is right above us... Can't pick // a rotation! return ( 0.0f ); } tempHeading.Normalize( ); // while we have these two vectors, find the angle between them... float angCos = DotProduct( currentOrientation[ headingAxis ], tempHeading ); // Mick: contrain Dot product to range -1.0f to +1.0f, since FP innacuracies might // make it go outside this range // (previously this was done only on NGC. Not sure why it has started failing now // but it seems logical that it would fail occasionally, so this check is necessary) float ang = angCos; if ( ang > 1.0f ) ang = 1.0f; if ( ang < -1.0f ) ang = -1.0f; float retVal = -acosf( ang ); Mth::Vector temp = Mth::CrossProduct( currentOrientation[ headingAxis ], tempHeading ); // check to see if the cross product is in the same quatrant as our rot axis... // if so, gots to rotate the other way and shit like that... int whichAxis; float tempMax = temp.GetMaxAxis( &whichAxis ); if ( ( tempMax > 0 ) == ( currentOrientation[ rotAxis ][ whichAxis ] > 0 ) ) { return ( -retVal ); } return ( retVal ); } float GetAngle(Vector &v1, Vector &v2) { Vector a=v1; Vector b=v2; a.Normalize(); b.Normalize(); float dot = Mth::DotProduct(a,b); if ( dot > 1.0f ) dot = 1.0f; if ( dot < -1.0f ) dot = -1.0f; return Mth::RadToDeg(acosf(dot)); } // Returns true if the angle between a and b is greater than the passed Angle. bool AngleBetweenGreaterThan(const Vector& a, const Vector& b, float Angle) { float dot=Mth::DotProduct(a,b); float len=a.Length(); if (len<0.5f) { return false; } dot/=len; len=b.Length(); if (len<0.5f) { return false; } dot/=len; float TestAngleCosine=cosf(Mth::DegToRad(Angle)); if (dot>=0.0f) { return dot=0.0f) { return true; } else { return dot