GetNthControlPointOrientationMatrix : How should we consider it?

A markups fiducial node has this function : GetNthControlPointOrientationMatrix.

While tinkering with it, it does not get modified if a transform is applied to the fiducial node, nor if it is placed in a reformatted slice view. If we modify this matrix with SetNthControlPointOrientationMatrix, the applied matrix is always retrieved unaltered.

Is it only a storage place intended for developers ?
Would the markups internals require/modifiy it ? In what circumstances?

Thanks for any input.

Please try this:

orientationMatrix = vtk.vtkMatrix3x3()
getNode('F').GetNthControlPointOrientationMatrix(0,matrix)
#should be the identity
print(matrix)

matrix.SetElement(1,1,-1)
matrix.SetElement(2,2,-1)
#matrix has changed
print(matrix)

#change the orientationMatrix by our changed matrix
getNode('F').SetNthControlPointOrientationMatrix(0,matrix)

#read the new orientationMatrix value, it should not be the identity
matrix2 = vtk.vtkMatrix3x3()
getNode('F').GetNthControlPointOrientationMatrix(0,matrix2)
print(matrix2)

#It's okey

It’s very clear, thank you.

But is it only a storage place ? If we modify it, how would it affect the fiducial node or a slice node ? I mean, does Slicer rely on it to do something ? Can we just store here an orientation matrix parameter that we would be needing later ?

I think it should work as storage for markups for what I have seen on a fast search through the C++ code. I don’t know about sliceNodes.

Yes I think you can save here an orientationMatrix that you would be needing later

That would simplify things a lot, thank you.

Fiducial orientations are a holdover from the original implementation in slicer2 - many of the coolest features of Delphine’s original work have never been ported to later slicer versions.

http://dspace.mit.edu/handle/1721.1/87240

In general all node properties are set and retrieved in the node’s coordinate system. You can apply the node’s parent transform to the positions, orientations, etc. to get that in world coordinate system. If you only have linear parent transforms then this is a simple matrix multiplication.

There are convenience functions with “World” or “RAS” suffix in their name that get/set information in world coordinate system. See for example here:

Yes, I noticed that, and tend to use the ‘World’ suffixed functions every time.

I noticed strange results with the World variants here :

matrix = vtk.vtkMatrix3x3()
f = slicer.util.getNode("F")
f.GetNthControlPointOrientationMatrixWorld(0, matrix)
# matrix is identity

matrix.SetElement(0, 1, 2.0)
matrix.SetElement(1, 2, -2.0)
print(matrix)

f.SetNthControlPointOrientationMatrixWorld(0, matrix)

matrix2 = vtk.vtkMatrix3x3()
f.GetNthControlPointOrientationMatrixWorld(0, matrix2)
print(matrix2)
# matrix2 : all 9 values are 0

seq = GetNthControlPointOrientationMatrixWorld(0)
# ValueError: cannot create object of unknown type "vtkVector_IdLi9EE"

I guess no one is relying on this, but it’s worth reporting.

Setting orientation of a control point in a non-transformed markup node using the SetNthControlPointOrientationMatrixWorld method indeed did not work correctly. It is fixed now. Since control point orientation is not used for anything else than recording it and storing it, it is not tested very widely and thoroughly and so the bug remain unnoticed.

What do you plan to use the control point orientation for?

In a self-contained tool, I need to record the orientation part of the SliceToRAS matrix. It will be different at each fiducial control point. This Get/Set facility seems to be available but not used in Slicer itself. So it gets in very handy.

As a side note, this orientation matrix is not saved with the markups node. Attaching this data to the control points will therefore be volatile, scene-wide only. It’s yet welcome.

Thank you.