Hello to all!

I wanted to ask is there a way to retrieve an angle information from the usual [0- 360] system?

While trying to implement some basic one axis rotations, I got confused about it working strangely. After some testing, I found out that my return values are given according to the attached picture (rotation is done around the axis perpendicular to the screen).

Beauty

06-08-2011 12:51:40

Hi eddy,

I know this problem very well, because I got confused, too.

The problem are the returned co-domains:

getYaw -90 .. 90

getPitch -180 .. 180

getRoll -180 .. 180

Also there is a lack of documentation.

A half year ago I suggested to add a description to the Ogre Class Documentation.

Unfortunately the documentation was not improved at this points.

One reason is, that an other user told, the co-domain would be -180 to 180.

I never got such results. Now I started a new discussion in the Ogre main forum.

Be welcome to post there, too. This will affirm the interest of an improved documentation.

http://www.ogre3d.org/forums/viewtopic.php?f=1&t=66030
To get the wanted values of Yaw, you also need to check the values of Pitch and Roll.

For my own application I wrote a method to get the wanted Yaw value. I will post it later.

Alternatively:

User Kojack posted a class for Euler Angles calculations.

I didn't check it, but maybe it solves you problem, too.

http://www.ogre3d.org/tikiwiki/Euler+Angle+Class
Thanks for your reply. I came to think this is some arcus trigonometry issue. I will check the links you posted, and I am very interested in seeing your solution.

For now I am countering this by checking the signs of the axis orientation vectors to determine in which quadrant is my object of interest pointing.

EDIT: I will check roll and pitch values and report them here.~~But probably not before the day after tomorrow~~. Now I have to finish some other coding stuff.

EDIT2.5:^scratch that. I tested ROLL (and pitch), and came to the same conclusion as beauty:

Beauty

06-08-2011 14:54:49

Here is my code.

This are 3 methods, which are used for different aims.

Also you can apply some settings by parameters.

By this it should be more flexible. Just use the parts, which you need.

Some descriptions I added. I hope you understand what I mean.

If you have problems, just tell me.

Note: The differentiation by the type "YawConvention" you can remove. I use it for my application, but it's not needed for common Mogre users.

/// <summary>

/// Calculate the Yaw angle from a given orientation (quaternion)

/// </summary>

/// <remarks>

/// The reference to SceneVariables is used better performance.

/// It prevents the re-creation of temporary variables for each call.

/// </remarks>

/// <param name="var">Reference to mScene.var, which contains helper variables</param>

/// <param name="orientation">Quaternion (contains the direction description)</param>

/// <param name="angleUnit">Define if the returned value is in Degree or Radian</param>

/// <param name="yawBasis">Define which axis is used to describe the rotation divergence</param>

/// <returns>Calculated angle in the co-domain of 0 to 360 degrees</returns>

public static Single GetYawAngle(ref PublicSceneVariables var, ref Quaternion orientation, Mogre.Math.AngleUnit angleUnit, YawConvention yawBasis)

{

var.gy_yawDirection = orientation.XAxis; // get direction vector

return GetYawAngle(ref var, ref var.gy_yawDirection, angleUnit, yawBasis);

}

/// <summary>

/// Calculate the Yaw angle of a given SceneNode

/// </summary>

/// <remarks>

/// The reference to SceneVariables is used better performance.

/// It prevents the re-creation of temporary variables for each call.

/// </remarks>

/// <param name="var">Reference to mScene.var, which contains helper variables</param>

/// <param name="sceneNode">SceneNode, which yaw value should be returned</param>

/// <param name="angleUnit">Define if the returned value is in Degree or Radian</param>

/// <param name="localOrWorld">Define if yaw value of local space or global space is needed</param>

/// <param name="yawBasis">Define which axis is used to describe the rotation divergence</param>

/// <returns>Calculated angle in the co-domain of 0 to 360 degrees</returns>

public static Single GetYawAngle(ref PublicSceneVariables var, ref SceneNode sceneNode, Mogre.Math.AngleUnit angleUnit, SceneNode.TransformSpace localOrWorld, YawConvention yawBasis)

{

if (sceneNode == null)

return 0;

switch (localOrWorld)

{

case Node.TransformSpace.TS_LOCAL:

var.gy_yawDirection = sceneNode.Orientation.XAxis;

break;

case Node.TransformSpace.TS_WORLD:

var.gy_yawDirection = sceneNode._getDerivedOrientation().XAxis;

break;

default:

// TS_PARENT

throw new NotSupportedException();

}

return GetYawAngle(ref var, ref var.gy_yawDirection, angleUnit, yawBasis);

}

/// <summary>

/// Calculate the Yaw angle from a given direction vector

/// </summary>

/// <remarks>

/// The reference to SceneVariables is used better performance.

/// It prevents the re-creation of temporary variables for each call.

/// </remarks>

/// <param name="var">Reference to mScene.var, which contains helper variables</param>

/// <param name="direction">Direction vector from which the Yaw angle should be extracted</param>

/// <param name="angleUnit">Define if the returned value is in Degree or Radian</param>

/// <param name="yawBasis">Define which axis is used to describe the rotation divergence</param>

/// <returns>Calculated angle in the co-domain of 0 to 360 degrees</returns>

public static Single GetYawAngle(ref PublicSceneVariables var, ref Vector3 direction, Mogre.Math.AngleUnit angleUnit, YawConvention yawBasis)

{

var.gy_yawDirection = direction;

var.gy_yawDirection.y = 0;

var.gy_yawDirection.Normalise();

if (yawBasis == YawConvention.NED)

{

var.gy_yawAngle = Mogre.Math.ACos(var.gy_yawDirection.DotProduct(Vector3.UNIT_X));

var.gy_overrunCheckAngle = Mogre.Math.ACos(var.gy_yawDirection.DotProduct(Vector3.UNIT_Z));

}

else // YawConvention.Ogre

{

var.gy_yawAngle = Mogre.Math.ACos(var.gy_yawDirection.DotProduct(Vector3.UNIT_Z));

var.gy_overrunCheckAngle = Mogre.Math.ACos(var.gy_yawDirection.DotProduct(Vector3.UNIT_X));

}

// adaption if more than 180 degree (because Ogre returns only a co-domain of -90..90 degrees)

if (var.gy_overrunCheckAngle.ValueRadians > var.gy_HalfPiInRad)

var.gy_yawAngle = var.gy_TwoPiInRad - var.gy_yawAngle;

if (angleUnit == Mogre.Math.AngleUnit.AU_DEGREE)

return var.gy_yawAngle.ValueDegrees;

else

return var.gy_yawAngle.ValueRadians;

} // GetYawAngle()

/// <summary>

/// Define used Yaw convention. Differences are the comparison axis for divergence calculation and the rotation direction.

/// </summary>

public enum YawConvention

{

/// <summary>Convention of NED coordinate system:

/// Rotation divergence to the X-axis; NEGATIVE rotation around the Ogre Y-axis

/// (Comply to the positive rotation around the NED Z-axis)</summary>

NED,

/// <summary>Convention of Ogre coordinate system:

/// Rotation divergence to the Z-axis; Positive rotation around the Ogre Y-axis</summary>

Ogre

}

//-------------------------

public class SceneVariables

{

// temp helper variables for Yaw calculations

public Vector3 gy_yawDirection;

public Radian gy_yawAngle;

public Radian gy_overrunCheckAngle;

public Radian gy_TwoPiInRad = new Radian(Mogre.Math.TWO_PI);

public Radian gy_HalfPiInRad = new Radian(Mogre.Math.HALF_PI);

}

SceneVariables var = new SceneVariables();

**update:** added souce code from next post
I don't know if it works for all cases.

Perhaps there are problems when Pitch and/or Roll is greater than +/-90 degree. (I didn't check it.) Such cases I don't have in my application.

You can check several cases by a simple test method.

Adapt this method and compare input/output values.

Then you know.

`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));

Beauty

07-08-2011 09:55:39

Addition:

My methods contains the parameter "ref PublicSceneVariables var".

The reason: For performance reasons I don't want to re-create temporary variables for each call. So I keep them in the class "PublicSceneVariables".

If you like, you can make them local or become a field of the same class. So there would not be a need to have an extra reference.

Here is the definition of my temporary variables:

`public class SceneVariables`

{

// temp helper variables for Yaw calculations

public Vector3 gy_yawDirection;

public Radian gy_yawAngle;

public Radian gy_overrunCheckAngle;

public Radian gy_TwoPiInRad = new Radian(Mogre.Math.TWO_PI);

public Radian gy_HalfPiInRad = new Radian(Mogre.Math.HALF_PI);

}

SceneVariables var = new SceneVariables();

Beauty

08-08-2011 09:10:04

**By help of user Kojack we found out that Mogre causes problems with getYaw.**
I suppose for performance reasons Mogre doesn't use a wrapped Ogre method.

Instead it uses a common equation. It's mathematical correct, but bad for usage with Ogre/Mogre.

Details are here:

http://www.ogre3d.org/forums/viewtopic. ... 56#p435756 (bad co-domain)

http://www.ogre3d.org/forums/viewtopic. ... 95#p426695 (NaN problem)

So we have 2 options for updating the Mogre wrapper:

1)

Just

**wrap** the Ogre function of

*getYaw*.

2)

Update the Mogre

*Yaw* property and mathematical functions and use a

**port** of the related Ogre source code.

In general we should compare all mathematical functions of Mogre.

If they are not wrapped (for performance reasons) we should use a port of the Ogre source code.

I prefer option 2, because of performance reasons. (

*getYaw* is a method which could be called very often)

Which options are prefered by the other Mogre users?