Commit 70ad602d authored by Matthew D Jones's avatar Matthew D Jones
Browse files

Merge pull request #15225 from...

Merge pull request #15225 from mantidproject/15163_color_scale_should_reset_when_zoom_to_peak_in_slice_viewer

Color scale should reset when zoom to peak in slice viewer
parents 2d93286d eec5db45
......@@ -25,6 +25,7 @@ set ( SRC_FILES
src/QPeaksTableModel.cpp
src/QScienceSpinBox.cpp
src/SliceViewer.cpp
src/SliceViewerFunctions.cpp
src/SliceViewerWindow.cpp
src/SnapToGridDialog.cpp
src/XYLimitsDialog.cpp
......@@ -66,6 +67,7 @@ set ( INC_FILES
inc/MantidQtSliceViewer/QPeaksTableModel.h
inc/MantidQtSliceViewer/QScienceSpinBox.h
inc/MantidQtSliceViewer/SliceViewer.h
inc/MantidQtSliceViewer/SliceViewerFunctions.h
inc/MantidQtSliceViewer/SliceViewerWindow.h
inc/MantidQtSliceViewer/SnapToGridDialog.h
inc/MantidQtSliceViewer/UpdateableOnDemand.h
......@@ -117,6 +119,7 @@ set ( TEST_FILES
test/PhysicalCrossPeakTest.h
test/PhysicalSphericalPeakTest.h
test/NullPeaksPresenterTest.h
test/SliceViewerFunctionsTest.h
)
# Python unit tests
......
......@@ -81,6 +81,9 @@ public:
void setAutoScale(bool autoscale);
bool getAutoScale() const;
bool getAutoColorScaleforCurrentSlice() const;
public slots:
void changedMinimum();
void changedMaximum();
......
......@@ -80,13 +80,23 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoScaleForCurrentSlice">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When this is checked the color scale range will be automatically set to the current slice whenever the user zooms to a new peak, pans through the view or changes the slice with the slider control&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Autoscale to current slice</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoScale">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This flag signals that the color scale range should be set automatically to the current slice range when a workspace is loaded. Note that auto scaling will be applied when a workspace is loaded for the very first time. This option is mainly relevant for live data workspaces, which are continuously being updated and reloaded.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Autoscale on Load</string>
<string>Autoscale on load</string>
</property>
</widget>
</item>
......
......@@ -243,6 +243,9 @@ private:
// Set aspect ratio type.
void setAspectRatio(AspectRatioType type);
/// Extracts and applies the color scaling for the current slice
void applyColorScalingForCurrentSliceIfRequired();
private:
......
#ifndef SLICEVIEWER_FUNCTIONS_H
#define SLICEVIEWER_FUNCTIONS_H
#include "DllOption.h"
#include "MantidAPI/IMDWorkspace.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include "MantidKernel/VMD.h"
namespace MantidQt {
namespace SliceViewer {
/// Checks if a slice lies within a workspace or not
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER doesSliceCutThroughWorkspace(
const Mantid::Kernel::VMD &min, const Mantid::Kernel::VMD &max,
const std::vector<Mantid::Geometry::MDHistoDimension_sptr> &dimensions);
/// Checks if rebin mode is in consistent state
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER isRebinInConsistentState(
Mantid::API::IMDWorkspace *rebinnedWS, bool useRebinMode);
/// Should perform auto color scaling on load
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER shouldAutoScaleForNewlySetWorkspace(
bool isFirstWorkspaceOpen, bool isAutoScalingOnLoad);
}
}
#endif
......@@ -53,6 +53,8 @@ ColorBarWidget::ColorBarWidget(QWidget *parent)
QObject::connect(ui.valMax, SIGNAL(editingFinished()), this, SLOT(changedMaximum()));
QObject::connect(ui.valMin, SIGNAL(valueChangedFromArrows()), this, SLOT(changedMinimum()));
QObject::connect(ui.valMax, SIGNAL(valueChangedFromArrows()), this, SLOT(changedMaximum()));
QObject::connect(ui.valMin, SIGNAL(valueChanged(double)), this, SLOT(changedMinimum()));
QObject::connect(ui.valMax, SIGNAL(valueChanged(double)), this, SLOT(changedMaximum()));
QObject::connect(m_colorBar, SIGNAL(mouseMoved(QPoint, double)), this, SLOT(colorBarMouseMoved(QPoint, double)));
// Initial view
......@@ -382,6 +384,15 @@ void ColorBarWidget::setAutoScale(bool autoscale) {
*/
bool ColorBarWidget::getAutoScale() const { return ui.autoScale->isChecked(); }
/**
* Gets the state of the "Autoscale for current slice" checkbox
* @returns true if it is checked else false
*/
bool ColorBarWidget::getAutoColorScaleforCurrentSlice() const {
return ui.autoScaleForCurrentSlice->isChecked();
}
ColorBarWidget::~ColorBarWidget()
{
}
......
......@@ -39,6 +39,7 @@
#include "MantidQtSliceViewer/PeakBoundingBox.h"
#include "MantidQtSliceViewer/PeaksViewerOverlayDialog.h"
#include "MantidQtSliceViewer/PeakOverlayViewFactorySelector.h"
#include "MantidQtSliceViewer/SliceViewerFunctions.h"
#include "MantidQtMantidWidgets/SelectWorkspacesDialog.h"
#include <qwt_plot_panner.h>
......@@ -65,26 +66,6 @@ using Poco::XML::NodeIterator;
using Poco::XML::NodeFilter;
using MantidQt::API::AlgorithmRunner;
namespace {
/*
Checks if the rebinning is in a consistent state, ie if rebin mode is selected and there
is a rebin workspace or there is no rebin workspace and no rebin mode selected.
The state is inconsistent if rebin mode is selected and there is no workspace.
*/
bool isRebinInConsistentState(Mantid::API::IMDWorkspace* rebinnedWS, bool useRebinMode) {
return (rebinnedWS != nullptr) && useRebinMode;
}
/**
* Checks if the colors scale range should be automatically set. We should provide auto scaling
* on load if the workspaces is either loaded the first time or if it is explictly selected.
*/
bool shouldAutoScaleForNewlySetWorkspace(bool isFirstWorkspaceOpen, bool isAutoScalingOnLoad) {
return !isFirstWorkspaceOpen || isAutoScalingOnLoad;
}
}
namespace MantidQt {
namespace SliceViewer {
......@@ -763,6 +744,7 @@ void SliceViewer::setWorkspace(Mantid::API::IMDWorkspace_sptr ws) {
// Build up the widgets
this->updateDimensionSliceWidgets();
// This will auto scale the color bar to the current slice when the workspace is
// loaded. This always happens when a workspace is loaded for the first time.
// For live event data workspaces subsequent updates might not lead to an auto
......@@ -772,6 +754,7 @@ void SliceViewer::setWorkspace(Mantid::API::IMDWorkspace_sptr ws) {
m_colorBar->setViewRange(m_colorRangeFull);
m_colorBar->updateColorMap();
}
// Initial display update
this->updateDisplay(
!m_firstWorkspaceOpen /*Force resetting the axes, the first time*/);
......@@ -1217,6 +1200,9 @@ void SliceViewer::updateDisplaySlot(int index, double value) {
// Trigger a rebin on each movement of the slice point
if (m_rebinMode && ui.btnAutoRebin->isOn())
this->rebinParamsChanged();
// Update the colors scale if required
applyColorScalingForCurrentSliceIfRequired();
}
//------------------------------------------------------------------------------
......@@ -1405,16 +1391,23 @@ void SliceViewer::findRangeSlice() {
// the rebin selection and continue to use the original WS
if (!isRebinInConsistentState(m_overlayWS.get(), m_rebinMode)) {
setRebinMode(false);
} else {
}
else {
workspace_used = this->m_overlayWS;
}
}
if (!workspace_used)
return;
// Set the full color range if it has not been set yet
// We need to do this before aquiring the dead lock
if (m_colorRangeFull == QwtDoubleInterval(0.0, -1.0)) {
findRangeFull();
}
// Acquire a scoped read-only lock on the workspace, preventing it from being
// written
// while we iterate through.
// written while we iterate through.
ReadLock lock(*workspace_used);
m_colorRangeSlice = QwtDoubleInterval(0., 1.0);
......@@ -1441,16 +1434,25 @@ void SliceViewer::findRangeSlice() {
max[d] = min[d] + dim->getBinWidth();
}
}
// This builds the implicit function for just this slice
MDBoxImplicitFunction *function = new MDBoxImplicitFunction(min, max);
// Iterate through the slice
m_colorRangeSlice = API::SignalRange(*workspace_used, *function,
this->getNormalization()).interval();
delete function;
// In case of failure, use the full range instead
if (m_colorRangeSlice == QwtDoubleInterval(0.0, 1.0))
if (doesSliceCutThroughWorkspace(min, max, m_dimensions)) {
// This builds the implicit function for just this slice
MDBoxImplicitFunction *function = new MDBoxImplicitFunction(min, max);
// Iterate through the slice
m_colorRangeSlice = API::SignalRange(*workspace_used, *function,
this->getNormalization()).interval();
delete function;
// In case of failure, use the full range instead
if (m_colorRangeSlice == QwtDoubleInterval(0.0, 1.0)) {
m_colorRangeSlice = m_colorRangeFull;
}
}
else {
// If the slice does not cut through the workspace we make use fo the full workspace
m_colorRangeSlice = m_colorRangeFull;
}
}
//------------------------------------------------------------------------------
......@@ -2243,6 +2245,8 @@ Event handler for plot panning.
void SliceViewer::panned(int, int) {
autoRebinIfRequired();
applyColorScalingForCurrentSliceIfRequired();
this->updatePeaksOverlay();
}
......@@ -2499,6 +2503,9 @@ void SliceViewer::zoomToRectangle(const PeakBoundingBox &boundingBox) {
QString::fromStdString(m_peaksSliderWidget->getDimName());
this->setSlicePoint(dimensionName, boundingBox.slicePoint());
// Set the color scale range for the current slice if required
applyColorScalingForCurrentSliceIfRequired();
// Make sure the view updates
m_plot->replot();
}
......@@ -2568,5 +2575,17 @@ void SliceViewer::setColorBarAutoScale(bool autoscale) {
m_colorBar->setAutoScale(autoscale);
}
/**
* Apply the color scaling for the current slice. This will
* be applied only if it is explicitly requested
*/
void SliceViewer::applyColorScalingForCurrentSliceIfRequired() {
auto useAutoColorScaleforCurrentSlice = m_colorBar->getAutoColorScaleforCurrentSlice();
if (useAutoColorScaleforCurrentSlice) {
setColorScaleAutoSlice();
}
}
} // namespace
}
#include "MantidQtSliceViewer/SliceViewerFunctions.h"
namespace MantidQt {
namespace SliceViewer {
/**
* Checks if a slice, defined by a min and a max vector, takes a slice which
* cuts through the workspace
* @param min: the min boundary of the slice
* @param max: the max boundary of the slice
* @param dimensions: a vector of dimension objects of the workspace which will
* be sliced
* @returns true if the slice goes fully or partially through the workspace
*/
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER doesSliceCutThroughWorkspace(
const Mantid::Kernel::VMD &min, const Mantid::Kernel::VMD &max,
const std::vector<Mantid::Geometry::MDHistoDimension_sptr> &dimensions) {
auto valueBetweenMinMax = [](
const Mantid::Kernel::VMD_t value, const Mantid::Kernel::VMD_t min,
const Mantid::Kernel::VMD_t max) { return value >= min && value <= max; };
int dimCounter = 0;
auto cutsThroughWorkspace = true;
// Check in either dimension if the the min and max values are withing the
// workspace boundaries
for (const auto &dimension : dimensions) {
const auto minDimension =
static_cast<Mantid::Kernel::VMD_t>(dimension->getMinimum());
const auto maxDimension =
static_cast<Mantid::Kernel::VMD_t>(dimension->getMaximum());
// If the the value for min and max is not in the min-max range of the
// dimension of the workspace
// then the cut is neither full nor partial
if (!valueBetweenMinMax(min[dimCounter], minDimension, maxDimension) &&
!valueBetweenMinMax(max[dimCounter], minDimension, maxDimension)) {
cutsThroughWorkspace = false;
break;
}
++dimCounter;
}
return cutsThroughWorkspace;
}
/**
* Checks if the colors scale range should be automatically set. We should
* provide auto scaling
* on load if the workspaces is either loaded the first time or if it is
* explictly selected.
* @param isFirstWorkspaceOpen: if the workspace is being loaded for the first
* time
* @param isAutoScalingOnLoad: is auto scaling on load selected
* @returns true if autos scaling on load should be performed else false
*/
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER shouldAutoScaleForNewlySetWorkspace(
bool isFirstWorkspaceOpen, bool isAutoScalingOnLoad) {
return !isFirstWorkspaceOpen || isAutoScalingOnLoad;
}
/*
* Checks if the rebinning is in a consistent state, ie if rebin mode is
* selected and there
* is a rebin workspace or there is no rebin workspace and no rebin mode
* selected.
* The state is inconsistent if rebin mode is selected and there is no
* workspace.
* @param rebinnedWS: a pointer to an MD overlay workspace
* @param useRebinMode: indicates if rebinning is to be used
* @returns true rebin state is consistent, else false
*/
bool EXPORT_OPT_MANTIDQT_SLICEVIEWER isRebinInConsistentState(
Mantid::API::IMDWorkspace *rebinnedWS, bool useRebinMode) {
return (rebinnedWS != nullptr) && useRebinMode;
}
}
}
#ifndef SLICE_VIEWER_SLICE_VIEWER_FUNCTIONS_TEST_H_
#define SLICE_VIEWER_SLICE_VIEWER_FUNCTIONS_TEST_H_
#include "MantidGeometry/MDGeometry/GeneralFrame.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include "MantidQtSliceViewer/SliceViewerFunctions.h"
#include <boost/make_shared.hpp>
#include <cxxtest/TestSuite.h>
using namespace MantidQt::SliceViewer;
namespace {
struct SliceDefinition {
SliceDefinition(size_t numDims) : min(numDims), max(numDims) {}
Mantid::Kernel::VMD min;
Mantid::Kernel::VMD max;
};
SliceDefinition get_slice_definition(const size_t numberOfDimensions,
const Mantid::Kernel::VMD_t minValue,
const Mantid::Kernel::VMD_t maxValue) {
SliceDefinition sliceDefinition(numberOfDimensions);
Mantid::Kernel::VMD min(numberOfDimensions);
Mantid::Kernel::VMD max(numberOfDimensions);
for (size_t index = 0; index < numberOfDimensions; ++index) {
sliceDefinition.min[index] = minValue;
sliceDefinition.max[index] = maxValue;
}
return sliceDefinition;
}
std::vector<Mantid::Geometry::MDHistoDimension_sptr> get_dimensions_collection(
const size_t numberOfDimensions, const Mantid::Kernel::VMD_t minValue,
const Mantid::Kernel::VMD_t maxValue, const std::string sliceLies) {
std::vector<Mantid::Geometry::MDHistoDimension_sptr> dimensions(
numberOfDimensions);
const size_t numberOfBins = 5;
auto minConverted = static_cast<Mantid::coord_t>(minValue);
auto maxConverted = static_cast<Mantid::coord_t>(maxValue);
const Mantid::coord_t shift = 0.5;
if (sliceLies == "inside") {
minConverted = minConverted - shift;
maxConverted = maxConverted + shift;
} else if (sliceLies == "outside") {
minConverted = minConverted + shift;
maxConverted = maxConverted - shift;
} else {
minConverted = minConverted + shift;
maxConverted = maxConverted + shift;
}
for (size_t index = 0; index < numberOfDimensions; ++index) {
Mantid::Kernel::UnitLabel unitLabel("Meters");
Mantid::Geometry::GeneralFrame frame("Length", unitLabel);
auto dimension = boost::make_shared<Mantid::Geometry::MDHistoDimension>(
"Distance", "Dist", frame, minConverted, maxConverted, numberOfBins);
dimensions[index] = dimension;
}
return dimensions;
}
}
class SliceViewerFunctionsTest : public CxxTest::TestSuite {
public:
bool do_test_slice_lies_in_workspace_boundaries(
const std::string sliceLiesWithinWorkspaceBoundary) {
// Arrange
const size_t numberOfDimensions = 3;
Mantid::Kernel::VMD_t minValue = 1;
Mantid::Kernel::VMD_t maxValue = 3;
auto sliceDefinition =
get_slice_definition(numberOfDimensions, minValue, maxValue);
auto dimensions =
get_dimensions_collection(numberOfDimensions, minValue, maxValue,
sliceLiesWithinWorkspaceBoundary);
// Act
return doesSliceCutThroughWorkspace(sliceDefinition.min,
sliceDefinition.max, dimensions);
}
void test_that_finds_slice_point_within_workspace_boundaries() {
std::string sliceLiesWithinWorkspaceBoundary = "inside";
auto liesInside = do_test_slice_lies_in_workspace_boundaries(
sliceLiesWithinWorkspaceBoundary);
TSM_ASSERT("Slice definition should lie within the workspace boundary",
liesInside);
}
void test_that_finds_slice_point_outside_workspace_boudaries() {
std::string sliceLiesWithinWorkspaceBoundary = "outside";
auto liesInside = do_test_slice_lies_in_workspace_boundaries(
sliceLiesWithinWorkspaceBoundary);
TSM_ASSERT("Slice definition should not lie within the workspace boundary",
!liesInside);
}
void
test_that_slice_point_which_is_partially_in_the_workspace_is_detected_as_not_being_in_the_workspace() {
std::string sliceLiesWithinWorkspaceBoundary = "partially";
auto liesInside = do_test_slice_lies_in_workspace_boundaries(
sliceLiesWithinWorkspaceBoundary);
TSM_ASSERT("Slice definition should lie within the workspace boundary",
liesInside);
}
};
#endif
// end SLICE_VIEWER_SLICE_VIEWER_FUNCTIONS_TEST_H_
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment