# Modifying \`vtkMRMLAbstractViewNode::Reset(...)\` function from MRMLCore

**URL:** <https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086>\
**Category:** Development\
**Created:** [October 9, 2021, 11:22pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086 "2021-10-09T23:22:31Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 9, 2021, 11:22pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/1 "2021-10-09T23:22:31Z")

</div>

Hi,

Here is the implementation of `vtkMRMLAbstractViewNode::Reset(...)` function:

```cpp
void vtkMRMLAbstractViewNode::Reset(vtkMRMLNode* defaultNode)
{
  // The LayoutName is preserved by vtkMRMLNode::Reset, however the layout
  // label (typically associated with the layoutName) is not preserved
  // automatically.
  // This require a custom behavior implemented here.
  std::string layoutLabel = this->GetLayoutLabel() ? this->GetLayoutLabel() : "";
  int viewGroup = this->GetViewGroup();
  this->Superclass::Reset(defaultNode);
  this->DisableModifiedEventOn();
  this->SetLayoutLabel(layoutLabel.c_str());
  this->SetViewGroup(viewGroup);
  this->AxisLabels->Reset();
  for (int i=0; i<vtkMRMLAbstractViewNode::AxisLabelsCount; i++)
    {
    this->AxisLabels->InsertNextValue(DEFAULT_AXIS_LABELS[i]);
    }
  this->DisableModifiedEventOff();
}

```

Why `this->AxisLabels` are set to some default medical values instead of copying them from the `defaultNode` node?

For custom application that works with axis labels `XYZ` for example this function brings a lot of problems as after calling `Reset(...)` axes labels will be changed to medical values `APSI etc` no matter what labels the `defaultNode` have.

Probably it is better to cast the `defaultNode` to `vtkMRMLAbstractViewNode` and if casting returns non `NULL` pointer then use `GetAxisLabel()` to set axes labels and if not then use the default medical values?

For example for now `ViewControllers` module uses the `Reset()` function and it thus I can’t use it in my custom app without some tricks that I do.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 9, 2021, 11:55pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/2 "2021-10-09T23:55:55Z")

</div>

Maybe modify it this way:

```cpp
void vtkMRMLAbstractViewNode::Reset(vtkMRMLNode* defaultNode)
{
  // The LayoutName is preserved by vtkMRMLNode::Reset, however the layout
  // label (typically associated with the layoutName) is not preserved
  // automatically.
  // This require a custom behavior implemented here.
  std::string layoutLabel = this->GetLayoutLabel() ? this->GetLayoutLabel() : "";
  int viewGroup = this->GetViewGroup();
  this->Superclass::Reset(defaultNode);
  this->DisableModifiedEventOn();
  this->SetLayoutLabel(layoutLabel.c_str());
  this->SetViewGroup(viewGroup);
  this->AxisLabels->Reset();
  vtkMRMLAbstractViewNode* defaultViewNode = vtkMRMLAbstractViewNode::SafeDownCast(defaultNode);
  if (defaultViewNode){
    for (int i=0; i<vtkMRMLAbstractViewNode::AxisLabelsCount; i++)
    {
      this->AxisLabels->InsertNextValue(defaultViewNode->GetAxisLabel(i));
    }
  } else {
  for (int i=0; i<vtkMRMLAbstractViewNode::AxisLabelsCount; i++)
    {
    this->AxisLabels->InsertNextValue(DEFAULT_AXIS_LABELS[i]);
    }
  }
  this->DisableModifiedEventOff();
}

```

---

<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:** [October 10, 2021, 12:28pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/3 "2021-10-10T12:28:09Z")

</div>

I don’t see why this additional resetting of the axis labels would be needed (node reset and copy from the default node should take care of this). Would removing AxisLabels Reset and InsertNextValue calls fix the behavior?

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 10, 2021, 3:39pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/4 "2021-10-10T15:39:38Z")

</div>

> [@lassoan](#):
>
> Would removing AxisLabels Reset and InsertNextValue calls fix the behavior?

Yes that would be enough. I just tested that while relying on `ViewControllers` module and by enabling/disabling this module (i.e. enabling disabling `Reset(defaultNode)`) I can say that if you change the code as you proposed (by removing everything connected with `AxisLabels` var) axes labels will be copied from the default node.

**Related question:**

There is one thing I’m not sure about yet is `void vtkMRMLNode::Reset(vtkMRMLNode* defaultNode)` calls `CopyWithScene` and the latter calls `Copy` and it calls `CopyContent`. Here it is:

```cpp
void vtkMRMLNode::CopyContent(vtkMRMLNode* node, bool vtkNotUsed(deepCopy)/*=true*/)
{
  MRMLNodeModifyBlocker blocker(this);
  vtkMRMLCopyBeginMacro(node);
  vtkMRMLCopyStringMacro(Description);
  vtkMRMLCopyBooleanMacro(Selectable);
  vtkMRMLCopyEndMacro();
  this->Attributes = node->Attributes;
}

```

`CopyContent` uses some macros that I can’t understand now but these macros somehow adds medical orientation presets to my default `XY, YZ, XZ`. I removed medical orientation presets (`Sagittal, Axial, Coronal`) from all already created slice nodes and from the default nodes but when `ViewControllers` is enabled the mentionned above macros adds those medical presets.  
Maybe I do something wrong but if you have something to say (maybe some key words about these macros) I would appreciate:

```cpp
  std::vector<std::string> axesNames({"X", "-X", "-Y", "Y", "-Z", "Z"});
  std::vector<std::string> orientationPresetOld({"Axial", "Sagittal", "Coronal"});
  std::vector<std::string> orientationPresetNew({"XY", "YZ", "XZ"});
  std::vector<std::string> defaultOrientation({"XY", "YZ", "XZ"});

  for (size_t i = 0; i < orientationPresetOld.size(); i++){
    if (defaultSliceNode->HasSliceOrientationPreset(orientationPresetOld[i])){
      defaultSliceNode->RemoveSliceOrientationPreset(
            orientationPresetOld[i]);
    }

    if (!defaultSliceNode->HasSliceOrientationPreset(orientationPresetNew[i])){
      defaultSliceNode->AddSliceOrientationPreset(
            orientationPresetNew[i],
            GenerateOrientationMatrix(orientationPresetNew[i]));
      defaultSliceNode->SetDefaultOrientation(defaultOrientation[i].c_str());
    }
  }

```

On the picture you can see that vtk macros from `CopyContent` add medical presets:  
 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/9/4/94dada94010dfc0569e7681046fec2f0de68a72d.png)

---

<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:** [October 10, 2021, 5:01pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/5 "2021-10-10T17:01:57Z")

</div>

You can update the slice node reset and copy methods to initialize the orientation presets from the default slice node.

The default orientation name for each slice view is specified in the view layout description. Therefore, if you change the orientation preset names then you may need to update the layout descriptions, too.

---

<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:** [October 11, 2021, 12:02am UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/6 "2021-10-11T00:02:56Z")

</div>

When you are done with these changes then please submit them in a pull request so that we can review and merge them into Slicer core.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 11, 2021, 1:07am UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/7 "2021-10-11T01:07:19Z")

</div>

From Slicer Astro I have found an example how to modify `vtkMRMLLayoutNode` description and I applied it to my case but still I can see the default slicer `Axial` `Sagittal` and `Coronal` presets:

```cpp
  vtkMRMLLayoutNode* layoutNode = vtkMRMLLayoutNode::SafeDownCast(
    this->LayoutManager->mrmlScene()->GetSingletonNode("vtkMRMLLayoutNode","vtkMRMLLayoutNode"));
  if(!layoutNode)
    {
    qCritical() << "qSlicerAstroVolumeModule::setup() : layoutNode not found!";
    return;
    }

  for(int i = 1 ; i < 36; i++)
    {
    if (i == 5 || i == 11 || i == 13 || i == 18 || i == 20)
      {
      continue;
      }

    std::string layoutDescription = layoutNode->GetLayoutDescription(i);
    std::vector<std::string>::const_iterator it;
    std::vector<std::string>::const_iterator jt;
    for(it = orientationPresetOld.begin(), jt = orientationPresetNew.begin();
        it != orientationPresetOld.end() && jt != orientationPresetNew.end(); ++it, ++jt)
      {
      size_t found = layoutDescription.find(*it);
      while (found!=std::string::npos)
        {
        layoutDescription.replace(found, it->size(), *jt);
        found = layoutDescription.find(*it);
        }
      }
    layoutNode->SetLayoutDescription(i, layoutDescription.c_str());
    }

```

I don’t understand yet some things especially how node’s description influences on app behaviour and why Slicer’s astro authors use numbers like 36, 5, 11, 13, 18, 20 in this code…

If possible please take a look at [dirty source code](https://github.com/tierra-colada/Colada/blob/1a91d0d2d6c3b8627a29e82ff069d26103a305e9/Applications/ColadaApp/qColadaAppMainWindow.cxx#L187-L296)

---

<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:** [October 11, 2021, 4:55am UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/8 "2021-10-11T04:55:16Z")

</div>

I had a look at orientation presets, and it all looks good. Orientation presets are already stored in the deafult slice node, initialized by `AddDefaultSliceOrientationPresets`. If you want to change the defaults just make sure you update the defaults after `AddDefaultSliceOrientationPresets` method is called and before you add your new presets, clear the old ones.

> [@keri](#):
>
> I don’t understand yet some things especially how node’s description influences on app behaviour and why Slicer’s astro authors use numbers like 36, 5, 11, 13, 18, 20 in this code…

As you can see `i` refers to layout indices. Instead of 5, 11, etc. the developer should have written `SlicerLayoutOneUpSliceView`, `SlicerLayoutLightboxView`, etc. (see [complete list](https://github.com/Slicer/Slicer/blob/master/Libs/MRML/Core/vtkMRMLLayoutNode.h#L88-L130)).

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 11, 2021, 2:14pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/9 "2021-10-11T14:14:10Z")

</div>

Thank you for reply,

I took a look at `AddDefaultSliceOrientationPresets` implementation and the idea pretty clear and now I understand why I need to overwrite presets after this function is called.

From the IDE I can find all references to `AddDefaultSliceOrientationPresets` and only [qSlicerViewControllersModule.cxx](https://github.com/Slicer/Slicer/blob/03e913587bf7b78990f0224bc77818e3ed31d5d3/Modules/Loadable/ViewControllers/qSlicerViewControllersModule.cxx#L205-L221) references to that function. I tried to comment these lines and rebuilt the target but still `Reset(...)` function adds medical orientation presets.

---

<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:** [October 11, 2021, 2:29pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/10 "2021-10-11T14:29:11Z")

</div>

You can add a breakpoint in `AddDefaultSliceOrientationPresets` to see what calls it.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 11, 2021, 3:24pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/11 "2021-10-11T15:24:42Z")

</div>

You were right, it was my carelessness: I commented `AddDefaultSliceOrientationPresets` from `qSlicerViewControllersModule.cxx` but I used to rebuild the `...Logic` target instead of `...Module` target. There is no any problem if I comment the section with `AddDefaultSliceOrientationPresets` from that module and the rebuild the correct target.

**Proposition:**  
Does `ViewControllers` module really need to add orientation presets and make other settings with `defaultViewNode`? That makes this module difficult to use in custom application.

I think the main purpose of this module is to use controller widgets from module tab and if so then this module can be useful not only in medical software.

I propose to modify this module (if possible of course, I haven’t precisely looked at its implementation yet) in a way that it won’t do any settings with default nodes.

---

<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:** [October 11, 2021, 7:11pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/12 "2021-10-11T19:11:17Z")

</div>

Default view presets need to be set _somewhere_. The View Controllers module seems to be a reasonable place for that. Where else would you put it?

Note that the preset is already customizable without any Slicer core code change, but if you have a preferred way of making it simpler then let us know. For example the View Controllers module could have a flag to control its behavior or could emit a signal after setting the defaults so that other modules can override those, or default orientation presets could be read from the application settings, etc.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 11, 2021, 8:32pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/13 "2021-10-11T20:32:38Z")

</div>

> [@lassoan](#):
>
> Default view presets need to be set _somewhere_ . The View Controllers module seems to be a reasonable place for that. Where else would you put it?

I agree that presets should be set somwhere but in my opinion they should be set somwhere in medical module.  
It is very difficult to guess that module named `ViewControllers` and that is aimed at some widget manipulation brings some medical staff to SlicerCAT.  
To figure that out I started launching SlicerCAT with disabled modules. The first module to disable was `Endoscopy` (though I don’t know how I included it to app) because it is very obvious to think that medical modules makes medical changes and I was very surprised when I discovered that at `ViewControllers` 🙂

I’m not familiar with most medical modules that Slicer uses but I think such things should be implemented there (I can’t tell where exactly). Or probably make some GUI-less module where one does especially medical customization like manipulation with presets. Then those developers who work on SlicerCAT could disable this module and create his own (though I couldn’t do GUI-less module that is completely hidden yet but believe that is possible, I remember I created topic on that on this forum).

> [@lassoan](#):
>
> For example the View Controllers module could have a flag to control its behavior or could emit a signal after setting the defaults so that other modules can override those, or default orientation presets could be read from the application settings, etc.

I think this would bring some complexity for developers. Slicer already has well structured philosophy with scene, views, slices, nodes, modules, superbuild etc and I think adding signals to _control such things_ is like using insulating tape to weld metall.

The only solution I can see is to try to keep medical staff in medical modules.

P.S.  
Sometimes I need to make changes in Slicer core that is not appropriate for medical goals (like [resizing slice view while preserving field of view or aspect ratio](https://discourse.slicer.org/t/resizing-slice-view-doesnt-preserve-field-of-view/19636)) and for this I use [cpp tool](https://github.com/tierra-colada/cppguts) or [python tool](https://github.com/tierra-colada/pythonguts) that replaces selected function implementation during build time and thus allowing to use it in superbuild. Of course I’m trying to make core changes as less as possible

---

<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:** [October 11, 2021, 9:30pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/14 "2021-10-11T21:30:12Z")

</div>

> [@keri](#):
>
> The first module to disable was `Endoscopy` (though I don’t know how I included it to app) because it is very obvious to think that medical modules makes medical changes

This is not a medical module at all. Endoscopy just means that you visualize from inside. It is used commonly in medical imaging but just as well for inspection of pipelines, tunnels, etc.

> [@keri](#):
>
> I agree that presets should be set somwhere but in my opinion they should be set somwhere in medical module.

While more than 99.9% of Slicer development has been funded for medical applications, nothing is hardcoded in Slicer for medical applications and there is no module that would only be applicable to medical imaging - all modules can be used for various industrial, engineering, etc. applications. Of course defaults must be set to something, and since medical imaging is the primary application area, the defaults are set accordingly. This should not be an issue, as Slicer core developers are willing to make things more generic and configurable, even if that means slightly increasing complexity.

> [@keri](#):
>
> I think adding signals to _control such things_ is like using insulating tape to weld metall.

Things that would be considered as workarounds in Slicer core are completely acceptable, good solutions in custom applications. For example, in a custom application you will know that no other modules will change the view preset names, so changing the default in response to a signal would be completely fine, nice and clear solution. However, if you don’t like this then you can propose a change in Slicer core to read default view presets from the application settings.

> [@keri](#):
>
> Sometimes I need to make changes in Slicer core that is not appropriate for medical goals

In general, source code changes are probably the best done using git, because all code changes are automatically synchronized (or you are prompted to resolve conflicts manually) whenever you rebase your Slicer core version. It is much simpler and more robust compared to patching files.

Of course these should only be used temporarily, while you are validating some ideas and once things are mature then you get them merged into the Slicer core (or make Slicer core configurable so that you can inject your custom behavior).

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [October 11, 2021, 10:40pm UTC](https://discourse.slicer.org/t/modifying-vtkmrmlabstractviewnode-reset-function-from-mrmlcore/20086/15 "2021-10-11T22:40:05Z")

</div>

Thank you for the information, I’m slightly ashamed about not knowing about Endoscopy module 🙂

**About ViewControllers:**  
The default presets are lodaded in file `vtkMRMLApplicationLogic.cxx` in function `void vtkMRMLApplicationLogic::SetMRMLSceneInternal(vtkMRMLScene* newScene)`.  
As I see `void qSlicerViewControllersModule::readDefaultSliceViewSettings(vtkMRMLSliceNode* defaultViewNode)` handles `PatientRightIsScreenLeft` and `PatientRightIsScreenRight`.  
I thought that we could added property like `IsAxesMedical` to default node and display it as a checkbox in `Edit->Application Settings->Views` and if this checkbox is uncheked then `View orientation` combobox should be greyed out and `ViewController` don’t have to do any manipulations with orientation presets. How do you think?

**EDIT:**  
I just remembered that you already proposed to set default preset from application properties - Yes that I also like.

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/8/1/814688a8b27cb12bf7be66a0ad9ebbd754073f90.png)

**About signal in this case:**  
If emitting signal directly from `vtkMRMLSliceNode::AddDefaultSliceOrientationPresets(newScene)` was possible I would like to do that. But instead of emitting it from `ViewControllers` I would prefer the method proposed in the upper paragraph with attribute.
