Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
watsug
Posts: 100
Joined: Sat Sep 26, 2020 10:51 pm

Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by watsug »

Hi all!

I'm trying to add a mode to rotate the model/scene at the bounding box center. This means the model will rotate around its center (like you've done Isometric and Zoom to Fit and the model is in the middle of the screen) even if the model is not in the middle of the screen.

I've modified NavigationStyle.cpp to get the scene boundingBox and set it as the rotationCenter. However I have some trouble understanding the existing code, and the best place to implement the new function.

1. In NavigationStyle.cpp, saveCursorPosition, what does the different cases (ScenePointAtCursor, FocalPointAtCursor) mean? If I understand correctly this has to do with "Rotate at cursor" setting. But what is ScenePoint and what is FocalPoint in this case?

2. This is my code to get the center and set the rotation center. I was thinking to make a third case, RotationAtBoundingBoxCenter, is this a good place to put it? I currently put it in case ScenePointAtCursor to try it out.

Code: Select all

            SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
            SbBox3f boundingBox = action.getBoundingBox();
            SbVec3f boundingBoxCenter = boundingBox.getCenter();

            setRotationCenter(boundingBoxCenter);
            break;
           

3. Here's how it looks, and it rotates at the models boundingBox center. The problem is that when it's started (mmb held down) the model is "teleported" to the mouse location. I want the model to stay in the same place and rotate. Youtube video link Why does it teleport?

Edit: forgot my FreeCAD info

Code: Select all

OS: Ubuntu 20.04.1 LTS (ubuntu:GNOME/ubuntu)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.22882 (Git)
Build type: Unknown
Branch: master
Hash: aebf568eaec7f62b95b29037851c04d1a6f65d47
Python version: 3.8.5
Qt version: 5.12.8
Coin version: 4.0.0
OCC version: 7.3.0
Locale: English/United States (en_US)
mike
Posts: 22
Joined: Thu Nov 06, 2014 12:06 pm

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by mike »

watsug wrote: Sat Nov 14, 2020 11:42 am I want the model to stay in the same place and rotate.
The model always stays in the same place AFAIK.
Any pan, zoom or rotate action moves the camera, not the object.
Or more precise: it sets the position and orientation of the camera.

I'm not sure, but i guess the rotation center is synonymous with the focus point of the camera (which is a point on the "focal plane" - hence the name).
That's why the camera view "jumps" to the new focus point if you set it to the center of the boundary box.

I guess there is a lot more vector math needed to achieve what you describe. Probably some kind of backwards calculation to move the camera to the desired position depending on the rotation vector?
User avatar
watsug
Posts: 100
Joined: Sat Sep 26, 2020 10:51 pm

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by watsug »

Thank you for your answer!
mike wrote: Fri Nov 20, 2020 6:19 pm I guess there is a lot more vector math needed to achieve what you describe. Probably some kind of backwards calculation to move the camera to the desired position depending on the rotation vector?
The thing is, the "rotate at cursor" mode does _almost_ what I want, and shows that the calculations to rotate on another part of the screen is already implemented. All that "should" be needed is to change the element under the mouse cursor to the boundingBox center. But I'm still having trouble understanding how the existing code works.
But I will continue and try to formulate some questions.
wmayer
Founder
Posts: 20319
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by wmayer »

1. In NavigationStyle.cpp, saveCursorPosition, what does the different cases (ScenePointAtCursor, FocalPointAtCursor) mean? If I understand correctly this has to do with "Rotate at cursor" setting. But what is ScenePoint and what is FocalPoint in this case?
ScenePointAtCursor gives you the exact intersection point between the ray (that is built of the current mouse position and view direction) and the model in the scene graph. However, the scene could consist of millions of triangles and thus the calculation of the exact intersection point can be quite expensive so that the user sees a short freeze.

Because of this and the fact that the user can click on an empty area so that there is not even an intersection point the option FocalPointAtCursor is used to get the intersection point between the ray and the focal plane.
2. This is my code to get the center and set the rotation center. I was thinking to make a third case, RotationAtBoundingBoxCenter, is this a good place to put it? I currently put it in case ScenePointAtCursor to try it out.
The calculation of the bounding center is wrong. Before calling the method getBoundingBox() you must apply the action to the scene graph, otherwise the result is always a void box with the center = (0,0,0).

In the next step you should add a new mode to RotationCenterMode and e.g. call it BoundingBoxCenter or so. Add its implementation to NavigationStyle::saveCursorPosition().
3. Here's how it looks, and it rotates at the models boundingBox center. The problem is that when it's started (mmb held down) the model is "teleported" to the mouse location. I want the model to stay in the same place and rotate.
As you may know the natural behaviour of OpenInventor is that the camera always points to the center of the 3d view and the interactive rotation is by default around this point. In order to support rotation around an arbitrary point you first move the camera position so that it points to the desired rotation center, then you do the rotation and afterwards you move the camera back.

In NavigationStyle::spin() you will find this code block:

Code: Select all


    if (PRIVATE(this)->dragAtCursor && PRIVATE(this)->rotationCenterFound) {
        SbVec3f hitpoint = PRIVATE(this)->rotationCenter;

        // set to the given position
        SbVec3f direction;
        viewer->getSoRenderManager()->getCamera()->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
        viewer->getSoRenderManager()->getCamera()->position = hitpoint - viewer->getSoRenderManager()->getCamera()->focalDistance.getValue() * direction;
    }
All what it does is to move the camera so that it points to the desired rotation point. Its focal distance or orientation is not touched, only its position.
In the next 20 lines the actual rotation is handled and afterwards you will find this block:

Code: Select all

    if (PRIVATE(this)->dragAtCursor && PRIVATE(this)->rotationCenterFound) {
        float ratio = vp.getViewportAspectRatio();
        SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(vp.getViewportAspectRatio());
        SbPlane panplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
        SbVec2f posn;
        posn[0] = float(this->localPos[0]) / float(std::max((int)(glsize[0]-1), 1));
        posn[1] = float(this->localPos[1]) / float(std::max((int)(glsize[1]-1), 1));
        panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, posn, SbVec2f(0.5,0.5));
    }
This now calculates the translation of the camera position back.
Youtube video link Why does it teleport?
Because this->localPos has stored the mouse position inside NavigationStyle::saveCursorPosition(). What you have to handle in NavigationStyle::saveCursorPosition() is to compute the 2D coordinates of the bounding center point and save it to this->localPos.
wmayer
Founder
Posts: 20319
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by wmayer »

See git commit c582e8a085

To test this mode activate the mode BoundingBoxCenter. You must do this directly in the code.
User avatar
watsug
Posts: 100
Joined: Sat Sep 26, 2020 10:51 pm

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by watsug »

Thank you for the phenomenal explanations for my questions!
And even solving the problem for me :P I works great!

I'll try to add a setting for it in the preferences menu.

How does the code choose if ScenePointAtCursor and FocalPointAtCursor is used? ScenePointAtCursor is what is set as the rotationCenterMode. So is FocalPointAtCursor only used if ScenePointAtCursor fails, or is there like a setting for using it?

I'm asking because I want to have both rotate at cursor and rotate at bbCenter.
If mouse is on object -> Rotate at element under the mouse
If mouse beside object -> Rotate at boundingBoxCenter

Thanks again!
wmayer
Founder
Posts: 20319
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by wmayer »

How does the code choose if ScenePointAtCursor and FocalPointAtCursor is used?
This is realized inside the method NavigationStyle::saveCursorPosition. In the switch-case checks it first handles ScenePointAtCursor (if rotationCenterMode is set to this mode) and only if this finds a picked point it jumps out with break, otherwise the case FocalPointAtCursor is executed automatically.
So is FocalPointAtCursor only used if ScenePointAtCursor fails, or is there like a setting for using it?
If rotationCenterMode is set to ScenePointAtCursor it first tries to get the exact point and if it fails it handles FocalPointAtCursor. But it's possible that rotationCenterMode is set to FocalPointAtCursor then it handles this case directly.
I'm asking because I want to have both rotate at cursor and rotate at bbCenter.
If mouse is on object -> Rotate at element under the mouse
If mouse beside object -> Rotate at boundingBoxCenter
Hmm, I wonder how intuitive this behaviour is. Anyway, so it's a matter if FocalPointAtCursor or BoundingBoxCenter is used in case ScenePointAtCursor fails.

Then the best solution probably is to allow to OR the different modes and replace the switch/case with if/else checks. So, rotationCenterMode could be set to ScenePointAtCursor | FocalPointAtCursor or ScenePointAtCursor | BoundingBoxCenter. But I have to think about this in detail first.

From GUI side we also need a change. Currently we have a check-box called Drag at cursor and this then should be replaced with a combo box that lists the possibilities. What text for the combo box do you suggest for the case to drag at cursor or alternatively the bounding box center? The text should be short and intuitive.
User avatar
watsug
Posts: 100
Joined: Sat Sep 26, 2020 10:51 pm

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by watsug »

Thanks again for explanations.
wmayer wrote: Sat Nov 28, 2020 2:51 pm Hmm, I wonder how intuitive this behaviour is.
I got an example mostly working last night, but I'm not at my computer now, so can't recall the code/logic. But for the it's really useful when you have long object like a beam, and looking at a detail at one end. I can make a video later or tomorrow, showing this.
wmayer wrote: Sat Nov 28, 2020 2:51 pm rom GUI side we also need a change. Currently we have a check-box called Drag at cursor and this then should be replaced with a combo box that lists the possibilities. What text for the combo box do you suggest for the case to drag at cursor or alternatively the bounding box center? The text should be short and intuitive.
Maybe something like "Rotate at object center" or is there a word for all the visible objects?
As a first step another checkbox would be enough.
[] Rotate at object center
[] Rotate at cursor
They can be switched independently.

Nothing checked = default behaviour as today.
Rotate at object center = rotating at the boundingbox center instead, as implemented.
Rotate at cursor only checked = rotating at the cursor, like old behaviour today
Rotate at object center and rotate at cursor checked = rotates at boudingbox center if mouse beside object and rotates at the yellow marked part of the object if the mouse is over the object.
As said, can show the code and example later.
User avatar
watsug
Posts: 100
Joined: Sat Sep 26, 2020 10:51 pm

Re: Help adding Rotation at BoundingBoxCenter mode in NavigationStyle.cpp

Post by watsug »

Fantastic!
I do have some thoughts.
1. The setting should not be named "Drag at cursor" but "Rotate at cursor". Drag doesn't make sense here.
2. Some people might want rotation at object center always, and never on mouse position. It could be useful if you have a large object, taking up most of the screen, so it's hard to click beside the object. But maybe this is a niche case. I tried to show it in the dice example, 0:58 in the video.

Maybe better wording in settings could be: "Rotation center mode:"
- Window center
- Cursor position
- Object center

Here's a video for anyone else browsing this thread, feel free to comment on the ux or wording in settings!
phpBB [video]


Will this be integrated for
Post Reply