From f711d6cd593ccf181e4cc27e3c1dd31f0ae32d82 Mon Sep 17 00:00:00 2001
From: Matthias Puchner <github@mpuchner.de>
Date: Thu, 20 May 2021 14:19:22 +0200
Subject: [PATCH] add inversion possibility to Rectangle

add unit tests as well
---
 Device/Mask/Rectangle.cpp                 | 11 ++++++--
 Device/Mask/Rectangle.h                   |  7 +++--
 Tests/UnitTests/Core/Mask/Shape2DTest.cpp | 31 +++++++++++++++++++++++
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/Device/Mask/Rectangle.cpp b/Device/Mask/Rectangle.cpp
index c457cf453e6..73ed150db20 100644
--- a/Device/Mask/Rectangle.cpp
+++ b/Device/Mask/Rectangle.cpp
@@ -19,7 +19,8 @@
 //! @param ylow y-coordinate of lower left corner
 //! @param xup x-coordinate of upper right corner
 //! @param yup y-coordinate of upper right corner
-Rectangle::Rectangle(double xlow, double ylow, double xup, double yup) : IShape2D("Rectangle")
+Rectangle::Rectangle(double xlow, double ylow, double xup, double yup, bool inverted)
+    : IShape2D("Rectangle"), m_inverted(inverted)
 {
     if (xup <= xlow) {
         std::ostringstream message;
@@ -39,9 +40,15 @@ Rectangle::Rectangle(double xlow, double ylow, double xup, double yup) : IShape2
     m_yup = yup;
 }
 
+void Rectangle::setInverted(bool inverted /*= true*/)
+{
+    m_inverted = inverted;
+}
+
 bool Rectangle::contains(double x, double y) const
 {
-    return x <= m_xup && x >= m_xlow && y <= m_yup && y >= m_ylow;
+    const bool inRect = x <= m_xup && x >= m_xlow && y <= m_yup && y >= m_ylow;
+    return m_inverted ? !inRect : inRect;
 }
 
 bool Rectangle::contains(const Bin1D& binx, const Bin1D& biny) const
diff --git a/Device/Mask/Rectangle.h b/Device/Mask/Rectangle.h
index bf7b4da4af4..0140c3444b3 100644
--- a/Device/Mask/Rectangle.h
+++ b/Device/Mask/Rectangle.h
@@ -24,8 +24,10 @@
 
 class Rectangle : public IShape2D {
 public:
-    Rectangle(double xlow, double ylow, double xup, double yup);
-    Rectangle* clone() const { return new Rectangle(m_xlow, m_ylow, m_xup, m_yup); }
+    Rectangle(double xlow, double ylow, double xup, double yup, bool inverted = false);
+    Rectangle* clone() const { return new Rectangle(m_xlow, m_ylow, m_xup, m_yup, m_inverted); }
+
+    void setInverted(bool inverted = true);
 
     bool contains(double x, double y) const;
     bool contains(const Bin1D& binx, const Bin1D& biny) const;
@@ -39,6 +41,7 @@ public:
 
 private:
     double m_xlow, m_ylow, m_xup, m_yup;
+    bool m_inverted;
 };
 
 #endif // BORNAGAIN_DEVICE_MASK_RECTANGLE_H
diff --git a/Tests/UnitTests/Core/Mask/Shape2DTest.cpp b/Tests/UnitTests/Core/Mask/Shape2DTest.cpp
index 7213291b224..6037f7be5e0 100644
--- a/Tests/UnitTests/Core/Mask/Shape2DTest.cpp
+++ b/Tests/UnitTests/Core/Mask/Shape2DTest.cpp
@@ -41,6 +41,37 @@ TEST_F(Shape2DTest, Rectangle)
     EXPECT_FALSE(clone->contains(binx2, biny2));
 }
 
+TEST_F(Shape2DTest, Rectangle_inverted)
+{
+    Rectangle rect(-4.0, -2.0, 4.0, 2.0, true);
+    EXPECT_DOUBLE_EQ(32.0, rect.getArea());
+    EXPECT_FALSE(rect.contains(0.0, 0.0));
+    EXPECT_FALSE(rect.contains(4.0, 2.0));
+    EXPECT_FALSE(rect.contains(-4.0, -2.0));
+    EXPECT_FALSE(rect.contains(-4.0, -2.0));
+    EXPECT_TRUE(rect.contains(0.0, 2.01));
+    EXPECT_TRUE(rect.contains(4.0, -2.01));
+
+    Bin1D binx1(3.5, 4.5);
+    Bin1D biny1(1.5, 2.5);
+    EXPECT_FALSE(rect.contains(binx1, biny1));
+
+    Bin1D binx2(3.5, 4.6);
+    Bin1D biny2(1.5, 2.6);
+    EXPECT_TRUE(rect.contains(binx2, biny2));
+
+    std::unique_ptr<Rectangle> clone(rect.clone());
+    EXPECT_DOUBLE_EQ(32.0, clone->getArea());
+    EXPECT_FALSE(clone->contains(0.0, 0.0));
+    EXPECT_FALSE(clone->contains(4.0, 2.0));
+    EXPECT_FALSE(clone->contains(-4.0, -2.0));
+    EXPECT_FALSE(clone->contains(-4.0, -2.0));
+    EXPECT_TRUE(clone->contains(0.0, 2.01));
+    EXPECT_TRUE(clone->contains(4.0, -2.01));
+    EXPECT_FALSE(clone->contains(binx1, biny1));
+    EXPECT_TRUE(clone->contains(binx2, biny2));
+}
+
 TEST_F(Shape2DTest, Ellipse)
 {
     Ellipse ellipse(10.0, 1.0, 8.0, 4.0);
-- 
GitLab