changeset 1630:78509230f0d7

SortedFrames sharing code with CoordinateSystem3D
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 09 Nov 2020 18:01:32 +0100
parents 7fc8a3ff09ee
children 960bb5fcc440
files Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp OrthancStone/Sources/Toolbox/CoordinateSystem3D.h OrthancStone/Sources/Toolbox/SortedFrames.cpp OrthancStone/Sources/Toolbox/SortedFrames.h UnitTestsSources/UnitTestsMain.cpp
diffstat 6 files changed, 81 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Nov 09 15:14:37 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Nov 09 18:01:32 2020 +0100
@@ -2250,7 +2250,7 @@
 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_;
 static std::string stringBuffer_;
 static bool softwareRendering_ = false;
-static WebViewerAction leftButtonAction_ = WebViewerAction_Rotate;  // WebViewerAction_GrayscaleWindowing;
+static WebViewerAction leftButtonAction_ = WebViewerAction_Crosshair; //WebViewerAction_GrayscaleWindowing;
 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan;
 static WebViewerAction rightButtonAction_ = WebViewerAction_Zoom;
 
--- a/OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp	Mon Nov 09 15:14:37 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/CoordinateSystem3D.cpp	Mon Nov 09 18:01:32 2020 +0100
@@ -41,7 +41,8 @@
     if (!LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(axisX_), 1.0) ||
         !LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(axisY_), 1.0))
     {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      LOG(WARNING) << "Invalid 3D geometry: Axes are not normal vectors";
+      SetupCanonical();
     }
 
     // The vectors within "Image Orientation Patient" must be
@@ -49,32 +50,39 @@
     // column direction cosine vectors shall be orthogonal, i.e.,
     // their dot product shall be zero."
     // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.2.html
-    if (!LinearAlgebra::IsCloseToZero(boost::numeric::ublas::inner_prod(axisX_, axisY_)))
+    else if (!LinearAlgebra::IsCloseToZero(boost::numeric::ublas::inner_prod(axisX_, axisY_)))
     {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      LOG(WARNING) << "Invalid 3D geometry: Image orientation patient is not orthogonal";
+      SetupCanonical();
     }
+    else
+    {
+      LinearAlgebra::CrossProduct(normal_, axisX_, axisY_);
 
-    LinearAlgebra::CrossProduct(normal_, axisX_, axisY_);
+      d_ = -(normal_[0] * origin_[0] + normal_[1] * origin_[1] + normal_[2] * origin_[2]);
 
-    d_ = -(normal_[0] * origin_[0] + normal_[1] * origin_[1] + normal_[2] * origin_[2]);
-
-    // Just a sanity check, it should be useless by construction
-    assert(LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(normal_), 1.0));
+      // Just a sanity check, it should be useless by construction
+      assert(LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(normal_), 1.0));
+    }
   }
 
 
   void CoordinateSystem3D::SetupCanonical()
   {
+    valid_ = false;
+
     LinearAlgebra::AssignVector(origin_, 0, 0, 0);
     LinearAlgebra::AssignVector(axisX_, 1, 0, 0);
     LinearAlgebra::AssignVector(axisY_, 0, 1, 0);
-    CheckAndComputeNormal();
+    LinearAlgebra::AssignVector(normal_, 0, 0, 1);
+    d_ = 0;
   }
 
 
   CoordinateSystem3D::CoordinateSystem3D(const Vector& origin,
                                          const Vector& axisX,
                                          const Vector& axisY) :
+    valid_(true),
     origin_(origin),
     axisX_(axisX),
     axisY_(axisY)
@@ -86,6 +94,8 @@
   void CoordinateSystem3D::Setup(const std::string& imagePositionPatient,
                                  const std::string& imageOrientationPatient)
   {
+    valid_ = true;
+    
     std::string tmpPosition = Orthanc::Toolbox::StripSpaces(imagePositionPatient);
     std::string tmpOrientation = Orthanc::Toolbox::StripSpaces(imageOrientationPatient);
 
@@ -95,20 +105,24 @@
         origin_.size() != 3 ||
         orientation.size() != 6)
     {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      LOG(WARNING) << "Bad 3D geometry: image position/orientation patient: \""
+                   << tmpPosition << "\" / \"" << tmpOrientation << "\"";
+      SetupCanonical();
     }
+    else
+    {
+      axisX_.resize(3);
+      axisX_[0] = orientation[0];
+      axisX_[1] = orientation[1];
+      axisX_[2] = orientation[2];
 
-    axisX_.resize(3);
-    axisX_[0] = orientation[0];
-    axisX_[1] = orientation[1];
-    axisX_[2] = orientation[2];
+      axisY_.resize(3);
+      axisY_[0] = orientation[3];
+      axisY_[1] = orientation[4];
+      axisY_[2] = orientation[5];
 
-    axisY_.resize(3);
-    axisY_[0] = orientation[3];
-    axisY_[1] = orientation[4];
-    axisY_[2] = orientation[5];
-
-    CheckAndComputeNormal();
+      CheckAndComputeNormal();
+    }
   }   
 
 
--- a/OrthancStone/Sources/Toolbox/CoordinateSystem3D.h	Mon Nov 09 15:14:37 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/CoordinateSystem3D.h	Mon Nov 09 18:01:32 2020 +0100
@@ -34,6 +34,7 @@
   class CoordinateSystem3D
   {
   private:
+    bool      valid_;
     Vector    origin_;
     Vector    normal_;
     Vector    axisX_;
@@ -71,6 +72,11 @@
 
     explicit CoordinateSystem3D(const Orthanc::DicomMap& dicom);
 
+    bool IsValid() const
+    {
+      return valid_;
+    }
+    
     const Vector& GetNormal() const
     {
       return normal_;
--- a/OrthancStone/Sources/Toolbox/SortedFrames.cpp	Mon Nov 09 15:14:37 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/SortedFrames.cpp	Mon Nov 09 18:01:32 2020 +0100
@@ -29,7 +29,8 @@
 
 namespace OrthancStone
 {
-  SortedFrames::Instance::Instance(const Orthanc::DicomMap& tags)
+  SortedFrames::Instance::Instance(const Orthanc::DicomMap& tags) :
+    geometry_(tags)
   {
     tags_.Assign(tags);
 
@@ -58,40 +59,9 @@
     {
       monochrome1_ = false;
     }
-
-    hasPosition_ = (
-      LinearAlgebra::ParseVector(position_, tags, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT) &&
-      position_.size() == 3 &&
-      GeometryToolbox::ComputeNormal(normal_, tags));
   }
 
 
-  const Vector& SortedFrames::Instance::GetNormal() const
-  {
-    if (hasPosition_)
-    {
-      return normal_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-
-
-  const Vector& SortedFrames::Instance::GetPosition() const
-  {
-    if (hasPosition_)
-    {
-      return position_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-
-  
   SortedFrames::Frame::Frame(const Instance& instance,
                              unsigned int frameNumber) :
     instance_(&instance),
@@ -343,10 +313,10 @@
       assert(instances_[*it] != NULL);
       const Instance& instance = *instances_[*it];
 
-      if (instance.HasPosition())
+      if (instance.GetGeometry().IsValid())
       {
         n += 1;
-        meanNormal += (instance.GetNormal() - meanNormal) / static_cast<float>(n);
+        meanNormal += (instance.GetGeometry().GetNormal() - meanNormal) / static_cast<float>(n);
       }
     }
 
@@ -358,13 +328,13 @@
     {
       assert(instances_[*it] != NULL);
       const Instance& instance = *instances_[*it];
-        
+      
       std::string sopInstanceUid;
-      if (instance.HasPosition() &&
+      if (instance.GetGeometry().IsValid() &&
           instance.GetTags().LookupStringValue(
             sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false))
       {
-        double p = LinearAlgebra::DotProduct(meanNormal, instance.GetPosition());
+        double p = LinearAlgebra::DotProduct(meanNormal, instance.GetGeometry().GetOrigin());
         items.push_back(SortableItem<float>(static_cast<float>(p), *it, sopInstanceUid));
       }
     }
--- a/OrthancStone/Sources/Toolbox/SortedFrames.h	Mon Nov 09 15:14:37 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/SortedFrames.h	Mon Nov 09 18:01:32 2020 +0100
@@ -22,6 +22,7 @@
 
 #pragma once
 
+#include "CoordinateSystem3D.h"
 #include "LinearAlgebra.h"
 
 namespace OrthancStone
@@ -32,13 +33,11 @@
     class Instance : public boost::noncopyable
     {
     private:
-      bool               hasPosition_;
-      Orthanc::DicomMap  tags_;
-      std::string        sopInstanceUid_;
-      unsigned int       numberOfFrames_;
-      Vector             normal_;    // Only used in "Sort()"
-      Vector             position_;  // Only used in "Sort()"
-      bool               monochrome1_;
+      Orthanc::DicomMap   tags_;
+      std::string         sopInstanceUid_;
+      unsigned int        numberOfFrames_;
+      CoordinateSystem3D  geometry_;
+      bool                monochrome1_;
 
     public:
       explicit Instance(const Orthanc::DicomMap& tags);
@@ -58,15 +57,11 @@
         return numberOfFrames_;
       }
 
-      bool HasPosition() const
+      const CoordinateSystem3D& GetGeometry() const
       {
-        return hasPosition_;
+        return geometry_;
       }
 
-      const Vector& GetNormal() const;
-
-      const Vector& GetPosition() const;
-
       bool IsMonochrome1() const
       {
         return monochrome1_;
@@ -164,6 +159,11 @@
       return GetInstance(instanceIndex).GetSopInstanceUid();
     }
 
+    const CoordinateSystem3D& GetInstanceGeometry(size_t instanceIndex) const
+    {
+      return GetInstance(instanceIndex).GetGeometry();
+    }
+
     bool LookupSopInstanceUid(size_t& instanceIndex,
                               const std::string& sopInstanceUid) const;
 
--- a/UnitTestsSources/UnitTestsMain.cpp	Mon Nov 09 15:14:37 2020 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Mon Nov 09 18:01:32 2020 +0100
@@ -879,6 +879,26 @@
 }
 
 
+TEST(CoordinateSystem3D, Basic)
+{
+  {
+    OrthancStone::CoordinateSystem3D c;
+    ASSERT_FALSE(c.IsValid());
+    ASSERT_FLOAT_EQ(c.GetNormal()[0], 0);
+    ASSERT_FLOAT_EQ(c.GetNormal()[1], 0);
+    ASSERT_FLOAT_EQ(c.GetNormal()[2], 1);
+  }
+
+  {
+    OrthancStone::CoordinateSystem3D c("nope1", "nope2");
+    ASSERT_FALSE(c.IsValid());
+    ASSERT_FLOAT_EQ(c.GetNormal()[0], 0);
+    ASSERT_FLOAT_EQ(c.GetNormal()[1], 0);
+    ASSERT_FLOAT_EQ(c.GetNormal()[2], 1);
+  }
+}
+
+
 int main(int argc, char **argv)
 {
   Orthanc::Logging::Initialize();