# Math for Dummies slide show error

I am translating Math For Dummies slideshow into a printable format and when going through the slides I am having a problem with understanding some things.

Hopefully this is clear.

If what I am showing here is correct for slide 40 where
quatA = Vector3f(1, 0, 0)
quatB = Vector3f(-1, 0, 0)
quatC = Vector3f(0, 0, 1)

``````Slide 40
Quaternion quatA = new Quaternion();
quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);
-90 deg around Z axis
(Y)                           Y
|  -z                        |  -z
| /                          | /
-x  ------+------  X         -x  ------+------  (X)
/ |                          / |
Z    |                       Z    |
-y                           -y

Before                        After

quatA = Vector3f(1, 0, 0)

Quaternion quatB = new Quaternion();
quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);
-90 deg around Y axis
Y                             Y
|  -z                         |  -z
| /                           | /
-x  ------+------  X        (-x)  ------+------  X
/ |                           / |
(Z)   |                        Z    |
-y                            -y

Before                          After

quatB = Vector3f(-1, 0, 0)

Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis & -90 deg around Y axis
(Y)                           Y                             Y
|  -z                        |  -z                         |  -z
| /                          | /                           | /
-x  ------+------  X         -x  ------+------  (X)        -x  ------+------  X
/ |                          / |                           / |
Z    |                       Z    |                       (Z)   |
-y                           -y                            -y

Before                        Step 1                       Step 2

quatC = Vector3f(0, 0, 1)
``````

Then is this correct where Vector3f vectorB = quatC.mult(vectorA);?
vectorB = Vector3f(0, -1, 0)

``````=======================================================
Slide 41
Vector3f vectorA = new Vector3f(0, 1, 0);
(Y)
|  -z
| /
-x  ------+------  X
/ |
Z    |
-y

Before

vectorA = Vector3f(0, 1, 0)

Vector3f vectorB = quatC.mult(vectorA);
90 deg around X axis
Y                            Y
|  -z                        |  -z
| /                          | /
-x  ------+------  X         -x  ------+------  X
/ |                          / |
(Z)   |                       Z    |
-y                          (-y)

Before                       After

vectorB = Vector3f(0, -1, 0)
``````

Slide 42 and 45 shows it as vectorB = Vecotr3f(0, 0, 1).

``````=======================================================
Slide 42 & 45
(Y)                           Y
|  -z                        |  -z
| /                          | /
-x  ------+------  X         -x  ------+------  X
/ |                          / |
Z    |                     ( Z)   |
-y                           -y

Before                        After

Vector3f(0, 0, 1)
``````
1 Like

Ok, something is wrong unless I am making a stupid mistake.

Slide shows

``````Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis & -90 deg around Y axis
(Y)                           Y                             Y
|  -z                        |  -z                         |  -z
| /                          | /                           | /
-x  ------+------  X         -x  ------+------  (X)        -x  ------+------  X
/ |                          / |                           / |
Z    |                       Z    |                       (Z)   |
-y                           -y                            -y

Before                        Step 1                       Step 2

quatC = Vector3f(0, 0, 1)
``````

But running the code shows,

``````Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis & -90 deg around X axis
(Y)                           Y                             Y
|  -z                        |  -z                         |  -z
| /                          | /                           | /
-x  ------+------  X         -x  ------+------  (X)        -x  ------+------  /X/
/ |                          / |                           / |
Z    |                       Z    |                         Z   |
-y                           -y                            -y

Before                        Step 1                       Step 2

quatC = Vector3f(1, 0, 0)
``````

Because the Quaternion first rotates from position Y to position X then rotates position X -90 deg.

The Slide show shows Quaternion rotates from Y to X then from X to Z.

This,
-90 deg around Z axis & -90 deg around Y axis

Should be
-90 deg around Z axis & -90 deg around X axis

Something must of changed between when this was made and now or I am applying these Quaternions wrong but this is what is happening in game.

The rotation is doing this,

``````Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis & -90 deg around Y axis
(Y)                          -X                             Z
|  -z                        |  -z                         |   x
| /                          | /                           | /
-x  ------+------  X         -y  ------+------  (Y)        -y  ------+------  /Y/
/ |                          / |                           / |
Z    |                       Z    |                        -X   |
-y                           -x                            -z

Before                        Step 1                       Step 2

quatC = Vector3f(1, 0, 0)
``````

Which is how it is explained in text.
` -90 deg around Z axis & -90 deg around Y axis`

Its just being demonstrated wrong in the slide graphics.
The slide keeps the orientation like so,

``````           Y
|  -z
| /
-x  ------+------  X
/ |
Z   |
-y
``````

That looks fishy already… aren’t they supposed to be Quaternions and no Vector3f? I see a lot of that in your post and looks like something is wrong in your understanding .
It’s a bit confusing. What is your question exactly?

Yeah, I found it very confusing also. I couldn’t even follow the post.

I do kind of feel like the slides are wrong, though.

quatC is quatA.mult(quatB) and then it describes that first it’s rotated by quatA and then by quatB which sounds backwards to me. I’d have to stop any think about it for longer than I have at the moment.

…but if you think of it in scene graph terms, the vector first rotates in the child space and then the parent space.

Its hard to describe images in text and keep it short.

The vector stuff is not meant to say there are vector changes, its meant to show rotation of a point as a description.

This is the scenegraph in text.

``````           Y
|  -z
| /
-x  ------+------  X
/ |
Z   |
-y
``````

Slide 40 shows these 3 variables.

``````Quaternion quatA = new Quaternion();
quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);

Quaternion quatB = new Quaternion();
quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

Quaternion quatC = quatA.mult(quatB);
``````

This is a textual representation of the rotation of quatA and quatB in slide 40. Positive Axis depicts orientation and rotation.

``````Quaternion quatA = new Quaternion();
quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);
-90 deg around Z axis
(Y)                          -x
|  -z                        |  -z
| /                          | /
-x  ------+------  X         -y  ------+------  (Y)
/ |                          / |
(Z)   |                      (Z)   |
-y                            X

Before                      After
``````
``````Quaternion quatB = new Quaternion();
quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);
-90 deg around Y axis
(Y)                            (Y)
|  -z                          |  -x
| /                            | /
-x  ------+------  X          (z)  ------+------  -Z
/ |                            / |
(Z)   |                         X    |
-y                             -y

Before                        After
``````

This is where the first error shows for Slide 40, quatC.

Slide 43 and Slide 44 say this is what happens. I will stop here in case I am wrong. It depicts rotation around Z axis correctly in Slide 43 but then shows rotation around X axis in Slide 44.

Edit: Whats depicted in slide 44 would be +90 deg rotation(Step 2 below) because rotation happens from the perspective of +X looking down to -X with +Y as top as in Step 1. The rotation is counter clockwise which means it is POSITIVE PI.

``````Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis    &     +90 deg around X axis
(Y)                          -X                            -X
|  -z                        |  -z                         |  -y
| /                          | /                           | /
-x  ------+------  X         -y  ------+------  (Y)      (z)   ------+------  -Z
/ |                          / |                           / |
(Z)   |                     (Z)    |                     (Y)     |
-y                            x                             x

Before                      Step 1                        Step 2
Slide 43                      Slide 44
``````

I say this is what happens. Just as what is described, rotate around Z axis, followed by rotation around Y axis.

``````Quaternion quatC = quatA.mult(quatB);
-90 deg around Z axis    &     -90 deg around Y axis
(Y)                          -X                            (Z)
|  -z                        |  -z                         |  -x
| /                          | /                           | /
-x  ------+------  X         -y  ------+------  (Y)        -y  ------+------  (Y)
/ |                          / |                           / |
(Z)   |                     (Z)    |                       X     |
-y                            x                            -z

Before                      Step 1                        Step 2
Slide 43                      Slide 44 should be this
``````

I hope this clarifies this better. What I say happens is what shows when running these variables in game.

Am I wrong or is slide 44 wrong is the question.

I wrote a test case to make this easier.

You set the Quaternion in the putShape() method.

It is moveable so a side by side comparison can be made with what I just posted.

``````package TestRotation;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.debug.Arrow;

public class TestRotation extends SimpleApplication {
private static final Quaternion ROTATION = new Quaternion().fromAngleAxis(FastMath.PI * 225/180, new Vector3f(0,1,0));
private static final Quaternion PITCH045 = new Quaternion().fromAngleAxis(FastMath.PI/4, new Vector3f(1,0,0));

public static void main(String[] args) {
TestRotation app = new TestRotation();
app.start();
}

@Override
public void simpleInitApp() {
flyCam.setEnabled(false);
cam.setLocation(new Vector3f(10, 10, 10));
Quaternion quat = ROTATION.mult(PITCH045);
cam.setRotation(quat);
Vector3f center = new Vector3f(Vector3f.ZERO);
attachCoordinateAxes(center);
}

@Override
public void simpleUpdate(float tpf) {
}

@Override
public void simpleRender(RenderManager rm) {
}

private void attachCoordinateAxes(Vector3f pos) {
Arrow arrow = new Arrow(Vector3f.UNIT_X);
putShape(arrow, ColorRGBA.Red).setLocalTranslation(pos);

arrow = new Arrow(Vector3f.UNIT_Y);
putShape(arrow, ColorRGBA.Green).setLocalTranslation(pos);

arrow = new Arrow(Vector3f.UNIT_Z);
putShape(arrow, ColorRGBA.Blue).setLocalTranslation(pos);
}

private Geometry putShape(Mesh shape, ColorRGBA color) {
Geometry g = new Geometry("coordinate axis", shape);
Material mat = new Material(assetManager,
mat.setColor("Color", color);
g.setMaterial(mat);

//-90 around Z Axis
Quaternion quatA = new Quaternion();
quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);

//-90 around Y Axis
Quaternion quatB = new Quaternion();
quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

//-90 around Z Axis, -90 around Y Axis
Quaternion quatC = quatA.mult(quatB);

//Uncomment and set this to each Quaternion to verify
//        g.setLocalRotation(quatA);

rootNode.attachChild(g);
return g;
}

}
``````

But wouldn’t you get the same result if you rotated around Y first (essentially a no-op) and then around X… I think the description of quatC is what is incorrect.

I’d have to see actual vectors in and out to confirm. The naming of the vectors after quaternions really threw me in your first post so I couldn’t follow very easily.

If I have time to investigate further I will do more than just these fly-by comments.

Yes and no. The description and illustration is what I think is wrong.

As I understand what’s happening, I could be wrong but here goes.

Yes as in exactly what you describe is done in Slide 46 with this Quanternion.
`quatC = quatB.mult(quatA);`

No as in
`quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);`

is rotating around Y in both local and world space. Then the final roatation of
`quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);`

is applied which rotates around local Z axis. World axis is X.

The slide descriptions for that Quaternion are also wrong.

I was trying to establish that my thinking is correct before moving onto the latter slides because after slide 40, everything falls apart if I am correct.

So for what I am describing with slide 40,
`quatC = quatA.mult(quatB);`

Slide 42 says its rotating right around Z axis local and world space, then slide 43 says towards you. Which is local space X axis and world space Y axis. This is not what is happening.

It’s rotated to your right around Z axis local and world space, then rotates face up. Which is local space Y axis and world space X axis.

Please correct me if I am wrong on this.

I am skipping the vector stuff because its also wrong and would be a distraction at this point.

it seems like each quat is a relative rotation.
vector results of each rotation step in the process should represent the principle vector next to the resultant vector to gauge the difference.
for example:
quatA is -90 about Z and begins at (0,1,0) and ends at (1,0,0) as noted…
quatB is -90 about Y, so a result of (-1,0,0) would mean a start at (0,0,1)?
…if quatB begins from quatA’s unitY rotated to unitX, it will result in a forward facing unitZ vector?
quatC is -90 about Z then Y and begins at (0,1,0) and ends at (0,0,1) as it applies both rotations to the same original vector.
also, i could be wrong here, but my assumption is that each quat rotation is applied using world coords, so even if you rotate the up vector to be the left vector, subsequent rotations still use the world’s up vector.

I rewrote the app from above to use key input to show what I am saying.

``````package TestRotation;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.debug.Arrow;

public class TestRotation extends SimpleApplication implements ActionListener {
private static final Quaternion ROTATION = new Quaternion().fromAngleAxis(FastMath.PI * 225/180, new Vector3f(0,1,0));
private static final Quaternion PITCH045 = new Quaternion().fromAngleAxis(FastMath.PI/4, new Vector3f(1,0,0));
private Node pivot;
Quaternion quatA, quatB, quatC, quatD, reset;
private String[] actionInputs;

public static void main(String[] args) {
TestRotation app = new TestRotation();
app.start();
}

@Override
public void simpleInitApp() {
flyCam.setEnabled(false);
cam.setLocation(new Vector3f(10, 10, 10));
Quaternion quat = ROTATION.mult(PITCH045);
cam.setRotation(quat);

actionInputs = new String[]{
"one", "two", "three", "four", "five", "six","seven", "eight", "nine", "ten"
};

//-90 around Z Axis
quatA = new Quaternion();
quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Z);

//-90 around Y Axis
quatB = new Quaternion();
quatB.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

//-90 around Z Axis, -90 around Y Axis
quatC = quatA.mult(quatB);

//-90 around Y axis, -90 around Z axis
quatD = quatB.mult(quatA);

//reset
reset = new Quaternion(0,0,0,1);

setupKeys();

pivot = new Node("pivot");
Vector3f center = new Vector3f(Vector3f.ZERO);
attachCoordinateAxes(center);
rootNode.attachChild(pivot);
}

@Override
public void simpleUpdate(float tpf) {
}

@Override
public void simpleRender(RenderManager rm) {
}

private void attachCoordinateAxes(Vector3f pos) {
Arrow arrow = new Arrow(Vector3f.UNIT_X);
putShape(arrow, ColorRGBA.Red).setLocalTranslation(pos);

arrow = new Arrow(Vector3f.UNIT_Y);
putShape(arrow, ColorRGBA.Green).setLocalTranslation(pos);

arrow = new Arrow(Vector3f.UNIT_Z);
putShape(arrow, ColorRGBA.Blue).setLocalTranslation(pos);
}

private Geometry putShape(Mesh shape, ColorRGBA color) {
Geometry g = new Geometry("coordinate axis", shape);
Material mat = new Material(assetManager,
mat.setColor("Color", color);
g.setMaterial(mat);

pivot.attachChild(g);
return g;
}

private void setupKeys() {
}

@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("one") && !isPressed) {
//-90 around Z Axis
pivot.rotate(quatA);
}

if (name.equals("two") && !isPressed) {
//-90 around Y Axis
pivot.rotate(quatB);
}

if (name.equals("three") && !isPressed) {
//-90 around Z Axis, -90 around Y Axis
pivot.rotate(quatC);
}

if (name.equals("four") && !isPressed) {
//-90 around Y axis, -90 around Z axis
pivot.rotate(quatD);
}

if (name.equals("five") && !isPressed) {
pivot.setLocalRotation(quatA);
}

if (name.equals("six") && !isPressed) {
pivot.setLocalRotation(quatB);
}

if (name.equals("seven") && !isPressed) {
pivot.setLocalRotation(quatC);
}

if (name.equals("eight") && !isPressed) {
pivot.setLocalRotation(quatD);
}

if (name.equals("ten") && !isPressed) {
pivot.setLocalRotation(reset);
}
}
}
``````

Relative as in from the start rotation at the time the Quaternion is applied in local space.

Yes and no.
No as in there are no vector changes. just a rotation. If this were a spatial, it would still be located at its original location. The vectors of (-1,0,0) and (0,0,1) you mention are not vectors but highlights of the axis for demonstration purposes.

As nehon pointed out,

A bad choice for a demonstration on my part.

Quaternion rotation is applied based on current rotation of the local space. 0 degrees for Y starts at forward (Z), 0 degrees for Z is Up (Y), zero degree for X is Up (Y).

So yes, as in, the (Y) axis is rotated -90 (clockwise), i.e. Z (zero degree), is rotated towards what you say is (-1,0,0).

The quaternion quatA rotated local (Y) to world (X) around local (Z) so local space is now on its side.

Next, quatB rotates -90 around local (Y), ie clockwise, using the forward Vector (Z) which, is zero degrees. This moves local (Z) to world space (Y). i.e your spatial is face up.

If you next apply another rotation Quaternion, it will rotate based off the current rotation of local space.

It first applies the rotaion of quatA, then applies the rotaion of quatB to wherever quatA roatation ended. Not to the same starting rotation both times.

Original rotation both times implies where quatA rotation started from is where quatB also rotates from. This is exactly what slide 44 says is happening.

This is what my original question is about and what I think have demonstrated is wrong with the slides after slide 40.

This is exactly what the whole purpose of this thread is about in a nutshell.

My answer is no, they are based on local space, otherwise things like this would never make sense,

``````Quaternion quatC = quatA.mult(quatB);
pivot.rotate(quatC);
pivot.rotate(quatA);
``````

This is quatA so we are rotating clockwise around the (Z) axis. You rotated Y once to WORLD SPACE X. It is then rotated face up with Z moving to the WORLD SPACE Y.

If the LOCAL SPACE is on its side with local (Y) at world (X), and local (Z) is at world (Y), and you then used a Quaternion to rotate around WORLD SPACE (Z), the rotation would be expected to rotate clockwise like so.

``````           Y                    (Z)
|                     |
|                     |
+------ X             +------  (Y)       +------  (Z)
/                     /                 / |
Z                      X               X    |
(y)

World Space         Local Space Start     Local Space End
``````

This is not what happens.

It is rotated around LOCAL SPACE (Z) and the rotation happens like so,

``````           Y                    (Z)                        (Z)
|                     |                          |
|                     |                          |
+------ X             +------  (Y)      x  ------+
/                     /                          /
Z                      X                        (Y)

World Space         Local Space Start     Local Space End
``````

You can test this in my app by hitting key 3, which will do quatC rotation, then key 1, which is quatA rotation. Key 0 will reset the rotation.

You can also test it by typing key 1 (quatA), key 2 (quatB), then key 1 (quatA).

BTW, key 1 followed by key 2 demonstrates the movement which shows slide 44 is wrong. The vector stuff is also wrong.

So either you are correct and Quaternions rotate based on world space always and everything I have written here is wrong, or I am correct and Quaternions rotate based on local space always.

No one has confirmed it either way.

What does “world space” and “local space” mean to a Quaternion?

quatA.mult(quatB) is of course going to give you some combination of those rotations such that if you applied them both in a particular order individually to a vector then you’d get the same result. There is no “world space” or “local space”… just where you start and where you end.

The idea of “world space” and “local space” only make sense in a scene graph.

Here is my take… without having time to write code to check but the scene graph would be broken if this weren’t true:
If quatA rotates 90 degrees around the Z-axis.
If quatB rotates 45 degrees around the Y-axis.
If quatC is quatA.mult(quatB)

Then I think (signs could be backwards but you will get the point):
quatA.mult(Vector3f.UNIT_Y) = 1, 0, 0
quatB.mult(Vecotr3f.UNIT_Z) = 0.707, 0, 0.707 (approximately)

Vector3f v = Vector3f.UNIT_Y;
v = quatC.mult(v);

…should be the same as:
Vector3f v = Vector3f.UNIT_Y;
v = quatB.mult(v);
v = quatA.mult(v);

Which I think would be something like: 0, 0.707, 0.707

…again I may have my signs flipped somewhere but the point should be the same.

In this particular case, it is being used as a visual to represent the rotation and orientation of axis.

Don’t take it literal.

This is how its visually depicted in math for dummies. This is what this is about. The visuals are not correct.

To try once more and get through, I will remove all references to axis or anything else, the visual shows the rotation is first to the right in slide 43. Then in slide 44, the visual shows the rotation is forward, towards you. This is not so… it rotates in place, ie face up…

The vector visual in slide 42 is also wrong…its says the rotation is from up then down towards you, around the X axis…in reality, it is from up then down to the right, around the Z axis…

Everything after slide 40 is either wrong about Quaternions or my demo app that uses the exact Quaternions and I am wrong. It’s pretty straight forward, compare the results of the app to the slides. They do not match.

You can even open this math for dummies link,
https://jmonkeyengine.github.io/wiki/jme3/math_for_dummies.html

and run the app side by side to compare. Anyone can do it. No calculating, brain crunching required. Enter 1, 2, 1. or to save time, 3, 1. 0 to reset. That’s it.

Wouldn’t be the first time I was wrong though.

I was trying to tell you how it should work. I don’t know if the slides are right or wrong and I don’t have time to look into it. Unless you can get my kids up for school and take my wife to get her cast removed.

But you know what… I’m done with this thread. Good luck.

Ditto.

I cant fix the tutorial anyway. Everyone will just have to figure it out on their own.