From 52ff95f3f00ad2e1ed9136084c3cd4b46b0b89c2 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Tue, 23 Jul 2024 19:23:31 +0200
Subject: [PATCH] DistributionItems provide common handle 'center'

---
 GUI/Model/Beam/DistributionItems.cpp     | 85 +++++++++---------------
 GUI/Model/Beam/DistributionItems.h       | 27 +++++---
 GUI/Model/FromCore/ItemizeSimulation.cpp |  3 +-
 GUI/View/Device/DistributionSelector.cpp | 16 +----
 4 files changed, 54 insertions(+), 77 deletions(-)

diff --git a/GUI/Model/Beam/DistributionItems.cpp b/GUI/Model/Beam/DistributionItems.cpp
index d47727f1664..1ddfb281541 100644
--- a/GUI/Model/Beam/DistributionItems.cpp
+++ b/GUI/Model/Beam/DistributionItems.cpp
@@ -21,6 +21,7 @@ namespace Tag {
 
 const QString BaseData("BaseData");
 const QString Center("Center");
+const QString Halfwidth("Halfwidth");
 const QString HWHM("HWHM");
 const QString LeftWidth("LeftWidth");
 const QString Maximum("Maximum");
@@ -58,10 +59,9 @@ void DistributionItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::NumberOfSamples)
             m_number_of_samples = XML::readTaggedUInt(r, tag);
-        else if (tag == Tag::RelSamplingWidth) {
+        else if (tag == Tag::RelSamplingWidth)
             m_rel_sampling_width.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -88,10 +88,9 @@ void SymmetricResolutionItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<DistributionItem>(r, tag, this);
-        else if (tag == Tag::Mean) {
+        else if (tag == Tag::Mean)
             m_mean.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -122,40 +121,28 @@ DoubleProperties DistributionNoneItem::distributionValues(bool withMean)
 
 DistributionGateItem::DistributionGateItem()
 {
-    m_minimum.init("Min", "", 0.0, 3, RealLimits::limitless(), "min");
-    m_maximum.init("Max", "", 1.0, 3, RealLimits::limitless(), "max");
+    m_center.init("Center", "", 0.0, 3, RealLimits::limitless(), "");
+    m_halfwidth.init("Half width", "", 1.0, 3, RealLimits::limitless(), "");
 }
 
 std::unique_ptr<IDistribution1D> DistributionGateItem::createDistribution(double scale) const
 {
-    return std::make_unique<DistributionGate>(scale * m_minimum.dVal(), scale * m_maximum.dVal(),
+    return std::make_unique<DistributionGate>(scale * (m_center.dVal() - m_halfwidth.dVal()),
+					      scale * (m_center.dVal() + m_halfwidth.dVal()),
                                               m_number_of_samples);
 }
 
 void DistributionGateItem::initDistribution(double value)
 {
-    double sigma(0.1 * std::abs(value));
-    if (sigma == 0.0)
-        sigma = 0.1;
-    m_minimum.setDVal(value - sigma);
-    m_maximum.setDVal(value + sigma);
-}
-
-void DistributionGateItem::setRange(double min, double max)
-{
-    m_minimum.setDVal(min);
-    m_maximum.setDVal(max);
+    m_center.setDVal(value);
+    m_halfwidth.setDVal(value / 2);
 }
 
 void DistributionGateItem::writeTo(QXmlStreamWriter* w) const
 {
     XML::writeBaseElement<DistributionItem>(w, XML::Tag::BaseData, this);
-
-    // minimum
-    m_minimum.writeTo2(w, Tag::Minimum);
-
-    // maximum
-    m_maximum.writeTo2(w, Tag::Maximum);
+    m_center.writeTo2(w, Tag::Center);
+    m_halfwidth.writeTo2(w, Tag::Halfwidth);
 }
 
 void DistributionGateItem::readFrom(QXmlStreamReader* r)
@@ -164,19 +151,18 @@ void DistributionGateItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<DistributionItem>(r, tag, this);
-        else if (tag == Tag::Minimum) {
-            m_minimum.readFrom2(r, tag);
-        } else if (tag == Tag::Maximum) {
-            m_maximum.readFrom2(r, tag);
-
-        } else
+        else if (tag == Tag::Center)
+            m_center.readFrom2(r, tag);
+        else if (tag == Tag::Halfwidth)
+            m_halfwidth.readFrom2(r, tag);
+        else
             r->skipCurrentElement();
     }
 }
 
 DoubleProperties DistributionGateItem::distributionValues(bool /*withMean*/)
 {
-    return {&m_minimum, &m_maximum};
+    return {&m_center, &m_halfwidth};
 }
 
 // --------------------------------------------------------------------------------------------- //
@@ -217,10 +203,9 @@ void DistributionLorentzItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<SymmetricResolutionItem>(r, tag, this);
-        else if (tag == Tag::HWHM) {
+        else if (tag == Tag::HWHM)
             m_hwhm.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -270,10 +255,9 @@ void DistributionGaussianItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<SymmetricResolutionItem>(r, tag, this);
-        else if (tag == Tag::StandardDeviation) {
+        else if (tag == Tag::StandardDeviation)
             m_standard_deviation.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -326,12 +310,11 @@ void DistributionLogNormalItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<DistributionItem>(r, tag, this);
-        else if (tag == Tag::Median) {
+        else if (tag == Tag::Median)
             m_median.readFrom2(r, tag);
-        } else if (tag == Tag::ScaleParameter) {
+        else if (tag == Tag::ScaleParameter)
             m_scale_parameter.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -379,10 +362,9 @@ void DistributionCosineItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<SymmetricResolutionItem>(r, tag, this);
-        else if (tag == Tag::Sigma) {
+        else if (tag == Tag::Sigma)
             m_hwhm.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
@@ -443,16 +425,15 @@ void DistributionTrapezoidItem::readFrom(QXmlStreamReader* r)
         QString tag = r->name().toString();
         if (tag == Tag::BaseData)
             XML::readBaseElement<DistributionItem>(r, tag, this);
-        else if (tag == Tag::Center) {
+        else if (tag == Tag::Center)
             m_center.readFrom2(r, tag);
-        } else if (tag == Tag::LeftWidth) {
+        else if (tag == Tag::LeftWidth)
             m_left_width.readFrom2(r, tag);
-        } else if (tag == Tag::MiddleWidth) {
+        else if (tag == Tag::MiddleWidth)
             m_middle_width.readFrom2(r, tag);
-        } else if (tag == Tag::RightWidth) {
+        else if (tag == Tag::RightWidth)
             m_right_width.readFrom2(r, tag);
-
-        } else
+        else
             r->skipCurrentElement();
     }
 }
diff --git a/GUI/Model/Beam/DistributionItems.h b/GUI/Model/Beam/DistributionItems.h
index 1bea7c34933..a80907edcbd 100644
--- a/GUI/Model/Beam/DistributionItems.h
+++ b/GUI/Model/Beam/DistributionItems.h
@@ -38,6 +38,9 @@ public:
     DoubleProperty& relSamplingWidth() { return m_rel_sampling_width; }
     const DoubleProperty& relSamplingWidth() const { return m_rel_sampling_width; }
 
+    virtual DoubleProperty& center() = 0;
+    virtual const DoubleProperty& center() const = 0;
+
     //! Serialization of contents.
     //!
     //! Important: limits will not be serialized here. They have
@@ -60,6 +63,9 @@ public:
     DoubleProperty& mean() { return m_mean; }
     const DoubleProperty& mean() const { return m_mean; }
 
+    DoubleProperty& center() override { return mean(); }
+    const DoubleProperty& center() const override { return mean(); }
+
     void writeTo(QXmlStreamWriter* w) const override;
     void readFrom(QXmlStreamReader* r) override;
 
@@ -84,13 +90,11 @@ public:
     std::unique_ptr<IDistribution1D> createDistribution(double scale = 1.0) const override;
     void initDistribution(double value) override;
 
-    DoubleProperty& minimum() { return m_minimum; }
-    const DoubleProperty& minimum() const { return m_minimum; }
-
-    DoubleProperty& maximum() { return m_maximum; }
-    const DoubleProperty& maximum() const { return m_maximum; }
+    DoubleProperty& center() override { return m_center; }
+    const DoubleProperty& center() const override { return m_center; }
 
-    void setRange(double min, double max);
+    DoubleProperty& halfwidth() { return m_halfwidth; }
+    const DoubleProperty& halfwidth() const { return m_halfwidth; }
 
     void writeTo(QXmlStreamWriter* w) const override;
     void readFrom(QXmlStreamReader* r) override;
@@ -98,8 +102,8 @@ public:
     DoubleProperties distributionValues(bool withMean = true) override;
 
 private:
-    DoubleProperty m_minimum;
-    DoubleProperty m_maximum;
+    DoubleProperty m_center;
+    DoubleProperty m_halfwidth;
 };
 
 class DistributionLorentzItem : public SymmetricResolutionItem {
@@ -152,6 +156,9 @@ public:
     DoubleProperty& median() { return m_median; }
     const DoubleProperty& median() const { return m_median; }
 
+    DoubleProperty& center() override { return median(); }
+    const DoubleProperty& center() const override { return median(); }
+
     DoubleProperty& scaleParameter() { return m_scale_parameter; }
     const DoubleProperty& scaleParameter() const { return m_scale_parameter; }
 
@@ -191,8 +198,8 @@ public:
     std::unique_ptr<IDistribution1D> createDistribution(double scale = 1.0) const override;
     void initDistribution(double value) override;
 
-    DoubleProperty& center() { return m_center; }
-    const DoubleProperty& center() const { return m_center; }
+    DoubleProperty& center() override { return m_center; }
+    const DoubleProperty& center() const override { return m_center; }
 
     DoubleProperty& leftWidth() { return m_left_width; }
     const DoubleProperty& leftWidth() const { return m_left_width; }
diff --git a/GUI/Model/FromCore/ItemizeSimulation.cpp b/GUI/Model/FromCore/ItemizeSimulation.cpp
index 23f752f3b75..38ebcd904ca 100644
--- a/GUI/Model/FromCore/ItemizeSimulation.cpp
+++ b/GUI/Model/FromCore/ItemizeSimulation.cpp
@@ -135,7 +135,8 @@ void setDistributionTypeAndPars(BeamDistributionItem* pdi, const IDistribution1D
 
     if (const auto* dd = dynamic_cast<const DistributionGate*>(d)) {
         auto* item = di.createCertainItem<DistributionGateItem>();
-        item->setRange(factor * dd->min(), factor * dd->max());
+        item->center().setDVal(factor * (dd->min() + dd->max()) / 2);
+        item->halfwidth().setDVal(factor * (dd->max() - dd->min()) / 2);
     } else if (const auto* dd = dynamic_cast<const DistributionLorentz*>(d)) {
         auto* item = di.createCertainItem<DistributionLorentzItem>();
         item->mean().setDVal(factor * dd->mean());
diff --git a/GUI/View/Device/DistributionSelector.cpp b/GUI/View/Device/DistributionSelector.cpp
index 2545fee5ce4..9470b825aae 100644
--- a/GUI/View/Device/DistributionSelector.cpp
+++ b/GUI/View/Device/DistributionSelector.cpp
@@ -56,20 +56,8 @@ void DistributionSelector::createDistributionWidgets()
         createSpinBox(it->hwhm());
         createNumSamplesSpinBox(it);
     } else if (auto* it = dynamic_cast<DistributionGateItem*>(m_item->distributionItem())) {
-        auto* minSpinBox = createSpinBox(it->minimum());
-        auto* maxSpinBox = createSpinBox(it->maximum());
-        connect(minSpinBox, &DSpinBox::valueChanged, [it, maxSpinBox](double d) {
-            if (d > it->maximum().dVal()) {
-                it->maximum().setDVal(d);
-                maxSpinBox->updateValue();
-            }
-        });
-        connect(maxSpinBox, &DSpinBox::valueChanged, [it, minSpinBox](double d) {
-            if (d < it->minimum().dVal()) {
-                it->minimum().setDVal(d);
-                minSpinBox->updateValue();
-            }
-        });
+        createSpinBox(it->center());
+        createSpinBox(it->halfwidth());
         createNumSamplesSpinBox(it);
     } else if (auto* it = dynamic_cast<DistributionGaussianItem*>(m_item->distributionItem())) {
         createMeanSpinBox(it->mean());
-- 
GitLab