From b12a6be8f52c1aa2e6e9218e4265c33e7eecdf8a Mon Sep 17 00:00:00 2001
From: Matthias Puchner <github@mpuchner.de>
Date: Thu, 20 May 2021 12:27:52 +0200
Subject: [PATCH] add convenience functions to axis classes; rectified error
 texts

necessary for later refactoring
---
 Base/Axis/ConstKBinAxis.cpp   | 32 ++++++++++++++++-------------
 Base/Axis/ConstKBinAxis.h     |  3 ++-
 Base/Axis/CustomBinAxis.cpp   | 10 +++++++--
 Base/Axis/CustomBinAxis.h     |  3 ++-
 Base/Axis/FixedBinAxis.cpp    | 38 +++++++++++++++++++++++------------
 Base/Axis/FixedBinAxis.h      |  3 ++-
 Base/Axis/IAxis.cpp           | 21 +++++++++++++++++--
 Base/Axis/IAxis.h             | 14 +++++++++++--
 Base/Axis/PointwiseAxis.cpp   | 19 +++++++++++-------
 Base/Axis/PointwiseAxis.h     |  4 ++--
 Base/Axis/VariableBinAxis.cpp | 36 ++++++++++++++++++---------------
 Base/Axis/VariableBinAxis.h   |  3 ++-
 12 files changed, 124 insertions(+), 62 deletions(-)

diff --git a/Base/Axis/ConstKBinAxis.cpp b/Base/Axis/ConstKBinAxis.cpp
index f85afab72b2..9a60913bc7f 100644
--- a/Base/Axis/ConstKBinAxis.cpp
+++ b/Base/Axis/ConstKBinAxis.cpp
@@ -45,19 +45,24 @@ ConstKBinAxis* ConstKBinAxis::clone() const
     return new ConstKBinAxis(getName(), m_nbins, m_start, m_end);
 }
 
-ConstKBinAxis* ConstKBinAxis::createClippedAxis(double left, double right) const
+ConstKBinAxis* ConstKBinAxis::createClippedAxis(double lower, double upper) const
 {
-    if (left >= right)
+    return static_cast<ConstKBinAxis*>(IAxis::createClippedAxis(lower, upper));
+}
+
+void ConstKBinAxis::clip(double lower, double upper)
+{
+    if (lower >= upper)
         throw std::runtime_error(
-            "ConstKBinAxis::createClippedAxis() -> Error. 'left'' should be smaller than 'right'");
+            "ConstKBinAxis::clip() -> Error. 'lower' should be smaller than 'upper'");
 
-    if (left < lowerBound())
-        left = bin(0).center();
-    if (right >= upperBound())
-        right = bin(size() - 1).center();
+    if (lower < lowerBound())
+        lower = bin(0).center();
+    if (upper >= upperBound())
+        upper = bin(size() - 1).center();
 
-    size_t nbin1 = findClosestIndex(left);
-    size_t nbin2 = findClosestIndex(right);
+    size_t nbin1 = findClosestIndex(lower);
+    size_t nbin2 = findClosestIndex(upper);
 
     size_t new_nbins = nbin2 - nbin1 + 1;
     std::vector<double> new_boundaries;
@@ -66,11 +71,10 @@ ConstKBinAxis* ConstKBinAxis::createClippedAxis(double left, double right) const
         new_boundaries.push_back(old_boundaries[nbin1 + i]);
     }
 
-    ConstKBinAxis* result = new ConstKBinAxis(getName(), new_nbins);
-    result->m_start = new_boundaries.front();
-    result->m_end = new_boundaries.back();
-    result->setBinBoundaries(new_boundaries);
-    return result;
+    m_nbins = new_nbins;
+    m_start = new_boundaries.front();
+    m_end = new_boundaries.back();
+    setBinBoundaries(new_boundaries);
 }
 
 bool ConstKBinAxis::equals(const IAxis& other) const
diff --git a/Base/Axis/ConstKBinAxis.h b/Base/Axis/ConstKBinAxis.h
index 61bb459bc36..c210243939d 100644
--- a/Base/Axis/ConstKBinAxis.h
+++ b/Base/Axis/ConstKBinAxis.h
@@ -32,7 +32,8 @@ public:
 
     ConstKBinAxis* clone() const override;
 
-    ConstKBinAxis* createClippedAxis(double left, double right) const override;
+    ConstKBinAxis* createClippedAxis(double lower, double upper) const override;
+    virtual void clip(double lower, double upper) override;
 
 protected:
     ConstKBinAxis(const std::string& name, size_t nbins);
diff --git a/Base/Axis/CustomBinAxis.cpp b/Base/Axis/CustomBinAxis.cpp
index 60ffa025623..d76b4a4372d 100644
--- a/Base/Axis/CustomBinAxis.cpp
+++ b/Base/Axis/CustomBinAxis.cpp
@@ -60,9 +60,15 @@ std::vector<double> CustomBinAxis::binCenters() const
     return m_bin_centers;
 }
 
-CustomBinAxis* CustomBinAxis::createClippedAxis(double /* left */, double /* right */) const
+CustomBinAxis* CustomBinAxis::createClippedAxis(double /* lower */, double /* upper */) const
 {
-    throw std::runtime_error("VariableBinAxis::CustomBinAxis() -> Error."
+    throw std::runtime_error("CustomBinAxis::createClippedAxis() -> Error."
+                             " Not implemented.");
+}
+
+void CustomBinAxis::clip(double /* lower */, double /* upper */)
+{
+    throw std::runtime_error("CustomBinAxis::clip() -> Error."
                              " Not implemented.");
 }
 
diff --git a/Base/Axis/CustomBinAxis.h b/Base/Axis/CustomBinAxis.h
index 31e051d2048..2e4a0c82f8d 100644
--- a/Base/Axis/CustomBinAxis.h
+++ b/Base/Axis/CustomBinAxis.h
@@ -37,7 +37,8 @@ public:
 
     std::vector<double> binCenters() const;
 
-    CustomBinAxis* createClippedAxis(double left, double right) const;
+    CustomBinAxis* createClippedAxis(double lower, double upper) const override;
+    virtual void clip(double lower, double upper) override;
 
 protected:
     void print(std::ostream& ostr) const;
diff --git a/Base/Axis/FixedBinAxis.cpp b/Base/Axis/FixedBinAxis.cpp
index b41ef06d077..ba743d387ef 100644
--- a/Base/Axis/FixedBinAxis.cpp
+++ b/Base/Axis/FixedBinAxis.cpp
@@ -80,21 +80,33 @@ std::vector<double> FixedBinAxis::binBoundaries() const
     return result;
 }
 
-FixedBinAxis* FixedBinAxis::createClippedAxis(double left, double right) const
+FixedBinAxis* FixedBinAxis::createClippedAxis(double lower, double upper) const
 {
-    if (left >= right)
-        throw std::runtime_error("FixedBinAxis::createClippedAxis() -> Error. "
-                                 "'left' should be smaller than 'right'");
-
-    if (left < lowerBound())
-        left = bin(0).center();
-    if (right >= upperBound())
-        right = bin(size() - 1).center();
-
-    size_t nbin1 = findClosestIndex(left);
-    size_t nbin2 = findClosestIndex(right);
+    return static_cast<FixedBinAxis*>(IAxis::createClippedAxis(lower, upper));
+}
 
-    return new FixedBinAxis(getName(), nbin2 - nbin1 + 1, bin(nbin1).m_lower, bin(nbin2).m_upper);
+void FixedBinAxis::clip(double lower, double upper)
+{
+    if (lower >= upper)
+        throw std::runtime_error(
+            "FixedBinAxis::clip() -> Error. 'lower' should be smaller than 'upper'");
+
+    if (lower < lowerBound())
+        lower = bin(0).center();
+    if (upper >= upperBound())
+        upper = bin(size() - 1).center();
+
+    const size_t nbin1 = findClosestIndex(lower);
+    const size_t nbin2 = findClosestIndex(upper);
+
+    // create tmp vars until everything is calculated, otherwise the calculation will be corrupted
+    // by partially changed values
+    const auto newStart = bin(nbin1).m_lower;
+    const auto newEnd = bin(nbin2).m_upper;
+
+    m_nbins = nbin2 - nbin1 + 1;
+    m_start = newStart;
+    m_end = newEnd;
 }
 
 void FixedBinAxis::print(std::ostream& ostr) const
diff --git a/Base/Axis/FixedBinAxis.h b/Base/Axis/FixedBinAxis.h
index 3bd6063a1bb..5440635d09c 100644
--- a/Base/Axis/FixedBinAxis.h
+++ b/Base/Axis/FixedBinAxis.h
@@ -49,7 +49,8 @@ public:
 
     std::vector<double> binBoundaries() const;
 
-    FixedBinAxis* createClippedAxis(double left, double right) const;
+    FixedBinAxis* createClippedAxis(double lower, double upper) const override;
+    void clip(double lower, double upper) override;
 
 protected:
     void print(std::ostream& ostr) const;
diff --git a/Base/Axis/IAxis.cpp b/Base/Axis/IAxis.cpp
index c1c772d6bcb..9431c618d66 100644
--- a/Base/Axis/IAxis.cpp
+++ b/Base/Axis/IAxis.cpp
@@ -29,9 +29,21 @@ std::vector<double> IAxis::binBoundaries() const
     throw std::runtime_error("IAxis::binBoundaries() -> Error. Not implemented.");
 }
 
-IAxis* IAxis::createClippedAxis(double /* left */, double /* right */) const
+IAxis* IAxis::createClippedAxis(double lower, double upper) const
 {
-    throw std::runtime_error("IAxis::createClippedAxis() -> Error. Not implemented.");
+    auto newAxis = clone();
+    newAxis->clip(lower, upper);
+    return newAxis;
+}
+
+void IAxis::clip(double lower, double upper)
+{
+    throw std::runtime_error("IAxis::clip() -> Error. Not implemented.");
+}
+
+void IAxis::clip(const std::pair<double, double> bounds)
+{
+    return clip(bounds.first, bounds.second);
 }
 
 bool IAxis::contains(double value) const
@@ -39,6 +51,11 @@ bool IAxis::contains(double value) const
     return value >= lowerBound() && value < upperBound();
 }
 
+std::pair<double, double> IAxis::bounds() const
+{
+    return {lowerBound(), upperBound()};
+}
+
 double IAxis::span() const
 {
     return upperBound() - lowerBound();
diff --git a/Base/Axis/IAxis.h b/Base/Axis/IAxis.h
index ca2c3b0eaf4..f8604160f17 100644
--- a/Base/Axis/IAxis.h
+++ b/Base/Axis/IAxis.h
@@ -44,6 +44,10 @@ public:
     //! Returns value of last point of axis
     virtual double upperBound() const = 0;
 
+    //! Returns lower and upper bound in a pair.
+    //! first is lower, second is upper.
+    std::pair<double, double> bounds() const;
+
     //! Returns distance from first to last point
     double span() const;
 
@@ -72,10 +76,16 @@ public:
     virtual bool contains(double value) const;
 
     //! Creates a new clipped axis
-    virtual IAxis* createClippedAxis(double left, double right) const;
+    virtual IAxis* createClippedAxis(double lower, double upper) const;
+
+    //! Clips this axis to the given values
+    virtual void clip(double lower, double upper);
+
+    //! Convenience overload to clip this axis to the given values.
+    //! bounds.first is lower, bounds.second is upper value.
+    void clip(const std::pair<double, double> bounds);
 
     //! test for equality
-    //!
     bool operator==(const IAxis& right) const { return equals(right); }
     bool operator!=(const IAxis& right) const { return !(*this == right); }
 
diff --git a/Base/Axis/PointwiseAxis.cpp b/Base/Axis/PointwiseAxis.cpp
index 567ca3353d9..021799a3451 100644
--- a/Base/Axis/PointwiseAxis.cpp
+++ b/Base/Axis/PointwiseAxis.cpp
@@ -70,17 +70,22 @@ std::vector<double> PointwiseAxis::binBoundaries() const
     return result;
 }
 
-PointwiseAxis* PointwiseAxis::createClippedAxis(double left, double right) const
+PointwiseAxis* PointwiseAxis::createClippedAxis(double lower, double upper) const
 {
-    if (left >= right)
-        throw std::runtime_error("Error in PointwiseAxis::createClippedAxis: "
-                                 "'left' should be smaller than 'right'");
+    return static_cast<PointwiseAxis*>(IAxis::createClippedAxis(lower, upper));
+}
+
+void PointwiseAxis::clip(double lower, double upper)
+{
+    if (lower >= upper)
+        throw std::runtime_error(
+            "PointwiseAxis::clip() -> Error. 'lower' should be smaller than 'upper'");
 
     using diff_t = std::vector<double>::iterator::difference_type;
-    auto begin = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(left));
-    auto end = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(right)) + 1;
+    const auto begin = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(lower));
+    const auto end = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(upper)) + 1;
 
-    return new PointwiseAxis(getName(), std::vector<double>(begin, end));
+    m_coordinates = std::vector<double>(begin, end);
 }
 
 void PointwiseAxis::print(std::ostream& ostr) const
diff --git a/Base/Axis/PointwiseAxis.h b/Base/Axis/PointwiseAxis.h
index 9a74bdc3208..0e321bda786 100644
--- a/Base/Axis/PointwiseAxis.h
+++ b/Base/Axis/PointwiseAxis.h
@@ -75,8 +75,8 @@ public:
 
     std::vector<double> binBoundaries() const override;
 
-    //! Creates a new clipped axis
-    PointwiseAxis* createClippedAxis(double left, double right) const override;
+    PointwiseAxis* createClippedAxis(double lower, double upper) const override;
+    virtual void clip(double lower, double upper) override;
 
 private:
     void print(std::ostream& ostr) const override;
diff --git a/Base/Axis/VariableBinAxis.cpp b/Base/Axis/VariableBinAxis.cpp
index c5f70197029..a3017ddb117 100644
--- a/Base/Axis/VariableBinAxis.cpp
+++ b/Base/Axis/VariableBinAxis.cpp
@@ -97,28 +97,32 @@ std::vector<double> VariableBinAxis::binCenters() const
     return result;
 }
 
-VariableBinAxis* VariableBinAxis::createClippedAxis(double left, double right) const
+VariableBinAxis* VariableBinAxis::createClippedAxis(double lower, double upper) const
 {
+    return static_cast<VariableBinAxis*>(IAxis::createClippedAxis(lower, upper));
+}
 
-    if (left >= right)
-        throw std::runtime_error("VariableBinAxis::createClippedAxis() -> Error. "
-                                 "'left'' should be smaller than 'right'");
+void VariableBinAxis::clip(double lower, double upper)
+{
+    if (lower >= upper)
+        throw std::runtime_error("VariableBinAxis::clip() -> Error. "
+                                 "'lower' should be smaller than 'upper'");
 
-    if (left < lowerBound())
-        left = bin(0).center();
-    if (right >= upperBound())
-        right = bin(size() - 1).center();
+    if (lower < lowerBound())
+        lower = bin(0).center();
+    if (upper >= upperBound())
+        upper = bin(size() - 1).center();
 
-    size_t nbin1 = findClosestIndex(left);
-    size_t nbin2 = findClosestIndex(right);
+    const size_t nbin1 = findClosestIndex(lower);
+    const size_t nbin2 = findClosestIndex(upper);
+    const size_t new_nbins = nbin2 - nbin1 + 1;
 
-    size_t new_nbins = nbin2 - nbin1 + 1;
     std::vector<double> new_boundaries;
-    for (size_t i = 0; i < new_nbins + 1; ++i) {
+    for (size_t i = 0; i < new_nbins + 1; ++i)
         new_boundaries.push_back(m_bin_boundaries[nbin1 + i]);
-    }
 
-    return new VariableBinAxis(getName(), new_nbins, new_boundaries);
+    m_nbins = new_nbins;
+    setBinBoundaries(new_boundaries);
 }
 
 void VariableBinAxis::print(std::ostream& ostr) const
@@ -156,7 +160,7 @@ void VariableBinAxis::setBinBoundaries(const std::vector<double>& bin_boundaries
     std::sort(vec_sorted.begin(), vec_sorted.end());
     for (size_t i = 0; i < bin_boundaries.size(); ++i) {
         if (vec_sorted[i] != bin_boundaries[i])
-            throw std::runtime_error("VariableBinAxis::VariableBinAxis() -> Error. "
+            throw std::runtime_error("VariableBinAxis::setBinBoundaries() -> Error. "
                                      "Array with bin edges is not sorted.");
     }
 
@@ -164,7 +168,7 @@ void VariableBinAxis::setBinBoundaries(const std::vector<double>& bin_boundaries
     vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
 
     if (vec.size() != bin_boundaries.size())
-        throw std::runtime_error("VariableBinAxis::VariableBinAxis() -> Error. "
+        throw std::runtime_error("VariableBinAxis::setBinBoundaries() -> Error. "
                                  "Array with bin edges contains repeating values.");
 
     m_bin_boundaries = bin_boundaries;
diff --git a/Base/Axis/VariableBinAxis.h b/Base/Axis/VariableBinAxis.h
index cae3dc33233..a1b7e855a00 100644
--- a/Base/Axis/VariableBinAxis.h
+++ b/Base/Axis/VariableBinAxis.h
@@ -49,7 +49,8 @@ public:
     std::vector<double> binCenters() const;
     std::vector<double> binBoundaries() const { return m_bin_boundaries; }
 
-    virtual VariableBinAxis* createClippedAxis(double left, double right) const;
+    virtual VariableBinAxis* createClippedAxis(double lower, double upper) const override;
+    virtual void clip(double lower, double upper) override;
 
 protected:
     VariableBinAxis(const std::string& name, size_t nbins = 0);
-- 
GitLab