123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "math/mRotation.h"
- #include "console/console.h"
- #include "console/engineAPI.h"
- #include "math/mathUtils.h"
- #ifdef TORQUE_TESTS_ENABLED
- #include "testing/unitTesting.h"
- #endif
- //====================================================================
- //Eulers setup
- //====================================================================
- RotationF::RotationF(EulerF _euler, UnitFormat format)
- {
- set(_euler.x, _euler.y, _euler.z, format);
- }
- RotationF::RotationF(F32 _x, F32 _y, F32 _z, UnitFormat format)
- {
- set(_x, _y, _z, format);
- }
- void RotationF::set(EulerF _euler, UnitFormat format)
- {
- x = format == Degrees ? mDegToRad(_euler.x) : _euler.x;
- y = format == Degrees ? mDegToRad(_euler.y) : _euler.y;
- z = format == Degrees ? mDegToRad(_euler.z) : _euler.z;
- mRotationType = Euler;
- }
- void RotationF::set(F32 _x, F32 _y, F32 _z, UnitFormat format)
- {
- EulerF tempEul;
- if (format == Degrees)
- {
- tempEul.set(mDegToRad(_x), mDegToRad(_y), mDegToRad(_z));
- }
- else
- {
- tempEul.set(_x, _y, _z);
- }
- set(tempEul);
- }
- //====================================================================
- //AxisAngle setup
- //====================================================================
- RotationF::RotationF(AngAxisF _aa, UnitFormat format)
- {
- set(_aa, format);
- }
- void RotationF::set(AngAxisF _aa, UnitFormat format)
- {
- x = _aa.axis.x;
- y = _aa.axis.y;
- z = _aa.axis.z;
- w = format == Degrees ? mDegToRad(_aa.angle) : _aa.angle;
- mRotationType = AxisAngle;
- }
- //====================================================================
- //QuatF setup
- //====================================================================
- RotationF::RotationF(QuatF _quat)
- {
- set(_quat);
- }
- void RotationF::set(QuatF _quat)
- {
- AngAxisF tmpAA;
- tmpAA.set(_quat);
- set(tmpAA);
- }
- //====================================================================
- //MatrixF setup
- //====================================================================
- RotationF::RotationF(MatrixF _mat)
- {
- set(_mat);
- }
- void RotationF::set(MatrixF _mat)
- {
- set(_mat.toEuler());
- }
- //
- inline F32 RotationF::len() const
- {
- return asEulerF().len();
- }
- inline void RotationF::interpolate(const RotationF& _from, const RotationF& _to, F32 _factor)
- {
- QuatF tmpQuat;
- tmpQuat.interpolate(_from.asQuatF(), _to.asQuatF(), _factor);
- set(tmpQuat);
- }
- void RotationF::lookAt(const Point3F& _origin, const Point3F& _target, const Point3F& _up)
- {
- MatrixF mat;
- VectorF newForward = _target - _origin;
- newForward.normalize();
- VectorF up(0.0f, 0.0f, 1.0f);
- VectorF axisX;
- VectorF axisY = newForward;
- VectorF axisZ;
- if (_up != VectorF::Zero)
- up = _up;
- // Validate and normalize input:
- F32 lenSq;
- lenSq = axisY.lenSquared();
- if (lenSq < 0.000001f)
- {
- //degenerate forward vector
- axisY.set(0.0f, 1.0f, 0.0f);
- }
- else
- {
- axisY /= mSqrt(lenSq);
- }
- lenSq = up.lenSquared();
- if (lenSq < 0.000001f)
- {
- //degenerate up vector - too small
- up.set(0.0f, 0.0f, 1.0f);
- }
- else
- {
- up /= mSqrt(lenSq);
- }
- if (fabsf(mDot(up, axisY)) > 0.9999f)
- {
- //degenerate up vector - same as forward
- F32 tmp = up.x;
- up.x = -up.y;
- up.y = up.z;
- up.z = tmp;
- }
- // construct the remaining axes:
- mCross(axisY, up, &axisX);
- mCross(axisX, axisY, &axisZ);
- mat.setColumn(0, axisX);
- mat.setColumn(1, axisY);
- mat.setColumn(2, axisZ);
- set(mat);
- }
- VectorF RotationF::getDirection()
- {
- VectorF dir;
- EulerF angles = asEulerF();
- MathUtils::getVectorFromAngles(dir, angles.z, angles.x);
- return dir;
- }
- //========================================================
- EulerF RotationF::asEulerF(UnitFormat _format) const
- {
- if (mRotationType == Euler)
- {
- if (_format == Degrees)
- {
- return EulerF(mRadToDeg(x), mRadToDeg(y), mRadToDeg(z));
- }
- else
- {
- return EulerF(x, y, z);
- }
- }
- else
- {
- EulerF returnEuler = asMatrixF().toEuler();
- if (_format == Degrees)
- {
- returnEuler.x = mRadToDeg(returnEuler.x);
- returnEuler.y = mRadToDeg(returnEuler.y);
- returnEuler.z = mRadToDeg(returnEuler.z);
- }
- return returnEuler;
- }
- }
- AngAxisF RotationF::asAxisAngle(UnitFormat format) const
- {
- AngAxisF returnAA;
- if (mRotationType == Euler)
- {
- returnAA.set(EulerF(x, y, z));
- }
- else
- {
- returnAA.set(Point3F(x, y, z), w);
- }
- if (format == Radians)
- {
- returnAA.angle = mDegToRad(returnAA.angle);
- }
- return returnAA;
- }
- MatrixF RotationF::asMatrixF() const
- {
- MatrixF returnMat;
- if (mRotationType == Euler)
- {
- MatrixF imat, xmat, ymat, zmat;
- xmat.set(EulerF(x, 0, 0));
- ymat.set(EulerF(0.0f, y, 0.0f));
- zmat.set(EulerF(0, 0, z));
- imat.mul(zmat, xmat);
- returnMat.mul(imat, ymat);
- }
- else
- {
- AngAxisF aa;
- aa.set(Point3F(x, y, z), w);
- MatrixF tempMat;
- aa.setMatrix(&tempMat);
- EulerF eul = tempMat.toEuler();
- MatrixF imat, xmat, ymat, zmat;
- xmat.set(EulerF(eul.x, 0, 0));
- ymat.set(EulerF(0.0f, eul.y, 0.0f));
- zmat.set(EulerF(0, 0, eul.z));
- imat.mul(zmat, xmat);
- returnMat.mul(imat, ymat);
- }
- return returnMat;
- }
- QuatF RotationF::asQuatF() const
- {
- QuatF returnQuat;
- if (mRotationType == Euler)
- {
- returnQuat.set(EulerF(x, y, z));
- }
- else
- {
- AngAxisF aa;
- aa.set(Point3F(x, y, z), w);
- returnQuat.set(aa);
- }
- return returnQuat;
- }
- void RotationF::normalize()
- {
- if (mRotationType == Euler)
- {
- EulerF eul = EulerF(x, y, z);
- eul.normalize();
- set(eul);
- }
- else
- {
- QuatF quat;
- quat.set(Point3F(x, y, z), w);
- quat.normalize();
- set(quat);
- }
- }
- //Testing
- #ifdef TORQUE_TESTS_ENABLED
- TEST(Maths, RotationF_Calculations)
- {
- //TODO: implement unit test
- };
- #endif
- DefineEngineFunction(AddRotation, RotationF, (RotationF a, RotationF b, const char* returnType), ("Euler"),
- "Adds two rotations together.\n"
- "@param a Rotation one."
- "@param b Rotation two."
- "@returns v sum of both rotations."
- "@ingroup Math")
- {
- RotationF ret;
- RotationF sum = a + b;
- if (String(returnType) == String("Euler"))
- ret.set(sum.asEulerF());
- else
- ret.set(sum.asAxisAngle());
- return ret;
- }
-
- DefineEngineFunction(SubtractRotation, RotationF, (RotationF a, RotationF b), ,
- "Subtracts two rotations.\n"
- "@param a Rotation one."
- "@param b Rotation two."
- "@returns v difference of both rotations."
- "@ingroup Math")
- {
- return a - b;
- }
-
- DefineEngineFunction(InterpolateRotation, RotationF, (RotationF a, RotationF b, F32 factor), ,
- "Interpolates between two rotations.\n"
- "@param a Rotation one."
- "@param b Rotation two."
- "@param factor The amount to interpolate between the two."
- "@returns v, interpolated result."
- "@ingroup Math")
- {
- RotationF result;
- result.interpolate(a, b, factor);
- return result;
- }
-
- DefineEngineFunction(RotationLookAt, RotationF, (Point3F origin, Point3F target, Point3F up),
- (Point3F(0, 0, 0), Point3F(0, 0, 0), Point3F(0, 0, 1)),
- "Provides a rotation orientation to look at a target from a given position.\n"
- "@param origin Position of the object doing the looking."
- "@param target Position to be looked at."
- "@param up The up angle to orient the rotation."
- "@returns v orientation result."
- "@ingroup Math")
- {
- RotationF result;
- result.lookAt(origin, target, up);
- return result;
- }
- DefineEngineFunction(setRotationRightVector, RotationF, (RotationF rot, VectorF rightVec), ,
- "Sets the right vector of the rotation.\n"
- "@param Starting rotation."
- "@param New up vector."
- "@returns New rotation with the set right vector."
- "@ingroup Math")
- {
- rot.asMatrixF().setColumn(0, rightVec);
- return rot;
- }
- DefineEngineFunction(setRotationUpVector, RotationF, (RotationF rot, VectorF upVec), ,
- "Sets the up vector of the rotation.\n"
- "@param Starting rotation."
- "@param New up vector."
- "@returns New rotation with the set up vector."
- "@ingroup Math")
- {
- rot.asMatrixF().setColumn(2, upVec);
- return rot;
- }
- DefineEngineFunction(getRotationForwardVector, VectorF, (RotationF rot), ,
- "Get the forward vector of a rotation.\n"
- "@ingroup Math")
- {
- return rot.asMatrixF().getForwardVector();
- }
- DefineEngineFunction(getRotationRightVector, VectorF, (RotationF rot), ,
- "Gets the right vector of a rotation.\n"
- "@param Our rotation."
- "@ingroup Math")
- {
- return rot.asMatrixF().getRightVector();
- }
- DefineEngineFunction(getRotationUpVector, VectorF, (RotationF rot), ,
- "Gets the up vector of a rotation.\n"
- "@param Our rotation."
- "@ingroup Math")
- {
- return rot.asMatrixF().getUpVector();
- }
- DefineEngineFunction(getRotationDirection, Point3F, (RotationF rot),,
- "Gets the direction from the rotation's angles.\n"
- "@param Our rotation."
- "@ingroup Math")
- {
- return rot.getDirection();
- }
|