Program Listing for File vtkMRMLLayerDMLayerManager.cxx

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

#include "vtkMRMLLayerDMLayerManager.h"

// Layer DM includes
#include "vtkMRMLLayerDMPipelineI.h"

// VTK includes
#include <vtkBoundingBox.h>
#include <vtkCamera.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>

vtkStandardNewMacro(vtkMRMLLayerDMLayerManager);

void vtkMRMLLayerDMLayerManager::AddPipeline(vtkMRMLLayerDMPipelineI* pipeline)
{
  if (!pipeline)
  {
    return;
  }

  auto key = this->GetPipelineLayerKey(pipeline);
  if (!this->ContainsLayerKey(key))
  {
    this->m_pipelineLayers[key] = {};
  }
  this->m_pipelineLayers[key].emplace(pipeline);
  this->UpdateLayers();
}

vtkMRMLLayerDMLayerManager::LayerKey vtkMRMLLayerDMLayerManager::GetPipelineLayerKey(vtkMRMLLayerDMPipelineI* pipeline)
{
  if (!pipeline)
  {
    return {};
  }
  return { pipeline->GetRenderOrder(), vtkMRMLLayerDMLayerManager::GetCameraId(pipeline->GetCustomCamera()) };
}

int vtkMRMLLayerDMLayerManager::GetNumberOfDistinctLayers() const
{
  return static_cast<int>(this->m_pipelineLayers.size());
}

int vtkMRMLLayerDMLayerManager::GetNumberOfManagedLayers() const
{
  return this->GetNumberOfDistinctLayers() - 1;
}

int vtkMRMLLayerDMLayerManager::GetNumberOfRenderers() const
{
  return static_cast<int>(this->m_renderers.size());
}

void vtkMRMLLayerDMLayerManager::RemovePipeline(vtkMRMLLayerDMPipelineI* pipeline)
{
  if (!pipeline)
  {
    return;
  }

  auto key = this->GetPipelineLayerKey(pipeline);
  if (!this->ContainsLayerKey(key))
  {
    return;
  }

  // Remove pipeline from its renderer
  this->RemovePipelineRenderer(pipeline);

  // Update the other pipeline layers if needed
  this->m_pipelineLayers[key].erase(pipeline);
  this->UpdateLayers();
}

void vtkMRMLLayerDMLayerManager::ResetCameraClippingRange() const
{
  // Reset first renderer clipping range
  if (const auto defaultRenderer = this->GetDefaultRenderer())
  {
    defaultRenderer->ResetCameraClippingRange();
  }

  // Reset the managed renderers grouped by common cameras
  for (const auto& pair : m_cameraRendererMap)
  {
    this->ResetRenderersCameraClippingRange(pair.second, this->ComputeRenderersVisibleBounds(pair.second));
  }
}

void vtkMRMLLayerDMLayerManager::SetRenderWindow(vtkRenderWindow* renderWindow)
{
  if (this->m_renderWindow == renderWindow)
  {
    return;
  }

  this->RemoveAllLayers();
  this->m_renderWindow = renderWindow;
  this->UpdateLayers();
}

void vtkMRMLLayerDMLayerManager::SetDefaultCamera(const vtkSmartPointer<vtkCamera>& camera)
{
  if (this->m_defaultCamera == camera)
  {
    return;
  }

  this->m_defaultCamera = camera;
  this->UpdateLayers();
}

vtkMRMLLayerDMLayerManager::vtkMRMLLayerDMLayerManager()
  : m_emptyPipeline(vtkSmartPointer<vtkMRMLLayerDMPipelineI>::New())
{
  this->AddPipeline(this->m_emptyPipeline);
}

vtkRenderer* vtkMRMLLayerDMLayerManager::GetRendererMatchingKey(const LayerKey& key)
{
  // If key index matches the default layer, return the render window's first renderer
  int keyIndex = this->GetKeyIndex(key);
  if (keyIndex == 0)
  {
    return this->GetDefaultRenderer();
  }

  // Otherwise, convert key index to matching managed renderer index and return the associated renderer
  int rendererIndex = keyIndex - 1;
  if (rendererIndex < 0 || rendererIndex >= this->GetNumberOfRenderers())
  {
    return nullptr;
  }
  return this->m_renderers[rendererIndex];
}

vtkRenderer* vtkMRMLLayerDMLayerManager::GetDefaultRenderer() const
{
  if (!this->m_renderWindow)
  {
    return nullptr;
  }
  return this->m_renderWindow->GetRenderers()->GetFirstRenderer();
}

void vtkMRMLLayerDMLayerManager::AddMissingLayers()
{
  while (this->GetNumberOfRenderers() < this->GetNumberOfManagedLayers())
  {
    // Managed renderers are displayed as overlays and should not catch any events.
    // Events handling is done using the DM mechanism.
    auto renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->InteractiveOff();
    this->m_renderWindow->AddRenderer(renderer);
    this->m_renderers.emplace_back(renderer);
  }
}

std::array<double, 6> vtkMRMLLayerDMLayerManager::ComputeRenderersVisibleBounds(const std::set<vtkWeakPointer<vtkRenderer>>& renderers)
{
  vtkBoundingBox bbox;

  for (const auto& renderer : renderers)
  {
    if (!renderer)
    {
      continue;
    }
    bbox.AddBounds(renderer->ComputeVisiblePropBounds());
  }

  std::array<double, 6> bounds{};
  bbox.GetBounds(bounds.data());
  return bounds;
}

bool vtkMRMLLayerDMLayerManager::ContainsLayerKey(const LayerKey& key)
{
  return this->m_pipelineLayers.find(key) != this->m_pipelineLayers.end();
}

std::uintptr_t vtkMRMLLayerDMLayerManager::GetCameraId(vtkCamera* camera)
{
  if (!camera)
  {
    return 0;
  }
  return reinterpret_cast<std::uintptr_t>(camera);
}

vtkCamera* vtkMRMLLayerDMLayerManager::GetCameraForLayer(const LayerKey& key, const std::set<vtkWeakPointer<vtkMRMLLayerDMPipelineI>>& pipelines) const
{
  if (const auto cameraId = std::get<1>(key); cameraId == 0)
  {
    return this->m_defaultCamera;
  }

  for (const auto& pipeline : pipelines)
  {
    if (pipeline)
    {
      return pipeline->GetCustomCamera();
    }
  }

  return nullptr;
}

int vtkMRMLLayerDMLayerManager::GetKeyIndex(const LayerKey& key) const
{
  int index = 0;
  for (const auto& pair : m_pipelineLayers)
  {
    if (pair.first == key)
    {
      return index;
    }
    ++index;
  }
  return -1;
}

void vtkMRMLLayerDMLayerManager::RemoveAllLayers()
{
  for (const auto& renderer : m_renderers)
  {
    this->RemoveRenderer(renderer);
  }
  this->UpdateRenderWindowNumberOfLayers();
  this->m_renderers.clear();
}

void vtkMRMLLayerDMLayerManager::RemoveAllPipelineRenderers()
{
  // if the render window is null, notify pipelines
  for (const auto& [key, pipelines] : m_pipelineLayers)
  {
    for (const auto& pipeline : pipelines)
    {
      this->RemovePipelineRenderer(pipeline);
    }
  }
}

void vtkMRMLLayerDMLayerManager::RemovePipelineRenderer(vtkMRMLLayerDMPipelineI* pipeline)
{
  if (pipeline)
  {
    pipeline->SetRenderer(nullptr);
  }
}

void vtkMRMLLayerDMLayerManager::RemoveOutdatedLayers()
{
  while (this->GetNumberOfRenderers() && (this->GetNumberOfRenderers() > this->GetNumberOfManagedLayers()))
  {
    this->RemoveRenderer(this->m_renderers[this->GetNumberOfRenderers() - 1]);
  }
}

void vtkMRMLLayerDMLayerManager::RemoveOutdatedPipelines()
{
  // Remove pipelines which have been garbage collected
  for (auto& [key, pipelines] : m_pipelineLayers)
  {
    for (const auto& pipeline : pipelines)
    {
      if (!pipeline)
      {
        pipelines.erase(pipeline);
      }
    }

    if (pipelines.empty())
    {
      this->m_pipelineLayers.erase(key);
    }
  }
}

void vtkMRMLLayerDMLayerManager::RemoveRenderer(const vtkSmartPointer<vtkRenderer>& renderer)
{
  if (this->m_renderWindow && this->m_renderWindow->HasRenderer(renderer))
  {
    this->m_renderWindow->RemoveRenderer(renderer);
  }

  this->m_renderers.erase(std::find(this->m_renderers.begin(), this->m_renderers.end(), renderer));
}

void vtkMRMLLayerDMLayerManager::ResetRenderersCameraClippingRange(const std::set<vtkWeakPointer<vtkRenderer>>& renderers, const std::array<double, 6>& bounds)
{
  for (const auto& renderer : renderers)
  {
    if (!renderer)
    {
      continue;
    }
    renderer->ResetCameraClippingRange(const_cast<double*>(bounds.data()));
  }
}

void vtkMRMLLayerDMLayerManager::SynchronizePipelineRenderers()
{
  for (const auto& pair : m_pipelineLayers)
  {
    auto renderer = this->GetRendererMatchingKey(pair.first);
    for (const auto& pipeline : pair.second)
    {
      if (pipeline)
      {
        pipeline->SetRenderer(renderer);
      }
    }
  }
}

void vtkMRMLLayerDMLayerManager::UpdateRenderWindowNumberOfLayers() const
{
  if (!this->m_renderWindow)
  {
    return;
  }

  // Synchronize the render window number of layers with its actual number of renderers
  int numberOfRenderers = this->m_renderWindow->GetRenderers()->GetNumberOfItems();
  int iMax = 0;
  for (int iRenderer = 0; iRenderer < numberOfRenderers; iRenderer++)
  {
    if (auto renderer = vtkRenderer::SafeDownCast(this->m_renderWindow->GetRenderers()->GetItemAsObject(iRenderer)))
    {
      iMax = std::max(iMax, renderer->GetLayer());
    }
  }

  this->m_renderWindow->SetNumberOfLayers(iMax + 1);
}

void vtkMRMLLayerDMLayerManager::UpdateLayers()
{
  if (!this->m_renderWindow)
  {
    this->RemoveAllPipelineRenderers();
    return;
  }

  this->RemoveOutdatedPipelines();
  this->RemoveOutdatedLayers();
  this->AddMissingLayers();
  this->UpdateRendererLayerOrdering();
  this->UpdateRendererCamera();
  this->SynchronizePipelineRenderers();
  this->UpdateRenderWindowNumberOfLayers();
}

void vtkMRMLLayerDMLayerManager::UpdateRendererLayerOrdering() const
{
  // Managed layers are always ordered from layer 1 to the number of managed renderers
  for (int iRenderer = 0; iRenderer < this->GetNumberOfRenderers(); iRenderer++)
  {
    this->m_renderers[iRenderer]->SetLayer(iRenderer + 1);
  }
}

void vtkMRMLLayerDMLayerManager::UpdateRendererCamera()
{
  // Set the camera for the managed renderers
  // Layer 0 is unmanaged and its camera is left unchanged by the layer manager
  // Pipelines with no explicit camera map to the default camera
  // Pipelines with custom camera are grouped and use their cameras
  this->m_cameraRendererMap.clear();

  int iRenderer = -1;
  for (const auto& pair : m_pipelineLayers)
  {
    if (iRenderer >= 0 && iRenderer < this->GetNumberOfRenderers())
    {
      auto camera = this->GetCameraForLayer(pair.first, pair.second);
      this->m_renderers[iRenderer]->SetActiveCamera(camera);
      this->m_cameraRendererMap[camera].emplace(this->m_renderers[iRenderer]);
    }

    iRenderer++;
  }
}