Skip to content
Snippets Groups Projects
vtkMDQuadFactory.cpp 5.88 KiB
Newer Older
#include "MantidVatesAPI/vtkMDQuadFactory.h"
#include "MantidVatesAPI/Common.h"
#include "MantidVatesAPI/ProgressAction.h"
#include "MantidVatesAPI/vtkNullUnstructuredGrid.h"
#include "MantidAPI/IMDWorkspace.h"
#include "MantidAPI/IMDEventWorkspace.h"
#include "MantidAPI/IMDIterator.h"
#include "MantidAPI/CoordTransform.h"
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <vtkUnstructuredGrid.h>
#include <vtkFloatArray.h>
#include <vtkQuad.h>
#include <vtkCellData.h>
#include "MantidKernel/ReadLock.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/make_unique.h"

using namespace Mantid::API;

Matthew D Jones's avatar
Matthew D Jones committed
namespace {
Mantid::Kernel::Logger g_log("vtkMDQuadFactory");
Matthew D Jones's avatar
Matthew D Jones committed
namespace Mantid {
namespace VATES {
/// Constructor
vtkMDQuadFactory::vtkMDQuadFactory(
    const VisualNormalization normalizationOption)
    : m_normalizationOption(normalizationOption) {}
Matthew D Jones's avatar
Matthew D Jones committed

/// Destructor
vtkMDQuadFactory::~vtkMDQuadFactory() {}

/**
Create the vtkStructuredGrid from the provided workspace
@param progressUpdating: Reporting object to pass progress information up the
stack.
@return fully constructed vtkDataSet.
*/
vtkSmartPointer<vtkDataSet>
vtkMDQuadFactory::create(ProgressAction &progressUpdating) const {
  auto product = tryDelegatingCreation<IMDEventWorkspace, 2>(m_workspace,
                                                             progressUpdating);
  if (product != nullptr) {
Matthew D Jones's avatar
Matthew D Jones committed
    return product;
  } else {
    g_log.warning() << "Factory " << this->getFactoryTypeName()
                    << " is being used. You are viewing data with less than "
                       "three dimensions in the VSI. \n";

    IMDEventWorkspace_sptr imdws =
        this->castAndCheck<IMDEventWorkspace, 2>(m_workspace);
    // Acquire a scoped read-only lock to the workspace (prevent segfault from
    // algos modifying ws)
    Mantid::Kernel::ReadLock lock(*imdws);

    const size_t nDims = imdws->getNumDims();
    size_t nNonIntegrated = imdws->getNonIntegratedDimensions().size();

    /*
    Write mask array with correct order for each internal dimension.
    auto masks = Mantid::Kernel::make_unique<bool[]>(nDims);
Matthew D Jones's avatar
Matthew D Jones committed
    for (size_t i_dim = 0; i_dim < nDims; ++i_dim) {
      bool bIntegrated = imdws->getDimension(i_dim)->getIsIntegrated();
      masks[i_dim] =
          !bIntegrated; // TRUE for unmaksed, integrated dimensions are masked.
    }
Matthew D Jones's avatar
Matthew D Jones committed
    // Make iterator, which will use the desired normalization. Ensure
    // destruction in any eventuality.
    auto it =
        createIteratorWithNormalization(m_normalizationOption, imdws.get());
Matthew D Jones's avatar
Matthew D Jones committed
    // Create 4 points per box.
    vtkNew<vtkPoints> points;
Matthew D Jones's avatar
Matthew D Jones committed
    points->SetNumberOfPoints(it->getDataSize() * 4);
Matthew D Jones's avatar
Matthew D Jones committed
    // One scalar per box
    vtkNew<vtkFloatArray> signals;
Matthew D Jones's avatar
Matthew D Jones committed
    signals->Allocate(it->getDataSize());
    signals->SetName(vtkDataSetFactory::ScalarName.c_str());
    signals->SetNumberOfComponents(1);
Matthew D Jones's avatar
Matthew D Jones committed
    size_t nVertexes;
    auto visualDataSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
Matthew D Jones's avatar
Matthew D Jones committed
    visualDataSet->Allocate(it->getDataSize());
    vtkNew<vtkIdList> quadPointList;
Matthew D Jones's avatar
Matthew D Jones committed
    quadPointList->SetNumberOfIds(4);
    Mantid::API::CoordTransform const *transform = nullptr;
Matthew D Jones's avatar
Matthew D Jones committed
    if (m_useTransform) {
      transform = imdws->getTransformToOriginal();
    }
Matthew D Jones's avatar
Matthew D Jones committed
    Mantid::coord_t out[2];
    auto useBox = std::vector<bool>(it->getDataSize());
Matthew D Jones's avatar
Matthew D Jones committed

    double progressFactor = 0.5 / double(it->getDataSize());
    double progressOffset = 0.5;

    size_t iBox = 0;
    do {
      progressUpdating.eventRaised(progressFactor * double(iBox));

      Mantid::signal_t signal = it->getNormalizedSignal();
      if (std::isfinite(signal)) {
Matthew D Jones's avatar
Matthew D Jones committed
        useBox[iBox] = true;
        signals->InsertNextValue(static_cast<float>(signal));

        auto coords =
            it->getVertexesArray(nVertexes, nNonIntegrated, masks.get());
Matthew D Jones's avatar
Matthew D Jones committed
        // Iterate through all coordinates. Candidate for speed improvement.
        for (size_t v = 0; v < nVertexes; ++v) {
          coord_t *coord = coords.get() + v * 2;
Matthew D Jones's avatar
Matthew D Jones committed
          size_t id = iBox * 4 + v;
          if (m_useTransform) {
            transform->apply(coord, out);
            points->SetPoint(id, out[0], out[1], 0);
          } else {
            points->SetPoint(id, coord[0], coord[1], 0);
Matthew D Jones's avatar
Matthew D Jones committed
      } // valid number of vertexes returned
      else {
        useBox[iBox] = false;
      }
      ++iBox;
    } while (it->next());

    for (size_t ii = 0; ii < it->getDataSize(); ++ii) {
      progressUpdating.eventRaised((progressFactor * double(ii)) +
                                   progressOffset);

      if (useBox[ii] == true) {
        vtkIdType pointIds = vtkIdType(ii * 4);

        quadPointList->SetId(0, pointIds + 0); // xyx
        quadPointList->SetId(1, pointIds + 1); // dxyz
        quadPointList->SetId(2, pointIds + 3); // dxdyz
        quadPointList->SetId(3, pointIds + 2); // xdyz
        visualDataSet->InsertNextCell(VTK_QUAD, quadPointList.GetPointer());
Matthew D Jones's avatar
Matthew D Jones committed
      } // valid number of vertexes returned
    }
Matthew D Jones's avatar
Matthew D Jones committed
    signals->Squeeze();
    points->Squeeze();
    visualDataSet->SetPoints(points.GetPointer());
    visualDataSet->GetCellData()->SetScalars(signals.GetPointer());
Matthew D Jones's avatar
Matthew D Jones committed
    visualDataSet->Squeeze();
Matthew D Jones's avatar
Matthew D Jones committed
    // Hedge against empty data sets
    if (visualDataSet->GetNumberOfPoints() <= 0) {
      vtkNullUnstructuredGrid nullGrid;
      visualDataSet = nullGrid.createNullData();
    vtkSmartPointer<vtkDataSet> dataSet = visualDataSet;
    return dataSet;
Matthew D Jones's avatar
Matthew D Jones committed
/// Initalize with a target workspace.
void vtkMDQuadFactory::initialize(const Mantid::API::Workspace_sptr &ws) {
Matthew D Jones's avatar
Matthew D Jones committed
  m_workspace = doInitialize<IMDEventWorkspace, 2>(ws);
}
Matthew D Jones's avatar
Matthew D Jones committed
/// Get the name of the type.
std::string vtkMDQuadFactory::getFactoryTypeName() const {
  return "vtkMDQuadFactory";
}
Matthew D Jones's avatar
Matthew D Jones committed
/// Template Method pattern to validate the factory before use.
void vtkMDQuadFactory::validate() const {
  if (!m_workspace) {
Matthew D Jones's avatar
Matthew D Jones committed
    throw std::runtime_error(
        "vtkMDQuadFactory has no workspace to run against");