public float angleOf(PVector one, PVector two, PVector axis) {
		PVector limb = PVector.sub(two, one);
		return degrees(PVector.angleBetween(limb, axis));
	}

	static public final float degrees(float radians) {
		return radians * RAD_TO_DEG;
	}

 

/**
* Calculate the angle between two vectors, using the dot product
* 
* @param v1
*            a vector
* @param v2
*            another vector
* @return the angle between the vectors
*/
static public float angleBetween(PVector v1, PVector v2) {
double dot = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
double v1mag = Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
double v2mag = Math.sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z);
return (float) Math.acos(dot / (v1mag * v2mag));
}

 

/**

	 * Subtract one vector from another
	 * 
	 * @param v1
	 *            a vector
	 * @param v2
	 *            another vector
	 * @return a new vector that is v1 - v2
	 */
	static public PVector sub(PVector v1, PVector v2) {
		return sub(v1, v2, null);
	}

	static public PVector sub(PVector v1, PVector v2, PVector target) {
		if (target == null) {
			target = new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
		} else {
			target.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
		}
		return target;
	}
 
/**
* initially started from "Making Things See" a excellent book and I recommend
*/
 
// reduce our joint vectors to two dimensions
PVector rightHandXY = new PVector(skeleton.rightHand.x, skeleton.rightHand.y);
PVector rightElbowXY = new PVector(skeleton.rightElbow.x, skeleton.rightElbow.y);
PVector rightElbowYZ = new PVector(skeleton.rightElbow.y, skeleton.rightElbow.z);
PVector rightShoulderXY = new PVector(skeleton.rightShoulder.x, skeleton.rightShoulder.y);
PVector rightShoulderYZ = new PVector(skeleton.rightShoulder.y, skeleton.rightShoulder.z);
PVector rightHipXY = new PVector(skeleton.rightHip.x, skeleton.rightHip.y);
 
PVector leftHandXY = new PVector(skeleton.leftHand.x, skeleton.leftHand.y);
PVector leftElbowXY = new PVector(skeleton.leftElbow.x, skeleton.leftElbow.y);
PVector leftElbowYZ = new PVector(skeleton.leftElbow.y, skeleton.leftElbow.z);
PVector leftShoulderXY = new PVector(skeleton.leftShoulder.x, skeleton.leftShoulder.y);
PVector leftShoulderYZ = new PVector(skeleton.leftShoulder.y, skeleton.leftShoulder.z);
PVector leftHipXY = new PVector(skeleton.leftHip.x, skeleton.leftHip.y);
 
// calculate the axis against which we want to measure our angles
// dunno if this needs all the defintion it has :P - normal of the
// "person" is pretty much XY
PVector rightTorsoOrientationXY = PVector.sub(rightShoulderXY, rightHipXY);
PVector rightUpperArmOrientationXY = PVector.sub(rightElbowXY, rightShoulderXY);
 
PVector leftTorsoOrientationXY = PVector.sub(leftShoulderXY, leftHipXY);
PVector leftUpperArmOrientationXY = PVector.sub(leftElbowXY, leftShoulderXY);
 
// FIXME !! - IS THIS CORRECT - CAN XY JUST BE RE-USED - SINCE THE
// NORMAL OF THE BODY IS IN THE Z ?
PVector leftTorsoOrientationYZ = PVector.sub(leftShoulderXY, leftHipXY);
PVector rightTorsoOrientationYZ = PVector.sub(rightShoulderXY, rightHipXY);
 
// calculate the angles between our joints
float rightShoulderAngleXY = angleOf(rightElbowXY, rightShoulderXY, rightTorsoOrientationXY);
float rightShoulderAngleYZ = angleOf(rightElbowYZ, rightShoulderYZ, rightTorsoOrientationYZ);
float rightElbowAngleXY = angleOf(rightHandXY, rightElbowXY, rightUpperArmOrientationXY);
 
float leftShoulderAngleXY = angleOf(leftElbowXY, leftShoulderXY, leftTorsoOrientationXY);
float leftShoulderAngleYZ = angleOf(leftElbowYZ, leftShoulderYZ, leftTorsoOrientationYZ);
float leftElbowAngleXY = angleOf(leftHandXY, leftElbowXY, leftUpperArmOrientationXY);
 
skeleton.rightShoulder.setAngleXY(rightShoulderAngleXY);
skeleton.rightElbow.setAngleXY(rightElbowAngleXY);
skeleton.rightShoulder.setAngleYZ(rightShoulderAngleYZ);
 
skeleton.leftShoulder.setAngleXY(leftShoulderAngleXY);
skeleton.leftElbow.setAngleXY(leftElbowAngleXY);
skeleton.leftShoulder.setAngleYZ(leftShoulderAngleYZ);
 
g2d.drawString(String.format("shoulder %d %d", Math.round(leftShoulderAngleYZ), Math.round(rightShoulderAngleYZ)), 20, 30);
g2d.drawString(String.format("omoplate %d %d", Math.round(rightShoulderAngleXY), Math.round(leftShoulderAngleXY)), 20, 40);
g2d.drawString(String.format("bicep %d %d", Math.round(rightElbowAngleXY), Math.round(leftElbowAngleXY)), 20, 50);
 
invoke("publish", skeleton);