<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "QmitkNavigationToolCreationWidget.h"

//mitk headers
#include "mitkTrackingTypes.h"
#include <mitkSTLFileReader.h>
#include <mitkSurface.h>
#include "mitkNavigationData.h"
#include "mitkRenderingManager.h"

//qt headers
#include <qfiledialog.h>
#include <qmessagebox.h>
#include <QDialog>

//poco headers
#include <Poco/Path.h>

// vtk
#include <vtkSphereSource.h>
#include "vtkConeSource.h"

const std::string QmitkNavigationToolCreationWidget::VIEW_ID = "org.mitk.views.navigationtoolcreationwizardwidget";

QmitkNavigationToolCreationWidget::QmitkNavigationToolCreationWidget(QWidget* parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
  m_Controls = NULL;
  m_AdvancedWidget = new QmitkNavigationToolCreationAdvancedWidget(this);
  m_AdvancedWidget->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
  m_AdvancedWidget->setWindowTitle("Tool Creation Advanced Options");
  m_AdvancedWidget->setModal(false);
  CreateQtPartControl(this);
  CreateConnections();
}

QmitkNavigationToolCreationWidget::~QmitkNavigationToolCreationWidget()
{
  delete m_AdvancedWidget;
}

void QmitkNavigationToolCreationWidget::CreateQtPartControl(QWidget *parent)
{
  if (!m_Controls)
  {
    // create GUI widgets
    m_Controls = new Ui::QmitkNavigationToolCreationWidgetControls;
    m_Controls->setupUi(parent);
  }
}

void QmitkNavigationToolCreationWidget::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->m_cancel), SIGNAL(clicked()), this, SLOT(OnCancel()) );
    connect( (QObject*)(m_Controls->m_finished), SIGNAL(clicked()), this, SLOT(OnFinished()) );
    connect( (QObject*)(m_Controls->m_LoadSurface), SIGNAL(clicked()), this, SLOT(OnLoadSurface()) );
    connect( (QObject*)(m_Controls->m_LoadCalibrationFile), SIGNAL(clicked()), this, SLOT(OnLoadCalibrationFile()) );
    connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsPB), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptions(bool)) );
    connect( (QObject*)(m_AdvancedWidget), SIGNAL(DialogCloseRequested()), this, SLOT(OnProcessDialogCloseRequest()) );
    connect( (QObject*)(m_AdvancedWidget), SIGNAL(RetrieveDataForManualToolTipManipulation()), this, SLOT(OnRetrieveDataForManualTooltipManipulation()) );
  }
}

void QmitkNavigationToolCreationWidget::Initialize(mitk::DataStorage* dataStorage, std::string supposedIdentifier, std::string supposedName)
{
  m_DataStorage = dataStorage;

  //initialize UI components
  m_Controls->m_SurfaceChooser->SetDataStorage(m_DataStorage);
  m_Controls->m_SurfaceChooser->SetAutoSelectNewItems(true);
  m_Controls->m_SurfaceChooser->SetPredicate(mitk::NodePredicateDataType::New("Surface"));

  //set default data
  m_Controls->m_ToolNameEdit->setText(supposedName.c_str());
  m_Controls->m_CalibrationFileName->setText("none");
  m_Controls->m_Surface_Use_Sphere->setChecked(true);
  m_AdvancedWidget->SetDataStorage(m_DataStorage);

}

void QmitkNavigationToolCreationWidget::SetTrackingDeviceType(mitk::TrackingDeviceType type, bool changeable)
{
  switch(type)
  {
  case mitk::NDIAurora:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);break;
  case mitk::NDIPolaris:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(1);break;
  case mitk::ClaronMicron:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(2);break;
  default:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);
  }
  m_Controls->m_TrackingDeviceTypeChooser->setEnabled(changeable);
}

mitk::NavigationTool::Pointer QmitkNavigationToolCreationWidget::GetCreatedTool()
{
  return m_CreatedTool;
}

//##################################################################################
//############################## slots                  ############################
//##################################################################################

void QmitkNavigationToolCreationWidget::OnFinished()
{
  //here we create a new tool
  m_CreatedTool = mitk::NavigationTool::New();

  //create DataNode...
  mitk::DataNode::Pointer newNode = mitk::DataNode::New();
  if(m_Controls->m_Surface_Use_Sphere->isChecked())
  {
    //create small sphere and use it as surface
    mitk::Surface::Pointer mySphere = mitk::Surface::New();
    vtkConeSource *vtkData = vtkConeSource::New();
    vtkData->SetAngle(5.0);
    vtkData->SetResolution(50);
    vtkData->SetHeight(6.0f);
    vtkData->SetRadius(2.0f);
    vtkData->SetCenter(0.0, 0.0, 0.0);
    vtkData->Update();
    mySphere->SetVtkPolyData(vtkData->GetOutput());
    vtkData->Delete();
    newNode->SetData(mySphere);
  }
  else
  {
    newNode->SetData(m_Controls->m_SurfaceChooser->GetSelectedNode()->GetData());
  }
  newNode->SetName(m_Controls->m_ToolNameEdit->text().toLatin1());

  m_CreatedTool->SetDataNode(newNode);

  //fill NavigationTool object
  m_CreatedTool->SetCalibrationFile(m_Controls->m_CalibrationFileName->text().toAscii().data());
  m_CreatedTool->SetIdentifier(m_Controls->m_IdentifierEdit->text().toAscii().data());
  m_CreatedTool->SetSerialNumber(m_Controls->m_SerialNumberEdit->text().toAscii().data());

  //Tracking Device
  if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="NDI Aurora") m_CreatedTool->SetTrackingDeviceType(mitk::NDIAurora);
  else if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="NDI Polaris") m_CreatedTool->SetTrackingDeviceType(mitk::NDIPolaris);
  else if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="Claron Technology Micron Tracker") m_CreatedTool->SetTrackingDeviceType(mitk::ClaronMicron);
  else m_CreatedTool->SetTrackingDeviceType(mitk::TrackingSystemNotSpecified);

  //ToolType
  if (m_Controls->m_ToolTypeChooser->currentText()=="Instrument") m_CreatedTool->SetType(mitk::NavigationTool::Instrument);
  else if (m_Controls->m_ToolTypeChooser->currentText()=="Fiducial") m_CreatedTool->SetType(mitk::NavigationTool::Fiducial);
  else if (m_Controls->m_ToolTypeChooser->currentText()=="Skinmarker") m_CreatedTool->SetType(mitk::NavigationTool::Skinmarker);
  else m_CreatedTool->SetType(mitk::NavigationTool::Unknown);

  mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(m_AdvancedWidget->GetManipulatedToolTip());
  m_CreatedTool->SetToolTipOrientation(tempND->GetOrientation());
  m_CreatedTool->SetToolTipPosition(tempND->GetPosition());

  emit NavigationToolFinished();
}

void QmitkNavigationToolCreationWidget::OnCancel()
{
  m_CreatedTool = NULL;

  emit Canceled();
}

void QmitkNavigationToolCreationWidget::OnLoadSurface()
{
  std::string filename = QFileDialog::getOpenFileName(NULL,tr("Open Surface"), "/", "*.stl").toLatin1().data();
  mitk::STLFileReader::Pointer stlReader = mitk::STLFileReader::New();
  try
  {
    stlReader->SetFileName( filename.c_str() );
    stlReader->Update();
  }
  catch (...)
  {
  }

  if ( stlReader->GetOutput() == NULL );
  else
  {
    mitk::DataNode::Pointer newNode = mitk::DataNode::New();
    newNode->SetName(filename);
    newNode->SetData(stlReader->GetOutput());
    m_DataStorage->Add(newNode);
  }
}

void QmitkNavigationToolCreationWidget::OnLoadCalibrationFile()
{
  m_Controls->m_CalibrationFileName->setText(QFileDialog::getOpenFileName(NULL,tr("Open Calibration File"), "/", "*.*"));
}

void QmitkNavigationToolCreationWidget::SetDefaultData(mitk::NavigationTool::Pointer DefaultTool)
{
  m_Controls->m_ToolNameEdit->setText(QString(DefaultTool->GetDataNode()->GetName().c_str()));
  m_Controls->m_IdentifierEdit->setText(QString(DefaultTool->GetIdentifier().c_str()));
  m_Controls->m_SerialNumberEdit->setText(QString(DefaultTool->GetSerialNumber().c_str()));
  m_AdvancedWidget->SetDefaultTooltip( DefaultTool->GetToolTipTransform() );
  switch(DefaultTool->GetTrackingDeviceType())
  {
  case mitk::NDIAurora:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);break;
  case mitk::NDIPolaris:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(1);break;
  case mitk::ClaronMicron:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(2);break;
  default:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);
  }
  m_Controls->m_CalibrationFileName->setText(QString(DefaultTool->GetCalibrationFile().c_str()));
  m_Controls->m_Surface_Use_Other->setChecked(true);
  switch(DefaultTool->GetType())
      {
      case mitk::NavigationTool::Instrument:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(0); break;
      case mitk::NavigationTool::Fiducial:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(1); break;
      case mitk::NavigationTool::Skinmarker:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(2); break;
      case mitk::NavigationTool::Unknown:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(3); break;
      }

  m_Controls->m_SurfaceChooser->SetSelectedNode(DefaultTool->GetDataNode());

}

//##################################################################################
//############################## internal help methods #############################
//##################################################################################
void QmitkNavigationToolCreationWidget::MessageBox(std::string s)
{
  QMessageBox msgBox;
  msgBox.setText(s.c_str());
  msgBox.exec();
}

void QmitkNavigationToolCreationWidget::OnShowAdvancedOptions(bool state)
{
  if(state)
  {
    m_AdvancedWidget->show();
    m_AdvancedWidget->SetDefaultTooltip(m_AdvancedWidget->GetManipulatedToolTip()); //use the last one, if there is one
    m_AdvancedWidget->ReInitialize();

    // reinit the views with the new nodes
    mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll();
    mitk::TimeGeometry::Pointer bounds = m_DataStorage->ComputeBoundingGeometry3D(rs, "visible");    // initialize the views to the bounding geometry
    mitk::RenderingManager::GetInstance()->InitializeViews(bounds);
  }
  else
  {
    m_AdvancedWidget->hide();
  }
}

void QmitkNavigationToolCreationWidget::OnProcessDialogCloseRequest()
{
  m_AdvancedWidget->hide();
  m_Controls->m_ShowAdvancedOptionsPB->setChecked(false);
}

void QmitkNavigationToolCreationWidget::OnRetrieveDataForManualTooltipManipulation()
{
  if(m_Controls->m_Surface_Use_Sphere->isChecked())
  {
    m_AdvancedWidget->SetToolTipSurface(true);
  }
  else
  {
    m_AdvancedWidget->SetToolTipSurface(false,
      dynamic_cast<mitk::DataNode*>(m_Controls->m_SurfaceChooser->GetSelectedNode().GetPointer()));
  }
}
<commit_msg>SupposedIdentifier is added as default text in Initialize.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "QmitkNavigationToolCreationWidget.h"

//mitk headers
#include "mitkTrackingTypes.h"
#include <mitkSTLFileReader.h>
#include <mitkSurface.h>
#include "mitkNavigationData.h"
#include "mitkRenderingManager.h"

//qt headers
#include <qfiledialog.h>
#include <qmessagebox.h>
#include <QDialog>

//poco headers
#include <Poco/Path.h>

// vtk
#include <vtkSphereSource.h>
#include "vtkConeSource.h"

const std::string QmitkNavigationToolCreationWidget::VIEW_ID = "org.mitk.views.navigationtoolcreationwizardwidget";

QmitkNavigationToolCreationWidget::QmitkNavigationToolCreationWidget(QWidget* parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
  m_Controls = NULL;
  m_AdvancedWidget = new QmitkNavigationToolCreationAdvancedWidget(this);
  m_AdvancedWidget->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
  m_AdvancedWidget->setWindowTitle("Tool Creation Advanced Options");
  m_AdvancedWidget->setModal(false);
  CreateQtPartControl(this);
  CreateConnections();
}

QmitkNavigationToolCreationWidget::~QmitkNavigationToolCreationWidget()
{
  delete m_AdvancedWidget;
}

void QmitkNavigationToolCreationWidget::CreateQtPartControl(QWidget *parent)
{
  if (!m_Controls)
  {
    // create GUI widgets
    m_Controls = new Ui::QmitkNavigationToolCreationWidgetControls;
    m_Controls->setupUi(parent);
  }
}

void QmitkNavigationToolCreationWidget::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->m_cancel), SIGNAL(clicked()), this, SLOT(OnCancel()) );
    connect( (QObject*)(m_Controls->m_finished), SIGNAL(clicked()), this, SLOT(OnFinished()) );
    connect( (QObject*)(m_Controls->m_LoadSurface), SIGNAL(clicked()), this, SLOT(OnLoadSurface()) );
    connect( (QObject*)(m_Controls->m_LoadCalibrationFile), SIGNAL(clicked()), this, SLOT(OnLoadCalibrationFile()) );
    connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsPB), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptions(bool)) );
    connect( (QObject*)(m_AdvancedWidget), SIGNAL(DialogCloseRequested()), this, SLOT(OnProcessDialogCloseRequest()) );
    connect( (QObject*)(m_AdvancedWidget), SIGNAL(RetrieveDataForManualToolTipManipulation()), this, SLOT(OnRetrieveDataForManualTooltipManipulation()) );
  }
}

void QmitkNavigationToolCreationWidget::Initialize(mitk::DataStorage* dataStorage, std::string supposedIdentifier, std::string supposedName)
{
  m_DataStorage = dataStorage;

  //initialize UI components
  m_Controls->m_SurfaceChooser->SetDataStorage(m_DataStorage);
  m_Controls->m_SurfaceChooser->SetAutoSelectNewItems(true);
  m_Controls->m_SurfaceChooser->SetPredicate(mitk::NodePredicateDataType::New("Surface"));

  //set default data
  m_Controls->m_ToolNameEdit->setText(supposedName.c_str());
  m_Controls->m_CalibrationFileName->setText("none");
  m_Controls->m_Surface_Use_Sphere->setChecked(true);
  m_AdvancedWidget->SetDataStorage(m_DataStorage);
  m_Controls->m_IdentifierEdit->setText(supposedIdentifier.c_str());

}

void QmitkNavigationToolCreationWidget::SetTrackingDeviceType(mitk::TrackingDeviceType type, bool changeable)
{
  switch(type)
  {
  case mitk::NDIAurora:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);break;
  case mitk::NDIPolaris:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(1);break;
  case mitk::ClaronMicron:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(2);break;
  default:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);
  }
  m_Controls->m_TrackingDeviceTypeChooser->setEnabled(changeable);
}

mitk::NavigationTool::Pointer QmitkNavigationToolCreationWidget::GetCreatedTool()
{
  return m_CreatedTool;
}

//##################################################################################
//############################## slots                  ############################
//##################################################################################

void QmitkNavigationToolCreationWidget::OnFinished()
{
  //here we create a new tool
  m_CreatedTool = mitk::NavigationTool::New();

  //create DataNode...
  mitk::DataNode::Pointer newNode = mitk::DataNode::New();
  if(m_Controls->m_Surface_Use_Sphere->isChecked())
  {
    //create small sphere and use it as surface
    mitk::Surface::Pointer mySphere = mitk::Surface::New();
    vtkConeSource *vtkData = vtkConeSource::New();
    vtkData->SetAngle(5.0);
    vtkData->SetResolution(50);
    vtkData->SetHeight(6.0f);
    vtkData->SetRadius(2.0f);
    vtkData->SetCenter(0.0, 0.0, 0.0);
    vtkData->Update();
    mySphere->SetVtkPolyData(vtkData->GetOutput());
    vtkData->Delete();
    newNode->SetData(mySphere);
  }
  else
  {
    newNode->SetData(m_Controls->m_SurfaceChooser->GetSelectedNode()->GetData());
  }
  newNode->SetName(m_Controls->m_ToolNameEdit->text().toLatin1());

  m_CreatedTool->SetDataNode(newNode);

  //fill NavigationTool object
  m_CreatedTool->SetCalibrationFile(m_Controls->m_CalibrationFileName->text().toAscii().data());
  m_CreatedTool->SetIdentifier(m_Controls->m_IdentifierEdit->text().toAscii().data());
  m_CreatedTool->SetSerialNumber(m_Controls->m_SerialNumberEdit->text().toAscii().data());

  //Tracking Device
  if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="NDI Aurora") m_CreatedTool->SetTrackingDeviceType(mitk::NDIAurora);
  else if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="NDI Polaris") m_CreatedTool->SetTrackingDeviceType(mitk::NDIPolaris);
  else if (m_Controls->m_TrackingDeviceTypeChooser->currentText()=="Claron Technology Micron Tracker") m_CreatedTool->SetTrackingDeviceType(mitk::ClaronMicron);
  else m_CreatedTool->SetTrackingDeviceType(mitk::TrackingSystemNotSpecified);

  //ToolType
  if (m_Controls->m_ToolTypeChooser->currentText()=="Instrument") m_CreatedTool->SetType(mitk::NavigationTool::Instrument);
  else if (m_Controls->m_ToolTypeChooser->currentText()=="Fiducial") m_CreatedTool->SetType(mitk::NavigationTool::Fiducial);
  else if (m_Controls->m_ToolTypeChooser->currentText()=="Skinmarker") m_CreatedTool->SetType(mitk::NavigationTool::Skinmarker);
  else m_CreatedTool->SetType(mitk::NavigationTool::Unknown);

  mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(m_AdvancedWidget->GetManipulatedToolTip());
  m_CreatedTool->SetToolTipOrientation(tempND->GetOrientation());
  m_CreatedTool->SetToolTipPosition(tempND->GetPosition());

  emit NavigationToolFinished();
}

void QmitkNavigationToolCreationWidget::OnCancel()
{
  m_CreatedTool = NULL;

  emit Canceled();
}

void QmitkNavigationToolCreationWidget::OnLoadSurface()
{
  std::string filename = QFileDialog::getOpenFileName(NULL,tr("Open Surface"), "/", "*.stl").toLatin1().data();
  mitk::STLFileReader::Pointer stlReader = mitk::STLFileReader::New();
  try
  {
    stlReader->SetFileName( filename.c_str() );
    stlReader->Update();
  }
  catch (...)
  {
  }

  if ( stlReader->GetOutput() == NULL );
  else
  {
    mitk::DataNode::Pointer newNode = mitk::DataNode::New();
    newNode->SetName(filename);
    newNode->SetData(stlReader->GetOutput());
    m_DataStorage->Add(newNode);
  }
}

void QmitkNavigationToolCreationWidget::OnLoadCalibrationFile()
{
  m_Controls->m_CalibrationFileName->setText(QFileDialog::getOpenFileName(NULL,tr("Open Calibration File"), "/", "*.*"));
}

void QmitkNavigationToolCreationWidget::SetDefaultData(mitk::NavigationTool::Pointer DefaultTool)
{
  m_Controls->m_ToolNameEdit->setText(QString(DefaultTool->GetDataNode()->GetName().c_str()));
  m_Controls->m_IdentifierEdit->setText(QString(DefaultTool->GetIdentifier().c_str()));
  m_Controls->m_SerialNumberEdit->setText(QString(DefaultTool->GetSerialNumber().c_str()));
  m_AdvancedWidget->SetDefaultTooltip( DefaultTool->GetToolTipTransform() );
  switch(DefaultTool->GetTrackingDeviceType())
  {
  case mitk::NDIAurora:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);break;
  case mitk::NDIPolaris:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(1);break;
  case mitk::ClaronMicron:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(2);break;
  default:
    m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(0);
  }
  m_Controls->m_CalibrationFileName->setText(QString(DefaultTool->GetCalibrationFile().c_str()));
  m_Controls->m_Surface_Use_Other->setChecked(true);
  switch(DefaultTool->GetType())
      {
      case mitk::NavigationTool::Instrument:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(0); break;
      case mitk::NavigationTool::Fiducial:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(1); break;
      case mitk::NavigationTool::Skinmarker:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(2); break;
      case mitk::NavigationTool::Unknown:
        m_Controls->m_ToolTypeChooser->setCurrentIndex(3); break;
      }

  m_Controls->m_SurfaceChooser->SetSelectedNode(DefaultTool->GetDataNode());

}

//##################################################################################
//############################## internal help methods #############################
//##################################################################################
void QmitkNavigationToolCreationWidget::MessageBox(std::string s)
{
  QMessageBox msgBox;
  msgBox.setText(s.c_str());
  msgBox.exec();
}

void QmitkNavigationToolCreationWidget::OnShowAdvancedOptions(bool state)
{
  if(state)
  {
    m_AdvancedWidget->show();
    m_AdvancedWidget->SetDefaultTooltip(m_AdvancedWidget->GetManipulatedToolTip()); //use the last one, if there is one
    m_AdvancedWidget->ReInitialize();

    // reinit the views with the new nodes
    mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll();
    mitk::TimeGeometry::Pointer bounds = m_DataStorage->ComputeBoundingGeometry3D(rs, "visible");    // initialize the views to the bounding geometry
    mitk::RenderingManager::GetInstance()->InitializeViews(bounds);
  }
  else
  {
    m_AdvancedWidget->hide();
  }
}

void QmitkNavigationToolCreationWidget::OnProcessDialogCloseRequest()
{
  m_AdvancedWidget->hide();
  m_Controls->m_ShowAdvancedOptionsPB->setChecked(false);
}

void QmitkNavigationToolCreationWidget::OnRetrieveDataForManualTooltipManipulation()
{
  if(m_Controls->m_Surface_Use_Sphere->isChecked())
  {
    m_AdvancedWidget->SetToolTipSurface(true);
  }
  else
  {
    m_AdvancedWidget->SetToolTipSurface(false,
      dynamic_cast<mitk::DataNode*>(m_Controls->m_SurfaceChooser->GetSelectedNode().GetPointer()));
  }
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkCorrectorTool2D.h"
#include "mitkCorrectorAlgorithm.h"

#include "mitkToolManager.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"

#include "mitkCorrectorTool2D.xpm"

// us
#include "mitkModule.h"
#include "mitkModuleResource.h"
#include <mitkGetModuleContext.h>

namespace mitk {
  MITK_TOOL_MACRO(Segmentation_EXPORT, CorrectorTool2D, "Correction tool");
}

mitk::CorrectorTool2D::CorrectorTool2D(int paintingPixelValue)
:FeedbackContourTool("PressMoveRelease"),
 m_PaintingPixelValue(paintingPixelValue)
{
  // great magic numbers
  CONNECT_ACTION( 80, OnMousePressed );
  CONNECT_ACTION( 90, OnMouseMoved );
  CONNECT_ACTION( 42, OnMouseReleased );

  GetFeedbackContour()->SetIsClosed( false ); // don't close the contour to a polygon
}

mitk::CorrectorTool2D::~CorrectorTool2D()
{
}

const char** mitk::CorrectorTool2D::GetXPM() const
{
  return mitkCorrectorTool2D_xpm;
}

mitk::ModuleResource mitk::CorrectorTool2D::GetIconResource() const
{
  Module* module = GetModuleContext()->GetModule();
  ModuleResource resource = module->GetResource("Correction_48x48.png");
  return resource;
}

mitk::ModuleResource mitk::CorrectorTool2D::GetCursorIconResource() const
{
  Module* module = GetModuleContext()->GetModule();
  ModuleResource resource = module->GetResource("Correction_Cursor_32x32.png");
  return resource;
}

const char* mitk::CorrectorTool2D::GetName() const
{
  return "Correction";
}

void mitk::CorrectorTool2D::Activated()
{
  Superclass::Activated();
}

void mitk::CorrectorTool2D::Deactivated()
{
  Superclass::Deactivated();
}

bool mitk::CorrectorTool2D::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  m_LastEventSender = positionEvent->GetSender();
  m_LastEventSlice = m_LastEventSender->GetSlice();

  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  ContourModel* contour = FeedbackContourTool::GetFeedbackContour();
  contour->Clear(positionEvent->GetSender()->GetTimeStep());
  contour->AddVertex( positionEvent->GetWorldPosition() );

  FeedbackContourTool::SetFeedbackContourVisible(true);

  return true;
}

bool mitk::CorrectorTool2D::OnMouseMoved   (Action* action, const StateEvent* stateEvent)
{
  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  ContourModel* contour = FeedbackContourTool::GetFeedbackContour();
  contour->AddVertex( positionEvent->GetWorldPosition() );

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );

  return true;
}

bool mitk::CorrectorTool2D::OnMouseReleased(Action* action, const StateEvent* stateEvent)
{
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that
  FeedbackContourTool::SetFeedbackContourVisible(false);

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );

  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  DataNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice
  m_WorkingSlice = FeedbackContourTool::GetAffectedImageSliceAs2DImage( positionEvent, image );

  if ( m_WorkingSlice.IsNull() )
  {
      MITK_ERROR << "Unable to extract slice." << std::endl;
      return false;
  }

  CorrectorAlgorithm::Pointer algorithm = CorrectorAlgorithm::New();
  algorithm->SetInput( m_WorkingSlice );
  algorithm->SetContour( FeedbackContourTool::GetFeedbackContour() );
  try
  {
      algorithm->UpdateLargestPossibleRegion();
  }
  catch ( std::exception& e )
  {
      MITK_ERROR << "Caught exception '" << e.what() << "'" << std::endl;
  }

  mitk::Image::Pointer resultSlice = mitk::Image::New();
  resultSlice->Initialize(algorithm->GetOutput());
  resultSlice->SetVolume(algorithm->GetOutput()->GetData());

  this->WriteBackSegmentationResult(positionEvent, resultSlice);

  return true;
}

<commit_msg>4D contour support for CorrectorTool<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkCorrectorTool2D.h"
#include "mitkCorrectorAlgorithm.h"

#include "mitkToolManager.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"

#include "mitkCorrectorTool2D.xpm"

// us
#include "mitkModule.h"
#include "mitkModuleResource.h"
#include <mitkGetModuleContext.h>

namespace mitk {
  MITK_TOOL_MACRO(Segmentation_EXPORT, CorrectorTool2D, "Correction tool");
}

mitk::CorrectorTool2D::CorrectorTool2D(int paintingPixelValue)
:FeedbackContourTool("PressMoveRelease"),
 m_PaintingPixelValue(paintingPixelValue)
{
  // great magic numbers
  CONNECT_ACTION( 80, OnMousePressed );
  CONNECT_ACTION( 90, OnMouseMoved );
  CONNECT_ACTION( 42, OnMouseReleased );

  GetFeedbackContour()->SetIsClosed( false ); // don't close the contour to a polygon
}

mitk::CorrectorTool2D::~CorrectorTool2D()
{
}

const char** mitk::CorrectorTool2D::GetXPM() const
{
  return mitkCorrectorTool2D_xpm;
}

mitk::ModuleResource mitk::CorrectorTool2D::GetIconResource() const
{
  Module* module = GetModuleContext()->GetModule();
  ModuleResource resource = module->GetResource("Correction_48x48.png");
  return resource;
}

mitk::ModuleResource mitk::CorrectorTool2D::GetCursorIconResource() const
{
  Module* module = GetModuleContext()->GetModule();
  ModuleResource resource = module->GetResource("Correction_Cursor_32x32.png");
  return resource;
}

const char* mitk::CorrectorTool2D::GetName() const
{
  return "Correction";
}

void mitk::CorrectorTool2D::Activated()
{
  Superclass::Activated();
}

void mitk::CorrectorTool2D::Deactivated()
{
  Superclass::Deactivated();
}

bool mitk::CorrectorTool2D::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  m_LastEventSender = positionEvent->GetSender();
  m_LastEventSlice = m_LastEventSender->GetSlice();

  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  int timestep = positionEvent->GetSender()->GetTimeStep();
  ContourModel* contour = FeedbackContourTool::GetFeedbackContour();
  contour->Clear();
  contour->Expand(timestep);
  contour->SetIsClosed(false, timestep);
  contour->AddVertex( positionEvent->GetWorldPosition(), timestep );

  FeedbackContourTool::SetFeedbackContourVisible(true);

  return true;
}

bool mitk::CorrectorTool2D::OnMouseMoved   (Action* action, const StateEvent* stateEvent)
{
  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  int timestep = positionEvent->GetSender()->GetTimeStep();
  ContourModel* contour = FeedbackContourTool::GetFeedbackContour();
  contour->AddVertex( positionEvent->GetWorldPosition(), timestep );

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );

  return true;
}

bool mitk::CorrectorTool2D::OnMouseReleased(Action* action, const StateEvent* stateEvent)
{
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that
  FeedbackContourTool::SetFeedbackContourVisible(false);

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );

  if ( FeedbackContourTool::CanHandleEvent(stateEvent) < 1.0 ) return false;

  DataNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice
  m_WorkingSlice = FeedbackContourTool::GetAffectedImageSliceAs2DImage( positionEvent, image );

  if ( m_WorkingSlice.IsNull() )
  {
      MITK_ERROR << "Unable to extract slice." << std::endl;
      return false;
  }

  mitk::ContourModel::Pointer singleTimestepContour = mitk::ContourModel::New();

  mitk::ContourModel::VertexIterator it = FeedbackContourTool::GetFeedbackContour()->Begin();
  mitk::ContourModel::VertexIterator end = FeedbackContourTool::GetFeedbackContour()->End();

  while(it!=end)
  {
    singleTimestepContour->AddVertex((*it)->Coordinates);
  }

  CorrectorAlgorithm::Pointer algorithm = CorrectorAlgorithm::New();
  algorithm->SetInput( m_WorkingSlice );
  algorithm->SetContour( singleTimestepContour );
  try
  {
      algorithm->UpdateLargestPossibleRegion();
  }
  catch ( std::exception& e )
  {
      MITK_ERROR << "Caught exception '" << e.what() << "'" << std::endl;
  }

  mitk::Image::Pointer resultSlice = mitk::Image::New();
  resultSlice->Initialize(algorithm->GetOutput());
  resultSlice->SetVolume(algorithm->GetOutput()->GetData());

  this->WriteBackSegmentationResult(positionEvent, resultSlice);

  return true;
}

<|endoftext|>


<commit_before><commit_msg>Added prologue and epilogue to the assembly visitor in comments.<commit_after><|endoftext|>


<commit_before>// $Id: mesh_refinement_flagging.C,v 1.16 2005-05-03 23:22:24 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh_config.h"

// only compile these functions if the user requests AMR support
#ifdef ENABLE_AMR

// C++ includes
#include <algorithm> // for std::sort

// Local includes
#include "error_vector.h"
#include "mesh_refinement.h"
#include "mesh_base.h"
#include "elem.h"

//-----------------------------------------------------------------
// Mesh refinement methods
void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector& error_per_cell_in,
						      const Real refine_fraction,
						      const Real coarsen_fraction,
						      const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  assert (refine_fraction  >= 0.);  assert (refine_fraction  <= 1.);
  assert (coarsen_fraction >= 0.);  assert (coarsen_fraction <= 1.);

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // Get the minimum, maximum, and delta error values
  // for the elements
  const Real error_max   = error_per_cell.maximum();
  const Real error_min   = error_per_cell.minimum();
  const Real error_delta = (error_max - error_min);

  // Compute the cutoff values for coarsening and refinement
  const Real refine_cutoff  = (1.- refine_fraction)*error_max;
  const Real coarsen_cutoff = coarsen_fraction*error_delta + error_min;

//   // Print information about the error
//   std::cout << " Error Information:"                     << std::endl
// 	    << " ------------------"                     << std::endl
// 	    << "   min:              " << error_min      << std::endl
// 	    << "   max:              " << error_max      << std::endl
// 	    << "   delta:            " << error_delta    << std::endl
// 	    << "     refine_cutoff:  " << refine_cutoff  << std::endl
// 	    << "     coarsen_cutoff: " << coarsen_cutoff << std::endl;

  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error
//   active_elem_iterator       elem_it (_mesh.elements_begin());
//   const active_elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem             = *elem_it;
      const unsigned int id  = elem->id();

      assert (id < error_per_cell.size());

      const float elem_error = error_per_cell[id];

      // Flag the element for coarsening if its error
      // is <= coarsen_fraction*delta + error_min
      if (elem_error <= coarsen_cutoff)
	{
	  elem->set_refinement_flag(Elem::COARSEN);
	}

      // Flag the element for refinement if its error
      // is >= refinement_cutoff.
      if (elem_error >= refine_cutoff)
	if (elem->level() < max_level)
	  elem->set_refinement_flag(Elem::REFINE);
    }
}

void MeshRefinement::flag_elements_by_elem_fraction (const ErrorVector& error_per_cell_in,
						     const Real refine_fraction,
						     const Real coarsen_fraction,
						     const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  assert (refine_fraction  >= 0.);  assert (refine_fraction  <= 1.);
  assert (coarsen_fraction >= 0.);  assert (coarsen_fraction <= 1.);

  // The number of active elements in the mesh
  const unsigned int n_active_elem  = _mesh.n_elem();

  // The number of elements to flag for coarsening
  const unsigned int n_elem_coarsen = static_cast<unsigned int>(coarsen_fraction * n_active_elem);

  // The number of elements to flag for refinement
  const unsigned int n_elem_refine  = static_cast<unsigned int>(refine_fraction  * n_active_elem);

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // This vector stores the error and element number for all the
  // active elements.  It will be sorted and the top & bottom
  // elements will then be flagged for coarsening & refinement
  std::vector<float> sorted_error;

  sorted_error.reserve (n_active_elem);

  // Loop over the active elements and create the entry
  // in the sorted_error vector
//   const_active_elem_iterator       elem_it (_mesh.const_elements_begin());
//   const const_active_elem_iterator elem_end(_mesh.const_elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      const Elem* elem = *elem_it;
      const unsigned int elem_number = elem->id();
      const float        elem_error  = error_per_cell[elem_number];

      sorted_error.push_back (elem_error);
    }

  // Now sort the sorted_error vector
  std::sort (sorted_error.begin(), sorted_error.end());

  float
    top_error= 0., bottom_error = 0.,
    min_error= 0., max_error    = 0.;

  // Get the maximum error value corresponding to the
  // bottom n_elem_coarsen elements
  {
    std::vector<float>::iterator
      it  = sorted_error.begin();

    min_error = *it;

    std::advance (it, n_elem_coarsen);

    bottom_error = *it;
  }

  // Get the minimum error value corresponding to the
  // top n_elem_refine elements
  {
    std::vector<float>::reverse_iterator
      it  = sorted_error.rbegin();

    max_error = *it;

    std::advance (it, n_elem_refine);

    top_error = *it;
  }

  assert (max_error >= min_error);
  const Real delta       = max_error - min_error;
  const Real top_frac    = (max_error    - top_error)/max_error;
  const Real bottom_frac = (bottom_error - min_error)/delta;

  // Call the other refinement scheme
  this->flag_elements_by_error_fraction  (error_per_cell, top_frac,
					  bottom_frac, max_level);
}

void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector& error_per_cell_in,
						   const Real refine_fraction,
						   const Real coarsen_fraction,
						   const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // Get the mean value from the error vector
  const Real mean = error_per_cell.mean();

  // Get the standard deviation.  This equals the
  // square-root of the variance
  const Real stddev = std::sqrt (error_per_cell.variance());

  // Check for valid fractions
  assert (refine_fraction  >= 0.);
  assert (coarsen_fraction >= 0.);

  // The refine and coarsen cutoff
  const Real refine_cutoff  =  mean + refine_fraction  * stddev;
  const Real coarsen_cutoff =  std::max(mean - coarsen_fraction * stddev, 0.);

  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error
  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem             = *elem_it;
      const unsigned int id  = elem->id();

      assert (id < error_per_cell.size());

      const float elem_error = error_per_cell[id];

      // Possibly flag the element for coarsening ...
      if (elem_error <= coarsen_cutoff)
	elem->set_refinement_flag(Elem::COARSEN);

      // ... or refinement
      if ((elem_error >= refine_cutoff) && (elem->level() < max_level))
	elem->set_refinement_flag(Elem::REFINE);
    }
}

void MeshRefinement::clean_refinement_flags ()
{
  // Possibly clean up the refinement flags from
  // a previous step
//   elem_iterator       elem_it (_mesh.elements_begin());
//   const elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.elements_end();

  for ( ; elem_it != elem_end; ++elem_it)
    {
      if ((*elem_it)->active())
        (*elem_it)->set_refinement_flag(Elem::DO_NOTHING);
      else
        (*elem_it)->set_refinement_flag(Elem::INACTIVE);
    }
}

#endif
<commit_msg>Bugfix for "all elements have identical error" case - yes, this actually happened to me.<commit_after>// $Id: mesh_refinement_flagging.C,v 1.17 2005-12-13 21:15:46 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh_config.h"

// only compile these functions if the user requests AMR support
#ifdef ENABLE_AMR

// C++ includes
#include <algorithm> // for std::sort

// Local includes
#include "error_vector.h"
#include "mesh_refinement.h"
#include "mesh_base.h"
#include "elem.h"

//-----------------------------------------------------------------
// Mesh refinement methods
void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector& error_per_cell_in,
						      const Real refine_fraction,
						      const Real coarsen_fraction,
						      const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  assert (refine_fraction  >= 0.);  assert (refine_fraction  <= 1.);
  assert (coarsen_fraction >= 0.);  assert (coarsen_fraction <= 1.);

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // Get the minimum, maximum, and delta error values
  // for the elements
  const Real error_max   = error_per_cell.maximum();
  const Real error_min   = error_per_cell.minimum();
  const Real error_delta = (error_max - error_min);

  // Compute the cutoff values for coarsening and refinement
  const Real refine_cutoff  = (1.- refine_fraction)*error_max;
  const Real coarsen_cutoff = coarsen_fraction*error_delta + error_min;

//   // Print information about the error
//   std::cout << " Error Information:"                     << std::endl
// 	    << " ------------------"                     << std::endl
// 	    << "   min:              " << error_min      << std::endl
// 	    << "   max:              " << error_max      << std::endl
// 	    << "   delta:            " << error_delta    << std::endl
// 	    << "     refine_cutoff:  " << refine_cutoff  << std::endl
// 	    << "     coarsen_cutoff: " << coarsen_cutoff << std::endl;

  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error
//   active_elem_iterator       elem_it (_mesh.elements_begin());
//   const active_elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem             = *elem_it;
      const unsigned int id  = elem->id();

      assert (id < error_per_cell.size());

      const float elem_error = error_per_cell[id];

      // Flag the element for coarsening if its error
      // is <= coarsen_fraction*delta + error_min
      if (elem_error <= coarsen_cutoff)
	{
	  elem->set_refinement_flag(Elem::COARSEN);
	}

      // Flag the element for refinement if its error
      // is >= refinement_cutoff.
      if (elem_error >= refine_cutoff)
	if (elem->level() < max_level)
	  elem->set_refinement_flag(Elem::REFINE);
    }
}

void MeshRefinement::flag_elements_by_elem_fraction (const ErrorVector& error_per_cell_in,
						     const Real refine_fraction,
						     const Real coarsen_fraction,
						     const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  assert (refine_fraction  >= 0.);  assert (refine_fraction  <= 1.);
  assert (coarsen_fraction >= 0.);  assert (coarsen_fraction <= 1.);

  // The number of active elements in the mesh
  const unsigned int n_active_elem  = _mesh.n_elem();

  // The number of elements to flag for coarsening
  const unsigned int n_elem_coarsen = static_cast<unsigned int>(coarsen_fraction * n_active_elem);

  // The number of elements to flag for refinement
  const unsigned int n_elem_refine  = static_cast<unsigned int>(refine_fraction  * n_active_elem);

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // This vector stores the error and element number for all the
  // active elements.  It will be sorted and the top & bottom
  // elements will then be flagged for coarsening & refinement
  std::vector<float> sorted_error;

  sorted_error.reserve (n_active_elem);

  // Loop over the active elements and create the entry
  // in the sorted_error vector
//   const_active_elem_iterator       elem_it (_mesh.const_elements_begin());
//   const const_active_elem_iterator elem_end(_mesh.const_elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      const Elem* elem = *elem_it;
      const unsigned int elem_number = elem->id();
      const float        elem_error  = error_per_cell[elem_number];

      sorted_error.push_back (elem_error);
    }

  // Now sort the sorted_error vector
  std::sort (sorted_error.begin(), sorted_error.end());

  float
    top_error= 0., bottom_error = 0.,
    min_error= 0., max_error    = 0.;

  // Get the maximum error value corresponding to the
  // bottom n_elem_coarsen elements
  {
    std::vector<float>::iterator
      it  = sorted_error.begin();

    min_error = *it;

    std::advance (it, n_elem_coarsen);

    bottom_error = *it;
  }

  // Get the minimum error value corresponding to the
  // top n_elem_refine elements
  {
    std::vector<float>::reverse_iterator
      it  = sorted_error.rbegin();

    max_error = *it;

    std::advance (it, n_elem_refine);

    top_error = *it;
  }

  assert (max_error >= min_error);
  const Real delta       = max_error - min_error;
  const Real top_frac    = (max_error    - top_error)/max_error;
  const Real bottom_frac = (bottom_error - min_error)/delta;

  // Call the other refinement scheme
  // If all elements have the same error value, refine them all
  if (!delta)
    this->flag_elements_by_error_fraction  (error_per_cell, 1.,
					    0., max_level);
  // Otherwise, refine the calculated fractions
  else
    this->flag_elements_by_error_fraction  (error_per_cell, top_frac,
					    bottom_frac, max_level);
}

void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector& error_per_cell_in,
						   const Real refine_fraction,
						   const Real coarsen_fraction,
						   const unsigned int max_level)
{
  // Copy the input error_per_cell so that we can modify it
  ErrorVector error_per_cell (error_per_cell_in);

//   // Set the error_per_cell to zero for elements at the
//   // maximum allowable refinement level
//   {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

//     for (; elem_it != elem_end; ++elem_it)
//       {
// 	Elem* elem               = *elem_it;
// 	const unsigned int id    = elem->id();
// 	const unsigned int level = elem->level();

// 	assert (id < error_per_cell.size());

// 	if (level >= max_level)
// 	  error_per_cell[id] = 0.;
//       }
//   }

  // Get the mean value from the error vector
  const Real mean = error_per_cell.mean();

  // Get the standard deviation.  This equals the
  // square-root of the variance
  const Real stddev = std::sqrt (error_per_cell.variance());

  // Check for valid fractions
  assert (refine_fraction  >= 0.);
  assert (coarsen_fraction >= 0.);

  // The refine and coarsen cutoff
  const Real refine_cutoff  =  mean + refine_fraction  * stddev;
  const Real coarsen_cutoff =  std::max(mean - coarsen_fraction * stddev, 0.);

  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error
  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem             = *elem_it;
      const unsigned int id  = elem->id();

      assert (id < error_per_cell.size());

      const float elem_error = error_per_cell[id];

      // Possibly flag the element for coarsening ...
      if (elem_error <= coarsen_cutoff)
	elem->set_refinement_flag(Elem::COARSEN);

      // ... or refinement
      if ((elem_error >= refine_cutoff) && (elem->level() < max_level))
	elem->set_refinement_flag(Elem::REFINE);
    }
}

void MeshRefinement::clean_refinement_flags ()
{
  // Possibly clean up the refinement flags from
  // a previous step
//   elem_iterator       elem_it (_mesh.elements_begin());
//   const elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.elements_end();

  for ( ; elem_it != elem_end; ++elem_it)
    {
      if ((*elem_it)->active())
        (*elem_it)->set_refinement_flag(Elem::DO_NOTHING);
      else
        (*elem_it)->set_refinement_flag(Elem::INACTIVE);
    }
}

#endif
<|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  09/2017

/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_RDATASOURCE
#define ROOT_RDATASOURCE

#include "ROOT/RStringView.hxx"
#include "RtypesCore.h" // ULong64_t
#include "TString.h"

#include <algorithm> // std::transform
#include <string>
#include <typeinfo>
#include <vector>

namespace ROOT {
namespace RDF {
class RDataSource;
}
}

/// Print a RDataSource at the prompt
namespace cling {
std::string printValue(ROOT::RDF::RDataSource *ds);
} // namespace cling

namespace ROOT {

namespace Internal {
namespace TDS {

/// Mother class of TTypedPointerHolder. The instances
/// of this class can be put in a container. Upon destruction,
/// the correct deletion of the pointer is performed in the
/// derived class.
class TPointerHolder {
protected:
   void *fPointer{nullptr};

public:
   TPointerHolder(void *ptr) : fPointer(ptr) {}
   void *GetPointer() { return fPointer; }
   void *GetPointerAddr() { return &fPointer; }
   virtual TPointerHolder *GetDeepCopy() = 0;
   virtual ~TPointerHolder(){};
};

/// Class to wrap a pointer and delete the memory associated to it
/// correctly
template <typename T>
class TTypedPointerHolder final : public TPointerHolder {
public:
   TTypedPointerHolder(T *ptr) : TPointerHolder((void *)ptr) {}

   virtual TPointerHolder *GetDeepCopy()
   {
      const auto typedPtr = static_cast<T *>(fPointer);
      return new TTypedPointerHolder(new T(*typedPtr));
   }

   ~TTypedPointerHolder() { delete static_cast<T *>(fPointer); }
};

} // ns TDS
} // ns Internal

namespace RDF {

// clang-format off
/**
\class ROOT::RDF::RDataSource
\ingroup dataframe
\brief RDataSource defines an API that RDataFrame can use to read arbitrary data formats.

A concrete RDataSource implementation (i.e. a class that inherits from RDataSource and implements all of its pure
methods) provides an adaptor that RDataFrame can leverage to read any kind of tabular data formats.
RDataFrame calls into RDataSource to retrieve information about the data, retrieve (thread-local) readers or "cursors"
for selected columns and to advance the readers to the desired data entry.

The sequence of calls that RDataFrame (or any other client of a RDataSource) performs is the following:

 - SetNSlots() : inform RDataSource of the desired level of parallelism
 - GetColumnReaders() : retrieve from RDataSource per-thread readers for the desired columns
 - Initialise() : inform RDataSource that an event-loop is about to start
 - GetEntryRanges() : retrieve from RDataSource a set of ranges of entries that can be processed concurrently
 - InitSlot() : inform RDataSource that a certain thread is about to start working on a certain range of entries
 - SetEntry() : inform RDataSource that a certain thread is about to start working on a certain entry
 - FinaliseSlot() : inform RDataSource that a certain thread finished working on a certain range of entries
 - Finalise() : inform RDataSource that an event-loop finished

RDataSource implementations must support running multiple event-loops consecutively (although sequentially) on the same dataset.
 - \b SetNSlots() is called once per RDataSource object, typically when it is associated to a RDataFrame.
 - \b GetColumnReaders() can be called several times, potentially with the same arguments, also in-between event-loops, but not during an event-loop.
 - \b Initialise() and \b Finalise() are called once per event-loop,  right before starting and right after finishing.
 - \b InitSlot(), \b SetEntry(), and \b FinaliseSlot() can be called concurrently from multiple threads, multiple times per event-loop.
*/
class RDataSource {
   // clang-format on
protected:
   using Record_t = std::vector<void *>;
   friend std::string cling::printValue(::ROOT::RDF::RDataSource *);

   virtual std::string AsString() { return "generic data source"; };

public:
   virtual ~RDataSource() = default;

   // clang-format off
   /// \brief Inform RDataSource of the number of processing slots (i.e. worker threads) used by the associated RDataFrame.
   /// Slots numbers are used to simplify parallel execution: RDataFrame guarantees that different threads will always
   /// pass different slot values when calling methods concurrently.
   // clang-format on
   virtual void SetNSlots(unsigned int nSlots) = 0;

   // clang-format off
   /// \brief Returns a reference to the collection of the dataset's column names
   // clang-format on
   virtual const std::vector<std::string> &GetColumnNames() const = 0;

   /// \brief Checks if the dataset has a certain column
   /// \param[in] columnName The name of the column
   virtual bool HasColumn(std::string_view) const = 0;

   // clang-format off
   /// \brief Type of a column as a string, e.g. `GetTypeName("x") == "double"`. Required for jitting e.g. `df.Filter("x>0")`.
   /// \param[in] columnName The name of the column
   // clang-format on
   virtual std::string GetTypeName(std::string_view) const = 0;

   // clang-format off
   /// Called at most once per column by RDF. Return vector of pointers to pointers to column values - one per slot.
   /// \tparam T The type of the data stored in the column
   /// \param[in] columnName The name of the column
   ///
   /// These pointers are veritable cursors: it's a responsibility of the RDataSource implementation that they point to
   /// the "right" memory region.
   // clang-format on
   template <typename T>
   std::vector<T **> GetColumnReaders(std::string_view columnName)
   {
      auto typeErasedVec = GetColumnReadersImpl(columnName, typeid(T));
      std::vector<T **> typedVec(typeErasedVec.size());
      std::transform(typeErasedVec.begin(), typeErasedVec.end(), typedVec.begin(),
                     [](void *p) { return static_cast<T **>(p); });
      return typedVec;
   }

   // clang-format off
   /// \brief Return ranges of entries to distribute to tasks.
   /// They are required to be contiguous intervals with no entries skipped. Supposing a dataset with nEntries, the
   /// intervals must start at 0 and end at nEntries, e.g. [0-5],[5-10] for 10 entries.
   // clang-format on
   virtual std::vector<std::pair<ULong64_t, ULong64_t>> GetEntryRanges() = 0;

   // clang-format off
   /// \brief Advance the "cursors" returned by GetColumnReaders to the selected entry for a particular slot.
   /// \param[in] slot The data processing slot that needs to be considered
   /// \param[in] entry The entry which needs to be pointed to by the reader pointers
   /// Slots are adopted to accommodate parallel data processing.
   /// Different workers will loop over different ranges and
   /// will be labelled by different "slot" values.
   /// Returns *true* if the entry has to be processed, *false* otherwise.
   // clang-format on
   virtual bool SetEntry(unsigned int slot, ULong64_t entry) = 0;

   // clang-format off
   /// \brief Convenience method called before starting an event-loop.
   /// This method might be called multiple times over the lifetime of a RDataSource, since
   /// users can run multiple event-loops with the same RDataFrame.
   /// Ideally, `Initialise` should set the state of the RDataSource so that multiple identical event-loops
   /// will produce identical results.
   // clang-format on
   virtual void Initialise() {}

   // clang-format off
   /// \brief Convenience method called at the start of the data processing associated to a slot.
   /// \param[in] slot The data processing slot wihch needs to be initialised
   /// \param[in] firstEntry The first entry of the range that the task will process.
   /// This method might be called multiple times per thread per event-loop.
   // clang-format on
   virtual void InitSlot(unsigned int /*slot*/, ULong64_t /*firstEntry*/) {}

   // clang-format off
   /// \brief Convenience method called at the end of the data processing associated to a slot.
   /// \param[in] slot The data processing slot wihch needs to be finalised
   /// This method might be called multiple times per thread per event-loop.
   // clang-format on
   virtual void FinaliseSlot(unsigned int /*slot*/) {}

   // clang-format off
   /// \brief Convenience method called after concluding an event-loop.
   /// See Initialise for more details.
   // clang-format on
   virtual void Finalise() {}

   virtual std::string GetDataSourceType() = 0;

protected:
   /// type-erased vector of pointers to pointers to column values - one per slot
   virtual Record_t GetColumnReadersImpl(std::string_view name, const std::type_info &) = 0;
};

} // ns RDF

} // ns ROOT

/// Print a RDataSource at the prompt
namespace cling {
inline std::string printValue(ROOT::RDF::RDataSource *ds)
{
   return ds->AsString();
}
} // namespace cling

#endif // ROOT_TDATASOURCE
<commit_msg>[DF] Improve DS GetEntryRanges method doc<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  09/2017

/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_RDATASOURCE
#define ROOT_RDATASOURCE

#include "ROOT/RStringView.hxx"
#include "RtypesCore.h" // ULong64_t
#include "TString.h"

#include <algorithm> // std::transform
#include <string>
#include <typeinfo>
#include <vector>

namespace ROOT {
namespace RDF {
class RDataSource;
}
}

/// Print a RDataSource at the prompt
namespace cling {
std::string printValue(ROOT::RDF::RDataSource *ds);
} // namespace cling

namespace ROOT {

namespace Internal {
namespace TDS {

/// Mother class of TTypedPointerHolder. The instances
/// of this class can be put in a container. Upon destruction,
/// the correct deletion of the pointer is performed in the
/// derived class.
class TPointerHolder {
protected:
   void *fPointer{nullptr};

public:
   TPointerHolder(void *ptr) : fPointer(ptr) {}
   void *GetPointer() { return fPointer; }
   void *GetPointerAddr() { return &fPointer; }
   virtual TPointerHolder *GetDeepCopy() = 0;
   virtual ~TPointerHolder(){};
};

/// Class to wrap a pointer and delete the memory associated to it
/// correctly
template <typename T>
class TTypedPointerHolder final : public TPointerHolder {
public:
   TTypedPointerHolder(T *ptr) : TPointerHolder((void *)ptr) {}

   virtual TPointerHolder *GetDeepCopy()
   {
      const auto typedPtr = static_cast<T *>(fPointer);
      return new TTypedPointerHolder(new T(*typedPtr));
   }

   ~TTypedPointerHolder() { delete static_cast<T *>(fPointer); }
};

} // ns TDS
} // ns Internal

namespace RDF {

// clang-format off
/**
\class ROOT::RDF::RDataSource
\ingroup dataframe
\brief RDataSource defines an API that RDataFrame can use to read arbitrary data formats.

A concrete RDataSource implementation (i.e. a class that inherits from RDataSource and implements all of its pure
methods) provides an adaptor that RDataFrame can leverage to read any kind of tabular data formats.
RDataFrame calls into RDataSource to retrieve information about the data, retrieve (thread-local) readers or "cursors"
for selected columns and to advance the readers to the desired data entry.

The sequence of calls that RDataFrame (or any other client of a RDataSource) performs is the following:

 - SetNSlots() : inform RDataSource of the desired level of parallelism
 - GetColumnReaders() : retrieve from RDataSource per-thread readers for the desired columns
 - Initialise() : inform RDataSource that an event-loop is about to start
 - GetEntryRanges() : retrieve from RDataSource a set of ranges of entries that can be processed concurrently
 - InitSlot() : inform RDataSource that a certain thread is about to start working on a certain range of entries
 - SetEntry() : inform RDataSource that a certain thread is about to start working on a certain entry
 - FinaliseSlot() : inform RDataSource that a certain thread finished working on a certain range of entries
 - Finalise() : inform RDataSource that an event-loop finished

RDataSource implementations must support running multiple event-loops consecutively (although sequentially) on the same dataset.
 - \b SetNSlots() is called once per RDataSource object, typically when it is associated to a RDataFrame.
 - \b GetColumnReaders() can be called several times, potentially with the same arguments, also in-between event-loops, but not during an event-loop.
 - \b Initialise() and \b Finalise() are called once per event-loop,  right before starting and right after finishing.
 - \b InitSlot(), \b SetEntry(), and \b FinaliseSlot() can be called concurrently from multiple threads, multiple times per event-loop.
*/
class RDataSource {
   // clang-format on
protected:
   using Record_t = std::vector<void *>;
   friend std::string cling::printValue(::ROOT::RDF::RDataSource *);

   virtual std::string AsString() { return "generic data source"; };

public:
   virtual ~RDataSource() = default;

   // clang-format off
   /// \brief Inform RDataSource of the number of processing slots (i.e. worker threads) used by the associated RDataFrame.
   /// Slots numbers are used to simplify parallel execution: RDataFrame guarantees that different threads will always
   /// pass different slot values when calling methods concurrently.
   // clang-format on
   virtual void SetNSlots(unsigned int nSlots) = 0;

   // clang-format off
   /// \brief Returns a reference to the collection of the dataset's column names
   // clang-format on
   virtual const std::vector<std::string> &GetColumnNames() const = 0;

   /// \brief Checks if the dataset has a certain column
   /// \param[in] columnName The name of the column
   virtual bool HasColumn(std::string_view) const = 0;

   // clang-format off
   /// \brief Type of a column as a string, e.g. `GetTypeName("x") == "double"`. Required for jitting e.g. `df.Filter("x>0")`.
   /// \param[in] columnName The name of the column
   // clang-format on
   virtual std::string GetTypeName(std::string_view) const = 0;

   // clang-format off
   /// Called at most once per column by RDF. Return vector of pointers to pointers to column values - one per slot.
   /// \tparam T The type of the data stored in the column
   /// \param[in] columnName The name of the column
   ///
   /// These pointers are veritable cursors: it's a responsibility of the RDataSource implementation that they point to
   /// the "right" memory region.
   // clang-format on
   template <typename T>
   std::vector<T **> GetColumnReaders(std::string_view columnName)
   {
      auto typeErasedVec = GetColumnReadersImpl(columnName, typeid(T));
      std::vector<T **> typedVec(typeErasedVec.size());
      std::transform(typeErasedVec.begin(), typeErasedVec.end(), typedVec.begin(),
                     [](void *p) { return static_cast<T **>(p); });
      return typedVec;
   }

   // clang-format off
   /// \brief Return ranges of entries to distribute to tasks.
   /// They are required to be contiguous intervals with no entries skipped. Supposing a dataset with nEntries, the
   /// intervals must start at 0 and end at nEntries, e.g. [0-5],[5-10] for 10 entries.
   /// Returning an empty collection of ranges signals to RDataFrame that the processing can stop.
   // clang-format on
   virtual std::vector<std::pair<ULong64_t, ULong64_t>> GetEntryRanges() = 0;

   // clang-format off
   /// \brief Advance the "cursors" returned by GetColumnReaders to the selected entry for a particular slot.
   /// \param[in] slot The data processing slot that needs to be considered
   /// \param[in] entry The entry which needs to be pointed to by the reader pointers
   /// Slots are adopted to accommodate parallel data processing.
   /// Different workers will loop over different ranges and
   /// will be labelled by different "slot" values.
   /// Returns *true* if the entry has to be processed, *false* otherwise.
   // clang-format on
   virtual bool SetEntry(unsigned int slot, ULong64_t entry) = 0;

   // clang-format off
   /// \brief Convenience method called before starting an event-loop.
   /// This method might be called multiple times over the lifetime of a RDataSource, since
   /// users can run multiple event-loops with the same RDataFrame.
   /// Ideally, `Initialise` should set the state of the RDataSource so that multiple identical event-loops
   /// will produce identical results.
   // clang-format on
   virtual void Initialise() {}

   // clang-format off
   /// \brief Convenience method called at the start of the data processing associated to a slot.
   /// \param[in] slot The data processing slot wihch needs to be initialised
   /// \param[in] firstEntry The first entry of the range that the task will process.
   /// This method might be called multiple times per thread per event-loop.
   // clang-format on
   virtual void InitSlot(unsigned int /*slot*/, ULong64_t /*firstEntry*/) {}

   // clang-format off
   /// \brief Convenience method called at the end of the data processing associated to a slot.
   /// \param[in] slot The data processing slot wihch needs to be finalised
   /// This method might be called multiple times per thread per event-loop.
   // clang-format on
   virtual void FinaliseSlot(unsigned int /*slot*/) {}

   // clang-format off
   /// \brief Convenience method called after concluding an event-loop.
   /// See Initialise for more details.
   // clang-format on
   virtual void Finalise() {}

   virtual std::string GetDataSourceType() = 0;

protected:
   /// type-erased vector of pointers to pointers to column values - one per slot
   virtual Record_t GetColumnReadersImpl(std::string_view name, const std::type_info &) = 0;
};

} // ns RDF

} // ns ROOT

/// Print a RDataSource at the prompt
namespace cling {
inline std::string printValue(ROOT::RDF::RDataSource *ds)
{
   return ds->AsString();
}
} // namespace cling

#endif // ROOT_TDATASOURCE
<|endoftext|>