Thank you very much Mick! Although in the end the explanation proves that there is no other parameter that needs to be added to your beautiful tool, this one necessarily had to be done. Can you show me the code of this latest addition? I can better understand the behavior through.... numbers
This is the code (freshly cleaned and commented) that takes an Az value and converts it into CueAz (the angle of the Cue dot).
JavaScript:
// Take a frame number in the video (i.e. a time in 1/30ths)
// and return the angle formed by projecting the camera's Az/El vector
// onto the plane of the wings
function Frame2CueAz(frame) {
// get az for this frame (el is constant, in par.el)
// this comes from video data, shown on the graph as yellow
var az = Frame2Az(frame)
// get a unit vector in the direction of Az/El
// the Az=0 and El=0 is always along the -Z axis
// This can be thought of as a position on a unit sphere.
// El is relative to the horizontal plane, so AoA is irrelevant
// Az is relative to the jet's forward direction in the horizontal plane
var AzElHeading = EA2XYZ(par.el, az, 1)
// Create a Plane object, representing the wing plane
// (a "plane" is a flat 2D surface in 3D space, not an aeroplane)
// the plane in Hessian normal form, normal unit vector (jetUp)
// and a distance from the origin (0, as the origin is the ATFLIR camera, i.e. the jet)
var jetRoll = jetRollFromFrame(frame) // get jet roll angle from either video data or constant
var jetUp = new THREE.Vector3(0, 1, 0) // y=1 is the jet up unit vector with no rotation
jetUp.applyAxisAngle(V3(0,0,1),-radians(jetRoll)) // apply roll about Z axis (-Z is fwd, so -ve)
jetUp.applyAxisAngle(V3(1,0,0),radians(par.aoa)) // apply pitch about X axis (right)
var wingPlane = new THREE.Plane(jetUp,0)
// project AzElHeading onto wingPlane, giving cueHeading
var cueHeading = wingPlane.projectPoint(AzElHeading,new THREE.Vector3)
// now find the jet's forward vector, which will be in the wing plane
// same rotations as with the up vector
var jetForward = new THREE.Vector3(0, 0, -1)
jetForward.applyAxisAngle(V3(0,0,1),-radians(jetRoll))
jetForward.applyAxisAngle(V3(1,0,0),radians(par.aoa))
// calculate the angle between the jet forward vector
var cueAz = degrees(jetForward.angleTo(cueHeading))
// angleTo always returns a positive value, so we
// need to negate it unless cross product is in same direction as jet up
// the cross product will give a vector either up or down from the plane
// depending on if cueHeading is left or right of JetForward when looking down
var cross = cueHeading.clone().cross(jetForward)
// then use a dot product which returns positive if two vectors are in the same direction
var sign = cross.dot(jetUp)
if (sign < 0) cueAz = -cueAz
// The return value is plotted in cyan (light blue)
return cueAz
}
And the code that makes the arrows
JavaScript:
// var rotationMatrix = new THREE.Matrix4().extractRotation(PodFrame.matrixWorld);
// var jetUp = new THREE.Vector3(0, 1, 0).applyMatrix4(rotationMatrix).normalize();
// The rotations below are equivalent to the above,
// but I'm doing it explicitly like this
// to match the code in Frame2CueAz,
// so the graph uses the same code as the arrows
// except instead of using a unit sphere
// we use one of radius vizRadius
// to get the large arrows in the display.
var jetUp = new THREE.Vector3(0, 1, 0)
jetUp.applyAxisAngle(V3(0,0,1),-radians(par.jetRoll))
jetUp.applyAxisAngle(V3(1,0,0),radians(par.aoa))
var jetPlane = new THREE.Plane(jetUp,0) // plane in Hessian normal form, normal unit vector and a distance from the origin
// take the idealPos (the white dot) and project it onto the jetPlane
var cuePos=new THREE.Vector3;
jetPlane.projectPoint(idealPos,cuePos) // project idealPos onto jetPlane, return in cuePos
DebugArrowAB("Projected Cue",idealPos,cuePos,0x00ffff,false)
DebugArrowAB("Cue Az",V3(0,0,0),cuePos,0x00ffff,false)
var horizonPlane = new THREE.Plane(V3(0,1,0),0)
var azPos=new THREE.Vector3;
horizonPlane.projectPoint(idealPos,azPos) // the same as just setting y to 0
DebugArrowAB("Projected Az",idealPos,azPos,0xffff00,false)
DebugArrowAB("Az",V3(0,0,0),azPos,0xffff00,false)
You can also just view source with the tool itself. https://www.metabunk.org/gimbal/