Skip to content
Snippets Groups Projects
vtkDataSetFactory.h 8.7 KiB
Newer Older


#ifndef MANTID_VATES_VTKDATASETFACTORY_H_
#define MANTID_VATES_VTKDATASETFACTORY_H_

#include "MantidAPI/IMDWorkspace.h"
#include "MantidAPI/Workspace_fwd.h"
#include "MantidKernel/Chainable.h"
#include "MantidKernel/make_unique.h"
#include "vtkSmartPointer.h"
#include <boost/shared_ptr.hpp>
#include <boost/tuple/tuple.hpp>
namespace Mantid {
// Forward declaration
class ProgressAction;
/* Helper struct allows recognition of points that we should not bother to draw.
*/
struct UnstructuredPoint {
  bool isSparse;
  vtkIdType pointId;
};
/** Abstract type to generate a vtk dataset on demand from a MDWorkspace.
 Uses Chain Of Responsibility pattern to self-manage and ensure that the
 workspace rendering is delegated to another factory
 if the present concrete type can't handle it.

 @author Owen Arnold, Tessella plc
 @date 24/01/2010

 Copyright &copy; 2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
 National Laboratory & European Spallation Source

 This file is part of Mantid.

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

 Mantid 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 File change history is stored at: <https://github.com/mantidproject/mantid>
 Code Documentation is available at: <http://doxygen.mantidproject.org>
 */

class DLLExport vtkDataSetFactory
    : public Mantid::Kernel::Chainable<vtkDataSetFactory> {
  /// Factory Method. Should also handle delegation to successors.
  virtual vtkSmartPointer<vtkDataSet> create(ProgressAction &) const = 0;
  /// Initalize with a target workspace.
  virtual void initialize(const Mantid::API::Workspace_sptr &workspace) = 0;
  /// Create the product in one step.
  virtual vtkSmartPointer<vtkDataSet> oneStepCreate(Mantid::API::Workspace_sptr,
                                                    ProgressAction &);
  virtual std::string getFactoryTypeName() const = 0;
  virtual void setRecursionDepth(size_t) // TODO subtype vtkDataSet factory
                                         // specifically for MDWEW type
                                         // workspaces and put this method on
                                         // that subtype.
    throw std::runtime_error(
        "vtkDataSetFactory does not implement ::setRecursionDepth");
  /// Setter for whether a workspace defined transformation should be used or
  /// not.
  virtual void setUseTransform(bool bUseTransform) {
    m_useTransform = bUseTransform;
  }

  /// Getter for the use transform status.
  virtual bool getUseTransform() const { return m_useTransform; }
  /// Setter to indicate that dimensionality should/should not be checked.
  void setCheckDimensionality(bool flag);

  /// Getter for the state of the dimensionality checking.
  bool doesCheckDimensionality() const;

  enum Dimensionality {
    OneDimensional = 1,
    TwoDimensional = 2,
    ThreeDimensional = 3,
    FourDimensional = 4
  };
  static const std::string ScalarName;

   Run checks based on the non-integrated dimensionality, which are only run
   if the factory is set to apply these checks.
Hahn, Steven's avatar
Hahn, Steven committed
   @param  imdws : workspace to check.
   @param  bExactMatch : run an exact match on non-integarated dimensionality if
   TRUE, otherwise is less than or equal to ExpectedDimensions.
   @return whether the checks pass or fail.
   */
  template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
  bool checkWorkspace(const IMDWorkspaceType &imdws,
                      bool bExactMatch = true) const {
    bool bPassesDimensionalityCheck = false;
    size_t actualNonIntegratedDimensionality =
        imdws.getNonIntegratedDimensions().size();
    if (bExactMatch) {
      bPassesDimensionalityCheck =
          (ExpectedNDimensions == actualNonIntegratedDimensionality);
    } else {
      bPassesDimensionalityCheck =
          (actualNonIntegratedDimensionality >= ExpectedNDimensions);
    if (this->doesCheckDimensionality() && !bPassesDimensionalityCheck) {
      // Abort as there are dimensionality checks to be applied and these checks
      // fail.
   Try to cast it to the specified IMDType and then run checks based on the
   non-integrated dimensionality.
   The latter checks are only run if the factory is set to apply these checks.
   @param  workspace : workspace to cast.
   @param  bExactMatch : run an exact match on non-integarated dimensionality if
   TRUE, otherwise is less than or equal to ExpectedDimensions.
   @return  correctly cast shared pointer or an empty shared pointer if cast or
   checks fail.
   */
  template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
  boost::shared_ptr<IMDWorkspaceType>
  castAndCheck(Mantid::API::Workspace_sptr workspace,
               bool bExactMatch = true) const {
    boost::shared_ptr<IMDWorkspaceType> imdws =
        boost::dynamic_pointer_cast<IMDWorkspaceType>(workspace);
    if (imdws &&
        this->checkWorkspace<IMDWorkspaceType, ExpectedNDimensions>(
            *imdws, bExactMatch)) {
      return imdws;
    } else {
      // Abort as imdws cannot be dynamically cast to the target type.
      return nullptr;
    }
  }

  /**
  Common initialization implementation. Most vtkDataSets will need this in
  order
  to correctly delegate initialization onto successors.
  @param workspace : workspace to cast.
  @param bExactMatch : run an exact match on non-integarated dimensionality if
  TRUE, otherwise is less than or equal to ExpectedDimensions.
  @return correctly cast shared pointer or an empty shared pointer if cast or
  checks fail.
  template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
  boost::shared_ptr<IMDWorkspaceType>
  doInitialize(Mantid::API::Workspace_sptr workspace,
               bool bExactMatch = true) const {
      std::string message = this->getFactoryTypeName() +
                            " initialize cannot operate on a null workspace";
      throw std::invalid_argument(message);
    }
    boost::shared_ptr<IMDWorkspaceType> imdws =
        castAndCheck<IMDWorkspaceType, ExpectedNDimensions>(workspace,
                                                            bExactMatch);
    if (!imdws) {
      if (this->hasSuccessor()) {
        m_successor->setUseTransform(m_useTransform);
        m_successor->initialize(workspace);
        std::string message = this->getFactoryTypeName() + " has no successor";
        throw std::runtime_error(message);
      }
    }
    return imdws;
Hahn, Steven's avatar
Hahn, Steven committed
  }
Hahn, Steven's avatar
Hahn, Steven committed
  /**
  Common creation implementation whereby delegation to successor is attempted
  if
  appropriate.
  @param workspace : workspace to cast and create from.
  @param progressUpdate : object used to pass progress information back up the
  stack.
  @param bExactMatch : Check for an exact match if true.
  @return TRUE if delegation to successors has occured. Otherwise returns
  false.
  */
  template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
  vtkSmartPointer<vtkDataSet>
  tryDelegatingCreation(Mantid::API::Workspace_sptr workspace,
                        ProgressAction &progressUpdate,
                        bool bExactMatch = true) const {
    boost::shared_ptr<IMDWorkspaceType> imdws =
        castAndCheck<IMDWorkspaceType, ExpectedNDimensions>(workspace,
                                                            bExactMatch);
    if (!imdws) {
      if (this->hasSuccessor()) {
        return m_successor->create(progressUpdate);
      } else {
        std::string message = this->getFactoryTypeName() + " has no successor";
        throw std::runtime_error(message);
Hahn, Steven's avatar
Hahn, Steven committed
    return nullptr;
  }
Hahn, Steven's avatar
Hahn, Steven committed
  /// Template Method pattern to validate the factory before use.
  virtual void validate() const = 0;
Hahn, Steven's avatar
Hahn, Steven committed
  /// Checks successor when set and throws if bad
  void checkSuccessor() const override;
Hahn, Steven's avatar
Hahn, Steven committed
  /// Flag indicating whether a transformation should be used.
  bool m_useTransform;
Hahn, Steven's avatar
Hahn, Steven committed
private:
  /// Dimensionality checking flag
  bool m_bCheckDimensionality;
using vtkDataSetFactory_sptr = boost::shared_ptr<vtkDataSetFactory>;
using vtkDataSetFactory_uptr = std::unique_ptr<vtkDataSetFactory>;