changeset 691:032a94cca5c4

DicomVolumeSlicer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 16 May 2019 20:32:16 +0200
parents 93a8949a1ef7
children 10910827f235
files Samples/Sdl/Loader.cpp
diffstat 1 files changed, 132 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/Samples/Sdl/Loader.cpp	Thu May 16 18:33:57 2019 +0200
+++ b/Samples/Sdl/Loader.cpp	Thu May 16 20:32:16 2019 +0200
@@ -27,7 +27,7 @@
 #include "../../Framework/Toolbox/GeometryToolbox.h"
 #include "../../Framework/Toolbox/SlicesSorter.h"
 #include "../../Framework/Volumes/ImageBuffer3D.h"
-#include "../../Framework/Scene2D/ScenePoint2D.h"
+#include "../../Framework/Scene2D/Scene2D.h"
 
 // From Orthanc framework
 #include <Core/Compression/GzipCompressor.h>
@@ -1229,7 +1229,7 @@
       assert(slices_.size() == image_->GetDepth() &&
              slices_.size() == slicesRevision_.size());
 
-      if (!IsGeometryReady())
+      if (!HasGeometry())
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
       }
@@ -1307,14 +1307,14 @@
       return revision_;
     }
 
-    bool IsGeometryReady() const
+    bool HasGeometry() const
     {
       return (image_.get() != NULL);
     }
 
     const OrthancStone::ImageBuffer3D& GetImage() const
     {
-      if (!IsGeometryReady())
+      if (!HasGeometry())
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
       }
@@ -1326,7 +1326,7 @@
 
     size_t GetSlicesCount() const
     {
-      if (!IsGeometryReady())
+      if (!HasGeometry())
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
       }
@@ -1603,7 +1603,134 @@
 
 
 
+  class VolumeSlicerBase : public IVolumeSlicer
+  {
+  private:
+    OrthancStone::Scene2D&            scene_;
+    int                               layerDepth_;
+    bool                              first_;
+    OrthancStone::CoordinateSystem3D  lastPlane_;
 
+  protected:
+    bool HasViewportPlaneChanged(const OrthancStone::CoordinateSystem3D& plane) const
+    {
+      if (first_ ||
+          !OrthancStone::LinearAlgebra::IsCloseToZero(
+            boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal())))
+      {
+        // This is the first rendering, or the plane has not the same orientation
+        return false;
+      }
+      else
+      {
+        double offset1 = lastPlane_.ProjectAlongNormal(plane.GetOrigin());
+        double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin());
+        return OrthancStone::LinearAlgebra::IsCloseToZero(offset2 - offset1);
+      }
+    }
+
+    void SetLastViewportPlane(const OrthancStone::CoordinateSystem3D& plane)
+    {
+      first_ = false;
+      lastPlane_ = plane;
+    }
+
+    void SetLayer(OrthancStone::ISceneLayer* layer)
+    {
+      scene_.SetLayer(layerDepth_, layer);
+    }
+
+    void DeleteLayer()
+    {
+      scene_.DeleteLayer(layerDepth_);
+    }
+    
+  public:
+    VolumeSlicerBase(OrthancStone::Scene2D& scene,
+                     int layerDepth) :
+      scene_(scene),
+      layerDepth_(layerDepth),
+      first_(true)
+    {
+    }
+  };
+  
+
+
+  class DicomVolumeSlicer : public VolumeSlicerBase
+  {
+  private:
+    const DicomVolumeImage&  volume_;
+    bool                     hasLastSlice_;
+    uint64_t                 lastSliceRevision_;
+
+  public:
+    DicomVolumeSlicer(OrthancStone::Scene2D& scene,
+                      int layerDepth,
+                      const DicomVolumeImage& volume) :
+      VolumeSlicerBase(scene, layerDepth),
+      volume_(volume),
+      hasLastSlice_(false)
+    {
+    }
+    
+    virtual void SetViewportPlane(const OrthancStone::CoordinateSystem3D& plane)
+    {
+      if (!volume_.HasGeometry())
+      {
+        DeleteLayer();
+        return;
+      }
+
+      OrthancStone::VolumeProjection projection;
+      unsigned int sliceIndex;
+      if (!volume_.GetImage().GetGeometry().DetectSlice(projection, sliceIndex, plane))
+      {
+        // The cutting plane is neither axial, nor coronal, nor
+        // sagittal. Could use "VolumeReslicer" here.
+        DeleteLayer();
+        return;
+      }
+
+      uint64_t sliceRevision;
+      if (projection == OrthancStone::VolumeProjection_Axial)
+      {
+        sliceRevision = volume_.GetSliceRevision(sliceIndex);
+      }
+      else
+      {
+        // For coronal and sagittal projections, we take the global
+        // revision of the volume
+        sliceRevision = volume_.GetRevision();
+      }
+      
+      if (!HasViewportPlaneChanged(plane) &&
+          hasLastSlice_ &&
+          lastSliceRevision_ == sliceRevision)
+      {
+        // The viewport plane and the content of the slice have not
+        // changed since the last time the layer was set: No update needed
+        return;
+      }
+      else
+      {
+        // The layer must be updated
+        SetLastViewportPlane(plane);
+        hasLastSlice_ = true;
+        lastSliceRevision_ = sliceRevision;
+
+        {
+          OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, sliceIndex);
+
+          // TODO: Convert the image to Float32 or RGB24
+          
+          // TODO: Set the layer
+        }
+      }
+    }
+  };
+  
+