[Case 6491] fixes rotation skip near 0 and 180.

Previously, when rotating, it would be easy to achieve 1 degree granularity, except near the 0 degree and 180 degree "poles", where it would often e.g. jump from 10 to -10, or 174 to -175, or similar.

yawZero/pitchZero/rollZero were all based on the yawHandle/pitchHandle/rollHandle ray intersection, and were not necessarily coplanar with rotateOverlayTarget. As a result, centerToZero didn't lie on the expected plane, while centerToIntersect did.  This had the effect of distorting the rotation range.

We also have a possible issue in here with editOverlay(rotationOverlayTarget,{rotation:...}) not taking effect immediately.  Better to take the existing ray and cast against a known plane, as e.g. translateXZTool and such do.  No risk of stale rotation in that case.

This also cleans up rotationHelper args a bit to avoid some string switches and keep flow a little more readable.

TODO: propagate ray-plane test to helperRotationHandleOnMove rather than relying on ray hit location; normalize onBegin/onMove/etc across all tools to take queryRay and results args to avoid recreating the ray.

Reviewed-by: LaShonda Hopper <lashonda@1stplayable.com>
This commit is contained in:
Leander Hasty 2017-08-10 13:29:57 -04:00 committed by LaShonda Hopper
parent fe171af31b
commit fa74fbc986

View file

@ -298,9 +298,7 @@ SelectionDisplay = (function() {
var yawCenter; var yawCenter;
var pitchCenter; var pitchCenter;
var rollCenter; var rollCenter;
var yawZero; var rotZero;
var pitchZero;
var rollZero;
var yawNormal; var yawNormal;
var pitchNormal; var pitchNormal;
var rollNormal; var rollNormal;
@ -3692,10 +3690,10 @@ SelectionDisplay = (function() {
} }
} }
function helperRotationHandleOnBegin( rotMode, rotNormal, rotCenter, handleRotation ) { function helperRotationHandleOnBegin( event, rotNormal, rotCenter, handleRotation ) {
var wantDebug = false; var wantDebug = false;
if (wantDebug) { if (wantDebug) {
print("================== " + rotMode + "(onBegin) -> ======================="); print("================== " + mode + "(rotation helper onBegin) -> =======================");
} }
SelectionManager.saveProperties(); SelectionManager.saveProperties();
@ -3704,7 +3702,6 @@ SelectionDisplay = (function() {
that.setGrabberMoveUpVisible( false ); that.setGrabberMoveUpVisible( false );
initialPosition = SelectionManager.worldPosition; initialPosition = SelectionManager.worldPosition;
mode = rotMode;
rotationNormal = rotNormal; rotationNormal = rotNormal;
// Size the overlays to the current selection size // Size the overlays to the current selection size
@ -3757,28 +3754,31 @@ SelectionDisplay = (function() {
}); });
updateRotationDegreesOverlay(0, handleRotation, rotCenter); updateRotationDegreesOverlay(0, handleRotation, rotCenter);
// Compute zero position now that the overlay is set up.
// TODO editOverlays sync
var pickRay = generalComputePickRay(event.x, event.y);
var result = rayPlaneIntersection( pickRay, rotCenter, rotationNormal );
rotZero = result;
if (wantDebug) { if (wantDebug) {
print("================== " + rotMode + "(onBegin) <- ======================="); print("================== " + mode + "(rotation helper onBegin) <- =======================");
} }
}//--End_Function( helperRotationHandleOnBegin ) }//--End_Function( helperRotationHandleOnBegin )
function helperRotationHandleOnMove( event, rotMode, rotZero, rotCenter, handleRotation ) { function helperRotationHandleOnMove( event, rotAroundAxis, rotCenter, handleRotation ) {
if ( ! (rotMode == "ROTATE_YAW" || rotMode == "ROTATE_PITCH" || rotMode == "ROTATE_ROLL") ) { if ( ! rotZero ) {
print("ERROR( handleRotationHandleOnMove ) - Encountered Unknown/Invalid RotationMode: " + rotMode ); print("ERROR( handleRotationHandleOnMove ) - Invalid RotationZero Specified (missed rotation target plane?)" );
//--EARLY EXIT--
return;
} else if ( ! rotZero ) {
print("ERROR( handleRotationHandleOnMove ) - Invalid RotationZero Specified" );
//--EARLY EXIT-- //--EARLY EXIT--
return; return;
} }
var wantDebug = false; var wantDebug = true;
if (wantDebug) { if (wantDebug) {
print("================== "+ rotMode + "(onMove) -> ======================="); print("================== "+ mode + "(rotation helper onMove) -> =======================");
Vec3.print(" rotZero: ", rotZero); Vec3.print(" rotZero: ", rotZero);
} }
var pickRay = generalComputePickRay(event.x, event.y); var pickRay = generalComputePickRay(event.x, event.y);
@ -3794,7 +3794,12 @@ SelectionDisplay = (function() {
var centerToZero = Vec3.subtract(rotZero, rotCenter); var centerToZero = Vec3.subtract(rotZero, rotCenter);
var centerToIntersect = Vec3.subtract(result.intersection, rotCenter); var centerToIntersect = Vec3.subtract(result.intersection, rotCenter);
if (wantDebug) { if (wantDebug) {
Vec3.print(" RotationNormal: ", rotationNormal); Vec3.print(" RotationNormal: ", rotationNormal);
Vec3.print(" rotZero: ", rotZero);
Vec3.print(" rotCenter: ", rotCenter);
Vec3.print(" intersect: ", result.intersection);
Vec3.print(" centerToZero: ", centerToZero);
Vec3.print(" centerToIntersect: ", centerToIntersect);
} }
// Note: orientedAngle which wants normalized centerToZero and centerToIntersect // Note: orientedAngle which wants normalized centerToZero and centerToIntersect
// handles that internally, so it's to pass unnormalized vectors here. // handles that internally, so it's to pass unnormalized vectors here.
@ -3805,18 +3810,9 @@ SelectionDisplay = (function() {
var snapAngle = snapToInner ? innerSnapAngle : 1.0; var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
var rotChange = null; var vec3Degrees = { x: 0, y: 0, z: 0 };
switch( rotMode ) { vec3Degrees[rotAroundAxis] = angleFromZero;
case "ROTATE_YAW": var rotChange = Quat.fromVec3Degrees( vec3Degrees );
rotChange = Quat.fromVec3Degrees( {x: 0, y: angleFromZero, z: 0} );
break;
case "ROTATE_PITCH":
rotChange = Quat.fromVec3Degrees( {x: angleFromZero, y: 0, z: 0} );
break;
case "ROTATE_ROLL":
rotChange = Quat.fromVec3Degrees( {x: 0, y: 0, z: angleFromZero} );
break;
}
updateSelectionsRotation( rotChange ); updateSelectionsRotation( rotChange );
updateRotationDegreesOverlay(angleFromZero, handleRotation, rotCenter); updateRotationDegreesOverlay(angleFromZero, handleRotation, rotCenter);
@ -3872,7 +3868,7 @@ SelectionDisplay = (function() {
}//--End_If( results.intersects ) }//--End_If( results.intersects )
if (wantDebug) { if (wantDebug) {
print("================== "+ rotMode + "(onMove) <- ======================="); print("================== "+ mode + "(rotation helper onMove) <- =======================");
} }
}//--End_Function( helperRotationHandleOnMove ) }//--End_Function( helperRotationHandleOnMove )
@ -3907,17 +3903,14 @@ SelectionDisplay = (function() {
addGrabberTool(yawHandle, { addGrabberTool(yawHandle, {
mode: "ROTATE_YAW", mode: "ROTATE_YAW",
onBegin: function(event, intersectResult) { onBegin: function(event, intersectResult) {
//note: It's expected that the intersect result is passed when this is called. mode = "ROTATE_YAW";
// validity will be checked later as a pre-requisite for onMove handling. helperRotationHandleOnBegin( event, yawNormal, yawCenter, yawHandleRotation );
yawZero = intersectResult.intersection;
helperRotationHandleOnBegin( "ROTATE_YAW", yawNormal, yawCenter, yawHandleRotation );
}, },
onEnd: function(event, reason) { onEnd: function(event, reason) {
helperRotationHandleOnEnd(); helperRotationHandleOnEnd();
}, },
onMove: function(event) { onMove: function(event) {
helperRotationHandleOnMove( event, "ROTATE_YAW", yawZero, yawCenter, yawHandleRotation ); helperRotationHandleOnMove( event, "y", yawCenter, yawHandleRotation );
} }
}); });
@ -3926,17 +3919,14 @@ SelectionDisplay = (function() {
addGrabberTool(pitchHandle, { addGrabberTool(pitchHandle, {
mode: "ROTATE_PITCH", mode: "ROTATE_PITCH",
onBegin: function (event, intersectResult) { onBegin: function (event, intersectResult) {
//note: It's expected that the intersect result is passed when this is called. mode = "ROTATE_PITCH";
// validity will be checked later as a pre-requisite for onMove handling. helperRotationHandleOnBegin( event, pitchNormal, pitchCenter, pitchHandleRotation );
pitchZero = intersectResult.intersection;
helperRotationHandleOnBegin( "ROTATE_PITCH", pitchNormal, pitchCenter, pitchHandleRotation );
}, },
onEnd: function(event, reason) { onEnd: function(event, reason) {
helperRotationHandleOnEnd(); helperRotationHandleOnEnd();
}, },
onMove: function (event) { onMove: function (event) {
helperRotationHandleOnMove( event, "ROTATE_PITCH", pitchZero, pitchCenter, pitchHandleRotation ); helperRotationHandleOnMove( event, "x", pitchCenter, pitchHandleRotation );
} }
}); });
@ -3945,17 +3935,14 @@ SelectionDisplay = (function() {
addGrabberTool(rollHandle, { addGrabberTool(rollHandle, {
mode: "ROTATE_ROLL", mode: "ROTATE_ROLL",
onBegin: function (event, intersectResult) { onBegin: function (event, intersectResult) {
//note: It's expected that the intersect result is passed when this is called. mode = "ROTATE_ROLL";
// validity will be checked later as a pre-requisite for onMove handling. helperRotationHandleOnBegin( event, rollNormal, rollCenter, rollHandleRotation );
rollZero = intersectResult.intersection;
helperRotationHandleOnBegin( "ROTATE_ROLL", rollNormal, rollCenter, rollHandleRotation );
}, },
onEnd: function (event, reason) { onEnd: function (event, reason) {
helperRotationHandleOnEnd(); helperRotationHandleOnEnd();
}, },
onMove: function(event) { onMove: function(event) {
helperRotationHandleOnMove( event, "ROTATE_ROLL", rollZero, rollCenter, rollHandleRotation ); helperRotationHandleOnMove( event, "z", rollCenter, rollHandleRotation );
} }
}); });