-
Notifications
You must be signed in to change notification settings - Fork 208
Quaternion: Shortest rotation between two vectors #55
Conversation
…hat maps one vector to another including tedious corner case handling for parallel vectors with 180 degree rotations
9380e80
to
a2dc1b5
Compare
including all the parallel vector corner cases
a2dc1b5
to
8f959d0
Compare
Fixed coverage, there was a typo like error which resulted in not covering the case I designed the test for. I made the tests even simpler such that this cannot happen anymore. |
matrix/Quaternion.hpp
Outdated
* @param src source vector (no need to normalize) | ||
* @param eps epsilon threshold which decides if a value is considered zero | ||
*/ | ||
Quaternion(const Vector3<Type> &src, const Vector<Type, 3> dst = Vector3<Type>(0, 0, 1), const Type eps = 1e-5f) : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Vector3< Type > dst = Vector3< Type >(0,0,1)
- const Type eps = (Type)1e-5;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was Vector<Type, 3>
which I switched to Vector3<Type>
now, that's what you meant right?
const Type eps = (Type)1e-5
is enough, constants are casted auatomatically to the correct type on compile time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Second statement is wrong... I put the explicit conversion now.
matrix/Quaternion.hpp
Outdated
Quaternion &q = *this; | ||
Vector3<Type> cr = src.cross(dst); | ||
float dt = src.dot(dst); | ||
if (cr.norm() < eps && dt < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we not comment anything within matrix lib?
for someone who just reads the code the first time it would make it much easier to write that this is the case for parallel vectors pointing opposite
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're totally right, I added comments for that.
matrix/Quaternion.hpp
Outdated
q(0) = Type(0); | ||
cr = src.cross(cr); | ||
} else { | ||
q(0) = src.dot(dst) + sqrt(src.norm_squared() * dst.norm_squared()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function is definitely not obvious.
maybe write something like "Half-Way Quaternion Solution".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment added
} | ||
} | ||
q(0) = Type(0); | ||
cr = src.cross(cr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get it what you do here with the cr manipulation, but I cannot really verify that it is correct or not?
Do you have a link to an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a bulk of (code) examples summarized here: https://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another
Also if you look at the unit tests you see in the comments which one is going through which case. Plus I can share the MATLAB code I used for intial prototyping of the functionality.
@Stifael Please have another look. |
0263638
to
dbb0e9b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
matrix/Vector.hpp
Outdated
@@ -71,6 +71,11 @@ class Vector : public Matrix<Type, M, 1> | |||
return Type(sqrt(a.dot(a))); | |||
} | |||
|
|||
Type norm_squared() const { | |||
const Vector &a(*this); | |||
return Type(a.dot(a)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it actually necessary to cast it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, you're right, I forgot to get rid of it. It was only necessary for sqrt() which can return double...
…ched type conversions, took out default destination vector because confusing
dbb0e9b
to
21b98db
Compare
I added the fix (took out the cast) to the latest commit. |
There are multiple application scenarios but I need this functionality for the quaternion controller: PX4/PX4-Autopilot#8003
And because of the reusability and the calculation itself suffering tedious corner cases I added it to the library with unit tests to ensure proper results.
A simple explanation for the corner cases: The input vectors are parallel but oposite and therefore require a 180 degree rotation but the cross product to get the perpendicular rotation axis is zero. For more discussion see: https://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another .