Getting velocity at a point from rotational velocity stored as a quaternion

I’ve been storing rotational velocities within quaternions (using the quaternions angle field for angular velocity). However, I’m now trying to interrogate them to get a velocity at a point in space relative to the centre of rotation. I.e. if an object has this rotational velocity then how fast is this corner of the object going.

If jmonkey quaternions will directly give this information then excellent. Otherwise I’m not afraid of a bit of maths and it would be easy to calculate if the quaternion would give me back the rotational axis (from which I can calculate the points distance to the rotational axis) and its angular velocity about that axis.

It will already give me the axis back, but I’m less sure about the angle

[java]Quaternion rotationTest=new Quaternion();
rotationTest.fromAngleAxis(FastMath.PI, new Vector3f(1,0,0)); //obviously in this example I could just store the FastMath.PI, but in the real example many quaternion have been combined

Vector3f axis=new Vector3f();
rotationTest.toAngleAxis(axis);
system.out.println(axis); // Vector3f(1,0,0) retrieved

//need command to get the angle back (i.e. FastMath.PI)[/java]

This “quaternions angle field” belies a misunderstanding of quaternions. They do not have an “angle field” just four magic values that represent an orientation.

You cannot use a Quaternion to track angular velocity, anyway. You will lose information.

And by the way, toAngleAxis() returns the angle… .which is exactly what the javadoc says:
http://hub.jmonkeyengine.org/javadoc/com/jme3/math/Quaternion.html#toAngleAxis(com.jme3.math.Vector3f)

This “quaternions angle field” belies a misunderstanding of quaternions. They do not have an “angle field” just four magic values that represent an orientation.
My use of the word 'field' was inaccurate, I meant 'concept of' or input to fromAngleAxis. That said, isn't the point of jmonkey quaternions that understanding them is unnecessary. I was just making clear that I understand that angle!=angular velocity and you need to be very careful to separate your cases.
You cannot use a Quaternion to track angular velocity, anyway. You will lose information.
Its worked fairly pleasingly so far, what specific issues arise? I've been normalising the rotation quaternion every time I "add"* a velocity part and normalising the velocity quaternion every time I add an acceleration part, before I did this I was having issues. What would be the correct way to store an angular velocity abour an arbitary axis

*within quaternions I know “adding” is done through multiplication

And by the way, toAngleAxis() returns the angle… .which is exactly what the javadoc says:
ok then, so fromAngleAxis gives 2 outputs, one as the axisStore and one as a direct output, slightly bazar but fair enough. It didn't occur to me to read the javadoc for a method that appeared to be working. I suppose I understand why it works this way, you can’t have a “float store” the way you can have a Vector3f store. Thanks for pointing this out to me

Quite apart from anything else quaternions can’t hold any velocity > 1 full revolution.

1 Like

That is a fair point, and I had a feeling it would be the case. However, I don’t think I’m going to want rotational velocities> 1 revolution/second anyway.

I’m not averse to changing my approach though if there is a more appropriate way to hold rotational velocities about an arbitrary axis? I could hold the axis as a vector3f and the rotational velocity as a float, but I chose a quaternion representation because of the ease with which several rotations on different axes could be combined

@richtea said: That is a fair point, and I had a feeling it would be the case. However, I don't think I'm going to want rotational velocities> 1 revolution/second anyway.

I’m not averse to changing my approach though if there is a more appropriate way to hold rotational velocities about an arbitrary axis? I could hold the axis as a vector3f and the rotational velocity as a float, but I chose a quaternion representation because of the ease with which several rotations on different axes could be combined

It’s not just rotations greater than greater than 1 rps. Anything greater than 0.5 rps will wrap and go the other way. Furthermore this is compounded when you start combining rotations around different axes. If you accumulate various roll, pitch, yaw, eventually you will start rotating in strange directions from what you expect.

A quaternion is a compact form of orientation.

My point about misunderstanding Quaternions was not that you have to understand the details to use them normally… but that if you are trying to use them for something else then you should understand what you are using. (Actually, I was just pointing out that you already did misunderstand… after all, you did ask for help and that is the source of your trouble…) And you should understand what use Quaternions are for in this case. They keep the unique orientation of an object in a compact form. They cannot really represent ambiguous rotations so if you plug some rotation in, you might not be able to get that rotation back out again. The only time two different Quaternions will represent the same orientation is if negated. So all ambiguity has been normalized… and not necessarily the way you want for angular velocities.

I usually see rotational velocities kept as a Vector3f… three rotations around the x,y,z axis. My own physics engine works this way, too. Rotational acceleration due to contact restitution is then also expressed as x,y,z and just added to this Vector3f. Looks like the Bullet stuff does, too: http://hub.jmonkeyengine.org/javadoc/com/jme3/bullet/objects/PhysicsRigidBody.html#getAngularVelocity()

I don’t know how else it could be done, really.

That may well be the way to go then. Although interstingly this website Is rotation a vector? suggests that unlike rotations; rotational velocities behave as vectors (a+b=b+a) and if expressed as a vector (whose direction is the the axis and length is the angular velocity) they can be simply added

@richtea said: That may well be the way to go then. Although interstingly this website http://farside.ph.utexas.edu/teaching/301/lectures/node100.html suggests that unlike rotations; rotational velocities behave as vectors (a+b=b+a) and if expressed as a vector (whose direction is the the axis and length is the angular velocity) they can be simply added

I’ve only read part way in but they are still talking about angle+axis. And they say that a vector form of angle+axis is not really a vector because a + b does not equal b + a.

On the other hand, a Vector3f of angular velocities is not an angle+axis. It is three separate angles… and it does work as a vector.

In the case of 3 decomposed angular velocities, a + b DOES equal b +a. It’s actually the entire point. As long as you compose and decompose them consistently it will always work.

The Vector3f descibed doesn’t contain the roll pitch yaw as its x,y,z, it contains Vector3f.length as the rotational velocity and Vector3f.normalise as the axis of rotation. This class I’ve written seems to model adding rotational velocities correctly (although so did the quaternion based one until it got to corner cases)

[java]package blockphysics;

import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;

/**
*

  • @author Richard
    */
    public class RotationalVelocity {
    //http://farside.ph.utexas.edu/teaching/301/lectures/node100.html
    //the direction represents the axis, the length represents the the righthanded velocity about a point

    public static RotationalVelocity ZERO=new RotationalVelocity(0,new Vector3f(1,0,0));

    Vector3f rotation;

    public RotationalVelocity(float velocity,Vector3f axis){
    rotation=axis.normalize().mult(velocity);
    }
    private RotationalVelocity(Vector3f rotation){
    this.rotation=rotation;;
    }

    public void addLocal(RotationalVelocity rotationalVelocity){
    this.rotation.addLocal(rotationalVelocity.rotation);
    }
    public RotationalVelocity add(RotationalVelocity rotationalVelocity){
    return new RotationalVelocity(this.rotation.add(rotationalVelocity.rotation));
    }

    public Vector3f getAxis(){
    return rotation.normalize();
    }

    public float getAngularVelocity(){
    return rotation.length();
    }

    private void setAngularVelocity(float angularVelocity){
    rotation.normalizeLocal();
    rotation.multLocal(angularVelocity);
    }

    public Vector3f getLinearVelocityAtPoint(Vector3f localPoint){
    //takes the position of a point (relative to the centre of rotation)
    //and returns the linear velocity due to the rotation at that point

     //first we find the component of the local point that is perpendicular
     //to the axis of rotation and we subtract that to get only the parallel
     //component
     
     Vector3f axis=getAxis();
     float angle=getAngularVelocity();
     
     Vector3f perpendicularComponents=axis.mult(axis.dot(localPoint));
     Vector3f parallelComponents=localPoint.subtract(perpendicularComponents);
     
     float distanceFromAxis=parallelComponents.length();
     
     //a complete circle's circumference would be 2 Pi r, which would be represented
     //as an angle of 2Pi, so the velocity's magnitude is v=r*angle
     float speed=distanceFromAxis*angle;
     
     //And the velocity's direction is the cross product between the axix and 
     //the parallel components (as it must be perpendicular to both
     
     return (parallelComponents.cross(axis).normalize()).mult(-speed);
    

    }

    public Quaternion getRotationStep(float timeStep){

     Quaternion rotationStep=new Quaternion();
     rotationStep.fromAngleAxis(timeStep*rotation.length(),rotation.normalize());
     return rotationStep;
    

    }

    public void inverseLocal(){
    rotation.negate();
    }
    }[/java]

It may help if you think of angular velocity as just that - a velocity. As a result it works in the same way a linear velocity does, even down to the storing it in a vector3f.