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.
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 . . .
I think your right. I tried this code and both cones are oriented correctly
// set cone to random orientation
// draw flat plane and axis for a reference
// draw first cone
cone.setPosition(-100, 0, 0);
// draw second cone
cone.setPosition(100, 0, 0);
// replace getOrientationQuat() with getOrientationEuler() for error
this is the result
but when I replaced getOrientationQuat() with getOrientationEuler().I got this
the orientation of the second cones is messed up
fixes issue #679
bank = x-axis, heading = y axis, attitude = z axis.
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.
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.
float getRotationAboutVector(ofVec3f vector, ofVec4f quat);
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.
Oh for reference I think this is what I'm talking about:
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;
*orthonormal1 = normal.cross(w);
*orthonormal2 = normal.cross(*orthonormal1);
float getQuaternionTwist(ofQuaternion q, ofVec3f axis)
//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;
//get angle between original vector and projected transform to get angle around normal
float a = (float)acosf(orthonormal1.dot(flattened));
ofVec3f transformByMatrix(ofVec3f v, ofMatrix4x4* m)
for ( int i = 0; i < 4; ++i )
result[i] = v * m->_mat[i] + v * m->_mat[i] + v + m->_mat[i] + v * m->_mat[i];
result = result/result;
result = result/result;
result = result/result;
@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;
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.