Program Listing for File vtkMRMLLayerDMPipelineManager.cxx

Return to documentation for file (MRMLDM/vtkMRMLLayerDMPipelineManager.cxx)

#include "vtkMRMLLayerDMPipelineManager.h"

// Layer DM includes
#include "vtkMRMLLayerDMCameraSynchronizer.h"
#include "vtkMRMLLayerDMInteractionLogic.h"
#include "vtkMRMLLayerDMLayerManager.h"
#include "vtkMRMLLayerDMNodeReferenceObserver.h"
#include "vtkMRMLLayerDMObjectEventObserver.h"
#include "vtkMRMLLayerDMPipelineFactory.h"
#include "vtkMRMLLayerDMPipelineI.h"

// Slicer includes
#include "vtkMRMLAbstractViewNode.h"
#include "vtkMRMLScene.h"

// VTK includes
#include <vtkCallbackCommand.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>

vtkStandardNewMacro(vtkMRMLLayerDMPipelineManager);

struct ResetPipelineDisplayOnceGuard
{
  explicit ResetPipelineDisplayOnceGuard(vtkSmartPointer<vtkMRMLLayerDMPipelineI> pipeline)
    : m_pipeline{ std::move(pipeline) }
  {
    if (m_pipeline)
    {
      m_wasBlocked = m_pipeline->BlockResetDisplay(true);
    }
  }

  ~ResetPipelineDisplayOnceGuard()
  {
    if (m_pipeline)
    {
      m_pipeline->BlockResetDisplay(m_wasBlocked);
      m_pipeline->ResetDisplay();
    }
  }

  vtkSmartPointer<vtkMRMLLayerDMPipelineI> m_pipeline;
  bool m_wasBlocked{};
};

struct RequestRenderOnceGuard
{
  explicit RequestRenderOnceGuard(vtkMRMLLayerDMPipelineManager& pipelineManager)
    : m_pipelineManager{ pipelineManager }
  {
    m_wasBlocked = m_pipelineManager.BlockRequestRender(true);
  }

  ~RequestRenderOnceGuard()
  {
    m_pipelineManager.BlockRequestRender(m_wasBlocked);
    m_pipelineManager.RequestRender();
  }

  vtkMRMLLayerDMPipelineManager& m_pipelineManager;
  bool m_wasBlocked{};
};

bool vtkMRMLLayerDMPipelineManager::CreatePipelineForNode(vtkMRMLNode* displayNode)
{
  // Early return if manager is not yet created
  if (!this->m_factory || !this->m_viewNode)
  {
    return false;
  }

  auto pipeline = this->m_factory->CreatePipeline(this->m_viewNode, displayNode);
  if (!pipeline)
  {
    return false;
  }

  RequestRenderOnceGuard renderGuard{ *this };
  ResetPipelineDisplayOnceGuard resetPipelineGuard{ pipeline };
  pipeline->SetViewNode(this->m_viewNode);
  pipeline->SetPipelineManager(this);
  pipeline->SetScene(this->m_scene);
  pipeline->SetViewNode(this->m_viewNode);
  pipeline->SetDisplayNode(displayNode);
  pipeline->OnDefaultCameraModified(this->m_defaultCamera);
  this->m_pipelineMap[displayNode] = pipeline;
  this->m_layerManager->AddPipeline(pipeline);
  this->m_interactionLogic->AddPipeline(pipeline);
  this->UpdatePipeline(pipeline);
  this->InvokeEvent(vtkCommand::ModifiedEvent);
  return true;
}

void vtkMRMLLayerDMPipelineManager::ClearDisplayableNodes()
{
  this->m_pipelineMap.clear();
}

bool vtkMRMLLayerDMPipelineManager::AddNode(vtkMRMLNode* node)
{
  if (auto pipeline = this->GetNodePipeline(node))
  {
    return false;
  }

  return this->CreatePipelineForNode(node);
}

void vtkMRMLLayerDMPipelineManager::UpdateAllPipelines()
{
  RequestRenderOnceGuard renderGuard{ *this };
  for (const auto& pipeline : m_pipelineMap)
  {
    this->UpdatePipeline(pipeline.second);
  }
}

bool vtkMRMLLayerDMPipelineManager::RemovePipeline(vtkMRMLNode* displayNode)
{
  auto pipeline = this->GetNodePipeline(displayNode);
  if (!pipeline)
  {
    return false;
  }

  RequestRenderOnceGuard renderGuard{ *this };
  pipeline->SetFrozen(true);
  // Let interaction logic process the removal first if the pipeline needs to lose focus.
  this->m_interactionLogic->RemovePipeline(pipeline);
  this->m_layerManager->RemovePipeline(pipeline);
  this->m_pipelineMap.erase(displayNode);
  this->InvokeEvent(vtkCommand::ModifiedEvent);
  return true;
}

void vtkMRMLLayerDMPipelineManager::SetRenderWindow(vtkRenderWindow* renderWindow)
{
  // Observe window resize updates (bound to default camera changed update for representations which depend on the camera / display properties)
  this->m_eventObs->UpdateObserver(this->m_renderWindow, renderWindow, vtkCommand::WindowResizeEvent);
  this->m_renderWindow = renderWindow;
  this->m_layerManager->SetRenderWindow(renderWindow);
}

void vtkMRMLLayerDMPipelineManager::SetViewNode(vtkMRMLAbstractViewNode* viewNode)
{
  if (this->m_viewNode == viewNode)
  {
    return;
  }

  this->m_viewNode = viewNode;
  this->m_cameraSync->SetViewNode(viewNode);
  this->m_interactionLogic->SetViewNode(viewNode);
  this->UpdateAllPipelines();
}

void vtkMRMLLayerDMPipelineManager::SetFactory(const vtkSmartPointer<vtkMRMLLayerDMPipelineFactory>& factory)
{
  if (this->m_factory == factory)
  {
    return;
  }

  this->m_eventObs->UpdateObserver(this->m_factory, factory);
  this->m_factory = factory;
  this->UpdateFromScene();
}

int vtkMRMLLayerDMPipelineManager::GetMouseCursor() const
{
  auto lastFocused = this->m_interactionLogic->GetLastFocusedPipeline();
  return lastFocused ? lastFocused->GetMouseCursor() : VTK_CURSOR_DEFAULT;
}

bool vtkMRMLLayerDMPipelineManager::CanProcessInteractionEvent(vtkMRMLInteractionEventData* eventData, double& distance2) const
{
  return this->m_interactionLogic->CanProcessInteractionEvent(eventData, distance2);
}

void vtkMRMLLayerDMPipelineManager::LoseFocus(vtkMRMLInteractionEventData* eventData) const
{
  this->m_interactionLogic->LoseFocus(eventData);
}

void vtkMRMLLayerDMPipelineManager::LoseFocus() const
{
  this->m_interactionLogic->LoseFocus();
}

bool vtkMRMLLayerDMPipelineManager::ProcessInteractionEvent(vtkMRMLInteractionEventData* eventData) const
{
  return this->m_interactionLogic->ProcessInteractionEvent(eventData);
}

bool vtkMRMLLayerDMPipelineManager::RemoveNode(vtkMRMLNode* node)
{
  return this->RemovePipeline(node);
}

void vtkMRMLLayerDMPipelineManager::ResetCameraClippingRange() const
{
  // Block camera sync update triggers during clipping range refresh
  const auto wasBlocked = this->m_cameraSync->BlockModified(true);
  this->m_layerManager->ResetCameraClippingRange();
  this->m_cameraSync->BlockModified(wasBlocked);
}

void vtkMRMLLayerDMPipelineManager::RequestRender()
{
  if (this->m_isRequestRenderBlocked || !this->m_renderWindow)
  {
    return;
  }

  this->BlockRequestRender(true);
  this->ResetCameraClippingRange();
  this->m_requestRender();
  this->BlockRequestRender(false);
}

void vtkMRMLLayerDMPipelineManager::OnDefaultCameraModified()
{
  RequestRenderOnceGuard renderGuard{ *this };
  for (const auto& pipeline : this->m_pipelineMap)
  {
    pipeline.second->OnDefaultCameraModified(this->m_defaultCamera);
  }
}

vtkMRMLLayerDMPipelineManager::vtkMRMLLayerDMPipelineManager()
  : m_factory{ nullptr }
  , m_layerManager(vtkSmartPointer<vtkMRMLLayerDMLayerManager>::New())
  , m_cameraSync(vtkSmartPointer<vtkMRMLLayerDMCameraSynchronizer>::New())
  , m_interactionLogic(vtkSmartPointer<vtkMRMLLayerDMInteractionLogic>::New())
  , m_eventObs(vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver>::New())
  , m_defaultCamera(vtkSmartPointer<vtkCamera>::New())
  , m_nodeRefObs{ vtkSmartPointer<vtkMRMLLayerDMNodeReferenceObserver>::New() }
  , m_viewNode{ nullptr }
  , m_scene{ nullptr }
  , m_pipelineMap{}
  , m_requestRender{ [] {} }
{
  this->m_cameraSync->SetDefaultCamera(this->m_defaultCamera);
  this->m_layerManager->SetDefaultCamera(this->m_defaultCamera);

  this->m_nodeRefObs->SetReferenceModifiedCallBack(
    [this](vtkMRMLNode* fromNode, vtkMRMLNode* toNode, const std::string& role, int eventType)
    {
      auto pipeline = this->GetNodePipeline(toNode);
      if (!pipeline)
      {
        return;
      }
      if (eventType == vtkMRMLLayerDMNodeReferenceObserver::ReferenceAddedEvent)
      {
        pipeline->OnReferenceToDisplayNodeAdded(fromNode, role);
      }
      else
      {
        pipeline->OnReferenceToDisplayNodeRemoved(fromNode, role);
      }
    });

  this->m_eventObs->SetUpdateCallback(
    [this](vtkObject* obj)
    {
      if (obj == this->m_factory)
      {
        this->UpdateFromScene();
      }

      if (obj == this->m_cameraSync || obj == this->m_renderWindow)
      {
        this->OnDefaultCameraModified();
      }
    });

  // Monitor camera updates
  this->m_eventObs->UpdateObserver(nullptr, this->m_cameraSync);
}

void vtkMRMLLayerDMPipelineManager::UpdatePipeline(const vtkSmartPointer<vtkMRMLLayerDMPipelineI>& pipeline) const
{
  if (!pipeline)
  {
    return;
  }

  ResetPipelineDisplayOnceGuard resetPipelineGuard{ pipeline };
  pipeline->SetViewNode(this->m_viewNode);
}

vtkSmartPointer<vtkMRMLLayerDMPipelineI> vtkMRMLLayerDMPipelineManager::GetNodePipeline(vtkMRMLNode* node) const
{
  const auto found = this->m_pipelineMap.find(node);
  if (found == std::end(this->m_pipelineMap))
  {
    return {};
  }
  return found->second;
}

int vtkMRMLLayerDMPipelineManager::GetNumberOfPipelines() const
{
  return this->m_pipelineMap.size();
}

vtkMRMLLayerDMPipelineI* vtkMRMLLayerDMPipelineManager::GetNthPipeline(int iPipeline) const
{
  if (iPipeline < 0 || iPipeline >= this->m_pipelineMap.size())
  {
    return nullptr;
  }

  return std::next(this->m_pipelineMap.begin(), iPipeline)->second;
}

void vtkMRMLLayerDMPipelineManager::SetRenderer(vtkRenderer* renderer) const
{
  // Pass the renderer to the camera sync
  this->m_cameraSync->SetRenderer(renderer);
}

void vtkMRMLLayerDMPipelineManager::SetRequestRender(const std::function<void()>& requestRender)
{
  this->m_requestRender = requestRender;
  this->UpdateAllPipelines();
}

vtkCamera* vtkMRMLLayerDMPipelineManager::GetDefaultCamera() const
{
  return this->m_defaultCamera;
}

void vtkMRMLLayerDMPipelineManager::RemoveOutdatedPipelines()
{
  if (!this->m_scene)
  {
    return;
  }

  std::vector<vtkWeakPointer<vtkMRMLNode>> outdatedPipelines;
  for (const auto& pipe : m_pipelineMap)
  {
    if (!pipe.first || !this->m_scene->GetNodeByID(pipe.first->GetID()))
    {
      outdatedPipelines.emplace_back(pipe.first);
    }
  }

  for (const auto& pipe : outdatedPipelines)
  {
    this->RemovePipeline(pipe);
  }
}

void vtkMRMLLayerDMPipelineManager::AddMissingPipelines()
{
  if (!this->m_scene)
  {
    return;
  }

  int nNodes = this->m_scene->GetNumberOfNodes();
  for (int iNode = 0; iNode < nNodes; iNode++)
  {
    if (auto node = vtkMRMLNode::SafeDownCast(this->m_scene->GetNodes()->GetItemAsObject(iNode)))
    {
      this->AddNode(node);
    }
  }
}

void vtkMRMLLayerDMPipelineManager::UpdateFromScene()
{
  if (!this->m_scene)
  {
    return;
  }

  RequestRenderOnceGuard renderGuard{ *this };
  this->RemoveOutdatedPipelines();
  this->AddMissingPipelines();
}

bool vtkMRMLLayerDMPipelineManager::BlockRequestRender(bool isBlocked)
{
  const auto wasBlocked = this->m_isRequestRenderBlocked;
  this->m_isRequestRenderBlocked = isBlocked;
  return wasBlocked;
}

void vtkMRMLLayerDMPipelineManager::SetScene(vtkMRMLScene* scene)
{
  if (this->m_scene == scene)
  {
    return;
  }

  this->m_scene = scene;
  this->m_nodeRefObs->SetScene(scene);
  for (const auto& [node, pipeline] : m_pipelineMap)
  {
    pipeline->SetScene(scene);
  }
}