Skip to content

Commit

Permalink
refs #5167. Show peaks as plane-cut spheres
Browse files Browse the repository at this point in the history
  • Loading branch information
OwenArnold committed Aug 31, 2012
1 parent 96e744e commit efd9fca
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ namespace API

};

typedef boost::shared_ptr<MultipleExperimentInfos> MultipleExperimentInfos_sptr;
typedef boost::shared_ptr<const MultipleExperimentInfos> MultipleExperimentInfos_const_sptr;

} // namespace API
} // namespace Mantid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace SliceViewer

public:
/// Constructor
PeakOverlay(QwtPlot * plot, QWidget * parent, const Mantid::Kernel::V3D& origin, const double& radius);
PeakOverlay(QwtPlot * plot, QWidget * parent, const Mantid::Kernel::V3D& origin, const double& intensity);
/// Destructor
virtual ~PeakOverlay();
/// Set the slice point at position.
Expand All @@ -59,6 +59,8 @@ namespace SliceViewer
/// Get the origin. md x, md y
const Mantid::Kernel::V3D & getOrigin() const;
double getRadius() const;
/// Setter for the normalisation.
void setNormalisation(const double& normalisation);

private:

Expand All @@ -70,12 +72,16 @@ namespace SliceViewer
int height() const;
int width() const;

bool hasIntensity() const;

/// QwtPlot containing this
QwtPlot * m_plot;
/// Origin md-x, md-y, and md-z
Mantid::Kernel::V3D m_origin;
/// Radius md-x, md-y
double m_radius;
/// intensity
double m_intensity;
/// normalisation value.
double m_normalisation;
/// Max opacity
const double m_opacityMax;
/// Min opacity
Expand All @@ -84,7 +90,10 @@ namespace SliceViewer
double m_opacityAtDistance;
/// Cached radius at the distance z from origin
double m_radiusAtDistance;
/// Cached radius at distance
/// Cached radius
double m_radius;
/// Cached scale
double m_scale;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
#include "MantidQtSliceViewer/PeakOverlayViewFactory.h"
#include <QtGui/qwidget.h>
#include <qwt_plot.h>
#include <boost/shared_ptr.hpp>

namespace Mantid
{
namespace API
{
/// Forward dec.
class IMDWorkspace;
}
}

namespace MantidQt
{
Expand Down Expand Up @@ -42,9 +52,10 @@ namespace MantidQt
QWidget * m_parent;
PeakDimensions m_peakDims;
public:
PeakOverlayFactory(QwtPlot * plot, QWidget * parent, const PeakDimensions peakDims);
PeakOverlayFactory(QwtPlot * plot, QWidget * parent, boost::shared_ptr<const Mantid::API::IMDWorkspace> ws);
virtual ~PeakOverlayFactory();
virtual boost::shared_ptr<PeakOverlayView> createView(const Mantid::API::IPeak&) const;
PeakDimensions getPeakDimensions() const;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ namespace MantidQt
virtual void updateView() = 0;
/// Hide the view.
virtual void hideView() = 0;
/// Setter for the normalisation value.
virtual void setNormalisation(const double& normalisation) = 0;
/// Destructor
virtual ~PeakOverlayView()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@ namespace SliceViewer
}

// Create views for every peak in the workspace.
double sumIntensity = 0;
boost::scoped_ptr<PeakOverlayViewFactory> factory_scptr(factory);
for(int i = 0; i < peaksWS->getNumberPeaks(); ++i)
{
const Mantid::API::IPeak& peak = peaksWS->getPeak(i);
sumIntensity += peak.getIntensity();
auto view = boost::shared_ptr<PeakOverlayView>( factory_scptr->createView(peak) );
m_viewPeaks.push_back( view );
}

// Set the normalisation. Applies to all peaks with intensity.
for(VecPeakOverlayView::iterator it = m_viewPeaks.begin(); it != m_viewPeaks.end(); ++it)
{
(*it)->setNormalisation(sumIntensity);
}

}

void ConcretePeaksPresenter::update()
Expand Down
65 changes: 44 additions & 21 deletions Code/Mantid/MantidQt/SliceViewer/src/PeakOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ namespace SliceViewer
//----------------------------------------------------------------------------------------------
/** Constructor
*/
PeakOverlay::PeakOverlay(QwtPlot * plot, QWidget * parent, const Mantid::Kernel::V3D& origin, const double& radius)
PeakOverlay::PeakOverlay(QwtPlot * plot, QWidget * parent, const Mantid::Kernel::V3D& origin, const double& intensity)
: QWidget( parent ),
m_plot(plot),
m_origin(origin),
m_radius(radius),
m_intensity(intensity),
m_normalisation(1),
m_opacityMax(0.6),
m_opacityMin(0.1)
{
Expand All @@ -41,6 +42,24 @@ namespace SliceViewer
{
}

//----------------------------------------------------------------------------------------------
/** Setter for the normalisation denominator.
@param normalisation : normalisation denominator to use.
*/
void PeakOverlay::setNormalisation(const double& normalisation)
{
m_normalisation = normalisation;
}

//----------------------------------------------------------------------------------------------
/** Method to determine if the intensity has been set.
@return True if the intensity is provided.
*/
bool PeakOverlay::hasIntensity() const
{
return m_intensity != 0;
}

//----------------------------------------------------------------------------------------------
/** Set the distance between the plane and the center of the peak in md coordinates
Expand All @@ -62,8 +81,13 @@ namespace SliceViewer
*/
void PeakOverlay::setSlicePoint(const double& z)
{
const double distance = z - m_origin.Z();
const double distanceSQ = distance * distance;
const double distanceSQ = (z - m_origin.Z()) * (z - m_origin.Z());
const double distance = std::sqrt(distanceSQ);
m_radius = 1;
if(hasIntensity())
{
m_radius = m_intensity / m_normalisation;
}
const double radSQ = m_radius * m_radius;

if(distanceSQ < radSQ)
Expand All @@ -74,8 +98,12 @@ namespace SliceViewer
{
m_radiusAtDistance = 0;
}


const QwtDoubleInterval interval = m_plot->axisScaleDiv(QwtPlot::yLeft)->interval();
const double yMin = interval.minValue();
const double yMax = interval.maxValue();
m_scale = height()/(yMax - yMin);

// Apply a linear transform to convert from a distance to an opacity between opacityMin and opacityMax.
m_opacityAtDistance = ((m_opacityMin - m_opacityMax)/m_radius) * distance + m_opacityMax;
m_opacityAtDistance = m_opacityAtDistance >= m_opacityMin ? m_opacityAtDistance : m_opacityMin;
Expand Down Expand Up @@ -117,27 +145,22 @@ namespace SliceViewer
const int yOrigin = m_plot->transform( QwtPlot::yLeft, m_origin.Y() );
const QPointF originWindows(xOrigin, yOrigin);

const QwtDoubleInterval interval = m_plot->axisScaleDiv(QwtPlot::yLeft)->interval();
const double yMin = interval.minValue();
const double yMax = interval.maxValue();
const double scale = height()/(yMax - yMin);

const double radius = scale * m_radiusAtDistance;
const double innerRadius = m_scale * m_radiusAtDistance;
double outerRadius = m_scale * m_radius;
double lineWidth = outerRadius - innerRadius;
outerRadius -= lineWidth/2;

// Draw circle and inner circle.
QPainter painter(this);
painter.setRenderHint( QPainter::Antialiasing );

painter.setOpacity(m_opacityAtDistance); //Set the pre-calculated opacity
painter.setBrush(Qt::cyan);
painter.drawEllipse( originWindows, radius, radius );


// Draw Outer circle
QPen pen( Qt::green );
pen.setWidth(2);
pen.setStyle(Qt::DashDotLine);
pen.setWidth(static_cast<int>(lineWidth));
painter.setPen( pen );
painter.drawEllipse( originWindows, radius, radius );

pen.setStyle(Qt::SolidLine);
painter.setOpacity(m_opacityAtDistance); //Set the pre-calculated opacity
painter.drawEllipse( originWindows, outerRadius, outerRadius );

}

void PeakOverlay::updateView()
Expand Down
107 changes: 73 additions & 34 deletions Code/Mantid/MantidQt/SliceViewer/src/PeakOverlayFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include "MantidQtSliceViewer/PeakOverlayFactory.h"
#include "MantidQtSliceViewer/PeakOverlay.h"
#include "MantidAPI/IPeak.h"
#include "MantidAPI/IMDWorkspace.h"
#include "MantidAPI/MultipleExperimentInfos.h"
#include "MantidAPI/IMDEventWorkspace.h"
#include "MantidAPI/IMDHistoWorkspace.h"
#include <boost/make_shared.hpp>

using namespace Mantid::API;
Expand All @@ -9,48 +13,83 @@ namespace MantidQt
{
namespace SliceViewer
{

PeakOverlayFactory::PeakOverlayFactory(QwtPlot * plot, QWidget * parent, const PeakDimensions peakDims) : m_plot(plot), m_parent(parent), m_peakDims(peakDims)
template<typename WS_SPTR_TYPE>
PeakDimensions establishPeakDimensionality(WS_SPTR_TYPE ws)
{
MultipleExperimentInfos_const_sptr expInfos = boost::dynamic_pointer_cast<const MultipleExperimentInfos>(ws);
PeakDimensions peakDims = PeakDimensions::LabView;
if( expInfos != NULL && expInfos->getNumExperimentInfo() > 0)
{
if(!plot)
throw std::invalid_argument("PeakOverlayFactory plot is null");
if(!parent)
throw std::invalid_argument("PeakOverlayFactory parent widget is null");
}

boost::shared_ptr<PeakOverlayView> PeakOverlayFactory::createView(const Mantid::API::IPeak& peak) const
{
Mantid::Kernel::V3D position;
switch(m_peakDims)
Mantid::API::ExperimentInfo_const_sptr expInfo = expInfos->getExperimentInfo(0);
if(expInfo->run().getGoniometerMatrix().isRotation())
{
case LabView:
position = peak.getQLabFrame();
break;
case SampleView:
position = peak.getQSampleFrame();
break;
case HKLView:
position = peak.getHKL();
break;
default:
throw std::runtime_error("Unknown PeakDimension type");
peakDims = PeakDimensions::SampleView;
if(expInfo->sample().hasOrientedLattice())
{
peakDims = PeakDimensions::HKLView;
}
}
}
return peakDims;
}

double radius = peak.getIntensity(); //TODO: we should normalise this!
radius = 1; //HACK
//QwtText xDim = m_plot->axisTitle(QwtPlot::xBottom);
//QwtText yDim = m_plot->axisTitle(QwtPlot::yLeft);

/* 1) Find out which dimensions are being plotted on x and y
2) Find out what h, k, l each of these dimensions correspond to.
3) Create the origin x, y based on these hkl values.
*/
PeakOverlayFactory::PeakOverlayFactory(QwtPlot * plot, QWidget * parent, IMDWorkspace_const_sptr ws) : m_plot(plot), m_parent(parent)
{
if(!plot)
throw std::invalid_argument("PeakOverlayFactory plot is null");
if(!parent)
throw std::invalid_argument("PeakOverlayFactory parent widget is null");

return boost::make_shared<PeakOverlay>(m_plot, m_parent, position, radius);
IMDEventWorkspace_const_sptr eventWS = boost::dynamic_pointer_cast<const IMDEventWorkspace>(ws);
if(eventWS != NULL)
{
m_peakDims = establishPeakDimensionality(eventWS);
}
else
{
IMDHistoWorkspace_const_sptr histoWS = boost::dynamic_pointer_cast<const IMDHistoWorkspace>(ws);
m_peakDims = establishPeakDimensionality(histoWS);
}
}

PeakOverlayFactory::~PeakOverlayFactory()
PeakDimensions PeakOverlayFactory::getPeakDimensions() const
{
return this->m_peakDims;
}

boost::shared_ptr<PeakOverlayView> PeakOverlayFactory::createView(const Mantid::API::IPeak& peak) const
{
Mantid::Kernel::V3D position;
switch(m_peakDims)
{
case PeakDimensions::LabView:
position = peak.getQLabFrame();
break;
case PeakDimensions::SampleView:
position = peak.getQSampleFrame();
break;
case PeakDimensions::HKLView:
position = peak.getHKL();
break;
default:
throw std::runtime_error("Unknown PeakDimension type");
}

double intensity = peak.getIntensity();

//QwtText xDim = m_plot->axisTitle(QwtPlot::xBottom);
//QwtText yDim = m_plot->axisTitle(QwtPlot::yLeft);

/* 1) Find out which dimensions are being plotted on x and y
2) Find out what h, k, l each of these dimensions correspond to.
3) Create the origin x, y based on these hkl values.
*/

return boost::make_shared<PeakOverlay>(m_plot, m_parent, position, intensity);
}

PeakOverlayFactory::~PeakOverlayFactory()
{
}
}
}
2 changes: 1 addition & 1 deletion Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2081,7 +2081,7 @@ void SliceViewer::peakOverlay_toggled(bool checked)
if(!list.isEmpty())
{
IPeaksWorkspace_sptr peaksWS = AnalysisDataService::Instance().retrieveWS<IPeaksWorkspace>(list.front().toStdString());
PeakOverlayFactory* factory = new PeakOverlayFactory(m_plot, m_plot->canvas(), PeakDimensions::HKLView);
PeakOverlayFactory* factory = new PeakOverlayFactory(m_plot, m_plot->canvas(), m_ws);
m_peaksPresenter = PeaksPresenter_sptr(new ConcretePeaksPresenter(factory, peaksWS));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ConcretePeaksPresenterTest : public CxxTest::TestSuite
MOCK_METHOD0(updateView, void());
MOCK_METHOD1(setSlicePoint, void(const double&));
MOCK_METHOD0(hideView, void());
MOCK_METHOD1(setNormalisation, void(const double&));
~MockPeakOverlayView(){}
};

Expand Down Expand Up @@ -60,13 +61,21 @@ class ConcretePeaksPresenterTest : public CxxTest::TestSuite

// Set the expectation on the number of calls
const int expectedNumberPeaks = 10;
EXPECT_CALL(*mockViewFactory, createView(_)).Times(expectedNumberPeaks).WillRepeatedly(Return(boost::make_shared<NiceMock<MockPeakOverlayView> >()));;

// Create a mock view object that will be returned by the mock factory.
auto pMockView = new NiceMock<MockPeakOverlayView>;
EXPECT_CALL(*pMockView, setNormalisation(_)).Times(expectedNumberPeaks);
auto mockView = boost::shared_ptr<NiceMock<MockPeakOverlayView> >(pMockView);


EXPECT_CALL(*mockViewFactory, createView(_)).Times(expectedNumberPeaks).WillRepeatedly(Return(mockView));;
Mantid::API::IPeaksWorkspace_sptr peaksWS = WorkspaceCreationHelper::createPeaksWorkspace(expectedNumberPeaks);

// Construction should cause the widget factory to be used to generate peak overlay objects.
ConcretePeaksPresenter presenter(mockViewFactory, peaksWS);

TSM_ASSERT("MockViewFactory not used as expected.", Mock::VerifyAndClearExpectations(mockViewFactory));
TSM_ASSERT("MockView not used as expected.", Mock::VerifyAndClearExpectations(pMockView));
}

void test_update()
Expand Down

0 comments on commit efd9fca

Please sign in to comment.