# Unexpected interactions of ROI objects with code

**URL:** <https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053>\
**Category:** Development\
**Created:** [November 6, 2024, 1:43pm UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053 "2024-11-06T13:43:38Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![shai-ikko](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shai-ikko/32/15765_2.png) [@shai-ikko](https://discourse.slicer.org/u/shai-ikko)\
**Post date:** [November 6, 2024, 1:43pm UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053/1 "2024-11-06T13:43:38Z")

</div>

This continues the topic [Configure ROI to match volume through code](https://discourse.slicer.org/t/configure-roi-to-match-volume-through-code/39695) but I think that post was not phrased very well, so let’s start again:

I’m creating a ROI with code based on an example from the script repository:

```python
self.roiNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")

cropVolumeParameters = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLCropVolumeParametersNode")
cropVolumeParameters.SetInputVolumeNodeID(self.volumeNode.GetID())
cropVolumeParameters.SetROINodeID(self.roiNode.GetID())
slicer.modules.cropvolume.logic().FitROIToInputVolume(cropVolumeParameters)
slicer.mrmlScene.RemoveNode(cropVolumeParameters)

```

I get this ROI object:

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/b/e/bef11f98100e31f03121908c2e8db91de0926299.jpeg)

But now if I tell it its ObjectToNode matrix is updated, it jumps (I need this because, as you can see, I give users rotation handles, and I also want to give them a “reset” button). And indeed, the center in the world has changed:

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/6/e/6e142e429ac847e140c68176d2ac4458b7730d82.jpeg)  
Now, here come some funnier parts: If I try to reset the center in the world, it doesn’t work:

```python
>>> roi.SetCenterWorld(center)
>>> roi.GetCenterWorld()
vtkmodules.vtkCommonDataModel.vtkVector3d([0.0, 0.0, 0.0])
>>> center
vtkmodules.vtkCommonDataModel.vtkVector3d([0.38079845905303955, -22.919204711914062, -175.25])

```

If I first reset the center to 0, then it semi-works: After

```auto
>>> roi.SetCenterWorld([0,0,0])
>>> roi.SetCenterWorld(center)

```

the ROI is visually back to its place fitting the volume, but

```auto
>>> roi.GetCenterWorld()
vtkmodules.vtkCommonDataModel.vtkVector3d([0.0, 0.0, 0.0])

```

I’m not even sure what exactly is the bug I should report, but I’m pretty convinced that this Can’t Be Right ™.

Slicer 5.6.2 on Ubuntu 20.04.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [November 7, 2024, 5:13am UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053/2 "2024-11-07T05:13:01Z")

</div>

I cannot reproduce any “jump” with neither the latest Slicer Stable Release (Slicer-5.6.2) nor the latest Slicer Preview Release (Slicer-5.7):

```python
import SampleData
volumeNode = SampleData.downloadSample('CTChest')

roiNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")
cropVolumeParameters = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLCropVolumeParametersNode")
cropVolumeParameters.SetInputVolumeNodeID(volumeNode.GetID())
cropVolumeParameters.SetROINodeID(roiNode.GetID())
slicer.modules.cropvolume.logic().FitROIToInputVolume(cropVolumeParameters)
slicer.mrmlScene.RemoveNode(cropVolumeParameters)

print(roiNode.GetCenter())
print(roiNode.GetCenterWorld())
roiNode.GetObjectToNodeMatrix().Modified()
print(roiNode.GetCenter())
print(roiNode.GetCenterWorld())

```

---

<div class="post-metadata">

**Author:** ![shai-ikko](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shai-ikko/32/15765_2.png) [@shai-ikko](https://discourse.slicer.org/u/shai-ikko)\
**Post date:** [November 7, 2024, 3:02pm UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053/3 "2024-11-07T15:02:16Z")

</div>

Thanks for the quick turnaround.

Following your message, I went and dug deeper, and was able to pinpoint the issue. Indeed, the code in the script repository is innocent. The issue turns out to be elsewhere.

Besides what I reported earlier, I have a callback for changes in the ROI. Among other things, it takes the ROI’s `ObjectToWorldMatrix`, and changes it a little in order to do some computations. I didn’t think this was relevant, because the documentation specifically [says](https://apidocs.slicer.org/master/classvtkMRMLMarkupsROINode.html#a540216cdf23db6e5766b84238e638996) that “Changes made to the matrix will not be applied”. And indeed, in most uses, this appears to be the case – but not if the change is in a callback for modifications.

To reproduce the jump:

```python
import SampleData
volumeNode = SampleData.downloadSample('CTChest')

roiNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")
cropVolumeParameters = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLCropVolumeParametersNode")
cropVolumeParameters.SetInputVolumeNodeID(volumeNode.GetID())
cropVolumeParameters.SetROINodeID(roiNode.GetID())
slicer.modules.cropvolume.logic().FitROIToInputVolume(cropVolumeParameters)
slicer.mrmlScene.RemoveNode(cropVolumeParameters)

def onROIModified(roi, event) -> None:
    mat4 = roi.GetObjectToWorldMatrix()
    for i in range(3):
        mat4.SetElement(i, 3, 0.0)
roiNode.AddObserver(vtk.vtkCommand.ModifiedEvent, onROIModified)

print(roiNode.GetCenter())
print(roiNode.GetCenterWorld())
roiNode.GetObjectToNodeMatrix().Modified()
print(roiNode.GetCenter())
print(roiNode.GetCenterWorld())

```

Now I know how to avoid the problem in my code; I maintain that the behavior shown here is surprising and even buggy, but I can totally see why fixing it would be more trouble than it’s worth – and perhaps some documentation fix is most appropriate.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [November 7, 2024, 4:31pm UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053/4 "2024-11-07T16:31:35Z")

</div>

ObjectToWorldMatrix is computed internally and must not be modified. The `Changes made to the matrix will not be applied` note meant to say that developers should not modify the matrix (if modifications has no effect then why would anyone change it?), but it seems that we have to be more explicit.

We could also change the API to require an input vtkMatrix4x4 object. It would prevent any invalid changes, but it would be a bit less convenient (you would need to create a new object before you call the Get… function).

---

<div class="post-metadata">

**Author:** ![shai-ikko](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shai-ikko/32/15765_2.png) [@shai-ikko](https://discourse.slicer.org/u/shai-ikko)\
**Post date:** [November 11, 2024, 9:49am UTC](https://discourse.slicer.org/t/unexpected-interactions-of-roi-objects-with-code/40053/5 "2024-11-11T09:49:55Z")

</div>

I made a little initial [PR](https://github.com/Slicer/Slicer/pull/8034) for this.

> [@lassoan](#):
>
> developers should not modify the matrix (if modifications has no effect then why would anyone change it?)

As hinted, in my case, I’m using the ROI as a control element, to pick a rotation which I want to apply elsewhere; however, I don’t want to apply the translation. One way to achieve this, if I’m not mistaken, is to take this matrix, and zero out the first three cells of the last column.
