changeset 1906:925aaf49150c

minor fix in UnionOfRectangles
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 31 Jan 2022 22:32:31 +0100
parents e318b524ad3f
children 0208f99b8bde
files OrthancStone/Sources/Toolbox/UnionOfRectangles.cpp OrthancStone/UnitTestsSources/ComputationalGeometryTests.cpp
diffstat 2 files changed, 97 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Toolbox/UnionOfRectangles.cpp	Mon Jan 31 18:50:35 2022 +0100
+++ b/OrthancStone/Sources/Toolbox/UnionOfRectangles.cpp	Mon Jan 31 22:32:31 2022 +0100
@@ -211,7 +211,7 @@
   {
     if (stack.size() % 2 != 0)
     {
-      throw std::runtime_error("internal error");
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
 
     typedef std::pair<size_t, size_t>  Interval;
@@ -224,7 +224,7 @@
       stack.pop();
       size_t low = stack.top();
       stack.pop();
-    
+
       if (!intervals.empty() &&
           intervals.back().second == low)
       {
@@ -240,19 +240,43 @@
     for (std::list<Interval>::const_iterator
            it = intervals.begin(); it != intervals.end(); ++it)
     {
-      if (it->first == it->second)
+      if (it->first >= it->second)
       {
-        throw std::runtime_error("parameter out of range");
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
       }
     
       // By convention, the left sides go downward, and the right go upward
       if (isLeft)
       {
-        edges.push_back(Internals::OrientedIntegerLine2D(x, it->first, x, it->second));
+        if (!edges.empty() &&
+            edges.back().GetX1() == x &&
+            edges.back().GetX2() == x &&
+            edges.back().GetY1() == it->second &&
+            edges.back().GetY2() == it->first)
+        {
+          // The two successive vertical segments cancel each other
+          edges.pop_back();
+        }
+        else
+        {
+          edges.push_back(Internals::OrientedIntegerLine2D(x, it->first, x, it->second));
+        }
       }
       else
       {
-        edges.push_back(Internals::OrientedIntegerLine2D(x, it->second, x, it->first));
+        if (!edges.empty() &&
+            edges.back().GetX1() == x &&
+            edges.back().GetX2() == x &&
+            edges.back().GetY1() == it->first &&
+            edges.back().GetY2() == it->second)
+        {
+          // The two successive vertical segments cancel each other
+          edges.pop_back();
+        }
+        else
+        {
+          edges.push_back(Internals::OrientedIntegerLine2D(x, it->second, x, it->first));
+        }
       }
     }
   }
--- a/OrthancStone/UnitTestsSources/ComputationalGeometryTests.cpp	Mon Jan 31 18:50:35 2022 +0100
+++ b/OrthancStone/UnitTestsSources/ComputationalGeometryTests.cpp	Mon Jan 31 22:32:31 2022 +0100
@@ -561,9 +561,33 @@
 
   fprintf(fp, "<rect fill=\"#fff\" stroke=\"#000\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n", ww, hh);
 
+  unsigned int count = 0;
+  
   for (std::list< std::vector<OrthancStone::ScenePoint2D> >::const_iterator
-         it = contours.begin(); it != contours.end(); ++it)
+         it = contours.begin(); it != contours.end(); ++it, count++)
   {
+    std::string color;
+    if (count == 0)
+    {
+      color = "blue";
+    }
+    else if (count == 1)
+    {
+      color = "red";
+    }
+    else if (count == 2)
+    {
+      color = "green";
+    }
+    else if (count == 3)
+    {
+      color = "orange";
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+    
     for (size_t i = 0; i + 1 < it->size(); i++)
     {
       float x1 = (*it)[i].GetX();
@@ -571,7 +595,7 @@
       float y1 = (*it)[i].GetY();
       float y2 = (*it)[i + 1].GetY();
       
-      fprintf(fp, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"blue\" stroke-width=\"0.05\" marker-end=\"url(#arrowhead)\"/>\n", x1, y1, x2, y2);
+      fprintf(fp, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"%s\" stroke-width=\"0.05\" marker-end=\"url(#arrowhead)\"/>\n", x1, y1, x2, y2, color.c_str());
     }
   }
   fprintf(fp, "</svg>\n");
@@ -653,25 +677,29 @@
     std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
     OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
 
-    ASSERT_EQ(1u, contours.size());
-    ASSERT_EQ(17u, contours.front().size());
+    ASSERT_EQ(2u, contours.size());
+
+    ASSERT_EQ(9u, contours.front().size());
     ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
     ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 8)));
     ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
     ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(10, 6)));
     ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(10, 4)));
     ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
-    ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(7, 2)));
-    ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
-    ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
-    ASSERT_TRUE(contours.front()[9].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
-    ASSERT_TRUE(contours.front()[10].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
-    ASSERT_TRUE(contours.front()[11].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
-    ASSERT_TRUE(contours.front()[12].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
-    ASSERT_TRUE(contours.front()[13].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
-    ASSERT_TRUE(contours.front()[14].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
-    ASSERT_TRUE(contours.front()[15].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
-    ASSERT_TRUE(contours.front()[16].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
+    ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
+    ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
+    ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
+
+    ASSERT_EQ(9u, contours.back().size());
+    ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
+    ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
+    ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
+    ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
+    ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(7, 2)));
+    ASSERT_TRUE(contours.back()[5].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
+    ASSERT_TRUE(contours.back()[6].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
+    ASSERT_TRUE(contours.back()[7].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
+    ASSERT_TRUE(contours.back()[8].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
   }
   
   {
@@ -736,7 +764,7 @@
 
   {
     std::list<OrthancStone::Extent2D>  rectangles;
-    rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
+    rectangles.push_back(OrthancStone::Extent2D(1, 4, 5, 6));
     rectangles.push_back(OrthancStone::Extent2D(6, 4, 9, 6));
     rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
     rectangles.push_back(OrthancStone::Extent2D(4, 2, 7, 6));
@@ -763,7 +791,7 @@
 
   {
     std::list<OrthancStone::Extent2D>  rectangles;
-    rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
+    rectangles.push_back(OrthancStone::Extent2D(1, 4, 5, 6));
     rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
     rectangles.push_back(OrthancStone::Extent2D(4, 2, 7, 6));
 
@@ -896,17 +924,21 @@
     std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
     OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
 
-    ASSERT_EQ(1u, contours.size());
-    ASSERT_EQ(9u, contours.front().size());
+    ASSERT_EQ(2u, contours.size());
+
+    ASSERT_EQ(5u, contours.front().size());
     ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
     ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
     ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(4, 3)));
     ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
-    ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
-    ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
-    ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
-    ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
-    ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
+    ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
+
+    ASSERT_EQ(5u, contours.back().size());
+    ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
+    ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
+    ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
+    ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
+    ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
   }
 
   {
@@ -938,17 +970,21 @@
     std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
     OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
 
-    ASSERT_EQ(1u, contours.size());
-    ASSERT_EQ(9u, contours.front().size());
+    ASSERT_EQ(2u, contours.size());
+
+    ASSERT_EQ(5u, contours.front().size());
     ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
     ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
     ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
     ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
-    ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
-    ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
-    ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
-    ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
-    ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
+    ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
+
+    ASSERT_EQ(5u, contours.back().size());
+    ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
+    ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
+    ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
+    ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
+    ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
   }
 
   {