diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QPeaksTableModel.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QPeaksTableModel.h index a95b7fd55e33f3b9a5593228fe0f8e1e1280fe60..775f269a859e69a905042904de78d53e56020326 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QPeaksTableModel.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QPeaksTableModel.h @@ -1,4 +1,5 @@ #include <QAbstractTableModel> +#include "DllOption.h" #include <boost/shared_ptr.hpp> #include "boost/bind.hpp" #include "boost/function.hpp" @@ -47,7 +48,7 @@ namespace MantidQt File change history is stored at: <https://github.com/mantidproject/mantid>. Code Documentation is available at: <http://doxygen.mantidproject.org> */ - class QPeaksTableModel : public QAbstractTableModel + class EXPORT_OPT_MANTIDQT_SLICEVIEWER QPeaksTableModel : public QAbstractTableModel { Q_OBJECT public: diff --git a/Code/Mantid/Vates/VatesAPI/CMakeLists.txt b/Code/Mantid/Vates/VatesAPI/CMakeLists.txt index 72465397a248a38914f15009fd78e7d87f587da2..42bff6c7353897a33c47b2f855a90c9fbafab583 100644 --- a/Code/Mantid/Vates/VatesAPI/CMakeLists.txt +++ b/Code/Mantid/Vates/VatesAPI/CMakeLists.txt @@ -7,6 +7,7 @@ set( SRC_FILES src/ADSWorkspaceProvider.cpp src/Clipper.cpp src/Common.cpp +src/ConcretePeaksPresenterVsi.cpp src/DimensionPresenter.cpp src/EscalatingRebinningActionManager.cpp src/EventNexusLoadingPresenter.cpp @@ -35,6 +36,7 @@ src/TimeStepToTimeStep.cpp src/TimeToTimeStep.cpp src/UserDefinedThresholdRange.cpp src/VatesConfigurations.cpp +src/ViewFrustum.cpp src/vtkDataSetFactory.cpp src/vtkDataSetToGeometry.cpp src/vtkDataSetToImplicitFunction.cpp @@ -58,6 +60,7 @@ set( INC_FILES inc/MantidVatesAPI/ADSWorkspaceProvider.h inc/MantidVatesAPI/Clipper.h inc/MantidVatesAPI/Common.h +inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h inc/MantidVatesAPI/DimensionPresenter.h inc/MantidVatesAPI/DimensionView.h inc/MantidVatesAPI/DimensionViewFactory.h @@ -89,6 +92,8 @@ inc/MantidVatesAPI/IMDDimensionComparitor.h inc/MantidVatesAPI/MetadataToFieldData.h inc/MantidVatesAPI/NoThresholdRange.h inc/MantidVatesAPI/NullRebinningPresenter.h +inc/MantidVatesAPI/NullPeaksPresenterVsi.h +inc/MantidVatesAPI/PeaksPresenterVsi.h inc/MantidVatesAPI/ProgressAction.h inc/MantidVatesAPI/RebinningActionManager.h inc/MantidVatesAPI/RebinningCutterXMLDefinitions.h @@ -100,6 +105,7 @@ inc/MantidVatesAPI/TimeStepToTimeStep.h inc/MantidVatesAPI/TimeToTimeStep.h inc/MantidVatesAPI/UserDefinedThresholdRange.h inc/MantidVatesAPI/VatesConfigurations.h +inc/MantidVatesAPI/ViewFrustum.h inc/MantidVatesAPI/vtkDataSetFactory.h inc/MantidVatesAPI/vtkDataSetToGeometry.h inc/MantidVatesAPI/vtkDataSetToImplicitFunction.h @@ -163,6 +169,7 @@ test/UserDefinedThresholdRangeTest.h test/MedianAndBelowThresholdRangeTest.h test/NoThresholdRangeTest.h test/IgnoreZerosThresholdRangeTest.h +test/ViewFrustumTest.h test/vtkDataSetToScaledDataSetTest.h test/vtkDataSetToNonOrthogonalDataSetTest.h ) diff --git a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h new file mode 100644 index 0000000000000000000000000000000000000000..5abce127f45eb431382912e591a72c64f82bd987 --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h @@ -0,0 +1,37 @@ +#ifndef MANTID_VATES_CONCRETE_PEAKS_PRESENTER_VSI_H +#define MANTID_VATES_CONCRETE_PEAKS_PRESENTER_VSI_H + +#include "MantidKernel/System.h" +#include "MantidVatesAPI/PeaksPresenterVsi.h" +#include "MantidAPI/PeakTransform.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include "MantidVatesAPI/ViewFrustum.h" +#include <vector> + + +namespace Mantid +{ +namespace VATES +{ +class DLLExport ConcretePeaksPresenterVsi : public PeaksPresenterVsi +{ + public: + ConcretePeaksPresenterVsi(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace, ViewFrustum frustum, std::string wsFrame); + ~ConcretePeaksPresenterVsi(); + virtual Mantid::API::IPeaksWorkspace_sptr getPeaksWorkspace(); + virtual std::vector<bool> getViewablePeaks(); + virtual void updateViewFrustum(ViewFrustum frustum); + virtual std::string getFrame(); + private: + /// Viewable Peaks + std::vector<bool> m_viewablePeaks; + /// The viewable region + ViewFrustum m_viewableRegion; + /// The peaks workspace + Mantid::API::IPeaksWorkspace_sptr m_peaksWorkspace; + /// The frame + std::string m_frame; +}; +} +} +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/NullPeaksPresenterVsi.h b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/NullPeaksPresenterVsi.h new file mode 100644 index 0000000000000000000000000000000000000000..44bcdf6887f7e93ccd3e9d732429a90f664d3351 --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/NullPeaksPresenterVsi.h @@ -0,0 +1,27 @@ +#ifndef MANTID_VATES_NULL_PEAKS_PRESENTER +#define MANTID_VATES_NULL_PEAKS_PRESENTER + +#include "MantidKernel/System.h" +#include "MantidVatesAPI/PeaksPresenterVsi.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include "MantidVatesAPI/ViewFrustum.h" +#include <vector> + +namespace Mantid +{ +namespace VATES +{ + class DLLExport NullPeaksPresenterVsi : public PeaksPresenterVsi + { + public: + NullPeaksPresenterVsi(){} + virtual ~NullPeaksPresenterVsi(){} + virtual Mantid::API::IPeaksWorkspace_sptr getPeaksWorkspace(){return Mantid::API::IPeaksWorkspace_sptr();}; + virtual std::vector<bool> getViewablePeaks() {return std::vector<bool>();} + virtual void updateViewFrustum(ViewFrustum frustum) {}; + virtual std::string getFrame(){return std::string();} + }; +} +} + +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/PeaksPresenterVsi.h b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/PeaksPresenterVsi.h new file mode 100644 index 0000000000000000000000000000000000000000..f125a4b96602254689d524268d24e7d624806030 --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/PeaksPresenterVsi.h @@ -0,0 +1,27 @@ +#ifndef MANTID_VATES_PEAKS_PRESENTER_VSI_H +#define MANTID_VATES_PEAKS_PRESENTER_VSI_H + +#include "MantidKernel/System.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include <vector> +#include <string> + + +namespace Mantid +{ +namespace VATES +{ +class ViewFrustum; + +class DLLExport PeaksPresenterVsi +{ + public: + virtual ~PeaksPresenterVsi(){}; + virtual std::vector<bool> getViewablePeaks() = 0; + virtual Mantid::API::IPeaksWorkspace_sptr getPeaksWorkspace() = 0; + virtual void updateViewFrustum(ViewFrustum frustum) = 0; + virtual std::string getFrame() = 0; +}; +} +} +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h new file mode 100644 index 0000000000000000000000000000000000000000..584fbe530a7681d42f1cb1184699204338646d1f --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h @@ -0,0 +1,176 @@ +#ifndef MANTID_PARAVIEW_VIEWFRUSTUM +#define MANTID_PARAVIEW_VIEWFRUSTUM + +#include "MantidKernel/System.h" +#include "MantidKernel/Matrix.h" +#include <stdexcept> +#include <cmath> +#include <cfloat> +#include <vector> + +namespace Mantid +{ +namespace VATES +{ + +enum PLANELOCATION{LEFTPLANE, RIGHTPLANE, BOTTOMPLANE, TOPPLANE, FARPLANE, NEARPLANE}; + +template<PLANELOCATION I, typename T> +class DLLExport FrustumPlane +{ + public: + explicit FrustumPlane(const T& paramA, const T& paramB, const T& paramC, const T& paramD) : m_paramA(paramA), + m_paramB(paramB), + m_paramC(paramC), + m_paramD(paramD){} + FrustumPlane(const FrustumPlane<I, T>& other) : m_paramA(other.m_paramA), + m_paramB(other.m_paramB), + m_paramC(other.m_paramC), + m_paramD(other.m_paramD){} + T A() {return m_paramA;} + T B() {return m_paramB;} + T C() {return m_paramC;} + T D() {return m_paramD;} + + std::vector<T> getPlaneCoefficients() + { + std::vector<T> coefficients; + coefficients.push_back(m_paramA); + coefficients.push_back(m_paramB); + coefficients.push_back(m_paramC); + coefficients.push_back(m_paramD); + + return coefficients; + } + +private: + T m_paramA; + T m_paramB; + T m_paramC; + T m_paramD; + enum{m_location = I}; +}; + +typedef FrustumPlane<LEFTPLANE, double> LeftPlane; +typedef FrustumPlane<RIGHTPLANE, double> RightPlane; +typedef FrustumPlane<BOTTOMPLANE, double> BottomPlane; +typedef FrustumPlane<TOPPLANE, double> TopPlane; +typedef FrustumPlane<FARPLANE, double> FarPlane; +typedef FrustumPlane<NEARPLANE, double> NearPlane; + + +class DLLExport ViewFrustum +{ + public: + ViewFrustum(const LeftPlane leftPlane, + const RightPlane rightPlane, + const BottomPlane bottomPlane, + const TopPlane topPlane, + const FarPlane farPlane, + const NearPlane nearPlane); + ViewFrustum(const ViewFrustum& other); + ~ViewFrustum(); + ViewFrustum& operator=(const ViewFrustum& other); + std::vector<std::pair<double, double>> toExtents() const; + std::string toExtentsAsString() const; + bool pointLiesInsideViewFrustum(std::vector<double> point) const; + + private: + mutable LeftPlane m_leftPlane; + mutable RightPlane m_rightPlane; + mutable TopPlane m_topPlane; + mutable BottomPlane m_bottomPlane; + mutable FarPlane m_farPlane; + mutable NearPlane m_nearPlane; + + template<PLANELOCATION p1, PLANELOCATION p2, PLANELOCATION p3, typename T> + std::vector<T> getIntersectionPointThreePlanes(FrustumPlane<p1, T> plane1, FrustumPlane<p2, T> plane2, FrustumPlane<p3, T> plane3) const; + + template<typename T> + void initializeMatrix(Mantid::Kernel::Matrix<T>& matrix, std::vector<T> vec0, std::vector<T> vec1, std::vector<T> vec2) const; +}; + /** + * Get the intersection point of three planes using Cramer's rule. + * @param plane1 The first frustum plane + * @param plane2 The second frustum plane + * @param plane3 The third frustum plane + */ + template<PLANELOCATION p1, PLANELOCATION p2, PLANELOCATION p3, typename T> + std::vector<T> ViewFrustum::getIntersectionPointThreePlanes(FrustumPlane<p1, T> plane1, FrustumPlane<p2, T> plane2, FrustumPlane<p3, T> plane3) const + { + const size_t dim = 3; + + std::vector<T> aVec; + aVec.push_back(plane1.A()); + aVec.push_back(plane2.A()); + aVec.push_back(plane3.A()); + + std::vector<T> bVec; + bVec.push_back(plane1.B()); + bVec.push_back(plane2.B()); + bVec.push_back(plane3.B()); + + std::vector<T> cVec; + cVec.push_back(plane1.C()); + cVec.push_back(plane2.C()); + cVec.push_back(plane3.C()); + + // The input is Ax+By+Cz+D=0 but we need the form Ax+By+Cz=D + std::vector<T> dVec; + const T factor = -1; + dVec.push_back(factor*plane1.D()); + dVec.push_back(factor*plane2.D()); + dVec.push_back(factor*plane3.D()); + + // Get the different matrix permutations + Mantid::Kernel::Matrix<T> abcMatrix(dim, dim); + Mantid::Kernel::Matrix<T> dbcMatrix(dim, dim); + Mantid::Kernel::Matrix<T> adcMatrix(dim, dim); + Mantid::Kernel::Matrix<T> abdMatrix(dim, dim); + + initializeMatrix<T>(abcMatrix, aVec, bVec, cVec); + T abcDet = abcMatrix.determinant(); + if (abcDet == 0) + { + throw std::runtime_error("Determinant for view frustum is 0."); + } + + initializeMatrix<T>(dbcMatrix, dVec, bVec, cVec); + initializeMatrix<T>(adcMatrix, aVec, dVec, cVec); + initializeMatrix<T>(abdMatrix, aVec, bVec, dVec); + + T dbcDet = dbcMatrix.determinant(); + T adcDet = adcMatrix.determinant(); + T abdDet = abdMatrix.determinant(); + + std::vector<T> intersection; + intersection.push_back(dbcDet/abcDet); + intersection.push_back(adcDet/abcDet); + intersection.push_back(abdDet/abcDet); + + return intersection; + } + + /** + * Initialize the matrix with the plane coefficient vectors. + * @param matrix The matrix to initialze. + * @param vec0 The first vector. + * @param vec1 The second vector. + * @param vec2 The third vector. + */ + template<typename T> + void ViewFrustum::initializeMatrix(Mantid::Kernel::Matrix<T>& matrix, std::vector<T> vec0, std::vector<T> vec1, std::vector<T> vec2) const + { + std::pair<size_t, size_t> size = matrix.size(); + + if (size.first != 3 || size.second != 3) + { + throw std::runtime_error("Matrix for view frustum calculation has the wrong dimensionality."); + } + matrix.setColumn(0, vec0); + matrix.setColumn(1, vec1); + matrix.setColumn(2, vec2); + } +} +} +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp b/Code/Mantid/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0593ae84f507b7bf699f75f1f77f8438ed7d9829 --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp @@ -0,0 +1,95 @@ +#include "MantidVatesAPI/ConcretePeaksPresenterVsi.h" +#include "MantidVatesAPI/ViewFrustum.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include "MantidAPI/AlgorithmManager.h" + +namespace Mantid +{ +namespace VATES +{ + /** + * Constructor + * @param peaksWorkspace The peaks workspace. + */ + ConcretePeaksPresenterVsi::ConcretePeaksPresenterVsi(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace, + ViewFrustum frustum, + std::string frame) : m_viewableRegion(frustum), + m_peaksWorkspace(peaksWorkspace), + m_frame(frame) + { + } + + ///Destructor + ConcretePeaksPresenterVsi::~ConcretePeaksPresenterVsi() + { + } + + /** + * Update the view frustum + */ + void ConcretePeaksPresenterVsi::updateViewFrustum(ViewFrustum frustum) + { + m_viewableRegion = frustum; + } + + /** + * Get the viewable peaks. Essentially copied from the slice viewer. + * @retruns A vector indicating which of the peaks are viewable. + */ + std::vector<bool> ConcretePeaksPresenterVsi::getViewablePeaks() + { + //Need to apply a transform. + // Don't bother to find peaks in the region if there are no peaks to find. + Mantid::API::ITableWorkspace_sptr outTable; + + if (this->m_peaksWorkspace->getNumberPeaks() >= 1) + { + double effectiveRadius = 1e-2; + std::string viewable = m_viewableRegion.toExtentsAsString(); + Mantid::API::IPeaksWorkspace_sptr peaksWS = m_peaksWorkspace; + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("PeaksInRegion"); + alg->setChild(true); + alg->setRethrows(true); + alg->initialize(); + alg->setProperty("InputWorkspace", peaksWS); + alg->setProperty("OutputWorkspace", peaksWS->name() + "_peaks_in_region"); + alg->setProperty("Extents", viewable); + alg->setProperty("CheckPeakExtents", true); + alg->setProperty("PeakRadius", effectiveRadius); + alg->setPropertyValue("CoordinateFrame", m_frame); + alg->execute(); + outTable = alg->getProperty("OutputWorkspace"); + std::vector<bool> viewablePeaks(outTable->rowCount()); + for (size_t i = 0; i < outTable->rowCount(); ++i) { + viewablePeaks[i] = outTable->cell<Mantid::API::Boolean>(i, 1); + } + m_viewablePeaks = viewablePeaks; + } + else{ + // No peaks will be viewable + m_viewablePeaks = std::vector<bool>(); + } + + return m_viewablePeaks; + } + + /** + * Get the underlying peaks workspace + * @returns A pointer to the underlying peaks workspace. + */ + Mantid::API::IPeaksWorkspace_sptr ConcretePeaksPresenterVsi::getPeaksWorkspace() + { + return m_peaksWorkspace; + } + + /** + * Get the frame + * @returns The frame. + */ + std::string ConcretePeaksPresenterVsi::getFrame() + { + return m_frame; + } +} +} \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesAPI/src/ViewFrustum.cpp b/Code/Mantid/Vates/VatesAPI/src/ViewFrustum.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d616e36e38d0ca6e50412c4cae950fc1f1d9cac --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/src/ViewFrustum.cpp @@ -0,0 +1,138 @@ +#include "MantidVatesAPI/ViewFrustum.h" +#include "MantidKernel/Matrix.h" +#include <sstream> +#include <cmath> +#include <cfloat> + +namespace Mantid +{ +namespace VATES +{ + /** + * Represents a view frustum. It contains the parameters for the six plane equations that define the view frustum. Note that the plane + * normals point into the box + * @param leftPlane The left plane. + * @param rightPlane The right plane. + * @param topPlane The top plane. + * @param bottomPlane The bottom plane. + * @param farPlane The far plane. + * @param nearPlane The near plane. + */ + ViewFrustum::ViewFrustum(const LeftPlane leftPlane, const RightPlane rightPlane, const BottomPlane bottomPlane, + const TopPlane topPlane, const FarPlane farPlane, const NearPlane nearPlane) : m_leftPlane(leftPlane), + m_rightPlane(rightPlane), + m_bottomPlane(bottomPlane), + m_topPlane(topPlane), + m_farPlane(farPlane), + m_nearPlane(nearPlane){} + /** + * Copy constructor for the view frustum. + * @param other The initializing view frustum. + */ + ViewFrustum::ViewFrustum(const ViewFrustum& other): m_leftPlane(other.m_leftPlane), + m_rightPlane(other.m_rightPlane), + m_topPlane(other.m_topPlane), + m_bottomPlane(other.m_bottomPlane), + m_farPlane(other.m_farPlane), + m_nearPlane(other.m_nearPlane){} + /// Destructor + ViewFrustum::~ViewFrustum(){} + + /** + * Assignment operator + * @param other The assigned view frustum. + */ + ViewFrustum& ViewFrustum::operator=(const ViewFrustum& other) + { + if (&other != this) + { + m_leftPlane = other.m_leftPlane; + m_rightPlane = other.m_rightPlane; + m_topPlane = other.m_topPlane; + m_bottomPlane = other.m_bottomPlane; + m_farPlane = other.m_farPlane; + m_nearPlane = other.m_nearPlane; + } + + return *this; + } + + /** + * Get the extents of the View frustum. We take the minimal rectangular box which in contains the + * view frustum fully. + * @returns A vector with the extents + */ + std::vector<std::pair<double, double>> ViewFrustum::toExtents() const + { + // Get the eight corner points of the view frustum + std::vector<std::vector<double>> frustumPoints; + frustumPoints.push_back(getIntersectionPointThreePlanes<LEFTPLANE, TOPPLANE, FARPLANE, double>(m_leftPlane, m_topPlane, m_farPlane)); + frustumPoints.push_back(getIntersectionPointThreePlanes<LEFTPLANE, TOPPLANE, NEARPLANE, double>(m_leftPlane, m_topPlane, m_nearPlane)); + + frustumPoints.push_back(getIntersectionPointThreePlanes<LEFTPLANE, BOTTOMPLANE, FARPLANE, double>(m_leftPlane, m_bottomPlane, m_farPlane)); + frustumPoints.push_back(getIntersectionPointThreePlanes<LEFTPLANE, BOTTOMPLANE, NEARPLANE, double>(m_leftPlane, m_bottomPlane, m_nearPlane)); + + frustumPoints.push_back(getIntersectionPointThreePlanes<RIGHTPLANE, TOPPLANE, FARPLANE, double>(m_rightPlane, m_topPlane, m_farPlane)); + frustumPoints.push_back(getIntersectionPointThreePlanes<RIGHTPLANE, TOPPLANE, NEARPLANE, double>(m_rightPlane, m_topPlane, m_nearPlane)); + + frustumPoints.push_back(getIntersectionPointThreePlanes<RIGHTPLANE, BOTTOMPLANE, FARPLANE, double>(m_rightPlane, m_bottomPlane, m_farPlane)); + frustumPoints.push_back(getIntersectionPointThreePlanes<RIGHTPLANE, BOTTOMPLANE, NEARPLANE, double>(m_rightPlane, m_bottomPlane, m_nearPlane)); + + std::vector<std::pair<double, double>> extents; + + for (int i = 0; i < 3; ++i) + { + std::pair<double, double> minMax(DBL_MAX, -DBL_MAX); + for (std::vector<std::vector<double>>::iterator it = frustumPoints.begin(); it != frustumPoints.end(); ++it) + { + if ((*it)[i] < minMax.first) + { + minMax.first = (*it)[i]; + } + + if ((*it)[i] > minMax.second) + { + minMax.second = (*it)[i]; + } + } + + extents.push_back(minMax); + } + + return extents; + } + + /** + * Get the extents as a concatenated string. + * @returns The extens of the view frustum as a concatenated string + */ + std::string ViewFrustum::toExtentsAsString() const + { + std::vector<std::pair<double, double>> extents = toExtents(); + + std::stringstream ss; + + for (std::vector<std::pair<double, double>>::iterator it = extents.begin(); it != extents.end(); ++it) + { + ss << it->first << "," << it->second; + + if ((it+1)!= extents.end()) + { + ss << ","; + } + } + + return ss.str(); + } + + /** + * Check if point lies in view frustum + * @param point A point to be checked. + * @returns If the point is inside the view frustum + */ + bool ViewFrustum::pointLiesInsideViewFrustum(std::vector<double> point) const + { + return true; + } +} +} diff --git a/Code/Mantid/Vates/VatesAPI/test/ViewFrustumTest.h b/Code/Mantid/Vates/VatesAPI/test/ViewFrustumTest.h new file mode 100644 index 0000000000000000000000000000000000000000..e4f2357e2d4963f0fb31a93563ea840d9fd19702 --- /dev/null +++ b/Code/Mantid/Vates/VatesAPI/test/ViewFrustumTest.h @@ -0,0 +1,91 @@ +#ifndef VIEWFRUSTUM_TEST_H_ +#define VIEWFRUSTUM_TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidVatesAPI/ViewFrustum.h" + +using namespace Mantid::VATES; + +class ViewFrustumTest: public CxxTest::TestSuite +{ +public: + void testThatExtentsAreFoundForStandardFrustum() + { + // Arrange + // Create a standard cube + LeftPlane left(1.0, 0.0, 0.0, 1.0); + RightPlane right(-1.0, 0.0, 0.0, 1.0); + + BottomPlane bottom(0.0, 1.0, 0.0, 1.0); + TopPlane top(0.0, -1.0, 0.0, 1.0); + + FarPlane far(0.0, 0.0, 1.0, 1.0); + NearPlane near(0.0, 0.0, -1.0,1.0); + + ViewFrustum frustum(left, right, bottom, top, far, near); + + //Act + std::vector<std::pair<double, double>> extents; + TSM_ASSERT_THROWS_NOTHING("Frustum is well defined, should not throw.", extents = frustum.toExtents()); + + //Assert + TSM_ASSERT_EQUALS("Extents should exist for x, y and z.", 3, extents.size()); + TSM_ASSERT_EQUALS("Frustum is well defined and should have xmin = -1", -1.0, extents[0].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have xmax = 1", 1.0, extents[0].second); + TSM_ASSERT_EQUALS("Frustum is well defined and should have ymin = -1", -1.0, extents[1].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have ymin = -1", 1.0, extents[1].second); + TSM_ASSERT_EQUALS("Frustum is well defined and should have zmin = -1", -1.0, extents[2].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have zmax = 1", 1.0, extents[2].second); + } + + void testThatExtentsAreFoundForFrustumWithRotation() + { + // Arrange + // Create skewed cube + LeftPlane left(1.0, -0.5, 0.0, 1.0); + RightPlane right(-1.0, 0.5, 0.0, 1.0); + + BottomPlane bottom(1.0, 0.5, 0.0, 1.0); + TopPlane top(-1.0, -0.5, 0.0, 1.0); + + FarPlane far(0.0, 0.0, 1.0, 1.0); + NearPlane near(0.0, 0.0, -1.0,1.0); + + ViewFrustum frustum(left, right, bottom, top, far, near); + + //Act + std::vector<std::pair<double, double>> extents; + TSM_ASSERT_THROWS_NOTHING("Frustum is well defined, should not throw.", extents = frustum.toExtents()); + + //Assert + TSM_ASSERT_EQUALS("Extents should exist for x, y and z.", 3, extents.size()); + TSM_ASSERT_EQUALS("Frustum is well defined and should have xmin = -1", -1.0, extents[0].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have xmax = 1", 1.0, extents[0].second); + TSM_ASSERT_EQUALS("Frustum is well defined and should have ymin = -1", -2.0, extents[1].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have ymin = -1", 2.0, extents[1].second); + TSM_ASSERT_EQUALS("Frustum is well defined and should have zmin = -1", -1.0, extents[2].first); + TSM_ASSERT_EQUALS("Frustum is well defined and should have zmax = 1", 1.0, extents[2].second); + } + + void testThatWrongPlanesThrowErrors() + { + // Arrange + // Just have one plane type. This should fail the calculation of intersection points + LeftPlane left(1.0, -0.5, 0.0, 1.0); + RightPlane right(1.0, -0.5, 0.0, 1.0); + + BottomPlane bottom(1.0, -0.5, 0.0, 1.0); + TopPlane top(1.0, -0.5, 0.0, 1.0); + + FarPlane far(1.0, -0.5, 0.0, 1.0); + NearPlane near(1.0, -0.5, 0.0, 1.0); + + ViewFrustum frustum(left, right, bottom, top, far, near); + + //Assert + TSM_ASSERT_THROWS("Frustum is not well defined, should throw error",frustum.toExtents(), std::runtime_error); + } + +}; + +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/CMakeLists.txt b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/CMakeLists.txt index 13afb6111864845f72cb36b3ce2b18065696762b..aea880cc132526859ef9ef2e76742f32836b4388 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/CMakeLists.txt +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/CMakeLists.txt @@ -9,6 +9,8 @@ set( INCLUDE_FILES inc/MantidVatesSimpleGuiViewWidgets/LibHelper.h inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h + inc/MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h + inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h inc/MantidVatesSimpleGuiViewWidgets/SaveScreenshotReaction.h inc/MantidVatesSimpleGuiViewWidgets/StandardView.h inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h @@ -25,6 +27,8 @@ set( SOURCE_FILES src/ColorUpdater.cpp src/MdViewerWidget.cpp src/MultisliceView.cpp + src/PeakViewerVsi.cpp + src/PeaksWidget.cpp src/SaveScreenshotReaction.cpp src/StandardView.cpp src/SplatterPlotView.cpp @@ -39,6 +43,8 @@ qt4_wrap_cpp( MOC_SOURCES inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.h inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h + inc/MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h + inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h inc/MantidVatesSimpleGuiViewWidgets/SaveScreenshotReaction.h inc/MantidVatesSimpleGuiViewWidgets/StandardView.h inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h @@ -53,6 +59,7 @@ qt4_wrap_ui( UI_BUILT_SOURCES inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.ui inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.ui inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.ui + inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.ui inc/MantidVatesSimpleGuiViewWidgets/StandardView.ui inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui inc/MantidVatesSimpleGuiViewWidgets/ThreesliceView.ui diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/CameraManager.h b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/CameraManager.h index a9065ac7561b591fa4bc066af262b5ad44e0c05a..9f0c5f9cdba1f3738e983b1ec7b3e91e874db78e 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/CameraManager.h +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/CameraManager.h @@ -2,7 +2,7 @@ #define CAMERAMANAGER_H_ #include "MantidVatesSimpleGuiViewWidgets/WidgetDllOption.h" - +#include "MantidVatesAPI/ViewFrustum.h" namespace Mantid { @@ -44,13 +44,10 @@ public: CameraManager(); ~CameraManager(); + + Mantid::VATES::ViewFrustum getCurrentViewFrustum(); - void getCurrentViewFrustum(double left[4], - double right[4], - double bottom[4], - double top[4], - double far[4], - double near[4]); + void setCameraToPeak(double xpos, double ypos, double zpos, double peakRadius); }; } diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h new file mode 100644 index 0000000000000000000000000000000000000000..8068370c28830986b321c5f2071b6592aad8dba4 --- /dev/null +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h @@ -0,0 +1,54 @@ +#ifndef PEAKSVIEWERVSI_H_ +#define PEAKSVIEWERVSI_H_ + +#include "MantidVatesSimpleGuiViewWidgets/WidgetDllOption.h" +#include "MantidVatesSimpleGuiViewWidgets/CameraManager.h" +#include "MantidVatesSimpleGuiViewWidgets/PeaksWidget.h" +#include "MantidVatesAPI/PeaksPresenterVsi.h" +#include "MantidAPI/PeakTransformSelector.h" +#include "MantidGeometry/Crystal/PeakShape.h" +#include <QWidget> +#include <QPointer> +#include <boost/shared_ptr.hpp> + +class pqPipelineSource; + +namespace Mantid +{ +namespace Vates +{ +namespace SimpleGui +{ +class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeaksViewerVsi : public QWidget +{ + Q_OBJECT +public: + PeaksViewerVsi(boost::shared_ptr<CameraManager> cameraManager, QWidget *parent=0); + void addWorkspace(pqPipelineSource* source, QPointer<pqPipelineSource> splatSource); + std::vector<bool> getViewablePeaks(); + bool hasPeaks(); + void showTable(); + void showFullTable(); + void removeTable(); + +public slots: + void updateViewableArea(); + void onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace, int row); + +private: + std::vector<std::string> extractFrameFromSource(QPointer<pqPipelineSource> splatSource); + bool checkMatchingSources(pqPipelineSource* source, QPointer<pqPipelineSource> splatSource); + double getMaxRadius(Mantid::Geometry::PeakShape_sptr shape); + void removeLayout(QWidget *widget); + void createTable(bool full); + boost::shared_ptr<CameraManager> m_cameraManager; + boost::shared_ptr<Mantid::VATES::PeaksPresenterVsi> m_presenter; + /// Object for choosing a PeakTransformFactory based on the workspace type. + Mantid::API::PeakTransformSelector m_peakTransformSelector; + PeaksWidget* m_peaksWidget; +}; + +} +} +} +#endif \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..c91ccd6115555b662d9f430a2221b9789cfd2e44 --- /dev/null +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h @@ -0,0 +1,40 @@ +#ifndef VSI_PEAKSWORKWIDGET_H +#define VSI_PEAKSWORKWIDGET_H + +#include "ui_PeaksWidget.h" +#include "MantidVatesSimpleGuiViewWidgets/WidgetDllOption.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include <QWidget> +#include <string> + +namespace Mantid +{ +namespace Vates +{ +namespace SimpleGui +{ + class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeaksWidget : public QWidget + { + Q_OBJECT + public: + PeaksWidget(Mantid::API::IPeaksWorkspace_sptr ws, const std::string& coordinateSystem, QWidget *parent = 0); + void PeaksWidget::setupMvc(std::vector<bool> visiblePeaks); + signals: + void zoomToPeak(Mantid::API::IPeaksWorkspace_sptr ws, int row); + public slots: + void onCurrentChanged(QModelIndex current, QModelIndex); + private: + /// Auto-generated UI controls. + Ui::PeaksWidget ui; + /// Peaks workspace to view. + Mantid::API::IPeaksWorkspace_sptr m_ws; + /// Coordinate system. + const std::string m_coordinateSystem; + /// Table width + int m_originalTableWidth; + }; + +} //namespace +} +} +#endif // PEAKSWORKSPACEWIDGET_H diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.ui b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..30cda706d49267577363d2c0aba906d84916739e --- /dev/null +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.ui @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PeaksWidget</class> + <widget class="QWidget" name="PeaksWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>474</width> + <height>156</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="1"> + <item> + <layout class="QHBoxLayout" name="tableLayout"> + <item> + <widget class="QTableView" name="tblPeaks"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderStretchLastSection"> + <bool>false</bool> + </attribute> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h index ab87a452167b85488870518caaec09b9d0ca2eb9..3092be898e717666b54c98e61a2fa17aca609f35 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h @@ -4,11 +4,15 @@ #include "ui_SplatterPlotView.h" #include "MantidVatesSimpleGuiViewWidgets/ViewBase.h" #include "MantidVatesSimpleGuiViewWidgets/WidgetDllOption.h" +#include "MantidVatesSimpleGuiViewWidgets/CameraManager.h" +#include "MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h" +#include <boost/shared_ptr.hpp> #include <QList> #include <QPointer> class QWidget; +class QAction; class pqPipelineRepresentation; class pqPipelineSource; @@ -95,6 +99,12 @@ signals: public slots: /// Check the coordinates for the peaks overlay if necessary void checkPeaksCoordinates(); + /// Show the visible peaks table. + void onShowVisiblePeaksTable(); + /// Remove the visible peaks table. + void onRemoveVisiblePeaksTable(); + /// Show all peaks in table. + void onShowAllPeaksTable(); protected slots: /// Check state of toggle button with respect to peak coordinates. @@ -117,6 +127,8 @@ private: bool eventFilter(QObject *obj, QEvent *ev); /// Read the coordinates and send to service. void readAndSendCoordinates(); + /// Setup the buttons for the visible peaks + void setupVisiblePeaksButtons(); bool noOverlay; ///< Flag to respond to overlay situation correctly QList<QPointer<pqPipelineSource> > peaksSource; ///< A list of peaks sources @@ -126,6 +138,11 @@ private: QPointer<pqPipelineSource> threshSource; ///< The thresholding filter source Ui::SplatterPlotView ui; ///< The splatter plot view'a UI form QPointer<pqRenderView> view; ///< The main view area + boost::shared_ptr<CameraManager> m_cameraManager; ///< The camera manager + PeaksViewerVsi* m_peaksViewer; ///< The peaks presenter + QAction* m_allPeaksAction;///<The action for showing all peaks in the table. + QAction* m_removePeaksAction; ///<The action for removing the peaks table. + QAction* m_visiblePeaksAction; ///<The action for adding the visible peaks table. }; } // SimpleGui diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui index d7b47a221a77f5d58bd8f8cdc523872f972a9e9a..c36e32e40d181d8268f5a8960213a1ab1c1c3171 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui @@ -59,6 +59,28 @@ </property> </widget> </item> + <item> + <widget class="QToolButton" name="peaksButton"> + <property name="minimumSize"> + <size> + <width>75</width> + <height>23</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Peaks</string> + </property> + <property name="arrowType"> + <enum>Qt::NoArrow</enum> + </property> + </widget> + </item> <item> <spacer name="horizontalSpacer_2"> <property name="orientation"> @@ -96,6 +118,9 @@ </property> </widget> </item> + <item> + <layout class="QHBoxLayout" name="tableLayout"/> + </item> </layout> </widget> <resources/> diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp index 375be604a1242bc74220d21223e4e0b77cffe44b..616eddaf2c20180b15204937945d3c0374b3421c 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp @@ -1,5 +1,6 @@ #include "MantidVatesSimpleGuiViewWidgets/CameraManager.h" - +#include "MantidVatesAPI/ViewFrustum.h" +#include <stdexcept> // Have to deal with ParaView warnings and Intel compiler the hard way. #if defined(__INTEL_COMPILER) #pragma warning disable 1170 @@ -10,6 +11,7 @@ #include <vtkSMRenderViewProxy.h> #include <vtkCamera.h> #include <vtkRenderer.h> +#include <vtkRenderWindow.h> namespace Mantid { @@ -24,14 +26,24 @@ namespace Mantid CameraManager::~CameraManager() { } - - void CameraManager::getCurrentViewFrustum(double left[4], - double right[4], - double bottom[4], - double top[4], - double far[4], - double near[4]) + /** + * Get the plane equation for the view frustum. + * @param left The left plane. + * @param right The right plane. + * @param bottom The bottom plane. + * @param top The top plane. + * @param far The far plane. + * @param near The near plane. + */ + Mantid::VATES::ViewFrustum CameraManager::getCurrentViewFrustum() { + double left[4]; + double right[4]; + double bottom[4]; + double top[4]; + double far[4]; + double near[4]; + pqView * view = pqActiveView::instance().current(); vtkSMRenderViewProxy* proxy = NULL; @@ -44,29 +56,26 @@ namespace Mantid if (!proxy) { // no active view, or active view is not a render view. - return; + throw std::invalid_argument("Invalid vtkSMRenderViewProxy."); } // Get the aspect ratio of the renderer - vtkRenderer* renderer = proxy->GetRenderer(); if (!renderer) { - return; + throw std::invalid_argument("Invalid vtkRenderer."); } double aspectDimensions[2]; renderer->GetAspect(aspectDimensions); - double aspectRatio = aspectDimensions[0]/aspectDimensions[1]; - // Get the active camera vtkCamera* camera = proxy->GetActiveCamera(); if (!camera) { - return; + throw std::invalid_argument("Invalid vtkCamera."); } double planes[24]; @@ -80,9 +89,57 @@ namespace Mantid bottom[k] = planes[k + 8]; top[k] = planes[k + 12]; - far[k] = planes[k + 16]; - near[k] = planes[k + 20]; + near[k] = planes[k + 16]; + far[k] = planes[k + 20]; + } + Mantid::VATES::ViewFrustum frustum(Mantid::VATES::LeftPlane(left[0], left[1], left[2], left[3]), + Mantid::VATES::RightPlane(right[0], right[1], right[2], right[3]), + Mantid::VATES::BottomPlane(bottom[0], bottom[1], bottom[2], bottom[3]), + Mantid::VATES::TopPlane(top[0], top[1], top[2], top[3]), + Mantid::VATES::FarPlane(far[0], far[1], far[2], far[3]), + Mantid::VATES::NearPlane(near[0], near[1], near[2], near[3])); + + return frustum; + } + + /** + * Set the view onto a peak + * @param xpos X position of the peak. + * @param ypos Y position of the peak. + * @param zpos Z position of the peak. + * @param peakRadius The radius of the peak. + */ + void CameraManager::setCameraToPeak(double xpos, double ypos, double zpos, double peakRadius) + { + pqView * view = pqActiveView::instance().current(); + vtkSMRenderViewProxy* proxy = NULL; + + if (view) + { + proxy = vtkSMRenderViewProxy::SafeDownCast(view->getViewProxy()); + } + + if (!proxy) + { + // no active view, or active view is not a render view. + throw std::invalid_argument("Invalid vtkSMRenderViewProxy."); } + + // Get the active camera + vtkCamera* camera = proxy->GetActiveCamera(); + + // Setup the focal point of the camera. we want this to be on the peak + camera->SetFocalPoint(xpos, ypos, zpos); + + // Setup the depth of the view + camera->SetClippingRange(0.1, 1.0); + + // Setup the position of the camera. We want this to be + double zposCamera = zpos + peakRadius; + camera->SetPosition(xpos, ypos, zposCamera); + camera->SetViewUp(0.0, 1.0, 0.0); + + view->forceRender(); } } } diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeakViewerVsi.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeakViewerVsi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4f115b734336f902f8415470e02e370ee6376b4 --- /dev/null +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeakViewerVsi.cpp @@ -0,0 +1,360 @@ +#include "MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h" +#include "MantidVatesSimpleGuiViewWidgets/PeaksWidget.h" +#include "MantidVatesSimpleGuiViewWidgets/CameraManager.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include "MantidAPI/IMDEventWorkspace.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/PeakTransformHKL.h" +#include "MantidAPI/PeakTransformQSample.h" +#include "MantidAPI/PeakTransformQLab.h" +#include "MantidAPI/IPeak.h" +#include "MantidKernel/V3D.h" +#include "MantidDataObjects/NoShape.h" +#include "MantidDataObjects/PeakShapeSpherical.h" +#include "MantidDataObjects/PeakShapeEllipsoid.h" +#include "MantidKernel/SpecialCoordinateSystem.h" +#include "MantidVatesAPI/PeaksPresenterVsi.h" +#include "MantidVatesAPI/NullPeaksPresenterVsi.h" +#include "MantidVatesAPI/ConcretePeaksPresenterVsi.h" +#include "MantidQtAPI/PlotAxis.h" +#include "MantidGeometry/MDGeometry/IMDDimension.h" +#include "MantidGeometry/Crystal/PeakShape.h" + +#include <boost/make_shared.hpp> +#include <boost/shared_ptr.hpp> +#include <stdexcept> +#include <algorithm> + +// Have to deal with ParaView warnings and Intel compiler the hard way. +#if defined(__INTEL_COMPILER) + #pragma warning disable 1170 +#endif + +#include <vtkSMPropertyHelper.h> +#include <pqPipelineSource.h> +#include <pqPipelineFilter.h> + +#include <QString> +#include <QPointer> +#include <QVBoxLayout> +#include <QLayout> +#include <QLayoutItem> + +namespace Mantid +{ +namespace Vates +{ +namespace SimpleGui +{ + /** + * Constructor + * @param cameraManager A cameraManager pointer. + * @param parent A pointer to a QWidget parent. + */ + PeaksViewerVsi::PeaksViewerVsi(boost::shared_ptr<CameraManager> cameraManager, QWidget *parent) : QWidget(parent), + m_cameraManager(cameraManager), + m_presenter(new Mantid::VATES::NullPeaksPresenterVsi()), + m_peaksWidget(NULL) + { + m_peakTransformSelector.registerCandidate(boost::make_shared<Mantid::API::PeakTransformHKLFactory>()); + m_peakTransformSelector.registerCandidate(boost::make_shared<Mantid::API::PeakTransformQSampleFactory>()); + m_peakTransformSelector.registerCandidate(boost::make_shared<Mantid::API::PeakTransformQLabFactory>()); + } + + /** + * Check for viewable peaks. + * @returns A vector of the peak indices which are visible and which are not visible. + */ + std::vector<bool> PeaksViewerVsi::getViewablePeaks() + { + std::vector<bool> viewablePeaks; + if (m_presenter) + { + // Get the up to date area + updateViewableArea(); + + //Get a list with viewable peak coordinates + viewablePeaks = m_presenter->getViewablePeaks(); + } + return viewablePeaks; + } + + /** + * Add a new workspace + * @param source A new peaks source + * @param splatSource A pointer to the splatter source + */ + void PeaksViewerVsi::addWorkspace(pqPipelineSource* source, QPointer<pqPipelineSource> splatSource) + { + if (!source || !splatSource) + { + throw std::invalid_argument("The pqPipelineSource of the peaks workspace does not exist."); + } + + // Get the pointer to the peaks workspace + std::string wsName(vtkSMPropertyHelper(source->getProxy(), "WorkspaceName", true).GetAsString()); + std::string peaksFrame(vtkSMPropertyHelper(source->getProxy(), "Peak Dimensions", true).GetAsString()); + + // Get dimensions from splattersource + std::vector<std::string> dimInfo = extractFrameFromSource(splatSource); + if (dimInfo.size() < 2) + { + throw std::invalid_argument("The workspace needs to have at least two dimensions"); + } + + std::string dimCompare = dimInfo[0]; + std::transform(dimCompare.begin(), dimCompare.end(),dimCompare.begin(), ::toupper); + std::transform(peaksFrame.begin(), peaksFrame.end(),peaksFrame.begin(), ::toupper); + // Check if frames match + if (dimCompare.find(peaksFrame) == std::string::npos) + { + throw std::runtime_error("The workspaces don't match"); + } + + Mantid::API::IPeaksWorkspace_sptr peaksWorkspace; + try + { + peaksWorkspace = Mantid::API::AnalysisDataService::Instance().retrieveWS<Mantid::API::IPeaksWorkspace>(wsName); + } + catch(Mantid::Kernel::Exception::NotFoundError&) + { + throw std::invalid_argument("The peaks workspace cannot be retrieved."); + } + + std::string frame; + try + { + Mantid::API::PeakTransformFactory_sptr transformFactory = m_peakTransformSelector.makeChoice(dimInfo[0], dimInfo[1]); + Mantid::API::PeakTransform_sptr transform = transformFactory->createTransform(dimInfo[0], dimInfo[1]); + frame = transform->getFriendlyName(); + } catch (std::invalid_argument &ex) { + throw std::invalid_argument("Couldn't create the transform factory"); + } + + m_presenter = boost::make_shared<Mantid::VATES::ConcretePeaksPresenterVsi>(peaksWorkspace, m_cameraManager->getCurrentViewFrustum(), frame); + } + + /** + * Update the view region for the presenters + */ + void PeaksViewerVsi::updateViewableArea() + { + Mantid::VATES::ViewFrustum frustum = m_cameraManager->getCurrentViewFrustum(); + m_presenter->updateViewFrustum(frustum); + } + + /** + * Extrac the frame from the source + * @param splatSource A pointer to a splatter plot source. + */ + std::vector<std::string> PeaksViewerVsi::extractFrameFromSource(QPointer<pqPipelineSource> splatSource) + { + pqPipelineFilter* filter = qobject_cast<pqPipelineFilter*>(splatSource); + + if (!filter) + { + throw std::invalid_argument("The splatter source is not a filter"); + } + + pqPipelineSource* originalSource = filter->getInput(0); + + if (!originalSource) + { + throw std::invalid_argument("The original source cannot be found"); + } + + std::string wsName(vtkSMPropertyHelper(originalSource->getProxy(), "WorkspaceName", true).GetAsString()); + Mantid::API::IMDEventWorkspace_sptr eventWorkspace = Mantid::API::AnalysisDataService::Instance().retrieveWS<Mantid::API::IMDEventWorkspace>(wsName); + + std::vector<std::string> dimensionInfo; + for (size_t i = 0; i < eventWorkspace->getNumDims(); i++) + { + dimensionInfo.push_back(MantidQt::API::PlotAxis(*(eventWorkspace->getDimension(i))).title().toStdString()); + } + + return dimensionInfo; + } + + /** + * Check if the peaks viewer has a peaks workspace loaded. + * @returns If the a peaks workspace is loaded. + */ + bool PeaksViewerVsi::hasPeaks() + { + if (!m_presenter) + { + return false; + } + else if (boost::dynamic_pointer_cast<Mantid::VATES::NullPeaksPresenterVsi>(m_presenter)) + { + return false; + } + else + { + return true; + } + } + + /** + * Show the table with the visible peaks + */ + void PeaksViewerVsi::showTable() + { + createTable(false); + } + + /** + * Show all peaks in the table. + */ + void PeaksViewerVsi::showFullTable() + { + createTable(true); + } + + /** + * Create the table + * @param full If the full table is to be displayed or only visible peaks. + */ + void PeaksViewerVsi::createTable(bool full) + { + // Create the table if it does not exist + if (hasPeaks()) + { + if (layout()) + { + removeLayout(this); + } + + this->setLayout(new QVBoxLayout); + + // Create new widget + PeaksWidget* widget = new PeaksWidget(m_presenter->getPeaksWorkspace(), m_presenter->getFrame(), this); + QObject::connect(widget, SIGNAL(zoomToPeak(Mantid::API::IPeaksWorkspace_sptr, int)), + this, SLOT(onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr, int))); + + // Initialize the viewablePeaks to be true + std::vector<bool> viewablePeaks(m_presenter->getPeaksWorkspace()->getNumberPeaks(),true); + + if (!full) + { + try + { + viewablePeaks = getViewablePeaks(); + } catch (...) + { + // Log + } + } + + widget->setupMvc(viewablePeaks); + layout()->addWidget(widget); + } + } + + /** + * Remove the layout + * @param widget + */ + void PeaksViewerVsi::removeLayout(QWidget *widget) { + QLayout *layout = widget->layout(); + if (layout != 0) { + QLayoutItem *item; + while ((item = layout->takeAt(0)) != 0){ + layout->removeItem(item); + delete item->widget(); + } + delete layout; + } + } + + /** + * Remvove the table. + */ + void PeaksViewerVsi::removeTable() + { + if (layout()) { + removeLayout(this); + } + } + + /** + * Zoom to a specific peak + * @param peaksWorkspace The peaksworkspace which is currently being displayed. + * @param row The selected row. + */ + void PeaksViewerVsi::onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace, int row) + { + // Extract the position + Mantid::Kernel::SpecialCoordinateSystem coordinateSystem = peaksWorkspace->getSpecialCoordinateSystem(); + + Mantid::Kernel::V3D position; + switch(coordinateSystem) + { + case(Mantid::Kernel::SpecialCoordinateSystem::QLab): + position = peaksWorkspace->getPeak(row).getQLabFrame(); + break; + case(Mantid::Kernel::SpecialCoordinateSystem::QSample): + position = peaksWorkspace->getPeak(row).getQSampleFrame(); + break; + case(Mantid::Kernel::SpecialCoordinateSystem::HKL): + position = peaksWorkspace->getPeak(row).getHKL(); + break; + default: + return; + } + + // Peak radius + Mantid::Geometry::PeakShape_sptr shape(peaksWorkspace->getPeakPtr(row)->getPeakShape().clone()); + double maxRadius = getMaxRadius(shape); + + // Peak position + double xpos = position[0]; + double ypos = position[1]; + double zpos = position[2]; + + // Direction + + + // Reset camera + m_cameraManager->setCameraToPeak(xpos, ypos, zpos, maxRadius); + } + + /** + * Get the maximal radius + * @param shape The shape of a peak. + * @param The maximal radius of the peak. + */ + double PeaksViewerVsi::getMaxRadius(Mantid::Geometry::PeakShape_sptr shape) + { + boost::shared_ptr<Mantid::DataObjects::NoShape> nullShape = boost::dynamic_pointer_cast<Mantid::DataObjects::NoShape>(shape); + boost::shared_ptr<Mantid::DataObjects::PeakShapeEllipsoid> ellipsoidShape = boost::dynamic_pointer_cast<Mantid::DataObjects::PeakShapeEllipsoid>(shape); + boost::shared_ptr<Mantid::DataObjects::PeakShapeSpherical> sphericalShape = boost::dynamic_pointer_cast<Mantid::DataObjects::PeakShapeSpherical>(shape); + + if (nullShape) + { + return 0; + } + else if (ellipsoidShape) + { + std::vector<double> radius = ellipsoidShape->abcRadiiBackgroundOuter(); + return *(std::max_element(radius.begin(),radius.end())); + } + else if (sphericalShape) + { + if (boost::optional<double> radius = sphericalShape->backgroundOuterRadius()) + { + return *radius; + } + else + { + return 0; + } + } + else + { + return 0; + } + } +} +} +} \ No newline at end of file diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e66af49ae62eda364173ec09f911cc531f2a69f5 --- /dev/null +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp @@ -0,0 +1,82 @@ +#include "MantidVatesSimpleGuiViewWidgets/PeaksWidget.h" +#include "MantidAPI/IPeaksWorkspace.h" +#include "MantidQtSliceViewer/QPeaksTableModel.h" +#include <QWidget> +#include <QItemSelectionModel> +#include <QModelIndex> + +namespace Mantid +{ +namespace Vates +{ +namespace SimpleGui +{ +/** +Constructor + +@param ws : Peaks Workspace (MODEL) +@param coordinateSystem : Name of coordinate system used +@param parent : parent widget +*/ +PeaksWidget::PeaksWidget(Mantid::API::IPeaksWorkspace_sptr ws, const std::string &coordinateSystem, QWidget *parent) : QWidget(parent), m_ws(ws), m_coordinateSystem(coordinateSystem){ + ui.setupUi(this); +} + +/** + * Setup the Table model + * @param visiblePeaks : A list of visible peaks + */ +void PeaksWidget::setupMvc(std::vector<bool> visiblePeaks) +{ + MantidQt::SliceViewer::QPeaksTableModel* model = new MantidQt::SliceViewer::QPeaksTableModel(this->m_ws); + ui.tblPeaks->setModel(model); + const std::vector<int> hideCols = model->defaultHideCols(); + for (auto it = hideCols.begin(); it != hideCols.end(); ++it) + ui.tblPeaks->setColumnHidden(*it, true); + ui.tblPeaks->verticalHeader()->setResizeMode(QHeaderView::Interactive); + ui.tblPeaks->horizontalHeader()->setResizeMode(QHeaderView::Interactive); + m_originalTableWidth = ui.tblPeaks->horizontalHeader()->length(); + // calculate the average width (in pixels) of numbers + QString allNums("0123456789"); + double char_width = + static_cast<double>( + ui.tblPeaks->fontMetrics().boundingRect(allNums).width()) / + static_cast<double>(allNums.size()); + // set the starting width of each column + for (int i = 0; i < m_originalTableWidth; ++i) { + double width = + static_cast<double>(model->numCharacters(i) + 3) * char_width; + ui.tblPeaks->horizontalHeader()->resizeSection(i, static_cast<int>(width)); + } + + // Hide the rows which are invisible + for (int i = 0; i < ui.tblPeaks->model()->rowCount(); i++) + { + if (visiblePeaks[i]) + { + ui.tblPeaks->showRow(i); + } + else + { + ui.tblPeaks->hideRow(i); + } + } + + QItemSelectionModel* selectionModel = ui.tblPeaks->selectionModel(); + connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(onCurrentChanged(QModelIndex, QModelIndex))); +} + +/** + * Detects a newly selectedd peaks workspace. + * @param current The currently selected index. + */ +void PeaksWidget::onCurrentChanged(QModelIndex current, QModelIndex) +{ + if (current.isValid()) + { + emit zoomToPeak(this->m_ws, current.row()); + } +} +} // namespace +} +} diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp index 08a110a003a22ac313df0fadc1c0fb450b837fc5..65c0256178a0d70f48015eeee0a3755049046a5b 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp @@ -1,9 +1,13 @@ #include "MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h" - +#include "MantidVatesSimpleGuiViewWidgets/CameraManager.h" +#include "MantidVatesSimpleGuiViewWidgets/PeakViewerVsi.h" #include "MantidAPI/IMDEventWorkspace.h" #include "MantidQtAPI/SelectionNotificationService.h" #include "MantidVatesAPI/ADSWorkspaceProvider.h" #include "MantidVatesAPI/vtkPeakMarkerFactory.h" +#include "MantidVatesAPI/ViewFrustum.h" +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> // Have to deal with ParaView warnings and Intel compiler the hard way. #if defined(__INTEL_COMPILER) @@ -30,6 +34,9 @@ #include <QKeyEvent> #include <QMessageBox> +#include <QToolButton> +#include <QMenu> +#include <QAction> using namespace MantidQt::API; using namespace Mantid::VATES; @@ -41,11 +48,19 @@ namespace Vates namespace SimpleGui { -SplatterPlotView::SplatterPlotView(QWidget *parent) : ViewBase(parent) +SplatterPlotView::SplatterPlotView(QWidget *parent) : ViewBase(parent), + m_cameraManager(boost::make_shared<CameraManager>()), + m_peaksViewer(NULL) + { this->noOverlay = false; this->ui.setupUi(this); + m_peaksViewer = new PeaksViewerVsi(m_cameraManager, this); + this->ui.tableLayout->addWidget(m_peaksViewer); + m_peaksViewer->setVisible(true); + + // Set the threshold button to create a threshold filter on data QObject::connect(this->ui.thresholdButton, SIGNAL(clicked()), this, SLOT(onThresholdButtonClicked())); @@ -64,6 +79,9 @@ SplatterPlotView::SplatterPlotView(QWidget *parent) : ViewBase(parent) this->view = this->createRenderView(this->ui.renderFrame); this->installEventFilter(this); + + setupVisiblePeaksButtons(); + } SplatterPlotView::~SplatterPlotView() @@ -190,6 +208,20 @@ void SplatterPlotView::render() { this->renderAll(); } + + // Add peaksSource to peaksViewer, currently only one + if (isPeaksWorkspace) + { + try + { + m_peaksViewer->addWorkspace(src, this->splatSource); + } + catch (...) + { + // Log the error + } + } + emit this->triggerAccept(); } @@ -344,6 +376,76 @@ void SplatterPlotView::readAndSendCoordinates() } } +/** + * Set up the buttons for the visible peaks. + */ +void SplatterPlotView::setupVisiblePeaksButtons() +{ + // Populate the rebin button + QMenu* peaksMenu = new QMenu(this->ui.peaksButton); + + m_allPeaksAction = new QAction("Show all peaks in table", peaksMenu); + m_allPeaksAction->setIconVisibleInMenu(false); + + m_visiblePeaksAction = new QAction("Show visible peaks in table", peaksMenu); + m_visiblePeaksAction->setIconVisibleInMenu(false); + + m_removePeaksAction = new QAction("Remove table", peaksMenu); + m_removePeaksAction->setIconVisibleInMenu(false); + + peaksMenu->addAction(m_allPeaksAction); + peaksMenu->addAction(m_visiblePeaksAction); + peaksMenu->addAction(m_removePeaksAction); + + this->ui.peaksButton->setPopupMode(QToolButton::InstantPopup); + this->ui.peaksButton->setMenu(peaksMenu); + + QObject::connect(m_allPeaksAction, SIGNAL(triggered()), + this, SLOT(onShowAllPeaksTable()), Qt::QueuedConnection); + + QObject::connect(m_visiblePeaksAction, SIGNAL(triggered()), + this, SLOT(onShowVisiblePeaksTable()), Qt::QueuedConnection); + + QObject::connect(m_removePeaksAction, SIGNAL(triggered()), + this, SLOT(onRemoveVisiblePeaksTable()), Qt::QueuedConnection); +} + +/** + * Show the visible peaks table. + */ +void SplatterPlotView::onShowVisiblePeaksTable() +{ + if (m_peaksViewer->hasPeaks()) + { + m_peaksViewer->showTable(); + m_peaksViewer->show(); + } +} + +/** + * Remove the visible peaks table. + */ +void SplatterPlotView::onRemoveVisiblePeaksTable() +{ + if (m_peaksViewer->hasPeaks()) + { + //m_peaksViewer->removeTable(); + m_peaksViewer->hide(); + } +} + +/** + * On show all peaks + */ +void SplatterPlotView::onShowAllPeaksTable() +{ + if (m_peaksViewer->hasPeaks()) + { + m_peaksViewer->showFullTable(); + m_peaksViewer->show(); + } +} + } // SimpleGui } // Vates } // Mantid