co-domains of Quaternion::getYaw(), getPitch() and getRoll()

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
User avatar
Beauty
OGRE Community Helper
OGRE Community Helper
Posts: 767
Joined: Wed Oct 10, 2007 2:36 pm
Location: Germany
x 39
Contact:

co-domains of Quaternion::getYaw(), getPitch() and getRoll()

Post by Beauty »

On the Ogre Class Reference several functions have no documentation.
This I want to improve and made suggestions in the papercut forum section.

I think for getYaw(), getPitch() and getRoll() it's important to know the co-domain of the returned values.
Especially the result of getYaw() can confuse people. (In the past I had problems, because of the lack of documentation. Today I read that also somebody else has problems related to getYaw().)

A half year ago I published the co-domains which I detected by a tiny test application.
getYaw -90 .. 90
getPitch -180 .. 180
getRoll -180 .. 180
User Kojack disagreed and said the co-domain of getYaw would be -180 to 180 degree.

Until today there is no consistency (of our both opinions) and thus there is not any documentation.
I want to fill this lack of documentation, but for this I need the state of the art.
I will be happy about every reply.


Here is the discussion of the papercut topic.
I want to continue the discussion here in the public/common Ogre forum to have a larger audience. (The papercut topic has fallen asleep.)

Beauty wrote:Related to Ogre::Quaternion::getYaw()

By some tests I found out that the co-domain of the returned value of getYaw() is from -90° to 90°.
This should be mentioned in the method description, because some people could suppose the returned value has a co-domain of -180°..180° or 0°..360°.
So the co-domain note would be a useful hint for people who doesn't know.

Proposed addition for the description of getYaw():
The co-domain of the returned value is from -90 to 90 degrees.
My personal background:
In maritime navigation it usual to use a 360° co-domain for Yaw. So I was confused because of wrong calculation values, until I recognized that getYaw() returns only a 180° co-domain.


Also the co-domain for the other getAngle methods should be documentated:

Ogre::Quaternion::getPitch()
-180°..180°

Ogre::Quaternion::getRoll()
-180°..180°
Kojack wrote:getYaw() is -180 to 180. I just tested it and it returned values below -90 and above 90 fine.
Beauty wrote:
Kojack wrote:getYaw() is -180 to 180. I just tested it and it returned values below -90 and above 90 fine.
I wrote a nested loop which creates a SceneNode and set its Orientation (quaternion) to several rotation states.
For each state it reads the yaw/pitch/roll values.
As results it shows the minimum and maximum values, that were returned by yaw/pitch/roll.
This is the investigated co-domain.

Source code of my test, witten in C#:

Code: Select all

        Single yaw = 0;
        Single pitch = 0;
        Single roll = 0;

        Single ymin = 0;
        Single ymax = 0;
        Single pmin = 0;
        Single pmax = 0;
        Single rmin = 0;
        Single rmax = 0;

        Single y, p, r;

        Quaternion quat = new Quaternion(new Degree(yaw), Vector3.UNIT_Y);
        SceneNode node = new SceneNode(Smgr);
        Console.WriteLine("Start calculation ...\n");
        Console.Write("Intermediate steps: ");

        for (yaw = -200; yaw <= 400; yaw++)
        {
            for (pitch = -200; pitch <= 200; pitch++)
            {
                for (roll = -200; roll <= 200; roll++)
                {
                    node.Orientation = new Quaternion(new Degree(yaw), Vector3.UNIT_Y);
                    node.Pitch(new Degree(pitch), Node.TransformSpace.TS_LOCAL);
                    node.Roll(new Degree(roll), Node.TransformSpace.TS_LOCAL);
                    quat = node.Orientation;

                    y = quat.Yaw.ValueDegrees;
                    p = quat.Pitch.ValueDegrees;
                    r = quat.Roll.ValueDegrees;

                    if (y < ymin)
                        ymin = y;
                    if (y > ymax)
                        ymax = y;
                    if (p < pmin)
                        pmin = p;
                    if (p > pmax)
                        pmax = p;
                    if (r < rmin)
                        rmin = r;
                    if (r > rmax)
                        rmax = r;

                }

            }
            Console.Write(".");
            if ((yaw % 10) == 0)
                Console.Write(yaw); // show current state of calculation

        }
        Console.WriteLine("\n\nCalculation ready.\n");

        Console.Write("co-domains:\n");
        Console.Write(String.Format("Yaw    {0} .. {1} \n", ymin, ymax));
        Console.Write(String.Format("Pitch  {0} .. {1} \n", pmin, pmax));
        Console.Write(String.Format("Roll   {0} .. {1} \n", rmin, rmax));
Result:
Yaw -90 .. 90
Pitch -180 .. 180
Roll -180 .. 180
Kojack wrote:getYaw() is -180 to 180. I just tested it and it returned values below -90 and above 90 fine.
No case of my test loop returned a Yaw value below -90 or above 90 degree.

Or is there a mistake in my test loop?
Beauty wrote:I made some more experiments with my test loop.
So I found a nice example case:

When I set the orientation of a SceneNode to yaw = 120 degree by
node.Orientation = new Quaternion(new Degree(120), Vector3.UNIT_Y);
and read the orientation values, then I get this result:
Yaw = 60
Pitch = 180
Roll = 180
Help to add information to the wiki. Also tiny edits will let it grow ... :idea:
Add your country to your profile ... it's interesting to know from where of the world you are.
eddy
Gnoblar
Posts: 4
Joined: Sat Aug 06, 2011 2:00 pm

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by eddy »

Hello to all!
Yaw -90 .. 90
Pitch -180 .. 180
Roll -180 .. 180
example case:

When I set the orientation of a SceneNode to yaw = 120 degree by
node.Orientation = new Quaternion(new Degree(120), Vector3.UNIT_Y);
and read the orientation values, then I get this result:
Yaw = 60
Pitch = 180
Roll = 180
I have to confirm that these are the values I am getting as well (my initial topic about the issue:http://www.ogre3d.org/addonforums/viewt ... 947#p81947). Can this be easily fixed in the source, to at least have the same system for each of the three rotations? Also, I support Beauty in updating the documentation.

EDIT: One more observation that might be helpful. With Yaw I often got back values for an angle stating Not a Number (mainly when overlapping the initial axis by 90 degree).
So i wrote my own method to find the inverse solution to a given matrix using Node.Orientation.XAxis, Node.Orientation.YAxis, Node.Orientation.ZAxis (according to page 33 of this book:http://books.google.com/books?hl=en&lr= ... &q&f=false). Now I checked my return values for pitch and roll as well, while it does not give the NaN "error", it returns exactly the same values as stated above. i.e.:
Yaw -90 .. 90
Pitch -180 .. 180
Roll -180 .. 180
I am thinking that it might be because of the SQR nature of the yaw equation (2.21) of the attached picture.

EDIT2: LoL. I have just seen that beauty also made a topic about the NaN issue. Going to check it out.
Attachments
ogre rotmat2.jpg
User avatar
Beauty
OGRE Community Helper
OGRE Community Helper
Posts: 767
Joined: Wed Oct 10, 2007 2:36 pm
Location: Germany
x 39
Contact:

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by Beauty »

eddy wrote:I have just seen that beauty also made a topic about the NaN issue.
Yes, the solution is here.
Help to add information to the wiki. Also tiny edits will let it grow ... :idea:
Add your country to your profile ... it's interesting to know from where of the world you are.
Sheen
Halfling
Posts: 58
Joined: Mon May 26, 2008 9:32 pm
Location: St. Petersburg, Russia
x 1

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by Sheen »

Here's screenshot of my app's debug info. You can see that camera node's yaw is -171.88 degrees, so it's in -180 .. 180.
Attachments
yaw.jpg
User avatar
Beauty
OGRE Community Helper
OGRE Community Helper
Posts: 767
Joined: Wed Oct 10, 2007 2:36 pm
Location: Germany
x 39
Contact:

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by Beauty »

Very strange.
I have only one idea for this result.
Currently Mogre uses this code:
Radian Quaternion::Yaw::get()
{
return Radian(System::Math::Asin(-2*(x*z - w*y)));
}
Kojack suggested in an other topic, it's better to use Ogre::Math::Asin() instead to avoid NaN problems.
Perhaps the Ogre arcus sinus also contains an other calculation related to the .NET one?
Help to add information to the wiki. Also tiny edits will let it grow ... :idea:
Add your country to your profile ... it's interesting to know from where of the world you are.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7154
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 525

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by Kojack »

Ogre's getYaw code is:

Code: Select all

if (reprojectAxis)
		{
			// yaw = atan2(localz.x, localz.z)
			// pick parts of zAxis() implementation that we need
			Real fTx  = 2.0f*x;
			Real fTy  = 2.0f*y;
			Real fTz  = 2.0f*z;
			Real fTwy = fTy*w;
			Real fTxx = fTx*x;
			Real fTxz = fTz*x;
			Real fTyy = fTy*y;

			// Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));

			return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy)));

		}
		else
		{
			// internal version
			return Radian(Math::ASin(-2*(x*z - w*y)));
		}
The reprojectAxis bool defaults to true.
This means that by default ogre is doing a different calculation than mogre, which is probably why I'm getting the full range while you are getting a smaller value. I'd probably get the 60,180,180 thing if I used the non default formula.

Mogre using System::Math::Asin is definitely the cause of the nans.
Asin can only accept numbers in the range -1 to 1. Anything outside that range is mathematically impossible and meaningless. Due to floating point error, the result of -2*(x*z-w*y) could end up being slightly off, such as 1.000001 or -1.000001. That is enough to make Asin (and Acos) fail. Ogre has protection against this, it checks the value before calling asin. Mogre should do this too if it isn't going to call the ogre version.

Edit: oops, just realised that I explained the nan thing roughly the same way in the other thread.
User avatar
Beauty
OGRE Community Helper
OGRE Community Helper
Posts: 767
Joined: Wed Oct 10, 2007 2:36 pm
Location: Germany
x 39
Contact:

Re: co-domains of Quaternion::getYaw(), getPitch() and getRo

Post by Beauty »

Kojack, thank you very much.
By your help now we know the concrete reason of the problems and can fix Mogre.
Also we know the real co-domains and we can add it to the Ogre Class Reference.

Don't worry about the NaN in this topic.
It also related to our getYaw problems.
Help to add information to the wiki. Also tiny edits will let it grow ... :idea:
Add your country to your profile ... it's interesting to know from where of the world you are.
Post Reply