# Get Euler angles from gp_Trsf with gp_Quaternion::getEulerAngles()

Hi,

I am creating a transformation (rotation only) by rotating around three fixed axes X, Y, Z by three angles c, b, a. As the result I am getting a gp_Quaternion "q".

Now I want to extract three euler angles "aProbe, bProbe, cProbe" from "q" in order to create the same transformation again (rotate around fixed axes X, Y, Z with cProbe, bProbe, aProbe). This results in a second gp_Quaternion "qProbe".

After all the "q" and "aProbe" should be equal.

The question is: How do I extract "cProbe, bProbe, aProbe" from "q"? Or: what "gp_EulerSequence sequence" do I have to use?

I thought "Extrinsic = fixed Axes, XYZ = order of Axes" and tried these two possibilities:

q.GetEulerAngles(gp_Extrinsic_XYZ, cProbe, bProbe, aProbe);

q.GetEulerAngles(gp_Extrinsic_XYZ, aProbe, bProbe, cProbe);

But both fails (q != qProbe). :-(

Ok, I can try all possibilities, but I want to understand what I am doing.

Here is my sample code:

---snip---

const double TO_RAD = M_PI / 180.0;

const double TO_DEG = 1.0 / TO_RAD;

double a = 10.0 * TO_RAD; // degrees

double b = 20.0 * TO_RAD; // degrees

double c = 30.0 * TO_RAD; // degrees

// Calculate trsf from three angles a, b, c

gp_Trsf trsf1, trsf2, trsf3, trsf;

trsf1.SetRotation(gp::OX(), c); // rotate around fixed X-Axis with c

trsf2.SetRotation(gp::OY(), b); // rotate around fixed Y-Axis with b

trsf3.SetRotation(gp::OZ(), a); // rotate around fixed Z-Axis with a

trsf = trsf1 * trsf2 * trsf3;

gp_Quaternion q = trsf.GetRotation();

// Check angles

double aProbe, bProbe, cProbe;

q.GetEulerAngles(sequence, aProbe, bProbe, cProbe);

//

gp_Trsf trsf1Probe, trsf2Probe, trsf3Probe, trsfProbe;

trsf1Probe.SetRotation(gp::OX(), cProbe);

trsf2Probe.SetRotation(gp::OY(), bProbe);

trsf3Probe.SetRotation(gp::OZ(), aProbe);

trsfProbe = trsf1Probe * trsf2Probe * trsf3Probe;

gp_Quaternion qProbe = trsfProbe.GetRotation();

---snap---

Regards

Thorsten

I stepped into the source code and compared the OCCT method with the algorithm by Ken Shoemake mentioned in gp_Quaternion.cxx:

---snip---

//=======================================================================

//function : translateEulerSequence

//purpose :

// Code supporting conversion between quaternion and generalized

// Euler angles (sequence of three rotations) is based on

// algorithm by Ken Shoemake, published in Graphics Gems IV, p. 222-22

// http://tog.acm.org/resources/GraphicsGems/gemsiv/euler_angle/EulerAngles.c

//=======================================================================

---snap---

I am doing the following rotation:

with c around the worlds x-Axis

with b around the worlds y-Axis

with a around the worlds z-Axis

In "Graphics Gems IV" this is EulOrdXYZs, which means:

- Initial axis: X

- parity of axis permutation: even

- repetition of initial axis as last: no

- take axes from initial frame (static axes): yes

The same euler parameters in OCCT results in the euler sequence "gp_Intrinsic_XYZ". But the equivalent gp_EulerSequence for EulOrdXYZs should be "gp_Extrinsic_XYZ", because I am rotating around static axes! I integrated the "Graphics Gems IV" sources into my tests and the results confirmed this: EulOrdXYZs is gp_Intrinsic_XYZ in OCCT!

Now I am using gp_Intrinsic_XYZ everywhere I rotate around static XYZ. Now all my algorithms are working correctly, but the naming of the "gp_EulerSequence"s in OCCT is obviously WRONG!

Is there any OCCT developer who can confirm this as a BUG (or a feature...)?

I'm not developing OCCT now, but I also noticed similar problems, and insufficient documentation to clarify what the code intended to do. I'm getting an axes instead of a transformation, eg.:

gp_EulerSequence mode = gp_Intrinsic_XYZ;

double alpha = 1.5,

beta = 0,

gamma = 0;

gp_Ax2 the_ax2;

gp_Quaternion q;

q.SetEulerAngles(mode, alpha, beta, gamma);

gp_Mat mat = q.GetMatrix();

gp_Dir dir(mat.Column(3));

gp_Dir Vx(mat.Column(1));

the_ax2.SetDirection(dir);

the_ax2.SetXDirection(Vx);

Something is wrong because when I make only alpha nonzero (that is a rotation about x axis), even the x direction of the_ax2 changes, which should happen for neither extrinsic nor intrinsic rotation about just the x axis. However, if I reverse the order of alpha, beta, gamma, or use mode = gp_Intrinsic_ZYX, I get what I expect.

Also, the comments in gp_TrsfForm.hxx really belong to the enum gp_EulerSequence in its own header file.

## DC,

DC,

OCCT 7.0 includes a fix for incorrect interpretation of intrinsic Tait-Bryan angles (including gp_YawPitchRoll), see #25574 issue in OCCT Mantis Bug Tracker.

We suppose that this fixes the problems described above.

Wrong comment in gp_TrsfForm.hxx should be fixed in master this week, see #27602.

Best Regards,

FSR