You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/RC/ResourceCompilerPC/AdjustRotLog.h

80 lines
3.0 KiB
C

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H
#pragma once
inline double DLength (const Vec3& v)
{
return sqrt (double(v.x) * double(v.x) + double(v.y) * double(v.y) + double(v.z) * double(v.z));
}
//////////////////////////////////////////////////////////////////////////
// Given the rotations in logarithmic space, adjusts the target rotation so
// that it's the same in rotational group, but the closest to the reference
// in the QLog space.
inline void AdjustRotLog (Vec3& vTgt, const Vec3& vRef)
{
double dLenTgt = DLength(vTgt);
const double dPi = 3.1415926535897932384626433832795;
if (dLenTgt < 1e-4)
{
// the target is very small rotation, so the algorithm is to find
// ANY vector of length n*PI closest to the vRef point
double dLenRef = DLength(vRef);
if (dLenRef > dPi / 2) // Otherwise the vRef vector is small enough not to make any adjustments
{
double f = (dPi * floor(dLenRef / dPi + 0.5) / dLenRef);
vTgt.x = float(vRef.x * f);
vTgt.y = float(vRef.y * f);
vTgt.z = float(vRef.z * f);
}
}
else
{
// the target is big enough rotation to pick the rotation axis out
// find the projection of the reference to the target axis
// then find the target (projection) mod PI
// there are basically three possibilities: the new target is in the same PI interval
// as the reference projection, in the next or in the previous. Find the closest.
double dProjRef = (vRef * vTgt) / dLenTgt;
double dModTgt = fmod (dLenTgt, dPi);
if (dModTgt < 0)
{
dModTgt += dPi;
}
assert (dModTgt >= 0 && dModTgt < dPi);
double dBaseTgt = dPi * floor (dProjRef / dPi + 0.5);
double dNewTgtR = dBaseTgt + dModTgt;
double dNewTgtL = dBaseTgt + dModTgt - dPi;
double dNewTgt = (fabs(dNewTgtR - dProjRef) < fabs(dNewTgtL - dProjRef))
? dNewTgtR : dNewTgtL;
assert (fabs(dNewTgt + dPi - dProjRef) > fabs(dNewTgt - dProjRef));
assert (fabs(dNewTgt - dPi - dProjRef) > fabs(dNewTgt - dProjRef));
double f = (dNewTgt / dLenTgt);
vTgt.x = float(vTgt.x * f);
vTgt.y = float(vTgt.y * f);
vTgt.z = float(vTgt.z * f);
}
}
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H