Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong conversion of quaternion to axis #11665

Closed
javagl opened this issue Dec 2, 2023 · 2 comments
Closed

Wrong conversion of quaternion to axis #11665

javagl opened this issue Dec 2, 2023 · 2 comments

Comments

@javagl
Copy link
Contributor

javagl commented Dec 2, 2023

The Quaternion.computeAxis function seems to be questionable in one case, and wrong in another case. When executing the following

const q0 = new Cesium.Quaternion(0,0,0,1);
console.log(Cesium.Quaternion.computeAngle(q0));
console.log(Cesium.Quaternion.computeAxis(q0, new Cesium.Cartesian3()));

const q1 = new Cesium.Quaternion(0,0,0,-1);
console.log(Cesium.Quaternion.computeAngle(q1));
console.log(Cesium.Quaternion.computeAxis(q1, new Cesium.Cartesian3()));

then the output will be

0
(0, 0, 0)
6.283185307179586
(NaN, NaN, NaN)

One could make a case for the first part: The unit quaternion 0,0,0,1 describes "no rotation" - so what is the axis of "no rotation"? It's arbitrary. But I'd be strongly in favor to return a "valid" (unit-length!!!) axis there as well. So it should probably be (1,0,0).

(I wonder how many "normalized result is not a number" errors have been caused by this under the hood...)

But the second output cannot be justified: These NaNs should not be there. One could argue whether it is a rotation about 0° or about 360°, of course, but computeAngle returns 360°, so the rotation axis could just be (1,0,0) as well.

Both cases boil down to this part of the code, which currently says

  const w = quaternion.w;
  if (Math.abs(w - 1.0) < CesiumMath.EPSILON6) {
    result.x = result.y = result.z = 0;
    return result;
  }

If everybody agrees, I could create a PR to change that to

  const w = quaternion.w;
  if (Math.abs(w - 1.0) < CesiumMath.EPSILON6 || Math.abs(w + 1.0) < CesiumMath.EPSILON6) {
    result.x = 1;
    result.y = result.z = 0;
    return result;
  }

(And update/add the unit tests, which probably do not cover that right now)

Then, the output will be

0
(1, 0, 0)
6.283185307179586
(1, 0, 0)

The following is ... somewhat unrelated, but I noticed this while debugging a bit:

EDIT: Moved to #11685

@javagl
Copy link
Contributor Author

javagl commented Dec 2, 2023

Just as an experiment: When doing this in glm...

import { quat, vec3 } from "gl-matrix";

function run() {

  const q0 : quat = [0,0,0,1];
  const axis0 : vec3 = [0,0,0];
  const angle0 = quat.getAxisAngle(axis0, q0);
  console.log(angle0);
  console.log(axis0);

  const q1 : quat = [0,0,0,-1];
  const axis1 : vec3 = [0,0,0];
  const angle1 = quat.getAxisAngle(axis1, q1);
  console.log(angle1);
  console.log(axis1);
}

run();

then it will print

0
[ 1, 0, 0 ]      
6.283185307179586
[ 1, 0, 0 ]      

@ggetz
Copy link
Contributor

ggetz commented Dec 13, 2023

Fixed in #11684

@ggetz ggetz closed this as completed Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants