# How can I support the clamping of quaternion-based rotations?

Currently I have an orbiting camera that fixates on a single point. In the node-based structure, _cameraNode is a child of _cameraTargetNode. I am able to orbit around the target node via the following code snippet:

Urho3D::Quaternion rotY = Urho3D::Quaternion(1.f, Urho3D::Vector3(dy, 0.f, 0.f));
Urho3D::Quaternion rotX = Urho3D::Quaternion(1.f, Urho3D::Vector3(0.f, dx, 0.f));

Urho3D::Vector3 curPos = _cameraNode->GetTransform().Inverse().Translation();

_cameraNode->RotateAround(curPos, rotY, Urho3D::TS_LOCAL);
_cameraNode->RotateAround(Urho3D::Vector3::ZERO, rotX, Urho3D::TS_PARENT);

cameraNode->LookAt(Urho3D::Vector3::ZERO, Urho3D::Vector3::UP, Urho3D::TS_PARENT);


Now what I want to do is clamp this movement. I want to be able to orbit within a set area between the two following values:

const Urho3D::Vector3 rotClampMin = Urho3D::Vector3(0.f, -45.f, 0.f);
const Urho3D::Vector3 rotClampMax = Urho3D::Vector3(90.f, 45.f, 0.f);


RotateAround sets both the angle and position of _cameraNode, so I must pre-compute the values with the clamping in mind. I would like to avoid working with Euler angles as much as possible. How can I clamp my rotation prior to calling _cameraNode->RotateAround?

• Well, since you want to clamp on Euler angles (or else I didn't get what was ratClampMin), converting your quaternion to Euler angles remains a valid solution. Else you need to do the conversion the other way round, converting the obvious inequalities with Euler angles into inequalities of quaternions, with an adequate change of variables (en.wikipedia.org/wiki/…). That may lead up to more than four inequalities due to the use of sine and cosine function. Also I didn't get what "values" you want to pre-compute. Commented Nov 27, 2014 at 3:29
• What I meant by pre-compute is that I would prefer to clamp, then rotate. I will see what comes from using Euler angles a bit more, however half the reason I started using Quaternions (outside of the obvious fact that Urho3D uses them internally) is because I've ran into the known issues of Euler angles and wish to avoid them.
– user39686
Commented Nov 27, 2014 at 11:58

I was able to do this by applying the correction after the initial transformation, though I would prefer an answer that applies the correction prior to the initial transformation so as to avoid transforming the camera twice.

After the:

_cameraNode->RotateAround(curPos, rotY, Urho3D::TS_LOCAL);
_cameraNode->RotateAround(Urho3D::Vector3::ZERO, rotX, Urho3D::TS_PARENT);


I added the following logic:

Urho3D::Vector3 curRotation = _cameraNode->GetRotation().EulerAngles();
Urho3D::Vector3 correction = Urho3D::Vector3::ZERO;

if (curRotation.x_ < rotClampMin.x_)
correction.x_ = rotClampMin.x_ - curRotation.x_;
else if (curRotation.x_ > rotClampMax.x_)
correction.x_ = rotClampMax.x_ - curRotation.x_;

if (curRotation.y_ < rotClampMin.y_)
correction.y_ = rotClampMin.y_ - curRotation.y_;
else if (curRotation.y_ > rotClampMax.y_)
correction.y_ = rotClampMax.y_ - curRotation.y_;

curPos = _cameraNode->GetTransform().Inverse().Translation();

rotX = Urho3D::Quaternion(correction.x_, Urho3D::Vector3(1.f, 0.f, 0.f));
rotY = Urho3D::Quaternion(correction.y_, Urho3D::Vector3(0.f, 1.f, 0.f));

_cameraNode->RotateAround(curPos, rotX, Urho3D::TS_LOCAL);
_cameraNode->RotateAround(Urho3D::Vector3::ZERO, rotY, Urho3D::TS_PARENT);


This works perfectly.

• You should mark this as the accepted answer; it should have been long enough that the timer is expired.
– user1430
Commented Dec 22, 2014 at 21:00