# possible bug in getEuler / getOrientation / getRoll#679

Closed
opened this Issue Jul 24, 2011 · 10 comments

### 4 participants

I think there's a bug in ofQuaternion in of007. When i use ofNode's setOrientation() or ofNode setRoll I can rotate my ofNode object around the Z axis. However when I try to obtain the current rotation around the Z axis it will always give a value like -180, 0 or 180.

Rick

Ha! 3 years, I'm getting the same issue in 2014

yes, the getEuler math is bad. It is returning Eurler angles based on the Quaternion, but they're not necessarily expressed in a single axis (moreover the axis you want), so a Z rotation may show up as a combination of other rotations that don't actually involve the Z axis. Better to set all rotations as a quat and keep track of you're own Eulers on the side. This is a very old comment / problem, but if I get a better solution I'll post it here . . .

commented Mar 21, 2014

I think your right. I tried this code and both cones are oriented correctly

```void ofApp::draw(){
ofEnableDepthTest();
ofConePrimitive cone;
cone.setScale(2);
// set cone to random orientation
cone.roll(20);
cone.pan(-34);
cone.tilt(50);

easyCam.begin();
// draw flat plane and axis for a reference
ofDrawAxis(1000);
ofPlanePrimitive plane;
plane.tilt(-90);
plane.setScale(10);
ofSetColor(ofColor::pink);
plane.draw();

// draw first cone
cone.setPosition(-100, 0, 0);
cone.drawAxes(50);
ofSetColor(ofColor::white);
cone.draw();
ofSetColor(ofColor::black);
cone.drawWireframe();

// draw second cone
cone.setPosition(100, 0, 0);
// replace getOrientationQuat() with getOrientationEuler() for error
cone.setOrientation(cone.getOrientationQuat());
cone.drawAxes(50);
ofSetColor(ofColor::white);
cone.draw();
ofSetColor(ofColor::black);
cone.drawWireframe();

easyCam.end();

}
```

this is the result

but when I replaced getOrientationQuat() with getOrientationEuler().I got this

the orientation of the second cones is messed up

pushed a commit that referenced this issue Mar 21, 2014
 Ahbee `fixes issue #679` `bank = x-axis, heading = y axis, attitude = z axis.` `2a1fad3`
commented Mar 21, 2014

I think the guy who implemented ofQuaternion::getEuler() made a typo. There is a link in the comments to this: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm. I looked at the openframeworks code and the code in the link. openframeworks confuses bank with attitude. see the standards http://www.euclideanspace.com/maths/standards/index.htm. I changed that in the pull request. Also the standard rotation order is here openframeworks also messes that up.

openFrameworks member

makes sense! i think especially with methods like these (which can have more than one mathematical meaning) it'd be good to have the return values explained in a comment or documentation - and i think the comment you put in is helpful, too =)

Re: (which can have more than one mathematical meaning)

yes! it seems like expecting the Euler angles you are looking for from a Quat is bad practice given multiple representations. Something I am just learning. Instead it seems best practices for a "getRoll()" type function (which is how this convo started) would be asking for a single axis of rotation based on a comparison vector.

something like:

so getRoll() would internally supply the correct vec3 (node's up vector), so that we get the rotation in the correct euler axis and it doesn't end up as a composite of 3 axis that may or may not be correct.

OK so I've ported that Java code to oF / C, it works to a certain point, but can't sort out negative rotations without some crossproduct math that I'm not sure how to implement. It calculates the shortest positive rotation. I think the moral of my story is just stop using Eulers for anything, and get hip to quats / mats.

Here's code in case it's useful to someone.

``````void getOrthonormals(ofVec3f normal, ofVec3f *orthonormal1, ofVec3f *orthonormal2)
{
ofMatrix4x4 OrthoX = ofMatrix4x4().newRotationMatrix(90, ofVec3f(1,0,0));
ofMatrix4x4 OrthoY = ofMatrix4x4().newRotationMatrix(90, ofVec3f(0,1,0));

ofVec3f w = transformByMatrix(normal, &OrthoX);

float dot = normal.dot(w);

if (fabsf(dot) > 0.6)
{
w = transformByMatrix(normal, &OrthoY);
OrthoY * normal;
}
w.normalize();

*orthonormal1 = normal.cross(w);
orthonormal1->normalize();
*orthonormal2 = normal.cross(*orthonormal1);
orthonormal2->normalize();
}

float getQuaternionTwist(ofQuaternion q, ofVec3f axis)
{
axis.normalize();

//get the plane the axis is a normal of
ofVec3f orthonormal1, orthonormal2;

getOrthonormals(axis, &orthonormal1, &orthonormal2);

ofVec3f transformed = orthonormal1 * q;

//project transformed vector onto plane
ofVec3f flattened = transformed - transformed.dot(axis) * axis;
flattened.normalize();

//get angle between original vector and projected transform to get angle around normal
float a = (float)acosf(orthonormal1.dot(flattened));

return a;

}

ofVec3f transformByMatrix(ofVec3f v, ofMatrix4x4* m)
{
ofVec3f result;
for ( int i = 0; i < 4; ++i )
result[i] = v[0] * m->_mat[0][i] + v[1] * m->_mat[1][i] + v[2] + m->_mat[2][i] + v[3] * m->_mat[3][i];
result[0] = result[0]/result[3];
result[1] = result[1]/result[3];
result[2] = result[2]/result[3];
return result;
}
``````
openFrameworks member
commented Mar 21, 2014

@structuresound, I think you should open a new issue for this, because what your asking for is a feature unrelated to the original bug. Start a new issue and say you want these functions implemneted.

```ofQuaternion::ofQuaternion(const ofQuaternion &twist, const ofQuaternion &swing);
ofQuaternion ofQuaternion::makeRotate(const ofQuaternion &twist, const ofQuaternion &swing);
ofQuaternion ofQuaternion::getTwist(const ofVec3f &twistAxis,const ofVec3f &swingAxis) const;
ofQuaternion ofQuaternion::getSwing(const ofVec3f &twistAxis,const ofVec3f &swingAxis) const;
```
pushed a commit that closed this issue Apr 8, 2014
 Ahbee `fixes #679` ```bank = xAxis,heading = yAxis, attitude = zAxis . The rotation order is Y,Z,X; OpenFrameworks works in row Major so, the Quaternion multiplication order is- xRotation * zRotation * yRotation.``` `ddd9900`
closed this in `ddd9900` Apr 8, 2014