Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fix: applying camera up.z vector at scene init #3256

Merged
merged 23 commits into from
Nov 22, 2018
Merged

Bug fix: applying camera up.z vector at scene init #3256

merged 23 commits into from
Nov 22, 2018

Conversation

archmoj
Copy link
Contributor

@archmoj archmoj commented Nov 17, 2018

Fixes #2425 by seting dragmode: 'orbit' at init time to allow tilted camera z vectors and then possibly switch to turntable mode as used to be desired default user mode.

Background: in plotly.js dragmode: 'turntable' was applied as the default camera behaviour which is desirable for most cases and it modifies & locks camera z-axis rotation. However in certain cases when the user had specified camera z-axis this value was ignored at the start.
The first approach applied here was to try to turn on dragmode: 'orbit' in those edge cases. The prototypes was working interactively but that introduced new side-effects and required complicated changes.
On the other hand the second approach applied is to simply set orbit as the default and then switch to turntable mode in all cases where the camera.z.up vector is different from being upwards i.e. [0,0,1].

@etpinard
@alexcjohnson

@@ -51,6 +51,14 @@ exports.plot = function plotGl3d(gd) {
scene = sceneLayout._scene;

if(!scene) {
if(fullLayout[sceneId].camera.up.z !== 1 &&
fullLayout[sceneId].dragmode === 'turntable') {
fullLayout[sceneId].dragmode = 'orbit';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be better to do this in supplyDefaults

Not sure where we ensure ||up||===1 but it doesn't look like that's done in supplyDefaults, so I guess at that point we might need a more complicated test (up.x || up.y || up.z < 0 perhaps?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of having more complicated test as you mentioned. On the other hand I was wondering that it is now rather difficult for the users to compute and pass z vector components. Could we add a function to normalize user inputs for this vector before reaching there too?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the direction of up matters, right? So feels to me like we shouldn't require it to be normalized at all. If the user passes in (0,0,0) we should revert to (0,0,1), otherwise seems to me we should normalize it for our own use but leave the un-normalized value in layout and fullLayout.

@alexcjohnson
Copy link
Collaborator

@archmoj I like this solution (subject to the comment above).

BTW, I notice a related issue: if you've set the plot in orbit mode, rotated to some different up vector, then you switch back to turntable mode; the plot rotates back to a compatible orientation, but layout.scene.camera.up, and the copy in _fullLayout, still have the up and eye they had at the end of the orbit interaction. But I think either I should take that in #3236 or we should address this after that merges, as it should use _guiRelayout or _storeDirectGuiEdits...

"x": 1,
"y": 0,
"x": 0,
"y": 1,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... gl3d_ibm_plot has the old (verrrry old) camera format, and converts to the new format with a tilted up, and you allowed it to shift into orbit mode; that's great. And gl3d_surface_lighting you converted to the new camera format and turntable-compatible up, so the image changed because it's somewhat different from the output of the previous old->new conversion; also great.

But what's going on with gl3d_snowden_altered? The image didn't change, but the change you made to up is not to {x: 0, y: 0, z: 1} so I'd have expected the image to change, since now it will render in orbit mode.

@@ -140,7 +140,7 @@ module.exports = {
valType: 'enumerated',
role: 'info',
values: ['orbit', 'turntable', 'zoom', 'pan', false],
dflt: 'turntable',
dflt: 'orbit',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I would prefer removing the dflt key entirely - as the default value is now dynamic.

Could you also add some info in the description about the new orbit-vs-turntable logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the description. Thanks @etpinard for the note. I will give removing dflt a try.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once I tried to remove dragmode.dflt, the default behaviour for drag using right-click (orbit/turntable) is not activated.
So we may keep it there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to pass the dynamic default to dragmode here:

coerce('dragmode', opts.getDfltFromLayout('dragmode'));

getDfltFromLayout is part of it but then there's the dynamic default based on camera. I don't think you want to be altering sceneIn.dragmode with enableTurnTable, you just want to be setting the dynamic default. The logic is something like:

  • If getDfltFromLayout returns a value, use that.
  • If not but the user provides a camera that's not {x: 0, y: 0, z: >0} dfltDragmode='orbit'
  • If neither of those, dfltDragmode = 'turntable'
  • Then you call coerce('dragmode', dfltDragmode) so the user can still explicitly provide whatever.
  • The only case that's still weird at that point is if the user explicitly says dragmode: 'turntable', camera: {up: {not z-up}}. My inclination at that point is to set sceneOut.camera.up (and NOT sceneIn.camera.up) to {x: 0, y: 0, z: 1}. That won't change the behavior - the user might still wonder why up is not being honored - but at least it would raise an alarm if you call Plotly.validate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @alexcjohnson, I will modify it to be this way.

@@ -394,7 +394,7 @@ describe('Test gl3d plots', function() {

it('@gl should be able to reversibly change trace type', function(done) {
var _mock = Lib.extendDeep({}, mock2);
var sceneLayout = { aspectratio: { x: 1, y: 1, z: 1 } };
var sceneLayout = { aspectratio: { x: 1, y: 1, z: 1 }, dragmode: 'turntable' };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you need to change this? I'm fearing a breaking change here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to set turnable the default behaviour the function needs to add the dragmode attribute to the sceneLayout.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So without setting dragmode: 'turntable' here, it would default to 'orbit'?

What are the camera settings in this case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@etpinard notice this isn't a setting, it's an expectation. But I agree, we shouldn't be mutating the input scene, per my comment above


if(!x || !y || !z) {
dragmode = 'turntable';
} else if(z / Math.sqrt(x * x + y * y + z * z) > 0.999) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is getting better by the minute. Thanks for your efforts @archmoj

Now, would there be a way to tweak this condition such that gl3d_ibm-plot and gl3d_surface-lighting still default to dragmode: 'turntable'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point @etpinard. Let me check.

@@ -114,7 +114,7 @@ exports.cleanLayout = function(layout) {
scene.camera = {
eye: {x: eye[0], y: eye[1], z: eye[2]},
center: {x: center[0], y: center[1], z: center[2]},
up: {x: mat[1], y: mat[5], z: mat[9]}
up: {x: 0, y: 0, z: 1} // we just ignore calculating camera z up in this case
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous calculations of camera.up for gl3d_surface-lighting & gl3d_ibm-plot didn't set up vector close to [0,0,1].
I thought we may ignore camera z up if cameraposition depreciated setting is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice solution.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and I presume the gl3d_opacity-surface.png baseline changed because of this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore that last comment. I didn't see #3256 (comment)

Thanks!

@archmoj
Copy link
Contributor Author

archmoj commented Nov 21, 2018

Also concerning the changes of 'gl3d_opacity-surfacebaseline (which is now the only baseline change in this PR): Becausedragmode: 'zoom'is applied with the latest fix it is oriented exactly upwards while thezoom` button is still enabled by default.

],
1.8771354322421991
]
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this might not be necessary. If one wants to enable cameraposition it is required to use "scene" instead of "undefined"! Also now I am curious about this mock & why it was named weirdness? Also if we could possibly remove it or reduce the width/height.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. Thanks for fixing this. That undefined shouldn't be there.

@etpinard
Copy link
Contributor

Very nice fix. 💃

@archmoj archmoj merged commit 2f6c6e7 into master Nov 22, 2018
@archmoj archmoj deleted the issue-2425 branch November 22, 2018 17:25
alexcjohnson added a commit that referenced this pull request Nov 29, 2018
interaction between previous changes in this PR and #3256
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants