Observe camera node events in a loadable module logic

Are there any specific requirements to observe vtkMRMLCameraNode events in C++ module logic?

Python code works as it should, and i can see “update beam” message

def updateBeamFromCamera(caller=None, event=None):
  print("update beam")

cameraObs = threeDcamera.AddObserver( vtk.vtkCommand.ModifiedEvent, updateBeamFromCamera)

But i can’t observe any camera node events in C++ module.

Did i miss something obvious?

Here is a part of C++ code

//-----------------------------------------------------------------------------
void vtkSlicerSomeLogic::RegisterNodes()
{
  vtkMRMLScene* scene = this->GetMRMLScene(); 
  if (!scene)
  {
    vtkErrorMacro("RegisterNodes: Invalid MRML scene");
    return;
  }
  if (!scene->IsNodeClassRegistered("vtkMRMLCameraNode"))
  {
    vtkWarningMacro("OnMRMLSceneNodeAdded: camera registered");
    scene->RegisterNodeClass(vtkSmartPointer<vtkMRMLCameraNode>::New());
  }
}

//---------------------------------------------------------------------------
void vtkSlicerSomeLogic::OnMRMLSceneNodeAdded(vtkMRMLNode* node)
{
  if (!node || !this->GetMRMLScene())
  {
    vtkErrorMacro("OnMRMLSceneNodeAdded: Invalid MRML scene or input node");
    return;
  }

  if (node->IsA("vtkMRMLCameraNode"))
  {
    vtkWarningMacro("OnMRMLSceneNodeAdded: Observe camera events");
    // Observe camera events
    vtkNew<vtkIntArray> events;
    events->InsertNextValue(vtkCommand::ModifiedEvent);
    vtkObserveMRMLNodeEventsMacro(node, events);
  }
}

//----------------------------------------------------------------------------
void vtkSlicerSomeLogic::ProcessMRMLNodesEvents(vtkObject* caller, unsigned long event, void* callData)
{
  Superclass::ProcessMRMLNodesEvents(caller, event, callData);

  vtkMRMLScene* mrmlScene = this->GetMRMLScene();
  if (!mrmlScene)
  {
    vtkErrorMacro("ProcessMRMLNodesEvents: Invalid MRML scene");
    return;
  }
  if (mrmlScene->IsBatchProcessing())
  {
    return;
  }

  if (caller->IsA("vtkMRMLCameraNode"))
  {
    vtkMRMLCameraNode* cameraNode = vtkMRMLCameraNode::SafeDownCast(caller);
    if (event == vtkCommand::ModifiedEvent)
    {
      vtkWarningMacro("ProcessMRMLNodesEvents: Camera modified");
    }
    else
    {
      vtkWarningMacro("ProcessMRMLNodesEvents: Other events");
    }
  }
}

This would re-register the vtkMRMLCameraNode class, this must not be done.

This would add observer to the last added camera node. Instead of this, you should either observe all the camera nodes or one that the user selected.

Thank you! I understood what was the problem.

Another question. Should i remove observe from previously observed camera if i change one camera to the other or it is an automatic process?

for example

//----------------------------------------------------------------------------
void vtkMRMLMyCustomNode::SetAndObserveCameraNode(vtkMRMLCameraNode* node)
{
  if (node && this->Scene != node->GetScene())
  {
    vtkErrorMacro("SetAndObserveCameraNode: Cannot set reference");
    return;
  }

  if(vtkMRMLCameraNode* previouslyObservedNode = this->GetCameraNode())
  {
    vtkUnObserveMRMLObjectMacro(previouslyObservedNode );
  }

  this->SetNodeReferenceID(CAMERA_REFERENCE_ROLE, (node ? node->GetID() : nullptr));

  if (node)
  {
    vtkNew<vtkIntArray> events;
    events->InsertNextValue(vtkCommand::ModifiedEvent);
    vtkObserveMRMLObjectEventsMacro(node, events);
  }
}

vtkObserveMRMLObjectEventsMacro only adds the observer, never removes it, so you either need to use vtkUnObserveMRMLObjectEventsMacro for the previously observed node; or use vtkSetAndObserveMRMLObjectMacro, which automatically removes the previous observation.