# HG changeset patch # User Sebastien Jodogne # Date 1666889000 -7200 # Node ID cbf54cd28d59a19985a403ffc5385eba8c43219f # Parent 40f8009ceb4e7e86c9794b595a3a597884e46c48 added CoordinateSystem3D::GetOrientationMarkers() diff -r 40f8009ceb4e -r cbf54cd28d59 OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp --- 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); + } + } } diff -r 40f8009ceb4e -r cbf54cd28d59 OrthancStone/Sources/Toolbox/CoordinateSystem3D.h --- 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; }; } diff -r 40f8009ceb4e -r cbf54cd28d59 OrthancStone/UnitTestsSources/GeometryToolboxTests.cpp --- 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); + } +}