Quaternion LVecBase4f confusion

This perhaps isn’t a bug, but a confusing convention.
Why is it that the real part of a quaternion (inherited by LVecBase4f) gets stored as x and not w?
r -> x
i -> y
j -> z
k -> w

for example, printing a LQuaternionf q

cout << q << endl;
cout << q.get_r() << q.get_i() << q.get_j() << q.get_k() << endl;
cout << q.get_w() << q.get_x() << q.get_y() << q.get_z() << endl;

would produce

0.5 + 0.0i + 0.2j + 0.4k
0.5   0.0    0.2    0.4
0.4   0.5    0.0    0.2

I’ve learned my lesson to use get_r() instead of get_w(), but it took me a while

I think the “why” is, roughly, “arbitrary”.

The conventional notation for quaternions is [r, i, j, k]. The GL math library GLM quaternion constructor uses the ordering tquat(w, x, y, z). (Internally GLM switches things around to be stored [x, y, z, w], but there’s no way to know that unless you look at the code implementing it.) DX, which likes to be different, uses Quaternion(x, y, z, w). Panda uses LQuaternion(r, i, j, k), like GLM, and stores them in that order as well.

I guess the bottom line is that the fact that Panda is using the LVecBase4f as a convenient storage mechanism is really an “implementation detail”. If you’ve got a LQuaternion you should use the quaternion-centric get_rijk, etc., rather than “poking around in the base class” by using get_xyzw.

I do agree that it’s somewhat confusing if you’re used to a system where w == r. It’s worth noting that a more complete quaternion notation is q = w + xi + yj + zk. In that sense, the convention of using xyz as synonyms for ijk (and w for r) is also confusingly incorrect. It could be argued that Panda’s explicit denotation of [r, i, j, k], rather than forcing you to use the overloaded names [w, x, y, z], is “more correct” than other approaches.

(Note that I didn’t write any of this code, I’m just throwing out a possible rationalization…)