diff --git a/Device/Detector/IDetector.cpp b/Device/Detector/IDetector.cpp index 353d06c6c3721872e7b8027ad807f0d8cc3c7b74..1b5f8d72d5164316ad32a9928f24ac2eb0445f5e 100644 --- a/Device/Detector/IDetector.cpp +++ b/Device/Detector/IDetector.cpp @@ -228,12 +228,12 @@ std::vector<size_t> IDetector::activeIndices() const void IDetector::addMask(const IShape2D& shape, bool mask_value) { - m_mask->maskToStack(shape, mask_value, false); + m_mask->pushMask(shape, mask_value, false); } void IDetector::addBinMask(const IShape2D& shape, bool mask_value) { - m_mask->maskToStack(shape, mask_value, true); + m_mask->pushMask(shape, mask_value, true); } void IDetector::maskAll() diff --git a/Device/Mask/MaskStack.cpp b/Device/Mask/MaskStack.cpp index 01224770abecfca5e9775034380bbb5ae44647e0..0e9a23a2c1a838ca2da9c4e80da12ae5401c2dd4 100644 --- a/Device/Mask/MaskStack.cpp +++ b/Device/Mask/MaskStack.cpp @@ -50,7 +50,7 @@ MaskStack::MaskStack() = default; MaskStack::MaskStack(const MaskStack&) = default; MaskStack::~MaskStack() = default; -void MaskStack::maskToStack(const IShape2D& shape, bool mask_value, bool in_bins) +void MaskStack::pushMask(const IShape2D& shape, bool mask_value, bool in_bins) { m_stack.emplace_back(new MaskPattern(shape.clone(), mask_value, in_bins)); } diff --git a/Device/Mask/MaskStack.h b/Device/Mask/MaskStack.h index b67707153854577620a904234437d80082f4b017..a88883b12e852af69e005923f996ac340193c735 100644 --- a/Device/Mask/MaskStack.h +++ b/Device/Mask/MaskStack.h @@ -34,7 +34,7 @@ public: ~MaskStack(); //! Add mask to the stack of detector masks. //! Argument mask_value=true means that the area will be excluded from the analysis. - void maskToStack(const IShape2D& shape, bool mask_value, bool in_bins); + void pushMask(const IShape2D& shape, bool mask_value, bool in_bins); bool isMasked(size_t i_flat, const Frame& frame) const; diff --git a/Doc/graph/mask-classes.gv b/Doc/graph/mask-classes.gv index 3f510b4380a79635ad9e50efa0d1da6b7ad62253..59f9af3765875dd4299a207316e0c61358ba2021 100644 --- a/Doc/graph/mask-classes.gv +++ b/Doc/graph/mask-classes.gv @@ -66,6 +66,8 @@ digraph maskClasses #SpecularPlot->ScientificPlot[arrowhead=onormal]; Data2DItem->MaskList; + Data2DItem->MaskeditorListmodel[style=dotted color=magenta]; + MaskList->MaskItem; EllipseOverlay->EllipseItem; diff --git a/GUI/Model/Data/Data2DItem.cpp b/GUI/Model/Data/Data2DItem.cpp index 6d1599473ca6b296d9d494adba3db4a3492150d4..215efef18a2af645fdc2fa52510c152460af9ea3 100644 --- a/GUI/Model/Data/Data2DItem.cpp +++ b/GUI/Model/Data/Data2DItem.cpp @@ -17,8 +17,11 @@ #include "Base/Axis/Scale.h" #include "Base/Util/Assert.h" #include "Device/Data/Datafield.h" +#include "Device/Mask/IShape2D.h" +#include "Device/Mask/MaskStack.h" #include "GUI/Model/Axis/AmplitudeAxisItem.h" #include "GUI/Model/Axis/BasicAxisItem.h" +#include "GUI/Model/Mask/MaskItems.h" #include "GUI/Model/Mask/MaskeditorListmodel.h" #include "GUI/Model/Mask/ProjectionList.h" #include "GUI/Support/Style/QCP_Util.h" @@ -365,6 +368,37 @@ MaskeditorListmodel* Data2DItem::getOrCreateMaskModel() return m_mask_model.get(); } +Datafield* Data2DItem::createMaskedField() const +{ + // Requesting mask information + std::unique_ptr<IShape2D> roi; + Datafield* result = c_field()->clone(); + MaskStack detectorMask; + const QVector<const MaskItem*> maskItems = maskContainerItem()->maskItems(); + for (auto maskIter = maskItems.rbegin(); maskIter != maskItems.rend(); maskIter++) + if ((*maskIter)->isVisible()) { + if (auto* roiItem = dynamic_cast<const RegionOfInterestItem*>((*maskIter))) + roi = roiItem->createShape(); + else { + std::unique_ptr<IShape2D> shape((*maskIter)->createShape()); + detectorMask.pushMask(*shape, (*maskIter)->maskValue(), false); + } + } + + // ROI mask has to be the last one, it can not be "unmasked" by other shapes + if (roi) + detectorMask.pushMask(*roi, true, false); + + if (!detectorMask.hasMasks()) + return nullptr; + + for (size_t i = 0; i < result->size(); ++i) + if (detectorMask.isMasked(i, result->frame())) + (*result)[i] = 0; + + return result; +} + ProjectionList* Data2DItem::projectionContainerItem() { return m_proj_model ? m_proj_model->projnItem() : nullptr; diff --git a/GUI/Model/Data/Data2DItem.h b/GUI/Model/Data/Data2DItem.h index aef93ea2b8b05e8f1401ce53225a10db2d5e6232..d7b2f7263d9fa6ab0d648b20fcca1957da9c49fa 100644 --- a/GUI/Model/Data/Data2DItem.h +++ b/GUI/Model/Data/Data2DItem.h @@ -78,6 +78,7 @@ public: MaskList* maskContainerItem(); const MaskList* maskContainerItem() const; MaskeditorListmodel* getOrCreateMaskModel(); + Datafield* createMaskedField() const; ProjectionList* projectionContainerItem(); const ProjectionList* projectionContainerItem() const; diff --git a/GUI/Model/Data/MaskResultsPresenter.cpp b/GUI/Model/Data/MaskResultsPresenter.cpp deleted file mode 100644 index 1aa5735ba2b9a1edac8fa4c2f895d317697f4827..0000000000000000000000000000000000000000 --- a/GUI/Model/Data/MaskResultsPresenter.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Data/MaskResultsPresenter.cpp -//! @brief Implements class MaskResultsPresenter. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#include "GUI/Model/Data/MaskResultsPresenter.h" -#include "Device/Data/Datafield.h" -#include "Device/Mask/IShape2D.h" -#include "Device/Mask/MaskStack.h" -#include "GUI/Model/Data/Data2DItem.h" -#include "GUI/Model/Mask/MaskItems.h" -#include "GUI/Model/Mask/MaskList.h" - -namespace { - -//! Constructs Datafield which contains original intensity data except masked areas, -//! and areas outside of ROI, where bin content is set to zero. - -Datafield* createMaskPresentation(Data2DItem* data2DItem) -{ - // Requesting mask information - std::unique_ptr<IShape2D> roi; - Datafield* result = data2DItem->c_field()->clone(); - MaskStack detectorMask; - const QVector<const MaskItem*> maskItems = data2DItem->maskContainerItem()->maskItems(); - for (auto maskIter = maskItems.rbegin(); maskIter != maskItems.rend(); maskIter++) - if ((*maskIter)->isVisible()) { - if (auto* roiItem = dynamic_cast<const RegionOfInterestItem*>((*maskIter))) - roi = roiItem->createShape(); - else { - std::unique_ptr<IShape2D> shape((*maskIter)->createShape()); - detectorMask.maskToStack(*shape, (*maskIter)->maskValue(), false); - } - } - - // ROI mask has to be the last one, it can not be "unmasked" by other shapes - if (roi) - detectorMask.maskToStack(*roi, true, false); - - if (!detectorMask.hasMasks()) - return nullptr; - - for (size_t i = 0; i < result->size(); ++i) - if (detectorMask.isMasked(i, result->frame())) - (*result)[i] = 0; - - return result; -} - -} // namespace - - -MaskResultsPresenter::MaskResultsPresenter() = default; - -MaskResultsPresenter::~MaskResultsPresenter() = default; - -void MaskResultsPresenter::updateMaskResults(Data2DItem* data2DItem) -{ - m_data2DItem = data2DItem; -} - -void MaskResultsPresenter::updatePresenter(bool pixelized) -{ - ASSERT(m_data2DItem); - - if (pixelized) { - if (Datafield* maskedData = ::createMaskPresentation(m_data2DItem)) { - // store data backup - m_backup_data.reset(m_data2DItem->c_field()->clone()); - m_backup_interpolated = m_data2DItem->isInterpolated(); - - m_data2DItem->setDatafield(*maskedData); - m_data2DItem->setInterpolated(false); - } else { - m_backup_data.reset(); - } - - } else { - if (m_backup_data) { - m_data2DItem->setDatafield(*m_backup_data); - m_data2DItem->setInterpolated(m_backup_interpolated); - } - } -} diff --git a/GUI/Model/Data/MaskResultsPresenter.h b/GUI/Model/Data/MaskResultsPresenter.h deleted file mode 100644 index 237b3192bf2c1c72693d257dc1210b5a1ca3719c..0000000000000000000000000000000000000000 --- a/GUI/Model/Data/MaskResultsPresenter.h +++ /dev/null @@ -1,40 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit reflection and scattering -// -//! @file GUI/Model/Data/MaskResultsPresenter.h -//! @brief Defines class MaskResultsPresenter. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#ifndef BORNAGAIN_GUI_MODEL_DATA_MASKRESULTSPRESENTER_H -#define BORNAGAIN_GUI_MODEL_DATA_MASKRESULTSPRESENTER_H - -#include <memory> - -class Data2DItem; -class Datafield; - -//! Updates bin values inside IntensityData to display current mask state. - -class MaskResultsPresenter { -public: - MaskResultsPresenter(); - ~MaskResultsPresenter(); - - void updateMaskResults(Data2DItem* data2DItem); - - void updatePresenter(bool pixelized); - -private: - Data2DItem* m_data2DItem; - std::unique_ptr<Datafield> m_backup_data; - bool m_backup_interpolated = false; -}; - -#endif // BORNAGAIN_GUI_MODEL_DATA_MASKRESULTSPRESENTER_H diff --git a/GUI/View/Canvas/MaskEditorCanvas.cpp b/GUI/View/Canvas/MaskEditorCanvas.cpp index 4be4fcce89d3ac9015792ca95bc98dc6edc97993..fc34ade3eaae31a73b2403f44db6f7d4c9d6ecdd 100644 --- a/GUI/View/Canvas/MaskEditorCanvas.cpp +++ b/GUI/View/Canvas/MaskEditorCanvas.cpp @@ -13,8 +13,8 @@ // ************************************************************************************************ #include "GUI/View/Canvas/MaskEditorCanvas.h" +#include "Device/Data/Datafield.h" #include "GUI/Model/Data/Data2DItem.h" -#include "GUI/Model/Data/MaskResultsPresenter.h" #include "GUI/Model/Mask/MaskItems.h" #include "GUI/Model/Mask/MaskList.h" #include "GUI/Model/Project/ProjectDocument.h" @@ -31,7 +31,6 @@ MaskEditorCanvas::MaskEditorCanvas(QWidget* parent) , m_view(new MaskGraphicsView(m_scene)) , m_data2DItem(nullptr) , m_statusLabel(new PlotStatusLabel(nullptr, this)) - , m_resultsPresenter(new MaskResultsPresenter) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -48,12 +47,12 @@ MaskEditorCanvas::MaskEditorCanvas(QWidget* parent) &MaskEditorCanvas::deleteSelectedRequest); } +MaskEditorCanvas::~MaskEditorCanvas() = default; + void MaskEditorCanvas::updateMaskCanvas(Data2DItem* data2DItem, QItemSelectionModel* selModel) { m_data2DItem = data2DItem; - m_resultsPresenter->updateMaskResults(data2DItem); - m_scene->updateSize(m_view->size()); m_scene->associateItems(data2DItem, data2DItem->getOrCreateMaskModel(), selModel); @@ -70,7 +69,28 @@ void MaskEditorCanvas::resetMaskCanvas() void MaskEditorCanvas::onPresentationChange(bool pixelized) { m_scene->clearSelection(); // important to avoid crash (unsubscribe while calling subscribers) - m_resultsPresenter->updatePresenter(pixelized); + + ASSERT(m_data2DItem); + + if (pixelized) { + if (Datafield* maskedData = m_data2DItem->createMaskedField()) { + // store data backup + m_backup_data.reset(m_data2DItem->c_field()->clone()); + m_backup_interpolated = m_data2DItem->isInterpolated(); + + m_data2DItem->setDatafield(*maskedData); + m_data2DItem->setInterpolated(false); + } else { + m_backup_data.reset(); + } + + } else { + if (m_backup_data) { + m_data2DItem->setDatafield(*m_backup_data); + m_data2DItem->setInterpolated(m_backup_interpolated); + } + } + m_scene->updateSize(m_view->size()); // TODO replace by proper repaint command if (auto* container = m_data2DItem->maskContainerItem()) for (MaskItem* mask : container->modifiableMaskItems()) diff --git a/GUI/View/Canvas/MaskEditorCanvas.h b/GUI/View/Canvas/MaskEditorCanvas.h index f32776cbe8f23988a54baf26ce33d1eabf4b8be2..b47bcb584d5b74a2d89d934716349201384f2249 100644 --- a/GUI/View/Canvas/MaskEditorCanvas.h +++ b/GUI/View/Canvas/MaskEditorCanvas.h @@ -19,11 +19,12 @@ #include <QItemSelectionModel> #include <QModelIndex> #include <QWidget> +#include <memory> class Data2DItem; +class Datafield; class MaskGraphicsScene; class MaskGraphicsView; -class MaskResultsPresenter; class PlotStatusLabel; //! Painting widget for MaskEditor, contains graphics scene and graphics view @@ -32,6 +33,7 @@ class MaskEditorCanvas : public QWidget { Q_OBJECT public: MaskEditorCanvas(QWidget* parent = nullptr); + ~MaskEditorCanvas(); void updateMaskCanvas(Data2DItem* data2DItem, QItemSelectionModel* selModel); @@ -55,7 +57,8 @@ private: MaskGraphicsView* m_view; Data2DItem* m_data2DItem; PlotStatusLabel* m_statusLabel; - MaskResultsPresenter* m_resultsPresenter; + std::unique_ptr<Datafield> m_backup_data; + bool m_backup_interpolated = false; }; #endif // BORNAGAIN_GUI_VIEW_CANVAS_MASKEDITORCANVAS_H diff --git a/GUI/View/Setup/MaskPanel.cpp b/GUI/View/Setup/MaskPanel.cpp index 020a8fb8eb953c86d1548702249b1d52939ad691..2e722d7f0d377e75353ef8a95fe20f6776b07438 100644 --- a/GUI/View/Setup/MaskPanel.cpp +++ b/GUI/View/Setup/MaskPanel.cpp @@ -204,10 +204,11 @@ void MaskPanel::addMaskCheckBox(const QString& title, std::function<bool()> gett gDoc->setModified(); }); - connect(m_currentMaskItem, &MaskItem::maskVisibilityChanged, [check_box, getter] { - QSignalBlocker b(check_box); - check_box->setChecked(getter()); - }); + // TODO reconsider + // connect(m_currentMaskItem, &MaskItem::maskVisibilityChanged, [check_box, getter] { + // QSignalBlocker b(check_box); + // check_box->setChecked(getter()); + // }); m_editor_layout->addRow(check_box); }