How to get mouse position in 3D view?

Operating system: window 10
Slicer version: 5.2.1

## Custom add markups functions 
def test():

    # get crosshair 
    crosshairNode=slicer.util.getNode("Crosshair")

    pos = [0,0,0]

    crosshairNode.GetCursorPositionRAS(pos)

    print(pos)

    slicer.modules.markups.logic().AddControlPoint(pos[0], pos[1], pos[2])


This code is an implementation of a code that creates markups according to the mouse position in the slicer view (R,Y,G).

How to do this function in 3D view?

placeModePersistence = 1
slicer.modules.markups.logic().StartPlaceMode(placeModePersistence)

If you add markups through the code above, it is not added to the markups list, so it doesn’t fit the purpose I’m trying to do.

image

The purpose is to replace the process of taking markup by clicking the Point list in GUI mode with ‘shortcut’.

Hi,

This code from the script repository should help.

Hi,

The code above is what I’ve been looking at for reference.

The code outputs the coordinates whenever the mouse is moved, but what I need is a function that gets the mouse coordinates only once for a specific action( right_button_click_in_mouse … )

crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)

Is there any way to make this work only once?

Can you describe in more specific terms the workflow and functionality of what you desire? This will help us provide more specific feedback to help solve the workflow that you desire.

Something like:
“While viewing a model in the 3D view, I would like to place a control point on the model at the location of the cursor as initiated by a keyboard shortcut so that I stay in ViewTransform mouse mode”

Are you looking for shortcuts to place multiple control points? Or shortcut to create an entirely new point list. Point lists can contain X number of control points so creating a new point list that only contains a single control point can be very inefficient.

Hi @jamesobutler

image

<fig1. nodes in Scene>

As in the example above, importing hundreds of markups through GUI manipulation in a 3D view is cumbersome, so I’m trying to create a new keyboard shortcut function.

def custom_import_markup() :

  #TODO

  1)   Get current mouse cursor position in 3D view.
 
  2)  Adds markup nodes to the 3D view based on the fetched mouse position.

  3)  Also add it to the nodes list you can see in fig1.

shortcut = qt.QShortcut(qt.QKeySequence("Ctrl+e"), slicer.util.mainWindow())
shortcut.connect("activated()", lambda: custom_import_markup())
 

Therefore, I would like to implement a function that, when I put the mouse somewhere in the 3D view and press ‘ctrl+e’, the markup is added to the 3D VIEW and at the same time, the markup node of ‘F_n(example_case n =5 )’ is added to the node list of fig.1.

TODO - 3) means

placeModePersistence = 1
slicer.modules.markups.logic().StartPlaceMode(placeModePersistence)

This code adds markup whenever the mouse is clicked in the 3D view. This feature works great for my purpose. However, there is a problem that it cannot be added to the node on the left.

I would appreciate it if you could let me know if you have any reference material or code to implement the above function.

I observe that the code appropriately adds a Markup Point List to the scene and persistently adds Control Points to the Markup Point List. The first table in the Markups module is the list of nodes. In the “Control Points” section there is the table that shows all the control points that are in the Point List Markup node.

Markup node Type: “Point List” (vtkMRMLMarkupsFiducialNode)
Markup node name: “F”
Markup “F” Control Points: F-1, F-2, F-3, F-4, F-5

There is also the Markups toolbar that allows for creating new markup nodes and accessing the placement mode button to add control points to the selected markup. Creating a new Point List markup through the toolbar, automatically puts the state into control point placement mode.
https://slicer.readthedocs.io/en/latest/user_guide/modules/markups.html#place-new-markups

1 Like

@jamesobutler

Oh my god,

Until now I had mistakenly thought that ‘vtkMRMLMarkupsFiducialNode’ was a position.
I clearly understood that ‘vtkMRMLMarkupsFiducialNode’ is a list of points.

Previously, I implemented the cunstom_undo function by deleting the node, but I need to modify it by individually accessing the control point elements of the point list.

@jamesobutler

Hello again,

With your help, I was able to complete the desired feature. However ,When I asked the company, they were using the inefficient method you mentioned for various reasons.
They were using only one control point per point list.

So my other question is how can I create a ‘Point List’ with a mouse click? ( one click → make one point list) If you can refer to any reference material, I will do it.

You would need to add code that utilizes AddNewNodeByClass methods for vtkMRMLMarkupsFiducialNode. As in Script repository — 3D Slicer documentation.

What is the reason for having multiple point list nodes with only one control point in each? There can be a drop in performance when there are a lot of nodes in the scene. To code, it would be easier to use one point list and access the individual control point locations in the point list.

Hi ! @jamesobutler

As you said, using one control point in one point list is very inefficient.

Here’s a quick summary of what my colleague told me:

  • A label is required for each control point.
  • In the case of an efficient method, when saving as a json file, one json file for one point list is saved.
  • They want to save and manage one control point each as a json file, and it has been in the past.
  • It is annoying to press the point list on the GUI and press the control point.

I also don’t understand why you use this method.
I know how to save each control point as a json file, but I have to implement it in an inefficient way because it takes too long to apply to what my company has done before.

======================================

In slicer view (R, Y, G), you can know the current coordinates of the mouse through the ‘crosshair node’, but is that impossible in 3D view?

In my opinion, one actions are required to achieve this inefficient method:

1. Get mouse coordinates from 3d view (only once)

def onMouseMoved(observer,eventid):
  ras=[0,0,0]
  crosshairNode.GetCursorPositionRAS(ras)
  print(ras)

crosshairNode=slicer.util.getNode("Crosshair")
crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)

In the case of the code above, the coordinates are retrieved whenever the mouse position is modified. Is there a way to obtain the coordinates only once when the mouse is clicked?

The rest is just a matter of creating a point list with the imported coordinate values.

In the Markups module a point list can show labels for each control point, or the labels can be hidden. Is the existing behavior not what is desired?

@jamesobutler

No

There is only one thing I want to know.

def test():

    # get crosshair 
    crosshairNode=slicer.util.getNode("Crosshair")

    pos = [0,0,0]

    crosshairNode.GetCursorPositionRAS(pos)

    print(pos)

    pointListNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode","F")

    pointListNode.AddControlPoint(pos[0], pos[1], pos[2])


shortcut = qt.QShortcut(qt.QKeySequence("Ctrl+r"), slicer.util.mainWindow())
shortcut.connect("activated()", lambda: test())

The above code gets the position of the mouse cursor in slicer view ( R,Y,G ), but it does not work in 3D view. Any way to solve this?