3D coordinate from mouse cursor position

Dear ROOT experts,

I want to customize the TH1:SetShowProjection method for TH3 histograms and write a more complex GUI. I found DynamicSlice.C and it’s a good starting point for me, essentially what I want to do is to extend it to the 3D case.

Coming to my question, I was wondering if there’s already an easy way to get the respective 3D point from a (px, py) mouse cursor position.

Thanks in advance.

I do not see a such function in TView or TView3D… If it exits it should be there seems to me…

Well, I thought that I could have a look to the current implementation of the 3D -> 2D projection (via SetShowProjection) in ROOT, there should be the piece of code I’m looking for… but I could not find it.

Indeed going from px py to x,y,z is not really possible conceptually. The best you can get is a 3D line parallel to two of the axis.

But then how does ROOT find the position of the slice from the mouse position when displaying the 2D projection?

In the example DynamicSlice.C the 2d histogram is plotted in 2D … do you have a example ?

I don’t have any working example, but this is what I want to achieve:

I have a TH3D and I want to write a GUI that displays the histogram along with two interactive 2D orthogonal slices (xy and xz, for example), all in the same canvas. The slices are taken from the position of the mouse cursor and I want to display the two current slicing planes onto the TH3D, just as it happens with one projection when enabling SetShowProjection.

It’s pretty clear in my mind how the implementation should be, having seen DynamicSlice.C, but the missing starting point is finding a way to obtain the position of the two slices (the x and the z, staying with the same example) from the mouse position.

I hope I explained myself :slight_smile:

You can do something like in the gl example glbox.C.
When you move the mouse on the back plaine it highlights then you can move the plane
using the shift+mouse

Looks really nice, but frankly I don’t know where to start, the code in glbox.C is unexpectedly simple… How do I retrieve the current positions of the planes?

It was just an example showing what can be done. But that’s done with OpenGL. I do not think you want that. You want to use the normal LEGo and SURF plots ? To draw in that space you can look at: Plot mean and max values of TGraphs in a TMultiGraph

What I did in the end is mainly stealing code from TH3::Project3D, find the script and a test ROOT file attached here.

As you can see there are problems in visualizing the polylines (but I find them as well with TH1::SetShowProjection, so it might be a more general bug): the horizontal plane vanishes after the respective 2D slice is drawn and the vertical one stays on screen until the next mouse click.

What do you suggest to fix the behaviour?

test.root (65.2 KB)
test_proj.C (11.4 KB)

I am not sure… may be redraw the 3D scene ?

I cannot do that because the histograms I normally visualize are quite big (not like the test I sent you) and it takes a while to render them… redrawing the 3D scene every time would kill the performance.

I will try to play around with different implementations and see if I can fix the problem, I wanted in any case to switch to filled shapes instead of polylines, maybe the problem will vanish…

Do you know how or the point in DynamicSlice.C where the old line gets erased? I just see a double DrawLine but I don’t think it is responsible for that…

I guess the double drawline is done in Xor mode. In that mode the 2nd drawline erases the previous one.

TVirtualX::kXor or TVirtualX::kInvert? Does the following work for you?

auto c = new TCanvas;
c->FeedbackMode(true); // hides a call to gVirtualX->SetDrawMode(TVirtualX::kInvert)
// gVirtualX->SetDrawMode(TVirtualX::KXor)
gVirtualX->DrawLine(0, 0, 100, 100);
gVirtualX->DrawLine(0, 0, 100, 100); // does the line stay on screen?

But the tricky thing is that in DynamicSlice.C it works… I have no clue why.

you are using X11 backend ?

Sure, I forgot to say that I’m on Linux.

Yes in DynamicSlice the code to erase the old line and redraw the new one is:

   if(pyold) gVirtualX->DrawLine(pxmin,pyold,pxmax,pyold);
   gVirtualX->DrawLine(pxmin,py,pxmax,py);

You need to keep track of the old/previous line.

Ok, but then I don’t know why it does not work in my macro, I’m doing the same thing! See attached an updated version:

test_proj.C (12.7 KB)

In particular, at line 47 I do canvas->FeedbackMode(true), at lines 136 and 138 I declare the static structures holding the drawn coordinates, so I can delete them with DrawPolyLine at lines 170 and 232 and finally I draw the new rectangles at lines 367 and 368.

But as you can see it does not work. Also, the simple code I quoted in one of my previous comment in an interactive ROOT session does not work for me…