changeset 1961:cbf54cd28d59

added CoordinateSystem3D::GetOrientationMarkers()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 27 Oct 2022 18:43:20 +0200
parents 40f8009ceb4e
children c6272d7bb6d9
files OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp OrthancStone/Sources/Toolbox/CoordinateSystem3D.h OrthancStone/UnitTestsSources/GeometryToolboxTests.cpp
diffstat 3 files changed, 193 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp	Thu Oct 27 17:17:14 2022 +0200
+++ b/OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp	Thu Oct 27 18:43:20 2022 +0200
@@ -381,4 +381,109 @@
 
     return CoordinateSystem3D(a, axisX, axisY);
   }
+
+
+  static std::string GetOrientationString(const Vector& v)
+  {
+    /**
+     * This function directly comes from David Clunie:
+     * https://sites.google.com/site/dicomnotes/
+     *
+     * It is also a C++ reimplementation of function
+     * "getOrientationString()" from Cornerstone:
+     * https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/local_dependencies/cornerstoneTools/cornerstoneTools.js
+     **/
+
+    const char orientationX = v[0] < 0 ? 'R' : 'L';
+    const char orientationY = v[1] < 0 ? 'A' : 'P';
+    const char orientationZ = v[2] < 0 ? 'F' : 'H';
+
+    double absX = abs(v[0]);
+    double absY = abs(v[1]);
+    double absZ = abs(v[2]);
+
+    std::string result;
+
+    static const double THRESHOLD = 0.0001;
+
+    for (unsigned int i = 0; i < 3; i++)
+    {
+      if (absX > THRESHOLD && absX > absY && absX > absZ)
+      {
+        result.push_back(orientationX);
+        absX = 0;
+      }
+      else if (absY > THRESHOLD && absY > absX && absY > absZ)
+      {
+        result.push_back(orientationY);
+        absY = 0;
+      }
+      else if (absZ > THRESHOLD && absZ > absX && absZ > absY)
+      {
+        result.push_back(orientationZ);
+        absZ = 0;
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    return result;
+  }
+
+
+  static std::string InvertOrientationString(const std::string& source)
+  {
+    std::string target;
+    target.resize(source.length());
+
+    for (unsigned int i = 0; i < source.length(); i++)
+    {
+      switch (source[i])
+      {
+        case 'H': target[i] = 'F'; break;
+        case 'F': target[i] = 'H'; break;
+        case 'R': target[i] = 'L'; break;
+        case 'L': target[i] = 'R'; break;
+        case 'A': target[i] = 'P'; break;
+        case 'P': target[i] = 'A'; break;
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+
+    return target;
+  }
+
+
+  void CoordinateSystem3D::GetOrientationMarkers(std::string& top /* out */,
+                                                 std::string& bottom /* out */,
+                                                 std::string& left /* out */,
+                                                 std::string& right /* out */) const
+  {
+    if (IsValid())
+    {
+      /**
+       * This is a C++ reimplementation of function
+       * "getOrientationMarkers()" from Cornerstone:
+       * https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/local_dependencies/cornerstoneTools/cornerstoneTools.js
+       *
+       * ImageOrientationPatient is row cosines then column cosines
+       * (i.e. horizontal then vertical).
+       * https://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.2
+       **/
+      const Vector& rowCosines = axisX_;  // horizontal
+      const Vector& columnCosines = axisY_;  // vertical
+
+      bottom = GetOrientationString(columnCosines);
+      right = GetOrientationString(rowCosines);
+      top = InvertOrientationString(bottom);
+      left = InvertOrientationString(right);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
 }
--- a/OrthancStone/Sources/Toolbox/CoordinateSystem3D.h	Thu Oct 27 17:17:14 2022 +0200
+++ b/OrthancStone/Sources/Toolbox/CoordinateSystem3D.h	Thu Oct 27 18:43:20 2022 +0200
@@ -160,5 +160,10 @@
     static CoordinateSystem3D CreateFromThreePoints(const Vector& a,
                                                     const Vector& b,
                                                     const Vector& c);
+
+    void GetOrientationMarkers(std::string& top /* out */,
+                               std::string& bottom /* out */,
+                               std::string& left /* out */,
+                               std::string& right /* out */) const;
   };
 }
--- a/OrthancStone/UnitTestsSources/GeometryToolboxTests.cpp	Thu Oct 27 17:17:14 2022 +0200
+++ b/OrthancStone/UnitTestsSources/GeometryToolboxTests.cpp	Thu Oct 27 18:43:20 2022 +0200
@@ -1091,3 +1091,86 @@
     ASSERT_EQ(376u - 323u, slice);
   }
 }
+
+
+TEST(GeometryToolbox, OrientationMarkers)
+{
+  std::string top, bottom, left, right;
+
+  OrthancStone::CoordinateSystem3D s;
+  ASSERT_FALSE(s.IsValid());
+  ASSERT_THROW(s.GetOrientationMarkers(top, bottom, left, right), Orthanc::OrthancException);
+
+  {
+    // BRAINIX series: 3ca69615-fcd4a4fb-e5f2cc9d-9c7a49a5-add98bbf
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "0.99971222877502\\7.8810308973E-12\\0.02398800104856\\-0.0017278126906\\0.99740260839462\\0.07200747728347");
+    ASSERT_TRUE(s.IsValid());
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("AFL", top);
+    ASSERT_EQ("PHR", bottom);
+    ASSERT_EQ("RF", left);
+    ASSERT_EQ("LH", right);
+  }
+
+  {
+    // BRAINIX series: dc0216d2-a406a5ad-31ef7a78-113ae9d9-29939f9e
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "0.99971222877502\\7.8810308973E-12\\0.02398800104856\\0.02392569556832\\0.07202820479869\\-0.9971156120300");
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("HAR", top);
+    ASSERT_EQ("FPL", bottom);
+    ASSERT_EQ("RF", left);
+    ASSERT_EQ("LH", right);
+  }
+
+  {
+    // ASSURANCETOURIX series: 1de00990-03680ef4-0be6bd5b-73a7d350-fb46abfa
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "1\\0\\0\\0\\1\\0");
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("A", top);
+    ASSERT_EQ("P", bottom);
+    ASSERT_EQ("R", left);
+    ASSERT_EQ("L", right);
+  }
+
+  {
+    // KNEE series: 4d04593b-953ced51-87e93f11-ae4cf03c-25defdcd
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "-0\\1\\0\\-0\\-0\\-1");
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("H", top);
+    ASSERT_EQ("F", bottom);
+    ASSERT_EQ("A", left);
+    ASSERT_EQ("P", right);
+  }
+
+  {
+    // KNEE series: 20b9d0c2-97d85e07-f4dbf4d2-f09e7e6a-0c19062e
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "0.999993\\-0.0036927\\0\\-0\\-0\\-1");
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("H", top);
+    ASSERT_EQ("F", bottom);
+    ASSERT_EQ("RP", left);
+    ASSERT_EQ("LA", right);
+  }
+
+  {
+    // KNEE series: f2635388-f01d497a-15f7c06b-ad7dba06-c4c599fe
+    s = OrthancStone::CoordinateSystem3D(
+      "0\\0\\0",
+      "0.999841\\0.000366209\\0.0178227\\-0.000427244\\0.999995\\0.00326546");
+    s.GetOrientationMarkers(top, bottom, left, right);
+    ASSERT_EQ("AFL", top);
+    ASSERT_EQ("PHR", bottom);
+    ASSERT_EQ("RFA", left);
+    ASSERT_EQ("LHP", right);
+  }
+}